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