xref: /openbmc/linux/drivers/mmc/host/sdhci-msm.c (revision 1dfbe3ff)
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>
170eb0d9f4SGeorgi Djakov 
180eb0d9f4SGeorgi Djakov #include "sdhci-pltfm.h"
1987a8df0dSRitesh Harjani #include "cqhci.h"
200eb0d9f4SGeorgi Djakov 
213a3ad3e9SGeorgi Djakov #define CORE_MCI_VERSION		0x50
223a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_SHIFT	28
233a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_MASK		(0xf << CORE_VERSION_MAJOR_SHIFT)
243a3ad3e9SGeorgi Djakov #define CORE_VERSION_MINOR_MASK		0xff
253a3ad3e9SGeorgi Djakov 
2652884f8fSBjorn Andersson #define CORE_MCI_GENERICS		0x70
2752884f8fSBjorn Andersson #define SWITCHABLE_SIGNALING_VOLTAGE	BIT(29)
2852884f8fSBjorn Andersson 
290eb0d9f4SGeorgi Djakov #define HC_MODE_EN		0x1
300eb0d9f4SGeorgi Djakov #define CORE_POWER		0x0
310eb0d9f4SGeorgi Djakov #define CORE_SW_RST		BIT(7)
32ff06ce41SVenkat Gopalakrishnan #define FF_CLK_SW_RST_DIS	BIT(13)
330eb0d9f4SGeorgi Djakov 
34ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_OFF	BIT(0)
35ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_ON	BIT(1)
36ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_LOW	BIT(2)
37ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_HIGH	BIT(3)
38ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_SUCCESS BIT(0)
39ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_SUCCESS	BIT(2)
40ad81d387SGeorgi Djakov #define REQ_BUS_OFF		BIT(0)
41ad81d387SGeorgi Djakov #define REQ_BUS_ON		BIT(1)
42ad81d387SGeorgi Djakov #define REQ_IO_LOW		BIT(2)
43ad81d387SGeorgi Djakov #define REQ_IO_HIGH		BIT(3)
44ad81d387SGeorgi Djakov #define INT_MASK		0xf
45415b5a75SGeorgi Djakov #define MAX_PHASES		16
46415b5a75SGeorgi Djakov #define CORE_DLL_LOCK		BIT(7)
4702e4293dSRitesh Harjani #define CORE_DDR_DLL_LOCK	BIT(11)
48415b5a75SGeorgi Djakov #define CORE_DLL_EN		BIT(16)
49415b5a75SGeorgi Djakov #define CORE_CDR_EN		BIT(17)
50415b5a75SGeorgi Djakov #define CORE_CK_OUT_EN		BIT(18)
51415b5a75SGeorgi Djakov #define CORE_CDR_EXT_EN		BIT(19)
52415b5a75SGeorgi Djakov #define CORE_DLL_PDN		BIT(29)
53415b5a75SGeorgi Djakov #define CORE_DLL_RST		BIT(30)
54cc392c58SRitesh Harjani #define CORE_CMD_DAT_TRACK_SEL	BIT(0)
55415b5a75SGeorgi Djakov 
5602e4293dSRitesh Harjani #define CORE_DDR_CAL_EN		BIT(0)
5783736352SVenkat Gopalakrishnan #define CORE_FLL_CYCLE_CNT	BIT(18)
5883736352SVenkat Gopalakrishnan #define CORE_DLL_CLOCK_DISABLE	BIT(21)
5983736352SVenkat Gopalakrishnan 
605c30f340SVeerabhadrarao Badiganti #define DLL_USR_CTL_POR_VAL	0x10800
615c30f340SVeerabhadrarao Badiganti #define ENABLE_DLL_LOCK_STATUS	BIT(26)
625c30f340SVeerabhadrarao Badiganti #define FINE_TUNE_MODE_EN	BIT(27)
635c30f340SVeerabhadrarao Badiganti #define BIAS_OK_SIGNAL		BIT(29)
645c30f340SVeerabhadrarao Badiganti 
6504816e67SSarthak Garg #define DLL_CONFIG_3_LOW_FREQ_VAL	0x08
6604816e67SSarthak Garg #define DLL_CONFIG_3_HIGH_FREQ_VAL	0x10
6704816e67SSarthak Garg 
68946932d9SVeerabhadrarao Badiganti #define CORE_VENDOR_SPEC_POR_VAL 0xa9c
69415b5a75SGeorgi Djakov #define CORE_CLK_PWRSAVE	BIT(1)
70ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_DFLT	(2 << 8)
71ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_HS400	(3 << 8)
72ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_MASK	(3 << 8)
73946932d9SVeerabhadrarao Badiganti #define CORE_IO_PAD_PWR_SWITCH_EN	BIT(15)
74946932d9SVeerabhadrarao Badiganti #define CORE_IO_PAD_PWR_SWITCH	BIT(16)
75ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_EN	BIT(18)
76ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_HS400	(6 << 19)
77ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_MASK	(7 << 19)
78415b5a75SGeorgi Djakov 
79946932d9SVeerabhadrarao Badiganti #define CORE_3_0V_SUPPORT	BIT(25)
80946932d9SVeerabhadrarao Badiganti #define CORE_1_8V_SUPPORT	BIT(26)
815c132323SVijay Viswanath #define CORE_VOLT_SUPPORT	(CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT)
82ac06fba1SVijay Viswanath 
83cc392c58SRitesh Harjani #define CORE_CSR_CDC_CTLR_CFG0		0x130
84cc392c58SRitesh Harjani #define CORE_SW_TRIG_FULL_CALIB		BIT(16)
85cc392c58SRitesh Harjani #define CORE_HW_AUTOCAL_ENA		BIT(17)
86cc392c58SRitesh Harjani 
87cc392c58SRitesh Harjani #define CORE_CSR_CDC_CTLR_CFG1		0x134
88cc392c58SRitesh Harjani #define CORE_CSR_CDC_CAL_TIMER_CFG0	0x138
89cc392c58SRitesh Harjani #define CORE_TIMER_ENA			BIT(16)
90cc392c58SRitesh Harjani 
91cc392c58SRitesh Harjani #define CORE_CSR_CDC_CAL_TIMER_CFG1	0x13C
92cc392c58SRitesh Harjani #define CORE_CSR_CDC_REFCOUNT_CFG	0x140
93cc392c58SRitesh Harjani #define CORE_CSR_CDC_COARSE_CAL_CFG	0x144
94cc392c58SRitesh Harjani #define CORE_CDC_OFFSET_CFG		0x14C
95cc392c58SRitesh Harjani #define CORE_CSR_CDC_DELAY_CFG		0x150
96cc392c58SRitesh Harjani #define CORE_CDC_SLAVE_DDA_CFG		0x160
97cc392c58SRitesh Harjani #define CORE_CSR_CDC_STATUS0		0x164
98cc392c58SRitesh Harjani #define CORE_CALIBRATION_DONE		BIT(0)
99cc392c58SRitesh Harjani 
100cc392c58SRitesh Harjani #define CORE_CDC_ERROR_CODE_MASK	0x7000000
101cc392c58SRitesh Harjani 
102cc392c58SRitesh Harjani #define CORE_CSR_CDC_GEN_CFG		0x178
103cc392c58SRitesh Harjani #define CORE_CDC_SWITCH_BYPASS_OFF	BIT(0)
104cc392c58SRitesh Harjani #define CORE_CDC_SWITCH_RC_EN		BIT(1)
105cc392c58SRitesh Harjani 
106cc392c58SRitesh Harjani #define CORE_CDC_T4_DLY_SEL		BIT(0)
10744bf2312SRitesh Harjani #define CORE_CMDIN_RCLK_EN		BIT(1)
108cc392c58SRitesh Harjani #define CORE_START_CDC_TRAFFIC		BIT(6)
109bc99266bSSayali Lokhande 
11002e4293dSRitesh Harjani #define CORE_PWRSAVE_DLL	BIT(3)
11102e4293dSRitesh Harjani 
112fa56ac97SVeerabhadrarao Badiganti #define DDR_CONFIG_POR_VAL	0x80040873
113cc392c58SRitesh Harjani 
1143a3ad3e9SGeorgi Djakov 
115abf270e5SRitesh Harjani #define INVALID_TUNING_PHASE	-1
11680031bdeSRitesh Harjani #define SDHCI_MSM_MIN_CLOCK	400000
117ff06ce41SVenkat Gopalakrishnan #define CORE_FREQ_100MHZ	(100 * 1000 * 1000)
11880031bdeSRitesh Harjani 
119415b5a75SGeorgi Djakov #define CDR_SELEXT_SHIFT	20
120415b5a75SGeorgi Djakov #define CDR_SELEXT_MASK		(0xf << CDR_SELEXT_SHIFT)
121415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_SHIFT	24
122415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_MASK	(7 << CMUX_SHIFT_PHASE_SHIFT)
123415b5a75SGeorgi Djakov 
12467e6db11SPramod Gurav #define MSM_MMC_AUTOSUSPEND_DELAY_MS	50
125c0309b38SVijay Viswanath 
126c0309b38SVijay Viswanath /* Timeout value to avoid infinite waiting for pwr_irq */
127c0309b38SVijay Viswanath #define MSM_PWR_IRQ_TIMEOUT_MS 5000
128c0309b38SVijay Viswanath 
129bc99266bSSayali Lokhande #define msm_host_readl(msm_host, host, offset) \
130bc99266bSSayali Lokhande 	msm_host->var_ops->msm_readl_relaxed(host, offset)
131bc99266bSSayali Lokhande 
132bc99266bSSayali Lokhande #define msm_host_writel(msm_host, val, host, offset) \
133bc99266bSSayali Lokhande 	msm_host->var_ops->msm_writel_relaxed(val, host, offset)
134bc99266bSSayali Lokhande 
13587a8df0dSRitesh Harjani /* CQHCI vendor specific registers */
13687a8df0dSRitesh Harjani #define CQHCI_VENDOR_CFG1	0xA00
13787a8df0dSRitesh Harjani #define CQHCI_VENDOR_DIS_RST_ON_CQ_EN	(0x3 << 13)
13887a8df0dSRitesh Harjani 
139f1535888SSayali Lokhande struct sdhci_msm_offset {
140f1535888SSayali Lokhande 	u32 core_hc_mode;
141f1535888SSayali Lokhande 	u32 core_mci_data_cnt;
142f1535888SSayali Lokhande 	u32 core_mci_status;
143f1535888SSayali Lokhande 	u32 core_mci_fifo_cnt;
144f1535888SSayali Lokhande 	u32 core_mci_version;
145f1535888SSayali Lokhande 	u32 core_generics;
146f1535888SSayali Lokhande 	u32 core_testbus_config;
147f1535888SSayali Lokhande 	u32 core_testbus_sel2_bit;
148f1535888SSayali Lokhande 	u32 core_testbus_ena;
149f1535888SSayali Lokhande 	u32 core_testbus_sel2;
150f1535888SSayali Lokhande 	u32 core_pwrctl_status;
151f1535888SSayali Lokhande 	u32 core_pwrctl_mask;
152f1535888SSayali Lokhande 	u32 core_pwrctl_clear;
153f1535888SSayali Lokhande 	u32 core_pwrctl_ctl;
154f1535888SSayali Lokhande 	u32 core_sdcc_debug_reg;
155f1535888SSayali Lokhande 	u32 core_dll_config;
156f1535888SSayali Lokhande 	u32 core_dll_status;
157f1535888SSayali Lokhande 	u32 core_vendor_spec;
158f1535888SSayali Lokhande 	u32 core_vendor_spec_adma_err_addr0;
159f1535888SSayali Lokhande 	u32 core_vendor_spec_adma_err_addr1;
160f1535888SSayali Lokhande 	u32 core_vendor_spec_func2;
161f1535888SSayali Lokhande 	u32 core_vendor_spec_capabilities0;
162f1535888SSayali Lokhande 	u32 core_ddr_200_cfg;
163f1535888SSayali Lokhande 	u32 core_vendor_spec3;
164f1535888SSayali Lokhande 	u32 core_dll_config_2;
165fa56ac97SVeerabhadrarao Badiganti 	u32 core_dll_config_3;
166fa56ac97SVeerabhadrarao Badiganti 	u32 core_ddr_config_old; /* Applicable to sdcc minor ver < 0x49 */
167f1535888SSayali Lokhande 	u32 core_ddr_config;
1685c30f340SVeerabhadrarao Badiganti 	u32 core_dll_usr_ctl; /* Present on SDCC5.1 onwards */
169f1535888SSayali Lokhande };
170f1535888SSayali Lokhande 
171f1535888SSayali Lokhande static const struct sdhci_msm_offset sdhci_msm_v5_offset = {
172f1535888SSayali Lokhande 	.core_mci_data_cnt = 0x35c,
173f1535888SSayali Lokhande 	.core_mci_status = 0x324,
174f1535888SSayali Lokhande 	.core_mci_fifo_cnt = 0x308,
175f1535888SSayali Lokhande 	.core_mci_version = 0x318,
176f1535888SSayali Lokhande 	.core_generics = 0x320,
177f1535888SSayali Lokhande 	.core_testbus_config = 0x32c,
178f1535888SSayali Lokhande 	.core_testbus_sel2_bit = 3,
179f1535888SSayali Lokhande 	.core_testbus_ena = (1 << 31),
180f1535888SSayali Lokhande 	.core_testbus_sel2 = (1 << 3),
181f1535888SSayali Lokhande 	.core_pwrctl_status = 0x240,
182f1535888SSayali Lokhande 	.core_pwrctl_mask = 0x244,
183f1535888SSayali Lokhande 	.core_pwrctl_clear = 0x248,
184f1535888SSayali Lokhande 	.core_pwrctl_ctl = 0x24c,
185f1535888SSayali Lokhande 	.core_sdcc_debug_reg = 0x358,
186f1535888SSayali Lokhande 	.core_dll_config = 0x200,
187f1535888SSayali Lokhande 	.core_dll_status = 0x208,
188f1535888SSayali Lokhande 	.core_vendor_spec = 0x20c,
189f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr0 = 0x214,
190f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr1 = 0x218,
191f1535888SSayali Lokhande 	.core_vendor_spec_func2 = 0x210,
192f1535888SSayali Lokhande 	.core_vendor_spec_capabilities0 = 0x21c,
193f1535888SSayali Lokhande 	.core_ddr_200_cfg = 0x224,
194f1535888SSayali Lokhande 	.core_vendor_spec3 = 0x250,
195f1535888SSayali Lokhande 	.core_dll_config_2 = 0x254,
196fa56ac97SVeerabhadrarao Badiganti 	.core_dll_config_3 = 0x258,
197fa56ac97SVeerabhadrarao Badiganti 	.core_ddr_config = 0x25c,
1985c30f340SVeerabhadrarao Badiganti 	.core_dll_usr_ctl = 0x388,
199f1535888SSayali Lokhande };
200f1535888SSayali Lokhande 
201f1535888SSayali Lokhande static const struct sdhci_msm_offset sdhci_msm_mci_offset = {
202f1535888SSayali Lokhande 	.core_hc_mode = 0x78,
203f1535888SSayali Lokhande 	.core_mci_data_cnt = 0x30,
204f1535888SSayali Lokhande 	.core_mci_status = 0x34,
205f1535888SSayali Lokhande 	.core_mci_fifo_cnt = 0x44,
206f1535888SSayali Lokhande 	.core_mci_version = 0x050,
207f1535888SSayali Lokhande 	.core_generics = 0x70,
208f1535888SSayali Lokhande 	.core_testbus_config = 0x0cc,
209f1535888SSayali Lokhande 	.core_testbus_sel2_bit = 4,
210f1535888SSayali Lokhande 	.core_testbus_ena = (1 << 3),
211f1535888SSayali Lokhande 	.core_testbus_sel2 = (1 << 4),
212f1535888SSayali Lokhande 	.core_pwrctl_status = 0xdc,
213f1535888SSayali Lokhande 	.core_pwrctl_mask = 0xe0,
214f1535888SSayali Lokhande 	.core_pwrctl_clear = 0xe4,
215f1535888SSayali Lokhande 	.core_pwrctl_ctl = 0xe8,
216f1535888SSayali Lokhande 	.core_sdcc_debug_reg = 0x124,
217f1535888SSayali Lokhande 	.core_dll_config = 0x100,
218f1535888SSayali Lokhande 	.core_dll_status = 0x108,
219f1535888SSayali Lokhande 	.core_vendor_spec = 0x10c,
220f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr0 = 0x114,
221f1535888SSayali Lokhande 	.core_vendor_spec_adma_err_addr1 = 0x118,
222f1535888SSayali Lokhande 	.core_vendor_spec_func2 = 0x110,
223f1535888SSayali Lokhande 	.core_vendor_spec_capabilities0 = 0x11c,
224f1535888SSayali Lokhande 	.core_ddr_200_cfg = 0x184,
225f1535888SSayali Lokhande 	.core_vendor_spec3 = 0x1b0,
226f1535888SSayali Lokhande 	.core_dll_config_2 = 0x1b4,
227fa56ac97SVeerabhadrarao Badiganti 	.core_ddr_config_old = 0x1b8,
228fa56ac97SVeerabhadrarao Badiganti 	.core_ddr_config = 0x1bc,
229f1535888SSayali Lokhande };
230f1535888SSayali Lokhande 
2316ed4bb43SVijay Viswanath struct sdhci_msm_variant_ops {
2326ed4bb43SVijay Viswanath 	u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
2336ed4bb43SVijay Viswanath 	void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
2346ed4bb43SVijay Viswanath 			u32 offset);
2356ed4bb43SVijay Viswanath };
2366ed4bb43SVijay Viswanath 
2376ed4bb43SVijay Viswanath /*
2386ed4bb43SVijay Viswanath  * From V5, register spaces have changed. Wrap this info in a structure
2396ed4bb43SVijay Viswanath  * and choose the data_structure based on version info mentioned in DT.
2406ed4bb43SVijay Viswanath  */
2416ed4bb43SVijay Viswanath struct sdhci_msm_variant_info {
2426ed4bb43SVijay Viswanath 	bool mci_removed;
24321f1e2d4SVeerabhadrarao Badiganti 	bool restore_dll_config;
2445c30f340SVeerabhadrarao Badiganti 	bool uses_tassadar_dll;
2456ed4bb43SVijay Viswanath 	const struct sdhci_msm_variant_ops *var_ops;
2466ed4bb43SVijay Viswanath 	const struct sdhci_msm_offset *offset;
2476ed4bb43SVijay Viswanath };
2486ed4bb43SVijay Viswanath 
2490eb0d9f4SGeorgi Djakov struct sdhci_msm_host {
2500eb0d9f4SGeorgi Djakov 	struct platform_device *pdev;
2510eb0d9f4SGeorgi Djakov 	void __iomem *core_mem;	/* MSM SDCC mapped address */
252ad81d387SGeorgi Djakov 	int pwr_irq;		/* power irq */
2530eb0d9f4SGeorgi Djakov 	struct clk *bus_clk;	/* SDHC bus voter clock */
25483736352SVenkat Gopalakrishnan 	struct clk *xo_clk;	/* TCXO clk needed for FLL feature of cm_dll*/
2554946b3afSBjorn Andersson 	struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */
256edc609fdSRitesh Harjani 	unsigned long clk_rate;
2570eb0d9f4SGeorgi Djakov 	struct mmc_host *mmc;
258c2b613d0SRajendra Nayak 	struct opp_table *opp_table;
259c2b613d0SRajendra Nayak 	bool has_opp_table;
26083736352SVenkat Gopalakrishnan 	bool use_14lpp_dll_reset;
261ff06ce41SVenkat Gopalakrishnan 	bool tuning_done;
262ff06ce41SVenkat Gopalakrishnan 	bool calibration_done;
263abf270e5SRitesh Harjani 	u8 saved_tuning_phase;
26402e4293dSRitesh Harjani 	bool use_cdclp533;
265c0309b38SVijay Viswanath 	u32 curr_pwr_state;
266c0309b38SVijay Viswanath 	u32 curr_io_level;
267c0309b38SVijay Viswanath 	wait_queue_head_t pwr_irq_wait;
268c0309b38SVijay Viswanath 	bool pwr_irq_flag;
269ac06fba1SVijay Viswanath 	u32 caps_0;
2706ed4bb43SVijay Viswanath 	bool mci_removed;
27121f1e2d4SVeerabhadrarao Badiganti 	bool restore_dll_config;
2726ed4bb43SVijay Viswanath 	const struct sdhci_msm_variant_ops *var_ops;
2736ed4bb43SVijay Viswanath 	const struct sdhci_msm_offset *offset;
274a89e7bcbSLoic Poulain 	bool use_cdr;
275a89e7bcbSLoic Poulain 	u32 transfer_mode;
276fa56ac97SVeerabhadrarao Badiganti 	bool updated_ddr_cfg;
2775c30f340SVeerabhadrarao Badiganti 	bool uses_tassadar_dll;
2781dfbe3ffSSarthak Garg 	u32 ddr_config;
2790eb0d9f4SGeorgi Djakov };
2800eb0d9f4SGeorgi Djakov 
281bc99266bSSayali Lokhande static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
282bc99266bSSayali Lokhande {
283bc99266bSSayali Lokhande 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
284bc99266bSSayali Lokhande 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
285bc99266bSSayali Lokhande 
286bc99266bSSayali Lokhande 	return msm_host->offset;
287bc99266bSSayali Lokhande }
288bc99266bSSayali Lokhande 
2896ed4bb43SVijay Viswanath /*
2906ed4bb43SVijay Viswanath  * APIs to read/write to vendor specific registers which were there in the
2916ed4bb43SVijay Viswanath  * core_mem region before MCI was removed.
2926ed4bb43SVijay Viswanath  */
2936ed4bb43SVijay Viswanath static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
2946ed4bb43SVijay Viswanath 		u32 offset)
2956ed4bb43SVijay Viswanath {
2966ed4bb43SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
2976ed4bb43SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
2986ed4bb43SVijay Viswanath 
2996ed4bb43SVijay Viswanath 	return readl_relaxed(msm_host->core_mem + offset);
3006ed4bb43SVijay Viswanath }
3016ed4bb43SVijay Viswanath 
3026ed4bb43SVijay Viswanath static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
3036ed4bb43SVijay Viswanath 		u32 offset)
3046ed4bb43SVijay Viswanath {
3056ed4bb43SVijay Viswanath 	return readl_relaxed(host->ioaddr + offset);
3066ed4bb43SVijay Viswanath }
3076ed4bb43SVijay Viswanath 
3086ed4bb43SVijay Viswanath static void sdhci_msm_mci_variant_writel_relaxed(u32 val,
3096ed4bb43SVijay Viswanath 		struct sdhci_host *host, u32 offset)
3106ed4bb43SVijay Viswanath {
3116ed4bb43SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3126ed4bb43SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
3136ed4bb43SVijay Viswanath 
3146ed4bb43SVijay Viswanath 	writel_relaxed(val, msm_host->core_mem + offset);
3156ed4bb43SVijay Viswanath }
3166ed4bb43SVijay Viswanath 
3176ed4bb43SVijay Viswanath static void sdhci_msm_v5_variant_writel_relaxed(u32 val,
3186ed4bb43SVijay Viswanath 		struct sdhci_host *host, u32 offset)
3196ed4bb43SVijay Viswanath {
3206ed4bb43SVijay Viswanath 	writel_relaxed(val, host->ioaddr + offset);
3216ed4bb43SVijay Viswanath }
3226ed4bb43SVijay Viswanath 
3230fb8a3d4SRitesh Harjani static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
3240fb8a3d4SRitesh Harjani 						    unsigned int clock)
3250fb8a3d4SRitesh Harjani {
3260fb8a3d4SRitesh Harjani 	struct mmc_ios ios = host->mmc->ios;
3270fb8a3d4SRitesh Harjani 	/*
3280fb8a3d4SRitesh Harjani 	 * The SDHC requires internal clock frequency to be double the
3290fb8a3d4SRitesh Harjani 	 * actual clock that will be set for DDR mode. The controller
3300fb8a3d4SRitesh Harjani 	 * uses the faster clock(100/400MHz) for some of its parts and
3310fb8a3d4SRitesh Harjani 	 * send the actual required clock (50/200MHz) to the card.
3320fb8a3d4SRitesh Harjani 	 */
3330fb8a3d4SRitesh Harjani 	if (ios.timing == MMC_TIMING_UHS_DDR50 ||
3340fb8a3d4SRitesh Harjani 	    ios.timing == MMC_TIMING_MMC_DDR52 ||
335d7507aa1SRitesh Harjani 	    ios.timing == MMC_TIMING_MMC_HS400 ||
336d7507aa1SRitesh Harjani 	    host->flags & SDHCI_HS400_TUNING)
3370fb8a3d4SRitesh Harjani 		clock *= 2;
3380fb8a3d4SRitesh Harjani 	return clock;
3390fb8a3d4SRitesh Harjani }
3400fb8a3d4SRitesh Harjani 
3410fb8a3d4SRitesh Harjani static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
3420fb8a3d4SRitesh Harjani 					    unsigned int clock)
3430fb8a3d4SRitesh Harjani {
3440fb8a3d4SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3450fb8a3d4SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
3460fb8a3d4SRitesh Harjani 	struct mmc_ios curr_ios = host->mmc->ios;
347e4bf91f6SBjorn Andersson 	struct clk *core_clk = msm_host->bulk_clks[0].clk;
3480fb8a3d4SRitesh Harjani 	int rc;
3490fb8a3d4SRitesh Harjani 
3500fb8a3d4SRitesh Harjani 	clock = msm_get_clock_rate_for_bus_mode(host, clock);
3510472f8d3SRajendra Nayak 	rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), clock);
3520fb8a3d4SRitesh Harjani 	if (rc) {
3530fb8a3d4SRitesh Harjani 		pr_err("%s: Failed to set clock at rate %u at timing %d\n",
3540fb8a3d4SRitesh Harjani 		       mmc_hostname(host->mmc), clock,
3550fb8a3d4SRitesh Harjani 		       curr_ios.timing);
3560fb8a3d4SRitesh Harjani 		return;
3570fb8a3d4SRitesh Harjani 	}
3580fb8a3d4SRitesh Harjani 	msm_host->clk_rate = clock;
3590fb8a3d4SRitesh Harjani 	pr_debug("%s: Setting clock at rate %lu at timing %d\n",
360e4bf91f6SBjorn Andersson 		 mmc_hostname(host->mmc), clk_get_rate(core_clk),
3610fb8a3d4SRitesh Harjani 		 curr_ios.timing);
3620fb8a3d4SRitesh Harjani }
3630fb8a3d4SRitesh Harjani 
3640eb0d9f4SGeorgi Djakov /* Platform specific tuning */
365415b5a75SGeorgi Djakov static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
366415b5a75SGeorgi Djakov {
367415b5a75SGeorgi Djakov 	u32 wait_cnt = 50;
368415b5a75SGeorgi Djakov 	u8 ck_out_en;
369415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
370bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
371bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
372415b5a75SGeorgi Djakov 
373415b5a75SGeorgi Djakov 	/* Poll for CK_OUT_EN bit.  max. poll time = 50us */
374bc99266bSSayali Lokhande 	ck_out_en = !!(readl_relaxed(host->ioaddr +
375bc99266bSSayali Lokhande 			msm_offset->core_dll_config) & CORE_CK_OUT_EN);
376415b5a75SGeorgi Djakov 
377415b5a75SGeorgi Djakov 	while (ck_out_en != poll) {
378415b5a75SGeorgi Djakov 		if (--wait_cnt == 0) {
379415b5a75SGeorgi Djakov 			dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
380415b5a75SGeorgi Djakov 			       mmc_hostname(mmc), poll);
381415b5a75SGeorgi Djakov 			return -ETIMEDOUT;
382415b5a75SGeorgi Djakov 		}
383415b5a75SGeorgi Djakov 		udelay(1);
384415b5a75SGeorgi Djakov 
385bc99266bSSayali Lokhande 		ck_out_en = !!(readl_relaxed(host->ioaddr +
386bc99266bSSayali Lokhande 			msm_offset->core_dll_config) & CORE_CK_OUT_EN);
387415b5a75SGeorgi Djakov 	}
388415b5a75SGeorgi Djakov 
389415b5a75SGeorgi Djakov 	return 0;
390415b5a75SGeorgi Djakov }
391415b5a75SGeorgi Djakov 
392415b5a75SGeorgi Djakov static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
393415b5a75SGeorgi Djakov {
394415b5a75SGeorgi Djakov 	int rc;
395415b5a75SGeorgi Djakov 	static const u8 grey_coded_phase_table[] = {
396415b5a75SGeorgi Djakov 		0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
397415b5a75SGeorgi Djakov 		0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
398415b5a75SGeorgi Djakov 	};
399415b5a75SGeorgi Djakov 	unsigned long flags;
400415b5a75SGeorgi Djakov 	u32 config;
401415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
402bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
403bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
404415b5a75SGeorgi Djakov 
405abf270e5SRitesh Harjani 	if (phase > 0xf)
406abf270e5SRitesh Harjani 		return -EINVAL;
407abf270e5SRitesh Harjani 
408415b5a75SGeorgi Djakov 	spin_lock_irqsave(&host->lock, flags);
409415b5a75SGeorgi Djakov 
410bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
411415b5a75SGeorgi Djakov 	config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
412415b5a75SGeorgi Djakov 	config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
413bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
414415b5a75SGeorgi Djakov 
415415b5a75SGeorgi Djakov 	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
416415b5a75SGeorgi Djakov 	rc = msm_dll_poll_ck_out_en(host, 0);
417415b5a75SGeorgi Djakov 	if (rc)
418415b5a75SGeorgi Djakov 		goto err_out;
419415b5a75SGeorgi Djakov 
420415b5a75SGeorgi Djakov 	/*
421415b5a75SGeorgi Djakov 	 * Write the selected DLL clock output phase (0 ... 15)
422415b5a75SGeorgi Djakov 	 * to CDR_SELEXT bit field of DLL_CONFIG register.
423415b5a75SGeorgi Djakov 	 */
424bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
425415b5a75SGeorgi Djakov 	config &= ~CDR_SELEXT_MASK;
426415b5a75SGeorgi Djakov 	config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
427bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
428415b5a75SGeorgi Djakov 
429bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
43029301f40SRitesh Harjani 	config |= CORE_CK_OUT_EN;
431bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
432415b5a75SGeorgi Djakov 
433415b5a75SGeorgi Djakov 	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
434415b5a75SGeorgi Djakov 	rc = msm_dll_poll_ck_out_en(host, 1);
435415b5a75SGeorgi Djakov 	if (rc)
436415b5a75SGeorgi Djakov 		goto err_out;
437415b5a75SGeorgi Djakov 
438bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
439415b5a75SGeorgi Djakov 	config |= CORE_CDR_EN;
440415b5a75SGeorgi Djakov 	config &= ~CORE_CDR_EXT_EN;
441bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
442415b5a75SGeorgi Djakov 	goto out;
443415b5a75SGeorgi Djakov 
444415b5a75SGeorgi Djakov err_out:
445415b5a75SGeorgi Djakov 	dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
446415b5a75SGeorgi Djakov 	       mmc_hostname(mmc), phase);
447415b5a75SGeorgi Djakov out:
448415b5a75SGeorgi Djakov 	spin_unlock_irqrestore(&host->lock, flags);
449415b5a75SGeorgi Djakov 	return rc;
450415b5a75SGeorgi Djakov }
451415b5a75SGeorgi Djakov 
452415b5a75SGeorgi Djakov /*
453415b5a75SGeorgi Djakov  * Find out the greatest range of consecuitive selected
454415b5a75SGeorgi Djakov  * DLL clock output phases that can be used as sampling
455415b5a75SGeorgi Djakov  * setting for SD3.0 UHS-I card read operation (in SDR104
456ff06ce41SVenkat Gopalakrishnan  * timing mode) or for eMMC4.5 card read operation (in
457ff06ce41SVenkat Gopalakrishnan  * HS400/HS200 timing mode).
458415b5a75SGeorgi Djakov  * Select the 3/4 of the range and configure the DLL with the
459415b5a75SGeorgi Djakov  * selected DLL clock output phase.
460415b5a75SGeorgi Djakov  */
461415b5a75SGeorgi Djakov 
462415b5a75SGeorgi Djakov static int msm_find_most_appropriate_phase(struct sdhci_host *host,
463415b5a75SGeorgi Djakov 					   u8 *phase_table, u8 total_phases)
464415b5a75SGeorgi Djakov {
465415b5a75SGeorgi Djakov 	int ret;
466415b5a75SGeorgi Djakov 	u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
467415b5a75SGeorgi Djakov 	u8 phases_per_row[MAX_PHASES] = { 0 };
468415b5a75SGeorgi Djakov 	int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
469415b5a75SGeorgi Djakov 	int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
470415b5a75SGeorgi Djakov 	bool phase_0_found = false, phase_15_found = false;
471415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
472415b5a75SGeorgi Djakov 
473415b5a75SGeorgi Djakov 	if (!total_phases || (total_phases > MAX_PHASES)) {
474415b5a75SGeorgi Djakov 		dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
475415b5a75SGeorgi Djakov 		       mmc_hostname(mmc), total_phases);
476415b5a75SGeorgi Djakov 		return -EINVAL;
477415b5a75SGeorgi Djakov 	}
478415b5a75SGeorgi Djakov 
479415b5a75SGeorgi Djakov 	for (cnt = 0; cnt < total_phases; cnt++) {
480415b5a75SGeorgi Djakov 		ranges[row_index][col_index] = phase_table[cnt];
481415b5a75SGeorgi Djakov 		phases_per_row[row_index] += 1;
482415b5a75SGeorgi Djakov 		col_index++;
483415b5a75SGeorgi Djakov 
484415b5a75SGeorgi Djakov 		if ((cnt + 1) == total_phases) {
485415b5a75SGeorgi Djakov 			continue;
486415b5a75SGeorgi Djakov 		/* check if next phase in phase_table is consecutive or not */
487415b5a75SGeorgi Djakov 		} else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
488415b5a75SGeorgi Djakov 			row_index++;
489415b5a75SGeorgi Djakov 			col_index = 0;
490415b5a75SGeorgi Djakov 		}
491415b5a75SGeorgi Djakov 	}
492415b5a75SGeorgi Djakov 
493415b5a75SGeorgi Djakov 	if (row_index >= MAX_PHASES)
494415b5a75SGeorgi Djakov 		return -EINVAL;
495415b5a75SGeorgi Djakov 
496415b5a75SGeorgi Djakov 	/* Check if phase-0 is present in first valid window? */
497415b5a75SGeorgi Djakov 	if (!ranges[0][0]) {
498415b5a75SGeorgi Djakov 		phase_0_found = true;
499415b5a75SGeorgi Djakov 		phase_0_raw_index = 0;
500415b5a75SGeorgi Djakov 		/* Check if cycle exist between 2 valid windows */
501415b5a75SGeorgi Djakov 		for (cnt = 1; cnt <= row_index; cnt++) {
502415b5a75SGeorgi Djakov 			if (phases_per_row[cnt]) {
503415b5a75SGeorgi Djakov 				for (i = 0; i < phases_per_row[cnt]; i++) {
504415b5a75SGeorgi Djakov 					if (ranges[cnt][i] == 15) {
505415b5a75SGeorgi Djakov 						phase_15_found = true;
506415b5a75SGeorgi Djakov 						phase_15_raw_index = cnt;
507415b5a75SGeorgi Djakov 						break;
508415b5a75SGeorgi Djakov 					}
509415b5a75SGeorgi Djakov 				}
510415b5a75SGeorgi Djakov 			}
511415b5a75SGeorgi Djakov 		}
512415b5a75SGeorgi Djakov 	}
513415b5a75SGeorgi Djakov 
514415b5a75SGeorgi Djakov 	/* If 2 valid windows form cycle then merge them as single window */
515415b5a75SGeorgi Djakov 	if (phase_0_found && phase_15_found) {
516415b5a75SGeorgi Djakov 		/* number of phases in raw where phase 0 is present */
517415b5a75SGeorgi Djakov 		u8 phases_0 = phases_per_row[phase_0_raw_index];
518415b5a75SGeorgi Djakov 		/* number of phases in raw where phase 15 is present */
519415b5a75SGeorgi Djakov 		u8 phases_15 = phases_per_row[phase_15_raw_index];
520415b5a75SGeorgi Djakov 
521415b5a75SGeorgi Djakov 		if (phases_0 + phases_15 >= MAX_PHASES)
522415b5a75SGeorgi Djakov 			/*
523415b5a75SGeorgi Djakov 			 * If there are more than 1 phase windows then total
524415b5a75SGeorgi Djakov 			 * number of phases in both the windows should not be
525415b5a75SGeorgi Djakov 			 * more than or equal to MAX_PHASES.
526415b5a75SGeorgi Djakov 			 */
527415b5a75SGeorgi Djakov 			return -EINVAL;
528415b5a75SGeorgi Djakov 
529415b5a75SGeorgi Djakov 		/* Merge 2 cyclic windows */
530415b5a75SGeorgi Djakov 		i = phases_15;
531415b5a75SGeorgi Djakov 		for (cnt = 0; cnt < phases_0; cnt++) {
532415b5a75SGeorgi Djakov 			ranges[phase_15_raw_index][i] =
533415b5a75SGeorgi Djakov 			    ranges[phase_0_raw_index][cnt];
534415b5a75SGeorgi Djakov 			if (++i >= MAX_PHASES)
535415b5a75SGeorgi Djakov 				break;
536415b5a75SGeorgi Djakov 		}
537415b5a75SGeorgi Djakov 
538415b5a75SGeorgi Djakov 		phases_per_row[phase_0_raw_index] = 0;
539415b5a75SGeorgi Djakov 		phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
540415b5a75SGeorgi Djakov 	}
541415b5a75SGeorgi Djakov 
542415b5a75SGeorgi Djakov 	for (cnt = 0; cnt <= row_index; cnt++) {
543415b5a75SGeorgi Djakov 		if (phases_per_row[cnt] > curr_max) {
544415b5a75SGeorgi Djakov 			curr_max = phases_per_row[cnt];
545415b5a75SGeorgi Djakov 			selected_row_index = cnt;
546415b5a75SGeorgi Djakov 		}
547415b5a75SGeorgi Djakov 	}
548415b5a75SGeorgi Djakov 
549415b5a75SGeorgi Djakov 	i = (curr_max * 3) / 4;
550415b5a75SGeorgi Djakov 	if (i)
551415b5a75SGeorgi Djakov 		i--;
552415b5a75SGeorgi Djakov 
553415b5a75SGeorgi Djakov 	ret = ranges[selected_row_index][i];
554415b5a75SGeorgi Djakov 
555415b5a75SGeorgi Djakov 	if (ret >= MAX_PHASES) {
556415b5a75SGeorgi Djakov 		ret = -EINVAL;
557415b5a75SGeorgi Djakov 		dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
558415b5a75SGeorgi Djakov 		       mmc_hostname(mmc), ret);
559415b5a75SGeorgi Djakov 	}
560415b5a75SGeorgi Djakov 
561415b5a75SGeorgi Djakov 	return ret;
562415b5a75SGeorgi Djakov }
563415b5a75SGeorgi Djakov 
564415b5a75SGeorgi Djakov static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
565415b5a75SGeorgi Djakov {
566415b5a75SGeorgi Djakov 	u32 mclk_freq = 0, config;
567bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
568bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
569415b5a75SGeorgi Djakov 
570415b5a75SGeorgi Djakov 	/* Program the MCLK value to MCLK_FREQ bit field */
571415b5a75SGeorgi Djakov 	if (host->clock <= 112000000)
572415b5a75SGeorgi Djakov 		mclk_freq = 0;
573415b5a75SGeorgi Djakov 	else if (host->clock <= 125000000)
574415b5a75SGeorgi Djakov 		mclk_freq = 1;
575415b5a75SGeorgi Djakov 	else if (host->clock <= 137000000)
576415b5a75SGeorgi Djakov 		mclk_freq = 2;
577415b5a75SGeorgi Djakov 	else if (host->clock <= 150000000)
578415b5a75SGeorgi Djakov 		mclk_freq = 3;
579415b5a75SGeorgi Djakov 	else if (host->clock <= 162000000)
580415b5a75SGeorgi Djakov 		mclk_freq = 4;
581415b5a75SGeorgi Djakov 	else if (host->clock <= 175000000)
582415b5a75SGeorgi Djakov 		mclk_freq = 5;
583415b5a75SGeorgi Djakov 	else if (host->clock <= 187000000)
584415b5a75SGeorgi Djakov 		mclk_freq = 6;
585415b5a75SGeorgi Djakov 	else if (host->clock <= 200000000)
586415b5a75SGeorgi Djakov 		mclk_freq = 7;
587415b5a75SGeorgi Djakov 
588bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
589415b5a75SGeorgi Djakov 	config &= ~CMUX_SHIFT_PHASE_MASK;
590415b5a75SGeorgi Djakov 	config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
591bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
592415b5a75SGeorgi Djakov }
593415b5a75SGeorgi Djakov 
594415b5a75SGeorgi Djakov /* Initialize the DLL (Programmable Delay Line) */
595415b5a75SGeorgi Djakov static int msm_init_cm_dll(struct sdhci_host *host)
596415b5a75SGeorgi Djakov {
597415b5a75SGeorgi Djakov 	struct mmc_host *mmc = host->mmc;
59883736352SVenkat Gopalakrishnan 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
59983736352SVenkat Gopalakrishnan 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
600415b5a75SGeorgi Djakov 	int wait_cnt = 50;
6015e6b6651SJorge Ramirez-Ortiz 	unsigned long flags, xo_clk = 0;
60229301f40SRitesh Harjani 	u32 config;
603bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
604bc99266bSSayali Lokhande 					msm_host->offset;
605415b5a75SGeorgi Djakov 
6065e6b6651SJorge Ramirez-Ortiz 	if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
6075e6b6651SJorge Ramirez-Ortiz 		xo_clk = clk_get_rate(msm_host->xo_clk);
6085e6b6651SJorge Ramirez-Ortiz 
609415b5a75SGeorgi Djakov 	spin_lock_irqsave(&host->lock, flags);
610415b5a75SGeorgi Djakov 
611415b5a75SGeorgi Djakov 	/*
612415b5a75SGeorgi Djakov 	 * Make sure that clock is always enabled when DLL
613415b5a75SGeorgi Djakov 	 * tuning is in progress. Keeping PWRSAVE ON may
614415b5a75SGeorgi Djakov 	 * turn off the clock.
615415b5a75SGeorgi Djakov 	 */
616bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
61729301f40SRitesh Harjani 	config &= ~CORE_CLK_PWRSAVE;
618bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
619415b5a75SGeorgi Djakov 
62083736352SVenkat Gopalakrishnan 	if (msm_host->use_14lpp_dll_reset) {
621bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
622bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
62383736352SVenkat Gopalakrishnan 		config &= ~CORE_CK_OUT_EN;
624bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
625bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
62683736352SVenkat Gopalakrishnan 
627bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
628bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
62983736352SVenkat Gopalakrishnan 		config |= CORE_DLL_CLOCK_DISABLE;
630bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
631bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
63283736352SVenkat Gopalakrishnan 	}
63383736352SVenkat Gopalakrishnan 
634bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
635bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
63629301f40SRitesh Harjani 	config |= CORE_DLL_RST;
637bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
638bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
639415b5a75SGeorgi Djakov 
640bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
641bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
64229301f40SRitesh Harjani 	config |= CORE_DLL_PDN;
643bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
644bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
645415b5a75SGeorgi Djakov 	msm_cm_dll_set_freq(host);
646415b5a75SGeorgi Djakov 
64783736352SVenkat Gopalakrishnan 	if (msm_host->use_14lpp_dll_reset &&
64883736352SVenkat Gopalakrishnan 	    !IS_ERR_OR_NULL(msm_host->xo_clk)) {
64983736352SVenkat Gopalakrishnan 		u32 mclk_freq = 0;
65083736352SVenkat Gopalakrishnan 
651bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
652bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
65383736352SVenkat Gopalakrishnan 		config &= CORE_FLL_CYCLE_CNT;
65483736352SVenkat Gopalakrishnan 		if (config)
65583736352SVenkat Gopalakrishnan 			mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
6565e6b6651SJorge Ramirez-Ortiz 					xo_clk);
65783736352SVenkat Gopalakrishnan 		else
65883736352SVenkat Gopalakrishnan 			mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
6595e6b6651SJorge Ramirez-Ortiz 					xo_clk);
66083736352SVenkat Gopalakrishnan 
661bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
662bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
66383736352SVenkat Gopalakrishnan 		config &= ~(0xFF << 10);
66483736352SVenkat Gopalakrishnan 		config |= mclk_freq << 10;
66583736352SVenkat Gopalakrishnan 
666bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
667bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
66883736352SVenkat Gopalakrishnan 		/* wait for 5us before enabling DLL clock */
66983736352SVenkat Gopalakrishnan 		udelay(5);
67083736352SVenkat Gopalakrishnan 	}
67183736352SVenkat Gopalakrishnan 
672bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
673bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
67429301f40SRitesh Harjani 	config &= ~CORE_DLL_RST;
675bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
676bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
677415b5a75SGeorgi Djakov 
678bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
679bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
68029301f40SRitesh Harjani 	config &= ~CORE_DLL_PDN;
681bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
682bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
683415b5a75SGeorgi Djakov 
68483736352SVenkat Gopalakrishnan 	if (msm_host->use_14lpp_dll_reset) {
68583736352SVenkat Gopalakrishnan 		msm_cm_dll_set_freq(host);
686bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
687bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
68883736352SVenkat Gopalakrishnan 		config &= ~CORE_DLL_CLOCK_DISABLE;
689bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
690bc99266bSSayali Lokhande 				msm_offset->core_dll_config_2);
69183736352SVenkat Gopalakrishnan 	}
69283736352SVenkat Gopalakrishnan 
6935c30f340SVeerabhadrarao Badiganti 	/*
6945c30f340SVeerabhadrarao Badiganti 	 * Configure DLL user control register to enable DLL status.
6955c30f340SVeerabhadrarao Badiganti 	 * This setting is applicable to SDCC v5.1 onwards only.
6965c30f340SVeerabhadrarao Badiganti 	 */
6975c30f340SVeerabhadrarao Badiganti 	if (msm_host->uses_tassadar_dll) {
6985c30f340SVeerabhadrarao Badiganti 		config = DLL_USR_CTL_POR_VAL | FINE_TUNE_MODE_EN |
6995c30f340SVeerabhadrarao Badiganti 			ENABLE_DLL_LOCK_STATUS | BIAS_OK_SIGNAL;
7005c30f340SVeerabhadrarao Badiganti 		writel_relaxed(config, host->ioaddr +
7015c30f340SVeerabhadrarao Badiganti 				msm_offset->core_dll_usr_ctl);
70204816e67SSarthak Garg 
70304816e67SSarthak Garg 		config = readl_relaxed(host->ioaddr +
70404816e67SSarthak Garg 				msm_offset->core_dll_config_3);
70504816e67SSarthak Garg 		config &= ~0xFF;
70604816e67SSarthak Garg 		if (msm_host->clk_rate < 150000000)
70704816e67SSarthak Garg 			config |= DLL_CONFIG_3_LOW_FREQ_VAL;
70804816e67SSarthak Garg 		else
70904816e67SSarthak Garg 			config |= DLL_CONFIG_3_HIGH_FREQ_VAL;
71004816e67SSarthak Garg 		writel_relaxed(config, host->ioaddr +
71104816e67SSarthak Garg 			msm_offset->core_dll_config_3);
7125c30f340SVeerabhadrarao Badiganti 	}
7135c30f340SVeerabhadrarao Badiganti 
714bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
715bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
71629301f40SRitesh Harjani 	config |= CORE_DLL_EN;
717bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
718bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
719415b5a75SGeorgi Djakov 
720bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr +
721bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
72229301f40SRitesh Harjani 	config |= CORE_CK_OUT_EN;
723bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr +
724bc99266bSSayali Lokhande 			msm_offset->core_dll_config);
725415b5a75SGeorgi Djakov 
726415b5a75SGeorgi Djakov 	/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
727bc99266bSSayali Lokhande 	while (!(readl_relaxed(host->ioaddr + msm_offset->core_dll_status) &
728415b5a75SGeorgi Djakov 		 CORE_DLL_LOCK)) {
729415b5a75SGeorgi Djakov 		/* max. wait for 50us sec for LOCK bit to be set */
730415b5a75SGeorgi Djakov 		if (--wait_cnt == 0) {
731415b5a75SGeorgi Djakov 			dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
732415b5a75SGeorgi Djakov 			       mmc_hostname(mmc));
733415b5a75SGeorgi Djakov 			spin_unlock_irqrestore(&host->lock, flags);
734415b5a75SGeorgi Djakov 			return -ETIMEDOUT;
735415b5a75SGeorgi Djakov 		}
736415b5a75SGeorgi Djakov 		udelay(1);
737415b5a75SGeorgi Djakov 	}
738415b5a75SGeorgi Djakov 
739415b5a75SGeorgi Djakov 	spin_unlock_irqrestore(&host->lock, flags);
740415b5a75SGeorgi Djakov 	return 0;
741415b5a75SGeorgi Djakov }
742415b5a75SGeorgi Djakov 
743b54aaa8aSRitesh Harjani static void msm_hc_select_default(struct sdhci_host *host)
744b54aaa8aSRitesh Harjani {
745b54aaa8aSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
746b54aaa8aSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
747b54aaa8aSRitesh Harjani 	u32 config;
748bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
749bc99266bSSayali Lokhande 					msm_host->offset;
750b54aaa8aSRitesh Harjani 
751b54aaa8aSRitesh Harjani 	if (!msm_host->use_cdclp533) {
752b54aaa8aSRitesh Harjani 		config = readl_relaxed(host->ioaddr +
753bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec3);
754b54aaa8aSRitesh Harjani 		config &= ~CORE_PWRSAVE_DLL;
755b54aaa8aSRitesh Harjani 		writel_relaxed(config, host->ioaddr +
756bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec3);
757b54aaa8aSRitesh Harjani 	}
758b54aaa8aSRitesh Harjani 
759bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
760b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_MCLK_SEL_MASK;
761b54aaa8aSRitesh Harjani 	config |= CORE_HC_MCLK_SEL_DFLT;
762bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
763b54aaa8aSRitesh Harjani 
764b54aaa8aSRitesh Harjani 	/*
765b54aaa8aSRitesh Harjani 	 * Disable HC_SELECT_IN to be able to use the UHS mode select
766b54aaa8aSRitesh Harjani 	 * configuration from Host Control2 register for all other
767b54aaa8aSRitesh Harjani 	 * modes.
768b54aaa8aSRitesh Harjani 	 * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
769b54aaa8aSRitesh Harjani 	 * in VENDOR_SPEC_FUNC
770b54aaa8aSRitesh Harjani 	 */
771bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
772b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_SELECT_IN_EN;
773b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_SELECT_IN_MASK;
774bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
775b54aaa8aSRitesh Harjani 
776b54aaa8aSRitesh Harjani 	/*
777b54aaa8aSRitesh Harjani 	 * Make sure above writes impacting free running MCLK are completed
778b54aaa8aSRitesh Harjani 	 * before changing the clk_rate at GCC.
779b54aaa8aSRitesh Harjani 	 */
780b54aaa8aSRitesh Harjani 	wmb();
781b54aaa8aSRitesh Harjani }
782b54aaa8aSRitesh Harjani 
783b54aaa8aSRitesh Harjani static void msm_hc_select_hs400(struct sdhci_host *host)
784b54aaa8aSRitesh Harjani {
785b54aaa8aSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
786b54aaa8aSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
78744bf2312SRitesh Harjani 	struct mmc_ios ios = host->mmc->ios;
788b54aaa8aSRitesh Harjani 	u32 config, dll_lock;
789b54aaa8aSRitesh Harjani 	int rc;
790bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
791bc99266bSSayali Lokhande 					msm_host->offset;
792b54aaa8aSRitesh Harjani 
793b54aaa8aSRitesh Harjani 	/* Select the divided clock (free running MCLK/2) */
794bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
795b54aaa8aSRitesh Harjani 	config &= ~CORE_HC_MCLK_SEL_MASK;
796b54aaa8aSRitesh Harjani 	config |= CORE_HC_MCLK_SEL_HS400;
797b54aaa8aSRitesh Harjani 
798bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
799b54aaa8aSRitesh Harjani 	/*
800b54aaa8aSRitesh Harjani 	 * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
801b54aaa8aSRitesh Harjani 	 * register
802b54aaa8aSRitesh Harjani 	 */
80344bf2312SRitesh Harjani 	if ((msm_host->tuning_done || ios.enhanced_strobe) &&
80444bf2312SRitesh Harjani 	    !msm_host->calibration_done) {
805bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
806bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
807b54aaa8aSRitesh Harjani 		config |= CORE_HC_SELECT_IN_HS400;
808b54aaa8aSRitesh Harjani 		config |= CORE_HC_SELECT_IN_EN;
809bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
810bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
811b54aaa8aSRitesh Harjani 	}
812b54aaa8aSRitesh Harjani 	if (!msm_host->clk_rate && !msm_host->use_cdclp533) {
813b54aaa8aSRitesh Harjani 		/*
814b54aaa8aSRitesh Harjani 		 * Poll on DLL_LOCK or DDR_DLL_LOCK bits in
815bc99266bSSayali Lokhande 		 * core_dll_status to be set. This should get set
816b54aaa8aSRitesh Harjani 		 * within 15 us at 200 MHz.
817b54aaa8aSRitesh Harjani 		 */
818b54aaa8aSRitesh Harjani 		rc = readl_relaxed_poll_timeout(host->ioaddr +
819bc99266bSSayali Lokhande 						msm_offset->core_dll_status,
820b54aaa8aSRitesh Harjani 						dll_lock,
821b54aaa8aSRitesh Harjani 						(dll_lock &
822b54aaa8aSRitesh Harjani 						(CORE_DLL_LOCK |
823b54aaa8aSRitesh Harjani 						CORE_DDR_DLL_LOCK)), 10,
824b54aaa8aSRitesh Harjani 						1000);
825b54aaa8aSRitesh Harjani 		if (rc == -ETIMEDOUT)
826b54aaa8aSRitesh Harjani 			pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n",
827b54aaa8aSRitesh Harjani 			       mmc_hostname(host->mmc), dll_lock);
828b54aaa8aSRitesh Harjani 	}
829b54aaa8aSRitesh Harjani 	/*
830b54aaa8aSRitesh Harjani 	 * Make sure above writes impacting free running MCLK are completed
831b54aaa8aSRitesh Harjani 	 * before changing the clk_rate at GCC.
832b54aaa8aSRitesh Harjani 	 */
833b54aaa8aSRitesh Harjani 	wmb();
834b54aaa8aSRitesh Harjani }
835b54aaa8aSRitesh Harjani 
836b54aaa8aSRitesh Harjani /*
837b54aaa8aSRitesh Harjani  * sdhci_msm_hc_select_mode :- In general all timing modes are
838b54aaa8aSRitesh Harjani  * controlled via UHS mode select in Host Control2 register.
839b54aaa8aSRitesh Harjani  * eMMC specific HS200/HS400 doesn't have their respective modes
840b54aaa8aSRitesh Harjani  * defined here, hence we use these values.
841b54aaa8aSRitesh Harjani  *
842b54aaa8aSRitesh Harjani  * HS200 - SDR104 (Since they both are equivalent in functionality)
843b54aaa8aSRitesh Harjani  * HS400 - This involves multiple configurations
844b54aaa8aSRitesh Harjani  *		Initially SDR104 - when tuning is required as HS200
845b54aaa8aSRitesh Harjani  *		Then when switching to DDR @ 400MHz (HS400) we use
846b54aaa8aSRitesh Harjani  *		the vendor specific HC_SELECT_IN to control the mode.
847b54aaa8aSRitesh Harjani  *
848b54aaa8aSRitesh Harjani  * In addition to controlling the modes we also need to select the
849b54aaa8aSRitesh Harjani  * correct input clock for DLL depending on the mode.
850b54aaa8aSRitesh Harjani  *
851b54aaa8aSRitesh Harjani  * HS400 - divided clock (free running MCLK/2)
852b54aaa8aSRitesh Harjani  * All other modes - default (free running MCLK)
853b54aaa8aSRitesh Harjani  */
85430de038dSMasahiro Yamada static void sdhci_msm_hc_select_mode(struct sdhci_host *host)
855b54aaa8aSRitesh Harjani {
856b54aaa8aSRitesh Harjani 	struct mmc_ios ios = host->mmc->ios;
857b54aaa8aSRitesh Harjani 
858d7507aa1SRitesh Harjani 	if (ios.timing == MMC_TIMING_MMC_HS400 ||
859d7507aa1SRitesh Harjani 	    host->flags & SDHCI_HS400_TUNING)
860b54aaa8aSRitesh Harjani 		msm_hc_select_hs400(host);
861b54aaa8aSRitesh Harjani 	else
862b54aaa8aSRitesh Harjani 		msm_hc_select_default(host);
863b54aaa8aSRitesh Harjani }
864b54aaa8aSRitesh Harjani 
865cc392c58SRitesh Harjani static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
866cc392c58SRitesh Harjani {
867cc392c58SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
868cc392c58SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
869cc392c58SRitesh Harjani 	u32 config, calib_done;
870cc392c58SRitesh Harjani 	int ret;
871bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
872bc99266bSSayali Lokhande 					msm_host->offset;
873cc392c58SRitesh Harjani 
874cc392c58SRitesh Harjani 	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
875cc392c58SRitesh Harjani 
876cc392c58SRitesh Harjani 	/*
877cc392c58SRitesh Harjani 	 * Retuning in HS400 (DDR mode) will fail, just reset the
878cc392c58SRitesh Harjani 	 * tuning block and restore the saved tuning phase.
879cc392c58SRitesh Harjani 	 */
880cc392c58SRitesh Harjani 	ret = msm_init_cm_dll(host);
881cc392c58SRitesh Harjani 	if (ret)
882cc392c58SRitesh Harjani 		goto out;
883cc392c58SRitesh Harjani 
884cc392c58SRitesh Harjani 	/* Set the selected phase in delay line hw block */
885cc392c58SRitesh Harjani 	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
886cc392c58SRitesh Harjani 	if (ret)
887cc392c58SRitesh Harjani 		goto out;
888cc392c58SRitesh Harjani 
889bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
890cc392c58SRitesh Harjani 	config |= CORE_CMD_DAT_TRACK_SEL;
891bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
892cc392c58SRitesh Harjani 
893bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
894cc392c58SRitesh Harjani 	config &= ~CORE_CDC_T4_DLY_SEL;
895bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
896cc392c58SRitesh Harjani 
897cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
898cc392c58SRitesh Harjani 	config &= ~CORE_CDC_SWITCH_BYPASS_OFF;
899cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
900cc392c58SRitesh Harjani 
901cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
902cc392c58SRitesh Harjani 	config |= CORE_CDC_SWITCH_RC_EN;
903cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
904cc392c58SRitesh Harjani 
905bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
906cc392c58SRitesh Harjani 	config &= ~CORE_START_CDC_TRAFFIC;
907bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
908cc392c58SRitesh Harjani 
909543c576dSRitesh Harjani 	/* Perform CDC Register Initialization Sequence */
910cc392c58SRitesh Harjani 
911cc392c58SRitesh Harjani 	writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
912cc392c58SRitesh Harjani 	writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
913cc392c58SRitesh Harjani 	writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
914cc392c58SRitesh Harjani 	writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
915cc392c58SRitesh Harjani 	writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
916cc392c58SRitesh Harjani 	writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
917083c9aa0SSubhash Jadavani 	writel_relaxed(0x4E2, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
918cc392c58SRitesh Harjani 	writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
919cc392c58SRitesh Harjani 	writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
920cc392c58SRitesh Harjani 
921cc392c58SRitesh Harjani 	/* CDC HW Calibration */
922cc392c58SRitesh Harjani 
923cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
924cc392c58SRitesh Harjani 	config |= CORE_SW_TRIG_FULL_CALIB;
925cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
926cc392c58SRitesh Harjani 
927cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
928cc392c58SRitesh Harjani 	config &= ~CORE_SW_TRIG_FULL_CALIB;
929cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
930cc392c58SRitesh Harjani 
931cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
932cc392c58SRitesh Harjani 	config |= CORE_HW_AUTOCAL_ENA;
933cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
934cc392c58SRitesh Harjani 
935cc392c58SRitesh Harjani 	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
936cc392c58SRitesh Harjani 	config |= CORE_TIMER_ENA;
937cc392c58SRitesh Harjani 	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
938cc392c58SRitesh Harjani 
939cc392c58SRitesh Harjani 	ret = readl_relaxed_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0,
940cc392c58SRitesh Harjani 					 calib_done,
941cc392c58SRitesh Harjani 					 (calib_done & CORE_CALIBRATION_DONE),
942cc392c58SRitesh Harjani 					 1, 50);
943cc392c58SRitesh Harjani 
944cc392c58SRitesh Harjani 	if (ret == -ETIMEDOUT) {
945cc392c58SRitesh Harjani 		pr_err("%s: %s: CDC calibration was not completed\n",
946cc392c58SRitesh Harjani 		       mmc_hostname(host->mmc), __func__);
947cc392c58SRitesh Harjani 		goto out;
948cc392c58SRitesh Harjani 	}
949cc392c58SRitesh Harjani 
950cc392c58SRitesh Harjani 	ret = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
951cc392c58SRitesh Harjani 			& CORE_CDC_ERROR_CODE_MASK;
952cc392c58SRitesh Harjani 	if (ret) {
953cc392c58SRitesh Harjani 		pr_err("%s: %s: CDC error code %d\n",
954cc392c58SRitesh Harjani 		       mmc_hostname(host->mmc), __func__, ret);
955cc392c58SRitesh Harjani 		ret = -EINVAL;
956cc392c58SRitesh Harjani 		goto out;
957cc392c58SRitesh Harjani 	}
958cc392c58SRitesh Harjani 
959bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
960cc392c58SRitesh Harjani 	config |= CORE_START_CDC_TRAFFIC;
961bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
962cc392c58SRitesh Harjani out:
963cc392c58SRitesh Harjani 	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
964cc392c58SRitesh Harjani 		 __func__, ret);
965cc392c58SRitesh Harjani 	return ret;
966cc392c58SRitesh Harjani }
967cc392c58SRitesh Harjani 
96802e4293dSRitesh Harjani static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
96902e4293dSRitesh Harjani {
97044bf2312SRitesh Harjani 	struct mmc_host *mmc = host->mmc;
971fa56ac97SVeerabhadrarao Badiganti 	u32 dll_status, config, ddr_cfg_offset;
97202e4293dSRitesh Harjani 	int ret;
973fa56ac97SVeerabhadrarao Badiganti 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
974fa56ac97SVeerabhadrarao Badiganti 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
975bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
976bc99266bSSayali Lokhande 					sdhci_priv_msm_offset(host);
97702e4293dSRitesh Harjani 
97802e4293dSRitesh Harjani 	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
97902e4293dSRitesh Harjani 
98002e4293dSRitesh Harjani 	/*
981bc99266bSSayali Lokhande 	 * Currently the core_ddr_config register defaults to desired
98202e4293dSRitesh Harjani 	 * configuration on reset. Currently reprogramming the power on
98302e4293dSRitesh Harjani 	 * reset (POR) value in case it might have been modified by
98402e4293dSRitesh Harjani 	 * bootloaders. In the future, if this changes, then the desired
98502e4293dSRitesh Harjani 	 * values will need to be programmed appropriately.
98602e4293dSRitesh Harjani 	 */
987fa56ac97SVeerabhadrarao Badiganti 	if (msm_host->updated_ddr_cfg)
988fa56ac97SVeerabhadrarao Badiganti 		ddr_cfg_offset = msm_offset->core_ddr_config;
989fa56ac97SVeerabhadrarao Badiganti 	else
990fa56ac97SVeerabhadrarao Badiganti 		ddr_cfg_offset = msm_offset->core_ddr_config_old;
9911dfbe3ffSSarthak Garg 	writel_relaxed(msm_host->ddr_config, host->ioaddr + ddr_cfg_offset);
99202e4293dSRitesh Harjani 
99344bf2312SRitesh Harjani 	if (mmc->ios.enhanced_strobe) {
994bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
995bc99266bSSayali Lokhande 				msm_offset->core_ddr_200_cfg);
99644bf2312SRitesh Harjani 		config |= CORE_CMDIN_RCLK_EN;
997bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
998bc99266bSSayali Lokhande 				msm_offset->core_ddr_200_cfg);
99944bf2312SRitesh Harjani 	}
100044bf2312SRitesh Harjani 
1001bc99266bSSayali Lokhande 	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2);
100202e4293dSRitesh Harjani 	config |= CORE_DDR_CAL_EN;
1003bc99266bSSayali Lokhande 	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config_2);
100402e4293dSRitesh Harjani 
1005bc99266bSSayali Lokhande 	ret = readl_relaxed_poll_timeout(host->ioaddr +
1006bc99266bSSayali Lokhande 					msm_offset->core_dll_status,
100702e4293dSRitesh Harjani 					dll_status,
100802e4293dSRitesh Harjani 					(dll_status & CORE_DDR_DLL_LOCK),
100902e4293dSRitesh Harjani 					10, 1000);
101002e4293dSRitesh Harjani 
101102e4293dSRitesh Harjani 	if (ret == -ETIMEDOUT) {
101202e4293dSRitesh Harjani 		pr_err("%s: %s: CM_DLL_SDC4 calibration was not completed\n",
101302e4293dSRitesh Harjani 		       mmc_hostname(host->mmc), __func__);
101402e4293dSRitesh Harjani 		goto out;
101502e4293dSRitesh Harjani 	}
101602e4293dSRitesh Harjani 
1017219c02caSRitesh Harjani 	/*
1018219c02caSRitesh Harjani 	 * Set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3.
1019219c02caSRitesh Harjani 	 * When MCLK is gated OFF, it is not gated for less than 0.5us
1020219c02caSRitesh Harjani 	 * and MCLK must be switched on for at-least 1us before DATA
1021219c02caSRitesh Harjani 	 * starts coming. Controllers with 14lpp and later tech DLL cannot
1022219c02caSRitesh Harjani 	 * guarantee above requirement. So PWRSAVE_DLL should not be
1023219c02caSRitesh Harjani 	 * turned on for host controllers using this DLL.
1024219c02caSRitesh Harjani 	 */
1025219c02caSRitesh Harjani 	if (!msm_host->use_14lpp_dll_reset) {
1026219c02caSRitesh Harjani 		config = readl_relaxed(host->ioaddr +
1027219c02caSRitesh Harjani 				msm_offset->core_vendor_spec3);
102802e4293dSRitesh Harjani 		config |= CORE_PWRSAVE_DLL;
1029219c02caSRitesh Harjani 		writel_relaxed(config, host->ioaddr +
1030219c02caSRitesh Harjani 				msm_offset->core_vendor_spec3);
1031219c02caSRitesh Harjani 	}
103202e4293dSRitesh Harjani 
103302e4293dSRitesh Harjani 	/*
103402e4293dSRitesh Harjani 	 * Drain writebuffer to ensure above DLL calibration
103502e4293dSRitesh Harjani 	 * and PWRSAVE DLL is enabled.
103602e4293dSRitesh Harjani 	 */
103702e4293dSRitesh Harjani 	wmb();
103802e4293dSRitesh Harjani out:
103902e4293dSRitesh Harjani 	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
104002e4293dSRitesh Harjani 		 __func__, ret);
104102e4293dSRitesh Harjani 	return ret;
104202e4293dSRitesh Harjani }
104302e4293dSRitesh Harjani 
104402e4293dSRitesh Harjani static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
104502e4293dSRitesh Harjani {
104602e4293dSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
104702e4293dSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
104844bf2312SRitesh Harjani 	struct mmc_host *mmc = host->mmc;
104902e4293dSRitesh Harjani 	int ret;
105002e4293dSRitesh Harjani 	u32 config;
1051bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1052bc99266bSSayali Lokhande 					msm_host->offset;
105302e4293dSRitesh Harjani 
105402e4293dSRitesh Harjani 	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
105502e4293dSRitesh Harjani 
105602e4293dSRitesh Harjani 	/*
105702e4293dSRitesh Harjani 	 * Retuning in HS400 (DDR mode) will fail, just reset the
105802e4293dSRitesh Harjani 	 * tuning block and restore the saved tuning phase.
105902e4293dSRitesh Harjani 	 */
106002e4293dSRitesh Harjani 	ret = msm_init_cm_dll(host);
106102e4293dSRitesh Harjani 	if (ret)
106202e4293dSRitesh Harjani 		goto out;
106302e4293dSRitesh Harjani 
106444bf2312SRitesh Harjani 	if (!mmc->ios.enhanced_strobe) {
106502e4293dSRitesh Harjani 		/* Set the selected phase in delay line hw block */
106644bf2312SRitesh Harjani 		ret = msm_config_cm_dll_phase(host,
106744bf2312SRitesh Harjani 					      msm_host->saved_tuning_phase);
106802e4293dSRitesh Harjani 		if (ret)
106902e4293dSRitesh Harjani 			goto out;
1070bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1071bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
107202e4293dSRitesh Harjani 		config |= CORE_CMD_DAT_TRACK_SEL;
1073bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
1074bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
107544bf2312SRitesh Harjani 	}
107644bf2312SRitesh Harjani 
107702e4293dSRitesh Harjani 	if (msm_host->use_cdclp533)
107802e4293dSRitesh Harjani 		ret = sdhci_msm_cdclp533_calibration(host);
107902e4293dSRitesh Harjani 	else
108002e4293dSRitesh Harjani 		ret = sdhci_msm_cm_dll_sdc4_calibration(host);
108102e4293dSRitesh Harjani out:
108202e4293dSRitesh Harjani 	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
108302e4293dSRitesh Harjani 		 __func__, ret);
108402e4293dSRitesh Harjani 	return ret;
108502e4293dSRitesh Harjani }
108602e4293dSRitesh Harjani 
108721f1e2d4SVeerabhadrarao Badiganti static bool sdhci_msm_is_tuning_needed(struct sdhci_host *host)
108821f1e2d4SVeerabhadrarao Badiganti {
108921f1e2d4SVeerabhadrarao Badiganti 	struct mmc_ios *ios = &host->mmc->ios;
109021f1e2d4SVeerabhadrarao Badiganti 
109121f1e2d4SVeerabhadrarao Badiganti 	/*
109221f1e2d4SVeerabhadrarao Badiganti 	 * Tuning is required for SDR104, HS200 and HS400 cards and
109321f1e2d4SVeerabhadrarao Badiganti 	 * if clock frequency is greater than 100MHz in these modes.
109421f1e2d4SVeerabhadrarao Badiganti 	 */
109521f1e2d4SVeerabhadrarao Badiganti 	if (host->clock <= CORE_FREQ_100MHZ ||
109621f1e2d4SVeerabhadrarao Badiganti 	    !(ios->timing == MMC_TIMING_MMC_HS400 ||
109721f1e2d4SVeerabhadrarao Badiganti 	    ios->timing == MMC_TIMING_MMC_HS200 ||
109821f1e2d4SVeerabhadrarao Badiganti 	    ios->timing == MMC_TIMING_UHS_SDR104) ||
109921f1e2d4SVeerabhadrarao Badiganti 	    ios->enhanced_strobe)
110021f1e2d4SVeerabhadrarao Badiganti 		return false;
110121f1e2d4SVeerabhadrarao Badiganti 
110221f1e2d4SVeerabhadrarao Badiganti 	return true;
110321f1e2d4SVeerabhadrarao Badiganti }
110421f1e2d4SVeerabhadrarao Badiganti 
110521f1e2d4SVeerabhadrarao Badiganti static int sdhci_msm_restore_sdr_dll_config(struct sdhci_host *host)
110621f1e2d4SVeerabhadrarao Badiganti {
110721f1e2d4SVeerabhadrarao Badiganti 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
110821f1e2d4SVeerabhadrarao Badiganti 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
110921f1e2d4SVeerabhadrarao Badiganti 	int ret;
111021f1e2d4SVeerabhadrarao Badiganti 
111121f1e2d4SVeerabhadrarao Badiganti 	/*
111221f1e2d4SVeerabhadrarao Badiganti 	 * SDR DLL comes into picture only for timing modes which needs
111321f1e2d4SVeerabhadrarao Badiganti 	 * tuning.
111421f1e2d4SVeerabhadrarao Badiganti 	 */
111521f1e2d4SVeerabhadrarao Badiganti 	if (!sdhci_msm_is_tuning_needed(host))
111621f1e2d4SVeerabhadrarao Badiganti 		return 0;
111721f1e2d4SVeerabhadrarao Badiganti 
111821f1e2d4SVeerabhadrarao Badiganti 	/* Reset the tuning block */
111921f1e2d4SVeerabhadrarao Badiganti 	ret = msm_init_cm_dll(host);
112021f1e2d4SVeerabhadrarao Badiganti 	if (ret)
112121f1e2d4SVeerabhadrarao Badiganti 		return ret;
112221f1e2d4SVeerabhadrarao Badiganti 
112321f1e2d4SVeerabhadrarao Badiganti 	/* Restore the tuning block */
112421f1e2d4SVeerabhadrarao Badiganti 	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
112521f1e2d4SVeerabhadrarao Badiganti 
112621f1e2d4SVeerabhadrarao Badiganti 	return ret;
112721f1e2d4SVeerabhadrarao Badiganti }
112821f1e2d4SVeerabhadrarao Badiganti 
1129a89e7bcbSLoic Poulain static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable)
1130a89e7bcbSLoic Poulain {
1131a89e7bcbSLoic Poulain 	const struct sdhci_msm_offset *msm_offset = sdhci_priv_msm_offset(host);
1132a89e7bcbSLoic Poulain 	u32 config, oldconfig = readl_relaxed(host->ioaddr +
1133a89e7bcbSLoic Poulain 					      msm_offset->core_dll_config);
1134a89e7bcbSLoic Poulain 
1135a89e7bcbSLoic Poulain 	config = oldconfig;
1136a89e7bcbSLoic Poulain 	if (enable) {
1137a89e7bcbSLoic Poulain 		config |= CORE_CDR_EN;
1138a89e7bcbSLoic Poulain 		config &= ~CORE_CDR_EXT_EN;
1139a89e7bcbSLoic Poulain 	} else {
1140a89e7bcbSLoic Poulain 		config &= ~CORE_CDR_EN;
1141a89e7bcbSLoic Poulain 		config |= CORE_CDR_EXT_EN;
1142a89e7bcbSLoic Poulain 	}
1143a89e7bcbSLoic Poulain 
1144a89e7bcbSLoic Poulain 	if (config != oldconfig) {
1145a89e7bcbSLoic Poulain 		writel_relaxed(config, host->ioaddr +
1146a89e7bcbSLoic Poulain 			       msm_offset->core_dll_config);
1147a89e7bcbSLoic Poulain 	}
1148a89e7bcbSLoic Poulain }
1149a89e7bcbSLoic Poulain 
11504436c535SRitesh Harjani static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
11510eb0d9f4SGeorgi Djakov {
11524436c535SRitesh Harjani 	struct sdhci_host *host = mmc_priv(mmc);
1153415b5a75SGeorgi Djakov 	int tuning_seq_cnt = 3;
115433d73935SUlf Hansson 	u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
1155415b5a75SGeorgi Djakov 	int rc;
1156415b5a75SGeorgi Djakov 	struct mmc_ios ios = host->mmc->ios;
1157abf270e5SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1158abf270e5SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1159415b5a75SGeorgi Djakov 
1160a89e7bcbSLoic Poulain 	if (!sdhci_msm_is_tuning_needed(host)) {
1161a89e7bcbSLoic Poulain 		msm_host->use_cdr = false;
1162a89e7bcbSLoic Poulain 		sdhci_msm_set_cdr(host, false);
11630eb0d9f4SGeorgi Djakov 		return 0;
1164a89e7bcbSLoic Poulain 	}
1165a89e7bcbSLoic Poulain 
1166a89e7bcbSLoic Poulain 	/* Clock-Data-Recovery used to dynamically adjust RX sampling point */
1167a89e7bcbSLoic Poulain 	msm_host->use_cdr = true;
1168415b5a75SGeorgi Djakov 
1169d7507aa1SRitesh Harjani 	/*
1170d7507aa1SRitesh Harjani 	 * For HS400 tuning in HS200 timing requires:
1171d7507aa1SRitesh Harjani 	 * - select MCLK/2 in VENDOR_SPEC
1172d7507aa1SRitesh Harjani 	 * - program MCLK to 400MHz (or nearest supported) in GCC
1173d7507aa1SRitesh Harjani 	 */
1174d7507aa1SRitesh Harjani 	if (host->flags & SDHCI_HS400_TUNING) {
1175d7507aa1SRitesh Harjani 		sdhci_msm_hc_select_mode(host);
1176d7507aa1SRitesh Harjani 		msm_set_clock_rate_for_bus_mode(host, ios.clock);
11774436c535SRitesh Harjani 		host->flags &= ~SDHCI_HS400_TUNING;
1178d7507aa1SRitesh Harjani 	}
1179d7507aa1SRitesh Harjani 
1180415b5a75SGeorgi Djakov retry:
1181415b5a75SGeorgi Djakov 	/* First of all reset the tuning block */
1182415b5a75SGeorgi Djakov 	rc = msm_init_cm_dll(host);
1183415b5a75SGeorgi Djakov 	if (rc)
118433d73935SUlf Hansson 		return rc;
1185415b5a75SGeorgi Djakov 
1186415b5a75SGeorgi Djakov 	phase = 0;
1187415b5a75SGeorgi Djakov 	do {
1188415b5a75SGeorgi Djakov 		/* Set the phase in delay line hw block */
1189415b5a75SGeorgi Djakov 		rc = msm_config_cm_dll_phase(host, phase);
1190415b5a75SGeorgi Djakov 		if (rc)
119133d73935SUlf Hansson 			return rc;
1192415b5a75SGeorgi Djakov 
11939979dbe5SChaotian Jing 		rc = mmc_send_tuning(mmc, opcode, NULL);
119433d73935SUlf Hansson 		if (!rc) {
1195415b5a75SGeorgi Djakov 			/* Tuning is successful at this tuning point */
1196415b5a75SGeorgi Djakov 			tuned_phases[tuned_phase_cnt++] = phase;
1197415b5a75SGeorgi Djakov 			dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
1198415b5a75SGeorgi Djakov 				 mmc_hostname(mmc), phase);
1199415b5a75SGeorgi Djakov 		}
1200415b5a75SGeorgi Djakov 	} while (++phase < ARRAY_SIZE(tuned_phases));
1201415b5a75SGeorgi Djakov 
1202415b5a75SGeorgi Djakov 	if (tuned_phase_cnt) {
1203415b5a75SGeorgi Djakov 		rc = msm_find_most_appropriate_phase(host, tuned_phases,
1204415b5a75SGeorgi Djakov 						     tuned_phase_cnt);
1205415b5a75SGeorgi Djakov 		if (rc < 0)
120633d73935SUlf Hansson 			return rc;
1207415b5a75SGeorgi Djakov 		else
1208415b5a75SGeorgi Djakov 			phase = rc;
1209415b5a75SGeorgi Djakov 
1210415b5a75SGeorgi Djakov 		/*
1211415b5a75SGeorgi Djakov 		 * Finally set the selected phase in delay
1212415b5a75SGeorgi Djakov 		 * line hw block.
1213415b5a75SGeorgi Djakov 		 */
1214415b5a75SGeorgi Djakov 		rc = msm_config_cm_dll_phase(host, phase);
1215415b5a75SGeorgi Djakov 		if (rc)
121633d73935SUlf Hansson 			return rc;
121721f1e2d4SVeerabhadrarao Badiganti 		msm_host->saved_tuning_phase = phase;
1218415b5a75SGeorgi Djakov 		dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
1219415b5a75SGeorgi Djakov 			 mmc_hostname(mmc), phase);
1220415b5a75SGeorgi Djakov 	} else {
1221415b5a75SGeorgi Djakov 		if (--tuning_seq_cnt)
1222415b5a75SGeorgi Djakov 			goto retry;
1223415b5a75SGeorgi Djakov 		/* Tuning failed */
1224415b5a75SGeorgi Djakov 		dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
1225415b5a75SGeorgi Djakov 		       mmc_hostname(mmc));
1226415b5a75SGeorgi Djakov 		rc = -EIO;
1227415b5a75SGeorgi Djakov 	}
1228415b5a75SGeorgi Djakov 
1229ff06ce41SVenkat Gopalakrishnan 	if (!rc)
1230ff06ce41SVenkat Gopalakrishnan 		msm_host->tuning_done = true;
1231415b5a75SGeorgi Djakov 	return rc;
12320eb0d9f4SGeorgi Djakov }
12330eb0d9f4SGeorgi Djakov 
1234db9bd163SRitesh Harjani /*
1235db9bd163SRitesh Harjani  * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation.
123644bf2312SRitesh Harjani  * This needs to be done for both tuning and enhanced_strobe mode.
1237db9bd163SRitesh Harjani  * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz
1238db9bd163SRitesh Harjani  * fixed feedback clock is used.
1239db9bd163SRitesh Harjani  */
1240db9bd163SRitesh Harjani static void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios)
1241db9bd163SRitesh Harjani {
1242db9bd163SRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1243db9bd163SRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1244db9bd163SRitesh Harjani 	int ret;
1245db9bd163SRitesh Harjani 
1246db9bd163SRitesh Harjani 	if (host->clock > CORE_FREQ_100MHZ &&
124744bf2312SRitesh Harjani 	    (msm_host->tuning_done || ios->enhanced_strobe) &&
124844bf2312SRitesh Harjani 	    !msm_host->calibration_done) {
1249db9bd163SRitesh Harjani 		ret = sdhci_msm_hs400_dll_calibration(host);
1250db9bd163SRitesh Harjani 		if (!ret)
1251db9bd163SRitesh Harjani 			msm_host->calibration_done = true;
1252db9bd163SRitesh Harjani 		else
1253db9bd163SRitesh Harjani 			pr_err("%s: Failed to calibrate DLL for hs400 mode (%d)\n",
1254db9bd163SRitesh Harjani 			       mmc_hostname(host->mmc), ret);
1255db9bd163SRitesh Harjani 	}
1256db9bd163SRitesh Harjani }
1257db9bd163SRitesh Harjani 
1258ee320674SRitesh Harjani static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
1259ee320674SRitesh Harjani 					unsigned int uhs)
1260ee320674SRitesh Harjani {
1261ee320674SRitesh Harjani 	struct mmc_host *mmc = host->mmc;
1262ff06ce41SVenkat Gopalakrishnan 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1263ff06ce41SVenkat Gopalakrishnan 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1264ee320674SRitesh Harjani 	u16 ctrl_2;
1265ff06ce41SVenkat Gopalakrishnan 	u32 config;
1266bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1267bc99266bSSayali Lokhande 					msm_host->offset;
1268ee320674SRitesh Harjani 
1269ee320674SRitesh Harjani 	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
1270ee320674SRitesh Harjani 	/* Select Bus Speed Mode for host */
1271ee320674SRitesh Harjani 	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
1272ee320674SRitesh Harjani 	switch (uhs) {
1273ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR12:
1274ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
1275ee320674SRitesh Harjani 		break;
1276ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR25:
1277ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
1278ee320674SRitesh Harjani 		break;
1279ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR50:
1280ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
1281ee320674SRitesh Harjani 		break;
1282ff06ce41SVenkat Gopalakrishnan 	case MMC_TIMING_MMC_HS400:
1283ee320674SRitesh Harjani 	case MMC_TIMING_MMC_HS200:
1284ee320674SRitesh Harjani 	case MMC_TIMING_UHS_SDR104:
1285ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
1286ee320674SRitesh Harjani 		break;
1287ee320674SRitesh Harjani 	case MMC_TIMING_UHS_DDR50:
1288ee320674SRitesh Harjani 	case MMC_TIMING_MMC_DDR52:
1289ee320674SRitesh Harjani 		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
1290ee320674SRitesh Harjani 		break;
1291ee320674SRitesh Harjani 	}
1292ee320674SRitesh Harjani 
1293ee320674SRitesh Harjani 	/*
1294ee320674SRitesh Harjani 	 * When clock frequency is less than 100MHz, the feedback clock must be
1295ee320674SRitesh Harjani 	 * provided and DLL must not be used so that tuning can be skipped. To
1296ee320674SRitesh Harjani 	 * provide feedback clock, the mode selection can be any value less
1297ee320674SRitesh Harjani 	 * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
1298ee320674SRitesh Harjani 	 */
1299ff06ce41SVenkat Gopalakrishnan 	if (host->clock <= CORE_FREQ_100MHZ) {
1300ff06ce41SVenkat Gopalakrishnan 		if (uhs == MMC_TIMING_MMC_HS400 ||
1301ee320674SRitesh Harjani 		    uhs == MMC_TIMING_MMC_HS200 ||
1302ff06ce41SVenkat Gopalakrishnan 		    uhs == MMC_TIMING_UHS_SDR104)
1303ee320674SRitesh Harjani 			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
1304ff06ce41SVenkat Gopalakrishnan 		/*
1305ff06ce41SVenkat Gopalakrishnan 		 * DLL is not required for clock <= 100MHz
1306ff06ce41SVenkat Gopalakrishnan 		 * Thus, make sure DLL it is disabled when not required
1307ff06ce41SVenkat Gopalakrishnan 		 */
1308bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1309bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1310ff06ce41SVenkat Gopalakrishnan 		config |= CORE_DLL_RST;
1311bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
1312bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1313ff06ce41SVenkat Gopalakrishnan 
1314bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1315bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1316ff06ce41SVenkat Gopalakrishnan 		config |= CORE_DLL_PDN;
1317bc99266bSSayali Lokhande 		writel_relaxed(config, host->ioaddr +
1318bc99266bSSayali Lokhande 				msm_offset->core_dll_config);
1319ff06ce41SVenkat Gopalakrishnan 
1320ff06ce41SVenkat Gopalakrishnan 		/*
1321ff06ce41SVenkat Gopalakrishnan 		 * The DLL needs to be restored and CDCLP533 recalibrated
1322ff06ce41SVenkat Gopalakrishnan 		 * when the clock frequency is set back to 400MHz.
1323ff06ce41SVenkat Gopalakrishnan 		 */
1324ff06ce41SVenkat Gopalakrishnan 		msm_host->calibration_done = false;
1325ff06ce41SVenkat Gopalakrishnan 	}
1326ee320674SRitesh Harjani 
1327ee320674SRitesh Harjani 	dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
1328ee320674SRitesh Harjani 		mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
1329ee320674SRitesh Harjani 	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
1330cc392c58SRitesh Harjani 
1331db9bd163SRitesh Harjani 	if (mmc->ios.timing == MMC_TIMING_MMC_HS400)
1332db9bd163SRitesh Harjani 		sdhci_msm_hs400(host, &mmc->ios);
1333ee320674SRitesh Harjani }
1334ee320674SRitesh Harjani 
1335c0309b38SVijay Viswanath static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
1336c0309b38SVijay Viswanath {
1337c0309b38SVijay Viswanath 	init_waitqueue_head(&msm_host->pwr_irq_wait);
1338c0309b38SVijay Viswanath }
1339c0309b38SVijay Viswanath 
1340c0309b38SVijay Viswanath static inline void sdhci_msm_complete_pwr_irq_wait(
1341c0309b38SVijay Viswanath 		struct sdhci_msm_host *msm_host)
1342c0309b38SVijay Viswanath {
1343c0309b38SVijay Viswanath 	wake_up(&msm_host->pwr_irq_wait);
1344c0309b38SVijay Viswanath }
1345c0309b38SVijay Viswanath 
1346c0309b38SVijay Viswanath /*
1347c0309b38SVijay Viswanath  * sdhci_msm_check_power_status API should be called when registers writes
1348c0309b38SVijay Viswanath  * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
1349c0309b38SVijay Viswanath  * To what state the register writes will change the IO lines should be passed
1350c0309b38SVijay Viswanath  * as the argument req_type. This API will check whether the IO line's state
1351c0309b38SVijay Viswanath  * is already the expected state and will wait for power irq only if
1352c0309b38SVijay Viswanath  * power irq is expected to be trigerred based on the current IO line state
1353c0309b38SVijay Viswanath  * and expected IO line state.
1354c0309b38SVijay Viswanath  */
1355c0309b38SVijay Viswanath static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
1356c0309b38SVijay Viswanath {
1357c0309b38SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1358c0309b38SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1359c0309b38SVijay Viswanath 	bool done = false;
1360bc99266bSSayali Lokhande 	u32 val = SWITCHABLE_SIGNALING_VOLTAGE;
1361bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1362bc99266bSSayali Lokhande 					msm_host->offset;
1363c0309b38SVijay Viswanath 
1364c0309b38SVijay Viswanath 	pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
1365c0309b38SVijay Viswanath 			mmc_hostname(host->mmc), __func__, req_type,
1366c0309b38SVijay Viswanath 			msm_host->curr_pwr_state, msm_host->curr_io_level);
1367c0309b38SVijay Viswanath 
1368c0309b38SVijay Viswanath 	/*
136952884f8fSBjorn Andersson 	 * The power interrupt will not be generated for signal voltage
137052884f8fSBjorn Andersson 	 * switches if SWITCHABLE_SIGNALING_VOLTAGE in MCI_GENERICS is not set.
1371bc99266bSSayali Lokhande 	 * Since sdhci-msm-v5, this bit has been removed and SW must consider
1372bc99266bSSayali Lokhande 	 * it as always set.
137352884f8fSBjorn Andersson 	 */
1374bc99266bSSayali Lokhande 	if (!msm_host->mci_removed)
1375bc99266bSSayali Lokhande 		val = msm_host_readl(msm_host, host,
1376bc99266bSSayali Lokhande 				msm_offset->core_generics);
137752884f8fSBjorn Andersson 	if ((req_type & REQ_IO_HIGH || req_type & REQ_IO_LOW) &&
137852884f8fSBjorn Andersson 	    !(val & SWITCHABLE_SIGNALING_VOLTAGE)) {
137952884f8fSBjorn Andersson 		return;
138052884f8fSBjorn Andersson 	}
138152884f8fSBjorn Andersson 
138252884f8fSBjorn Andersson 	/*
1383c0309b38SVijay Viswanath 	 * The IRQ for request type IO High/LOW will be generated when -
1384c0309b38SVijay Viswanath 	 * there is a state change in 1.8V enable bit (bit 3) of
1385c0309b38SVijay Viswanath 	 * SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
1386c0309b38SVijay Viswanath 	 * which indicates 3.3V IO voltage. So, when MMC core layer tries
1387c0309b38SVijay Viswanath 	 * to set it to 3.3V before card detection happens, the
1388c0309b38SVijay Viswanath 	 * IRQ doesn't get triggered as there is no state change in this bit.
1389c0309b38SVijay Viswanath 	 * The driver already handles this case by changing the IO voltage
1390c0309b38SVijay Viswanath 	 * level to high as part of controller power up sequence. Hence, check
1391c0309b38SVijay Viswanath 	 * for host->pwr to handle a case where IO voltage high request is
1392c0309b38SVijay Viswanath 	 * issued even before controller power up.
1393c0309b38SVijay Viswanath 	 */
1394c0309b38SVijay Viswanath 	if ((req_type & REQ_IO_HIGH) && !host->pwr) {
1395c0309b38SVijay Viswanath 		pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n",
1396c0309b38SVijay Viswanath 				mmc_hostname(host->mmc), req_type);
1397c0309b38SVijay Viswanath 		return;
1398c0309b38SVijay Viswanath 	}
1399c0309b38SVijay Viswanath 	if ((req_type & msm_host->curr_pwr_state) ||
1400c0309b38SVijay Viswanath 			(req_type & msm_host->curr_io_level))
1401c0309b38SVijay Viswanath 		done = true;
1402c0309b38SVijay Viswanath 	/*
1403c0309b38SVijay Viswanath 	 * This is needed here to handle cases where register writes will
1404c0309b38SVijay Viswanath 	 * not change the current bus state or io level of the controller.
1405c0309b38SVijay Viswanath 	 * In this case, no power irq will be triggerred and we should
1406c0309b38SVijay Viswanath 	 * not wait.
1407c0309b38SVijay Viswanath 	 */
1408c0309b38SVijay Viswanath 	if (!done) {
1409c0309b38SVijay Viswanath 		if (!wait_event_timeout(msm_host->pwr_irq_wait,
1410c0309b38SVijay Viswanath 				msm_host->pwr_irq_flag,
1411c0309b38SVijay Viswanath 				msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
14129ccfa817SArnd Bergmann 			dev_warn(&msm_host->pdev->dev,
14139ccfa817SArnd Bergmann 				 "%s: pwr_irq for req: (%d) timed out\n",
1414c0309b38SVijay Viswanath 				 mmc_hostname(host->mmc), req_type);
1415c0309b38SVijay Viswanath 	}
1416c0309b38SVijay Viswanath 	pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
1417c0309b38SVijay Viswanath 			__func__, req_type);
1418c0309b38SVijay Viswanath }
1419c0309b38SVijay Viswanath 
1420401b2d06SSahitya Tummala static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
1421401b2d06SSahitya Tummala {
1422401b2d06SSahitya Tummala 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1423401b2d06SSahitya Tummala 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1424bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset =
1425bc99266bSSayali Lokhande 					msm_host->offset;
1426401b2d06SSahitya Tummala 
1427401b2d06SSahitya Tummala 	pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
1428401b2d06SSahitya Tummala 		mmc_hostname(host->mmc),
1429bc99266bSSayali Lokhande 		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_status),
1430bc99266bSSayali Lokhande 		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_mask),
1431bc99266bSSayali Lokhande 		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_ctl));
1432401b2d06SSahitya Tummala }
1433401b2d06SSahitya Tummala 
1434401b2d06SSahitya Tummala static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
1435ad81d387SGeorgi Djakov {
1436ad81d387SGeorgi Djakov 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1437ad81d387SGeorgi Djakov 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1438ad81d387SGeorgi Djakov 	u32 irq_status, irq_ack = 0;
1439401b2d06SSahitya Tummala 	int retry = 10;
1440ac06fba1SVijay Viswanath 	u32 pwr_state = 0, io_level = 0;
14415c132323SVijay Viswanath 	u32 config;
1442bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
1443ad81d387SGeorgi Djakov 
1444bc99266bSSayali Lokhande 	irq_status = msm_host_readl(msm_host, host,
1445bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_status);
1446ad81d387SGeorgi Djakov 	irq_status &= INT_MASK;
1447ad81d387SGeorgi Djakov 
1448bc99266bSSayali Lokhande 	msm_host_writel(msm_host, irq_status, host,
1449bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_clear);
1450ad81d387SGeorgi Djakov 
1451401b2d06SSahitya Tummala 	/*
1452401b2d06SSahitya Tummala 	 * There is a rare HW scenario where the first clear pulse could be
1453401b2d06SSahitya Tummala 	 * lost when actual reset and clear/read of status register is
1454401b2d06SSahitya Tummala 	 * happening at a time. Hence, retry for at least 10 times to make
1455401b2d06SSahitya Tummala 	 * sure status register is cleared. Otherwise, this will result in
1456401b2d06SSahitya Tummala 	 * a spurious power IRQ resulting in system instability.
1457401b2d06SSahitya Tummala 	 */
1458bc99266bSSayali Lokhande 	while (irq_status & msm_host_readl(msm_host, host,
1459bc99266bSSayali Lokhande 				msm_offset->core_pwrctl_status)) {
1460401b2d06SSahitya Tummala 		if (retry == 0) {
1461401b2d06SSahitya Tummala 			pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
1462401b2d06SSahitya Tummala 					mmc_hostname(host->mmc), irq_status);
1463401b2d06SSahitya Tummala 			sdhci_msm_dump_pwr_ctrl_regs(host);
1464401b2d06SSahitya Tummala 			WARN_ON(1);
1465401b2d06SSahitya Tummala 			break;
1466401b2d06SSahitya Tummala 		}
1467bc99266bSSayali Lokhande 		msm_host_writel(msm_host, irq_status, host,
1468bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_clear);
1469401b2d06SSahitya Tummala 		retry--;
1470401b2d06SSahitya Tummala 		udelay(10);
1471401b2d06SSahitya Tummala 	}
1472401b2d06SSahitya Tummala 
1473c0309b38SVijay Viswanath 	/* Handle BUS ON/OFF*/
1474c0309b38SVijay Viswanath 	if (irq_status & CORE_PWRCTL_BUS_ON) {
1475c0309b38SVijay Viswanath 		pwr_state = REQ_BUS_ON;
1476c0309b38SVijay Viswanath 		io_level = REQ_IO_HIGH;
1477ad81d387SGeorgi Djakov 		irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
1478c0309b38SVijay Viswanath 	}
1479c0309b38SVijay Viswanath 	if (irq_status & CORE_PWRCTL_BUS_OFF) {
1480c0309b38SVijay Viswanath 		pwr_state = REQ_BUS_OFF;
1481c0309b38SVijay Viswanath 		io_level = REQ_IO_LOW;
1482c0309b38SVijay Viswanath 		irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
1483c0309b38SVijay Viswanath 	}
1484c0309b38SVijay Viswanath 	/* Handle IO LOW/HIGH */
1485c0309b38SVijay Viswanath 	if (irq_status & CORE_PWRCTL_IO_LOW) {
1486c0309b38SVijay Viswanath 		io_level = REQ_IO_LOW;
1487ad81d387SGeorgi Djakov 		irq_ack |= CORE_PWRCTL_IO_SUCCESS;
1488c0309b38SVijay Viswanath 	}
1489c0309b38SVijay Viswanath 	if (irq_status & CORE_PWRCTL_IO_HIGH) {
1490c0309b38SVijay Viswanath 		io_level = REQ_IO_HIGH;
1491c0309b38SVijay Viswanath 		irq_ack |= CORE_PWRCTL_IO_SUCCESS;
1492c0309b38SVijay Viswanath 	}
1493ad81d387SGeorgi Djakov 
1494ad81d387SGeorgi Djakov 	/*
1495ad81d387SGeorgi Djakov 	 * The driver has to acknowledge the interrupt, switch voltages and
1496ad81d387SGeorgi Djakov 	 * report back if it succeded or not to this register. The voltage
1497ad81d387SGeorgi Djakov 	 * switches are handled by the sdhci core, so just report success.
1498ad81d387SGeorgi Djakov 	 */
1499bc99266bSSayali Lokhande 	msm_host_writel(msm_host, irq_ack, host,
1500bc99266bSSayali Lokhande 			msm_offset->core_pwrctl_ctl);
1501401b2d06SSahitya Tummala 
15025c132323SVijay Viswanath 	/*
15035c132323SVijay Viswanath 	 * If we don't have info regarding the voltage levels supported by
15045c132323SVijay Viswanath 	 * regulators, don't change the IO PAD PWR SWITCH.
15055c132323SVijay Viswanath 	 */
15065c132323SVijay Viswanath 	if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
15075c132323SVijay Viswanath 		u32 new_config;
15085c132323SVijay Viswanath 		/*
15095c132323SVijay Viswanath 		 * We should unset IO PAD PWR switch only if the register write
15105c132323SVijay Viswanath 		 * can set IO lines high and the regulator also switches to 3 V.
15115c132323SVijay Viswanath 		 * Else, we should keep the IO PAD PWR switch set.
15125c132323SVijay Viswanath 		 * This is applicable to certain targets where eMMC vccq supply
15135c132323SVijay Viswanath 		 * is only 1.8V. In such targets, even during REQ_IO_HIGH, the
15145c132323SVijay Viswanath 		 * IO PAD PWR switch must be kept set to reflect actual
15155c132323SVijay Viswanath 		 * regulator voltage. This way, during initialization of
15165c132323SVijay Viswanath 		 * controllers with only 1.8V, we will set the IO PAD bit
15175c132323SVijay Viswanath 		 * without waiting for a REQ_IO_LOW.
15185c132323SVijay Viswanath 		 */
1519bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1520bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
15215c132323SVijay Viswanath 		new_config = config;
15225c132323SVijay Viswanath 
15235c132323SVijay Viswanath 		if ((io_level & REQ_IO_HIGH) &&
15245c132323SVijay Viswanath 				(msm_host->caps_0 & CORE_3_0V_SUPPORT))
15255c132323SVijay Viswanath 			new_config &= ~CORE_IO_PAD_PWR_SWITCH;
15265c132323SVijay Viswanath 		else if ((io_level & REQ_IO_LOW) ||
15275c132323SVijay Viswanath 				(msm_host->caps_0 & CORE_1_8V_SUPPORT))
15285c132323SVijay Viswanath 			new_config |= CORE_IO_PAD_PWR_SWITCH;
15295c132323SVijay Viswanath 
15305c132323SVijay Viswanath 		if (config ^ new_config)
1531bc99266bSSayali Lokhande 			writel_relaxed(new_config, host->ioaddr +
1532bc99266bSSayali Lokhande 					msm_offset->core_vendor_spec);
15335c132323SVijay Viswanath 	}
15345c132323SVijay Viswanath 
1535c0309b38SVijay Viswanath 	if (pwr_state)
1536c0309b38SVijay Viswanath 		msm_host->curr_pwr_state = pwr_state;
1537c0309b38SVijay Viswanath 	if (io_level)
1538c0309b38SVijay Viswanath 		msm_host->curr_io_level = io_level;
1539c0309b38SVijay Viswanath 
1540401b2d06SSahitya Tummala 	pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
1541401b2d06SSahitya Tummala 		mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
1542401b2d06SSahitya Tummala 		irq_ack);
1543ad81d387SGeorgi Djakov }
1544ad81d387SGeorgi Djakov 
1545ad81d387SGeorgi Djakov static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
1546ad81d387SGeorgi Djakov {
1547ad81d387SGeorgi Djakov 	struct sdhci_host *host = (struct sdhci_host *)data;
1548c0309b38SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1549c0309b38SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1550ad81d387SGeorgi Djakov 
1551401b2d06SSahitya Tummala 	sdhci_msm_handle_pwr_irq(host, irq);
1552c0309b38SVijay Viswanath 	msm_host->pwr_irq_flag = 1;
1553c0309b38SVijay Viswanath 	sdhci_msm_complete_pwr_irq_wait(msm_host);
1554c0309b38SVijay Viswanath 
1555ad81d387SGeorgi Djakov 
1556ad81d387SGeorgi Djakov 	return IRQ_HANDLED;
1557ad81d387SGeorgi Djakov }
1558ad81d387SGeorgi Djakov 
155980031bdeSRitesh Harjani static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host)
156080031bdeSRitesh Harjani {
156180031bdeSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
156280031bdeSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1563e4bf91f6SBjorn Andersson 	struct clk *core_clk = msm_host->bulk_clks[0].clk;
156480031bdeSRitesh Harjani 
1565e4bf91f6SBjorn Andersson 	return clk_round_rate(core_clk, ULONG_MAX);
156680031bdeSRitesh Harjani }
156780031bdeSRitesh Harjani 
156880031bdeSRitesh Harjani static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
156980031bdeSRitesh Harjani {
157080031bdeSRitesh Harjani 	return SDHCI_MSM_MIN_CLOCK;
157180031bdeSRitesh Harjani }
157280031bdeSRitesh Harjani 
1573edc609fdSRitesh Harjani /**
1574edc609fdSRitesh Harjani  * __sdhci_msm_set_clock - sdhci_msm clock control.
1575edc609fdSRitesh Harjani  *
1576edc609fdSRitesh Harjani  * Description:
1577edc609fdSRitesh Harjani  * MSM controller does not use internal divider and
1578edc609fdSRitesh Harjani  * instead directly control the GCC clock as per
1579edc609fdSRitesh Harjani  * HW recommendation.
1580edc609fdSRitesh Harjani  **/
158130de038dSMasahiro Yamada static void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
1582edc609fdSRitesh Harjani {
1583edc609fdSRitesh Harjani 	u16 clk;
1584edc609fdSRitesh Harjani 	/*
1585edc609fdSRitesh Harjani 	 * Keep actual_clock as zero -
1586edc609fdSRitesh Harjani 	 * - since there is no divider used so no need of having actual_clock.
1587edc609fdSRitesh Harjani 	 * - MSM controller uses SDCLK for data timeout calculation. If
1588edc609fdSRitesh Harjani 	 *   actual_clock is zero, host->clock is taken for calculation.
1589edc609fdSRitesh Harjani 	 */
1590edc609fdSRitesh Harjani 	host->mmc->actual_clock = 0;
1591edc609fdSRitesh Harjani 
1592edc609fdSRitesh Harjani 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
1593edc609fdSRitesh Harjani 
1594edc609fdSRitesh Harjani 	if (clock == 0)
1595edc609fdSRitesh Harjani 		return;
1596edc609fdSRitesh Harjani 
1597edc609fdSRitesh Harjani 	/*
1598edc609fdSRitesh Harjani 	 * MSM controller do not use clock divider.
1599edc609fdSRitesh Harjani 	 * Thus read SDHCI_CLOCK_CONTROL and only enable
1600edc609fdSRitesh Harjani 	 * clock with no divider value programmed.
1601edc609fdSRitesh Harjani 	 */
1602edc609fdSRitesh Harjani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
1603edc609fdSRitesh Harjani 	sdhci_enable_clk(host, clk);
1604edc609fdSRitesh Harjani }
1605edc609fdSRitesh Harjani 
1606edc609fdSRitesh Harjani /* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */
1607edc609fdSRitesh Harjani static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
1608edc609fdSRitesh Harjani {
1609edc609fdSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1610edc609fdSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1611edc609fdSRitesh Harjani 
1612edc609fdSRitesh Harjani 	if (!clock) {
1613edc609fdSRitesh Harjani 		msm_host->clk_rate = clock;
1614edc609fdSRitesh Harjani 		goto out;
1615edc609fdSRitesh Harjani 	}
1616edc609fdSRitesh Harjani 
1617b54aaa8aSRitesh Harjani 	sdhci_msm_hc_select_mode(host);
1618edc609fdSRitesh Harjani 
16190fb8a3d4SRitesh Harjani 	msm_set_clock_rate_for_bus_mode(host, clock);
1620edc609fdSRitesh Harjani out:
1621edc609fdSRitesh Harjani 	__sdhci_msm_set_clock(host, clock);
1622edc609fdSRitesh Harjani }
1623edc609fdSRitesh Harjani 
162487a8df0dSRitesh Harjani /*****************************************************************************\
162587a8df0dSRitesh Harjani  *                                                                           *
162687a8df0dSRitesh Harjani  * MSM Command Queue Engine (CQE)                                            *
162787a8df0dSRitesh Harjani  *                                                                           *
162887a8df0dSRitesh Harjani \*****************************************************************************/
162987a8df0dSRitesh Harjani 
163087a8df0dSRitesh Harjani static u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask)
163187a8df0dSRitesh Harjani {
163287a8df0dSRitesh Harjani 	int cmd_error = 0;
163387a8df0dSRitesh Harjani 	int data_error = 0;
163487a8df0dSRitesh Harjani 
163587a8df0dSRitesh Harjani 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
163687a8df0dSRitesh Harjani 		return intmask;
163787a8df0dSRitesh Harjani 
163887a8df0dSRitesh Harjani 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
163987a8df0dSRitesh Harjani 	return 0;
164087a8df0dSRitesh Harjani }
164187a8df0dSRitesh Harjani 
16429051db38SStephen Boyd static void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery)
164387a8df0dSRitesh Harjani {
164487a8df0dSRitesh Harjani 	struct sdhci_host *host = mmc_priv(mmc);
164587a8df0dSRitesh Harjani 	unsigned long flags;
164687a8df0dSRitesh Harjani 	u32 ctrl;
164787a8df0dSRitesh Harjani 
164887a8df0dSRitesh Harjani 	/*
164987a8df0dSRitesh Harjani 	 * When CQE is halted, the legacy SDHCI path operates only
165087a8df0dSRitesh Harjani 	 * on 16-byte descriptors in 64bit mode.
165187a8df0dSRitesh Harjani 	 */
165287a8df0dSRitesh Harjani 	if (host->flags & SDHCI_USE_64_BIT_DMA)
165387a8df0dSRitesh Harjani 		host->desc_sz = 16;
165487a8df0dSRitesh Harjani 
165587a8df0dSRitesh Harjani 	spin_lock_irqsave(&host->lock, flags);
165687a8df0dSRitesh Harjani 
165787a8df0dSRitesh Harjani 	/*
165887a8df0dSRitesh Harjani 	 * During CQE command transfers, command complete bit gets latched.
165987a8df0dSRitesh Harjani 	 * So s/w should clear command complete interrupt status when CQE is
166087a8df0dSRitesh Harjani 	 * either halted or disabled. Otherwise unexpected SDCHI legacy
166187a8df0dSRitesh Harjani 	 * interrupt gets triggered when CQE is halted/disabled.
166287a8df0dSRitesh Harjani 	 */
166387a8df0dSRitesh Harjani 	ctrl = sdhci_readl(host, SDHCI_INT_ENABLE);
166487a8df0dSRitesh Harjani 	ctrl |= SDHCI_INT_RESPONSE;
166587a8df0dSRitesh Harjani 	sdhci_writel(host,  ctrl, SDHCI_INT_ENABLE);
166687a8df0dSRitesh Harjani 	sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
166787a8df0dSRitesh Harjani 
166887a8df0dSRitesh Harjani 	spin_unlock_irqrestore(&host->lock, flags);
166987a8df0dSRitesh Harjani 
167087a8df0dSRitesh Harjani 	sdhci_cqe_disable(mmc, recovery);
167187a8df0dSRitesh Harjani }
167287a8df0dSRitesh Harjani 
167387a8df0dSRitesh Harjani static const struct cqhci_host_ops sdhci_msm_cqhci_ops = {
167487a8df0dSRitesh Harjani 	.enable		= sdhci_cqe_enable,
167587a8df0dSRitesh Harjani 	.disable	= sdhci_msm_cqe_disable,
167687a8df0dSRitesh Harjani };
167787a8df0dSRitesh Harjani 
167887a8df0dSRitesh Harjani static int sdhci_msm_cqe_add_host(struct sdhci_host *host,
167987a8df0dSRitesh Harjani 				struct platform_device *pdev)
168087a8df0dSRitesh Harjani {
168187a8df0dSRitesh Harjani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
168287a8df0dSRitesh Harjani 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
168387a8df0dSRitesh Harjani 	struct cqhci_host *cq_host;
168487a8df0dSRitesh Harjani 	bool dma64;
168587a8df0dSRitesh Harjani 	u32 cqcfg;
168687a8df0dSRitesh Harjani 	int ret;
168787a8df0dSRitesh Harjani 
168887a8df0dSRitesh Harjani 	/*
168987a8df0dSRitesh Harjani 	 * When CQE is halted, SDHC operates only on 16byte ADMA descriptors.
169087a8df0dSRitesh Harjani 	 * So ensure ADMA table is allocated for 16byte descriptors.
169187a8df0dSRitesh Harjani 	 */
169287a8df0dSRitesh Harjani 	if (host->caps & SDHCI_CAN_64BIT)
169387a8df0dSRitesh Harjani 		host->alloc_desc_sz = 16;
169487a8df0dSRitesh Harjani 
169587a8df0dSRitesh Harjani 	ret = sdhci_setup_host(host);
169687a8df0dSRitesh Harjani 	if (ret)
169787a8df0dSRitesh Harjani 		return ret;
169887a8df0dSRitesh Harjani 
169987a8df0dSRitesh Harjani 	cq_host = cqhci_pltfm_init(pdev);
170087a8df0dSRitesh Harjani 	if (IS_ERR(cq_host)) {
170187a8df0dSRitesh Harjani 		ret = PTR_ERR(cq_host);
170287a8df0dSRitesh Harjani 		dev_err(&pdev->dev, "cqhci-pltfm init: failed: %d\n", ret);
170387a8df0dSRitesh Harjani 		goto cleanup;
170487a8df0dSRitesh Harjani 	}
170587a8df0dSRitesh Harjani 
170687a8df0dSRitesh Harjani 	msm_host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
170787a8df0dSRitesh Harjani 	cq_host->ops = &sdhci_msm_cqhci_ops;
170887a8df0dSRitesh Harjani 
170987a8df0dSRitesh Harjani 	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
171087a8df0dSRitesh Harjani 
171187a8df0dSRitesh Harjani 	ret = cqhci_init(cq_host, host->mmc, dma64);
171287a8df0dSRitesh Harjani 	if (ret) {
171387a8df0dSRitesh Harjani 		dev_err(&pdev->dev, "%s: CQE init: failed (%d)\n",
171487a8df0dSRitesh Harjani 				mmc_hostname(host->mmc), ret);
171587a8df0dSRitesh Harjani 		goto cleanup;
171687a8df0dSRitesh Harjani 	}
171787a8df0dSRitesh Harjani 
171887a8df0dSRitesh Harjani 	/* Disable cqe reset due to cqe enable signal */
171987a8df0dSRitesh Harjani 	cqcfg = cqhci_readl(cq_host, CQHCI_VENDOR_CFG1);
172087a8df0dSRitesh Harjani 	cqcfg |= CQHCI_VENDOR_DIS_RST_ON_CQ_EN;
172187a8df0dSRitesh Harjani 	cqhci_writel(cq_host, cqcfg, CQHCI_VENDOR_CFG1);
172287a8df0dSRitesh Harjani 
172387a8df0dSRitesh Harjani 	/*
172487a8df0dSRitesh Harjani 	 * SDHC expects 12byte ADMA descriptors till CQE is enabled.
172587a8df0dSRitesh Harjani 	 * So limit desc_sz to 12 so that the data commands that are sent
172687a8df0dSRitesh Harjani 	 * during card initialization (before CQE gets enabled) would
172787a8df0dSRitesh Harjani 	 * get executed without any issues.
172887a8df0dSRitesh Harjani 	 */
172987a8df0dSRitesh Harjani 	if (host->flags & SDHCI_USE_64_BIT_DMA)
173087a8df0dSRitesh Harjani 		host->desc_sz = 12;
173187a8df0dSRitesh Harjani 
173287a8df0dSRitesh Harjani 	ret = __sdhci_add_host(host);
173387a8df0dSRitesh Harjani 	if (ret)
173487a8df0dSRitesh Harjani 		goto cleanup;
173587a8df0dSRitesh Harjani 
173687a8df0dSRitesh Harjani 	dev_info(&pdev->dev, "%s: CQE init: success\n",
173787a8df0dSRitesh Harjani 			mmc_hostname(host->mmc));
173887a8df0dSRitesh Harjani 	return ret;
173987a8df0dSRitesh Harjani 
174087a8df0dSRitesh Harjani cleanup:
174187a8df0dSRitesh Harjani 	sdhci_cleanup_host(host);
174287a8df0dSRitesh Harjani 	return ret;
174387a8df0dSRitesh Harjani }
174487a8df0dSRitesh Harjani 
1745c0309b38SVijay Viswanath /*
1746c0309b38SVijay Viswanath  * Platform specific register write functions. This is so that, if any
1747c0309b38SVijay Viswanath  * register write needs to be followed up by platform specific actions,
1748c0309b38SVijay Viswanath  * they can be added here. These functions can go to sleep when writes
1749c0309b38SVijay Viswanath  * to certain registers are done.
1750c0309b38SVijay Viswanath  * These functions are relying on sdhci_set_ios not using spinlock.
1751c0309b38SVijay Viswanath  */
1752c0309b38SVijay Viswanath static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
1753c0309b38SVijay Viswanath {
1754c0309b38SVijay Viswanath 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1755c0309b38SVijay Viswanath 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
1756c0309b38SVijay Viswanath 	u32 req_type = 0;
1757c0309b38SVijay Viswanath 
1758c0309b38SVijay Viswanath 	switch (reg) {
1759c0309b38SVijay Viswanath 	case SDHCI_HOST_CONTROL2:
1760c0309b38SVijay Viswanath 		req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
1761c0309b38SVijay Viswanath 			REQ_IO_HIGH;
1762c0309b38SVijay Viswanath 		break;
1763c0309b38SVijay Viswanath 	case SDHCI_SOFTWARE_RESET:
1764c0309b38SVijay Viswanath 		if (host->pwr && (val & SDHCI_RESET_ALL))
1765c0309b38SVijay Viswanath 			req_type = REQ_BUS_OFF;
1766c0309b38SVijay Viswanath 		break;
1767c0309b38SVijay Viswanath 	case SDHCI_POWER_CONTROL:
1768c0309b38SVijay Viswanath 		req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
1769c0309b38SVijay Viswanath 		break;
1770a89e7bcbSLoic Poulain 	case SDHCI_TRANSFER_MODE:
1771a89e7bcbSLoic Poulain 		msm_host->transfer_mode = val;
1772a89e7bcbSLoic Poulain 		break;
1773a89e7bcbSLoic Poulain 	case SDHCI_COMMAND:
1774a89e7bcbSLoic Poulain 		if (!msm_host->use_cdr)
1775a89e7bcbSLoic Poulain 			break;
1776a89e7bcbSLoic Poulain 		if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
1777a89e7bcbSLoic Poulain 		    SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 &&
1778a89e7bcbSLoic Poulain 		    SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK)
1779a89e7bcbSLoic Poulain 			sdhci_msm_set_cdr(host, true);
1780a89e7bcbSLoic Poulain 		else
1781a89e7bcbSLoic Poulain 			sdhci_msm_set_cdr(host, false);
1782a89e7bcbSLoic Poulain 		break;
1783c0309b38SVijay Viswanath 	}
1784c0309b38SVijay Viswanath 
1785c0309b38SVijay Viswanath 	if (req_type) {
1786c0309b38SVijay Viswanath 		msm_host->pwr_irq_flag = 0;
1787c0309b38SVijay Viswanath 		/*
1788c0309b38SVijay Viswanath 		 * Since this register write may trigger a power irq, ensure
1789c0309b38SVijay Viswanath 		 * all previous register writes are complete by this point.
1790c0309b38SVijay Viswanath 		 */
1791c0309b38SVijay Viswanath 		mb();
1792c0309b38SVijay Viswanath 	}
1793c0309b38SVijay Viswanath 	return req_type;
1794c0309b38SVijay Viswanath }
1795c0309b38SVijay Viswanath 
1796c0309b38SVijay Viswanath /* This function may sleep*/
1797c0309b38SVijay Viswanath static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
1798c0309b38SVijay Viswanath {
1799c0309b38SVijay Viswanath 	u32 req_type = 0;
1800c0309b38SVijay Viswanath 
1801c0309b38SVijay Viswanath 	req_type = __sdhci_msm_check_write(host, val, reg);
1802c0309b38SVijay Viswanath 	writew_relaxed(val, host->ioaddr + reg);
1803c0309b38SVijay Viswanath 
1804c0309b38SVijay Viswanath 	if (req_type)
1805c0309b38SVijay Viswanath 		sdhci_msm_check_power_status(host, req_type);
1806c0309b38SVijay Viswanath }
1807c0309b38SVijay Viswanath 
1808c0309b38SVijay Viswanath /* This function may sleep*/
1809c0309b38SVijay Viswanath static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
1810c0309b38SVijay Viswanath {
1811c0309b38SVijay Viswanath 	u32 req_type = 0;
1812c0309b38SVijay Viswanath 
1813c0309b38SVijay Viswanath 	req_type = __sdhci_msm_check_write(host, val, reg);
1814c0309b38SVijay Viswanath 
1815c0309b38SVijay Viswanath 	writeb_relaxed(val, host->ioaddr + reg);
1816c0309b38SVijay Viswanath 
1817c0309b38SVijay Viswanath 	if (req_type)
1818c0309b38SVijay Viswanath 		sdhci_msm_check_power_status(host, req_type);
1819c0309b38SVijay Viswanath }
1820c0309b38SVijay Viswanath 
1821ac06fba1SVijay Viswanath static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)
1822ac06fba1SVijay Viswanath {
1823ac06fba1SVijay Viswanath 	struct mmc_host *mmc = msm_host->mmc;
1824ac06fba1SVijay Viswanath 	struct regulator *supply = mmc->supply.vqmmc;
18255c132323SVijay Viswanath 	u32 caps = 0, config;
18265c132323SVijay Viswanath 	struct sdhci_host *host = mmc_priv(mmc);
1827bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
1828ac06fba1SVijay Viswanath 
1829ac06fba1SVijay Viswanath 	if (!IS_ERR(mmc->supply.vqmmc)) {
1830ac06fba1SVijay Viswanath 		if (regulator_is_supported_voltage(supply, 1700000, 1950000))
1831ac06fba1SVijay Viswanath 			caps |= CORE_1_8V_SUPPORT;
1832ac06fba1SVijay Viswanath 		if (regulator_is_supported_voltage(supply, 2700000, 3600000))
1833ac06fba1SVijay Viswanath 			caps |= CORE_3_0V_SUPPORT;
1834ac06fba1SVijay Viswanath 
1835ac06fba1SVijay Viswanath 		if (!caps)
1836ac06fba1SVijay Viswanath 			pr_warn("%s: 1.8/3V not supported for vqmmc\n",
1837ac06fba1SVijay Viswanath 					mmc_hostname(mmc));
1838ac06fba1SVijay Viswanath 	}
1839ac06fba1SVijay Viswanath 
18405c132323SVijay Viswanath 	if (caps) {
18415c132323SVijay Viswanath 		/*
18425c132323SVijay Viswanath 		 * Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH
18435c132323SVijay Viswanath 		 * bit can be used as required later on.
18445c132323SVijay Viswanath 		 */
18455c132323SVijay Viswanath 		u32 io_level = msm_host->curr_io_level;
18465c132323SVijay Viswanath 
1847bc99266bSSayali Lokhande 		config = readl_relaxed(host->ioaddr +
1848bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec);
18495c132323SVijay Viswanath 		config |= CORE_IO_PAD_PWR_SWITCH_EN;
18505c132323SVijay Viswanath 
18515c132323SVijay Viswanath 		if ((io_level & REQ_IO_HIGH) && (caps &	CORE_3_0V_SUPPORT))
18525c132323SVijay Viswanath 			config &= ~CORE_IO_PAD_PWR_SWITCH;
18535c132323SVijay Viswanath 		else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT))
18545c132323SVijay Viswanath 			config |= CORE_IO_PAD_PWR_SWITCH;
18555c132323SVijay Viswanath 
1856bc99266bSSayali Lokhande 		writel_relaxed(config,
1857bc99266bSSayali Lokhande 				host->ioaddr + msm_offset->core_vendor_spec);
18585c132323SVijay Viswanath 	}
1859ac06fba1SVijay Viswanath 	msm_host->caps_0 |= caps;
1860ac06fba1SVijay Viswanath 	pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
1861ac06fba1SVijay Viswanath }
1862ac06fba1SVijay Viswanath 
18635cf583f1SVeerabhadrarao Badiganti static void sdhci_msm_reset(struct sdhci_host *host, u8 mask)
18645cf583f1SVeerabhadrarao Badiganti {
18655cf583f1SVeerabhadrarao Badiganti 	if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL))
18665cf583f1SVeerabhadrarao Badiganti 		cqhci_deactivate(host->mmc);
18675cf583f1SVeerabhadrarao Badiganti 	sdhci_reset(host, mask);
18685cf583f1SVeerabhadrarao Badiganti }
18695cf583f1SVeerabhadrarao Badiganti 
18706ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_ops mci_var_ops = {
18716ed4bb43SVijay Viswanath 	.msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed,
18726ed4bb43SVijay Viswanath 	.msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed,
18736ed4bb43SVijay Viswanath };
18746ed4bb43SVijay Viswanath 
18756ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_ops v5_var_ops = {
18766ed4bb43SVijay Viswanath 	.msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed,
18776ed4bb43SVijay Viswanath 	.msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed,
18786ed4bb43SVijay Viswanath };
18796ed4bb43SVijay Viswanath 
18806ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_info sdhci_msm_mci_var = {
18816ed4bb43SVijay Viswanath 	.var_ops = &mci_var_ops,
18826ed4bb43SVijay Viswanath 	.offset = &sdhci_msm_mci_offset,
18836ed4bb43SVijay Viswanath };
18846ed4bb43SVijay Viswanath 
18856ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_info sdhci_msm_v5_var = {
18866ed4bb43SVijay Viswanath 	.mci_removed = true,
18876ed4bb43SVijay Viswanath 	.var_ops = &v5_var_ops,
18886ed4bb43SVijay Viswanath 	.offset = &sdhci_msm_v5_offset,
18896ed4bb43SVijay Viswanath };
18906ed4bb43SVijay Viswanath 
189121f1e2d4SVeerabhadrarao Badiganti static const struct sdhci_msm_variant_info sdm845_sdhci_var = {
189221f1e2d4SVeerabhadrarao Badiganti 	.mci_removed = true,
189321f1e2d4SVeerabhadrarao Badiganti 	.restore_dll_config = true,
189421f1e2d4SVeerabhadrarao Badiganti 	.var_ops = &v5_var_ops,
189521f1e2d4SVeerabhadrarao Badiganti 	.offset = &sdhci_msm_v5_offset,
189621f1e2d4SVeerabhadrarao Badiganti };
189721f1e2d4SVeerabhadrarao Badiganti 
18985c30f340SVeerabhadrarao Badiganti static const struct sdhci_msm_variant_info sm8250_sdhci_var = {
18995c30f340SVeerabhadrarao Badiganti 	.mci_removed = true,
19005c30f340SVeerabhadrarao Badiganti 	.uses_tassadar_dll = true,
19015c30f340SVeerabhadrarao Badiganti 	.var_ops = &v5_var_ops,
19025c30f340SVeerabhadrarao Badiganti 	.offset = &sdhci_msm_v5_offset,
19035c30f340SVeerabhadrarao Badiganti };
19045c30f340SVeerabhadrarao Badiganti 
19050eb0d9f4SGeorgi Djakov static const struct of_device_id sdhci_msm_dt_match[] = {
1906bc99266bSSayali Lokhande 	{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
1907bc99266bSSayali Lokhande 	{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
190821f1e2d4SVeerabhadrarao Badiganti 	{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
19095c30f340SVeerabhadrarao Badiganti 	{.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var},
19100eb0d9f4SGeorgi Djakov 	{},
19110eb0d9f4SGeorgi Djakov };
19120eb0d9f4SGeorgi Djakov 
19130eb0d9f4SGeorgi Djakov MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
19140eb0d9f4SGeorgi Djakov 
1915a50396a4SJisheng Zhang static const struct sdhci_ops sdhci_msm_ops = {
19165cf583f1SVeerabhadrarao Badiganti 	.reset = sdhci_msm_reset,
1917edc609fdSRitesh Harjani 	.set_clock = sdhci_msm_set_clock,
191880031bdeSRitesh Harjani 	.get_min_clock = sdhci_msm_get_min_clock,
191980031bdeSRitesh Harjani 	.get_max_clock = sdhci_msm_get_max_clock,
1920ed1761d7SStephen Boyd 	.set_bus_width = sdhci_set_bus_width,
1921ee320674SRitesh Harjani 	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
1922c0309b38SVijay Viswanath 	.write_w = sdhci_msm_writew,
1923c0309b38SVijay Viswanath 	.write_b = sdhci_msm_writeb,
192487a8df0dSRitesh Harjani 	.irq	= sdhci_msm_cqe_irq,
19250eb0d9f4SGeorgi Djakov };
19260eb0d9f4SGeorgi Djakov 
1927a50396a4SJisheng Zhang static const struct sdhci_pltfm_data sdhci_msm_pdata = {
1928a50396a4SJisheng Zhang 	.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
1929a0e31428SRitesh Harjani 		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
1930d863cb03SVeerabhadrarao Badiganti 		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
1931d863cb03SVeerabhadrarao Badiganti 		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
1932d863cb03SVeerabhadrarao Badiganti 
1933a0e31428SRitesh Harjani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
1934a50396a4SJisheng Zhang 	.ops = &sdhci_msm_ops,
1935a50396a4SJisheng Zhang };
1936a50396a4SJisheng Zhang 
19371dfbe3ffSSarthak Garg static inline void sdhci_msm_get_of_property(struct platform_device *pdev,
19381dfbe3ffSSarthak Garg 		struct sdhci_host *host)
19391dfbe3ffSSarthak Garg {
19401dfbe3ffSSarthak Garg 	struct device_node *node = pdev->dev.of_node;
19411dfbe3ffSSarthak Garg 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
19421dfbe3ffSSarthak Garg 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
19431dfbe3ffSSarthak Garg 
19441dfbe3ffSSarthak Garg 	if (of_property_read_u32(node, "qcom,ddr-config",
19451dfbe3ffSSarthak Garg 				&msm_host->ddr_config))
19461dfbe3ffSSarthak Garg 		msm_host->ddr_config = DDR_CONFIG_POR_VAL;
19471dfbe3ffSSarthak Garg }
19481dfbe3ffSSarthak Garg 
19491dfbe3ffSSarthak Garg 
19500eb0d9f4SGeorgi Djakov static int sdhci_msm_probe(struct platform_device *pdev)
19510eb0d9f4SGeorgi Djakov {
19520eb0d9f4SGeorgi Djakov 	struct sdhci_host *host;
19530eb0d9f4SGeorgi Djakov 	struct sdhci_pltfm_host *pltfm_host;
19540eb0d9f4SGeorgi Djakov 	struct sdhci_msm_host *msm_host;
1955e4bf91f6SBjorn Andersson 	struct clk *clk;
19560eb0d9f4SGeorgi Djakov 	int ret;
19573a3ad3e9SGeorgi Djakov 	u16 host_version, core_minor;
195829301f40SRitesh Harjani 	u32 core_version, config;
19593a3ad3e9SGeorgi Djakov 	u8 core_major;
1960bc99266bSSayali Lokhande 	const struct sdhci_msm_offset *msm_offset;
1961bc99266bSSayali Lokhande 	const struct sdhci_msm_variant_info *var_info;
196287a8df0dSRitesh Harjani 	struct device_node *node = pdev->dev.of_node;
19630eb0d9f4SGeorgi Djakov 
19646f699531SJisheng Zhang 	host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
19650eb0d9f4SGeorgi Djakov 	if (IS_ERR(host))
19660eb0d9f4SGeorgi Djakov 		return PTR_ERR(host);
19670eb0d9f4SGeorgi Djakov 
19682a641e53SSrinivas Kandagatla 	host->sdma_boundary = 0;
19690eb0d9f4SGeorgi Djakov 	pltfm_host = sdhci_priv(host);
19706f699531SJisheng Zhang 	msm_host = sdhci_pltfm_priv(pltfm_host);
19710eb0d9f4SGeorgi Djakov 	msm_host->mmc = host->mmc;
19720eb0d9f4SGeorgi Djakov 	msm_host->pdev = pdev;
19730eb0d9f4SGeorgi Djakov 
19740eb0d9f4SGeorgi Djakov 	ret = mmc_of_parse(host->mmc);
19750eb0d9f4SGeorgi Djakov 	if (ret)
19760eb0d9f4SGeorgi Djakov 		goto pltfm_free;
19770eb0d9f4SGeorgi Djakov 
1978bc99266bSSayali Lokhande 	/*
1979bc99266bSSayali Lokhande 	 * Based on the compatible string, load the required msm host info from
1980bc99266bSSayali Lokhande 	 * the data associated with the version info.
1981bc99266bSSayali Lokhande 	 */
1982bc99266bSSayali Lokhande 	var_info = of_device_get_match_data(&pdev->dev);
1983bc99266bSSayali Lokhande 
1984bc99266bSSayali Lokhande 	msm_host->mci_removed = var_info->mci_removed;
198521f1e2d4SVeerabhadrarao Badiganti 	msm_host->restore_dll_config = var_info->restore_dll_config;
1986bc99266bSSayali Lokhande 	msm_host->var_ops = var_info->var_ops;
1987bc99266bSSayali Lokhande 	msm_host->offset = var_info->offset;
19885c30f340SVeerabhadrarao Badiganti 	msm_host->uses_tassadar_dll = var_info->uses_tassadar_dll;
1989bc99266bSSayali Lokhande 
1990bc99266bSSayali Lokhande 	msm_offset = msm_host->offset;
1991bc99266bSSayali Lokhande 
19920eb0d9f4SGeorgi Djakov 	sdhci_get_of_property(pdev);
19931dfbe3ffSSarthak Garg 	sdhci_msm_get_of_property(pdev, host);
19940eb0d9f4SGeorgi Djakov 
1995abf270e5SRitesh Harjani 	msm_host->saved_tuning_phase = INVALID_TUNING_PHASE;
1996abf270e5SRitesh Harjani 
19970eb0d9f4SGeorgi Djakov 	/* Setup SDCC bus voter clock. */
19980eb0d9f4SGeorgi Djakov 	msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
19990eb0d9f4SGeorgi Djakov 	if (!IS_ERR(msm_host->bus_clk)) {
20000eb0d9f4SGeorgi Djakov 		/* Vote for max. clk rate for max. performance */
20010eb0d9f4SGeorgi Djakov 		ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
20020eb0d9f4SGeorgi Djakov 		if (ret)
20030eb0d9f4SGeorgi Djakov 			goto pltfm_free;
20040eb0d9f4SGeorgi Djakov 		ret = clk_prepare_enable(msm_host->bus_clk);
20050eb0d9f4SGeorgi Djakov 		if (ret)
20060eb0d9f4SGeorgi Djakov 			goto pltfm_free;
20070eb0d9f4SGeorgi Djakov 	}
20080eb0d9f4SGeorgi Djakov 
20090eb0d9f4SGeorgi Djakov 	/* Setup main peripheral bus clock */
2010e4bf91f6SBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "iface");
2011e4bf91f6SBjorn Andersson 	if (IS_ERR(clk)) {
2012e4bf91f6SBjorn Andersson 		ret = PTR_ERR(clk);
20132801b95eSColin Ian King 		dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
20140eb0d9f4SGeorgi Djakov 		goto bus_clk_disable;
20150eb0d9f4SGeorgi Djakov 	}
2016e4bf91f6SBjorn Andersson 	msm_host->bulk_clks[1].clk = clk;
20170eb0d9f4SGeorgi Djakov 
20180eb0d9f4SGeorgi Djakov 	/* Setup SDC MMC clock */
2019e4bf91f6SBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "core");
2020e4bf91f6SBjorn Andersson 	if (IS_ERR(clk)) {
2021e4bf91f6SBjorn Andersson 		ret = PTR_ERR(clk);
20220eb0d9f4SGeorgi Djakov 		dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
2023e4bf91f6SBjorn Andersson 		goto bus_clk_disable;
20240eb0d9f4SGeorgi Djakov 	}
2025e4bf91f6SBjorn Andersson 	msm_host->bulk_clks[0].clk = clk;
2026e4bf91f6SBjorn Andersson 
2027c2b613d0SRajendra Nayak 	msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
2028c2b613d0SRajendra Nayak 	if (IS_ERR(msm_host->opp_table)) {
2029c2b613d0SRajendra Nayak 		ret = PTR_ERR(msm_host->opp_table);
20300472f8d3SRajendra Nayak 		goto bus_clk_disable;
20310472f8d3SRajendra Nayak 	}
20320472f8d3SRajendra Nayak 
20330472f8d3SRajendra Nayak 	/* OPP table is optional */
2034c2b613d0SRajendra Nayak 	ret = dev_pm_opp_of_add_table(&pdev->dev);
2035c2b613d0SRajendra Nayak 	if (!ret) {
2036c2b613d0SRajendra Nayak 		msm_host->has_opp_table = true;
2037c2b613d0SRajendra Nayak 	} else if (ret != -ENODEV) {
2038c2b613d0SRajendra Nayak 		dev_err(&pdev->dev, "Invalid OPP table in Device tree\n");
2039c2b613d0SRajendra Nayak 		goto opp_cleanup;
2040c2b613d0SRajendra Nayak 	}
20410472f8d3SRajendra Nayak 
2042e4bf91f6SBjorn Andersson 	/* Vote for maximum clock rate for maximum performance */
20430472f8d3SRajendra Nayak 	ret = dev_pm_opp_set_rate(&pdev->dev, INT_MAX);
2044e4bf91f6SBjorn Andersson 	if (ret)
2045e4bf91f6SBjorn Andersson 		dev_warn(&pdev->dev, "core clock boost failed\n");
2046e4bf91f6SBjorn Andersson 
20474946b3afSBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "cal");
20484946b3afSBjorn Andersson 	if (IS_ERR(clk))
20494946b3afSBjorn Andersson 		clk = NULL;
20504946b3afSBjorn Andersson 	msm_host->bulk_clks[2].clk = clk;
20514946b3afSBjorn Andersson 
20524946b3afSBjorn Andersson 	clk = devm_clk_get(&pdev->dev, "sleep");
20534946b3afSBjorn Andersson 	if (IS_ERR(clk))
20544946b3afSBjorn Andersson 		clk = NULL;
20554946b3afSBjorn Andersson 	msm_host->bulk_clks[3].clk = clk;
20564946b3afSBjorn Andersson 
2057e4bf91f6SBjorn Andersson 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
2058e4bf91f6SBjorn Andersson 				      msm_host->bulk_clks);
2059e4bf91f6SBjorn Andersson 	if (ret)
20600472f8d3SRajendra Nayak 		goto opp_cleanup;
20610eb0d9f4SGeorgi Djakov 
206283736352SVenkat Gopalakrishnan 	/*
206383736352SVenkat Gopalakrishnan 	 * xo clock is needed for FLL feature of cm_dll.
206483736352SVenkat Gopalakrishnan 	 * In case if xo clock is not mentioned in DT, warn and proceed.
206583736352SVenkat Gopalakrishnan 	 */
206683736352SVenkat Gopalakrishnan 	msm_host->xo_clk = devm_clk_get(&pdev->dev, "xo");
206783736352SVenkat Gopalakrishnan 	if (IS_ERR(msm_host->xo_clk)) {
206883736352SVenkat Gopalakrishnan 		ret = PTR_ERR(msm_host->xo_clk);
206983736352SVenkat Gopalakrishnan 		dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret);
207083736352SVenkat Gopalakrishnan 	}
207183736352SVenkat Gopalakrishnan 
2072bc99266bSSayali Lokhande 	if (!msm_host->mci_removed) {
2073cb064b50SYangtao Li 		msm_host->core_mem = devm_platform_ioremap_resource(pdev, 1);
20740eb0d9f4SGeorgi Djakov 		if (IS_ERR(msm_host->core_mem)) {
20750eb0d9f4SGeorgi Djakov 			ret = PTR_ERR(msm_host->core_mem);
20760eb0d9f4SGeorgi Djakov 			goto clk_disable;
20770eb0d9f4SGeorgi Djakov 		}
2078bc99266bSSayali Lokhande 	}
20790eb0d9f4SGeorgi Djakov 
20805574ddccSVenkat Gopalakrishnan 	/* Reset the vendor spec register to power on reset state */
20815574ddccSVenkat Gopalakrishnan 	writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
2082bc99266bSSayali Lokhande 			host->ioaddr + msm_offset->core_vendor_spec);
20830eb0d9f4SGeorgi Djakov 
2084bc99266bSSayali Lokhande 	if (!msm_host->mci_removed) {
20850eb0d9f4SGeorgi Djakov 		/* Set HC_MODE_EN bit in HC_MODE register */
2086bc99266bSSayali Lokhande 		msm_host_writel(msm_host, HC_MODE_EN, host,
2087bc99266bSSayali Lokhande 				msm_offset->core_hc_mode);
2088bc99266bSSayali Lokhande 		config = msm_host_readl(msm_host, host,
2089bc99266bSSayali Lokhande 				msm_offset->core_hc_mode);
2090ff06ce41SVenkat Gopalakrishnan 		config |= FF_CLK_SW_RST_DIS;
2091bc99266bSSayali Lokhande 		msm_host_writel(msm_host, config, host,
2092bc99266bSSayali Lokhande 				msm_offset->core_hc_mode);
2093bc99266bSSayali Lokhande 	}
2094ff06ce41SVenkat Gopalakrishnan 
20950eb0d9f4SGeorgi Djakov 	host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
20960eb0d9f4SGeorgi Djakov 	dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
20970eb0d9f4SGeorgi Djakov 		host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
20980eb0d9f4SGeorgi Djakov 			       SDHCI_VENDOR_VER_SHIFT));
20990eb0d9f4SGeorgi Djakov 
2100bc99266bSSayali Lokhande 	core_version = msm_host_readl(msm_host, host,
2101bc99266bSSayali Lokhande 			msm_offset->core_mci_version);
21023a3ad3e9SGeorgi Djakov 	core_major = (core_version & CORE_VERSION_MAJOR_MASK) >>
21033a3ad3e9SGeorgi Djakov 		      CORE_VERSION_MAJOR_SHIFT;
21043a3ad3e9SGeorgi Djakov 	core_minor = core_version & CORE_VERSION_MINOR_MASK;
21053a3ad3e9SGeorgi Djakov 	dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
21063a3ad3e9SGeorgi Djakov 		core_version, core_major, core_minor);
21073a3ad3e9SGeorgi Djakov 
210883736352SVenkat Gopalakrishnan 	if (core_major == 1 && core_minor >= 0x42)
210983736352SVenkat Gopalakrishnan 		msm_host->use_14lpp_dll_reset = true;
211083736352SVenkat Gopalakrishnan 
21113a3ad3e9SGeorgi Djakov 	/*
211202e4293dSRitesh Harjani 	 * SDCC 5 controller with major version 1, minor version 0x34 and later
211302e4293dSRitesh Harjani 	 * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL.
211402e4293dSRitesh Harjani 	 */
211502e4293dSRitesh Harjani 	if (core_major == 1 && core_minor < 0x34)
211602e4293dSRitesh Harjani 		msm_host->use_cdclp533 = true;
211702e4293dSRitesh Harjani 
211802e4293dSRitesh Harjani 	/*
21193a3ad3e9SGeorgi Djakov 	 * Support for some capabilities is not advertised by newer
21203a3ad3e9SGeorgi Djakov 	 * controller versions and must be explicitly enabled.
21213a3ad3e9SGeorgi Djakov 	 */
21223a3ad3e9SGeorgi Djakov 	if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) {
212329301f40SRitesh Harjani 		config = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES);
212429301f40SRitesh Harjani 		config |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT;
212529301f40SRitesh Harjani 		writel_relaxed(config, host->ioaddr +
2126bc99266bSSayali Lokhande 				msm_offset->core_vendor_spec_capabilities0);
21273a3ad3e9SGeorgi Djakov 	}
21283a3ad3e9SGeorgi Djakov 
2129fa56ac97SVeerabhadrarao Badiganti 	if (core_major == 1 && core_minor >= 0x49)
2130fa56ac97SVeerabhadrarao Badiganti 		msm_host->updated_ddr_cfg = true;
2131fa56ac97SVeerabhadrarao Badiganti 
2132c7ccee22SSubhash Jadavani 	/*
2133c7ccee22SSubhash Jadavani 	 * Power on reset state may trigger power irq if previous status of
2134c7ccee22SSubhash Jadavani 	 * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
2135c7ccee22SSubhash Jadavani 	 * interrupt in GIC, any pending power irq interrupt should be
2136c7ccee22SSubhash Jadavani 	 * acknowledged. Otherwise power irq interrupt handler would be
2137c7ccee22SSubhash Jadavani 	 * fired prematurely.
2138c7ccee22SSubhash Jadavani 	 */
2139401b2d06SSahitya Tummala 	sdhci_msm_handle_pwr_irq(host, 0);
2140c7ccee22SSubhash Jadavani 
2141c7ccee22SSubhash Jadavani 	/*
2142c7ccee22SSubhash Jadavani 	 * Ensure that above writes are propogated before interrupt enablement
2143c7ccee22SSubhash Jadavani 	 * in GIC.
2144c7ccee22SSubhash Jadavani 	 */
2145c7ccee22SSubhash Jadavani 	mb();
2146c7ccee22SSubhash Jadavani 
2147ad81d387SGeorgi Djakov 	/* Setup IRQ for handling power/voltage tasks with PMIC */
2148ad81d387SGeorgi Djakov 	msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
2149ad81d387SGeorgi Djakov 	if (msm_host->pwr_irq < 0) {
2150d1f63f0cSWei Yongjun 		ret = msm_host->pwr_irq;
2151ad81d387SGeorgi Djakov 		goto clk_disable;
2152ad81d387SGeorgi Djakov 	}
2153ad81d387SGeorgi Djakov 
2154c0309b38SVijay Viswanath 	sdhci_msm_init_pwr_irq_wait(msm_host);
2155c7ccee22SSubhash Jadavani 	/* Enable pwr irq interrupts */
2156bc99266bSSayali Lokhande 	msm_host_writel(msm_host, INT_MASK, host,
2157bc99266bSSayali Lokhande 		msm_offset->core_pwrctl_mask);
2158c7ccee22SSubhash Jadavani 
2159ad81d387SGeorgi Djakov 	ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
2160ad81d387SGeorgi Djakov 					sdhci_msm_pwr_irq, IRQF_ONESHOT,
2161ad81d387SGeorgi Djakov 					dev_name(&pdev->dev), host);
2162ad81d387SGeorgi Djakov 	if (ret) {
2163ad81d387SGeorgi Djakov 		dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
2164ad81d387SGeorgi Djakov 		goto clk_disable;
2165ad81d387SGeorgi Djakov 	}
2166ad81d387SGeorgi Djakov 
21679d8cb586SVeerabhadrarao Badiganti 	msm_host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY;
21689d8cb586SVeerabhadrarao Badiganti 
216967e6db11SPramod Gurav 	pm_runtime_get_noresume(&pdev->dev);
217067e6db11SPramod Gurav 	pm_runtime_set_active(&pdev->dev);
217167e6db11SPramod Gurav 	pm_runtime_enable(&pdev->dev);
217267e6db11SPramod Gurav 	pm_runtime_set_autosuspend_delay(&pdev->dev,
217367e6db11SPramod Gurav 					 MSM_MMC_AUTOSUSPEND_DELAY_MS);
217467e6db11SPramod Gurav 	pm_runtime_use_autosuspend(&pdev->dev);
217567e6db11SPramod Gurav 
21764436c535SRitesh Harjani 	host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning;
217787a8df0dSRitesh Harjani 	if (of_property_read_bool(node, "supports-cqe"))
217887a8df0dSRitesh Harjani 		ret = sdhci_msm_cqe_add_host(host, pdev);
217987a8df0dSRitesh Harjani 	else
21800eb0d9f4SGeorgi Djakov 		ret = sdhci_add_host(host);
21810eb0d9f4SGeorgi Djakov 	if (ret)
218267e6db11SPramod Gurav 		goto pm_runtime_disable;
2183ac06fba1SVijay Viswanath 	sdhci_msm_set_regulator_caps(msm_host);
218467e6db11SPramod Gurav 
218567e6db11SPramod Gurav 	pm_runtime_mark_last_busy(&pdev->dev);
218667e6db11SPramod Gurav 	pm_runtime_put_autosuspend(&pdev->dev);
21870eb0d9f4SGeorgi Djakov 
21880eb0d9f4SGeorgi Djakov 	return 0;
21890eb0d9f4SGeorgi Djakov 
219067e6db11SPramod Gurav pm_runtime_disable:
219167e6db11SPramod Gurav 	pm_runtime_disable(&pdev->dev);
219267e6db11SPramod Gurav 	pm_runtime_set_suspended(&pdev->dev);
219367e6db11SPramod Gurav 	pm_runtime_put_noidle(&pdev->dev);
21940eb0d9f4SGeorgi Djakov clk_disable:
2195e4bf91f6SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
2196e4bf91f6SBjorn Andersson 				   msm_host->bulk_clks);
21970472f8d3SRajendra Nayak opp_cleanup:
2198c2b613d0SRajendra Nayak 	if (msm_host->has_opp_table)
21990472f8d3SRajendra Nayak 		dev_pm_opp_of_remove_table(&pdev->dev);
2200c2b613d0SRajendra Nayak 	dev_pm_opp_put_clkname(msm_host->opp_table);
22010eb0d9f4SGeorgi Djakov bus_clk_disable:
22020eb0d9f4SGeorgi Djakov 	if (!IS_ERR(msm_host->bus_clk))
22030eb0d9f4SGeorgi Djakov 		clk_disable_unprepare(msm_host->bus_clk);
22040eb0d9f4SGeorgi Djakov pltfm_free:
22050eb0d9f4SGeorgi Djakov 	sdhci_pltfm_free(pdev);
22060eb0d9f4SGeorgi Djakov 	return ret;
22070eb0d9f4SGeorgi Djakov }
22080eb0d9f4SGeorgi Djakov 
22090eb0d9f4SGeorgi Djakov static int sdhci_msm_remove(struct platform_device *pdev)
22100eb0d9f4SGeorgi Djakov {
22110eb0d9f4SGeorgi Djakov 	struct sdhci_host *host = platform_get_drvdata(pdev);
22120eb0d9f4SGeorgi Djakov 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
22136f699531SJisheng Zhang 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
22140eb0d9f4SGeorgi Djakov 	int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
22150eb0d9f4SGeorgi Djakov 		    0xffffffff);
22160eb0d9f4SGeorgi Djakov 
22170eb0d9f4SGeorgi Djakov 	sdhci_remove_host(host, dead);
221867e6db11SPramod Gurav 
2219c2b613d0SRajendra Nayak 	if (msm_host->has_opp_table)
22200472f8d3SRajendra Nayak 		dev_pm_opp_of_remove_table(&pdev->dev);
2221c2b613d0SRajendra Nayak 	dev_pm_opp_put_clkname(msm_host->opp_table);
222267e6db11SPramod Gurav 	pm_runtime_get_sync(&pdev->dev);
222367e6db11SPramod Gurav 	pm_runtime_disable(&pdev->dev);
222467e6db11SPramod Gurav 	pm_runtime_put_noidle(&pdev->dev);
222567e6db11SPramod Gurav 
2226e4bf91f6SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
2227e4bf91f6SBjorn Andersson 				   msm_host->bulk_clks);
22280eb0d9f4SGeorgi Djakov 	if (!IS_ERR(msm_host->bus_clk))
22290eb0d9f4SGeorgi Djakov 		clk_disable_unprepare(msm_host->bus_clk);
22306f699531SJisheng Zhang 	sdhci_pltfm_free(pdev);
22310eb0d9f4SGeorgi Djakov 	return 0;
22320eb0d9f4SGeorgi Djakov }
22330eb0d9f4SGeorgi Djakov 
22346809a5f7SArnd Bergmann static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
223567e6db11SPramod Gurav {
223667e6db11SPramod Gurav 	struct sdhci_host *host = dev_get_drvdata(dev);
223767e6db11SPramod Gurav 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
223867e6db11SPramod Gurav 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
223967e6db11SPramod Gurav 
22400472f8d3SRajendra Nayak 	/* Drop the performance vote */
22410472f8d3SRajendra Nayak 	dev_pm_opp_set_rate(dev, 0);
2242e4bf91f6SBjorn Andersson 	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
2243e4bf91f6SBjorn Andersson 				   msm_host->bulk_clks);
224467e6db11SPramod Gurav 
224567e6db11SPramod Gurav 	return 0;
224667e6db11SPramod Gurav }
224767e6db11SPramod Gurav 
22486809a5f7SArnd Bergmann static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
224967e6db11SPramod Gurav {
225067e6db11SPramod Gurav 	struct sdhci_host *host = dev_get_drvdata(dev);
225167e6db11SPramod Gurav 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
225267e6db11SPramod Gurav 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
225321f1e2d4SVeerabhadrarao Badiganti 	int ret;
225467e6db11SPramod Gurav 
225521f1e2d4SVeerabhadrarao Badiganti 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
2256e4bf91f6SBjorn Andersson 				       msm_host->bulk_clks);
225721f1e2d4SVeerabhadrarao Badiganti 	if (ret)
225821f1e2d4SVeerabhadrarao Badiganti 		return ret;
225921f1e2d4SVeerabhadrarao Badiganti 	/*
226021f1e2d4SVeerabhadrarao Badiganti 	 * Whenever core-clock is gated dynamically, it's needed to
226121f1e2d4SVeerabhadrarao Badiganti 	 * restore the SDR DLL settings when the clock is ungated.
226221f1e2d4SVeerabhadrarao Badiganti 	 */
226321f1e2d4SVeerabhadrarao Badiganti 	if (msm_host->restore_dll_config && msm_host->clk_rate)
22640472f8d3SRajendra Nayak 		ret = sdhci_msm_restore_sdr_dll_config(host);
226521f1e2d4SVeerabhadrarao Badiganti 
22660472f8d3SRajendra Nayak 	dev_pm_opp_set_rate(dev, msm_host->clk_rate);
22670472f8d3SRajendra Nayak 
22680472f8d3SRajendra Nayak 	return ret;
226967e6db11SPramod Gurav }
227067e6db11SPramod Gurav 
227167e6db11SPramod Gurav static const struct dev_pm_ops sdhci_msm_pm_ops = {
227267e6db11SPramod Gurav 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
227367e6db11SPramod Gurav 				pm_runtime_force_resume)
227467e6db11SPramod Gurav 	SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend,
227567e6db11SPramod Gurav 			   sdhci_msm_runtime_resume,
227667e6db11SPramod Gurav 			   NULL)
227767e6db11SPramod Gurav };
227867e6db11SPramod Gurav 
22790eb0d9f4SGeorgi Djakov static struct platform_driver sdhci_msm_driver = {
22800eb0d9f4SGeorgi Djakov 	.probe = sdhci_msm_probe,
22810eb0d9f4SGeorgi Djakov 	.remove = sdhci_msm_remove,
22820eb0d9f4SGeorgi Djakov 	.driver = {
22830eb0d9f4SGeorgi Djakov 		   .name = "sdhci_msm",
22840eb0d9f4SGeorgi Djakov 		   .of_match_table = sdhci_msm_dt_match,
228567e6db11SPramod Gurav 		   .pm = &sdhci_msm_pm_ops,
22860eb0d9f4SGeorgi Djakov 	},
22870eb0d9f4SGeorgi Djakov };
22880eb0d9f4SGeorgi Djakov 
22890eb0d9f4SGeorgi Djakov module_platform_driver(sdhci_msm_driver);
22900eb0d9f4SGeorgi Djakov 
22910eb0d9f4SGeorgi Djakov MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
22920eb0d9f4SGeorgi Djakov MODULE_LICENSE("GPL v2");
2293