From owner-p4-projects@FreeBSD.ORG Fri Aug 19 00:47:05 2011 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id AEBEF106566C; Fri, 19 Aug 2011 00:47:05 +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 703F4106567A for ; Fri, 19 Aug 2011 00:47:05 +0000 (UTC) (envelope-from jceel@freebsd.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:4f8:fff6::2d]) by mx1.freebsd.org (Postfix) with ESMTP id 5DD928FC29 for ; Fri, 19 Aug 2011 00:47:05 +0000 (UTC) Received: from skunkworks.freebsd.org (localhost [127.0.0.1]) by skunkworks.freebsd.org (8.14.4/8.14.4) with ESMTP id p7J0l5n2099427 for ; Fri, 19 Aug 2011 00:47:05 GMT (envelope-from jceel@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.4/8.14.4/Submit) id p7J0l5DY099424 for perforce@freebsd.org; Fri, 19 Aug 2011 00:47:05 GMT (envelope-from jceel@freebsd.org) Date: Fri, 19 Aug 2011 00:47:05 GMT Message-Id: <201108190047.p7J0l5DY099424@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.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 197847 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: Fri, 19 Aug 2011 00:47:05 -0000 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 #include +#include + #include #include @@ -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 #include +#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 */