On Sun, Nov 02, 2014 at 09:31:26PM +1100, Jonathan Gray wrote: > On Mon, Oct 20, 2014 at 02:40:13AM -0400, Andrew Hills wrote: > > On 10/19/14, 11:15 AM, Gerke M. Preussner wrote: > > > I haven't had any time yet to look into this. Were you able to make any > > > progress on your end? > > > > I'm not sure I'd call it progress; I'm not familiar with the MMC > > protocol, so I'm spending most of my time learning rather than debugging. > > > > During the initialization, I see sys/dev/sdmmc roughly follow this order: > > > > sdmmc_card_attach() > > . sdmmc_enable() > > .. sdmmc_mem_enable() > > ... sdmmc_mem_send_op_cond() reads memory OCR > > ... sdmmc_mem_send_op_cond() attempts to send memory OCR > > .... sdmmc_mmc_command() doesn't fail, but doesn't succeed > > (MMC_OCR_MEM_READY is not set) > > .... command times out after 100 attempts (sdmmc_mem.c:519-538) > > > > What I haven't been able to figure out is why the command doesn't have > > the intended effect. Unfortunately, I enabled debug statements in > > sys/arch/armv7/omap/ommmc.c without thinking, so the system is unusable > > until I get the old bsd.umg back. Hopefully more to come soon. > > > > I tracked the problem down, it seems u-boot only sets up CAPA for emmc.
ok syl@. > > With the diff below I can access the sd card on my bbb rev C (sd0) in > addition to the emmc (sd1). Both are still quite slow though, with > reads to the raw device around 780 KB/s on sd and 800 KB/s on emmc. > > Besides DMA, it sounds like opting into a higher bus width > (4 bit on sd, 8 bit on emmc) and clock speeds might help there? > Then there is also the HSPE/High Speed Enable bit in HCTL. If you want I already tried to do something for the DMA. The diff below works 95% of the time, but the 5 other pourcent it broke your filesystem... I think the problem has something to do with arm cache, perhaps in bus_dmamap_sync ? I've already shared this diff with rapha@ but we haven't find how to fix this. I broke my BBB few weeks ago so I haven't test this diff with the fix for l1 pte... If you want to try the dma code (at your own fs risk :)) you will need to remove my fist goto without_dma; Cheers, Index: am335x.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/am335x.c,v retrieving revision 1.4 diff -u -p -u -p -r1.4 am335x.c --- am335x.c 18 Oct 2013 15:23:58 -0000 1.4 +++ am335x.c 22 Oct 2013 14:00:41 -0000 @@ -72,6 +72,10 @@ #define EDMACOMP_IRQ 12 #define EDMAMPERR_IRQ 13 #define EDMAERR_IRQ 14 +#define SDQTXEVT1 2 +#define SDQRXEVT1 3 +#define SDQTXEVT0 24 +#define SDQRXEVT0 25 #define UARTx_SIZE 0x90 #define UART0_ADDR 0x44E09000 @@ -177,13 +181,15 @@ struct omap_dev am335x_devs[] = { { .name = "ommmc", .unit = 0, .mem = { { HSMMC0_ADDR, HSMMCx_SIZE } }, - .irq = { HSMMC0_IRQ } + .irq = { HSMMC0_IRQ }, + .dma = { SDQRXEVT0, SDQTXEVT0 } }, { .name = "ommmc", .unit = 1, .mem = { { HSMMC1_ADDR, HSMMCx_SIZE } }, - .irq = { HSMMC1_IRQ } + .irq = { HSMMC1_IRQ }, + .dma = { SDQRXEVT1, SDQTXEVT1 } }, /* cpsw Ethernet */ Index: ommmc.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/ommmc.c,v retrieving revision 1.7 diff -u -p -u -p -r1.7 ommmc.c --- ommmc.c 18 Oct 2013 15:23:58 -0000 1.7 +++ ommmc.c 22 Oct 2013 14:00:46 -0000 @@ -33,6 +33,7 @@ #include <armv7/omap/omapvar.h> #include <armv7/omap/prcmvar.h> +#include <armv7/omap/edmavar.h> /* * NOTE: on OMAP4430/AM335x these registers skew by 0x100 @@ -178,23 +179,35 @@ #define SDHC_BUFFER_TIMEOUT hz #define SDHC_TRANSFER_TIMEOUT hz +#define OMMMC_DMA_BUFSIZE MAXPHYS +#define OMMMC_DMA_SEGSIZE OMMMC_DMA_BUFSIZE + void ommmc_attach(struct device *parent, struct device *self, void *args); struct ommmc_softc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; - void *sc_ih; /* Interrupt handler */ - uint32_t sc_flags; + void *sc_ih; /* Interrupt handler */ - struct device *sdmmc; /* generic SD/MMC device */ - int clockbit; /* clock control bit */ - uint32_t clkbase; /* base clock frequency in KHz */ - int maxblklen; /* maximum block length */ - int flags; /* flags for this host */ - uint32_t ocr; /* OCR value from capabilities */ - uint32_t intr_status; /* soft interrupt status */ - uint32_t intr_error_status; /* */ + /* DMA */ + bus_dma_tag_t sc_bdt; + bus_dmamap_t sc_dmap; + uint32_t sc_dma_tx_ch; + uint32_t sc_dma_rx_ch; + uint32_t sc_hwfifo_addr; + bus_dma_segment_t sc_segs; + caddr_t sc_datakvap; + int sc_rsegs; + + struct device *sdmmc; /* generic SD/MMC device */ + int clockbit; /* clock control bit */ + uint32_t clkbase; /* base clock frequency in KHz */ + int maxblklen; /* maximum block length */ + int flags; /* flags for this host */ + uint32_t ocr; /* OCR value from capabilities */ + uint32_t intr_status; /* soft interrupt status */ + uint32_t intr_error_status; /* */ }; @@ -236,6 +249,8 @@ int ommmc_wait_state(struct ommmc_softc int ommmc_soft_reset(struct ommmc_softc *, int); int ommmc_wait_intr(struct ommmc_softc *, int, int); void ommmc_transfer_data(struct ommmc_softc *, struct sdmmc_command *); +int ommmc_dma_xfer_init(struct ommmc_softc *, struct sdmmc_command *); +int ommmc_dma_xfer_finish(struct ommmc_softc *, struct sdmmc_command *); void ommmc_read_data(struct ommmc_softc *, uint8_t *, int); void ommmc_write_data(struct ommmc_softc *, uint8_t *, int); @@ -274,15 +289,24 @@ struct cfattach ommmc_ca = { sizeof(struct ommmc_softc), NULL, ommmc_attach }; +static void +edma_it(void *sc) +{ + wakeup(sc); +} + void ommmc_attach(struct device *parent, struct device *self, void *args) { struct ommmc_softc *sc = (struct ommmc_softc *) self; struct armv7_attach_args *aa = args; struct sdmmcbus_attach_args saa; uint32_t caps; sc->sc_iot = aa->aa_iot; + sc->sc_bdt = aa->aa_dmat; + sc->sc_hwfifo_addr = aa->aa_dev->mem[0].addr + MMCHS_DATA; + if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr, aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) panic("%s: bus_space_map failed!", __func__); @@ -311,12 +334,26 @@ ommmc_attach(struct device *parent, stru /* Determine host capabilities. */ caps = HREAD4(sc, MMCHS_CAPA); -#if 0 - /* we want this !! */ - /* Use DMA if the host system and the controller support it. */ - if (usedma && ISSET(caps, SDHC_DMA_SUPPORT)) + if (ISSET(caps, MMCHS_CAPA_DS)) { + goto without_dma; + if (board_id != BOARD_ID_AM335X_BEAGLEBONE) + goto without_dma; + + /* Get DMA channels */ + sc->sc_dma_rx_ch = aa->aa_dev->dma[0]; + sc->sc_dma_tx_ch = aa->aa_dev->dma[1]; + + if (edma_intr_dma_en(sc->sc_dma_rx_ch, edma_it, sc) || + edma_intr_dma_en(sc->sc_dma_tx_ch, edma_it, sc)) + goto without_dma; + + if (bus_dmamap_create(sc->sc_bdt, OMMMC_DMA_BUFSIZE, 1, + OMMMC_DMA_SEGSIZE, 0 , BUS_DMA_WAITOK, &sc->sc_dmap) != 0) + goto without_dma; + SET(sc->flags, SHF_USE_DMA); -#endif + } +without_dma: /* * Determine the base clock frequency. (2.2.24) @@ -798,8 +837,13 @@ ommmc_exec_command(sdmmc_chipset_handle_ * If the command has data to transfer in any direction, * execute the transfer now. */ - if (cmd->c_error == 0 && cmd->c_data != NULL) - ommmc_transfer_data(sc, cmd); + + if (cmd->c_error == 0 && cmd->c_data != NULL) { + if (!ISSET(sc->flags, SHF_USE_DMA)) + ommmc_transfer_data(sc, cmd); + else + ommmc_dma_xfer_finish(sc, cmd); + } #if 0 /* Turn off the LED. */ @@ -860,16 +904,15 @@ ommmc_start_command(struct ommmc_softc * command |= MMCHS_CMD_ACEN; } } -#ifdef notyet + if (ISSET(sc->flags, SHF_USE_DMA)) command |= MMCHS_CMD_DE; -#endif /* * Prepare command register value. (2.2.6) */ command |= (cmd->c_opcode << MMCHS_CMD_INDX_SHIFT) & - MMCHS_CMD_INDX_SHIFT_MASK; + MMCHS_CMD_INDX_SHIFT_MASK; if (ISSET(cmd->c_flags, SCF_RSP_CRC)) command |= MMCHS_CMD_CCCE; @@ -890,6 +933,9 @@ ommmc_start_command(struct ommmc_softc * /* Wait until command and data inhibit bits are clear. (1.5) */ if ((error = ommmc_wait_state(sc, MMCHS_PSTATE_CMDI, 0)) != 0) return (error); + /* Wait until command and data inhibit bits are clear. (1.5) */ + if ((error = ommmc_wait_state(sc, MMCHS_PSTATE_DATI, 0)) != 0) + return (error); s = splsdmmc(); @@ -898,11 +944,15 @@ ommmc_start_command(struct ommmc_softc * HSET1(sc, SDHC_HOST_CTL, SDHC_LED_ON); #endif - /* XXX: Set DMA start address if SHF_USE_DMA is set. */ - DPRINTF(1,("%s: cmd=%#x blksize=%d blkcount=%d\n", DEVNAME(sc), command, blksize, blkcount)); + if (cmd->c_datalen > 0 && ISSET(sc->flags, SHF_USE_DMA)) { + error = ommmc_dma_xfer_init(sc, cmd); + if (error) + return (error); + } + /* * Start a CPU data transfer. Writing to the high order byte * of the SDHC_COMMAND register triggers the SD command. (1.5) @@ -914,6 +964,141 @@ ommmc_start_command(struct ommmc_softc * splx(s); return (0); +} + +int +ommmc_dma_xfer_init(struct ommmc_softc *sc, struct sdmmc_command *cmd) +{ + struct edma_param params; + uint32_t blksize = 0; + uint32_t blkcount = 0; + int error; + uint32_t ch; + int read; + + blksize = MIN(cmd->c_datalen, cmd->c_blklen); + blkcount = cmd->c_datalen / blksize; + read = ISSET(cmd->c_flags, SCF_CMD_READ); + + + /* Allocate and map DMA memory for data xfer */ + error = bus_dmamem_alloc(sc->sc_bdt, cmd->c_datalen, 0, 0, + &sc->sc_segs, 1, &sc->sc_rsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO); + if (error) { + printf("%s: could not allocate %d bytes\n", + DEVNAME(sc), cmd->c_datalen); + goto ret; + } + + error = bus_dmamem_map(sc->sc_bdt, &sc->sc_segs, sc->sc_rsegs, + cmd->c_datalen, &sc->sc_datakvap, BUS_DMA_WAITOK | + BUS_DMA_COHERENT); + if (error) { + printf("%s: could not map data buffer\n", DEVNAME(sc)); + goto free_databuf; + } + + /* If it is a write, copy data from sdmmmc-provided buffer. */ + if (!read) + memcpy(sc->sc_datakvap, cmd->c_data, cmd->c_datalen); + + /* Load the data buffer and sync it */ + error = bus_dmamap_load(sc->sc_bdt, sc->sc_dmap, sc->sc_datakvap, + cmd->c_datalen, NULL, ((read) ? BUS_DMA_READ : BUS_DMA_WRITE) + | BUS_DMA_WAITOK); + if (error) { + printf("%s: could not load DMA map\n", DEVNAME(sc)); + goto unmap_databuf; + } + + bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen, + BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen, + BUS_DMASYNC_PREWRITE); + + /* set edma params and enable dma xfer trigged by device */ + bzero(¶ms, sizeof(params)); + if (read) { + ch = sc->sc_dma_rx_ch; + params.src = sc->sc_hwfifo_addr; + params.dst = sc->sc_dmap->dm_segs[0].ds_addr; + params.dstbidx = 64; + params.dstcidx = blksize; + params.opt = 1; /* enable sam */ + } else { + ch = sc->sc_dma_tx_ch; + params.src = sc->sc_dmap->dm_segs[0].ds_addr; + params.dst = sc->sc_hwfifo_addr; + params.srcbidx = 64; + params.srccidx = blksize; + params.opt = (1 << 1); /* enable dam */ + } + params.acnt = 64; + params.bcnt = blksize / 64; + params.ccnt = blkcount; + params.link = 0xffff; + params.opt |= (1<<20) | (ch << 12) | (2 << 8) | (1 << 2); + + edma_param_write(ch, ¶ms); + edma_trig_xfer_by_dev(ch); + + return (0); + +unmap_databuf: + bus_dmamem_unmap(sc->sc_bdt, sc->sc_datakvap, cmd->c_datalen); +free_databuf: + bus_dmamem_free(sc->sc_bdt, &sc->sc_segs, sc->sc_rsegs); +ret: + printf("%s: xfer error=%d\n", DEVNAME(sc), error); + + return (error); +} + +int +ommmc_dma_xfer_finish(struct ommmc_softc *sc, struct sdmmc_command *cmd) +{ + int error = 0; + int read; + + read = ISSET(cmd->c_flags, SCF_CMD_READ); + + /* wait for completion */ + if (!ommmc_wait_intr(sc, MMCHS_STAT_TC, SDHC_TRANSFER_TIMEOUT)) + error = ETIMEDOUT; + /* Wait until command and data inhibit bits are clear. (1.5) */ + if (!error) + error = ommmc_wait_state(sc, MMCHS_PSTATE_DATI, 0); + + if (error != 0) + cmd->c_error = error; + SET(cmd->c_flags, SCF_ITSDONE); + + DPRINTF(1,("%s: data transfer done (error=%d)\n", DEVNAME(sc), + cmd->c_error)); + + if (error) + goto unload_databuf; + + bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen, + BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen, + BUS_DMASYNC_POSTWRITE); + +unload_databuf: + bus_dmamap_unload(sc->sc_bdt, sc->sc_dmap); + + /* If this is a read, copy data into sdmmc-provided buffer. */ + if (error == 0 && read) + memcpy(cmd->c_data, sc->sc_datakvap, cmd->c_datalen); + + /* Free DMA data buffer */ + + bus_dmamem_unmap(sc->sc_bdt, sc->sc_datakvap, cmd->c_datalen); + bus_dmamem_free(sc->sc_bdt, &sc->sc_segs, sc->sc_rsegs); + + if (error) + printf("%s: xfer done, error=%d\n", DEVNAME(sc), error); + return (error); } void