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