summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2007-03-21 12:20:31 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2007-03-21 12:20:31 +0000
commitcadcf6ece765dbbd4617ce6a3bcd5823ae8f563e (patch)
tree0e49b7e3cae0693cac037c7bf69be9d02f4e817c /sys/dev/pci
parenta75543aecae6a3e1c41846c4eb0562fbed48f05e (diff)
Basic support for JMicron PATA.
JMB368 supported for now, multi port cards that share PATA/SATA need to do a complicated internal channel mapping dance I plan to look into next. ok grange@
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pciide.c161
-rw-r--r--sys/dev/pci/pciide_jmicron_reg.h32
2 files changed, 191 insertions, 2 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c
index ca34830b223..fa85b4a178c 100644
--- a/sys/dev/pci/pciide.c
+++ b/sys/dev/pci/pciide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pciide.c,v 1.262 2006/11/21 21:48:54 brad Exp $ */
+/* $OpenBSD: pciide.c,v 1.263 2007/03/21 12:20:30 jsg Exp $ */
/* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */
/*
@@ -134,6 +134,7 @@ int wdcdebug_pciide_mask = WDCDEBUG_PCIIDE_MASK;
#include <dev/pci/pciide_ite_reg.h>
#include <dev/pci/pciide_ixp_reg.h>
#include <dev/pci/pciide_svwsata_reg.h>
+#include <dev/pci/pciide_jmicron_reg.h>
#include <dev/pci/cy82c693var.h>
/* inlines for reading/writing 8-bit PCI registers */
@@ -282,6 +283,9 @@ void ite_setup_channel(struct channel_softc *);
void ixp_chip_map(struct pciide_softc *, struct pci_attach_args *);
void ixp_setup_channel(struct channel_softc *);
+void jmicron_chip_map(struct pciide_softc *, struct pci_attach_args *);
+void jmicron_setup_channel(struct channel_softc *);
+
u_int8_t pciide_dmacmd_read(struct pciide_softc *, int);
void pciide_dmacmd_write(struct pciide_softc *, int, u_int8_t);
u_int8_t pciide_dmactl_read(struct pciide_softc *, int);
@@ -1046,6 +1050,13 @@ const struct pciide_product_desc pciide_ati_products[] = {
}
};
+const struct pciide_product_desc pciide_jmicron_products[] = {
+ { PCI_PRODUCT_JMICRON_JMB368,
+ 0,
+ jmicron_chip_map
+ }
+};
+
struct pciide_vendor_desc {
u_int32_t ide_vendor;
const struct pciide_product_desc *ide_products;
@@ -1086,7 +1097,9 @@ const struct pciide_vendor_desc pciide_vendors[] = {
{ PCI_VENDOR_ITEXPRESS, pciide_ite_products,
sizeof(pciide_ite_products)/sizeof(pciide_ite_products[0]) },
{ PCI_VENDOR_ATI, pciide_ati_products,
- sizeof(pciide_ati_products)/sizeof(pciide_ati_products[0]) }
+ sizeof(pciide_ati_products)/sizeof(pciide_ati_products[0]) },
+ { PCI_VENDOR_JMICRON, pciide_jmicron_products,
+ sizeof(pciide_jmicron_products)/sizeof(pciide_jmicron_products[0]) }
};
/* options passed via the 'flags' config keyword */
@@ -8308,3 +8321,147 @@ ixp_setup_channel(struct channel_softc *chp)
pciide_print_modes(cp);
}
+
+void
+jmicron_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;
+ u_int32_t conf;
+
+ conf = pci_conf_read(sc->sc_pc, sc->sc_tag, JMICRON_CONF);
+ WDCDEBUG_PRINT(("%s: conf register 0x%x\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE);
+
+ 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 = jmicron_setup_channel;
+ sc->sc_wdcdev.channels = sc->wdc_chanarray;
+ sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
+
+ pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
+
+ for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
+ cp = &sc->pciide_channels[channel];
+
+ if (pciide_chansetup(sc, channel, interface) == 0)
+ continue;
+
+#if 0
+ if ((conf & JMICRON_CHAN_EN(channel)) == 0) {
+ printf("%s: %s ignored (disabled)\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
+ continue;
+ }
+#endif
+
+ pciide_map_compat_intr(pa, cp, channel, interface);
+ if (cp->hw_ok == 0)
+ continue;
+ pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
+ pciide_pci_intr);
+ if (cp->hw_ok == 0) {
+ pciide_unmap_compat_intr(pa, cp, channel, interface);
+ continue;
+ }
+
+ if (pciide_chan_candisable(cp)) {
+ conf &= ~JMICRON_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
+jmicron_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;
+ u_int32_t conf;
+
+ conf = pci_conf_read(sc->sc_pc, sc->sc_tag, JMICRON_CONF);
+
+ /* 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;
+
+ /* see if cable is up to scratch */
+ if ((conf & JMICRON_CONF_40PIN) &&
+ (drvp->UDMA_mode > 2))
+ drvp->UDMA_mode = 2;
+
+ 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 {
+ mode = drvp->PIO_mode;
+ 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;
+ }
+ }
+
+ 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);
+}
diff --git a/sys/dev/pci/pciide_jmicron_reg.h b/sys/dev/pci/pciide_jmicron_reg.h
new file mode 100644
index 00000000000..4279c006743
--- /dev/null
+++ b/sys/dev/pci/pciide_jmicron_reg.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: pciide_jmicron_reg.h,v 1.1 2007/03/21 12:20:30 jsg Exp $ */
+
+/*
+ * Copyright (c) 2007 Jonathan Gray <jsg@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_JMICRON_REG_H
+#define _DEV_PCI_PCIIDE_JMICRON_REG_H
+
+#define JMICRON_MASTER_UDMA (1 << 2)
+#define JMICRON_MASTER_SHIFT 4
+#define JMICRON_SLAVE_SHIFT 12
+
+#define JMICRON_CONF 0x40
+#define JMICRON_CHAN_EN(chan) ((chan == 1) ? 4 : 0)
+
+#define JMICRON_CONF_SWAP (1 << 22)
+#define JMICRON_CONF_40PIN (1 << 3)
+
+#endif