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.
This commit is contained in:
itohy 2006-09-07 14:22:07 +00:00
parent 4f593623cc
commit cb2fb285ec
10 changed files with 1378 additions and 6 deletions

View File

@ -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

View File

@ -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 \

97
share/man/man4/njata.4 Normal file
View File

@ -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

View File

@ -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] }

View File

@ -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

View File

@ -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

View File

@ -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;
}

726
sys/dev/ic/ninjaata32.c Normal file
View File

@ -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;
}

154
sys/dev/ic/ninjaata32reg.h Normal file
View File

@ -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_ */

118
sys/dev/ic/ninjaata32var.h Normal file
View File

@ -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_ */