summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPavan Kunapuli <pkunapuli@nvidia.com>2013-08-16 19:22:24 +0530
committerMrutyunjay Sawant <msawant@nvidia.com>2013-08-19 10:37:21 -0700
commit80a3a19595e472381eee4624edd0dce74367b7f3 (patch)
tree959d3192963e0992108ed9ddded2d2025e5a7e2b /drivers/mmc
parent8df2d3e3fbb53c6e18fc326b4f8848bd2e3f5087 (diff)
mmc: tegra: Remove chip specific hw_ops
Removed chip specific hw_ops. There really is only one callback being used currently to handle T30 clock stabilization bug. Added a quirk2 to handle clock stabilization WAR for T30. Added nvquirk to selectively enable HS200 capability. Bug 1330567 Change-Id: I2c2e7a07677c4c4fc7262643ae94537c786110fe Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com> Reviewed-on: http://git-master/r/260565 GVS: Gerrit_Virtual_Submit Reviewed-by: Naveen Kumar Arepalli <naveenk@nvidia.com> Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci-tegra.c180
-rw-r--r--drivers/mmc/host/sdhci.c25
2 files changed, 46 insertions, 159 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index f0c28f285f8c..7296a68e48fc 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -110,32 +110,6 @@ static unsigned int uhs_max_freq_MHz[] = {
[MMC_TIMING_MMC_HS200] = 200,
};
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock);
-#endif
-
-static unsigned long get_nearest_clock_freq(unsigned long pll_rate,
- unsigned long desired_rate);
-static void sdhci_tegra_set_tap_delay(struct sdhci_host *sdhci,
- unsigned int tap_delay);
-
-struct tegra_sdhci_hw_ops {
- /* Set the internal clk and card clk.*/
- void (*set_card_clock)(struct sdhci_host *sdhci, unsigned int clock);
-};
-
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
-static struct tegra_sdhci_hw_ops tegra_2x_sdhci_ops = {
-};
-#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static struct tegra_sdhci_hw_ops tegra_3x_sdhci_ops = {
- .set_card_clock = tegra_3x_sdhci_set_card_clock,
-};
-#else
-static struct tegra_sdhci_hw_ops tegra_11x_sdhci_ops = {
-};
-#endif
-
/* Erratum: Version register is invalid in HW */
#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
/* Erratum: Enable block gap interrupt detection */
@@ -164,19 +138,16 @@ static struct tegra_sdhci_hw_ops tegra_11x_sdhci_ops = {
#define NVQUIRK_ENABLE_DDR50 BIT(12)
/* Enable Frequency Tuning for SDR50 mode */
#define NVQUIRK_ENABLE_SDR50_TUNING BIT(13)
+/* Enable HS200 mode */
+#define NVQUIRK_ENABLE_HS200 BIT(14)
/* Enable Infinite Erase Timeout*/
-#define NVQUIRK_INFINITE_ERASE_TIMEOUT BIT(14)
+#define NVQUIRK_INFINITE_ERASE_TIMEOUT BIT(15)
/* Disable AUTO CMD23 */
-#define NVQUIRK_DISABLE_AUTO_CMD23 BIT(15)
+#define NVQUIRK_DISABLE_AUTO_CMD23 BIT(16)
/* ENAABLE FEEDBACK IO CLOCK */
-#define NVQUIRK_EN_FEEDBACK_CLK BIT(16)
+#define NVQUIRK_EN_FEEDBACK_CLK BIT(17)
/* Shadow write xfer mode reg and write it alongwith CMD register */
-#define NVQUIRK_SHADOW_XFER_MODE_REG BIT(17)
-/* In SDR50 mode, run the sdmmc controller at freq greater than
- * 104MHz to ensure the core voltage is at 1.2V. If the core voltage
- * is below 1.2V, CRC errors would occur during data transfers
- */
-#define NVQUIRK_BROKEN_SDR50_CONTROLLER_CLOCK BIT(19)
+#define NVQUIRK_SHADOW_XFER_MODE_REG BIT(18)
struct sdhci_tegra_soc_data {
struct sdhci_pltfm_data *pdata;
@@ -284,8 +255,6 @@ struct sdhci_tegra {
struct regulator *vdd_io_reg;
struct regulator *vdd_slot_reg;
struct regulator *vcore_reg;
- /* Pointer to the chip specific HW ops */
- struct tegra_sdhci_hw_ops *hw_ops;
/* Host controller instance */
unsigned int instance;
/* vddio_min */
@@ -332,6 +301,11 @@ static struct clk *pll_p;
static unsigned long pll_c_rate;
static unsigned long pll_p_rate;
+static unsigned long get_nearest_clock_freq(unsigned long pll_rate,
+ unsigned long desired_rate);
+static void sdhci_tegra_set_tap_delay(struct sdhci_host *sdhci,
+ unsigned int tap_delay);
+
static int show_error_stats_dump(struct seq_file *s, void *data)
{
struct sdhci_host *host = s->private;
@@ -1052,37 +1026,20 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
struct sdhci_tegra *tegra_host = pltfm_host->priv;
- const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
unsigned int clk_rate;
- unsigned int emc_clk;
if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_DDR50) {
/*
* In ddr mode, tegra sdmmc controller clock frequency
* should be double the card clock frequency.
*/
- if (tegra_host->ddr_clk_limit) {
+ if (tegra_host->ddr_clk_limit)
clk_rate = tegra_host->ddr_clk_limit * 2;
- if (tegra_host->emc_clk) {
- emc_clk = clk_get_rate(tegra_host->emc_clk);
- if (emc_clk == tegra_host->emc_max_clk)
- clk_rate = clock * 2;
- }
- } else {
+ else
clk_rate = clock * 2;
- }
- } else if ((sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) &&
- (soc_data->nvquirks & NVQUIRK_BROKEN_SDR50_CONTROLLER_CLOCK)) {
-
- /*
- * In SDR50 mode, run the sdmmc controller at freq greater
- * than 104MHz to ensure the core voltage is at 1.2V.
- * If the core voltage is below 1.2V, CRC errors would
- * occur during data transfers.
- */
- clk_rate = clock * 2;
- } else
+ } else {
clk_rate = clock;
+ }
if (tegra_host->max_clk_limit &&
(clk_rate > tegra_host->max_clk_limit))
@@ -1118,92 +1075,6 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
}
#endif
}
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock)
-{
- int div;
- u16 clk;
- unsigned long timeout;
- u8 ctrl;
-
- if (clock && clock == sdhci->clock)
- return;
-
- /*
- * Disable the card clock before disabling the internal
- * clock to avoid abnormal clock waveforms.
- */
- clk = sdhci_readw(sdhci, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL);
- sdhci_writew(sdhci, 0, SDHCI_CLOCK_CONTROL);
-
- if (clock == 0)
- goto out;
- if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_DDR50) {
- div = 1;
- goto set_clk;
- }
-
- if (sdhci->version >= SDHCI_SPEC_300) {
- /* Version 3.00 divisors must be a multiple of 2. */
- if (sdhci->max_clk <= clock) {
- div = 1;
- } else {
- for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
- if ((sdhci->max_clk / div) <= clock)
- break;
- }
- }
- } else {
- /* Version 2.00 divisors must be a power of 2. */
- for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
- if ((sdhci->max_clk / div) <= clock)
- break;
- }
- }
- div >>= 1;
-
- /*
- * Tegra3 sdmmc controller internal clock will not be stabilized when
- * we use a clock divider value greater than 4. The WAR is as follows.
- * - Enable internal clock.
- * - Wait for 5 usec and do a dummy write.
- * - Poll for clk stable.
- */
-set_clk:
- 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;
- sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL);
-
- /* Wait for 5 usec */
- udelay(5);
-
- /* Do a dummy write */
- ctrl = sdhci_readb(sdhci, SDHCI_CAPABILITIES);
- ctrl |= 1;
- sdhci_writeb(sdhci, ctrl, SDHCI_CAPABILITIES);
-
- /* Wait max 20 ms */
- timeout = 20;
- while (!((clk = sdhci_readw(sdhci, SDHCI_CLOCK_CONTROL))
- & SDHCI_CLOCK_INT_STABLE)) {
- if (timeout == 0) {
- dev_err(mmc_dev(sdhci->mmc), "Internal clock never stabilised\n");
- return;
- }
- timeout--;
- mdelay(1);
- }
-
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL);
-out:
- sdhci->clock = clock;
-}
-#endif /* #ifdef CONFIG_ARCH_TEGRA_3x_SOC */
static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
{
@@ -1225,8 +1096,6 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
tegra_host->clk_enabled = true;
}
tegra_sdhci_set_clk_rate(sdhci, clock);
- if (tegra_host->hw_ops->set_card_clock)
- tegra_host->hw_ops->set_card_clock(sdhci, clock);
if (tegra_host->emc_clk && (!tegra_host->emc_clk_enabled)) {
clk_prepare_enable(tegra_host->emc_clk);
@@ -1248,8 +1117,6 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
tegra_host->is_sdmmc_sclk_on = false;
}
- if (tegra_host->hw_ops->set_card_clock)
- tegra_host->hw_ops->set_card_clock(sdhci, clock);
ctrl = sdhci_readb(sdhci, SDHCI_VNDR_CLK_CTRL);
ctrl &= ~SDHCI_VNDR_CLK_CTRL_SDMMC_CLK;
sdhci_writeb(sdhci, ctrl, SDHCI_VNDR_CLK_CTRL);
@@ -2378,9 +2245,6 @@ static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
#endif
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- SDHCI_QUIRK_NONSTANDARD_CLOCK |
-#endif
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
@@ -2388,6 +2252,9 @@ static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
.quirks2 = SDHCI_QUIRK2_BROKEN_PRESET_VALUES |
SDHCI_QUIRK2_NON_STD_VOLTAGE_SWITCHING |
SDHCI_QUIRK2_NON_STANDARD_TUNING |
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ SDHCI_QUIRK2_INT_CLK_STABLE_REQ_DUMMY_REG_WRITE |
+#endif
SDHCI_QUIRK2_NO_CALC_MAX_DISCARD_TO,
.ops = &tegra_sdhci_ops,
};
@@ -2417,6 +2284,7 @@ static struct sdhci_tegra_soc_data soc_data_tegra20 = {
NVQUIRK_ENABLE_DDR50 |
NVQUIRK_INFINITE_ERASE_TIMEOUT |
NVQUIRK_DISABLE_AUTO_CMD23 |
+ NVQUIRK_ENABLE_HS200 |
#endif
NVQUIRK_ENABLE_BLOCK_GAP_DET,
};
@@ -2825,17 +2693,11 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
#ifdef CONFIG_MMC_BKOPS
host->mmc->caps2 |= MMC_CAP2_BKOPS;
#endif
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
- tegra_host->hw_ops = &tegra_2x_sdhci_ops;
-#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
- tegra_host->hw_ops = &tegra_3x_sdhci_ops;
-#else
- tegra_host->hw_ops = &tegra_11x_sdhci_ops;
- host->mmc->caps2 |= MMC_CAP2_HS200;
+ if (soc_data->nvquirks & NVQUIRK_ENABLE_HS200)
+ host->mmc->caps2 |= MMC_CAP2_HS200;
host->mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
host->mmc->caps |= MMC_CAP_CMD23;
host->mmc->caps2 |= MMC_CAP2_PACKED_CMD;
-#endif
#ifdef CONFIG_MMC_FREQ_SCALING
/*
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 928126dd3654..df69b43f7066 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1076,6 +1076,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
int real_div = div, clk_mul = 1;
u16 clk = 0;
unsigned long timeout;
+ u32 caps;
if (clock && clock == host->clock)
return;
@@ -1085,6 +1086,16 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
return;
+ /*
+ * If the entire clock control register is updated with zero, some
+ * controllers might first update clock divisor fields and then update
+ * the INT_CLK_EN and CARD_CLK_EN fields. Disable card clock first
+ * to ensure there is no abnormal clock behavior.
+ */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ clk = 0;
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0)
@@ -1157,6 +1168,20 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ /*
+ * For Tegra3 sdmmc controller, internal clock will not be stable bit
+ * will get set only after some other register write is done. To
+ * handle, do a dummy reg write to the caps reg if
+ * SDHCI_QUIRK2_INT_CLK_STABLE_REQ_DUMMY_REG_WRITE is set.
+ */
+ if (host->quirks2 & SDHCI_QUIRK2_INT_CLK_STABLE_REQ_DUMMY_REG_WRITE) {
+ udelay(5);
+
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ caps |= 1;
+ sdhci_writel(host, caps, SDHCI_CAPABILITIES);
+ }
+
/* Wait max 20 ms */
timeout = 20;
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))