]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
mmc: sdhci: sdmmc1/3 vddio voltage changes.
authorNaveen Kumar Arepalli <naveenk@nvidia.com>
Mon, 20 Oct 2014 03:53:12 +0000 (09:23 +0530)
committerNaveen Kumar Arepalli <naveenk@nvidia.com>
Tue, 21 Oct 2014 05:29:23 +0000 (22:29 -0700)
-Enable Broken SD2.0 Support.
-Limit vddio min and max voltage to 2.8V-3.0V

Bug 1561291

Change-Id: I02e6b98374fc435c8128e284e263769cbdb6000c
Signed-off-by: Naveen Kumar Arepalli <naveenk@nvidia.com>
Reviewed-on: http://git-master/r/554180
Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
drivers/mmc/core/sd.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
include/linux/mmc/host.h
include/linux/platform_data/mmc-sdhci-tegra.h

index 50efc8f871b06fc426f15261055e0413ab715af0..c8b34224bdbba204c2c8b5f7bbda3c7cd786d9c5 100644 (file)
@@ -5,7 +5,7 @@
  *  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
@@ -184,7 +184,6 @@ static int mmc_decode_scr(struct mmc_card *card)
        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];
 
@@ -208,6 +207,7 @@ static int mmc_decode_scr(struct mmc_card *card)
 
        if (scr->sda_spec3)
                scr->cmds = UNSTUFF_BITS(resp, 32, 2);
+
        return 0;
 }
 
@@ -781,6 +781,12 @@ try_again:
                        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))
index 8e20d260763d2c4d63f6c3cfe72d8281510277d9..dad0f2585c7dd16a0aee555d675f058a08709d3b 100644 (file)
 #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
@@ -1937,6 +1940,36 @@ static void tegra_sdhci_do_calibration(struct sdhci_host *sdhci,
        }
 }
 
+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)
 {
@@ -2043,7 +2076,7 @@ static int tegra_sdhci_configure_regulators(struct sdhci_tegra *tegra_host,
                                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);
@@ -4376,6 +4409,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
        .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,
@@ -4477,6 +4511,7 @@ static struct sdhci_tegra_soc_data soc_data_tegra21 = {
                    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,
 };
 
@@ -4538,6 +4573,8 @@ static struct tegra_sdhci_platform_data *sdhci_tegra_dt_parse_pdata(
        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");
@@ -4886,6 +4923,10 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
                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)) {
index 057afd47343a2a36011489e541b5f26f23bf6251..15daf25bbdc7dbad563ab93fa1213532b8fe00a9 100644 (file)
@@ -89,6 +89,7 @@ static void sdhci_finish_data(struct sdhci_host *);
 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);
 
@@ -2238,6 +2239,18 @@ static void sdhci_config_tap(struct mmc_host *mmc, u8 option)
                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;
@@ -2662,6 +2675,7 @@ static const struct mmc_host_ops sdhci_ops = {
        .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
index 5cfc3c7d4dbc3d9ff57f6c51f517f96bbfc95591..0666b6953807dc26d88c789d3ac624b1a18ac315 100644 (file)
@@ -389,6 +389,7 @@ struct sdhci_ops {
        void    (*dump_host_cust_regs)(struct sdhci_host *host);
        int     (*get_max_tuning_loop_counter)(struct sdhci_host *sdhci);
        void    (*config_tap_delay)(struct sdhci_host *host, u8 option);
+       int     (*validate_sd2_0)(struct sdhci_host *sdhci);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
index dcf89d9d93cea705b54effa905222c596ce095fb..6c88e1d78799f8b7939fb22a7e4cbbae60a308d8 100644 (file)
@@ -145,6 +145,7 @@ struct mmc_host_ops {
 
        /* The tuning command opcode value is different for SD and eMMC cards */
        int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
+       int     (*validate_sd2_0)(struct mmc_host *host);
        int     (*select_drive_strength)(struct mmc_host *host,
                                         unsigned int max_dtr,
                                         int host_drv, int card_drv);
index 0573ed374935468981756b1d7b54fa864a478e58..29d25a1e40d30666fe483cec75ad85a7e2c3afe7 100644 (file)
@@ -83,6 +83,7 @@ struct tegra_sdhci_platform_data {
        unsigned int auto_cal_step;
        bool en_io_trim_volt;
        bool is_emmc;
+       bool limit_vddio_max_volt;
 };
 
 #endif