]>
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> |
334955ef | 10 | #include <linux/i8253.h> |
1da177e4 LT |
11 | #include <linux/init.h> |
12 | #include <linux/interrupt.h> | |
13 | #include <linux/kernel.h> | |
631330f5 | 14 | #include <linux/smp.h> |
1da177e4 | 15 | #include <linux/spinlock.h> |
ca4d3e67 | 16 | #include <linux/irq.h> |
1da177e4 | 17 | |
ea202c63 | 18 | #include <asm/irq_cpu.h> |
1da177e4 LT |
19 | #include <asm/i8259.h> |
20 | #include <asm/io.h> | |
21 | #include <asm/jazz.h> | |
ea202c63 | 22 | #include <asm/pgtable.h> |
3d18c983 | 23 | #include <asm/tlbmisc.h> |
1da177e4 | 24 | |
4a41abe5 | 25 | static DEFINE_RAW_SPINLOCK(r4030_lock); |
1da177e4 | 26 | |
db00bed4 | 27 | static void enable_r4030_irq(struct irq_data *d) |
1da177e4 | 28 | { |
db00bed4 | 29 | unsigned int mask = 1 << (d->irq - JAZZ_IRQ_START); |
1da177e4 LT |
30 | unsigned long flags; |
31 | ||
4a41abe5 | 32 | raw_spin_lock_irqsave(&r4030_lock, flags); |
1da177e4 LT |
33 | mask |= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); |
34 | r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); | |
4a41abe5 | 35 | raw_spin_unlock_irqrestore(&r4030_lock, flags); |
1da177e4 LT |
36 | } |
37 | ||
db00bed4 | 38 | void disable_r4030_irq(struct irq_data *d) |
1da177e4 | 39 | { |
db00bed4 | 40 | unsigned int mask = ~(1 << (d->irq - JAZZ_IRQ_START)); |
1da177e4 LT |
41 | unsigned long flags; |
42 | ||
4a41abe5 | 43 | raw_spin_lock_irqsave(&r4030_lock, flags); |
1da177e4 LT |
44 | mask &= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE); |
45 | r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask); | |
4a41abe5 | 46 | raw_spin_unlock_irqrestore(&r4030_lock, flags); |
1da177e4 LT |
47 | } |
48 | ||
94dee171 | 49 | static struct irq_chip r4030_irq_type = { |
70d21cde | 50 | .name = "R4030", |
db00bed4 TG |
51 | .irq_mask = disable_r4030_irq, |
52 | .irq_unmask = enable_r4030_irq, | |
1da177e4 LT |
53 | }; |
54 | ||
55 | void __init init_r4030_ints(void) | |
56 | { | |
57 | int i; | |
58 | ||
ea202c63 | 59 | for (i = JAZZ_IRQ_START; i <= JAZZ_IRQ_END; i++) |
e4ec7989 | 60 | irq_set_chip_and_handler(i, &r4030_irq_type, handle_level_irq); |
1da177e4 LT |
61 | |
62 | r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0); | |
63 | r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ | |
64 | r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); /* clear error bits */ | |
65 | } | |
66 | ||
67 | /* | |
68 | * On systems with i8259-style interrupt controllers we assume for | |
69 | * driver compatibility reasons interrupts 0 - 15 to be the i8259 | |
70 | * interrupts even if the hardware uses a different interrupt numbering. | |
71 | */ | |
72 | void __init arch_init_irq(void) | |
73 | { | |
ea202c63 TB |
74 | /* |
75 | * this is a hack to get back the still needed wired mapping | |
76 | * killed by init_mm() | |
77 | */ | |
78 | ||
79 | /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ | |
80 | add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); | |
81 | /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ | |
82 | add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); | |
83 | /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ | |
84 | add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); | |
85 | ||
1da177e4 | 86 | init_i8259_irqs(); /* Integrated i8259 */ |
ea202c63 | 87 | mips_cpu_irq_init(); |
1da177e4 LT |
88 | init_r4030_ints(); |
89 | ||
ea202c63 | 90 | change_c0_status(ST0_IM, IE_IRQ2 | IE_IRQ1); |
e4ac58af RB |
91 | } |
92 | ||
937a8015 | 93 | asmlinkage void plat_irq_dispatch(void) |
e4ac58af | 94 | { |
119537c0 | 95 | unsigned int pending = read_c0_cause() & read_c0_status(); |
ea202c63 | 96 | unsigned int irq; |
e4ac58af | 97 | |
ea202c63 | 98 | if (pending & IE_IRQ4) { |
e4ac58af | 99 | r4030_read_reg32(JAZZ_TIMER_REGISTER); |
937a8015 | 100 | do_IRQ(JAZZ_TIMER_IRQ); |
3be51f70 TB |
101 | } else if (pending & IE_IRQ2) { |
102 | irq = *(volatile u8 *)JAZZ_EISA_IRQ_ACK; | |
103 | do_IRQ(irq); | |
104 | } else if (pending & IE_IRQ1) { | |
ea202c63 TB |
105 | irq = *(volatile u8 *)JAZZ_IO_IRQ_SOURCE >> 2; |
106 | if (likely(irq > 0)) | |
107 | do_IRQ(irq + JAZZ_IRQ_START - 1); | |
108 | else | |
109 | panic("Unimplemented loc_no_irq handler"); | |
e4ac58af RB |
110 | } |
111 | } | |
584d98be RB |
112 | |
113 | static void r4030_set_mode(enum clock_event_mode mode, | |
70342287 | 114 | struct clock_event_device *evt) |
584d98be RB |
115 | { |
116 | /* Nothing to do ... */ | |
117 | } | |
118 | ||
119 | struct clock_event_device r4030_clockevent = { | |
120 | .name = "r4030", | |
121 | .features = CLOCK_EVT_FEAT_PERIODIC, | |
3be51f70 | 122 | .rating = 300, |
584d98be | 123 | .irq = JAZZ_TIMER_IRQ, |
584d98be RB |
124 | .set_mode = r4030_set_mode, |
125 | }; | |
126 | ||
127 | static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) | |
128 | { | |
3be51f70 | 129 | struct clock_event_device *cd = dev_id; |
584d98be | 130 | |
3be51f70 | 131 | cd->event_handler(cd); |
584d98be RB |
132 | return IRQ_HANDLED; |
133 | } | |
134 | ||
135 | static struct irqaction r4030_timer_irqaction = { | |
136 | .handler = r4030_timer_interrupt, | |
8b5690f8 | 137 | .flags = IRQF_TIMER, |
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 | ||
70342287 | 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 | } |