[BACK]Return to simide.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / acorn32 / podulebus

Annotation of src/sys/arch/acorn32/podulebus/simide.c, Revision 1.1.4.3

1.1.4.3 ! nathanw     1: /*     $NetBSD: simide.c,v 1.1.4.2 2002/06/20 03:37:21 nathanw Exp $   */
1.1.4.2   nathanw     2:
                      3: /*
                      4:  * Copyright (c) 1997-1998 Mark Brinicombe
                      5:  * Copyright (c) 1997-1998 Causality Limited
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by Mark Brinicombe
                     18:  *     for the NetBSD Project.
                     19:  * 4. The name of the author may not be used to endorse or promote products
                     20:  *    derived from this software without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     32:  *
                     33:  * Card driver and probe and attach functions to use generic IDE driver
                     34:  * for the Simtec IDE podule
                     35:  */
                     36:
                     37: /*
                     38:  * Thanks to Gareth Simpson, Simtec Electronics for providing
                     39:  * the hardware information
                     40:  */
                     41:
                     42: #include <sys/param.h>
                     43: #include <sys/systm.h>
                     44: #include <sys/conf.h>
                     45: #include <sys/device.h>
                     46: #include <sys/malloc.h>
                     47:
                     48: #include <machine/intr.h>
                     49: #include <machine/io.h>
                     50: #include <machine/bus.h>
                     51: #include <acorn32/podulebus/podulebus.h>
                     52: #include <acorn32/podulebus/simidereg.h>
                     53:
                     54: #include <dev/ata/atavar.h>
                     55: #include <dev/ic/wdcvar.h>
                     56: #include <dev/podulebus/podules.h>
                     57:
                     58:
                     59: /*
                     60:  * Simtec IDE podule device.
                     61:  *
                     62:  * This probes and attaches the top level Simtec IDE device to the podulebus.
                     63:  * It then configures any children of the Simtec IDE device.
                     64:  * The attach args specify whether it is configuring the primary or
                     65:  * secondary channel.
                     66:  * The children are expected to be wdc devices using simide attachments.
                     67:  */
                     68:
                     69: /*
                     70:  * Simtec IDE card softc structure.
                     71:  *
                     72:  * Contains the device node, podule information and global information
                     73:  * required by the driver such as the card version and the interrupt mask.
                     74:  */
                     75:
                     76: struct simide_softc {
                     77:        struct wdc_softc        sc_wdcdev;      /* common wdc definitions */
                     78:        struct channel_softc    *wdc_chanarray[2]; /* channels definition */
                     79:        podule_t                *sc_podule;             /* Our podule info */
                     80:        int                     sc_podule_number;       /* Our podule number */
                     81:        int                     sc_ctl_reg;             /* Global ctl reg */
                     82:        int                     sc_version;             /* Card version */
                     83:        bus_space_tag_t         sc_ctliot;              /* Bus tag */
                     84:        bus_space_handle_t      sc_ctlioh;              /* control handle */
                     85:        struct bus_space        sc_tag;                 /* custom tag */
                     86:        struct simide_channel {
                     87:                struct channel_softc wdc_channel; /* generic part */
                     88:                irqhandler_t    sc_ih;                  /* interrupt handler */
                     89:                int             sc_irqmask;     /* IRQ mask for this channel */
                     90:        } simide_channels[2];
                     91: };
                     92:
                     93: int    simide_probe    __P((struct device *, struct cfdata *, void *));
                     94: void   simide_attach   __P((struct device *, struct device *, void *));
                     95: void   simide_shutdown __P((void *arg));
                     96: int    simide_intr     __P((void *arg));
                     97:
                     98: struct cfattach simide_ca = {
                     99:        sizeof(struct simide_softc), simide_probe, simide_attach
                    100: };
                    101:
                    102:
                    103: /*
                    104:  * Define prototypes for custom bus space functions.
                    105:  */
                    106:
                    107: bs_rm_2_proto(simide);
                    108: bs_wm_2_proto(simide);
                    109:
                    110: /*
                    111:  * Create an array of address structures. These define the addresses and
                    112:  * masks needed for the different channels.
                    113:  *
                    114:  * index = channel
                    115:  */
                    116:
                    117: struct {
                    118:        u_int drive_registers;
                    119:        u_int aux_register;
                    120:        u_int irq_mask;
                    121: } simide_info[] = {
                    122:        { PRIMARY_DRIVE_REGISTERS_POFFSET, PRIMARY_AUX_REGISTER_POFFSET,
                    123:          CONTROL_PRIMARY_IRQ },
                    124:        { SECONDARY_DRIVE_REGISTERS_POFFSET, SECONDARY_AUX_REGISTER_POFFSET,
                    125:          CONTROL_SECONDARY_IRQ }
                    126: };
                    127:
                    128: /*
                    129:  * Card probe function
                    130:  *
                    131:  * Just match the manufacturer and podule ID's
                    132:  */
                    133:
                    134: int
                    135: simide_probe(parent, cf, aux)
                    136:        struct device *parent;
                    137:        struct cfdata *cf;
                    138:        void *aux;
                    139: {
                    140:        struct podule_attach_args *pa = (void *)aux;
                    141:
1.1.4.3 ! nathanw   142:        return (pa->pa_product == PODULE_SIMTEC_IDE);
1.1.4.2   nathanw   143: }
                    144:
                    145: /*
                    146:  * Card attach function
                    147:  *
                    148:  * Identify the card version and configure any children.
                    149:  * Install a shutdown handler to kill interrupts on shutdown
                    150:  */
                    151:
                    152: void
                    153: simide_attach(parent, self, aux)
                    154:        struct device *parent, *self;
                    155:        void *aux;
                    156: {
                    157:        struct simide_softc *sc = (void *)self;
                    158:        struct podule_attach_args *pa = (void *)aux;
                    159:        int status;
                    160:        u_int iobase;
                    161:        int channel;
                    162:        struct simide_channel *scp;
                    163:        struct channel_softc *cp;
                    164:        irqhandler_t *ihp;
                    165:
                    166:        /* Note the podule number and validate */
                    167:        if (pa->pa_podule_number == -1)
                    168:                panic("Podule has disappeared !");
                    169:
                    170:        sc->sc_podule_number = pa->pa_podule_number;
                    171:        sc->sc_podule = pa->pa_podule;
                    172:        podules[sc->sc_podule_number].attached = 1;
                    173:
                    174:        /*
                    175:         * Ok we need our own bus tag as the register spacing
                    176:         * is not the default.
                    177:         *
                    178:         * For the podulebus the bus tag cookie is the shift
                    179:         * to apply to registers
                    180:         * So duplicate the bus space tag and change the
                    181:         * cookie.
                    182:         *
                    183:         * Also while we are at it replace the default
                    184:         * read/write mulitple short functions with
                    185:         * optimised versions
                    186:         */
                    187:
                    188:        sc->sc_tag = *pa->pa_iot;
                    189:        sc->sc_tag.bs_cookie = (void *) DRIVE_REGISTER_SPACING_SHIFT;
                    190:        sc->sc_tag.bs_rm_2 = simide_bs_rm_2;
                    191:        sc->sc_tag.bs_wm_2 = simide_bs_wm_2;
                    192:        sc->sc_ctliot = pa->pa_iot;
                    193:
                    194:        /* Obtain bus space handles for all the control registers */
                    195:        if (bus_space_map(sc->sc_ctliot, pa->pa_podule->mod_base +
                    196:            CONTROL_REGISTERS_POFFSET, CONTROL_REGISTER_SPACE, 0,
                    197:            &sc->sc_ctlioh))
                    198:                panic("%s: Cannot map control registers\n", self->dv_xname);
                    199:
                    200:        /* Install a clean up handler to make sure IRQ's are disabled */
                    201:        if (shutdownhook_establish(simide_shutdown, (void *)sc) == NULL)
                    202:                panic("%s: Cannot install shutdown handler", self->dv_xname);
                    203:
                    204:        /* Set the interrupt info for this podule */
                    205:        sc->sc_podule->irq_addr = pa->pa_podule->mod_base
                    206:            + CONTROL_REGISTERS_POFFSET + (CONTROL_REGISTER_OFFSET << 2);
                    207:        sc->sc_podule->irq_mask = STATUS_IRQ;
                    208:
                    209:        sc->sc_ctl_reg = 0;
                    210:
                    211:        status = bus_space_read_1(sc->sc_ctliot, sc->sc_ctlioh,
                    212:            STATUS_REGISTER_OFFSET);
                    213:
                    214:        printf(":");
                    215:        /* If any of the bits in STATUS_FAULT are zero then we have a fault. */
                    216:        if ((status & STATUS_FAULT) != STATUS_FAULT)
                    217:                printf(" card/cable fault (%02x) -", status);
                    218:
                    219:        if (!(status & STATUS_RESET))
                    220:                printf(" (reset)");
                    221:        if (!(status & STATUS_ADDR_TEST))
                    222:                printf(" (addr)");
                    223:        if (!(status & STATUS_CS_TEST))
                    224:                printf(" (cs)");
                    225:        if (!(status & STATUS_RW_TEST))
                    226:                printf(" (rw)");
                    227:
                    228:        printf("\n");
                    229:
                    230:        /* Perhaps we should just abort at this point. */
                    231: /*     if ((status & STATUS_FAULT) != STATUS_FAULT)
                    232:                return;*/
                    233:
                    234:        /*
                    235:         * Enable IDE, Obey IORDY and disabled slow mode
                    236:         */
                    237:        sc->sc_ctl_reg |= CONTROL_IDE_ENABLE | CONTROL_IORDY
                    238:                        | CONTROL_SLOW_MODE_OFF;
                    239:        bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    240:            CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
                    241:
                    242:        /* Fill in wdc and channel infos */
                    243:        sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
                    244:        sc->sc_wdcdev.PIO_cap = 0;
                    245:        sc->sc_wdcdev.channels = sc->wdc_chanarray;
                    246:        sc->sc_wdcdev.nchannels = 2;
                    247:        for (channel = 0 ; channel < 2; channel++) {
                    248:                scp = &sc->simide_channels[channel];
                    249:                sc->wdc_chanarray[channel] = &scp->wdc_channel;
                    250:                cp = &scp->wdc_channel;
                    251:
                    252:                cp->channel = channel;
                    253:                cp->wdc = &sc->sc_wdcdev;
                    254:                cp->ch_queue = malloc(sizeof(struct channel_queue),
                    255:                    M_DEVBUF, M_NOWAIT);
                    256:                if (cp->ch_queue == NULL) {
                    257:                        printf("%s %s channel: can't allocate memory for "
                    258:                            "command queue", self->dv_xname,
                    259:                            (channel == 0) ? "primary" : "secondary");
                    260:                        continue;
                    261:                }
                    262:                cp->cmd_iot = cp->ctl_iot = &sc->sc_tag;
                    263:                iobase = pa->pa_podule->mod_base;
                    264:                if (bus_space_map(cp->cmd_iot, iobase +
                    265:                    simide_info[channel].drive_registers,
                    266:                    DRIVE_REGISTERS_SPACE, 0, &cp->cmd_ioh))
                    267:                        continue;
                    268:                if (bus_space_map(cp->ctl_iot, iobase +
                    269:                    simide_info[channel].aux_register, 4, 0, &cp->ctl_ioh)) {
                    270:                        bus_space_unmap(cp->cmd_iot, cp->cmd_ioh,
                    271:                            DRIVE_REGISTERS_SPACE);
                    272:                        continue;
                    273:                }
                    274:                /* Disable interrupts and clear any pending interrupts */
                    275:                scp->sc_irqmask = simide_info[channel].irq_mask;
                    276:                sc->sc_ctl_reg &= ~scp->sc_irqmask;
                    277:                bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    278:                    CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
                    279:                wdcattach(cp);
                    280:                ihp = &scp->sc_ih;
                    281:                ihp->ih_func = simide_intr;
                    282:                ihp->ih_arg = scp;
                    283:                ihp->ih_level = IPL_BIO;
                    284:                ihp->ih_name = "simide";
                    285:                ihp->ih_maskaddr = pa->pa_podule->irq_addr;
                    286:                ihp->ih_maskbits = scp->sc_irqmask;
                    287:                if (irq_claim(sc->sc_podule->interrupt, ihp))
                    288:                        panic("%s: Cannot claim interrupt %d\n",
                    289:                            self->dv_xname, sc->sc_podule->interrupt);
                    290:                /* clear any pending interrupts and enable interrupts */
                    291:                sc->sc_ctl_reg |= scp->sc_irqmask;
                    292:                bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    293:                    CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
                    294:        }
                    295:
                    296: }
                    297:
                    298: /*
                    299:  * Card shutdown function
                    300:  *
                    301:  * Called via do_shutdown_hooks() during kernel shutdown.
                    302:  * Clear the cards's interrupt mask to stop any podule interrupts.
                    303:  */
                    304:
                    305: void
                    306: simide_shutdown(arg)
                    307:        void *arg;
                    308: {
                    309:        struct simide_softc *sc = arg;
                    310:
                    311:        sc->sc_ctl_reg &= (CONTROL_PRIMARY_IRQ | CONTROL_SECONDARY_IRQ);
                    312:
                    313:        /* Disable card interrupts */
                    314:        bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    315:            CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
                    316: }
                    317:
                    318: /*
                    319:  * Podule interrupt handler
                    320:  *
                    321:  * If the interrupt was from our card pass it on to the wdc interrupt handler
                    322:  */
                    323: int
                    324: simide_intr(arg)
                    325:        void *arg;
                    326: {
                    327:        struct simide_channel *scp = arg;
                    328:        irqhandler_t *ihp = &scp->sc_ih;
                    329:        volatile u_char *intraddr = (volatile u_char *)ihp->ih_maskaddr;
                    330:
                    331:        /* XXX - not bus space yet - should really be handled by podulebus */
                    332:        if ((*intraddr) & ihp->ih_maskbits)
                    333:                wdcintr(&scp->wdc_channel);
                    334:
                    335:        return(0);
                    336: }

CVSweb <webmaster@jp.NetBSD.org>