summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/i386/pci/pciide_gcsc_reg.h87
-rw-r--r--sys/arch/i386/pci/pciide_machdep.c132
-rw-r--r--sys/dev/pci/pciide.c12
-rw-r--r--sys/dev/pci/pciidevar.h6
4 files changed, 234 insertions, 3 deletions
diff --git a/sys/arch/i386/pci/pciide_gcsc_reg.h b/sys/arch/i386/pci/pciide_gcsc_reg.h
new file mode 100644
index 00000000000..1e9a5148505
--- /dev/null
+++ b/sys/arch/i386/pci/pciide_gcsc_reg.h
@@ -0,0 +1,87 @@
+/* $OpenBSD: pciide_gcsc_reg.h,v 1.1 2009/01/04 10:37:40 jsg Exp $ */
+/* $NetBSD: gcscide.c,v 1.6 2007/10/06 07:21:03 xtraeme Exp $ */
+
+/*-
+ * Copyright (c) 2007 Juan Romero Pardines.
+ * 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.
+ */
+
+
+/*
+ * 6.4 - ATA-5 Controller Register Definitions.
+ */
+#define GCSC_MSR_ATAC_BASE 0x51300000
+#define GCSC_ATAC_GLD_MSR_CAP (GCSC_MSR_ATAC_BASE + 0)
+#define GCSC_ATAC_GLD_MSR_CONFIG (GCSC_MSR_ATAC_BASE + 0x01)
+#define GCSC_ATAC_GLD_MSR_SMI (GCSC_MSR_ATAC_BASE + 0x02)
+#define GCSC_ATAC_GLD_MSR_ERROR (GCSC_MSR_ATAC_BASE + 0x03)
+#define GCSC_ATAC_GLD_MSR_PM (GCSC_MSR_ATAC_BASE + 0x04)
+#define GCSC_ATAC_GLD_MSR_DIAG (GCSC_MSR_ATAC_BASE + 0x05)
+#define GCSC_ATAC_IO_BAR (GCSC_MSR_ATAC_BASE + 0x08)
+#define GCSC_ATAC_RESET (GCSC_MSR_ATAC_BASE + 0x10)
+#define GCSC_ATAC_CH0D0_PIO (GCSC_MSR_ATAC_BASE + 0x20)
+#define GCSC_ATAC_CH0D0_DMA (GCSC_MSR_ATAC_BASE + 0x21)
+#define GCSC_ATAC_CH0D1_PIO (GCSC_MSR_ATAC_BASE + 0x22)
+#define GCSC_ATAC_CH0D1_DMA (GCSC_MSR_ATAC_BASE + 0x23)
+#define GCSC_ATAC_PCI_ABRTERR (GCSC_MSR_ATAC_BASE + 0x24)
+#define GCSC_ATAC_BM0_CMD_PRIM 0x00
+#define GCSC_ATAC_BM0_STS_PRIM 0x02
+#define GCSC_ATAC_BM0_PRD 0x04
+
+/*
+ * ATAC_CH0D0_DMA registers:
+ *
+ * PIO Format (bit 31): Format 1 allows independent control of command
+ * and data per drive, while Format 0 selects the slowest speed
+ * of the two drives.
+ */
+#define GCSC_ATAC_PIO_FORMAT (1 << 31) /* PIO Mode Format 1 */
+/*
+ * DMA_SEL (bit 20): sets Ultra DMA mode (if enabled) or Multi-word
+ * DMA mode (if disabled).
+ */
+#define GCSC_ATAC_DMA_SEL (1 << 20)
+
+/* PIO Format 1 settings */
+static const uint32_t gcsc_pio_timings[] = {
+ 0xf7f4f7f4, /* PIO Mode 0 */
+ 0x53f3f173, /* PIO Mode 1 */
+ 0x13f18141, /* PIO Mode 2 */
+ 0x51315131, /* PIO Mode 3 */
+ 0x11311131 /* PIO Mode 4 */
+};
+
+static const uint32_t gcsc_mdma_timings[] = {
+ 0x7f0ffff3, /* MDMA Mode 0 */
+ 0x7f035352, /* MDMA Mode 1 */
+ 0x7f024241 /* MDMA Mode 2 */
+};
+
+static const uint32_t gcsc_udma_timings[] = {
+ 0x7f7436a1, /* Ultra DMA Mode 0 */
+ 0x7f733481, /* Ultra DMA Mode 1 */
+ 0x7f723261, /* Ultra DMA Mode 2 */
+ 0x7f713161, /* Ultra DMA Mode 3 */
+ 0x7f703061 /* Ultra DMA Mode 4 */
+};
+
diff --git a/sys/arch/i386/pci/pciide_machdep.c b/sys/arch/i386/pci/pciide_machdep.c
index 6efa9eae90b..180267ad684 100644
--- a/sys/arch/i386/pci/pciide_machdep.c
+++ b/sys/arch/i386/pci/pciide_machdep.c
@@ -1,6 +1,31 @@
-/* $OpenBSD: pciide_machdep.c,v 1.6 2006/09/19 11:06:34 jsg Exp $ */
+/* $OpenBSD: pciide_machdep.c,v 1.7 2009/01/04 10:37:40 jsg Exp $ */
/* $NetBSD: pciide_machdep.c,v 1.2 1999/02/19 18:01:27 mycroft Exp $ */
+/*-
+ * Copyright (c) 2007 Juan Romero Pardines.
+ * 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.
+ */
+
/*
* Copyright (c) 1998 Christopher G. Demetriou. All rights reserved.
*
@@ -52,6 +77,11 @@
#include <dev/isa/isavar.h>
+#include <machine/cpufunc.h>
+#include <i386/pci/pciide_gcsc_reg.h>
+
+void gcsc_setup_channel(struct channel_softc *);
+
void *
pciide_machdep_compat_intr_establish(struct device *dev,
struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
@@ -70,3 +100,103 @@ pciide_machdep_compat_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
{
isa_intr_disestablish(NULL, cookie);
}
+
+void
+gcsc_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
+{
+ struct pciide_channel *cp;
+ pcireg_t interface;
+ bus_size_t cmdsize, ctlsize;
+
+ printf(": DMA");
+ pciide_mapreg_dma(sc, pa);
+
+ sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
+ WDC_CAPABILITY_MODE;
+ if (sc->sc_dma_ok) {
+ sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
+ sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
+ sc->sc_wdcdev.irqack = pciide_irqack;
+ }
+
+ sc->sc_wdcdev.PIO_cap = 4;
+ sc->sc_wdcdev.DMA_cap = 2;
+ sc->sc_wdcdev.UDMA_cap = 4;
+ sc->sc_wdcdev.set_modes = gcsc_setup_channel;
+ sc->sc_wdcdev.channels = sc->wdc_chanarray;
+ sc->sc_wdcdev.nchannels = 1;
+
+ interface = PCI_INTERFACE(pa->pa_class);
+
+ pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
+
+ cp = &sc->pciide_channels[0];
+
+ if (pciide_chansetup(sc, 0, interface) == 0)
+ return;
+
+ pciide_map_compat_intr(pa, cp, 0, interface);
+ if (cp->hw_ok == 0)
+ return;
+
+ pciide_mapchan(pa, cp, interface,
+ &cmdsize, &ctlsize, pciide_pci_intr);
+ if (cp->hw_ok == 0) {
+ pciide_unmap_compat_intr(pa, cp, 0, interface);
+ return;
+ }
+
+ gcsc_setup_channel(&cp->wdc_channel);
+}
+
+void
+gcsc_setup_channel(struct channel_softc *chp)
+{
+ struct pciide_channel *cp = (struct pciide_channel *)chp;
+ struct ata_drive_datas *drvp;
+ uint64_t reg = 0;
+ int drive, s;
+
+ pciide_channel_dma_setup(cp);
+
+ for (drive = 0; drive < 2; drive++) {
+ drvp = &chp->ch_drive[drive];
+ if ((drvp->drive_flags & DRIVE) == 0)
+ continue;
+
+ reg = rdmsr(drive ? GCSC_ATAC_CH0D1_DMA :
+ GCSC_ATAC_CH0D0_DMA);
+
+ if (drvp->drive_flags & DRIVE_UDMA) {
+ s = splbio();
+ drvp->drive_flags &= ~DRIVE_DMA;
+ splx(s);
+ /* Enable the Ultra DMA mode bit */
+ reg |= GCSC_ATAC_DMA_SEL;
+ /* set the Ultra DMA mode */
+ reg |= gcsc_udma_timings[drvp->UDMA_mode];
+
+ wrmsr(drive ? GCSC_ATAC_CH0D1_DMA :
+ GCSC_ATAC_CH0D0_DMA, reg);
+
+ } else if (drvp->drive_flags & DRIVE_DMA) {
+ /* Enable the Multi-word DMA bit */
+ reg &= ~GCSC_ATAC_DMA_SEL;
+ /* set the Multi-word DMA mode */
+ reg |= gcsc_mdma_timings[drvp->DMA_mode];
+
+ wrmsr(drive ? GCSC_ATAC_CH0D1_DMA :
+ GCSC_ATAC_CH0D0_DMA, reg);
+ }
+
+ /* Always use PIO Format 1. */
+ wrmsr(drive ? GCSC_ATAC_CH0D1_DMA :
+ GCSC_ATAC_CH0D0_DMA, reg | GCSC_ATAC_PIO_FORMAT);
+
+ /* Set PIO mode */
+ wrmsr(drive ? GCSC_ATAC_CH0D1_PIO : GCSC_ATAC_CH0D0_PIO,
+ gcsc_pio_timings[drvp->PIO_mode]);
+ }
+
+ pciide_print_modes(cp);
+}
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c
index e03135a53b0..2e2acf4a134 100644
--- a/sys/dev/pci/pciide.c
+++ b/sys/dev/pci/pciide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pciide.c,v 1.291 2009/01/04 10:22:01 jsg Exp $ */
+/* $OpenBSD: pciide.c,v 1.292 2009/01/04 10:37:40 jsg Exp $ */
/* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */
/*
@@ -671,7 +671,17 @@ const struct pciide_product_desc pciide_sis_products[] = {
}
};
+/*
+ * The National/AMD CS5535 requires MSRs to set DMA/PIO modes so it
+ * has been banished to the MD i386 pciide_machdep
+ */
const struct pciide_product_desc pciide_natsemi_products[] = {
+#ifdef __i386__
+ { PCI_PRODUCT_NS_CS5535_IDE, /* National/AMD CS5535 IDE */
+ 0,
+ gcsc_chip_map
+ },
+#endif
{ PCI_PRODUCT_NS_PC87415, /* National Semi PC87415 IDE */
0,
natsemi_chip_map
diff --git a/sys/dev/pci/pciidevar.h b/sys/dev/pci/pciidevar.h
index c957ba9db2d..fb7d3591388 100644
--- a/sys/dev/pci/pciidevar.h
+++ b/sys/dev/pci/pciidevar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pciidevar.h,v 1.17 2009/01/04 10:22:01 jsg Exp $ */
+/* $OpenBSD: pciidevar.h,v 1.18 2009/01/04 10:37:40 jsg Exp $ */
/* $NetBSD: pciidevar.h,v 1.6 2001/01/12 16:04:00 bouyer Exp $ */
/*
@@ -161,6 +161,10 @@ void pciide_print_channels(int, pcireg_t);
* Functions defined by machine-dependent code.
*/
+#ifdef __i386__
+void gcsc_chip_map(struct pciide_softc *, struct pci_attach_args *);
+#endif
+
/* Attach compat interrupt handler, returning handle or NULL if failed. */
#if !defined(pciide_machdep_compat_intr_establish)
void *pciide_machdep_compat_intr_establish(struct device *,