179697Snon/* $NecBSD: bshw_machdep.c,v 1.8.12.6 2001/06/29 06:28:05 honda Exp $ */ 2119418Sobrien 3119418Sobrien#include <sys/cdefs.h> 4119418Sobrien__FBSDID("$FreeBSD$"); 573149Snyan/* $NetBSD$ */ 673149Snyan 7139749Simp/*- 873149Snyan * [NetBSD for NEC PC-98 series] 979697Snon * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 1073149Snyan * NetBSD/pc98 porting staff. All rights reserved. 1173149Snyan * 1279697Snon * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 1373149Snyan * Naofumi HONDA. All rights reserved. 1473149Snyan * 1573149Snyan * Redistribution and use in source and binary forms, with or without 1673149Snyan * modification, are permitted provided that the following conditions 1773149Snyan * are met: 1873149Snyan * 1. Redistributions of source code must retain the above copyright 1973149Snyan * notice, this list of conditions and the following disclaimer. 2073149Snyan * 2. Redistributions in binary form must reproduce the above copyright 2173149Snyan * notice, this list of conditions and the following disclaimer in the 2273149Snyan * documentation and/or other materials provided with the distribution. 2373149Snyan * 3. The name of the author may not be used to endorse or promote products 2473149Snyan * derived from this software without specific prior written permission. 2573149Snyan * 2673149Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2773149Snyan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2873149Snyan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2973149Snyan * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 3073149Snyan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3173149Snyan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3273149Snyan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3373149Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3473149Snyan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 3573149Snyan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3673149Snyan * POSSIBILITY OF SUCH DAMAGE. 3773149Snyan */ 3873149Snyan 3973149Snyan#include "opt_ddb.h" 4073149Snyan 4173149Snyan#include <sys/param.h> 4273149Snyan#include <sys/systm.h> 4373149Snyan#include <sys/kernel.h> 4473149Snyan#include <sys/bio.h> 4573149Snyan#include <sys/buf.h> 4673149Snyan#include <sys/queue.h> 4773149Snyan#include <sys/malloc.h> 4873149Snyan#include <sys/errno.h> 4973149Snyan 5073149Snyan#include <vm/vm.h> 5173149Snyan 5273149Snyan#include <machine/bus.h> 5373149Snyan#include <machine/md_var.h> 5473149Snyan 55126928Speter#include <compat/netbsd/dvcfg.h> 5673149Snyan 5773149Snyan#include <cam/scsi/scsi_low.h> 5873149Snyan 5978209Snyan#include <dev/ic/wd33c93reg.h> 6073149Snyan#include <dev/ct/ctvar.h> 6179697Snon#include <dev/ct/ct_machdep.h> 6273149Snyan#include <dev/ct/bshwvar.h> 6379697Snon 6479697Snon#include <vm/pmap.h> 6573149Snyan 6679697Snon#define BSHW_IO_CONTROL_FLAGS 0 6779697Snon 6879697Snonu_int bshw_io_control = BSHW_IO_CONTROL_FLAGS; 6979697Snonint bshw_data_read_bytes = 4096; 7079697Snonint bshw_data_write_bytes = 4096; 7179697Snon 7273149Snyan/********************************************************* 7379697Snon * OS dep part 7479697Snon *********************************************************/ 7579697Snontypedef unsigned long vaddr_t; 7679697Snon 7779697Snon/********************************************************* 7873149Snyan * GENERIC MACHDEP FUNCTIONS 7973149Snyan *********************************************************/ 8073149Snyanvoid 81242871Snyanbshw_synch_setup(struct ct_softc *ct, struct targ_info *ti) 8273149Snyan{ 8379697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 8473149Snyan struct ct_targ_info *cti = (void *) ti; 8573149Snyan struct bshw_softc *bs = ct->ct_hw; 8673149Snyan struct bshw *hw = bs->sc_hw; 8773149Snyan 8879697Snon if (hw->hw_sregaddr == 0) 8973149Snyan return; 9073149Snyan 9179697Snon ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id, cti->cti_syncreg); 9273149Snyan if (hw->hw_flags & BSHW_DOUBLE_DMACHAN) 9373149Snyan { 9479697Snon ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id + 8, 9573149Snyan cti->cti_syncreg); 9673149Snyan } 9773149Snyan} 9873149Snyan 9973149Snyanvoid 100242871Snyanbshw_bus_reset(struct ct_softc *ct) 10173149Snyan{ 10273149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 10379697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 10473149Snyan struct bshw_softc *bs = ct->ct_hw; 10573149Snyan struct bshw *hw = bs->sc_hw; 10673149Snyan bus_addr_t offs; 10773149Snyan u_int8_t regv; 10873149Snyan int i; 10973149Snyan 11073149Snyan /* open hardware busmaster mode */ 11179697Snon if (hw->hw_dma_init != NULL && ((*hw->hw_dma_init)(ct)) != 0) 11273149Snyan { 113240325Sjhb device_printf(slp->sl_dev, 114240325Sjhb "change mode using external DMA (%x)\n", 115240325Sjhb (u_int)ct_cr_read_1(chp, 0x37)); 11673149Snyan } 11773149Snyan 11873149Snyan /* clear hardware synch registers */ 11979697Snon offs = hw->hw_sregaddr; 12073149Snyan if (offs != 0) 12173149Snyan { 12273149Snyan for (i = 0; i < 8; i ++, offs ++) 12373149Snyan { 12479697Snon ct_cr_write_1(chp, offs, 0); 12573149Snyan if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0) 12679697Snon ct_cr_write_1(chp, offs + 8, 0); 12773149Snyan } 12873149Snyan } 12973149Snyan 13073149Snyan /* disable interrupt & assert reset */ 13179697Snon regv = ct_cr_read_1(chp, wd3s_mbank); 13273149Snyan regv |= MBR_RST; 13373149Snyan regv &= ~MBR_IEN; 13479697Snon ct_cr_write_1(chp, wd3s_mbank, regv); 13573149Snyan 136240172Sjhb DELAY(500000); 13773149Snyan 13873149Snyan /* reset signal off */ 13973149Snyan regv &= ~MBR_RST; 14079697Snon ct_cr_write_1(chp, wd3s_mbank, regv); 14173149Snyan 14273149Snyan /* interrupt enable */ 14373149Snyan regv |= MBR_IEN; 14479697Snon ct_cr_write_1(chp, wd3s_mbank, regv); 14573149Snyan} 14673149Snyan 14773149Snyan/* probe */ 14873149Snyanint 149242871Snyanbshw_read_settings(struct ct_bus_access_handle *chp, struct bshw_softc *bs) 15073149Snyan{ 15173149Snyan static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 }; 15273149Snyan 15379697Snon bs->sc_hostid = (ct_cr_read_1(chp, wd3s_auxc) & AUXCR_HIDM); 15479697Snon bs->sc_irq = irq_tbl[(ct_cr_read_1(chp, wd3s_auxc) >> 3) & 7]; 15579697Snon bs->sc_drq = ct_cmdp_read_1(chp) & 3; 15673149Snyan return 0; 15773149Snyan} 15873149Snyan 15973149Snyan/********************************************************* 16073149Snyan * DMA PIO TRANSFER (SMIT) 16173149Snyan *********************************************************/ 16273149Snyan#define LC_SMIT_TIMEOUT 2 /* 2 sec: timeout for a fifo status ready */ 16373149Snyan#define LC_SMIT_OFFSET 0x1000 16473149Snyan#define LC_FSZ DEV_BSIZE 16573149Snyan#define LC_SFSZ 0x0c 16673149Snyan#define LC_REST (LC_FSZ - LC_SFSZ) 16773149Snyan 16873149Snyan#define BSHW_LC_FSET 0x36 16973149Snyan#define BSHW_LC_FCTRL 0x44 17073149Snyan#define FCTRL_EN 0x01 17173149Snyan#define FCTRL_WRITE 0x02 17273149Snyan 17373149Snyan#define SF_ABORT 0x08 17473149Snyan#define SF_RDY 0x10 17573149Snyan 17692739Salfredstatic __inline void bshw_lc_smit_start(struct ct_softc *, int, u_int); 17792739Salfredstatic __inline void bshw_lc_smit_stop(struct ct_softc *); 17892739Salfredstatic int bshw_lc_smit_fstat(struct ct_softc *, int, int); 17973149Snyan 18073149Snyanstatic __inline void 181242871Snyanbshw_lc_smit_stop(struct ct_softc *ct) 18273149Snyan{ 18379697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 18473149Snyan 18579697Snon ct_cr_write_1(chp, BSHW_LC_FCTRL, 0); 18679697Snon ct_cmdp_write_1(chp, CMDP_DMER); 18773149Snyan} 18873149Snyan 18973149Snyanstatic __inline void 190242871Snyanbshw_lc_smit_start(struct ct_softc *ct, int count, u_int direction) 19173149Snyan{ 19279697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 19373149Snyan u_int8_t pval, val; 19473149Snyan 19579697Snon val = ct_cr_read_1(chp, BSHW_LC_FSET); 19679697Snon cthw_set_count(chp, count); 19773149Snyan 19873149Snyan pval = FCTRL_EN; 19973149Snyan if (direction == SCSI_LOW_WRITE) 20073149Snyan pval |= (val & 0xe0) | FCTRL_WRITE; 20179697Snon ct_cr_write_1(chp, BSHW_LC_FCTRL, pval); 20279697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO); 20373149Snyan} 20473149Snyan 20573149Snyanstatic int 206242871Snyanbshw_lc_smit_fstat(struct ct_softc *ct, int wc, int read) 20773149Snyan{ 20879697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 20973149Snyan u_int8_t stat; 21073149Snyan 21173149Snyan while (wc -- > 0) 21273149Snyan { 21379697Snon chp->ch_bus_weight(chp); 21479697Snon stat = ct_cmdp_read_1(chp); 21573149Snyan if (read == SCSI_LOW_READ) 21673149Snyan { 21773149Snyan if ((stat & SF_RDY) != 0) 21873149Snyan return 0; 21973149Snyan if ((stat & SF_ABORT) != 0) 22073149Snyan return EIO; 22173149Snyan } 22273149Snyan else 22373149Snyan { 22473149Snyan if ((stat & SF_ABORT) != 0) 22573149Snyan return EIO; 22673149Snyan if ((stat & SF_RDY) != 0) 22773149Snyan return 0; 22873149Snyan } 22973149Snyan } 23073149Snyan 231240325Sjhb device_printf(ct->sc_sclow.sl_dev, "SMIT fifo status timeout\n"); 23273149Snyan return EIO; 23373149Snyan} 23473149Snyan 23573149Snyanvoid 236242871Snyanbshw_smit_xfer_stop(struct ct_softc *ct) 23773149Snyan{ 23873149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 23973149Snyan struct bshw_softc *bs = ct->ct_hw; 24073149Snyan struct targ_info *ti; 24173149Snyan struct sc_p *sp = &slp->sl_scp; 24273149Snyan u_int count; 24373149Snyan 24473149Snyan bshw_lc_smit_stop(ct); 24573149Snyan 24679697Snon ti = slp->sl_Tnexus; 24773149Snyan if (ti == NULL) 24873149Snyan return; 24973149Snyan 25073149Snyan if (ti->ti_phase == PH_DATA) 25173149Snyan { 25279697Snon count = cthw_get_count(&ct->sc_ch); 25379697Snon if (count < bs->sc_sdatalen) 25473149Snyan { 25573149Snyan if (sp->scp_direction == SCSI_LOW_READ && 25679697Snon count != bs->sc_edatalen) 25773149Snyan goto bad; 25879697Snon 25979697Snon count = bs->sc_sdatalen - count; 26079697Snon if (count > (u_int) sp->scp_datalen) 26179697Snon goto bad; 26279697Snon 26379697Snon sp->scp_data += count; 26479697Snon sp->scp_datalen -= count; 26573149Snyan } 26679697Snon else if (count > bs->sc_sdatalen) 26773149Snyan { 26879697Snonbad: 269240325Sjhb device_printf(slp->sl_dev, 270240325Sjhb "smit_xfer_end: cnt error\n"); 27179697Snon slp->sl_error |= PDMAERR; 27273149Snyan } 27379697Snon scsi_low_data_finish(slp); 27473149Snyan } 27573149Snyan else 27679697Snon { 277240325Sjhb device_printf(slp->sl_dev, "smit_xfer_end: phase miss\n"); 27879697Snon slp->sl_error |= PDMAERR; 27979697Snon } 28073149Snyan} 28173149Snyan 28279697Snonint 283242871Snyanbshw_smit_xfer_start(struct ct_softc *ct) 28473149Snyan{ 28573149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 28679697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 28773149Snyan struct bshw_softc *bs = ct->ct_hw; 28873149Snyan struct sc_p *sp = &slp->sl_scp; 28979697Snon struct targ_info *ti = slp->sl_Tnexus; 29073149Snyan struct ct_targ_info *cti = (void *) ti; 29179697Snon u_int datalen, count, io_control; 29279697Snon int wc; 29373149Snyan u_int8_t *data; 29473149Snyan 29579697Snon io_control = bs->sc_io_control | bshw_io_control; 29679697Snon if ((io_control & BSHW_SMIT_BLOCK) != 0) 29779697Snon return EINVAL; 29879697Snon 29979697Snon if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0) 30079697Snon return EINVAL; 30179697Snon 30273149Snyan datalen = sp->scp_datalen; 30379697Snon if (slp->sl_scp.scp_direction == SCSI_LOW_READ) 30479697Snon { 30579697Snon if ((io_control & BSHW_READ_INTERRUPT_DRIVEN) != 0 && 30679697Snon datalen > bshw_data_read_bytes) 30779697Snon datalen = bshw_data_read_bytes; 30879697Snon } 30979697Snon else 31079697Snon { 31179697Snon if ((io_control & BSHW_WRITE_INTERRUPT_DRIVEN) != 0 && 31279697Snon datalen > bshw_data_write_bytes) 31379697Snon datalen = bshw_data_write_bytes; 31479697Snon } 31573149Snyan 31679697Snon bs->sc_sdatalen = datalen; 31779697Snon data = sp->scp_data; 31879697Snon wc = LC_SMIT_TIMEOUT * 1024 * 1024; 31973149Snyan 32079697Snon ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA); 32179697Snon bshw_lc_smit_start(ct, datalen, sp->scp_direction); 32279697Snon 32373149Snyan if (sp->scp_direction == SCSI_LOW_READ) 32473149Snyan { 32573149Snyan do 32673149Snyan { 32773149Snyan if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_READ)) 32873149Snyan break; 32973149Snyan 33073149Snyan count = (datalen > LC_FSZ ? LC_FSZ : datalen); 33179697Snon bus_space_read_region_4(chp->ch_memt, chp->ch_memh, 33273149Snyan LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2); 33373149Snyan data += count; 33473149Snyan datalen -= count; 33573149Snyan } 33673149Snyan while (datalen > 0); 33773149Snyan 33879697Snon bs->sc_edatalen = datalen; 33973149Snyan } 34073149Snyan else 34173149Snyan { 34273149Snyan do 34373149Snyan { 34473149Snyan if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) 34573149Snyan break; 34673149Snyan if (cti->cti_syncreg == 0) 34773149Snyan { 34873149Snyan /* XXX: 34973149Snyan * If async transfer, reconfirm a scsi phase 35073149Snyan * again. Unless C bus might hang up. 35173149Snyan */ 35273149Snyan if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) 35373149Snyan break; 35473149Snyan } 35573149Snyan 35673149Snyan count = (datalen > LC_SFSZ ? LC_SFSZ : datalen); 35779697Snon bus_space_write_region_4(chp->ch_memt, chp->ch_memh, 35873149Snyan LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2); 35973149Snyan data += count; 36073149Snyan datalen -= count; 36173149Snyan 36273149Snyan if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) 36373149Snyan break; 36473149Snyan 36573149Snyan count = (datalen > LC_REST ? LC_REST : datalen); 36679697Snon bus_space_write_region_4(chp->ch_memt, chp->ch_memh, 36773149Snyan LC_SMIT_OFFSET + LC_SFSZ, 36873149Snyan (u_int32_t *) data, count >> 2); 36973149Snyan data += count; 37073149Snyan datalen -= count; 37173149Snyan } 37273149Snyan while (datalen > 0); 37373149Snyan } 37479697Snon return 0; 37573149Snyan} 37673149Snyan 37773149Snyan/********************************************************* 37873149Snyan * DMA TRANSFER (BS) 37973149Snyan *********************************************************/ 38079697Snonstatic __inline void bshw_dma_write_1 \ 38192739Salfred (struct ct_bus_access_handle *, bus_addr_t, u_int8_t); 38292739Salfredstatic void bshw_dmastart(struct ct_softc *); 38392739Salfredstatic void bshw_dmadone(struct ct_softc *); 38473149Snyan 38579697Snonint 386242871Snyanbshw_dma_xfer_start(struct ct_softc *ct) 38773149Snyan{ 38873149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 38973149Snyan struct sc_p *sp = &slp->sl_scp; 39079697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 39173149Snyan struct bshw_softc *bs = ct->ct_hw; 39273149Snyan vaddr_t va, endva, phys, nphys; 39379697Snon u_int io_control; 39473149Snyan 39579697Snon io_control = bs->sc_io_control | bshw_io_control; 39679697Snon if ((io_control & BSHW_DMA_BLOCK) != 0 && sp->scp_datalen < 256) 39779697Snon return EINVAL; 39879697Snon 39979697Snon ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA); 40073149Snyan phys = vtophys((vaddr_t) sp->scp_data); 40173149Snyan if (phys >= bs->sc_minphys) 40273149Snyan { 40373149Snyan /* setup segaddr */ 40473149Snyan bs->sc_segaddr = bs->sc_bounce_phys; 40573149Snyan /* setup seglen */ 40673149Snyan bs->sc_seglen = sp->scp_datalen; 40773149Snyan if (bs->sc_seglen > bs->sc_bounce_size) 40873149Snyan bs->sc_seglen = bs->sc_bounce_size; 40973149Snyan /* setup bufp */ 41073149Snyan bs->sc_bufp = bs->sc_bounce_addr; 41173149Snyan if (sp->scp_direction == SCSI_LOW_WRITE) 41273149Snyan bcopy(sp->scp_data, bs->sc_bufp, bs->sc_seglen); 41373149Snyan } 41473149Snyan else 41573149Snyan { 41673149Snyan /* setup segaddr */ 41773149Snyan bs->sc_segaddr = (u_int8_t *) phys; 41873149Snyan /* setup seglen */ 41979697Snon endva = (vaddr_t) round_page((vaddr_t) sp->scp_data + sp->scp_datalen); 42073149Snyan for (va = (vaddr_t) sp->scp_data; ; phys = nphys) 42173149Snyan { 422240172Sjhb if ((va += PAGE_SIZE) >= endva) 42373149Snyan { 42473149Snyan bs->sc_seglen = sp->scp_datalen; 42573149Snyan break; 42673149Snyan } 42773149Snyan 42873149Snyan nphys = vtophys(va); 429240172Sjhb if (phys + PAGE_SIZE != nphys || nphys >= bs->sc_minphys) 43073149Snyan { 43173149Snyan bs->sc_seglen = 43273149Snyan (u_int8_t *) trunc_page(va) - sp->scp_data; 43373149Snyan break; 43473149Snyan } 43573149Snyan } 43673149Snyan /* setup bufp */ 43773149Snyan bs->sc_bufp = NULL; 43873149Snyan } 43973149Snyan 44073149Snyan bshw_dmastart(ct); 44179697Snon cthw_set_count(chp, bs->sc_seglen); 44279697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO); 44379697Snon return 0; 44473149Snyan} 44573149Snyan 44673149Snyanvoid 447242871Snyanbshw_dma_xfer_stop(struct ct_softc *ct) 44873149Snyan{ 44973149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 45073149Snyan struct sc_p *sp = &slp->sl_scp; 45173149Snyan struct bshw_softc *bs = ct->ct_hw; 45273149Snyan struct targ_info *ti; 45373149Snyan u_int count, transbytes; 45473149Snyan 45573149Snyan bshw_dmadone(ct); 45673149Snyan 45779697Snon ti = slp->sl_Tnexus; 45873149Snyan if (ti == NULL) 45973149Snyan return; 46073149Snyan 46173149Snyan if (ti->ti_phase == PH_DATA) 46273149Snyan { 46379697Snon count = cthw_get_count(&ct->sc_ch); 46473149Snyan if (count < (u_int) bs->sc_seglen) 46573149Snyan { 46673149Snyan transbytes = bs->sc_seglen - count; 46773149Snyan if (bs->sc_bufp != NULL && 46873149Snyan sp->scp_direction == SCSI_LOW_READ) 46973149Snyan bcopy(bs->sc_bufp, sp->scp_data, transbytes); 47073149Snyan 47173149Snyan sp->scp_data += transbytes; 47273149Snyan sp->scp_datalen -= transbytes; 47373149Snyan } 47479697Snon else if (count > (u_int) bs->sc_seglen) 47573149Snyan { 476240325Sjhb device_printf(slp->sl_dev, 477240325Sjhb "port data %x != seglen %x\n", 478240325Sjhb count, bs->sc_seglen); 47979697Snon slp->sl_error |= PDMAERR; 48073149Snyan } 48173149Snyan 48279697Snon scsi_low_data_finish(slp); 48373149Snyan } 48473149Snyan else 48573149Snyan { 486240325Sjhb device_printf(slp->sl_dev, "extra DMA interrupt\n"); 48779697Snon slp->sl_error |= PDMAERR; 48873149Snyan } 48973149Snyan 49073149Snyan bs->sc_bufp = NULL; 49173149Snyan} 49273149Snyan 49373149Snyan/* common dma settings */ 49473149Snyan#undef DMA1_SMSK 49573149Snyan#define DMA1_SMSK (0x15) 49673149Snyan#undef DMA1_MODE 49773149Snyan#define DMA1_MODE (0x17) 49873149Snyan#undef DMA1_FFC 49973149Snyan#define DMA1_FFC (0x19) 50073149Snyan#undef DMA1_CHN 50173149Snyan#define DMA1_CHN(c) (0x01 + ((c) << 2)) 50273149Snyan 50373149Snyan#define DMA37SM_SET 0x04 50473149Snyan#define DMA37MD_WRITE 0x04 50573149Snyan#define DMA37MD_READ 0x08 50673149Snyan#define DMA37MD_SINGLE 0x40 50773149Snyan 50879697Snonstatic bus_addr_t dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 }; 50979697Snon 51079697Snonstatic __inline void 511242871Snyanbshw_dma_write_1(struct ct_bus_access_handle *chp, bus_addr_t port, 512242871Snyan u_int8_t val) 51379697Snon{ 51479697Snon 51579697Snon CT_BUS_WEIGHT(chp); 51679697Snon outb(port, val); 51779697Snon} 51879697Snon 51973149Snyanstatic void 520242871Snyanbshw_dmastart(struct ct_softc *ct) 52173149Snyan{ 52273149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 52373149Snyan struct bshw_softc *bs = ct->ct_hw; 52479697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 52573149Snyan int chan = bs->sc_drq; 52679697Snon bus_addr_t waport; 52779697Snon u_int8_t regv, *phys = bs->sc_segaddr; 52873149Snyan u_int nbytes = bs->sc_seglen; 52973149Snyan 53079697Snon /* flush cpu cache */ 53179697Snon (*bs->sc_dmasync_before) (ct); 53279697Snon 53373149Snyan /* 53473149Snyan * Program one of DMA channels 0..3. These are 53573149Snyan * byte mode channels. 53673149Snyan */ 53773149Snyan /* set dma channel mode, and reset address ff */ 53873149Snyan 53973149Snyan if (slp->sl_scp.scp_direction == SCSI_LOW_READ) 54079697Snon regv = DMA37MD_WRITE | DMA37MD_SINGLE | chan; 54173149Snyan else 54279697Snon regv = DMA37MD_READ | DMA37MD_SINGLE | chan; 54373149Snyan 54479697Snon bshw_dma_write_1(chp, DMA1_MODE, regv); 54579697Snon bshw_dma_write_1(chp, DMA1_FFC, 0); 54679697Snon 54773149Snyan /* send start address */ 54873149Snyan waport = DMA1_CHN(chan); 54979697Snon bshw_dma_write_1(chp, waport, (u_int) phys); 55079697Snon bshw_dma_write_1(chp, waport, ((u_int) phys) >> 8); 55179697Snon bshw_dma_write_1(chp, dmapageport[chan], ((u_int) phys) >> 16); 55273149Snyan 55373149Snyan /* send count */ 55479697Snon bshw_dma_write_1(chp, waport + 2, --nbytes); 55579697Snon bshw_dma_write_1(chp, waport + 2, nbytes >> 8); 55673149Snyan 55773149Snyan /* vendor unique hook */ 55879697Snon if (bs->sc_hw->hw_dma_start) 55979697Snon (*bs->sc_hw->hw_dma_start)(ct); 56073149Snyan 56179697Snon bshw_dma_write_1(chp, DMA1_SMSK, chan); 56279697Snon ct_cmdp_write_1(chp, CMDP_DMES); 56373149Snyan} 56473149Snyan 56573149Snyanstatic void 566242871Snyanbshw_dmadone(struct ct_softc *ct) 56773149Snyan{ 56873149Snyan struct bshw_softc *bs = ct->ct_hw; 56979697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 57073149Snyan 57179697Snon bshw_dma_write_1(chp, DMA1_SMSK, (bs->sc_drq | DMA37SM_SET)); 57279697Snon ct_cmdp_write_1(chp, CMDP_DMER); 57373149Snyan 57473149Snyan /* vendor unique hook */ 57579697Snon if (bs->sc_hw->hw_dma_stop) 57679697Snon (*bs->sc_hw->hw_dma_stop) (ct); 57773149Snyan 57879697Snon /* flush cpu cache */ 57979697Snon (*bs->sc_dmasync_after) (ct); 58073149Snyan} 58173149Snyan 58273149Snyan/********************************************** 58373149Snyan * VENDOR UNIQUE DMA FUNCS 58473149Snyan **********************************************/ 58592739Salfredstatic int bshw_dma_init_sc98(struct ct_softc *); 58692739Salfredstatic void bshw_dma_start_sc98(struct ct_softc *); 58792739Salfredstatic void bshw_dma_stop_sc98(struct ct_softc *); 58892739Salfredstatic int bshw_dma_init_texa(struct ct_softc *); 58992739Salfredstatic void bshw_dma_start_elecom(struct ct_softc *); 59092739Salfredstatic void bshw_dma_stop_elecom(struct ct_softc *); 59173149Snyan 59273149Snyanstatic int 593242871Snyanbshw_dma_init_texa(struct ct_softc *ct) 59473149Snyan{ 59579697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 59673149Snyan u_int8_t regval; 59773149Snyan 59879697Snon if ((regval = ct_cr_read_1(chp, 0x37)) & 0x08) 59973149Snyan return 0; 60073149Snyan 60179697Snon ct_cr_write_1(chp, 0x37, regval | 0x08); 60279697Snon regval = ct_cr_read_1(chp, 0x3f); 60379697Snon ct_cr_write_1(chp, 0x3f, regval | 0x08); 60473149Snyan return 1; 60573149Snyan} 60673149Snyan 60773149Snyanstatic int 608242871Snyanbshw_dma_init_sc98(struct ct_softc *ct) 60973149Snyan{ 61079697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 61173149Snyan 61279697Snon if (ct_cr_read_1(chp, 0x37) & 0x08) 61373149Snyan return 0; 61473149Snyan 61573149Snyan /* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */ 61679697Snon ct_cr_write_1(chp, 0x37, 0x1a); 61779697Snon ct_cr_write_1(chp, 0x3f, 0x1a); 61873149Snyan#if 0 61973149Snyan /* only valid for IO */ 62079697Snon ct_cr_write_1(chp, 0x40, 0xf4); 62179697Snon ct_cr_write_1(chp, 0x41, 0x9); 62279697Snon ct_cr_write_1(chp, 0x43, 0xff); 62379697Snon ct_cr_write_1(chp, 0x46, 0x4e); 62473149Snyan 62579697Snon ct_cr_write_1(chp, 0x48, 0xf4); 62679697Snon ct_cr_write_1(chp, 0x49, 0x9); 62779697Snon ct_cr_write_1(chp, 0x4b, 0xff); 62879697Snon ct_cr_write_1(chp, 0x4e, 0x4e); 62973149Snyan#endif 63073149Snyan return 1; 63173149Snyan} 63273149Snyan 63373149Snyanstatic void 634242871Snyanbshw_dma_start_sc98(struct ct_softc *ct) 63573149Snyan{ 63679697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 63773149Snyan 63879697Snon ct_cr_write_1(chp, 0x73, 0x32); 63979697Snon ct_cr_write_1(chp, 0x74, 0x23); 64073149Snyan} 64173149Snyan 64273149Snyanstatic void 643242871Snyanbshw_dma_stop_sc98(struct ct_softc *ct) 64473149Snyan{ 64579697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 64673149Snyan 64779697Snon ct_cr_write_1(chp, 0x73, 0x43); 64879697Snon ct_cr_write_1(chp, 0x74, 0x34); 64973149Snyan} 65073149Snyan 65173149Snyanstatic void 652242871Snyanbshw_dma_start_elecom(struct ct_softc *ct) 65373149Snyan{ 65479697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 65579697Snon u_int8_t tmp = ct_cr_read_1(chp, 0x4c); 65673149Snyan 65779697Snon ct_cr_write_1(chp, 0x32, tmp & 0xdf); 65873149Snyan} 65973149Snyan 66073149Snyanstatic void 661242871Snyanbshw_dma_stop_elecom(struct ct_softc *ct) 66273149Snyan{ 66379697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 66479697Snon u_int8_t tmp = ct_cr_read_1(chp, 0x4c); 66573149Snyan 66679697Snon ct_cr_write_1(chp, 0x32, tmp | 0x20); 66773149Snyan} 66873149Snyan 66973149Snyanstatic struct bshw bshw_generic = { 67073149Snyan BSHW_SYNC_RELOAD, 67173149Snyan 67273149Snyan 0, 67373149Snyan 67473149Snyan NULL, 67573149Snyan NULL, 67673149Snyan NULL, 67773149Snyan}; 67873149Snyan 67973149Snyanstatic struct bshw bshw_sc98 = { 68073149Snyan BSHW_DOUBLE_DMACHAN, 68173149Snyan 68273149Snyan 0x60, 68373149Snyan 68473149Snyan bshw_dma_init_sc98, 68573149Snyan bshw_dma_start_sc98, 68673149Snyan bshw_dma_stop_sc98, 68773149Snyan}; 68873149Snyan 68973149Snyanstatic struct bshw bshw_texa = { 69073149Snyan BSHW_DOUBLE_DMACHAN, 69173149Snyan 69273149Snyan 0x60, 69373149Snyan 69473149Snyan bshw_dma_init_texa, 69573149Snyan NULL, 69673149Snyan NULL, 69773149Snyan}; 69873149Snyan 69973149Snyanstatic struct bshw bshw_elecom = { 70073149Snyan 0, 70173149Snyan 70273149Snyan 0x38, 70373149Snyan 70473149Snyan NULL, 70573149Snyan bshw_dma_start_elecom, 70673149Snyan bshw_dma_stop_elecom, 70773149Snyan}; 70873149Snyan 70973149Snyanstatic struct bshw bshw_lc_smit = { 71073149Snyan BSHW_SMFIFO | BSHW_DOUBLE_DMACHAN, 71173149Snyan 71273149Snyan 0x60, 71373149Snyan 71473149Snyan NULL, 71573149Snyan NULL, 71673149Snyan NULL, 71773149Snyan}; 71873149Snyan 71973149Snyanstatic struct bshw bshw_lha20X = { 72073149Snyan BSHW_DOUBLE_DMACHAN, 72173149Snyan 72273149Snyan 0x60, 72373149Snyan 72473149Snyan NULL, 72573149Snyan NULL, 72673149Snyan NULL, 72773149Snyan}; 72873149Snyan 72973149Snyan/* hw tabs */ 73073149Snyanstatic dvcfg_hw_t bshw_hwsel_array[] = { 73173149Snyan/* 0x00 */ &bshw_generic, 73273149Snyan/* 0x01 */ &bshw_sc98, 73373149Snyan/* 0x02 */ &bshw_texa, 73473149Snyan/* 0x03 */ &bshw_elecom, 73573149Snyan/* 0x04 */ &bshw_lc_smit, 73673149Snyan/* 0x05 */ &bshw_lha20X, 73773149Snyan}; 73873149Snyan 73973149Snyanstruct dvcfg_hwsel bshw_hwsel = { 74073149Snyan DVCFG_HWSEL_SZ(bshw_hwsel_array), 74173149Snyan bshw_hwsel_array 74273149Snyan}; 743