MMC instance 1 and 2 is capable of ADMA in omap4, omap5.
Add support for ADMA and enable ADMA for read/write to
improve mmc throughput.

Signed-off-by: Balaji T K <balaj...@ti.com>
---
 arch/arm/include/asm/omap_mmc.h |   14 +++
 drivers/mmc/omap_hsmmc.c        |  163 +++++++++++++++++++++++++++++++++++++---
 include/configs/omap5_uevm.h    |    2 
 3 files changed, 169 insertions(+), 10 deletions(-)

Index: u-boot_denx/arch/arm/include/asm/omap_mmc.h
===================================================================
--- u-boot_denx.orig/arch/arm/include/asm/omap_mmc.h    2014-05-02 
19:02:39.042727752 +0530
+++ u-boot_denx/arch/arm/include/asm/omap_mmc.h 2014-05-02 19:18:00.783780277 
+0530
@@ -47,6 +47,9 @@ struct hsmmc {
        unsigned int ie;                /* 0x134 */
        unsigned char res4[0x8];
        unsigned int capa;              /* 0x140 */
+       unsigned char res5[0x10];
+       unsigned int adma_es;           /* 0x154 */
+       unsigned int adma_sal;          /* 0x158 */
 };
 
 /*
@@ -68,9 +71,11 @@ struct hsmmc {
 #define WPP_ACTIVEHIGH                 (0x0 << 8)
 #define RESERVED_MASK                  (0x3 << 9)
 #define CTPL_MMC_SD                    (0x0 << 11)
+#define DMA_MNS_ADMA_MODE              (0x1 << 20)
 #define BLEN_512BYTESLEN               (0x200 << 0)
 #define NBLK_STPCNT                    (0x0 << 16)
 #define DE_DISABLE                     (0x0 << 0)
+#define DE_ENABLE                      (0x1 << 0)
 #define BCE_DISABLE                    (0x0 << 1)
 #define BCE_ENABLE                     (0x1 << 1)
 #define ACEN_DISABLE                   (0x0 << 2)
@@ -103,6 +108,7 @@ struct hsmmc {
 #define DTW_1_BITMODE                  (0x0 << 1)
 #define DTW_4_BITMODE                  (0x1 << 1)
 #define DTW_8_BITMODE                   (0x1 << 5) /* CON[DW8]*/
+#define DMAS                           (0x2 << 3)
 #define SDBP_PWROFF                    (0x0 << 8)
 #define SDBP_PWRON                     (0x1 << 8)
 #define SDVS_1V8                       (0x5 << 9)
@@ -136,12 +142,18 @@ struct hsmmc {
 #define IE_DTO                         (0x01 << 20)
 #define IE_DCRC                                (0x01 << 21)
 #define IE_DEB                         (0x01 << 22)
+#define IE_ADMAE                       (0x01 << 25)
 #define IE_CERR                                (0x01 << 28)
 #define IE_BADA                                (0x01 << 29)
 
+#define CAPA_ADMA_SUPPORT              (1 << 19)
 #define VS30_3V0SUP                    (1 << 25)
 #define VS18_1V8SUP                    (1 << 26)
 
+#define ADMA_XFER_VALID                        (1 << 0)
+#define ADMA_XFER_END                  (1 << 1)
+#define ADMA_XFER_DESC                 (1 << 5)
+
 /* Driver definitions */
 #define MMCSD_SECTOR_SIZE              512
 #define MMC_CARD                       0
@@ -151,6 +163,8 @@ struct hsmmc {
 #define CLK_INITSEQ                    0
 #define CLK_400KHZ                     1
 #define CLK_MISC                       2
+#define DMA_TYPE_SDMA                  1
+#define DMA_TYPE_ADMA                  2
 
 #define RSP_TYPE_NONE  (RSP_TYPE_NORSP   | CCCE_NOCHECK | CICE_NOCHECK)
 #define MMC_CMD0       (INDEX(0)  | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
Index: u-boot_denx/drivers/mmc/omap_hsmmc.c
===================================================================
--- u-boot_denx.orig/drivers/mmc/omap_hsmmc.c   2014-05-02 19:02:39.066727884 
+0530
+++ u-boot_denx/drivers/mmc/omap_hsmmc.c        2014-05-02 19:17:25.247585485 
+0530
@@ -22,6 +22,7 @@
  * MA 02111-1307 USA
  */
 
+#include <bouncebuf.h>
 #include <config.h>
 #include <common.h>
 #include <malloc.h>
@@ -44,12 +45,30 @@
 #undef OMAP_HSMMC_USE_GPIO
 #endif
 
+#ifdef CONFIG_SPL_BUILD
+#undef CONFIG_OMAP_MMC_ADMA
+#endif
+
+#ifdef CONFIG_OMAP_MMC_ADMA
+struct adma_desc_table {
+       u16 attr;
+       u16 length;
+       u32 addr;
+};
+#define ADMA_MAX_BYTES_PER_ROW (127 * 512)
+#define ADMA_TABLE_NUM_ENTRIES 517
+#endif
+
 /* common definitions for all OMAPs */
 #define SYSCTL_SRC     (1 << 25)
 #define SYSCTL_SRD     (1 << 26)
+#define IE_MASK                (IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO 
|\
+                        IE_CIE | IE_CEB | IE_CCRC | IE_CTO | IE_BRR |\
+                        IE_BWR | IE_TC | IE_CC)
 
 struct omap_hsmmc_data {
        struct hsmmc *base_addr;
+       int cap_dma;
        struct mmc_config cfg;
 #ifdef OMAP_HSMMC_USE_GPIO
        int cd_gpio;
@@ -205,11 +224,13 @@ void mmc_init_stream(struct hsmmc *mmc_b
 static int omap_hsmmc_init_setup(struct mmc *mmc)
 {
        struct hsmmc *mmc_base;
+       struct omap_hsmmc_data *hsmmc_data;
        unsigned int reg_val;
        unsigned int dsor;
        ulong start;
 
        mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
+       hsmmc_data = (struct omap_hsmmc_data *)mmc->priv;
        mmc_board_init(mmc);
 
        writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
@@ -239,6 +260,16 @@ static int omap_hsmmc_init_setup(struct
        writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
                MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
                HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
+#ifdef CONFIG_OMAP_MMC_ADMA
+       if (readl(&mmc_base->capa) & CAPA_ADMA_SUPPORT) {
+               reg_val = readl(&mmc_base->con);
+               writel(reg_val | DMA_MNS_ADMA_MODE, &mmc_base->con);
+               writel(readl(&mmc_base->hctl) | DMAS, &mmc_base->hctl);
+               hsmmc_data->cap_dma = DMA_TYPE_ADMA;
+       }
+#else
+               hsmmc_data->cap_dma = 0;
+#endif
 
        dsor = 240;
        mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
@@ -255,10 +286,7 @@ static int omap_hsmmc_init_setup(struct
        writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
 
        writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
-
-       writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
-               IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
-               &mmc_base->ie);
+       writel(IE_MASK, &mmc_base->ie);
 
        mmc_init_stream(mmc_base);
 
@@ -311,14 +339,93 @@ static void mmc_reset_controller_fsm(str
        }
 }
 
+#ifdef CONFIG_OMAP_MMC_ADMA
+static int omap_hsmmc_adma_start(struct hsmmc *mmc_base,
+       struct adma_desc_table *pdesc, struct mmc_data *data,
+       void *bounce_buffer)
+{
+       int i;
+       u32 dmaaddr;
+       ulong blocks;
+       ulong data_start, data_end;
+
+       dmaaddr = (u32) bounce_buffer;
+       blocks = data->blocks;
+       writel((u32)pdesc, &mmc_base->adma_sal);
+       data_start = (ulong) pdesc;
+
+       for (i = 0; blocks != 0; i++) {
+               pdesc->addr = dmaaddr;
+               pdesc->attr = (ADMA_XFER_DESC | ADMA_XFER_VALID);
+               if ((blocks * data->blocksize) <= ADMA_MAX_BYTES_PER_ROW) {
+                       pdesc->length = data->blocksize * blocks;
+                       pdesc->attr |= ADMA_XFER_END;
+                       break;
+               } else {
+                       pdesc->length = ADMA_MAX_BYTES_PER_ROW;
+                       blocks -= (ADMA_MAX_BYTES_PER_ROW / data->blocksize);
+                       dmaaddr += ADMA_MAX_BYTES_PER_ROW;
+                       pdesc++;
+               }
+       }
+       data_end = (ulong) pdesc;
+       flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN);
+
+       return 0;
+}
+
+static int omap_hsmmc_adma_wait_for_tc(struct hsmmc *mmc_base)
+{
+       unsigned mmc_stat;
+       ulong start;
+       int ret = 0;
+
+       start = get_timer(0);
+       while (1) {
+               mmc_stat = readl(&mmc_base->stat);
+
+               if (get_timer(0) - start > 10 * MAX_RETRY_MS) {
+                       printf("%s: timed out waiting for status!\n",
+                              __func__);
+                       ret = TIMEOUT;
+                       break;
+               }
+
+               if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
+                       mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
+
+               if (mmc_stat & ERRI_MASK) {
+                       ret = 1;
+                       break;
+               }
+
+               if (mmc_stat & TC_MASK) {
+                       writel(mmc_stat | TC_MASK, &mmc_base->stat);
+                       break;
+               }
+       }
+
+       return ret;
+}
+#endif
+
 static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
                        struct mmc_data *data)
 {
        struct hsmmc *mmc_base;
+       struct omap_hsmmc_data *hsmmc_data;
        unsigned int flags, mmc_stat;
        ulong start;
+       int dma_type = 0;
+       u32 ie_val;
+#ifdef CONFIG_OMAP_MMC_ADMA
+       struct bounce_buffer bb;
+       ALLOC_CACHE_ALIGN_BUFFER(struct adma_desc_table, adma_desc,
+                                ADMA_TABLE_NUM_ENTRIES);
+#endif
 
        mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
+       hsmmc_data = (struct omap_hsmmc_data *)mmc->priv;
        start = get_timer(0);
        while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {
                if (get_timer(0) - start > MAX_RETRY_MS) {
@@ -373,6 +480,8 @@ static int omap_hsmmc_send_cmd(struct mm
                flags |= CICE_CHECK;
 
        if (data) {
+               ie_val = IE_MASK;
+               writel(ie_val, &mmc_base->ie);
                if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
                         (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
                        flags |= (MSBS_MULTIBLK | BCE_ENABLE);
@@ -386,6 +495,29 @@ static int omap_hsmmc_send_cmd(struct mm
                        flags |= (DP_DATA | DDIR_READ);
                else
                        flags |= (DP_DATA | DDIR_WRITE);
+
+               if (!(hsmmc_data->cap_dma & DMA_TYPE_ADMA)) {
+                       dma_type = 0;
+#ifdef CONFIG_OMAP_MMC_ADMA
+               } else {
+                       dma_type = DMA_TYPE_ADMA;
+                       flags = flags | DE_ENABLE;
+                       ie_val &= ~(IE_BRR | IE_BWR);
+                       ie_val |= IE_ADMAE;
+                       writel(ie_val, &mmc_base->ie);
+                       if (data->flags == MMC_DATA_READ) {
+                               bounce_buffer_start(&bb, (void *)data->dest,
+                                                   data->blocksize *
+                                                   data->blocks, GEN_BB_WRITE);
+                       } else {
+                               bounce_buffer_start(&bb, (void *)data->src,
+                                                   data->blocksize *
+                                                   data->blocks, GEN_BB_READ);
+                       }
+                       omap_hsmmc_adma_start(mmc_base, adma_desc, data,
+                                             bb.bounce_buffer);
+#endif
+               }
        }
 
        writel(cmd->cmdarg, &mmc_base->arg);
@@ -422,13 +554,24 @@ static int omap_hsmmc_send_cmd(struct mm
                }
        }
 
-       if (data && (data->flags & MMC_DATA_READ)) {
-               mmc_read_data(mmc_base, data->dest,
-                               data->blocksize * data->blocks);
-       } else if (data && (data->flags & MMC_DATA_WRITE)) {
-               mmc_write_data(mmc_base, data->src,
-                               data->blocksize * data->blocks);
+       if (!dma_type) {
+               if (data && (data->flags & MMC_DATA_READ)) {
+                       mmc_read_data(mmc_base, data->dest,
+                                     data->blocksize * data->blocks);
+               } else if (data && (data->flags & MMC_DATA_WRITE)) {
+                       mmc_write_data(mmc_base, data->src,
+                                      data->blocksize * data->blocks);
+               }
+#ifdef CONFIG_OMAP_MMC_ADMA
+       } else {
+               omap_hsmmc_adma_wait_for_tc(mmc_base);
+#endif
        }
+
+#ifdef CONFIG_OMAP_MMC_ADMA
+       if (dma_type)
+               bounce_buffer_stop(&bb);
+#endif
        return 0;
 }
 
Index: u-boot_denx/include/configs/omap5_uevm.h
===================================================================
--- u-boot_denx.orig/include/configs/omap5_uevm.h       2014-05-02 
19:02:39.094728037 +0530
+++ u-boot_denx/include/configs/omap5_uevm.h    2014-05-02 19:17:25.247585485 
+0530
@@ -31,6 +31,8 @@
 #define CONFIG_SYS_REDUNDAND_ENVIRONMENT
 #define CONFIG_CMD_SAVEENV
 
+#define CONFIG_BOUNCE_BUFFER
+#define CONFIG_OMAP_MMC_ADMA
 /* Enhance our eMMC support / experience. */
 #define CONFIG_CMD_GPT
 #define CONFIG_EFI_PARTITION
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to