From cb2fb285ec0147ac24ff9a9bd47729a90fbad54f Mon Sep 17 00:00:00 2001 From: itohy Date: Thu, 7 Sep 2006 14:22:07 +0000 Subject: [PATCH] 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. --- distrib/sets/lists/man/mi | 4 +- share/man/man4/Makefile | 4 +- share/man/man4/njata.4 | 97 +++++ sys/conf/files | 6 +- sys/dev/DEVNAMES | 3 +- sys/dev/cardbus/files.cardbus | 8 +- sys/dev/cardbus/njata_cardbus.c | 264 ++++++++++++ sys/dev/ic/ninjaata32.c | 726 ++++++++++++++++++++++++++++++++ sys/dev/ic/ninjaata32reg.h | 154 +++++++ sys/dev/ic/ninjaata32var.h | 118 ++++++ 10 files changed, 1378 insertions(+), 6 deletions(-) create mode 100644 share/man/man4/njata.4 create mode 100644 sys/dev/cardbus/njata_cardbus.c create mode 100644 sys/dev/ic/ninjaata32.c create mode 100644 sys/dev/ic/ninjaata32reg.h create mode 100644 sys/dev/ic/ninjaata32var.h diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi index 1eb2df6939e6..770392368f80 100644 --- a/distrib/sets/lists/man/mi +++ b/distrib/sets/lists/man/mi @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.927 2006/09/07 00:50:45 ad Exp $ +# $NetBSD: mi,v 1.928 2006/09/07 14:22:08 itohy Exp $ ./etc/mtree/set.man man-sys-root ./usr/share/info/am-utils.info man-amd-info info ./usr/share/info/as.info man-computil-info bfd,info @@ -1097,6 +1097,7 @@ ./usr/share/man/cat4/netintro.0 man-sys-catman .cat ./usr/share/man/cat4/netsmb.0 man-sys-catman .cat ./usr/share/man/cat4/networking.0 man-sys-catman .cat +./usr/share/man/cat4/njata.0 man-sys-catman .cat ./usr/share/man/cat4/njs.0 man-sys-catman .cat ./usr/share/man/cat4/nfe.0 man-sys-catman .cat ./usr/share/man/cat4/ns.0 man-obsolete obsolete @@ -3468,6 +3469,7 @@ ./usr/share/man/man4/netsmb.4 man-sys-man .man ./usr/share/man/man4/networking.4 man-sys-man .man ./usr/share/man/man4/nfe.4 man-sys-man .man +./usr/share/man/man4/njata.4 man-sys-man .man ./usr/share/man/man4/njs.4 man-sys-man .man ./usr/share/man/man4/ns.4 man-obsolete obsolete ./usr/share/man/man4/nsclpcsio.4 man-sys-man .man diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index d99e47d37cc9..68a54a6390f2 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.402 2006/09/02 23:39:56 wiz Exp $ +# $NetBSD: Makefile,v 1.403 2006/09/07 14:22:08 itohy Exp $ # @(#)Makefile 8.1 (Berkeley) 6/18/93 MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 adc.4 adt7467c.4 adv.4 \ @@ -26,7 +26,7 @@ MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 adc.4 adt7467c.4 adv.4 \ ksyms.4 kttcp.4 lc.4 ld.4 lkm.4 lo.4 lxtphy.4 mainbus.4 makphy.4 \ mbe.4 mca.4 mcclock.4 md.4 mfb.4 mhzc.4 midi.4 \ mii.4 mk48txx.4 mlx.4 mly.4 mpt.4 mpu.4 mtd.4 \ - mtio.4 multicast.4 ne.4 neo.4 netintro.4 nfe.4 njs.4 \ + mtio.4 multicast.4 ne.4 neo.4 netintro.4 nfe.4 njata.4 njs.4 \ nsclpcsio.4 nsphy.4 nsphyter.4 ntwoc.4 \ null.4 nsmb.4 oak.4 oosiop.4 opl.4 options.4 \ optiide.4 osiop.4 pas.4 pcdisplay.4 pciide.4 \ diff --git a/share/man/man4/njata.4 b/share/man/man4/njata.4 new file mode 100644 index 000000000000..4941e792de1d --- /dev/null +++ b/share/man/man4/njata.4 @@ -0,0 +1,97 @@ +.\" $NetBSD: njata.4,v 1.1 2006/09/07 14:22:08 itohy Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by ITOH Yasufumi. +.\" +.\" 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 NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd September 7, 2006 +.Dt NJATA 4 +.Os +.Sh NAME +.Nm njata +.Nd Workbit NinjaATA-32 CardBus IDE controller driver +.Sh SYNOPSIS +.Cd "njata* at cardbus? function ?" +.Cd "njata* at cardbus? function ? flags 1 # with wait 1" +.Sh DESCRIPTION +The +.Nm +driver provides support for the following +Workbit Bus-Master CardBus IDE controller chips: +.Pp +.Bl -tag -width "NinjaATA-32Bi" -offset indent +.It NinjaATA-32Bi +CardBus / PCMCIA dual mode IDE controller +.Pq Dq DuoATA . +This controller is mainly used for portable drives's equipment. +This driver supports the CardBus mode. +.It NPATA-32 +CardBus IDE controller. +This controller is widely used for CardBus CompactFlash adapter. +.El +.Pp +These controllers are capable of bus-mastering +for ATA PIO transfer. +The +.Nm +driver uses the bus-mastering PIO transfer +unless transfer buffer is unaligned, +and significantly reduces CPU usage for PIO-only ATA devices +compared with usual PIO transfer. +.Sh CONFIGURATION +The optional flags parameter is the +.Dq wait +value for ATA transfer. +Some combinations of host and device may fail without flags parameter or +.Tn flags 0 , +in which case try the wait value +between +.Tn flags 1 +and +.Tn flags 3 . +The smaller wait value should be faster. +Too long wait may cause DMA error. +.Sh SEE ALSO +.Xr ata 4 , +.Xr atapi 4 , +.Xr cardbus 4 , +.Xr intro 4 , +.Xr wd 4 , +.Xr wdc 4 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Nx 5.0 . +.Sh AUTHORS +.An ITOH Yasufumi Aq itohy@NetBSD.org diff --git a/sys/conf/files b/sys/conf/files index 0ab8cd3f5a86..411e57dacc60 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.809 2006/09/07 12:34:41 itohy Exp $ +# $NetBSD: files,v 1.810 2006/09/07 14:22:07 itohy Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -857,6 +857,10 @@ attach atabus at ata # The strange expression is to dump ata_* definitions to ata_dma.h. file dev/ic/wdc.c (ata_dma | ata_udma | ata_piobm | atabus) & atabus & wdc_common needs-flag +# Workbit NinjaATA-32 IDE controllers +device njata: ata, ata_piobm, wdc_common +file dev/ic/ninjaata32.c njata + # CHIPS and Technologies 82C7[12][01] Universal Peripheral Controller # device upc { [offset = -1] } diff --git a/sys/dev/DEVNAMES b/sys/dev/DEVNAMES index 24ab76108fcd..1c00aad79329 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 4a396fa9e4bd..5709163c789b 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 000000000000..26e6b23ddfdf --- /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 . + * 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 +__KERNEL_RCSID(0, "$NetBSD: njata_cardbus.c,v 1.1 2006/09/07 14:22:07 itohy Exp $"); + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#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 000000000000..17609b334d63 --- /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 . + * 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 +__KERNEL_RCSID(0, "$NetBSD: ninjaata32.c,v 1.1 2006/09/07 14:22:07 itohy Exp $"); + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#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 000000000000..0cd57887d66c --- /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 . + * 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 000000000000..a0d77609da91 --- /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 . + * 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_ */