Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * linux/arch/alpha/kernel/sys_jensen.c | |
4 | * | |
5 | * Copyright (C) 1995 Linus Torvalds | |
6 | * Copyright (C) 1998, 1999 Richard Henderson | |
7 | * | |
8 | * Code supporting the Jensen. | |
9 | */ | |
10 | ||
11 | #include <linux/kernel.h> | |
12 | #include <linux/types.h> | |
13 | #include <linux/mm.h> | |
14 | #include <linux/sched.h> | |
15 | #include <linux/pci.h> | |
16 | #include <linux/init.h> | |
17 | ||
18 | #include <asm/ptrace.h> | |
1da177e4 LT |
19 | |
20 | #define __EXTERN_INLINE inline | |
21 | #include <asm/io.h> | |
22 | #include <asm/jensen.h> | |
23 | #undef __EXTERN_INLINE | |
24 | ||
25 | #include <asm/dma.h> | |
26 | #include <asm/irq.h> | |
27 | #include <asm/mmu_context.h> | |
28 | #include <asm/pgtable.h> | |
29 | #include <asm/tlbflush.h> | |
30 | ||
31 | #include "proto.h" | |
32 | #include "irq_impl.h" | |
33 | #include "pci_impl.h" | |
34 | #include "machvec_impl.h" | |
35 | ||
36 | ||
37 | /* | |
38 | * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and | |
39 | * 0x9X0 for the local motherboard interrupts. | |
40 | * | |
41 | * Note especially that those local interrupts CANNOT be masked, | |
42 | * which causes much of the pain below... | |
43 | * | |
44 | * 0x660 - NMI | |
45 | * | |
46 | * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer) | |
47 | * 0x810 - IRQ1 line printer (duh..) | |
48 | * 0x860 - IRQ6 floppy disk | |
49 | * | |
50 | * 0x900 - COM1 | |
51 | * 0x920 - COM2 | |
52 | * 0x980 - keyboard | |
53 | * 0x990 - mouse | |
54 | * | |
55 | * PCI-based systems are more sane: they don't have the local | |
56 | * interrupts at all, and have only normal PCI interrupts from | |
57 | * devices. Happily it's easy enough to do a sane mapping from the | |
58 | * Jensen. | |
59 | * | |
60 | * Note that this means that we may have to do a hardware | |
61 | * "local_op" to a different interrupt than we report to the rest of the | |
62 | * world. | |
63 | */ | |
64 | ||
1da177e4 | 65 | static void |
ff53afe6 | 66 | jensen_local_enable(struct irq_data *d) |
1da177e4 LT |
67 | { |
68 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
ff53afe6 TG |
69 | if (d->irq == 7) |
70 | i8259a_enable_irq(d); | |
1da177e4 LT |
71 | } |
72 | ||
73 | static void | |
ff53afe6 | 74 | jensen_local_disable(struct irq_data *d) |
1da177e4 LT |
75 | { |
76 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
ff53afe6 TG |
77 | if (d->irq == 7) |
78 | i8259a_disable_irq(d); | |
1da177e4 LT |
79 | } |
80 | ||
81 | static void | |
ff53afe6 | 82 | jensen_local_mask_ack(struct irq_data *d) |
1da177e4 LT |
83 | { |
84 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
ff53afe6 TG |
85 | if (d->irq == 7) |
86 | i8259a_mask_and_ack_irq(d); | |
1da177e4 LT |
87 | } |
88 | ||
44377f62 | 89 | static struct irq_chip jensen_local_irq_type = { |
8ab1221c | 90 | .name = "LOCAL", |
ff53afe6 TG |
91 | .irq_unmask = jensen_local_enable, |
92 | .irq_mask = jensen_local_disable, | |
93 | .irq_mask_ack = jensen_local_mask_ack, | |
1da177e4 LT |
94 | }; |
95 | ||
96 | static void | |
7ca56053 | 97 | jensen_device_interrupt(unsigned long vector) |
1da177e4 LT |
98 | { |
99 | int irq; | |
100 | ||
101 | switch (vector) { | |
102 | case 0x660: | |
103 | printk("Whee.. NMI received. Probable hardware error\n"); | |
104 | printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); | |
105 | return; | |
106 | ||
107 | /* local device interrupts: */ | |
108 | case 0x900: irq = 4; break; /* com1 -> irq 4 */ | |
109 | case 0x920: irq = 3; break; /* com2 -> irq 3 */ | |
110 | case 0x980: irq = 1; break; /* kbd -> irq 1 */ | |
111 | case 0x990: irq = 9; break; /* mouse -> irq 9 */ | |
112 | ||
113 | default: | |
114 | if (vector > 0x900) { | |
115 | printk("Unknown local interrupt %lx\n", vector); | |
116 | return; | |
117 | } | |
118 | ||
119 | irq = (vector - 0x800) >> 4; | |
120 | if (irq == 1) | |
121 | irq = 7; | |
122 | break; | |
123 | } | |
124 | ||
125 | /* If there is no handler yet... */ | |
a891b393 | 126 | if (!irq_has_action(irq)) { |
1da177e4 LT |
127 | /* If it is a local interrupt that cannot be masked... */ |
128 | if (vector >= 0x900) | |
129 | { | |
130 | /* Clear keyboard/mouse state */ | |
131 | inb(0x64); | |
132 | inb(0x60); | |
133 | /* Reset serial ports */ | |
134 | inb(0x3fa); | |
135 | inb(0x2fa); | |
136 | outb(0x0c, 0x3fc); | |
137 | outb(0x0c, 0x2fc); | |
138 | /* Clear NMI */ | |
139 | outb(0,0x61); | |
140 | outb(0,0x461); | |
141 | } | |
142 | } | |
143 | ||
144 | #if 0 | |
145 | /* A useful bit of code to find out if an interrupt is going wild. */ | |
146 | { | |
147 | static unsigned int last_msg = 0, last_cc = 0; | |
148 | static int last_irq = -1, count = 0; | |
149 | unsigned int cc; | |
150 | ||
151 | __asm __volatile("rpcc %0" : "=r"(cc)); | |
152 | ++count; | |
153 | #define JENSEN_CYCLES_PER_SEC (150000000) | |
154 | if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) || | |
155 | irq != last_irq) { | |
156 | printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n", | |
7ca56053 | 157 | irq, count, cc-last_cc, get_irq_regs()->pc); |
1da177e4 LT |
158 | count = 0; |
159 | last_msg = cc; | |
160 | last_irq = irq; | |
161 | } | |
162 | last_cc = cc; | |
163 | } | |
164 | #endif | |
165 | ||
3dbb8c62 | 166 | handle_irq(irq); |
1da177e4 LT |
167 | } |
168 | ||
169 | static void __init | |
170 | jensen_init_irq(void) | |
171 | { | |
172 | init_i8259a_irqs(); | |
173 | ||
a9eb076b TG |
174 | irq_set_chip_and_handler(1, &jensen_local_irq_type, handle_level_irq); |
175 | irq_set_chip_and_handler(4, &jensen_local_irq_type, handle_level_irq); | |
176 | irq_set_chip_and_handler(3, &jensen_local_irq_type, handle_level_irq); | |
177 | irq_set_chip_and_handler(7, &jensen_local_irq_type, handle_level_irq); | |
178 | irq_set_chip_and_handler(9, &jensen_local_irq_type, handle_level_irq); | |
1da177e4 LT |
179 | |
180 | common_init_isa_dma(); | |
181 | } | |
182 | ||
183 | static void __init | |
184 | jensen_init_arch(void) | |
185 | { | |
186 | struct pci_controller *hose; | |
187 | #ifdef CONFIG_PCI | |
188 | static struct pci_dev fake_isa_bridge = { .dma_mask = 0xffffffffUL, }; | |
189 | ||
190 | isa_bridge = &fake_isa_bridge; | |
191 | #endif | |
192 | ||
193 | /* Create a hose so that we can report i/o base addresses to | |
194 | userland. */ | |
195 | ||
196 | pci_isa_hose = hose = alloc_pci_controller(); | |
197 | hose->io_space = &ioport_resource; | |
198 | hose->mem_space = &iomem_resource; | |
199 | hose->index = 0; | |
200 | ||
201 | hose->sparse_mem_base = EISA_MEM - IDENT_ADDR; | |
202 | hose->dense_mem_base = 0; | |
203 | hose->sparse_io_base = EISA_IO - IDENT_ADDR; | |
204 | hose->dense_io_base = 0; | |
205 | ||
206 | hose->sg_isa = hose->sg_pci = NULL; | |
207 | __direct_map_base = 0; | |
208 | __direct_map_size = 0xffffffff; | |
209 | } | |
210 | ||
211 | static void | |
5f0e3da6 | 212 | jensen_machine_check(unsigned long vector, unsigned long la) |
1da177e4 LT |
213 | { |
214 | printk(KERN_CRIT "Machine check\n"); | |
215 | } | |
216 | ||
1da177e4 LT |
217 | /* |
218 | * The System Vector | |
219 | */ | |
220 | ||
221 | struct alpha_machine_vector jensen_mv __initmv = { | |
222 | .vector_name = "Jensen", | |
223 | DO_EV4_MMU, | |
224 | IO_LITE(JENSEN,jensen), | |
225 | .machine_check = jensen_machine_check, | |
226 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | |
227 | .rtc_port = 0x170, | |
228 | ||
229 | .nr_irqs = 16, | |
230 | .device_interrupt = jensen_device_interrupt, | |
231 | ||
232 | .init_arch = jensen_init_arch, | |
233 | .init_irq = jensen_init_irq, | |
234 | .init_rtc = common_init_rtc, | |
235 | .init_pci = NULL, | |
236 | .kill_arch = NULL, | |
237 | }; | |
238 | ALIAS_MV(jensen) |