103d2bfc8SOlof Johansson /* 203d2bfc8SOlof Johansson * Copyright (C) 2010 Google, Inc. 303d2bfc8SOlof Johansson * 403d2bfc8SOlof Johansson * This software is licensed under the terms of the GNU General Public 503d2bfc8SOlof Johansson * License version 2, as published by the Free Software Foundation, and 603d2bfc8SOlof Johansson * may be copied, distributed, and modified under those terms. 703d2bfc8SOlof Johansson * 803d2bfc8SOlof Johansson * This program is distributed in the hope that it will be useful, 903d2bfc8SOlof Johansson * but WITHOUT ANY WARRANTY; without even the implied warranty of 1003d2bfc8SOlof Johansson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1103d2bfc8SOlof Johansson * GNU General Public License for more details. 1203d2bfc8SOlof Johansson * 1303d2bfc8SOlof Johansson */ 1403d2bfc8SOlof Johansson 15e5c63d91SLucas Stach #include <linux/delay.h> 1603d2bfc8SOlof Johansson #include <linux/err.h> 1796547f5dSPaul Gortmaker #include <linux/module.h> 1803d2bfc8SOlof Johansson #include <linux/init.h> 19e7c07148SAapo Vienamo #include <linux/iopoll.h> 2003d2bfc8SOlof Johansson #include <linux/platform_device.h> 2103d2bfc8SOlof Johansson #include <linux/clk.h> 2203d2bfc8SOlof Johansson #include <linux/io.h> 2355cd65e4SStephen Warren #include <linux/of.h> 243e44a1a7SStephen Warren #include <linux/of_device.h> 2586ac2f8bSAapo Vienamo #include <linux/pinctrl/consumer.h> 2686ac2f8bSAapo Vienamo #include <linux/regulator/consumer.h> 2720567be9SThierry Reding #include <linux/reset.h> 2803d2bfc8SOlof Johansson #include <linux/mmc/card.h> 2903d2bfc8SOlof Johansson #include <linux/mmc/host.h> 30c3c2384cSLucas Stach #include <linux/mmc/mmc.h> 310aacd23fSJoseph Lo #include <linux/mmc/slot-gpio.h> 322391b340SMylene JOSSERAND #include <linux/gpio/consumer.h> 3361dad40eSAapo Vienamo #include <linux/ktime.h> 3403d2bfc8SOlof Johansson 3503d2bfc8SOlof Johansson #include "sdhci-pltfm.h" 3603d2bfc8SOlof Johansson 37ca5879d3SPavan Kunapuli /* Tegra SDHOST controller vendor register definitions */ 3874cd42bcSLucas Stach #define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 39c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 40c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 4141a0b8d7SAapo Vienamo #define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000 4241a0b8d7SAapo Vienamo #define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24 43c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) 4474cd42bcSLucas Stach #define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3) 4574cd42bcSLucas Stach #define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2) 4674cd42bcSLucas Stach 47dfc9700cSAapo Vienamo #define SDHCI_TEGRA_VENDOR_SYS_SW_CTRL 0x104 48dfc9700cSAapo Vienamo #define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE BIT(31) 49dfc9700cSAapo Vienamo 50f5313aaaSAapo Vienamo #define SDHCI_TEGRA_VENDOR_CAP_OVERRIDES 0x10c 51f5313aaaSAapo Vienamo #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK 0x00003f00 52f5313aaaSAapo Vienamo #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT 8 53f5313aaaSAapo Vienamo 54ca5879d3SPavan Kunapuli #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 553145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8 563145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10 57ca5879d3SPavan Kunapuli #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 583145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200 59ca5879d3SPavan Kunapuli 60bc5568bfSAapo Vienamo #define SDHCI_TEGRA_VENDOR_DLLCAL_CFG 0x1b0 61bc5568bfSAapo Vienamo #define SDHCI_TEGRA_DLLCAL_CALIBRATE BIT(31) 62bc5568bfSAapo Vienamo 63bc5568bfSAapo Vienamo #define SDHCI_TEGRA_VENDOR_DLLCAL_STA 0x1bc 64bc5568bfSAapo Vienamo #define SDHCI_TEGRA_DLLCAL_STA_ACTIVE BIT(31) 65bc5568bfSAapo Vienamo 66d4501d8eSAapo Vienamo #define SDHCI_VNDR_TUN_CTRL0_0 0x1c0 67d4501d8eSAapo Vienamo #define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP 0x20000 68d4501d8eSAapo Vienamo 69e5c63d91SLucas Stach #define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4 70e5c63d91SLucas Stach #define SDHCI_AUTO_CAL_START BIT(31) 71e5c63d91SLucas Stach #define SDHCI_AUTO_CAL_ENABLE BIT(29) 7251b77c8eSAapo Vienamo #define SDHCI_AUTO_CAL_PDPU_OFFSET_MASK 0x0000ffff 73e5c63d91SLucas Stach 749d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL 0x1e0 759d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK 0x0000000f 769d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL 0x7 77212b0cf1SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD BIT(31) 789d548f11SAapo Vienamo 79e7c07148SAapo Vienamo #define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec 80e7c07148SAapo Vienamo #define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31) 81e7c07148SAapo Vienamo 823e44a1a7SStephen Warren #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) 833e44a1a7SStephen Warren #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) 84ca5879d3SPavan Kunapuli #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) 857ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_SDR50 BIT(3) 867ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_SDR104 BIT(4) 877ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_DDR50 BIT(5) 88e5c63d91SLucas Stach #define NVQUIRK_HAS_PADCALIB BIT(6) 8986ac2f8bSAapo Vienamo #define NVQUIRK_NEEDS_PAD_CONTROL BIT(7) 90d4501d8eSAapo Vienamo #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) 913e44a1a7SStephen Warren 923e44a1a7SStephen Warren struct sdhci_tegra_soc_data { 931db5eebfSLars-Peter Clausen const struct sdhci_pltfm_data *pdata; 943e44a1a7SStephen Warren u32 nvquirks; 953e44a1a7SStephen Warren }; 963e44a1a7SStephen Warren 9751b77c8eSAapo Vienamo /* Magic pull up and pull down pad calibration offsets */ 9851b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets { 9951b77c8eSAapo Vienamo u32 pull_up_3v3; 10051b77c8eSAapo Vienamo u32 pull_down_3v3; 10151b77c8eSAapo Vienamo u32 pull_up_3v3_timeout; 10251b77c8eSAapo Vienamo u32 pull_down_3v3_timeout; 10351b77c8eSAapo Vienamo u32 pull_up_1v8; 10451b77c8eSAapo Vienamo u32 pull_down_1v8; 10551b77c8eSAapo Vienamo u32 pull_up_1v8_timeout; 10651b77c8eSAapo Vienamo u32 pull_down_1v8_timeout; 10751b77c8eSAapo Vienamo u32 pull_up_sdr104; 10851b77c8eSAapo Vienamo u32 pull_down_sdr104; 10951b77c8eSAapo Vienamo u32 pull_up_hs400; 11051b77c8eSAapo Vienamo u32 pull_down_hs400; 11151b77c8eSAapo Vienamo }; 11251b77c8eSAapo Vienamo 1133e44a1a7SStephen Warren struct sdhci_tegra { 1143e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data; 1152391b340SMylene JOSSERAND struct gpio_desc *power_gpio; 116a8e326a9SLucas Stach bool ddr_signaling; 117e5c63d91SLucas Stach bool pad_calib_required; 11886ac2f8bSAapo Vienamo bool pad_control_available; 11920567be9SThierry Reding 12020567be9SThierry Reding struct reset_control *rst; 12186ac2f8bSAapo Vienamo struct pinctrl *pinctrl_sdmmc; 12286ac2f8bSAapo Vienamo struct pinctrl_state *pinctrl_state_3v3; 12386ac2f8bSAapo Vienamo struct pinctrl_state *pinctrl_state_1v8; 12451b77c8eSAapo Vienamo 12551b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets autocal_offsets; 12661dad40eSAapo Vienamo ktime_t last_calib; 12785c0da17SAapo Vienamo 12885c0da17SAapo Vienamo u32 default_tap; 12985c0da17SAapo Vienamo u32 default_trim; 130f5313aaaSAapo Vienamo u32 dqs_trim; 1313e44a1a7SStephen Warren }; 1323e44a1a7SStephen Warren 13303d2bfc8SOlof Johansson static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) 13403d2bfc8SOlof Johansson { 1353e44a1a7SStephen Warren struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1360734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1373e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 1383e44a1a7SStephen Warren 1393e44a1a7SStephen Warren if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && 1403e44a1a7SStephen Warren (reg == SDHCI_HOST_VERSION))) { 14103d2bfc8SOlof Johansson /* Erratum: Version register is invalid in HW. */ 14203d2bfc8SOlof Johansson return SDHCI_SPEC_200; 14303d2bfc8SOlof Johansson } 14403d2bfc8SOlof Johansson 14503d2bfc8SOlof Johansson return readw(host->ioaddr + reg); 14603d2bfc8SOlof Johansson } 14703d2bfc8SOlof Johansson 148352ee868SPavan Kunapuli static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg) 149352ee868SPavan Kunapuli { 150352ee868SPavan Kunapuli struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 151352ee868SPavan Kunapuli 152352ee868SPavan Kunapuli switch (reg) { 153352ee868SPavan Kunapuli case SDHCI_TRANSFER_MODE: 154352ee868SPavan Kunapuli /* 155352ee868SPavan Kunapuli * Postpone this write, we must do it together with a 156352ee868SPavan Kunapuli * command write that is down below. 157352ee868SPavan Kunapuli */ 158352ee868SPavan Kunapuli pltfm_host->xfer_mode_shadow = val; 159352ee868SPavan Kunapuli return; 160352ee868SPavan Kunapuli case SDHCI_COMMAND: 161352ee868SPavan Kunapuli writel((val << 16) | pltfm_host->xfer_mode_shadow, 162352ee868SPavan Kunapuli host->ioaddr + SDHCI_TRANSFER_MODE); 163352ee868SPavan Kunapuli return; 164352ee868SPavan Kunapuli } 165352ee868SPavan Kunapuli 166352ee868SPavan Kunapuli writew(val, host->ioaddr + reg); 167352ee868SPavan Kunapuli } 168352ee868SPavan Kunapuli 16903d2bfc8SOlof Johansson static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) 17003d2bfc8SOlof Johansson { 1713e44a1a7SStephen Warren struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1720734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1733e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 1743e44a1a7SStephen Warren 17503d2bfc8SOlof Johansson /* Seems like we're getting spurious timeout and crc errors, so 17603d2bfc8SOlof Johansson * disable signalling of them. In case of real errors software 17703d2bfc8SOlof Johansson * timers should take care of eventually detecting them. 17803d2bfc8SOlof Johansson */ 17903d2bfc8SOlof Johansson if (unlikely(reg == SDHCI_SIGNAL_ENABLE)) 18003d2bfc8SOlof Johansson val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC); 18103d2bfc8SOlof Johansson 18203d2bfc8SOlof Johansson writel(val, host->ioaddr + reg); 18303d2bfc8SOlof Johansson 1843e44a1a7SStephen Warren if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) && 1853e44a1a7SStephen Warren (reg == SDHCI_INT_ENABLE))) { 18603d2bfc8SOlof Johansson /* Erratum: Must enable block gap interrupt detection */ 18703d2bfc8SOlof Johansson u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 18803d2bfc8SOlof Johansson if (val & SDHCI_INT_CARD_INT) 18903d2bfc8SOlof Johansson gap_ctrl |= 0x8; 19003d2bfc8SOlof Johansson else 19103d2bfc8SOlof Johansson gap_ctrl &= ~0x8; 19203d2bfc8SOlof Johansson writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 19303d2bfc8SOlof Johansson } 19403d2bfc8SOlof Johansson } 19503d2bfc8SOlof Johansson 19638a284d9SAapo Vienamo static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable) 19738a284d9SAapo Vienamo { 19838a284d9SAapo Vienamo bool status; 19938a284d9SAapo Vienamo u32 reg; 20038a284d9SAapo Vienamo 20138a284d9SAapo Vienamo reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 20238a284d9SAapo Vienamo status = !!(reg & SDHCI_CLOCK_CARD_EN); 20338a284d9SAapo Vienamo 20438a284d9SAapo Vienamo if (status == enable) 20538a284d9SAapo Vienamo return status; 20638a284d9SAapo Vienamo 20738a284d9SAapo Vienamo if (enable) 20838a284d9SAapo Vienamo reg |= SDHCI_CLOCK_CARD_EN; 20938a284d9SAapo Vienamo else 21038a284d9SAapo Vienamo reg &= ~SDHCI_CLOCK_CARD_EN; 21138a284d9SAapo Vienamo 21238a284d9SAapo Vienamo sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); 21338a284d9SAapo Vienamo 21438a284d9SAapo Vienamo return status; 21538a284d9SAapo Vienamo } 21638a284d9SAapo Vienamo 21738a284d9SAapo Vienamo static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg) 21838a284d9SAapo Vienamo { 21938a284d9SAapo Vienamo bool is_tuning_cmd = 0; 22038a284d9SAapo Vienamo bool clk_enabled; 22138a284d9SAapo Vienamo u8 cmd; 22238a284d9SAapo Vienamo 22338a284d9SAapo Vienamo if (reg == SDHCI_COMMAND) { 22438a284d9SAapo Vienamo cmd = SDHCI_GET_CMD(val); 22538a284d9SAapo Vienamo is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK || 22638a284d9SAapo Vienamo cmd == MMC_SEND_TUNING_BLOCK_HS200; 22738a284d9SAapo Vienamo } 22838a284d9SAapo Vienamo 22938a284d9SAapo Vienamo if (is_tuning_cmd) 23038a284d9SAapo Vienamo clk_enabled = tegra_sdhci_configure_card_clk(host, 0); 23138a284d9SAapo Vienamo 23238a284d9SAapo Vienamo writew(val, host->ioaddr + reg); 23338a284d9SAapo Vienamo 23438a284d9SAapo Vienamo if (is_tuning_cmd) { 23538a284d9SAapo Vienamo udelay(1); 23638a284d9SAapo Vienamo tegra_sdhci_configure_card_clk(host, clk_enabled); 23738a284d9SAapo Vienamo } 23838a284d9SAapo Vienamo } 23938a284d9SAapo Vienamo 2403e44a1a7SStephen Warren static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) 24103d2bfc8SOlof Johansson { 2420aacd23fSJoseph Lo return mmc_gpio_get_ro(host->mmc); 24303d2bfc8SOlof Johansson } 24403d2bfc8SOlof Johansson 24586ac2f8bSAapo Vienamo static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host) 24686ac2f8bSAapo Vienamo { 24786ac2f8bSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 24886ac2f8bSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 24986ac2f8bSAapo Vienamo int has_1v8, has_3v3; 25086ac2f8bSAapo Vienamo 25186ac2f8bSAapo Vienamo /* 25286ac2f8bSAapo Vienamo * The SoCs which have NVQUIRK_NEEDS_PAD_CONTROL require software pad 25386ac2f8bSAapo Vienamo * voltage configuration in order to perform voltage switching. This 25486ac2f8bSAapo Vienamo * means that valid pinctrl info is required on SDHCI instances capable 25586ac2f8bSAapo Vienamo * of performing voltage switching. Whether or not an SDHCI instance is 25686ac2f8bSAapo Vienamo * capable of voltage switching is determined based on the regulator. 25786ac2f8bSAapo Vienamo */ 25886ac2f8bSAapo Vienamo 25986ac2f8bSAapo Vienamo if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)) 26086ac2f8bSAapo Vienamo return true; 26186ac2f8bSAapo Vienamo 26286ac2f8bSAapo Vienamo if (IS_ERR(host->mmc->supply.vqmmc)) 26386ac2f8bSAapo Vienamo return false; 26486ac2f8bSAapo Vienamo 26586ac2f8bSAapo Vienamo has_1v8 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 26686ac2f8bSAapo Vienamo 1700000, 1950000); 26786ac2f8bSAapo Vienamo 26886ac2f8bSAapo Vienamo has_3v3 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 26986ac2f8bSAapo Vienamo 2700000, 3600000); 27086ac2f8bSAapo Vienamo 27186ac2f8bSAapo Vienamo if (has_1v8 == 1 && has_3v3 == 1) 27286ac2f8bSAapo Vienamo return tegra_host->pad_control_available; 27386ac2f8bSAapo Vienamo 27486ac2f8bSAapo Vienamo /* Fixed voltage, no pad control required. */ 27586ac2f8bSAapo Vienamo return true; 27686ac2f8bSAapo Vienamo } 27786ac2f8bSAapo Vienamo 278c2c09678SAapo Vienamo static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) 279c2c09678SAapo Vienamo { 280c2c09678SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 281c2c09678SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 282c2c09678SAapo Vienamo const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 283c2c09678SAapo Vienamo bool card_clk_enabled = false; 284c2c09678SAapo Vienamo u32 reg; 285c2c09678SAapo Vienamo 286c2c09678SAapo Vienamo /* 287c2c09678SAapo Vienamo * Touching the tap values is a bit tricky on some SoC generations. 288c2c09678SAapo Vienamo * The quirk enables a workaround for a glitch that sometimes occurs if 289c2c09678SAapo Vienamo * the tap values are changed. 290c2c09678SAapo Vienamo */ 291c2c09678SAapo Vienamo 292c2c09678SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP) 293c2c09678SAapo Vienamo card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); 294c2c09678SAapo Vienamo 295c2c09678SAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 296c2c09678SAapo Vienamo reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; 297c2c09678SAapo Vienamo reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; 298c2c09678SAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 299c2c09678SAapo Vienamo 300c2c09678SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP && 301c2c09678SAapo Vienamo card_clk_enabled) { 302c2c09678SAapo Vienamo udelay(1); 303c2c09678SAapo Vienamo sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 304c2c09678SAapo Vienamo tegra_sdhci_configure_card_clk(host, card_clk_enabled); 305c2c09678SAapo Vienamo } 306c2c09678SAapo Vienamo } 307c2c09678SAapo Vienamo 308dfc9700cSAapo Vienamo static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, 309dfc9700cSAapo Vienamo struct mmc_ios *ios) 310dfc9700cSAapo Vienamo { 311dfc9700cSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 312dfc9700cSAapo Vienamo u32 val; 313dfc9700cSAapo Vienamo 314dfc9700cSAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); 315dfc9700cSAapo Vienamo 316dfc9700cSAapo Vienamo if (ios->enhanced_strobe) 317dfc9700cSAapo Vienamo val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; 318dfc9700cSAapo Vienamo else 319dfc9700cSAapo Vienamo val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; 320dfc9700cSAapo Vienamo 321dfc9700cSAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); 322dfc9700cSAapo Vienamo 323dfc9700cSAapo Vienamo } 324dfc9700cSAapo Vienamo 32503231f9bSRussell King static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) 326ca5879d3SPavan Kunapuli { 327ca5879d3SPavan Kunapuli struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 3280734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 329ca5879d3SPavan Kunapuli const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 3309d548f11SAapo Vienamo u32 misc_ctrl, clk_ctrl, pad_ctrl; 331ca5879d3SPavan Kunapuli 33203231f9bSRussell King sdhci_reset(host, mask); 33303231f9bSRussell King 334ca5879d3SPavan Kunapuli if (!(mask & SDHCI_RESET_ALL)) 335ca5879d3SPavan Kunapuli return; 336ca5879d3SPavan Kunapuli 337c2c09678SAapo Vienamo tegra_sdhci_set_tap(host, tegra_host->default_tap); 338c2c09678SAapo Vienamo 3391b84def8SLucas Stach misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); 3404f6aa326SJon Hunter clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 3414f6aa326SJon Hunter 3424f6aa326SJon Hunter misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 | 3434f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_SDR50 | 3444f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_DDR50 | 3454f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_SDR104); 3464f6aa326SJon Hunter 34741a0b8d7SAapo Vienamo clk_ctrl &= ~(SDHCI_CLOCK_CTRL_TRIM_MASK | 34841a0b8d7SAapo Vienamo SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE); 3494f6aa326SJon Hunter 35086ac2f8bSAapo Vienamo if (tegra_sdhci_is_pad_and_regulator_valid(host)) { 351ca5879d3SPavan Kunapuli /* Erratum: Enable SDHCI spec v3.00 support */ 3523145351aSAndrew Bresticker if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) 353ca5879d3SPavan Kunapuli misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; 3547ad2ed1dSLucas Stach /* Advertise UHS modes as supported by host */ 3557ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) 3567ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; 3577ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 3587ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; 3597ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) 3607ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; 3617ad2ed1dSLucas Stach if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) 362c3c2384cSLucas Stach clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; 3634f6aa326SJon Hunter } 3644f6aa326SJon Hunter 36541a0b8d7SAapo Vienamo clk_ctrl |= tegra_host->default_trim << SDHCI_CLOCK_CTRL_TRIM_SHIFT; 36641a0b8d7SAapo Vienamo 3674f6aa326SJon Hunter sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); 36874cd42bcSLucas Stach sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 36974cd42bcSLucas Stach 3709d548f11SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) { 3719d548f11SAapo Vienamo pad_ctrl = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 3729d548f11SAapo Vienamo pad_ctrl &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK; 3739d548f11SAapo Vienamo pad_ctrl |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL; 3749d548f11SAapo Vienamo sdhci_writel(host, pad_ctrl, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 3759d548f11SAapo Vienamo 376e5c63d91SLucas Stach tegra_host->pad_calib_required = true; 3779d548f11SAapo Vienamo } 378e5c63d91SLucas Stach 379a8e326a9SLucas Stach tegra_host->ddr_signaling = false; 380ca5879d3SPavan Kunapuli } 381ca5879d3SPavan Kunapuli 382212b0cf1SAapo Vienamo static void tegra_sdhci_configure_cal_pad(struct sdhci_host *host, bool enable) 383212b0cf1SAapo Vienamo { 384212b0cf1SAapo Vienamo u32 val; 385212b0cf1SAapo Vienamo 386212b0cf1SAapo Vienamo /* 387212b0cf1SAapo Vienamo * Enable or disable the additional I/O pad used by the drive strength 388212b0cf1SAapo Vienamo * calibration process. 389212b0cf1SAapo Vienamo */ 390212b0cf1SAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 391212b0cf1SAapo Vienamo 392212b0cf1SAapo Vienamo if (enable) 393212b0cf1SAapo Vienamo val |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; 394212b0cf1SAapo Vienamo else 395212b0cf1SAapo Vienamo val &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; 396212b0cf1SAapo Vienamo 397212b0cf1SAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 398212b0cf1SAapo Vienamo 399212b0cf1SAapo Vienamo if (enable) 400212b0cf1SAapo Vienamo usleep_range(1, 2); 401212b0cf1SAapo Vienamo } 402212b0cf1SAapo Vienamo 40351b77c8eSAapo Vienamo static void tegra_sdhci_set_pad_autocal_offset(struct sdhci_host *host, 40451b77c8eSAapo Vienamo u16 pdpu) 40551b77c8eSAapo Vienamo { 40651b77c8eSAapo Vienamo u32 reg; 40751b77c8eSAapo Vienamo 40851b77c8eSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 40951b77c8eSAapo Vienamo reg &= ~SDHCI_AUTO_CAL_PDPU_OFFSET_MASK; 41051b77c8eSAapo Vienamo reg |= pdpu; 41151b77c8eSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 41251b77c8eSAapo Vienamo } 41351b77c8eSAapo Vienamo 414e5c63d91SLucas Stach static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) 415e5c63d91SLucas Stach { 41651b77c8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 41751b77c8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 41851b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets offsets = 41951b77c8eSAapo Vienamo tegra_host->autocal_offsets; 42051b77c8eSAapo Vienamo struct mmc_ios *ios = &host->mmc->ios; 421887bda8fSAapo Vienamo bool card_clk_enabled; 42251b77c8eSAapo Vienamo u16 pdpu; 423e7c07148SAapo Vienamo u32 reg; 424e7c07148SAapo Vienamo int ret; 425e5c63d91SLucas Stach 42651b77c8eSAapo Vienamo switch (ios->timing) { 42751b77c8eSAapo Vienamo case MMC_TIMING_UHS_SDR104: 42851b77c8eSAapo Vienamo pdpu = offsets.pull_down_sdr104 << 8 | offsets.pull_up_sdr104; 42951b77c8eSAapo Vienamo break; 43051b77c8eSAapo Vienamo case MMC_TIMING_MMC_HS400: 43151b77c8eSAapo Vienamo pdpu = offsets.pull_down_hs400 << 8 | offsets.pull_up_hs400; 43251b77c8eSAapo Vienamo break; 43351b77c8eSAapo Vienamo default: 43451b77c8eSAapo Vienamo if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) 43551b77c8eSAapo Vienamo pdpu = offsets.pull_down_1v8 << 8 | offsets.pull_up_1v8; 43651b77c8eSAapo Vienamo else 43751b77c8eSAapo Vienamo pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3; 43851b77c8eSAapo Vienamo } 43951b77c8eSAapo Vienamo 44051b77c8eSAapo Vienamo tegra_sdhci_set_pad_autocal_offset(host, pdpu); 44151b77c8eSAapo Vienamo 442887bda8fSAapo Vienamo card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); 443887bda8fSAapo Vienamo 444212b0cf1SAapo Vienamo tegra_sdhci_configure_cal_pad(host, true); 445212b0cf1SAapo Vienamo 446e7c07148SAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 447e7c07148SAapo Vienamo reg |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START; 448e7c07148SAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 449e5c63d91SLucas Stach 450e7c07148SAapo Vienamo usleep_range(1, 2); 451e7c07148SAapo Vienamo /* 10 ms timeout */ 452e7c07148SAapo Vienamo ret = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_AUTO_CAL_STATUS, 453e7c07148SAapo Vienamo reg, !(reg & SDHCI_TEGRA_AUTO_CAL_ACTIVE), 454e7c07148SAapo Vienamo 1000, 10000); 455e7c07148SAapo Vienamo 456212b0cf1SAapo Vienamo tegra_sdhci_configure_cal_pad(host, false); 457212b0cf1SAapo Vienamo 458887bda8fSAapo Vienamo tegra_sdhci_configure_card_clk(host, card_clk_enabled); 459887bda8fSAapo Vienamo 46051b77c8eSAapo Vienamo if (ret) { 461e7c07148SAapo Vienamo dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n"); 46251b77c8eSAapo Vienamo 46351b77c8eSAapo Vienamo if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) 46451b77c8eSAapo Vienamo pdpu = offsets.pull_down_1v8_timeout << 8 | 46551b77c8eSAapo Vienamo offsets.pull_up_1v8_timeout; 46651b77c8eSAapo Vienamo else 46751b77c8eSAapo Vienamo pdpu = offsets.pull_down_3v3_timeout << 8 | 46851b77c8eSAapo Vienamo offsets.pull_up_3v3_timeout; 46951b77c8eSAapo Vienamo 47051b77c8eSAapo Vienamo /* Disable automatic calibration and use fixed offsets */ 47151b77c8eSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 47251b77c8eSAapo Vienamo reg &= ~SDHCI_AUTO_CAL_ENABLE; 47351b77c8eSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 47451b77c8eSAapo Vienamo 47551b77c8eSAapo Vienamo tegra_sdhci_set_pad_autocal_offset(host, pdpu); 47651b77c8eSAapo Vienamo } 47751b77c8eSAapo Vienamo } 47851b77c8eSAapo Vienamo 47951b77c8eSAapo Vienamo static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host) 48051b77c8eSAapo Vienamo { 48151b77c8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 48251b77c8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 48351b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets *autocal = 48451b77c8eSAapo Vienamo &tegra_host->autocal_offsets; 48551b77c8eSAapo Vienamo int err; 48651b77c8eSAapo Vienamo 48751b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 48851b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-3v3", 48951b77c8eSAapo Vienamo &autocal->pull_up_3v3); 49051b77c8eSAapo Vienamo if (err) 49151b77c8eSAapo Vienamo autocal->pull_up_3v3 = 0; 49251b77c8eSAapo Vienamo 49351b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 49451b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-3v3", 49551b77c8eSAapo Vienamo &autocal->pull_down_3v3); 49651b77c8eSAapo Vienamo if (err) 49751b77c8eSAapo Vienamo autocal->pull_down_3v3 = 0; 49851b77c8eSAapo Vienamo 49951b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 50051b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-1v8", 50151b77c8eSAapo Vienamo &autocal->pull_up_1v8); 50251b77c8eSAapo Vienamo if (err) 50351b77c8eSAapo Vienamo autocal->pull_up_1v8 = 0; 50451b77c8eSAapo Vienamo 50551b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 50651b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-1v8", 50751b77c8eSAapo Vienamo &autocal->pull_down_1v8); 50851b77c8eSAapo Vienamo if (err) 50951b77c8eSAapo Vienamo autocal->pull_down_1v8 = 0; 51051b77c8eSAapo Vienamo 51151b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 51251b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-3v3-timeout", 5135ccf7f55SSowjanya Komatineni &autocal->pull_up_3v3_timeout); 51451b77c8eSAapo Vienamo if (err) 51551b77c8eSAapo Vienamo autocal->pull_up_3v3_timeout = 0; 51651b77c8eSAapo Vienamo 51751b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 51851b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-3v3-timeout", 5195ccf7f55SSowjanya Komatineni &autocal->pull_down_3v3_timeout); 52051b77c8eSAapo Vienamo if (err) 52151b77c8eSAapo Vienamo autocal->pull_down_3v3_timeout = 0; 52251b77c8eSAapo Vienamo 52351b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 52451b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-1v8-timeout", 5255ccf7f55SSowjanya Komatineni &autocal->pull_up_1v8_timeout); 52651b77c8eSAapo Vienamo if (err) 52751b77c8eSAapo Vienamo autocal->pull_up_1v8_timeout = 0; 52851b77c8eSAapo Vienamo 52951b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 53051b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-1v8-timeout", 5315ccf7f55SSowjanya Komatineni &autocal->pull_down_1v8_timeout); 53251b77c8eSAapo Vienamo if (err) 53351b77c8eSAapo Vienamo autocal->pull_down_1v8_timeout = 0; 53451b77c8eSAapo Vienamo 53551b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 53651b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-sdr104", 53751b77c8eSAapo Vienamo &autocal->pull_up_sdr104); 53851b77c8eSAapo Vienamo if (err) 53951b77c8eSAapo Vienamo autocal->pull_up_sdr104 = autocal->pull_up_1v8; 54051b77c8eSAapo Vienamo 54151b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 54251b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-sdr104", 54351b77c8eSAapo Vienamo &autocal->pull_down_sdr104); 54451b77c8eSAapo Vienamo if (err) 54551b77c8eSAapo Vienamo autocal->pull_down_sdr104 = autocal->pull_down_1v8; 54651b77c8eSAapo Vienamo 54751b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 54851b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-hs400", 54951b77c8eSAapo Vienamo &autocal->pull_up_hs400); 55051b77c8eSAapo Vienamo if (err) 55151b77c8eSAapo Vienamo autocal->pull_up_hs400 = autocal->pull_up_1v8; 55251b77c8eSAapo Vienamo 55351b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 55451b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-hs400", 55551b77c8eSAapo Vienamo &autocal->pull_down_hs400); 55651b77c8eSAapo Vienamo if (err) 55751b77c8eSAapo Vienamo autocal->pull_down_hs400 = autocal->pull_down_1v8; 558e5c63d91SLucas Stach } 559e5c63d91SLucas Stach 56061dad40eSAapo Vienamo static void tegra_sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) 56161dad40eSAapo Vienamo { 56261dad40eSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 56361dad40eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 56461dad40eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 56561dad40eSAapo Vienamo ktime_t since_calib = ktime_sub(ktime_get(), tegra_host->last_calib); 56661dad40eSAapo Vienamo 56761dad40eSAapo Vienamo /* 100 ms calibration interval is specified in the TRM */ 56861dad40eSAapo Vienamo if (ktime_to_ms(since_calib) > 100) { 56961dad40eSAapo Vienamo tegra_sdhci_pad_autocalib(host); 57061dad40eSAapo Vienamo tegra_host->last_calib = ktime_get(); 57161dad40eSAapo Vienamo } 57261dad40eSAapo Vienamo 57361dad40eSAapo Vienamo sdhci_request(mmc, mrq); 57461dad40eSAapo Vienamo } 57561dad40eSAapo Vienamo 576f5313aaaSAapo Vienamo static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host) 57785c0da17SAapo Vienamo { 57885c0da17SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 57985c0da17SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 58085c0da17SAapo Vienamo int err; 58185c0da17SAapo Vienamo 58285c0da17SAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,default-tap", 58385c0da17SAapo Vienamo &tegra_host->default_tap); 58485c0da17SAapo Vienamo if (err) 58585c0da17SAapo Vienamo tegra_host->default_tap = 0; 58685c0da17SAapo Vienamo 58785c0da17SAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,default-trim", 58885c0da17SAapo Vienamo &tegra_host->default_trim); 58985c0da17SAapo Vienamo if (err) 59085c0da17SAapo Vienamo tegra_host->default_trim = 0; 591f5313aaaSAapo Vienamo 592f5313aaaSAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim", 593f5313aaaSAapo Vienamo &tegra_host->dqs_trim); 594f5313aaaSAapo Vienamo if (err) 595f5313aaaSAapo Vienamo tegra_host->dqs_trim = 0x11; 59685c0da17SAapo Vienamo } 59785c0da17SAapo Vienamo 598a8e326a9SLucas Stach static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 599a8e326a9SLucas Stach { 600a8e326a9SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 6010734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 602a8e326a9SLucas Stach unsigned long host_clk; 603a8e326a9SLucas Stach 604a8e326a9SLucas Stach if (!clock) 6053491b690SLucas Stach return sdhci_set_clock(host, clock); 606a8e326a9SLucas Stach 60757d1654eSAapo Vienamo /* 60857d1654eSAapo Vienamo * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI 60957d1654eSAapo Vienamo * divider to be configured to divided the host clock by two. The SDHCI 61057d1654eSAapo Vienamo * clock divider is calculated as part of sdhci_set_clock() by 61157d1654eSAapo Vienamo * sdhci_calc_clk(). The divider is calculated from host->max_clk and 61257d1654eSAapo Vienamo * the requested clock rate. 61357d1654eSAapo Vienamo * 61457d1654eSAapo Vienamo * By setting the host->max_clk to clock * 2 the divider calculation 61557d1654eSAapo Vienamo * will always result in the correct value for DDR50/52 modes, 61657d1654eSAapo Vienamo * regardless of clock rate rounding, which may happen if the value 61757d1654eSAapo Vienamo * from clk_get_rate() is used. 61857d1654eSAapo Vienamo */ 619a8e326a9SLucas Stach host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; 620a8e326a9SLucas Stach clk_set_rate(pltfm_host->clk, host_clk); 62157d1654eSAapo Vienamo if (tegra_host->ddr_signaling) 62257d1654eSAapo Vienamo host->max_clk = host_clk; 62357d1654eSAapo Vienamo else 624a8e326a9SLucas Stach host->max_clk = clk_get_rate(pltfm_host->clk); 625a8e326a9SLucas Stach 626e5c63d91SLucas Stach sdhci_set_clock(host, clock); 627e5c63d91SLucas Stach 628e5c63d91SLucas Stach if (tegra_host->pad_calib_required) { 629e5c63d91SLucas Stach tegra_sdhci_pad_autocalib(host); 630e5c63d91SLucas Stach tegra_host->pad_calib_required = false; 631e5c63d91SLucas Stach } 632a8e326a9SLucas Stach } 633a8e326a9SLucas Stach 63444350993SAapo Vienamo static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) 63544350993SAapo Vienamo { 63644350993SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 63744350993SAapo Vienamo 63844350993SAapo Vienamo return clk_round_rate(pltfm_host->clk, UINT_MAX); 63944350993SAapo Vienamo } 64044350993SAapo Vienamo 641f5313aaaSAapo Vienamo static void tegra_sdhci_set_dqs_trim(struct sdhci_host *host, u8 trim) 642f5313aaaSAapo Vienamo { 643f5313aaaSAapo Vienamo u32 val; 644f5313aaaSAapo Vienamo 645f5313aaaSAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); 646f5313aaaSAapo Vienamo val &= ~SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK; 647f5313aaaSAapo Vienamo val |= trim << SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT; 648f5313aaaSAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); 649f5313aaaSAapo Vienamo } 650f5313aaaSAapo Vienamo 651bc5568bfSAapo Vienamo static void tegra_sdhci_hs400_dll_cal(struct sdhci_host *host) 652bc5568bfSAapo Vienamo { 653bc5568bfSAapo Vienamo u32 reg; 654bc5568bfSAapo Vienamo int err; 655bc5568bfSAapo Vienamo 656bc5568bfSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); 657bc5568bfSAapo Vienamo reg |= SDHCI_TEGRA_DLLCAL_CALIBRATE; 658bc5568bfSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); 659bc5568bfSAapo Vienamo 660bc5568bfSAapo Vienamo /* 1 ms sleep, 5 ms timeout */ 661bc5568bfSAapo Vienamo err = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_VENDOR_DLLCAL_STA, 662bc5568bfSAapo Vienamo reg, !(reg & SDHCI_TEGRA_DLLCAL_STA_ACTIVE), 663bc5568bfSAapo Vienamo 1000, 5000); 664bc5568bfSAapo Vienamo if (err) 665bc5568bfSAapo Vienamo dev_err(mmc_dev(host->mmc), 666bc5568bfSAapo Vienamo "HS400 delay line calibration timed out\n"); 667bc5568bfSAapo Vienamo } 668bc5568bfSAapo Vienamo 669c2c09678SAapo Vienamo static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, 670c2c09678SAapo Vienamo unsigned timing) 671c3c2384cSLucas Stach { 672d4501d8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 673d4501d8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 674c2c09678SAapo Vienamo bool set_default_tap = false; 675f5313aaaSAapo Vienamo bool set_dqs_trim = false; 676bc5568bfSAapo Vienamo bool do_hs400_dll_cal = false; 677c3c2384cSLucas Stach 678c2c09678SAapo Vienamo switch (timing) { 679c2c09678SAapo Vienamo case MMC_TIMING_UHS_SDR50: 680c2c09678SAapo Vienamo case MMC_TIMING_UHS_SDR104: 681c2c09678SAapo Vienamo case MMC_TIMING_MMC_HS200: 682c2c09678SAapo Vienamo /* Don't set default tap on tunable modes. */ 683c2c09678SAapo Vienamo break; 684f5313aaaSAapo Vienamo case MMC_TIMING_MMC_HS400: 685f5313aaaSAapo Vienamo set_dqs_trim = true; 686bc5568bfSAapo Vienamo do_hs400_dll_cal = true; 687f5313aaaSAapo Vienamo break; 688c2c09678SAapo Vienamo case MMC_TIMING_MMC_DDR52: 689c2c09678SAapo Vienamo case MMC_TIMING_UHS_DDR50: 690c2c09678SAapo Vienamo tegra_host->ddr_signaling = true; 691c2c09678SAapo Vienamo set_default_tap = true; 692c2c09678SAapo Vienamo break; 693c2c09678SAapo Vienamo default: 694c2c09678SAapo Vienamo set_default_tap = true; 695c2c09678SAapo Vienamo break; 696d4501d8eSAapo Vienamo } 697c2c09678SAapo Vienamo 698c2c09678SAapo Vienamo sdhci_set_uhs_signaling(host, timing); 699c2c09678SAapo Vienamo 700c2c09678SAapo Vienamo tegra_sdhci_pad_autocalib(host); 701c2c09678SAapo Vienamo 702c2c09678SAapo Vienamo if (set_default_tap) 703c2c09678SAapo Vienamo tegra_sdhci_set_tap(host, tegra_host->default_tap); 704f5313aaaSAapo Vienamo 705f5313aaaSAapo Vienamo if (set_dqs_trim) 706f5313aaaSAapo Vienamo tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim); 707bc5568bfSAapo Vienamo 708bc5568bfSAapo Vienamo if (do_hs400_dll_cal) 709bc5568bfSAapo Vienamo tegra_sdhci_hs400_dll_cal(host); 710c3c2384cSLucas Stach } 711c3c2384cSLucas Stach 712c3c2384cSLucas Stach static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) 713c3c2384cSLucas Stach { 714c3c2384cSLucas Stach unsigned int min, max; 715c3c2384cSLucas Stach 716c3c2384cSLucas Stach /* 717c3c2384cSLucas Stach * Start search for minimum tap value at 10, as smaller values are 718c3c2384cSLucas Stach * may wrongly be reported as working but fail at higher speeds, 719c3c2384cSLucas Stach * according to the TRM. 720c3c2384cSLucas Stach */ 721c3c2384cSLucas Stach min = 10; 722c3c2384cSLucas Stach while (min < 255) { 723c3c2384cSLucas Stach tegra_sdhci_set_tap(host, min); 724c3c2384cSLucas Stach if (!mmc_send_tuning(host->mmc, opcode, NULL)) 725c3c2384cSLucas Stach break; 726c3c2384cSLucas Stach min++; 727c3c2384cSLucas Stach } 728c3c2384cSLucas Stach 729c3c2384cSLucas Stach /* Find the maximum tap value that still passes. */ 730c3c2384cSLucas Stach max = min + 1; 731c3c2384cSLucas Stach while (max < 255) { 732c3c2384cSLucas Stach tegra_sdhci_set_tap(host, max); 733c3c2384cSLucas Stach if (mmc_send_tuning(host->mmc, opcode, NULL)) { 734c3c2384cSLucas Stach max--; 735c3c2384cSLucas Stach break; 736c3c2384cSLucas Stach } 737c3c2384cSLucas Stach max++; 738c3c2384cSLucas Stach } 739c3c2384cSLucas Stach 740c3c2384cSLucas Stach /* The TRM states the ideal tap value is at 75% in the passing range. */ 741c3c2384cSLucas Stach tegra_sdhci_set_tap(host, min + ((max - min) * 3 / 4)); 742c3c2384cSLucas Stach 743c3c2384cSLucas Stach return mmc_send_tuning(host->mmc, opcode, NULL); 744c3c2384cSLucas Stach } 745c3c2384cSLucas Stach 74686ac2f8bSAapo Vienamo static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage) 74786ac2f8bSAapo Vienamo { 74886ac2f8bSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 74986ac2f8bSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 75086ac2f8bSAapo Vienamo int ret; 75186ac2f8bSAapo Vienamo 75286ac2f8bSAapo Vienamo if (!tegra_host->pad_control_available) 75386ac2f8bSAapo Vienamo return 0; 75486ac2f8bSAapo Vienamo 75586ac2f8bSAapo Vienamo if (voltage == MMC_SIGNAL_VOLTAGE_180) { 75686ac2f8bSAapo Vienamo ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 75786ac2f8bSAapo Vienamo tegra_host->pinctrl_state_1v8); 75886ac2f8bSAapo Vienamo if (ret < 0) 75986ac2f8bSAapo Vienamo dev_err(mmc_dev(host->mmc), 76086ac2f8bSAapo Vienamo "setting 1.8V failed, ret: %d\n", ret); 76186ac2f8bSAapo Vienamo } else { 76286ac2f8bSAapo Vienamo ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 76386ac2f8bSAapo Vienamo tegra_host->pinctrl_state_3v3); 76486ac2f8bSAapo Vienamo if (ret < 0) 76586ac2f8bSAapo Vienamo dev_err(mmc_dev(host->mmc), 76686ac2f8bSAapo Vienamo "setting 3.3V failed, ret: %d\n", ret); 76786ac2f8bSAapo Vienamo } 76886ac2f8bSAapo Vienamo 76986ac2f8bSAapo Vienamo return ret; 77086ac2f8bSAapo Vienamo } 77186ac2f8bSAapo Vienamo 77286ac2f8bSAapo Vienamo static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, 77386ac2f8bSAapo Vienamo struct mmc_ios *ios) 77486ac2f8bSAapo Vienamo { 77586ac2f8bSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 77644babea2SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 77744babea2SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 77886ac2f8bSAapo Vienamo int ret = 0; 77986ac2f8bSAapo Vienamo 78086ac2f8bSAapo Vienamo if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 78186ac2f8bSAapo Vienamo ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); 78286ac2f8bSAapo Vienamo if (ret < 0) 78386ac2f8bSAapo Vienamo return ret; 78486ac2f8bSAapo Vienamo ret = sdhci_start_signal_voltage_switch(mmc, ios); 78586ac2f8bSAapo Vienamo } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { 78686ac2f8bSAapo Vienamo ret = sdhci_start_signal_voltage_switch(mmc, ios); 78786ac2f8bSAapo Vienamo if (ret < 0) 78886ac2f8bSAapo Vienamo return ret; 78986ac2f8bSAapo Vienamo ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); 79086ac2f8bSAapo Vienamo } 79186ac2f8bSAapo Vienamo 79244babea2SAapo Vienamo if (tegra_host->pad_calib_required) 79344babea2SAapo Vienamo tegra_sdhci_pad_autocalib(host); 79444babea2SAapo Vienamo 79586ac2f8bSAapo Vienamo return ret; 79686ac2f8bSAapo Vienamo } 79786ac2f8bSAapo Vienamo 79886ac2f8bSAapo Vienamo static int tegra_sdhci_init_pinctrl_info(struct device *dev, 79986ac2f8bSAapo Vienamo struct sdhci_tegra *tegra_host) 80086ac2f8bSAapo Vienamo { 80186ac2f8bSAapo Vienamo tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev); 80286ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_sdmmc)) { 80386ac2f8bSAapo Vienamo dev_dbg(dev, "No pinctrl info, err: %ld\n", 80486ac2f8bSAapo Vienamo PTR_ERR(tegra_host->pinctrl_sdmmc)); 80586ac2f8bSAapo Vienamo return -1; 80686ac2f8bSAapo Vienamo } 80786ac2f8bSAapo Vienamo 80886ac2f8bSAapo Vienamo tegra_host->pinctrl_state_3v3 = 80986ac2f8bSAapo Vienamo pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-3v3"); 81086ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_state_3v3)) { 81186ac2f8bSAapo Vienamo dev_warn(dev, "Missing 3.3V pad state, err: %ld\n", 81286ac2f8bSAapo Vienamo PTR_ERR(tegra_host->pinctrl_state_3v3)); 81386ac2f8bSAapo Vienamo return -1; 81486ac2f8bSAapo Vienamo } 81586ac2f8bSAapo Vienamo 81686ac2f8bSAapo Vienamo tegra_host->pinctrl_state_1v8 = 81786ac2f8bSAapo Vienamo pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-1v8"); 81886ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_state_1v8)) { 81986ac2f8bSAapo Vienamo dev_warn(dev, "Missing 1.8V pad state, err: %ld\n", 820e5378247SYueHaibing PTR_ERR(tegra_host->pinctrl_state_1v8)); 82186ac2f8bSAapo Vienamo return -1; 82286ac2f8bSAapo Vienamo } 82386ac2f8bSAapo Vienamo 82486ac2f8bSAapo Vienamo tegra_host->pad_control_available = true; 82586ac2f8bSAapo Vienamo 82686ac2f8bSAapo Vienamo return 0; 82786ac2f8bSAapo Vienamo } 82886ac2f8bSAapo Vienamo 829e5c63d91SLucas Stach static void tegra_sdhci_voltage_switch(struct sdhci_host *host) 830e5c63d91SLucas Stach { 831e5c63d91SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 832e5c63d91SLucas Stach struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 833e5c63d91SLucas Stach const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 834e5c63d91SLucas Stach 835e5c63d91SLucas Stach if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 836e5c63d91SLucas Stach tegra_host->pad_calib_required = true; 837e5c63d91SLucas Stach } 838e5c63d91SLucas Stach 839c915568dSLars-Peter Clausen static const struct sdhci_ops tegra_sdhci_ops = { 84085d6509dSShawn Guo .get_ro = tegra_sdhci_get_ro, 84185d6509dSShawn Guo .read_w = tegra_sdhci_readw, 84285d6509dSShawn Guo .write_l = tegra_sdhci_writel, 843a8e326a9SLucas Stach .set_clock = tegra_sdhci_set_clock, 84414b04c6aSMichał Mirosław .set_bus_width = sdhci_set_bus_width, 84503231f9bSRussell King .reset = tegra_sdhci_reset, 846c3c2384cSLucas Stach .platform_execute_tuning = tegra_sdhci_execute_tuning, 847a8e326a9SLucas Stach .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 848e5c63d91SLucas Stach .voltage_switch = tegra_sdhci_voltage_switch, 84944350993SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 85085d6509dSShawn Guo }; 85103d2bfc8SOlof Johansson 8521db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { 85385d6509dSShawn Guo .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 85485d6509dSShawn Guo SDHCI_QUIRK_SINGLE_POWER_WRITE | 85585d6509dSShawn Guo SDHCI_QUIRK_NO_HISPD_BIT | 856f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 857f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 85885d6509dSShawn Guo .ops = &tegra_sdhci_ops, 85985d6509dSShawn Guo }; 86085d6509dSShawn Guo 861d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra20 = { 8623e44a1a7SStephen Warren .pdata = &sdhci_tegra20_pdata, 8633e44a1a7SStephen Warren .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | 8643e44a1a7SStephen Warren NVQUIRK_ENABLE_BLOCK_GAP_DET, 8653e44a1a7SStephen Warren }; 8663e44a1a7SStephen Warren 8671db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { 8683e44a1a7SStephen Warren .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 8693e44a1a7SStephen Warren SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 8703e44a1a7SStephen Warren SDHCI_QUIRK_SINGLE_POWER_WRITE | 8713e44a1a7SStephen Warren SDHCI_QUIRK_NO_HISPD_BIT | 872f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 873f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 874127407e3SStefan Agner .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 875726df1d5SStefan Agner SDHCI_QUIRK2_BROKEN_HS200 | 876726df1d5SStefan Agner /* 877726df1d5SStefan Agner * Auto-CMD23 leads to "Got command interrupt 0x00010000 even 878726df1d5SStefan Agner * though no command operation was in progress." 879726df1d5SStefan Agner * 880726df1d5SStefan Agner * The exact reason is unknown, as the same hardware seems 881726df1d5SStefan Agner * to support Auto CMD23 on a downstream 3.1 kernel. 882726df1d5SStefan Agner */ 883726df1d5SStefan Agner SDHCI_QUIRK2_ACMD23_BROKEN, 8843e44a1a7SStephen Warren .ops = &tegra_sdhci_ops, 8853e44a1a7SStephen Warren }; 8863e44a1a7SStephen Warren 887d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra30 = { 8883e44a1a7SStephen Warren .pdata = &sdhci_tegra30_pdata, 8893145351aSAndrew Bresticker .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | 8907ad2ed1dSLucas Stach NVQUIRK_ENABLE_SDR50 | 891e5c63d91SLucas Stach NVQUIRK_ENABLE_SDR104 | 892e5c63d91SLucas Stach NVQUIRK_HAS_PADCALIB, 8933e44a1a7SStephen Warren }; 8943e44a1a7SStephen Warren 89501df7ecdSRhyland Klein static const struct sdhci_ops tegra114_sdhci_ops = { 89601df7ecdSRhyland Klein .get_ro = tegra_sdhci_get_ro, 89701df7ecdSRhyland Klein .read_w = tegra_sdhci_readw, 89801df7ecdSRhyland Klein .write_w = tegra_sdhci_writew, 89901df7ecdSRhyland Klein .write_l = tegra_sdhci_writel, 900a8e326a9SLucas Stach .set_clock = tegra_sdhci_set_clock, 90114b04c6aSMichał Mirosław .set_bus_width = sdhci_set_bus_width, 90201df7ecdSRhyland Klein .reset = tegra_sdhci_reset, 903c3c2384cSLucas Stach .platform_execute_tuning = tegra_sdhci_execute_tuning, 904a8e326a9SLucas Stach .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 905e5c63d91SLucas Stach .voltage_switch = tegra_sdhci_voltage_switch, 90644350993SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 90701df7ecdSRhyland Klein }; 90801df7ecdSRhyland Klein 9091db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { 9105ebf2552SRhyland Klein .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 9115ebf2552SRhyland Klein SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 9125ebf2552SRhyland Klein SDHCI_QUIRK_SINGLE_POWER_WRITE | 9135ebf2552SRhyland Klein SDHCI_QUIRK_NO_HISPD_BIT | 914f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 915f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 916a8e326a9SLucas Stach .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 91701df7ecdSRhyland Klein .ops = &tegra114_sdhci_ops, 9185ebf2552SRhyland Klein }; 9195ebf2552SRhyland Klein 920d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra114 = { 9215ebf2552SRhyland Klein .pdata = &sdhci_tegra114_pdata, 9227bf037d6SJon Hunter }; 9237bf037d6SJon Hunter 9244ae12588SThierry Reding static const struct sdhci_pltfm_data sdhci_tegra124_pdata = { 9254ae12588SThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 9264ae12588SThierry Reding SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 9274ae12588SThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 9284ae12588SThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 9294ae12588SThierry Reding SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 9304ae12588SThierry Reding SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 9314ae12588SThierry Reding .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 9324ae12588SThierry Reding /* 9334ae12588SThierry Reding * The TRM states that the SD/MMC controller found on 9344ae12588SThierry Reding * Tegra124 can address 34 bits (the maximum supported by 9354ae12588SThierry Reding * the Tegra memory controller), but tests show that DMA 9364ae12588SThierry Reding * to or from above 4 GiB doesn't work. This is possibly 9374ae12588SThierry Reding * caused by missing programming, though it's not obvious 9384ae12588SThierry Reding * what sequence is required. Mark 64-bit DMA broken for 9394ae12588SThierry Reding * now to fix this for existing users (e.g. Nyan boards). 9404ae12588SThierry Reding */ 9414ae12588SThierry Reding SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 9424ae12588SThierry Reding .ops = &tegra114_sdhci_ops, 9434ae12588SThierry Reding }; 9444ae12588SThierry Reding 9454ae12588SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra124 = { 9464ae12588SThierry Reding .pdata = &sdhci_tegra124_pdata, 9474ae12588SThierry Reding }; 9484ae12588SThierry Reding 9491070e83aSAapo Vienamo static const struct sdhci_ops tegra210_sdhci_ops = { 9501070e83aSAapo Vienamo .get_ro = tegra_sdhci_get_ro, 9511070e83aSAapo Vienamo .read_w = tegra_sdhci_readw, 95238a284d9SAapo Vienamo .write_w = tegra210_sdhci_writew, 9531070e83aSAapo Vienamo .write_l = tegra_sdhci_writel, 9541070e83aSAapo Vienamo .set_clock = tegra_sdhci_set_clock, 9551070e83aSAapo Vienamo .set_bus_width = sdhci_set_bus_width, 9561070e83aSAapo Vienamo .reset = tegra_sdhci_reset, 9571070e83aSAapo Vienamo .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 9581070e83aSAapo Vienamo .voltage_switch = tegra_sdhci_voltage_switch, 9591070e83aSAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 9601070e83aSAapo Vienamo }; 9611070e83aSAapo Vienamo 962b5a84ecfSThierry Reding static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { 963b5a84ecfSThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 964b5a84ecfSThierry Reding SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 965b5a84ecfSThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 966b5a84ecfSThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 967a8e326a9SLucas Stach SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 968a8e326a9SLucas Stach SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 969a8e326a9SLucas Stach .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 9701070e83aSAapo Vienamo .ops = &tegra210_sdhci_ops, 971b5a84ecfSThierry Reding }; 972b5a84ecfSThierry Reding 973b5a84ecfSThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra210 = { 974b5a84ecfSThierry Reding .pdata = &sdhci_tegra210_pdata, 975d943f6e9SAapo Vienamo .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | 976d4501d8eSAapo Vienamo NVQUIRK_HAS_PADCALIB | 9773559d4a6SAapo Vienamo NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | 9783559d4a6SAapo Vienamo NVQUIRK_ENABLE_SDR50 | 9793559d4a6SAapo Vienamo NVQUIRK_ENABLE_SDR104, 980b5a84ecfSThierry Reding }; 981b5a84ecfSThierry Reding 98238a284d9SAapo Vienamo static const struct sdhci_ops tegra186_sdhci_ops = { 98338a284d9SAapo Vienamo .get_ro = tegra_sdhci_get_ro, 98438a284d9SAapo Vienamo .read_w = tegra_sdhci_readw, 98538a284d9SAapo Vienamo .write_l = tegra_sdhci_writel, 98638a284d9SAapo Vienamo .set_clock = tegra_sdhci_set_clock, 98738a284d9SAapo Vienamo .set_bus_width = sdhci_set_bus_width, 98838a284d9SAapo Vienamo .reset = tegra_sdhci_reset, 98938a284d9SAapo Vienamo .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 99038a284d9SAapo Vienamo .voltage_switch = tegra_sdhci_voltage_switch, 99138a284d9SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 99238a284d9SAapo Vienamo }; 99338a284d9SAapo Vienamo 9944346b7c7SThierry Reding static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { 9954346b7c7SThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 9964346b7c7SThierry Reding SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 9974346b7c7SThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 9984346b7c7SThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 9994346b7c7SThierry Reding SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 10004346b7c7SThierry Reding SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 100168481a7eSKrishna Reddy .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 100268481a7eSKrishna Reddy /* SDHCI controllers on Tegra186 support 40-bit addressing. 100368481a7eSKrishna Reddy * IOVA addresses are 48-bit wide on Tegra186. 100468481a7eSKrishna Reddy * With 64-bit dma mask used for SDHCI, accesses can 100568481a7eSKrishna Reddy * be broken. Disable 64-bit dma, which would fall back 100668481a7eSKrishna Reddy * to 32-bit dma mask. Ideally 40-bit dma mask would work, 100768481a7eSKrishna Reddy * But it is not supported as of now. 100868481a7eSKrishna Reddy */ 100968481a7eSKrishna Reddy SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 101038a284d9SAapo Vienamo .ops = &tegra186_sdhci_ops, 10114346b7c7SThierry Reding }; 10124346b7c7SThierry Reding 10134346b7c7SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra186 = { 10144346b7c7SThierry Reding .pdata = &sdhci_tegra186_pdata, 1015d943f6e9SAapo Vienamo .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | 1016d4501d8eSAapo Vienamo NVQUIRK_HAS_PADCALIB | 10172ad50051SAapo Vienamo NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | 10182ad50051SAapo Vienamo NVQUIRK_ENABLE_SDR50 | 10192ad50051SAapo Vienamo NVQUIRK_ENABLE_SDR104, 10204346b7c7SThierry Reding }; 10214346b7c7SThierry Reding 1022498d83e7SBill Pemberton static const struct of_device_id sdhci_tegra_dt_match[] = { 10234346b7c7SThierry Reding { .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 }, 1024b5a84ecfSThierry Reding { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, 10254ae12588SThierry Reding { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, 10265ebf2552SRhyland Klein { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, 10273e44a1a7SStephen Warren { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, 10283e44a1a7SStephen Warren { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, 1029275173b2SGrant Likely {} 1030275173b2SGrant Likely }; 1031e4404fabSArnd Bergmann MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); 1032275173b2SGrant Likely 1033c3be1efdSBill Pemberton static int sdhci_tegra_probe(struct platform_device *pdev) 103403d2bfc8SOlof Johansson { 10353e44a1a7SStephen Warren const struct of_device_id *match; 10363e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data; 10373e44a1a7SStephen Warren struct sdhci_host *host; 103885d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 10393e44a1a7SStephen Warren struct sdhci_tegra *tegra_host; 104003d2bfc8SOlof Johansson struct clk *clk; 104103d2bfc8SOlof Johansson int rc; 104203d2bfc8SOlof Johansson 10433e44a1a7SStephen Warren match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); 1044b37f9d98SJoseph Lo if (!match) 1045b37f9d98SJoseph Lo return -EINVAL; 10463e44a1a7SStephen Warren soc_data = match->data; 10473e44a1a7SStephen Warren 10480734e79cSJisheng Zhang host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*tegra_host)); 104985d6509dSShawn Guo if (IS_ERR(host)) 105085d6509dSShawn Guo return PTR_ERR(host); 105185d6509dSShawn Guo pltfm_host = sdhci_priv(host); 105285d6509dSShawn Guo 10530734e79cSJisheng Zhang tegra_host = sdhci_pltfm_priv(pltfm_host); 1054a8e326a9SLucas Stach tegra_host->ddr_signaling = false; 1055e5c63d91SLucas Stach tegra_host->pad_calib_required = false; 105686ac2f8bSAapo Vienamo tegra_host->pad_control_available = false; 10573e44a1a7SStephen Warren tegra_host->soc_data = soc_data; 1058275173b2SGrant Likely 105986ac2f8bSAapo Vienamo if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) { 106086ac2f8bSAapo Vienamo rc = tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host); 106186ac2f8bSAapo Vienamo if (rc == 0) 106286ac2f8bSAapo Vienamo host->mmc_host_ops.start_signal_voltage_switch = 106386ac2f8bSAapo Vienamo sdhci_tegra_start_signal_voltage_switch; 106486ac2f8bSAapo Vienamo } 106586ac2f8bSAapo Vienamo 106661dad40eSAapo Vienamo /* Hook to periodically rerun pad calibration */ 106761dad40eSAapo Vienamo if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 106861dad40eSAapo Vienamo host->mmc_host_ops.request = tegra_sdhci_request; 106961dad40eSAapo Vienamo 1070dfc9700cSAapo Vienamo host->mmc_host_ops.hs400_enhanced_strobe = 1071dfc9700cSAapo Vienamo tegra_sdhci_hs400_enhanced_strobe; 1072dfc9700cSAapo Vienamo 10732391b340SMylene JOSSERAND rc = mmc_of_parse(host->mmc); 107447caa84fSSimon Baatz if (rc) 107547caa84fSSimon Baatz goto err_parse_dt; 10760e786102SStephen Warren 10777ad2ed1dSLucas Stach if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 1078c3c2384cSLucas Stach host->mmc->caps |= MMC_CAP_1_8V_DDR; 1079c3c2384cSLucas Stach 108051b77c8eSAapo Vienamo tegra_sdhci_parse_pad_autocal_dt(host); 108151b77c8eSAapo Vienamo 1082f5313aaaSAapo Vienamo tegra_sdhci_parse_tap_and_trim(host); 108385c0da17SAapo Vienamo 10842391b340SMylene JOSSERAND tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", 10852391b340SMylene JOSSERAND GPIOD_OUT_HIGH); 10862391b340SMylene JOSSERAND if (IS_ERR(tegra_host->power_gpio)) { 10872391b340SMylene JOSSERAND rc = PTR_ERR(tegra_host->power_gpio); 108885d6509dSShawn Guo goto err_power_req; 108903d2bfc8SOlof Johansson } 109003d2bfc8SOlof Johansson 1091e4f79d9cSKevin Hao clk = devm_clk_get(mmc_dev(host->mmc), NULL); 109203d2bfc8SOlof Johansson if (IS_ERR(clk)) { 109303d2bfc8SOlof Johansson dev_err(mmc_dev(host->mmc), "clk err\n"); 109403d2bfc8SOlof Johansson rc = PTR_ERR(clk); 109585d6509dSShawn Guo goto err_clk_get; 109603d2bfc8SOlof Johansson } 10971e674bc6SPrashant Gaikwad clk_prepare_enable(clk); 109803d2bfc8SOlof Johansson pltfm_host->clk = clk; 109903d2bfc8SOlof Johansson 11002cd6c49dSPhilipp Zabel tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev, 11012cd6c49dSPhilipp Zabel "sdhci"); 110220567be9SThierry Reding if (IS_ERR(tegra_host->rst)) { 110320567be9SThierry Reding rc = PTR_ERR(tegra_host->rst); 110420567be9SThierry Reding dev_err(&pdev->dev, "failed to get reset control: %d\n", rc); 110520567be9SThierry Reding goto err_rst_get; 110620567be9SThierry Reding } 110720567be9SThierry Reding 110820567be9SThierry Reding rc = reset_control_assert(tegra_host->rst); 110920567be9SThierry Reding if (rc) 111020567be9SThierry Reding goto err_rst_get; 111120567be9SThierry Reding 111220567be9SThierry Reding usleep_range(2000, 4000); 111320567be9SThierry Reding 111420567be9SThierry Reding rc = reset_control_deassert(tegra_host->rst); 111520567be9SThierry Reding if (rc) 111620567be9SThierry Reding goto err_rst_get; 111720567be9SThierry Reding 111820567be9SThierry Reding usleep_range(2000, 4000); 111920567be9SThierry Reding 112085d6509dSShawn Guo rc = sdhci_add_host(host); 112185d6509dSShawn Guo if (rc) 112285d6509dSShawn Guo goto err_add_host; 112385d6509dSShawn Guo 112403d2bfc8SOlof Johansson return 0; 112503d2bfc8SOlof Johansson 112685d6509dSShawn Guo err_add_host: 112720567be9SThierry Reding reset_control_assert(tegra_host->rst); 112820567be9SThierry Reding err_rst_get: 11291e674bc6SPrashant Gaikwad clk_disable_unprepare(pltfm_host->clk); 113085d6509dSShawn Guo err_clk_get: 113185d6509dSShawn Guo err_power_req: 113247caa84fSSimon Baatz err_parse_dt: 113385d6509dSShawn Guo sdhci_pltfm_free(pdev); 113403d2bfc8SOlof Johansson return rc; 113503d2bfc8SOlof Johansson } 113603d2bfc8SOlof Johansson 113720567be9SThierry Reding static int sdhci_tegra_remove(struct platform_device *pdev) 113820567be9SThierry Reding { 113920567be9SThierry Reding struct sdhci_host *host = platform_get_drvdata(pdev); 114020567be9SThierry Reding struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 114120567be9SThierry Reding struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 114220567be9SThierry Reding 114320567be9SThierry Reding sdhci_remove_host(host, 0); 114420567be9SThierry Reding 114520567be9SThierry Reding reset_control_assert(tegra_host->rst); 114620567be9SThierry Reding usleep_range(2000, 4000); 114720567be9SThierry Reding clk_disable_unprepare(pltfm_host->clk); 114820567be9SThierry Reding 114920567be9SThierry Reding sdhci_pltfm_free(pdev); 115020567be9SThierry Reding 115120567be9SThierry Reding return 0; 115220567be9SThierry Reding } 115320567be9SThierry Reding 115485d6509dSShawn Guo static struct platform_driver sdhci_tegra_driver = { 115585d6509dSShawn Guo .driver = { 115685d6509dSShawn Guo .name = "sdhci-tegra", 1157275173b2SGrant Likely .of_match_table = sdhci_tegra_dt_match, 1158fa243f64SUlf Hansson .pm = &sdhci_pltfm_pmops, 115985d6509dSShawn Guo }, 116085d6509dSShawn Guo .probe = sdhci_tegra_probe, 116120567be9SThierry Reding .remove = sdhci_tegra_remove, 116203d2bfc8SOlof Johansson }; 116303d2bfc8SOlof Johansson 1164d1f81a64SAxel Lin module_platform_driver(sdhci_tegra_driver); 116585d6509dSShawn Guo 116685d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Tegra"); 116785d6509dSShawn Guo MODULE_AUTHOR("Google, Inc."); 116885d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 1169