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(&params, 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, &params);
+       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

Reply via email to