[U-Boot] [PATCH] mmc: omap_hsmmc: add adma support
Balaji T K
balajitk at ti.com
Fri May 2 15:55:20 CEST 2014
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 <balajitk at 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
More information about the U-Boot
mailing list