From owner-p4-projects@FreeBSD.ORG Wed Jul 21 13:33:13 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 08F851065688; Wed, 21 Jul 2010 13:33:13 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C0EA0106566C for ; Wed, 21 Jul 2010 13:33:12 +0000 (UTC) (envelope-from jceel@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id AD00F8FC27 for ; Wed, 21 Jul 2010 13:33:12 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o6LDXCJk049925 for ; Wed, 21 Jul 2010 13:33:12 GMT (envelope-from jceel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o6LDXC2S049922 for perforce@freebsd.org; Wed, 21 Jul 2010 13:33:12 GMT (envelope-from jceel@freebsd.org) Date: Wed, 21 Jul 2010 13:33:12 GMT Message-Id: <201007211333.o6LDXC2S049922@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jceel@freebsd.org using -f From: Jakub Wojciech Klama To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 181257 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 21 Jul 2010 13:33:13 -0000 http://p4web.freebsd.org/@@181257?ac=10 Change 181257 by jceel@jceel on 2010/07/21 13:32:59 Add support for DMA in DaVinci MMC/SD controller. Affected files ... .. //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_mmc.c#2 edit Differences ... ==== //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_mmc.c#2 (text+ko) ==== @@ -54,6 +54,8 @@ #include #include +#include + #include #include #include @@ -66,19 +68,33 @@ #include #include +#include + #include #include #include "mmcbr_if.h" +#define DEBUG +#undef DEBUG +#ifdef DEBUG +#define debugf(fmt, args...) do { \ + printf("edma: " fmt "\n", ##args); } while (0) +#else /* DEBUG */ +#define debugf(fmt, args...) +#endif /* DEBUG */ + #define DAVINCI_MMC_CLK davinci_sysclk(DAVINCI_SYSCLK5) #define DAVINCI_MMC_BLKSIZE 512 struct davinci_mmc_softc { device_t dm_dev; struct mtx dm_mtx; - struct resource * dm_mem_res; - struct resource * dm_irq_res; + struct resource * dm_res[4]; +#define dm_mem_res dm_res[0] +#define dm_irq_res dm_res[1] +#define dm_dmarx_res dm_res[2] +#define dm_dmatx_res dm_res[3] bus_space_tag_t dm_bst; bus_space_handle_t dm_bsh; void * dm_intrhand; @@ -86,6 +102,7 @@ struct mmc_request * dm_req; struct mmc_data * dm_data; int dm_bus_busy; + int dm_use_dma; int dm_fifosz; #define FIFO_4BYTE 0 #define FIFO_8BYTE 1 @@ -99,12 +116,34 @@ #define DIRECTION_WRITE 1 /* Transferred data counter */ int dm_xfer_done; + /* RX channel */ + void * dm_rx_buffer; + bus_addr_t dm_rx_phys; + bus_dma_tag_t dm_rx_tag; + bus_dmamap_t dm_rx_map; + gpdma_transfer_t dm_rx_xfer; + /* TX channel */ + void * dm_tx_buffer; + bus_addr_t dm_tx_phys; + bus_dma_tag_t dm_tx_tag; + bus_dmamap_t dm_tx_map; + gpdma_transfer_t dm_tx_xfer; }; +static struct resource_spec davinci_mmc_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { SYS_RES_DMA, 0, RF_ACTIVE }, + { SYS_RES_DMA, 1, RF_ACTIVE }, + { -1, 0 } +}; + static int davinci_mmc_probe(device_t); static int davinci_mmc_attach(device_t); static int davinci_mmc_detach(device_t); static void davinci_mmc_intr(void *); +static void davinci_mmc_dmarxintr(int, void *); +static void davinci_mmc_dmatxintr(int, void *); static void davinci_mmc_cmd(struct davinci_mmc_softc *, struct mmc_command *); static void davinci_mmc_setup_xfer(struct davinci_mmc_softc *, struct mmc_data *); @@ -128,6 +167,14 @@ #define davinci_mmc_write_4(_sc, _reg, _value) \ bus_space_write_4((_sc)->dm_bst, (_sc)->dm_bsh, _reg, _value) +static void +davinci_mmc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) +{ + bus_addr_t *phys = (bus_addr_t *)arg; + + *phys = segs[0].ds_addr; +} + static int davinci_mmc_probe(device_t dev) { @@ -141,33 +188,20 @@ struct davinci_mmc_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *ctx; device_t child; - int rid; sc->dm_dev = dev; sc->dm_state = IDLE; - mtx_init(&sc->dm_mtx, "dvmmc", "mmc", MTX_DEF); + mtx_init(&sc->dm_mtx, "dvmmc", "dvmmc", MTX_DEF); - rid = 0; - sc->dm_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (!sc->dm_mem_res) { - device_printf(dev, "cannot allocate memory window\n"); - return (ENXIO); + if (bus_alloc_resources(dev, davinci_mmc_spec, sc->dm_res)) { + device_printf(dev, "could not allocate resources\n"); + goto out; } sc->dm_bst = rman_get_bustag(sc->dm_mem_res); sc->dm_bsh = rman_get_bushandle(sc->dm_mem_res); - rid = 0; - sc->dm_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); - if (!sc->dm_irq_res) { - device_printf(dev, "cannot allocate interrupt\n"); - bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->dm_mem_res); - return (ENXIO); - } - if (bus_setup_intr(dev, sc->dm_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, davinci_mmc_intr, sc, &sc->dm_intrhand)) { @@ -177,12 +211,115 @@ return (ENXIO); } + sc->dm_use_dma = 1; + + sc->dm_rx_xfer = gpdma_alloc_transfer(sc->dm_dmarx_res); + if (sc->dm_rx_xfer == NULL) { + sc->dm_use_dma = 0; + } + + sc->dm_tx_xfer = gpdma_alloc_transfer(sc->dm_dmatx_res); + if (sc->dm_tx_xfer == NULL) { + sc->dm_use_dma = 0; + } + + device_printf(dev, "Using %s transfers\n", sc->dm_use_dma + ? "DMA" : "PIO"); + + if (sc->dm_use_dma) { + /* RX buffer tag */ + if (bus_dma_tag_create( + gpdma_get_dma_tag(sc->dm_dmarx_res), + 1, 0, + BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, + NULL, NULL, + DAVINCI_MMC_BLKSIZE, 1, + DAVINCI_MMC_BLKSIZE, 0, + NULL, NULL, + &sc->dm_rx_tag)) { + device_printf(dev, "cannot create DMA tag\n"); + } + + if (bus_dmamem_alloc(sc->dm_rx_tag, &sc->dm_rx_buffer, + BUS_DMA_WAITOK, &sc->dm_rx_map)) { + device_printf(dev, "cannot allocate DMA memory\n"); + } + + if (bus_dmamap_load(sc->dm_rx_tag, sc->dm_rx_map, sc->dm_rx_buffer, + DAVINCI_MMC_BLKSIZE, davinci_mmc_dmamap_cb, + &sc->dm_rx_phys, 0)) { + device_printf(dev, "cannot load DMA map\n"); + } + + /* TX buffer tag */ + if (bus_dma_tag_create( + gpdma_get_dma_tag(sc->dm_dmatx_res), + 1, 0, + BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, + NULL, NULL, + DAVINCI_MMC_BLKSIZE, 1, + DAVINCI_MMC_BLKSIZE, 0, + NULL, NULL, + &sc->dm_tx_tag)) { + device_printf(dev, "cannot create DMA tag\n"); + } + + if (bus_dmamem_alloc(sc->dm_tx_tag, &sc->dm_tx_buffer, + BUS_DMA_WAITOK, &sc->dm_tx_map)) { + device_printf(dev, "cannot allocate DMA memory\n"); + } + + if (bus_dmamap_load(sc->dm_tx_tag, sc->dm_tx_map, sc->dm_tx_buffer, + DAVINCI_MMC_BLKSIZE, davinci_mmc_dmamap_cb, + &sc->dm_tx_phys, 0)) { + device_printf(dev, "cannot load DMA map\n"); + } + + /* Pre-set some transfer settings */ + gpdma_set_transfer_func(sc->dm_rx_xfer, GPDMA_COPY); + gpdma_set_transfer_opts(sc->dm_rx_xfer, GPDMA_TRANSFER_EXTTRIG | + GPDMA_TRANSFER_STRIDE_SYNC); + gpdma_set_transfer_callback(sc->dm_rx_xfer, davinci_mmc_dmarxintr, sc); + + sc->dm_rx_xfer->dt_dst.db_dmatag = sc->dm_rx_tag; + sc->dm_rx_xfer->dt_dst.db_dmamap = sc->dm_rx_map; + + /* Source buffer */ + gpdma_set_buffer_layout(sc->dm_rx_xfer, GPDMA_BUF_SRC, GPDMABUF_FRAME); + gpdma_set_buffer_flags(sc->dm_rx_xfer, GPDMA_BUF_SRC, GPDMA_BUFFER_FIFO); + gpdma_set_buffer_stride(sc->dm_rx_xfer, GPDMA_BUF_SRC, 32, 0); + gpdma_set_buffer_fifo_width(sc->dm_rx_xfer, GPDMA_BUF_SRC, 4); + + /* Destination buffer */ + gpdma_set_buffer_layout(sc->dm_rx_xfer, GPDMA_BUF_DST, GPDMABUF_BLOCK); + + /* Pre-set some transfer settings */ + gpdma_set_transfer_func(sc->dm_tx_xfer, GPDMA_COPY); + gpdma_set_transfer_opts(sc->dm_tx_xfer, GPDMA_TRANSFER_EXTTRIG); + gpdma_set_transfer_callback(sc->dm_tx_xfer, davinci_mmc_dmatxintr, sc); + + + sc->dm_tx_xfer->dt_src.db_dmatag = sc->dm_tx_tag; + sc->dm_tx_xfer->dt_src.db_dmamap = sc->dm_tx_map; + + /* Source buffer */ + gpdma_set_buffer_layout(sc->dm_tx_xfer, GPDMA_BUF_SRC, GPDMABUF_BLOCK); + + /* Destination buffer */ + gpdma_set_buffer_layout(sc->dm_tx_xfer, GPDMA_BUF_DST, GPDMABUF_FRAME); + gpdma_set_buffer_flags(sc->dm_tx_xfer, GPDMA_BUF_DST, GPDMA_BUFFER_FIFO); + gpdma_set_buffer_stride(sc->dm_tx_xfer, GPDMA_BUF_DST, 32, 0); + gpdma_set_buffer_fifo_width(sc->dm_tx_xfer, GPDMA_BUF_DST, 4); + } + /* * Controller supports clocks from 312kHz to 25MHz, * voltage range between 3.2V and 3.4V and 4-bit data */ sc->dm_host.f_min = 312500; - sc->dm_host.f_max = 50000000; + sc->dm_host.f_max = 25000000; sc->dm_host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; sc->dm_host.caps = MMC_CAP_4_BIT_DATA; @@ -222,6 +359,8 @@ bus_generic_attach(dev); return (0); +out: + return (ENXIO); } static int @@ -322,16 +461,28 @@ } /* Data receive|transmit ready */ - if (mmcst0 & (DAVINCI_MMC_DRRDY | DAVINCI_MMC_DXRDY)) - davinci_mmc_fifo_xfer(sc); + if (mmcst0 & (DAVINCI_MMC_DRRDY | DAVINCI_MMC_DXRDY)) { + // if (mmcst0 & DAVINCI_MMC_DRRDY) + // printf("davinci_mmc: DAVINCI_MMC_DRRDY\n"); + // if (mmcst0 & DAVINCI_MMC_DXRDY) + // printf("davinci_mmc: DAVINCI_MMC_DXRDY\n"); + + if (!sc->dm_use_dma) + davinci_mmc_fifo_xfer(sc); + } /* Data done */ if (mmcst0 & DAVINCI_MMC_DATDNE) { + debugf("davinci_mmc: DAVINCI_MMC_DATDNE\n"); /* * If there's something to read, read it from * FIFO now (up to FIFO size). */ - davinci_mmc_fifo_xfer(sc); + if (!sc->dm_use_dma) + davinci_mmc_fifo_xfer(sc); + else if (sc->dm_xfer_direction == DIRECTION_READ) { + memcpy(sc->dm_data->data, sc->dm_rx_buffer, sc->dm_data->len); + } if (sc->dm_req->stop) { printf("WARNING: stop started!\n"); @@ -343,19 +494,20 @@ } } -#if 0 +//#if 0 /* Transfer done */ if (mmcst0 & DAVINCI_MMC_TRNDNE) { - device_printf(sc->dm_dev, "transfer done\n"); + // device_printf(sc->dm_dev, "transfer done\n"); /* * Not sure what to do here... probably we don't need * this interrupt. */ } -#endif +//#endif /* Request is done */ if (done) { + debugf("davinci_mmc: submitting command callback\n"); sc->dm_state = IDLE; sc->dm_req->done(sc->dm_req); sc->dm_req = NULL; @@ -365,6 +517,25 @@ } static void +davinci_mmc_dmarxintr(int status, void *arg) +{ +// struct davinci_mmc_softc *sc = (struct davinci_mmc_softc *)arg; + +// device_printf(sc->dm_dev, "davinci_mmc_dmarxintr(%d)\n", status); + //if (sc->dm_data != NULL && sc->dm_data->data != NULL) + // memcpy(sc->dm_data->data, sc->dm_rx_buffer, sc->dm_data->len); +} + +static void +davinci_mmc_dmatxintr(int status, void *arg) +{ + struct davinci_mmc_softc *sc = (struct davinci_mmc_softc *)arg; + + //device_printf(sc->dm_dev, "davinci_mmc_dmatxintr(%d)\n", status); + sc->dm_xfer_done = sc->dm_data->len; +} + +static void davinci_mmc_cmd(struct davinci_mmc_softc *sc, struct mmc_command *cmd) { struct mmc_data *data = cmd->data; @@ -411,6 +582,7 @@ static void davinci_mmc_setup_xfer(struct davinci_mmc_softc *sc, struct mmc_data *data) { + void *cookie; uint32_t fifoctl = 0; sc->dm_data = data; @@ -444,7 +616,38 @@ DAVINCI_MMC_FIFORST); davinci_mmc_write_4(sc, DAVINCI_MMC_MMCFIFOCTL, fifoctl); - if (sc->dm_xfer_direction == DIRECTION_WRITE) { + if (sc->dm_use_dma) { + switch (sc->dm_xfer_direction) { + case DIRECTION_READ: + gpdma_load_buffer_raw(sc->dm_rx_xfer, GPDMA_BUF_SRC, + (bus_addr_t)(DAVINCI_CFGBUS_PHYS_BASE + 0x210000 + + DAVINCI_MMC_MMCDRR), sc->dm_data->len); + gpdma_load_buffer_raw(sc->dm_rx_xfer, GPDMA_BUF_DST, + sc->dm_rx_phys, sc->dm_data->len); + gpdma_program_transfer(sc->dm_rx_xfer, &cookie); + + debugf("### READ data buffer: %p\n", sc->dm_data->data); + + break; + case DIRECTION_WRITE: + memcpy(sc->dm_tx_buffer, sc->dm_data->data, + sc->dm_data->len); + gpdma_load_buffer_raw(sc->dm_tx_xfer, GPDMA_BUF_SRC, + sc->dm_tx_phys, sc->dm_data->len); + gpdma_load_buffer_raw(sc->dm_tx_xfer, GPDMA_BUF_DST, + (bus_addr_t)(DAVINCI_CFGBUS_PHYS_BASE + 0x210000 + + DAVINCI_MMC_MMCDXR), sc->dm_data->len); + gpdma_program_transfer(sc->dm_tx_xfer, &cookie); + + debugf("### WRITE data buffer: %p\n", sc->dm_data->data); + + break; + default: + panic("unknown value in sc->dm_xfer_direction!"); + } + } + + if (sc->dm_xfer_direction == DIRECTION_WRITE && !sc->dm_use_dma) { /* Send first 16 bytes */ davinci_mmc_fifo_xfer(sc); } @@ -611,8 +814,10 @@ /* * Only one request at time allowed. */ - if (sc->dm_req) + if (sc->dm_req) { + davinci_mmc_unlock(sc); return (EBUSY); + } sc->dm_req = request; sc->dm_state = STARTED_CMD;