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 789742e53SRalf Baechle * Copyright (C) 1994 - 2001, 2003, 07 Ralf Baechle 81da177e4SLinus Torvalds */ 9584d98beSRalf Baechle #include <linux/clockchips.h> 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/interrupt.h> 121da177e4SLinus Torvalds #include <linux/kernel.h> 13631330f5SRalf Baechle #include <linux/smp.h> 141da177e4SLinus Torvalds #include <linux/spinlock.h> 15*ca4d3e67SDavid Howells #include <linux/irq.h> 161da177e4SLinus Torvalds 17ea202c63SThomas Bogendoerfer #include <asm/irq_cpu.h> 1889742e53SRalf Baechle #include <asm/i8253.h> 191da177e4SLinus Torvalds #include <asm/i8259.h> 201da177e4SLinus Torvalds #include <asm/io.h> 211da177e4SLinus Torvalds #include <asm/jazz.h> 22ea202c63SThomas Bogendoerfer #include <asm/pgtable.h> 231da177e4SLinus Torvalds 244a41abe5SRalf Baechle static DEFINE_RAW_SPINLOCK(r4030_lock); 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds static void enable_r4030_irq(unsigned int irq) 271da177e4SLinus Torvalds { 28ea202c63SThomas Bogendoerfer unsigned int mask = 1 << (irq - JAZZ_IRQ_START); 291da177e4SLinus Torvalds unsigned long flags; 301da177e4SLinus Torvalds 314a41abe5SRalf Baechle raw_spin_lock_irqsave(&r4030_lock, flags); 321da177e4SLinus Torvalds mask |= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 331da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 344a41abe5SRalf Baechle raw_spin_unlock_irqrestore(&r4030_lock, flags); 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds void disable_r4030_irq(unsigned int irq) 381da177e4SLinus Torvalds { 39ea202c63SThomas Bogendoerfer unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START)); 401da177e4SLinus Torvalds unsigned long flags; 411da177e4SLinus Torvalds 424a41abe5SRalf Baechle raw_spin_lock_irqsave(&r4030_lock, flags); 431da177e4SLinus Torvalds mask &= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 441da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 454a41abe5SRalf Baechle raw_spin_unlock_irqrestore(&r4030_lock, flags); 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 4894dee171SRalf Baechle static struct irq_chip r4030_irq_type = { 4970d21cdeSAtsushi Nemoto .name = "R4030", 501603b5acSAtsushi Nemoto .ack = disable_r4030_irq, 511603b5acSAtsushi Nemoto .mask = disable_r4030_irq, 521603b5acSAtsushi Nemoto .mask_ack = disable_r4030_irq, 531603b5acSAtsushi Nemoto .unmask = enable_r4030_irq, 541da177e4SLinus Torvalds }; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds void __init init_r4030_ints(void) 571da177e4SLinus Torvalds { 581da177e4SLinus Torvalds int i; 591da177e4SLinus Torvalds 60ea202c63SThomas Bogendoerfer for (i = JAZZ_IRQ_START; i <= JAZZ_IRQ_END; i++) 611417836eSAtsushi Nemoto set_irq_chip_and_handler(i, &r4030_irq_type, handle_level_irq); 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0); 641da177e4SLinus Torvalds r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ 651da177e4SLinus Torvalds r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); /* clear error bits */ 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds /* 691da177e4SLinus Torvalds * On systems with i8259-style interrupt controllers we assume for 701da177e4SLinus Torvalds * driver compatibility reasons interrupts 0 - 15 to be the i8259 711da177e4SLinus Torvalds * interrupts even if the hardware uses a different interrupt numbering. 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds void __init arch_init_irq(void) 741da177e4SLinus Torvalds { 75ea202c63SThomas Bogendoerfer /* 76ea202c63SThomas Bogendoerfer * this is a hack to get back the still needed wired mapping 77ea202c63SThomas Bogendoerfer * killed by init_mm() 78ea202c63SThomas Bogendoerfer */ 79ea202c63SThomas Bogendoerfer 80ea202c63SThomas Bogendoerfer /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ 81ea202c63SThomas Bogendoerfer add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); 82ea202c63SThomas Bogendoerfer /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ 83ea202c63SThomas Bogendoerfer add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); 84ea202c63SThomas Bogendoerfer /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ 85ea202c63SThomas Bogendoerfer add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); 86ea202c63SThomas Bogendoerfer 871da177e4SLinus Torvalds init_i8259_irqs(); /* Integrated i8259 */ 88ea202c63SThomas Bogendoerfer mips_cpu_irq_init(); 891da177e4SLinus Torvalds init_r4030_ints(); 901da177e4SLinus Torvalds 91ea202c63SThomas Bogendoerfer change_c0_status(ST0_IM, IE_IRQ2 | IE_IRQ1); 92e4ac58afSRalf Baechle } 93e4ac58afSRalf Baechle 94937a8015SRalf Baechle asmlinkage void plat_irq_dispatch(void) 95e4ac58afSRalf Baechle { 96119537c0SThiemo Seufer unsigned int pending = read_c0_cause() & read_c0_status(); 97ea202c63SThomas Bogendoerfer unsigned int irq; 98e4ac58afSRalf Baechle 99ea202c63SThomas Bogendoerfer if (pending & IE_IRQ4) { 100e4ac58afSRalf Baechle r4030_read_reg32(JAZZ_TIMER_REGISTER); 101937a8015SRalf Baechle do_IRQ(JAZZ_TIMER_IRQ); 1023be51f70SThomas Bogendoerfer } else if (pending & IE_IRQ2) { 1033be51f70SThomas Bogendoerfer irq = *(volatile u8 *)JAZZ_EISA_IRQ_ACK; 1043be51f70SThomas Bogendoerfer do_IRQ(irq); 1053be51f70SThomas Bogendoerfer } else if (pending & IE_IRQ1) { 106ea202c63SThomas Bogendoerfer irq = *(volatile u8 *)JAZZ_IO_IRQ_SOURCE >> 2; 107ea202c63SThomas Bogendoerfer if (likely(irq > 0)) 108ea202c63SThomas Bogendoerfer do_IRQ(irq + JAZZ_IRQ_START - 1); 109ea202c63SThomas Bogendoerfer else 110ea202c63SThomas Bogendoerfer panic("Unimplemented loc_no_irq handler"); 111e4ac58afSRalf Baechle } 112e4ac58afSRalf Baechle } 113584d98beSRalf Baechle 114584d98beSRalf Baechle static void r4030_set_mode(enum clock_event_mode mode, 115584d98beSRalf Baechle struct clock_event_device *evt) 116584d98beSRalf Baechle { 117584d98beSRalf Baechle /* Nothing to do ... */ 118584d98beSRalf Baechle } 119584d98beSRalf Baechle 120584d98beSRalf Baechle struct clock_event_device r4030_clockevent = { 121584d98beSRalf Baechle .name = "r4030", 122584d98beSRalf Baechle .features = CLOCK_EVT_FEAT_PERIODIC, 1233be51f70SThomas Bogendoerfer .rating = 300, 124584d98beSRalf Baechle .irq = JAZZ_TIMER_IRQ, 125584d98beSRalf Baechle .set_mode = r4030_set_mode, 126584d98beSRalf Baechle }; 127584d98beSRalf Baechle 128584d98beSRalf Baechle static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) 129584d98beSRalf Baechle { 1303be51f70SThomas Bogendoerfer struct clock_event_device *cd = dev_id; 131584d98beSRalf Baechle 1323be51f70SThomas Bogendoerfer cd->event_handler(cd); 133584d98beSRalf Baechle return IRQ_HANDLED; 134584d98beSRalf Baechle } 135584d98beSRalf Baechle 136584d98beSRalf Baechle static struct irqaction r4030_timer_irqaction = { 137584d98beSRalf Baechle .handler = r4030_timer_interrupt, 138f45e5183SWu Zhangjin .flags = IRQF_DISABLED | IRQF_TIMER, 1393be51f70SThomas Bogendoerfer .name = "R4030 timer", 140584d98beSRalf Baechle }; 141584d98beSRalf Baechle 14289742e53SRalf Baechle void __init plat_time_init(void) 143584d98beSRalf Baechle { 1443be51f70SThomas Bogendoerfer struct clock_event_device *cd = &r4030_clockevent; 1453be51f70SThomas Bogendoerfer struct irqaction *action = &r4030_timer_irqaction; 1463be51f70SThomas Bogendoerfer unsigned int cpu = smp_processor_id(); 147584d98beSRalf Baechle 148584d98beSRalf Baechle BUG_ON(HZ != 100); 149584d98beSRalf Baechle 150320ab2b0SRusty Russell cd->cpumask = cpumask_of(cpu); 1513be51f70SThomas Bogendoerfer clockevents_register_device(cd); 1523be51f70SThomas Bogendoerfer action->dev_id = cd; 1533be51f70SThomas Bogendoerfer setup_irq(JAZZ_TIMER_IRQ, action); 1543be51f70SThomas Bogendoerfer 155584d98beSRalf Baechle /* 156584d98beSRalf Baechle * Set clock to 100Hz. 157584d98beSRalf Baechle * 158584d98beSRalf Baechle * The R4030 timer receives an input clock of 1kHz which is divieded by 159584d98beSRalf Baechle * a programmable 4-bit divider. This makes it fairly inflexible. 160584d98beSRalf Baechle */ 161584d98beSRalf Baechle r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); 16289742e53SRalf Baechle setup_pit_timer(); 163584d98beSRalf Baechle } 164