summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2003-12-20 08:03:56 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2003-12-20 08:03:56 +0000
commit94d388451135f5de7b419306a08b1713414676db (patch)
treedc7c3d5eda4aa608e976b1897486ae6636a45410 /sys/dev
parentbe61be8f4a672ac13622798179e51bb6cd043020 (diff)
Support for ITExpress IT8212F ATA133 controller; close PR 3540.
Submitter is unresponsible so the diff is not tested. If you have any problems with it open a new PR.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/pciide.c226
-rw-r--r--sys/dev/pci/pciide_ite_reg.h42
2 files changed, 266 insertions, 2 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c
index e653eb81bad..81fa8c6da76 100644
--- a/sys/dev/pci/pciide.c
+++ b/sys/dev/pci/pciide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pciide.c,v 1.151 2003/12/12 13:03:51 grange Exp $ */
+/* $OpenBSD: pciide.c,v 1.152 2003/12/20 08:03:54 grange Exp $ */
/* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */
/*
@@ -120,6 +120,7 @@ int wdcdebug_pciide_mask = WDCDEBUG_PCIIDE_MASK;
#include <dev/pci/pciide_natsemi_reg.h>
#include <dev/pci/pciide_nforce_reg.h>
#include <dev/pci/pciide_i31244_reg.h>
+#include <dev/pci/pciide_ite_reg.h>
#include <dev/pci/cy82c693var.h>
#include <dev/ata/atavar.h>
@@ -287,6 +288,10 @@ int nforce_pci_intr(void *);
void artisea_chip_map(struct pciide_softc *, struct pci_attach_args *);
+void ite_chip_map(struct pciide_softc *, struct pci_attach_args *);
+void ite_setup_channel(struct channel_softc *);
+int ite_pci_intr(void *);
+
void pciide_channel_dma_setup(struct pciide_channel *);
int pciide_dma_table_setup(struct pciide_softc*, int, int);
int pciide_dma_init(void *, int, int, void *, size_t, int);
@@ -623,6 +628,13 @@ const struct pciide_product_desc pciide_nvidia_products[] = {
}
};
+const struct pciide_product_desc pciide_ite_products[] = {
+ { PCI_PRODUCT_ITEXPRESS_IT8212F,
+ IDE_PCI_CLASS_OVERRIDE,
+ ite_chip_map
+ }
+};
+
struct pciide_vendor_desc {
u_int32_t ide_vendor;
@@ -660,7 +672,9 @@ const struct pciide_vendor_desc pciide_vendors[] = {
{ PCI_VENDOR_PROMISE, pciide_promise_products,
sizeof(pciide_promise_products)/sizeof(pciide_promise_products[0]) },
{ PCI_VENDOR_NVIDIA, pciide_nvidia_products,
- sizeof(pciide_nvidia_products)/sizeof(pciide_nvidia_products[0]) }
+ sizeof(pciide_nvidia_products)/sizeof(pciide_nvidia_products[0]) },
+ { PCI_VENDOR_ITEXPRESS, pciide_ite_products,
+ sizeof(pciide_ite_products)/sizeof(pciide_ite_products[0]) }
};
/* options passed via the 'flags' config keyword */
@@ -6089,3 +6103,211 @@ artisea_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
sata_setup_channel(&cp->wdc_channel);
}
}
+
+void
+ite_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
+{
+ struct pciide_channel *cp;
+ int channel;
+ pcireg_t interface = PCI_INTERFACE(pa->pa_class);
+ bus_size_t cmdsize, ctlsize;
+ pcireg_t cfg, modectl;
+
+ cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG);
+ modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG);
+ WDCDEBUG_PRINT(("%s: cfg=0x%x, modectl=0x%x\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, cfg & IT_CFG_MASK,
+ modectl & IT_MODE_MASK), DEBUG_PROBE);
+
+ 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;
+ 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 = 6;
+
+ sc->sc_wdcdev.set_modes = ite_setup_channel;
+ sc->sc_wdcdev.channels = sc->wdc_chanarray;
+ sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
+
+ pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
+
+ /* Disable RAID */
+ modectl &= ~IT_MODE_RAID1;
+ /* Disable CPU firmware mode */
+ modectl &= ~IT_MODE_CPU;
+ /* Select 66 MHz bus */
+ modectl &= ~(IT_MODE_50MHZ(0) | IT_MODE_50MHZ(1));
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, IT_CFG, modectl);
+
+ for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
+ cp = &sc->pciide_channels[channel];
+
+ if (pciide_chansetup(sc, channel, interface) == 0)
+ continue;
+ pciide_map_compat_intr(pa, cp, channel, interface);
+ if (cp->hw_ok == 0)
+ continue;
+ pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
+ ite_pci_intr);
+ if (cp->hw_ok == 0) {
+ pciide_unmap_compat_intr(pa, cp, channel, interface);
+ continue;
+ }
+ sc->sc_wdcdev.set_modes(&cp->wdc_channel);
+ }
+
+ /* Re-read configuration registers after channels setup */
+ cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG);
+ modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE);
+ WDCDEBUG_PRINT(("%s: cfg=0x%x, modectl=0x%x\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, cfg & IT_CFG_MASK,
+ modectl & IT_MODE_MASK), DEBUG_PROBE);
+}
+
+void
+ite_setup_channel(struct channel_softc *chp)
+{
+ struct ata_drive_datas *drvp;
+ 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;
+ pcireg_t cfg, modectl;
+ pcireg_t tim;
+
+ cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG);
+ modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE);
+ tim = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_TIM(channel));
+ WDCDEBUG_PRINT(("%s:%d: tim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname,
+ channel, tim), DEBUG_PROBE);
+
+ /* Setup DMA if needed */
+ pciide_channel_dma_setup(cp);
+
+ /* Clear all bits for this channel */
+ idedma_ctl = 0;
+
+ /* Per channel settings */
+ for (drive = 0; drive < 2; drive++) {
+ drvp = &chp->ch_drive[drive];
+
+ /* If no drive, skip */
+ if ((drvp->drive_flags & DRIVE) == 0)
+ continue;
+
+ if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
+ (drvp->drive_flags & DRIVE_UDMA) != 0) {
+ /* Setup UltraDMA mode */
+ drvp->drive_flags &= ~DRIVE_DMA;
+ modectl &= ~IT_MODE_DMA(channel, drive);
+
+ /* Check cable */
+ if (drvp->UDMA_mode > 2 &&
+ (cfg & IT_CFG_CABLE(channel, drive)) == 0) {
+ 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;
+ }
+
+ if (drvp->UDMA_mode >= 5)
+ tim |= IT_TIM_UDMA5(drive);
+ else
+ tim &= ~IT_TIM_UDMA5(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;
+ modectl |= IT_MODE_DMA(channel, drive);
+
+ /* 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;
+ }
+
+ /* Enable IORDY if PIO mode >= 3 */
+ if (drvp->PIO_mode >= 3)
+ cfg |= IT_CFG_IORDY(channel);
+ }
+
+ WDCDEBUG_PRINT(("%s: tim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname,
+ tim), DEBUG_PROBE);
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, IT_CFG, cfg);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, IT_MODE, modectl);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, IT_TIM(channel), tim);
+
+ if (idedma_ctl != 0) {
+ /* Add software bits in status register */
+ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
+ IDEDMA_CTL(channel), idedma_ctl);
+ }
+
+ pciide_print_modes(cp);
+}
+
+int
+ite_pci_intr(void *arg)
+{
+ struct pciide_softc *sc = arg;
+ struct pciide_channel *cp;
+ struct channel_softc *wdc_cp;
+ int i, rv, crv;
+ u_int8_t dmastat;
+
+ rv = 0;
+ for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
+ cp = &sc->pciide_channels[i];
+ wdc_cp = &cp->wdc_channel;
+
+ /* Skip compat channel */
+ if (cp->compat)
+ continue;
+
+ dmastat = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
+ IDEDMA_CTL(i));
+ if ((dmastat & IDEDMA_CTL_INTR) == 0)
+ continue;
+
+ crv = wdcintr(wdc_cp);
+ if (crv == 0)
+ printf("%s:%d: bogus intr\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, i);
+ else
+ rv = 1;
+ }
+ return rv;
+}
diff --git a/sys/dev/pci/pciide_ite_reg.h b/sys/dev/pci/pciide_ite_reg.h
new file mode 100644
index 00000000000..3c8288cd5f4
--- /dev/null
+++ b/sys/dev/pci/pciide_ite_reg.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: pciide_ite_reg.h,v 1.1 2003/12/20 08:03:55 grange Exp $ */
+/*
+ * Copyright (c) 2003 Alexander Yurchenko <grange@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DEV_PCI_PCIIDE_ITE_REG_H_
+#define _DEV_PCI_PCIIDE_ITE_REG_H_
+
+/*
+ * Registers definition for IT8212F
+ */
+#define IT_CFG 0x40 /* I/O configuration */
+#define IT_CFG_MASK 0x0000ffff
+#define IT_CFG_IORDY(chan) (0x0001 << (chan))
+#define IT_CFG_BLID(chan) (0x0004 << (chan))
+#define IT_CFG_CABLE(chan, drive) (0x0010 << ((chan) * 2 + (drive)))
+#define IT_CFG_DECODE(chan) (0x8000 >> ((chan) * 2))
+
+#define IT_MODE 0x50 /* mode control / RAID function */
+#define IT_MODE_MASK 0x0000ffff
+#define IT_MODE_CPU 0x0001
+#define IT_MODE_50MHZ(chan) (0x0002 << (chan))
+#define IT_MODE_DMA(chan, drive) (0x0008 << ((chan) * 2 + (drive)))
+#define IT_MODE_RESET 0x0080
+#define IT_MODE_RAID1 0x0100
+
+#define IT_TIM(chan) ((chan) ? 0x58 : 0x54) /* timings */
+#define IT_TIM_UDMA5(drive) (0x00800000 << (drive) * 8)
+
+#endif /* !_DEV_PCI_PCIIDE_ITE_REG_H_ */