summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2003-02-13 15:40:00 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2003-02-13 15:40:00 +0000
commitd2a52fd74f310e85737fba828c2718264df94379 (patch)
tree755b1212170135b35117e4eec1127ed45bc2ebfe /sys/dev
parente9dcaa1e5d58eda63d3c67529f0de5e8b1265325 (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.c90
-rw-r--r--sys/dev/pci/pciide_nforce_reg.h58
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 };