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" 363c4019f9SSowjanya Komatineni #include "cqhci.h" 3703d2bfc8SOlof Johansson 38ca5879d3SPavan Kunapuli /* Tegra SDHOST controller vendor register definitions */ 3974cd42bcSLucas Stach #define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 40c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 41c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 4241a0b8d7SAapo Vienamo #define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000 4341a0b8d7SAapo Vienamo #define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24 44c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) 4574cd42bcSLucas Stach #define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3) 4674cd42bcSLucas Stach #define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2) 4774cd42bcSLucas Stach 48dfc9700cSAapo Vienamo #define SDHCI_TEGRA_VENDOR_SYS_SW_CTRL 0x104 49dfc9700cSAapo Vienamo #define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE BIT(31) 50dfc9700cSAapo Vienamo 51f5313aaaSAapo Vienamo #define SDHCI_TEGRA_VENDOR_CAP_OVERRIDES 0x10c 52f5313aaaSAapo Vienamo #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK 0x00003f00 53f5313aaaSAapo Vienamo #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT 8 54f5313aaaSAapo Vienamo 55ca5879d3SPavan Kunapuli #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 563145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8 573145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10 58ca5879d3SPavan Kunapuli #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 593145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200 60ca5879d3SPavan Kunapuli 61bc5568bfSAapo Vienamo #define SDHCI_TEGRA_VENDOR_DLLCAL_CFG 0x1b0 62bc5568bfSAapo Vienamo #define SDHCI_TEGRA_DLLCAL_CALIBRATE BIT(31) 63bc5568bfSAapo Vienamo 64bc5568bfSAapo Vienamo #define SDHCI_TEGRA_VENDOR_DLLCAL_STA 0x1bc 65bc5568bfSAapo Vienamo #define SDHCI_TEGRA_DLLCAL_STA_ACTIVE BIT(31) 66bc5568bfSAapo Vienamo 67d4501d8eSAapo Vienamo #define SDHCI_VNDR_TUN_CTRL0_0 0x1c0 68d4501d8eSAapo Vienamo #define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP 0x20000 69d4501d8eSAapo Vienamo 70e5c63d91SLucas Stach #define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4 71e5c63d91SLucas Stach #define SDHCI_AUTO_CAL_START BIT(31) 72e5c63d91SLucas Stach #define SDHCI_AUTO_CAL_ENABLE BIT(29) 7351b77c8eSAapo Vienamo #define SDHCI_AUTO_CAL_PDPU_OFFSET_MASK 0x0000ffff 74e5c63d91SLucas Stach 759d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL 0x1e0 769d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK 0x0000000f 779d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL 0x7 78212b0cf1SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD BIT(31) 79de25fa5aSSowjanya Komatineni #define SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK 0x07FFF000 809d548f11SAapo Vienamo 81e7c07148SAapo Vienamo #define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec 82e7c07148SAapo Vienamo #define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31) 83e7c07148SAapo Vienamo 843e44a1a7SStephen Warren #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) 853e44a1a7SStephen Warren #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) 86ca5879d3SPavan Kunapuli #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) 877ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_SDR50 BIT(3) 887ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_SDR104 BIT(4) 897ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_DDR50 BIT(5) 90e5c63d91SLucas Stach #define NVQUIRK_HAS_PADCALIB BIT(6) 9186ac2f8bSAapo Vienamo #define NVQUIRK_NEEDS_PAD_CONTROL BIT(7) 92d4501d8eSAapo Vienamo #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) 933e44a1a7SStephen Warren 943c4019f9SSowjanya Komatineni /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */ 953c4019f9SSowjanya Komatineni #define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000 963c4019f9SSowjanya Komatineni 973e44a1a7SStephen Warren struct sdhci_tegra_soc_data { 981db5eebfSLars-Peter Clausen const struct sdhci_pltfm_data *pdata; 993e44a1a7SStephen Warren u32 nvquirks; 1003e44a1a7SStephen Warren }; 1013e44a1a7SStephen Warren 10251b77c8eSAapo Vienamo /* Magic pull up and pull down pad calibration offsets */ 10351b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets { 10451b77c8eSAapo Vienamo u32 pull_up_3v3; 10551b77c8eSAapo Vienamo u32 pull_down_3v3; 10651b77c8eSAapo Vienamo u32 pull_up_3v3_timeout; 10751b77c8eSAapo Vienamo u32 pull_down_3v3_timeout; 10851b77c8eSAapo Vienamo u32 pull_up_1v8; 10951b77c8eSAapo Vienamo u32 pull_down_1v8; 11051b77c8eSAapo Vienamo u32 pull_up_1v8_timeout; 11151b77c8eSAapo Vienamo u32 pull_down_1v8_timeout; 11251b77c8eSAapo Vienamo u32 pull_up_sdr104; 11351b77c8eSAapo Vienamo u32 pull_down_sdr104; 11451b77c8eSAapo Vienamo u32 pull_up_hs400; 11551b77c8eSAapo Vienamo u32 pull_down_hs400; 11651b77c8eSAapo Vienamo }; 11751b77c8eSAapo Vienamo 1183e44a1a7SStephen Warren struct sdhci_tegra { 1193e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data; 1202391b340SMylene JOSSERAND struct gpio_desc *power_gpio; 121a8e326a9SLucas Stach bool ddr_signaling; 122e5c63d91SLucas Stach bool pad_calib_required; 12386ac2f8bSAapo Vienamo bool pad_control_available; 12420567be9SThierry Reding 12520567be9SThierry Reding struct reset_control *rst; 12686ac2f8bSAapo Vienamo struct pinctrl *pinctrl_sdmmc; 12786ac2f8bSAapo Vienamo struct pinctrl_state *pinctrl_state_3v3; 12886ac2f8bSAapo Vienamo struct pinctrl_state *pinctrl_state_1v8; 129de25fa5aSSowjanya Komatineni struct pinctrl_state *pinctrl_state_3v3_drv; 130de25fa5aSSowjanya Komatineni struct pinctrl_state *pinctrl_state_1v8_drv; 13151b77c8eSAapo Vienamo 13251b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets autocal_offsets; 13361dad40eSAapo Vienamo ktime_t last_calib; 13485c0da17SAapo Vienamo 13585c0da17SAapo Vienamo u32 default_tap; 13685c0da17SAapo Vienamo u32 default_trim; 137f5313aaaSAapo Vienamo u32 dqs_trim; 1383c4019f9SSowjanya Komatineni bool enable_hwcq; 1393e44a1a7SStephen Warren }; 1403e44a1a7SStephen Warren 14103d2bfc8SOlof Johansson static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) 14203d2bfc8SOlof Johansson { 1433e44a1a7SStephen Warren struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1440734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1453e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 1463e44a1a7SStephen Warren 1473e44a1a7SStephen Warren if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && 1483e44a1a7SStephen Warren (reg == SDHCI_HOST_VERSION))) { 14903d2bfc8SOlof Johansson /* Erratum: Version register is invalid in HW. */ 15003d2bfc8SOlof Johansson return SDHCI_SPEC_200; 15103d2bfc8SOlof Johansson } 15203d2bfc8SOlof Johansson 15303d2bfc8SOlof Johansson return readw(host->ioaddr + reg); 15403d2bfc8SOlof Johansson } 15503d2bfc8SOlof Johansson 156352ee868SPavan Kunapuli static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg) 157352ee868SPavan Kunapuli { 158352ee868SPavan Kunapuli struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 159352ee868SPavan Kunapuli 160352ee868SPavan Kunapuli switch (reg) { 161352ee868SPavan Kunapuli case SDHCI_TRANSFER_MODE: 162352ee868SPavan Kunapuli /* 163352ee868SPavan Kunapuli * Postpone this write, we must do it together with a 164352ee868SPavan Kunapuli * command write that is down below. 165352ee868SPavan Kunapuli */ 166352ee868SPavan Kunapuli pltfm_host->xfer_mode_shadow = val; 167352ee868SPavan Kunapuli return; 168352ee868SPavan Kunapuli case SDHCI_COMMAND: 169352ee868SPavan Kunapuli writel((val << 16) | pltfm_host->xfer_mode_shadow, 170352ee868SPavan Kunapuli host->ioaddr + SDHCI_TRANSFER_MODE); 171352ee868SPavan Kunapuli return; 172352ee868SPavan Kunapuli } 173352ee868SPavan Kunapuli 174352ee868SPavan Kunapuli writew(val, host->ioaddr + reg); 175352ee868SPavan Kunapuli } 176352ee868SPavan Kunapuli 17703d2bfc8SOlof Johansson static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) 17803d2bfc8SOlof Johansson { 1793e44a1a7SStephen Warren struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1800734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1813e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 1823e44a1a7SStephen Warren 18303d2bfc8SOlof Johansson /* Seems like we're getting spurious timeout and crc errors, so 18403d2bfc8SOlof Johansson * disable signalling of them. In case of real errors software 18503d2bfc8SOlof Johansson * timers should take care of eventually detecting them. 18603d2bfc8SOlof Johansson */ 18703d2bfc8SOlof Johansson if (unlikely(reg == SDHCI_SIGNAL_ENABLE)) 18803d2bfc8SOlof Johansson val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC); 18903d2bfc8SOlof Johansson 19003d2bfc8SOlof Johansson writel(val, host->ioaddr + reg); 19103d2bfc8SOlof Johansson 1923e44a1a7SStephen Warren if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) && 1933e44a1a7SStephen Warren (reg == SDHCI_INT_ENABLE))) { 19403d2bfc8SOlof Johansson /* Erratum: Must enable block gap interrupt detection */ 19503d2bfc8SOlof Johansson u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 19603d2bfc8SOlof Johansson if (val & SDHCI_INT_CARD_INT) 19703d2bfc8SOlof Johansson gap_ctrl |= 0x8; 19803d2bfc8SOlof Johansson else 19903d2bfc8SOlof Johansson gap_ctrl &= ~0x8; 20003d2bfc8SOlof Johansson writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 20103d2bfc8SOlof Johansson } 20203d2bfc8SOlof Johansson } 20303d2bfc8SOlof Johansson 20438a284d9SAapo Vienamo static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable) 20538a284d9SAapo Vienamo { 20638a284d9SAapo Vienamo bool status; 20738a284d9SAapo Vienamo u32 reg; 20838a284d9SAapo Vienamo 20938a284d9SAapo Vienamo reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 21038a284d9SAapo Vienamo status = !!(reg & SDHCI_CLOCK_CARD_EN); 21138a284d9SAapo Vienamo 21238a284d9SAapo Vienamo if (status == enable) 21338a284d9SAapo Vienamo return status; 21438a284d9SAapo Vienamo 21538a284d9SAapo Vienamo if (enable) 21638a284d9SAapo Vienamo reg |= SDHCI_CLOCK_CARD_EN; 21738a284d9SAapo Vienamo else 21838a284d9SAapo Vienamo reg &= ~SDHCI_CLOCK_CARD_EN; 21938a284d9SAapo Vienamo 22038a284d9SAapo Vienamo sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); 22138a284d9SAapo Vienamo 22238a284d9SAapo Vienamo return status; 22338a284d9SAapo Vienamo } 22438a284d9SAapo Vienamo 22538a284d9SAapo Vienamo static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg) 22638a284d9SAapo Vienamo { 22738a284d9SAapo Vienamo bool is_tuning_cmd = 0; 22838a284d9SAapo Vienamo bool clk_enabled; 22938a284d9SAapo Vienamo u8 cmd; 23038a284d9SAapo Vienamo 23138a284d9SAapo Vienamo if (reg == SDHCI_COMMAND) { 23238a284d9SAapo Vienamo cmd = SDHCI_GET_CMD(val); 23338a284d9SAapo Vienamo is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK || 23438a284d9SAapo Vienamo cmd == MMC_SEND_TUNING_BLOCK_HS200; 23538a284d9SAapo Vienamo } 23638a284d9SAapo Vienamo 23738a284d9SAapo Vienamo if (is_tuning_cmd) 23838a284d9SAapo Vienamo clk_enabled = tegra_sdhci_configure_card_clk(host, 0); 23938a284d9SAapo Vienamo 24038a284d9SAapo Vienamo writew(val, host->ioaddr + reg); 24138a284d9SAapo Vienamo 24238a284d9SAapo Vienamo if (is_tuning_cmd) { 24338a284d9SAapo Vienamo udelay(1); 24438a284d9SAapo Vienamo tegra_sdhci_configure_card_clk(host, clk_enabled); 24538a284d9SAapo Vienamo } 24638a284d9SAapo Vienamo } 24738a284d9SAapo Vienamo 24886ac2f8bSAapo Vienamo static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host) 24986ac2f8bSAapo Vienamo { 25086ac2f8bSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 25186ac2f8bSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 25286ac2f8bSAapo Vienamo int has_1v8, has_3v3; 25386ac2f8bSAapo Vienamo 25486ac2f8bSAapo Vienamo /* 25586ac2f8bSAapo Vienamo * The SoCs which have NVQUIRK_NEEDS_PAD_CONTROL require software pad 25686ac2f8bSAapo Vienamo * voltage configuration in order to perform voltage switching. This 25786ac2f8bSAapo Vienamo * means that valid pinctrl info is required on SDHCI instances capable 25886ac2f8bSAapo Vienamo * of performing voltage switching. Whether or not an SDHCI instance is 25986ac2f8bSAapo Vienamo * capable of voltage switching is determined based on the regulator. 26086ac2f8bSAapo Vienamo */ 26186ac2f8bSAapo Vienamo 26286ac2f8bSAapo Vienamo if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)) 26386ac2f8bSAapo Vienamo return true; 26486ac2f8bSAapo Vienamo 26586ac2f8bSAapo Vienamo if (IS_ERR(host->mmc->supply.vqmmc)) 26686ac2f8bSAapo Vienamo return false; 26786ac2f8bSAapo Vienamo 26886ac2f8bSAapo Vienamo has_1v8 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 26986ac2f8bSAapo Vienamo 1700000, 1950000); 27086ac2f8bSAapo Vienamo 27186ac2f8bSAapo Vienamo has_3v3 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 27286ac2f8bSAapo Vienamo 2700000, 3600000); 27386ac2f8bSAapo Vienamo 27486ac2f8bSAapo Vienamo if (has_1v8 == 1 && has_3v3 == 1) 27586ac2f8bSAapo Vienamo return tegra_host->pad_control_available; 27686ac2f8bSAapo Vienamo 27786ac2f8bSAapo Vienamo /* Fixed voltage, no pad control required. */ 27886ac2f8bSAapo Vienamo return true; 27986ac2f8bSAapo Vienamo } 28086ac2f8bSAapo Vienamo 281c2c09678SAapo Vienamo static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) 282c2c09678SAapo Vienamo { 283c2c09678SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 284c2c09678SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 285c2c09678SAapo Vienamo const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 286c2c09678SAapo Vienamo bool card_clk_enabled = false; 287c2c09678SAapo Vienamo u32 reg; 288c2c09678SAapo Vienamo 289c2c09678SAapo Vienamo /* 290c2c09678SAapo Vienamo * Touching the tap values is a bit tricky on some SoC generations. 291c2c09678SAapo Vienamo * The quirk enables a workaround for a glitch that sometimes occurs if 292c2c09678SAapo Vienamo * the tap values are changed. 293c2c09678SAapo Vienamo */ 294c2c09678SAapo Vienamo 295c2c09678SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP) 296c2c09678SAapo Vienamo card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); 297c2c09678SAapo Vienamo 298c2c09678SAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 299c2c09678SAapo Vienamo reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; 300c2c09678SAapo Vienamo reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; 301c2c09678SAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 302c2c09678SAapo Vienamo 303c2c09678SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP && 304c2c09678SAapo Vienamo card_clk_enabled) { 305c2c09678SAapo Vienamo udelay(1); 306c2c09678SAapo Vienamo sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 307c2c09678SAapo Vienamo tegra_sdhci_configure_card_clk(host, card_clk_enabled); 308c2c09678SAapo Vienamo } 309c2c09678SAapo Vienamo } 310c2c09678SAapo Vienamo 311dfc9700cSAapo Vienamo static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, 312dfc9700cSAapo Vienamo struct mmc_ios *ios) 313dfc9700cSAapo Vienamo { 314dfc9700cSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 315dfc9700cSAapo Vienamo u32 val; 316dfc9700cSAapo Vienamo 317dfc9700cSAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); 318dfc9700cSAapo Vienamo 319dfc9700cSAapo Vienamo if (ios->enhanced_strobe) 320dfc9700cSAapo Vienamo val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; 321dfc9700cSAapo Vienamo else 322dfc9700cSAapo Vienamo val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; 323dfc9700cSAapo Vienamo 324dfc9700cSAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); 325dfc9700cSAapo Vienamo 326dfc9700cSAapo Vienamo } 327dfc9700cSAapo Vienamo 32803231f9bSRussell King static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) 329ca5879d3SPavan Kunapuli { 330ca5879d3SPavan Kunapuli struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 3310734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 332ca5879d3SPavan Kunapuli const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 3339d548f11SAapo Vienamo u32 misc_ctrl, clk_ctrl, pad_ctrl; 334ca5879d3SPavan Kunapuli 33503231f9bSRussell King sdhci_reset(host, mask); 33603231f9bSRussell King 337ca5879d3SPavan Kunapuli if (!(mask & SDHCI_RESET_ALL)) 338ca5879d3SPavan Kunapuli return; 339ca5879d3SPavan Kunapuli 340c2c09678SAapo Vienamo tegra_sdhci_set_tap(host, tegra_host->default_tap); 341c2c09678SAapo Vienamo 3421b84def8SLucas Stach misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); 3434f6aa326SJon Hunter clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 3444f6aa326SJon Hunter 3454f6aa326SJon Hunter misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 | 3464f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_SDR50 | 3474f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_DDR50 | 3484f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_SDR104); 3494f6aa326SJon Hunter 35041a0b8d7SAapo Vienamo clk_ctrl &= ~(SDHCI_CLOCK_CTRL_TRIM_MASK | 35141a0b8d7SAapo Vienamo SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE); 3524f6aa326SJon Hunter 35386ac2f8bSAapo Vienamo if (tegra_sdhci_is_pad_and_regulator_valid(host)) { 354ca5879d3SPavan Kunapuli /* Erratum: Enable SDHCI spec v3.00 support */ 3553145351aSAndrew Bresticker if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) 356ca5879d3SPavan Kunapuli misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; 3577ad2ed1dSLucas Stach /* Advertise UHS modes as supported by host */ 3587ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) 3597ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; 3607ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 3617ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; 3627ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) 3637ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; 3647ad2ed1dSLucas Stach if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) 365c3c2384cSLucas Stach clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; 3664f6aa326SJon Hunter } 3674f6aa326SJon Hunter 36841a0b8d7SAapo Vienamo clk_ctrl |= tegra_host->default_trim << SDHCI_CLOCK_CTRL_TRIM_SHIFT; 36941a0b8d7SAapo Vienamo 3704f6aa326SJon Hunter sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); 37174cd42bcSLucas Stach sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 37274cd42bcSLucas Stach 3739d548f11SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) { 3749d548f11SAapo Vienamo pad_ctrl = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 3759d548f11SAapo Vienamo pad_ctrl &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK; 3769d548f11SAapo Vienamo pad_ctrl |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL; 3779d548f11SAapo Vienamo sdhci_writel(host, pad_ctrl, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 3789d548f11SAapo Vienamo 379e5c63d91SLucas Stach tegra_host->pad_calib_required = true; 3809d548f11SAapo Vienamo } 381e5c63d91SLucas Stach 382a8e326a9SLucas Stach tegra_host->ddr_signaling = false; 383ca5879d3SPavan Kunapuli } 384ca5879d3SPavan Kunapuli 385212b0cf1SAapo Vienamo static void tegra_sdhci_configure_cal_pad(struct sdhci_host *host, bool enable) 386212b0cf1SAapo Vienamo { 387212b0cf1SAapo Vienamo u32 val; 388212b0cf1SAapo Vienamo 389212b0cf1SAapo Vienamo /* 390212b0cf1SAapo Vienamo * Enable or disable the additional I/O pad used by the drive strength 391212b0cf1SAapo Vienamo * calibration process. 392212b0cf1SAapo Vienamo */ 393212b0cf1SAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 394212b0cf1SAapo Vienamo 395212b0cf1SAapo Vienamo if (enable) 396212b0cf1SAapo Vienamo val |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; 397212b0cf1SAapo Vienamo else 398212b0cf1SAapo Vienamo val &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; 399212b0cf1SAapo Vienamo 400212b0cf1SAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 401212b0cf1SAapo Vienamo 402212b0cf1SAapo Vienamo if (enable) 403212b0cf1SAapo Vienamo usleep_range(1, 2); 404212b0cf1SAapo Vienamo } 405212b0cf1SAapo Vienamo 40651b77c8eSAapo Vienamo static void tegra_sdhci_set_pad_autocal_offset(struct sdhci_host *host, 40751b77c8eSAapo Vienamo u16 pdpu) 40851b77c8eSAapo Vienamo { 40951b77c8eSAapo Vienamo u32 reg; 41051b77c8eSAapo Vienamo 41151b77c8eSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 41251b77c8eSAapo Vienamo reg &= ~SDHCI_AUTO_CAL_PDPU_OFFSET_MASK; 41351b77c8eSAapo Vienamo reg |= pdpu; 41451b77c8eSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 41551b77c8eSAapo Vienamo } 41651b77c8eSAapo Vienamo 417de25fa5aSSowjanya Komatineni static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage, 418de25fa5aSSowjanya Komatineni bool state_drvupdn) 419de25fa5aSSowjanya Komatineni { 420de25fa5aSSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 421de25fa5aSSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 422de25fa5aSSowjanya Komatineni struct sdhci_tegra_autocal_offsets *offsets = 423de25fa5aSSowjanya Komatineni &tegra_host->autocal_offsets; 424de25fa5aSSowjanya Komatineni struct pinctrl_state *pinctrl_drvupdn = NULL; 425de25fa5aSSowjanya Komatineni int ret = 0; 426de25fa5aSSowjanya Komatineni u8 drvup = 0, drvdn = 0; 427de25fa5aSSowjanya Komatineni u32 reg; 428de25fa5aSSowjanya Komatineni 429de25fa5aSSowjanya Komatineni if (!state_drvupdn) { 430de25fa5aSSowjanya Komatineni /* PADS Drive Strength */ 431de25fa5aSSowjanya Komatineni if (voltage == MMC_SIGNAL_VOLTAGE_180) { 432de25fa5aSSowjanya Komatineni if (tegra_host->pinctrl_state_1v8_drv) { 433de25fa5aSSowjanya Komatineni pinctrl_drvupdn = 434de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8_drv; 435de25fa5aSSowjanya Komatineni } else { 436de25fa5aSSowjanya Komatineni drvup = offsets->pull_up_1v8_timeout; 437de25fa5aSSowjanya Komatineni drvdn = offsets->pull_down_1v8_timeout; 438de25fa5aSSowjanya Komatineni } 439de25fa5aSSowjanya Komatineni } else { 440de25fa5aSSowjanya Komatineni if (tegra_host->pinctrl_state_3v3_drv) { 441de25fa5aSSowjanya Komatineni pinctrl_drvupdn = 442de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3_drv; 443de25fa5aSSowjanya Komatineni } else { 444de25fa5aSSowjanya Komatineni drvup = offsets->pull_up_3v3_timeout; 445de25fa5aSSowjanya Komatineni drvdn = offsets->pull_down_3v3_timeout; 446de25fa5aSSowjanya Komatineni } 447de25fa5aSSowjanya Komatineni } 448de25fa5aSSowjanya Komatineni 449de25fa5aSSowjanya Komatineni if (pinctrl_drvupdn != NULL) { 450de25fa5aSSowjanya Komatineni ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 451de25fa5aSSowjanya Komatineni pinctrl_drvupdn); 452de25fa5aSSowjanya Komatineni if (ret < 0) 453de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 454de25fa5aSSowjanya Komatineni "failed pads drvupdn, ret: %d\n", ret); 455de25fa5aSSowjanya Komatineni } else if ((drvup) || (drvdn)) { 456de25fa5aSSowjanya Komatineni reg = sdhci_readl(host, 457de25fa5aSSowjanya Komatineni SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 458de25fa5aSSowjanya Komatineni reg &= ~SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK; 459de25fa5aSSowjanya Komatineni reg |= (drvup << 20) | (drvdn << 12); 460de25fa5aSSowjanya Komatineni sdhci_writel(host, reg, 461de25fa5aSSowjanya Komatineni SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 462de25fa5aSSowjanya Komatineni } 463de25fa5aSSowjanya Komatineni 464de25fa5aSSowjanya Komatineni } else { 465de25fa5aSSowjanya Komatineni /* Dual Voltage PADS Voltage selection */ 466de25fa5aSSowjanya Komatineni if (!tegra_host->pad_control_available) 467de25fa5aSSowjanya Komatineni return 0; 468de25fa5aSSowjanya Komatineni 469de25fa5aSSowjanya Komatineni if (voltage == MMC_SIGNAL_VOLTAGE_180) { 470de25fa5aSSowjanya Komatineni ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 471de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8); 472de25fa5aSSowjanya Komatineni if (ret < 0) 473de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 474de25fa5aSSowjanya Komatineni "setting 1.8V failed, ret: %d\n", ret); 475de25fa5aSSowjanya Komatineni } else { 476de25fa5aSSowjanya Komatineni ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 477de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3); 478de25fa5aSSowjanya Komatineni if (ret < 0) 479de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 480de25fa5aSSowjanya Komatineni "setting 3.3V failed, ret: %d\n", ret); 481de25fa5aSSowjanya Komatineni } 482de25fa5aSSowjanya Komatineni } 483de25fa5aSSowjanya Komatineni 484de25fa5aSSowjanya Komatineni return ret; 485de25fa5aSSowjanya Komatineni } 486de25fa5aSSowjanya Komatineni 487e5c63d91SLucas Stach static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) 488e5c63d91SLucas Stach { 48951b77c8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 49051b77c8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 49151b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets offsets = 49251b77c8eSAapo Vienamo tegra_host->autocal_offsets; 49351b77c8eSAapo Vienamo struct mmc_ios *ios = &host->mmc->ios; 494887bda8fSAapo Vienamo bool card_clk_enabled; 49551b77c8eSAapo Vienamo u16 pdpu; 496e7c07148SAapo Vienamo u32 reg; 497e7c07148SAapo Vienamo int ret; 498e5c63d91SLucas Stach 49951b77c8eSAapo Vienamo switch (ios->timing) { 50051b77c8eSAapo Vienamo case MMC_TIMING_UHS_SDR104: 50151b77c8eSAapo Vienamo pdpu = offsets.pull_down_sdr104 << 8 | offsets.pull_up_sdr104; 50251b77c8eSAapo Vienamo break; 50351b77c8eSAapo Vienamo case MMC_TIMING_MMC_HS400: 50451b77c8eSAapo Vienamo pdpu = offsets.pull_down_hs400 << 8 | offsets.pull_up_hs400; 50551b77c8eSAapo Vienamo break; 50651b77c8eSAapo Vienamo default: 50751b77c8eSAapo Vienamo if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) 50851b77c8eSAapo Vienamo pdpu = offsets.pull_down_1v8 << 8 | offsets.pull_up_1v8; 50951b77c8eSAapo Vienamo else 51051b77c8eSAapo Vienamo pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3; 51151b77c8eSAapo Vienamo } 51251b77c8eSAapo Vienamo 513de25fa5aSSowjanya Komatineni /* Set initial offset before auto-calibration */ 51451b77c8eSAapo Vienamo tegra_sdhci_set_pad_autocal_offset(host, pdpu); 51551b77c8eSAapo Vienamo 516887bda8fSAapo Vienamo card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); 517887bda8fSAapo Vienamo 518212b0cf1SAapo Vienamo tegra_sdhci_configure_cal_pad(host, true); 519212b0cf1SAapo Vienamo 520e7c07148SAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 521e7c07148SAapo Vienamo reg |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START; 522e7c07148SAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 523e5c63d91SLucas Stach 524e7c07148SAapo Vienamo usleep_range(1, 2); 525e7c07148SAapo Vienamo /* 10 ms timeout */ 526e7c07148SAapo Vienamo ret = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_AUTO_CAL_STATUS, 527e7c07148SAapo Vienamo reg, !(reg & SDHCI_TEGRA_AUTO_CAL_ACTIVE), 528e7c07148SAapo Vienamo 1000, 10000); 529e7c07148SAapo Vienamo 530212b0cf1SAapo Vienamo tegra_sdhci_configure_cal_pad(host, false); 531212b0cf1SAapo Vienamo 532887bda8fSAapo Vienamo tegra_sdhci_configure_card_clk(host, card_clk_enabled); 533887bda8fSAapo Vienamo 53451b77c8eSAapo Vienamo if (ret) { 535e7c07148SAapo Vienamo dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n"); 53651b77c8eSAapo Vienamo 537de25fa5aSSowjanya Komatineni /* Disable automatic cal and use fixed Drive Strengths */ 53851b77c8eSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 53951b77c8eSAapo Vienamo reg &= ~SDHCI_AUTO_CAL_ENABLE; 54051b77c8eSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 54151b77c8eSAapo Vienamo 542de25fa5aSSowjanya Komatineni ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, false); 543de25fa5aSSowjanya Komatineni if (ret < 0) 544de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 545de25fa5aSSowjanya Komatineni "Setting drive strengths failed: %d\n", ret); 54651b77c8eSAapo Vienamo } 54751b77c8eSAapo Vienamo } 54851b77c8eSAapo Vienamo 54951b77c8eSAapo Vienamo static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host) 55051b77c8eSAapo Vienamo { 55151b77c8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 55251b77c8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 55351b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets *autocal = 55451b77c8eSAapo Vienamo &tegra_host->autocal_offsets; 55551b77c8eSAapo Vienamo int err; 55651b77c8eSAapo Vienamo 55751b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 55851b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-3v3", 55951b77c8eSAapo Vienamo &autocal->pull_up_3v3); 56051b77c8eSAapo Vienamo if (err) 56151b77c8eSAapo Vienamo autocal->pull_up_3v3 = 0; 56251b77c8eSAapo Vienamo 56351b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 56451b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-3v3", 56551b77c8eSAapo Vienamo &autocal->pull_down_3v3); 56651b77c8eSAapo Vienamo if (err) 56751b77c8eSAapo Vienamo autocal->pull_down_3v3 = 0; 56851b77c8eSAapo Vienamo 56951b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 57051b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-1v8", 57151b77c8eSAapo Vienamo &autocal->pull_up_1v8); 57251b77c8eSAapo Vienamo if (err) 57351b77c8eSAapo Vienamo autocal->pull_up_1v8 = 0; 57451b77c8eSAapo Vienamo 57551b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 57651b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-1v8", 57751b77c8eSAapo Vienamo &autocal->pull_down_1v8); 57851b77c8eSAapo Vienamo if (err) 57951b77c8eSAapo Vienamo autocal->pull_down_1v8 = 0; 58051b77c8eSAapo Vienamo 58151b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 58251b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-3v3-timeout", 5835ccf7f55SSowjanya Komatineni &autocal->pull_up_3v3_timeout); 584de25fa5aSSowjanya Komatineni if (err) { 585de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_3v3) && 586de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_3v3_drv == NULL)) 587de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n", 588de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 58951b77c8eSAapo Vienamo autocal->pull_up_3v3_timeout = 0; 590de25fa5aSSowjanya Komatineni } 59151b77c8eSAapo Vienamo 59251b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 59351b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-3v3-timeout", 5945ccf7f55SSowjanya Komatineni &autocal->pull_down_3v3_timeout); 595de25fa5aSSowjanya Komatineni if (err) { 596de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_3v3) && 597de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_3v3_drv == NULL)) 598de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n", 599de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 60051b77c8eSAapo Vienamo autocal->pull_down_3v3_timeout = 0; 601de25fa5aSSowjanya Komatineni } 60251b77c8eSAapo Vienamo 60351b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 60451b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-1v8-timeout", 6055ccf7f55SSowjanya Komatineni &autocal->pull_up_1v8_timeout); 606de25fa5aSSowjanya Komatineni if (err) { 607de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_1v8) && 608de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_1v8_drv == NULL)) 609de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n", 610de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 61151b77c8eSAapo Vienamo autocal->pull_up_1v8_timeout = 0; 612de25fa5aSSowjanya Komatineni } 61351b77c8eSAapo Vienamo 61451b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 61551b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-1v8-timeout", 6165ccf7f55SSowjanya Komatineni &autocal->pull_down_1v8_timeout); 617de25fa5aSSowjanya Komatineni if (err) { 618de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_1v8) && 619de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_1v8_drv == NULL)) 620de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n", 621de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 62251b77c8eSAapo Vienamo autocal->pull_down_1v8_timeout = 0; 623de25fa5aSSowjanya Komatineni } 62451b77c8eSAapo Vienamo 62551b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 62651b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-sdr104", 62751b77c8eSAapo Vienamo &autocal->pull_up_sdr104); 62851b77c8eSAapo Vienamo if (err) 62951b77c8eSAapo Vienamo autocal->pull_up_sdr104 = autocal->pull_up_1v8; 63051b77c8eSAapo Vienamo 63151b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 63251b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-sdr104", 63351b77c8eSAapo Vienamo &autocal->pull_down_sdr104); 63451b77c8eSAapo Vienamo if (err) 63551b77c8eSAapo Vienamo autocal->pull_down_sdr104 = autocal->pull_down_1v8; 63651b77c8eSAapo Vienamo 63751b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 63851b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-hs400", 63951b77c8eSAapo Vienamo &autocal->pull_up_hs400); 64051b77c8eSAapo Vienamo if (err) 64151b77c8eSAapo Vienamo autocal->pull_up_hs400 = autocal->pull_up_1v8; 64251b77c8eSAapo Vienamo 64351b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 64451b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-hs400", 64551b77c8eSAapo Vienamo &autocal->pull_down_hs400); 64651b77c8eSAapo Vienamo if (err) 64751b77c8eSAapo Vienamo autocal->pull_down_hs400 = autocal->pull_down_1v8; 648e5c63d91SLucas Stach } 649e5c63d91SLucas Stach 65061dad40eSAapo Vienamo static void tegra_sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) 65161dad40eSAapo Vienamo { 65261dad40eSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 65361dad40eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 65461dad40eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 65561dad40eSAapo Vienamo ktime_t since_calib = ktime_sub(ktime_get(), tegra_host->last_calib); 65661dad40eSAapo Vienamo 65761dad40eSAapo Vienamo /* 100 ms calibration interval is specified in the TRM */ 65861dad40eSAapo Vienamo if (ktime_to_ms(since_calib) > 100) { 65961dad40eSAapo Vienamo tegra_sdhci_pad_autocalib(host); 66061dad40eSAapo Vienamo tegra_host->last_calib = ktime_get(); 66161dad40eSAapo Vienamo } 66261dad40eSAapo Vienamo 66361dad40eSAapo Vienamo sdhci_request(mmc, mrq); 66461dad40eSAapo Vienamo } 66561dad40eSAapo Vienamo 666f5313aaaSAapo Vienamo static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host) 66785c0da17SAapo Vienamo { 66885c0da17SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 66985c0da17SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 67085c0da17SAapo Vienamo int err; 67185c0da17SAapo Vienamo 67285c0da17SAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,default-tap", 67385c0da17SAapo Vienamo &tegra_host->default_tap); 67485c0da17SAapo Vienamo if (err) 67585c0da17SAapo Vienamo tegra_host->default_tap = 0; 67685c0da17SAapo Vienamo 67785c0da17SAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,default-trim", 67885c0da17SAapo Vienamo &tegra_host->default_trim); 67985c0da17SAapo Vienamo if (err) 68085c0da17SAapo Vienamo tegra_host->default_trim = 0; 681f5313aaaSAapo Vienamo 682f5313aaaSAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim", 683f5313aaaSAapo Vienamo &tegra_host->dqs_trim); 684f5313aaaSAapo Vienamo if (err) 685f5313aaaSAapo Vienamo tegra_host->dqs_trim = 0x11; 68685c0da17SAapo Vienamo } 68785c0da17SAapo Vienamo 6883c4019f9SSowjanya Komatineni static void tegra_sdhci_parse_dt(struct sdhci_host *host) 6893c4019f9SSowjanya Komatineni { 6903c4019f9SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 6913c4019f9SSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 6923c4019f9SSowjanya Komatineni 6933c4019f9SSowjanya Komatineni if (device_property_read_bool(host->mmc->parent, "supports-cqe")) 6943c4019f9SSowjanya Komatineni tegra_host->enable_hwcq = true; 6953c4019f9SSowjanya Komatineni else 6963c4019f9SSowjanya Komatineni tegra_host->enable_hwcq = false; 6973c4019f9SSowjanya Komatineni 6983c4019f9SSowjanya Komatineni tegra_sdhci_parse_pad_autocal_dt(host); 6993c4019f9SSowjanya Komatineni tegra_sdhci_parse_tap_and_trim(host); 7003c4019f9SSowjanya Komatineni } 7013c4019f9SSowjanya Komatineni 702a8e326a9SLucas Stach static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 703a8e326a9SLucas Stach { 704a8e326a9SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 7050734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 706a8e326a9SLucas Stach unsigned long host_clk; 707a8e326a9SLucas Stach 708a8e326a9SLucas Stach if (!clock) 7093491b690SLucas Stach return sdhci_set_clock(host, clock); 710a8e326a9SLucas Stach 71157d1654eSAapo Vienamo /* 71257d1654eSAapo Vienamo * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI 71357d1654eSAapo Vienamo * divider to be configured to divided the host clock by two. The SDHCI 71457d1654eSAapo Vienamo * clock divider is calculated as part of sdhci_set_clock() by 71557d1654eSAapo Vienamo * sdhci_calc_clk(). The divider is calculated from host->max_clk and 71657d1654eSAapo Vienamo * the requested clock rate. 71757d1654eSAapo Vienamo * 71857d1654eSAapo Vienamo * By setting the host->max_clk to clock * 2 the divider calculation 71957d1654eSAapo Vienamo * will always result in the correct value for DDR50/52 modes, 72057d1654eSAapo Vienamo * regardless of clock rate rounding, which may happen if the value 72157d1654eSAapo Vienamo * from clk_get_rate() is used. 72257d1654eSAapo Vienamo */ 723a8e326a9SLucas Stach host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; 724a8e326a9SLucas Stach clk_set_rate(pltfm_host->clk, host_clk); 72557d1654eSAapo Vienamo if (tegra_host->ddr_signaling) 72657d1654eSAapo Vienamo host->max_clk = host_clk; 72757d1654eSAapo Vienamo else 728a8e326a9SLucas Stach host->max_clk = clk_get_rate(pltfm_host->clk); 729a8e326a9SLucas Stach 730e5c63d91SLucas Stach sdhci_set_clock(host, clock); 731e5c63d91SLucas Stach 732e5c63d91SLucas Stach if (tegra_host->pad_calib_required) { 733e5c63d91SLucas Stach tegra_sdhci_pad_autocalib(host); 734e5c63d91SLucas Stach tegra_host->pad_calib_required = false; 735e5c63d91SLucas Stach } 736a8e326a9SLucas Stach } 737a8e326a9SLucas Stach 73844350993SAapo Vienamo static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) 73944350993SAapo Vienamo { 74044350993SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 74144350993SAapo Vienamo 74244350993SAapo Vienamo return clk_round_rate(pltfm_host->clk, UINT_MAX); 74344350993SAapo Vienamo } 74444350993SAapo Vienamo 745f5313aaaSAapo Vienamo static void tegra_sdhci_set_dqs_trim(struct sdhci_host *host, u8 trim) 746f5313aaaSAapo Vienamo { 747f5313aaaSAapo Vienamo u32 val; 748f5313aaaSAapo Vienamo 749f5313aaaSAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); 750f5313aaaSAapo Vienamo val &= ~SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK; 751f5313aaaSAapo Vienamo val |= trim << SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT; 752f5313aaaSAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); 753f5313aaaSAapo Vienamo } 754f5313aaaSAapo Vienamo 755bc5568bfSAapo Vienamo static void tegra_sdhci_hs400_dll_cal(struct sdhci_host *host) 756bc5568bfSAapo Vienamo { 757bc5568bfSAapo Vienamo u32 reg; 758bc5568bfSAapo Vienamo int err; 759bc5568bfSAapo Vienamo 760bc5568bfSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); 761bc5568bfSAapo Vienamo reg |= SDHCI_TEGRA_DLLCAL_CALIBRATE; 762bc5568bfSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); 763bc5568bfSAapo Vienamo 764bc5568bfSAapo Vienamo /* 1 ms sleep, 5 ms timeout */ 765bc5568bfSAapo Vienamo err = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_VENDOR_DLLCAL_STA, 766bc5568bfSAapo Vienamo reg, !(reg & SDHCI_TEGRA_DLLCAL_STA_ACTIVE), 767bc5568bfSAapo Vienamo 1000, 5000); 768bc5568bfSAapo Vienamo if (err) 769bc5568bfSAapo Vienamo dev_err(mmc_dev(host->mmc), 770bc5568bfSAapo Vienamo "HS400 delay line calibration timed out\n"); 771bc5568bfSAapo Vienamo } 772bc5568bfSAapo Vienamo 773c2c09678SAapo Vienamo static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, 774c2c09678SAapo Vienamo unsigned timing) 775c3c2384cSLucas Stach { 776d4501d8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 777d4501d8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 778c2c09678SAapo Vienamo bool set_default_tap = false; 779f5313aaaSAapo Vienamo bool set_dqs_trim = false; 780bc5568bfSAapo Vienamo bool do_hs400_dll_cal = false; 781c3c2384cSLucas Stach 78292cd1667SSowjanya Komatineni tegra_host->ddr_signaling = false; 783c2c09678SAapo Vienamo switch (timing) { 784c2c09678SAapo Vienamo case MMC_TIMING_UHS_SDR50: 785c2c09678SAapo Vienamo case MMC_TIMING_UHS_SDR104: 786c2c09678SAapo Vienamo case MMC_TIMING_MMC_HS200: 787c2c09678SAapo Vienamo /* Don't set default tap on tunable modes. */ 788c2c09678SAapo Vienamo break; 789f5313aaaSAapo Vienamo case MMC_TIMING_MMC_HS400: 790f5313aaaSAapo Vienamo set_dqs_trim = true; 791bc5568bfSAapo Vienamo do_hs400_dll_cal = true; 792f5313aaaSAapo Vienamo break; 793c2c09678SAapo Vienamo case MMC_TIMING_MMC_DDR52: 794c2c09678SAapo Vienamo case MMC_TIMING_UHS_DDR50: 795c2c09678SAapo Vienamo tegra_host->ddr_signaling = true; 796c2c09678SAapo Vienamo set_default_tap = true; 797c2c09678SAapo Vienamo break; 798c2c09678SAapo Vienamo default: 799c2c09678SAapo Vienamo set_default_tap = true; 800c2c09678SAapo Vienamo break; 801d4501d8eSAapo Vienamo } 802c2c09678SAapo Vienamo 803c2c09678SAapo Vienamo sdhci_set_uhs_signaling(host, timing); 804c2c09678SAapo Vienamo 805c2c09678SAapo Vienamo tegra_sdhci_pad_autocalib(host); 806c2c09678SAapo Vienamo 807c2c09678SAapo Vienamo if (set_default_tap) 808c2c09678SAapo Vienamo tegra_sdhci_set_tap(host, tegra_host->default_tap); 809f5313aaaSAapo Vienamo 810f5313aaaSAapo Vienamo if (set_dqs_trim) 811f5313aaaSAapo Vienamo tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim); 812bc5568bfSAapo Vienamo 813bc5568bfSAapo Vienamo if (do_hs400_dll_cal) 814bc5568bfSAapo Vienamo tegra_sdhci_hs400_dll_cal(host); 815c3c2384cSLucas Stach } 816c3c2384cSLucas Stach 817c3c2384cSLucas Stach static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) 818c3c2384cSLucas Stach { 819c3c2384cSLucas Stach unsigned int min, max; 820c3c2384cSLucas Stach 821c3c2384cSLucas Stach /* 822c3c2384cSLucas Stach * Start search for minimum tap value at 10, as smaller values are 823c3c2384cSLucas Stach * may wrongly be reported as working but fail at higher speeds, 824c3c2384cSLucas Stach * according to the TRM. 825c3c2384cSLucas Stach */ 826c3c2384cSLucas Stach min = 10; 827c3c2384cSLucas Stach while (min < 255) { 828c3c2384cSLucas Stach tegra_sdhci_set_tap(host, min); 829c3c2384cSLucas Stach if (!mmc_send_tuning(host->mmc, opcode, NULL)) 830c3c2384cSLucas Stach break; 831c3c2384cSLucas Stach min++; 832c3c2384cSLucas Stach } 833c3c2384cSLucas Stach 834c3c2384cSLucas Stach /* Find the maximum tap value that still passes. */ 835c3c2384cSLucas Stach max = min + 1; 836c3c2384cSLucas Stach while (max < 255) { 837c3c2384cSLucas Stach tegra_sdhci_set_tap(host, max); 838c3c2384cSLucas Stach if (mmc_send_tuning(host->mmc, opcode, NULL)) { 839c3c2384cSLucas Stach max--; 840c3c2384cSLucas Stach break; 841c3c2384cSLucas Stach } 842c3c2384cSLucas Stach max++; 843c3c2384cSLucas Stach } 844c3c2384cSLucas Stach 845c3c2384cSLucas Stach /* The TRM states the ideal tap value is at 75% in the passing range. */ 846c3c2384cSLucas Stach tegra_sdhci_set_tap(host, min + ((max - min) * 3 / 4)); 847c3c2384cSLucas Stach 848c3c2384cSLucas Stach return mmc_send_tuning(host->mmc, opcode, NULL); 849c3c2384cSLucas Stach } 850c3c2384cSLucas Stach 85186ac2f8bSAapo Vienamo static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, 85286ac2f8bSAapo Vienamo struct mmc_ios *ios) 85386ac2f8bSAapo Vienamo { 85486ac2f8bSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 85544babea2SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 85644babea2SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 85786ac2f8bSAapo Vienamo int ret = 0; 85886ac2f8bSAapo Vienamo 85986ac2f8bSAapo Vienamo if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 860de25fa5aSSowjanya Komatineni ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true); 86186ac2f8bSAapo Vienamo if (ret < 0) 86286ac2f8bSAapo Vienamo return ret; 86386ac2f8bSAapo Vienamo ret = sdhci_start_signal_voltage_switch(mmc, ios); 86486ac2f8bSAapo Vienamo } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { 86586ac2f8bSAapo Vienamo ret = sdhci_start_signal_voltage_switch(mmc, ios); 86686ac2f8bSAapo Vienamo if (ret < 0) 86786ac2f8bSAapo Vienamo return ret; 868de25fa5aSSowjanya Komatineni ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true); 86986ac2f8bSAapo Vienamo } 87086ac2f8bSAapo Vienamo 87144babea2SAapo Vienamo if (tegra_host->pad_calib_required) 87244babea2SAapo Vienamo tegra_sdhci_pad_autocalib(host); 87344babea2SAapo Vienamo 87486ac2f8bSAapo Vienamo return ret; 87586ac2f8bSAapo Vienamo } 87686ac2f8bSAapo Vienamo 87786ac2f8bSAapo Vienamo static int tegra_sdhci_init_pinctrl_info(struct device *dev, 87886ac2f8bSAapo Vienamo struct sdhci_tegra *tegra_host) 87986ac2f8bSAapo Vienamo { 88086ac2f8bSAapo Vienamo tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev); 88186ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_sdmmc)) { 88286ac2f8bSAapo Vienamo dev_dbg(dev, "No pinctrl info, err: %ld\n", 88386ac2f8bSAapo Vienamo PTR_ERR(tegra_host->pinctrl_sdmmc)); 88486ac2f8bSAapo Vienamo return -1; 88586ac2f8bSAapo Vienamo } 88686ac2f8bSAapo Vienamo 887de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8_drv = pinctrl_lookup_state( 888de25fa5aSSowjanya Komatineni tegra_host->pinctrl_sdmmc, "sdmmc-1v8-drv"); 889de25fa5aSSowjanya Komatineni if (IS_ERR(tegra_host->pinctrl_state_1v8_drv)) { 890de25fa5aSSowjanya Komatineni if (PTR_ERR(tegra_host->pinctrl_state_1v8_drv) == -ENODEV) 891de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8_drv = NULL; 892de25fa5aSSowjanya Komatineni } 893de25fa5aSSowjanya Komatineni 894de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3_drv = pinctrl_lookup_state( 895de25fa5aSSowjanya Komatineni tegra_host->pinctrl_sdmmc, "sdmmc-3v3-drv"); 896de25fa5aSSowjanya Komatineni if (IS_ERR(tegra_host->pinctrl_state_3v3_drv)) { 897de25fa5aSSowjanya Komatineni if (PTR_ERR(tegra_host->pinctrl_state_3v3_drv) == -ENODEV) 898de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3_drv = NULL; 899de25fa5aSSowjanya Komatineni } 900de25fa5aSSowjanya Komatineni 90186ac2f8bSAapo Vienamo tegra_host->pinctrl_state_3v3 = 90286ac2f8bSAapo Vienamo pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-3v3"); 90386ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_state_3v3)) { 90486ac2f8bSAapo Vienamo dev_warn(dev, "Missing 3.3V pad state, err: %ld\n", 90586ac2f8bSAapo Vienamo PTR_ERR(tegra_host->pinctrl_state_3v3)); 90686ac2f8bSAapo Vienamo return -1; 90786ac2f8bSAapo Vienamo } 90886ac2f8bSAapo Vienamo 90986ac2f8bSAapo Vienamo tegra_host->pinctrl_state_1v8 = 91086ac2f8bSAapo Vienamo pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-1v8"); 91186ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_state_1v8)) { 91286ac2f8bSAapo Vienamo dev_warn(dev, "Missing 1.8V pad state, err: %ld\n", 913e5378247SYueHaibing PTR_ERR(tegra_host->pinctrl_state_1v8)); 91486ac2f8bSAapo Vienamo return -1; 91586ac2f8bSAapo Vienamo } 91686ac2f8bSAapo Vienamo 91786ac2f8bSAapo Vienamo tegra_host->pad_control_available = true; 91886ac2f8bSAapo Vienamo 91986ac2f8bSAapo Vienamo return 0; 92086ac2f8bSAapo Vienamo } 92186ac2f8bSAapo Vienamo 922e5c63d91SLucas Stach static void tegra_sdhci_voltage_switch(struct sdhci_host *host) 923e5c63d91SLucas Stach { 924e5c63d91SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 925e5c63d91SLucas Stach struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 926e5c63d91SLucas Stach const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 927e5c63d91SLucas Stach 928e5c63d91SLucas Stach if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 929e5c63d91SLucas Stach tegra_host->pad_calib_required = true; 930e5c63d91SLucas Stach } 931e5c63d91SLucas Stach 9323c4019f9SSowjanya Komatineni static void sdhci_tegra_cqe_enable(struct mmc_host *mmc) 9333c4019f9SSowjanya Komatineni { 9343c4019f9SSowjanya Komatineni struct cqhci_host *cq_host = mmc->cqe_private; 9353c4019f9SSowjanya Komatineni u32 cqcfg = 0; 9363c4019f9SSowjanya Komatineni 9373c4019f9SSowjanya Komatineni /* 9383c4019f9SSowjanya Komatineni * Tegra SDMMC Controller design prevents write access to BLOCK_COUNT 9393c4019f9SSowjanya Komatineni * registers when CQE is enabled. 9403c4019f9SSowjanya Komatineni */ 9413c4019f9SSowjanya Komatineni cqcfg = cqhci_readl(cq_host, CQHCI_CFG); 9423c4019f9SSowjanya Komatineni if (cqcfg & CQHCI_ENABLE) 9433c4019f9SSowjanya Komatineni cqhci_writel(cq_host, (cqcfg & ~CQHCI_ENABLE), CQHCI_CFG); 9443c4019f9SSowjanya Komatineni 9453c4019f9SSowjanya Komatineni sdhci_cqe_enable(mmc); 9463c4019f9SSowjanya Komatineni 9473c4019f9SSowjanya Komatineni if (cqcfg & CQHCI_ENABLE) 9483c4019f9SSowjanya Komatineni cqhci_writel(cq_host, cqcfg, CQHCI_CFG); 9493c4019f9SSowjanya Komatineni } 9503c4019f9SSowjanya Komatineni 9513c4019f9SSowjanya Komatineni static void sdhci_tegra_dumpregs(struct mmc_host *mmc) 9523c4019f9SSowjanya Komatineni { 9533c4019f9SSowjanya Komatineni sdhci_dumpregs(mmc_priv(mmc)); 9543c4019f9SSowjanya Komatineni } 9553c4019f9SSowjanya Komatineni 9563c4019f9SSowjanya Komatineni static u32 sdhci_tegra_cqhci_irq(struct sdhci_host *host, u32 intmask) 9573c4019f9SSowjanya Komatineni { 9583c4019f9SSowjanya Komatineni int cmd_error = 0; 9593c4019f9SSowjanya Komatineni int data_error = 0; 9603c4019f9SSowjanya Komatineni 9613c4019f9SSowjanya Komatineni if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 9623c4019f9SSowjanya Komatineni return intmask; 9633c4019f9SSowjanya Komatineni 9643c4019f9SSowjanya Komatineni cqhci_irq(host->mmc, intmask, cmd_error, data_error); 9653c4019f9SSowjanya Komatineni 9663c4019f9SSowjanya Komatineni return 0; 9673c4019f9SSowjanya Komatineni } 9683c4019f9SSowjanya Komatineni 9693c4019f9SSowjanya Komatineni static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = { 9703c4019f9SSowjanya Komatineni .enable = sdhci_tegra_cqe_enable, 9713c4019f9SSowjanya Komatineni .disable = sdhci_cqe_disable, 9723c4019f9SSowjanya Komatineni .dumpregs = sdhci_tegra_dumpregs, 9733c4019f9SSowjanya Komatineni }; 9743c4019f9SSowjanya Komatineni 975c915568dSLars-Peter Clausen static const struct sdhci_ops tegra_sdhci_ops = { 97685d6509dSShawn Guo .read_w = tegra_sdhci_readw, 97785d6509dSShawn Guo .write_l = tegra_sdhci_writel, 978a8e326a9SLucas Stach .set_clock = tegra_sdhci_set_clock, 97914b04c6aSMichał Mirosław .set_bus_width = sdhci_set_bus_width, 98003231f9bSRussell King .reset = tegra_sdhci_reset, 981c3c2384cSLucas Stach .platform_execute_tuning = tegra_sdhci_execute_tuning, 982a8e326a9SLucas Stach .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 983e5c63d91SLucas Stach .voltage_switch = tegra_sdhci_voltage_switch, 98444350993SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 98585d6509dSShawn Guo }; 98603d2bfc8SOlof Johansson 9871db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { 98885d6509dSShawn Guo .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 98985d6509dSShawn Guo SDHCI_QUIRK_SINGLE_POWER_WRITE | 99085d6509dSShawn Guo SDHCI_QUIRK_NO_HISPD_BIT | 991f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 992f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 99385d6509dSShawn Guo .ops = &tegra_sdhci_ops, 99485d6509dSShawn Guo }; 99585d6509dSShawn Guo 996d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra20 = { 9973e44a1a7SStephen Warren .pdata = &sdhci_tegra20_pdata, 9983e44a1a7SStephen Warren .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | 9993e44a1a7SStephen Warren NVQUIRK_ENABLE_BLOCK_GAP_DET, 10003e44a1a7SStephen Warren }; 10013e44a1a7SStephen Warren 10021db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { 10033e44a1a7SStephen Warren .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 10043e44a1a7SStephen Warren SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 10053e44a1a7SStephen Warren SDHCI_QUIRK_SINGLE_POWER_WRITE | 10063e44a1a7SStephen Warren SDHCI_QUIRK_NO_HISPD_BIT | 1007f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 1008f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1009127407e3SStefan Agner .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 1010726df1d5SStefan Agner SDHCI_QUIRK2_BROKEN_HS200 | 1011726df1d5SStefan Agner /* 1012726df1d5SStefan Agner * Auto-CMD23 leads to "Got command interrupt 0x00010000 even 1013726df1d5SStefan Agner * though no command operation was in progress." 1014726df1d5SStefan Agner * 1015726df1d5SStefan Agner * The exact reason is unknown, as the same hardware seems 1016726df1d5SStefan Agner * to support Auto CMD23 on a downstream 3.1 kernel. 1017726df1d5SStefan Agner */ 1018726df1d5SStefan Agner SDHCI_QUIRK2_ACMD23_BROKEN, 10193e44a1a7SStephen Warren .ops = &tegra_sdhci_ops, 10203e44a1a7SStephen Warren }; 10213e44a1a7SStephen Warren 1022d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra30 = { 10233e44a1a7SStephen Warren .pdata = &sdhci_tegra30_pdata, 10243145351aSAndrew Bresticker .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | 10257ad2ed1dSLucas Stach NVQUIRK_ENABLE_SDR50 | 1026e5c63d91SLucas Stach NVQUIRK_ENABLE_SDR104 | 1027e5c63d91SLucas Stach NVQUIRK_HAS_PADCALIB, 10283e44a1a7SStephen Warren }; 10293e44a1a7SStephen Warren 103001df7ecdSRhyland Klein static const struct sdhci_ops tegra114_sdhci_ops = { 103101df7ecdSRhyland Klein .read_w = tegra_sdhci_readw, 103201df7ecdSRhyland Klein .write_w = tegra_sdhci_writew, 103301df7ecdSRhyland Klein .write_l = tegra_sdhci_writel, 1034a8e326a9SLucas Stach .set_clock = tegra_sdhci_set_clock, 103514b04c6aSMichał Mirosław .set_bus_width = sdhci_set_bus_width, 103601df7ecdSRhyland Klein .reset = tegra_sdhci_reset, 1037c3c2384cSLucas Stach .platform_execute_tuning = tegra_sdhci_execute_tuning, 1038a8e326a9SLucas Stach .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 1039e5c63d91SLucas Stach .voltage_switch = tegra_sdhci_voltage_switch, 104044350993SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 104101df7ecdSRhyland Klein }; 104201df7ecdSRhyland Klein 10431db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { 10445ebf2552SRhyland Klein .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 10455ebf2552SRhyland Klein SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 10465ebf2552SRhyland Klein SDHCI_QUIRK_SINGLE_POWER_WRITE | 10475ebf2552SRhyland Klein SDHCI_QUIRK_NO_HISPD_BIT | 1048f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 1049f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1050a8e326a9SLucas Stach .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 105101df7ecdSRhyland Klein .ops = &tegra114_sdhci_ops, 10525ebf2552SRhyland Klein }; 10535ebf2552SRhyland Klein 1054d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra114 = { 10555ebf2552SRhyland Klein .pdata = &sdhci_tegra114_pdata, 10567bf037d6SJon Hunter }; 10577bf037d6SJon Hunter 10584ae12588SThierry Reding static const struct sdhci_pltfm_data sdhci_tegra124_pdata = { 10594ae12588SThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 10604ae12588SThierry Reding SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 10614ae12588SThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 10624ae12588SThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 10634ae12588SThierry Reding SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 10644ae12588SThierry Reding SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 10654ae12588SThierry Reding .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 10664ae12588SThierry Reding /* 10674ae12588SThierry Reding * The TRM states that the SD/MMC controller found on 10684ae12588SThierry Reding * Tegra124 can address 34 bits (the maximum supported by 10694ae12588SThierry Reding * the Tegra memory controller), but tests show that DMA 10704ae12588SThierry Reding * to or from above 4 GiB doesn't work. This is possibly 10714ae12588SThierry Reding * caused by missing programming, though it's not obvious 10724ae12588SThierry Reding * what sequence is required. Mark 64-bit DMA broken for 10734ae12588SThierry Reding * now to fix this for existing users (e.g. Nyan boards). 10744ae12588SThierry Reding */ 10754ae12588SThierry Reding SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 10764ae12588SThierry Reding .ops = &tegra114_sdhci_ops, 10774ae12588SThierry Reding }; 10784ae12588SThierry Reding 10794ae12588SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra124 = { 10804ae12588SThierry Reding .pdata = &sdhci_tegra124_pdata, 10814ae12588SThierry Reding }; 10824ae12588SThierry Reding 10831070e83aSAapo Vienamo static const struct sdhci_ops tegra210_sdhci_ops = { 10841070e83aSAapo Vienamo .read_w = tegra_sdhci_readw, 108538a284d9SAapo Vienamo .write_w = tegra210_sdhci_writew, 10861070e83aSAapo Vienamo .write_l = tegra_sdhci_writel, 10871070e83aSAapo Vienamo .set_clock = tegra_sdhci_set_clock, 10881070e83aSAapo Vienamo .set_bus_width = sdhci_set_bus_width, 10891070e83aSAapo Vienamo .reset = tegra_sdhci_reset, 10901070e83aSAapo Vienamo .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 10911070e83aSAapo Vienamo .voltage_switch = tegra_sdhci_voltage_switch, 10921070e83aSAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 10931070e83aSAapo Vienamo }; 10941070e83aSAapo Vienamo 1095b5a84ecfSThierry Reding static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { 1096b5a84ecfSThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 1097b5a84ecfSThierry Reding SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 1098b5a84ecfSThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 1099b5a84ecfSThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 1100a8e326a9SLucas Stach SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 1101a8e326a9SLucas Stach SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1102a8e326a9SLucas Stach .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 11031070e83aSAapo Vienamo .ops = &tegra210_sdhci_ops, 1104b5a84ecfSThierry Reding }; 1105b5a84ecfSThierry Reding 1106b5a84ecfSThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra210 = { 1107b5a84ecfSThierry Reding .pdata = &sdhci_tegra210_pdata, 1108d943f6e9SAapo Vienamo .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | 1109d4501d8eSAapo Vienamo NVQUIRK_HAS_PADCALIB | 11103559d4a6SAapo Vienamo NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | 11113559d4a6SAapo Vienamo NVQUIRK_ENABLE_SDR50 | 11123559d4a6SAapo Vienamo NVQUIRK_ENABLE_SDR104, 1113b5a84ecfSThierry Reding }; 1114b5a84ecfSThierry Reding 111538a284d9SAapo Vienamo static const struct sdhci_ops tegra186_sdhci_ops = { 111638a284d9SAapo Vienamo .read_w = tegra_sdhci_readw, 111738a284d9SAapo Vienamo .write_l = tegra_sdhci_writel, 111838a284d9SAapo Vienamo .set_clock = tegra_sdhci_set_clock, 111938a284d9SAapo Vienamo .set_bus_width = sdhci_set_bus_width, 112038a284d9SAapo Vienamo .reset = tegra_sdhci_reset, 112138a284d9SAapo Vienamo .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 112238a284d9SAapo Vienamo .voltage_switch = tegra_sdhci_voltage_switch, 112338a284d9SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 11243c4019f9SSowjanya Komatineni .irq = sdhci_tegra_cqhci_irq, 112538a284d9SAapo Vienamo }; 112638a284d9SAapo Vienamo 11274346b7c7SThierry Reding static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { 11284346b7c7SThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 11294346b7c7SThierry Reding SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 11304346b7c7SThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 11314346b7c7SThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 11324346b7c7SThierry Reding SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 11334346b7c7SThierry Reding SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 113468481a7eSKrishna Reddy .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 113568481a7eSKrishna Reddy /* SDHCI controllers on Tegra186 support 40-bit addressing. 113668481a7eSKrishna Reddy * IOVA addresses are 48-bit wide on Tegra186. 113768481a7eSKrishna Reddy * With 64-bit dma mask used for SDHCI, accesses can 113868481a7eSKrishna Reddy * be broken. Disable 64-bit dma, which would fall back 113968481a7eSKrishna Reddy * to 32-bit dma mask. Ideally 40-bit dma mask would work, 114068481a7eSKrishna Reddy * But it is not supported as of now. 114168481a7eSKrishna Reddy */ 114268481a7eSKrishna Reddy SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 114338a284d9SAapo Vienamo .ops = &tegra186_sdhci_ops, 11444346b7c7SThierry Reding }; 11454346b7c7SThierry Reding 11464346b7c7SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra186 = { 11474346b7c7SThierry Reding .pdata = &sdhci_tegra186_pdata, 1148d943f6e9SAapo Vienamo .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | 1149d4501d8eSAapo Vienamo NVQUIRK_HAS_PADCALIB | 11502ad50051SAapo Vienamo NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | 11512ad50051SAapo Vienamo NVQUIRK_ENABLE_SDR50 | 11522ad50051SAapo Vienamo NVQUIRK_ENABLE_SDR104, 11534346b7c7SThierry Reding }; 11544346b7c7SThierry Reding 1155498d83e7SBill Pemberton static const struct of_device_id sdhci_tegra_dt_match[] = { 11564346b7c7SThierry Reding { .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 }, 1157b5a84ecfSThierry Reding { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, 11584ae12588SThierry Reding { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, 11595ebf2552SRhyland Klein { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, 11603e44a1a7SStephen Warren { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, 11613e44a1a7SStephen Warren { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, 1162275173b2SGrant Likely {} 1163275173b2SGrant Likely }; 1164e4404fabSArnd Bergmann MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); 1165275173b2SGrant Likely 11663c4019f9SSowjanya Komatineni static int sdhci_tegra_add_host(struct sdhci_host *host) 11673c4019f9SSowjanya Komatineni { 11683c4019f9SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 11693c4019f9SSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 11703c4019f9SSowjanya Komatineni struct cqhci_host *cq_host; 11713c4019f9SSowjanya Komatineni bool dma64; 11723c4019f9SSowjanya Komatineni int ret; 11733c4019f9SSowjanya Komatineni 11743c4019f9SSowjanya Komatineni if (!tegra_host->enable_hwcq) 11753c4019f9SSowjanya Komatineni return sdhci_add_host(host); 11763c4019f9SSowjanya Komatineni 11773c4019f9SSowjanya Komatineni sdhci_enable_v4_mode(host); 11783c4019f9SSowjanya Komatineni 11793c4019f9SSowjanya Komatineni ret = sdhci_setup_host(host); 11803c4019f9SSowjanya Komatineni if (ret) 11813c4019f9SSowjanya Komatineni return ret; 11823c4019f9SSowjanya Komatineni 11833c4019f9SSowjanya Komatineni host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 11843c4019f9SSowjanya Komatineni 11853c4019f9SSowjanya Komatineni cq_host = devm_kzalloc(host->mmc->parent, 11863c4019f9SSowjanya Komatineni sizeof(*cq_host), GFP_KERNEL); 11873c4019f9SSowjanya Komatineni if (!cq_host) { 11883c4019f9SSowjanya Komatineni ret = -ENOMEM; 11893c4019f9SSowjanya Komatineni goto cleanup; 11903c4019f9SSowjanya Komatineni } 11913c4019f9SSowjanya Komatineni 11923c4019f9SSowjanya Komatineni cq_host->mmio = host->ioaddr + SDHCI_TEGRA_CQE_BASE_ADDR; 11933c4019f9SSowjanya Komatineni cq_host->ops = &sdhci_tegra_cqhci_ops; 11943c4019f9SSowjanya Komatineni 11953c4019f9SSowjanya Komatineni dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 11963c4019f9SSowjanya Komatineni if (dma64) 11973c4019f9SSowjanya Komatineni cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 11983c4019f9SSowjanya Komatineni 11993c4019f9SSowjanya Komatineni ret = cqhci_init(cq_host, host->mmc, dma64); 12003c4019f9SSowjanya Komatineni if (ret) 12013c4019f9SSowjanya Komatineni goto cleanup; 12023c4019f9SSowjanya Komatineni 12033c4019f9SSowjanya Komatineni ret = __sdhci_add_host(host); 12043c4019f9SSowjanya Komatineni if (ret) 12053c4019f9SSowjanya Komatineni goto cleanup; 12063c4019f9SSowjanya Komatineni 12073c4019f9SSowjanya Komatineni return 0; 12083c4019f9SSowjanya Komatineni 12093c4019f9SSowjanya Komatineni cleanup: 12103c4019f9SSowjanya Komatineni sdhci_cleanup_host(host); 12113c4019f9SSowjanya Komatineni return ret; 12123c4019f9SSowjanya Komatineni } 12133c4019f9SSowjanya Komatineni 1214c3be1efdSBill Pemberton static int sdhci_tegra_probe(struct platform_device *pdev) 121503d2bfc8SOlof Johansson { 12163e44a1a7SStephen Warren const struct of_device_id *match; 12173e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data; 12183e44a1a7SStephen Warren struct sdhci_host *host; 121985d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 12203e44a1a7SStephen Warren struct sdhci_tegra *tegra_host; 122103d2bfc8SOlof Johansson struct clk *clk; 122203d2bfc8SOlof Johansson int rc; 122303d2bfc8SOlof Johansson 12243e44a1a7SStephen Warren match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); 1225b37f9d98SJoseph Lo if (!match) 1226b37f9d98SJoseph Lo return -EINVAL; 12273e44a1a7SStephen Warren soc_data = match->data; 12283e44a1a7SStephen Warren 12290734e79cSJisheng Zhang host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*tegra_host)); 123085d6509dSShawn Guo if (IS_ERR(host)) 123185d6509dSShawn Guo return PTR_ERR(host); 123285d6509dSShawn Guo pltfm_host = sdhci_priv(host); 123385d6509dSShawn Guo 12340734e79cSJisheng Zhang tegra_host = sdhci_pltfm_priv(pltfm_host); 1235a8e326a9SLucas Stach tegra_host->ddr_signaling = false; 1236e5c63d91SLucas Stach tegra_host->pad_calib_required = false; 123786ac2f8bSAapo Vienamo tegra_host->pad_control_available = false; 12383e44a1a7SStephen Warren tegra_host->soc_data = soc_data; 1239275173b2SGrant Likely 124086ac2f8bSAapo Vienamo if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) { 124186ac2f8bSAapo Vienamo rc = tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host); 124286ac2f8bSAapo Vienamo if (rc == 0) 124386ac2f8bSAapo Vienamo host->mmc_host_ops.start_signal_voltage_switch = 124486ac2f8bSAapo Vienamo sdhci_tegra_start_signal_voltage_switch; 124586ac2f8bSAapo Vienamo } 124686ac2f8bSAapo Vienamo 124761dad40eSAapo Vienamo /* Hook to periodically rerun pad calibration */ 124861dad40eSAapo Vienamo if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 124961dad40eSAapo Vienamo host->mmc_host_ops.request = tegra_sdhci_request; 125061dad40eSAapo Vienamo 1251dfc9700cSAapo Vienamo host->mmc_host_ops.hs400_enhanced_strobe = 1252dfc9700cSAapo Vienamo tegra_sdhci_hs400_enhanced_strobe; 1253dfc9700cSAapo Vienamo 12542391b340SMylene JOSSERAND rc = mmc_of_parse(host->mmc); 125547caa84fSSimon Baatz if (rc) 125647caa84fSSimon Baatz goto err_parse_dt; 12570e786102SStephen Warren 12587ad2ed1dSLucas Stach if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 1259c3c2384cSLucas Stach host->mmc->caps |= MMC_CAP_1_8V_DDR; 1260c3c2384cSLucas Stach 12613c4019f9SSowjanya Komatineni tegra_sdhci_parse_dt(host); 126285c0da17SAapo Vienamo 12632391b340SMylene JOSSERAND tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", 12642391b340SMylene JOSSERAND GPIOD_OUT_HIGH); 12652391b340SMylene JOSSERAND if (IS_ERR(tegra_host->power_gpio)) { 12662391b340SMylene JOSSERAND rc = PTR_ERR(tegra_host->power_gpio); 126785d6509dSShawn Guo goto err_power_req; 126803d2bfc8SOlof Johansson } 126903d2bfc8SOlof Johansson 1270e4f79d9cSKevin Hao clk = devm_clk_get(mmc_dev(host->mmc), NULL); 127103d2bfc8SOlof Johansson if (IS_ERR(clk)) { 127203d2bfc8SOlof Johansson dev_err(mmc_dev(host->mmc), "clk err\n"); 127303d2bfc8SOlof Johansson rc = PTR_ERR(clk); 127485d6509dSShawn Guo goto err_clk_get; 127503d2bfc8SOlof Johansson } 12761e674bc6SPrashant Gaikwad clk_prepare_enable(clk); 127703d2bfc8SOlof Johansson pltfm_host->clk = clk; 127803d2bfc8SOlof Johansson 12792cd6c49dSPhilipp Zabel tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev, 12802cd6c49dSPhilipp Zabel "sdhci"); 128120567be9SThierry Reding if (IS_ERR(tegra_host->rst)) { 128220567be9SThierry Reding rc = PTR_ERR(tegra_host->rst); 128320567be9SThierry Reding dev_err(&pdev->dev, "failed to get reset control: %d\n", rc); 128420567be9SThierry Reding goto err_rst_get; 128520567be9SThierry Reding } 128620567be9SThierry Reding 128720567be9SThierry Reding rc = reset_control_assert(tegra_host->rst); 128820567be9SThierry Reding if (rc) 128920567be9SThierry Reding goto err_rst_get; 129020567be9SThierry Reding 129120567be9SThierry Reding usleep_range(2000, 4000); 129220567be9SThierry Reding 129320567be9SThierry Reding rc = reset_control_deassert(tegra_host->rst); 129420567be9SThierry Reding if (rc) 129520567be9SThierry Reding goto err_rst_get; 129620567be9SThierry Reding 129720567be9SThierry Reding usleep_range(2000, 4000); 129820567be9SThierry Reding 12993c4019f9SSowjanya Komatineni rc = sdhci_tegra_add_host(host); 130085d6509dSShawn Guo if (rc) 130185d6509dSShawn Guo goto err_add_host; 130285d6509dSShawn Guo 130303d2bfc8SOlof Johansson return 0; 130403d2bfc8SOlof Johansson 130585d6509dSShawn Guo err_add_host: 130620567be9SThierry Reding reset_control_assert(tegra_host->rst); 130720567be9SThierry Reding err_rst_get: 13081e674bc6SPrashant Gaikwad clk_disable_unprepare(pltfm_host->clk); 130985d6509dSShawn Guo err_clk_get: 131085d6509dSShawn Guo err_power_req: 131147caa84fSSimon Baatz err_parse_dt: 131285d6509dSShawn Guo sdhci_pltfm_free(pdev); 131303d2bfc8SOlof Johansson return rc; 131403d2bfc8SOlof Johansson } 131503d2bfc8SOlof Johansson 131620567be9SThierry Reding static int sdhci_tegra_remove(struct platform_device *pdev) 131720567be9SThierry Reding { 131820567be9SThierry Reding struct sdhci_host *host = platform_get_drvdata(pdev); 131920567be9SThierry Reding struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 132020567be9SThierry Reding struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 132120567be9SThierry Reding 132220567be9SThierry Reding sdhci_remove_host(host, 0); 132320567be9SThierry Reding 132420567be9SThierry Reding reset_control_assert(tegra_host->rst); 132520567be9SThierry Reding usleep_range(2000, 4000); 132620567be9SThierry Reding clk_disable_unprepare(pltfm_host->clk); 132720567be9SThierry Reding 132820567be9SThierry Reding sdhci_pltfm_free(pdev); 132920567be9SThierry Reding 133020567be9SThierry Reding return 0; 133120567be9SThierry Reding } 133220567be9SThierry Reding 133385d6509dSShawn Guo static struct platform_driver sdhci_tegra_driver = { 133485d6509dSShawn Guo .driver = { 133585d6509dSShawn Guo .name = "sdhci-tegra", 1336275173b2SGrant Likely .of_match_table = sdhci_tegra_dt_match, 1337fa243f64SUlf Hansson .pm = &sdhci_pltfm_pmops, 133885d6509dSShawn Guo }, 133985d6509dSShawn Guo .probe = sdhci_tegra_probe, 134020567be9SThierry Reding .remove = sdhci_tegra_remove, 134103d2bfc8SOlof Johansson }; 134203d2bfc8SOlof Johansson 1343d1f81a64SAxel Lin module_platform_driver(sdhci_tegra_driver); 134485d6509dSShawn Guo 134585d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Tegra"); 134685d6509dSShawn Guo MODULE_AUTHOR("Google, Inc."); 134785d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 1348