diff options
author | Chris Cappuccio <chris@cvs.openbsd.org> | 2000-06-13 03:56:43 +0000 |
---|---|---|
committer | Chris Cappuccio <chris@cvs.openbsd.org> | 2000-06-13 03:56:43 +0000 |
commit | b8a10218d7a9228cccfeeb16d19f74bddae195a9 (patch) | |
tree | 330d84c4e41544537fa5954f134c8ecb6778a785 | |
parent | 87d6a272b4571fa7bd3e96f21394f90fed614bbd (diff) |
clean up Cypress section (obviously nobody has used these w/OpenBSD)
also sync w/NetBSD
support map memory mapped or IO mapped controllers
program DMA modes for Cypress controllers
support for OPTi chipsets (82C621 and compatible 82C568/82D568)
-rw-r--r-- | sys/dev/pci/pciide.c | 351 | ||||
-rw-r--r-- | sys/dev/pci/pciide_opti_reg.h | 128 |
2 files changed, 443 insertions, 36 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index 3acd59e9360..f5044b67ede 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.23 2000/05/04 19:42:53 millert Exp $ */ +/* $OpenBSD: pciide.c,v 1.24 2000/06/13 03:56:41 chris Exp $ */ /* $NetBSD: pciide.c,v 1.48 1999/11/28 20:05:18 bouyer Exp $ */ /* @@ -110,6 +110,10 @@ int wdcdebug_pciide_mask = 0; #include <dev/pci/pciide_sis_reg.h> #include <dev/pci/pciide_acer_reg.h> #include <dev/pci/pciide_pdc202xx_reg.h> +#include <dev/pci/pciide_opti_reg.h> + +#include <dev/pci/cy82c693var.h> + #include <dev/ata/atavar.h> #include <dev/ic/wdcreg.h> #include <dev/ic/wdcvar.h> @@ -164,6 +168,11 @@ struct pciide_softc { bus_space_tag_t sc_dma_iot; bus_space_handle_t sc_dma_ioh; bus_dma_tag_t sc_dmat; + + /* For Cypress */ + const struct cy82c693_handle *sc_cy_handle; + int sc_cy_compatchan; + /* Chip description */ const struct pciide_product_desc *sc_pp; /* common definitions */ @@ -220,6 +229,9 @@ int acer_pci_intr __P((void *)); void pdc202xx_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); void pdc202xx_setup_channel __P((struct channel_softc*)); int pdc202xx_pci_intr __P((void *)); + +void opti_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); +void opti_setup_channel __P((struct channel_softc*)); void pciide_channel_dma_setup __P((struct pciide_channel *)); int pciide_dma_table_setup __P((struct pciide_softc*, int, int)); @@ -280,6 +292,21 @@ const struct pciide_product_desc pciide_amd_products[] = { }, }; +const struct pciide_product_desc pciide_opti_products[] = { + { PCI_PRODUCT_OPTI_82C621, + 0, + opti_chip_map + }, + { PCI_PRODUCT_OPTI_82C568, + 0, + opti_chip_map + }, + { PCI_PRODUCT_OPTI_82D568, + 0, + opti_chip_map + }, +}; + const struct pciide_product_desc pciide_cmd_products[] = { { PCI_PRODUCT_CMDTECH_640, /* CMD Technology PCI0640 */ 0, @@ -351,6 +378,8 @@ const struct pciide_vendor_desc pciide_vendors[] = { sizeof(pciide_intel_products)/sizeof(pciide_intel_products[0]) }, { PCI_VENDOR_AMD, pciide_amd_products, sizeof(pciide_amd_products)/sizeof(pciide_amd_products[0]) }, + { PCI_VENDOR_OPTI, pciide_opti_products, + sizeof(pciide_opti_products)/sizeof(pciide_opti_products[0]) }, { PCI_VENDOR_CMDTECH, pciide_cmd_products, sizeof(pciide_cmd_products)/sizeof(pciide_cmd_products[0]) }, { PCI_VENDOR_VIATECH, pciide_via_products, @@ -400,7 +429,7 @@ int pciide_chansetup __P((struct pciide_softc *, int, pcireg_t)); void pciide_mapchan __P((struct pci_attach_args *, struct pciide_channel *, pcireg_t, bus_size_t *, bus_size_t *, int (*pci_intr) __P((void *)))); -int pciiide_chan_candisable __P((struct pciide_channel *)); +int pciide_chan_candisable __P((struct pciide_channel *)); void pciide_map_compat_intr __P(( struct pci_attach_args *, struct pciide_channel *, int, int)); int pciide_print __P((void *, const char *pnp)); @@ -498,7 +527,6 @@ pciide_attach(parent, self, aux) sc->sc_pc = pa->pa_pc; sc->sc_tag = pa->pa_tag; - #ifdef WDCDEBUG if (wdcdebug_pciide_mask & DEBUG_PROBE) printf("sc_pc %s, sc_tag %s\n", sc->sc_pc, sc->sc_tag); @@ -640,6 +668,8 @@ pciide_mapreg_dma(sc, pa) struct pciide_softc *sc; struct pci_attach_args *pa; { + pcireg_t maptype; + /* * Map DMA registers * @@ -654,21 +684,31 @@ pciide_mapreg_dma(sc, pa) * XXX say that "The bus master IDE function uses 16 bytes of IO * XXX space," some controllers (at least the United * XXX Microelectronics UM8886BF) place it in memory space. - * XXX eventually, we should probably read the register and check - * XXX which type it is. Either that or 'quirk' certain devices. */ - sc->sc_dma_ok = (pci_mapreg_map(pa, - PCIIDE_REG_BUS_MASTER_DMA, PCI_MAPREG_TYPE_IO, 0, - &sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, NULL) == 0); - sc->sc_dmat = pa->pa_dmat; - if (sc->sc_dma_ok == 0) { - printf(", (unuseable)"); /* couldn't map registers */ - } else { - sc->sc_wdcdev.dma_arg = sc; - sc->sc_wdcdev.dma_init = pciide_dma_init; - sc->sc_wdcdev.dma_start = pciide_dma_start; - sc->sc_wdcdev.dma_finish = pciide_dma_finish; + maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, + PCIIDE_REG_BUS_MASTER_DMA); + + switch (maptype) { + case PCI_MAPREG_TYPE_IO: + case PCI_MAPREG_MEM_TYPE_32BIT: + sc->sc_dma_ok = (pci_mapreg_map(pa, + PCIIDE_REG_BUS_MASTER_DMA, maptype, 0, + &sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, NULL) == 0); + sc->sc_dmat = pa->pa_dmat; + if (sc->sc_dma_ok == 0) { + printf(", (unuseable)"); /* couldn't map registers */ + } else { + sc->sc_wdcdev.dma_arg = sc; + sc->sc_wdcdev.dma_init = pciide_dma_init; + sc->sc_wdcdev.dma_start = pciide_dma_start; + sc->sc_wdcdev.dma_finish = pciide_dma_finish; + } + break; + + default: + sc->sc_dma_ok = 0; + printf(", (unsupported maptype 0x%x)", maptype); } } @@ -1049,7 +1089,7 @@ pciide_mapchan(pa, cp, interface, cmdsizep, ctlsizep, pci_intr) * if channel can be disabled, 0 if not */ int -pciiide_chan_candisable(cp) +pciide_chan_candisable(cp) struct pciide_channel *cp; { struct channel_softc *wdc_cp = &cp->wdc_channel; @@ -1353,7 +1393,7 @@ piix_chip_map(sc, pa) pciide_mapchan(pa, cp, 0, &cmdsize, &ctlsize, pciide_pci_intr); if (cp->hw_ok == 0) continue; - if (pciiide_chan_candisable(cp)) { + if (pciide_chan_candisable(cp)) { idetim = PIIX_IDETIM_CLEAR(idetim, PIIX_IDETIM_IDE, channel); pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM, @@ -1735,7 +1775,7 @@ amd756_chip_map(sc, pa) pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, pciide_pci_intr); - if (pciiide_chan_candisable(cp)) + if (pciide_chan_candisable(cp)) chanenable &= ~AMD756_CHAN_EN(channel); pciide_map_compat_intr(pa, cp, channel, interface); if (cp->hw_ok == 0) @@ -1881,7 +1921,7 @@ apollo_chip_map(sc, pa) pciide_pci_intr); if (cp->hw_ok == 0) continue; - if (pciiide_chan_candisable(cp)) { + if (pciide_chan_candisable(cp)) { ideconf &= ~APO_IDECONF_EN(channel); pci_conf_write(sc->sc_pc, sc->sc_tag, APO_IDECONF, ideconf); @@ -2021,7 +2061,7 @@ cmd_channel_map(pa, sc, channel) if (cp->hw_ok == 0) return; if (channel == 1) { - if (pciiide_chan_candisable(cp)) { + if (pciide_chan_candisable(cp)) { ctrl &= ~CMD_CTRL_2PORT; pciide_pci_write(pa->pa_pc, pa->pa_tag, CMD_CTRL, ctrl); @@ -2213,7 +2253,7 @@ cy693_chip_map(sc, pa) struct pciide_channel *cp; pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); - int compatchan; + bus_size_t cmdsize, ctlsize; if (pciide_chipen(sc, pa) == 0) return; @@ -2223,14 +2263,14 @@ cy693_chip_map(sc, pa) * the real channel */ if (pa->pa_function == 1) { - compatchan = 0; + sc->sc_cy_compatchan = 0; } else if (pa->pa_function == 2) { - compatchan = 1; + sc->sc_cy_compatchan = 1; } else { - printf("%s: unexpected PCI function %d\n", - sc->sc_wdcdev.sc_dev.dv_xname, pa->pa_function); + printf(": unexpected PCI function %d\n", pa->pa_function); return; } + if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) { printf(": DMA"); pciide_mapreg_dma(sc, pa); @@ -2239,7 +2279,11 @@ cy693_chip_map(sc, pa) sc->sc_dma_ok = 0; } - pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + sc->sc_cy_handle = cy82c693_init(pa->pa_iot); + if (sc->sc_cy_handle == NULL) { + printf(", (unable to map ctl registers)"); + sc->sc_dma_ok = 0; + } if (sc->sc_dma_ok) sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; @@ -2254,27 +2298,39 @@ cy693_chip_map(sc, pa) /* Only one channel for this chip; if we are here it's enabled */ cp = &sc->pciide_channels[0]; - sc->wdc_chanarray[0] = &cp->wdc_channel; + sc->wdc_chanarray[0] = &cp->wdc_channel; cp->name = PCIIDE_CHANNEL_NAME(0); cp->wdc_channel.channel = 0; cp->wdc_channel.wdc = &sc->sc_wdcdev; cp->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue), M_DEVBUF, M_NOWAIT); if (cp->wdc_channel.ch_queue == NULL) { - printf("%s: %s" - "cannot allocate memory for command queue", - sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + printf(": cannot allocate memory for command queue\n"); return; } + printf("%s: primary channel %s to ", + sc->sc_wdcdev.sc_dev.dv_xname, + (interface & PCIIDE_INTERFACE_SETTABLE(0)) ? + "configured" : "wired"); + if (interface & PCIIDE_INTERFACE_PCI(0)) { + printf("native-PCI"); + cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize, &ctlsize, + pciide_pci_intr); + } else { + printf("compatibility"); + cp->hw_ok = pciide_mapregs_compat(pa, cp, sc->sc_cy_compatchan, + &cmdsize, &ctlsize); + } + printf(" mode\n"); cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot; cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh; wdcattach(&cp->wdc_channel); - if (pciiide_chan_candisable(cp)) { + if (pciide_chan_candisable(cp)) { pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, 0); } - pciide_map_compat_intr(pa, cp, compatchan, interface); + pciide_map_compat_intr(pa, cp, sc->sc_cy_compatchan, interface); if (cp->hw_ok == 0) return; WDCDEBUG_PRINT(("cy693_chip_map: old timings reg 0x%x\n", @@ -2325,7 +2381,19 @@ cy693_setup_channel(chp) pci_conf_write(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL, cy_cmd_ctrl); chp->ch_drive[0].DMA_mode = dma_mode; chp->ch_drive[1].DMA_mode = dma_mode; + + if (dma_mode == -1) + dma_mode = 0; + + if (sc->sc_cy_handle != NULL) { + /* Note: `multiple' is implied. */ + cy82c693_write(sc->sc_cy_handle, + (sc->sc_cy_compatchan == 0) ? + CY_DMA_IDX_PRIMARY : CY_DMA_IDX_SECONDARY, dma_mode); + } + pciide_print_modes(cp); + if (idedma_ctl != 0) { /* Add software bits in status register */ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, @@ -2389,7 +2457,7 @@ sis_chip_map(sc, pa) pciide_pci_intr); if (cp->hw_ok == 0) continue; - if (pciiide_chan_candisable(cp)) { + if (pciide_chan_candisable(cp)) { if (channel == 0) sis_ctr0 &= ~SIS_CTRL0_CHAN0_EN; else @@ -2535,7 +2603,7 @@ acer_chip_map(sc, pa) acer_pci_intr); if (cp->hw_ok == 0) continue; - if (pciiide_chan_candisable(cp)) { + if (pciide_chan_candisable(cp)) { cr &= ~(PCIIDE_CHAN_EN(channel) << PCI_INTERFACE_SHIFT); pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr); @@ -2653,6 +2721,217 @@ acer_pci_intr(arg) return rv; } +/* + * Inline functions for accessing the timing registers of the + * OPTi controller. + * + * These *MUST* disable interrupts as they need atomic access to + * certain magic registers. Failure to adhere to this *will* + * break things in subtle ways if the wdc registers are accessed + * by an interrupt routine while this magic sequence is executing. + */ +static __inline__ u_int8_t +opti_read_config(struct channel_softc *chp, int reg) +{ + u_int8_t rv; + int s = splhigh(); + + /* Two consecutive 16-bit reads from register #1 (0x1f1/0x171) */ + (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features); + (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features); + + /* Followed by an 8-bit write of 0x3 to register #2 */ + bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x03u); + + /* Now we can read the required register */ + rv = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, reg); + + /* Restore the real registers */ + bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x83u); + + splx(s); + + return rv; +} + +static __inline__ void +opti_write_config(struct channel_softc *chp, int reg, u_int8_t val) +{ + int s = splhigh(); + + /* Two consecutive 16-bit reads from register #1 (0x1f1/0x171) */ + (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features); + (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features); + + /* Followed by an 8-bit write of 0x3 to register #2 */ + bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x03u); + + /* Now we can write the required register */ + bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, reg, val); + + /* Restore the real registers */ + bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x83u); + + splx(s); +} + +void +opti_chip_map(sc, pa) + struct pciide_softc *sc; + struct pci_attach_args *pa; +{ + struct pciide_channel *cp; + bus_size_t cmdsize, ctlsize; + pcireg_t interface; + u_int8_t init_ctrl; + int channel; + + if (pciide_chipen(sc, pa) == 0) + return; + printf(": DMA"); + pciide_mapreg_dma(sc, pa); + + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE; + sc->sc_wdcdev.PIO_cap = 4; + if (sc->sc_dma_ok) { + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; + sc->sc_wdcdev.DMA_cap = 2; + } + sc->sc_wdcdev.set_modes = opti_setup_channel; + + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; + + init_ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag, + OPTI_REG_INIT_CONTROL); + + interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, + sc->sc_tag, PCI_CLASS_REG)); + + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + cp = &sc->pciide_channels[channel]; + if (pciide_chansetup(sc, channel, interface) == 0) + continue; + if (channel == 1 && + (init_ctrl & OPTI_INIT_CONTROL_CH2_DISABLE) != 0) { + printf("%s: %s channel ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + continue; + } + pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, + pciide_pci_intr); + if (cp->hw_ok == 0) + continue; + pciide_map_compat_intr(pa, cp, channel, interface); + if (cp->hw_ok == 0) + continue; + opti_setup_channel(&cp->wdc_channel); + } +} + +void +opti_setup_channel(chp) + struct channel_softc *chp; +{ + struct ata_drive_datas *drvp; + struct pciide_channel *cp = (struct pciide_channel*)chp; + struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + int drive,spd; + int mode[2]; + u_int8_t rv, mr; + + /* + * The `Delay' and `Address Setup Time' fields of the + * Miscellaneous Register are always zero initially. + */ + mr = opti_read_config(chp, OPTI_REG_MISC) & ~OPTI_MISC_INDEX_MASK; + mr &= ~(OPTI_MISC_DELAY_MASK | + OPTI_MISC_ADDR_SETUP_MASK | + OPTI_MISC_INDEX_MASK); + + /* Prime the control register before setting timing values */ + opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_DISABLE); + + /* Determine the clockrate of the PCIbus the chip is attached to */ + spd = (int) opti_read_config(chp, OPTI_REG_STRAP); + spd &= OPTI_STRAP_PCI_SPEED_MASK; + + /* setup DMA if needed */ + pciide_channel_dma_setup(cp); + + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + /* If no drive, skip */ + if ((drvp->drive_flags & DRIVE) == 0) { + mode[drive] = -1; + continue; + } + + if ((drvp->drive_flags & DRIVE_DMA)) { + /* + * Timings will be used for both PIO and DMA, + * so adjust DMA mode if needed + */ + if (drvp->PIO_mode > (drvp->DMA_mode + 2)) + drvp->PIO_mode = drvp->DMA_mode + 2; + if (drvp->DMA_mode + 2 > (drvp->PIO_mode)) + drvp->DMA_mode = (drvp->PIO_mode > 2) ? + drvp->PIO_mode - 2 : 0; + if (drvp->DMA_mode == 0) + drvp->PIO_mode = 0; + + mode[drive] = drvp->DMA_mode + 5; + } else + mode[drive] = drvp->PIO_mode; + + if (drive && mode[0] >= 0 && + (opti_tim_as[spd][mode[0]] != opti_tim_as[spd][mode[1]])) { + /* + * Can't have two drives using different values + * for `Address Setup Time'. + * Slow down the faster drive to compensate. + */ + int d = (opti_tim_as[spd][mode[0]] > + opti_tim_as[spd][mode[1]]) ? 0 : 1; + + mode[d] = mode[1-d]; + chp->ch_drive[d].PIO_mode = chp->ch_drive[1-d].PIO_mode; + chp->ch_drive[d].DMA_mode = 0; + chp->ch_drive[d].drive_flags &= DRIVE_DMA; + } + } + + for (drive = 0; drive < 2; drive++) { + int m; + if ((m = mode[drive]) < 0) + continue; + + /* Set the Address Setup Time and select appropriate index */ + rv = opti_tim_as[spd][m] << OPTI_MISC_ADDR_SETUP_SHIFT; + rv |= OPTI_MISC_INDEX(drive); + opti_write_config(chp, OPTI_REG_MISC, mr | rv); + + /* Set the pulse width and recovery timing parameters */ + rv = opti_tim_cp[spd][m] << OPTI_PULSE_WIDTH_SHIFT; + rv |= opti_tim_rt[spd][m] << OPTI_RECOVERY_TIME_SHIFT; + opti_write_config(chp, OPTI_REG_READ_CYCLE_TIMING, rv); + opti_write_config(chp, OPTI_REG_WRITE_CYCLE_TIMING, rv); + + /* Set the Enhanced Mode register appropriately */ + rv = pciide_pci_read(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE); + rv &= ~OPTI_ENH_MODE_MASK(chp->channel, drive); + rv |= OPTI_ENH_MODE(chp->channel, drive, opti_tim_em[m]); + pciide_pci_write(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE, rv); + } + + /* Finally, enable the timings */ + opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_ENABLE); + + pciide_print_modes(cp); +} + /* A macro to test product */ #define PDC_IS_262(sc) (sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA66) @@ -2765,7 +3044,7 @@ pdc202xx_chip_map(sc, pa) pdc202xx_pci_intr); if (cp->hw_ok == 0) continue; - if (pciiide_chan_candisable(cp)) + if (pciide_chan_candisable(cp)) st &= ~(PDC_IS_262(sc) ? PDC262_STATE_EN(channel):PDC246_STATE_EN(channel)); pciide_map_compat_intr(pa, cp, channel, interface); diff --git a/sys/dev/pci/pciide_opti_reg.h b/sys/dev/pci/pciide_opti_reg.h new file mode 100644 index 00000000000..409a092ff3c --- /dev/null +++ b/sys/dev/pci/pciide_opti_reg.h @@ -0,0 +1,128 @@ +/* $OpenBSD: pciide_opti_reg.h,v 1.1 2000/06/13 03:56:42 chris Exp $ */ +/* $NetBSD: pciide_opti_reg.h,v 1.2 2000/06/07 20:42:53 scw Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Steve C. Woodford. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Register definitions for OPTi PCIIDE controllers based on + * their 82c621 chip. + */ + +/* IDE Initialization Control Register */ +#define OPTI_REG_INIT_CONTROL 0x40 +#define OPTI_INIT_CONTROL_MODE_PIO_0 0 +#define OPTI_INIT_CONTROL_MODE_PIO_1 2 +#define OPTI_INIT_CONTROL_MODE_PIO_2 1 +#define OPTI_INIT_CONTROL_MODE_PIO_3 3 +#define OPTI_INIT_CONTROL_ADDR_RELOC (1u << 2) +#define OPTI_INIT_CONTROL_CH2_ENABLE 0 +#define OPTI_INIT_CONTROL_CH2_DISABLE (1u << 3) +#define OPTI_INIT_CONTROL_FIFO_16 0 +#define OPTI_INIT_CONTROL_FIFO_32 (1u << 5) +#define OPTI_INIT_CONTROL_FIFO_REQ_32 0 +#define OPTI_INIT_CONTROL_FIFO_REQ_30 (1u << 6) +#define OPTI_INIT_CONTROL_FIFO_REQ_28 (2u << 6) +#define OPTI_INIT_CONTROL_FIFO_REQ_26 (3u << 6) + +/* IDE Enhanced Features Register */ +#define OPTI_REG_ENH_FEAT 0x42 +#define OPTI_ENH_FEAT_X111_ENABLE (1u << 1) +#define OPTI_ENH_FEAT_CONCURRENT_MAST (1u << 2) +#define OPTI_ENH_FEAT_PCI_INVALIDATE (1u << 3) +#define OPTI_ENH_FEAT_IDE_CONCUR (1u << 4) +#define OPTI_ENH_FEAT_SLAVE_FIFO_ISA (1u << 5) + +/* IDE Enhanced Mode Register */ +#define OPTI_REG_ENH_MODE 0x43 +#define OPTI_ENH_MODE_MASK(c,d) (3u << (((c) * 4) + ((d) * 2))) +#define OPTI_ENH_MODE_USE_TIMING(c,d) 0 +#define OPTI_ENH_MODE(c,d,m) ((m) << (((c) * 4) + ((d) * 2))) + +/* Timing registers */ +#define OPTI_REG_READ_CYCLE_TIMING 0x00 +#define OPTI_REG_WRITE_CYCLE_TIMING 0x01 +#define OPTI_RECOVERY_TIME_SHIFT 0 +#define OPTI_PULSE_WIDTH_SHIFT 4 + +/* + * Control register. + */ +#define OPTI_REG_CONTROL 0x03 +#define OPTI_CONTROL_DISABLE 0x11 +#define OPTI_CONTROL_ENABLE 0x95 + +/* Strap register */ +#define OPTI_REG_STRAP 0x05 +#define OPTI_STRAP_PCI_SPEED_MASK 0x1u +#define OPTI_STRAP_PCI_33 0 +#define OPTI_STRAP_PCI_25 1 + +/* Miscellaneous register */ +#define OPTI_REG_MISC 0x06 +#define OPTI_MISC_INDEX(d) ((unsigned)(d)) +#define OPTI_MISC_INDEX_MASK 0x01u +#define OPTI_MISC_DELAY_MASK 0x07u +#define OPTI_MISC_DELAY_SHIFT 1 +#define OPTI_MISC_ADDR_SETUP_MASK 0x3u +#define OPTI_MISC_ADDR_SETUP_SHIFT 4 +#define OPTI_MISC_READ_PREFETCH_ENABLE (1u << 6) +#define OPTI_MISC_ADDR_SETUP_MASK 0x3u +#define OPTI_MISC_WRITE_MASK 0x7fu + +/* + * These are the timing register values for the various IDE modes + * supported by the OPTi chip. The first index of the two-dimensional + * arrays is used for a 33MHz PCIbus, the second for a 25MHz PCIbus. + */ +static u_int8_t opti_tim_cp[2][8] = { /* Command Pulse */ + {5, 4, 3, 2, 2, 7, 2, 2}, + {4, 3, 2, 2, 1, 5, 2, 1} +}; + +static u_int8_t opti_tim_rt[2][8] = { /* Recovery Time */ + {9, 4, 0, 0, 0, 6, 0, 0}, + {6, 2, 0, 0, 0, 4, 0, 0} +}; + +static u_int8_t opti_tim_as[2][8] = { /* Address Setup */ + {2, 1, 1, 1, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 0} +}; + +static u_int8_t opti_tim_em[8] = { /* Enhanced Mode */ + 0, 0, 0, 1, 2, 0, 1 ,2 +}; |