Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Aug 2011 00:47:05 GMT
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 197847 for review
Message-ID:  <201108190047.p7J0l5DY099424@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@197847?ac=10

Change 197847 by jceel@jceel_cyclone on 2011/08/19 00:46:29

	* Initial version of working MMC/SD controller driver. Reads are working stable, but writes are still unstable. Only 1-bit databus.
	* Some minor cleanups in lpc_dmac.c

Affected files ...

.. //depot/projects/soc2011/jceel_lpc/sys/arm/conf/EA3250#11 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpc_dmac.c#4 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpc_mmc.c#5 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpcreg.h#11 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpcvar.h#8 edit
.. //depot/projects/soc2011/jceel_lpc/sys/dev/mmc/mmc.c#4 edit

Differences ...

==== //depot/projects/soc2011/jceel_lpc/sys/arm/conf/EA3250#11 (text+ko) ====

@@ -20,6 +20,7 @@
 options 	NFSCL			#Network Filesystem Client
 options 	NFSLOCKD		#Network Lock Manager
 options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+options 	MSDOSFS
 options 	BOOTP
 options 	BOOTP_NFSROOT
 options 	BOOTP_NFSV3
@@ -56,7 +57,7 @@
 options KTR
 options KTR_COMPILE=(KTR_DEV|KTR_GEOM|KTR_INTR|KTR_PROC)
 options	KTR_MASK=(KTR_DEV|KTR_GEOM|KTR_INTR|KTR_PROC)
-options KTR_CPUMASK=0x3
+options KTR_CPUMASK=("0x3")
 options KTR_ENTRIES=8192
 
 # Pseudo devices

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpc_dmac.c#4 (text+ko) ====

@@ -47,6 +47,8 @@
 #include <sys/timetc.h>
 #include <sys/watchdog.h>
 
+#include <sys/kdb.h>
+
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
@@ -82,9 +84,9 @@
 #define	lpc_dmac_write_4(_sc, _reg, _value) \
     bus_space_write_4(_sc->ld_bst, _sc->ld_bsh, _reg, _value)
 #define	lpc_dmac_read_ch_4(_sc, _n, _reg) \
-    bus_space_read_4(_sc->ld_bst, _sc->ld_bsh, _reg + (_n * LPC_DMAC_CHSIZE))
+    bus_space_read_4(_sc->ld_bst, _sc->ld_bsh, (_reg + LPC_DMAC_CHADDR(_n)))
 #define	lpc_dmac_write_ch_4(_sc, _n, _reg, _value) \
-    bus_space_write_4(_sc->ld_bst, _sc->ld_bsh, _reg + (_n * LPC_DMAC_CHSIZE), _value)
+    bus_space_write_4(_sc->ld_bst, _sc->ld_bsh, (_reg + LPC_DMAC_CHADDR(_n)), _value)
 
 static int lpc_dmac_probe(device_t dev)
 {
@@ -134,6 +136,10 @@
 	lpc_dmac_sc = sc;
 
 	lpc_pwr_write(dev, LPC_CLKPWR_DMACLK_CTRL, LPC_CLKPWR_DMACLK_CTRL_EN);
+	lpc_dmac_write_4(sc, LPC_DMAC_CONFIG, LPC_DMAC_CONFIG_ENABLE);
+
+	lpc_dmac_write_4(sc, LPC_DMAC_INTTCCLEAR, 0xff);
+	lpc_dmac_write_4(sc, LPC_DMAC_INTERRCLEAR, 0xff);
 
 	return (0);
 }
@@ -156,11 +162,17 @@
 			tcstat = lpc_dmac_read_4(sc, LPC_DMAC_INTTCSTAT);
 			errstat = lpc_dmac_read_4(sc, LPC_DMAC_INTERRSTAT);
 
-			if (tcstat & (1 << i))
-				ch->ldc_config->ldc_success_handler();
+			if (tcstat & (1 << i)) {
+				ch->ldc_config->ldc_success_handler(
+				    ch->ldc_config->ldc_handler_arg);
+				lpc_dmac_write_4(sc, LPC_DMAC_INTTCCLEAR, (1 << i));
+			}
 
-			if (errstat & (1 << i))
-				ch->ldc_config->ldc_error_handler();
+			if (errstat & (1 << i)) {
+				ch->ldc_config->ldc_error_handler(
+				    ch->ldc_config->ldc_handler_arg);
+				lpc_dmac_write_4(sc, LPC_DMAC_INTERRCLEAR, (1 << i));
+			}
 		}
 
 	} while (intstat);
@@ -197,27 +209,27 @@
 	ctrl = LPC_DMAC_CH_CONTROL_I |
 	    (ch->ldc_config->ldc_dst_incr ? LPC_DMAC_CH_CONTROL_DI : 0) | 
 	    (ch->ldc_config->ldc_src_incr ? LPC_DMAC_CH_CONTROL_SI : 0) |
-	    LPC_DMAC_CH_CONTROL_DWIDTH(2) |
-	    LPC_DMAC_CH_CONTROL_SWIDTH(2) |
-	    LPC_DMAC_CH_CONTROL_DBSIZE(ch->ldc_config->ldc_dst_width) |
-	    LPC_DMAC_CH_CONTROL_SBSIZE(ch->ldc_config->ldc_src_width) |
+	    LPC_DMAC_CH_CONTROL_DWIDTH(ch->ldc_config->ldc_dst_width) |
+	    LPC_DMAC_CH_CONTROL_SWIDTH(ch->ldc_config->ldc_src_width) |
+	    LPC_DMAC_CH_CONTROL_DBSIZE(ch->ldc_config->ldc_dst_burst) |
+	    LPC_DMAC_CH_CONTROL_SBSIZE(ch->ldc_config->ldc_src_burst) |
 	    size;
 
 	cfg = LPC_DMAC_CH_CONFIG_ITC | LPC_DMAC_CH_CONFIG_IE |
 	    LPC_DMAC_CH_CONFIG_FLOWCNTL(ch->ldc_config->ldc_fcntl) |
 	    LPC_DMAC_CH_CONFIG_DESTP(ch->ldc_config->ldc_dst_periph) |
-	    LPC_DMAC_CH_CONFIG_SRCP(ch->ldc_config->ldc_src_periph);
-
+	    LPC_DMAC_CH_CONFIG_SRCP(ch->ldc_config->ldc_src_periph) | LPC_DMAC_CH_CONFIG_E; // XXX
 	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_SRCADDR, src);
 	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_DSTADDR, dst);
 	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_LLI, 0);
 	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_CONTROL, ctrl);
 	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_CONFIG, cfg);
+
 	return 0;
 }
 
 int
-lpc_dmac_enable_transfer(device_t dev, int chno)
+lpc_dmac_enable_channel(device_t dev, int chno)
 {
 	struct lpc_dmac_softc *sc = lpc_dmac_sc;
 	uint32_t cfg;
@@ -233,6 +245,32 @@
 	return 0;
 }
 
+int
+lpc_dmac_disable_channel(device_t dev, int chno)
+{
+	struct lpc_dmac_softc *sc = lpc_dmac_sc;
+	uint32_t cfg;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	cfg = lpc_dmac_read_ch_4(sc, chno, LPC_DMAC_CH_CONFIG);
+	cfg &= ~LPC_DMAC_CH_CONFIG_E;
+
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_CONFIG, cfg);
+
+	return 0;
+}
+
+int
+lpc_dmac_start_burst(device_t dev, int id)
+{
+	struct lpc_dmac_softc *sc = lpc_dmac_sc;
+
+	lpc_dmac_write_4(sc, LPC_DMAC_SOFTBREQ, (1 << id));
+	return (0);
+}
+
 static device_method_t lpc_dmac_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		lpc_dmac_probe),

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpc_mmc.c#5 (text+ko) ====

@@ -65,6 +65,20 @@
 #include <arm/lpc/lpcreg.h>
 #include <arm/lpc/lpcvar.h>
 
+#define	DEBUG
+//#undef	DEBUG
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+struct lpc_mmc_dmamap_arg {
+	bus_addr_t		lm_dma_busaddr;
+};
+
 struct lpc_mmc_softc {
 	device_t		lm_dev;
 	struct mtx		lm_mtx;
@@ -83,9 +97,17 @@
 #define	DIRECTION_WRITE		1
 	int			lm_xfer_done;
 	int			lm_bus_busy;
+	bus_dma_tag_t		lm_dma_tag;
+	bus_dmamap_t		lm_dma_map;
+	bus_addr_t		lm_buffer_phys;
+	void *			lm_buffer;
 };
 
-#define	LPC_SD_BLOCKSIZE	512
+#define	LPC_SD_MAX_BLOCKSIZE	1024
+/* XXX */
+#define	LPC_MMC_DMACH_READ	1
+#define	LPC_MMC_DMACH_WRITE	0
+
 
 static int lpc_mmc_probe(device_t);
 static int lpc_mmc_attach(device_t);
@@ -94,8 +116,6 @@
 
 static void lpc_mmc_cmd(struct lpc_mmc_softc *, struct mmc_command *);
 static void lpc_mmc_setup_xfer(struct lpc_mmc_softc *, struct mmc_data *);
-static void lpc_mmc_fifo_read(struct lpc_mmc_softc *);
-static void lpc_mmc_fifo_write(struct lpc_mmc_softc *);
 
 static int lpc_mmc_update_ios(device_t, device_t);
 static int lpc_mmc_request(device_t, device_t, struct mmc_request *);
@@ -103,6 +123,13 @@
 static int lpc_mmc_acquire_host(device_t, device_t);
 static int lpc_mmc_release_host(device_t, device_t);
 
+static void lpc_mmc_dma_rxfinish(void *);
+static void lpc_mmc_dma_rxerror(void *);
+static void lpc_mmc_dma_txfinish(void *);
+static void lpc_mmc_dma_txerror(void *);
+
+static void lpc_mmc_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+
 #define	lpc_mmc_lock(_sc)						\
     mtx_lock(&_sc->lm_mtx);
 #define	lpc_mmc_unlock(_sc)						\
@@ -112,6 +139,34 @@
 #define	lpc_mmc_write_4(_sc, _reg, _value)				\
     bus_space_write_4(_sc->lm_bst, _sc->lm_bsh, _reg, _value)
 
+static struct lpc_dmac_channel_config lpc_mmc_dma_rxconf = {
+	.ldc_fcntl = LPC_DMAC_FLOW_D_P2M,
+	.ldc_src_periph = LPC_DMAC_SD_ID,
+	.ldc_src_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_src_incr = 0,
+	.ldc_src_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_dst_periph = LPC_DMAC_SD_ID,
+	.ldc_dst_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_dst_incr = 1,
+	.ldc_dst_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_success_handler = lpc_mmc_dma_rxfinish,
+	.ldc_error_handler = lpc_mmc_dma_rxerror,
+};
+
+static struct lpc_dmac_channel_config lpc_mmc_dma_txconf = {
+	.ldc_fcntl = LPC_DMAC_FLOW_P_M2P,
+	.ldc_src_periph = LPC_DMAC_SD_ID,
+	.ldc_src_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_src_incr = 1,
+	.ldc_src_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_dst_periph = LPC_DMAC_SD_ID,
+	.ldc_dst_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_dst_incr = 0,
+	.ldc_dst_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_success_handler = lpc_mmc_dma_txfinish,
+	.ldc_error_handler = lpc_mmc_dma_txerror,
+};
+
 static int
 lpc_mmc_probe(device_t dev)
 {
@@ -126,8 +181,9 @@
 lpc_mmc_attach(device_t dev)
 {
 	struct lpc_mmc_softc *sc = device_get_softc(dev);
+	struct lpc_mmc_dmamap_arg ctx;
 	device_t child;
-	int rid;
+	int rid, err;
 
 	sc->lm_dev = dev;
 	sc->lm_req = NULL;
@@ -145,7 +201,7 @@
 	sc->lm_bst = rman_get_bustag(sc->lm_mem_res);
 	sc->lm_bsh = rman_get_bushandle(sc->lm_mem_res);
 
-	device_printf(dev, "virtual register space: 0x%08lx\n", sc->lm_bsh);
+	debugf("virtual register space: 0x%08lx\n", sc->lm_bsh);
 
 	rid = 0;
 	sc->lm_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
@@ -166,9 +222,12 @@
 	}
 
 	sc->lm_host.f_min = 312500;
-	sc->lm_host.f_max = 25000000;
-	sc->lm_host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
+	sc->lm_host.f_max = 2500000;
+	sc->lm_host.host_ocr = MMC_OCR_300_310 | MMC_OCR_310_320 |
+	    MMC_OCR_320_330 | MMC_OCR_330_340;
+#if 0
 	sc->lm_host.caps = MMC_CAP_4_BIT_DATA;
+#endif
 
 	lpc_pwr_write(dev, LPC_CLKPWR_MS_CTRL,
 	    LPC_CLKPWR_MS_CTRL_CLOCK_EN | LPC_CLKPWR_MS_CTRL_SD_CLOCK | 1);
@@ -185,17 +244,68 @@
 		return (ENXIO);
 	}
 
+	/* Alloc DMA memory */
+	err = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->lm_dev),
+	    4, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    LPC_SD_MAX_BLOCKSIZE, 1,	/* maxsize, nsegments */
+	    LPC_SD_MAX_BLOCKSIZE, 0,	/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lm_dma_tag);
+
+	err = bus_dmamem_alloc(sc->lm_dma_tag, (void **)&sc->lm_buffer,
+	    0, &sc->lm_dma_map);
+	if (err) {
+		device_printf(dev, "cannot allocate framebuffer\n");
+		goto fail;
+	}
+
+	err = bus_dmamap_load(sc->lm_dma_tag, sc->lm_dma_map, sc->lm_buffer,
+	    LPC_SD_MAX_BLOCKSIZE, lpc_mmc_dmamap_cb, &ctx, BUS_DMA_NOWAIT);
+	if (err) {
+		device_printf(dev, "cannot load DMA map\n");
+		goto fail;
+	}
+
+	sc->lm_buffer_phys = ctx.lm_dma_busaddr;
+
+	lpc_mmc_dma_rxconf.ldc_handler_arg = (void *)sc;
+	err = lpc_dmac_config_channel(dev, LPC_MMC_DMACH_READ, &lpc_mmc_dma_rxconf);
+	if (err) {
+		device_printf(dev, "cannot allocate RX DMA channel\n");
+		goto fail;
+	}
+
+
+	lpc_mmc_dma_txconf.ldc_handler_arg = (void *)sc;
+	err = lpc_dmac_config_channel(dev, LPC_MMC_DMACH_WRITE, &lpc_mmc_dma_txconf);	
+	if (err) {
+		device_printf(dev, "cannot allocate TX DMA channel\n");
+		goto fail;
+	}
+
 	bus_generic_probe(dev);
 	bus_generic_attach(dev);
 
-	device_printf(dev, "attached\n");
+	return (0);
 
-	return (0);
+fail:
+	if (sc->lm_intrhand)
+		bus_teardown_intr(dev, sc->lm_irq_res, sc->lm_intrhand);
+	if (sc->lm_irq_res)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lm_irq_res);
+	if (sc->lm_mem_res)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res);
+	return (err);
 }
 
 static int
 lpc_mmc_detach(device_t dev)
 {
+	/* XXX */
 	return (0);
 }
 
@@ -208,35 +318,21 @@
 
 	status = lpc_mmc_read_4(sc, LPC_SD_STATUS);
 
-	device_printf(sc->lm_dev, "interrupt: 0x%08x\n", status);
-
-	if (status & LPC_SD_STATUS_TXACTIVE) {
-		device_printf(sc->lm_dev, "TX active\n");
-		lpc_mmc_fifo_write(sc);
-	}
-
-	if (status & LPC_SD_STATUS_RXACTIVE) {
-		device_printf(sc->lm_dev, "RX active\n");
-		lpc_mmc_fifo_read(sc);
-	}
+	debugf("interrupt: 0x%08x\n", status);
 
 	if (status & LPC_SD_STATUS_CMDCRCFAIL) {
-		device_printf(sc->lm_dev, "command CRC error\n");
 		cmd = sc->lm_req->cmd;
-		cmd->error = MMC_ERR_NONE;
+		cmd->error = sc->lm_flags & LPC_SD_FLAGS_IGNORECRC
+		    ? MMC_ERR_NONE : MMC_ERR_BADCRC;
 		cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0);
 		sc->lm_req->done(sc->lm_req);
 		sc->lm_req = NULL;
 		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDCRCFAIL);	
 	}
-#if 0
-	if (status & LPC_SD_STATUS_DATACRCFAIL) {
 
-	}
-#endif
 	if (status & LPC_SD_STATUS_CMDACTIVE)
 	{
-		device_printf(sc->lm_dev, "command active\n");
+		debugf("command active\n");
 		cmd = sc->lm_req->cmd;
 		cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0);
 		sc->lm_req->done(sc->lm_req);
@@ -247,20 +343,16 @@
 		device_printf(sc->lm_dev, "data timeout\n");
 		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATATIMEOUT);
 	}
-#if 0
+
 	if (status & LPC_SD_STATUS_TXUNDERRUN) {
-
+		device_printf(sc->lm_dev, "TX underrun\n");
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_TXUNDERRUN);
 	}
-
-	if (status & LPC_SD_STATUS_RXOVERRUN) {
-
-	}
-#endif
+	
 	if (status & LPC_SD_STATUS_CMDRESPEND) {
-		device_printf(sc->lm_dev, "command response\n");
-		device_printf(sc->lm_dev, "req: %p\n", sc->lm_req);
-		device_printf(sc->lm_dev, "cmd: %p\n", sc->lm_req->cmd);
+		debugf("command response\n");
 		cmd = sc->lm_req->cmd;
+		
 		if (cmd->flags & MMC_RSP_136) {
 			cmd->resp[3] = lpc_mmc_read_4(sc, LPC_SD_RESP3);
 			cmd->resp[2] = lpc_mmc_read_4(sc, LPC_SD_RESP2);
@@ -269,53 +361,79 @@
 
 		cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0);
 		cmd->error = MMC_ERR_NONE;
-		
-		sc->lm_req->done(sc->lm_req);
-		sc->lm_req = NULL;
+	
+		if (cmd->data && (cmd->data->flags & MMC_DATA_WRITE))
+			lpc_mmc_setup_xfer(sc, sc->lm_req->cmd->data);
+
+		if (!cmd->data) {	
+			sc->lm_req->done(sc->lm_req);
+			sc->lm_req = NULL;
+		}
+
 		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDRESPEND);
-		device_printf(sc->lm_dev, "command response done\n");
 	}
 
 	if (status & LPC_SD_STATUS_CMDSENT) {
-		device_printf(sc->lm_dev, "command sent\n");
+		debugf("command sent\n");
 		cmd = sc->lm_req->cmd;
 		cmd->error = MMC_ERR_NONE;
 		sc->lm_req->done(sc->lm_req);
 		sc->lm_req = NULL;
 		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDSENT);
 	}
-#if 0
+	
 	if (status & LPC_SD_STATUS_DATAEND) {
+		if (sc->lm_xfer_direction == DIRECTION_READ)
+			lpc_dmac_start_burst(sc->lm_dev, LPC_DMAC_SD_ID);
+
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATAEND);
+	}
 
+	if (status & LPC_SD_STATUS_CMDTIMEOUT) {
+		device_printf(sc->lm_dev, "command response timeout\n");
+		cmd = sc->lm_req->cmd;
+		cmd->error = MMC_ERR_TIMEOUT;
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDTIMEOUT);
+		return;
 	}
 
 	if (status & LPC_SD_STATUS_STARTBITERR) {
+		device_printf(sc->lm_dev, "start bit error\n");
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_STARTBITERR);
+	}
 
-	}
+	if (status & LPC_SD_STATUS_DATACRCFAIL) {		
+		device_printf(sc->lm_dev, "data CRC error\n");
+		debugf("data buffer: %p\n", sc->lm_buffer);
+		cmd = sc->lm_req->cmd;
+		cmd->error = MMC_ERR_BADCRC;
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
 
-	if (status & LPC_SD_STATUS_DATABLOCKEND) {
+		if (sc->lm_xfer_direction == DIRECTION_READ)
+			lpc_dmac_start_burst(sc->lm_dev, LPC_DMAC_SD_ID);
 
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATACRCFAIL);
 	}
 
-	if (status & LPC_SD_STATUS_CMDACTIVE) {
-		if (sc->lm_req == NULL)
-			return;
+	if (status & LPC_SD_STATUS_DATABLOCKEND) {
+		debugf("data block end\n");
+		if (sc->lm_xfer_direction == DIRECTION_READ)
+			memcpy(sc->lm_data->data, sc->lm_buffer, sc->lm_data->len);
 
-		cmd = sc->lm_req->cmd;
-		printf("sc=%p req=%p\n", sc, sc->lm_req);
-		printf("cmd=%p\n", cmd);
-
-		cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0);
-		cmd->error = MMC_ERR_NONE;
+		if (sc->lm_xfer_direction == DIRECTION_WRITE) {
+			lpc_dmac_disable_channel(sc->lm_dev, LPC_MMC_DMACH_WRITE);
+			lpc_mmc_write_4(sc, LPC_SD_DATACTRL, 0);
+		}
+	
 		sc->lm_req->done(sc->lm_req);
 		sc->lm_req = NULL;
-		lpc_mmc_write_4(sc, LPC_SD_MASK0, (0xffffffff & ~LPC_SD_STATUS_CMDACTIVE));
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATABLOCKEND);
 	}
-#endif
 
-	lpc_mmc_write_4(sc, LPC_SD_CLEAR, 0xfff);
-	lpc_mmc_write_4(sc, LPC_SD_MASK0, 0);
-	device_printf(sc->lm_dev, "isr done\n");
+	debugf("done\n");
 }
 
 static int
@@ -323,14 +441,20 @@
 {
 	struct lpc_mmc_softc *sc = device_get_softc(bus);
 
-	device_printf(bus, "lpc_mmc_request: %p\n", req);
+	debugf("request: %p\n", req);
 
 	lpc_mmc_lock(sc);
 	if (sc->lm_req)
 		return (EBUSY);
 
 	sc->lm_req = req;
-	//sc->lm_state = STARTED_CMD;
+
+	if (req->cmd->data && req->cmd->data->flags & MMC_DATA_WRITE) {
+		memcpy(sc->lm_buffer, req->cmd->data->data, req->cmd->data->len);
+		lpc_mmc_cmd(sc, req->cmd);
+		lpc_mmc_unlock(sc);
+		return (0);
+	}
 
 	if (req->cmd->data)
 		lpc_mmc_setup_xfer(sc, req->cmd->data);
@@ -344,10 +468,16 @@
 static void
 lpc_mmc_cmd(struct lpc_mmc_softc *sc, struct mmc_command *cmd)
 {
-	//struct mmc_data *data = cmd->data;
 	uint32_t cmdreg = 0;
 
-	device_printf(sc->lm_dev, "cmd: %d arg: 0x%08x\n", cmd->opcode, cmd->arg);
+	debugf("cmd: %d arg: 0x%08x\n", cmd->opcode, cmd->arg);
+
+	if (lpc_mmc_read_4(sc, LPC_SD_COMMAND) & LPC_SD_COMMAND_ENABLE) {
+		lpc_mmc_write_4(sc, LPC_SD_COMMAND, 0);
+		DELAY(1000);
+	}
+
+	sc->lm_flags &= ~LPC_SD_FLAGS_IGNORECRC;
 
 	if (cmd->flags & MMC_RSP_PRESENT)
 		cmdreg |= LPC_SD_COMMAND_RESPONSE;
@@ -365,85 +495,46 @@
 	lpc_mmc_write_4(sc, LPC_SD_MASK1, 0xffffffff);
 	lpc_mmc_write_4(sc, LPC_SD_ARGUMENT, cmd->arg);
 	lpc_mmc_write_4(sc, LPC_SD_COMMAND, cmdreg);
-
-	device_printf(sc->lm_dev, "cmdarg: 0x%08x, cmdreg: 0x%08x\n", cmd->arg, cmdreg);
 }
 
 static void
 lpc_mmc_setup_xfer(struct lpc_mmc_softc *sc, struct mmc_data *data)
 {
 	uint32_t datactrl = 0;
+	int data_words = data->len / 4;
 
 	sc->lm_data = data;
 	sc->lm_xfer_done = 0;
 
-	device_printf(sc->lm_dev, "setup_xfer data: %p\n", data);
+	debugf("data: %p, len: %d, %s\n", data,
+	    data->len, (data->flags & MMC_DATA_READ) ? "read" : "write");
 
-	if (data->flags & MMC_DATA_READ)
+	if (data->flags & MMC_DATA_READ) {
 		sc->lm_xfer_direction = DIRECTION_READ;
+		lpc_dmac_setup_transfer(sc->lm_dev, LPC_MMC_DMACH_READ,
+		    LPC_SD_BASE + LPC_SD_FIFO, sc->lm_buffer_phys,
+		    data_words, 0);
+	}
 
-	if (data->flags & MMC_DATA_WRITE)
+	if (data->flags & MMC_DATA_WRITE) {
 		sc->lm_xfer_direction = DIRECTION_WRITE;
+		lpc_dmac_setup_transfer(sc->lm_dev, LPC_MMC_DMACH_WRITE,
+		    sc->lm_buffer_phys, LPC_SD_BASE + LPC_SD_FIFO,
+		    data_words, 0);
+	}
 
 	datactrl |= (sc->lm_xfer_direction 
 	    ? LPC_SD_DATACTRL_WRITE 
 	    : LPC_SD_DATACTRL_READ);
 
-	datactrl |= LPC_SD_DATACTRL_ENABLE;
+	datactrl |= LPC_SD_DATACTRL_DMAENABLE | LPC_SD_DATACTRL_ENABLE;
+	datactrl |= (ffs(data->len) - 1) << 4;
 
-	if (data->len > LPC_SD_BLOCKSIZE)
-		datactrl |= 0x90;
+	debugf("datactrl: 0x%08x\n", datactrl);
 
-	device_printf(sc->lm_dev, "setup_xfer: datactrl=0x%08x\n", datactrl);
-
-	lpc_mmc_write_4(sc, LPC_SD_DATATIMER, 0x100000);
+	lpc_mmc_write_4(sc, LPC_SD_DATATIMER, 0xFFFF0000);
 	lpc_mmc_write_4(sc, LPC_SD_DATALENGTH, data->len);
 	lpc_mmc_write_4(sc, LPC_SD_DATACTRL, datactrl);
-
-	if (sc->lm_xfer_direction == DIRECTION_WRITE)
-		lpc_mmc_fifo_write(sc);
-}
-
-static void
-lpc_mmc_fifo_read(struct lpc_mmc_softc *sc)
-{
-	do {
-		uint32_t *data = sc->lm_data->data;
-		int i;
-		int todo = sc->lm_data->len > 16 ? 16 : (sc->lm_data->len / 4) - sc->lm_xfer_done; 
-		device_printf(sc->lm_dev, "reading from fifo %d words [%d of %d words done]\n",
-		    todo, sc->lm_xfer_done, (sc->lm_data->len / 4));
-	
-		for (i = 0; i < 16; i++) {
-			data[sc->lm_xfer_done] = 
-			    lpc_mmc_read_4(sc, LPC_SD_FIFO);
-			sc->lm_xfer_done++;
-		}
-
-		/*
-		bus_space_read_region_4(sc->lm_bst, sc->lm_bsh,
-		    LPC_SD_FIFO,
-		    &data[sc->lm_xfer_done],
-		    todo);
-		*/
-
-		//sc->lm_xfer_done += 16;
-		device_printf(sc->lm_dev, "currently done %d\n", sc->lm_xfer_done);
-		kdb_enter("data read", "data read");
-	} while (lpc_mmc_read_4(sc, LPC_SD_STATUS) & LPC_SD_STATUS_RXDATAAVLBL);
-
-	device_printf(sc->lm_dev, "partial read done\n");
-}
-
-static void
-lpc_mmc_fifo_write(struct lpc_mmc_softc *sc)
-{
-	do {
-		lpc_mmc_write_4(sc, LPC_SD_FIFO,
-		    ((uint32_t *)sc->lm_data->data)[sc->lm_xfer_done]);
-
-		sc->lm_xfer_done++;
-	} while (lpc_mmc_read_4(sc, LPC_SD_STATUS) & LPC_SD_STATUS_TXDATAAVLBL);
 }
 
 static int
@@ -548,7 +639,7 @@
 {
 	struct lpc_mmc_softc *sc = device_get_softc(bus);
 	struct mmc_ios *ios = &sc->lm_host.ios;
-	uint32_t clkdiv = 0;
+	uint32_t clkdiv = 0, pwr = 0;
 
 	if (ios->bus_width == bus_width_4)
 		clkdiv |= LPC_SD_CLOCK_WIDEBUS;
@@ -560,9 +651,32 @@
 	if ((LPC_SD_CLK / (2 * (clkdiv + 1))) > ios->clock)
 		clkdiv++;
 
-	device_printf(bus, "clock: %dHz, clkdiv: %d\n", ios->clock, clkdiv);
+	debugf("clock: %dHz, clkdiv: %d\n", ios->clock, clkdiv);
+
+	if (ios->bus_width == bus_width_4) {
+		debugf("using wide bus mode\n");
+		clkdiv |= LPC_SD_CLOCK_WIDEBUS;
+	}
 
 	lpc_mmc_write_4(sc, LPC_SD_CLOCK, clkdiv | LPC_SD_CLOCK_ENABLE);
+
+	switch (ios->power_mode) {
+	case power_off:
+		pwr |= LPC_SD_POWER_CTRL_OFF;
+		break;
+	case power_up:
+		pwr |= LPC_SD_POWER_CTRL_UP;
+		break;
+	case power_on:
+		pwr |= LPC_SD_POWER_CTRL_ON;
+		break;
+	}
+
+	if (ios->bus_mode == opendrain)
+		pwr |= LPC_SD_POWER_OPENDRAIN;
+
+	lpc_mmc_write_4(sc, LPC_SD_POWER, pwr);
+
 	return (0);
 }
 
@@ -600,6 +714,38 @@
 	return (0);
 }
 
+static void lpc_mmc_dma_rxfinish(void *arg)
+{
+}
+
+static void lpc_mmc_dma_rxerror(void *arg)
+{
+	struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg;
+	device_printf(sc->lm_dev, "DMA RX error\n");
+}
+
+static void lpc_mmc_dma_txfinish(void *arg)
+{
+}
+
+static void lpc_mmc_dma_txerror(void *arg)
+{
+	struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg;
+	device_printf(sc->lm_dev, "DMA TX error\n");
+}
+
+static void
+lpc_mmc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
+{
+	struct lpc_mmc_dmamap_arg *ctx;
+
+	if (err)
+		return;
+
+	ctx = (struct lpc_mmc_dmamap_arg *)arg;
+	ctx->lm_dma_busaddr = segs[0].ds_addr;
+}
+
 static device_method_t lpc_mmc_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		lpc_mmc_probe),

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpcreg.h#11 (text+ko) ====

@@ -216,6 +216,7 @@
 #define	LPC_SD_POWER			0x00
 #define	LPC_SD_POWER_OPENDRAIN		(1 << 6)
 #define	LPC_SD_POWER_CTRL_OFF		0x00
+#define	LPC_SD_POWER_CTRL_UP		0x02
 #define	LPC_SD_POWER_CTRL_ON		0x03
 #define	LPC_SD_CLOCK			0x04
 #define	LPC_SD_CLOCK_WIDEBUS		(1 << 11)
@@ -558,7 +559,7 @@
 #define	LPC_DMAC_INTTCSTAT		0x04
 #define	LPC_DMAC_INTTCCLEAR		0x08
 #define	LPC_DMAC_INTERRSTAT		0x0c
-#define	LPC_DMAC_INTERRCLR		0x10
+#define	LPC_DMAC_INTERRCLEAR		0x10
 #define	LPC_DMAC_RAWINTTCSTAT		0x14
 #define	LPC_DMAC_RAWINTERRSTAT		0x18
 #define	LPC_DMAC_ENABLED_CHANNELS	0x1c
@@ -583,8 +584,10 @@
 #define	LPC_DMAC_CH_CONTROL_SI		(1 << 26)
 #define	LPC_DMAC_CH_CONTROL_D		(1 << 25)
 #define	LPC_DMAC_CH_CONTROL_S		(1 << 24)
+#define	LPC_DMAC_CH_CONTROL_WIDTH_4	2
 #define	LPC_DMAC_CH_CONTROL_DWIDTH(_n)	((_n & 0x7) << 21)
 #define	LPC_DMAC_CH_CONTROL_SWIDTH(_n)	((_n & 0x7) << 18)
+#define	LPC_DMAC_CH_CONTROL_BURST_8	2
 #define	LPC_DMAC_CH_CONTROL_DBSIZE(_n)	((_n & 0x7) << 15)
 #define	LPC_DMAC_CH_CONTROL_SBSIZE(_n)	((_n & 0x7) << 12)
 #define	LPC_DMAC_CH_CONTROL_XFERLEN(_n)	(_n & 0xfff) 
@@ -595,14 +598,20 @@
 #define	LPC_DMAC_CH_CONFIG_ITC		(1 << 15)
 #define	LPC_DMAC_CH_CONFIG_IE		(1 << 14)
 #define	LPC_DMAC_CH_CONFIG_FLOWCNTL(_n)	((_n & 0x7) << 11)
-#define	LPC_DMAC_CH_FCNTL_MEM_TO_MEM	0
-#define	LPC_DMAC_CH_FCNTL_MEM_TO_DEV	1
-#define	LPC_DMAC_CH_FCNTL_DEV_TO_MEM	2
-#define	LPC_DMAC_CH_FCNTL_DEV_TO_DEV	3
 #define	LPC_DMAC_CH_CONFIG_DESTP(_n)	((_n & 0x1f) << 6)
 #define	LPC_DMAC_CH_CONFIG_SRCP(_n)	((_n & 0x1f) << 1)
 #define	LPC_DMAC_CH_CONFIG_E		(1 << 0)
 
+/* DMA flow control values */
+#define	LPC_DMAC_FLOW_D_M2M		0
+#define	LPC_DMAC_FLOW_D_M2P		1
+#define	LPC_DMAC_FLOW_D_P2M		2
+#define	LPC_DMAC_FLOW_D_P2P		3
+#define	LPC_DMAC_FLOW_DP_P2P		4
+#define	LPC_DMAC_FLOW_P_M2P		5
+#define	LPC_DMAC_FLOW_P_P2M		6
+#define	LPC_DMAC_FLOW_SP_P2P		7
+
 /* DMA peripheral ID's */
 #define	LPC_DMAC_I2S0_DMA0_ID		0
 #define	LPC_DMAC_NAND_ID		1

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpcvar.h#8 (text+ko) ====

@@ -48,15 +48,20 @@
 	int		ldc_src_periph;
 	int		ldc_src_width;
 	int		ldc_src_incr;
+	int		ldc_src_burst;
 	int		ldc_dst_periph;
 	int		ldc_dst_width;
 	int		ldc_dst_incr;
-	void		(*ldc_success_handler)(void);
-	void		(*ldc_error_handler)(void);
+	int		ldc_dst_burst;
+	void		(*ldc_success_handler)(void *);
+	void		(*ldc_error_handler)(void *);
+	void *		ldc_handler_arg;
 };
 
 int lpc_dmac_config_channel(device_t, int, struct lpc_dmac_channel_config *);
 int lpc_dmac_setup_transfer(device_t, int, bus_addr_t, bus_addr_t, bus_size_t, int);
-int lpc_dmac_enable_transfer(device_t, int);
+int lpc_dmac_enable_channel(device_t, int);
+int lpc_dmac_disable_channel(device_t, int);
+int lpc_dmac_start_burst(device_t, int);
 
 #endif	/* _ARM_LPC_LPCVAR_H */

==== //depot/projects/soc2011/jceel_lpc/sys/dev/mmc/mmc.c#4 (text+ko) ====

@@ -107,7 +107,7 @@
 
 SYSCTL_NODE(_hw, OID_AUTO, mmc, CTLFLAG_RD, NULL, "mmc driver");
 
-static int mmc_debug = 3;
+static int mmc_debug = 0;//3;
 SYSCTL_INT(_hw_mmc, OID_AUTO, debug, CTLFLAG_RW, &mmc_debug, 0, "Debug level");
 
 /* bus entry points */



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