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