Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 1992 Linus Torvalds | |
89742e53 | 7 | * Copyright (C) 1994 - 2001, 2003, 07 Ralf Baechle |
1da177e4 | 8 | */ |
584d98be | 9 | #include <linux/clockchips.h> |
1da177e4 LT |
10 | #include <linux/init.h> |
11 | #include <linux/interrupt.h> | |
12 | #include <linux/kernel.h> | |
13 | #include <linux/spinlock.h> | |
14 | ||
ea202c63 | 15 | #include <asm/irq_cpu.h> |
89742e53 | 16 | #include <asm/i8253.h> |
1da177e4 LT |
17 | #include <asm/i8259.h> |
18 | #include <asm/io.h> | |
19 | #include <asm/jazz.h> | |
ea202c63 | 20 | #include <asm/pgtable.h> |
1da177e4 | 21 | |
1da177e4 LT |
22 | static DEFINE_SPINLOCK(r4030_lock); |
23 | ||
24 | static void enable_r4030_irq(unsigned int irq) | |
25 | { | |
ea202c63 | 26 | unsigned int mask = 1 << (irq - JAZZ_IRQ_START); |
1da177e4 LT |
27 | unsigned long flags; |
28 | ||
29 | spin_lock_irqsave(&r4030_lock, flags); | |
30 | mask |= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); | |
31 | r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); | |
32 | spin_unlock_irqrestore(&r4030_lock, flags); | |
33 | } | |
34 | ||
1da177e4 LT |
35 | void disable_r4030_irq(unsigned int irq) |
36 | { | |
ea202c63 | 37 | unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START)); |
1da177e4 LT |
38 | unsigned long flags; |
39 | ||
40 | spin_lock_irqsave(&r4030_lock, flags); | |
41 | mask &= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); | |
42 | r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); | |
43 | spin_unlock_irqrestore(&r4030_lock, flags); | |
44 | } | |
45 | ||
94dee171 | 46 | static struct irq_chip r4030_irq_type = { |
70d21cde | 47 | .name = "R4030", |
1603b5ac AN |
48 | .ack = disable_r4030_irq, |
49 | .mask = disable_r4030_irq, | |
50 | .mask_ack = disable_r4030_irq, | |
51 | .unmask = enable_r4030_irq, | |
1da177e4 LT |
52 | }; |
53 | ||
54 | void __init init_r4030_ints(void) | |
55 | { | |
56 | int i; | |
57 | ||
ea202c63 | 58 | for (i = JAZZ_IRQ_START; i <= JAZZ_IRQ_END; i++) |
1417836e | 59 | set_irq_chip_and_handler(i, &r4030_irq_type, handle_level_irq); |
1da177e4 LT |
60 | |
61 | r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0); | |
62 | r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ | |
63 | r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); /* clear error bits */ | |
64 | } | |
65 | ||
66 | /* | |
67 | * On systems with i8259-style interrupt controllers we assume for | |
68 | * driver compatibility reasons interrupts 0 - 15 to be the i8259 | |
69 | * interrupts even if the hardware uses a different interrupt numbering. | |
70 | */ | |
71 | void __init arch_init_irq(void) | |
72 | { | |
ea202c63 TB |
73 | /* |
74 | * this is a hack to get back the still needed wired mapping | |
75 | * killed by init_mm() | |
76 | */ | |
77 | ||
78 | /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ | |
79 | add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); | |
80 | /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ | |
81 | add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); | |
82 | /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ | |
83 | add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); | |
84 | ||
1da177e4 | 85 | init_i8259_irqs(); /* Integrated i8259 */ |
ea202c63 | 86 | mips_cpu_irq_init(); |
1da177e4 LT |
87 | init_r4030_ints(); |
88 | ||
ea202c63 | 89 | change_c0_status(ST0_IM, IE_IRQ2 | IE_IRQ1); |
e4ac58af RB |
90 | } |
91 | ||
937a8015 | 92 | asmlinkage void plat_irq_dispatch(void) |
e4ac58af | 93 | { |
119537c0 | 94 | unsigned int pending = read_c0_cause() & read_c0_status(); |
ea202c63 | 95 | unsigned int irq; |
e4ac58af | 96 | |
ea202c63 | 97 | if (pending & IE_IRQ4) { |
e4ac58af | 98 | r4030_read_reg32(JAZZ_TIMER_REGISTER); |
937a8015 | 99 | do_IRQ(JAZZ_TIMER_IRQ); |
3be51f70 TB |
100 | } else if (pending & IE_IRQ2) { |
101 | irq = *(volatile u8 *)JAZZ_EISA_IRQ_ACK; | |
102 | do_IRQ(irq); | |
103 | } else if (pending & IE_IRQ1) { | |
ea202c63 TB |
104 | irq = *(volatile u8 *)JAZZ_IO_IRQ_SOURCE >> 2; |
105 | if (likely(irq > 0)) | |
106 | do_IRQ(irq + JAZZ_IRQ_START - 1); | |
107 | else | |
108 | panic("Unimplemented loc_no_irq handler"); | |
e4ac58af RB |
109 | } |
110 | } | |
584d98be RB |
111 | |
112 | static void r4030_set_mode(enum clock_event_mode mode, | |
113 | struct clock_event_device *evt) | |
114 | { | |
115 | /* Nothing to do ... */ | |
116 | } | |
117 | ||
118 | struct clock_event_device r4030_clockevent = { | |
119 | .name = "r4030", | |
120 | .features = CLOCK_EVT_FEAT_PERIODIC, | |
3be51f70 | 121 | .rating = 300, |
584d98be | 122 | .irq = JAZZ_TIMER_IRQ, |
584d98be RB |
123 | .set_mode = r4030_set_mode, |
124 | }; | |
125 | ||
126 | static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) | |
127 | { | |
3be51f70 | 128 | struct clock_event_device *cd = dev_id; |
584d98be | 129 | |
3be51f70 | 130 | cd->event_handler(cd); |
584d98be RB |
131 | return IRQ_HANDLED; |
132 | } | |
133 | ||
134 | static struct irqaction r4030_timer_irqaction = { | |
135 | .handler = r4030_timer_interrupt, | |
136 | .flags = IRQF_DISABLED, | |
137 | .mask = CPU_MASK_CPU0, | |
3be51f70 | 138 | .name = "R4030 timer", |
584d98be RB |
139 | }; |
140 | ||
89742e53 | 141 | void __init plat_time_init(void) |
584d98be | 142 | { |
3be51f70 TB |
143 | struct clock_event_device *cd = &r4030_clockevent; |
144 | struct irqaction *action = &r4030_timer_irqaction; | |
145 | unsigned int cpu = smp_processor_id(); | |
584d98be RB |
146 | |
147 | BUG_ON(HZ != 100); | |
148 | ||
320ab2b0 | 149 | cd->cpumask = cpumask_of(cpu); |
3be51f70 TB |
150 | clockevents_register_device(cd); |
151 | action->dev_id = cd; | |
152 | setup_irq(JAZZ_TIMER_IRQ, action); | |
153 | ||
584d98be RB |
154 | /* |
155 | * Set clock to 100Hz. | |
156 | * | |
157 | * The R4030 timer receives an input clock of 1kHz which is divieded by | |
158 | * a programmable 4-bit divider. This makes it fairly inflexible. | |
159 | */ | |
160 | r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); | |
89742e53 | 161 | setup_pit_timer(); |
584d98be | 162 | } |