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 7*89742e53SRalf 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> 131da177e4SLinus Torvalds #include <linux/spinlock.h> 141da177e4SLinus Torvalds 15ea202c63SThomas Bogendoerfer #include <asm/irq_cpu.h> 16*89742e53SRalf Baechle #include <asm/i8253.h> 171da177e4SLinus Torvalds #include <asm/i8259.h> 181da177e4SLinus Torvalds #include <asm/io.h> 191da177e4SLinus Torvalds #include <asm/jazz.h> 20ea202c63SThomas Bogendoerfer #include <asm/pgtable.h> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds static DEFINE_SPINLOCK(r4030_lock); 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds static void enable_r4030_irq(unsigned int irq) 251da177e4SLinus Torvalds { 26ea202c63SThomas Bogendoerfer unsigned int mask = 1 << (irq - JAZZ_IRQ_START); 271da177e4SLinus Torvalds unsigned long flags; 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds spin_lock_irqsave(&r4030_lock, flags); 301da177e4SLinus Torvalds mask |= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 311da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 321da177e4SLinus Torvalds spin_unlock_irqrestore(&r4030_lock, flags); 331da177e4SLinus Torvalds } 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds void disable_r4030_irq(unsigned int irq) 361da177e4SLinus Torvalds { 37ea202c63SThomas Bogendoerfer unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START)); 381da177e4SLinus Torvalds unsigned long flags; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds spin_lock_irqsave(&r4030_lock, flags); 411da177e4SLinus Torvalds mask &= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); 421da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); 431da177e4SLinus Torvalds spin_unlock_irqrestore(&r4030_lock, flags); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 4694dee171SRalf Baechle static struct irq_chip r4030_irq_type = { 4770d21cdeSAtsushi Nemoto .name = "R4030", 481603b5acSAtsushi Nemoto .ack = disable_r4030_irq, 491603b5acSAtsushi Nemoto .mask = disable_r4030_irq, 501603b5acSAtsushi Nemoto .mask_ack = disable_r4030_irq, 511603b5acSAtsushi Nemoto .unmask = enable_r4030_irq, 521da177e4SLinus Torvalds }; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds void __init init_r4030_ints(void) 551da177e4SLinus Torvalds { 561da177e4SLinus Torvalds int i; 571da177e4SLinus Torvalds 58ea202c63SThomas Bogendoerfer for (i = JAZZ_IRQ_START; i <= JAZZ_IRQ_END; i++) 591417836eSAtsushi Nemoto set_irq_chip_and_handler(i, &r4030_irq_type, handle_level_irq); 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0); 621da177e4SLinus Torvalds r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ 631da177e4SLinus Torvalds r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); /* clear error bits */ 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /* 671da177e4SLinus Torvalds * On systems with i8259-style interrupt controllers we assume for 681da177e4SLinus Torvalds * driver compatibility reasons interrupts 0 - 15 to be the i8259 691da177e4SLinus Torvalds * interrupts even if the hardware uses a different interrupt numbering. 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds void __init arch_init_irq(void) 721da177e4SLinus Torvalds { 73ea202c63SThomas Bogendoerfer /* 74ea202c63SThomas Bogendoerfer * this is a hack to get back the still needed wired mapping 75ea202c63SThomas Bogendoerfer * killed by init_mm() 76ea202c63SThomas Bogendoerfer */ 77ea202c63SThomas Bogendoerfer 78ea202c63SThomas Bogendoerfer /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ 79ea202c63SThomas Bogendoerfer add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); 80ea202c63SThomas Bogendoerfer /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ 81ea202c63SThomas Bogendoerfer add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); 82ea202c63SThomas Bogendoerfer /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ 83ea202c63SThomas Bogendoerfer add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); 84ea202c63SThomas Bogendoerfer 851da177e4SLinus Torvalds init_i8259_irqs(); /* Integrated i8259 */ 86ea202c63SThomas Bogendoerfer mips_cpu_irq_init(); 871da177e4SLinus Torvalds init_r4030_ints(); 881da177e4SLinus Torvalds 89ea202c63SThomas Bogendoerfer change_c0_status(ST0_IM, IE_IRQ2 | IE_IRQ1); 90e4ac58afSRalf Baechle } 91e4ac58afSRalf Baechle 92937a8015SRalf Baechle asmlinkage void plat_irq_dispatch(void) 93e4ac58afSRalf Baechle { 94119537c0SThiemo Seufer unsigned int pending = read_c0_cause() & read_c0_status(); 95ea202c63SThomas Bogendoerfer unsigned int irq; 96e4ac58afSRalf Baechle 97ea202c63SThomas Bogendoerfer if (pending & IE_IRQ4) { 98e4ac58afSRalf Baechle r4030_read_reg32(JAZZ_TIMER_REGISTER); 99937a8015SRalf Baechle do_IRQ(JAZZ_TIMER_IRQ); 100ea202c63SThomas Bogendoerfer } else if (pending & IE_IRQ2) 101937a8015SRalf Baechle do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK)); 102e4ac58afSRalf Baechle else if (pending & IE_IRQ1) { 103ea202c63SThomas Bogendoerfer irq = *(volatile u8 *)JAZZ_IO_IRQ_SOURCE >> 2; 104ea202c63SThomas Bogendoerfer if (likely(irq > 0)) 105ea202c63SThomas Bogendoerfer do_IRQ(irq + JAZZ_IRQ_START - 1); 106ea202c63SThomas Bogendoerfer else 107ea202c63SThomas Bogendoerfer panic("Unimplemented loc_no_irq handler"); 108e4ac58afSRalf Baechle } 109e4ac58afSRalf Baechle } 110584d98beSRalf Baechle 111584d98beSRalf Baechle static void r4030_set_mode(enum clock_event_mode mode, 112584d98beSRalf Baechle struct clock_event_device *evt) 113584d98beSRalf Baechle { 114584d98beSRalf Baechle /* Nothing to do ... */ 115584d98beSRalf Baechle } 116584d98beSRalf Baechle 117584d98beSRalf Baechle struct clock_event_device r4030_clockevent = { 118584d98beSRalf Baechle .name = "r4030", 119584d98beSRalf Baechle .features = CLOCK_EVT_FEAT_PERIODIC, 120584d98beSRalf Baechle .rating = 100, 121584d98beSRalf Baechle .irq = JAZZ_TIMER_IRQ, 122584d98beSRalf Baechle .cpumask = CPU_MASK_CPU0, 123584d98beSRalf Baechle .set_mode = r4030_set_mode, 124584d98beSRalf Baechle }; 125584d98beSRalf Baechle 126584d98beSRalf Baechle static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) 127584d98beSRalf Baechle { 128584d98beSRalf Baechle r4030_clockevent.event_handler(&r4030_clockevent); 129584d98beSRalf Baechle 130584d98beSRalf Baechle return IRQ_HANDLED; 131584d98beSRalf Baechle } 132584d98beSRalf Baechle 133584d98beSRalf Baechle static struct irqaction r4030_timer_irqaction = { 134584d98beSRalf Baechle .handler = r4030_timer_interrupt, 135584d98beSRalf Baechle .flags = IRQF_DISABLED, 136584d98beSRalf Baechle .mask = CPU_MASK_CPU0, 137584d98beSRalf Baechle .name = "timer", 138584d98beSRalf Baechle }; 139584d98beSRalf Baechle 140*89742e53SRalf Baechle void __init plat_time_init(void) 141584d98beSRalf Baechle { 142584d98beSRalf Baechle struct irqaction *irq = &r4030_timer_irqaction; 143584d98beSRalf Baechle 144584d98beSRalf Baechle BUG_ON(HZ != 100); 145584d98beSRalf Baechle 146584d98beSRalf Baechle /* 147584d98beSRalf Baechle * Set clock to 100Hz. 148584d98beSRalf Baechle * 149584d98beSRalf Baechle * The R4030 timer receives an input clock of 1kHz which is divieded by 150584d98beSRalf Baechle * a programmable 4-bit divider. This makes it fairly inflexible. 151584d98beSRalf Baechle */ 152584d98beSRalf Baechle r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); 153584d98beSRalf Baechle setup_irq(JAZZ_TIMER_IRQ, irq); 154584d98beSRalf Baechle 155584d98beSRalf Baechle clockevents_register_device(&r4030_clockevent); 156*89742e53SRalf Baechle setup_pit_timer(); 157584d98beSRalf Baechle } 158