Annotation of sys/arch/hppa/dev/ssio.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ssio.c,v 1.6 2007/07/05 11:28:30 kettenis 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: 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 offset\n", 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: }
CVSweb