* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
struct sd_scr *scr = &card->scr;
unsigned int scr_struct;
u32 resp[4];
-
resp[3] = card->raw_scr[1];
resp[2] = card->raw_scr[0];
if (scr->sda_spec3)
scr->cmds = UNSTUFF_BITS(resp, 32, 2);
+
return 0;
}
retries = 0;
goto try_again;
}
+ } else {
+ if (host->ops->validate_sd2_0) {
+ err = host->ops->validate_sd2_0(host);
+ if (err)
+ return err;
+ }
}
if (mmc_host_is_spi(host))
#define NVQUIRK2_UPDATE_HW_TUNING_CONFG BIT(1)
/* Enable Enhanced strobe mode support */
#define NVQUIRK2_EN_STROBE_SUPPORT BIT(2)
+/*controller does not support cards if 1.8 V is not supported by cards*/
+#define NVQUIRK2_BROKEN_SD2_0_SUPPORT BIT(3)
/* Common subset of quirks for Tegra3 and later sdmmc controllers */
#define TEGRA_SDHCI_NVQUIRKS (NVQUIRK_ENABLE_PADPIPE_CLKEN | \
#define SDHOST_LOW_VOLT_MAX 1800000
#define SDHOST_HIGH_VOLT_3V2 3200000
#define SDHOST_HIGH_VOLT_3V3 3300000
+#define SDHOST_MAX_VOLT_SUPPORT 3000000
/* Clock related definitions */
#define MAX_DIVISOR_VALUE 128
}
}
+static int tegra_sdhci_validate_sd2_0(struct sdhci_host *sdhci)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc));
+ const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+ struct tegra_sdhci_platform_data *plat;
+ int rc;
+
+ plat = pdev->dev.platform_data;
+
+ if ((soc_data->nvquirks2 & NVQUIRK2_BROKEN_SD2_0_SUPPORT) &&
+ (plat->limit_vddio_max_volt)) {
+ /* T210: Bug 1561291
+ * Design issue where a cap connected to IO node is stressed
+ * to 3.3v while it can only tolerate up to 1.8v.
+ */
+ rc = tegra_sdhci_configure_regulators(tegra_host,
+ CONFIG_REG_DIS, 0, 0);
+ if (rc)
+ dev_err(mmc_dev(sdhci->mmc),
+ "Regulator disable failed %d\n", rc);
+ dev_err(mmc_dev(sdhci->mmc),
+ "SD cards with out 1.8V is not supported\n");
+ return -EPERM;
+ } else {
+ return 0;
+ }
+
+}
static int tegra_sdhci_signal_voltage_switch(struct sdhci_host *sdhci,
unsigned int signal_voltage)
{
plat = tegra_host->plat;
/* set pwrdet sdmmc1 before set 3.3 V */
if ((vddio_prev < min_uV) &&
- (min_uV >= SDHOST_HIGH_VOLT_3V3)) {
+ (min_uV >= SDHOST_HIGH_VOLT_2V8)) {
if (plat->pwrdet_support)
pwr_detect_bit_write(
plat->pwrdet_bit, true);
.platform_ios_config_exit = tegra_sdhci_ios_config_exit,
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
.switch_signal_voltage = tegra_sdhci_signal_voltage_switch,
+ .validate_sd2_0 = tegra_sdhci_validate_sd2_0,
.switch_signal_voltage_exit = tegra_sdhci_do_calibration,
.execute_freq_tuning = sdhci_tegra_execute_tuning,
.sd_error_stats = sdhci_tegra_sd_error_stats,
NVQUIRK_USE_TMCLK_WR_CRC_TIMEOUT,
.nvquirks2 = NVQUIRK2_UPDATE_HW_TUNING_CONFG |
NVQUIRK2_CONFIG_PWR_DET |
+ NVQUIRK2_BROKEN_SD2_0_SUPPORT |
NVQUIRK_UPDATE_PIN_CNTRL_REG,
};
plat->pwr_off_during_lp0 = of_property_read_bool(np,
"pwr-off-during-lp0");
+ plat->limit_vddio_max_volt = of_property_read_bool(np,
+ "nvidia,limit-vddio-max-volt");
plat->mmc_data.built_in = of_property_read_bool(np, "built-in");
plat->update_pinctrl_settings = of_property_read_bool(np,
"nvidia,update-pinctrl-settings");
tegra_host->vddio_max_uv = SDHOST_HIGH_VOLT_MAX;
}
+ if (plat->limit_vddio_max_volt) {
+ tegra_host->vddio_min_uv = SDHOST_HIGH_VOLT_2V8;
+ tegra_host->vddio_max_uv = SDHOST_MAX_VOLT_SUPPORT;
+ }
tegra_host->vdd_io_reg = regulator_get(mmc_dev(host->mmc),
"vddio_sdmmc");
if (IS_ERR_OR_NULL(tegra_host->vdd_io_reg)) {
static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
static void sdhci_finish_command(struct sdhci_host *);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
+static int sdhci_validate_sd2_0(struct mmc_host *mmc);
static void sdhci_tuning_timer(unsigned long data);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
host->ops->config_tap_delay(host, option);
}
+static int sdhci_validate_sd2_0(struct mmc_host *mmc)
+{
+ struct sdhci_host *host;
+ int err = 0;
+
+ host = mmc_priv(mmc);
+
+ if (host->ops->validate_sd2_0)
+ err = host->ops->validate_sd2_0(host);
+ return err;
+}
+
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host;
.enable_sdio_irq = sdhci_enable_sdio_irq,
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.execute_tuning = sdhci_execute_tuning,
+ .validate_sd2_0 = sdhci_validate_sd2_0,
.card_event = sdhci_card_event,
.card_busy = sdhci_card_busy,
#ifdef CONFIG_MMC_FREQ_SCALING