Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jul 2010 13:33:12 GMT
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 181257 for review
Message-ID:  <201007211333.o6LDXC2S049922@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007211333.o6LDXC2S049922>