ssio.c revision 1.3.2.1 1 1.3.2.1 thorpej /* $NetBSD: ssio.c,v 1.3.2.1 2021/08/01 22:42:09 thorpej Exp $ */
2 1.1 skrll
3 1.1 skrll /* $OpenBSD: ssio.c,v 1.7 2009/03/08 22:19:04 miod Exp $ */
4 1.1 skrll
5 1.1 skrll /*
6 1.1 skrll * Copyright (c) 2007 Mark Kettenis
7 1.1 skrll *
8 1.1 skrll * Permission to use, copy, modify, and distribute this software for any
9 1.1 skrll * purpose with or without fee is hereby granted, provided that the above
10 1.1 skrll * copyright notice and this permission notice appear in all copies.
11 1.1 skrll *
12 1.1 skrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 1.1 skrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 1.1 skrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 1.1 skrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 1.1 skrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 1.1 skrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 1.1 skrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 1.1 skrll */
20 1.1 skrll
21 1.1 skrll /*
22 1.1 skrll * Driver for the National Semiconductor PC87560 Legacy I/O chip.
23 1.1 skrll */
24 1.1 skrll
25 1.1 skrll #include <sys/param.h>
26 1.1 skrll #include <sys/systm.h>
27 1.1 skrll #include <sys/device.h>
28 1.1 skrll
29 1.1 skrll #include <sys/bus.h>
30 1.1 skrll #include <machine/iomod.h>
31 1.1 skrll
32 1.1 skrll #include <dev/pci/pcireg.h>
33 1.1 skrll #include <dev/pci/pcivar.h>
34 1.1 skrll #include <dev/pci/pcidevs.h>
35 1.1 skrll #include <dev/pci/pciidereg.h>
36 1.1 skrll
37 1.1 skrll #include <hppa/hppa/machdep.h>
38 1.1 skrll #include <hppa/dev/ssiovar.h>
39 1.1 skrll
40 1.1 skrll #include "ukbd.h"
41 1.1 skrll #if NUKBD > 0
42 1.1 skrll #include <dev/usb/ohcireg.h>
43 1.1 skrll #include <dev/usb/ukbdvar.h>
44 1.1 skrll #endif
45 1.1 skrll
46 1.1 skrll /* PCI config space. */
47 1.1 skrll #define SSIO_PCI_DMA_RC2 0x64
48 1.1 skrll #define SSIO_PCI_INT_TC1 0x67
49 1.1 skrll #define SSIO_PCI_INT_TC2 0x68
50 1.1 skrll #define SSIO_PCI_INT_RC1 0x69
51 1.1 skrll #define SSIO_PCI_INT_RC2 0x6a
52 1.1 skrll #define SSIO_PCI_INT_RC3 0x6b
53 1.1 skrll #define SSIO_PCI_INT_RC4 0x6c
54 1.1 skrll #define SSIO_PCI_INT_RC5 0x6d
55 1.1 skrll #define SSIO_PCI_INT_RC6 0x6e
56 1.1 skrll #define SSIO_PCI_INT_RC7 0x6f
57 1.1 skrll #define SSIO_PCI_INT_RC8 0x70
58 1.1 skrll #define SSIO_PCI_INT_RC9 0x71
59 1.1 skrll #define SSIO_PCI_SP1BAR 0x94
60 1.1 skrll #define SSIO_PCI_SP2BAR 0x98
61 1.1 skrll #define SSIO_PCI_PPBAR 0x9c
62 1.1 skrll
63 1.1 skrll #define SSIO_PCI_INT_TC1_MASK 0xff
64 1.1 skrll #define SSIO_PCI_INT_TC1_SHIFT 24
65 1.1 skrll
66 1.1 skrll #define SSIO_PCI_INT_TC2_MASK 0xff
67 1.1 skrll #define SSIO_PCI_INT_TC2_SHIFT 0
68 1.1 skrll
69 1.1 skrll #define SSIO_PCI_INT_RC1_MASK 0xff
70 1.1 skrll #define SSIO_PCI_INT_RC1_SHIFT 8
71 1.1 skrll
72 1.1 skrll #define SSIO_PCI_INT_RC2_MASK 0xff
73 1.1 skrll #define SSIO_PCI_INT_RC2_SHIFT 16
74 1.1 skrll
75 1.1 skrll #define SSIO_PCI_INT_RC3_MASK 0xff
76 1.1 skrll #define SSIO_PCI_INT_RC3_SHIFT 24
77 1.1 skrll
78 1.1 skrll #define SSIO_PCI_INT_RC4_MASK 0xff
79 1.1 skrll #define SSIO_PCI_INT_RC4_SHIFT 0
80 1.1 skrll
81 1.1 skrll #define SSIO_PCI_INT_RC5_MASK 0xff
82 1.1 skrll #define SSIO_PCI_INT_RC5_SHIFT 8
83 1.1 skrll
84 1.1 skrll #define SSIO_PCI_INT_RC6_MASK 0xff
85 1.1 skrll #define SSIO_PCI_INT_RC6_SHIFT 16
86 1.1 skrll
87 1.1 skrll #define SSIO_PCI_INT_RC7_MASK 0xff
88 1.1 skrll #define SSIO_PCI_INT_RC7_SHIFT 24
89 1.1 skrll
90 1.1 skrll #define SSIO_PCI_INT_RC8_MASK 0xff
91 1.1 skrll #define SSIO_PCI_INT_RC8_SHIFT 0
92 1.1 skrll
93 1.1 skrll #define SSIO_PCI_INT_RC9_MASK 0xff
94 1.1 skrll #define SSIO_PCI_INT_RC9_SHIFT 8
95 1.1 skrll
96 1.1 skrll /* Cascaded i8259-compatible PICs. */
97 1.1 skrll #define SSIO_PIC1 0x20
98 1.1 skrll #define SSIO_PIC2 0xa0
99 1.1 skrll #define SSIO_NINTS 16
100 1.1 skrll
101 1.1 skrll struct ssio_iv {
102 1.1 skrll int (*handler)(void *);
103 1.1 skrll void *arg;
104 1.1 skrll };
105 1.1 skrll
106 1.1 skrll struct ssio_iv ssio_intr_table[SSIO_NINTS];
107 1.1 skrll
108 1.1 skrll struct ssio_softc {
109 1.1 skrll bus_space_tag_t sc_iot;
110 1.1 skrll bus_space_handle_t sc_ic1h;
111 1.1 skrll bus_space_handle_t sc_ic2h;
112 1.1 skrll void *sc_ih;
113 1.1 skrll };
114 1.1 skrll
115 1.1 skrll int ssio_match(device_t, cfdata_t, void *);
116 1.1 skrll void ssio_attach(device_t, device_t, void *);
117 1.1 skrll
118 1.1 skrll CFATTACH_DECL_NEW(ssio, sizeof(struct ssio_softc), ssio_match, ssio_attach, NULL,
119 1.1 skrll NULL);
120 1.1 skrll
121 1.1 skrll extern struct cfdriver ssio_cd;
122 1.1 skrll
123 1.1 skrll int ssio_intr(void *);
124 1.1 skrll int ssio_print(void *, const char *);
125 1.1 skrll
126 1.1 skrll int
127 1.1 skrll ssio_match(device_t parent, cfdata_t match, void *aux)
128 1.1 skrll {
129 1.1 skrll struct pci_attach_args *pa = aux;
130 1.1 skrll pcireg_t bhlc, id;
131 1.1 skrll pcitag_t tag;
132 1.1 skrll
133 1.1 skrll /*
134 1.1 skrll * The firmware doesn't always switch the IDE function into native
135 1.1 skrll * mode. So we do that ourselves since it makes life much simpler.
136 1.1 skrll * Note that we have to do this in the match function since the
137 1.1 skrll * Legacy I/O function attaches after the IDE function.
138 1.1 skrll */
139 1.1 skrll if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS &&
140 1.1 skrll PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_PC87415) {
141 1.1 skrll bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
142 1.1 skrll if (!PCI_HDRTYPE_MULTIFN(bhlc))
143 1.1 skrll return (0);
144 1.1 skrll
145 1.1 skrll tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 1);
146 1.1 skrll id = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG);
147 1.1 skrll if (PCI_VENDOR(id) != PCI_VENDOR_NS ||
148 1.1 skrll PCI_PRODUCT(id) != PCI_PRODUCT_NS_PC87560)
149 1.1 skrll return (0);
150 1.1 skrll
151 1.1 skrll pa->pa_class |= PCIIDE_INTERFACE_PCI(0) << PCI_INTERFACE_SHIFT;
152 1.1 skrll pa->pa_class |= PCIIDE_INTERFACE_PCI(1) << PCI_INTERFACE_SHIFT;
153 1.1 skrll pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG,
154 1.1 skrll pa->pa_class);
155 1.1 skrll return (0);
156 1.1 skrll }
157 1.1 skrll
158 1.1 skrll if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NS)
159 1.1 skrll return 0;
160 1.1 skrll
161 1.1 skrll if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_PC87560)
162 1.1 skrll return 1;
163 1.1 skrll
164 1.1 skrll return 0;
165 1.1 skrll }
166 1.1 skrll
167 1.1 skrll void
168 1.1 skrll ssio_attach(device_t parent, device_t self, void *aux)
169 1.1 skrll {
170 1.1 skrll struct ssio_softc *sc = device_private(self);
171 1.1 skrll struct pci_attach_args *pa = aux;
172 1.1 skrll struct ssio_attach_args saa;
173 1.1 skrll pci_intr_handle_t ih;
174 1.1 skrll char devinfo[256];
175 1.1 skrll const char *intrstr;
176 1.1 skrll pcireg_t reg;
177 1.1 skrll int revision;
178 1.1 skrll #if NUKBD > 0
179 1.1 skrll pcitag_t tag;
180 1.1 skrll int pagezero_cookie;
181 1.1 skrll #endif
182 1.2 christos char buf[PCI_INTRSTR_LEN];
183 1.1 skrll
184 1.1 skrll pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof devinfo);
185 1.1 skrll revision = PCI_REVISION(pa->pa_class);
186 1.1 skrll aprint_normal(": %s (rev. 0x%02x)\n", devinfo, revision);
187 1.1 skrll
188 1.1 skrll sc->sc_iot = pa->pa_iot;
189 1.1 skrll if (bus_space_map(sc->sc_iot, SSIO_PIC1, 2, 0, &sc->sc_ic1h)) {
190 1.1 skrll aprint_error_dev(self, "unable to map PIC1 registers\n");
191 1.1 skrll return;
192 1.1 skrll }
193 1.1 skrll if (bus_space_map(sc->sc_iot, SSIO_PIC2, 2, 0, &sc->sc_ic2h)) {
194 1.1 skrll aprint_error_dev(self, "unable to map PIC2 registers\n");
195 1.1 skrll goto unmap_ic1;
196 1.1 skrll }
197 1.1 skrll
198 1.1 skrll if (pci_intr_map(pa, &ih)) {
199 1.1 skrll aprint_error_dev(self, "unable to map interrupt\n");
200 1.1 skrll goto unmap_ic2;
201 1.1 skrll }
202 1.2 christos intrstr = pci_intr_string(pa->pa_pc, ih, buf, sizeof(buf));
203 1.1 skrll sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY, ssio_intr,
204 1.1 skrll sc);
205 1.1 skrll if (sc->sc_ih == NULL) {
206 1.1 skrll aprint_error_dev(self, "could not establish interrupt");
207 1.1 skrll if (intrstr != NULL)
208 1.1 skrll aprint_error(" at %s", intrstr);
209 1.1 skrll aprint_error("\n");
210 1.1 skrll goto unmap_ic2;
211 1.1 skrll }
212 1.1 skrll aprint_normal_dev(self, "interrupting at %s\n", intrstr);
213 1.1 skrll
214 1.1 skrll /*
215 1.1 skrll * We use the following interrupt mapping:
216 1.1 skrll *
217 1.1 skrll * USB (INTD#) IRQ 1
218 1.1 skrll * IDE Channel 1 IRQ 5
219 1.1 skrll * Serial Port 1 IRQ 4
220 1.1 skrll * Serial Port 2 IRQ 3
221 1.1 skrll * Parallel Port IRQ 7
222 1.1 skrll *
223 1.1 skrll * USB and IDE are set to level triggered, all others to edge
224 1.1 skrll * triggered.
225 1.1 skrll *
226 1.1 skrll * We disable all other interrupts since we don't need them.
227 1.1 skrll */
228 1.1 skrll reg = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_DMA_RC2);
229 1.1 skrll reg &= ~(SSIO_PCI_INT_TC1_MASK << SSIO_PCI_INT_TC1_SHIFT);
230 1.1 skrll reg |= 0x22 << SSIO_PCI_INT_TC1_SHIFT;
231 1.1 skrll pci_conf_write(pa->pa_pc, pa->pa_tag, SSIO_PCI_DMA_RC2, reg);
232 1.1 skrll
233 1.1 skrll reg = 0;
234 1.1 skrll reg |= 0x34 << SSIO_PCI_INT_RC1_SHIFT; /* SP1, SP2 */
235 1.1 skrll reg |= 0x07 << SSIO_PCI_INT_RC2_SHIFT; /* PP */
236 1.1 skrll reg |= 0x05 << SSIO_PCI_INT_RC3_SHIFT; /* IDE1 */
237 1.1 skrll pci_conf_write(pa->pa_pc, pa->pa_tag, SSIO_PCI_INT_TC2, reg);
238 1.1 skrll
239 1.1 skrll reg = 0;
240 1.1 skrll reg |= 0x10 << SSIO_PCI_INT_RC5_SHIFT; /* INTD# (USB) */
241 1.1 skrll pci_conf_write(pa->pa_pc, pa->pa_tag, SSIO_PCI_INT_RC4, reg);
242 1.1 skrll
243 1.1 skrll /* Program PIC1. */
244 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x11);
245 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x00);
246 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x04);
247 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x01);
248 1.1 skrll
249 1.1 skrll /* Priority (3-7,0-2). */
250 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0xc2);
251 1.1 skrll
252 1.1 skrll /* Program PIC2. */
253 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 0, 0x11);
254 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x00);
255 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x02);
256 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x01);
257 1.1 skrll
258 1.1 skrll /* Unmask all interrupts. */
259 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x00);
260 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x00);
261 1.1 skrll
262 1.1 skrll /* Serial Port 1. */
263 1.1 skrll saa.saa_name = "com";
264 1.1 skrll saa.saa_iot = sc->sc_iot;
265 1.1 skrll saa.saa_iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_SP1BAR);
266 1.1 skrll saa.saa_iobase &= 0xfffffffe;
267 1.1 skrll saa.saa_irq = 4;
268 1.3 thorpej config_found(self, &saa, ssio_print, CFARG_EOL);
269 1.1 skrll
270 1.1 skrll /* Serial Port 2. */
271 1.1 skrll saa.saa_name = "com";
272 1.1 skrll saa.saa_iot = sc->sc_iot;
273 1.1 skrll saa.saa_iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_SP2BAR);
274 1.1 skrll saa.saa_iobase &= 0xfffffffe;
275 1.1 skrll saa.saa_irq = 3;
276 1.3 thorpej config_found(self, &saa, ssio_print, CFARG_EOL);
277 1.1 skrll
278 1.1 skrll /* Parallel Port. */
279 1.1 skrll saa.saa_name = "lpt";
280 1.1 skrll saa.saa_iot = sc->sc_iot;
281 1.1 skrll saa.saa_iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_PPBAR);
282 1.1 skrll saa.saa_iobase &= 0xfffffffe;
283 1.1 skrll saa.saa_irq = 7;
284 1.3 thorpej config_found(self, &saa, ssio_print, CFARG_EOL);
285 1.1 skrll
286 1.1 skrll #if NUKBD > 0
287 1.1 skrll /*
288 1.3.2.1 thorpej * If a USB keyboard is used for console input, the firmware passes
289 1.1 skrll * the mmio address of the USB controller the keyboard is attached
290 1.1 skrll * to. Since we know the USB controller is function 2 on the same
291 1.1 skrll * device and comes right after us (we're function 1 remember),
292 1.1 skrll * this is a convenient spot to mark the USB keyboard as console
293 1.1 skrll * if the address matches.
294 1.1 skrll */
295 1.1 skrll tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 2);
296 1.1 skrll reg = pci_conf_read(pa->pa_pc, tag, PCI_CBMEM);
297 1.1 skrll
298 1.1 skrll pagezero_cookie = hppa_pagezero_map();
299 1.1 skrll if (PAGE0->mem_kbd.pz_class == PCL_KEYBD &&
300 1.1 skrll PAGE0->mem_kbd.pz_hpa == (struct iomod *)reg)
301 1.1 skrll ukbd_cnattach();
302 1.1 skrll hppa_pagezero_unmap(pagezero_cookie);
303 1.1 skrll #endif
304 1.1 skrll
305 1.1 skrll return;
306 1.1 skrll
307 1.1 skrll unmap_ic2:
308 1.1 skrll bus_space_unmap(sc->sc_iot, sc->sc_ic2h, 2);
309 1.1 skrll unmap_ic1:
310 1.1 skrll bus_space_unmap(sc->sc_iot, sc->sc_ic1h, 2);
311 1.1 skrll }
312 1.1 skrll
313 1.1 skrll int
314 1.1 skrll ssio_intr(void *v)
315 1.1 skrll {
316 1.1 skrll struct ssio_softc *sc = v;
317 1.1 skrll struct ssio_iv *iv;
318 1.1 skrll int claimed = 0;
319 1.1 skrll int irq, isr;
320 1.1 skrll
321 1.1 skrll /* Poll for interrupt. */
322 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x0c);
323 1.1 skrll irq = bus_space_read_1(sc->sc_iot, sc->sc_ic1h, 0);
324 1.1 skrll irq &= 0x07;
325 1.1 skrll
326 1.1 skrll if (irq == 7) {
327 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x0b);
328 1.1 skrll isr = bus_space_read_1(sc->sc_iot, sc->sc_ic1h, 0);
329 1.1 skrll if ((isr & 0x80) == 0)
330 1.1 skrll /* Spurious interrupt. */
331 1.1 skrll return (0);
332 1.1 skrll }
333 1.1 skrll
334 1.1 skrll iv = &ssio_intr_table[irq];
335 1.1 skrll if (iv->handler)
336 1.1 skrll claimed = iv->handler(iv->arg);
337 1.1 skrll
338 1.1 skrll /* Signal EOI. */
339 1.1 skrll bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x60 | (irq & 0x0f));
340 1.1 skrll
341 1.1 skrll return (claimed);
342 1.1 skrll }
343 1.1 skrll
344 1.1 skrll void *
345 1.1 skrll ssio_intr_establish(int pri, int irq, int (*handler)(void *), void *arg,
346 1.1 skrll const char *name)
347 1.1 skrll {
348 1.1 skrll struct ssio_iv *iv;
349 1.1 skrll
350 1.1 skrll if (irq < 0 || irq >= SSIO_NINTS || ssio_intr_table[irq].handler)
351 1.1 skrll return (NULL);
352 1.1 skrll
353 1.1 skrll iv = &ssio_intr_table[irq];
354 1.1 skrll iv->handler = handler;
355 1.1 skrll iv->arg = arg;
356 1.1 skrll
357 1.1 skrll return (iv);
358 1.1 skrll }
359 1.1 skrll
360 1.1 skrll int
361 1.1 skrll ssio_print(void *aux, const char *pnp)
362 1.1 skrll {
363 1.1 skrll struct ssio_attach_args *saa = aux;
364 1.1 skrll
365 1.1 skrll if (pnp)
366 1.1 skrll printf("%s at %s", saa->saa_name, pnp);
367 1.1 skrll if (saa->saa_iobase) {
368 1.1 skrll printf(" offset %lx", saa->saa_iobase);
369 1.1 skrll if (!pnp && saa->saa_irq >= 0)
370 1.1 skrll printf(" irq %d", saa->saa_irq);
371 1.1 skrll }
372 1.1 skrll
373 1.1 skrll return (UNCONF);
374 1.1 skrll }
375