[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.26.2.1

1.26.2.1! yamt        1: /*     $NetBSD: simide.c,v 1.26 2011/07/19 15:59:54 dyoung Exp $       */
1.1       reinoud     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:  */
1.8       lukem      41:
                     42: #include <sys/cdefs.h>
1.26.2.1! yamt       43: __KERNEL_RCSID(0, "$NetBSD: simide.c,v 1.26 2011/07/19 15:59:54 dyoung Exp $");
1.1       reinoud    44:
                     45: #include <sys/param.h>
                     46: #include <sys/systm.h>
                     47: #include <sys/conf.h>
                     48: #include <sys/device.h>
                     49: #include <sys/malloc.h>
1.26      dyoung     50: #include <sys/bus.h>
1.1       reinoud    51:
1.2       thorpej    52: #include <machine/intr.h>
1.1       reinoud    53: #include <machine/io.h>
                     54: #include <acorn32/podulebus/podulebus.h>
                     55: #include <acorn32/podulebus/simidereg.h>
                     56:
                     57: #include <dev/ata/atavar.h>
1.14      bjh21      58: #include <dev/ic/wdcreg.h>
1.1       reinoud    59: #include <dev/ic/wdcvar.h>
                     60: #include <dev/podulebus/podules.h>
                     61:
                     62:
                     63: /*
                     64:  * Simtec IDE podule device.
                     65:  *
                     66:  * This probes and attaches the top level Simtec IDE device to the podulebus.
                     67:  * It then configures any children of the Simtec IDE device.
                     68:  * The attach args specify whether it is configuring the primary or
                     69:  * secondary channel.
                     70:  * The children are expected to be wdc devices using simide attachments.
                     71:  */
                     72:
                     73: /*
                     74:  * Simtec IDE card softc structure.
                     75:  *
                     76:  * Contains the device node, podule information and global information
                     77:  * required by the driver such as the card version and the interrupt mask.
                     78:  */
                     79:
                     80: struct simide_softc {
                     81:        struct wdc_softc        sc_wdcdev;      /* common wdc definitions */
1.20      thorpej    82:        struct ata_channel      *sc_chanarray[2]; /* channels definition */
1.1       reinoud    83:        podule_t                *sc_podule;             /* Our podule info */
                     84:        int                     sc_podule_number;       /* Our podule number */
                     85:        int                     sc_ctl_reg;             /* Global ctl reg */
                     86:        int                     sc_version;             /* Card version */
                     87:        bus_space_tag_t         sc_ctliot;              /* Bus tag */
                     88:        bus_space_handle_t      sc_ctlioh;              /* control handle */
                     89:        struct bus_space        sc_tag;                 /* custom tag */
                     90:        struct simide_channel {
1.20      thorpej    91:                struct ata_channel sc_channel;  /* generic part */
                     92:                struct ata_queue sc_chqueue;            /* channel queue */
1.1       reinoud    93:                irqhandler_t    sc_ih;                  /* interrupt handler */
                     94:                int             sc_irqmask;     /* IRQ mask for this channel */
                     95:        } simide_channels[2];
1.20      thorpej    96:        struct wdc_regs sc_wdc_regs[2];
1.1       reinoud    97: };
                     98:
1.25      cube       99: int    simide_probe    (device_t, cfdata_t, void *);
                    100: void   simide_attach   (device_t, device_t, void *);
                    101: void   simide_shutdown (void *arg);
                    102: int    simide_intr     (void *arg);
1.1       reinoud   103:
1.25      cube      104: CFATTACH_DECL_NEW(simide, sizeof(struct simide_softc),
1.7       thorpej   105:     simide_probe, simide_attach, NULL, NULL);
1.1       reinoud   106:
                    107:
                    108: /*
                    109:  * Define prototypes for custom bus space functions.
                    110:  */
                    111:
                    112: bs_rm_2_proto(simide);
                    113: bs_wm_2_proto(simide);
                    114:
                    115: /*
                    116:  * Create an array of address structures. These define the addresses and
                    117:  * masks needed for the different channels.
                    118:  *
                    119:  * index = channel
                    120:  */
                    121:
                    122: struct {
                    123:        u_int drive_registers;
                    124:        u_int aux_register;
                    125:        u_int irq_mask;
                    126: } simide_info[] = {
                    127:        { PRIMARY_DRIVE_REGISTERS_POFFSET, PRIMARY_AUX_REGISTER_POFFSET,
                    128:          CONTROL_PRIMARY_IRQ },
                    129:        { SECONDARY_DRIVE_REGISTERS_POFFSET, SECONDARY_AUX_REGISTER_POFFSET,
                    130:          CONTROL_SECONDARY_IRQ }
                    131: };
                    132:
                    133: /*
                    134:  * Card probe function
                    135:  *
                    136:  * Just match the manufacturer and podule ID's
                    137:  */
                    138:
                    139: int
1.25      cube      140: simide_probe(device_t parent, cfdata_t cf, void *aux)
1.1       reinoud   141: {
                    142:        struct podule_attach_args *pa = (void *)aux;
                    143:
1.3       bjh21     144:        return (pa->pa_product == PODULE_SIMTEC_IDE);
1.1       reinoud   145: }
                    146:
                    147: /*
                    148:  * Card attach function
                    149:  *
                    150:  * Identify the card version and configure any children.
                    151:  * Install a shutdown handler to kill interrupts on shutdown
                    152:  */
                    153:
                    154: void
1.25      cube      155: simide_attach(device_t parent, device_t self, void *aux)
1.1       reinoud   156: {
1.25      cube      157:        struct simide_softc *sc = device_private(self);
1.1       reinoud   158:        struct podule_attach_args *pa = (void *)aux;
                    159:        int status;
                    160:        u_int iobase;
1.14      bjh21     161:        int channel, i;
1.1       reinoud   162:        struct simide_channel *scp;
1.20      thorpej   163:        struct ata_channel *cp;
                    164:        struct wdc_regs *wdr;
1.1       reinoud   165:        irqhandler_t *ihp;
                    166:
                    167:        /* Note the podule number and validate */
                    168:        if (pa->pa_podule_number == -1)
                    169:                panic("Podule has disappeared !");
                    170:
1.25      cube      171:        sc->sc_wdcdev.sc_atac.atac_dev = self;
1.1       reinoud   172:        sc->sc_podule_number = pa->pa_podule_number;
                    173:        sc->sc_podule = pa->pa_podule;
                    174:        podules[sc->sc_podule_number].attached = 1;
                    175:
1.20      thorpej   176:        sc->sc_wdcdev.regs = sc->sc_wdc_regs;
                    177:
1.1       reinoud   178:        /*
                    179:         * Ok we need our own bus tag as the register spacing
                    180:         * is not the default.
                    181:         *
                    182:         * For the podulebus the bus tag cookie is the shift
                    183:         * to apply to registers
                    184:         * So duplicate the bus space tag and change the
                    185:         * cookie.
                    186:         *
                    187:         * Also while we are at it replace the default
                    188:         * read/write mulitple short functions with
                    189:         * optimised versions
                    190:         */
                    191:
                    192:        sc->sc_tag = *pa->pa_iot;
                    193:        sc->sc_tag.bs_cookie = (void *) DRIVE_REGISTER_SPACING_SHIFT;
                    194:        sc->sc_tag.bs_rm_2 = simide_bs_rm_2;
                    195:        sc->sc_tag.bs_wm_2 = simide_bs_wm_2;
                    196:        sc->sc_ctliot = pa->pa_iot;
                    197:
                    198:        /* Obtain bus space handles for all the control registers */
                    199:        if (bus_space_map(sc->sc_ctliot, pa->pa_podule->mod_base +
                    200:            CONTROL_REGISTERS_POFFSET, CONTROL_REGISTER_SPACE, 0,
                    201:            &sc->sc_ctlioh))
1.25      cube      202:                panic("%s: Cannot map control registers", device_xname(self));
1.1       reinoud   203:
                    204:        /* Install a clean up handler to make sure IRQ's are disabled */
                    205:        if (shutdownhook_establish(simide_shutdown, (void *)sc) == NULL)
1.25      cube      206:                panic("%s: Cannot install shutdown handler",
                    207:                    device_xname(self));
1.1       reinoud   208:
                    209:        /* Set the interrupt info for this podule */
                    210:        sc->sc_podule->irq_addr = pa->pa_podule->mod_base
                    211:            + CONTROL_REGISTERS_POFFSET + (CONTROL_REGISTER_OFFSET << 2);
                    212:        sc->sc_podule->irq_mask = STATUS_IRQ;
                    213:
                    214:        sc->sc_ctl_reg = 0;
                    215:
                    216:        status = bus_space_read_1(sc->sc_ctliot, sc->sc_ctlioh,
                    217:            STATUS_REGISTER_OFFSET);
                    218:
1.25      cube      219:        aprint_normal(":");
1.1       reinoud   220:        /* If any of the bits in STATUS_FAULT are zero then we have a fault. */
                    221:        if ((status & STATUS_FAULT) != STATUS_FAULT)
1.25      cube      222:                aprint_normal(" card/cable fault (%02x) -", status);
1.1       reinoud   223:
                    224:        if (!(status & STATUS_RESET))
1.25      cube      225:                aprint_normal(" (reset)");
1.1       reinoud   226:        if (!(status & STATUS_ADDR_TEST))
1.25      cube      227:                aprint_normal(" (addr)");
1.1       reinoud   228:        if (!(status & STATUS_CS_TEST))
1.25      cube      229:                aprint_normal(" (cs)");
1.1       reinoud   230:        if (!(status & STATUS_RW_TEST))
1.25      cube      231:                aprint_normal(" (rw)");
1.1       reinoud   232:
1.25      cube      233:        aprint_normal("\n");
1.1       reinoud   234:
                    235:        /* Perhaps we should just abort at this point. */
                    236: /*     if ((status & STATUS_FAULT) != STATUS_FAULT)
                    237:                return;*/
                    238:
                    239:        /*
                    240:         * Enable IDE, Obey IORDY and disabled slow mode
                    241:         */
                    242:        sc->sc_ctl_reg |= CONTROL_IDE_ENABLE | CONTROL_IORDY
                    243:                        | CONTROL_SLOW_MODE_OFF;
                    244:        bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    245:            CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
                    246:
                    247:        /* Fill in wdc and channel infos */
1.21      thorpej   248:        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16;
                    249:        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
                    250:        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray;
                    251:        sc->sc_wdcdev.sc_atac.atac_nchannels = 2;
1.26.2.1! yamt      252:        sc->sc_wdcdev.wdc_maxdrives = 2;
1.1       reinoud   253:        for (channel = 0 ; channel < 2; channel++) {
                    254:                scp = &sc->simide_channels[channel];
1.20      thorpej   255:                sc->sc_chanarray[channel] = &scp->sc_channel;
                    256:                cp = &scp->sc_channel;
                    257:                wdr = &sc->sc_wdc_regs[channel];
1.1       reinoud   258:
1.18      thorpej   259:                cp->ch_channel = channel;
1.21      thorpej   260:                cp->ch_atac = &sc->sc_wdcdev.sc_atac;
1.20      thorpej   261:                cp->ch_queue = &scp->sc_chqueue;
                    262:                wdr->cmd_iot = wdr->ctl_iot = &sc->sc_tag;
1.1       reinoud   263:                iobase = pa->pa_podule->mod_base;
1.20      thorpej   264:                if (bus_space_map(wdr->cmd_iot, iobase +
1.1       reinoud   265:                    simide_info[channel].drive_registers,
1.20      thorpej   266:                    DRIVE_REGISTERS_SPACE, 0, &wdr->cmd_baseioh))
1.1       reinoud   267:                        continue;
1.24      bjh21     268:                for (i = 0; i < WDC_NREG; i++) {
1.20      thorpej   269:                        if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
                    270:                                i, i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
                    271:                                bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh,
1.14      bjh21     272:                                    DRIVE_REGISTERS_SPACE);
                    273:                                continue;
                    274:                        }
                    275:                }
1.19      thorpej   276:                wdc_init_shadow_regs(cp);
1.20      thorpej   277:                if (bus_space_map(wdr->ctl_iot, iobase +
                    278:                    simide_info[channel].aux_register, 4, 0, &wdr->ctl_ioh)) {
                    279:                        bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh,
1.1       reinoud   280:                            DRIVE_REGISTERS_SPACE);
                    281:                        continue;
                    282:                }
                    283:                /* Disable interrupts and clear any pending interrupts */
                    284:                scp->sc_irqmask = simide_info[channel].irq_mask;
                    285:                sc->sc_ctl_reg &= ~scp->sc_irqmask;
                    286:                bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    287:                    CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
                    288:                ihp = &scp->sc_ih;
                    289:                ihp->ih_func = simide_intr;
                    290:                ihp->ih_arg = scp;
                    291:                ihp->ih_level = IPL_BIO;
                    292:                ihp->ih_name = "simide";
                    293:                ihp->ih_maskaddr = pa->pa_podule->irq_addr;
                    294:                ihp->ih_maskbits = scp->sc_irqmask;
                    295:                if (irq_claim(sc->sc_podule->interrupt, ihp))
1.4       provos    296:                        panic("%s: Cannot claim interrupt %d",
1.25      cube      297:                            device_xname(self), sc->sc_podule->interrupt);
1.1       reinoud   298:                /* clear any pending interrupts and enable interrupts */
                    299:                sc->sc_ctl_reg |= scp->sc_irqmask;
                    300:                bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    301:                    CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
1.13      he        302:                wdcattach(cp);
1.1       reinoud   303:        }
                    304: }
                    305:
                    306: /*
                    307:  * Card shutdown function
                    308:  *
                    309:  * Called via do_shutdown_hooks() during kernel shutdown.
                    310:  * Clear the cards's interrupt mask to stop any podule interrupts.
                    311:  */
                    312:
                    313: void
1.25      cube      314: simide_shutdown(void *arg)
1.1       reinoud   315: {
                    316:        struct simide_softc *sc = arg;
                    317:
                    318:        sc->sc_ctl_reg &= (CONTROL_PRIMARY_IRQ | CONTROL_SECONDARY_IRQ);
                    319:
                    320:        /* Disable card interrupts */
                    321:        bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
                    322:            CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
                    323: }
                    324:
                    325: /*
                    326:  * Podule interrupt handler
                    327:  *
                    328:  * If the interrupt was from our card pass it on to the wdc interrupt handler
                    329:  */
                    330: int
1.25      cube      331: simide_intr(void *arg)
1.1       reinoud   332: {
                    333:        struct simide_channel *scp = arg;
                    334:        irqhandler_t *ihp = &scp->sc_ih;
                    335:        volatile u_char *intraddr = (volatile u_char *)ihp->ih_maskaddr;
                    336:
                    337:        /* XXX - not bus space yet - should really be handled by podulebus */
                    338:        if ((*intraddr) & ihp->ih_maskbits)
1.20      thorpej   339:                wdcintr(&scp->sc_channel);
1.1       reinoud   340:
                    341:        return(0);
                    342: }

CVSweb <webmaster@jp.NetBSD.org>