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
* Copyright ( C ) 1994 - 2001 , 2003 Ralf Baechle
*/
2007-10-12 02:46:09 +04:00
# include <linux/clockchips.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/spinlock.h>
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
static DEFINE_SPINLOCK ( r4030_lock ) ;
static void enable_r4030_irq ( unsigned int irq )
{
2007-08-25 13:01:50 +04:00
unsigned int mask = 1 < < ( irq - JAZZ_IRQ_START ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
spin_lock_irqsave ( & r4030_lock , flags ) ;
mask | = r4030_read_reg16 ( JAZZ_IO_IRQ_ENABLE ) ;
r4030_write_reg16 ( JAZZ_IO_IRQ_ENABLE , mask ) ;
spin_unlock_irqrestore ( & r4030_lock , flags ) ;
}
void disable_r4030_irq ( unsigned int irq )
{
2007-08-25 13:01:50 +04:00
unsigned int mask = ~ ( 1 < < ( irq - JAZZ_IRQ_START ) ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
spin_lock_irqsave ( & r4030_lock , flags ) ;
mask & = r4030_read_reg16 ( JAZZ_IO_IRQ_ENABLE ) ;
r4030_write_reg16 ( JAZZ_IO_IRQ_ENABLE , mask ) ;
spin_unlock_irqrestore ( & r4030_lock , flags ) ;
}
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 " ,
2006-11-01 20:08:36 +03:00
. ack = disable_r4030_irq ,
. mask = disable_r4030_irq ,
. mask_ack = disable_r4030_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 + + )
2006-11-13 19:13:18 +03:00
set_irq_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-08-25 13:01:50 +04:00
} else if ( pending & IE_IRQ2 )
2006-10-07 22:44:33 +04:00
do_IRQ ( r4030_read_reg32 ( JAZZ_EISA_IRQ_ACK ) ) ;
2006-04-03 20:56:36 +04:00
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 ,
. rating = 100 ,
. irq = JAZZ_TIMER_IRQ ,
. cpumask = CPU_MASK_CPU0 ,
. set_mode = r4030_set_mode ,
} ;
static irqreturn_t r4030_timer_interrupt ( int irq , void * dev_id )
{
r4030_clockevent . event_handler ( & r4030_clockevent ) ;
return IRQ_HANDLED ;
}
static struct irqaction r4030_timer_irqaction = {
. handler = r4030_timer_interrupt ,
. flags = IRQF_DISABLED ,
. mask = CPU_MASK_CPU0 ,
. name = " timer " ,
} ;
void __init plat_timer_setup ( struct irqaction * ignored )
{
struct irqaction * irq = & r4030_timer_irqaction ;
BUG_ON ( HZ ! = 100 ) ;
/*
* 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 ) ;
setup_irq ( JAZZ_TIMER_IRQ , irq ) ;
clockevents_register_device ( & r4030_clockevent ) ;
}