freebsd-nq/sys/i386/isa/bs/bshw_dma.c
KATO Takenori 8f856e3156 Synchronize with NetBSD/pc98 based on NetBSD/i386 version 1.3G patch
level 117.

Reviewed by:	Naofumi Honda <honda@Kururu.math.sci.hokudai.ac.jp>
1998-01-16 11:32:13 +00:00

343 lines
7.9 KiB
C

/* $NecBSD: bshw_dma.c,v 1.3 1997/07/26 06:03:16 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC98 series]
* Copyright (c) 1994, 1995, 1996 NetBSD/pc98 porting staff.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Copyright (c) 1994, 1995, 1996 Naofumi HONDA. All rights reserved.
*/
/*********************************************************
* static declare.
*********************************************************/
static BS_INLINE void bshw_dmastart __P((struct bs_softc *));
static void bshw_dmadone __P((struct bs_softc *));
/**********************************************
* UPPER INTERFACE FUNCS (all funcs exported)
**********************************************/
void
bshw_dmaabort(bsc, ti)
struct bs_softc *bsc;
struct targ_info *ti;
{
bshw_dmadone(bsc);
bsc->sc_p.seglen = 0;
bshw_set_count(bsc, 0);
if (ti == NULL)
{
int i;
struct targ_info *tmpti;
for (i = 0; i < NTARGETS; i++)
if ((tmpti = bsc->sc_ti[i]) != NULL)
tmpti->ti_scsp.seglen = 0;
}
else
ti->ti_scsp.seglen = 0;
}
/* DMA TRANSFER */
void
bs_dma_xfer(ti, direction)
struct targ_info *ti;
u_int direction;
{
vm_offset_t va, endva, phys, nphys;
struct bs_softc *bsc = ti->ti_bsc;
struct sc_p *sp = &bsc->sc_p;
bsc->sc_dmadir = direction;
bshw_set_dma_trans(bsc, ti->ti_cfgflags);
if (sp->seglen == 0)
{
phys = vtophys((vm_offset_t) sp->data);
if (phys >= RAM_END)
{
/* setup segaddr */
sp->segaddr = ti->bounce_phys;
/* setup seglen */
sp->seglen = sp->datalen;
if (sp->seglen > ti->bounce_size)
sp->seglen = ti->bounce_size;
/* setup bufp */
sp->bufp = ti->bounce_addr;
if (bsc->sc_dmadir != BSHW_READ)
bcopy(sp->data, sp->bufp, sp->seglen);
#ifdef BS_STATICS
bs_bounce_used[ti->ti_id]++;
#endif /* BS_STATICS */
}
else
{
/* setup segaddr */
sp->segaddr = (u_int8_t *) phys;
/* setup seglen */
endva = (vm_offset_t)round_page(sp->data + sp->datalen);
for (va = (vm_offset_t) sp->data; ; phys = nphys)
{
if ((va += BSHW_NBPG) >= endva)
{
sp->seglen = sp->datalen;
break;
}
nphys = vtophys(va);
if (phys + BSHW_NBPG != nphys || nphys >= RAM_END)
{
sp->seglen =
(u_int8_t *) trunc_page(va) - sp->data;
break;
}
}
/* setup bufp */
sp->bufp = NULL;
}
}
bshw_dmastart(bsc);
bshw_set_count(bsc, sp->seglen);
}
void
bs_dma_xfer_end(ti)
struct targ_info *ti;
{
struct bs_softc *bsc = ti->ti_bsc;
struct sc_p *sp = &bsc->sc_p;
u_int count, transbytes;
bshw_dmadone(bsc);
if (ti->ti_phase == DATAPHASE)
{
count = bshw_get_count(bsc);
if (count < (u_int) sp->seglen)
{
transbytes = sp->seglen - count;
if (sp->bufp)
{
if (bsc->sc_dmadir == BSHW_READ)
bcopy(sp->bufp, sp->data, transbytes);
sp->bufp += transbytes;
}
sp->seglen = count;
sp->segaddr += transbytes;
sp->data += transbytes;
sp->datalen -= transbytes;
return;
}
else if (count == (u_int) sp->seglen)
{
return;
}
bs_printf(ti, "xfer_end", "strange count");
printf("port data %x seglen %x\n", count, sp->seglen);
}
else
bs_printf(ti, "xfer_end", "extra dma interrupt");
ti->ti_error |= BSDMAABNORMAL;
sp->seglen = ti->ti_scsp.seglen = 0; /* XXX */
}
/**********************************************
* GENERIC DMA FUNCS
**********************************************/
static short dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
/* common dma settings */
#undef DMA1_SMSK
#define DMA1_SMSK (0x15)
#undef DMA1_MODE
#define DMA1_MODE (0x17)
#undef DMA1_FFC
#define DMA1_FFC (0x19)
#undef DMA37SM_SET
#define DMA37SM_SET 0x04
#undef DMA1_CHN
#define DMA1_CHN(c) (0x01 + ((c) << 2))
static BS_INLINE void
bshw_dmastart(bsc)
struct bs_softc *bsc;
{
int chan = bsc->sc_dmachan;
int waport;
u_int8_t *phys = bsc->sc_p.segaddr;
u_int nbytes = bsc->sc_p.seglen;
/*
* Program one of DMA channels 0..3. These are
* byte mode channels.
*/
/* set dma channel mode, and reset address ff */
#ifdef __FreeBSD__
if (need_pre_dma_flush)
wbinvd();
#else /* NetBSD/pc98 */
if (bsc->sc_dmadir & BSHW_READ)
cpu_cf_preRead(curcpu);
else
cpu_cf_preWrite(curcpu);
#endif
if (bsc->sc_dmadir & BSHW_READ)
outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_WRITE | chan);
else
outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_READ | chan);
outb(DMA1_FFC, 0);
/* send start address */
waport = DMA1_CHN(chan);
outb(waport, (u_int) phys);
outb(waport, ((u_int) phys) >> 8);
outb(dmapageport[chan], ((u_int) phys) >> 16);
/* send count */
outb(waport + 2, --nbytes);
outb(waport + 2, nbytes >> 8);
/* vendor unique hook */
if (bsc->sc_hw->dma_start)
(*bsc->sc_hw->dma_start)(bsc);
outb(DMA1_SMSK, chan);
BUS_IOW(cmd_port, CMDP_DMES);
bsc->sc_flags |= BSDMASTART;
}
static void
bshw_dmadone(bsc)
struct bs_softc *bsc;
{
outb(DMA1_SMSK, (bsc->sc_dmachan | DMA37SM_SET));
BUS_IOW(cmd_port, CMDP_DMER);
/* vendor unique hook */
if (bsc->sc_hw->dma_stop)
(*bsc->sc_hw->dma_stop)(bsc);
#ifdef __FreeBSD__
if (need_post_dma_flush)
invd();
#else
if (bsc->sc_dmadir & BSHW_READ)
cpu_cf_postRead(curcpu);
else
cpu_cf_postWrite(curcpu);
#endif
bsc->sc_flags &= (~BSDMASTART);
}
/**********************************************
* VENDOR UNIQUE DMA FUNCS
**********************************************/
static int
bshw_dma_init_texa(bsc)
struct bs_softc *bsc;
{
u_int8_t regval;
if ((regval = read_wd33c93(bsc, 0x37)) & 0x08)
return 0;
write_wd33c93(bsc, 0x37, regval | 0x08);
regval = read_wd33c93(bsc, 0x3f);
write_wd33c93(bsc, 0x3f, regval | 0x08);
return 1;
}
static int
bshw_dma_init_sc98(bsc)
struct bs_softc *bsc;
{
if (read_wd33c93(bsc, 0x37) & 0x08)
return 0;
/* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */
write_wd33c93(bsc, 0x37, 0x1a);
write_wd33c93(bsc, 0x3f, 0x1a);
#if 0
/* only valid for IO */
write_wd33c93(bsc, 0x40, 0xf4);
write_wd33c93(bsc, 0x41, 0x9);
write_wd33c93(bsc, 0x43, 0xff);
write_wd33c93(bsc, 0x46, 0x4e);
write_wd33c93(bsc, 0x48, 0xf4);
write_wd33c93(bsc, 0x49, 0x9);
write_wd33c93(bsc, 0x4b, 0xff);
write_wd33c93(bsc, 0x4e, 0x4e);
#endif
return 1;
}
static void
bshw_dma_start_sc98(bsc)
struct bs_softc *bsc;
{
write_wd33c93(bsc, 0x73, 0x32);
write_wd33c93(bsc, 0x74, 0x23);
}
static void
bshw_dma_stop_sc98(bsc)
struct bs_softc *bsc;
{
write_wd33c93(bsc, 0x73, 0x43);
write_wd33c93(bsc, 0x74, 0x34);
}
static void
bshw_dma_start_elecom(bsc)
struct bs_softc *bsc;
{
u_int8_t tmp = read_wd33c93(bsc, 0x4c);
write_wd33c93(bsc, 0x32, tmp & 0xdf);
}
static void
bshw_dma_stop_elecom(bsc)
struct bs_softc *bsc;
{
u_int8_t tmp = read_wd33c93(bsc, 0x4c);
write_wd33c93(bsc, 0x32, tmp | 0x20);
}