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