From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kever Yang Date: Fri, 30 Sep 2016 18:05:25 +0800 Subject: [U-Boot] [PATCH v2] mmc: sdhci: Add the programmable clock mode support In-Reply-To: <1474160482-7332-1-git-send-email-wenyou.yang@atmel.com> References: <1474160482-7332-1-git-send-email-wenyou.yang@atmel.com> Message-ID: <57EE38E5.3000406@rock-chips.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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. 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 > --- > > 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; > + > return 0; > } > > diff --git a/include/sdhci.h b/include/sdhci.h > 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;