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