diff options
author | Alexander Yurchenko <grange@cvs.openbsd.org> | 2003-02-13 15:40:00 +0000 |
---|---|---|
committer | Alexander Yurchenko <grange@cvs.openbsd.org> | 2003-02-13 15:40:00 +0000 |
commit | d2a52fd74f310e85737fba828c2718264df94379 (patch) | |
tree | 755b1212170135b35117e4eec1127ed45bc2ebfe /sys/dev | |
parent | e9dcaa1e5d58eda63d3c67529f0de5e8b1265325 (diff) |
Final part of NVIDIA nForce/nForce2 IDE support:
- registers definitions
- timing values setup
- cable detection
Partially from Linux, FreeBSD and AMD specs.
Many thanks to Johan Lindman <tybollt@solace.mh.se> for providing
access to the testing machine.
ok gluk@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/pciide.c | 90 | ||||
-rw-r--r-- | sys/dev/pci/pciide_nforce_reg.h | 58 |
2 files changed, 142 insertions, 6 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index 632eef517d7..7a542880d1b 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.112 2003/02/13 15:30:21 grange Exp $ */ +/* $OpenBSD: pciide.c,v 1.113 2003/02/13 15:39:59 grange Exp $ */ /* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */ /* @@ -115,6 +115,7 @@ int wdcdebug_pciide_mask = 0; #include <dev/pci/pciide_hpt_reg.h> #include <dev/pci/pciide_acard_reg.h> #include <dev/pci/pciide_natsemi_reg.h> +#include <dev/pci/pciide_nforce_reg.h> #include <dev/pci/cy82c693var.h> #include <dev/ata/atavar.h> @@ -5083,6 +5084,11 @@ nforce_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa) int channel; pcireg_t interface = PCI_INTERFACE(pa->pa_class); bus_size_t cmdsize, ctlsize; + u_int32_t conf; + + conf = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_CONF); + WDCDEBUG_PRINT(("%s: conf register 0x%x\n", + sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE); if (pciide_chipen(sc, pa) == 0) return; @@ -5120,6 +5126,13 @@ nforce_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa) if (pciide_chansetup(sc, channel, interface) == 0) continue; + + if ((conf & NFORCE_CHAN_EN(channel)) == 0) { + printf("%s: %s ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + continue; + } + pciide_map_compat_intr(pa, cp, channel, interface); if (cp->hw_ok == 0) continue; @@ -5131,27 +5144,44 @@ nforce_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa) } if (pciide_chan_candisable(cp)) { + conf &= ~NFORCE_CHAN_EN(channel); pciide_unmap_compat_intr(pa, cp, channel, interface); + continue; } sc->sc_wdcdev.set_modes(&cp->wdc_channel); } + WDCDEBUG_PRINT(("%s: new conf register 0x%x\n", + sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE); + pci_conf_write(sc->sc_pc, sc->sc_tag, NFORCE_CONF, conf); } void nforce_setup_channel(struct channel_softc *chp) { struct ata_drive_datas *drvp; - int drive; + int drive, mode; u_int32_t idedma_ctl; struct pciide_channel *cp = (struct pciide_channel*)chp; struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; int channel = chp->channel; + u_int32_t conf, piodmatim, piotim, udmatim; + + conf = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_CONF); + piodmatim = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_PIODMATIM); + piotim = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_PIOTIM); + udmatim = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_UDMATIM); + WDCDEBUG_PRINT(("%s: %s old timing values: piodmatim=0x%x, " + "piotim=0x%x, udmatim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname, + cp->name, piodmatim, piotim, udmatim), DEBUG_PROBE); /* Setup DMA if needed */ pciide_channel_dma_setup(cp); + /* Clear all bits for this channel */ idedma_ctl = 0; + piodmatim &= ~NFORCE_PIODMATIM_MASK(channel); + udmatim &= ~NFORCE_UDMATIM_MASK(channel); /* Per channel settings */ for (drive = 0; drive < 2; drive++) { @@ -5161,13 +5191,54 @@ nforce_setup_channel(struct channel_softc *chp) if ((drvp->drive_flags & DRIVE) == 0) continue; - if (drvp->drive_flags & DRIVE_UDMA) { + if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 && + (drvp->drive_flags & DRIVE_UDMA) != 0) { + /* Setup UltraDMA mode */ drvp->drive_flags &= ~DRIVE_DMA; - idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); - } else if (drvp->drive_flags & DRIVE_DMA) { - idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); + + /* Check cable */ + if ((conf & NFORCE_CONF_CABLE(channel, drive)) == 0 && + drvp->UDMA_mode > 2) { + WDCDEBUG_PRINT(("%s(%s:%d:%d): 80-wire " + "cable not detected\n", drvp->drive_name, + sc->sc_wdcdev.sc_dev.dv_xname, + channel, drive), DEBUG_PROBE); + drvp->UDMA_mode = 2; + } + + udmatim |= NFORCE_UDMATIM_SET(channel, drive, + nforce_udma[drvp->UDMA_mode]) | + NFORCE_UDMA_EN(channel, drive) | + NFORCE_UDMA_ENM(channel, drive); + + mode = drvp->PIO_mode; + } else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 && + (drvp->drive_flags & DRIVE_DMA) != 0) { + /* Setup multiword DMA mode */ + drvp->drive_flags &= ~DRIVE_UDMA; + + /* mode = min(pio, dma + 2) */ + if (drvp->PIO_mode <= (drvp->DMA_mode + 2)) + mode = drvp->PIO_mode; + else + mode = drvp->DMA_mode + 2; } else { + goto pio; } + idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); + +pio: + /* Setup PIO mode */ + if (mode <= 2) { + drvp->DMA_mode = 0; + drvp->PIO_mode = 0; + mode = 0; + } else { + drvp->PIO_mode = mode; + drvp->DMA_mode = mode - 2; + } + piodmatim |= NFORCE_PIODMATIM_SET(channel, drive, + nforce_pio[mode]); } if (idedma_ctl != 0) { @@ -5175,6 +5246,13 @@ nforce_setup_channel(struct channel_softc *chp) bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CTL(channel), idedma_ctl); } + + WDCDEBUG_PRINT(("%s: %s new timing values: piodmatim=0x%x, " + "piotim=0x%x, udmatim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname, + cp->name, piodmatim, piotim, udmatim), DEBUG_PROBE); + pci_conf_write(sc->sc_pc, sc->sc_tag, NFORCE_PIODMATIM, piodmatim); + pci_conf_write(sc->sc_pc, sc->sc_tag, NFORCE_UDMATIM, udmatim); + pciide_print_modes(cp); } diff --git a/sys/dev/pci/pciide_nforce_reg.h b/sys/dev/pci/pciide_nforce_reg.h new file mode 100644 index 00000000000..c96ac8e4dd6 --- /dev/null +++ b/sys/dev/pci/pciide_nforce_reg.h @@ -0,0 +1,58 @@ +/* $OpenBSD: pciide_nforce_reg.h,v 1.1 2003/02/13 15:39:59 grange Exp $ */ + +/* + * Copyright (c) 2003 Alexander Yurchenko <grange@openbsd.org> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* Configuration register */ +#define NFORCE_CONF 0x50 +#define NFORCE_CHAN_EN(chan) \ + (0x00000001 << (1 - (chan))) +#define NFORCE_CONF_CABLE(chan, drive) \ + (0x00010000 << ((chan) * 2 + (drive))) + +/* PIO and multiword DMA timing register */ +#define NFORCE_PIODMATIM 0x58 +#define NFORCE_PIODMATIM_MASK(chan) \ + (0xffff << ((1 - (chan)) * 16)) +#define NFORCE_PIODMATIM_SET(chan, drive, x) \ + ((x) << ((3 - ((chan) * 2 + (drive))) * 8)) + +/* PIO timing register */ +#define NFORCE_PIOTIM 0x5c + +/* UDMA timing register */ +#define NFORCE_UDMATIM 0x60 +#define NFORCE_UDMATIM_MASK(chan) \ + (0xffff << ((1 - (chan)) * 16)) +#define NFORCE_UDMATIM_SET(chan, drive, x) \ + ((x) << ((3 - ((chan) * 2 + (drive))) * 8)) +#define NFORCE_UDMA_EN(chan, drive) \ + (0x40 << ((3 - ((chan) * 2 + (drive))) * 8)) +#define NFORCE_UDMA_ENM(chan, drive) \ + (0x80 << ((3 - ((chan) * 2 + (drive))) * 8)) + +/* Timing values */ +static u_int8_t nforce_pio[] = { 0xa8, 0x65, 0x42, 0x22, 0x20 }; +static u_int8_t nforce_udma[] = { 0x02, 0x01, 0x00, 0x04, 0x05, 0x06, 0x07 }; |