19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 203d2bfc8SOlof Johansson /* 303d2bfc8SOlof Johansson * Copyright (C) 2010 Google, Inc. 403d2bfc8SOlof Johansson */ 503d2bfc8SOlof Johansson 6e5c63d91SLucas Stach #include <linux/delay.h> 7b960bc44SNicolin Chen #include <linux/dma-mapping.h> 803d2bfc8SOlof Johansson #include <linux/err.h> 996547f5dSPaul Gortmaker #include <linux/module.h> 1003d2bfc8SOlof Johansson #include <linux/init.h> 11e7c07148SAapo Vienamo #include <linux/iopoll.h> 1203d2bfc8SOlof Johansson #include <linux/platform_device.h> 1303d2bfc8SOlof Johansson #include <linux/clk.h> 1403d2bfc8SOlof Johansson #include <linux/io.h> 1555cd65e4SStephen Warren #include <linux/of.h> 163e44a1a7SStephen Warren #include <linux/of_device.h> 1786ac2f8bSAapo Vienamo #include <linux/pinctrl/consumer.h> 1886ac2f8bSAapo Vienamo #include <linux/regulator/consumer.h> 1920567be9SThierry Reding #include <linux/reset.h> 2003d2bfc8SOlof Johansson #include <linux/mmc/card.h> 2103d2bfc8SOlof Johansson #include <linux/mmc/host.h> 22c3c2384cSLucas Stach #include <linux/mmc/mmc.h> 230aacd23fSJoseph Lo #include <linux/mmc/slot-gpio.h> 242391b340SMylene JOSSERAND #include <linux/gpio/consumer.h> 2561dad40eSAapo Vienamo #include <linux/ktime.h> 2603d2bfc8SOlof Johansson 2703d2bfc8SOlof Johansson #include "sdhci-pltfm.h" 283c4019f9SSowjanya Komatineni #include "cqhci.h" 2903d2bfc8SOlof Johansson 30ca5879d3SPavan Kunapuli /* Tegra SDHOST controller vendor register definitions */ 3174cd42bcSLucas Stach #define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 32c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 33c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 3441a0b8d7SAapo Vienamo #define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000 3541a0b8d7SAapo Vienamo #define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24 36c3c2384cSLucas Stach #define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) 3774cd42bcSLucas Stach #define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3) 3874cd42bcSLucas Stach #define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2) 3974cd42bcSLucas Stach 40dfc9700cSAapo Vienamo #define SDHCI_TEGRA_VENDOR_SYS_SW_CTRL 0x104 41dfc9700cSAapo Vienamo #define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE BIT(31) 42dfc9700cSAapo Vienamo 43f5313aaaSAapo Vienamo #define SDHCI_TEGRA_VENDOR_CAP_OVERRIDES 0x10c 44f5313aaaSAapo Vienamo #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK 0x00003f00 45f5313aaaSAapo Vienamo #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT 8 46f5313aaaSAapo Vienamo 47ca5879d3SPavan Kunapuli #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 485e958e4aSSowjanya Komatineni #define SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT BIT(0) 493145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8 503145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10 51ca5879d3SPavan Kunapuli #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 523145351aSAndrew Bresticker #define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200 53ca5879d3SPavan Kunapuli 54bc5568bfSAapo Vienamo #define SDHCI_TEGRA_VENDOR_DLLCAL_CFG 0x1b0 55bc5568bfSAapo Vienamo #define SDHCI_TEGRA_DLLCAL_CALIBRATE BIT(31) 56bc5568bfSAapo Vienamo 57bc5568bfSAapo Vienamo #define SDHCI_TEGRA_VENDOR_DLLCAL_STA 0x1bc 58bc5568bfSAapo Vienamo #define SDHCI_TEGRA_DLLCAL_STA_ACTIVE BIT(31) 59bc5568bfSAapo Vienamo 60d4501d8eSAapo Vienamo #define SDHCI_VNDR_TUN_CTRL0_0 0x1c0 61d4501d8eSAapo Vienamo #define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP 0x20000 62ea8fc595SSowjanya Komatineni #define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK 0x03fc0000 63ea8fc595SSowjanya Komatineni #define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT 18 64ea8fc595SSowjanya Komatineni #define SDHCI_VNDR_TUN_CTRL0_MUL_M_MASK 0x00001fc0 65ea8fc595SSowjanya Komatineni #define SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT 6 66ea8fc595SSowjanya Komatineni #define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK 0x000e000 67ea8fc595SSowjanya Komatineni #define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT 13 68ea8fc595SSowjanya Komatineni #define TRIES_128 2 69ea8fc595SSowjanya Komatineni #define TRIES_256 4 70ea8fc595SSowjanya Komatineni #define SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK 0x7 71ea8fc595SSowjanya Komatineni 72ea8fc595SSowjanya Komatineni #define SDHCI_TEGRA_VNDR_TUN_CTRL1_0 0x1c4 73ea8fc595SSowjanya Komatineni #define SDHCI_TEGRA_VNDR_TUN_STATUS0 0x1C8 74ea8fc595SSowjanya Komatineni #define SDHCI_TEGRA_VNDR_TUN_STATUS1 0x1CC 75ea8fc595SSowjanya Komatineni #define SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK 0xFF 76ea8fc595SSowjanya Komatineni #define SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT 0x8 77ea8fc595SSowjanya Komatineni #define TUNING_WORD_BIT_SIZE 32 78d4501d8eSAapo Vienamo 79e5c63d91SLucas Stach #define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4 80e5c63d91SLucas Stach #define SDHCI_AUTO_CAL_START BIT(31) 81e5c63d91SLucas Stach #define SDHCI_AUTO_CAL_ENABLE BIT(29) 8251b77c8eSAapo Vienamo #define SDHCI_AUTO_CAL_PDPU_OFFSET_MASK 0x0000ffff 83e5c63d91SLucas Stach 849d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL 0x1e0 859d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK 0x0000000f 869d548f11SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL 0x7 87212b0cf1SAapo Vienamo #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD BIT(31) 88de25fa5aSSowjanya Komatineni #define SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK 0x07FFF000 899d548f11SAapo Vienamo 90e7c07148SAapo Vienamo #define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec 91e7c07148SAapo Vienamo #define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31) 92e7c07148SAapo Vienamo 933e44a1a7SStephen Warren #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) 943e44a1a7SStephen Warren #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) 95ca5879d3SPavan Kunapuli #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) 967ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_SDR50 BIT(3) 977ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_SDR104 BIT(4) 987ad2ed1dSLucas Stach #define NVQUIRK_ENABLE_DDR50 BIT(5) 9947fad46bSSowjanya Komatineni /* 10047fad46bSSowjanya Komatineni * HAS_PADCALIB NVQUIRK is for SoC's supporting auto calibration of pads 10147fad46bSSowjanya Komatineni * drive strength. 10247fad46bSSowjanya Komatineni */ 103e5c63d91SLucas Stach #define NVQUIRK_HAS_PADCALIB BIT(6) 10447fad46bSSowjanya Komatineni /* 10547fad46bSSowjanya Komatineni * NEEDS_PAD_CONTROL NVQUIRK is for SoC's having separate 3V3 and 1V8 pads. 10647fad46bSSowjanya Komatineni * 3V3/1V8 pad selection happens through pinctrl state selection depending 10747fad46bSSowjanya Komatineni * on the signaling mode. 10847fad46bSSowjanya Komatineni */ 10986ac2f8bSAapo Vienamo #define NVQUIRK_NEEDS_PAD_CONTROL BIT(7) 110d4501d8eSAapo Vienamo #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) 111c6e7ab90SSowjanya Komatineni #define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9) 1123e44a1a7SStephen Warren 1138048822bSSowjanya Komatineni /* 1148048822bSSowjanya Komatineni * NVQUIRK_HAS_TMCLK is for SoC's having separate timeout clock for Tegra 1158048822bSSowjanya Komatineni * SDMMC hardware data timeout. 1168048822bSSowjanya Komatineni */ 1178048822bSSowjanya Komatineni #define NVQUIRK_HAS_TMCLK BIT(10) 1188048822bSSowjanya Komatineni 1193c4019f9SSowjanya Komatineni /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */ 1203c4019f9SSowjanya Komatineni #define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000 1213c4019f9SSowjanya Komatineni 1223e44a1a7SStephen Warren struct sdhci_tegra_soc_data { 1231db5eebfSLars-Peter Clausen const struct sdhci_pltfm_data *pdata; 124b960bc44SNicolin Chen u64 dma_mask; 1253e44a1a7SStephen Warren u32 nvquirks; 126ea8fc595SSowjanya Komatineni u8 min_tap_delay; 127ea8fc595SSowjanya Komatineni u8 max_tap_delay; 1283e44a1a7SStephen Warren }; 1293e44a1a7SStephen Warren 13051b77c8eSAapo Vienamo /* Magic pull up and pull down pad calibration offsets */ 13151b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets { 13251b77c8eSAapo Vienamo u32 pull_up_3v3; 13351b77c8eSAapo Vienamo u32 pull_down_3v3; 13451b77c8eSAapo Vienamo u32 pull_up_3v3_timeout; 13551b77c8eSAapo Vienamo u32 pull_down_3v3_timeout; 13651b77c8eSAapo Vienamo u32 pull_up_1v8; 13751b77c8eSAapo Vienamo u32 pull_down_1v8; 13851b77c8eSAapo Vienamo u32 pull_up_1v8_timeout; 13951b77c8eSAapo Vienamo u32 pull_down_1v8_timeout; 14051b77c8eSAapo Vienamo u32 pull_up_sdr104; 14151b77c8eSAapo Vienamo u32 pull_down_sdr104; 14251b77c8eSAapo Vienamo u32 pull_up_hs400; 14351b77c8eSAapo Vienamo u32 pull_down_hs400; 14451b77c8eSAapo Vienamo }; 14551b77c8eSAapo Vienamo 1463e44a1a7SStephen Warren struct sdhci_tegra { 1473e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data; 1482391b340SMylene JOSSERAND struct gpio_desc *power_gpio; 1498048822bSSowjanya Komatineni struct clk *tmclk; 150a8e326a9SLucas Stach bool ddr_signaling; 151e5c63d91SLucas Stach bool pad_calib_required; 15286ac2f8bSAapo Vienamo bool pad_control_available; 15320567be9SThierry Reding 15420567be9SThierry Reding struct reset_control *rst; 15586ac2f8bSAapo Vienamo struct pinctrl *pinctrl_sdmmc; 15686ac2f8bSAapo Vienamo struct pinctrl_state *pinctrl_state_3v3; 15786ac2f8bSAapo Vienamo struct pinctrl_state *pinctrl_state_1v8; 158de25fa5aSSowjanya Komatineni struct pinctrl_state *pinctrl_state_3v3_drv; 159de25fa5aSSowjanya Komatineni struct pinctrl_state *pinctrl_state_1v8_drv; 16051b77c8eSAapo Vienamo 16151b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets autocal_offsets; 16261dad40eSAapo Vienamo ktime_t last_calib; 16385c0da17SAapo Vienamo 16485c0da17SAapo Vienamo u32 default_tap; 16585c0da17SAapo Vienamo u32 default_trim; 166f5313aaaSAapo Vienamo u32 dqs_trim; 1673c4019f9SSowjanya Komatineni bool enable_hwcq; 168ea8fc595SSowjanya Komatineni unsigned long curr_clk_rate; 169ea8fc595SSowjanya Komatineni u8 tuned_tap_delay; 1703e44a1a7SStephen Warren }; 1713e44a1a7SStephen Warren 17203d2bfc8SOlof Johansson static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) 17303d2bfc8SOlof Johansson { 1743e44a1a7SStephen Warren struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1750734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1763e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 1773e44a1a7SStephen Warren 1783e44a1a7SStephen Warren if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && 1793e44a1a7SStephen Warren (reg == SDHCI_HOST_VERSION))) { 18003d2bfc8SOlof Johansson /* Erratum: Version register is invalid in HW. */ 18103d2bfc8SOlof Johansson return SDHCI_SPEC_200; 18203d2bfc8SOlof Johansson } 18303d2bfc8SOlof Johansson 18403d2bfc8SOlof Johansson return readw(host->ioaddr + reg); 18503d2bfc8SOlof Johansson } 18603d2bfc8SOlof Johansson 187352ee868SPavan Kunapuli static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg) 188352ee868SPavan Kunapuli { 189352ee868SPavan Kunapuli struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 190352ee868SPavan Kunapuli 191352ee868SPavan Kunapuli switch (reg) { 192352ee868SPavan Kunapuli case SDHCI_TRANSFER_MODE: 193352ee868SPavan Kunapuli /* 194352ee868SPavan Kunapuli * Postpone this write, we must do it together with a 195352ee868SPavan Kunapuli * command write that is down below. 196352ee868SPavan Kunapuli */ 197352ee868SPavan Kunapuli pltfm_host->xfer_mode_shadow = val; 198352ee868SPavan Kunapuli return; 199352ee868SPavan Kunapuli case SDHCI_COMMAND: 200352ee868SPavan Kunapuli writel((val << 16) | pltfm_host->xfer_mode_shadow, 201352ee868SPavan Kunapuli host->ioaddr + SDHCI_TRANSFER_MODE); 202352ee868SPavan Kunapuli return; 203352ee868SPavan Kunapuli } 204352ee868SPavan Kunapuli 205352ee868SPavan Kunapuli writew(val, host->ioaddr + reg); 206352ee868SPavan Kunapuli } 207352ee868SPavan Kunapuli 20803d2bfc8SOlof Johansson static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) 20903d2bfc8SOlof Johansson { 2103e44a1a7SStephen Warren struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2110734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 2123e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 2133e44a1a7SStephen Warren 21403d2bfc8SOlof Johansson /* Seems like we're getting spurious timeout and crc errors, so 21503d2bfc8SOlof Johansson * disable signalling of them. In case of real errors software 21603d2bfc8SOlof Johansson * timers should take care of eventually detecting them. 21703d2bfc8SOlof Johansson */ 21803d2bfc8SOlof Johansson if (unlikely(reg == SDHCI_SIGNAL_ENABLE)) 21903d2bfc8SOlof Johansson val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC); 22003d2bfc8SOlof Johansson 22103d2bfc8SOlof Johansson writel(val, host->ioaddr + reg); 22203d2bfc8SOlof Johansson 2233e44a1a7SStephen Warren if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) && 2243e44a1a7SStephen Warren (reg == SDHCI_INT_ENABLE))) { 22503d2bfc8SOlof Johansson /* Erratum: Must enable block gap interrupt detection */ 22603d2bfc8SOlof Johansson u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 22703d2bfc8SOlof Johansson if (val & SDHCI_INT_CARD_INT) 22803d2bfc8SOlof Johansson gap_ctrl |= 0x8; 22903d2bfc8SOlof Johansson else 23003d2bfc8SOlof Johansson gap_ctrl &= ~0x8; 23103d2bfc8SOlof Johansson writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 23203d2bfc8SOlof Johansson } 23303d2bfc8SOlof Johansson } 23403d2bfc8SOlof Johansson 23538a284d9SAapo Vienamo static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable) 23638a284d9SAapo Vienamo { 23738a284d9SAapo Vienamo bool status; 23838a284d9SAapo Vienamo u32 reg; 23938a284d9SAapo Vienamo 24038a284d9SAapo Vienamo reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 24138a284d9SAapo Vienamo status = !!(reg & SDHCI_CLOCK_CARD_EN); 24238a284d9SAapo Vienamo 24338a284d9SAapo Vienamo if (status == enable) 24438a284d9SAapo Vienamo return status; 24538a284d9SAapo Vienamo 24638a284d9SAapo Vienamo if (enable) 24738a284d9SAapo Vienamo reg |= SDHCI_CLOCK_CARD_EN; 24838a284d9SAapo Vienamo else 24938a284d9SAapo Vienamo reg &= ~SDHCI_CLOCK_CARD_EN; 25038a284d9SAapo Vienamo 25138a284d9SAapo Vienamo sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); 25238a284d9SAapo Vienamo 25338a284d9SAapo Vienamo return status; 25438a284d9SAapo Vienamo } 25538a284d9SAapo Vienamo 25638a284d9SAapo Vienamo static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg) 25738a284d9SAapo Vienamo { 25838a284d9SAapo Vienamo bool is_tuning_cmd = 0; 25938a284d9SAapo Vienamo bool clk_enabled; 26038a284d9SAapo Vienamo u8 cmd; 26138a284d9SAapo Vienamo 26238a284d9SAapo Vienamo if (reg == SDHCI_COMMAND) { 26338a284d9SAapo Vienamo cmd = SDHCI_GET_CMD(val); 26438a284d9SAapo Vienamo is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK || 26538a284d9SAapo Vienamo cmd == MMC_SEND_TUNING_BLOCK_HS200; 26638a284d9SAapo Vienamo } 26738a284d9SAapo Vienamo 26838a284d9SAapo Vienamo if (is_tuning_cmd) 26938a284d9SAapo Vienamo clk_enabled = tegra_sdhci_configure_card_clk(host, 0); 27038a284d9SAapo Vienamo 27138a284d9SAapo Vienamo writew(val, host->ioaddr + reg); 27238a284d9SAapo Vienamo 27338a284d9SAapo Vienamo if (is_tuning_cmd) { 27438a284d9SAapo Vienamo udelay(1); 275ea8fc595SSowjanya Komatineni sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 27638a284d9SAapo Vienamo tegra_sdhci_configure_card_clk(host, clk_enabled); 27738a284d9SAapo Vienamo } 27838a284d9SAapo Vienamo } 27938a284d9SAapo Vienamo 2800f686ca9SDmitry Osipenko static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) 2810f686ca9SDmitry Osipenko { 2820f686ca9SDmitry Osipenko /* 2830f686ca9SDmitry Osipenko * Write-enable shall be assumed if GPIO is missing in a board's 2840f686ca9SDmitry Osipenko * device-tree because SDHCI's WRITE_PROTECT bit doesn't work on 2850f686ca9SDmitry Osipenko * Tegra. 2860f686ca9SDmitry Osipenko */ 2870f686ca9SDmitry Osipenko return mmc_gpio_get_ro(host->mmc); 2880f686ca9SDmitry Osipenko } 2890f686ca9SDmitry Osipenko 29086ac2f8bSAapo Vienamo static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host) 29186ac2f8bSAapo Vienamo { 29286ac2f8bSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 29386ac2f8bSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 29486ac2f8bSAapo Vienamo int has_1v8, has_3v3; 29586ac2f8bSAapo Vienamo 29686ac2f8bSAapo Vienamo /* 29786ac2f8bSAapo Vienamo * The SoCs which have NVQUIRK_NEEDS_PAD_CONTROL require software pad 29886ac2f8bSAapo Vienamo * voltage configuration in order to perform voltage switching. This 29986ac2f8bSAapo Vienamo * means that valid pinctrl info is required on SDHCI instances capable 30086ac2f8bSAapo Vienamo * of performing voltage switching. Whether or not an SDHCI instance is 30186ac2f8bSAapo Vienamo * capable of voltage switching is determined based on the regulator. 30286ac2f8bSAapo Vienamo */ 30386ac2f8bSAapo Vienamo 30486ac2f8bSAapo Vienamo if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)) 30586ac2f8bSAapo Vienamo return true; 30686ac2f8bSAapo Vienamo 30786ac2f8bSAapo Vienamo if (IS_ERR(host->mmc->supply.vqmmc)) 30886ac2f8bSAapo Vienamo return false; 30986ac2f8bSAapo Vienamo 31086ac2f8bSAapo Vienamo has_1v8 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 31186ac2f8bSAapo Vienamo 1700000, 1950000); 31286ac2f8bSAapo Vienamo 31386ac2f8bSAapo Vienamo has_3v3 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 31486ac2f8bSAapo Vienamo 2700000, 3600000); 31586ac2f8bSAapo Vienamo 31686ac2f8bSAapo Vienamo if (has_1v8 == 1 && has_3v3 == 1) 31786ac2f8bSAapo Vienamo return tegra_host->pad_control_available; 31886ac2f8bSAapo Vienamo 31986ac2f8bSAapo Vienamo /* Fixed voltage, no pad control required. */ 32086ac2f8bSAapo Vienamo return true; 32186ac2f8bSAapo Vienamo } 32286ac2f8bSAapo Vienamo 323c2c09678SAapo Vienamo static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) 324c2c09678SAapo Vienamo { 325c2c09678SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 326c2c09678SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 327c2c09678SAapo Vienamo const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 328c2c09678SAapo Vienamo bool card_clk_enabled = false; 329c2c09678SAapo Vienamo u32 reg; 330c2c09678SAapo Vienamo 331c2c09678SAapo Vienamo /* 332c2c09678SAapo Vienamo * Touching the tap values is a bit tricky on some SoC generations. 333c2c09678SAapo Vienamo * The quirk enables a workaround for a glitch that sometimes occurs if 334c2c09678SAapo Vienamo * the tap values are changed. 335c2c09678SAapo Vienamo */ 336c2c09678SAapo Vienamo 337c2c09678SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP) 338c2c09678SAapo Vienamo card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); 339c2c09678SAapo Vienamo 340c2c09678SAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 341c2c09678SAapo Vienamo reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; 342c2c09678SAapo Vienamo reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; 343c2c09678SAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 344c2c09678SAapo Vienamo 345c2c09678SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP && 346c2c09678SAapo Vienamo card_clk_enabled) { 347c2c09678SAapo Vienamo udelay(1); 348c2c09678SAapo Vienamo sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 349c2c09678SAapo Vienamo tegra_sdhci_configure_card_clk(host, card_clk_enabled); 350c2c09678SAapo Vienamo } 351c2c09678SAapo Vienamo } 352c2c09678SAapo Vienamo 353dfc9700cSAapo Vienamo static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, 354dfc9700cSAapo Vienamo struct mmc_ios *ios) 355dfc9700cSAapo Vienamo { 356dfc9700cSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 357dfc9700cSAapo Vienamo u32 val; 358dfc9700cSAapo Vienamo 359dfc9700cSAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); 360dfc9700cSAapo Vienamo 361dfc9700cSAapo Vienamo if (ios->enhanced_strobe) 362dfc9700cSAapo Vienamo val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; 363dfc9700cSAapo Vienamo else 364dfc9700cSAapo Vienamo val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; 365dfc9700cSAapo Vienamo 366dfc9700cSAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); 367dfc9700cSAapo Vienamo 368dfc9700cSAapo Vienamo } 369dfc9700cSAapo Vienamo 37003231f9bSRussell King static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) 371ca5879d3SPavan Kunapuli { 372ca5879d3SPavan Kunapuli struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 3730734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 374ca5879d3SPavan Kunapuli const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 3759d548f11SAapo Vienamo u32 misc_ctrl, clk_ctrl, pad_ctrl; 376ca5879d3SPavan Kunapuli 37703231f9bSRussell King sdhci_reset(host, mask); 37803231f9bSRussell King 379ca5879d3SPavan Kunapuli if (!(mask & SDHCI_RESET_ALL)) 380ca5879d3SPavan Kunapuli return; 381ca5879d3SPavan Kunapuli 382c2c09678SAapo Vienamo tegra_sdhci_set_tap(host, tegra_host->default_tap); 383c2c09678SAapo Vienamo 3841b84def8SLucas Stach misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); 3854f6aa326SJon Hunter clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 3864f6aa326SJon Hunter 3874f6aa326SJon Hunter misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 | 3884f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_SDR50 | 3894f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_DDR50 | 3904f6aa326SJon Hunter SDHCI_MISC_CTRL_ENABLE_SDR104); 3914f6aa326SJon Hunter 39241a0b8d7SAapo Vienamo clk_ctrl &= ~(SDHCI_CLOCK_CTRL_TRIM_MASK | 39341a0b8d7SAapo Vienamo SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE); 3944f6aa326SJon Hunter 39586ac2f8bSAapo Vienamo if (tegra_sdhci_is_pad_and_regulator_valid(host)) { 396ca5879d3SPavan Kunapuli /* Erratum: Enable SDHCI spec v3.00 support */ 3973145351aSAndrew Bresticker if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) 398ca5879d3SPavan Kunapuli misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; 3997ad2ed1dSLucas Stach /* Advertise UHS modes as supported by host */ 4007ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) 4017ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; 4027ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 4037ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; 4047ad2ed1dSLucas Stach if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) 4057ad2ed1dSLucas Stach misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; 406f571389cSMichał Mirosław if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) 407c3c2384cSLucas Stach clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; 4084f6aa326SJon Hunter } 4094f6aa326SJon Hunter 41041a0b8d7SAapo Vienamo clk_ctrl |= tegra_host->default_trim << SDHCI_CLOCK_CTRL_TRIM_SHIFT; 41141a0b8d7SAapo Vienamo 4124f6aa326SJon Hunter sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); 41374cd42bcSLucas Stach sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 41474cd42bcSLucas Stach 4159d548f11SAapo Vienamo if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) { 4169d548f11SAapo Vienamo pad_ctrl = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 4179d548f11SAapo Vienamo pad_ctrl &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK; 4189d548f11SAapo Vienamo pad_ctrl |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL; 4199d548f11SAapo Vienamo sdhci_writel(host, pad_ctrl, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 4209d548f11SAapo Vienamo 421e5c63d91SLucas Stach tegra_host->pad_calib_required = true; 4229d548f11SAapo Vienamo } 423e5c63d91SLucas Stach 424a8e326a9SLucas Stach tegra_host->ddr_signaling = false; 425ca5879d3SPavan Kunapuli } 426ca5879d3SPavan Kunapuli 427212b0cf1SAapo Vienamo static void tegra_sdhci_configure_cal_pad(struct sdhci_host *host, bool enable) 428212b0cf1SAapo Vienamo { 429212b0cf1SAapo Vienamo u32 val; 430212b0cf1SAapo Vienamo 431212b0cf1SAapo Vienamo /* 432212b0cf1SAapo Vienamo * Enable or disable the additional I/O pad used by the drive strength 433212b0cf1SAapo Vienamo * calibration process. 434212b0cf1SAapo Vienamo */ 435212b0cf1SAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 436212b0cf1SAapo Vienamo 437212b0cf1SAapo Vienamo if (enable) 438212b0cf1SAapo Vienamo val |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; 439212b0cf1SAapo Vienamo else 440212b0cf1SAapo Vienamo val &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; 441212b0cf1SAapo Vienamo 442212b0cf1SAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 443212b0cf1SAapo Vienamo 444212b0cf1SAapo Vienamo if (enable) 445212b0cf1SAapo Vienamo usleep_range(1, 2); 446212b0cf1SAapo Vienamo } 447212b0cf1SAapo Vienamo 44851b77c8eSAapo Vienamo static void tegra_sdhci_set_pad_autocal_offset(struct sdhci_host *host, 44951b77c8eSAapo Vienamo u16 pdpu) 45051b77c8eSAapo Vienamo { 45151b77c8eSAapo Vienamo u32 reg; 45251b77c8eSAapo Vienamo 45351b77c8eSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 45451b77c8eSAapo Vienamo reg &= ~SDHCI_AUTO_CAL_PDPU_OFFSET_MASK; 45551b77c8eSAapo Vienamo reg |= pdpu; 45651b77c8eSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 45751b77c8eSAapo Vienamo } 45851b77c8eSAapo Vienamo 459de25fa5aSSowjanya Komatineni static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage, 460de25fa5aSSowjanya Komatineni bool state_drvupdn) 461de25fa5aSSowjanya Komatineni { 462de25fa5aSSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 463de25fa5aSSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 464de25fa5aSSowjanya Komatineni struct sdhci_tegra_autocal_offsets *offsets = 465de25fa5aSSowjanya Komatineni &tegra_host->autocal_offsets; 466de25fa5aSSowjanya Komatineni struct pinctrl_state *pinctrl_drvupdn = NULL; 467de25fa5aSSowjanya Komatineni int ret = 0; 468de25fa5aSSowjanya Komatineni u8 drvup = 0, drvdn = 0; 469de25fa5aSSowjanya Komatineni u32 reg; 470de25fa5aSSowjanya Komatineni 471de25fa5aSSowjanya Komatineni if (!state_drvupdn) { 472de25fa5aSSowjanya Komatineni /* PADS Drive Strength */ 473de25fa5aSSowjanya Komatineni if (voltage == MMC_SIGNAL_VOLTAGE_180) { 474de25fa5aSSowjanya Komatineni if (tegra_host->pinctrl_state_1v8_drv) { 475de25fa5aSSowjanya Komatineni pinctrl_drvupdn = 476de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8_drv; 477de25fa5aSSowjanya Komatineni } else { 478de25fa5aSSowjanya Komatineni drvup = offsets->pull_up_1v8_timeout; 479de25fa5aSSowjanya Komatineni drvdn = offsets->pull_down_1v8_timeout; 480de25fa5aSSowjanya Komatineni } 481de25fa5aSSowjanya Komatineni } else { 482de25fa5aSSowjanya Komatineni if (tegra_host->pinctrl_state_3v3_drv) { 483de25fa5aSSowjanya Komatineni pinctrl_drvupdn = 484de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3_drv; 485de25fa5aSSowjanya Komatineni } else { 486de25fa5aSSowjanya Komatineni drvup = offsets->pull_up_3v3_timeout; 487de25fa5aSSowjanya Komatineni drvdn = offsets->pull_down_3v3_timeout; 488de25fa5aSSowjanya Komatineni } 489de25fa5aSSowjanya Komatineni } 490de25fa5aSSowjanya Komatineni 491de25fa5aSSowjanya Komatineni if (pinctrl_drvupdn != NULL) { 492de25fa5aSSowjanya Komatineni ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 493de25fa5aSSowjanya Komatineni pinctrl_drvupdn); 494de25fa5aSSowjanya Komatineni if (ret < 0) 495de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 496de25fa5aSSowjanya Komatineni "failed pads drvupdn, ret: %d\n", ret); 497de25fa5aSSowjanya Komatineni } else if ((drvup) || (drvdn)) { 498de25fa5aSSowjanya Komatineni reg = sdhci_readl(host, 499de25fa5aSSowjanya Komatineni SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 500de25fa5aSSowjanya Komatineni reg &= ~SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK; 501de25fa5aSSowjanya Komatineni reg |= (drvup << 20) | (drvdn << 12); 502de25fa5aSSowjanya Komatineni sdhci_writel(host, reg, 503de25fa5aSSowjanya Komatineni SDHCI_TEGRA_SDMEM_COMP_PADCTRL); 504de25fa5aSSowjanya Komatineni } 505de25fa5aSSowjanya Komatineni 506de25fa5aSSowjanya Komatineni } else { 507de25fa5aSSowjanya Komatineni /* Dual Voltage PADS Voltage selection */ 508de25fa5aSSowjanya Komatineni if (!tegra_host->pad_control_available) 509de25fa5aSSowjanya Komatineni return 0; 510de25fa5aSSowjanya Komatineni 511de25fa5aSSowjanya Komatineni if (voltage == MMC_SIGNAL_VOLTAGE_180) { 512de25fa5aSSowjanya Komatineni ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 513de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8); 514de25fa5aSSowjanya Komatineni if (ret < 0) 515de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 516de25fa5aSSowjanya Komatineni "setting 1.8V failed, ret: %d\n", ret); 517de25fa5aSSowjanya Komatineni } else { 518de25fa5aSSowjanya Komatineni ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, 519de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3); 520de25fa5aSSowjanya Komatineni if (ret < 0) 521de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 522de25fa5aSSowjanya Komatineni "setting 3.3V failed, ret: %d\n", ret); 523de25fa5aSSowjanya Komatineni } 524de25fa5aSSowjanya Komatineni } 525de25fa5aSSowjanya Komatineni 526de25fa5aSSowjanya Komatineni return ret; 527de25fa5aSSowjanya Komatineni } 528de25fa5aSSowjanya Komatineni 529e5c63d91SLucas Stach static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) 530e5c63d91SLucas Stach { 53151b77c8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 53251b77c8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 53351b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets offsets = 53451b77c8eSAapo Vienamo tegra_host->autocal_offsets; 53551b77c8eSAapo Vienamo struct mmc_ios *ios = &host->mmc->ios; 536887bda8fSAapo Vienamo bool card_clk_enabled; 53751b77c8eSAapo Vienamo u16 pdpu; 538e7c07148SAapo Vienamo u32 reg; 539e7c07148SAapo Vienamo int ret; 540e5c63d91SLucas Stach 54151b77c8eSAapo Vienamo switch (ios->timing) { 54251b77c8eSAapo Vienamo case MMC_TIMING_UHS_SDR104: 54351b77c8eSAapo Vienamo pdpu = offsets.pull_down_sdr104 << 8 | offsets.pull_up_sdr104; 54451b77c8eSAapo Vienamo break; 54551b77c8eSAapo Vienamo case MMC_TIMING_MMC_HS400: 54651b77c8eSAapo Vienamo pdpu = offsets.pull_down_hs400 << 8 | offsets.pull_up_hs400; 54751b77c8eSAapo Vienamo break; 54851b77c8eSAapo Vienamo default: 54951b77c8eSAapo Vienamo if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) 55051b77c8eSAapo Vienamo pdpu = offsets.pull_down_1v8 << 8 | offsets.pull_up_1v8; 55151b77c8eSAapo Vienamo else 55251b77c8eSAapo Vienamo pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3; 55351b77c8eSAapo Vienamo } 55451b77c8eSAapo Vienamo 555de25fa5aSSowjanya Komatineni /* Set initial offset before auto-calibration */ 55651b77c8eSAapo Vienamo tegra_sdhci_set_pad_autocal_offset(host, pdpu); 55751b77c8eSAapo Vienamo 558887bda8fSAapo Vienamo card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); 559887bda8fSAapo Vienamo 560212b0cf1SAapo Vienamo tegra_sdhci_configure_cal_pad(host, true); 561212b0cf1SAapo Vienamo 562e7c07148SAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 563e7c07148SAapo Vienamo reg |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START; 564e7c07148SAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 565e5c63d91SLucas Stach 566e7c07148SAapo Vienamo usleep_range(1, 2); 567e7c07148SAapo Vienamo /* 10 ms timeout */ 568e7c07148SAapo Vienamo ret = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_AUTO_CAL_STATUS, 569e7c07148SAapo Vienamo reg, !(reg & SDHCI_TEGRA_AUTO_CAL_ACTIVE), 570e7c07148SAapo Vienamo 1000, 10000); 571e7c07148SAapo Vienamo 572212b0cf1SAapo Vienamo tegra_sdhci_configure_cal_pad(host, false); 573212b0cf1SAapo Vienamo 574887bda8fSAapo Vienamo tegra_sdhci_configure_card_clk(host, card_clk_enabled); 575887bda8fSAapo Vienamo 57651b77c8eSAapo Vienamo if (ret) { 577e7c07148SAapo Vienamo dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n"); 57851b77c8eSAapo Vienamo 579de25fa5aSSowjanya Komatineni /* Disable automatic cal and use fixed Drive Strengths */ 58051b77c8eSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); 58151b77c8eSAapo Vienamo reg &= ~SDHCI_AUTO_CAL_ENABLE; 58251b77c8eSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); 58351b77c8eSAapo Vienamo 584de25fa5aSSowjanya Komatineni ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, false); 585de25fa5aSSowjanya Komatineni if (ret < 0) 586de25fa5aSSowjanya Komatineni dev_err(mmc_dev(host->mmc), 587de25fa5aSSowjanya Komatineni "Setting drive strengths failed: %d\n", ret); 58851b77c8eSAapo Vienamo } 58951b77c8eSAapo Vienamo } 59051b77c8eSAapo Vienamo 59151b77c8eSAapo Vienamo static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host) 59251b77c8eSAapo Vienamo { 59351b77c8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 59451b77c8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 59551b77c8eSAapo Vienamo struct sdhci_tegra_autocal_offsets *autocal = 59651b77c8eSAapo Vienamo &tegra_host->autocal_offsets; 59751b77c8eSAapo Vienamo int err; 59851b77c8eSAapo Vienamo 59951b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 60051b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-3v3", 60151b77c8eSAapo Vienamo &autocal->pull_up_3v3); 60251b77c8eSAapo Vienamo if (err) 60351b77c8eSAapo Vienamo autocal->pull_up_3v3 = 0; 60451b77c8eSAapo Vienamo 60551b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 60651b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-3v3", 60751b77c8eSAapo Vienamo &autocal->pull_down_3v3); 60851b77c8eSAapo Vienamo if (err) 60951b77c8eSAapo Vienamo autocal->pull_down_3v3 = 0; 61051b77c8eSAapo Vienamo 61151b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 61251b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-1v8", 61351b77c8eSAapo Vienamo &autocal->pull_up_1v8); 61451b77c8eSAapo Vienamo if (err) 61551b77c8eSAapo Vienamo autocal->pull_up_1v8 = 0; 61651b77c8eSAapo Vienamo 61751b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 61851b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-1v8", 61951b77c8eSAapo Vienamo &autocal->pull_down_1v8); 62051b77c8eSAapo Vienamo if (err) 62151b77c8eSAapo Vienamo autocal->pull_down_1v8 = 0; 62251b77c8eSAapo Vienamo 62351b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 624aebbf577SSowjanya Komatineni "nvidia,pad-autocal-pull-up-offset-sdr104", 625aebbf577SSowjanya Komatineni &autocal->pull_up_sdr104); 626aebbf577SSowjanya Komatineni if (err) 627aebbf577SSowjanya Komatineni autocal->pull_up_sdr104 = autocal->pull_up_1v8; 628aebbf577SSowjanya Komatineni 629aebbf577SSowjanya Komatineni err = device_property_read_u32(host->mmc->parent, 630aebbf577SSowjanya Komatineni "nvidia,pad-autocal-pull-down-offset-sdr104", 631aebbf577SSowjanya Komatineni &autocal->pull_down_sdr104); 632aebbf577SSowjanya Komatineni if (err) 633aebbf577SSowjanya Komatineni autocal->pull_down_sdr104 = autocal->pull_down_1v8; 634aebbf577SSowjanya Komatineni 635aebbf577SSowjanya Komatineni err = device_property_read_u32(host->mmc->parent, 636aebbf577SSowjanya Komatineni "nvidia,pad-autocal-pull-up-offset-hs400", 637aebbf577SSowjanya Komatineni &autocal->pull_up_hs400); 638aebbf577SSowjanya Komatineni if (err) 639aebbf577SSowjanya Komatineni autocal->pull_up_hs400 = autocal->pull_up_1v8; 640aebbf577SSowjanya Komatineni 641aebbf577SSowjanya Komatineni err = device_property_read_u32(host->mmc->parent, 642aebbf577SSowjanya Komatineni "nvidia,pad-autocal-pull-down-offset-hs400", 643aebbf577SSowjanya Komatineni &autocal->pull_down_hs400); 644aebbf577SSowjanya Komatineni if (err) 645aebbf577SSowjanya Komatineni autocal->pull_down_hs400 = autocal->pull_down_1v8; 646aebbf577SSowjanya Komatineni 647aebbf577SSowjanya Komatineni /* 648aebbf577SSowjanya Komatineni * Different fail-safe drive strength values based on the signaling 649aebbf577SSowjanya Komatineni * voltage are applicable for SoCs supporting 3V3 and 1V8 pad controls. 650aebbf577SSowjanya Komatineni * So, avoid reading below device tree properties for SoCs that don't 651aebbf577SSowjanya Komatineni * have NVQUIRK_NEEDS_PAD_CONTROL. 652aebbf577SSowjanya Komatineni */ 653aebbf577SSowjanya Komatineni if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)) 654aebbf577SSowjanya Komatineni return; 655aebbf577SSowjanya Komatineni 656aebbf577SSowjanya Komatineni err = device_property_read_u32(host->mmc->parent, 65751b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-3v3-timeout", 6585ccf7f55SSowjanya Komatineni &autocal->pull_up_3v3_timeout); 659de25fa5aSSowjanya Komatineni if (err) { 660de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_3v3) && 661de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_3v3_drv == NULL)) 662de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n", 663de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 66451b77c8eSAapo Vienamo autocal->pull_up_3v3_timeout = 0; 665de25fa5aSSowjanya Komatineni } 66651b77c8eSAapo Vienamo 66751b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 66851b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-3v3-timeout", 6695ccf7f55SSowjanya Komatineni &autocal->pull_down_3v3_timeout); 670de25fa5aSSowjanya Komatineni if (err) { 671de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_3v3) && 672de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_3v3_drv == NULL)) 673de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n", 674de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 67551b77c8eSAapo Vienamo autocal->pull_down_3v3_timeout = 0; 676de25fa5aSSowjanya Komatineni } 67751b77c8eSAapo Vienamo 67851b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 67951b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-up-offset-1v8-timeout", 6805ccf7f55SSowjanya Komatineni &autocal->pull_up_1v8_timeout); 681de25fa5aSSowjanya Komatineni if (err) { 682de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_1v8) && 683de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_1v8_drv == NULL)) 684de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n", 685de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 68651b77c8eSAapo Vienamo autocal->pull_up_1v8_timeout = 0; 687de25fa5aSSowjanya Komatineni } 68851b77c8eSAapo Vienamo 68951b77c8eSAapo Vienamo err = device_property_read_u32(host->mmc->parent, 69051b77c8eSAapo Vienamo "nvidia,pad-autocal-pull-down-offset-1v8-timeout", 6915ccf7f55SSowjanya Komatineni &autocal->pull_down_1v8_timeout); 692de25fa5aSSowjanya Komatineni if (err) { 693de25fa5aSSowjanya Komatineni if (!IS_ERR(tegra_host->pinctrl_state_1v8) && 694de25fa5aSSowjanya Komatineni (tegra_host->pinctrl_state_1v8_drv == NULL)) 695de25fa5aSSowjanya Komatineni pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n", 696de25fa5aSSowjanya Komatineni mmc_hostname(host->mmc)); 69751b77c8eSAapo Vienamo autocal->pull_down_1v8_timeout = 0; 698de25fa5aSSowjanya Komatineni } 699e5c63d91SLucas Stach } 700e5c63d91SLucas Stach 70161dad40eSAapo Vienamo static void tegra_sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) 70261dad40eSAapo Vienamo { 70361dad40eSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 70461dad40eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 70561dad40eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 70661dad40eSAapo Vienamo ktime_t since_calib = ktime_sub(ktime_get(), tegra_host->last_calib); 70761dad40eSAapo Vienamo 70861dad40eSAapo Vienamo /* 100 ms calibration interval is specified in the TRM */ 70961dad40eSAapo Vienamo if (ktime_to_ms(since_calib) > 100) { 71061dad40eSAapo Vienamo tegra_sdhci_pad_autocalib(host); 71161dad40eSAapo Vienamo tegra_host->last_calib = ktime_get(); 71261dad40eSAapo Vienamo } 71361dad40eSAapo Vienamo 71461dad40eSAapo Vienamo sdhci_request(mmc, mrq); 71561dad40eSAapo Vienamo } 71661dad40eSAapo Vienamo 717f5313aaaSAapo Vienamo static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host) 71885c0da17SAapo Vienamo { 71985c0da17SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 72085c0da17SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 72185c0da17SAapo Vienamo int err; 72285c0da17SAapo Vienamo 72385c0da17SAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,default-tap", 72485c0da17SAapo Vienamo &tegra_host->default_tap); 72585c0da17SAapo Vienamo if (err) 72685c0da17SAapo Vienamo tegra_host->default_tap = 0; 72785c0da17SAapo Vienamo 72885c0da17SAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,default-trim", 72985c0da17SAapo Vienamo &tegra_host->default_trim); 73085c0da17SAapo Vienamo if (err) 73185c0da17SAapo Vienamo tegra_host->default_trim = 0; 732f5313aaaSAapo Vienamo 733f5313aaaSAapo Vienamo err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim", 734f5313aaaSAapo Vienamo &tegra_host->dqs_trim); 735f5313aaaSAapo Vienamo if (err) 736f5313aaaSAapo Vienamo tegra_host->dqs_trim = 0x11; 73785c0da17SAapo Vienamo } 73885c0da17SAapo Vienamo 7393c4019f9SSowjanya Komatineni static void tegra_sdhci_parse_dt(struct sdhci_host *host) 7403c4019f9SSowjanya Komatineni { 7413c4019f9SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 7423c4019f9SSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 7433c4019f9SSowjanya Komatineni 7443c4019f9SSowjanya Komatineni if (device_property_read_bool(host->mmc->parent, "supports-cqe")) 7453c4019f9SSowjanya Komatineni tegra_host->enable_hwcq = true; 7463c4019f9SSowjanya Komatineni else 7473c4019f9SSowjanya Komatineni tegra_host->enable_hwcq = false; 7483c4019f9SSowjanya Komatineni 7493c4019f9SSowjanya Komatineni tegra_sdhci_parse_pad_autocal_dt(host); 7503c4019f9SSowjanya Komatineni tegra_sdhci_parse_tap_and_trim(host); 7513c4019f9SSowjanya Komatineni } 7523c4019f9SSowjanya Komatineni 753a8e326a9SLucas Stach static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 754a8e326a9SLucas Stach { 755a8e326a9SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 7560734e79cSJisheng Zhang struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 757a8e326a9SLucas Stach unsigned long host_clk; 758a8e326a9SLucas Stach 759a8e326a9SLucas Stach if (!clock) 7603491b690SLucas Stach return sdhci_set_clock(host, clock); 761a8e326a9SLucas Stach 76257d1654eSAapo Vienamo /* 76357d1654eSAapo Vienamo * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI 76457d1654eSAapo Vienamo * divider to be configured to divided the host clock by two. The SDHCI 76557d1654eSAapo Vienamo * clock divider is calculated as part of sdhci_set_clock() by 76657d1654eSAapo Vienamo * sdhci_calc_clk(). The divider is calculated from host->max_clk and 76757d1654eSAapo Vienamo * the requested clock rate. 76857d1654eSAapo Vienamo * 76957d1654eSAapo Vienamo * By setting the host->max_clk to clock * 2 the divider calculation 77057d1654eSAapo Vienamo * will always result in the correct value for DDR50/52 modes, 77157d1654eSAapo Vienamo * regardless of clock rate rounding, which may happen if the value 77257d1654eSAapo Vienamo * from clk_get_rate() is used. 77357d1654eSAapo Vienamo */ 774a8e326a9SLucas Stach host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; 775a8e326a9SLucas Stach clk_set_rate(pltfm_host->clk, host_clk); 776ea8fc595SSowjanya Komatineni tegra_host->curr_clk_rate = host_clk; 77757d1654eSAapo Vienamo if (tegra_host->ddr_signaling) 77857d1654eSAapo Vienamo host->max_clk = host_clk; 77957d1654eSAapo Vienamo else 780a8e326a9SLucas Stach host->max_clk = clk_get_rate(pltfm_host->clk); 781a8e326a9SLucas Stach 782e5c63d91SLucas Stach sdhci_set_clock(host, clock); 783e5c63d91SLucas Stach 784e5c63d91SLucas Stach if (tegra_host->pad_calib_required) { 785e5c63d91SLucas Stach tegra_sdhci_pad_autocalib(host); 786e5c63d91SLucas Stach tegra_host->pad_calib_required = false; 787e5c63d91SLucas Stach } 788a8e326a9SLucas Stach } 789a8e326a9SLucas Stach 79044350993SAapo Vienamo static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) 79144350993SAapo Vienamo { 79244350993SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 79344350993SAapo Vienamo 79444350993SAapo Vienamo return clk_round_rate(pltfm_host->clk, UINT_MAX); 79544350993SAapo Vienamo } 79644350993SAapo Vienamo 797f5313aaaSAapo Vienamo static void tegra_sdhci_set_dqs_trim(struct sdhci_host *host, u8 trim) 798f5313aaaSAapo Vienamo { 799f5313aaaSAapo Vienamo u32 val; 800f5313aaaSAapo Vienamo 801f5313aaaSAapo Vienamo val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); 802f5313aaaSAapo Vienamo val &= ~SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK; 803f5313aaaSAapo Vienamo val |= trim << SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT; 804f5313aaaSAapo Vienamo sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); 805f5313aaaSAapo Vienamo } 806f5313aaaSAapo Vienamo 807bc5568bfSAapo Vienamo static void tegra_sdhci_hs400_dll_cal(struct sdhci_host *host) 808bc5568bfSAapo Vienamo { 809bc5568bfSAapo Vienamo u32 reg; 810bc5568bfSAapo Vienamo int err; 811bc5568bfSAapo Vienamo 812bc5568bfSAapo Vienamo reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); 813bc5568bfSAapo Vienamo reg |= SDHCI_TEGRA_DLLCAL_CALIBRATE; 814bc5568bfSAapo Vienamo sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); 815bc5568bfSAapo Vienamo 816bc5568bfSAapo Vienamo /* 1 ms sleep, 5 ms timeout */ 817bc5568bfSAapo Vienamo err = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_VENDOR_DLLCAL_STA, 818bc5568bfSAapo Vienamo reg, !(reg & SDHCI_TEGRA_DLLCAL_STA_ACTIVE), 819bc5568bfSAapo Vienamo 1000, 5000); 820bc5568bfSAapo Vienamo if (err) 821bc5568bfSAapo Vienamo dev_err(mmc_dev(host->mmc), 822bc5568bfSAapo Vienamo "HS400 delay line calibration timed out\n"); 823bc5568bfSAapo Vienamo } 824bc5568bfSAapo Vienamo 825ea8fc595SSowjanya Komatineni static void tegra_sdhci_tap_correction(struct sdhci_host *host, u8 thd_up, 826ea8fc595SSowjanya Komatineni u8 thd_low, u8 fixed_tap) 827ea8fc595SSowjanya Komatineni { 828ea8fc595SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 829ea8fc595SSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 830ea8fc595SSowjanya Komatineni u32 val, tun_status; 831ea8fc595SSowjanya Komatineni u8 word, bit, edge1, tap, window; 832ea8fc595SSowjanya Komatineni bool tap_result; 833ea8fc595SSowjanya Komatineni bool start_fail = false; 834ea8fc595SSowjanya Komatineni bool start_pass = false; 835ea8fc595SSowjanya Komatineni bool end_pass = false; 836ea8fc595SSowjanya Komatineni bool first_fail = false; 837ea8fc595SSowjanya Komatineni bool first_pass = false; 838ea8fc595SSowjanya Komatineni u8 start_pass_tap = 0; 839ea8fc595SSowjanya Komatineni u8 end_pass_tap = 0; 840ea8fc595SSowjanya Komatineni u8 first_fail_tap = 0; 841ea8fc595SSowjanya Komatineni u8 first_pass_tap = 0; 842ea8fc595SSowjanya Komatineni u8 total_tuning_words = host->tuning_loop_count / TUNING_WORD_BIT_SIZE; 843ea8fc595SSowjanya Komatineni 844ea8fc595SSowjanya Komatineni /* 845ea8fc595SSowjanya Komatineni * Read auto-tuned results and extract good valid passing window by 846ea8fc595SSowjanya Komatineni * filtering out un-wanted bubble/partial/merged windows. 847ea8fc595SSowjanya Komatineni */ 848ea8fc595SSowjanya Komatineni for (word = 0; word < total_tuning_words; word++) { 849ea8fc595SSowjanya Komatineni val = sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0); 850ea8fc595SSowjanya Komatineni val &= ~SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK; 851ea8fc595SSowjanya Komatineni val |= word; 852ea8fc595SSowjanya Komatineni sdhci_writel(host, val, SDHCI_VNDR_TUN_CTRL0_0); 853ea8fc595SSowjanya Komatineni tun_status = sdhci_readl(host, SDHCI_TEGRA_VNDR_TUN_STATUS0); 854ea8fc595SSowjanya Komatineni bit = 0; 855ea8fc595SSowjanya Komatineni while (bit < TUNING_WORD_BIT_SIZE) { 856ea8fc595SSowjanya Komatineni tap = word * TUNING_WORD_BIT_SIZE + bit; 857ea8fc595SSowjanya Komatineni tap_result = tun_status & (1 << bit); 858ea8fc595SSowjanya Komatineni if (!tap_result && !start_fail) { 859ea8fc595SSowjanya Komatineni start_fail = true; 860ea8fc595SSowjanya Komatineni if (!first_fail) { 861ea8fc595SSowjanya Komatineni first_fail_tap = tap; 862ea8fc595SSowjanya Komatineni first_fail = true; 863ea8fc595SSowjanya Komatineni } 864ea8fc595SSowjanya Komatineni 865ea8fc595SSowjanya Komatineni } else if (tap_result && start_fail && !start_pass) { 866ea8fc595SSowjanya Komatineni start_pass_tap = tap; 867ea8fc595SSowjanya Komatineni start_pass = true; 868ea8fc595SSowjanya Komatineni if (!first_pass) { 869ea8fc595SSowjanya Komatineni first_pass_tap = tap; 870ea8fc595SSowjanya Komatineni first_pass = true; 871ea8fc595SSowjanya Komatineni } 872ea8fc595SSowjanya Komatineni 873ea8fc595SSowjanya Komatineni } else if (!tap_result && start_fail && start_pass && 874ea8fc595SSowjanya Komatineni !end_pass) { 875ea8fc595SSowjanya Komatineni end_pass_tap = tap - 1; 876ea8fc595SSowjanya Komatineni end_pass = true; 877ea8fc595SSowjanya Komatineni } else if (tap_result && start_pass && start_fail && 878ea8fc595SSowjanya Komatineni end_pass) { 879ea8fc595SSowjanya Komatineni window = end_pass_tap - start_pass_tap; 880ea8fc595SSowjanya Komatineni /* discard merged window and bubble window */ 881ea8fc595SSowjanya Komatineni if (window >= thd_up || window < thd_low) { 882ea8fc595SSowjanya Komatineni start_pass_tap = tap; 883ea8fc595SSowjanya Komatineni end_pass = false; 884ea8fc595SSowjanya Komatineni } else { 885ea8fc595SSowjanya Komatineni /* set tap at middle of valid window */ 886ea8fc595SSowjanya Komatineni tap = start_pass_tap + window / 2; 887ea8fc595SSowjanya Komatineni tegra_host->tuned_tap_delay = tap; 888ea8fc595SSowjanya Komatineni return; 889ea8fc595SSowjanya Komatineni } 890ea8fc595SSowjanya Komatineni } 891ea8fc595SSowjanya Komatineni 892ea8fc595SSowjanya Komatineni bit++; 893ea8fc595SSowjanya Komatineni } 894ea8fc595SSowjanya Komatineni } 895ea8fc595SSowjanya Komatineni 896ea8fc595SSowjanya Komatineni if (!first_fail) { 897d96dc68eSDan Carpenter WARN(1, "no edge detected, continue with hw tuned delay.\n"); 898ea8fc595SSowjanya Komatineni } else if (first_pass) { 899ea8fc595SSowjanya Komatineni /* set tap location at fixed tap relative to the first edge */ 900ea8fc595SSowjanya Komatineni edge1 = first_fail_tap + (first_pass_tap - first_fail_tap) / 2; 901ea8fc595SSowjanya Komatineni if (edge1 - 1 > fixed_tap) 902ea8fc595SSowjanya Komatineni tegra_host->tuned_tap_delay = edge1 - fixed_tap; 903ea8fc595SSowjanya Komatineni else 904ea8fc595SSowjanya Komatineni tegra_host->tuned_tap_delay = edge1 + fixed_tap; 905ea8fc595SSowjanya Komatineni } 906ea8fc595SSowjanya Komatineni } 907ea8fc595SSowjanya Komatineni 908ea8fc595SSowjanya Komatineni static void tegra_sdhci_post_tuning(struct sdhci_host *host) 909ea8fc595SSowjanya Komatineni { 910ea8fc595SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 911ea8fc595SSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 912ea8fc595SSowjanya Komatineni const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 913ea8fc595SSowjanya Komatineni u32 avg_tap_dly, val, min_tap_dly, max_tap_dly; 914ea8fc595SSowjanya Komatineni u8 fixed_tap, start_tap, end_tap, window_width; 915ea8fc595SSowjanya Komatineni u8 thdupper, thdlower; 916ea8fc595SSowjanya Komatineni u8 num_iter; 917ea8fc595SSowjanya Komatineni u32 clk_rate_mhz, period_ps, bestcase, worstcase; 918ea8fc595SSowjanya Komatineni 919ea8fc595SSowjanya Komatineni /* retain HW tuned tap to use incase if no correction is needed */ 920ea8fc595SSowjanya Komatineni val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); 921ea8fc595SSowjanya Komatineni tegra_host->tuned_tap_delay = (val & SDHCI_CLOCK_CTRL_TAP_MASK) >> 922ea8fc595SSowjanya Komatineni SDHCI_CLOCK_CTRL_TAP_SHIFT; 923ea8fc595SSowjanya Komatineni if (soc_data->min_tap_delay && soc_data->max_tap_delay) { 924ea8fc595SSowjanya Komatineni min_tap_dly = soc_data->min_tap_delay; 925ea8fc595SSowjanya Komatineni max_tap_dly = soc_data->max_tap_delay; 926ea8fc595SSowjanya Komatineni clk_rate_mhz = tegra_host->curr_clk_rate / USEC_PER_SEC; 927ea8fc595SSowjanya Komatineni period_ps = USEC_PER_SEC / clk_rate_mhz; 928ea8fc595SSowjanya Komatineni bestcase = period_ps / min_tap_dly; 929ea8fc595SSowjanya Komatineni worstcase = period_ps / max_tap_dly; 930ea8fc595SSowjanya Komatineni /* 931ea8fc595SSowjanya Komatineni * Upper and Lower bound thresholds used to detect merged and 932ea8fc595SSowjanya Komatineni * bubble windows 933ea8fc595SSowjanya Komatineni */ 934ea8fc595SSowjanya Komatineni thdupper = (2 * worstcase + bestcase) / 2; 935ea8fc595SSowjanya Komatineni thdlower = worstcase / 4; 936ea8fc595SSowjanya Komatineni /* 937ea8fc595SSowjanya Komatineni * fixed tap is used when HW tuning result contains single edge 938ea8fc595SSowjanya Komatineni * and tap is set at fixed tap delay relative to the first edge 939ea8fc595SSowjanya Komatineni */ 940ea8fc595SSowjanya Komatineni avg_tap_dly = (period_ps * 2) / (min_tap_dly + max_tap_dly); 941ea8fc595SSowjanya Komatineni fixed_tap = avg_tap_dly / 2; 942ea8fc595SSowjanya Komatineni 943ea8fc595SSowjanya Komatineni val = sdhci_readl(host, SDHCI_TEGRA_VNDR_TUN_STATUS1); 944ea8fc595SSowjanya Komatineni start_tap = val & SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK; 945ea8fc595SSowjanya Komatineni end_tap = (val >> SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT) & 946ea8fc595SSowjanya Komatineni SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK; 947ea8fc595SSowjanya Komatineni window_width = end_tap - start_tap; 948ea8fc595SSowjanya Komatineni num_iter = host->tuning_loop_count; 949ea8fc595SSowjanya Komatineni /* 950ea8fc595SSowjanya Komatineni * partial window includes edges of the tuning range. 951ea8fc595SSowjanya Komatineni * merged window includes more taps so window width is higher 952ea8fc595SSowjanya Komatineni * than upper threshold. 953ea8fc595SSowjanya Komatineni */ 954ea8fc595SSowjanya Komatineni if (start_tap == 0 || (end_tap == (num_iter - 1)) || 955ea8fc595SSowjanya Komatineni (end_tap == num_iter - 2) || window_width >= thdupper) { 956ea8fc595SSowjanya Komatineni pr_debug("%s: Apply tuning correction\n", 957ea8fc595SSowjanya Komatineni mmc_hostname(host->mmc)); 958ea8fc595SSowjanya Komatineni tegra_sdhci_tap_correction(host, thdupper, thdlower, 959ea8fc595SSowjanya Komatineni fixed_tap); 960ea8fc595SSowjanya Komatineni } 961ea8fc595SSowjanya Komatineni } 962ea8fc595SSowjanya Komatineni 963ea8fc595SSowjanya Komatineni tegra_sdhci_set_tap(host, tegra_host->tuned_tap_delay); 964ea8fc595SSowjanya Komatineni } 965ea8fc595SSowjanya Komatineni 966ea8fc595SSowjanya Komatineni static int tegra_sdhci_execute_hw_tuning(struct mmc_host *mmc, u32 opcode) 967ea8fc595SSowjanya Komatineni { 968ea8fc595SSowjanya Komatineni struct sdhci_host *host = mmc_priv(mmc); 969ea8fc595SSowjanya Komatineni int err; 970ea8fc595SSowjanya Komatineni 971ea8fc595SSowjanya Komatineni err = sdhci_execute_tuning(mmc, opcode); 972ea8fc595SSowjanya Komatineni if (!err && !host->tuning_err) 973ea8fc595SSowjanya Komatineni tegra_sdhci_post_tuning(host); 974ea8fc595SSowjanya Komatineni 975ea8fc595SSowjanya Komatineni return err; 976ea8fc595SSowjanya Komatineni } 977ea8fc595SSowjanya Komatineni 978c2c09678SAapo Vienamo static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, 979c2c09678SAapo Vienamo unsigned timing) 980c3c2384cSLucas Stach { 981d4501d8eSAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 982d4501d8eSAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 983c2c09678SAapo Vienamo bool set_default_tap = false; 984f5313aaaSAapo Vienamo bool set_dqs_trim = false; 985bc5568bfSAapo Vienamo bool do_hs400_dll_cal = false; 986ea8fc595SSowjanya Komatineni u8 iter = TRIES_256; 987ea8fc595SSowjanya Komatineni u32 val; 988c3c2384cSLucas Stach 98992cd1667SSowjanya Komatineni tegra_host->ddr_signaling = false; 990c2c09678SAapo Vienamo switch (timing) { 991c2c09678SAapo Vienamo case MMC_TIMING_UHS_SDR50: 992ea8fc595SSowjanya Komatineni break; 993c2c09678SAapo Vienamo case MMC_TIMING_UHS_SDR104: 994c2c09678SAapo Vienamo case MMC_TIMING_MMC_HS200: 995c2c09678SAapo Vienamo /* Don't set default tap on tunable modes. */ 996ea8fc595SSowjanya Komatineni iter = TRIES_128; 997c2c09678SAapo Vienamo break; 998f5313aaaSAapo Vienamo case MMC_TIMING_MMC_HS400: 999f5313aaaSAapo Vienamo set_dqs_trim = true; 1000bc5568bfSAapo Vienamo do_hs400_dll_cal = true; 1001ea8fc595SSowjanya Komatineni iter = TRIES_128; 1002f5313aaaSAapo Vienamo break; 1003c2c09678SAapo Vienamo case MMC_TIMING_MMC_DDR52: 1004c2c09678SAapo Vienamo case MMC_TIMING_UHS_DDR50: 1005c2c09678SAapo Vienamo tegra_host->ddr_signaling = true; 1006c2c09678SAapo Vienamo set_default_tap = true; 1007c2c09678SAapo Vienamo break; 1008c2c09678SAapo Vienamo default: 1009c2c09678SAapo Vienamo set_default_tap = true; 1010c2c09678SAapo Vienamo break; 1011d4501d8eSAapo Vienamo } 1012c2c09678SAapo Vienamo 1013ea8fc595SSowjanya Komatineni val = sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0); 1014ea8fc595SSowjanya Komatineni val &= ~(SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK | 1015ea8fc595SSowjanya Komatineni SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK | 1016ea8fc595SSowjanya Komatineni SDHCI_VNDR_TUN_CTRL0_MUL_M_MASK); 1017ea8fc595SSowjanya Komatineni val |= (iter << SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT | 1018ea8fc595SSowjanya Komatineni 0 << SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT | 1019ea8fc595SSowjanya Komatineni 1 << SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT); 1020ea8fc595SSowjanya Komatineni sdhci_writel(host, val, SDHCI_VNDR_TUN_CTRL0_0); 1021ea8fc595SSowjanya Komatineni sdhci_writel(host, 0, SDHCI_TEGRA_VNDR_TUN_CTRL1_0); 1022ea8fc595SSowjanya Komatineni 1023ea8fc595SSowjanya Komatineni host->tuning_loop_count = (iter == TRIES_128) ? 128 : 256; 1024ea8fc595SSowjanya Komatineni 1025c2c09678SAapo Vienamo sdhci_set_uhs_signaling(host, timing); 1026c2c09678SAapo Vienamo 1027c2c09678SAapo Vienamo tegra_sdhci_pad_autocalib(host); 1028c2c09678SAapo Vienamo 1029ea8fc595SSowjanya Komatineni if (tegra_host->tuned_tap_delay && !set_default_tap) 1030ea8fc595SSowjanya Komatineni tegra_sdhci_set_tap(host, tegra_host->tuned_tap_delay); 1031ea8fc595SSowjanya Komatineni else 1032c2c09678SAapo Vienamo tegra_sdhci_set_tap(host, tegra_host->default_tap); 1033f5313aaaSAapo Vienamo 1034f5313aaaSAapo Vienamo if (set_dqs_trim) 1035f5313aaaSAapo Vienamo tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim); 1036bc5568bfSAapo Vienamo 1037bc5568bfSAapo Vienamo if (do_hs400_dll_cal) 1038bc5568bfSAapo Vienamo tegra_sdhci_hs400_dll_cal(host); 1039c3c2384cSLucas Stach } 1040c3c2384cSLucas Stach 1041c3c2384cSLucas Stach static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) 1042c3c2384cSLucas Stach { 1043c3c2384cSLucas Stach unsigned int min, max; 1044c3c2384cSLucas Stach 1045c3c2384cSLucas Stach /* 1046c3c2384cSLucas Stach * Start search for minimum tap value at 10, as smaller values are 1047c3c2384cSLucas Stach * may wrongly be reported as working but fail at higher speeds, 1048c3c2384cSLucas Stach * according to the TRM. 1049c3c2384cSLucas Stach */ 1050c3c2384cSLucas Stach min = 10; 1051c3c2384cSLucas Stach while (min < 255) { 1052c3c2384cSLucas Stach tegra_sdhci_set_tap(host, min); 1053c3c2384cSLucas Stach if (!mmc_send_tuning(host->mmc, opcode, NULL)) 1054c3c2384cSLucas Stach break; 1055c3c2384cSLucas Stach min++; 1056c3c2384cSLucas Stach } 1057c3c2384cSLucas Stach 1058c3c2384cSLucas Stach /* Find the maximum tap value that still passes. */ 1059c3c2384cSLucas Stach max = min + 1; 1060c3c2384cSLucas Stach while (max < 255) { 1061c3c2384cSLucas Stach tegra_sdhci_set_tap(host, max); 1062c3c2384cSLucas Stach if (mmc_send_tuning(host->mmc, opcode, NULL)) { 1063c3c2384cSLucas Stach max--; 1064c3c2384cSLucas Stach break; 1065c3c2384cSLucas Stach } 1066c3c2384cSLucas Stach max++; 1067c3c2384cSLucas Stach } 1068c3c2384cSLucas Stach 1069c3c2384cSLucas Stach /* The TRM states the ideal tap value is at 75% in the passing range. */ 1070c3c2384cSLucas Stach tegra_sdhci_set_tap(host, min + ((max - min) * 3 / 4)); 1071c3c2384cSLucas Stach 1072c3c2384cSLucas Stach return mmc_send_tuning(host->mmc, opcode, NULL); 1073c3c2384cSLucas Stach } 1074c3c2384cSLucas Stach 107586ac2f8bSAapo Vienamo static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, 107686ac2f8bSAapo Vienamo struct mmc_ios *ios) 107786ac2f8bSAapo Vienamo { 107886ac2f8bSAapo Vienamo struct sdhci_host *host = mmc_priv(mmc); 107944babea2SAapo Vienamo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 108044babea2SAapo Vienamo struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 108186ac2f8bSAapo Vienamo int ret = 0; 108286ac2f8bSAapo Vienamo 108386ac2f8bSAapo Vienamo if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 1084de25fa5aSSowjanya Komatineni ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true); 108586ac2f8bSAapo Vienamo if (ret < 0) 108686ac2f8bSAapo Vienamo return ret; 108786ac2f8bSAapo Vienamo ret = sdhci_start_signal_voltage_switch(mmc, ios); 108886ac2f8bSAapo Vienamo } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { 108986ac2f8bSAapo Vienamo ret = sdhci_start_signal_voltage_switch(mmc, ios); 109086ac2f8bSAapo Vienamo if (ret < 0) 109186ac2f8bSAapo Vienamo return ret; 1092de25fa5aSSowjanya Komatineni ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true); 109386ac2f8bSAapo Vienamo } 109486ac2f8bSAapo Vienamo 109544babea2SAapo Vienamo if (tegra_host->pad_calib_required) 109644babea2SAapo Vienamo tegra_sdhci_pad_autocalib(host); 109744babea2SAapo Vienamo 109886ac2f8bSAapo Vienamo return ret; 109986ac2f8bSAapo Vienamo } 110086ac2f8bSAapo Vienamo 110186ac2f8bSAapo Vienamo static int tegra_sdhci_init_pinctrl_info(struct device *dev, 110286ac2f8bSAapo Vienamo struct sdhci_tegra *tegra_host) 110386ac2f8bSAapo Vienamo { 110486ac2f8bSAapo Vienamo tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev); 110586ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_sdmmc)) { 110686ac2f8bSAapo Vienamo dev_dbg(dev, "No pinctrl info, err: %ld\n", 110786ac2f8bSAapo Vienamo PTR_ERR(tegra_host->pinctrl_sdmmc)); 110886ac2f8bSAapo Vienamo return -1; 110986ac2f8bSAapo Vienamo } 111086ac2f8bSAapo Vienamo 1111de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8_drv = pinctrl_lookup_state( 1112de25fa5aSSowjanya Komatineni tegra_host->pinctrl_sdmmc, "sdmmc-1v8-drv"); 1113de25fa5aSSowjanya Komatineni if (IS_ERR(tegra_host->pinctrl_state_1v8_drv)) { 1114de25fa5aSSowjanya Komatineni if (PTR_ERR(tegra_host->pinctrl_state_1v8_drv) == -ENODEV) 1115de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_1v8_drv = NULL; 1116de25fa5aSSowjanya Komatineni } 1117de25fa5aSSowjanya Komatineni 1118de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3_drv = pinctrl_lookup_state( 1119de25fa5aSSowjanya Komatineni tegra_host->pinctrl_sdmmc, "sdmmc-3v3-drv"); 1120de25fa5aSSowjanya Komatineni if (IS_ERR(tegra_host->pinctrl_state_3v3_drv)) { 1121de25fa5aSSowjanya Komatineni if (PTR_ERR(tegra_host->pinctrl_state_3v3_drv) == -ENODEV) 1122de25fa5aSSowjanya Komatineni tegra_host->pinctrl_state_3v3_drv = NULL; 1123de25fa5aSSowjanya Komatineni } 1124de25fa5aSSowjanya Komatineni 112586ac2f8bSAapo Vienamo tegra_host->pinctrl_state_3v3 = 112686ac2f8bSAapo Vienamo pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-3v3"); 112786ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_state_3v3)) { 112886ac2f8bSAapo Vienamo dev_warn(dev, "Missing 3.3V pad state, err: %ld\n", 112986ac2f8bSAapo Vienamo PTR_ERR(tegra_host->pinctrl_state_3v3)); 113086ac2f8bSAapo Vienamo return -1; 113186ac2f8bSAapo Vienamo } 113286ac2f8bSAapo Vienamo 113386ac2f8bSAapo Vienamo tegra_host->pinctrl_state_1v8 = 113486ac2f8bSAapo Vienamo pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-1v8"); 113586ac2f8bSAapo Vienamo if (IS_ERR(tegra_host->pinctrl_state_1v8)) { 113686ac2f8bSAapo Vienamo dev_warn(dev, "Missing 1.8V pad state, err: %ld\n", 1137e5378247SYueHaibing PTR_ERR(tegra_host->pinctrl_state_1v8)); 113886ac2f8bSAapo Vienamo return -1; 113986ac2f8bSAapo Vienamo } 114086ac2f8bSAapo Vienamo 114186ac2f8bSAapo Vienamo tegra_host->pad_control_available = true; 114286ac2f8bSAapo Vienamo 114386ac2f8bSAapo Vienamo return 0; 114486ac2f8bSAapo Vienamo } 114586ac2f8bSAapo Vienamo 1146e5c63d91SLucas Stach static void tegra_sdhci_voltage_switch(struct sdhci_host *host) 1147e5c63d91SLucas Stach { 1148e5c63d91SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1149e5c63d91SLucas Stach struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1150e5c63d91SLucas Stach const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 1151e5c63d91SLucas Stach 1152e5c63d91SLucas Stach if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 1153e5c63d91SLucas Stach tegra_host->pad_calib_required = true; 1154e5c63d91SLucas Stach } 1155e5c63d91SLucas Stach 1156b7754428SSowjanya Komatineni static void tegra_cqhci_writel(struct cqhci_host *cq_host, u32 val, int reg) 1157b7754428SSowjanya Komatineni { 1158b7754428SSowjanya Komatineni struct mmc_host *mmc = cq_host->mmc; 1159b7754428SSowjanya Komatineni u8 ctrl; 1160b7754428SSowjanya Komatineni ktime_t timeout; 1161b7754428SSowjanya Komatineni bool timed_out; 1162b7754428SSowjanya Komatineni 1163b7754428SSowjanya Komatineni /* 1164b7754428SSowjanya Komatineni * During CQE resume/unhalt, CQHCI driver unhalts CQE prior to 1165b7754428SSowjanya Komatineni * cqhci_host_ops enable where SDHCI DMA and BLOCK_SIZE registers need 1166b7754428SSowjanya Komatineni * to be re-configured. 1167b7754428SSowjanya Komatineni * Tegra CQHCI/SDHCI prevents write access to block size register when 1168b7754428SSowjanya Komatineni * CQE is unhalted. So handling CQE resume sequence here to configure 1169b7754428SSowjanya Komatineni * SDHCI block registers prior to exiting CQE halt state. 1170b7754428SSowjanya Komatineni */ 1171b7754428SSowjanya Komatineni if (reg == CQHCI_CTL && !(val & CQHCI_HALT) && 1172b7754428SSowjanya Komatineni cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) { 1173b7754428SSowjanya Komatineni sdhci_cqe_enable(mmc); 1174b7754428SSowjanya Komatineni writel(val, cq_host->mmio + reg); 1175b7754428SSowjanya Komatineni timeout = ktime_add_us(ktime_get(), 50); 1176b7754428SSowjanya Komatineni while (1) { 1177b7754428SSowjanya Komatineni timed_out = ktime_compare(ktime_get(), timeout) > 0; 1178b7754428SSowjanya Komatineni ctrl = cqhci_readl(cq_host, CQHCI_CTL); 1179b7754428SSowjanya Komatineni if (!(ctrl & CQHCI_HALT) || timed_out) 1180b7754428SSowjanya Komatineni break; 1181b7754428SSowjanya Komatineni } 1182b7754428SSowjanya Komatineni /* 1183b7754428SSowjanya Komatineni * CQE usually resumes very quick, but incase if Tegra CQE 1184b7754428SSowjanya Komatineni * doesn't resume retry unhalt. 1185b7754428SSowjanya Komatineni */ 1186b7754428SSowjanya Komatineni if (timed_out) 1187b7754428SSowjanya Komatineni writel(val, cq_host->mmio + reg); 1188b7754428SSowjanya Komatineni } else { 1189b7754428SSowjanya Komatineni writel(val, cq_host->mmio + reg); 1190b7754428SSowjanya Komatineni } 1191b7754428SSowjanya Komatineni } 1192b7754428SSowjanya Komatineni 1193c6e7ab90SSowjanya Komatineni static void sdhci_tegra_update_dcmd_desc(struct mmc_host *mmc, 1194c6e7ab90SSowjanya Komatineni struct mmc_request *mrq, u64 *data) 1195c6e7ab90SSowjanya Komatineni { 1196c6e7ab90SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(mmc_priv(mmc)); 1197c6e7ab90SSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 1198c6e7ab90SSowjanya Komatineni const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; 1199c6e7ab90SSowjanya Komatineni 1200c6e7ab90SSowjanya Komatineni if (soc_data->nvquirks & NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING && 1201c6e7ab90SSowjanya Komatineni mrq->cmd->flags & MMC_RSP_R1B) 1202c6e7ab90SSowjanya Komatineni *data |= CQHCI_CMD_TIMING(1); 1203c6e7ab90SSowjanya Komatineni } 1204c6e7ab90SSowjanya Komatineni 12053c4019f9SSowjanya Komatineni static void sdhci_tegra_cqe_enable(struct mmc_host *mmc) 12063c4019f9SSowjanya Komatineni { 12073c4019f9SSowjanya Komatineni struct cqhci_host *cq_host = mmc->cqe_private; 1208b7754428SSowjanya Komatineni u32 val; 12093c4019f9SSowjanya Komatineni 12103c4019f9SSowjanya Komatineni /* 1211b7754428SSowjanya Komatineni * Tegra CQHCI/SDMMC design prevents write access to sdhci block size 1212b7754428SSowjanya Komatineni * register when CQE is enabled and unhalted. 1213b7754428SSowjanya Komatineni * CQHCI driver enables CQE prior to activation, so disable CQE before 1214b7754428SSowjanya Komatineni * programming block size in sdhci controller and enable it back. 12153c4019f9SSowjanya Komatineni */ 1216b7754428SSowjanya Komatineni if (!cq_host->activated) { 1217b7754428SSowjanya Komatineni val = cqhci_readl(cq_host, CQHCI_CFG); 1218b7754428SSowjanya Komatineni if (val & CQHCI_ENABLE) 1219b7754428SSowjanya Komatineni cqhci_writel(cq_host, (val & ~CQHCI_ENABLE), 1220b7754428SSowjanya Komatineni CQHCI_CFG); 12213c4019f9SSowjanya Komatineni sdhci_cqe_enable(mmc); 1222b7754428SSowjanya Komatineni if (val & CQHCI_ENABLE) 1223b7754428SSowjanya Komatineni cqhci_writel(cq_host, val, CQHCI_CFG); 1224b7754428SSowjanya Komatineni } 12253c4019f9SSowjanya Komatineni 1226b7754428SSowjanya Komatineni /* 1227b7754428SSowjanya Komatineni * CMD CRC errors are seen sometimes with some eMMC devices when status 1228b7754428SSowjanya Komatineni * command is sent during transfer of last data block which is the 1229b7754428SSowjanya Komatineni * default case as send status command block counter (CBC) is 1. 1230b7754428SSowjanya Komatineni * Recommended fix to set CBC to 0 allowing send status command only 1231b7754428SSowjanya Komatineni * when data lines are idle. 1232b7754428SSowjanya Komatineni */ 1233b7754428SSowjanya Komatineni val = cqhci_readl(cq_host, CQHCI_SSC1); 1234b7754428SSowjanya Komatineni val &= ~CQHCI_SSC1_CBC_MASK; 1235b7754428SSowjanya Komatineni cqhci_writel(cq_host, val, CQHCI_SSC1); 12363c4019f9SSowjanya Komatineni } 12373c4019f9SSowjanya Komatineni 12383c4019f9SSowjanya Komatineni static void sdhci_tegra_dumpregs(struct mmc_host *mmc) 12393c4019f9SSowjanya Komatineni { 12403c4019f9SSowjanya Komatineni sdhci_dumpregs(mmc_priv(mmc)); 12413c4019f9SSowjanya Komatineni } 12423c4019f9SSowjanya Komatineni 12433c4019f9SSowjanya Komatineni static u32 sdhci_tegra_cqhci_irq(struct sdhci_host *host, u32 intmask) 12443c4019f9SSowjanya Komatineni { 12453c4019f9SSowjanya Komatineni int cmd_error = 0; 12463c4019f9SSowjanya Komatineni int data_error = 0; 12473c4019f9SSowjanya Komatineni 12483c4019f9SSowjanya Komatineni if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 12493c4019f9SSowjanya Komatineni return intmask; 12503c4019f9SSowjanya Komatineni 12513c4019f9SSowjanya Komatineni cqhci_irq(host->mmc, intmask, cmd_error, data_error); 12523c4019f9SSowjanya Komatineni 12533c4019f9SSowjanya Komatineni return 0; 12543c4019f9SSowjanya Komatineni } 12553c4019f9SSowjanya Komatineni 12565e958e4aSSowjanya Komatineni static void tegra_sdhci_set_timeout(struct sdhci_host *host, 12575e958e4aSSowjanya Komatineni struct mmc_command *cmd) 12585e958e4aSSowjanya Komatineni { 12595e958e4aSSowjanya Komatineni u32 val; 12605e958e4aSSowjanya Komatineni 12615e958e4aSSowjanya Komatineni /* 12625e958e4aSSowjanya Komatineni * HW busy detection timeout is based on programmed data timeout 12635e958e4aSSowjanya Komatineni * counter and maximum supported timeout is 11s which may not be 12645e958e4aSSowjanya Komatineni * enough for long operations like cache flush, sleep awake, erase. 12655e958e4aSSowjanya Komatineni * 12665e958e4aSSowjanya Komatineni * ERASE_TIMEOUT_LIMIT bit of VENDOR_MISC_CTRL register allows 12675e958e4aSSowjanya Komatineni * host controller to wait for busy state until the card is busy 12685e958e4aSSowjanya Komatineni * without HW timeout. 12695e958e4aSSowjanya Komatineni * 12705e958e4aSSowjanya Komatineni * So, use infinite busy wait mode for operations that may take 12715e958e4aSSowjanya Komatineni * more than maximum HW busy timeout of 11s otherwise use finite 12725e958e4aSSowjanya Komatineni * busy wait mode. 12735e958e4aSSowjanya Komatineni */ 12745e958e4aSSowjanya Komatineni val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); 12755e958e4aSSowjanya Komatineni if (cmd && cmd->busy_timeout >= 11 * HZ) 12765e958e4aSSowjanya Komatineni val |= SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT; 12775e958e4aSSowjanya Komatineni else 12785e958e4aSSowjanya Komatineni val &= ~SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT; 12795e958e4aSSowjanya Komatineni sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_MISC_CTRL); 12805e958e4aSSowjanya Komatineni 12815e958e4aSSowjanya Komatineni __sdhci_set_timeout(host, cmd); 12825e958e4aSSowjanya Komatineni } 12835e958e4aSSowjanya Komatineni 12843c4019f9SSowjanya Komatineni static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = { 1285b7754428SSowjanya Komatineni .write_l = tegra_cqhci_writel, 12863c4019f9SSowjanya Komatineni .enable = sdhci_tegra_cqe_enable, 12873c4019f9SSowjanya Komatineni .disable = sdhci_cqe_disable, 12883c4019f9SSowjanya Komatineni .dumpregs = sdhci_tegra_dumpregs, 1289c6e7ab90SSowjanya Komatineni .update_dcmd_desc = sdhci_tegra_update_dcmd_desc, 12903c4019f9SSowjanya Komatineni }; 12913c4019f9SSowjanya Komatineni 1292b960bc44SNicolin Chen static int tegra_sdhci_set_dma_mask(struct sdhci_host *host) 1293b960bc44SNicolin Chen { 1294b960bc44SNicolin Chen struct sdhci_pltfm_host *platform = sdhci_priv(host); 1295b960bc44SNicolin Chen struct sdhci_tegra *tegra = sdhci_pltfm_priv(platform); 1296b960bc44SNicolin Chen const struct sdhci_tegra_soc_data *soc = tegra->soc_data; 1297b960bc44SNicolin Chen struct device *dev = mmc_dev(host->mmc); 1298b960bc44SNicolin Chen 1299b960bc44SNicolin Chen if (soc->dma_mask) 1300b960bc44SNicolin Chen return dma_set_mask_and_coherent(dev, soc->dma_mask); 1301b960bc44SNicolin Chen 1302b960bc44SNicolin Chen return 0; 1303b960bc44SNicolin Chen } 1304b960bc44SNicolin Chen 1305c915568dSLars-Peter Clausen static const struct sdhci_ops tegra_sdhci_ops = { 13060f686ca9SDmitry Osipenko .get_ro = tegra_sdhci_get_ro, 130785d6509dSShawn Guo .read_w = tegra_sdhci_readw, 130885d6509dSShawn Guo .write_l = tegra_sdhci_writel, 1309a8e326a9SLucas Stach .set_clock = tegra_sdhci_set_clock, 1310b960bc44SNicolin Chen .set_dma_mask = tegra_sdhci_set_dma_mask, 131114b04c6aSMichał Mirosław .set_bus_width = sdhci_set_bus_width, 131203231f9bSRussell King .reset = tegra_sdhci_reset, 1313c3c2384cSLucas Stach .platform_execute_tuning = tegra_sdhci_execute_tuning, 1314a8e326a9SLucas Stach .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 1315e5c63d91SLucas Stach .voltage_switch = tegra_sdhci_voltage_switch, 131644350993SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 131785d6509dSShawn Guo }; 131803d2bfc8SOlof Johansson 13191db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { 132085d6509dSShawn Guo .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 132185d6509dSShawn Guo SDHCI_QUIRK_SINGLE_POWER_WRITE | 132285d6509dSShawn Guo SDHCI_QUIRK_NO_HISPD_BIT | 1323f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 1324f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 132585d6509dSShawn Guo .ops = &tegra_sdhci_ops, 132685d6509dSShawn Guo }; 132785d6509dSShawn Guo 1328d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra20 = { 13293e44a1a7SStephen Warren .pdata = &sdhci_tegra20_pdata, 1330b960bc44SNicolin Chen .dma_mask = DMA_BIT_MASK(32), 13313e44a1a7SStephen Warren .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | 13323e44a1a7SStephen Warren NVQUIRK_ENABLE_BLOCK_GAP_DET, 13333e44a1a7SStephen Warren }; 13343e44a1a7SStephen Warren 13351db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { 13363e44a1a7SStephen Warren .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 13373e44a1a7SStephen Warren SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 13383e44a1a7SStephen Warren SDHCI_QUIRK_SINGLE_POWER_WRITE | 13393e44a1a7SStephen Warren SDHCI_QUIRK_NO_HISPD_BIT | 1340f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 1341f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1342127407e3SStefan Agner .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 1343726df1d5SStefan Agner SDHCI_QUIRK2_BROKEN_HS200 | 1344726df1d5SStefan Agner /* 1345726df1d5SStefan Agner * Auto-CMD23 leads to "Got command interrupt 0x00010000 even 1346726df1d5SStefan Agner * though no command operation was in progress." 1347726df1d5SStefan Agner * 1348726df1d5SStefan Agner * The exact reason is unknown, as the same hardware seems 1349726df1d5SStefan Agner * to support Auto CMD23 on a downstream 3.1 kernel. 1350726df1d5SStefan Agner */ 1351726df1d5SStefan Agner SDHCI_QUIRK2_ACMD23_BROKEN, 13523e44a1a7SStephen Warren .ops = &tegra_sdhci_ops, 13533e44a1a7SStephen Warren }; 13543e44a1a7SStephen Warren 1355d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra30 = { 13563e44a1a7SStephen Warren .pdata = &sdhci_tegra30_pdata, 1357b960bc44SNicolin Chen .dma_mask = DMA_BIT_MASK(32), 13583145351aSAndrew Bresticker .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | 13597ad2ed1dSLucas Stach NVQUIRK_ENABLE_SDR50 | 1360e5c63d91SLucas Stach NVQUIRK_ENABLE_SDR104 | 1361e5c63d91SLucas Stach NVQUIRK_HAS_PADCALIB, 13623e44a1a7SStephen Warren }; 13633e44a1a7SStephen Warren 136401df7ecdSRhyland Klein static const struct sdhci_ops tegra114_sdhci_ops = { 13650f686ca9SDmitry Osipenko .get_ro = tegra_sdhci_get_ro, 136601df7ecdSRhyland Klein .read_w = tegra_sdhci_readw, 136701df7ecdSRhyland Klein .write_w = tegra_sdhci_writew, 136801df7ecdSRhyland Klein .write_l = tegra_sdhci_writel, 1369a8e326a9SLucas Stach .set_clock = tegra_sdhci_set_clock, 1370b960bc44SNicolin Chen .set_dma_mask = tegra_sdhci_set_dma_mask, 137114b04c6aSMichał Mirosław .set_bus_width = sdhci_set_bus_width, 137201df7ecdSRhyland Klein .reset = tegra_sdhci_reset, 1373c3c2384cSLucas Stach .platform_execute_tuning = tegra_sdhci_execute_tuning, 1374a8e326a9SLucas Stach .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 1375e5c63d91SLucas Stach .voltage_switch = tegra_sdhci_voltage_switch, 137644350993SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 137701df7ecdSRhyland Klein }; 137801df7ecdSRhyland Klein 13791db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { 13805ebf2552SRhyland Klein .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 13815ebf2552SRhyland Klein SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 13825ebf2552SRhyland Klein SDHCI_QUIRK_SINGLE_POWER_WRITE | 13835ebf2552SRhyland Klein SDHCI_QUIRK_NO_HISPD_BIT | 1384f9260355SAndrew Bresticker SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 1385f9260355SAndrew Bresticker SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1386a8e326a9SLucas Stach .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 138701df7ecdSRhyland Klein .ops = &tegra114_sdhci_ops, 13885ebf2552SRhyland Klein }; 13895ebf2552SRhyland Klein 1390d49d19c2SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra114 = { 13915ebf2552SRhyland Klein .pdata = &sdhci_tegra114_pdata, 1392b960bc44SNicolin Chen .dma_mask = DMA_BIT_MASK(32), 13937bf037d6SJon Hunter }; 13947bf037d6SJon Hunter 13954ae12588SThierry Reding static const struct sdhci_pltfm_data sdhci_tegra124_pdata = { 13964ae12588SThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 13974ae12588SThierry Reding SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 13984ae12588SThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 13994ae12588SThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 14004ae12588SThierry Reding SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 14014ae12588SThierry Reding SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1402b960bc44SNicolin Chen .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 14034ae12588SThierry Reding .ops = &tegra114_sdhci_ops, 14044ae12588SThierry Reding }; 14054ae12588SThierry Reding 14064ae12588SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra124 = { 14074ae12588SThierry Reding .pdata = &sdhci_tegra124_pdata, 1408b960bc44SNicolin Chen .dma_mask = DMA_BIT_MASK(34), 14094ae12588SThierry Reding }; 14104ae12588SThierry Reding 14111070e83aSAapo Vienamo static const struct sdhci_ops tegra210_sdhci_ops = { 14120f686ca9SDmitry Osipenko .get_ro = tegra_sdhci_get_ro, 14131070e83aSAapo Vienamo .read_w = tegra_sdhci_readw, 141438a284d9SAapo Vienamo .write_w = tegra210_sdhci_writew, 14151070e83aSAapo Vienamo .write_l = tegra_sdhci_writel, 14161070e83aSAapo Vienamo .set_clock = tegra_sdhci_set_clock, 1417b960bc44SNicolin Chen .set_dma_mask = tegra_sdhci_set_dma_mask, 14181070e83aSAapo Vienamo .set_bus_width = sdhci_set_bus_width, 14191070e83aSAapo Vienamo .reset = tegra_sdhci_reset, 14201070e83aSAapo Vienamo .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 14211070e83aSAapo Vienamo .voltage_switch = tegra_sdhci_voltage_switch, 14221070e83aSAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 14235e958e4aSSowjanya Komatineni .set_timeout = tegra_sdhci_set_timeout, 14241070e83aSAapo Vienamo }; 14251070e83aSAapo Vienamo 1426b5a84ecfSThierry Reding static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { 1427b5a84ecfSThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 1428b5a84ecfSThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 1429b5a84ecfSThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 1430a8e326a9SLucas Stach SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 1431a8e326a9SLucas Stach SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1432a8e326a9SLucas Stach .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 14331070e83aSAapo Vienamo .ops = &tegra210_sdhci_ops, 1434b5a84ecfSThierry Reding }; 1435b5a84ecfSThierry Reding 1436b5a84ecfSThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra210 = { 1437b5a84ecfSThierry Reding .pdata = &sdhci_tegra210_pdata, 1438b960bc44SNicolin Chen .dma_mask = DMA_BIT_MASK(34), 1439d943f6e9SAapo Vienamo .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | 1440d4501d8eSAapo Vienamo NVQUIRK_HAS_PADCALIB | 14413559d4a6SAapo Vienamo NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | 14423559d4a6SAapo Vienamo NVQUIRK_ENABLE_SDR50 | 14438048822bSSowjanya Komatineni NVQUIRK_ENABLE_SDR104 | 14448048822bSSowjanya Komatineni NVQUIRK_HAS_TMCLK, 1445ea8fc595SSowjanya Komatineni .min_tap_delay = 106, 1446ea8fc595SSowjanya Komatineni .max_tap_delay = 185, 1447b5a84ecfSThierry Reding }; 1448b5a84ecfSThierry Reding 144938a284d9SAapo Vienamo static const struct sdhci_ops tegra186_sdhci_ops = { 14500f686ca9SDmitry Osipenko .get_ro = tegra_sdhci_get_ro, 145138a284d9SAapo Vienamo .read_w = tegra_sdhci_readw, 145238a284d9SAapo Vienamo .write_l = tegra_sdhci_writel, 145338a284d9SAapo Vienamo .set_clock = tegra_sdhci_set_clock, 1454b960bc44SNicolin Chen .set_dma_mask = tegra_sdhci_set_dma_mask, 145538a284d9SAapo Vienamo .set_bus_width = sdhci_set_bus_width, 145638a284d9SAapo Vienamo .reset = tegra_sdhci_reset, 145738a284d9SAapo Vienamo .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, 145838a284d9SAapo Vienamo .voltage_switch = tegra_sdhci_voltage_switch, 145938a284d9SAapo Vienamo .get_max_clock = tegra_sdhci_get_max_clock, 14603c4019f9SSowjanya Komatineni .irq = sdhci_tegra_cqhci_irq, 14615e958e4aSSowjanya Komatineni .set_timeout = tegra_sdhci_set_timeout, 146238a284d9SAapo Vienamo }; 146338a284d9SAapo Vienamo 14644346b7c7SThierry Reding static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { 14654346b7c7SThierry Reding .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 14664346b7c7SThierry Reding SDHCI_QUIRK_SINGLE_POWER_WRITE | 14674346b7c7SThierry Reding SDHCI_QUIRK_NO_HISPD_BIT | 14684346b7c7SThierry Reding SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | 14694346b7c7SThierry Reding SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1470b960bc44SNicolin Chen .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 147138a284d9SAapo Vienamo .ops = &tegra186_sdhci_ops, 14724346b7c7SThierry Reding }; 14734346b7c7SThierry Reding 14744346b7c7SThierry Reding static const struct sdhci_tegra_soc_data soc_data_tegra186 = { 14754346b7c7SThierry Reding .pdata = &sdhci_tegra186_pdata, 1476b960bc44SNicolin Chen .dma_mask = DMA_BIT_MASK(40), 1477d943f6e9SAapo Vienamo .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | 1478d4501d8eSAapo Vienamo NVQUIRK_HAS_PADCALIB | 14792ad50051SAapo Vienamo NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | 14802ad50051SAapo Vienamo NVQUIRK_ENABLE_SDR50 | 1481c6e7ab90SSowjanya Komatineni NVQUIRK_ENABLE_SDR104 | 14828048822bSSowjanya Komatineni NVQUIRK_HAS_TMCLK | 1483c6e7ab90SSowjanya Komatineni NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING, 1484ea8fc595SSowjanya Komatineni .min_tap_delay = 84, 1485ea8fc595SSowjanya Komatineni .max_tap_delay = 136, 1486ea8fc595SSowjanya Komatineni }; 1487ea8fc595SSowjanya Komatineni 1488ea8fc595SSowjanya Komatineni static const struct sdhci_tegra_soc_data soc_data_tegra194 = { 1489ea8fc595SSowjanya Komatineni .pdata = &sdhci_tegra186_pdata, 1490b960bc44SNicolin Chen .dma_mask = DMA_BIT_MASK(39), 1491ea8fc595SSowjanya Komatineni .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | 1492ea8fc595SSowjanya Komatineni NVQUIRK_HAS_PADCALIB | 1493ea8fc595SSowjanya Komatineni NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | 1494ea8fc595SSowjanya Komatineni NVQUIRK_ENABLE_SDR50 | 14958048822bSSowjanya Komatineni NVQUIRK_ENABLE_SDR104 | 14968048822bSSowjanya Komatineni NVQUIRK_HAS_TMCLK, 1497ea8fc595SSowjanya Komatineni .min_tap_delay = 96, 1498ea8fc595SSowjanya Komatineni .max_tap_delay = 139, 14994346b7c7SThierry Reding }; 15004346b7c7SThierry Reding 1501498d83e7SBill Pemberton static const struct of_device_id sdhci_tegra_dt_match[] = { 1502ea8fc595SSowjanya Komatineni { .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 }, 15034346b7c7SThierry Reding { .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 }, 1504b5a84ecfSThierry Reding { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, 15054ae12588SThierry Reding { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, 15065ebf2552SRhyland Klein { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, 15073e44a1a7SStephen Warren { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, 15083e44a1a7SStephen Warren { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, 1509275173b2SGrant Likely {} 1510275173b2SGrant Likely }; 1511e4404fabSArnd Bergmann MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); 1512275173b2SGrant Likely 15133c4019f9SSowjanya Komatineni static int sdhci_tegra_add_host(struct sdhci_host *host) 15143c4019f9SSowjanya Komatineni { 15153c4019f9SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 15163c4019f9SSowjanya Komatineni struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 15173c4019f9SSowjanya Komatineni struct cqhci_host *cq_host; 15183c4019f9SSowjanya Komatineni bool dma64; 15193c4019f9SSowjanya Komatineni int ret; 15203c4019f9SSowjanya Komatineni 15213c4019f9SSowjanya Komatineni if (!tegra_host->enable_hwcq) 15223c4019f9SSowjanya Komatineni return sdhci_add_host(host); 15233c4019f9SSowjanya Komatineni 15243c4019f9SSowjanya Komatineni sdhci_enable_v4_mode(host); 15253c4019f9SSowjanya Komatineni 15263c4019f9SSowjanya Komatineni ret = sdhci_setup_host(host); 15273c4019f9SSowjanya Komatineni if (ret) 15283c4019f9SSowjanya Komatineni return ret; 15293c4019f9SSowjanya Komatineni 15303c4019f9SSowjanya Komatineni host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 15313c4019f9SSowjanya Komatineni 15323c4019f9SSowjanya Komatineni cq_host = devm_kzalloc(host->mmc->parent, 15333c4019f9SSowjanya Komatineni sizeof(*cq_host), GFP_KERNEL); 15343c4019f9SSowjanya Komatineni if (!cq_host) { 15353c4019f9SSowjanya Komatineni ret = -ENOMEM; 15363c4019f9SSowjanya Komatineni goto cleanup; 15373c4019f9SSowjanya Komatineni } 15383c4019f9SSowjanya Komatineni 15393c4019f9SSowjanya Komatineni cq_host->mmio = host->ioaddr + SDHCI_TEGRA_CQE_BASE_ADDR; 15403c4019f9SSowjanya Komatineni cq_host->ops = &sdhci_tegra_cqhci_ops; 15413c4019f9SSowjanya Komatineni 15423c4019f9SSowjanya Komatineni dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 15433c4019f9SSowjanya Komatineni if (dma64) 15443c4019f9SSowjanya Komatineni cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 15453c4019f9SSowjanya Komatineni 15463c4019f9SSowjanya Komatineni ret = cqhci_init(cq_host, host->mmc, dma64); 15473c4019f9SSowjanya Komatineni if (ret) 15483c4019f9SSowjanya Komatineni goto cleanup; 15493c4019f9SSowjanya Komatineni 15503c4019f9SSowjanya Komatineni ret = __sdhci_add_host(host); 15513c4019f9SSowjanya Komatineni if (ret) 15523c4019f9SSowjanya Komatineni goto cleanup; 15533c4019f9SSowjanya Komatineni 15543c4019f9SSowjanya Komatineni return 0; 15553c4019f9SSowjanya Komatineni 15563c4019f9SSowjanya Komatineni cleanup: 15573c4019f9SSowjanya Komatineni sdhci_cleanup_host(host); 15583c4019f9SSowjanya Komatineni return ret; 15593c4019f9SSowjanya Komatineni } 15603c4019f9SSowjanya Komatineni 1561c3be1efdSBill Pemberton static int sdhci_tegra_probe(struct platform_device *pdev) 156203d2bfc8SOlof Johansson { 15633e44a1a7SStephen Warren const struct of_device_id *match; 15643e44a1a7SStephen Warren const struct sdhci_tegra_soc_data *soc_data; 15653e44a1a7SStephen Warren struct sdhci_host *host; 156685d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 15673e44a1a7SStephen Warren struct sdhci_tegra *tegra_host; 156803d2bfc8SOlof Johansson struct clk *clk; 156903d2bfc8SOlof Johansson int rc; 157003d2bfc8SOlof Johansson 15713e44a1a7SStephen Warren match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); 1572b37f9d98SJoseph Lo if (!match) 1573b37f9d98SJoseph Lo return -EINVAL; 15743e44a1a7SStephen Warren soc_data = match->data; 15753e44a1a7SStephen Warren 15760734e79cSJisheng Zhang host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*tegra_host)); 157785d6509dSShawn Guo if (IS_ERR(host)) 157885d6509dSShawn Guo return PTR_ERR(host); 157985d6509dSShawn Guo pltfm_host = sdhci_priv(host); 158085d6509dSShawn Guo 15810734e79cSJisheng Zhang tegra_host = sdhci_pltfm_priv(pltfm_host); 1582a8e326a9SLucas Stach tegra_host->ddr_signaling = false; 1583e5c63d91SLucas Stach tegra_host->pad_calib_required = false; 158486ac2f8bSAapo Vienamo tegra_host->pad_control_available = false; 15853e44a1a7SStephen Warren tegra_host->soc_data = soc_data; 1586275173b2SGrant Likely 158786ac2f8bSAapo Vienamo if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) { 158886ac2f8bSAapo Vienamo rc = tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host); 158986ac2f8bSAapo Vienamo if (rc == 0) 159086ac2f8bSAapo Vienamo host->mmc_host_ops.start_signal_voltage_switch = 159186ac2f8bSAapo Vienamo sdhci_tegra_start_signal_voltage_switch; 159286ac2f8bSAapo Vienamo } 159386ac2f8bSAapo Vienamo 159461dad40eSAapo Vienamo /* Hook to periodically rerun pad calibration */ 159561dad40eSAapo Vienamo if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) 159661dad40eSAapo Vienamo host->mmc_host_ops.request = tegra_sdhci_request; 159761dad40eSAapo Vienamo 1598dfc9700cSAapo Vienamo host->mmc_host_ops.hs400_enhanced_strobe = 1599dfc9700cSAapo Vienamo tegra_sdhci_hs400_enhanced_strobe; 1600dfc9700cSAapo Vienamo 1601ea8fc595SSowjanya Komatineni if (!host->ops->platform_execute_tuning) 1602ea8fc595SSowjanya Komatineni host->mmc_host_ops.execute_tuning = 1603ea8fc595SSowjanya Komatineni tegra_sdhci_execute_hw_tuning; 1604ea8fc595SSowjanya Komatineni 16052391b340SMylene JOSSERAND rc = mmc_of_parse(host->mmc); 160647caa84fSSimon Baatz if (rc) 160747caa84fSSimon Baatz goto err_parse_dt; 16080e786102SStephen Warren 16097ad2ed1dSLucas Stach if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) 1610c3c2384cSLucas Stach host->mmc->caps |= MMC_CAP_1_8V_DDR; 1611c3c2384cSLucas Stach 1612ff124c31SSowjanya Komatineni /* HW busy detection is supported, but R1B responses are required. */ 1613ff124c31SSowjanya Komatineni host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY; 1614d2f8bfa4SUlf Hansson 16153c4019f9SSowjanya Komatineni tegra_sdhci_parse_dt(host); 161685c0da17SAapo Vienamo 16172391b340SMylene JOSSERAND tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", 16182391b340SMylene JOSSERAND GPIOD_OUT_HIGH); 16192391b340SMylene JOSSERAND if (IS_ERR(tegra_host->power_gpio)) { 16202391b340SMylene JOSSERAND rc = PTR_ERR(tegra_host->power_gpio); 162185d6509dSShawn Guo goto err_power_req; 162203d2bfc8SOlof Johansson } 162303d2bfc8SOlof Johansson 16248048822bSSowjanya Komatineni /* 16258048822bSSowjanya Komatineni * Tegra210 has a separate SDMMC_LEGACY_TM clock used for host 16268048822bSSowjanya Komatineni * timeout clock and SW can choose TMCLK or SDCLK for hardware 16278048822bSSowjanya Komatineni * data timeout through the bit USE_TMCLK_FOR_DATA_TIMEOUT of 16288048822bSSowjanya Komatineni * the register SDHCI_TEGRA_VENDOR_SYS_SW_CTRL. 16298048822bSSowjanya Komatineni * 16308048822bSSowjanya Komatineni * USE_TMCLK_FOR_DATA_TIMEOUT bit default is set to 1 and SDMMC uses 16318048822bSSowjanya Komatineni * 12Mhz TMCLK which is advertised in host capability register. 16328048822bSSowjanya Komatineni * With TMCLK of 12Mhz provides maximum data timeout period that can 16338048822bSSowjanya Komatineni * be achieved is 11s better than using SDCLK for data timeout. 16348048822bSSowjanya Komatineni * 16358048822bSSowjanya Komatineni * So, TMCLK is set to 12Mhz and kept enabled all the time on SoC's 16368048822bSSowjanya Komatineni * supporting separate TMCLK. 16378048822bSSowjanya Komatineni */ 16388048822bSSowjanya Komatineni 16398048822bSSowjanya Komatineni if (soc_data->nvquirks & NVQUIRK_HAS_TMCLK) { 16408048822bSSowjanya Komatineni clk = devm_clk_get(&pdev->dev, "tmclk"); 16418048822bSSowjanya Komatineni if (IS_ERR(clk)) { 16428048822bSSowjanya Komatineni rc = PTR_ERR(clk); 16438048822bSSowjanya Komatineni if (rc == -EPROBE_DEFER) 16448048822bSSowjanya Komatineni goto err_power_req; 16458048822bSSowjanya Komatineni 16468048822bSSowjanya Komatineni dev_warn(&pdev->dev, "failed to get tmclk: %d\n", rc); 16478048822bSSowjanya Komatineni clk = NULL; 16488048822bSSowjanya Komatineni } 16498048822bSSowjanya Komatineni 16508048822bSSowjanya Komatineni clk_set_rate(clk, 12000000); 16518048822bSSowjanya Komatineni rc = clk_prepare_enable(clk); 16528048822bSSowjanya Komatineni if (rc) { 16538048822bSSowjanya Komatineni dev_err(&pdev->dev, 16548048822bSSowjanya Komatineni "failed to enable tmclk: %d\n", rc); 16558048822bSSowjanya Komatineni goto err_power_req; 16568048822bSSowjanya Komatineni } 16578048822bSSowjanya Komatineni 16588048822bSSowjanya Komatineni tegra_host->tmclk = clk; 16598048822bSSowjanya Komatineni } 16608048822bSSowjanya Komatineni 1661e4f79d9cSKevin Hao clk = devm_clk_get(mmc_dev(host->mmc), NULL); 166203d2bfc8SOlof Johansson if (IS_ERR(clk)) { 1663180a4665SKrzysztof Kozlowski rc = dev_err_probe(&pdev->dev, PTR_ERR(clk), 1664180a4665SKrzysztof Kozlowski "failed to get clock\n"); 166585d6509dSShawn Guo goto err_clk_get; 166603d2bfc8SOlof Johansson } 16671e674bc6SPrashant Gaikwad clk_prepare_enable(clk); 166803d2bfc8SOlof Johansson pltfm_host->clk = clk; 166903d2bfc8SOlof Johansson 16702cd6c49dSPhilipp Zabel tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev, 16712cd6c49dSPhilipp Zabel "sdhci"); 167220567be9SThierry Reding if (IS_ERR(tegra_host->rst)) { 167320567be9SThierry Reding rc = PTR_ERR(tegra_host->rst); 167420567be9SThierry Reding dev_err(&pdev->dev, "failed to get reset control: %d\n", rc); 167520567be9SThierry Reding goto err_rst_get; 167620567be9SThierry Reding } 167720567be9SThierry Reding 167820567be9SThierry Reding rc = reset_control_assert(tegra_host->rst); 167920567be9SThierry Reding if (rc) 168020567be9SThierry Reding goto err_rst_get; 168120567be9SThierry Reding 168220567be9SThierry Reding usleep_range(2000, 4000); 168320567be9SThierry Reding 168420567be9SThierry Reding rc = reset_control_deassert(tegra_host->rst); 168520567be9SThierry Reding if (rc) 168620567be9SThierry Reding goto err_rst_get; 168720567be9SThierry Reding 168820567be9SThierry Reding usleep_range(2000, 4000); 168920567be9SThierry Reding 16903c4019f9SSowjanya Komatineni rc = sdhci_tegra_add_host(host); 169185d6509dSShawn Guo if (rc) 169285d6509dSShawn Guo goto err_add_host; 169385d6509dSShawn Guo 169403d2bfc8SOlof Johansson return 0; 169503d2bfc8SOlof Johansson 169685d6509dSShawn Guo err_add_host: 169720567be9SThierry Reding reset_control_assert(tegra_host->rst); 169820567be9SThierry Reding err_rst_get: 16991e674bc6SPrashant Gaikwad clk_disable_unprepare(pltfm_host->clk); 170085d6509dSShawn Guo err_clk_get: 17018048822bSSowjanya Komatineni clk_disable_unprepare(tegra_host->tmclk); 170285d6509dSShawn Guo err_power_req: 170347caa84fSSimon Baatz err_parse_dt: 170485d6509dSShawn Guo sdhci_pltfm_free(pdev); 170503d2bfc8SOlof Johansson return rc; 170603d2bfc8SOlof Johansson } 170703d2bfc8SOlof Johansson 170820567be9SThierry Reding static int sdhci_tegra_remove(struct platform_device *pdev) 170920567be9SThierry Reding { 171020567be9SThierry Reding struct sdhci_host *host = platform_get_drvdata(pdev); 171120567be9SThierry Reding struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 171220567be9SThierry Reding struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); 171320567be9SThierry Reding 171420567be9SThierry Reding sdhci_remove_host(host, 0); 171520567be9SThierry Reding 171620567be9SThierry Reding reset_control_assert(tegra_host->rst); 171720567be9SThierry Reding usleep_range(2000, 4000); 171820567be9SThierry Reding clk_disable_unprepare(pltfm_host->clk); 17198048822bSSowjanya Komatineni clk_disable_unprepare(tegra_host->tmclk); 172020567be9SThierry Reding 172120567be9SThierry Reding sdhci_pltfm_free(pdev); 172220567be9SThierry Reding 172320567be9SThierry Reding return 0; 172420567be9SThierry Reding } 172520567be9SThierry Reding 172671c733c4SSowjanya Komatineni #ifdef CONFIG_PM_SLEEP 172771c733c4SSowjanya Komatineni static int __maybe_unused sdhci_tegra_suspend(struct device *dev) 172871c733c4SSowjanya Komatineni { 172971c733c4SSowjanya Komatineni struct sdhci_host *host = dev_get_drvdata(dev); 173071c733c4SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 173171c733c4SSowjanya Komatineni int ret; 173271c733c4SSowjanya Komatineni 173371c733c4SSowjanya Komatineni if (host->mmc->caps2 & MMC_CAP2_CQE) { 173471c733c4SSowjanya Komatineni ret = cqhci_suspend(host->mmc); 173571c733c4SSowjanya Komatineni if (ret) 173671c733c4SSowjanya Komatineni return ret; 173771c733c4SSowjanya Komatineni } 173871c733c4SSowjanya Komatineni 173971c733c4SSowjanya Komatineni ret = sdhci_suspend_host(host); 174071c733c4SSowjanya Komatineni if (ret) { 174171c733c4SSowjanya Komatineni cqhci_resume(host->mmc); 174271c733c4SSowjanya Komatineni return ret; 174371c733c4SSowjanya Komatineni } 174471c733c4SSowjanya Komatineni 174571c733c4SSowjanya Komatineni clk_disable_unprepare(pltfm_host->clk); 174671c733c4SSowjanya Komatineni return 0; 174771c733c4SSowjanya Komatineni } 174871c733c4SSowjanya Komatineni 174971c733c4SSowjanya Komatineni static int __maybe_unused sdhci_tegra_resume(struct device *dev) 175071c733c4SSowjanya Komatineni { 175171c733c4SSowjanya Komatineni struct sdhci_host *host = dev_get_drvdata(dev); 175271c733c4SSowjanya Komatineni struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 175371c733c4SSowjanya Komatineni int ret; 175471c733c4SSowjanya Komatineni 175571c733c4SSowjanya Komatineni ret = clk_prepare_enable(pltfm_host->clk); 175671c733c4SSowjanya Komatineni if (ret) 175771c733c4SSowjanya Komatineni return ret; 175871c733c4SSowjanya Komatineni 175971c733c4SSowjanya Komatineni ret = sdhci_resume_host(host); 176071c733c4SSowjanya Komatineni if (ret) 176171c733c4SSowjanya Komatineni goto disable_clk; 176271c733c4SSowjanya Komatineni 176371c733c4SSowjanya Komatineni if (host->mmc->caps2 & MMC_CAP2_CQE) { 176471c733c4SSowjanya Komatineni ret = cqhci_resume(host->mmc); 176571c733c4SSowjanya Komatineni if (ret) 176671c733c4SSowjanya Komatineni goto suspend_host; 176771c733c4SSowjanya Komatineni } 176871c733c4SSowjanya Komatineni 176971c733c4SSowjanya Komatineni return 0; 177071c733c4SSowjanya Komatineni 177171c733c4SSowjanya Komatineni suspend_host: 177271c733c4SSowjanya Komatineni sdhci_suspend_host(host); 177371c733c4SSowjanya Komatineni disable_clk: 177471c733c4SSowjanya Komatineni clk_disable_unprepare(pltfm_host->clk); 177571c733c4SSowjanya Komatineni return ret; 177671c733c4SSowjanya Komatineni } 177771c733c4SSowjanya Komatineni #endif 177871c733c4SSowjanya Komatineni 177971c733c4SSowjanya Komatineni static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend, 178071c733c4SSowjanya Komatineni sdhci_tegra_resume); 178171c733c4SSowjanya Komatineni 178285d6509dSShawn Guo static struct platform_driver sdhci_tegra_driver = { 178385d6509dSShawn Guo .driver = { 178485d6509dSShawn Guo .name = "sdhci-tegra", 178521b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1786275173b2SGrant Likely .of_match_table = sdhci_tegra_dt_match, 178771c733c4SSowjanya Komatineni .pm = &sdhci_tegra_dev_pm_ops, 178885d6509dSShawn Guo }, 178985d6509dSShawn Guo .probe = sdhci_tegra_probe, 179020567be9SThierry Reding .remove = sdhci_tegra_remove, 179103d2bfc8SOlof Johansson }; 179203d2bfc8SOlof Johansson 1793d1f81a64SAxel Lin module_platform_driver(sdhci_tegra_driver); 179485d6509dSShawn Guo 179585d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Tegra"); 179685d6509dSShawn Guo MODULE_AUTHOR("Google, Inc."); 179785d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 1798