Date: Mon, 10 Jul 2006 07:59:39 GMT From: Warner Losh <imp@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 101186 for review Message-ID: <200607100759.k6A7xdGZ031318@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=101186 Change 101186 by imp@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[] = {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607100759.k6A7xdGZ031318>