xref: /openbmc/linux/drivers/mmc/host/sdhci-msm.c (revision 53e888d1)
197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20eb0d9f4SGeorgi Djakov /*
30eb0d9f4SGeorgi Djakov  * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
40eb0d9f4SGeorgi Djakov  *
50eb0d9f4SGeorgi Djakov  * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
60eb0d9f4SGeorgi Djakov  */
70eb0d9f4SGeorgi Djakov 
80eb0d9f4SGeorgi Djakov #include <linux/module.h>
90eb0d9f4SGeorgi Djakov #include <linux/of_device.h>
100eb0d9f4SGeorgi Djakov #include <linux/delay.h>
11415b5a75SGeorgi Djakov #include <linux/mmc/mmc.h>
1267e6db11SPramod Gurav #include <linux/pm_runtime.h>
130472f8d3SRajendra Nayak #include <linux/pm_opp.h>
14415b5a75SGeorgi Djakov #include <linux/slab.h>
15cc392c58SRitesh Harjani #include <linux/iopoll.h>
16ac06fba1SVijay Viswanath #include <linux/regulator/consumer.h>
17b4fc8278SPradeep P V K #include <linux/interconnect.h>
180eb0d9f4SGeorgi Djakov 
190eb0d9f4SGeorgi Djakov #include "sdhci-pltfm.h"
2087a8df0dSRitesh Harjani #include "cqhci.h"
210eb0d9f4SGeorgi Djakov 
223a3ad3e9SGeorgi Djakov #define CORE_MCI_VERSION		0x50
233a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_SHIFT	28
243a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_MASK		(0xf << CORE_VERSION_MAJOR_SHIFT)
253a3ad3e9SGeorgi Djakov #define CORE_VERSION_MINOR_MASK		0xff
263a3ad3e9SGeorgi Djakov 
2752884f8fSBjorn Andersson #define CORE_MCI_GENERICS		0x70
2852884f8fSBjorn Andersson #define SWITCHABLE_SIGNALING_VOLTAGE	BIT(29)
2952884f8fSBjorn Andersson 
300eb0d9f4SGeorgi Djakov #define HC_MODE_EN		0x1
310eb0d9f4SGeorgi Djakov #define CORE_POWER		0x0
320eb0d9f4SGeorgi Djakov #define CORE_SW_RST		BIT(7)
33ff06ce41SVenkat Gopalakrishnan #define FF_CLK_SW_RST_DIS	BIT(13)
340eb0d9f4SGeorgi Djakov 
35ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_OFF	BIT(0)
36ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_ON	BIT(1)
37ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_LOW	BIT(2)
38ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_HIGH	BIT(3)
39ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_SUCCESS BIT(0)
4092a21738SVeerabhadrarao Badiganti #define CORE_PWRCTL_BUS_FAIL    BIT(1)
41ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_SUCCESS	BIT(2)
4292a21738SVeerabhadrarao Badiganti #define CORE_PWRCTL_IO_FAIL     BIT(3)
43ad81d387SGeorgi Djakov #define REQ_BUS_OFF		BIT(0)
44ad81d387SGeorgi Djakov #define REQ_BUS_ON		BIT(1)
45ad81d387SGeorgi Djakov #define REQ_IO_LOW		BIT(2)
46ad81d387SGeorgi Djakov #define REQ_IO_HIGH		BIT(3)
47ad81d387SGeorgi Djakov #define INT_MASK		0xf
48415b5a75SGeorgi Djakov #define MAX_PHASES		16
49415b5a75SGeorgi Djakov #define CORE_DLL_LOCK		BIT(7)
5002e4293dSRitesh Harjani #define CORE_DDR_DLL_LOCK	BIT(11)
51415b5a75SGeorgi Djakov #define CORE_DLL_EN		BIT(16)
52415b5a75SGeorgi Djakov #define CORE_CDR_EN		BIT(17)
53415b5a75SGeorgi Djakov #define CORE_CK_OUT_EN		BIT(18)
54415b5a75SGeorgi Djakov #define CORE_CDR_EXT_EN		BIT(19)
55415b5a75SGeorgi Djakov #define CORE_DLL_PDN		BIT(29)
56415b5a75SGeorgi Djakov #define CORE_DLL_RST		BIT(30)
57cc392c58SRitesh Harjani #define CORE_CMD_DAT_TRACK_SEL	BIT(0)
58415b5a75SGeorgi Djakov 
5902e4293dSRitesh Harjani #define CORE_DDR_CAL_EN		BIT(0)
6083736352SVenkat Gopalakrishnan #define CORE_FLL_CYCLE_CNT	BIT(18)
6183736352SVenkat Gopalakrishnan #define CORE_DLL_CLOCK_DISABLE	BIT(21)
6283736352SVenkat Gopalakrishnan 
635c30f340SVeerabhadrarao Badiganti #define DLL_USR_CTL_POR_VAL	0x10800
645c30f340SVeerabhadrarao Badiganti #define ENABLE_DLL_LOCK_STATUS	BIT(26)
655c30f340SVeerabhadrarao Badiganti #define FINE_TUNE_MODE_EN	BIT(27)
665c30f340SVeerabhadrarao Badiganti #define BIAS_OK_SIGNAL		BIT(29)
675c30f340SVeerabhadrarao Badiganti 
6804816e67SSarthak Garg #define DLL_CONFIG_3_LOW_FREQ_VAL	0x08
6904816e67SSarthak Garg #define DLL_CONFIG_3_HIGH_FREQ_VAL	0x10
7004816e67SSarthak Garg 
71946932d9SVeerabhadrarao Badiganti #define CORE_VENDOR_SPEC_POR_VAL 0xa9c
72415b5a75SGeorgi Djakov #define CORE_CLK_PWRSAVE	BIT(1)
73ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_DFLT	(2 << 8)
74ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_HS400	(3 << 8)
75ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_MASK	(3 << 8)
76946932d9SVeerabhadrarao Badiganti #define CORE_IO_PAD_PWR_SWITCH_EN	BIT(15)
77946932d9SVeerabhadrarao Badiganti #define CORE_IO_PAD_PWR_SWITCH	BIT(16)
78ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_EN	BIT(18)
79ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_HS400	(6 << 19)
80ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_MASK	(7 << 19)
81415b5a75SGeorgi Djakov 
82946932d9SVeerabhadrarao Badiganti #define CORE_3_0V_SUPPORT	BIT(25)
83946932d9SVeerabhadrarao Badiganti #define CORE_1_8V_SUPPORT	BIT(26)
845c132323SVijay Viswanath #define CORE_VOLT_SUPPORT	(CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT)
85ac06fba1SVijay Viswanath 
86cc392c58SRitesh Harjani #define CORE_CSR_CDC_CTLR_CFG0		0x130
87cc392c58SRitesh Harjani #define CORE_SW_TRIG_FULL_CALIB		BIT(16)
88cc392c58SRitesh Harjani #define CORE_HW_AUTOCAL_ENA		BIT(17)
89cc392c58SRitesh Harjani 
90cc392c58SRitesh Harjani #define CORE_CSR_CDC_CTLR_CFG1		0x134
91cc392c58SRitesh Harjani #define CORE_CSR_CDC_CAL_TIMER_CFG0	0x138
92cc392c58SRitesh Harjani #define CORE_TIMER_ENA			BIT(16)
93cc392c58SRitesh Harjani 
94cc392c58SRitesh Harjani #define CORE_CSR_CDC_CAL_TIMER_CFG1	0x13C
95cc392c58SRitesh Harjani #define CORE_CSR_CDC_REFCOUNT_CFG	0x140
96cc392c58SRitesh Harjani #define CORE_CSR_CDC_COARSE_CAL_CFG	0x144
97cc392c58SRitesh Harjani #define CORE_CDC_OFFSET_CFG		0x14C
98cc392c58SRitesh Harjani #define CORE_CSR_CDC_DELAY_CFG		0x150
99cc392c58SRitesh Harjani #define CORE_CDC_SLAVE_DDA_CFG		0x160
100cc392c58SRitesh Harjani #define CORE_CSR_CDC_STATUS0		0x164
101cc392c58SRitesh Harjani #define CORE_CALIBRATION_DONE		BIT(0)
102cc392c58SRitesh Harjani 
103cc392c58SRitesh Harjani #define CORE_CDC_ERROR_CODE_MASK	0x7000000
104cc392c58SRitesh Harjani 
105cc392c58SRitesh Harjani #define CORE_CSR_CDC_GEN_CFG		0x178
106cc392c58SRitesh Harjani #define CORE_CDC_SWITCH_BYPASS_OFF	BIT(0)
107cc392c58SRitesh Harjani #define CORE_CDC_SWITCH_RC_EN		BIT(1)
108cc392c58SRitesh Harjani 
109cc392c58SRitesh Harjani #define CORE_CDC_T4_DLY_SEL		BIT(0)
11044bf2312SRitesh Harjani #define CORE_CMDIN_RCLK_EN		BIT(1)
111cc392c58SRitesh Harjani #define CORE_START_CDC_TRAFFIC		BIT(6)
112bc99266bSSayali Lokhande 
11302e4293dSRitesh Harjani #define CORE_PWRSAVE_DLL	BIT(3)
11402e4293dSRitesh Harjani 
115fa56ac97SVeerabhadrarao Badiganti #define DDR_CONFIG_POR_VAL	0x80040873
116cc392c58SRitesh Harjani 
1173a3ad3e9SGeorgi Djakov 
118abf270e5SRitesh Harjani #define INVALID_TUNING_PHASE	-1
11980031bdeSRitesh Harjani #define SDHCI_MSM_MIN_CLOCK	400000
120ff06ce41SVenkat Gopalakrishnan #define CORE_FREQ_100MHZ	(100 * 1000 * 1000)
12180031bdeSRitesh Harjani 
122415b5a75SGeorgi Djakov #define CDR_SELEXT_SHIFT	20
123415b5a75SGeorgi Djakov #define CDR_SELEXT_MASK		(0xf << CDR_SELEXT_SHIFT)
124415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_SHIFT	24
125415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_MASK	(7 << CMUX_SHIFT_PHASE_SHIFT)
126415b5a75SGeorgi Djakov 
12767e6db11SPramod Gurav #define MSM_MMC_AUTOSUSPEND_DELAY_MS	50
128c0309b38SVijay Viswanath 
129c0309b38SVijay Viswanath /* Timeout value to avoid infinite waiting for pwr_irq */
130c0309b38SVijay Viswanath #define MSM_PWR_IRQ_TIMEOUT_MS 5000
131c0309b38SVijay Viswanath 
13292a21738SVeerabhadrarao Badiganti /* Max load for eMMC Vdd-io supply */
13392a21738SVeerabhadrarao Badiganti #define MMC_VQMMC_MAX_LOAD_UA	325000
13492a21738SVeerabhadrarao Badiganti 
135bc99266bSSayali Lokhande #define msm_host_readl(msm_host, host, offset) \
136bc99266bSSayali Lokhande 	msm_host->var_ops->msm_readl_relaxed(host, offset)
137bc99266bSSayali Lokhande 
138bc99266bSSayali Lokhande #define msm_host_writel(msm_host, val, host, offset) \
139bc99266bSSayali Lokhande 	msm_host->var_ops->msm_writel_relaxed(val, host, offset)
140bc99266bSSayali Lokhande 
14187a8df0dSRitesh Harjani /* CQHCI vendor specific registers */
14287a8df0dSRitesh Harjani #define CQHCI_VENDOR_CFG1	0xA00
14387a8df0dSRitesh Harjani #define CQHCI_VENDOR_DIS_RST_ON_CQ_EN	(0x3 << 13)
14487a8df0dSRitesh Harjani 
145f1535888SSayali Lokhande struct sdhci_msm_offset {
146f1535888SSayali Lokhande 	u32 core_hc_mode;
147f1535888SSayali Lokhande 	u32 core_mci_data_cnt;
148f1535888SSayali Lokhande 	u32 core_mci_status;
149f1535888SSayali Lokhande 	u32 core_mci_fifo_cnt;
150f1535888SSayali Lokhande 	u32 core_mci_version;
151f1535888SSayali Lokhande 	u32 core_generics;
152f1535888SSayali Lokhande 	u32 core_testbus_config;
153f1535888SSayali Lokhande 	u32 core_testbus_sel2_bit;
154f1535888SSayali Lokhande 	u32 core_testbus_ena;
155f1535888SSayali Lokhande 	u32 core_testbus_sel2;
156f1535888SSayali Lokhande 	u32 core_pwrctl_status;
157f1535888SSayali Lokhande 	u32 core_pwrctl_mask;
158f1535888SSayali Lokhande 	u32 core_pwrctl_clear;
159f1535888SSayali Lokhande 	u32 core_pwrctl_ctl;
160f1535888SSayali Lokhande 	u32 core_sdcc_debug_reg;
161f1535888SSayali Lokhande 	u32 core_dll_config;
162f1535888SSayali Lokhande 	u32 core_dll_status;
163f1535888SSayali Lokhande 	u32 core_vendor_spec;
164f1535888SSayali Lokhande 	u32 core_vendor_spec_adma_err_addr0;
165f1535888SSayali Lokhande 	u32 core_vendor_spec_adma_err_addr1;
166f1535888SSayali Lokhande 	u32 core_vendor_spec_func2;
167f1535888SSayali Lokhande 	u32 core_vendor_spec_capabilities0;
168f1535888SSayali Lokhande 	u32 core_ddr_200_cfg;
169f1535888SSayali Lokhande 	u32 core_vendor_spec3;
170f1535888SSayali Lokhande 	u32 core_dll_config_2;
171fa56ac97SVeerabhadrarao Badiganti 	u32 core_dll_config_3;
172fa56ac97SVeerabhadrarao Badiganti 	u32 core_ddr_config_old; /* Applicable to sdcc minor ver < 0x49 */
173f1535888SSayali Lokhande 	u32 core_ddr_config;
1745c30f340SVeerabhadrarao Badiganti 	u32 core_dll_usr_ctl; /* Present on SDCC5.1 onwards */
175f1535888SSayali Lokhande };
176f1535888SSayali Lokhande 
177f1535888SSayali Lokhande static const struct sdhci_msm_offset sdhci_msm_v5_offset = {
178f1535888SSayali Lokhande 	.core_mci_data_cnt = 0x35c,
179f1535888SSayali Lokhande 	.core_mci_status = 0x324,
180f1535888SSayali Lokhande 	.core_mci_fifo_cnt = 0x308,
181f1535888SSayali Lokhande 	.core_mci_version = 0x318,
182f1535888SSayali Lokhande 	.core_generics = 0x320,
183f1535888SSayali Lokhande 	.core_testbus_config = 0x32c,
184f1535888SSayali Lokhande 	.core_testbus_sel2_bit = 3,
185f1535888SSayali Lokhande 	.core_testbus_ena = (1 << 31),
186f1535888SSayali Lokhande 	.core_testbus_sel2 = (1 << 3),
187f1535888SSayali Lokhande 	.core_pwrctl_status = 0x240,
188f1535888SSayali Lokhande 	.core_pwrctl_mask = 0x244,
189f1535888SSayali Lokhande 	.core_pwrctl_clear = 0x248,
190f1535888SSayali Lokhande 	.core_pwrctl_ctl = 0x24c,
191f1535888SSayali Lokhande 	.core_sdcc_debug_reg = 0x358,
192f1535888SSayali Lokhande 	.core_dll_config = 0x200,
193f1535888SSayali Lokhande 	.core_dll_status = 0x208,
194f1535888SSayali Lokhande 	.core_vendor_spec = 0x20c,
195f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr0 = 0x214,
196f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr1 = 0x218,
197f1535888SSayali Lokhande 	.core_vendor_spec_func2 = 0x210,
198f1535888SSayali Lokhande 	.core_vendor_spec_capabilities0 = 0x21c,
199f1535888SSayali Lokhande 	.core_ddr_200_cfg = 0x224,
200f1535888SSayali Lokhande 	.core_vendor_spec3 = 0x250,
201f1535888SSayali Lokhande 	.core_dll_config_2 = 0x254,
202fa56ac97SVeerabhadrarao Badiganti 	.core_dll_config_3 = 0x258,
203fa56ac97SVeerabhadrarao Badiganti 	.core_ddr_config = 0x25c,
2045c30f340SVeerabhadrarao Badiganti 	.core_dll_usr_ctl = 0x388,
205f1535888SSayali Lokhande };
206f1535888SSayali Lokhande 
207f1535888SSayali Lokhande static const struct sdhci_msm_offset sdhci_msm_mci_offset = {
208f1535888SSayali Lokhande 	.core_hc_mode = 0x78,
209f1535888SSayali Lokhande 	.core_mci_data_cnt = 0x30,
210f1535888SSayali Lokhande 	.core_mci_status = 0x34,
211f1535888SSayali Lokhande 	.core_mci_fifo_cnt = 0x44,
212f1535888SSayali Lokhande 	.core_mci_version = 0x050,
213f1535888SSayali Lokhande 	.core_generics = 0x70,
214f1535888SSayali Lokhande 	.core_testbus_config = 0x0cc,
215f1535888SSayali Lokhande 	.core_testbus_sel2_bit = 4,
216f1535888SSayali Lokhande 	.core_testbus_ena = (1 << 3),
217f1535888SSayali Lokhande 	.core_testbus_sel2 = (1 << 4),
218f1535888SSayali Lokhande 	.core_pwrctl_status = 0xdc,
219f1535888SSayali Lokhande 	.core_pwrctl_mask = 0xe0,
220f1535888SSayali Lokhande 	.core_pwrctl_clear = 0xe4,
221f1535888SSayali Lokhande 	.core_pwrctl_ctl = 0xe8,
222f1535888SSayali Lokhande 	.core_sdcc_debug_reg = 0x124,
223f1535888SSayali Lokhande 	.core_dll_config = 0x100,
224f1535888SSayali Lokhande 	.core_dll_status = 0x108,
225f1535888SSayali Lokhande 	.core_vendor_spec = 0x10c,
226f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr0 = 0x114,
227f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr1 = 0x118,
228f1535888SSayali Lokhande 	.core_vendor_spec_func2 = 0x110,
229f1535888SSayali Lokhande 	.core_vendor_spec_capabilities0 = 0x11c,
230f1535888SSayali Lokhande 	.core_ddr_200_cfg = 0x184,
231f1535888SSayali Lokhande 	.core_vendor_spec3 = 0x1b0,
232f1535888SSayali Lokhande 	.core_dll_config_2 = 0x1b4,
233fa56ac97SVeerabhadrarao Badiganti 	.core_ddr_config_old = 0x1b8,
234fa56ac97SVeerabhadrarao Badiganti 	.core_ddr_config = 0x1bc,
235f1535888SSayali Lokhande };
236f1535888SSayali Lokhande 
2376ed4bb43SVijay Viswanath struct sdhci_msm_variant_ops {
2386ed4bb43SVijay Viswanath 	u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
2396ed4bb43SVijay Viswanath 	void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
2406ed4bb43SVijay Viswanath 			u32 offset);
2416ed4bb43SVijay Viswanath };
2426ed4bb43SVijay Viswanath 
2436ed4bb43SVijay Viswanath /*
2446ed4bb43SVijay Viswanath  * From V5, register spaces have changed. Wrap this info in a structure
2456ed4bb43SVijay Viswanath  * and choose the data_structure based on version info mentioned in DT.
2466ed4bb43SVijay Viswanath  */
2476ed4bb43SVijay Viswanath struct sdhci_msm_variant_info {
2486ed4bb43SVijay Viswanath 	bool mci_removed;
24921f1e2d4SVeerabhadrarao Badiganti 	bool restore_dll_config;
2505c30f340SVeerabhadrarao Badiganti 	bool uses_tassadar_dll;
2516ed4bb43SVijay Viswanath 	const struct sdhci_msm_variant_ops *var_ops;
2526ed4bb43SVijay Viswanath 	const struct sdhci_msm_offset *offset;
2536ed4bb43SVijay Viswanath };
2546ed4bb43SVijay Viswanath 
2550eb0d9f4SGeorgi Djakov struct sdhci_msm_host {
2560eb0d9f4SGeorgi Djakov 	struct platform_device *pdev;
2570eb0d9f4SGeorgi Djakov 	void __iomem *core_mem;	/* MSM SDCC mapped address */
258ad81d387SGeorgi Djakov 	int pwr_irq;		/* power irq */
2590eb0d9f4SGeorgi Djakov 	struct clk *bus_clk;	/* SDHC bus voter clock */
26083736352SVenkat Gopalakrishnan 	struct clk *xo_clk;	/* TCXO clk needed for FLL feature of cm_dll*/
2614946b3afSBjorn Andersson 	struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */
262edc609fdSRitesh Harjani 	unsigned long clk_rate;
2630eb0d9f4SGeorgi Djakov 	struct mmc_host *mmc;
264c2b613d0SRajendra Nayak 	struct opp_table *opp_table;
265c2b613d0SRajendra Nayak 	bool has_opp_table;
26683736352SVenkat Gopalakrishnan 	bool use_14lpp_dll_reset;
267ff06ce41SVenkat Gopalakrishnan 	bool tuning_done;
268ff06ce41SVenkat Gopalakrishnan 	bool calibration_done;
269abf270e5SRitesh Harjani 	u8 saved_tuning_phase;
27002e4293dSRitesh Harjani 	bool use_cdclp533;
271c0309b38SVijay Viswanath 	u32 curr_pwr_state;
272c0309b38SVijay Viswanath 	u32 curr_io_level;
273c0309b38SVijay Viswanath 	wait_queue_head_t pwr_irq_wait;
274c0309b38SVijay Viswanath 	bool pwr_irq_flag;
275ac06fba1SVijay Viswanath 	u32 caps_0;
2766ed4bb43SVijay Viswanath 	bool mci_removed;
27721f1e2d4SVeerabhadrarao Badiganti 	bool restore_dll_config;
2786ed4bb43SVijay Viswanath 	const struct sdhci_msm_variant_ops *var_ops;
2796ed4bb43SVijay Viswanath 	const struct sdhci_msm_offset *offset;
280a89e7bcbSLoic Poulain 	bool use_cdr;
281a89e7bcbSLoic Poulain 	u32 transfer_mode;
282fa56ac97SVeerabhadrarao Badiganti 	bool updated_ddr_cfg;
2835c30f340SVeerabhadrarao Badiganti 	bool uses_tassadar_dll;
28403591160SSarthak Garg 	u32 dll_config;
2851dfbe3ffSSarthak Garg 	u32 ddr_config;
28692a21738SVeerabhadrarao Badiganti 	bool vqmmc_enabled;
2870eb0d9f4SGeorgi Djakov };
2880eb0d9f4SGeorgi Djakov 
289bc99266bSSayali Lokhande static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
290bc99266bSSayali Lokhande {
291bc99266bSSayali Lokhande 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
292bc99266bSSayali Lokhande 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
293bc99266bSSayali Lokhande 
294bc99266bSSayali Lokhande 	return msm_host->offset;
295bc99266bSSayali Lokhande }
296bc99266bSSayali Lokhande 
2976ed4bb43SVijay Viswanath /*
2986ed4bb43SVijay Viswanath  * APIs to read/write to vendor specific registers which were there in the
2996ed4bb43SVijay Viswanath  * core_mem region before MCI was removed.
3006ed4bb43SVijay Viswanath  */
3016ed4bb43SVijay Viswanath static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
3026ed4bb43SVijay Viswanath 		u32 offset)
3036ed4bb43SVijay Viswanath {
3046ed4bb43SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3056ed4bb43SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
3066ed4bb43SVijay Viswanath 
3076ed4bb43SVijay Viswanath 	return readl_relaxed(msm_host->core_mem + offset);
3086ed4bb43SVijay Viswanath }
3096ed4bb43SVijay Viswanath 
3106ed4bb43SVijay Viswanath static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
3116ed4bb43SVijay Viswanath 		u32 offset)
3126ed4bb43SVijay Viswanath {
3136ed4bb43SVijay Viswanath 	return readl_relaxed(host->ioaddr + offset);
3146ed4bb43SVijay Viswanath }
3156ed4bb43SVijay Viswanath 
3166ed4bb43SVijay Viswanath static void sdhci_msm_mci_variant_writel_relaxed(u32 val,
3176ed4bb43SVijay Viswanath 		struct sdhci_host *host, u32 offset)
3186ed4bb43SVijay Viswanath {
3196ed4bb43SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3206ed4bb43SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
3216ed4bb43SVijay Viswanath 
3226ed4bb43SVijay Viswanath 	writel_relaxed(val, msm_host->core_mem + offset);
3236ed4bb43SVijay Viswanath }
3246ed4bb43SVijay Viswanath 
3256ed4bb43SVijay Viswanath static void sdhci_msm_v5_variant_writel_relaxed(u32 val,
3266ed4bb43SVijay Viswanath 		struct sdhci_host *host, u32 offset)
3276ed4bb43SVijay Viswanath {
3286ed4bb43SVijay Viswanath 	writel_relaxed(val, host->ioaddr + offset);
3296ed4bb43SVijay Viswanath }
3306ed4bb43SVijay Viswanath 
3310fb8a3d4SRitesh Harjani static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
3320fb8a3d4SRitesh Harjani 						    unsigned int clock)
3330fb8a3d4SRitesh Harjani {
3340fb8a3d4SRitesh Harjani 	struct mmc_ios ios = host->mmc->ios;
3350fb8a3d4SRitesh Harjani 	/*
3360fb8a3d4SRitesh Harjani 	 * The SDHC requires internal clock frequency to be double the
3370fb8a3d4SRitesh Harjani 	 * actual clock that will be set for DDR mode. The controller
3380fb8a3d4SRitesh Harjani 	 * uses the faster clock(100/400MHz) for some of its parts and
3390fb8a3d4SRitesh Harjani 	 * send the actual required clock (50/200MHz) to the card.
3400fb8a3d4SRitesh Harjani 	 */
3410fb8a3d4SRitesh Harjani 	if (ios.timing == MMC_TIMING_UHS_DDR50 ||
3420fb8a3d4SRitesh Harjani 	    ios.timing == MMC_TIMING_MMC_DDR52 ||
343d7507aa1SRitesh Harjani 	    ios.timing == MMC_TIMING_MMC_HS400 ||
344d7507aa1SRitesh Harjani 	    host->flags & SDHCI_HS400_TUNING)
3450fb8a3d4SRitesh Harjani 		clock *= 2;
3460fb8a3d4SRitesh Harjani 	return clock;
3470fb8a3d4SRitesh Harjani }
3480fb8a3d4SRitesh Harjani 
3490fb8a3d4SRitesh Harjani static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
3500fb8a3d4SRitesh Harjani 					    unsigned int clock)
3510fb8a3d4SRitesh Harjani {
3520fb8a3d4SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3530fb8a3d4SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
3540fb8a3d4SRitesh Harjani 	struct mmc_ios curr_ios = host->mmc->ios;
355e4bf91f6SBjorn Andersson 	struct clk *core_clk = msm_host->bulk_clks[0].clk;
3560fb8a3d4SRitesh Harjani 	int rc;
3570fb8a3d4SRitesh Harjani 
3580fb8a3d4SRitesh Harjani 	clock = msm_get_clock_rate_for_bus_mode(host, clock);
3590472f8d3SRajendra Nayak 	rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), clock);
3600fb8a3d4SRitesh Harjani 	if (rc) {
3610fb8a3d4SRitesh Harjani 		pr_err("%s: Failed to set clock at rate %u at timing %d\n",
3620fb8a3d4SRitesh Harjani 		       mmc_hostname(host->mmc), clock,
3630fb8a3d4SRitesh Harjani 		       curr_ios.timing);
3640fb8a3d4SRitesh Harjani 		return;
3650fb8a3d4SRitesh Harjani 	}
3660fb8a3d4SRitesh Harjani 	msm_host->clk_rate = clock;
3670fb8a3d4SRitesh Harjani 	pr_debug("%s: Setting clock at rate %lu at timing %d\n",
368e4bf91f6SBjorn Andersson 		 mmc_hostname(host->mmc), clk_get_rate(core_clk),
3690fb8a3d4SRitesh Harjani 		 curr_ios.timing);
3700fb8a3d4SRitesh Harjani }
3710fb8a3d4SRitesh Harjani 
3720eb0d9f4SGeorgi Djakov /* Platform specific tuning */
373415b5a75SGeorgi Djakov static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
374415b5a75SGeorgi Djakov {
375415b5a75SGeorgi Djakov 	u32 wait_cnt = 50;
376415b5a75SGeorgi Djakov 	u8 ck_out_en;
377415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
378bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
379bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
380415b5a75SGeorgi Djakov 
381415b5a75SGeorgi Djakov 	/* Poll for CK_OUT_EN bit.  max. poll time = 50us */
382bc99266bSSayali Lokhande 	ck_out_en = !!(readl_relaxed(host->ioaddr +
383bc99266bSSayali Lokhande 			msm_offset->core_dll_config) & CORE_CK_OUT_EN);
384415b5a75SGeorgi Djakov 
385415b5a75SGeorgi Djakov 	while (ck_out_en != poll) {
386415b5a75SGeorgi Djakov 		if (--wait_cnt == 0) {
387415b5a75SGeorgi Djakov 			dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
388415b5a75SGeorgi Djakov 			       mmc_hostname(mmc), poll);
389415b5a75SGeorgi Djakov 			return -ETIMEDOUT;
390415b5a75SGeorgi Djakov 		}
391415b5a75SGeorgi Djakov 		udelay(1);
392415b5a75SGeorgi Djakov 
393bc99266bSSayali Lokhande 		ck_out_en = !!(readl_relaxed(host->ioaddr +
394bc99266bSSayali Lokhande 			msm_offset->core_dll_config) & CORE_CK_OUT_EN);
395415b5a75SGeorgi Djakov 	}
396415b5a75SGeorgi Djakov 
397415b5a75SGeorgi Djakov 	return 0;
398415b5a75SGeorgi Djakov }
399415b5a75SGeorgi Djakov 
400415b5a75SGeorgi Djakov static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
401415b5a75SGeorgi Djakov {
402415b5a75SGeorgi Djakov 	int rc;
403415b5a75SGeorgi Djakov 	static const u8 grey_coded_phase_table[] = {
404415b5a75SGeorgi Djakov 		0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
405415b5a75SGeorgi Djakov 		0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
406415b5a75SGeorgi Djakov 	};
407415b5a75SGeorgi Djakov 	unsigned long flags;
408415b5a75SGeorgi Djakov 	u32 config;
409415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
410bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
411bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
412415b5a75SGeorgi Djakov 
413abf270e5SRitesh Harjani 	if (phase > 0xf)
414abf270e5SRitesh Harjani 		return -EINVAL;
415abf270e5SRitesh Harjani 
416415b5a75SGeorgi Djakov 	spin_lock_irqsave(&host->lock, flags);
417415b5a75SGeorgi Djakov 
418bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
419415b5a75SGeorgi Djakov 	config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
420415b5a75SGeorgi Djakov 	config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
421bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
422415b5a75SGeorgi Djakov 
423415b5a75SGeorgi Djakov 	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
424415b5a75SGeorgi Djakov 	rc = msm_dll_poll_ck_out_en(host, 0);
425415b5a75SGeorgi Djakov 	if (rc)
426415b5a75SGeorgi Djakov 		goto err_out;
427415b5a75SGeorgi Djakov 
428415b5a75SGeorgi Djakov 	/*
429415b5a75SGeorgi Djakov 	 * Write the selected DLL clock output phase (0 ... 15)
430415b5a75SGeorgi Djakov 	 * to CDR_SELEXT bit field of DLL_CONFIG register.
431415b5a75SGeorgi Djakov 	 */
432bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
433415b5a75SGeorgi Djakov 	config &= ~CDR_SELEXT_MASK;
434415b5a75SGeorgi Djakov 	config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
435bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
436415b5a75SGeorgi Djakov 
437bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
43829301f40SRitesh Harjani 	config |= CORE_CK_OUT_EN;
439bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
440415b5a75SGeorgi Djakov 
441415b5a75SGeorgi Djakov 	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
442415b5a75SGeorgi Djakov 	rc = msm_dll_poll_ck_out_en(host, 1);
443415b5a75SGeorgi Djakov 	if (rc)
444415b5a75SGeorgi Djakov 		goto err_out;
445415b5a75SGeorgi Djakov 
446bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
447415b5a75SGeorgi Djakov 	config |= CORE_CDR_EN;
448415b5a75SGeorgi Djakov 	config &= ~CORE_CDR_EXT_EN;
449bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
450415b5a75SGeorgi Djakov 	goto out;
451415b5a75SGeorgi Djakov 
452415b5a75SGeorgi Djakov err_out:
453415b5a75SGeorgi Djakov 	dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
454415b5a75SGeorgi Djakov 	       mmc_hostname(mmc), phase);
455415b5a75SGeorgi Djakov out:
456415b5a75SGeorgi Djakov 	spin_unlock_irqrestore(&host->lock, flags);
457415b5a75SGeorgi Djakov 	return rc;
458415b5a75SGeorgi Djakov }
459415b5a75SGeorgi Djakov 
460415b5a75SGeorgi Djakov /*
461415b5a75SGeorgi Djakov  * Find out the greatest range of consecuitive selected
462415b5a75SGeorgi Djakov  * DLL clock output phases that can be used as sampling
463415b5a75SGeorgi Djakov  * setting for SD3.0 UHS-I card read operation (in SDR104
464ff06ce41SVenkat Gopalakrishnan  * timing mode) or for eMMC4.5 card read operation (in
465ff06ce41SVenkat Gopalakrishnan  * HS400/HS200 timing mode).
466415b5a75SGeorgi Djakov  * Select the 3/4 of the range and configure the DLL with the
467415b5a75SGeorgi Djakov  * selected DLL clock output phase.
468415b5a75SGeorgi Djakov  */
469415b5a75SGeorgi Djakov 
470415b5a75SGeorgi Djakov static int msm_find_most_appropriate_phase(struct sdhci_host *host,
471415b5a75SGeorgi Djakov 					   u8 *phase_table, u8 total_phases)
472415b5a75SGeorgi Djakov {
473415b5a75SGeorgi Djakov 	int ret;
474415b5a75SGeorgi Djakov 	u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
475415b5a75SGeorgi Djakov 	u8 phases_per_row[MAX_PHASES] = { 0 };
476415b5a75SGeorgi Djakov 	int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
477415b5a75SGeorgi Djakov 	int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
478415b5a75SGeorgi Djakov 	bool phase_0_found = false, phase_15_found = false;
479415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
480415b5a75SGeorgi Djakov 
481415b5a75SGeorgi Djakov 	if (!total_phases || (total_phases > MAX_PHASES)) {
482415b5a75SGeorgi Djakov 		dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
483415b5a75SGeorgi Djakov 		       mmc_hostname(mmc), total_phases);
484415b5a75SGeorgi Djakov 		return -EINVAL;
485415b5a75SGeorgi Djakov 	}
486415b5a75SGeorgi Djakov 
487415b5a75SGeorgi Djakov 	for (cnt = 0; cnt < total_phases; cnt++) {
488415b5a75SGeorgi Djakov 		ranges[row_index][col_index] = phase_table[cnt];
489415b5a75SGeorgi Djakov 		phases_per_row[row_index] += 1;
490415b5a75SGeorgi Djakov 		col_index++;
491415b5a75SGeorgi Djakov 
492415b5a75SGeorgi Djakov 		if ((cnt + 1) == total_phases) {
493415b5a75SGeorgi Djakov 			continue;
494415b5a75SGeorgi Djakov 		/* check if next phase in phase_table is consecutive or not */
495415b5a75SGeorgi Djakov 		} else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
496415b5a75SGeorgi Djakov 			row_index++;
497415b5a75SGeorgi Djakov 			col_index = 0;
498415b5a75SGeorgi Djakov 		}
499415b5a75SGeorgi Djakov 	}
500415b5a75SGeorgi Djakov 
501415b5a75SGeorgi Djakov 	if (row_index >= MAX_PHASES)
502415b5a75SGeorgi Djakov 		return -EINVAL;
503415b5a75SGeorgi Djakov 
504415b5a75SGeorgi Djakov 	/* Check if phase-0 is present in first valid window? */
505415b5a75SGeorgi Djakov 	if (!ranges[0][0]) {
506415b5a75SGeorgi Djakov 		phase_0_found = true;
507415b5a75SGeorgi Djakov 		phase_0_raw_index = 0;
508415b5a75SGeorgi Djakov 		/* Check if cycle exist between 2 valid windows */
509415b5a75SGeorgi Djakov 		for (cnt = 1; cnt <= row_index; cnt++) {
510415b5a75SGeorgi Djakov 			if (phases_per_row[cnt]) {
511415b5a75SGeorgi Djakov 				for (i = 0; i < phases_per_row[cnt]; i++) {
512415b5a75SGeorgi Djakov 					if (ranges[cnt][i] == 15) {
513415b5a75SGeorgi Djakov 						phase_15_found = true;
514415b5a75SGeorgi Djakov 						phase_15_raw_index = cnt;
515415b5a75SGeorgi Djakov 						break;
516415b5a75SGeorgi Djakov 					}
517415b5a75SGeorgi Djakov 				}
518415b5a75SGeorgi Djakov 			}
519415b5a75SGeorgi Djakov 		}
520415b5a75SGeorgi Djakov 	}
521415b5a75SGeorgi Djakov 
522415b5a75SGeorgi Djakov 	/* If 2 valid windows form cycle then merge them as single window */
523415b5a75SGeorgi Djakov 	if (phase_0_found && phase_15_found) {
524415b5a75SGeorgi Djakov 		/* number of phases in raw where phase 0 is present */
525415b5a75SGeorgi Djakov 		u8 phases_0 = phases_per_row[phase_0_raw_index];
526415b5a75SGeorgi Djakov 		/* number of phases in raw where phase 15 is present */
527415b5a75SGeorgi Djakov 		u8 phases_15 = phases_per_row[phase_15_raw_index];
528415b5a75SGeorgi Djakov 
529415b5a75SGeorgi Djakov 		if (phases_0 + phases_15 >= MAX_PHASES)
530415b5a75SGeorgi Djakov 			/*
531415b5a75SGeorgi Djakov 			 * If there are more than 1 phase windows then total
532415b5a75SGeorgi Djakov 			 * number of phases in both the windows should not be
533415b5a75SGeorgi Djakov 			 * more than or equal to MAX_PHASES.
534415b5a75SGeorgi Djakov 			 */
535415b5a75SGeorgi Djakov 			return -EINVAL;
536415b5a75SGeorgi Djakov 
537415b5a75SGeorgi Djakov 		/* Merge 2 cyclic windows */
538415b5a75SGeorgi Djakov 		i = phases_15;
539415b5a75SGeorgi Djakov 		for (cnt = 0; cnt < phases_0; cnt++) {
540415b5a75SGeorgi Djakov 			ranges[phase_15_raw_index][i] =
541415b5a75SGeorgi Djakov 			    ranges[phase_0_raw_index][cnt];
542415b5a75SGeorgi Djakov 			if (++i >= MAX_PHASES)
543415b5a75SGeorgi Djakov 				break;
544415b5a75SGeorgi Djakov 		}
545415b5a75SGeorgi Djakov 
546415b5a75SGeorgi Djakov 		phases_per_row[phase_0_raw_index] = 0;
547415b5a75SGeorgi Djakov 		phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
548415b5a75SGeorgi Djakov 	}
549415b5a75SGeorgi Djakov 
550415b5a75SGeorgi Djakov 	for (cnt = 0; cnt <= row_index; cnt++) {
551415b5a75SGeorgi Djakov 		if (phases_per_row[cnt] > curr_max) {
552415b5a75SGeorgi Djakov 			curr_max = phases_per_row[cnt];
553415b5a75SGeorgi Djakov 			selected_row_index = cnt;
554415b5a75SGeorgi Djakov 		}
555415b5a75SGeorgi Djakov 	}
556415b5a75SGeorgi Djakov 
557415b5a75SGeorgi Djakov 	i = (curr_max * 3) / 4;
558415b5a75SGeorgi Djakov 	if (i)
559415b5a75SGeorgi Djakov 		i--;
560415b5a75SGeorgi Djakov 
561415b5a75SGeorgi Djakov 	ret = ranges[selected_row_index][i];
562415b5a75SGeorgi Djakov 
563415b5a75SGeorgi Djakov 	if (ret >= MAX_PHASES) {
564415b5a75SGeorgi Djakov 		ret = -EINVAL;
565415b5a75SGeorgi Djakov 		dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
566415b5a75SGeorgi Djakov 		       mmc_hostname(mmc), ret);
567415b5a75SGeorgi Djakov 	}
568415b5a75SGeorgi Djakov 
569415b5a75SGeorgi Djakov 	return ret;
570415b5a75SGeorgi Djakov }
571415b5a75SGeorgi Djakov 
572415b5a75SGeorgi Djakov static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
573415b5a75SGeorgi Djakov {
574415b5a75SGeorgi Djakov 	u32 mclk_freq = 0, config;
575bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
576bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
577415b5a75SGeorgi Djakov 
578415b5a75SGeorgi Djakov 	/* Program the MCLK value to MCLK_FREQ bit field */
579415b5a75SGeorgi Djakov 	if (host->clock <= 112000000)
580415b5a75SGeorgi Djakov 		mclk_freq = 0;
581415b5a75SGeorgi Djakov 	else if (host->clock <= 125000000)
582415b5a75SGeorgi Djakov 		mclk_freq = 1;
583415b5a75SGeorgi Djakov 	else if (host->clock <= 137000000)
584415b5a75SGeorgi Djakov 		mclk_freq = 2;
585415b5a75SGeorgi Djakov 	else if (host->clock <= 150000000)
586415b5a75SGeorgi Djakov 		mclk_freq = 3;
587415b5a75SGeorgi Djakov 	else if (host->clock <= 162000000)
588415b5a75SGeorgi Djakov 		mclk_freq = 4;
589415b5a75SGeorgi Djakov 	else if (host->clock <= 175000000)
590415b5a75SGeorgi Djakov 		mclk_freq = 5;
591415b5a75SGeorgi Djakov 	else if (host->clock <= 187000000)
592415b5a75SGeorgi Djakov 		mclk_freq = 6;
593415b5a75SGeorgi Djakov 	else if (host->clock <= 200000000)
594415b5a75SGeorgi Djakov 		mclk_freq = 7;
595415b5a75SGeorgi Djakov 
596bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
597415b5a75SGeorgi Djakov 	config &= ~CMUX_SHIFT_PHASE_MASK;
598415b5a75SGeorgi Djakov 	config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
599bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
600415b5a75SGeorgi Djakov }
601415b5a75SGeorgi Djakov 
602415b5a75SGeorgi Djakov /* Initialize the DLL (Programmable Delay Line) */
603415b5a75SGeorgi Djakov static int msm_init_cm_dll(struct sdhci_host *host)
604415b5a75SGeorgi Djakov {
605415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
60683736352SVenkat Gopalakrishnan 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
60783736352SVenkat Gopalakrishnan 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
608415b5a75SGeorgi Djakov 	int wait_cnt = 50;
6095e6b6651SJorge Ramirez-Ortiz 	unsigned long flags, xo_clk = 0;
61029301f40SRitesh Harjani 	u32 config;
611bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
612bc99266bSSayali Lokhande 					msm_host->offset;
613415b5a75SGeorgi Djakov 
6145e6b6651SJorge Ramirez-Ortiz 	if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
6155e6b6651SJorge Ramirez-Ortiz 		xo_clk = clk_get_rate(msm_host->xo_clk);
6165e6b6651SJorge Ramirez-Ortiz 
617415b5a75SGeorgi Djakov 	spin_lock_irqsave(&host->lock, flags);
618415b5a75SGeorgi Djakov 
619415b5a75SGeorgi Djakov 	/*
620415b5a75SGeorgi Djakov 	 * Make sure that clock is always enabled when DLL
621415b5a75SGeorgi Djakov 	 * tuning is in progress. Keeping PWRSAVE ON may
622415b5a75SGeorgi Djakov 	 * turn off the clock.
623415b5a75SGeorgi Djakov 	 */
624bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
62529301f40SRitesh Harjani 	config &= ~CORE_CLK_PWRSAVE;
626bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
627415b5a75SGeorgi Djakov 
6283ec2d511SVeerabhadrarao Badiganti 	if (msm_host->dll_config)
6293ec2d511SVeerabhadrarao Badiganti 		writel_relaxed(msm_host->dll_config,
6303ec2d511SVeerabhadrarao Badiganti 				host->ioaddr + msm_offset->core_dll_config);
63103591160SSarthak Garg 
63283736352SVenkat Gopalakrishnan 	if (msm_host->use_14lpp_dll_reset) {
633bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
634bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
63583736352SVenkat Gopalakrishnan 		config &= ~CORE_CK_OUT_EN;
636bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
637bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
63883736352SVenkat Gopalakrishnan 
639bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
640bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
64183736352SVenkat Gopalakrishnan 		config |= CORE_DLL_CLOCK_DISABLE;
642bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
643bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
64483736352SVenkat Gopalakrishnan 	}
64583736352SVenkat Gopalakrishnan 
646bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
647bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
64829301f40SRitesh Harjani 	config |= CORE_DLL_RST;
649bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
650bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
651415b5a75SGeorgi Djakov 
652bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
653bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
65429301f40SRitesh Harjani 	config |= CORE_DLL_PDN;
655bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
656bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
65703591160SSarthak Garg 
65803591160SSarthak Garg 	if (!msm_host->dll_config)
659415b5a75SGeorgi Djakov 		msm_cm_dll_set_freq(host);
660415b5a75SGeorgi Djakov 
66183736352SVenkat Gopalakrishnan 	if (msm_host->use_14lpp_dll_reset &&
66283736352SVenkat Gopalakrishnan 	    !IS_ERR_OR_NULL(msm_host->xo_clk)) {
66383736352SVenkat Gopalakrishnan 		u32 mclk_freq = 0;
66483736352SVenkat Gopalakrishnan 
665bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
666bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
66783736352SVenkat Gopalakrishnan 		config &= CORE_FLL_CYCLE_CNT;
66883736352SVenkat Gopalakrishnan 		if (config)
66983736352SVenkat Gopalakrishnan 			mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
6705e6b6651SJorge Ramirez-Ortiz 					xo_clk);
67183736352SVenkat Gopalakrishnan 		else
67283736352SVenkat Gopalakrishnan 			mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
6735e6b6651SJorge Ramirez-Ortiz 					xo_clk);
67483736352SVenkat Gopalakrishnan 
675bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
676bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
67783736352SVenkat Gopalakrishnan 		config &= ~(0xFF << 10);
67883736352SVenkat Gopalakrishnan 		config |= mclk_freq << 10;
67983736352SVenkat Gopalakrishnan 
680bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
681bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
68283736352SVenkat Gopalakrishnan 		/* wait for 5us before enabling DLL clock */
68383736352SVenkat Gopalakrishnan 		udelay(5);
68483736352SVenkat Gopalakrishnan 	}
68583736352SVenkat Gopalakrishnan 
686bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
687bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
68829301f40SRitesh Harjani 	config &= ~CORE_DLL_RST;
689bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
690bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
691415b5a75SGeorgi Djakov 
692bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
693bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
69429301f40SRitesh Harjani 	config &= ~CORE_DLL_PDN;
695bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
696bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
697415b5a75SGeorgi Djakov 
69883736352SVenkat Gopalakrishnan 	if (msm_host->use_14lpp_dll_reset) {
69903591160SSarthak Garg 		if (!msm_host->dll_config)
70083736352SVenkat Gopalakrishnan 			msm_cm_dll_set_freq(host);
701bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
702bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
70383736352SVenkat Gopalakrishnan 		config &= ~CORE_DLL_CLOCK_DISABLE;
704bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
705bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
70683736352SVenkat Gopalakrishnan 	}
70783736352SVenkat Gopalakrishnan 
7085c30f340SVeerabhadrarao Badiganti 	/*
7095c30f340SVeerabhadrarao Badiganti 	 * Configure DLL user control register to enable DLL status.
7105c30f340SVeerabhadrarao Badiganti 	 * This setting is applicable to SDCC v5.1 onwards only.
7115c30f340SVeerabhadrarao Badiganti 	 */
7125c30f340SVeerabhadrarao Badiganti 	if (msm_host->uses_tassadar_dll) {
7135c30f340SVeerabhadrarao Badiganti 		config = DLL_USR_CTL_POR_VAL | FINE_TUNE_MODE_EN |
7145c30f340SVeerabhadrarao Badiganti 			ENABLE_DLL_LOCK_STATUS | BIAS_OK_SIGNAL;
7155c30f340SVeerabhadrarao Badiganti 		writel_relaxed(config, host->ioaddr +
7165c30f340SVeerabhadrarao Badiganti 				msm_offset->core_dll_usr_ctl);
71704816e67SSarthak Garg 
71804816e67SSarthak Garg 		config = readl_relaxed(host->ioaddr +
71904816e67SSarthak Garg 				msm_offset->core_dll_config_3);
72004816e67SSarthak Garg 		config &= ~0xFF;
72104816e67SSarthak Garg 		if (msm_host->clk_rate < 150000000)
72204816e67SSarthak Garg 			config |= DLL_CONFIG_3_LOW_FREQ_VAL;
72304816e67SSarthak Garg 		else
72404816e67SSarthak Garg 			config |= DLL_CONFIG_3_HIGH_FREQ_VAL;
72504816e67SSarthak Garg 		writel_relaxed(config, host->ioaddr +
72604816e67SSarthak Garg 			msm_offset->core_dll_config_3);
7275c30f340SVeerabhadrarao Badiganti 	}
7285c30f340SVeerabhadrarao Badiganti 
729bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
730bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
73129301f40SRitesh Harjani 	config |= CORE_DLL_EN;
732bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
733bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
734415b5a75SGeorgi Djakov 
735bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
736bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
73729301f40SRitesh Harjani 	config |= CORE_CK_OUT_EN;
738bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
739bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
740415b5a75SGeorgi Djakov 
741415b5a75SGeorgi Djakov 	/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
742bc99266bSSayali Lokhande 	while (!(readl_relaxed(host->ioaddr + msm_offset->core_dll_status) &
743415b5a75SGeorgi Djakov 		 CORE_DLL_LOCK)) {
744415b5a75SGeorgi Djakov 		/* max. wait for 50us sec for LOCK bit to be set */
745415b5a75SGeorgi Djakov 		if (--wait_cnt == 0) {
746415b5a75SGeorgi Djakov 			dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
747415b5a75SGeorgi Djakov 			       mmc_hostname(mmc));
748415b5a75SGeorgi Djakov 			spin_unlock_irqrestore(&host->lock, flags);
749415b5a75SGeorgi Djakov 			return -ETIMEDOUT;
750415b5a75SGeorgi Djakov 		}
751415b5a75SGeorgi Djakov 		udelay(1);
752415b5a75SGeorgi Djakov 	}
753415b5a75SGeorgi Djakov 
754415b5a75SGeorgi Djakov 	spin_unlock_irqrestore(&host->lock, flags);
755415b5a75SGeorgi Djakov 	return 0;
756415b5a75SGeorgi Djakov }
757415b5a75SGeorgi Djakov 
758b54aaa8aSRitesh Harjani static void msm_hc_select_default(struct sdhci_host *host)
759b54aaa8aSRitesh Harjani {
760b54aaa8aSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
761b54aaa8aSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
762b54aaa8aSRitesh Harjani 	u32 config;
763bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
764bc99266bSSayali Lokhande 					msm_host->offset;
765b54aaa8aSRitesh Harjani 
766b54aaa8aSRitesh Harjani 	if (!msm_host->use_cdclp533) {
767b54aaa8aSRitesh Harjani 		config = readl_relaxed(host->ioaddr +
768bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec3);
769b54aaa8aSRitesh Harjani 		config &= ~CORE_PWRSAVE_DLL;
770b54aaa8aSRitesh Harjani 		writel_relaxed(config, host->ioaddr +
771bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec3);
772b54aaa8aSRitesh Harjani 	}
773b54aaa8aSRitesh Harjani 
774bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
775b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_MCLK_SEL_MASK;
776b54aaa8aSRitesh Harjani 	config |= CORE_HC_MCLK_SEL_DFLT;
777bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
778b54aaa8aSRitesh Harjani 
779b54aaa8aSRitesh Harjani 	/*
780b54aaa8aSRitesh Harjani 	 * Disable HC_SELECT_IN to be able to use the UHS mode select
781b54aaa8aSRitesh Harjani 	 * configuration from Host Control2 register for all other
782b54aaa8aSRitesh Harjani 	 * modes.
783b54aaa8aSRitesh Harjani 	 * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
784b54aaa8aSRitesh Harjani 	 * in VENDOR_SPEC_FUNC
785b54aaa8aSRitesh Harjani 	 */
786bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
787b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_SELECT_IN_EN;
788b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_SELECT_IN_MASK;
789bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
790b54aaa8aSRitesh Harjani 
791b54aaa8aSRitesh Harjani 	/*
792b54aaa8aSRitesh Harjani 	 * Make sure above writes impacting free running MCLK are completed
793b54aaa8aSRitesh Harjani 	 * before changing the clk_rate at GCC.
794b54aaa8aSRitesh Harjani 	 */
795b54aaa8aSRitesh Harjani 	wmb();
796b54aaa8aSRitesh Harjani }
797b54aaa8aSRitesh Harjani 
798b54aaa8aSRitesh Harjani static void msm_hc_select_hs400(struct sdhci_host *host)
799b54aaa8aSRitesh Harjani {
800b54aaa8aSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
801b54aaa8aSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
80244bf2312SRitesh Harjani 	struct mmc_ios ios = host->mmc->ios;
803b54aaa8aSRitesh Harjani 	u32 config, dll_lock;
804b54aaa8aSRitesh Harjani 	int rc;
805bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
806bc99266bSSayali Lokhande 					msm_host->offset;
807b54aaa8aSRitesh Harjani 
808b54aaa8aSRitesh Harjani 	/* Select the divided clock (free running MCLK/2) */
809bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
810b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_MCLK_SEL_MASK;
811b54aaa8aSRitesh Harjani 	config |= CORE_HC_MCLK_SEL_HS400;
812b54aaa8aSRitesh Harjani 
813bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
814b54aaa8aSRitesh Harjani 	/*
815b54aaa8aSRitesh Harjani 	 * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
816b54aaa8aSRitesh Harjani 	 * register
817b54aaa8aSRitesh Harjani 	 */
81844bf2312SRitesh Harjani 	if ((msm_host->tuning_done || ios.enhanced_strobe) &&
81944bf2312SRitesh Harjani 	    !msm_host->calibration_done) {
820bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
821bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
822b54aaa8aSRitesh Harjani 		config |= CORE_HC_SELECT_IN_HS400;
823b54aaa8aSRitesh Harjani 		config |= CORE_HC_SELECT_IN_EN;
824bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
825bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
826b54aaa8aSRitesh Harjani 	}
827b54aaa8aSRitesh Harjani 	if (!msm_host->clk_rate && !msm_host->use_cdclp533) {
828b54aaa8aSRitesh Harjani 		/*
829b54aaa8aSRitesh Harjani 		 * Poll on DLL_LOCK or DDR_DLL_LOCK bits in
830bc99266bSSayali Lokhande 		 * core_dll_status to be set. This should get set
831b54aaa8aSRitesh Harjani 		 * within 15 us at 200 MHz.
832b54aaa8aSRitesh Harjani 		 */
833b54aaa8aSRitesh Harjani 		rc = readl_relaxed_poll_timeout(host->ioaddr +
834bc99266bSSayali Lokhande 						msm_offset->core_dll_status,
835b54aaa8aSRitesh Harjani 						dll_lock,
836b54aaa8aSRitesh Harjani 						(dll_lock &
837b54aaa8aSRitesh Harjani 						(CORE_DLL_LOCK |
838b54aaa8aSRitesh Harjani 						CORE_DDR_DLL_LOCK)), 10,
839b54aaa8aSRitesh Harjani 						1000);
840b54aaa8aSRitesh Harjani 		if (rc == -ETIMEDOUT)
841b54aaa8aSRitesh Harjani 			pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n",
842b54aaa8aSRitesh Harjani 			       mmc_hostname(host->mmc), dll_lock);
843b54aaa8aSRitesh Harjani 	}
844b54aaa8aSRitesh Harjani 	/*
845b54aaa8aSRitesh Harjani 	 * Make sure above writes impacting free running MCLK are completed
846b54aaa8aSRitesh Harjani 	 * before changing the clk_rate at GCC.
847b54aaa8aSRitesh Harjani 	 */
848b54aaa8aSRitesh Harjani 	wmb();
849b54aaa8aSRitesh Harjani }
850b54aaa8aSRitesh Harjani 
851b54aaa8aSRitesh Harjani /*
852b54aaa8aSRitesh Harjani  * sdhci_msm_hc_select_mode :- In general all timing modes are
853b54aaa8aSRitesh Harjani  * controlled via UHS mode select in Host Control2 register.
854b54aaa8aSRitesh Harjani  * eMMC specific HS200/HS400 doesn't have their respective modes
855b54aaa8aSRitesh Harjani  * defined here, hence we use these values.
856b54aaa8aSRitesh Harjani  *
857b54aaa8aSRitesh Harjani  * HS200 - SDR104 (Since they both are equivalent in functionality)
858b54aaa8aSRitesh Harjani  * HS400 - This involves multiple configurations
859b54aaa8aSRitesh Harjani  *		Initially SDR104 - when tuning is required as HS200
860b54aaa8aSRitesh Harjani  *		Then when switching to DDR @ 400MHz (HS400) we use
861b54aaa8aSRitesh Harjani  *		the vendor specific HC_SELECT_IN to control the mode.
862b54aaa8aSRitesh Harjani  *
863b54aaa8aSRitesh Harjani  * In addition to controlling the modes we also need to select the
864b54aaa8aSRitesh Harjani  * correct input clock for DLL depending on the mode.
865b54aaa8aSRitesh Harjani  *
866b54aaa8aSRitesh Harjani  * HS400 - divided clock (free running MCLK/2)
867b54aaa8aSRitesh Harjani  * All other modes - default (free running MCLK)
868b54aaa8aSRitesh Harjani  */
86930de038dSMasahiro Yamada static void sdhci_msm_hc_select_mode(struct sdhci_host *host)
870b54aaa8aSRitesh Harjani {
871b54aaa8aSRitesh Harjani 	struct mmc_ios ios = host->mmc->ios;
872b54aaa8aSRitesh Harjani 
873d7507aa1SRitesh Harjani 	if (ios.timing == MMC_TIMING_MMC_HS400 ||
874d7507aa1SRitesh Harjani 	    host->flags & SDHCI_HS400_TUNING)
875b54aaa8aSRitesh Harjani 		msm_hc_select_hs400(host);
876b54aaa8aSRitesh Harjani 	else
877b54aaa8aSRitesh Harjani 		msm_hc_select_default(host);
878b54aaa8aSRitesh Harjani }
879b54aaa8aSRitesh Harjani 
880cc392c58SRitesh Harjani static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
881cc392c58SRitesh Harjani {
882cc392c58SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
883cc392c58SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
884cc392c58SRitesh Harjani 	u32 config, calib_done;
885cc392c58SRitesh Harjani 	int ret;
886bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
887bc99266bSSayali Lokhande 					msm_host->offset;
888cc392c58SRitesh Harjani 
889cc392c58SRitesh Harjani 	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
890cc392c58SRitesh Harjani 
891cc392c58SRitesh Harjani 	/*
892cc392c58SRitesh Harjani 	 * Retuning in HS400 (DDR mode) will fail, just reset the
893cc392c58SRitesh Harjani 	 * tuning block and restore the saved tuning phase.
894cc392c58SRitesh Harjani 	 */
895cc392c58SRitesh Harjani 	ret = msm_init_cm_dll(host);
896cc392c58SRitesh Harjani 	if (ret)
897cc392c58SRitesh Harjani 		goto out;
898cc392c58SRitesh Harjani 
899cc392c58SRitesh Harjani 	/* Set the selected phase in delay line hw block */
900cc392c58SRitesh Harjani 	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
901cc392c58SRitesh Harjani 	if (ret)
902cc392c58SRitesh Harjani 		goto out;
903cc392c58SRitesh Harjani 
904bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
905cc392c58SRitesh Harjani 	config |= CORE_CMD_DAT_TRACK_SEL;
906bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
907cc392c58SRitesh Harjani 
908bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
909cc392c58SRitesh Harjani 	config &= ~CORE_CDC_T4_DLY_SEL;
910bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
911cc392c58SRitesh Harjani 
912cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
913cc392c58SRitesh Harjani 	config &= ~CORE_CDC_SWITCH_BYPASS_OFF;
914cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
915cc392c58SRitesh Harjani 
916cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
917cc392c58SRitesh Harjani 	config |= CORE_CDC_SWITCH_RC_EN;
918cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
919cc392c58SRitesh Harjani 
920bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
921cc392c58SRitesh Harjani 	config &= ~CORE_START_CDC_TRAFFIC;
922bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
923cc392c58SRitesh Harjani 
924543c576dSRitesh Harjani 	/* Perform CDC Register Initialization Sequence */
925cc392c58SRitesh Harjani 
926cc392c58SRitesh Harjani 	writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
927cc392c58SRitesh Harjani 	writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
928cc392c58SRitesh Harjani 	writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
929cc392c58SRitesh Harjani 	writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
930cc392c58SRitesh Harjani 	writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
931cc392c58SRitesh Harjani 	writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
932083c9aa0SSubhash Jadavani 	writel_relaxed(0x4E2, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
933cc392c58SRitesh Harjani 	writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
934cc392c58SRitesh Harjani 	writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
935cc392c58SRitesh Harjani 
936cc392c58SRitesh Harjani 	/* CDC HW Calibration */
937cc392c58SRitesh Harjani 
938cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
939cc392c58SRitesh Harjani 	config |= CORE_SW_TRIG_FULL_CALIB;
940cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
941cc392c58SRitesh Harjani 
942cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
943cc392c58SRitesh Harjani 	config &= ~CORE_SW_TRIG_FULL_CALIB;
944cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
945cc392c58SRitesh Harjani 
946cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
947cc392c58SRitesh Harjani 	config |= CORE_HW_AUTOCAL_ENA;
948cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
949cc392c58SRitesh Harjani 
950cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
951cc392c58SRitesh Harjani 	config |= CORE_TIMER_ENA;
952cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
953cc392c58SRitesh Harjani 
954cc392c58SRitesh Harjani 	ret = readl_relaxed_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0,
955cc392c58SRitesh Harjani 					 calib_done,
956cc392c58SRitesh Harjani 					 (calib_done & CORE_CALIBRATION_DONE),
957cc392c58SRitesh Harjani 					 1, 50);
958cc392c58SRitesh Harjani 
959cc392c58SRitesh Harjani 	if (ret == -ETIMEDOUT) {
960cc392c58SRitesh Harjani 		pr_err("%s: %s: CDC calibration was not completed\n",
961cc392c58SRitesh Harjani 		       mmc_hostname(host->mmc), __func__);
962cc392c58SRitesh Harjani 		goto out;
963cc392c58SRitesh Harjani 	}
964cc392c58SRitesh Harjani 
965cc392c58SRitesh Harjani 	ret = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
966cc392c58SRitesh Harjani 			& CORE_CDC_ERROR_CODE_MASK;
967cc392c58SRitesh Harjani 	if (ret) {
968cc392c58SRitesh Harjani 		pr_err("%s: %s: CDC error code %d\n",
969cc392c58SRitesh Harjani 		       mmc_hostname(host->mmc), __func__, ret);
970cc392c58SRitesh Harjani 		ret = -EINVAL;
971cc392c58SRitesh Harjani 		goto out;
972cc392c58SRitesh Harjani 	}
973cc392c58SRitesh Harjani 
974bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
975cc392c58SRitesh Harjani 	config |= CORE_START_CDC_TRAFFIC;
976bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
977cc392c58SRitesh Harjani out:
978cc392c58SRitesh Harjani 	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
979cc392c58SRitesh Harjani 		 __func__, ret);
980cc392c58SRitesh Harjani 	return ret;
981cc392c58SRitesh Harjani }
982cc392c58SRitesh Harjani 
98302e4293dSRitesh Harjani static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
98402e4293dSRitesh Harjani {
98544bf2312SRitesh Harjani 	struct mmc_host *mmc = host->mmc;
986fa56ac97SVeerabhadrarao Badiganti 	u32 dll_status, config, ddr_cfg_offset;
98702e4293dSRitesh Harjani 	int ret;
988fa56ac97SVeerabhadrarao Badiganti 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
989fa56ac97SVeerabhadrarao Badiganti 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
990bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
991bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
99202e4293dSRitesh Harjani 
99302e4293dSRitesh Harjani 	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
99402e4293dSRitesh Harjani 
99502e4293dSRitesh Harjani 	/*
996bc99266bSSayali Lokhande 	 * Currently the core_ddr_config register defaults to desired
99702e4293dSRitesh Harjani 	 * configuration on reset. Currently reprogramming the power on
99802e4293dSRitesh Harjani 	 * reset (POR) value in case it might have been modified by
99902e4293dSRitesh Harjani 	 * bootloaders. In the future, if this changes, then the desired
100002e4293dSRitesh Harjani 	 * values will need to be programmed appropriately.
100102e4293dSRitesh Harjani 	 */
1002fa56ac97SVeerabhadrarao Badiganti 	if (msm_host->updated_ddr_cfg)
1003fa56ac97SVeerabhadrarao Badiganti 		ddr_cfg_offset = msm_offset->core_ddr_config;
1004fa56ac97SVeerabhadrarao Badiganti 	else
1005fa56ac97SVeerabhadrarao Badiganti 		ddr_cfg_offset = msm_offset->core_ddr_config_old;
10061dfbe3ffSSarthak Garg 	writel_relaxed(msm_host->ddr_config, host->ioaddr + ddr_cfg_offset);
100702e4293dSRitesh Harjani 
100844bf2312SRitesh Harjani 	if (mmc->ios.enhanced_strobe) {
1009bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1010bc99266bSSayali Lokhande 				msm_offset->core_ddr_200_cfg);
101144bf2312SRitesh Harjani 		config |= CORE_CMDIN_RCLK_EN;
1012bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
1013bc99266bSSayali Lokhande 				msm_offset->core_ddr_200_cfg);
101444bf2312SRitesh Harjani 	}
101544bf2312SRitesh Harjani 
1016bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2);
101702e4293dSRitesh Harjani 	config |= CORE_DDR_CAL_EN;
1018bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config_2);
101902e4293dSRitesh Harjani 
1020bc99266bSSayali Lokhande 	ret = readl_relaxed_poll_timeout(host->ioaddr +
1021bc99266bSSayali Lokhande 					msm_offset->core_dll_status,
102202e4293dSRitesh Harjani 					dll_status,
102302e4293dSRitesh Harjani 					(dll_status & CORE_DDR_DLL_LOCK),
102402e4293dSRitesh Harjani 					10, 1000);
102502e4293dSRitesh Harjani 
102602e4293dSRitesh Harjani 	if (ret == -ETIMEDOUT) {
102702e4293dSRitesh Harjani 		pr_err("%s: %s: CM_DLL_SDC4 calibration was not completed\n",
102802e4293dSRitesh Harjani 		       mmc_hostname(host->mmc), __func__);
102902e4293dSRitesh Harjani 		goto out;
103002e4293dSRitesh Harjani 	}
103102e4293dSRitesh Harjani 
1032219c02caSRitesh Harjani 	/*
1033219c02caSRitesh Harjani 	 * Set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3.
1034219c02caSRitesh Harjani 	 * When MCLK is gated OFF, it is not gated for less than 0.5us
1035219c02caSRitesh Harjani 	 * and MCLK must be switched on for at-least 1us before DATA
1036219c02caSRitesh Harjani 	 * starts coming. Controllers with 14lpp and later tech DLL cannot
1037219c02caSRitesh Harjani 	 * guarantee above requirement. So PWRSAVE_DLL should not be
1038219c02caSRitesh Harjani 	 * turned on for host controllers using this DLL.
1039219c02caSRitesh Harjani 	 */
1040219c02caSRitesh Harjani 	if (!msm_host->use_14lpp_dll_reset) {
1041219c02caSRitesh Harjani 		config = readl_relaxed(host->ioaddr +
1042219c02caSRitesh Harjani 				msm_offset->core_vendor_spec3);
104302e4293dSRitesh Harjani 		config |= CORE_PWRSAVE_DLL;
1044219c02caSRitesh Harjani 		writel_relaxed(config, host->ioaddr +
1045219c02caSRitesh Harjani 				msm_offset->core_vendor_spec3);
1046219c02caSRitesh Harjani 	}
104702e4293dSRitesh Harjani 
104802e4293dSRitesh Harjani 	/*
104902e4293dSRitesh Harjani 	 * Drain writebuffer to ensure above DLL calibration
105002e4293dSRitesh Harjani 	 * and PWRSAVE DLL is enabled.
105102e4293dSRitesh Harjani 	 */
105202e4293dSRitesh Harjani 	wmb();
105302e4293dSRitesh Harjani out:
105402e4293dSRitesh Harjani 	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
105502e4293dSRitesh Harjani 		 __func__, ret);
105602e4293dSRitesh Harjani 	return ret;
105702e4293dSRitesh Harjani }
105802e4293dSRitesh Harjani 
105902e4293dSRitesh Harjani static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
106002e4293dSRitesh Harjani {
106102e4293dSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
106202e4293dSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
106344bf2312SRitesh Harjani 	struct mmc_host *mmc = host->mmc;
106402e4293dSRitesh Harjani 	int ret;
106502e4293dSRitesh Harjani 	u32 config;
1066bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1067bc99266bSSayali Lokhande 					msm_host->offset;
106802e4293dSRitesh Harjani 
106902e4293dSRitesh Harjani 	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
107002e4293dSRitesh Harjani 
107102e4293dSRitesh Harjani 	/*
107202e4293dSRitesh Harjani 	 * Retuning in HS400 (DDR mode) will fail, just reset the
107302e4293dSRitesh Harjani 	 * tuning block and restore the saved tuning phase.
107402e4293dSRitesh Harjani 	 */
107502e4293dSRitesh Harjani 	ret = msm_init_cm_dll(host);
107602e4293dSRitesh Harjani 	if (ret)
107702e4293dSRitesh Harjani 		goto out;
107802e4293dSRitesh Harjani 
107944bf2312SRitesh Harjani 	if (!mmc->ios.enhanced_strobe) {
108002e4293dSRitesh Harjani 		/* Set the selected phase in delay line hw block */
108144bf2312SRitesh Harjani 		ret = msm_config_cm_dll_phase(host,
108244bf2312SRitesh Harjani 					      msm_host->saved_tuning_phase);
108302e4293dSRitesh Harjani 		if (ret)
108402e4293dSRitesh Harjani 			goto out;
1085bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1086bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
108702e4293dSRitesh Harjani 		config |= CORE_CMD_DAT_TRACK_SEL;
1088bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
1089bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
109044bf2312SRitesh Harjani 	}
109144bf2312SRitesh Harjani 
109202e4293dSRitesh Harjani 	if (msm_host->use_cdclp533)
109302e4293dSRitesh Harjani 		ret = sdhci_msm_cdclp533_calibration(host);
109402e4293dSRitesh Harjani 	else
109502e4293dSRitesh Harjani 		ret = sdhci_msm_cm_dll_sdc4_calibration(host);
109602e4293dSRitesh Harjani out:
109702e4293dSRitesh Harjani 	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
109802e4293dSRitesh Harjani 		 __func__, ret);
109902e4293dSRitesh Harjani 	return ret;
110002e4293dSRitesh Harjani }
110102e4293dSRitesh Harjani 
110221f1e2d4SVeerabhadrarao Badiganti static bool sdhci_msm_is_tuning_needed(struct sdhci_host *host)
110321f1e2d4SVeerabhadrarao Badiganti {
110421f1e2d4SVeerabhadrarao Badiganti 	struct mmc_ios *ios = &host->mmc->ios;
110521f1e2d4SVeerabhadrarao Badiganti 
110621f1e2d4SVeerabhadrarao Badiganti 	/*
110721f1e2d4SVeerabhadrarao Badiganti 	 * Tuning is required for SDR104, HS200 and HS400 cards and
110821f1e2d4SVeerabhadrarao Badiganti 	 * if clock frequency is greater than 100MHz in these modes.
110921f1e2d4SVeerabhadrarao Badiganti 	 */
111021f1e2d4SVeerabhadrarao Badiganti 	if (host->clock <= CORE_FREQ_100MHZ ||
111121f1e2d4SVeerabhadrarao Badiganti 	    !(ios->timing == MMC_TIMING_MMC_HS400 ||
111221f1e2d4SVeerabhadrarao Badiganti 	    ios->timing == MMC_TIMING_MMC_HS200 ||
111321f1e2d4SVeerabhadrarao Badiganti 	    ios->timing == MMC_TIMING_UHS_SDR104) ||
111421f1e2d4SVeerabhadrarao Badiganti 	    ios->enhanced_strobe)
111521f1e2d4SVeerabhadrarao Badiganti 		return false;
111621f1e2d4SVeerabhadrarao Badiganti 
111721f1e2d4SVeerabhadrarao Badiganti 	return true;
111821f1e2d4SVeerabhadrarao Badiganti }
111921f1e2d4SVeerabhadrarao Badiganti 
112021f1e2d4SVeerabhadrarao Badiganti static int sdhci_msm_restore_sdr_dll_config(struct sdhci_host *host)
112121f1e2d4SVeerabhadrarao Badiganti {
112221f1e2d4SVeerabhadrarao Badiganti 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
112321f1e2d4SVeerabhadrarao Badiganti 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
112421f1e2d4SVeerabhadrarao Badiganti 	int ret;
112521f1e2d4SVeerabhadrarao Badiganti 
112621f1e2d4SVeerabhadrarao Badiganti 	/*
112721f1e2d4SVeerabhadrarao Badiganti 	 * SDR DLL comes into picture only for timing modes which needs
112821f1e2d4SVeerabhadrarao Badiganti 	 * tuning.
112921f1e2d4SVeerabhadrarao Badiganti 	 */
113021f1e2d4SVeerabhadrarao Badiganti 	if (!sdhci_msm_is_tuning_needed(host))
113121f1e2d4SVeerabhadrarao Badiganti 		return 0;
113221f1e2d4SVeerabhadrarao Badiganti 
113321f1e2d4SVeerabhadrarao Badiganti 	/* Reset the tuning block */
113421f1e2d4SVeerabhadrarao Badiganti 	ret = msm_init_cm_dll(host);
113521f1e2d4SVeerabhadrarao Badiganti 	if (ret)
113621f1e2d4SVeerabhadrarao Badiganti 		return ret;
113721f1e2d4SVeerabhadrarao Badiganti 
113821f1e2d4SVeerabhadrarao Badiganti 	/* Restore the tuning block */
113921f1e2d4SVeerabhadrarao Badiganti 	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
114021f1e2d4SVeerabhadrarao Badiganti 
114121f1e2d4SVeerabhadrarao Badiganti 	return ret;
114221f1e2d4SVeerabhadrarao Badiganti }
114321f1e2d4SVeerabhadrarao Badiganti 
1144a89e7bcbSLoic Poulain static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable)
1145a89e7bcbSLoic Poulain {
1146a89e7bcbSLoic Poulain 	const struct sdhci_msm_offset *msm_offset = sdhci_priv_msm_offset(host);
1147a89e7bcbSLoic Poulain 	u32 config, oldconfig = readl_relaxed(host->ioaddr +
1148a89e7bcbSLoic Poulain 					      msm_offset->core_dll_config);
1149a89e7bcbSLoic Poulain 
1150a89e7bcbSLoic Poulain 	config = oldconfig;
1151a89e7bcbSLoic Poulain 	if (enable) {
1152a89e7bcbSLoic Poulain 		config |= CORE_CDR_EN;
1153a89e7bcbSLoic Poulain 		config &= ~CORE_CDR_EXT_EN;
1154a89e7bcbSLoic Poulain 	} else {
1155a89e7bcbSLoic Poulain 		config &= ~CORE_CDR_EN;
1156a89e7bcbSLoic Poulain 		config |= CORE_CDR_EXT_EN;
1157a89e7bcbSLoic Poulain 	}
1158a89e7bcbSLoic Poulain 
1159a89e7bcbSLoic Poulain 	if (config != oldconfig) {
1160a89e7bcbSLoic Poulain 		writel_relaxed(config, host->ioaddr +
1161a89e7bcbSLoic Poulain 			       msm_offset->core_dll_config);
1162a89e7bcbSLoic Poulain 	}
1163a89e7bcbSLoic Poulain }
1164a89e7bcbSLoic Poulain 
11654436c535SRitesh Harjani static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
11660eb0d9f4SGeorgi Djakov {
11674436c535SRitesh Harjani 	struct sdhci_host *host = mmc_priv(mmc);
1168415b5a75SGeorgi Djakov 	int tuning_seq_cnt = 3;
116933d73935SUlf Hansson 	u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
1170415b5a75SGeorgi Djakov 	int rc;
1171415b5a75SGeorgi Djakov 	struct mmc_ios ios = host->mmc->ios;
1172abf270e5SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1173abf270e5SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1174415b5a75SGeorgi Djakov 
1175a89e7bcbSLoic Poulain 	if (!sdhci_msm_is_tuning_needed(host)) {
1176a89e7bcbSLoic Poulain 		msm_host->use_cdr = false;
1177a89e7bcbSLoic Poulain 		sdhci_msm_set_cdr(host, false);
11780eb0d9f4SGeorgi Djakov 		return 0;
1179a89e7bcbSLoic Poulain 	}
1180a89e7bcbSLoic Poulain 
1181a89e7bcbSLoic Poulain 	/* Clock-Data-Recovery used to dynamically adjust RX sampling point */
1182a89e7bcbSLoic Poulain 	msm_host->use_cdr = true;
1183415b5a75SGeorgi Djakov 
1184d7507aa1SRitesh Harjani 	/*
11859253d710SVeerabhadrarao Badiganti 	 * Clear tuning_done flag before tuning to ensure proper
11869253d710SVeerabhadrarao Badiganti 	 * HS400 settings.
11879253d710SVeerabhadrarao Badiganti 	 */
11889253d710SVeerabhadrarao Badiganti 	msm_host->tuning_done = 0;
11899253d710SVeerabhadrarao Badiganti 
11909253d710SVeerabhadrarao Badiganti 	/*
1191d7507aa1SRitesh Harjani 	 * For HS400 tuning in HS200 timing requires:
1192d7507aa1SRitesh Harjani 	 * - select MCLK/2 in VENDOR_SPEC
1193d7507aa1SRitesh Harjani 	 * - program MCLK to 400MHz (or nearest supported) in GCC
1194d7507aa1SRitesh Harjani 	 */
1195d7507aa1SRitesh Harjani 	if (host->flags & SDHCI_HS400_TUNING) {
1196d7507aa1SRitesh Harjani 		sdhci_msm_hc_select_mode(host);
1197d7507aa1SRitesh Harjani 		msm_set_clock_rate_for_bus_mode(host, ios.clock);
11984436c535SRitesh Harjani 		host->flags &= ~SDHCI_HS400_TUNING;
1199d7507aa1SRitesh Harjani 	}
1200d7507aa1SRitesh Harjani 
1201415b5a75SGeorgi Djakov retry:
1202415b5a75SGeorgi Djakov 	/* First of all reset the tuning block */
1203415b5a75SGeorgi Djakov 	rc = msm_init_cm_dll(host);
1204415b5a75SGeorgi Djakov 	if (rc)
120533d73935SUlf Hansson 		return rc;
1206415b5a75SGeorgi Djakov 
1207415b5a75SGeorgi Djakov 	phase = 0;
1208415b5a75SGeorgi Djakov 	do {
1209415b5a75SGeorgi Djakov 		/* Set the phase in delay line hw block */
1210415b5a75SGeorgi Djakov 		rc = msm_config_cm_dll_phase(host, phase);
1211415b5a75SGeorgi Djakov 		if (rc)
121233d73935SUlf Hansson 			return rc;
1213415b5a75SGeorgi Djakov 
12149979dbe5SChaotian Jing 		rc = mmc_send_tuning(mmc, opcode, NULL);
121533d73935SUlf Hansson 		if (!rc) {
1216415b5a75SGeorgi Djakov 			/* Tuning is successful at this tuning point */
1217415b5a75SGeorgi Djakov 			tuned_phases[tuned_phase_cnt++] = phase;
1218415b5a75SGeorgi Djakov 			dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
1219415b5a75SGeorgi Djakov 				 mmc_hostname(mmc), phase);
1220415b5a75SGeorgi Djakov 		}
1221415b5a75SGeorgi Djakov 	} while (++phase < ARRAY_SIZE(tuned_phases));
1222415b5a75SGeorgi Djakov 
1223415b5a75SGeorgi Djakov 	if (tuned_phase_cnt) {
1224415b5a75SGeorgi Djakov 		rc = msm_find_most_appropriate_phase(host, tuned_phases,
1225415b5a75SGeorgi Djakov 						     tuned_phase_cnt);
1226415b5a75SGeorgi Djakov 		if (rc < 0)
122733d73935SUlf Hansson 			return rc;
1228415b5a75SGeorgi Djakov 		else
1229415b5a75SGeorgi Djakov 			phase = rc;
1230415b5a75SGeorgi Djakov 
1231415b5a75SGeorgi Djakov 		/*
1232415b5a75SGeorgi Djakov 		 * Finally set the selected phase in delay
1233415b5a75SGeorgi Djakov 		 * line hw block.
1234415b5a75SGeorgi Djakov 		 */
1235415b5a75SGeorgi Djakov 		rc = msm_config_cm_dll_phase(host, phase);
1236415b5a75SGeorgi Djakov 		if (rc)
123733d73935SUlf Hansson 			return rc;
123821f1e2d4SVeerabhadrarao Badiganti 		msm_host->saved_tuning_phase = phase;
1239415b5a75SGeorgi Djakov 		dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
1240415b5a75SGeorgi Djakov 			 mmc_hostname(mmc), phase);
1241415b5a75SGeorgi Djakov 	} else {
1242415b5a75SGeorgi Djakov 		if (--tuning_seq_cnt)
1243415b5a75SGeorgi Djakov 			goto retry;
1244415b5a75SGeorgi Djakov 		/* Tuning failed */
1245415b5a75SGeorgi Djakov 		dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
1246415b5a75SGeorgi Djakov 		       mmc_hostname(mmc));
1247415b5a75SGeorgi Djakov 		rc = -EIO;
1248415b5a75SGeorgi Djakov 	}
1249415b5a75SGeorgi Djakov 
1250ff06ce41SVenkat Gopalakrishnan 	if (!rc)
1251ff06ce41SVenkat Gopalakrishnan 		msm_host->tuning_done = true;
1252415b5a75SGeorgi Djakov 	return rc;
12530eb0d9f4SGeorgi Djakov }
12540eb0d9f4SGeorgi Djakov 
1255db9bd163SRitesh Harjani /*
1256db9bd163SRitesh Harjani  * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation.
125744bf2312SRitesh Harjani  * This needs to be done for both tuning and enhanced_strobe mode.
1258db9bd163SRitesh Harjani  * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz
1259db9bd163SRitesh Harjani  * fixed feedback clock is used.
1260db9bd163SRitesh Harjani  */
1261db9bd163SRitesh Harjani static void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios)
1262db9bd163SRitesh Harjani {
1263db9bd163SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1264db9bd163SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1265db9bd163SRitesh Harjani 	int ret;
1266db9bd163SRitesh Harjani 
1267db9bd163SRitesh Harjani 	if (host->clock > CORE_FREQ_100MHZ &&
126844bf2312SRitesh Harjani 	    (msm_host->tuning_done || ios->enhanced_strobe) &&
126944bf2312SRitesh Harjani 	    !msm_host->calibration_done) {
1270db9bd163SRitesh Harjani 		ret = sdhci_msm_hs400_dll_calibration(host);
1271db9bd163SRitesh Harjani 		if (!ret)
1272db9bd163SRitesh Harjani 			msm_host->calibration_done = true;
1273db9bd163SRitesh Harjani 		else
1274db9bd163SRitesh Harjani 			pr_err("%s: Failed to calibrate DLL for hs400 mode (%d)\n",
1275db9bd163SRitesh Harjani 			       mmc_hostname(host->mmc), ret);
1276db9bd163SRitesh Harjani 	}
1277db9bd163SRitesh Harjani }
1278db9bd163SRitesh Harjani 
1279ee320674SRitesh Harjani static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
1280ee320674SRitesh Harjani 					unsigned int uhs)
1281ee320674SRitesh Harjani {
1282ee320674SRitesh Harjani 	struct mmc_host *mmc = host->mmc;
1283ff06ce41SVenkat Gopalakrishnan 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1284ff06ce41SVenkat Gopalakrishnan 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1285ee320674SRitesh Harjani 	u16 ctrl_2;
1286ff06ce41SVenkat Gopalakrishnan 	u32 config;
1287bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1288bc99266bSSayali Lokhande 					msm_host->offset;
1289ee320674SRitesh Harjani 
1290ee320674SRitesh Harjani 	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
1291ee320674SRitesh Harjani 	/* Select Bus Speed Mode for host */
1292ee320674SRitesh Harjani 	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
1293ee320674SRitesh Harjani 	switch (uhs) {
1294ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR12:
1295ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
1296ee320674SRitesh Harjani 		break;
1297ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR25:
1298ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
1299ee320674SRitesh Harjani 		break;
1300ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR50:
1301ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
1302ee320674SRitesh Harjani 		break;
1303ff06ce41SVenkat Gopalakrishnan 	case MMC_TIMING_MMC_HS400:
1304ee320674SRitesh Harjani 	case MMC_TIMING_MMC_HS200:
1305ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR104:
1306ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
1307ee320674SRitesh Harjani 		break;
1308ee320674SRitesh Harjani 	case MMC_TIMING_UHS_DDR50:
1309ee320674SRitesh Harjani 	case MMC_TIMING_MMC_DDR52:
1310ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
1311ee320674SRitesh Harjani 		break;
1312ee320674SRitesh Harjani 	}
1313ee320674SRitesh Harjani 
1314ee320674SRitesh Harjani 	/*
1315ee320674SRitesh Harjani 	 * When clock frequency is less than 100MHz, the feedback clock must be
1316ee320674SRitesh Harjani 	 * provided and DLL must not be used so that tuning can be skipped. To
1317ee320674SRitesh Harjani 	 * provide feedback clock, the mode selection can be any value less
1318ee320674SRitesh Harjani 	 * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
1319ee320674SRitesh Harjani 	 */
1320ff06ce41SVenkat Gopalakrishnan 	if (host->clock <= CORE_FREQ_100MHZ) {
1321ff06ce41SVenkat Gopalakrishnan 		if (uhs == MMC_TIMING_MMC_HS400 ||
1322ee320674SRitesh Harjani 		    uhs == MMC_TIMING_MMC_HS200 ||
1323ff06ce41SVenkat Gopalakrishnan 		    uhs == MMC_TIMING_UHS_SDR104)
1324ee320674SRitesh Harjani 			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
1325ff06ce41SVenkat Gopalakrishnan 		/*
1326ff06ce41SVenkat Gopalakrishnan 		 * DLL is not required for clock <= 100MHz
1327ff06ce41SVenkat Gopalakrishnan 		 * Thus, make sure DLL it is disabled when not required
1328ff06ce41SVenkat Gopalakrishnan 		 */
1329bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1330bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1331ff06ce41SVenkat Gopalakrishnan 		config |= CORE_DLL_RST;
1332bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
1333bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1334ff06ce41SVenkat Gopalakrishnan 
1335bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1336bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1337ff06ce41SVenkat Gopalakrishnan 		config |= CORE_DLL_PDN;
1338bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
1339bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1340ff06ce41SVenkat Gopalakrishnan 
1341ff06ce41SVenkat Gopalakrishnan 		/*
1342ff06ce41SVenkat Gopalakrishnan 		 * The DLL needs to be restored and CDCLP533 recalibrated
1343ff06ce41SVenkat Gopalakrishnan 		 * when the clock frequency is set back to 400MHz.
1344ff06ce41SVenkat Gopalakrishnan 		 */
1345ff06ce41SVenkat Gopalakrishnan 		msm_host->calibration_done = false;
1346ff06ce41SVenkat Gopalakrishnan 	}
1347ee320674SRitesh Harjani 
1348ee320674SRitesh Harjani 	dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
1349ee320674SRitesh Harjani 		mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
1350ee320674SRitesh Harjani 	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
1351cc392c58SRitesh Harjani 
1352db9bd163SRitesh Harjani 	if (mmc->ios.timing == MMC_TIMING_MMC_HS400)
1353db9bd163SRitesh Harjani 		sdhci_msm_hs400(host, &mmc->ios);
1354ee320674SRitesh Harjani }
1355ee320674SRitesh Harjani 
135692a21738SVeerabhadrarao Badiganti static int sdhci_msm_set_vmmc(struct mmc_host *mmc)
135792a21738SVeerabhadrarao Badiganti {
135892a21738SVeerabhadrarao Badiganti 	if (IS_ERR(mmc->supply.vmmc))
135992a21738SVeerabhadrarao Badiganti 		return 0;
136092a21738SVeerabhadrarao Badiganti 
136192a21738SVeerabhadrarao Badiganti 	return mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, mmc->ios.vdd);
136292a21738SVeerabhadrarao Badiganti }
136392a21738SVeerabhadrarao Badiganti 
136492a21738SVeerabhadrarao Badiganti static int msm_toggle_vqmmc(struct sdhci_msm_host *msm_host,
136592a21738SVeerabhadrarao Badiganti 			      struct mmc_host *mmc, bool level)
136692a21738SVeerabhadrarao Badiganti {
136792a21738SVeerabhadrarao Badiganti 	int ret;
136892a21738SVeerabhadrarao Badiganti 	struct mmc_ios ios;
136992a21738SVeerabhadrarao Badiganti 
137092a21738SVeerabhadrarao Badiganti 	if (msm_host->vqmmc_enabled == level)
137192a21738SVeerabhadrarao Badiganti 		return 0;
137292a21738SVeerabhadrarao Badiganti 
137392a21738SVeerabhadrarao Badiganti 	if (level) {
137492a21738SVeerabhadrarao Badiganti 		/* Set the IO voltage regulator to default voltage level */
137592a21738SVeerabhadrarao Badiganti 		if (msm_host->caps_0 & CORE_3_0V_SUPPORT)
137692a21738SVeerabhadrarao Badiganti 			ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330;
137792a21738SVeerabhadrarao Badiganti 		else if (msm_host->caps_0 & CORE_1_8V_SUPPORT)
137892a21738SVeerabhadrarao Badiganti 			ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180;
137992a21738SVeerabhadrarao Badiganti 
138092a21738SVeerabhadrarao Badiganti 		if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
138192a21738SVeerabhadrarao Badiganti 			ret = mmc_regulator_set_vqmmc(mmc, &ios);
138292a21738SVeerabhadrarao Badiganti 			if (ret < 0) {
138392a21738SVeerabhadrarao Badiganti 				dev_err(mmc_dev(mmc), "%s: vqmmc set volgate failed: %d\n",
138492a21738SVeerabhadrarao Badiganti 					mmc_hostname(mmc), ret);
138592a21738SVeerabhadrarao Badiganti 				goto out;
138692a21738SVeerabhadrarao Badiganti 			}
138792a21738SVeerabhadrarao Badiganti 		}
138892a21738SVeerabhadrarao Badiganti 		ret = regulator_enable(mmc->supply.vqmmc);
138992a21738SVeerabhadrarao Badiganti 	} else {
139092a21738SVeerabhadrarao Badiganti 		ret = regulator_disable(mmc->supply.vqmmc);
139192a21738SVeerabhadrarao Badiganti 	}
139292a21738SVeerabhadrarao Badiganti 
139392a21738SVeerabhadrarao Badiganti 	if (ret)
139492a21738SVeerabhadrarao Badiganti 		dev_err(mmc_dev(mmc), "%s: vqmm %sable failed: %d\n",
139592a21738SVeerabhadrarao Badiganti 			mmc_hostname(mmc), level ? "en":"dis", ret);
139692a21738SVeerabhadrarao Badiganti 	else
139792a21738SVeerabhadrarao Badiganti 		msm_host->vqmmc_enabled = level;
139892a21738SVeerabhadrarao Badiganti out:
139992a21738SVeerabhadrarao Badiganti 	return ret;
140092a21738SVeerabhadrarao Badiganti }
140192a21738SVeerabhadrarao Badiganti 
140292a21738SVeerabhadrarao Badiganti static int msm_config_vqmmc_mode(struct sdhci_msm_host *msm_host,
140392a21738SVeerabhadrarao Badiganti 			      struct mmc_host *mmc, bool hpm)
140492a21738SVeerabhadrarao Badiganti {
140592a21738SVeerabhadrarao Badiganti 	int load, ret;
140692a21738SVeerabhadrarao Badiganti 
140792a21738SVeerabhadrarao Badiganti 	load = hpm ? MMC_VQMMC_MAX_LOAD_UA : 0;
140892a21738SVeerabhadrarao Badiganti 	ret = regulator_set_load(mmc->supply.vqmmc, load);
140992a21738SVeerabhadrarao Badiganti 	if (ret)
141092a21738SVeerabhadrarao Badiganti 		dev_err(mmc_dev(mmc), "%s: vqmmc set load failed: %d\n",
141192a21738SVeerabhadrarao Badiganti 			mmc_hostname(mmc), ret);
141292a21738SVeerabhadrarao Badiganti 	return ret;
141392a21738SVeerabhadrarao Badiganti }
141492a21738SVeerabhadrarao Badiganti 
141592a21738SVeerabhadrarao Badiganti static int sdhci_msm_set_vqmmc(struct sdhci_msm_host *msm_host,
141692a21738SVeerabhadrarao Badiganti 			      struct mmc_host *mmc, bool level)
141792a21738SVeerabhadrarao Badiganti {
141892a21738SVeerabhadrarao Badiganti 	int ret;
141992a21738SVeerabhadrarao Badiganti 	bool always_on;
142092a21738SVeerabhadrarao Badiganti 
142192a21738SVeerabhadrarao Badiganti 	if (IS_ERR(mmc->supply.vqmmc) ||
142292a21738SVeerabhadrarao Badiganti 			(mmc->ios.power_mode == MMC_POWER_UNDEFINED))
142392a21738SVeerabhadrarao Badiganti 		return 0;
142492a21738SVeerabhadrarao Badiganti 	/*
142592a21738SVeerabhadrarao Badiganti 	 * For eMMC don't turn off Vqmmc, Instead just configure it in LPM
142692a21738SVeerabhadrarao Badiganti 	 * and HPM modes by setting the corresponding load.
142792a21738SVeerabhadrarao Badiganti 	 *
142892a21738SVeerabhadrarao Badiganti 	 * Till eMMC is initialized (i.e. always_on == 0), just turn on/off
142992a21738SVeerabhadrarao Badiganti 	 * Vqmmc. Vqmmc gets turned off only if init fails and mmc_power_off
143092a21738SVeerabhadrarao Badiganti 	 * gets invoked. Once eMMC is initialized (i.e. always_on == 1),
143192a21738SVeerabhadrarao Badiganti 	 * Vqmmc should remain ON, So just set the load instead of turning it
143292a21738SVeerabhadrarao Badiganti 	 * off/on.
143392a21738SVeerabhadrarao Badiganti 	 */
143492a21738SVeerabhadrarao Badiganti 	always_on = !mmc_card_is_removable(mmc) &&
143592a21738SVeerabhadrarao Badiganti 			mmc->card && mmc_card_mmc(mmc->card);
143692a21738SVeerabhadrarao Badiganti 
143792a21738SVeerabhadrarao Badiganti 	if (always_on)
143892a21738SVeerabhadrarao Badiganti 		ret = msm_config_vqmmc_mode(msm_host, mmc, level);
143992a21738SVeerabhadrarao Badiganti 	else
144092a21738SVeerabhadrarao Badiganti 		ret = msm_toggle_vqmmc(msm_host, mmc, level);
144192a21738SVeerabhadrarao Badiganti 
144292a21738SVeerabhadrarao Badiganti 	return ret;
144392a21738SVeerabhadrarao Badiganti }
144492a21738SVeerabhadrarao Badiganti 
1445c0309b38SVijay Viswanath static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
1446c0309b38SVijay Viswanath {
1447c0309b38SVijay Viswanath 	init_waitqueue_head(&msm_host->pwr_irq_wait);
1448c0309b38SVijay Viswanath }
1449c0309b38SVijay Viswanath 
1450c0309b38SVijay Viswanath static inline void sdhci_msm_complete_pwr_irq_wait(
1451c0309b38SVijay Viswanath 		struct sdhci_msm_host *msm_host)
1452c0309b38SVijay Viswanath {
1453c0309b38SVijay Viswanath 	wake_up(&msm_host->pwr_irq_wait);
1454c0309b38SVijay Viswanath }
1455c0309b38SVijay Viswanath 
1456c0309b38SVijay Viswanath /*
1457c0309b38SVijay Viswanath  * sdhci_msm_check_power_status API should be called when registers writes
1458c0309b38SVijay Viswanath  * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
1459c0309b38SVijay Viswanath  * To what state the register writes will change the IO lines should be passed
1460c0309b38SVijay Viswanath  * as the argument req_type. This API will check whether the IO line's state
1461c0309b38SVijay Viswanath  * is already the expected state and will wait for power irq only if
146227d8a86aSFlavio Suligoi  * power irq is expected to be triggered based on the current IO line state
1463c0309b38SVijay Viswanath  * and expected IO line state.
1464c0309b38SVijay Viswanath  */
1465c0309b38SVijay Viswanath static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
1466c0309b38SVijay Viswanath {
1467c0309b38SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1468c0309b38SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1469c0309b38SVijay Viswanath 	bool done = false;
1470bc99266bSSayali Lokhande 	u32 val = SWITCHABLE_SIGNALING_VOLTAGE;
1471bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1472bc99266bSSayali Lokhande 					msm_host->offset;
1473c0309b38SVijay Viswanath 
1474c0309b38SVijay Viswanath 	pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
1475c0309b38SVijay Viswanath 			mmc_hostname(host->mmc), __func__, req_type,
1476c0309b38SVijay Viswanath 			msm_host->curr_pwr_state, msm_host->curr_io_level);
1477c0309b38SVijay Viswanath 
1478c0309b38SVijay Viswanath 	/*
147952884f8fSBjorn Andersson 	 * The power interrupt will not be generated for signal voltage
148052884f8fSBjorn Andersson 	 * switches if SWITCHABLE_SIGNALING_VOLTAGE in MCI_GENERICS is not set.
1481bc99266bSSayali Lokhande 	 * Since sdhci-msm-v5, this bit has been removed and SW must consider
1482bc99266bSSayali Lokhande 	 * it as always set.
148352884f8fSBjorn Andersson 	 */
1484bc99266bSSayali Lokhande 	if (!msm_host->mci_removed)
1485bc99266bSSayali Lokhande 		val = msm_host_readl(msm_host, host,
1486bc99266bSSayali Lokhande 				msm_offset->core_generics);
148752884f8fSBjorn Andersson 	if ((req_type & REQ_IO_HIGH || req_type & REQ_IO_LOW) &&
148852884f8fSBjorn Andersson 	    !(val & SWITCHABLE_SIGNALING_VOLTAGE)) {
148952884f8fSBjorn Andersson 		return;
149052884f8fSBjorn Andersson 	}
149152884f8fSBjorn Andersson 
149252884f8fSBjorn Andersson 	/*
1493c0309b38SVijay Viswanath 	 * The IRQ for request type IO High/LOW will be generated when -
1494c0309b38SVijay Viswanath 	 * there is a state change in 1.8V enable bit (bit 3) of
1495c0309b38SVijay Viswanath 	 * SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
1496c0309b38SVijay Viswanath 	 * which indicates 3.3V IO voltage. So, when MMC core layer tries
1497c0309b38SVijay Viswanath 	 * to set it to 3.3V before card detection happens, the
1498c0309b38SVijay Viswanath 	 * IRQ doesn't get triggered as there is no state change in this bit.
1499c0309b38SVijay Viswanath 	 * The driver already handles this case by changing the IO voltage
1500c0309b38SVijay Viswanath 	 * level to high as part of controller power up sequence. Hence, check
1501c0309b38SVijay Viswanath 	 * for host->pwr to handle a case where IO voltage high request is
1502c0309b38SVijay Viswanath 	 * issued even before controller power up.
1503c0309b38SVijay Viswanath 	 */
1504c0309b38SVijay Viswanath 	if ((req_type & REQ_IO_HIGH) && !host->pwr) {
1505c0309b38SVijay Viswanath 		pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n",
1506c0309b38SVijay Viswanath 				mmc_hostname(host->mmc), req_type);
1507c0309b38SVijay Viswanath 		return;
1508c0309b38SVijay Viswanath 	}
1509c0309b38SVijay Viswanath 	if ((req_type & msm_host->curr_pwr_state) ||
1510c0309b38SVijay Viswanath 			(req_type & msm_host->curr_io_level))
1511c0309b38SVijay Viswanath 		done = true;
1512c0309b38SVijay Viswanath 	/*
1513c0309b38SVijay Viswanath 	 * This is needed here to handle cases where register writes will
1514c0309b38SVijay Viswanath 	 * not change the current bus state or io level of the controller.
1515c0309b38SVijay Viswanath 	 * In this case, no power irq will be triggerred and we should
1516c0309b38SVijay Viswanath 	 * not wait.
1517c0309b38SVijay Viswanath 	 */
1518c0309b38SVijay Viswanath 	if (!done) {
1519c0309b38SVijay Viswanath 		if (!wait_event_timeout(msm_host->pwr_irq_wait,
1520c0309b38SVijay Viswanath 				msm_host->pwr_irq_flag,
1521c0309b38SVijay Viswanath 				msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
15229ccfa817SArnd Bergmann 			dev_warn(&msm_host->pdev->dev,
15239ccfa817SArnd Bergmann 				 "%s: pwr_irq for req: (%d) timed out\n",
1524c0309b38SVijay Viswanath 				 mmc_hostname(host->mmc), req_type);
1525c0309b38SVijay Viswanath 	}
1526c0309b38SVijay Viswanath 	pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
1527c0309b38SVijay Viswanath 			__func__, req_type);
1528c0309b38SVijay Viswanath }
1529c0309b38SVijay Viswanath 
1530401b2d06SSahitya Tummala static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
1531401b2d06SSahitya Tummala {
1532401b2d06SSahitya Tummala 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1533401b2d06SSahitya Tummala 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1534bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1535bc99266bSSayali Lokhande 					msm_host->offset;
1536401b2d06SSahitya Tummala 
1537401b2d06SSahitya Tummala 	pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
1538401b2d06SSahitya Tummala 		mmc_hostname(host->mmc),
1539bc99266bSSayali Lokhande 		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_status),
1540bc99266bSSayali Lokhande 		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_mask),
1541bc99266bSSayali Lokhande 		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_ctl));
1542401b2d06SSahitya Tummala }
1543401b2d06SSahitya Tummala 
1544401b2d06SSahitya Tummala static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
1545ad81d387SGeorgi Djakov {
1546ad81d387SGeorgi Djakov 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1547ad81d387SGeorgi Djakov 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
154892a21738SVeerabhadrarao Badiganti 	struct mmc_host *mmc = host->mmc;
1549ad81d387SGeorgi Djakov 	u32 irq_status, irq_ack = 0;
155092a21738SVeerabhadrarao Badiganti 	int retry = 10, ret;
1551ac06fba1SVijay Viswanath 	u32 pwr_state = 0, io_level = 0;
15525c132323SVijay Viswanath 	u32 config;
1553bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
1554ad81d387SGeorgi Djakov 
1555bc99266bSSayali Lokhande 	irq_status = msm_host_readl(msm_host, host,
1556bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_status);
1557ad81d387SGeorgi Djakov 	irq_status &= INT_MASK;
1558ad81d387SGeorgi Djakov 
1559bc99266bSSayali Lokhande 	msm_host_writel(msm_host, irq_status, host,
1560bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_clear);
1561ad81d387SGeorgi Djakov 
1562401b2d06SSahitya Tummala 	/*
1563401b2d06SSahitya Tummala 	 * There is a rare HW scenario where the first clear pulse could be
1564401b2d06SSahitya Tummala 	 * lost when actual reset and clear/read of status register is
1565401b2d06SSahitya Tummala 	 * happening at a time. Hence, retry for at least 10 times to make
1566401b2d06SSahitya Tummala 	 * sure status register is cleared. Otherwise, this will result in
1567401b2d06SSahitya Tummala 	 * a spurious power IRQ resulting in system instability.
1568401b2d06SSahitya Tummala 	 */
1569bc99266bSSayali Lokhande 	while (irq_status & msm_host_readl(msm_host, host,
1570bc99266bSSayali Lokhande 				msm_offset->core_pwrctl_status)) {
1571401b2d06SSahitya Tummala 		if (retry == 0) {
1572401b2d06SSahitya Tummala 			pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
1573401b2d06SSahitya Tummala 					mmc_hostname(host->mmc), irq_status);
1574401b2d06SSahitya Tummala 			sdhci_msm_dump_pwr_ctrl_regs(host);
1575401b2d06SSahitya Tummala 			WARN_ON(1);
1576401b2d06SSahitya Tummala 			break;
1577401b2d06SSahitya Tummala 		}
1578bc99266bSSayali Lokhande 		msm_host_writel(msm_host, irq_status, host,
1579bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_clear);
1580401b2d06SSahitya Tummala 		retry--;
1581401b2d06SSahitya Tummala 		udelay(10);
1582401b2d06SSahitya Tummala 	}
1583401b2d06SSahitya Tummala 
1584c0309b38SVijay Viswanath 	/* Handle BUS ON/OFF*/
1585c0309b38SVijay Viswanath 	if (irq_status & CORE_PWRCTL_BUS_ON) {
1586c0309b38SVijay Viswanath 		pwr_state = REQ_BUS_ON;
1587c0309b38SVijay Viswanath 		io_level = REQ_IO_HIGH;
1588c0309b38SVijay Viswanath 	}
1589c0309b38SVijay Viswanath 	if (irq_status & CORE_PWRCTL_BUS_OFF) {
1590c0309b38SVijay Viswanath 		pwr_state = REQ_BUS_OFF;
1591c0309b38SVijay Viswanath 		io_level = REQ_IO_LOW;
159292a21738SVeerabhadrarao Badiganti 	}
159392a21738SVeerabhadrarao Badiganti 
159492a21738SVeerabhadrarao Badiganti 	if (pwr_state) {
159592a21738SVeerabhadrarao Badiganti 		ret = sdhci_msm_set_vmmc(mmc);
159692a21738SVeerabhadrarao Badiganti 		if (!ret)
159792a21738SVeerabhadrarao Badiganti 			ret = sdhci_msm_set_vqmmc(msm_host, mmc,
159892a21738SVeerabhadrarao Badiganti 					pwr_state & REQ_BUS_ON);
159992a21738SVeerabhadrarao Badiganti 		if (!ret)
1600c0309b38SVijay Viswanath 			irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
160192a21738SVeerabhadrarao Badiganti 		else
160292a21738SVeerabhadrarao Badiganti 			irq_ack |= CORE_PWRCTL_BUS_FAIL;
1603c0309b38SVijay Viswanath 	}
160492a21738SVeerabhadrarao Badiganti 
1605c0309b38SVijay Viswanath 	/* Handle IO LOW/HIGH */
160692a21738SVeerabhadrarao Badiganti 	if (irq_status & CORE_PWRCTL_IO_LOW)
1607c0309b38SVijay Viswanath 		io_level = REQ_IO_LOW;
160892a21738SVeerabhadrarao Badiganti 
160992a21738SVeerabhadrarao Badiganti 	if (irq_status & CORE_PWRCTL_IO_HIGH)
1610c0309b38SVijay Viswanath 		io_level = REQ_IO_HIGH;
161192a21738SVeerabhadrarao Badiganti 
161292a21738SVeerabhadrarao Badiganti 	if (io_level)
1613c0309b38SVijay Viswanath 		irq_ack |= CORE_PWRCTL_IO_SUCCESS;
161492a21738SVeerabhadrarao Badiganti 
161592a21738SVeerabhadrarao Badiganti 	if (io_level && !IS_ERR(mmc->supply.vqmmc) && !pwr_state) {
161692a21738SVeerabhadrarao Badiganti 		ret = mmc_regulator_set_vqmmc(mmc, &mmc->ios);
161792a21738SVeerabhadrarao Badiganti 		if (ret < 0) {
161892a21738SVeerabhadrarao Badiganti 			dev_err(mmc_dev(mmc), "%s: IO_level setting failed(%d). signal_voltage: %d, vdd: %d irq_status: 0x%08x\n",
161992a21738SVeerabhadrarao Badiganti 					mmc_hostname(mmc), ret,
162092a21738SVeerabhadrarao Badiganti 					mmc->ios.signal_voltage, mmc->ios.vdd,
162192a21738SVeerabhadrarao Badiganti 					irq_status);
162292a21738SVeerabhadrarao Badiganti 			irq_ack |= CORE_PWRCTL_IO_FAIL;
162392a21738SVeerabhadrarao Badiganti 		}
1624c0309b38SVijay Viswanath 	}
1625ad81d387SGeorgi Djakov 
1626ad81d387SGeorgi Djakov 	/*
1627ad81d387SGeorgi Djakov 	 * The driver has to acknowledge the interrupt, switch voltages and
1628ad81d387SGeorgi Djakov 	 * report back if it succeded or not to this register. The voltage
1629ad81d387SGeorgi Djakov 	 * switches are handled by the sdhci core, so just report success.
1630ad81d387SGeorgi Djakov 	 */
1631bc99266bSSayali Lokhande 	msm_host_writel(msm_host, irq_ack, host,
1632bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_ctl);
1633401b2d06SSahitya Tummala 
16345c132323SVijay Viswanath 	/*
16355c132323SVijay Viswanath 	 * If we don't have info regarding the voltage levels supported by
16365c132323SVijay Viswanath 	 * regulators, don't change the IO PAD PWR SWITCH.
16375c132323SVijay Viswanath 	 */
16385c132323SVijay Viswanath 	if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
16395c132323SVijay Viswanath 		u32 new_config;
16405c132323SVijay Viswanath 		/*
16415c132323SVijay Viswanath 		 * We should unset IO PAD PWR switch only if the register write
16425c132323SVijay Viswanath 		 * can set IO lines high and the regulator also switches to 3 V.
16435c132323SVijay Viswanath 		 * Else, we should keep the IO PAD PWR switch set.
16445c132323SVijay Viswanath 		 * This is applicable to certain targets where eMMC vccq supply
16455c132323SVijay Viswanath 		 * is only 1.8V. In such targets, even during REQ_IO_HIGH, the
16465c132323SVijay Viswanath 		 * IO PAD PWR switch must be kept set to reflect actual
16475c132323SVijay Viswanath 		 * regulator voltage. This way, during initialization of
16485c132323SVijay Viswanath 		 * controllers with only 1.8V, we will set the IO PAD bit
16495c132323SVijay Viswanath 		 * without waiting for a REQ_IO_LOW.
16505c132323SVijay Viswanath 		 */
1651bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1652bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
16535c132323SVijay Viswanath 		new_config = config;
16545c132323SVijay Viswanath 
16555c132323SVijay Viswanath 		if ((io_level & REQ_IO_HIGH) &&
16565c132323SVijay Viswanath 				(msm_host->caps_0 & CORE_3_0V_SUPPORT))
16575c132323SVijay Viswanath 			new_config &= ~CORE_IO_PAD_PWR_SWITCH;
16585c132323SVijay Viswanath 		else if ((io_level & REQ_IO_LOW) ||
16595c132323SVijay Viswanath 				(msm_host->caps_0 & CORE_1_8V_SUPPORT))
16605c132323SVijay Viswanath 			new_config |= CORE_IO_PAD_PWR_SWITCH;
16615c132323SVijay Viswanath 
16625c132323SVijay Viswanath 		if (config ^ new_config)
1663bc99266bSSayali Lokhande 			writel_relaxed(new_config, host->ioaddr +
1664bc99266bSSayali Lokhande 					msm_offset->core_vendor_spec);
16655c132323SVijay Viswanath 	}
16665c132323SVijay Viswanath 
1667c0309b38SVijay Viswanath 	if (pwr_state)
1668c0309b38SVijay Viswanath 		msm_host->curr_pwr_state = pwr_state;
1669c0309b38SVijay Viswanath 	if (io_level)
1670c0309b38SVijay Viswanath 		msm_host->curr_io_level = io_level;
1671c0309b38SVijay Viswanath 
167292a21738SVeerabhadrarao Badiganti 	dev_dbg(mmc_dev(mmc), "%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
1673401b2d06SSahitya Tummala 		mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
1674401b2d06SSahitya Tummala 		irq_ack);
1675ad81d387SGeorgi Djakov }
1676ad81d387SGeorgi Djakov 
1677ad81d387SGeorgi Djakov static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
1678ad81d387SGeorgi Djakov {
1679ad81d387SGeorgi Djakov 	struct sdhci_host *host = (struct sdhci_host *)data;
1680c0309b38SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1681c0309b38SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1682ad81d387SGeorgi Djakov 
1683401b2d06SSahitya Tummala 	sdhci_msm_handle_pwr_irq(host, irq);
1684c0309b38SVijay Viswanath 	msm_host->pwr_irq_flag = 1;
1685c0309b38SVijay Viswanath 	sdhci_msm_complete_pwr_irq_wait(msm_host);
1686c0309b38SVijay Viswanath 
1687ad81d387SGeorgi Djakov 
1688ad81d387SGeorgi Djakov 	return IRQ_HANDLED;
1689ad81d387SGeorgi Djakov }
1690ad81d387SGeorgi Djakov 
169180031bdeSRitesh Harjani static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host)
169280031bdeSRitesh Harjani {
169380031bdeSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
169480031bdeSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1695e4bf91f6SBjorn Andersson 	struct clk *core_clk = msm_host->bulk_clks[0].clk;
169680031bdeSRitesh Harjani 
1697e4bf91f6SBjorn Andersson 	return clk_round_rate(core_clk, ULONG_MAX);
169880031bdeSRitesh Harjani }
169980031bdeSRitesh Harjani 
170080031bdeSRitesh Harjani static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
170180031bdeSRitesh Harjani {
170280031bdeSRitesh Harjani 	return SDHCI_MSM_MIN_CLOCK;
170380031bdeSRitesh Harjani }
170480031bdeSRitesh Harjani 
1705edc609fdSRitesh Harjani /**
1706edc609fdSRitesh Harjani  * __sdhci_msm_set_clock - sdhci_msm clock control.
1707edc609fdSRitesh Harjani  *
1708edc609fdSRitesh Harjani  * Description:
1709edc609fdSRitesh Harjani  * MSM controller does not use internal divider and
1710edc609fdSRitesh Harjani  * instead directly control the GCC clock as per
1711edc609fdSRitesh Harjani  * HW recommendation.
1712edc609fdSRitesh Harjani  **/
171330de038dSMasahiro Yamada static void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
1714edc609fdSRitesh Harjani {
1715edc609fdSRitesh Harjani 	u16 clk;
1716edc609fdSRitesh Harjani 	/*
1717edc609fdSRitesh Harjani 	 * Keep actual_clock as zero -
1718edc609fdSRitesh Harjani 	 * - since there is no divider used so no need of having actual_clock.
1719edc609fdSRitesh Harjani 	 * - MSM controller uses SDCLK for data timeout calculation. If
1720edc609fdSRitesh Harjani 	 *   actual_clock is zero, host->clock is taken for calculation.
1721edc609fdSRitesh Harjani 	 */
1722edc609fdSRitesh Harjani 	host->mmc->actual_clock = 0;
1723edc609fdSRitesh Harjani 
1724edc609fdSRitesh Harjani 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
1725edc609fdSRitesh Harjani 
1726edc609fdSRitesh Harjani 	if (clock == 0)
1727edc609fdSRitesh Harjani 		return;
1728edc609fdSRitesh Harjani 
1729edc609fdSRitesh Harjani 	/*
1730edc609fdSRitesh Harjani 	 * MSM controller do not use clock divider.
1731edc609fdSRitesh Harjani 	 * Thus read SDHCI_CLOCK_CONTROL and only enable
1732edc609fdSRitesh Harjani 	 * clock with no divider value programmed.
1733edc609fdSRitesh Harjani 	 */
1734edc609fdSRitesh Harjani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
1735edc609fdSRitesh Harjani 	sdhci_enable_clk(host, clk);
1736edc609fdSRitesh Harjani }
1737edc609fdSRitesh Harjani 
1738edc609fdSRitesh Harjani /* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */
1739edc609fdSRitesh Harjani static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
1740edc609fdSRitesh Harjani {
1741edc609fdSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1742edc609fdSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1743edc609fdSRitesh Harjani 
1744edc609fdSRitesh Harjani 	if (!clock) {
1745edc609fdSRitesh Harjani 		msm_host->clk_rate = clock;
1746edc609fdSRitesh Harjani 		goto out;
1747edc609fdSRitesh Harjani 	}
1748edc609fdSRitesh Harjani 
1749b54aaa8aSRitesh Harjani 	sdhci_msm_hc_select_mode(host);
1750edc609fdSRitesh Harjani 
17510fb8a3d4SRitesh Harjani 	msm_set_clock_rate_for_bus_mode(host, clock);
1752edc609fdSRitesh Harjani out:
1753edc609fdSRitesh Harjani 	__sdhci_msm_set_clock(host, clock);
1754edc609fdSRitesh Harjani }
1755edc609fdSRitesh Harjani 
175687a8df0dSRitesh Harjani /*****************************************************************************\
175787a8df0dSRitesh Harjani  *                                                                           *
175887a8df0dSRitesh Harjani  * MSM Command Queue Engine (CQE)                                            *
175987a8df0dSRitesh Harjani  *                                                                           *
176087a8df0dSRitesh Harjani \*****************************************************************************/
176187a8df0dSRitesh Harjani 
176287a8df0dSRitesh Harjani static u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask)
176387a8df0dSRitesh Harjani {
176487a8df0dSRitesh Harjani 	int cmd_error = 0;
176587a8df0dSRitesh Harjani 	int data_error = 0;
176687a8df0dSRitesh Harjani 
176787a8df0dSRitesh Harjani 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
176887a8df0dSRitesh Harjani 		return intmask;
176987a8df0dSRitesh Harjani 
177087a8df0dSRitesh Harjani 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
177187a8df0dSRitesh Harjani 	return 0;
177287a8df0dSRitesh Harjani }
177387a8df0dSRitesh Harjani 
17749051db38SStephen Boyd static void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery)
177587a8df0dSRitesh Harjani {
177687a8df0dSRitesh Harjani 	struct sdhci_host *host = mmc_priv(mmc);
177787a8df0dSRitesh Harjani 	unsigned long flags;
177887a8df0dSRitesh Harjani 	u32 ctrl;
177987a8df0dSRitesh Harjani 
178087a8df0dSRitesh Harjani 	/*
178187a8df0dSRitesh Harjani 	 * When CQE is halted, the legacy SDHCI path operates only
178287a8df0dSRitesh Harjani 	 * on 16-byte descriptors in 64bit mode.
178387a8df0dSRitesh Harjani 	 */
178487a8df0dSRitesh Harjani 	if (host->flags & SDHCI_USE_64_BIT_DMA)
178587a8df0dSRitesh Harjani 		host->desc_sz = 16;
178687a8df0dSRitesh Harjani 
178787a8df0dSRitesh Harjani 	spin_lock_irqsave(&host->lock, flags);
178887a8df0dSRitesh Harjani 
178987a8df0dSRitesh Harjani 	/*
179087a8df0dSRitesh Harjani 	 * During CQE command transfers, command complete bit gets latched.
179187a8df0dSRitesh Harjani 	 * So s/w should clear command complete interrupt status when CQE is
179287a8df0dSRitesh Harjani 	 * either halted or disabled. Otherwise unexpected SDCHI legacy
179387a8df0dSRitesh Harjani 	 * interrupt gets triggered when CQE is halted/disabled.
179487a8df0dSRitesh Harjani 	 */
179587a8df0dSRitesh Harjani 	ctrl = sdhci_readl(host, SDHCI_INT_ENABLE);
179687a8df0dSRitesh Harjani 	ctrl |= SDHCI_INT_RESPONSE;
179787a8df0dSRitesh Harjani 	sdhci_writel(host,  ctrl, SDHCI_INT_ENABLE);
179887a8df0dSRitesh Harjani 	sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
179987a8df0dSRitesh Harjani 
180087a8df0dSRitesh Harjani 	spin_unlock_irqrestore(&host->lock, flags);
180187a8df0dSRitesh Harjani 
180287a8df0dSRitesh Harjani 	sdhci_cqe_disable(mmc, recovery);
180387a8df0dSRitesh Harjani }
180487a8df0dSRitesh Harjani 
180587a8df0dSRitesh Harjani static const struct cqhci_host_ops sdhci_msm_cqhci_ops = {
180687a8df0dSRitesh Harjani 	.enable		= sdhci_cqe_enable,
180787a8df0dSRitesh Harjani 	.disable	= sdhci_msm_cqe_disable,
180887a8df0dSRitesh Harjani };
180987a8df0dSRitesh Harjani 
181087a8df0dSRitesh Harjani static int sdhci_msm_cqe_add_host(struct sdhci_host *host,
181187a8df0dSRitesh Harjani 				struct platform_device *pdev)
181287a8df0dSRitesh Harjani {
181387a8df0dSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
181487a8df0dSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
181587a8df0dSRitesh Harjani 	struct cqhci_host *cq_host;
181687a8df0dSRitesh Harjani 	bool dma64;
181787a8df0dSRitesh Harjani 	u32 cqcfg;
181887a8df0dSRitesh Harjani 	int ret;
181987a8df0dSRitesh Harjani 
182087a8df0dSRitesh Harjani 	/*
182187a8df0dSRitesh Harjani 	 * When CQE is halted, SDHC operates only on 16byte ADMA descriptors.
182287a8df0dSRitesh Harjani 	 * So ensure ADMA table is allocated for 16byte descriptors.
182387a8df0dSRitesh Harjani 	 */
182487a8df0dSRitesh Harjani 	if (host->caps & SDHCI_CAN_64BIT)
182587a8df0dSRitesh Harjani 		host->alloc_desc_sz = 16;
182687a8df0dSRitesh Harjani 
182787a8df0dSRitesh Harjani 	ret = sdhci_setup_host(host);
182887a8df0dSRitesh Harjani 	if (ret)
182987a8df0dSRitesh Harjani 		return ret;
183087a8df0dSRitesh Harjani 
183187a8df0dSRitesh Harjani 	cq_host = cqhci_pltfm_init(pdev);
183287a8df0dSRitesh Harjani 	if (IS_ERR(cq_host)) {
183387a8df0dSRitesh Harjani 		ret = PTR_ERR(cq_host);
183487a8df0dSRitesh Harjani 		dev_err(&pdev->dev, "cqhci-pltfm init: failed: %d\n", ret);
183587a8df0dSRitesh Harjani 		goto cleanup;
183687a8df0dSRitesh Harjani 	}
183787a8df0dSRitesh Harjani 
183887a8df0dSRitesh Harjani 	msm_host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
183987a8df0dSRitesh Harjani 	cq_host->ops = &sdhci_msm_cqhci_ops;
184087a8df0dSRitesh Harjani 
184187a8df0dSRitesh Harjani 	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
184287a8df0dSRitesh Harjani 
184387a8df0dSRitesh Harjani 	ret = cqhci_init(cq_host, host->mmc, dma64);
184487a8df0dSRitesh Harjani 	if (ret) {
184587a8df0dSRitesh Harjani 		dev_err(&pdev->dev, "%s: CQE init: failed (%d)\n",
184687a8df0dSRitesh Harjani 				mmc_hostname(host->mmc), ret);
184787a8df0dSRitesh Harjani 		goto cleanup;
184887a8df0dSRitesh Harjani 	}
184987a8df0dSRitesh Harjani 
185087a8df0dSRitesh Harjani 	/* Disable cqe reset due to cqe enable signal */
185187a8df0dSRitesh Harjani 	cqcfg = cqhci_readl(cq_host, CQHCI_VENDOR_CFG1);
185287a8df0dSRitesh Harjani 	cqcfg |= CQHCI_VENDOR_DIS_RST_ON_CQ_EN;
185387a8df0dSRitesh Harjani 	cqhci_writel(cq_host, cqcfg, CQHCI_VENDOR_CFG1);
185487a8df0dSRitesh Harjani 
185587a8df0dSRitesh Harjani 	/*
185687a8df0dSRitesh Harjani 	 * SDHC expects 12byte ADMA descriptors till CQE is enabled.
185787a8df0dSRitesh Harjani 	 * So limit desc_sz to 12 so that the data commands that are sent
185887a8df0dSRitesh Harjani 	 * during card initialization (before CQE gets enabled) would
185987a8df0dSRitesh Harjani 	 * get executed without any issues.
186087a8df0dSRitesh Harjani 	 */
186187a8df0dSRitesh Harjani 	if (host->flags & SDHCI_USE_64_BIT_DMA)
186287a8df0dSRitesh Harjani 		host->desc_sz = 12;
186387a8df0dSRitesh Harjani 
186487a8df0dSRitesh Harjani 	ret = __sdhci_add_host(host);
186587a8df0dSRitesh Harjani 	if (ret)
186687a8df0dSRitesh Harjani 		goto cleanup;
186787a8df0dSRitesh Harjani 
186887a8df0dSRitesh Harjani 	dev_info(&pdev->dev, "%s: CQE init: success\n",
186987a8df0dSRitesh Harjani 			mmc_hostname(host->mmc));
187087a8df0dSRitesh Harjani 	return ret;
187187a8df0dSRitesh Harjani 
187287a8df0dSRitesh Harjani cleanup:
187387a8df0dSRitesh Harjani 	sdhci_cleanup_host(host);
187487a8df0dSRitesh Harjani 	return ret;
187587a8df0dSRitesh Harjani }
187687a8df0dSRitesh Harjani 
1877c0309b38SVijay Viswanath /*
1878c0309b38SVijay Viswanath  * Platform specific register write functions. This is so that, if any
1879c0309b38SVijay Viswanath  * register write needs to be followed up by platform specific actions,
1880c0309b38SVijay Viswanath  * they can be added here. These functions can go to sleep when writes
1881c0309b38SVijay Viswanath  * to certain registers are done.
1882c0309b38SVijay Viswanath  * These functions are relying on sdhci_set_ios not using spinlock.
1883c0309b38SVijay Viswanath  */
1884c0309b38SVijay Viswanath static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
1885c0309b38SVijay Viswanath {
1886c0309b38SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1887c0309b38SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1888c0309b38SVijay Viswanath 	u32 req_type = 0;
1889c0309b38SVijay Viswanath 
1890c0309b38SVijay Viswanath 	switch (reg) {
1891c0309b38SVijay Viswanath 	case SDHCI_HOST_CONTROL2:
1892c0309b38SVijay Viswanath 		req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
1893c0309b38SVijay Viswanath 			REQ_IO_HIGH;
1894c0309b38SVijay Viswanath 		break;
1895c0309b38SVijay Viswanath 	case SDHCI_SOFTWARE_RESET:
1896c0309b38SVijay Viswanath 		if (host->pwr && (val & SDHCI_RESET_ALL))
1897c0309b38SVijay Viswanath 			req_type = REQ_BUS_OFF;
1898c0309b38SVijay Viswanath 		break;
1899c0309b38SVijay Viswanath 	case SDHCI_POWER_CONTROL:
1900c0309b38SVijay Viswanath 		req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
1901c0309b38SVijay Viswanath 		break;
1902a89e7bcbSLoic Poulain 	case SDHCI_TRANSFER_MODE:
1903a89e7bcbSLoic Poulain 		msm_host->transfer_mode = val;
1904a89e7bcbSLoic Poulain 		break;
1905a89e7bcbSLoic Poulain 	case SDHCI_COMMAND:
1906a89e7bcbSLoic Poulain 		if (!msm_host->use_cdr)
1907a89e7bcbSLoic Poulain 			break;
1908a89e7bcbSLoic Poulain 		if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
1909a89e7bcbSLoic Poulain 		    SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 &&
1910a89e7bcbSLoic Poulain 		    SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK)
1911a89e7bcbSLoic Poulain 			sdhci_msm_set_cdr(host, true);
1912a89e7bcbSLoic Poulain 		else
1913a89e7bcbSLoic Poulain 			sdhci_msm_set_cdr(host, false);
1914a89e7bcbSLoic Poulain 		break;
1915c0309b38SVijay Viswanath 	}
1916c0309b38SVijay Viswanath 
1917c0309b38SVijay Viswanath 	if (req_type) {
1918c0309b38SVijay Viswanath 		msm_host->pwr_irq_flag = 0;
1919c0309b38SVijay Viswanath 		/*
1920c0309b38SVijay Viswanath 		 * Since this register write may trigger a power irq, ensure
1921c0309b38SVijay Viswanath 		 * all previous register writes are complete by this point.
1922c0309b38SVijay Viswanath 		 */
1923c0309b38SVijay Viswanath 		mb();
1924c0309b38SVijay Viswanath 	}
1925c0309b38SVijay Viswanath 	return req_type;
1926c0309b38SVijay Viswanath }
1927c0309b38SVijay Viswanath 
1928c0309b38SVijay Viswanath /* This function may sleep*/
1929c0309b38SVijay Viswanath static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
1930c0309b38SVijay Viswanath {
1931c0309b38SVijay Viswanath 	u32 req_type = 0;
1932c0309b38SVijay Viswanath 
1933c0309b38SVijay Viswanath 	req_type = __sdhci_msm_check_write(host, val, reg);
1934c0309b38SVijay Viswanath 	writew_relaxed(val, host->ioaddr + reg);
1935c0309b38SVijay Viswanath 
1936c0309b38SVijay Viswanath 	if (req_type)
1937c0309b38SVijay Viswanath 		sdhci_msm_check_power_status(host, req_type);
1938c0309b38SVijay Viswanath }
1939c0309b38SVijay Viswanath 
1940c0309b38SVijay Viswanath /* This function may sleep*/
1941c0309b38SVijay Viswanath static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
1942c0309b38SVijay Viswanath {
1943c0309b38SVijay Viswanath 	u32 req_type = 0;
1944c0309b38SVijay Viswanath 
1945c0309b38SVijay Viswanath 	req_type = __sdhci_msm_check_write(host, val, reg);
1946c0309b38SVijay Viswanath 
1947c0309b38SVijay Viswanath 	writeb_relaxed(val, host->ioaddr + reg);
1948c0309b38SVijay Viswanath 
1949c0309b38SVijay Viswanath 	if (req_type)
1950c0309b38SVijay Viswanath 		sdhci_msm_check_power_status(host, req_type);
1951c0309b38SVijay Viswanath }
1952c0309b38SVijay Viswanath 
1953ac06fba1SVijay Viswanath static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)
1954ac06fba1SVijay Viswanath {
1955ac06fba1SVijay Viswanath 	struct mmc_host *mmc = msm_host->mmc;
1956ac06fba1SVijay Viswanath 	struct regulator *supply = mmc->supply.vqmmc;
19575c132323SVijay Viswanath 	u32 caps = 0, config;
19585c132323SVijay Viswanath 	struct sdhci_host *host = mmc_priv(mmc);
1959bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
1960ac06fba1SVijay Viswanath 
1961ac06fba1SVijay Viswanath 	if (!IS_ERR(mmc->supply.vqmmc)) {
1962ac06fba1SVijay Viswanath 		if (regulator_is_supported_voltage(supply, 1700000, 1950000))
1963ac06fba1SVijay Viswanath 			caps |= CORE_1_8V_SUPPORT;
1964ac06fba1SVijay Viswanath 		if (regulator_is_supported_voltage(supply, 2700000, 3600000))
1965ac06fba1SVijay Viswanath 			caps |= CORE_3_0V_SUPPORT;
1966ac06fba1SVijay Viswanath 
1967ac06fba1SVijay Viswanath 		if (!caps)
1968ac06fba1SVijay Viswanath 			pr_warn("%s: 1.8/3V not supported for vqmmc\n",
1969ac06fba1SVijay Viswanath 					mmc_hostname(mmc));
1970ac06fba1SVijay Viswanath 	}
1971ac06fba1SVijay Viswanath 
19725c132323SVijay Viswanath 	if (caps) {
19735c132323SVijay Viswanath 		/*
19745c132323SVijay Viswanath 		 * Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH
19755c132323SVijay Viswanath 		 * bit can be used as required later on.
19765c132323SVijay Viswanath 		 */
19775c132323SVijay Viswanath 		u32 io_level = msm_host->curr_io_level;
19785c132323SVijay Viswanath 
1979bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1980bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
19815c132323SVijay Viswanath 		config |= CORE_IO_PAD_PWR_SWITCH_EN;
19825c132323SVijay Viswanath 
19835c132323SVijay Viswanath 		if ((io_level & REQ_IO_HIGH) && (caps &	CORE_3_0V_SUPPORT))
19845c132323SVijay Viswanath 			config &= ~CORE_IO_PAD_PWR_SWITCH;
19855c132323SVijay Viswanath 		else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT))
19865c132323SVijay Viswanath 			config |= CORE_IO_PAD_PWR_SWITCH;
19875c132323SVijay Viswanath 
1988bc99266bSSayali Lokhande 		writel_relaxed(config,
1989bc99266bSSayali Lokhande 				host->ioaddr + msm_offset->core_vendor_spec);
19905c132323SVijay Viswanath 	}
1991ac06fba1SVijay Viswanath 	msm_host->caps_0 |= caps;
1992ac06fba1SVijay Viswanath 	pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
1993ac06fba1SVijay Viswanath }
1994ac06fba1SVijay Viswanath 
19955cf583f1SVeerabhadrarao Badiganti static void sdhci_msm_reset(struct sdhci_host *host, u8 mask)
19965cf583f1SVeerabhadrarao Badiganti {
19975cf583f1SVeerabhadrarao Badiganti 	if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL))
19985cf583f1SVeerabhadrarao Badiganti 		cqhci_deactivate(host->mmc);
19995cf583f1SVeerabhadrarao Badiganti 	sdhci_reset(host, mask);
20005cf583f1SVeerabhadrarao Badiganti }
20015cf583f1SVeerabhadrarao Badiganti 
200292a21738SVeerabhadrarao Badiganti static int sdhci_msm_register_vreg(struct sdhci_msm_host *msm_host)
200392a21738SVeerabhadrarao Badiganti {
200492a21738SVeerabhadrarao Badiganti 	int ret;
200592a21738SVeerabhadrarao Badiganti 
200692a21738SVeerabhadrarao Badiganti 	ret = mmc_regulator_get_supply(msm_host->mmc);
200792a21738SVeerabhadrarao Badiganti 	if (ret)
200892a21738SVeerabhadrarao Badiganti 		return ret;
200992a21738SVeerabhadrarao Badiganti 
201092a21738SVeerabhadrarao Badiganti 	sdhci_msm_set_regulator_caps(msm_host);
201192a21738SVeerabhadrarao Badiganti 
201292a21738SVeerabhadrarao Badiganti 	return 0;
201392a21738SVeerabhadrarao Badiganti }
201492a21738SVeerabhadrarao Badiganti 
201592a21738SVeerabhadrarao Badiganti static int sdhci_msm_start_signal_voltage_switch(struct mmc_host *mmc,
201692a21738SVeerabhadrarao Badiganti 				      struct mmc_ios *ios)
201792a21738SVeerabhadrarao Badiganti {
201892a21738SVeerabhadrarao Badiganti 	struct sdhci_host *host = mmc_priv(mmc);
201992a21738SVeerabhadrarao Badiganti 	u16 ctrl, status;
202092a21738SVeerabhadrarao Badiganti 
202192a21738SVeerabhadrarao Badiganti 	/*
202292a21738SVeerabhadrarao Badiganti 	 * Signal Voltage Switching is only applicable for Host Controllers
202392a21738SVeerabhadrarao Badiganti 	 * v3.00 and above.
202492a21738SVeerabhadrarao Badiganti 	 */
202592a21738SVeerabhadrarao Badiganti 	if (host->version < SDHCI_SPEC_300)
202692a21738SVeerabhadrarao Badiganti 		return 0;
202792a21738SVeerabhadrarao Badiganti 
202892a21738SVeerabhadrarao Badiganti 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
202992a21738SVeerabhadrarao Badiganti 
203092a21738SVeerabhadrarao Badiganti 	switch (ios->signal_voltage) {
203192a21738SVeerabhadrarao Badiganti 	case MMC_SIGNAL_VOLTAGE_330:
203292a21738SVeerabhadrarao Badiganti 		if (!(host->flags & SDHCI_SIGNALING_330))
203392a21738SVeerabhadrarao Badiganti 			return -EINVAL;
203492a21738SVeerabhadrarao Badiganti 
203592a21738SVeerabhadrarao Badiganti 		/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
203692a21738SVeerabhadrarao Badiganti 		ctrl &= ~SDHCI_CTRL_VDD_180;
203792a21738SVeerabhadrarao Badiganti 		break;
203892a21738SVeerabhadrarao Badiganti 	case MMC_SIGNAL_VOLTAGE_180:
203992a21738SVeerabhadrarao Badiganti 		if (!(host->flags & SDHCI_SIGNALING_180))
204092a21738SVeerabhadrarao Badiganti 			return -EINVAL;
204192a21738SVeerabhadrarao Badiganti 
204292a21738SVeerabhadrarao Badiganti 		/* Enable 1.8V Signal Enable in the Host Control2 register */
204392a21738SVeerabhadrarao Badiganti 		ctrl |= SDHCI_CTRL_VDD_180;
204492a21738SVeerabhadrarao Badiganti 		break;
204592a21738SVeerabhadrarao Badiganti 
204692a21738SVeerabhadrarao Badiganti 	default:
204792a21738SVeerabhadrarao Badiganti 		return -EINVAL;
204892a21738SVeerabhadrarao Badiganti 	}
204992a21738SVeerabhadrarao Badiganti 
205092a21738SVeerabhadrarao Badiganti 	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
205192a21738SVeerabhadrarao Badiganti 
205292a21738SVeerabhadrarao Badiganti 	/* Wait for 5ms */
205392a21738SVeerabhadrarao Badiganti 	usleep_range(5000, 5500);
205492a21738SVeerabhadrarao Badiganti 
205592a21738SVeerabhadrarao Badiganti 	/* regulator output should be stable within 5 ms */
205692a21738SVeerabhadrarao Badiganti 	status = ctrl & SDHCI_CTRL_VDD_180;
205792a21738SVeerabhadrarao Badiganti 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
205892a21738SVeerabhadrarao Badiganti 	if ((ctrl & SDHCI_CTRL_VDD_180) == status)
205992a21738SVeerabhadrarao Badiganti 		return 0;
206092a21738SVeerabhadrarao Badiganti 
206192a21738SVeerabhadrarao Badiganti 	dev_warn(mmc_dev(mmc), "%s: Regulator output did not became stable\n",
206292a21738SVeerabhadrarao Badiganti 		mmc_hostname(mmc));
206392a21738SVeerabhadrarao Badiganti 
206492a21738SVeerabhadrarao Badiganti 	return -EAGAIN;
206592a21738SVeerabhadrarao Badiganti }
206692a21738SVeerabhadrarao Badiganti 
206716d18d89SSarthak Garg #define DRIVER_NAME "sdhci_msm"
206816d18d89SSarthak Garg #define SDHCI_MSM_DUMP(f, x...) \
206916d18d89SSarthak Garg 	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
207016d18d89SSarthak Garg 
207153e888d1SHulk Robot static void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
207216d18d89SSarthak Garg {
207316d18d89SSarthak Garg 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
207416d18d89SSarthak Garg 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
207516d18d89SSarthak Garg 	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
207616d18d89SSarthak Garg 
207716d18d89SSarthak Garg 	SDHCI_MSM_DUMP("----------- VENDOR REGISTER DUMP -----------\n");
207816d18d89SSarthak Garg 
207916d18d89SSarthak Garg 	SDHCI_MSM_DUMP(
208016d18d89SSarthak Garg 			"DLL sts: 0x%08x | DLL cfg:  0x%08x | DLL cfg2: 0x%08x\n",
208116d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_dll_status),
208216d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_dll_config),
208316d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2));
208416d18d89SSarthak Garg 	SDHCI_MSM_DUMP(
208516d18d89SSarthak Garg 			"DLL cfg3: 0x%08x | DLL usr ctl:  0x%08x | DDR cfg: 0x%08x\n",
208616d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_dll_config_3),
208716d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_dll_usr_ctl),
208816d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_ddr_config));
208916d18d89SSarthak Garg 	SDHCI_MSM_DUMP(
209016d18d89SSarthak Garg 			"Vndr func: 0x%08x | Vndr func2 : 0x%08x Vndr func3: 0x%08x\n",
209116d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec),
209216d18d89SSarthak Garg 		readl_relaxed(host->ioaddr +
209316d18d89SSarthak Garg 			msm_offset->core_vendor_spec_func2),
209416d18d89SSarthak Garg 		readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec3));
209516d18d89SSarthak Garg }
209616d18d89SSarthak Garg 
20976ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_ops mci_var_ops = {
20986ed4bb43SVijay Viswanath 	.msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed,
20996ed4bb43SVijay Viswanath 	.msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed,
21006ed4bb43SVijay Viswanath };
21016ed4bb43SVijay Viswanath 
21026ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_ops v5_var_ops = {
21036ed4bb43SVijay Viswanath 	.msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed,
21046ed4bb43SVijay Viswanath 	.msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed,
21056ed4bb43SVijay Viswanath };
21066ed4bb43SVijay Viswanath 
21076ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_info sdhci_msm_mci_var = {
21086ed4bb43SVijay Viswanath 	.var_ops = &mci_var_ops,
21096ed4bb43SVijay Viswanath 	.offset = &sdhci_msm_mci_offset,
21106ed4bb43SVijay Viswanath };
21116ed4bb43SVijay Viswanath 
21126ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_info sdhci_msm_v5_var = {
21136ed4bb43SVijay Viswanath 	.mci_removed = true,
21146ed4bb43SVijay Viswanath 	.var_ops = &v5_var_ops,
21156ed4bb43SVijay Viswanath 	.offset = &sdhci_msm_v5_offset,
21166ed4bb43SVijay Viswanath };
21176ed4bb43SVijay Viswanath 
211821f1e2d4SVeerabhadrarao Badiganti static const struct sdhci_msm_variant_info sdm845_sdhci_var = {
211921f1e2d4SVeerabhadrarao Badiganti 	.mci_removed = true,
212021f1e2d4SVeerabhadrarao Badiganti 	.restore_dll_config = true,
212121f1e2d4SVeerabhadrarao Badiganti 	.var_ops = &v5_var_ops,
212221f1e2d4SVeerabhadrarao Badiganti 	.offset = &sdhci_msm_v5_offset,
212321f1e2d4SVeerabhadrarao Badiganti };
212421f1e2d4SVeerabhadrarao Badiganti 
21255c30f340SVeerabhadrarao Badiganti static const struct sdhci_msm_variant_info sm8250_sdhci_var = {
21265c30f340SVeerabhadrarao Badiganti 	.mci_removed = true,
21275c30f340SVeerabhadrarao Badiganti 	.uses_tassadar_dll = true,
21285c30f340SVeerabhadrarao Badiganti 	.var_ops = &v5_var_ops,
21295c30f340SVeerabhadrarao Badiganti 	.offset = &sdhci_msm_v5_offset,
21305c30f340SVeerabhadrarao Badiganti };
21315c30f340SVeerabhadrarao Badiganti 
21320eb0d9f4SGeorgi Djakov static const struct of_device_id sdhci_msm_dt_match[] = {
2133bc99266bSSayali Lokhande 	{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
2134bc99266bSSayali Lokhande 	{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
213521f1e2d4SVeerabhadrarao Badiganti 	{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
21365c30f340SVeerabhadrarao Badiganti 	{.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var},
21370eb0d9f4SGeorgi Djakov 	{},
21380eb0d9f4SGeorgi Djakov };
21390eb0d9f4SGeorgi Djakov 
21400eb0d9f4SGeorgi Djakov MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
21410eb0d9f4SGeorgi Djakov 
2142a50396a4SJisheng Zhang static const struct sdhci_ops sdhci_msm_ops = {
21435cf583f1SVeerabhadrarao Badiganti 	.reset = sdhci_msm_reset,
2144edc609fdSRitesh Harjani 	.set_clock = sdhci_msm_set_clock,
214580031bdeSRitesh Harjani 	.get_min_clock = sdhci_msm_get_min_clock,
214680031bdeSRitesh Harjani 	.get_max_clock = sdhci_msm_get_max_clock,
2147ed1761d7SStephen Boyd 	.set_bus_width = sdhci_set_bus_width,
2148ee320674SRitesh Harjani 	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
2149c0309b38SVijay Viswanath 	.write_w = sdhci_msm_writew,
2150c0309b38SVijay Viswanath 	.write_b = sdhci_msm_writeb,
215187a8df0dSRitesh Harjani 	.irq	= sdhci_msm_cqe_irq,
215216d18d89SSarthak Garg 	.dump_vendor_regs = sdhci_msm_dump_vendor_regs,
215392a21738SVeerabhadrarao Badiganti 	.set_power = sdhci_set_power_noreg,
21540eb0d9f4SGeorgi Djakov };
21550eb0d9f4SGeorgi Djakov 
2156a50396a4SJisheng Zhang static const struct sdhci_pltfm_data sdhci_msm_pdata = {
2157a50396a4SJisheng Zhang 	.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
2158a0e31428SRitesh Harjani 		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
2159d863cb03SVeerabhadrarao Badiganti 		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
2160d863cb03SVeerabhadrarao Badiganti 		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
2161d863cb03SVeerabhadrarao Badiganti 
2162a0e31428SRitesh Harjani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
2163a50396a4SJisheng Zhang 	.ops = &sdhci_msm_ops,
2164a50396a4SJisheng Zhang };
2165a50396a4SJisheng Zhang 
21661dfbe3ffSSarthak Garg static inline void sdhci_msm_get_of_property(struct platform_device *pdev,
21671dfbe3ffSSarthak Garg 		struct sdhci_host *host)
21681dfbe3ffSSarthak Garg {
21691dfbe3ffSSarthak Garg 	struct device_node *node = pdev->dev.of_node;
21701dfbe3ffSSarthak Garg 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
21711dfbe3ffSSarthak Garg 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
21721dfbe3ffSSarthak Garg 
21731dfbe3ffSSarthak Garg 	if (of_property_read_u32(node, "qcom,ddr-config",
21741dfbe3ffSSarthak Garg 				&msm_host->ddr_config))
21751dfbe3ffSSarthak Garg 		msm_host->ddr_config = DDR_CONFIG_POR_VAL;
217603591160SSarthak Garg 
217703591160SSarthak Garg 	of_property_read_u32(node, "qcom,dll-config", &msm_host->dll_config);
21781dfbe3ffSSarthak Garg }
21791dfbe3ffSSarthak Garg 
21801dfbe3ffSSarthak Garg 
21810eb0d9f4SGeorgi Djakov static int sdhci_msm_probe(struct platform_device *pdev)
21820eb0d9f4SGeorgi Djakov {
21830eb0d9f4SGeorgi Djakov 	struct sdhci_host *host;
21840eb0d9f4SGeorgi Djakov 	struct sdhci_pltfm_host *pltfm_host;
21850eb0d9f4SGeorgi Djakov 	struct sdhci_msm_host *msm_host;
2186e4bf91f6SBjorn Andersson 	struct clk *clk;
21870eb0d9f4SGeorgi Djakov 	int ret;
21883a3ad3e9SGeorgi Djakov 	u16 host_version, core_minor;
218929301f40SRitesh Harjani 	u32 core_version, config;
21903a3ad3e9SGeorgi Djakov 	u8 core_major;
2191bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset;
2192bc99266bSSayali Lokhande 	const struct sdhci_msm_variant_info *var_info;
219387a8df0dSRitesh Harjani 	struct device_node *node = pdev->dev.of_node;
21940eb0d9f4SGeorgi Djakov 
21956f699531SJisheng Zhang 	host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
21960eb0d9f4SGeorgi Djakov 	if (IS_ERR(host))
21970eb0d9f4SGeorgi Djakov 		return PTR_ERR(host);
21980eb0d9f4SGeorgi Djakov 
21992a641e53SSrinivas Kandagatla 	host->sdma_boundary = 0;
22000eb0d9f4SGeorgi Djakov 	pltfm_host = sdhci_priv(host);
22016f699531SJisheng Zhang 	msm_host = sdhci_pltfm_priv(pltfm_host);
22020eb0d9f4SGeorgi Djakov 	msm_host->mmc = host->mmc;
22030eb0d9f4SGeorgi Djakov 	msm_host->pdev = pdev;
22040eb0d9f4SGeorgi Djakov 
22050eb0d9f4SGeorgi Djakov 	ret = mmc_of_parse(host->mmc);
22060eb0d9f4SGeorgi Djakov 	if (ret)
22070eb0d9f4SGeorgi Djakov 		goto pltfm_free;
22080eb0d9f4SGeorgi Djakov 
2209bc99266bSSayali Lokhande 	/*
2210bc99266bSSayali Lokhande 	 * Based on the compatible string, load the required msm host info from
2211bc99266bSSayali Lokhande 	 * the data associated with the version info.
2212bc99266bSSayali Lokhande 	 */
2213bc99266bSSayali Lokhande 	var_info = of_device_get_match_data(&pdev->dev);
2214bc99266bSSayali Lokhande 
2215bc99266bSSayali Lokhande 	msm_host->mci_removed = var_info->mci_removed;
221621f1e2d4SVeerabhadrarao Badiganti 	msm_host->restore_dll_config = var_info->restore_dll_config;
2217bc99266bSSayali Lokhande 	msm_host->var_ops = var_info->var_ops;
2218bc99266bSSayali Lokhande 	msm_host->offset = var_info->offset;
22195c30f340SVeerabhadrarao Badiganti 	msm_host->uses_tassadar_dll = var_info->uses_tassadar_dll;
2220bc99266bSSayali Lokhande 
2221bc99266bSSayali Lokhande 	msm_offset = msm_host->offset;
2222bc99266bSSayali Lokhande 
22230eb0d9f4SGeorgi Djakov 	sdhci_get_of_property(pdev);
22241dfbe3ffSSarthak Garg 	sdhci_msm_get_of_property(pdev, host);
22250eb0d9f4SGeorgi Djakov 
2226abf270e5SRitesh Harjani 	msm_host->saved_tuning_phase = INVALID_TUNING_PHASE;
2227abf270e5SRitesh Harjani 
22280eb0d9f4SGeorgi Djakov 	/* Setup SDCC bus voter clock. */
22290eb0d9f4SGeorgi Djakov 	msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
22300eb0d9f4SGeorgi Djakov 	if (!IS_ERR(msm_host->bus_clk)) {
22310eb0d9f4SGeorgi Djakov 		/* Vote for max. clk rate for max. performance */
22320eb0d9f4SGeorgi Djakov 		ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
22330eb0d9f4SGeorgi Djakov 		if (ret)
22340eb0d9f4SGeorgi Djakov 			goto pltfm_free;
22350eb0d9f4SGeorgi Djakov 		ret = clk_prepare_enable(msm_host->bus_clk);
22360eb0d9f4SGeorgi Djakov 		if (ret)
22370eb0d9f4SGeorgi Djakov 			goto pltfm_free;
22380eb0d9f4SGeorgi Djakov 	}
22390eb0d9f4SGeorgi Djakov 
22400eb0d9f4SGeorgi Djakov 	/* Setup main peripheral bus clock */
2241e4bf91f6SBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "iface");
2242e4bf91f6SBjorn Andersson 	if (IS_ERR(clk)) {
2243e4bf91f6SBjorn Andersson 		ret = PTR_ERR(clk);
22442801b95eSColin Ian King 		dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
22450eb0d9f4SGeorgi Djakov 		goto bus_clk_disable;
22460eb0d9f4SGeorgi Djakov 	}
2247e4bf91f6SBjorn Andersson 	msm_host->bulk_clks[1].clk = clk;
22480eb0d9f4SGeorgi Djakov 
22490eb0d9f4SGeorgi Djakov 	/* Setup SDC MMC clock */
2250e4bf91f6SBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "core");
2251e4bf91f6SBjorn Andersson 	if (IS_ERR(clk)) {
2252e4bf91f6SBjorn Andersson 		ret = PTR_ERR(clk);
22530eb0d9f4SGeorgi Djakov 		dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
2254e4bf91f6SBjorn Andersson 		goto bus_clk_disable;
22550eb0d9f4SGeorgi Djakov 	}
2256e4bf91f6SBjorn Andersson 	msm_host->bulk_clks[0].clk = clk;
2257e4bf91f6SBjorn Andersson 
2258b4fc8278SPradeep P V K 	 /* Check for optional interconnect paths */
2259b4fc8278SPradeep P V K 	ret = dev_pm_opp_of_find_icc_paths(&pdev->dev, NULL);
2260b4fc8278SPradeep P V K 	if (ret)
2261b4fc8278SPradeep P V K 		goto bus_clk_disable;
2262b4fc8278SPradeep P V K 
2263c2b613d0SRajendra Nayak 	msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
2264c2b613d0SRajendra Nayak 	if (IS_ERR(msm_host->opp_table)) {
2265c2b613d0SRajendra Nayak 		ret = PTR_ERR(msm_host->opp_table);
22660472f8d3SRajendra Nayak 		goto bus_clk_disable;
22670472f8d3SRajendra Nayak 	}
22680472f8d3SRajendra Nayak 
22690472f8d3SRajendra Nayak 	/* OPP table is optional */
2270c2b613d0SRajendra Nayak 	ret = dev_pm_opp_of_add_table(&pdev->dev);
2271c2b613d0SRajendra Nayak 	if (!ret) {
2272c2b613d0SRajendra Nayak 		msm_host->has_opp_table = true;
2273c2b613d0SRajendra Nayak 	} else if (ret != -ENODEV) {
2274c2b613d0SRajendra Nayak 		dev_err(&pdev->dev, "Invalid OPP table in Device tree\n");
2275c2b613d0SRajendra Nayak 		goto opp_cleanup;
2276c2b613d0SRajendra Nayak 	}
22770472f8d3SRajendra Nayak 
2278e4bf91f6SBjorn Andersson 	/* Vote for maximum clock rate for maximum performance */
22790472f8d3SRajendra Nayak 	ret = dev_pm_opp_set_rate(&pdev->dev, INT_MAX);
2280e4bf91f6SBjorn Andersson 	if (ret)
2281e4bf91f6SBjorn Andersson 		dev_warn(&pdev->dev, "core clock boost failed\n");
2282e4bf91f6SBjorn Andersson 
22834946b3afSBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "cal");
22844946b3afSBjorn Andersson 	if (IS_ERR(clk))
22854946b3afSBjorn Andersson 		clk = NULL;
22864946b3afSBjorn Andersson 	msm_host->bulk_clks[2].clk = clk;
22874946b3afSBjorn Andersson 
22884946b3afSBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "sleep");
22894946b3afSBjorn Andersson 	if (IS_ERR(clk))
22904946b3afSBjorn Andersson 		clk = NULL;
22914946b3afSBjorn Andersson 	msm_host->bulk_clks[3].clk = clk;
22924946b3afSBjorn Andersson 
2293e4bf91f6SBjorn Andersson 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
2294e4bf91f6SBjorn Andersson 				      msm_host->bulk_clks);
2295e4bf91f6SBjorn Andersson 	if (ret)
22960472f8d3SRajendra Nayak 		goto opp_cleanup;
22970eb0d9f4SGeorgi Djakov 
229883736352SVenkat Gopalakrishnan 	/*
229983736352SVenkat Gopalakrishnan 	 * xo clock is needed for FLL feature of cm_dll.
230083736352SVenkat Gopalakrishnan 	 * In case if xo clock is not mentioned in DT, warn and proceed.
230183736352SVenkat Gopalakrishnan 	 */
230283736352SVenkat Gopalakrishnan 	msm_host->xo_clk = devm_clk_get(&pdev->dev, "xo");
230383736352SVenkat Gopalakrishnan 	if (IS_ERR(msm_host->xo_clk)) {
230483736352SVenkat Gopalakrishnan 		ret = PTR_ERR(msm_host->xo_clk);
230583736352SVenkat Gopalakrishnan 		dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret);
230683736352SVenkat Gopalakrishnan 	}
230783736352SVenkat Gopalakrishnan 
2308bc99266bSSayali Lokhande 	if (!msm_host->mci_removed) {
2309cb064b50SYangtao Li 		msm_host->core_mem = devm_platform_ioremap_resource(pdev, 1);
23100eb0d9f4SGeorgi Djakov 		if (IS_ERR(msm_host->core_mem)) {
23110eb0d9f4SGeorgi Djakov 			ret = PTR_ERR(msm_host->core_mem);
23120eb0d9f4SGeorgi Djakov 			goto clk_disable;
23130eb0d9f4SGeorgi Djakov 		}
2314bc99266bSSayali Lokhande 	}
23150eb0d9f4SGeorgi Djakov 
23165574ddccSVenkat Gopalakrishnan 	/* Reset the vendor spec register to power on reset state */
23175574ddccSVenkat Gopalakrishnan 	writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
2318bc99266bSSayali Lokhande 			host->ioaddr + msm_offset->core_vendor_spec);
23190eb0d9f4SGeorgi Djakov 
2320bc99266bSSayali Lokhande 	if (!msm_host->mci_removed) {
23210eb0d9f4SGeorgi Djakov 		/* Set HC_MODE_EN bit in HC_MODE register */
2322bc99266bSSayali Lokhande 		msm_host_writel(msm_host, HC_MODE_EN, host,
2323bc99266bSSayali Lokhande 				msm_offset->core_hc_mode);
2324bc99266bSSayali Lokhande 		config = msm_host_readl(msm_host, host,
2325bc99266bSSayali Lokhande 				msm_offset->core_hc_mode);
2326ff06ce41SVenkat Gopalakrishnan 		config |= FF_CLK_SW_RST_DIS;
2327bc99266bSSayali Lokhande 		msm_host_writel(msm_host, config, host,
2328bc99266bSSayali Lokhande 				msm_offset->core_hc_mode);
2329bc99266bSSayali Lokhande 	}
2330ff06ce41SVenkat Gopalakrishnan 
23310eb0d9f4SGeorgi Djakov 	host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
23320eb0d9f4SGeorgi Djakov 	dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
23330eb0d9f4SGeorgi Djakov 		host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
23340eb0d9f4SGeorgi Djakov 			       SDHCI_VENDOR_VER_SHIFT));
23350eb0d9f4SGeorgi Djakov 
2336bc99266bSSayali Lokhande 	core_version = msm_host_readl(msm_host, host,
2337bc99266bSSayali Lokhande 			msm_offset->core_mci_version);
23383a3ad3e9SGeorgi Djakov 	core_major = (core_version & CORE_VERSION_MAJOR_MASK) >>
23393a3ad3e9SGeorgi Djakov 		      CORE_VERSION_MAJOR_SHIFT;
23403a3ad3e9SGeorgi Djakov 	core_minor = core_version & CORE_VERSION_MINOR_MASK;
23413a3ad3e9SGeorgi Djakov 	dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
23423a3ad3e9SGeorgi Djakov 		core_version, core_major, core_minor);
23433a3ad3e9SGeorgi Djakov 
234483736352SVenkat Gopalakrishnan 	if (core_major == 1 && core_minor >= 0x42)
234583736352SVenkat Gopalakrishnan 		msm_host->use_14lpp_dll_reset = true;
234683736352SVenkat Gopalakrishnan 
23473a3ad3e9SGeorgi Djakov 	/*
234802e4293dSRitesh Harjani 	 * SDCC 5 controller with major version 1, minor version 0x34 and later
234902e4293dSRitesh Harjani 	 * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL.
235002e4293dSRitesh Harjani 	 */
235102e4293dSRitesh Harjani 	if (core_major == 1 && core_minor < 0x34)
235202e4293dSRitesh Harjani 		msm_host->use_cdclp533 = true;
235302e4293dSRitesh Harjani 
235402e4293dSRitesh Harjani 	/*
23553a3ad3e9SGeorgi Djakov 	 * Support for some capabilities is not advertised by newer
23563a3ad3e9SGeorgi Djakov 	 * controller versions and must be explicitly enabled.
23573a3ad3e9SGeorgi Djakov 	 */
23583a3ad3e9SGeorgi Djakov 	if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) {
235929301f40SRitesh Harjani 		config = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES);
236029301f40SRitesh Harjani 		config |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT;
236129301f40SRitesh Harjani 		writel_relaxed(config, host->ioaddr +
2362bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec_capabilities0);
23633a3ad3e9SGeorgi Djakov 	}
23643a3ad3e9SGeorgi Djakov 
2365fa56ac97SVeerabhadrarao Badiganti 	if (core_major == 1 && core_minor >= 0x49)
2366fa56ac97SVeerabhadrarao Badiganti 		msm_host->updated_ddr_cfg = true;
2367fa56ac97SVeerabhadrarao Badiganti 
236892a21738SVeerabhadrarao Badiganti 	ret = sdhci_msm_register_vreg(msm_host);
236992a21738SVeerabhadrarao Badiganti 	if (ret)
237092a21738SVeerabhadrarao Badiganti 		goto clk_disable;
237192a21738SVeerabhadrarao Badiganti 
2372c7ccee22SSubhash Jadavani 	/*
2373c7ccee22SSubhash Jadavani 	 * Power on reset state may trigger power irq if previous status of
2374c7ccee22SSubhash Jadavani 	 * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
2375c7ccee22SSubhash Jadavani 	 * interrupt in GIC, any pending power irq interrupt should be
2376c7ccee22SSubhash Jadavani 	 * acknowledged. Otherwise power irq interrupt handler would be
2377c7ccee22SSubhash Jadavani 	 * fired prematurely.
2378c7ccee22SSubhash Jadavani 	 */
2379401b2d06SSahitya Tummala 	sdhci_msm_handle_pwr_irq(host, 0);
2380c7ccee22SSubhash Jadavani 
2381c7ccee22SSubhash Jadavani 	/*
2382c7ccee22SSubhash Jadavani 	 * Ensure that above writes are propogated before interrupt enablement
2383c7ccee22SSubhash Jadavani 	 * in GIC.
2384c7ccee22SSubhash Jadavani 	 */
2385c7ccee22SSubhash Jadavani 	mb();
2386c7ccee22SSubhash Jadavani 
2387ad81d387SGeorgi Djakov 	/* Setup IRQ for handling power/voltage tasks with PMIC */
2388ad81d387SGeorgi Djakov 	msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
2389ad81d387SGeorgi Djakov 	if (msm_host->pwr_irq < 0) {
2390d1f63f0cSWei Yongjun 		ret = msm_host->pwr_irq;
2391ad81d387SGeorgi Djakov 		goto clk_disable;
2392ad81d387SGeorgi Djakov 	}
2393ad81d387SGeorgi Djakov 
2394c0309b38SVijay Viswanath 	sdhci_msm_init_pwr_irq_wait(msm_host);
2395c7ccee22SSubhash Jadavani 	/* Enable pwr irq interrupts */
2396bc99266bSSayali Lokhande 	msm_host_writel(msm_host, INT_MASK, host,
2397bc99266bSSayali Lokhande 		msm_offset->core_pwrctl_mask);
2398c7ccee22SSubhash Jadavani 
2399ad81d387SGeorgi Djakov 	ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
2400ad81d387SGeorgi Djakov 					sdhci_msm_pwr_irq, IRQF_ONESHOT,
2401ad81d387SGeorgi Djakov 					dev_name(&pdev->dev), host);
2402ad81d387SGeorgi Djakov 	if (ret) {
2403ad81d387SGeorgi Djakov 		dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
2404ad81d387SGeorgi Djakov 		goto clk_disable;
2405ad81d387SGeorgi Djakov 	}
2406ad81d387SGeorgi Djakov 
24079d8cb586SVeerabhadrarao Badiganti 	msm_host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY;
24089d8cb586SVeerabhadrarao Badiganti 
240967e6db11SPramod Gurav 	pm_runtime_get_noresume(&pdev->dev);
241067e6db11SPramod Gurav 	pm_runtime_set_active(&pdev->dev);
241167e6db11SPramod Gurav 	pm_runtime_enable(&pdev->dev);
241267e6db11SPramod Gurav 	pm_runtime_set_autosuspend_delay(&pdev->dev,
241367e6db11SPramod Gurav 					 MSM_MMC_AUTOSUSPEND_DELAY_MS);
241467e6db11SPramod Gurav 	pm_runtime_use_autosuspend(&pdev->dev);
241567e6db11SPramod Gurav 
241692a21738SVeerabhadrarao Badiganti 	host->mmc_host_ops.start_signal_voltage_switch =
241792a21738SVeerabhadrarao Badiganti 		sdhci_msm_start_signal_voltage_switch;
24184436c535SRitesh Harjani 	host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning;
241987a8df0dSRitesh Harjani 	if (of_property_read_bool(node, "supports-cqe"))
242087a8df0dSRitesh Harjani 		ret = sdhci_msm_cqe_add_host(host, pdev);
242187a8df0dSRitesh Harjani 	else
24220eb0d9f4SGeorgi Djakov 		ret = sdhci_add_host(host);
24230eb0d9f4SGeorgi Djakov 	if (ret)
242467e6db11SPramod Gurav 		goto pm_runtime_disable;
242567e6db11SPramod Gurav 
242667e6db11SPramod Gurav 	pm_runtime_mark_last_busy(&pdev->dev);
242767e6db11SPramod Gurav 	pm_runtime_put_autosuspend(&pdev->dev);
24280eb0d9f4SGeorgi Djakov 
24290eb0d9f4SGeorgi Djakov 	return 0;
24300eb0d9f4SGeorgi Djakov 
243167e6db11SPramod Gurav pm_runtime_disable:
243267e6db11SPramod Gurav 	pm_runtime_disable(&pdev->dev);
243367e6db11SPramod Gurav 	pm_runtime_set_suspended(&pdev->dev);
243467e6db11SPramod Gurav 	pm_runtime_put_noidle(&pdev->dev);
24350eb0d9f4SGeorgi Djakov clk_disable:
2436e4bf91f6SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
2437e4bf91f6SBjorn Andersson 				   msm_host->bulk_clks);
24380472f8d3SRajendra Nayak opp_cleanup:
2439c2b613d0SRajendra Nayak 	if (msm_host->has_opp_table)
24400472f8d3SRajendra Nayak 		dev_pm_opp_of_remove_table(&pdev->dev);
2441c2b613d0SRajendra Nayak 	dev_pm_opp_put_clkname(msm_host->opp_table);
24420eb0d9f4SGeorgi Djakov bus_clk_disable:
24430eb0d9f4SGeorgi Djakov 	if (!IS_ERR(msm_host->bus_clk))
24440eb0d9f4SGeorgi Djakov 		clk_disable_unprepare(msm_host->bus_clk);
24450eb0d9f4SGeorgi Djakov pltfm_free:
24460eb0d9f4SGeorgi Djakov 	sdhci_pltfm_free(pdev);
24470eb0d9f4SGeorgi Djakov 	return ret;
24480eb0d9f4SGeorgi Djakov }
24490eb0d9f4SGeorgi Djakov 
24500eb0d9f4SGeorgi Djakov static int sdhci_msm_remove(struct platform_device *pdev)
24510eb0d9f4SGeorgi Djakov {
24520eb0d9f4SGeorgi Djakov 	struct sdhci_host *host = platform_get_drvdata(pdev);
24530eb0d9f4SGeorgi Djakov 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
24546f699531SJisheng Zhang 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
24550eb0d9f4SGeorgi Djakov 	int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
24560eb0d9f4SGeorgi Djakov 		    0xffffffff);
24570eb0d9f4SGeorgi Djakov 
24580eb0d9f4SGeorgi Djakov 	sdhci_remove_host(host, dead);
245967e6db11SPramod Gurav 
2460c2b613d0SRajendra Nayak 	if (msm_host->has_opp_table)
24610472f8d3SRajendra Nayak 		dev_pm_opp_of_remove_table(&pdev->dev);
2462c2b613d0SRajendra Nayak 	dev_pm_opp_put_clkname(msm_host->opp_table);
246367e6db11SPramod Gurav 	pm_runtime_get_sync(&pdev->dev);
246467e6db11SPramod Gurav 	pm_runtime_disable(&pdev->dev);
246567e6db11SPramod Gurav 	pm_runtime_put_noidle(&pdev->dev);
246667e6db11SPramod Gurav 
2467e4bf91f6SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
2468e4bf91f6SBjorn Andersson 				   msm_host->bulk_clks);
24690eb0d9f4SGeorgi Djakov 	if (!IS_ERR(msm_host->bus_clk))
24700eb0d9f4SGeorgi Djakov 		clk_disable_unprepare(msm_host->bus_clk);
24716f699531SJisheng Zhang 	sdhci_pltfm_free(pdev);
24720eb0d9f4SGeorgi Djakov 	return 0;
24730eb0d9f4SGeorgi Djakov }
24740eb0d9f4SGeorgi Djakov 
24756809a5f7SArnd Bergmann static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
247667e6db11SPramod Gurav {
247767e6db11SPramod Gurav 	struct sdhci_host *host = dev_get_drvdata(dev);
247867e6db11SPramod Gurav 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
247967e6db11SPramod Gurav 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
248067e6db11SPramod Gurav 
24810472f8d3SRajendra Nayak 	/* Drop the performance vote */
24820472f8d3SRajendra Nayak 	dev_pm_opp_set_rate(dev, 0);
2483e4bf91f6SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
2484e4bf91f6SBjorn Andersson 				   msm_host->bulk_clks);
248567e6db11SPramod Gurav 
248667e6db11SPramod Gurav 	return 0;
248767e6db11SPramod Gurav }
248867e6db11SPramod Gurav 
24896809a5f7SArnd Bergmann static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
249067e6db11SPramod Gurav {
249167e6db11SPramod Gurav 	struct sdhci_host *host = dev_get_drvdata(dev);
249267e6db11SPramod Gurav 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
249367e6db11SPramod Gurav 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
249421f1e2d4SVeerabhadrarao Badiganti 	int ret;
249567e6db11SPramod Gurav 
249621f1e2d4SVeerabhadrarao Badiganti 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
2497e4bf91f6SBjorn Andersson 				       msm_host->bulk_clks);
249821f1e2d4SVeerabhadrarao Badiganti 	if (ret)
249921f1e2d4SVeerabhadrarao Badiganti 		return ret;
250021f1e2d4SVeerabhadrarao Badiganti 	/*
250121f1e2d4SVeerabhadrarao Badiganti 	 * Whenever core-clock is gated dynamically, it's needed to
250221f1e2d4SVeerabhadrarao Badiganti 	 * restore the SDR DLL settings when the clock is ungated.
250321f1e2d4SVeerabhadrarao Badiganti 	 */
250421f1e2d4SVeerabhadrarao Badiganti 	if (msm_host->restore_dll_config && msm_host->clk_rate)
25050472f8d3SRajendra Nayak 		ret = sdhci_msm_restore_sdr_dll_config(host);
250621f1e2d4SVeerabhadrarao Badiganti 
25070472f8d3SRajendra Nayak 	dev_pm_opp_set_rate(dev, msm_host->clk_rate);
25080472f8d3SRajendra Nayak 
25090472f8d3SRajendra Nayak 	return ret;
251067e6db11SPramod Gurav }
251167e6db11SPramod Gurav 
251267e6db11SPramod Gurav static const struct dev_pm_ops sdhci_msm_pm_ops = {
251367e6db11SPramod Gurav 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
251467e6db11SPramod Gurav 				pm_runtime_force_resume)
251567e6db11SPramod Gurav 	SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend,
251667e6db11SPramod Gurav 			   sdhci_msm_runtime_resume,
251767e6db11SPramod Gurav 			   NULL)
251867e6db11SPramod Gurav };
251967e6db11SPramod Gurav 
25200eb0d9f4SGeorgi Djakov static struct platform_driver sdhci_msm_driver = {
25210eb0d9f4SGeorgi Djakov 	.probe = sdhci_msm_probe,
25220eb0d9f4SGeorgi Djakov 	.remove = sdhci_msm_remove,
25230eb0d9f4SGeorgi Djakov 	.driver = {
25240eb0d9f4SGeorgi Djakov 		   .name = "sdhci_msm",
25250eb0d9f4SGeorgi Djakov 		   .of_match_table = sdhci_msm_dt_match,
252667e6db11SPramod Gurav 		   .pm = &sdhci_msm_pm_ops,
25270eb0d9f4SGeorgi Djakov 	},
25280eb0d9f4SGeorgi Djakov };
25290eb0d9f4SGeorgi Djakov 
25300eb0d9f4SGeorgi Djakov module_platform_driver(sdhci_msm_driver);
25310eb0d9f4SGeorgi Djakov 
25320eb0d9f4SGeorgi Djakov MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
25330eb0d9f4SGeorgi Djakov MODULE_LICENSE("GPL v2");
2534