[U-Boot] [PATCH v2] mmc: sdhci: Add the programmable clock mode support

Kever Yang kever.yang at rock-chips.com
Fri Sep 30 12:05:25 CEST 2016


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 <wenyou.yang at 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;
> +
>   	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;




More information about the U-Boot mailing list