[U-Boot] [PATCH 0/3] MMC: atmel: enable the features supported by MCI

This patch series enable the features supported by the MCI which not enabled before.
For example: high speed mode without this patch: U-Boot> fatload mmc 0 0x20000000 uimage reading uimage 3973216 bytes read in 392 ms (9.7 MiB/s)
with this patch U-Boot> fatload mmc 0 0x20000000 uimage reading uimage 3973216 bytes read in 275 ms (13.8 MiB/s)
It near 50% performance improvement.
Bo Shen (3): MMC: atmel_mci: refactor setting the mode register MMC: atmel_mci: add configuration register definition MMC: atmel_mci: enable high speed mode support
drivers/mmc/gen_atmel_mci.c | 63 ++++++++++++++++++++++++++++++++++----------- include/atmel_mci.h | 18 ++++++++++++- 2 files changed, 65 insertions(+), 16 deletions(-)

The mode register is different between MCI IP version. So, according to MCI IP version to set the mode register.
Signed-off-by: Bo Shen voice.shen@atmel.com --- drivers/mmc/gen_atmel_mci.c | 56 +++++++++++++++++++++++++++++++++------------ include/atmel_mci.h | 4 ++++ 2 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index a57a9b1..8778a4d 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -58,30 +58,58 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) atmel_mci_t *mci = mmc->priv; u32 bus_hz = get_mci_clk_rate(); u32 clkdiv = 255; + unsigned int version = atmel_mci_get_version(mci); + u32 clkodd = 0; + u32 mr;
debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n", bus_hz, hz, blklen); if (hz > 0) { - /* find lowest clkdiv yielding a rate <= than requested */ - for (clkdiv=0; clkdiv<255; clkdiv++) { - if ((bus_hz / (clkdiv+1) / 2) <= hz) - break; + if (version >= 0x500) { + clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2; + if (clkdiv > 511) + clkdiv = 511; + + clkodd = clkdiv & 1; + clkdiv >>= 1; + + printf("mci: setting clock %u Hz, block size %u\n", + bus_hz / (clkdiv * 2 + clkodd + 2), blklen); + } else { + /* find clkdiv yielding a rate <= than requested */ + for (clkdiv = 0; clkdiv < 255; clkdiv++) { + if ((bus_hz / (clkdiv + 1) / 2) <= hz) + break; + } + printf("mci: setting clock %u Hz, block size %u\n", + (bus_hz / (clkdiv + 1)) / 2, blklen); + } } - printf("mci: setting clock %u Hz, block size %u\n", - (bus_hz / (clkdiv+1)) / 2, blklen);
blklen &= 0xfffc; - /* On some platforms RDPROOF and WRPROOF are ignored */ - writel((MMCI_BF(CLKDIV, clkdiv) - | MMCI_BF(BLKLEN, blklen) - | MMCI_BIT(RDPROOF) - | MMCI_BIT(WRPROOF)), &mci->mr); + + mr = MMCI_BF(CLKDIV, clkdiv); + + /* MCI IP version >= 0x200 has R/WPROOF */ + if (version >= 0x200) + mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF); + /* - * On some new platforms BLKLEN in mci->mr is ignored. - * Should use the BLKLEN in the block register. + * MCI IP version >= 0x500 use bit 16 as clkodd. + * MCI IP version < 0x500 use upper 16 bits for blklen. */ - writel(MMCI_BF(BLKLEN, blklen), &mci->blkr); + if (version >= 0x500) + mr |= MMCI_BF(CLKODD, clkodd); + else + mr |= MMCI_BF(BLKLEN, blklen); + + writel(mr, &mci->mr); + + /* MCI IP version >= 0x200 has blkr */ + if (version >= 0x200) + writel(MMCI_BF(BLKLEN, blklen), &mci->blkr); + initialized = 1; }
diff --git a/include/atmel_mci.h b/include/atmel_mci.h index 090574d..3d2870f 100644 --- a/include/atmel_mci.h +++ b/include/atmel_mci.h @@ -67,6 +67,10 @@ typedef struct atmel_mci { #define MMCI_PDCPADV_SIZE 1 #define MMCI_PDCMODE_OFFSET 15 #define MMCI_PDCMODE_SIZE 1 +/* MCI IP version >= 0x500, MR bit 16 used for CLKODD */ +#define MMCI_CLKODD_OFFSET 16 +#define MMCI_CLKODD_SIZE 1 +/* MCI IP version < 0x200, MR higher 16bits for BLKLEN */ #define MMCI_BLKLEN_OFFSET 16 #define MMCI_BLKLEN_SIZE 16

Hi Bo,
On Jul 31, 2014, at 9:39 AM, Bo Shen wrote:
The mode register is different between MCI IP version. So, according to MCI IP version to set the mode register.
Signed-off-by: Bo Shen voice.shen@atmel.com
drivers/mmc/gen_atmel_mci.c | 56 +++++++++++++++++++++++++++++++++------------ include/atmel_mci.h | 4 ++++ 2 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index a57a9b1..8778a4d 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -58,30 +58,58 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) atmel_mci_t *mci = mmc->priv; u32 bus_hz = get_mci_clk_rate(); u32 clkdiv = 255;
unsigned int version = atmel_mci_get_version(mci);
u32 clkodd = 0;
u32 mr;
debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n", bus_hz, hz, blklen); if (hz > 0) {
/* find lowest clkdiv yielding a rate <= than requested */
for (clkdiv=0; clkdiv<255; clkdiv++) {
if ((bus_hz / (clkdiv+1) / 2) <= hz)
break;
if (version >= 0x500) {
clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
if (clkdiv > 511)
clkdiv = 511;
clkodd = clkdiv & 1;
clkdiv >>= 1;
printf("mci: setting clock %u Hz, block size %u\n",
bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
} else {
/* find clkdiv yielding a rate <= than requested */
for (clkdiv = 0; clkdiv < 255; clkdiv++) {
if ((bus_hz / (clkdiv + 1) / 2) <= hz)
break;
}
printf("mci: setting clock %u Hz, block size %u\n",
(bus_hz / (clkdiv + 1)) / 2, blklen);
- } }
printf("mci: setting clock %u Hz, block size %u\n",
(bus_hz / (clkdiv+1)) / 2, blklen);
blklen &= 0xfffc;
/* On some platforms RDPROOF and WRPROOF are ignored */
writel((MMCI_BF(CLKDIV, clkdiv)
| MMCI_BF(BLKLEN, blklen)
| MMCI_BIT(RDPROOF)
| MMCI_BIT(WRPROOF)), &mci->mr);
- mr = MMCI_BF(CLKDIV, clkdiv);
- /* MCI IP version >= 0x200 has R/WPROOF */
- if (version >= 0x200)
mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
- /*
* On some new platforms BLKLEN in mci->mr is ignored.
* Should use the BLKLEN in the block register.
* MCI IP version >= 0x500 use bit 16 as clkodd.
*/* MCI IP version < 0x500 use upper 16 bits for blklen.
- writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
- if (version >= 0x500)
mr |= MMCI_BF(CLKODD, clkodd);
- else
mr |= MMCI_BF(BLKLEN, blklen);
- writel(mr, &mci->mr);
- /* MCI IP version >= 0x200 has blkr */
- if (version >= 0x200)
writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
- initialized = 1;
}
diff --git a/include/atmel_mci.h b/include/atmel_mci.h index 090574d..3d2870f 100644 --- a/include/atmel_mci.h +++ b/include/atmel_mci.h @@ -67,6 +67,10 @@ typedef struct atmel_mci { #define MMCI_PDCPADV_SIZE 1 #define MMCI_PDCMODE_OFFSET 15 #define MMCI_PDCMODE_SIZE 1 +/* MCI IP version >= 0x500, MR bit 16 used for CLKODD */ +#define MMCI_CLKODD_OFFSET 16 +#define MMCI_CLKODD_SIZE 1 +/* MCI IP version < 0x200, MR higher 16bits for BLKLEN */ #define MMCI_BLKLEN_OFFSET 16 #define MMCI_BLKLEN_SIZE 16
-- 1.8.5.2
Looks good.
Applied, thanks.

Add configuration register definition, this register only exists on MCI IP version >= 0x300.
Signed-off-by: Bo Shen voice.shen@atmel.com --- include/atmel_mci.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/include/atmel_mci.h b/include/atmel_mci.h index 3d2870f..de24148 100644 --- a/include/atmel_mci.h +++ b/include/atmel_mci.h @@ -36,7 +36,9 @@ typedef struct atmel_mci { u32 ier; /* 0x44 */ u32 idr; /* 0x48 */ u32 imr; /* 0x4c */ - u32 reserved[43]; + u32 dma; /* 0x50 */ + u32 cfg; /* 0x54 */ + u32 reserved[41]; u32 version; } atmel_mci_t;
@@ -189,6 +191,16 @@ typedef struct atmel_mci { #define MMCI_TRTYP_MULTI_BLOCK 1 #define MMCI_TRTYP_STREAM 2
+/* Bitfields in CFG */ +#define MMCI_FIFOMODE_OFFSET 0 +#define MMCI_FIFOMODE_SIZE 1 +#define MMCI_FERRCTRL_OFFSET 4 +#define MMCI_FERRCTRL_SIZE 1 +#define MMCI_HSMODE_OFFSET 8 +#define MMCI_HSMODE_SIZE 1 +#define MMCI_LSYNC_OFFSET 12 +#define MMCI_LSYNC_SIZE 1 + /* Bit manipulation macros */ #define MMCI_BIT(name) \ (1 << MMCI_##name##_OFFSET)

Hi Bo,
On Jul 31, 2014, at 9:39 AM, Bo Shen wrote:
Add configuration register definition, this register only exists on MCI IP version >= 0x300.
Signed-off-by: Bo Shen voice.shen@atmel.com
include/atmel_mci.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/include/atmel_mci.h b/include/atmel_mci.h index 3d2870f..de24148 100644 --- a/include/atmel_mci.h +++ b/include/atmel_mci.h @@ -36,7 +36,9 @@ typedef struct atmel_mci { u32 ier; /* 0x44 */ u32 idr; /* 0x48 */ u32 imr; /* 0x4c */
- u32 reserved[43];
- u32 dma; /* 0x50 */
- u32 cfg; /* 0x54 */
- u32 reserved[41]; u32 version;
} atmel_mci_t;
@@ -189,6 +191,16 @@ typedef struct atmel_mci { #define MMCI_TRTYP_MULTI_BLOCK 1 #define MMCI_TRTYP_STREAM 2
+/* Bitfields in CFG */ +#define MMCI_FIFOMODE_OFFSET 0 +#define MMCI_FIFOMODE_SIZE 1 +#define MMCI_FERRCTRL_OFFSET 4 +#define MMCI_FERRCTRL_SIZE 1 +#define MMCI_HSMODE_OFFSET 8 +#define MMCI_HSMODE_SIZE 1 +#define MMCI_LSYNC_OFFSET 12 +#define MMCI_LSYNC_SIZE 1
/* Bit manipulation macros */ #define MMCI_BIT(name) \ (1 << MMCI_##name##_OFFSET) -- 1.8.5.2
Applied, thanks.
-- Pantelis

If the MCI IP version >= 0x300, it supports hight speed mode option, this patch enable it.
Signed-off-by: Bo Shen voice.shen@atmel.com --- drivers/mmc/gen_atmel_mci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index 8778a4d..45bcffb 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -110,6 +110,9 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) if (version >= 0x200) writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
+ if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS) + writel(MMCI_BIT(HSMODE), &mci->cfg); + initialized = 1; }
@@ -404,8 +407,10 @@ int atmel_mci_init(void *regs) /* need to be able to pass these in on a board by board basis */ cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; version = atmel_mci_get_version(mci); - if ((version & 0xf00) >= 0x300) + if ((version & 0xf00) >= 0x300) { cfg->host_caps = MMC_MODE_8BIT; + cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; + }
cfg->host_caps |= MMC_MODE_4BIT;

Hi Bo,
On Jul 31, 2014, at 9:39 AM, Bo Shen wrote:
If the MCI IP version >= 0x300, it supports hight speed mode option, this patch enable it.
Signed-off-by: Bo Shen voice.shen@atmel.com
drivers/mmc/gen_atmel_mci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index 8778a4d..45bcffb 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -110,6 +110,9 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) if (version >= 0x200) writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
- if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
writel(MMCI_BIT(HSMODE), &mci->cfg);
- initialized = 1;
}
@@ -404,8 +407,10 @@ int atmel_mci_init(void *regs) /* need to be able to pass these in on a board by board basis */ cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; version = atmel_mci_get_version(mci);
- if ((version & 0xf00) >= 0x300)
if ((version & 0xf00) >= 0x300) { cfg->host_caps = MMC_MODE_8BIT;
cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
}
cfg->host_caps |= MMC_MODE_4BIT;
-- 1.8.5.2
Applied, thanks.
-- Pantelis
participants (2)
-
Bo Shen
-
Pantelis Antoniou