2005-04-17 02:20:36 +04:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 1992 Linus Torvalds
2007-10-18 16:51:15 +04:00
* Copyright ( C ) 1994 - 2001 , 2003 , 07 Ralf Baechle
2005-04-17 02:20:36 +04:00
*/
2007-10-12 02:46:09 +04:00
# include <linux/clockchips.h>
2011-06-01 22:04:57 +04:00
# include <linux/i8253.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
2009-06-19 17:05:26 +04:00
# include <linux/smp.h>
2005-04-17 02:20:36 +04:00
# include <linux/spinlock.h>
2010-10-07 17:08:54 +04:00
# include <linux/irq.h>
2005-04-17 02:20:36 +04:00
2007-08-25 13:01:50 +04:00
# include <asm/irq_cpu.h>
2005-04-17 02:20:36 +04:00
# include <asm/i8259.h>
# include <asm/io.h>
# include <asm/jazz.h>
2007-08-25 13:01:50 +04:00
# include <asm/pgtable.h>
2005-04-17 02:20:36 +04:00
2010-02-27 14:53:31 +03:00
static DEFINE_RAW_SPINLOCK ( r4030_lock ) ;
2005-04-17 02:20:36 +04:00
2011-03-24 00:08:52 +03:00
static void enable_r4030_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2011-03-24 00:08:52 +03:00
unsigned int mask = 1 < < ( d - > irq - JAZZ_IRQ_START ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2010-02-27 14:53:31 +03:00
raw_spin_lock_irqsave ( & r4030_lock , flags ) ;
2005-04-17 02:20:36 +04:00
mask | = r4030_read_reg16 ( JAZZ_IO_IRQ_ENABLE ) ;
r4030_write_reg16 ( JAZZ_IO_IRQ_ENABLE , mask ) ;
2010-02-27 14:53:31 +03:00
raw_spin_unlock_irqrestore ( & r4030_lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
2011-03-24 00:08:52 +03:00
void disable_r4030_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2011-03-24 00:08:52 +03:00
unsigned int mask = ~ ( 1 < < ( d - > irq - JAZZ_IRQ_START ) ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2010-02-27 14:53:31 +03:00
raw_spin_lock_irqsave ( & r4030_lock , flags ) ;
2005-04-17 02:20:36 +04:00
mask & = r4030_read_reg16 ( JAZZ_IO_IRQ_ENABLE ) ;
r4030_write_reg16 ( JAZZ_IO_IRQ_ENABLE , mask ) ;
2010-02-27 14:53:31 +03:00
raw_spin_unlock_irqrestore ( & r4030_lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
2006-07-02 17:41:42 +04:00
static struct irq_chip r4030_irq_type = {
2007-01-14 18:07:25 +03:00
. name = " R4030 " ,
2011-03-24 00:08:52 +03:00
. irq_mask = disable_r4030_irq ,
. irq_unmask = enable_r4030_irq ,
2005-04-17 02:20:36 +04:00
} ;
void __init init_r4030_ints ( void )
{
int i ;
2007-08-25 13:01:50 +04:00
for ( i = JAZZ_IRQ_START ; i < = JAZZ_IRQ_END ; i + + )
2011-03-27 17:19:28 +04:00
irq_set_chip_and_handler ( i , & r4030_irq_type , handle_level_irq ) ;
2005-04-17 02:20:36 +04:00
r4030_write_reg16 ( JAZZ_IO_IRQ_ENABLE , 0 ) ;
r4030_read_reg16 ( JAZZ_IO_IRQ_SOURCE ) ; /* clear pending IRQs */
r4030_read_reg32 ( JAZZ_R4030_INVAL_ADDR ) ; /* clear error bits */
}
/*
* On systems with i8259 - style interrupt controllers we assume for
* driver compatibility reasons interrupts 0 - 15 to be the i8259
* interrupts even if the hardware uses a different interrupt numbering .
*/
void __init arch_init_irq ( void )
{
2007-08-25 13:01:50 +04:00
/*
* this is a hack to get back the still needed wired mapping
* killed by init_mm ( )
*/
/* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */
add_wired_entry ( 0x02000017 , 0x03c00017 , 0xe0000000 , PM_64K ) ;
/* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */
add_wired_entry ( 0x02400017 , 0x02440017 , 0xe2000000 , PM_16M ) ;
/* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */
add_wired_entry ( 0x01800017 , 0x01000017 , 0xe4000000 , PM_4M ) ;
2005-04-17 02:20:36 +04:00
init_i8259_irqs ( ) ; /* Integrated i8259 */
2007-08-25 13:01:50 +04:00
mips_cpu_irq_init ( ) ;
2005-04-17 02:20:36 +04:00
init_r4030_ints ( ) ;
2007-08-25 13:01:50 +04:00
change_c0_status ( ST0_IM , IE_IRQ2 | IE_IRQ1 ) ;
2006-04-03 20:56:36 +04:00
}
2006-10-07 22:44:33 +04:00
asmlinkage void plat_irq_dispatch ( void )
2006-04-03 20:56:36 +04:00
{
2007-03-19 03:13:37 +03:00
unsigned int pending = read_c0_cause ( ) & read_c0_status ( ) ;
2007-08-25 13:01:50 +04:00
unsigned int irq ;
2006-04-03 20:56:36 +04:00
2007-08-25 13:01:50 +04:00
if ( pending & IE_IRQ4 ) {
2006-04-03 20:56:36 +04:00
r4030_read_reg32 ( JAZZ_TIMER_REGISTER ) ;
2006-10-07 22:44:33 +04:00
do_IRQ ( JAZZ_TIMER_IRQ ) ;
2007-11-02 13:17:13 +03:00
} else if ( pending & IE_IRQ2 ) {
irq = * ( volatile u8 * ) JAZZ_EISA_IRQ_ACK ;
do_IRQ ( irq ) ;
} else if ( pending & IE_IRQ1 ) {
2007-08-25 13:01:50 +04:00
irq = * ( volatile u8 * ) JAZZ_IO_IRQ_SOURCE > > 2 ;
if ( likely ( irq > 0 ) )
do_IRQ ( irq + JAZZ_IRQ_START - 1 ) ;
else
panic ( " Unimplemented loc_no_irq handler " ) ;
2006-04-03 20:56:36 +04:00
}
}
2007-10-12 02:46:09 +04:00
static void r4030_set_mode ( enum clock_event_mode mode ,
struct clock_event_device * evt )
{
/* Nothing to do ... */
}
struct clock_event_device r4030_clockevent = {
. name = " r4030 " ,
. features = CLOCK_EVT_FEAT_PERIODIC ,
2007-11-02 13:17:13 +03:00
. rating = 300 ,
2007-10-12 02:46:09 +04:00
. irq = JAZZ_TIMER_IRQ ,
. set_mode = r4030_set_mode ,
} ;
static irqreturn_t r4030_timer_interrupt ( int irq , void * dev_id )
{
2007-11-02 13:17:13 +03:00
struct clock_event_device * cd = dev_id ;
2007-10-12 02:46:09 +04:00
2007-11-02 13:17:13 +03:00
cd - > event_handler ( cd ) ;
2007-10-12 02:46:09 +04:00
return IRQ_HANDLED ;
}
static struct irqaction r4030_timer_irqaction = {
. handler = r4030_timer_interrupt ,
2009-10-08 17:17:54 +04:00
. flags = IRQF_DISABLED | IRQF_TIMER ,
2007-11-02 13:17:13 +03:00
. name = " R4030 timer " ,
2007-10-12 02:46:09 +04:00
} ;
2007-10-18 16:51:15 +04:00
void __init plat_time_init ( void )
2007-10-12 02:46:09 +04:00
{
2007-11-02 13:17:13 +03:00
struct clock_event_device * cd = & r4030_clockevent ;
struct irqaction * action = & r4030_timer_irqaction ;
unsigned int cpu = smp_processor_id ( ) ;
2007-10-12 02:46:09 +04:00
BUG_ON ( HZ ! = 100 ) ;
2008-12-13 13:50:26 +03:00
cd - > cpumask = cpumask_of ( cpu ) ;
2007-11-02 13:17:13 +03:00
clockevents_register_device ( cd ) ;
action - > dev_id = cd ;
setup_irq ( JAZZ_TIMER_IRQ , action ) ;
2007-10-12 02:46:09 +04:00
/*
* Set clock to 100 Hz .
*
* The R4030 timer receives an input clock of 1 kHz which is divieded by
* a programmable 4 - bit divider . This makes it fairly inflexible .
*/
r4030_write_reg32 ( JAZZ_TIMER_INTERVAL , 9 ) ;
2007-10-18 16:51:15 +04:00
setup_pit_timer ( ) ;
2007-10-12 02:46:09 +04:00
}