PERFORCE change 101186 for review

Warner Losh imp at FreeBSD.org
Mon Jul 10 07:59:45 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=101186

Change 101186 by imp at imp_lighthouse on 2006/07/10 07:59:33

	Implement transfer using busdma goo
	
	Note 1: Turns out that atmel is going to have a AVR32 processor
	that I think freebsd could run on (it has MMU) and which reuses
	the devices from AT91 families.
	
	Note 2: I need to add interlocks to preclude multiple transactions
	outstanding at the same time.  I may need to hack the transfer
	spi interface to allow for queueing and waiting to be decoupled.
	
	Note 3: Shouldn't busy poll, but since this is just for SPI
	update, performance doesn't matter.

Affected files ...

.. //depot/projects/arm/src/sys/arm/at91/at91_spi.c#6 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/at91/at91_spi.c#6 (text+ko) ====

@@ -51,6 +51,8 @@
 	struct resource *irq_res;	/* IRQ resource */
 	struct resource	*mem_res;	/* Memory resource */
 	struct mtx sc_mtx;		/* basically a perimeter lock */
+	bus_dma_tag_t dmatag;		/* bus dma tag for mbufs */
+	bus_dmamap_t map[4];		/* Maps for the transaction */
 };
 
 static inline uint32_t
@@ -97,7 +99,7 @@
 at91_spi_attach(device_t dev)
 {
 	struct at91_spi_softc *sc = device_get_softc(dev);
-	int err;
+	int err, i;
 
 	sc->dev = dev;
 	err = at91_spi_activate(dev);
@@ -106,6 +108,20 @@
 
 	AT91_SPI_LOCK_INIT(sc);
 
+	/*
+	 * Allocate DMA tags and maps
+	 */
+	err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+	    BUS_SPACE_MAXADDR, NULL, NULL, 2058, 1, 2048, BUS_DMA_ALLOCNOW,
+	    NULL, NULL, &sc->dmatag);
+	if (err != 0)
+		goto out;
+	for (i = 0; i < 4; i++) {
+		err = bus_dmamap_create(sc->dmatag, 0,  &sc->map[i]);
+		if (err != 0)
+			goto out;
+	}
+
 	// reset the SPI
 	WR4(sc, SPI_CR, SPI_CR_SWRST);
 
@@ -188,31 +204,71 @@
 	return;
 }
 
+static void
+at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	if (error != 0)
+		return;
+	*(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
 static int
 at91_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
 {
 	struct at91_spi_softc *sc;
+	int i;
+	bus_addr_t addr;
 
 	sc = device_get_softc(dev);
 	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
-#if 0
-	// XXX setup busdma
-	pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd;
-	pSPI->SPI_RCR = pCommand->rx_cmd_size;
-	pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd;
-	pSPI->SPI_TCR = pCommand->tx_cmd_size;
+	i = 0;
+	if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_cmd,
+	    cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
+		goto out;
+	WR4(sc, PDC_TPR, addr);
+	WR4(sc, PDC_TCR, cmd->tx_cmd_sz);
+	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
+	i++;
+	if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_data,
+	    cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
+		goto out;
+	WR4(sc, PDC_TNPR, addr);
+	WR4(sc, PDC_TNCR, cmd->tx_cmd_sz);
+	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
+	i++;
+	if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_cmd,
+	    cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
+		goto out;
+	WR4(sc, PDC_RPR, addr);
+	WR4(sc, PDC_RCR, cmd->tx_cmd_sz);
+	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
+	i++;
+	if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_data,
+	    cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
+		goto out;
+	WR4(sc, PDC_RNPR, addr);
+	WR4(sc, PDC_RNCR, cmd->tx_data_sz);
+	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
 
-	pSPI->SPI_TNPR = (unsigned)pCommand->tx_data;
-	pSPI->SPI_TNCR = pCommand->tx_data_size;
-	pSPI->SPI_RNPR = (unsigned)pCommand->rx_data;
-	pSPI->SPI_RNCR = pCommand->rx_data_size;
-#endif
 	WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);
 
 	// wait for completion
+	// XXX should be done as an ISR of some sort.
 	while (RD4(sc, SPI_SR) & SPI_SR_ENDRX)
 		DELAY(700);
+
+	// Sync the buffers after the DMA is done, and unload them.
+	bus_dmamap_sync(sc->dmatag, sc->map[0], BUS_DMASYNC_POSTWRITE);
+	bus_dmamap_sync(sc->dmatag, sc->map[1], BUS_DMASYNC_POSTWRITE);
+	bus_dmamap_sync(sc->dmatag, sc->map[2], BUS_DMASYNC_POSTREAD);
+	bus_dmamap_sync(sc->dmatag, sc->map[3], BUS_DMASYNC_POSTREAD);
+	for (i = 0; i < 4; i++)
+		bus_dmamap_unload(sc->dmatag, sc->map[i]);
 	return (0);
+out:;
+	while (i-- > 0)
+		bus_dmamap_unload(sc->dmatag, sc->map[i]);
+	return (EIO);
 }
 
 static device_method_t at91_spi_methods[] = {


More information about the p4-projects mailing list