summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authoritohy <itohy@NetBSD.org>2006-09-07 14:22:07 +0000
committeritohy <itohy@NetBSD.org>2006-09-07 14:22:07 +0000
commitcb2fb285ec0147ac24ff9a9bd47729a90fbad54f (patch)
tree5e34a43e837af08b35944f4f965a8bd4f5501430 /sys/dev
parent4f593623cc0eb799a1d177a5821178c176f98fa4 (diff)
Workbit NinjaATA-32 busmastering PIO IDE controller driver (njata)
This driver supports NinjaATA-32Bi and NPATA-32 chips, which are used for CardBus ATA interface cards and CardBus CompactFlash adapters.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/DEVNAMES3
-rw-r--r--sys/dev/cardbus/files.cardbus8
-rw-r--r--sys/dev/cardbus/njata_cardbus.c264
-rw-r--r--sys/dev/ic/ninjaata32.c726
-rw-r--r--sys/dev/ic/ninjaata32reg.h154
-rw-r--r--sys/dev/ic/ninjaata32var.h118
6 files changed, 1271 insertions, 2 deletions
diff --git a/sys/dev/DEVNAMES b/sys/dev/DEVNAMES
index 24ab76108fc..1c00aad7932 100644
--- a/sys/dev/DEVNAMES
+++ b/sys/dev/DEVNAMES
@@ -1,4 +1,4 @@
-# $NetBSD: DEVNAMES,v 1.214 2006/09/07 12:34:42 itohy Exp $
+# $NetBSD: DEVNAMES,v 1.215 2006/09/07 14:22:07 itohy Exp $
#
# This file contains all used device names and defined attributes in
# alphabetical order. New devices added to the system somewhere should first
@@ -883,6 +883,7 @@ nextkbd next68k
nfe MI
nhpib hp300
ni MI
+njata MI
njs MI
np vax
npx i386
diff --git a/sys/dev/cardbus/files.cardbus b/sys/dev/cardbus/files.cardbus
index 4a396fa9e4b..5709163c789 100644
--- a/sys/dev/cardbus/files.cardbus
+++ b/sys/dev/cardbus/files.cardbus
@@ -1,4 +1,4 @@
-# $NetBSD: files.cardbus,v 1.33 2006/06/06 21:00:41 rpaulo Exp $
+# $NetBSD: files.cardbus,v 1.34 2006/09/07 14:22:07 itohy Exp $
#
# files.cardbus
#
@@ -125,3 +125,9 @@ file dev/cardbus/if_ath_cardbus.c ath_cardbus
#
attach njs at cardbus with njs_cardbus
file dev/cardbus/njs_cardbus.c njs_cardbus
+
+#
+# Workbit NinjaATA-32 controllers
+#
+attach njata at cardbus with njata_cardbus
+file dev/cardbus/njata_cardbus.c njata_cardbus
diff --git a/sys/dev/cardbus/njata_cardbus.c b/sys/dev/cardbus/njata_cardbus.c
new file mode 100644
index 00000000000..26e6b23ddfd
--- /dev/null
+++ b/sys/dev/cardbus/njata_cardbus.c
@@ -0,0 +1,264 @@
+/* $Id: njata_cardbus.c,v 1.1 2006/09/07 14:22:07 itohy Exp $ */
+
+/*
+ * Copyright (c) 2006 ITOH Yasufumi <itohy@NetBSD.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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: njata_cardbus.c,v 1.1 2006/09/07 14:22:07 itohy Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/cardbus/cardbusvar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/ata/atavar.h>
+#include <dev/ic/wdcreg.h>
+#include <dev/ic/wdcvar.h>
+
+#include <dev/ic/ninjaata32reg.h>
+#include <dev/ic/ninjaata32var.h>
+
+#define NJATA32_CARDBUS_BASEADDR_IO CARDBUS_BASE0_REG
+#define NJATA32_CARDBUS_BASEADDR_MEM CARDBUS_BASE1_REG
+
+struct njata32_cardbus_softc {
+ struct njata32_softc sc_njata32;
+
+ /* CardBus-specific goo */
+ cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */
+ int sc_intrline; /* our interrupt line */
+ cardbustag_t sc_tag;
+
+ bus_space_handle_t sc_regmaph;
+ bus_size_t sc_regmap_size;
+};
+
+static const struct njata32_cardbus_product *njata_cardbus_lookup
+ (const struct cardbus_attach_args *);
+static int njata_cardbus_match(struct device *, struct cfdata *,
+ void *);
+static void njata_cardbus_attach(struct device *, struct device *,
+ void *);
+static int njata_cardbus_detach(struct device *, int);
+
+CFATTACH_DECL(njata_cardbus, sizeof(struct njata32_cardbus_softc),
+ njata_cardbus_match, njata_cardbus_attach, njata_cardbus_detach, NULL);
+
+static const struct njata32_cardbus_product {
+ cardbus_vendor_id_t p_vendor;
+ cardbus_product_id_t p_product;
+ uint8_t p_flags;
+#define NJATA32_FL_IOMAP_ONLY 1 /* registers are only in the I/O map */
+} njata32_cardbus_products[] = {
+ { PCI_VENDOR_IODATA, PCI_PRODUCT_IODATA_CBIDE2,
+ 0 },
+ { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NJATA32BI,
+ 0 },
+ { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NJATA32BI_KME,
+ 0 },
+ { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NPATA32_CF32A,
+ NJATA32_FL_IOMAP_ONLY },
+ { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NPATA32_KME,
+ NJATA32_FL_IOMAP_ONLY },
+
+ { PCI_VENDOR_INVALID, 0,
+ 0 }
+};
+
+static const struct njata32_cardbus_product *
+njata_cardbus_lookup(ca)
+ const struct cardbus_attach_args *ca;
+{
+ const struct njata32_cardbus_product *p;
+
+ for (p = njata32_cardbus_products;
+ p->p_vendor != PCI_VENDOR_INVALID; p++) {
+ if (CARDBUS_VENDOR(ca->ca_id) == p->p_vendor &&
+ CARDBUS_PRODUCT(ca->ca_id) == p->p_product)
+ return p;
+ }
+
+ return NULL;
+}
+
+static int
+njata_cardbus_match(parent, match, aux)
+ struct device *parent;
+ struct cfdata *match;
+ void *aux;
+{
+ struct cardbus_attach_args *ca = aux;
+
+ if (njata_cardbus_lookup(ca))
+ return 1;
+
+ return 0;
+}
+
+static void
+njata_cardbus_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct cardbus_attach_args *ca = aux;
+ struct njata32_cardbus_softc *csc = (void *)self;
+ struct njata32_softc *sc = &csc->sc_njata32;
+ const struct njata32_cardbus_product *prod;
+ cardbus_devfunc_t ct = ca->ca_ct;
+ cardbus_chipset_tag_t cc = ct->ct_cc;
+ cardbus_function_tag_t cf = ct->ct_cf;
+ pcireg_t reg;
+ int csr;
+ uint8_t latency = 0x20;
+
+ if ((prod = njata_cardbus_lookup(ca)) == NULL)
+ panic("njata_cardbus_attach");
+
+ printf(": Workbit NinjaATA-32 IDE controller\n");
+
+ csc->sc_ct = ct;
+ csc->sc_tag = ca->ca_tag;
+ csc->sc_intrline = ca->ca_intrline;
+
+ /*
+ * Map the device.
+ */
+ csr = PCI_COMMAND_MASTER_ENABLE;
+
+ /*
+ * Map registers.
+ * Try memory map first, and then try I/O.
+ */
+ if ((prod->p_flags & NJATA32_FL_IOMAP_ONLY) == 0 &&
+ Cardbus_mapreg_map(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_MEM,
+ PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &NJATA32_REGT(sc), &csc->sc_regmaph, NULL, &csc->sc_regmap_size)
+ == 0) {
+ if (bus_space_subregion(NJATA32_REGT(sc), csc->sc_regmaph,
+ NJATA32_MEMOFFSET_REG, NJATA32_REGSIZE, &NJATA32_REGH(sc))
+ != 0) {
+ /* failed -- undo map and try I/O */
+ Cardbus_mapreg_unmap(csc->sc_ct,
+ NJATA32_CARDBUS_BASEADDR_MEM, NJATA32_REGT(sc),
+ csc->sc_regmaph, csc->sc_regmap_size);
+ goto try_io;
+ }
+#ifdef NJATA32_DEBUG
+ printf("%s: memory space mapped, size %u\n",
+ NJATA32NAME(sc), (unsigned)csc->sc_regmap_size);
+#endif
+ csr |= PCI_COMMAND_MEM_ENABLE;
+ sc->sc_flags = NJATA32_MEM_MAPPED;
+ (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
+ } else {
+ try_io:
+ if (Cardbus_mapreg_map(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_IO,
+ PCI_MAPREG_TYPE_IO, 0, &NJATA32_REGT(sc),
+ &NJATA32_REGH(sc), NULL, &csc->sc_regmap_size) == 0) {
+#ifdef NJATA32_DEBUG
+ printf("%s: io space mapped, size %u\n",
+ NJATA32NAME(sc), (unsigned)csc->sc_regmap_size);
+#endif
+ csr |= PCI_COMMAND_IO_ENABLE;
+ sc->sc_flags = NJATA32_IO_MAPPED;
+ (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE);
+ } else {
+ printf("%s: unable to map device registers\n",
+ NJATA32NAME(sc));
+ return;
+ }
+ }
+
+ /* Make sure the right access type is on the CardBus bridge. */
+ (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
+
+ /* Enable the appropriate bits in the PCI CSR. */
+ reg = cardbus_conf_read(cc, cf, ca->ca_tag, PCI_COMMAND_STATUS_REG);
+ reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE);
+ reg |= csr;
+ cardbus_conf_write(cc, cf, ca->ca_tag, PCI_COMMAND_STATUS_REG, reg);
+
+ /*
+ * Make sure the latency timer is set to some reasonable
+ * value.
+ */
+ reg = cardbus_conf_read(cc, cf, ca->ca_tag, CARDBUS_BHLC_REG);
+ if (CARDBUS_LATTIMER(reg) < latency) {
+ reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
+ reg |= (latency << CARDBUS_LATTIMER_SHIFT);
+ cardbus_conf_write(cc, cf, ca->ca_tag, CARDBUS_BHLC_REG, reg);
+ }
+
+ sc->sc_dmat = ca->ca_dmat;
+
+ /*
+ * Establish the interrupt.
+ */
+ sc->sc_ih = cardbus_intr_establish(cc, cf, ca->ca_intrline, IPL_BIO,
+ njata32_intr, sc);
+ if (sc->sc_ih == NULL) {
+ printf("%s: unable to establish interrupt at %d\n",
+ NJATA32NAME(sc), ca->ca_intrline);
+ return;
+ }
+ printf("%s: interrupting at %d\n", NJATA32NAME(sc), ca->ca_intrline);
+
+ /* attach */
+ njata32_attach(sc);
+}
+
+static int
+njata_cardbus_detach(self, flags)
+ struct device *self;
+ int flags;
+{
+ struct njata32_cardbus_softc *csc = (void *) self;
+ struct njata32_softc *sc = &csc->sc_njata32;
+ int rv;
+
+ rv = njata32_detach(sc, flags);
+ if (rv)
+ return rv;
+
+ if (sc->sc_ih)
+ cardbus_intr_disestablish(csc->sc_ct->ct_cc,
+ csc->sc_ct->ct_cf, sc->sc_ih);
+
+ if (sc->sc_flags & NJATA32_IO_MAPPED)
+ Cardbus_mapreg_unmap(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_IO,
+ NJATA32_REGT(sc), NJATA32_REGH(sc), csc->sc_regmap_size);
+ if (sc->sc_flags & NJATA32_MEM_MAPPED)
+ Cardbus_mapreg_unmap(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_MEM,
+ NJATA32_REGT(sc), csc->sc_regmaph, csc->sc_regmap_size);
+
+ return 0;
+}
diff --git a/sys/dev/ic/ninjaata32.c b/sys/dev/ic/ninjaata32.c
new file mode 100644
index 00000000000..17609b334d6
--- /dev/null
+++ b/sys/dev/ic/ninjaata32.c
@@ -0,0 +1,726 @@
+/* $Id: ninjaata32.c,v 1.1 2006/09/07 14:22:07 itohy Exp $ */
+
+/*
+ * Copyright (c) 2006 ITOH Yasufumi <itohy@NetBSD.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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: ninjaata32.c,v 1.1 2006/09/07 14:22:07 itohy Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/ata/atavar.h>
+#include <dev/ic/wdcreg.h>
+#include <dev/ic/wdcvar.h>
+
+#include <dev/ic/ninjaata32reg.h>
+#include <dev/ic/ninjaata32var.h>
+
+#ifdef NJATA32_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+static void njata32_init(struct njata32_softc *, int nosleep);
+static void njata32_irqack(struct ata_channel *);
+static void njata32_clearirq(struct ata_channel *, int);
+static void njata32_setup_channel(struct ata_channel *);
+static int njata32_dma_init(void *, int channel, int drive,
+ void *databuf, size_t datalen, int flags);
+static void njata32_piobm_start(void *, int channel, int drive, int skip,
+ int xferlen, int flags);
+static int njata32_dma_finish(void *, int channel, int drive, int force);
+static void njata32_piobm_done(void *, int channel, int drive);
+
+#if 0 /* ATA DMA is currently unused */
+static const uint8_t njata32_timing_dma[NJATA32_MODE_MAX_DMA + 1] = {
+ NJATA32_TIMING_DMA0, NJATA32_TIMING_DMA1, NJATA32_TIMING_DMA2
+};
+#endif
+static const uint8_t njata32_timing_pio[NJATA32_MODE_MAX_PIO + 1] = {
+ NJATA32_TIMING_PIO0, NJATA32_TIMING_PIO1, NJATA32_TIMING_PIO2,
+ NJATA32_TIMING_PIO3, NJATA32_TIMING_PIO4
+};
+
+static void
+njata32_init(sc, nosleep)
+ struct njata32_softc *sc;
+ int nosleep; /* can't sleep (during cold boot and in interrupt) */
+{
+
+ /* disable interrupts */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_IRQ_SELECT, 0);
+
+ /* bus reset */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_AS,
+ NJATA32_AS_WAIT0 | NJATA32_AS_BUS_RESET);
+ if (nosleep)
+ delay(50000);
+ else
+ tsleep(sc, PRIBIO, "njaini", mstohz(50));
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_AS,
+ NJATA32_AS_WAIT0);
+
+ /* initial transfer speed */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_TIMING, NJATA32_TIMING_PIO0);
+
+ /* setup busmaster mode */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_IOBM,
+ NJATA32_IOBM_DEFAULT);
+
+ /* enable interrupts */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_IRQ_SELECT, NJATA32_IRQ_XFER | NJATA32_IRQ_DEV);
+}
+
+void
+njata32_attach(sc)
+ struct njata32_softc *sc;
+{
+ bus_addr_t dmaaddr;
+ int i, devno, error;
+ struct wdc_regs *wdr;
+
+ /*
+ * allocate DMA resource
+ */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat,
+ sizeof(struct njata32_dma_page), PAGE_SIZE, 0,
+ &sc->sc_sgt_seg, 1, &sc->sc_sgt_nsegs, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to allocate sgt page, error = %d\n",
+ NJATA32NAME(sc), error);
+ return;
+ }
+ if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_sgt_seg,
+ sc->sc_sgt_nsegs, sizeof(struct njata32_dma_page),
+ (caddr_t *)&sc->sc_sgtpg,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ printf("%s: unable to map sgt page, error = %d\n",
+ NJATA32NAME(sc), error);
+ goto fail1;
+ }
+ if ((error = bus_dmamap_create(sc->sc_dmat,
+ sizeof(struct njata32_dma_page), 1,
+ sizeof(struct njata32_dma_page), 0, BUS_DMA_NOWAIT,
+ &sc->sc_dmamap_sgt)) != 0) {
+ printf("%s: unable to create sgt DMA map, error = %d\n",
+ NJATA32NAME(sc), error);
+ goto fail2;
+ }
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_sgt,
+ sc->sc_sgtpg, sizeof(struct njata32_dma_page),
+ NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load sgt DMA map, error = %d\n",
+ NJATA32NAME(sc), error);
+ goto fail3;
+ }
+
+ dmaaddr = sc->sc_dmamap_sgt->dm_segs[0].ds_addr;
+
+ for (devno = 0; devno < NJATA32_NUM_DEV; devno++) {
+ sc->sc_dev[devno].d_sgt = sc->sc_sgtpg->dp_sg[devno];
+ sc->sc_dev[devno].d_sgt_dma = dmaaddr +
+ offsetof(struct njata32_dma_page, dp_sg[devno]);
+
+ error = bus_dmamap_create(sc->sc_dmat,
+ NJATA32_MAX_XFER, /* max total map size */
+ NJATA32_NUM_SG, /* max number of segments */
+ NJATA32_SGT_MAXSEGLEN, /* max size of a segment */
+ 0, /* boundary */
+ BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &sc->sc_dev[devno].d_dmamap_xfer);
+ if (error) {
+ printf("%s: failed to create DMA map (error = %d)\n",
+ NJATA32NAME(sc), error);
+ goto fail4;
+ }
+ }
+
+ /* device properties */
+ sc->sc_wdcdev.sc_atac.atac_cap =
+ ATAC_CAP_DATA16 | ATAC_CAP_DATA32 | ATAC_CAP_PIOBM;
+ sc->sc_wdcdev.irqack = njata32_irqack;
+ sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_wdc_chanarray;
+ sc->sc_wdcdev.sc_atac.atac_nchannels = NJATA32_NCHAN; /* 1 */
+ sc->sc_wdcdev.sc_atac.atac_pio_cap = NJATA32_MODE_MAX_PIO;
+#if 0 /* ATA DMA is currently unused */
+ sc->sc_wdcdev.sc_atac.atac_dma_cap = NJATA32_MODE_MAX_DMA;
+#endif
+ sc->sc_wdcdev.sc_atac.atac_set_modes = njata32_setup_channel;
+
+ /* DMA control functions */
+ sc->sc_wdcdev.dma_arg = sc;
+ sc->sc_wdcdev.dma_init = njata32_dma_init;
+ sc->sc_wdcdev.piobm_start = njata32_piobm_start;
+ sc->sc_wdcdev.dma_finish = njata32_dma_finish;
+ sc->sc_wdcdev.piobm_done = njata32_piobm_done;
+
+ sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS;
+
+ sc->sc_wdcdev.regs = wdr = &sc->sc_wdc_regs;
+
+ /* only one channel */
+ sc->sc_wdc_chanarray[0] = &sc->sc_ch[0].ch_ata_channel;
+ sc->sc_ch[0].ch_ata_channel.ch_channel = 0;
+ sc->sc_ch[0].ch_ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
+ sc->sc_ch[0].ch_ata_channel.ch_queue = &sc->sc_wdc_chqueue;
+ sc->sc_ch[0].ch_ata_channel.ch_ndrive = 2; /* max number of drives */
+
+ /* map ATA registers */
+ for (i = 0; i < WDC_NREG; i++) {
+ if (bus_space_subregion(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_OFFSET_WDCREGS + i,
+ i == wd_data ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
+ aprint_error("%s: couldn't subregion cmd regs\n",
+ NJATA32NAME(sc));
+ goto fail4;
+ }
+ }
+ wdc_init_shadow_regs(&sc->sc_ch[0].ch_ata_channel);
+ wdr->data32iot = NJATA32_REGT(sc);
+ wdr->data32ioh = wdr->cmd_iohs[wd_data];
+
+ /* map ATA ctl reg */
+ wdr->ctl_iot = NJATA32_REGT(sc);
+ if (bus_space_subregion(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_ALTSTATUS, 1, &wdr->ctl_ioh) != 0) {
+ aprint_error("%s: couldn't subregion ctl regs\n",
+ NJATA32NAME(sc));
+ goto fail4;
+ }
+
+ sc->sc_flags |= NJATA32_CMDPG_MAPPED;
+
+ /* use flags value as busmaster wait */
+ if ((sc->sc_bmwait =
+ device_cfdata(&sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags &
+ (NJATA32_BM_WAIT_MASK >> NJATA32_BM_WAIT_SHIFT)) > 0)
+ aprint_normal("%s: busmaster wait = %d\n",
+ NJATA32NAME(sc), sc->sc_bmwait);
+
+ njata32_init(sc, cold);
+
+ wdcattach(&sc->sc_ch[0].ch_ata_channel);
+
+ return;
+
+ /*
+ * cleanup
+ */
+fail4: while (--devno >= 0) {
+ bus_dmamap_destroy(sc->sc_dmat,
+ sc->sc_dev[devno].d_dmamap_xfer);
+ }
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap_sgt);
+fail3: bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap_sgt);
+fail2: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_sgtpg,
+ sizeof(struct njata32_dma_page));
+fail1: bus_dmamem_free(sc->sc_dmat, &sc->sc_sgt_seg, sc->sc_sgt_nsegs);
+}
+
+int
+njata32_detach(sc, flags)
+ struct njata32_softc *sc;
+ int flags;
+{
+ int rv, devno;
+
+ if (sc->sc_flags & NJATA32_CMDPG_MAPPED) {
+ if ((rv = wdcdetach(&sc->sc_wdcdev.sc_atac.atac_dev, flags)))
+ return rv;
+
+ /* free DMA resource */
+ for (devno = 0; devno < NJATA32_NUM_DEV; devno++) {
+ bus_dmamap_destroy(sc->sc_dmat,
+ sc->sc_dev[devno].d_dmamap_xfer);
+ }
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap_sgt);
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap_sgt);
+ bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_sgtpg,
+ sizeof(struct njata32_dma_page));
+ bus_dmamem_free(sc->sc_dmat, &sc->sc_sgt_seg, sc->sc_sgt_nsegs);
+ }
+
+ return 0;
+}
+
+static void
+njata32_irqack(chp)
+ struct ata_channel *chp;
+{
+ struct njata32_softc *sc = (void *)chp->ch_atac;
+
+ /* disable busmaster */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_BM, (sc->sc_bmwait << NJATA32_BM_WAIT_SHIFT));
+}
+
+static void
+njata32_clearirq(chp, irq)
+ struct ata_channel *chp;
+ int irq;
+{
+ struct njata32_softc *sc = (void *)chp->ch_atac;
+
+ printf("%s: unhandled intr: irq %#x, bm %#x, ",
+ NJATA32NAME(sc), irq,
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_BM));
+
+ /* disable busmaster */
+ njata32_irqack(chp);
+
+ /* clear device interrupt */
+ printf("err %#x, seccnt %#x, cyl %#x, sdh %#x, ",
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_ERROR),
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_SECCNT),
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_CYL_LO) |
+ (bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_CYL_HI) << 8),
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_SDH));
+ printf("status %#x\n",
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_STATUS));
+}
+
+static void
+njata32_setup_channel(chp)
+ struct ata_channel *chp;
+{
+ struct njata32_softc *sc = (void *)chp->ch_atac;
+ struct ata_drive_datas *drvp;
+ int drive;
+ uint8_t mode;
+
+ KASSERT(chp->ch_ndrive != 0);
+
+ sc->sc_timing_pio = 0;
+#if 0 /* ATA DMA is currently unused */
+ sc->sc_timing_dma = 0;
+#endif
+
+ for (drive = 0; drive < chp->ch_ndrive; drive++) {
+ drvp = &chp->ch_drive[drive];
+ if ((drvp->drive_flags & DRIVE) == 0)
+ continue; /* no drive */
+
+#if 0 /* ATA DMA is currently unused */
+ if ((drvp->drive_flags & DRIVE_DMA) != 0) {
+ /*
+ * Multiword DMA
+ */
+ if ((mode = drvp->DMA_mode) > NJATA32_MODE_MAX_DMA)
+ mode = NJATA32_MODE_MAX_DMA;
+ if (sc->sc_timing_dma < njata32_timing_dma[mode])
+ sc->sc_timing_dma = njata32_timing_dma[mode];
+ }
+#endif
+ /*
+ * PIO
+ */
+ if ((mode = drvp->PIO_mode) > NJATA32_MODE_MAX_PIO)
+ mode = NJATA32_MODE_MAX_PIO;
+ if (sc->sc_timing_pio < njata32_timing_pio[mode])
+ sc->sc_timing_pio = njata32_timing_pio[mode];
+ }
+
+ /* set timing for PIO */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_TIMING, sc->sc_timing_pio);
+}
+
+/*
+ * map DMA buffer
+ */
+int
+njata32_dma_init(v, channel, drive, databuf, datalen, flags)
+ void *v;
+ int channel, drive;
+ void *databuf;
+ size_t datalen;
+ int flags;
+{
+ struct njata32_softc *sc = v;
+ int error;
+ struct njata32_device *dev = &sc->sc_dev[drive];
+
+ KASSERT(channel == 0);
+ KASSERT((dev->d_flags & NJATA32_DEV_DMA_MAPPED) == 0);
+ KASSERT((dev->d_flags & NJATA32_DEV_DMA_STARTED) == 0);
+
+ KASSERT(flags & (WDC_DMA_PIOBM_ATA | WDC_DMA_PIOBM_ATAPI));
+
+ /* use PIO for short transfer */
+ if (datalen < 64 /* needs tune */) {
+ DPRINTF(("%s: njata32_dma_init: short transfer (%u)\n",
+ NJATA32NAME(sc), (unsigned)datalen));
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_TIMING, sc->sc_timing_pio);
+ return EINVAL;
+ }
+
+ /* use PIO for unaligned transfer (word alignment seems OK) */
+ if (((uintptr_t)databuf & 1) || (datalen & 1)) {
+ DPRINTF(("%s: njata32_dma_init: unaligned: buf %p, len %u\n",
+ NJATA32NAME(sc), databuf, (unsigned)datalen));
+ return EINVAL;
+ }
+
+ DPRINTF(("%s: njata32_dma_init: %s: databuf %p, datalen %u\n",
+ NJATA32NAME(sc), (flags & WDC_DMA_READ) ? "read" : "write",
+ databuf, (unsigned)datalen));
+
+ error = bus_dmamap_load(sc->sc_dmat, dev->d_dmamap_xfer,
+ databuf, datalen, NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
+ ((flags & WDC_DMA_READ) ? BUS_DMA_READ : BUS_DMA_WRITE));
+ if (error) {
+ printf("%s: load xfer failed, error %d\n",
+ NJATA32NAME(sc), error);
+ return error;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, dev->d_dmamap_xfer, 0,
+ dev->d_dmamap_xfer->dm_mapsize,
+ (flags & WDC_DMA_READ) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+
+ dev->d_flags =
+ ((flags & WDC_DMA_READ) ? NJATA32_DEV_DMA_READ : 0) |
+ ((flags & WDC_DMA_PIOBM_ATAPI) ? NJATA32_DEV_DMA_ATAPI : 0) |
+ NJATA32_DEV_DMA_MAPPED;
+
+ return 0;
+}
+
+/*
+ * start DMA
+ *
+ * top: databuf + skip
+ * size: xferlen
+ */
+void
+njata32_piobm_start(v, channel, drive, skip, xferlen, flags)
+ void *v;
+ int channel, drive;
+ int skip, xferlen; /* offset/size in mapped DMA buffer */
+ int flags;
+{
+ struct njata32_softc *sc = v;
+ struct njata32_device *dev = &sc->sc_dev[drive];
+ int i, nsegs, seglen;
+ uint8_t bmreg;
+
+ DPRINTF(("%s: njata32_piobm_start: ch%d, dv%d, skip %d, xferlen %d\n",
+ NJATA32NAME(sc), channel, drive, skip, xferlen));
+
+ KASSERT(channel == 0);
+ KASSERT(dev->d_flags & NJATA32_DEV_DMA_MAPPED);
+ KASSERT((dev->d_flags & NJATA32_DEV_DMA_STARTED) == 0);
+
+ /*
+ * create scatter/gather table
+ * XXX this code may be slow
+ */
+ for (i = nsegs = 0;
+ i < dev->d_dmamap_xfer->dm_nsegs && xferlen > 0; i++) {
+ if (dev->d_dmamap_xfer->dm_segs[i].ds_len <= skip) {
+ skip -= dev->d_dmamap_xfer->dm_segs[i].ds_len;
+ continue;
+ }
+
+ seglen = dev->d_dmamap_xfer->dm_segs[i].ds_len - skip;
+ if (seglen > xferlen)
+ seglen = xferlen;
+
+ dev->d_sgt[nsegs].sg_addr =
+ htole32(dev->d_dmamap_xfer->dm_segs[i].ds_addr + skip);
+ dev->d_sgt[nsegs].sg_len = htole32(seglen);
+
+ xferlen -= seglen;
+ nsegs++;
+ skip = 0;
+ }
+ sc->sc_piobm_nsegs = nsegs;
+ /* end mark */
+ dev->d_sgt[nsegs - 1].sg_len |= htole32(NJATA32_SGT_ENDMARK);
+
+#ifdef DIAGNOSTIC
+ if (xferlen)
+ panic("%s: njata32_piobm_start: xferlen residue %d\n",
+ NJATA32NAME(sc), xferlen);
+#endif
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_sgt,
+ (char *)dev->d_sgt - (char *)sc->sc_sgtpg,
+ sizeof(struct njata32_sgtable) * nsegs,
+ BUS_DMASYNC_PREWRITE);
+
+ /* set timing for PIO */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_TIMING, sc->sc_timing_pio);
+
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_IOBM,
+ NJATA32_IOBM_DEFAULT);
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_AS,
+ NJATA32_AS_WAIT0);
+
+ /*
+ * interrupt configuration
+ */
+ if ((dev->d_flags & (NJATA32_DEV_DMA_READ | NJATA32_DEV_DMA_ATAPI)) ==
+ NJATA32_DEV_DMA_READ) {
+ /*
+ * ATA piobm read is executed while device interrupt is active,
+ * so disable device interrupt here
+ */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_IRQ_SELECT, NJATA32_IRQ_XFER);
+ }
+
+ /* enable scatter/gather busmaster transfer */
+ bmreg = NJATA32_BM_EN | NJATA32_BM_SG |
+ (sc->sc_bmwait << NJATA32_BM_WAIT_SHIFT) |
+ ((dev->d_flags & NJATA32_DEV_DMA_READ) ? NJATA32_BM_RD : 0);
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_BM,
+ bmreg);
+
+ /* load scatter/gather table */
+ bus_space_write_4(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_DMAADDR, dev->d_sgt_dma);
+ bus_space_write_4(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_DMALENGTH, sizeof(struct njata32_sgtable) * nsegs);
+
+ /* start transfer */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_BM,
+ (bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_BM)
+ & ~(NJATA32_BM_RD|NJATA32_BM_SG|NJATA32_BM_WAIT_MASK)) |
+ bmreg | NJATA32_BM_GO);
+
+ sc->sc_devflags = dev->d_flags;
+ if (flags & WDC_PIOBM_XFER_IRQ)
+ sc->sc_devflags |= NJATA32_DEV_XFER_INTR;
+#ifdef DIAGNOSTIC
+ dev->d_flags |= NJATA32_DEV_DMA_STARTED;
+#endif
+}
+
+/*
+ * end of DMA
+ */
+int
+njata32_dma_finish(v, channel, drive, force)
+ void *v;
+ int channel, drive;
+ int force;
+{
+ struct njata32_softc *sc = v;
+ int bm;
+ int error = 0;
+
+ DPRINTF(("%s: njata32_dma_finish: bm = %#x\n", NJATA32NAME(sc),
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_BM)));
+
+ KASSERT(channel == 0);
+ KASSERT(sc->sc_dev[drive].d_flags & NJATA32_DEV_DMA_MAPPED);
+ KASSERT(sc->sc_dev[drive].d_flags & NJATA32_DEV_DMA_STARTED);
+
+ bm = bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_BM);
+
+#ifdef NJATA32_DEBUG
+ printf("%s: irq %#x, bm %#x, 18 %#x, 1c %#x\n", NJATA32NAME(sc),
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_IRQ_STAT),
+ bm,
+ bus_space_read_4(NJATA32_REGT(sc), NJATA32_REGH(sc), 0x18),
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc), 0x1c));
+#endif
+
+ /* check if DMA is active */
+ if (bm & NJATA32_BM_GO) {
+ error = WDC_DMAST_NOIRQ;
+
+ switch (force) {
+ case WDC_DMAEND_END:
+ return error;
+
+ case WDC_DMAEND_ABRT:
+ printf("%s: aborting DMA\n", NJATA32NAME(sc));
+ break;
+ }
+ }
+
+ /*
+ * ???
+ * For unknown reason, PIOBM transfer sometimes fails in the middle,
+ * in which case the bit #7 of BM register becomes 0.
+ * Increasing the wait value seems to improve the situation.
+ */
+ if ((bm & NJATA32_BM_DONE) == 0) {
+ error |= WDC_DMAST_ERR;
+ printf("%s: busmaster error", NJATA32NAME(sc));
+ if (sc->sc_bmwait < 1 /* XXX */) {
+ sc->sc_bmwait++;
+ printf(", new busmaster wait = %d", sc->sc_bmwait);
+ }
+ printf("\n");
+ }
+
+ /* stop command */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_AS,
+ NJATA32_AS_WAIT0);
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc), NJATA32_REG_BM,
+ (sc->sc_bmwait << NJATA32_BM_WAIT_SHIFT));
+
+ /* set timing for PIO */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_TIMING, sc->sc_timing_pio);
+
+ /*
+ * reenable device interrupt in case it was disabled for
+ * this transfer
+ */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_IRQ_SELECT, NJATA32_IRQ_XFER | NJATA32_IRQ_DEV);
+
+#if 1 /* should be? */
+ if ((sc->sc_devflags & NJATA32_DEV_GOT_XFER_INTR) == 0)
+ error |= WDC_DMAST_ERR;
+#endif
+ sc->sc_devflags = 0;
+
+#ifdef DIAGNOSTIC
+ sc->sc_dev[drive].d_flags &= ~NJATA32_DEV_DMA_STARTED;
+#endif
+
+ return error;
+}
+
+/*
+ * unmap DMA buffer
+ */
+void
+njata32_piobm_done(v, channel, drive)
+ void *v;
+ int channel, drive;
+{
+ struct njata32_softc *sc = v;
+ struct njata32_device *dev = &sc->sc_dev[drive];
+
+ DPRINTF(("%s: njata32_piobm_done: ch%d dv%d\n",
+ NJATA32NAME(sc), channel, drive));
+
+ KASSERT(channel == 0);
+ KASSERT(dev->d_flags & NJATA32_DEV_DMA_MAPPED);
+ KASSERT((dev->d_flags & NJATA32_DEV_DMA_STARTED) == 0);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_sgt,
+ (char *)dev->d_sgt - (char *)sc->sc_sgtpg,
+ sizeof(struct njata32_sgtable) * sc->sc_piobm_nsegs,
+ BUS_DMASYNC_POSTWRITE);
+
+ /* unload dma map */
+ bus_dmamap_sync(sc->sc_dmat, dev->d_dmamap_xfer,
+ 0, dev->d_dmamap_xfer->dm_mapsize,
+ (dev->d_flags & NJATA32_DEV_DMA_READ) ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_sgt,
+ (char *)dev->d_sgt - (char *)sc->sc_sgtpg,
+ sizeof(struct njata32_sgtable) * NJATA32_NUM_SG,
+ BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_unload(sc->sc_dmat, dev->d_dmamap_xfer);
+ dev->d_flags &= ~NJATA32_DEV_DMA_MAPPED;
+}
+
+int
+njata32_intr(arg)
+ void *arg;
+{
+ struct njata32_softc *sc = arg;
+ struct ata_channel *chp;
+ int irq;
+
+ irq = bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_IRQ_STAT);
+ if ((irq & (NJATA32_IRQ_XFER | NJATA32_IRQ_DEV)) == 0)
+ return 0; /* not mine */
+
+ DPRINTF(("%s: njata32_intr: irq = %#x, altstatus = %#x\n",
+ NJATA32NAME(sc), irq,
+ bus_space_read_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_WD_ALTSTATUS)));
+
+ chp = &sc->sc_ch[0].ch_ata_channel;
+
+ if (irq & NJATA32_IRQ_XFER)
+ sc->sc_devflags |= NJATA32_DEV_GOT_XFER_INTR;
+
+ if ((irq & (NJATA32_IRQ_XFER | NJATA32_IRQ_DEV)) == NJATA32_IRQ_XFER &&
+ (sc->sc_devflags & NJATA32_DEV_XFER_INTR) == 0) {
+ /*
+ * transfer done, wait for device interrupt
+ */
+ bus_space_write_1(NJATA32_REGT(sc), NJATA32_REGH(sc),
+ NJATA32_REG_BM, (sc->sc_bmwait << NJATA32_BM_WAIT_SHIFT));
+ return 1;
+ }
+
+ /*
+ * If both transfer done interrupt and device interrupt are
+ * active for ATAPI transfer, call wdcintr() twice.
+ */
+ if ((sc->sc_devflags & NJATA32_DEV_DMA_ATAPI) &&
+ (irq & (NJATA32_IRQ_XFER | NJATA32_IRQ_DEV)) ==
+ (NJATA32_IRQ_XFER | NJATA32_IRQ_DEV) &&
+ (sc->sc_devflags & NJATA32_DEV_XFER_INTR)) {
+ if (wdcintr(chp) == 0) {
+ njata32_clearirq(&sc->sc_ch[0].ch_ata_channel, irq);
+ }
+ }
+
+ if (wdcintr(chp) == 0) {
+ njata32_clearirq(&sc->sc_ch[0].ch_ata_channel, irq);
+ }
+
+ return 1;
+}
diff --git a/sys/dev/ic/ninjaata32reg.h b/sys/dev/ic/ninjaata32reg.h
new file mode 100644
index 00000000000..0cd57887d66
--- /dev/null
+++ b/sys/dev/ic/ninjaata32reg.h
@@ -0,0 +1,154 @@
+/* $Id: ninjaata32reg.h,v 1.1 2006/09/07 14:22:07 itohy Exp $ */
+
+/*
+ * Copyright (c) 2006 ITOH Yasufumi <itohy@NetBSD.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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _NJATA32REG_H_
+#define _NJATA32REG_H_
+
+/*
+ * Workbit NinjaATA (32bit versions), IDE Controller with Busmastering PIO:
+ * NinjaATA-32Bi PCMCIA/CardBus dual mode device ("DuoATA")
+ * (CardBus mode only)
+ * PATA-32 CardBus device
+ */
+
+/*
+ * CAVEAT
+ * The names and the functions of the registers are probably incorrect
+ * since no programming information is available in the public.
+ */
+
+#define NJATA32_REGSIZE 32 /* size of register set */
+#define NJATA32_MEMOFFSET_REG 0x860 /* offset of memory mapped register */
+
+#define NJATA32_REG_IRQ_STAT 0x00 /* len=1 RO */
+#define NJATA32_REG_IRQ_SELECT 0x01 /* len=1 WO */
+# define NJATA32_IRQ_XFER 0x01
+# define NJATA32_IRQ_DEV 0x04
+
+#define NJATA32_REG_IOBM 0x02 /* len=1 WO */
+# define NJATA32_IOBM_01 0x01
+# define NJATA32_IOBM_02 0x02
+# define NJATA32_IOBM_MMENBL 0x08
+# define NJATA32_IOBM_BURST 0x10
+# define NJATA32_IOBM_NO_BMSTART0 0x20
+# define NJATA32_IOBM_80 0x80
+
+# define NJATA32_IOBM_DEFAULT (NJATA32_IOBM_01 | NJATA32_IOBM_02 | \
+ NJATA32_IOBM_BURST | NJATA32_IOBM_NO_BMSTART0 | NJATA32_IOBM_80)
+
+#define NJATA32_REG_AS 0x04 /* len=1 WO */
+# define NJATA32_AS_START 0x01 /* 0: PIO BM, 1: DMA BM */
+# define NJATA32_AS_WAIT0 0x00
+# define NJATA32_AS_WAIT1 0x04
+# define NJATA32_AS_WAIT2 0x08
+# define NJATA32_AS_WAIT3 0x0c
+# define NJATA32_AS_BUS_RESET 0x80
+
+#define NJATA32_REG_DMAADDR 0x08 /* len=4 R/W */
+#define NJATA32_REG_DMALENGTH 0x0c /* len=4 R/W */
+
+/*
+ * WDC registers
+ */
+#define NJATA32_OFFSET_WDCREGS 0x10
+
+#define NJATA32_REG_WD_DATA 0x10 /* len=1/2/4 R/W */
+#define NJATA32_REG_WD_ERROR 0x11 /* len=1 RO */
+#define NJATA32_REG_WD_FEATURES 0x11 /* len=1 WO */
+#define NJATA32_REG_WD_SECCNT 0x12 /* len=1 R/W */
+#define NJATA32_REG_WD_IREASON 0x12 /* len=1 R/W (ATAPI) */
+#define NJATA32_REG_WD_SECTOR 0x13 /* len=1 R/W */
+#define NJATA32_REG_WD_LBA_LO 0x13 /* len=1 R/W */
+#define NJATA32_REG_WD_CYL_LO 0x14 /* len=1 R/W */
+#define NJATA32_REG_WD_LBA_MI 0x14 /* len=1 R/W */
+#define NJATA32_REG_WD_CYL_HI 0x15 /* len=1 R/W */
+#define NJATA32_REG_WD_LBA_HI 0x15 /* len=1 R/W */
+#define NJATA32_REG_WD_SDH 0x16 /* len=1 R/W */
+#define NJATA32_REG_WD_COMMAND 0x17 /* len=1 WO */
+#define NJATA32_REG_WD_STATUS 0x17 /* len=1 RO */
+
+#if 0 /* these registers seem to show the busmaster status */
+/* ? */
+#define NJATA32_REG_18 0x18 /* len=4 RO */
+/* ? */
+#define NJATA32_REG_1c 0x1c /* len=1 RO */
+#endif
+
+#define NJATA32_REG_BM 0x1d /* len=1 R/W */
+# define NJATA32_BM_EN 0x01
+# define NJATA32_BM_RD 0x02 /* 0: write, 1: read */
+# define NJATA32_BM_SG 0x04 /* 1: use scatter/gather tbl */
+# define NJATA32_BM_GO 0x08
+# define NJATA32_BM_WAIT0 0x00
+# define NJATA32_BM_WAIT1 0x10
+# define NJATA32_BM_WAIT2 0x20
+# define NJATA32_BM_WAIT3 0x30
+# define NJATA32_BM_WAIT_MASK 0x30
+# define NJATA32_BM_WAIT_SHIFT 4
+# define NJATA32_BM_DONE 0x80 /* ? */
+
+#define NJATA32_REG_WD_ALTSTATUS 0x1e /* len=1 R */
+
+#define NJATA32_REG_TIMING 0x1f /* len=1 W */
+/* timing values for PIO transfer */
+# define NJATA32_TIMING_PIO0 0xd6
+# define NJATA32_TIMING_PIO1 0x85
+# define NJATA32_TIMING_PIO2 0x44
+# define NJATA32_TIMING_PIO3 0x33
+# define NJATA32_TIMING_PIO4 0x13
+# define NJATA32_TIMING_PIO4_ 0x14 /* for timing tweak */
+# define NJATA32_TIMING_PIO4__ 0x24 /* for timing tweak */
+/* timing values for multiword DMA transfer */
+# define NJATA32_TIMING_DMA0 0x88
+# define NJATA32_TIMING_DMA1 0x23
+# define NJATA32_TIMING_DMA2 0x13
+/* timing values for obsolete singleword DMA transfer */
+# define NJATA32_TIMING_SMDMA0 0xff
+# define NJATA32_TIMING_SMDMA1 0x88
+# define NJATA32_TIMING_SMDMA2 0x44
+
+/*
+ * DMA data structure
+ */
+
+/* scatter/gather transfer table entry (8 bytes) */
+struct njata32_sgtable {
+ uint32_t sg_addr; /* transfer address (little endian) */
+ uint32_t sg_len; /* transfer length (little endian) */
+#define NJATA32_SGT_ENDMARK 0x80000000
+#define NJATA32_SGT_MAXSEGLEN 0x10000
+};
+#define NJATA32_SGT_MAXENTRY 18
+
+/*
+ * device specific constants
+ */
+#define NJATA32_MODE_MAX_DMA 2
+#define NJATA32_MODE_MAX_PIO 4
+
+#endif /* _NJATA32REG_H_ */
diff --git a/sys/dev/ic/ninjaata32var.h b/sys/dev/ic/ninjaata32var.h
new file mode 100644
index 00000000000..a0d77609da9
--- /dev/null
+++ b/sys/dev/ic/ninjaata32var.h
@@ -0,0 +1,118 @@
+/* $Id: ninjaata32var.h,v 1.1 2006/09/07 14:22:08 itohy Exp $ */
+
+/*
+ * Copyright (c) 2006 ITOH Yasufumi <itohy@NetBSD.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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _NJATA32VAR_H_
+#define _NJATA32VAR_H_
+
+#define NJATA32NAME(sc) (sc->sc_wdcdev.sc_atac.atac_dev.dv_xname)
+
+/* ??? */
+#define NJATA32_MAX_XFER (64 * 1024)
+
+/*
+ * DMA page
+ */
+/* # device */
+#define NJATA32_NUM_DEV 2
+/* # scatter/gather table entries */
+#define NJATA32_NUM_SG NJATA32_SGT_MAXENTRY
+
+struct njata32_dma_page {
+ /*
+ * scatter/gather transfer table
+ */
+ struct njata32_sgtable dp_sg[NJATA32_NUM_DEV][NJATA32_NUM_SG];
+};
+
+#define NJATA32_NCHAN 1 /* only one channel */
+
+struct njata32_softc {
+ struct wdc_softc sc_wdcdev; /* common wdc definitions */
+
+ unsigned sc_flags;
+#define NJATA32_IO_MAPPED 0x00000001
+#define NJATA32_MEM_MAPPED 0x00000002
+#define NJATA32_CMDPG_MAPPED 0x00000004
+
+ unsigned sc_devflags;
+
+ /* interrupt handle */
+ void *sc_ih;
+
+ struct ninjaata32_channel { /* per-channel data */
+ struct ata_channel ch_ata_channel; /* generic part */
+ } sc_ch[NJATA32_NCHAN];
+
+ struct ata_channel *sc_wdc_chanarray[NJATA32_NCHAN];
+ struct ata_queue sc_wdc_chqueue;
+ struct wdc_regs sc_wdc_regs;
+#define NJATA32_REGT(sc) (sc)->sc_wdc_regs.cmd_iot
+#define NJATA32_REGH(sc) (sc)->sc_wdc_regs.cmd_baseioh
+
+ /* for DMA */
+ bus_dma_tag_t sc_dmat;
+ struct njata32_dma_page *sc_sgtpg; /* scatter/gather table page */
+#if 0
+ bus_addr_t sc_sgt_dma;
+#endif
+ bus_dma_segment_t sc_sgt_seg;
+ bus_dmamap_t sc_dmamap_sgt;
+ int sc_sgt_nsegs;
+
+ int sc_piobm_nsegs;
+
+ uint8_t sc_timing_pio;
+#if 0 /* ATA DMA is currently unused */
+ uint8_t sc_timing_dma;
+#endif
+
+ uint8_t sc_bmwait;
+
+ /* per-device structure */
+ struct njata32_device {
+ /* DMA resource */
+ struct njata32_sgtable *d_sgt; /* for host */
+ bus_addr_t d_sgt_dma; /* for device */
+ bus_dmamap_t d_dmamap_xfer;
+ unsigned d_flags;
+#define NJATA32_DEV_DMA_MAPPED 0x0001
+#define NJATA32_DEV_DMA_READ 0x0002
+#define NJATA32_DEV_DMA_ATAPI 0x0004
+#define NJATA32_DEV_XFER_INTR 0x0100 /* only for sc_devflags */
+#define NJATA32_DEV_GOT_XFER_INTR 0x0200 /* only for sc_devflags */
+#define NJATA32_DEV_DMA_STARTED 0x8000 /* for diag */
+ } sc_dev[NJATA32_NUM_DEV];
+};
+
+#ifdef _KERNEL
+void njata32_attach(struct njata32_softc *);
+int njata32_detach(struct njata32_softc *, int);
+int njata32_intr(void *);
+#endif
+
+#endif /* _NJATA32VAR_H_ */