summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorChris Cappuccio <chris@cvs.openbsd.org>2001-03-26 22:17:07 +0000
committerChris Cappuccio <chris@cvs.openbsd.org>2001-03-26 22:17:07 +0000
commit0e96e488a04af4fcdc4289aa5fc213b852986638 (patch)
tree9991f228ecc65b85438343d4771ab074e776d46e /sys/dev
parentcd9396d0ddec6794902927e94975d7078639f4ec (diff)
Support for Ultra/66 on Highpoint HPT366 and Ultra/100 on HPT370
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/pciide.c226
-rw-r--r--sys/dev/pci/pciide_hpt_reg.h130
2 files changed, 350 insertions, 6 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c
index 679498dccc0..b860c856db8 100644
--- a/sys/dev/pci/pciide.c
+++ b/sys/dev/pci/pciide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pciide.c,v 1.47 2001/03/25 13:11:54 csapuntz Exp $ */
+/* $OpenBSD: pciide.c,v 1.48 2001/03/26 22:17:05 chris Exp $ */
/* $NetBSD: pciide.c,v 1.48 1999/11/28 20:05:18 bouyer Exp $ */
/*
@@ -111,6 +111,7 @@ int wdcdebug_pciide_mask = 0;
#include <dev/pci/pciide_acer_reg.h>
#include <dev/pci/pciide_pdc202xx_reg.h>
#include <dev/pci/pciide_opti_reg.h>
+#include <dev/pci/pciide_hpt_reg.h>
#include <dev/pci/cy82c693var.h>
@@ -236,6 +237,10 @@ int pdc20265_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 hpt_chip_map __P((struct pciide_softc*, struct pci_attach_args*));
+void hpt_setup_channel __P((struct channel_softc*));
+int hpt_pci_intr __P((void *));
void pciide_channel_dma_setup __P((struct pciide_channel *));
int pciide_dma_table_setup __P((struct pciide_softc*, int, int));
@@ -385,6 +390,13 @@ const struct pciide_product_desc pciide_acer_products[] = {
};
#endif
+const struct pciide_product_desc pciide_triones_products[] = {
+ { PCI_PRODUCT_TRIONES_HPT366, /* Highpoint HPT36x/37x IDE */
+ IDE_PCI_CLASS_OVERRIDE,
+ hpt_chip_map,
+ }
+};
+
const struct pciide_product_desc pciide_promise_products[] = {
{ PCI_PRODUCT_PROMISE_PDC20246,
IDE_PCI_CLASS_OVERRIDE,
@@ -431,6 +443,8 @@ const struct pciide_vendor_desc pciide_vendors[] = {
{ PCI_VENDOR_ALI, pciide_acer_products,
sizeof(pciide_acer_products)/sizeof(pciide_acer_products[0]) },
#endif
+ { PCI_VENDOR_TRIONES, pciide_triones_products,
+ sizeof(pciide_triones_products)/sizeof(pciide_triones_products[0]) },
{ PCI_VENDOR_PROMISE, pciide_promise_products,
sizeof(pciide_promise_products)/sizeof(pciide_promise_products[0]) }
};
@@ -3018,6 +3032,210 @@ acer_pci_intr(arg)
return rv;
}
+void
+hpt_chip_map(sc, pa)
+ struct pciide_softc *sc;
+ struct pci_attach_args *pa;
+{
+ struct pciide_channel *cp;
+ int i, compatchan, revision;
+ pcireg_t interface;
+ bus_size_t cmdsize, ctlsize;
+
+ if (pciide_chipen(sc, pa) == 0)
+ return;
+ revision = PCI_REVISION(pa->pa_class);
+
+ /*
+ * when the chip is in native mode it identifies itself as a
+ * 'misc mass storage'. Fake interface in this case.
+ */
+ if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
+ interface = PCI_INTERFACE(pa->pa_class);
+ } else {
+ interface = PCIIDE_INTERFACE_BUS_MASTER_DMA |
+ PCIIDE_INTERFACE_PCI(0);
+ if (revision == HPT370_REV)
+ interface |= PCIIDE_INTERFACE_PCI(1);
+ }
+
+ printf(": DMA");
+ pciide_mapreg_dma(sc, pa);
+ printf("\n");
+ 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.set_modes = hpt_setup_channel;
+ sc->sc_wdcdev.channels = sc->wdc_chanarray;
+ if (revision < HPT370_REV) {
+ sc->sc_wdcdev.UDMA_cap = 4;
+ /*
+ * The 366 has 2 PCI IDE functions, one for primary and one
+ * for secondary. So we need to call pciide_mapregs_compat()
+ * with the real channel
+ */
+ if (pa->pa_function == 0) {
+ compatchan = 0;
+ } else if (pa->pa_function == 1) {
+ compatchan = 1;
+ } else {
+ printf("%s: unexpected PCI function %d\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, pa->pa_function);
+ return;
+ }
+ sc->sc_wdcdev.nchannels = 1;
+ } else {
+ sc->sc_wdcdev.nchannels = 2;
+ sc->sc_wdcdev.UDMA_cap = 5;
+ }
+ for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
+ cp = &sc->pciide_channels[i];
+ if (sc->sc_wdcdev.nchannels > 1) {
+ compatchan = i;
+ if((pciide_pci_read(sc->sc_pc, sc->sc_tag,
+ HPT370_CTRL1(i)) & HPT370_CTRL1_EN) == 0) {
+ printf("%s: %s ignored (disabled)\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
+ continue;
+ }
+ }
+ if (pciide_chansetup(sc, i, interface) == 0)
+ continue;
+ if (interface & PCIIDE_INTERFACE_PCI(i)) {
+ cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize,
+ &ctlsize, hpt_pci_intr);
+ } else {
+ cp->hw_ok = pciide_mapregs_compat(pa, cp, compatchan,
+ &cmdsize, &ctlsize);
+ }
+ if (cp->hw_ok == 0)
+ return;
+ cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
+ cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
+ wdcattach(&cp->wdc_channel);
+ hpt_setup_channel(&cp->wdc_channel);
+ }
+ if (revision == HPT370_REV) {
+ /*
+ * HPT370_REV has a bit to disable interrupts, make sure
+ * to clear it
+ */
+ pciide_pci_write(sc->sc_pc, sc->sc_tag, HPT_CSEL,
+ pciide_pci_read(sc->sc_pc, sc->sc_tag, HPT_CSEL) &
+ ~HPT_CSEL_IRQDIS);
+ }
+ return;
+}
+
+void
+hpt_setup_channel(chp)
+ struct channel_softc *chp;
+{
+ struct ata_drive_datas *drvp;
+ int drive;
+ int cable;
+ u_int32_t before, after;
+ u_int32_t idedma_ctl;
+ struct pciide_channel *cp = (struct pciide_channel*)chp;
+ struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
+
+ cable = pciide_pci_read(sc->sc_pc, sc->sc_tag, HPT_CSEL);
+
+ /* setup DMA if needed */
+ pciide_channel_dma_setup(cp);
+
+ idedma_ctl = 0;
+
+ /* Per drive settings */
+ for (drive = 0; drive < 2; drive++) {
+ drvp = &chp->ch_drive[drive];
+ /* If no drive, skip */
+ if ((drvp->drive_flags & DRIVE) == 0)
+ continue;
+ before = pci_conf_read(sc->sc_pc, sc->sc_tag,
+ HPT_IDETIM(chp->channel, drive));
+
+ /* add timing values, setup DMA if needed */
+ if (drvp->drive_flags & DRIVE_UDMA) {
+ /* use Ultra/DMA */
+ drvp->drive_flags &= ~DRIVE_DMA;
+ if ((cable & HPT_CSEL_CBLID(chp->channel)) != 0 &&
+ drvp->UDMA_mode > 2)
+ drvp->UDMA_mode = 2;
+ after = (sc->sc_wdcdev.nchannels == 2) ?
+ hpt370_udma[drvp->UDMA_mode] :
+ hpt366_udma[drvp->UDMA_mode];
+ idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
+ } else if (drvp->drive_flags & DRIVE_DMA) {
+ /*
+ * use Multiword DMA.
+ * Timings will be used for both PIO and DMA, so adjust
+ * DMA mode if needed
+ */
+ if (drvp->PIO_mode >= 3 &&
+ (drvp->DMA_mode + 2) > drvp->PIO_mode) {
+ drvp->DMA_mode = drvp->PIO_mode - 2;
+ }
+ after = (sc->sc_wdcdev.nchannels == 2) ?
+ hpt370_dma[drvp->DMA_mode] :
+ hpt366_dma[drvp->DMA_mode];
+ idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
+ } else {
+ /* PIO only */
+ after = (sc->sc_wdcdev.nchannels == 2) ?
+ hpt370_pio[drvp->PIO_mode] :
+ hpt366_pio[drvp->PIO_mode];
+ }
+ pci_conf_write(sc->sc_pc, sc->sc_tag,
+ HPT_IDETIM(chp->channel, drive), after);
+ WDCDEBUG_PRINT(("%s: bus speed register set to 0x%08x "
+ "(BIOS 0x%08x)\n", drvp->drv_softc->dv_xname,
+ after, before), DEBUG_PROBE);
+ }
+ if (idedma_ctl != 0) {
+ /* Add software bits in status register */
+ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
+ IDEDMA_CTL, idedma_ctl);
+ }
+ pciide_print_modes(cp);
+}
+
+int
+hpt_pci_intr(arg)
+ void *arg;
+{
+ struct pciide_softc *sc = arg;
+ struct pciide_channel *cp;
+ struct channel_softc *wdc_cp;
+ int rv = 0;
+ int dmastat, i, crv;
+
+ for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
+ dmastat = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
+ IDEDMA_CTL + IDEDMA_SCH_OFFSET * i);
+ if ((dmastat & IDEDMA_CTL_INTR) == 0)
+ continue;
+ cp = &sc->pciide_channels[i];
+ wdc_cp = &cp->wdc_channel;
+ crv = wdcintr(wdc_cp);
+ if (crv == 0) {
+ printf("%s:%d: bogus intr\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, i);
+ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
+ IDEDMA_CTL + IDEDMA_SCH_OFFSET * i, dmastat);
+ } else
+ rv = 1;
+ }
+ return rv;
+}
+
/*
* Inline functions for accessing the timing registers of the
* OPTi controller.
@@ -3315,11 +3533,7 @@ pdc202xx_chip_map(sc, pa)
}
mode = PDC2xx_SCR_DMA;
- if (PDC_IS_265(sc)) {
- /* the BIOS set it up this way */
- mode = PDC2xx_SCR_SET_GEN(mode, 0x3);
- mode |= 0x80000000;
- } else if (PDC_IS_262(sc)) {
+ if (PDC_IS_262(sc)) {
mode = PDC2xx_SCR_SET_GEN(mode, PDC262_SCR_GEN_LAT);
} else {
/* the BIOS set it up this way */
diff --git a/sys/dev/pci/pciide_hpt_reg.h b/sys/dev/pci/pciide_hpt_reg.h
new file mode 100644
index 00000000000..cce13448285
--- /dev/null
+++ b/sys/dev/pci/pciide_hpt_reg.h
@@ -0,0 +1,130 @@
+/* $OpenBSD: pciide_hpt_reg.h,v 1.1 2001/03/26 22:17:06 chris Exp $ */
+/* $NetBSD: pciide_hpt_reg.h,v 1.3 2001/01/05 15:20:53 bouyer Exp $ */
+
+/*
+ * Copyright (c) 2000 Manuel Bouyer.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 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.
+ *
+ */
+
+
+/*
+ * Register definitions for the Highpoint HPT366 UDMA/66 * and HPT370 UDMA/100
+ * PCI IDE controller.
+ *
+ * The HPT366 has 2 PCI IDE functions, each of them has only one channel.
+ * The HPT370 has the 2 channels on the same PCI IDE function.
+ */
+
+/*
+ * The HPT366 and HPT370 have the save vendor/device ID but not the
+ * same revision
+ */
+#define HPT366_REV 0x01
+#define HPT370_REV 0x03
+
+#define HPT_IDETIM(chan, drive) (0x40 + ((drive) * 4) + ((chan) * 8))
+#define HPT_IDETIM_BUFEN 0x80000000
+#define HPT_IDETIM_MSTEN 0x40000000
+#define HPT_IDETIM_DMAEN 0x20000000
+#define HPT_IDETIM_UDMAEN 0x10000000
+
+#define HPT366_CTRL1 0x50
+#define HPT366_CTRL1_BLKDIS(chan) (0x40 << (chan))
+#define HPT366_CTRL1_CHANEN(chan) (0x10 << (chan))
+#define HPT366_CTRL1_CLRBUF(chan) (0x04 << (chan))
+#define HPT366_CTRL1_LEG(chan) (0x01 << (chan))
+
+#define HPT366_CTRL2 0x51
+#define HPT366_CTRL2_FASTIRQ 0x80
+#define HPT366_CTRL2_HOLDIRQ(chan) (0x20 << (chan))
+#define HPT366_CTRL2_SGEN 0x10
+#define HPT366_CTRL2_CLEARFIFO(chan) (0x04 << (chan))
+#define HPT366_CTRL2_CLEARBMSM 0x02
+#define HPT366_CTRL2_CLEARSG 0x01
+
+#define HPT366_CTRL3(chan) (0x52 + ((chan) * 4))
+#define HPT366_CTRL3_PDMA 0x8000
+#define HPT366_CTRL3_BP 0x4000
+#define HPT366_CTRL3_FASTIRQ_OFFSET 9
+#define HPT366_CTRL3_FASTIRQ_MASK 0x3
+
+#define HPT370_CTRL1(chan) (0x50 + ((chan) * 4))
+#define HPT370_CTRL1_CLRSG 0x80
+#define HPT370_CTRL1_READF 0x40
+#define HPT370_CTRL1_CLRST 0x20
+#define HPT370_CTRL1_CLRSGC 0x10
+#define HPT370_CTRL1_BLKDIS 0x08
+#define HPT370_CTRL1_EN 0x04
+#define HPT370_CTRL1_CLRDBUF 0x02
+#define HPT370_CTRL1_LEGEN 0x01
+
+#define HPT370_CTRL2(chan) (0x51 + ((chan) * 4))
+#define HPT370_CTRL2_FASTIRQ 0x02
+#define HPT370_CTRL2_HIRQ 0x01
+
+#define HPT370_CTRL3(chan) (0x52 + ((chan) * 4))
+#define HPT370_CTRL3_HIZ 0x8000
+#define HPT370_CTRL3_BP 0x4000
+#define HPT370_CTRL3_FASTIRQ_OFFSET 9
+#define HPT370_CTRL3_FASTIRQ_MASK 0x3
+
+#define HPT_STAT1 0x58
+#define HPT_STAT1_IRQPOLL(chan) (0x40 << (chan)) /* 366 only */
+#define HPT_STAT1_DMARQ(chan) (0x04 << ((chan) * 3))
+#define HPT_STAT1_DMACK(chan) (0x02 << ((chan) * 3))
+#define HPT_STAT1_IORDY(chan) (0x01 << ((chan) * 3))
+
+#define HPT_STAT2 0x59
+#define HPT_STAT2_FLT_RST 0x40 /* 366 only */
+#define HPT_STAT2_RST(chan) (0x40 << (chan)) /* 370 only */
+#define HPT_STAT2_POLLEN(chan) (0x04 << ((chan) * 3))
+#define HPT_STAT2_IRQD1(chan) (0x02 << ((chan) * 3))
+#define HPT_STAT2_IRQD0_CH1 0x08
+#define HPT_STAT2_POLLST 0x01
+
+#define HPT_CSEL 0x5a
+#define HPT_CSEL_IRQDIS 0x10 /* 370 only */
+#define HPT_CSEL_PCIDIS 0x08 /* 370 only */
+#define HPT_CSEL_PCIWR 0x04 /* 370 only */
+#define HPT_CSEL_CBLID(chan) (0x01 << (1 - (chan)))
+
+static u_int32_t hpt366_pio[] =
+ {0x00d0a7aa, 0x00c8a753, 0x00c8a742, 0x00c8a731};
+static u_int32_t hpt366_dma[] =
+ {0x20c8a797, 0x20c8a742, 0x20c8a731};
+static u_int32_t hpt366_udma[] =
+ {0x10c8a731, 0x10cba731, 0x10caa731, 0x10cfa731, 0x10c9a731};
+
+static u_int32_t hpt370_pio[] =
+ {0x06914e8a, 0x06914e65, 0x06514e33, 0x06514e22, 0x06514e21};
+static u_int32_t hpt370_dma[] =
+ {0x26514e97, 0x26514e33, 0x26514e21};
+static u_int32_t hpt370_udma[] =
+ {0x16514e31, 0x164d4e31, 0x16494e31, 0x166d4e31, 0x16454e31,
+ 0x1a85f442};