
Hi Kever,
On 09/30/2016 07:05 PM, Kever Yang wrote:
Hi Wenyou,
I can not enable my emmc device on my evb-rk3399 with this patch, could you help to fix it?
Here is the debug info may help:
mmc->cfg->f_max is 200000000;
[with this patch] I get host->clk_mul 16 ; When driver want to set clock to 400000, always get div 1024, and then write 0x21 to SDHCI_CLOCK_CONTROL register, mmc controller can not work because of the wrong clock rate;
[without this patch] we don't use host->clk_mul; When driver want to set clock to 400000, get div 250, and then write 0xfa01 to SDHCI_CLOCK_CONTROL register, mmc controller works OK.
If you don't use host->clk_mul, then your host controller is the lower version than V3.0..?
host->clk_mul is assigned to dummy value? Could you check this?
When i have checked Whenyou's patch, there is only difference about "host->clk_mul".
Best Regards, Jaehoon Chung
Thanks,
- Kever
On 09/18/2016 09:01 AM, Wenyou Yang wrote:
Add the programmable clock mode for the clock generator.
Signed-off-by: Wenyou Yang wenyou.yang@atmel.com
Changes in v2:
- Rebase on the latest u-boot-mmc.
- Fix the typo Muliplier->Multiplier.
drivers/mmc/sdhci.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- include/sdhci.h | 2 ++ 2 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 504f2d2..b2bf5a0 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -294,7 +294,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv;
- unsigned int div, clk, timeout, reg;
- unsigned int div, clk = 0, timeout, reg; /* Wait max 20 ms */ timeout = 200;
@@ -318,14 +318,36 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) return 0; if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
/* Version 3.00 divisors must be a multiple of 2. */
if (mmc->cfg->f_max <= clock)
div = 1;
else {
for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
if ((mmc->cfg->f_max / div) <= clock)
/*
* Check if the Host Controller supports Programmable Clock
* Mode.
*/
if (host->clk_mul) {
for (div = 1; div <= 1024; div++) {
if ((mmc->cfg->f_max * host->clk_mul / div)
<= clock) break; }
/*
* Set Programmable Clock Mode in the Clock
* Control register.
*/
clk = SDHCI_PROG_CLOCK_MODE;
div--;
} else {
/* Version 3.00 divisors must be a multiple of 2. */
if (mmc->cfg->f_max <= clock) {
div = 1;
} else {
for (div = 2;
div < SDHCI_MAX_DIV_SPEC_300;
div += 2) {
if ((mmc->cfg->f_max / div) <= clock)
break;
}
}
div >>= 1; } } else { /* Version 2.00 divisors must be a power of 2. */
@@ -333,13 +355,13 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if ((mmc->cfg->f_max / div) <= clock) break; }
div >>= 1; }
- div >>= 1; if (host->set_clock) host->set_clock(host->index, div);
- clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
- clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; clk |= SDHCI_CLOCK_INT_EN;
@@ -513,7 +535,7 @@ static const struct mmc_ops sdhci_ops = { int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 max_clk, u32 min_clk) {
- u32 caps;
- u32 caps, caps_1; caps = sdhci_readl(host, SDHCI_CAPABILITIES); @@ -577,6 +599,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
- /*
* In case of Host Controller v3.00, find out whether clock
* multiplier is supported.
*/
- caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
- host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
SDHCI_CLOCK_MUL_SHIFT;
} diff --git a/include/sdhci.h b/include/sdhci.hreturn 0;
index 6844c73..144570f 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -97,6 +97,7 @@ #define SDHCI_DIV_MASK 0xFF #define SDHCI_DIV_MASK_LEN 8 #define SDHCI_DIV_HI_MASK 0x300 +#define SDHCI_PROG_CLOCK_MODE 0x0020 #define SDHCI_CLOCK_CARD_EN 0x0004 #define SDHCI_CLOCK_INT_STABLE 0x0002 #define SDHCI_CLOCK_INT_EN 0x0001 @@ -242,6 +243,7 @@ struct sdhci_host { unsigned int quirks; unsigned int host_caps; unsigned int version;
- unsigned int clk_mul; /* Clock Multiplier value */ unsigned int clock; struct mmc *mmc; const struct sdhci_ops *ops;