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> 151da177e4SLinus Torvalds 16ea202c63SThomas Bogendoerfer #include <asm/irq_cpu.h> 1789742e53SRalf Baechle #include <asm/i8253.h> 181da177e4SLinus Torvalds #include <asm/i8259.h> 191da177e4SLinus Torvalds #include <asm/io.h> 201da177e4SLinus Torvalds #include <asm/jazz.h> 21ea202c63SThomas Bogendoerfer #include <asm/pgtable.h> 221da177e4SLinus Torvalds 23*4a41abe5SRalf Baechle static DEFINE_RAW_SPINLOCK(r4030_lock); 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds static void enable_r4030_irq(unsigned int irq) 261da177e4SLinus Torvalds { 27ea202c63SThomas Bogendoerfer unsigned int mask = 1 << (irq - JAZZ_IRQ_START); 281da177e4SLinus Torvalds unsigned long flags; 291da177e4SLinus Torvalds 30*4a41abe5SRalf Baechle raw_spin_lock_irqsave(&r4030_lock, flags); 311da177e4SLinus Torvalds mask |= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 321da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 33*4a41abe5SRalf Baechle raw_spin_unlock_irqrestore(&r4030_lock, flags); 341da177e4SLinus Torvalds } 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds void disable_r4030_irq(unsigned int irq) 371da177e4SLinus Torvalds { 38ea202c63SThomas Bogendoerfer unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START)); 391da177e4SLinus Torvalds unsigned long flags; 401da177e4SLinus Torvalds 41*4a41abe5SRalf Baechle raw_spin_lock_irqsave(&r4030_lock, flags); 421da177e4SLinus Torvalds mask &= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 431da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 44*4a41abe5SRalf Baechle raw_spin_unlock_irqrestore(&r4030_lock, flags); 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 4794dee171SRalf Baechle static struct irq_chip r4030_irq_type = { 4870d21cdeSAtsushi Nemoto .name = "R4030", 491603b5acSAtsushi Nemoto .ack = disable_r4030_irq, 501603b5acSAtsushi Nemoto .mask = disable_r4030_irq, 511603b5acSAtsushi Nemoto .mask_ack = disable_r4030_irq, 521603b5acSAtsushi Nemoto .unmask = enable_r4030_irq, 531da177e4SLinus Torvalds }; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds void __init init_r4030_ints(void) 561da177e4SLinus Torvalds { 571da177e4SLinus Torvalds int i; 581da177e4SLinus Torvalds 59ea202c63SThomas Bogendoerfer for (i = JAZZ_IRQ_START; i <= JAZZ_IRQ_END; i++) 601417836eSAtsushi Nemoto set_irq_chip_and_handler(i, &r4030_irq_type, handle_level_irq); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0); 631da177e4SLinus Torvalds r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ 641da177e4SLinus Torvalds r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); /* clear error bits */ 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* 681da177e4SLinus Torvalds * On systems with i8259-style interrupt controllers we assume for 691da177e4SLinus Torvalds * driver compatibility reasons interrupts 0 - 15 to be the i8259 701da177e4SLinus Torvalds * interrupts even if the hardware uses a different interrupt numbering. 711da177e4SLinus Torvalds */ 721da177e4SLinus Torvalds void __init arch_init_irq(void) 731da177e4SLinus Torvalds { 74ea202c63SThomas Bogendoerfer /* 75ea202c63SThomas Bogendoerfer * this is a hack to get back the still needed wired mapping 76ea202c63SThomas Bogendoerfer * killed by init_mm() 77ea202c63SThomas Bogendoerfer */ 78ea202c63SThomas Bogendoerfer 79ea202c63SThomas Bogendoerfer /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ 80ea202c63SThomas Bogendoerfer add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); 81ea202c63SThomas Bogendoerfer /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ 82ea202c63SThomas Bogendoerfer add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); 83ea202c63SThomas Bogendoerfer /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ 84ea202c63SThomas Bogendoerfer add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); 85ea202c63SThomas Bogendoerfer 861da177e4SLinus Torvalds init_i8259_irqs(); /* Integrated i8259 */ 87ea202c63SThomas Bogendoerfer mips_cpu_irq_init(); 881da177e4SLinus Torvalds init_r4030_ints(); 891da177e4SLinus Torvalds 90ea202c63SThomas Bogendoerfer change_c0_status(ST0_IM, IE_IRQ2 | IE_IRQ1); 91e4ac58afSRalf Baechle } 92e4ac58afSRalf Baechle 93937a8015SRalf Baechle asmlinkage void plat_irq_dispatch(void) 94e4ac58afSRalf Baechle { 95119537c0SThiemo Seufer unsigned int pending = read_c0_cause() & read_c0_status(); 96ea202c63SThomas Bogendoerfer unsigned int irq; 97e4ac58afSRalf Baechle 98ea202c63SThomas Bogendoerfer if (pending & IE_IRQ4) { 99e4ac58afSRalf Baechle r4030_read_reg32(JAZZ_TIMER_REGISTER); 100937a8015SRalf Baechle do_IRQ(JAZZ_TIMER_IRQ); 1013be51f70SThomas Bogendoerfer } else if (pending & IE_IRQ2) { 1023be51f70SThomas Bogendoerfer irq = *(volatile u8 *)JAZZ_EISA_IRQ_ACK; 1033be51f70SThomas Bogendoerfer do_IRQ(irq); 1043be51f70SThomas Bogendoerfer } else if (pending & IE_IRQ1) { 105ea202c63SThomas Bogendoerfer irq = *(volatile u8 *)JAZZ_IO_IRQ_SOURCE >> 2; 106ea202c63SThomas Bogendoerfer if (likely(irq > 0)) 107ea202c63SThomas Bogendoerfer do_IRQ(irq + JAZZ_IRQ_START - 1); 108ea202c63SThomas Bogendoerfer else 109ea202c63SThomas Bogendoerfer panic("Unimplemented loc_no_irq handler"); 110e4ac58afSRalf Baechle } 111e4ac58afSRalf Baechle } 112584d98beSRalf Baechle 113584d98beSRalf Baechle static void r4030_set_mode(enum clock_event_mode mode, 114584d98beSRalf Baechle struct clock_event_device *evt) 115584d98beSRalf Baechle { 116584d98beSRalf Baechle /* Nothing to do ... */ 117584d98beSRalf Baechle } 118584d98beSRalf Baechle 119584d98beSRalf Baechle struct clock_event_device r4030_clockevent = { 120584d98beSRalf Baechle .name = "r4030", 121584d98beSRalf Baechle .features = CLOCK_EVT_FEAT_PERIODIC, 1223be51f70SThomas Bogendoerfer .rating = 300, 123584d98beSRalf Baechle .irq = JAZZ_TIMER_IRQ, 124584d98beSRalf Baechle .set_mode = r4030_set_mode, 125584d98beSRalf Baechle }; 126584d98beSRalf Baechle 127584d98beSRalf Baechle static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) 128584d98beSRalf Baechle { 1293be51f70SThomas Bogendoerfer struct clock_event_device *cd = dev_id; 130584d98beSRalf Baechle 1313be51f70SThomas Bogendoerfer cd->event_handler(cd); 132584d98beSRalf Baechle return IRQ_HANDLED; 133584d98beSRalf Baechle } 134584d98beSRalf Baechle 135584d98beSRalf Baechle static struct irqaction r4030_timer_irqaction = { 136584d98beSRalf Baechle .handler = r4030_timer_interrupt, 137f45e5183SWu Zhangjin .flags = IRQF_DISABLED | IRQF_TIMER, 1383be51f70SThomas Bogendoerfer .name = "R4030 timer", 139584d98beSRalf Baechle }; 140584d98beSRalf Baechle 14189742e53SRalf Baechle void __init plat_time_init(void) 142584d98beSRalf Baechle { 1433be51f70SThomas Bogendoerfer struct clock_event_device *cd = &r4030_clockevent; 1443be51f70SThomas Bogendoerfer struct irqaction *action = &r4030_timer_irqaction; 1453be51f70SThomas Bogendoerfer unsigned int cpu = smp_processor_id(); 146584d98beSRalf Baechle 147584d98beSRalf Baechle BUG_ON(HZ != 100); 148584d98beSRalf Baechle 149320ab2b0SRusty Russell cd->cpumask = cpumask_of(cpu); 1503be51f70SThomas Bogendoerfer clockevents_register_device(cd); 1513be51f70SThomas Bogendoerfer action->dev_id = cd; 1523be51f70SThomas Bogendoerfer setup_irq(JAZZ_TIMER_IRQ, action); 1533be51f70SThomas Bogendoerfer 154584d98beSRalf Baechle /* 155584d98beSRalf Baechle * Set clock to 100Hz. 156584d98beSRalf Baechle * 157584d98beSRalf Baechle * The R4030 timer receives an input clock of 1kHz which is divieded by 158584d98beSRalf Baechle * a programmable 4-bit divider. This makes it fairly inflexible. 159584d98beSRalf Baechle */ 160584d98beSRalf Baechle r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); 16189742e53SRalf Baechle setup_pit_timer(); 162584d98beSRalf Baechle } 163