diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-tegra.c')
| -rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 37 | 
1 files changed, 29 insertions, 8 deletions
| diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 970d38f68939..908b23e6a03c 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -210,9 +210,24 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  	if (!clock)  		return sdhci_set_clock(host, clock); +	/* +	 * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI +	 * divider to be configured to divided the host clock by two. The SDHCI +	 * clock divider is calculated as part of sdhci_set_clock() by +	 * sdhci_calc_clk(). The divider is calculated from host->max_clk and +	 * the requested clock rate. +	 * +	 * By setting the host->max_clk to clock * 2 the divider calculation +	 * will always result in the correct value for DDR50/52 modes, +	 * regardless of clock rate rounding, which may happen if the value +	 * from clk_get_rate() is used. +	 */  	host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;  	clk_set_rate(pltfm_host->clk, host_clk); -	host->max_clk = clk_get_rate(pltfm_host->clk); +	if (tegra_host->ddr_signaling) +		host->max_clk = host_clk; +	else +		host->max_clk = clk_get_rate(pltfm_host->clk);  	sdhci_set_clock(host, clock); @@ -228,7 +243,8 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); -	if (timing == MMC_TIMING_UHS_DDR50) +	if (timing == MMC_TIMING_UHS_DDR50 || +	    timing == MMC_TIMING_MMC_DDR52)  		tegra_host->ddr_signaling = true;  	sdhci_set_uhs_signaling(host, timing); @@ -238,11 +254,7 @@ static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)  {  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	/* -	 * DDR modes require the host to run at double the card frequency, so -	 * the maximum rate we can support is half of the module input clock. -	 */ -	return clk_round_rate(pltfm_host->clk, UINT_MAX) / 2; +	return clk_round_rate(pltfm_host->clk, UINT_MAX);  }  static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) @@ -334,7 +346,16 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {  		  SDHCI_QUIRK_NO_HISPD_BIT |  		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |  		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, -	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +		   SDHCI_QUIRK2_BROKEN_HS200 | +		   /* +		    * Auto-CMD23 leads to "Got command interrupt 0x00010000 even +		    * though no command operation was in progress." +		    * +		    * The exact reason is unknown, as the same hardware seems +		    * to support Auto CMD23 on a downstream 3.1 kernel. +		    */ +		   SDHCI_QUIRK2_ACMD23_BROKEN,  	.ops  = &tegra_sdhci_ops,  }; |