]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
mmc: tegra: Update vendor IO trim control reg
authorR Raj Kumar <rrajk@nvidia.com>
Thu, 7 Aug 2014 16:07:02 +0000 (21:37 +0530)
committerTom Cherry <tcherry@nvidia.com>
Mon, 18 Aug 2014 22:57:07 +0000 (15:57 -0700)
- Add dll_calib_needed member in platform data
- Restore DLL calibration settings in resume
- Restore DQS trim delay settings in resume
- Set IB trimmer delay independent of VDD_CORE
  by clearing SEL_VREG bit in vendor IO Trim control register.
- Enable Quirks HOST_OFF_CARD_ON and USE_64BIT_ADDR

Change-Id: Iee2b94397f62feb33ae14707e43d2c1201758f70
Signed-off-by: R Raj Kumar <rrajk@nvidia.com>
Reviewed-on: http://git-master/r/456024
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Documentation/devicetree/bindings/mmc/sdhci-tegra.txt
arch/arm64/boot/dts/tegra210-platforms/tegra210-sdhci.dtsi
drivers/mmc/host/sdhci-tegra.c
include/linux/platform_data/mmc-sdhci-tegra.h

index 51153855e3d644435c170e5cded84530eff33f5c..7a25ee64be277ef8d22dcfd1c4ba9e4174c13a04 100644 (file)
@@ -40,6 +40,8 @@ Optional properties:
 - vddio_sdmmc-supply: regulator with this name
 - vddio_sd_slot-supply: regulator with this name
 - update-pinctrl-settings: flag when set using pictrl apis for updating sdmmc pins
+- nvidia,dll-calib-needed: DLL calibration is needed for SDMMC4 and SDMMC2 devices if they are enumerated
+in HS400 mode.
 
 Example:
 
@@ -62,6 +64,7 @@ Example:
                calib-3v3-offsets = <0x0202>;
                calib-1v8-offsets = <0x0202>;
                vddio_sdmmc-supply = <&max77620_sd3>;
+               nvidia,dll-calib-needed;
                status = "okay";
        };
 
index 1dec582e35a1df6a8e3e618ac8fa9d17cd30bc50..3152b5277855ec3c35e14a4a3e3602d0c49aabf5 100644 (file)
@@ -30,6 +30,7 @@
                compad-vref-1v8 = <0x7>;
                vddio_sdmmc-supply = <&max77620_sd3>;
                vddio_sd_slot-supply = <&vdd_3v3>;
+               nvidia,dll-calib-needed;
        };
 
        sdhci@700b0400 {
index 4e56a25b20ac28e333de0ebb9c21ed61bd7f5ab6..6f4a860699b341e29ef247318806953e3d69507e 100644 (file)
@@ -73,6 +73,7 @@
 
 #define SDHCI_VNDR_CAP_OVERRIDES_0                     0x10c
 #define SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_SHIFT      8
+#define SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_MASK       0x3F
 
 #define SDHCI_VNDR_MISC_CTRL                           0x120
 #define SDHCI_VNDR_MISC_CTRL_ENABLE_SDR104_SUPPORT     0x8
 #define SDMMC_VENDOR_IO_TRIM_CNTRL_0   0x1AC
 #define SDMMC_VENDOR_IO_TRIM_CNTRL_0_SEL_VREG_MASK     0x4
 
+#define SDMMC_VNDR_IO_TRIM_CNTRL_0     0x1AC
+#define SDMMC_VNDR_IO_TRIM_CNTRL_0_SEL_VREG    0x4
 /* Erratum: Version register is invalid in HW */
 #define NVQUIRK_FORCE_SDHCI_SPEC_200           BIT(0)
 /* Erratum: Enable block gap interrupt detection */
@@ -597,6 +600,7 @@ struct sdhci_tegra {
        struct pinctrl_state *schmitt_enable[2];
        struct pinctrl_state *schmitt_disable[2];
        int drive_group_sel;
+       u32 dll_calib;
 };
 
 static unsigned int boot_volt_req_refcount;
@@ -1072,9 +1076,10 @@ static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
 
        if (uhs == MMC_TIMING_MMC_HS400) {
                ctrl_2 = sdhci_readl(host, SDHCI_VNDR_CAP_OVERRIDES_0);
-               ctrl_2 &= ~(0x3F <<
+               ctrl_2 &= ~(SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_MASK <<
                        SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_SHIFT);
-               ctrl_2 |= ((plat->dqs_trim_delay & 0x3F) <<
+               ctrl_2 |= ((plat->dqs_trim_delay &
+                       SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_MASK) <<
                        SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_SHIFT);
                sdhci_writel(host, ctrl_2, SDHCI_VNDR_CAP_OVERRIDES_0);
        }
@@ -1350,6 +1355,26 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
                vendor_ctrl |= SDHCI_VNDR_TUN_CTRL_RETUNE_REQ_EN;
                sdhci_writel(host, vendor_ctrl, SDHCI_VNDR_TUN_CTRL);
        }
+       /* Restore DLL calibration and DQS Trim delay values */
+       if (plat->dll_calib_needed && tegra_host->dll_calib)
+               sdhci_writel(host, tegra_host->dll_calib,
+                               SDHCI_VNDR_DLLCAL_CFG);
+       if (plat->dqs_trim_delay) {
+               misc_ctrl = ((plat->dqs_trim_delay &
+                       SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_MASK) <<
+                       SDHCI_VNDR_CAP_OVERRIDES_0_DQS_TRIM_SHIFT);
+               sdhci_writel(host, misc_ctrl, SDHCI_VNDR_CAP_OVERRIDES_0);
+       }
+
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+       /* Enable Band Gap trimmers and VIO supply.
+        * Wait for 3usec after enabling the trimmers.
+        */
+       misc_ctrl = sdhci_readl(host, SDMMC_VNDR_IO_TRIM_CNTRL_0);
+       misc_ctrl &= ~(SDMMC_VNDR_IO_TRIM_CNTRL_0_SEL_VREG);
+       sdhci_writel(host, misc_ctrl, SDMMC_VNDR_IO_TRIM_CNTRL_0);
+       udelay(3);
+#endif
 }
 
 static int tegra_sdhci_buswidth(struct sdhci_host *sdhci, int bus_width)
@@ -1611,6 +1636,8 @@ static void tegra_sdhci_do_dll_calibration(struct sdhci_host *sdhci)
 {
        u32 dll_cfg;
        unsigned timeout = 5;
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
 
        dll_cfg = sdhci_readl(sdhci, SDHCI_VNDR_DLLCAL_CFG);
        dll_cfg |= SDHCI_VNDR_DLLCAL_CFG_EN_CALIBRATE;
@@ -1631,6 +1658,7 @@ static void tegra_sdhci_do_dll_calibration(struct sdhci_host *sdhci)
        if (!timeout) {
                dev_err(mmc_dev(sdhci->mmc), "DLL calibration is failed\n");
        }
+       tegra_host->dll_calib = sdhci_readl(sdhci, SDHCI_VNDR_DLLCAL_CFG);
 }
 
 static void tegra_sdhci_update_sdmmc_pinctrl_register(struct sdhci_host *sdhci,
@@ -4193,6 +4221,8 @@ static struct sdhci_pltfm_data sdhci_tegra21_pdata = {
                   SDHCI_QUIRK2_NON_STD_VOLTAGE_SWITCHING |
                   SDHCI_QUIRK2_NO_CALC_MAX_DISCARD_TO |
                   SDHCI_QUIRK2_REG_ACCESS_REQ_HOST_CLK |
+                  SDHCI_QUIRK2_HOST_OFF_CARD_ON |
+                  SDHCI_QUIRK2_USE_64BIT_ADDR |
                   SDHCI_QUIRK2_SUPPORT_64BIT_DMA,
        .ops  = &tegra_sdhci_ops,
 };
@@ -4264,6 +4294,7 @@ static struct tegra_sdhci_platform_data *sdhci_tegra_dt_parse_pdata(
        plat->mmc_data.built_in = of_property_read_bool(np, "built-in");
        plat->update_pinctrl_settings = of_property_read_bool(np,
                        "update-pinctrl-settings");
+       plat->dll_calib_needed = of_property_read_bool(np, "dll-calib-needed");
        plat->disable_clock_gate = of_property_read_bool(np,
                "disable-clock-gate");
        of_property_read_u8(np, "default-drv-type", &plat->default_drv_type);
index 119a38cd36d56d820dfb7bd7446c6ec6f198b138..7b41a62caf0048b2775cc2745bb0a32cc6a618ce 100644 (file)
@@ -72,6 +72,7 @@ struct tegra_sdhci_platform_data {
        bool update_pinctrl_settings;
        u32 cpu_speedo;
        unsigned char default_drv_type;
+       bool dll_calib_needed;
 };
 
 #endif