Beispiel #1
0
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;
}
Beispiel #2
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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
}