PERFORCE change 181257 for review
Jakub Wojciech Klama
jceel at FreeBSD.org
Wed Jul 21 13:33:13 UTC 2010
http://p4web.freebsd.org/@@181257?ac=10
Change 181257 by jceel at 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 <sys/timetc.h>
#include <sys/watchdog.h>
+#include <sys/kdb.h>
+
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
@@ -66,19 +68,33 @@
#include <dev/mmc/mmcvar.h>
#include <dev/mmc/mmcbrvar.h>
+#include <dev/gpdma/gpdma.h>
+
#include <arm/davinci/davincireg.h>
#include <arm/davinci/davincivar.h>
#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;
More information about the p4-projects
mailing list