[BACK]Return to ssio.c CVS log [TXT][DIR] Up to [local] / sys / arch / hppa / dev

Annotation of sys/arch/hppa/dev/ssio.c, Revision 1.1.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