3 /* $OpenBSD: ssio.c,v 1.7 2009/03/08 22:19:04 miod Exp $ */
6 * Copyright (c) 2007 Mark Kettenis
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Driver for the National Semiconductor PC87560 Legacy I/O chip.
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/device.h>
29 #include <machine/bus.h>
30 #include <machine/iomod.h>
32 #include <dev/pci/pcireg.h>
33 #include <dev/pci/pcivar.h>
34 #include <dev/pci/pcidevs.h>
35 #include <dev/pci/pciidereg.h>
37 #include <hp700/hp700/machdep.h>
38 #include <hp700/dev/ssiovar.h>
42 #include <dev/usb/ohcireg.h>
43 #include <dev/usb/ukbdvar.h>
46 /* PCI config space. */
47 #define SSIO_PCI_DMA_RC2 0x64
48 #define SSIO_PCI_INT_TC1 0x67
49 #define SSIO_PCI_INT_TC2 0x68
50 #define SSIO_PCI_INT_RC1 0x69
51 #define SSIO_PCI_INT_RC2 0x6a
52 #define SSIO_PCI_INT_RC3 0x6b
53 #define SSIO_PCI_INT_RC4 0x6c
54 #define SSIO_PCI_INT_RC5 0x6d
55 #define SSIO_PCI_INT_RC6 0x6e
56 #define SSIO_PCI_INT_RC7 0x6f
57 #define SSIO_PCI_INT_RC8 0x70
58 #define SSIO_PCI_INT_RC9 0x71
59 #define SSIO_PCI_SP1BAR 0x94
60 #define SSIO_PCI_SP2BAR 0x98
61 #define SSIO_PCI_PPBAR 0x9c
63 #define SSIO_PCI_INT_TC1_MASK 0xff
64 #define SSIO_PCI_INT_TC1_SHIFT 24
66 #define SSIO_PCI_INT_TC2_MASK 0xff
67 #define SSIO_PCI_INT_TC2_SHIFT 0
69 #define SSIO_PCI_INT_RC1_MASK 0xff
70 #define SSIO_PCI_INT_RC1_SHIFT 8
72 #define SSIO_PCI_INT_RC2_MASK 0xff
73 #define SSIO_PCI_INT_RC2_SHIFT 16
75 #define SSIO_PCI_INT_RC3_MASK 0xff
76 #define SSIO_PCI_INT_RC3_SHIFT 24
78 #define SSIO_PCI_INT_RC4_MASK 0xff
79 #define SSIO_PCI_INT_RC4_SHIFT 0
81 #define SSIO_PCI_INT_RC5_MASK 0xff
82 #define SSIO_PCI_INT_RC5_SHIFT 8
84 #define SSIO_PCI_INT_RC6_MASK 0xff
85 #define SSIO_PCI_INT_RC6_SHIFT 16
87 #define SSIO_PCI_INT_RC7_MASK 0xff
88 #define SSIO_PCI_INT_RC7_SHIFT 24
90 #define SSIO_PCI_INT_RC8_MASK 0xff
91 #define SSIO_PCI_INT_RC8_SHIFT 0
93 #define SSIO_PCI_INT_RC9_MASK 0xff
94 #define SSIO_PCI_INT_RC9_SHIFT 8
96 /* Cascaded i8259-compatible PICs. */
97 #define SSIO_PIC1 0x20
98 #define SSIO_PIC2 0xa0
102 int (*handler
)(void *);
106 struct ssio_iv ssio_intr_table
[SSIO_NINTS
];
109 struct device sc_dev
;
111 bus_space_tag_t sc_iot
;
112 bus_space_handle_t sc_ic1h
;
113 bus_space_handle_t sc_ic2h
;
117 int ssio_match(device_t
, cfdata_t
, void *);
118 void ssio_attach(device_t
, device_t
, void *);
120 CFATTACH_DECL_NEW(ssio
, sizeof(struct ssio_softc
), ssio_match
, ssio_attach
, NULL
,
123 extern struct cfdriver ssio_cd
;
125 int ssio_intr(void *);
126 int ssio_print(void *, const char *);
129 ssio_match(device_t parent
, cfdata_t match
, void *aux
)
131 struct pci_attach_args
*pa
= aux
;
136 * The firmware doesn't always switch the IDE function into native
137 * mode. So we do that ourselves since it makes life much simpler.
138 * Note that we have to do this in the match function since the
139 * Legacy I/O function attaches after the IDE function.
141 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_NS
&&
142 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_NS_PC87415
) {
143 bhlc
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_BHLC_REG
);
144 if (!PCI_HDRTYPE_MULTIFN(bhlc
))
147 tag
= pci_make_tag(pa
->pa_pc
, pa
->pa_bus
, pa
->pa_device
, 1);
148 id
= pci_conf_read(pa
->pa_pc
, tag
, PCI_ID_REG
);
149 if (PCI_VENDOR(id
) != PCI_VENDOR_NS
||
150 PCI_PRODUCT(id
) != PCI_PRODUCT_NS_PC87560
)
153 pa
->pa_class
|= PCIIDE_INTERFACE_PCI(0) << PCI_INTERFACE_SHIFT
;
154 pa
->pa_class
|= PCIIDE_INTERFACE_PCI(1) << PCI_INTERFACE_SHIFT
;
155 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, PCI_CLASS_REG
,
160 if (PCI_VENDOR(pa
->pa_id
) != PCI_VENDOR_NS
)
163 if (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_NS_PC87560
)
170 ssio_attach(device_t parent
, device_t self
, void *aux
)
172 struct ssio_softc
*sc
= device_private(self
);
173 struct pci_attach_args
*pa
= aux
;
174 struct ssio_attach_args saa
;
175 pci_intr_handle_t ih
;
185 pci_devinfo(pa
->pa_id
, pa
->pa_class
, 0, devinfo
, sizeof devinfo
);
186 revision
= PCI_REVISION(pa
->pa_class
);
187 aprint_normal(": %s (rev. 0x%02x)\n", devinfo
, revision
);
189 sc
->sc_iot
= pa
->pa_iot
;
190 if (bus_space_map(sc
->sc_iot
, SSIO_PIC1
, 2, 0, &sc
->sc_ic1h
)) {
191 aprint_error_dev(self
, "unable to map PIC1 registers\n");
194 if (bus_space_map(sc
->sc_iot
, SSIO_PIC2
, 2, 0, &sc
->sc_ic2h
)) {
195 aprint_error_dev(self
, "unable to map PIC2 registers\n");
199 if (pci_intr_map(pa
, &ih
)) {
200 aprint_error_dev(self
, "unable to map interrupt\n");
203 intrstr
= pci_intr_string(pa
->pa_pc
, ih
);
204 sc
->sc_ih
= pci_intr_establish(pa
->pa_pc
, ih
, IPL_TTY
, ssio_intr
,
206 if (sc
->sc_ih
== NULL
) {
207 aprint_error_dev(self
, "could not establish interrupt");
209 aprint_error(" at %s", intrstr
);
213 aprint_normal_dev(self
, "interrupting at %s\n", intrstr
);
216 * We use the following interrupt mapping:
219 * IDE Channel 1 IRQ 5
220 * Serial Port 1 IRQ 4
221 * Serial Port 2 IRQ 3
222 * Parallel Port IRQ 7
224 * USB and IDE are set to level triggered, all others to edge
227 * We disable all other interrupts since we don't need them.
229 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, SSIO_PCI_DMA_RC2
);
230 reg
&= ~(SSIO_PCI_INT_TC1_MASK
<< SSIO_PCI_INT_TC1_SHIFT
);
231 reg
|= 0x22 << SSIO_PCI_INT_TC1_SHIFT
;
232 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, SSIO_PCI_DMA_RC2
, reg
);
235 reg
|= 0x34 << SSIO_PCI_INT_RC1_SHIFT
; /* SP1, SP2 */
236 reg
|= 0x07 << SSIO_PCI_INT_RC2_SHIFT
; /* PP */
237 reg
|= 0x05 << SSIO_PCI_INT_RC3_SHIFT
; /* IDE1 */
238 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, SSIO_PCI_INT_TC2
, reg
);
241 reg
|= 0x10 << SSIO_PCI_INT_RC5_SHIFT
; /* INTD# (USB) */
242 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, SSIO_PCI_INT_RC4
, reg
);
245 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 0, 0x11);
246 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 1, 0x00);
247 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 1, 0x04);
248 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 1, 0x01);
250 /* Priority (3-7,0-2). */
251 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 0, 0xc2);
254 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic2h
, 0, 0x11);
255 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic2h
, 1, 0x00);
256 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic2h
, 1, 0x02);
257 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic2h
, 1, 0x01);
259 /* Unmask all interrupts. */
260 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 1, 0x00);
261 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic2h
, 1, 0x00);
264 saa
.saa_name
= "com";
265 saa
.saa_iot
= sc
->sc_iot
;
266 saa
.saa_iobase
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, SSIO_PCI_SP1BAR
);
267 saa
.saa_iobase
&= 0xfffffffe;
269 config_found(self
, &saa
, ssio_print
);
272 saa
.saa_name
= "com";
273 saa
.saa_iot
= sc
->sc_iot
;
274 saa
.saa_iobase
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, SSIO_PCI_SP2BAR
);
275 saa
.saa_iobase
&= 0xfffffffe;
277 config_found(self
, &saa
, ssio_print
);
280 saa
.saa_name
= "lpt";
281 saa
.saa_iot
= sc
->sc_iot
;
282 saa
.saa_iobase
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, SSIO_PCI_PPBAR
);
283 saa
.saa_iobase
&= 0xfffffffe;
285 config_found(self
, &saa
, ssio_print
);
289 * If a USB keybard is used for console input, the firmware passes
290 * the mmio address of the USB controller the keyboard is attached
291 * to. Since we know the USB controller is function 2 on the same
292 * device and comes right after us (we're function 1 remember),
293 * this is a convenient spot to mark the USB keyboard as console
294 * if the address matches.
296 tag
= pci_make_tag(pa
->pa_pc
, pa
->pa_bus
, pa
->pa_device
, 2);
297 reg
= pci_conf_read(pa
->pa_pc
, tag
, PCI_CBMEM
);
299 pagezero_cookie
= hp700_pagezero_map();
300 if (PAGE0
->mem_kbd
.pz_class
== PCL_KEYBD
&&
301 PAGE0
->mem_kbd
.pz_hpa
== (struct iomod
*)reg
)
303 hp700_pagezero_unmap(pagezero_cookie
);
309 bus_space_unmap(sc
->sc_iot
, sc
->sc_ic2h
, 2);
311 bus_space_unmap(sc
->sc_iot
, sc
->sc_ic1h
, 2);
317 struct ssio_softc
*sc
= v
;
322 /* Poll for interrupt. */
323 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 0, 0x0c);
324 irq
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ic1h
, 0);
328 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 0, 0x0b);
329 isr
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ic1h
, 0);
330 if ((isr
& 0x80) == 0)
331 /* Spurious interrupt. */
335 iv
= &ssio_intr_table
[irq
];
337 claimed
= iv
->handler(iv
->arg
);
340 bus_space_write_1(sc
->sc_iot
, sc
->sc_ic1h
, 0, 0x60 | (irq
& 0x0f));
346 ssio_intr_establish(int pri
, int irq
, int (*handler
)(void *), void *arg
,
351 if (irq
< 0 || irq
>= SSIO_NINTS
|| ssio_intr_table
[irq
].handler
)
354 iv
= &ssio_intr_table
[irq
];
355 iv
->handler
= handler
;
362 ssio_print(void *aux
, const char *pnp
)
364 struct ssio_attach_args
*saa
= aux
;
367 printf("%s at %s", saa
->saa_name
, pnp
);
368 if (saa
->saa_iobase
) {
369 printf(" offset %lx", saa
->saa_iobase
);
370 if (!pnp
&& saa
->saa_irq
>= 0)
371 printf(" irq %d", saa
->saa_irq
);