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