static int hcsc_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen, uint8_t *data) { struct hcsc_softc *sc = (struct hcsc_softc *)ncr_sc; bus_space_tag_t pdmat = sc->sc_pdmat; bus_space_handle_t pdmah = sc->sc_pdmah; int s, resid, len; s = splbio(); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_irecv, 0); resid = datalen; while (resid > 0) { len = min(resid, HCSC_TSIZE_IN); if (hcsc_ready(ncr_sc) == 0) goto interrupt; bus_space_read_multi_1(pdmat, pdmah, 0, data, len); data += len; resid -= len; } hcsc_wait_not_req(ncr_sc); interrupt: SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); splx(s); return datalen - resid; }
/* Return zero on success. */ static __inline void oak_wait_not_req(struct ncr5380_softc *sc) { int timo; for (timo = TIMEOUT; timo; timo--) { if ((NCR5380_READ(sc, sci_bus_csr) & SCI_BUS_REQ) == 0 || (NCR5380_READ(sc, sci_csr) & SCI_CSR_PHASE_MATCH) == 0 || SCI_BUSY(sc) == 0) { return; } } printf("%s: pdma not_req timeout\n", sc->sc_dev.dv_xname); }
static inline int hcsc_ready(struct ncr5380_softc *sc) { int i; for (i = TIMEOUT; i > 0; i--) { if ((NCR5380_READ(sc,sci_csr) & (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) == (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) return 1; if ((NCR5380_READ(sc, sci_csr) & SCI_CSR_PHASE_MATCH) == 0 || SCI_BUSY(sc) == 0) return 0; } printf("%s: ready timeout\n", device_xname(sc->sc_dev)); return 0; }
static int oak_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen, u_char *data) { struct oak_softc *sc = (void *)ncr_sc; bus_space_tag_t pdmat = sc->sc_pdmat; bus_space_handle_t pdmah = sc->sc_pdmah; int s, resid, len; s = splbio(); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_irecv, 0); resid = datalen; while (resid > 0) { len = min(resid, OAK_TSIZE_IN); if (oak_ready(ncr_sc) == 0) goto interrupt; KASSERT(BUS_SPACE_ALIGNED_POINTER(data, u_int16_t)); bus_space_read_multi_2(pdmat, pdmah, OAK_PDMA_READ, (u_int16_t *)data, len/2); data += len; resid -= len; } oak_wait_not_req(ncr_sc); interrupt: SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); splx(s); return datalen - resid; }
static __inline int oak_ready(struct ncr5380_softc *sc) { int i; int status; for (i = TIMEOUT; i > 0; i--) { status = NCR5380_READ(sc, sci_csr); if ((status & (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) == (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) return(1); if ((status & SCI_CSR_PHASE_MATCH) == 0 || SCI_BUSY(sc) == 0) return(0); } printf("%s: ready timeout\n", sc->sc_dev.dv_xname); return(0); #if 0 /* The Linux driver does this: */ struct oak_softc *sc = (void *)ncr_sc; bus_space_tag_t pdmat = sc->sc_pdmat; bus_space_handle_t pdmah = sc->sc_pdmah; int i, status; for (i = TIMEOUT; i > 0; i--) { status = bus_space_read_2(pdmat, pdmah, OAK_PDMA_STATUS); if (status & 0x200) return(0); if (status & 0x100) return(1); } printf("%s: ready timeout, status = 0x%x\n", ncr_sc->sc_dev.dv_xname, status); return(0); #endif }
static int hcsc_pdma_out(struct ncr5380_softc *ncr_sc, int phase, int datalen, uint8_t *data) { struct hcsc_softc *sc = (struct hcsc_softc *)ncr_sc; bus_space_tag_t pdmat = sc->sc_pdmat; bus_space_handle_t pdmah = sc->sc_pdmah; int i, s, icmd, resid; s = splbio(); icmd = NCR5380_READ(ncr_sc, sci_icmd) & SCI_ICMD_RMASK; NCR5380_WRITE(ncr_sc, sci_icmd, icmd | SCI_ICMD_DATA); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_dma_send, 0); resid = datalen; if (hcsc_ready(ncr_sc) == 0) goto interrupt; if (resid > HCSC_TSIZE_OUT) { /* * Because of the chips DMA prefetch, phase changes * etc, won't be detected until we have written at * least one byte more. We pre-write 4 bytes so * subsequent transfers will be aligned to a 4 byte * boundary. Assuming disconects will only occur on * block boundaries, we then correct for the pre-write * when and if we get a phase change. If the chip had * DMA byte counting hardware, the assumption would not * be necessary. */ bus_space_write_multi_1(pdmat, pdmah, 0, data, 4); data += 4; resid -= 4; for (; resid >= HCSC_TSIZE_OUT; resid -= HCSC_TSIZE_OUT) { if (hcsc_ready(ncr_sc) == 0) { resid += 4; /* Overshot */ goto interrupt; } bus_space_write_multi_1(pdmat, pdmah, 0, data, HCSC_TSIZE_OUT); data += HCSC_TSIZE_OUT; } if (hcsc_ready(ncr_sc) == 0) { resid += 4; /* Overshot */ goto interrupt; } } if (resid) { bus_space_write_multi_1(pdmat, pdmah, 0, data, resid); resid = 0; } for (i = TIMEOUT; i > 0; i--) { if ((NCR5380_READ(ncr_sc, sci_csr) & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) != SCI_CSR_DREQ) break; } if (i != 0) bus_space_write_1(pdmat, pdmah, 0, 0); else printf("%s: timeout waiting for final SCI_DSR_DREQ.\n", device_xname(ncr_sc->sc_dev)); hcsc_wait_not_req(ncr_sc); interrupt: SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_icmd, icmd); splx(s); return datalen - resid; }
void sw_dma_start(struct ncr5380_softc *ncr_sc) { struct sw_softc *sc = (struct sw_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct sw_dma_handle *dh = sr->sr_dma_hand; u_long dva; int xlen, adj, adjlen; u_int mode; uint32_t csr; /* * Get the DVMA mapping for this segment. */ dva = (u_long)(dh->dh_dvma); if (dva & 1) panic("%s: bad dva=0x%lx", __func__, dva); xlen = ncr_sc->sc_datalen; xlen &= ~1; sc->sc_xlen = xlen; /* XXX: or less... */ #ifdef DEBUG if (sw_debug & 2) { printf("%s: dh=%p, dva=0x%lx, xlen=%d\n", __func__, dh, dva, xlen); } #endif /* * Set up the DMA controller. * Note that (dh->dh_len < sc_datalen) */ /* Set direction (send/recv) */ csr = SWREG_READ(ncr_sc, SWREG_CSR); if (dh->dh_flags & SIDH_OUT) { csr |= SW_CSR_SEND; } else { csr &= ~SW_CSR_SEND; } SWREG_WRITE(ncr_sc, SWREG_CSR, csr); /* * The "sw" needs longword aligned transfers. We * detect a shortword aligned transfer here, and adjust the * DMA transfer by 2 bytes. These two bytes are read/written * in PIO mode just before the DMA is started. */ adj = 0; if (dva & 2) { adj = 2; #ifdef DEBUG if (sw_debug & 2) printf("%s: adjusted up %d bytes\n", __func__, adj); #endif } /* We have to frob the address on the "sw". */ dh->dh_startingpa = (dva | 0xF00000); SWREG_WRITE(ncr_sc, SWREG_DMA_ADDR, (u_int)(dh->dh_startingpa + adj)); SWREG_WRITE(ncr_sc, SWREG_DMA_CNT, xlen - adj); /* * Acknowledge the phase change. (After DMA setup!) * Put the SBIC into DMA mode, and start the transfer. */ if (dh->dh_flags & SIDH_OUT) { NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); if (adj) { adjlen = ncr5380_pio_out(ncr_sc, PHASE_DATA_OUT, adj, dh->dh_addr); if (adjlen != adj) printf("%s: bad outgoing adj, %d != %d\n", device_xname(ncr_sc->sc_dev), adjlen, adj); } SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); mode = NCR5380_READ(ncr_sc, sci_mode); mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); NCR5380_WRITE(ncr_sc, sci_mode, mode); NCR5380_WRITE(ncr_sc, sci_dma_send, 0); /* start it */ } else { NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); if (adj) { adjlen = ncr5380_pio_in(ncr_sc, PHASE_DATA_IN, adj, dh->dh_addr); if (adjlen != adj) printf("%s: bad incoming adj, %d != %d\n", device_xname(ncr_sc->sc_dev), adjlen, adj); } SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_icmd, 0); mode = NCR5380_READ(ncr_sc, sci_mode); mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); NCR5380_WRITE(ncr_sc, sci_mode, mode); NCR5380_WRITE(ncr_sc, sci_irecv, 0); /* start it */ } /* Let'er rip! */ csr |= SW_CSR_DMA_EN; SWREG_WRITE(ncr_sc, SWREG_CSR, csr); ncr_sc->sc_state |= NCR_DOINGDMA; #ifdef DEBUG if (sw_debug & 2) { printf("%s: started, flags=0x%x\n", __func__, ncr_sc->sc_state); } #endif }