11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 31da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 41da177e4SLinus Torvalds * for more details. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1992 Linus Torvalds 71da177e4SLinus Torvalds * Copyright (C) 1994 - 2001, 2003 Ralf Baechle 81da177e4SLinus Torvalds */ 9*584d98beSRalf Baechle #include <linux/clockchips.h> 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/interrupt.h> 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/spinlock.h> 141da177e4SLinus Torvalds 15ea202c63SThomas Bogendoerfer #include <asm/irq_cpu.h> 161da177e4SLinus Torvalds #include <asm/i8259.h> 171da177e4SLinus Torvalds #include <asm/io.h> 181da177e4SLinus Torvalds #include <asm/jazz.h> 19ea202c63SThomas Bogendoerfer #include <asm/pgtable.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds static DEFINE_SPINLOCK(r4030_lock); 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds static void enable_r4030_irq(unsigned int irq) 241da177e4SLinus Torvalds { 25ea202c63SThomas Bogendoerfer unsigned int mask = 1 << (irq - JAZZ_IRQ_START); 261da177e4SLinus Torvalds unsigned long flags; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds spin_lock_irqsave(&r4030_lock, flags); 291da177e4SLinus Torvalds mask |= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 301da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 311da177e4SLinus Torvalds spin_unlock_irqrestore(&r4030_lock, flags); 321da177e4SLinus Torvalds } 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds void disable_r4030_irq(unsigned int irq) 351da177e4SLinus Torvalds { 36ea202c63SThomas Bogendoerfer unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START)); 371da177e4SLinus Torvalds unsigned long flags; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds spin_lock_irqsave(&r4030_lock, flags); 401da177e4SLinus Torvalds mask &= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 411da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 421da177e4SLinus Torvalds spin_unlock_irqrestore(&r4030_lock, flags); 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds 4594dee171SRalf Baechle static struct irq_chip r4030_irq_type = { 4670d21cdeSAtsushi Nemoto .name = "R4030", 471603b5acSAtsushi Nemoto .ack = disable_r4030_irq, 481603b5acSAtsushi Nemoto .mask = disable_r4030_irq, 491603b5acSAtsushi Nemoto .mask_ack = disable_r4030_irq, 501603b5acSAtsushi Nemoto .unmask = enable_r4030_irq, 511da177e4SLinus Torvalds }; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds void __init init_r4030_ints(void) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds int i; 561da177e4SLinus Torvalds 57ea202c63SThomas Bogendoerfer for (i = JAZZ_IRQ_START; i <= JAZZ_IRQ_END; i++) 581417836eSAtsushi Nemoto set_irq_chip_and_handler(i, &r4030_irq_type, handle_level_irq); 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0); 611da177e4SLinus Torvalds r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ 621da177e4SLinus Torvalds r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); /* clear error bits */ 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds /* 661da177e4SLinus Torvalds * On systems with i8259-style interrupt controllers we assume for 671da177e4SLinus Torvalds * driver compatibility reasons interrupts 0 - 15 to be the i8259 681da177e4SLinus Torvalds * interrupts even if the hardware uses a different interrupt numbering. 691da177e4SLinus Torvalds */ 701da177e4SLinus Torvalds void __init arch_init_irq(void) 711da177e4SLinus Torvalds { 72ea202c63SThomas Bogendoerfer /* 73ea202c63SThomas Bogendoerfer * this is a hack to get back the still needed wired mapping 74ea202c63SThomas Bogendoerfer * killed by init_mm() 75ea202c63SThomas Bogendoerfer */ 76ea202c63SThomas Bogendoerfer 77ea202c63SThomas Bogendoerfer /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ 78ea202c63SThomas Bogendoerfer add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); 79ea202c63SThomas Bogendoerfer /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ 80ea202c63SThomas Bogendoerfer add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); 81ea202c63SThomas Bogendoerfer /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ 82ea202c63SThomas Bogendoerfer add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); 83ea202c63SThomas Bogendoerfer 841da177e4SLinus Torvalds init_i8259_irqs(); /* Integrated i8259 */ 85ea202c63SThomas Bogendoerfer mips_cpu_irq_init(); 861da177e4SLinus Torvalds init_r4030_ints(); 871da177e4SLinus Torvalds 88ea202c63SThomas Bogendoerfer change_c0_status(ST0_IM, IE_IRQ2 | IE_IRQ1); 89e4ac58afSRalf Baechle } 90e4ac58afSRalf Baechle 91937a8015SRalf Baechle asmlinkage void plat_irq_dispatch(void) 92e4ac58afSRalf Baechle { 93119537c0SThiemo Seufer unsigned int pending = read_c0_cause() & read_c0_status(); 94ea202c63SThomas Bogendoerfer unsigned int irq; 95e4ac58afSRalf Baechle 96ea202c63SThomas Bogendoerfer if (pending & IE_IRQ4) { 97e4ac58afSRalf Baechle r4030_read_reg32(JAZZ_TIMER_REGISTER); 98937a8015SRalf Baechle do_IRQ(JAZZ_TIMER_IRQ); 99ea202c63SThomas Bogendoerfer } else if (pending & IE_IRQ2) 100937a8015SRalf Baechle do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK)); 101e4ac58afSRalf Baechle else if (pending & IE_IRQ1) { 102ea202c63SThomas Bogendoerfer irq = *(volatile u8 *)JAZZ_IO_IRQ_SOURCE >> 2; 103ea202c63SThomas Bogendoerfer if (likely(irq > 0)) 104ea202c63SThomas Bogendoerfer do_IRQ(irq + JAZZ_IRQ_START - 1); 105ea202c63SThomas Bogendoerfer else 106ea202c63SThomas Bogendoerfer panic("Unimplemented loc_no_irq handler"); 107e4ac58afSRalf Baechle } 108e4ac58afSRalf Baechle } 109*584d98beSRalf Baechle 110*584d98beSRalf Baechle static void r4030_set_mode(enum clock_event_mode mode, 111*584d98beSRalf Baechle struct clock_event_device *evt) 112*584d98beSRalf Baechle { 113*584d98beSRalf Baechle /* Nothing to do ... */ 114*584d98beSRalf Baechle } 115*584d98beSRalf Baechle 116*584d98beSRalf Baechle struct clock_event_device r4030_clockevent = { 117*584d98beSRalf Baechle .name = "r4030", 118*584d98beSRalf Baechle .features = CLOCK_EVT_FEAT_PERIODIC, 119*584d98beSRalf Baechle .rating = 100, 120*584d98beSRalf Baechle .irq = JAZZ_TIMER_IRQ, 121*584d98beSRalf Baechle .cpumask = CPU_MASK_CPU0, 122*584d98beSRalf Baechle .set_mode = r4030_set_mode, 123*584d98beSRalf Baechle }; 124*584d98beSRalf Baechle 125*584d98beSRalf Baechle static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) 126*584d98beSRalf Baechle { 127*584d98beSRalf Baechle r4030_clockevent.event_handler(&r4030_clockevent); 128*584d98beSRalf Baechle 129*584d98beSRalf Baechle return IRQ_HANDLED; 130*584d98beSRalf Baechle } 131*584d98beSRalf Baechle 132*584d98beSRalf Baechle static struct irqaction r4030_timer_irqaction = { 133*584d98beSRalf Baechle .handler = r4030_timer_interrupt, 134*584d98beSRalf Baechle .flags = IRQF_DISABLED, 135*584d98beSRalf Baechle .mask = CPU_MASK_CPU0, 136*584d98beSRalf Baechle .name = "timer", 137*584d98beSRalf Baechle }; 138*584d98beSRalf Baechle 139*584d98beSRalf Baechle void __init plat_timer_setup(struct irqaction *ignored) 140*584d98beSRalf Baechle { 141*584d98beSRalf Baechle struct irqaction *irq = &r4030_timer_irqaction; 142*584d98beSRalf Baechle 143*584d98beSRalf Baechle BUG_ON(HZ != 100); 144*584d98beSRalf Baechle 145*584d98beSRalf Baechle /* 146*584d98beSRalf Baechle * Set clock to 100Hz. 147*584d98beSRalf Baechle * 148*584d98beSRalf Baechle * The R4030 timer receives an input clock of 1kHz which is divieded by 149*584d98beSRalf Baechle * a programmable 4-bit divider. This makes it fairly inflexible. 150*584d98beSRalf Baechle */ 151*584d98beSRalf Baechle r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); 152*584d98beSRalf Baechle setup_irq(JAZZ_TIMER_IRQ, irq); 153*584d98beSRalf Baechle 154*584d98beSRalf Baechle clockevents_register_device(&r4030_clockevent); 155*584d98beSRalf Baechle } 156