PERFORCE change 197847 for review
Jakub Wojciech Klama
jceel at FreeBSD.org
Fri Aug 19 00:47:05 UTC 2011
http://p4web.freebsd.org/@@197847?ac=10
Change 197847 by jceel at 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 */
More information about the p4-projects
mailing list