From 412cfe272238b47776d7211314af8db13fefbf3c Mon Sep 17 00:00:00 2001 From: Pavan Kunapuli Date: Thu, 1 Dec 2011 00:38:21 +0530 Subject: mmc: tegra: Enforce platform specific clk limits Some platforms cannot support higher clocks and result in CRC errors during read/write transactions. Do not exceed platform specific clk limits to prevent this. Bug 908560 Change-Id: I8bff6c6b66ee1018325f90cd7bf3061bd1bc5fdb Signed-off-by: Pavan Kunapuli Reviewed-on: http://git-master/r/67483 Reviewed-by: Sachin Nikam --- drivers/mmc/host/sdhci-tegra.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 777ea7807a3f..cef05c5baa3e 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -78,6 +78,8 @@ struct tegra_sdhci_host { unsigned int vddio_min_uv; /* vddio_max */ unsigned int vddio_max_uv; + /* max clk supported by the platform */ + unsigned int max_clk_limit; }; static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) @@ -269,6 +271,37 @@ static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) return 0; } +static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci, + unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + unsigned int clk_rate; + + if (sdhci->mmc->card && + mmc_card_ddr_mode(sdhci->mmc->card)) { + /* + * In ddr mode, tegra sdmmc controller clock frequency + * should be double the card clock frequency. + */ + clk_rate = clock * 2; + } else { + if (clock <= tegra_sdhost_min_freq) + clk_rate = tegra_sdhost_min_freq; + else if (clock <= tegra_sdhost_std_freq) + clk_rate = tegra_sdhost_std_freq; + else + clk_rate = clock; + } + + if (tegra_host->max_clk_limit && + (clk_rate > tegra_host->max_clk_limit)) + clk_rate = tegra_host->max_clk_limit; + + clk_set_rate(pltfm_host->clk, clk_rate); + sdhci->max_clk = clk_get_rate(pltfm_host->clk); +} + static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock) { int div; @@ -375,13 +408,7 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock) sdhci_writeb(sdhci, ctrl, SDHCI_VENDOR_CLOCK_CNTRL); tegra_host->clk_enabled = true; } - if (clock <= tegra_sdhost_min_freq) - clk_set_rate(pltfm_host->clk, tegra_sdhost_min_freq); - else if (clock <= tegra_sdhost_std_freq) - clk_set_rate(pltfm_host->clk, tegra_sdhost_std_freq); - else - clk_set_rate(pltfm_host->clk, clock); - sdhci->max_clk = clk_get_rate(pltfm_host->clk); + tegra_sdhci_set_clk_rate(sdhci, clock); if (tegra_host->hw_ops->set_card_clock) tegra_host->hw_ops->set_card_clock(sdhci, clock); } else if (!clock && tegra_host->clk_enabled) { @@ -622,6 +649,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) pltfm_host->clk = clk; pltfm_host->priv = tegra_host; tegra_host->clk_enabled = true; + tegra_host->max_clk_limit = plat->max_clk_limit; tegra_host->instance = pdev->id; host->mmc->pm_caps = plat->pm_flags; -- cgit v1.2.3