/* $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); }