162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/mmc/mmc.h>
1162306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1262306a36Sopenharmony_ci#include <linux/pm_opp.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/iopoll.h>
1562306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1662306a36Sopenharmony_ci#include <linux/interconnect.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
1962306a36Sopenharmony_ci#include <linux/reset.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <soc/qcom/ice.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "sdhci-cqhci.h"
2462306a36Sopenharmony_ci#include "sdhci-pltfm.h"
2562306a36Sopenharmony_ci#include "cqhci.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define CORE_MCI_VERSION		0x50
2862306a36Sopenharmony_ci#define CORE_VERSION_MAJOR_SHIFT	28
2962306a36Sopenharmony_ci#define CORE_VERSION_MAJOR_MASK		(0xf << CORE_VERSION_MAJOR_SHIFT)
3062306a36Sopenharmony_ci#define CORE_VERSION_MINOR_MASK		0xff
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define CORE_MCI_GENERICS		0x70
3362306a36Sopenharmony_ci#define SWITCHABLE_SIGNALING_VOLTAGE	BIT(29)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define HC_MODE_EN		0x1
3662306a36Sopenharmony_ci#define CORE_POWER		0x0
3762306a36Sopenharmony_ci#define CORE_SW_RST		BIT(7)
3862306a36Sopenharmony_ci#define FF_CLK_SW_RST_DIS	BIT(13)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define CORE_PWRCTL_BUS_OFF	BIT(0)
4162306a36Sopenharmony_ci#define CORE_PWRCTL_BUS_ON	BIT(1)
4262306a36Sopenharmony_ci#define CORE_PWRCTL_IO_LOW	BIT(2)
4362306a36Sopenharmony_ci#define CORE_PWRCTL_IO_HIGH	BIT(3)
4462306a36Sopenharmony_ci#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
4562306a36Sopenharmony_ci#define CORE_PWRCTL_BUS_FAIL    BIT(1)
4662306a36Sopenharmony_ci#define CORE_PWRCTL_IO_SUCCESS	BIT(2)
4762306a36Sopenharmony_ci#define CORE_PWRCTL_IO_FAIL     BIT(3)
4862306a36Sopenharmony_ci#define REQ_BUS_OFF		BIT(0)
4962306a36Sopenharmony_ci#define REQ_BUS_ON		BIT(1)
5062306a36Sopenharmony_ci#define REQ_IO_LOW		BIT(2)
5162306a36Sopenharmony_ci#define REQ_IO_HIGH		BIT(3)
5262306a36Sopenharmony_ci#define INT_MASK		0xf
5362306a36Sopenharmony_ci#define MAX_PHASES		16
5462306a36Sopenharmony_ci#define CORE_DLL_LOCK		BIT(7)
5562306a36Sopenharmony_ci#define CORE_DDR_DLL_LOCK	BIT(11)
5662306a36Sopenharmony_ci#define CORE_DLL_EN		BIT(16)
5762306a36Sopenharmony_ci#define CORE_CDR_EN		BIT(17)
5862306a36Sopenharmony_ci#define CORE_CK_OUT_EN		BIT(18)
5962306a36Sopenharmony_ci#define CORE_CDR_EXT_EN		BIT(19)
6062306a36Sopenharmony_ci#define CORE_DLL_PDN		BIT(29)
6162306a36Sopenharmony_ci#define CORE_DLL_RST		BIT(30)
6262306a36Sopenharmony_ci#define CORE_CMD_DAT_TRACK_SEL	BIT(0)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define CORE_DDR_CAL_EN		BIT(0)
6562306a36Sopenharmony_ci#define CORE_FLL_CYCLE_CNT	BIT(18)
6662306a36Sopenharmony_ci#define CORE_DLL_CLOCK_DISABLE	BIT(21)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define DLL_USR_CTL_POR_VAL	0x10800
6962306a36Sopenharmony_ci#define ENABLE_DLL_LOCK_STATUS	BIT(26)
7062306a36Sopenharmony_ci#define FINE_TUNE_MODE_EN	BIT(27)
7162306a36Sopenharmony_ci#define BIAS_OK_SIGNAL		BIT(29)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define DLL_CONFIG_3_LOW_FREQ_VAL	0x08
7462306a36Sopenharmony_ci#define DLL_CONFIG_3_HIGH_FREQ_VAL	0x10
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define CORE_VENDOR_SPEC_POR_VAL 0xa9c
7762306a36Sopenharmony_ci#define CORE_CLK_PWRSAVE	BIT(1)
7862306a36Sopenharmony_ci#define CORE_HC_MCLK_SEL_DFLT	(2 << 8)
7962306a36Sopenharmony_ci#define CORE_HC_MCLK_SEL_HS400	(3 << 8)
8062306a36Sopenharmony_ci#define CORE_HC_MCLK_SEL_MASK	(3 << 8)
8162306a36Sopenharmony_ci#define CORE_IO_PAD_PWR_SWITCH_EN	BIT(15)
8262306a36Sopenharmony_ci#define CORE_IO_PAD_PWR_SWITCH	BIT(16)
8362306a36Sopenharmony_ci#define CORE_HC_SELECT_IN_EN	BIT(18)
8462306a36Sopenharmony_ci#define CORE_HC_SELECT_IN_HS400	(6 << 19)
8562306a36Sopenharmony_ci#define CORE_HC_SELECT_IN_MASK	(7 << 19)
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define CORE_3_0V_SUPPORT	BIT(25)
8862306a36Sopenharmony_ci#define CORE_1_8V_SUPPORT	BIT(26)
8962306a36Sopenharmony_ci#define CORE_VOLT_SUPPORT	(CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define CORE_CSR_CDC_CTLR_CFG0		0x130
9262306a36Sopenharmony_ci#define CORE_SW_TRIG_FULL_CALIB		BIT(16)
9362306a36Sopenharmony_ci#define CORE_HW_AUTOCAL_ENA		BIT(17)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define CORE_CSR_CDC_CTLR_CFG1		0x134
9662306a36Sopenharmony_ci#define CORE_CSR_CDC_CAL_TIMER_CFG0	0x138
9762306a36Sopenharmony_ci#define CORE_TIMER_ENA			BIT(16)
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define CORE_CSR_CDC_CAL_TIMER_CFG1	0x13C
10062306a36Sopenharmony_ci#define CORE_CSR_CDC_REFCOUNT_CFG	0x140
10162306a36Sopenharmony_ci#define CORE_CSR_CDC_COARSE_CAL_CFG	0x144
10262306a36Sopenharmony_ci#define CORE_CDC_OFFSET_CFG		0x14C
10362306a36Sopenharmony_ci#define CORE_CSR_CDC_DELAY_CFG		0x150
10462306a36Sopenharmony_ci#define CORE_CDC_SLAVE_DDA_CFG		0x160
10562306a36Sopenharmony_ci#define CORE_CSR_CDC_STATUS0		0x164
10662306a36Sopenharmony_ci#define CORE_CALIBRATION_DONE		BIT(0)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define CORE_CDC_ERROR_CODE_MASK	0x7000000
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define CORE_CSR_CDC_GEN_CFG		0x178
11162306a36Sopenharmony_ci#define CORE_CDC_SWITCH_BYPASS_OFF	BIT(0)
11262306a36Sopenharmony_ci#define CORE_CDC_SWITCH_RC_EN		BIT(1)
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define CORE_CDC_T4_DLY_SEL		BIT(0)
11562306a36Sopenharmony_ci#define CORE_CMDIN_RCLK_EN		BIT(1)
11662306a36Sopenharmony_ci#define CORE_START_CDC_TRAFFIC		BIT(6)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define CORE_PWRSAVE_DLL	BIT(3)
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define DDR_CONFIG_POR_VAL	0x80040873
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define INVALID_TUNING_PHASE	-1
12462306a36Sopenharmony_ci#define SDHCI_MSM_MIN_CLOCK	400000
12562306a36Sopenharmony_ci#define CORE_FREQ_100MHZ	(100 * 1000 * 1000)
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define CDR_SELEXT_SHIFT	20
12862306a36Sopenharmony_ci#define CDR_SELEXT_MASK		(0xf << CDR_SELEXT_SHIFT)
12962306a36Sopenharmony_ci#define CMUX_SHIFT_PHASE_SHIFT	24
13062306a36Sopenharmony_ci#define CMUX_SHIFT_PHASE_MASK	(7 << CMUX_SHIFT_PHASE_SHIFT)
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define MSM_MMC_AUTOSUSPEND_DELAY_MS	50
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* Timeout value to avoid infinite waiting for pwr_irq */
13562306a36Sopenharmony_ci#define MSM_PWR_IRQ_TIMEOUT_MS 5000
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/* Max load for eMMC Vdd-io supply */
13862306a36Sopenharmony_ci#define MMC_VQMMC_MAX_LOAD_UA	325000
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci#define msm_host_readl(msm_host, host, offset) \
14162306a36Sopenharmony_ci	msm_host->var_ops->msm_readl_relaxed(host, offset)
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define msm_host_writel(msm_host, val, host, offset) \
14462306a36Sopenharmony_ci	msm_host->var_ops->msm_writel_relaxed(val, host, offset)
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* CQHCI vendor specific registers */
14762306a36Sopenharmony_ci#define CQHCI_VENDOR_CFG1	0xA00
14862306a36Sopenharmony_ci#define CQHCI_VENDOR_DIS_RST_ON_CQ_EN	(0x3 << 13)
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistruct sdhci_msm_offset {
15162306a36Sopenharmony_ci	u32 core_hc_mode;
15262306a36Sopenharmony_ci	u32 core_mci_data_cnt;
15362306a36Sopenharmony_ci	u32 core_mci_status;
15462306a36Sopenharmony_ci	u32 core_mci_fifo_cnt;
15562306a36Sopenharmony_ci	u32 core_mci_version;
15662306a36Sopenharmony_ci	u32 core_generics;
15762306a36Sopenharmony_ci	u32 core_testbus_config;
15862306a36Sopenharmony_ci	u32 core_testbus_sel2_bit;
15962306a36Sopenharmony_ci	u32 core_testbus_ena;
16062306a36Sopenharmony_ci	u32 core_testbus_sel2;
16162306a36Sopenharmony_ci	u32 core_pwrctl_status;
16262306a36Sopenharmony_ci	u32 core_pwrctl_mask;
16362306a36Sopenharmony_ci	u32 core_pwrctl_clear;
16462306a36Sopenharmony_ci	u32 core_pwrctl_ctl;
16562306a36Sopenharmony_ci	u32 core_sdcc_debug_reg;
16662306a36Sopenharmony_ci	u32 core_dll_config;
16762306a36Sopenharmony_ci	u32 core_dll_status;
16862306a36Sopenharmony_ci	u32 core_vendor_spec;
16962306a36Sopenharmony_ci	u32 core_vendor_spec_adma_err_addr0;
17062306a36Sopenharmony_ci	u32 core_vendor_spec_adma_err_addr1;
17162306a36Sopenharmony_ci	u32 core_vendor_spec_func2;
17262306a36Sopenharmony_ci	u32 core_vendor_spec_capabilities0;
17362306a36Sopenharmony_ci	u32 core_ddr_200_cfg;
17462306a36Sopenharmony_ci	u32 core_vendor_spec3;
17562306a36Sopenharmony_ci	u32 core_dll_config_2;
17662306a36Sopenharmony_ci	u32 core_dll_config_3;
17762306a36Sopenharmony_ci	u32 core_ddr_config_old; /* Applicable to sdcc minor ver < 0x49 */
17862306a36Sopenharmony_ci	u32 core_ddr_config;
17962306a36Sopenharmony_ci	u32 core_dll_usr_ctl; /* Present on SDCC5.1 onwards */
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic const struct sdhci_msm_offset sdhci_msm_v5_offset = {
18362306a36Sopenharmony_ci	.core_mci_data_cnt = 0x35c,
18462306a36Sopenharmony_ci	.core_mci_status = 0x324,
18562306a36Sopenharmony_ci	.core_mci_fifo_cnt = 0x308,
18662306a36Sopenharmony_ci	.core_mci_version = 0x318,
18762306a36Sopenharmony_ci	.core_generics = 0x320,
18862306a36Sopenharmony_ci	.core_testbus_config = 0x32c,
18962306a36Sopenharmony_ci	.core_testbus_sel2_bit = 3,
19062306a36Sopenharmony_ci	.core_testbus_ena = (1 << 31),
19162306a36Sopenharmony_ci	.core_testbus_sel2 = (1 << 3),
19262306a36Sopenharmony_ci	.core_pwrctl_status = 0x240,
19362306a36Sopenharmony_ci	.core_pwrctl_mask = 0x244,
19462306a36Sopenharmony_ci	.core_pwrctl_clear = 0x248,
19562306a36Sopenharmony_ci	.core_pwrctl_ctl = 0x24c,
19662306a36Sopenharmony_ci	.core_sdcc_debug_reg = 0x358,
19762306a36Sopenharmony_ci	.core_dll_config = 0x200,
19862306a36Sopenharmony_ci	.core_dll_status = 0x208,
19962306a36Sopenharmony_ci	.core_vendor_spec = 0x20c,
20062306a36Sopenharmony_ci	.core_vendor_spec_adma_err_addr0 = 0x214,
20162306a36Sopenharmony_ci	.core_vendor_spec_adma_err_addr1 = 0x218,
20262306a36Sopenharmony_ci	.core_vendor_spec_func2 = 0x210,
20362306a36Sopenharmony_ci	.core_vendor_spec_capabilities0 = 0x21c,
20462306a36Sopenharmony_ci	.core_ddr_200_cfg = 0x224,
20562306a36Sopenharmony_ci	.core_vendor_spec3 = 0x250,
20662306a36Sopenharmony_ci	.core_dll_config_2 = 0x254,
20762306a36Sopenharmony_ci	.core_dll_config_3 = 0x258,
20862306a36Sopenharmony_ci	.core_ddr_config = 0x25c,
20962306a36Sopenharmony_ci	.core_dll_usr_ctl = 0x388,
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic const struct sdhci_msm_offset sdhci_msm_mci_offset = {
21362306a36Sopenharmony_ci	.core_hc_mode = 0x78,
21462306a36Sopenharmony_ci	.core_mci_data_cnt = 0x30,
21562306a36Sopenharmony_ci	.core_mci_status = 0x34,
21662306a36Sopenharmony_ci	.core_mci_fifo_cnt = 0x44,
21762306a36Sopenharmony_ci	.core_mci_version = 0x050,
21862306a36Sopenharmony_ci	.core_generics = 0x70,
21962306a36Sopenharmony_ci	.core_testbus_config = 0x0cc,
22062306a36Sopenharmony_ci	.core_testbus_sel2_bit = 4,
22162306a36Sopenharmony_ci	.core_testbus_ena = (1 << 3),
22262306a36Sopenharmony_ci	.core_testbus_sel2 = (1 << 4),
22362306a36Sopenharmony_ci	.core_pwrctl_status = 0xdc,
22462306a36Sopenharmony_ci	.core_pwrctl_mask = 0xe0,
22562306a36Sopenharmony_ci	.core_pwrctl_clear = 0xe4,
22662306a36Sopenharmony_ci	.core_pwrctl_ctl = 0xe8,
22762306a36Sopenharmony_ci	.core_sdcc_debug_reg = 0x124,
22862306a36Sopenharmony_ci	.core_dll_config = 0x100,
22962306a36Sopenharmony_ci	.core_dll_status = 0x108,
23062306a36Sopenharmony_ci	.core_vendor_spec = 0x10c,
23162306a36Sopenharmony_ci	.core_vendor_spec_adma_err_addr0 = 0x114,
23262306a36Sopenharmony_ci	.core_vendor_spec_adma_err_addr1 = 0x118,
23362306a36Sopenharmony_ci	.core_vendor_spec_func2 = 0x110,
23462306a36Sopenharmony_ci	.core_vendor_spec_capabilities0 = 0x11c,
23562306a36Sopenharmony_ci	.core_ddr_200_cfg = 0x184,
23662306a36Sopenharmony_ci	.core_vendor_spec3 = 0x1b0,
23762306a36Sopenharmony_ci	.core_dll_config_2 = 0x1b4,
23862306a36Sopenharmony_ci	.core_ddr_config_old = 0x1b8,
23962306a36Sopenharmony_ci	.core_ddr_config = 0x1bc,
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistruct sdhci_msm_variant_ops {
24362306a36Sopenharmony_ci	u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
24462306a36Sopenharmony_ci	void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
24562306a36Sopenharmony_ci			u32 offset);
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/*
24962306a36Sopenharmony_ci * From V5, register spaces have changed. Wrap this info in a structure
25062306a36Sopenharmony_ci * and choose the data_structure based on version info mentioned in DT.
25162306a36Sopenharmony_ci */
25262306a36Sopenharmony_cistruct sdhci_msm_variant_info {
25362306a36Sopenharmony_ci	bool mci_removed;
25462306a36Sopenharmony_ci	bool restore_dll_config;
25562306a36Sopenharmony_ci	const struct sdhci_msm_variant_ops *var_ops;
25662306a36Sopenharmony_ci	const struct sdhci_msm_offset *offset;
25762306a36Sopenharmony_ci};
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistruct sdhci_msm_host {
26062306a36Sopenharmony_ci	struct platform_device *pdev;
26162306a36Sopenharmony_ci	void __iomem *core_mem;	/* MSM SDCC mapped address */
26262306a36Sopenharmony_ci	int pwr_irq;		/* power irq */
26362306a36Sopenharmony_ci	struct clk *bus_clk;	/* SDHC bus voter clock */
26462306a36Sopenharmony_ci	struct clk *xo_clk;	/* TCXO clk needed for FLL feature of cm_dll*/
26562306a36Sopenharmony_ci	/* core, iface, cal and sleep clocks */
26662306a36Sopenharmony_ci	struct clk_bulk_data bulk_clks[4];
26762306a36Sopenharmony_ci#ifdef CONFIG_MMC_CRYPTO
26862306a36Sopenharmony_ci	struct qcom_ice *ice;
26962306a36Sopenharmony_ci#endif
27062306a36Sopenharmony_ci	unsigned long clk_rate;
27162306a36Sopenharmony_ci	struct mmc_host *mmc;
27262306a36Sopenharmony_ci	bool use_14lpp_dll_reset;
27362306a36Sopenharmony_ci	bool tuning_done;
27462306a36Sopenharmony_ci	bool calibration_done;
27562306a36Sopenharmony_ci	u8 saved_tuning_phase;
27662306a36Sopenharmony_ci	bool use_cdclp533;
27762306a36Sopenharmony_ci	u32 curr_pwr_state;
27862306a36Sopenharmony_ci	u32 curr_io_level;
27962306a36Sopenharmony_ci	wait_queue_head_t pwr_irq_wait;
28062306a36Sopenharmony_ci	bool pwr_irq_flag;
28162306a36Sopenharmony_ci	u32 caps_0;
28262306a36Sopenharmony_ci	bool mci_removed;
28362306a36Sopenharmony_ci	bool restore_dll_config;
28462306a36Sopenharmony_ci	const struct sdhci_msm_variant_ops *var_ops;
28562306a36Sopenharmony_ci	const struct sdhci_msm_offset *offset;
28662306a36Sopenharmony_ci	bool use_cdr;
28762306a36Sopenharmony_ci	u32 transfer_mode;
28862306a36Sopenharmony_ci	bool updated_ddr_cfg;
28962306a36Sopenharmony_ci	bool uses_tassadar_dll;
29062306a36Sopenharmony_ci	u32 dll_config;
29162306a36Sopenharmony_ci	u32 ddr_config;
29262306a36Sopenharmony_ci	bool vqmmc_enabled;
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
29862306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return msm_host->offset;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/*
30462306a36Sopenharmony_ci * APIs to read/write to vendor specific registers which were there in the
30562306a36Sopenharmony_ci * core_mem region before MCI was removed.
30662306a36Sopenharmony_ci */
30762306a36Sopenharmony_cistatic u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
30862306a36Sopenharmony_ci		u32 offset)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
31162306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return readl_relaxed(msm_host->core_mem + offset);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
31762306a36Sopenharmony_ci		u32 offset)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	return readl_relaxed(host->ioaddr + offset);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic void sdhci_msm_mci_variant_writel_relaxed(u32 val,
32362306a36Sopenharmony_ci		struct sdhci_host *host, u32 offset)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
32662306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	writel_relaxed(val, msm_host->core_mem + offset);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic void sdhci_msm_v5_variant_writel_relaxed(u32 val,
33262306a36Sopenharmony_ci		struct sdhci_host *host, u32 offset)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	writel_relaxed(val, host->ioaddr + offset);
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic unsigned int msm_get_clock_mult_for_bus_mode(struct sdhci_host *host)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct mmc_ios ios = host->mmc->ios;
34062306a36Sopenharmony_ci	/*
34162306a36Sopenharmony_ci	 * The SDHC requires internal clock frequency to be double the
34262306a36Sopenharmony_ci	 * actual clock that will be set for DDR mode. The controller
34362306a36Sopenharmony_ci	 * uses the faster clock(100/400MHz) for some of its parts and
34462306a36Sopenharmony_ci	 * send the actual required clock (50/200MHz) to the card.
34562306a36Sopenharmony_ci	 */
34662306a36Sopenharmony_ci	if (ios.timing == MMC_TIMING_UHS_DDR50 ||
34762306a36Sopenharmony_ci	    ios.timing == MMC_TIMING_MMC_DDR52 ||
34862306a36Sopenharmony_ci	    ios.timing == MMC_TIMING_MMC_HS400 ||
34962306a36Sopenharmony_ci	    host->flags & SDHCI_HS400_TUNING)
35062306a36Sopenharmony_ci		return 2;
35162306a36Sopenharmony_ci	return 1;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
35562306a36Sopenharmony_ci					    unsigned int clock)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
35862306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
35962306a36Sopenharmony_ci	struct mmc_ios curr_ios = host->mmc->ios;
36062306a36Sopenharmony_ci	struct clk *core_clk = msm_host->bulk_clks[0].clk;
36162306a36Sopenharmony_ci	unsigned long achieved_rate;
36262306a36Sopenharmony_ci	unsigned int desired_rate;
36362306a36Sopenharmony_ci	unsigned int mult;
36462306a36Sopenharmony_ci	int rc;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	mult = msm_get_clock_mult_for_bus_mode(host);
36762306a36Sopenharmony_ci	desired_rate = clock * mult;
36862306a36Sopenharmony_ci	rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), desired_rate);
36962306a36Sopenharmony_ci	if (rc) {
37062306a36Sopenharmony_ci		pr_err("%s: Failed to set clock at rate %u at timing %d\n",
37162306a36Sopenharmony_ci		       mmc_hostname(host->mmc), desired_rate, curr_ios.timing);
37262306a36Sopenharmony_ci		return;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/*
37662306a36Sopenharmony_ci	 * Qualcomm clock drivers by default round clock _up_ if they can't
37762306a36Sopenharmony_ci	 * make the requested rate.  This is not good for SD.  Yell if we
37862306a36Sopenharmony_ci	 * encounter it.
37962306a36Sopenharmony_ci	 */
38062306a36Sopenharmony_ci	achieved_rate = clk_get_rate(core_clk);
38162306a36Sopenharmony_ci	if (achieved_rate > desired_rate)
38262306a36Sopenharmony_ci		pr_warn("%s: Card appears overclocked; req %u Hz, actual %lu Hz\n",
38362306a36Sopenharmony_ci			mmc_hostname(host->mmc), desired_rate, achieved_rate);
38462306a36Sopenharmony_ci	host->mmc->actual_clock = achieved_rate / mult;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Stash the rate we requested to use in sdhci_msm_runtime_resume() */
38762306a36Sopenharmony_ci	msm_host->clk_rate = desired_rate;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	pr_debug("%s: Setting clock at rate %lu at timing %d\n",
39062306a36Sopenharmony_ci		 mmc_hostname(host->mmc), achieved_rate, curr_ios.timing);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/* Platform specific tuning */
39462306a36Sopenharmony_cistatic inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	u32 wait_cnt = 50;
39762306a36Sopenharmony_ci	u8 ck_out_en;
39862306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
39962306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
40062306a36Sopenharmony_ci					sdhci_priv_msm_offset(host);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Poll for CK_OUT_EN bit.  max. poll time = 50us */
40362306a36Sopenharmony_ci	ck_out_en = !!(readl_relaxed(host->ioaddr +
40462306a36Sopenharmony_ci			msm_offset->core_dll_config) & CORE_CK_OUT_EN);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	while (ck_out_en != poll) {
40762306a36Sopenharmony_ci		if (--wait_cnt == 0) {
40862306a36Sopenharmony_ci			dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
40962306a36Sopenharmony_ci			       mmc_hostname(mmc), poll);
41062306a36Sopenharmony_ci			return -ETIMEDOUT;
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci		udelay(1);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		ck_out_en = !!(readl_relaxed(host->ioaddr +
41562306a36Sopenharmony_ci			msm_offset->core_dll_config) & CORE_CK_OUT_EN);
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return 0;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	int rc;
42462306a36Sopenharmony_ci	static const u8 grey_coded_phase_table[] = {
42562306a36Sopenharmony_ci		0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
42662306a36Sopenharmony_ci		0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
42762306a36Sopenharmony_ci	};
42862306a36Sopenharmony_ci	unsigned long flags;
42962306a36Sopenharmony_ci	u32 config;
43062306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
43162306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
43262306a36Sopenharmony_ci					sdhci_priv_msm_offset(host);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (phase > 0xf)
43562306a36Sopenharmony_ci		return -EINVAL;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	spin_lock_irqsave(&host->lock, flags);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
44062306a36Sopenharmony_ci	config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
44162306a36Sopenharmony_ci	config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
44262306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
44562306a36Sopenharmony_ci	rc = msm_dll_poll_ck_out_en(host, 0);
44662306a36Sopenharmony_ci	if (rc)
44762306a36Sopenharmony_ci		goto err_out;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/*
45062306a36Sopenharmony_ci	 * Write the selected DLL clock output phase (0 ... 15)
45162306a36Sopenharmony_ci	 * to CDR_SELEXT bit field of DLL_CONFIG register.
45262306a36Sopenharmony_ci	 */
45362306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
45462306a36Sopenharmony_ci	config &= ~CDR_SELEXT_MASK;
45562306a36Sopenharmony_ci	config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
45662306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
45962306a36Sopenharmony_ci	config |= CORE_CK_OUT_EN;
46062306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
46362306a36Sopenharmony_ci	rc = msm_dll_poll_ck_out_en(host, 1);
46462306a36Sopenharmony_ci	if (rc)
46562306a36Sopenharmony_ci		goto err_out;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
46862306a36Sopenharmony_ci	config |= CORE_CDR_EN;
46962306a36Sopenharmony_ci	config &= ~CORE_CDR_EXT_EN;
47062306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
47162306a36Sopenharmony_ci	goto out;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cierr_out:
47462306a36Sopenharmony_ci	dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
47562306a36Sopenharmony_ci	       mmc_hostname(mmc), phase);
47662306a36Sopenharmony_ciout:
47762306a36Sopenharmony_ci	spin_unlock_irqrestore(&host->lock, flags);
47862306a36Sopenharmony_ci	return rc;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci/*
48262306a36Sopenharmony_ci * Find out the greatest range of consecuitive selected
48362306a36Sopenharmony_ci * DLL clock output phases that can be used as sampling
48462306a36Sopenharmony_ci * setting for SD3.0 UHS-I card read operation (in SDR104
48562306a36Sopenharmony_ci * timing mode) or for eMMC4.5 card read operation (in
48662306a36Sopenharmony_ci * HS400/HS200 timing mode).
48762306a36Sopenharmony_ci * Select the 3/4 of the range and configure the DLL with the
48862306a36Sopenharmony_ci * selected DLL clock output phase.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic int msm_find_most_appropriate_phase(struct sdhci_host *host,
49262306a36Sopenharmony_ci					   u8 *phase_table, u8 total_phases)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	int ret;
49562306a36Sopenharmony_ci	u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
49662306a36Sopenharmony_ci	u8 phases_per_row[MAX_PHASES] = { 0 };
49762306a36Sopenharmony_ci	int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
49862306a36Sopenharmony_ci	int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
49962306a36Sopenharmony_ci	bool phase_0_found = false, phase_15_found = false;
50062306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (!total_phases || (total_phases > MAX_PHASES)) {
50362306a36Sopenharmony_ci		dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
50462306a36Sopenharmony_ci		       mmc_hostname(mmc), total_phases);
50562306a36Sopenharmony_ci		return -EINVAL;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	for (cnt = 0; cnt < total_phases; cnt++) {
50962306a36Sopenharmony_ci		ranges[row_index][col_index] = phase_table[cnt];
51062306a36Sopenharmony_ci		phases_per_row[row_index] += 1;
51162306a36Sopenharmony_ci		col_index++;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		if ((cnt + 1) == total_phases) {
51462306a36Sopenharmony_ci			continue;
51562306a36Sopenharmony_ci		/* check if next phase in phase_table is consecutive or not */
51662306a36Sopenharmony_ci		} else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
51762306a36Sopenharmony_ci			row_index++;
51862306a36Sopenharmony_ci			col_index = 0;
51962306a36Sopenharmony_ci		}
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (row_index >= MAX_PHASES)
52362306a36Sopenharmony_ci		return -EINVAL;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* Check if phase-0 is present in first valid window? */
52662306a36Sopenharmony_ci	if (!ranges[0][0]) {
52762306a36Sopenharmony_ci		phase_0_found = true;
52862306a36Sopenharmony_ci		phase_0_raw_index = 0;
52962306a36Sopenharmony_ci		/* Check if cycle exist between 2 valid windows */
53062306a36Sopenharmony_ci		for (cnt = 1; cnt <= row_index; cnt++) {
53162306a36Sopenharmony_ci			if (phases_per_row[cnt]) {
53262306a36Sopenharmony_ci				for (i = 0; i < phases_per_row[cnt]; i++) {
53362306a36Sopenharmony_ci					if (ranges[cnt][i] == 15) {
53462306a36Sopenharmony_ci						phase_15_found = true;
53562306a36Sopenharmony_ci						phase_15_raw_index = cnt;
53662306a36Sopenharmony_ci						break;
53762306a36Sopenharmony_ci					}
53862306a36Sopenharmony_ci				}
53962306a36Sopenharmony_ci			}
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* If 2 valid windows form cycle then merge them as single window */
54462306a36Sopenharmony_ci	if (phase_0_found && phase_15_found) {
54562306a36Sopenharmony_ci		/* number of phases in raw where phase 0 is present */
54662306a36Sopenharmony_ci		u8 phases_0 = phases_per_row[phase_0_raw_index];
54762306a36Sopenharmony_ci		/* number of phases in raw where phase 15 is present */
54862306a36Sopenharmony_ci		u8 phases_15 = phases_per_row[phase_15_raw_index];
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		if (phases_0 + phases_15 >= MAX_PHASES)
55162306a36Sopenharmony_ci			/*
55262306a36Sopenharmony_ci			 * If there are more than 1 phase windows then total
55362306a36Sopenharmony_ci			 * number of phases in both the windows should not be
55462306a36Sopenharmony_ci			 * more than or equal to MAX_PHASES.
55562306a36Sopenharmony_ci			 */
55662306a36Sopenharmony_ci			return -EINVAL;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci		/* Merge 2 cyclic windows */
55962306a36Sopenharmony_ci		i = phases_15;
56062306a36Sopenharmony_ci		for (cnt = 0; cnt < phases_0; cnt++) {
56162306a36Sopenharmony_ci			ranges[phase_15_raw_index][i] =
56262306a36Sopenharmony_ci			    ranges[phase_0_raw_index][cnt];
56362306a36Sopenharmony_ci			if (++i >= MAX_PHASES)
56462306a36Sopenharmony_ci				break;
56562306a36Sopenharmony_ci		}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		phases_per_row[phase_0_raw_index] = 0;
56862306a36Sopenharmony_ci		phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	for (cnt = 0; cnt <= row_index; cnt++) {
57262306a36Sopenharmony_ci		if (phases_per_row[cnt] > curr_max) {
57362306a36Sopenharmony_ci			curr_max = phases_per_row[cnt];
57462306a36Sopenharmony_ci			selected_row_index = cnt;
57562306a36Sopenharmony_ci		}
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	i = (curr_max * 3) / 4;
57962306a36Sopenharmony_ci	if (i)
58062306a36Sopenharmony_ci		i--;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	ret = ranges[selected_row_index][i];
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (ret >= MAX_PHASES) {
58562306a36Sopenharmony_ci		ret = -EINVAL;
58662306a36Sopenharmony_ci		dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
58762306a36Sopenharmony_ci		       mmc_hostname(mmc), ret);
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return ret;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic inline void msm_cm_dll_set_freq(struct sdhci_host *host)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	u32 mclk_freq = 0, config;
59662306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
59762306a36Sopenharmony_ci					sdhci_priv_msm_offset(host);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* Program the MCLK value to MCLK_FREQ bit field */
60062306a36Sopenharmony_ci	if (host->clock <= 112000000)
60162306a36Sopenharmony_ci		mclk_freq = 0;
60262306a36Sopenharmony_ci	else if (host->clock <= 125000000)
60362306a36Sopenharmony_ci		mclk_freq = 1;
60462306a36Sopenharmony_ci	else if (host->clock <= 137000000)
60562306a36Sopenharmony_ci		mclk_freq = 2;
60662306a36Sopenharmony_ci	else if (host->clock <= 150000000)
60762306a36Sopenharmony_ci		mclk_freq = 3;
60862306a36Sopenharmony_ci	else if (host->clock <= 162000000)
60962306a36Sopenharmony_ci		mclk_freq = 4;
61062306a36Sopenharmony_ci	else if (host->clock <= 175000000)
61162306a36Sopenharmony_ci		mclk_freq = 5;
61262306a36Sopenharmony_ci	else if (host->clock <= 187000000)
61362306a36Sopenharmony_ci		mclk_freq = 6;
61462306a36Sopenharmony_ci	else if (host->clock <= 200000000)
61562306a36Sopenharmony_ci		mclk_freq = 7;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
61862306a36Sopenharmony_ci	config &= ~CMUX_SHIFT_PHASE_MASK;
61962306a36Sopenharmony_ci	config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
62062306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/* Initialize the DLL (Programmable Delay Line) */
62462306a36Sopenharmony_cistatic int msm_init_cm_dll(struct sdhci_host *host)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
62762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
62862306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
62962306a36Sopenharmony_ci	int wait_cnt = 50;
63062306a36Sopenharmony_ci	unsigned long flags, xo_clk = 0;
63162306a36Sopenharmony_ci	u32 config;
63262306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
63362306a36Sopenharmony_ci					msm_host->offset;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
63662306a36Sopenharmony_ci		xo_clk = clk_get_rate(msm_host->xo_clk);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	spin_lock_irqsave(&host->lock, flags);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/*
64162306a36Sopenharmony_ci	 * Make sure that clock is always enabled when DLL
64262306a36Sopenharmony_ci	 * tuning is in progress. Keeping PWRSAVE ON may
64362306a36Sopenharmony_ci	 * turn off the clock.
64462306a36Sopenharmony_ci	 */
64562306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
64662306a36Sopenharmony_ci	config &= ~CORE_CLK_PWRSAVE;
64762306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (msm_host->dll_config)
65062306a36Sopenharmony_ci		writel_relaxed(msm_host->dll_config,
65162306a36Sopenharmony_ci				host->ioaddr + msm_offset->core_dll_config);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (msm_host->use_14lpp_dll_reset) {
65462306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
65562306a36Sopenharmony_ci				msm_offset->core_dll_config);
65662306a36Sopenharmony_ci		config &= ~CORE_CK_OUT_EN;
65762306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
65862306a36Sopenharmony_ci				msm_offset->core_dll_config);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
66162306a36Sopenharmony_ci				msm_offset->core_dll_config_2);
66262306a36Sopenharmony_ci		config |= CORE_DLL_CLOCK_DISABLE;
66362306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
66462306a36Sopenharmony_ci				msm_offset->core_dll_config_2);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr +
66862306a36Sopenharmony_ci			msm_offset->core_dll_config);
66962306a36Sopenharmony_ci	config |= CORE_DLL_RST;
67062306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr +
67162306a36Sopenharmony_ci			msm_offset->core_dll_config);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr +
67462306a36Sopenharmony_ci			msm_offset->core_dll_config);
67562306a36Sopenharmony_ci	config |= CORE_DLL_PDN;
67662306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr +
67762306a36Sopenharmony_ci			msm_offset->core_dll_config);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (!msm_host->dll_config)
68062306a36Sopenharmony_ci		msm_cm_dll_set_freq(host);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (msm_host->use_14lpp_dll_reset &&
68362306a36Sopenharmony_ci	    !IS_ERR_OR_NULL(msm_host->xo_clk)) {
68462306a36Sopenharmony_ci		u32 mclk_freq = 0;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
68762306a36Sopenharmony_ci				msm_offset->core_dll_config_2);
68862306a36Sopenharmony_ci		config &= CORE_FLL_CYCLE_CNT;
68962306a36Sopenharmony_ci		if (config)
69062306a36Sopenharmony_ci			mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
69162306a36Sopenharmony_ci					xo_clk);
69262306a36Sopenharmony_ci		else
69362306a36Sopenharmony_ci			mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
69462306a36Sopenharmony_ci					xo_clk);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
69762306a36Sopenharmony_ci				msm_offset->core_dll_config_2);
69862306a36Sopenharmony_ci		config &= ~(0xFF << 10);
69962306a36Sopenharmony_ci		config |= mclk_freq << 10;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
70262306a36Sopenharmony_ci				msm_offset->core_dll_config_2);
70362306a36Sopenharmony_ci		/* wait for 5us before enabling DLL clock */
70462306a36Sopenharmony_ci		udelay(5);
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr +
70862306a36Sopenharmony_ci			msm_offset->core_dll_config);
70962306a36Sopenharmony_ci	config &= ~CORE_DLL_RST;
71062306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr +
71162306a36Sopenharmony_ci			msm_offset->core_dll_config);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr +
71462306a36Sopenharmony_ci			msm_offset->core_dll_config);
71562306a36Sopenharmony_ci	config &= ~CORE_DLL_PDN;
71662306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr +
71762306a36Sopenharmony_ci			msm_offset->core_dll_config);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (msm_host->use_14lpp_dll_reset) {
72062306a36Sopenharmony_ci		if (!msm_host->dll_config)
72162306a36Sopenharmony_ci			msm_cm_dll_set_freq(host);
72262306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
72362306a36Sopenharmony_ci				msm_offset->core_dll_config_2);
72462306a36Sopenharmony_ci		config &= ~CORE_DLL_CLOCK_DISABLE;
72562306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
72662306a36Sopenharmony_ci				msm_offset->core_dll_config_2);
72762306a36Sopenharmony_ci	}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/*
73062306a36Sopenharmony_ci	 * Configure DLL user control register to enable DLL status.
73162306a36Sopenharmony_ci	 * This setting is applicable to SDCC v5.1 onwards only.
73262306a36Sopenharmony_ci	 */
73362306a36Sopenharmony_ci	if (msm_host->uses_tassadar_dll) {
73462306a36Sopenharmony_ci		config = DLL_USR_CTL_POR_VAL | FINE_TUNE_MODE_EN |
73562306a36Sopenharmony_ci			ENABLE_DLL_LOCK_STATUS | BIAS_OK_SIGNAL;
73662306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
73762306a36Sopenharmony_ci				msm_offset->core_dll_usr_ctl);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
74062306a36Sopenharmony_ci				msm_offset->core_dll_config_3);
74162306a36Sopenharmony_ci		config &= ~0xFF;
74262306a36Sopenharmony_ci		if (msm_host->clk_rate < 150000000)
74362306a36Sopenharmony_ci			config |= DLL_CONFIG_3_LOW_FREQ_VAL;
74462306a36Sopenharmony_ci		else
74562306a36Sopenharmony_ci			config |= DLL_CONFIG_3_HIGH_FREQ_VAL;
74662306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
74762306a36Sopenharmony_ci			msm_offset->core_dll_config_3);
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr +
75162306a36Sopenharmony_ci			msm_offset->core_dll_config);
75262306a36Sopenharmony_ci	config |= CORE_DLL_EN;
75362306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr +
75462306a36Sopenharmony_ci			msm_offset->core_dll_config);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr +
75762306a36Sopenharmony_ci			msm_offset->core_dll_config);
75862306a36Sopenharmony_ci	config |= CORE_CK_OUT_EN;
75962306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr +
76062306a36Sopenharmony_ci			msm_offset->core_dll_config);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
76362306a36Sopenharmony_ci	while (!(readl_relaxed(host->ioaddr + msm_offset->core_dll_status) &
76462306a36Sopenharmony_ci		 CORE_DLL_LOCK)) {
76562306a36Sopenharmony_ci		/* max. wait for 50us sec for LOCK bit to be set */
76662306a36Sopenharmony_ci		if (--wait_cnt == 0) {
76762306a36Sopenharmony_ci			dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
76862306a36Sopenharmony_ci			       mmc_hostname(mmc));
76962306a36Sopenharmony_ci			spin_unlock_irqrestore(&host->lock, flags);
77062306a36Sopenharmony_ci			return -ETIMEDOUT;
77162306a36Sopenharmony_ci		}
77262306a36Sopenharmony_ci		udelay(1);
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	spin_unlock_irqrestore(&host->lock, flags);
77662306a36Sopenharmony_ci	return 0;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic void msm_hc_select_default(struct sdhci_host *host)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
78262306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
78362306a36Sopenharmony_ci	u32 config;
78462306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
78562306a36Sopenharmony_ci					msm_host->offset;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (!msm_host->use_cdclp533) {
78862306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
78962306a36Sopenharmony_ci				msm_offset->core_vendor_spec3);
79062306a36Sopenharmony_ci		config &= ~CORE_PWRSAVE_DLL;
79162306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
79262306a36Sopenharmony_ci				msm_offset->core_vendor_spec3);
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
79662306a36Sopenharmony_ci	config &= ~CORE_HC_MCLK_SEL_MASK;
79762306a36Sopenharmony_ci	config |= CORE_HC_MCLK_SEL_DFLT;
79862306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/*
80162306a36Sopenharmony_ci	 * Disable HC_SELECT_IN to be able to use the UHS mode select
80262306a36Sopenharmony_ci	 * configuration from Host Control2 register for all other
80362306a36Sopenharmony_ci	 * modes.
80462306a36Sopenharmony_ci	 * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
80562306a36Sopenharmony_ci	 * in VENDOR_SPEC_FUNC
80662306a36Sopenharmony_ci	 */
80762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
80862306a36Sopenharmony_ci	config &= ~CORE_HC_SELECT_IN_EN;
80962306a36Sopenharmony_ci	config &= ~CORE_HC_SELECT_IN_MASK;
81062306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/*
81362306a36Sopenharmony_ci	 * Make sure above writes impacting free running MCLK are completed
81462306a36Sopenharmony_ci	 * before changing the clk_rate at GCC.
81562306a36Sopenharmony_ci	 */
81662306a36Sopenharmony_ci	wmb();
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic void msm_hc_select_hs400(struct sdhci_host *host)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
82262306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
82362306a36Sopenharmony_ci	struct mmc_ios ios = host->mmc->ios;
82462306a36Sopenharmony_ci	u32 config, dll_lock;
82562306a36Sopenharmony_ci	int rc;
82662306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
82762306a36Sopenharmony_ci					msm_host->offset;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/* Select the divided clock (free running MCLK/2) */
83062306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
83162306a36Sopenharmony_ci	config &= ~CORE_HC_MCLK_SEL_MASK;
83262306a36Sopenharmony_ci	config |= CORE_HC_MCLK_SEL_HS400;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
83562306a36Sopenharmony_ci	/*
83662306a36Sopenharmony_ci	 * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
83762306a36Sopenharmony_ci	 * register
83862306a36Sopenharmony_ci	 */
83962306a36Sopenharmony_ci	if ((msm_host->tuning_done || ios.enhanced_strobe) &&
84062306a36Sopenharmony_ci	    !msm_host->calibration_done) {
84162306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
84262306a36Sopenharmony_ci				msm_offset->core_vendor_spec);
84362306a36Sopenharmony_ci		config |= CORE_HC_SELECT_IN_HS400;
84462306a36Sopenharmony_ci		config |= CORE_HC_SELECT_IN_EN;
84562306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
84662306a36Sopenharmony_ci				msm_offset->core_vendor_spec);
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci	if (!msm_host->clk_rate && !msm_host->use_cdclp533) {
84962306a36Sopenharmony_ci		/*
85062306a36Sopenharmony_ci		 * Poll on DLL_LOCK or DDR_DLL_LOCK bits in
85162306a36Sopenharmony_ci		 * core_dll_status to be set. This should get set
85262306a36Sopenharmony_ci		 * within 15 us at 200 MHz.
85362306a36Sopenharmony_ci		 */
85462306a36Sopenharmony_ci		rc = readl_relaxed_poll_timeout(host->ioaddr +
85562306a36Sopenharmony_ci						msm_offset->core_dll_status,
85662306a36Sopenharmony_ci						dll_lock,
85762306a36Sopenharmony_ci						(dll_lock &
85862306a36Sopenharmony_ci						(CORE_DLL_LOCK |
85962306a36Sopenharmony_ci						CORE_DDR_DLL_LOCK)), 10,
86062306a36Sopenharmony_ci						1000);
86162306a36Sopenharmony_ci		if (rc == -ETIMEDOUT)
86262306a36Sopenharmony_ci			pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n",
86362306a36Sopenharmony_ci			       mmc_hostname(host->mmc), dll_lock);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci	/*
86662306a36Sopenharmony_ci	 * Make sure above writes impacting free running MCLK are completed
86762306a36Sopenharmony_ci	 * before changing the clk_rate at GCC.
86862306a36Sopenharmony_ci	 */
86962306a36Sopenharmony_ci	wmb();
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci/*
87362306a36Sopenharmony_ci * sdhci_msm_hc_select_mode :- In general all timing modes are
87462306a36Sopenharmony_ci * controlled via UHS mode select in Host Control2 register.
87562306a36Sopenharmony_ci * eMMC specific HS200/HS400 doesn't have their respective modes
87662306a36Sopenharmony_ci * defined here, hence we use these values.
87762306a36Sopenharmony_ci *
87862306a36Sopenharmony_ci * HS200 - SDR104 (Since they both are equivalent in functionality)
87962306a36Sopenharmony_ci * HS400 - This involves multiple configurations
88062306a36Sopenharmony_ci *		Initially SDR104 - when tuning is required as HS200
88162306a36Sopenharmony_ci *		Then when switching to DDR @ 400MHz (HS400) we use
88262306a36Sopenharmony_ci *		the vendor specific HC_SELECT_IN to control the mode.
88362306a36Sopenharmony_ci *
88462306a36Sopenharmony_ci * In addition to controlling the modes we also need to select the
88562306a36Sopenharmony_ci * correct input clock for DLL depending on the mode.
88662306a36Sopenharmony_ci *
88762306a36Sopenharmony_ci * HS400 - divided clock (free running MCLK/2)
88862306a36Sopenharmony_ci * All other modes - default (free running MCLK)
88962306a36Sopenharmony_ci */
89062306a36Sopenharmony_cistatic void sdhci_msm_hc_select_mode(struct sdhci_host *host)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	struct mmc_ios ios = host->mmc->ios;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (ios.timing == MMC_TIMING_MMC_HS400 ||
89562306a36Sopenharmony_ci	    host->flags & SDHCI_HS400_TUNING)
89662306a36Sopenharmony_ci		msm_hc_select_hs400(host);
89762306a36Sopenharmony_ci	else
89862306a36Sopenharmony_ci		msm_hc_select_default(host);
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistatic int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
90462306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
90562306a36Sopenharmony_ci	u32 config, calib_done;
90662306a36Sopenharmony_ci	int ret;
90762306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
90862306a36Sopenharmony_ci					msm_host->offset;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	/*
91362306a36Sopenharmony_ci	 * Retuning in HS400 (DDR mode) will fail, just reset the
91462306a36Sopenharmony_ci	 * tuning block and restore the saved tuning phase.
91562306a36Sopenharmony_ci	 */
91662306a36Sopenharmony_ci	ret = msm_init_cm_dll(host);
91762306a36Sopenharmony_ci	if (ret)
91862306a36Sopenharmony_ci		goto out;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* Set the selected phase in delay line hw block */
92162306a36Sopenharmony_ci	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
92262306a36Sopenharmony_ci	if (ret)
92362306a36Sopenharmony_ci		goto out;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config);
92662306a36Sopenharmony_ci	config |= CORE_CMD_DAT_TRACK_SEL;
92762306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
93062306a36Sopenharmony_ci	config &= ~CORE_CDC_T4_DLY_SEL;
93162306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
93462306a36Sopenharmony_ci	config &= ~CORE_CDC_SWITCH_BYPASS_OFF;
93562306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
93862306a36Sopenharmony_ci	config |= CORE_CDC_SWITCH_RC_EN;
93962306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
94262306a36Sopenharmony_ci	config &= ~CORE_START_CDC_TRAFFIC;
94362306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	/* Perform CDC Register Initialization Sequence */
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
94862306a36Sopenharmony_ci	writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
94962306a36Sopenharmony_ci	writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
95062306a36Sopenharmony_ci	writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
95162306a36Sopenharmony_ci	writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
95262306a36Sopenharmony_ci	writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
95362306a36Sopenharmony_ci	writel_relaxed(0x4E2, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
95462306a36Sopenharmony_ci	writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
95562306a36Sopenharmony_ci	writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	/* CDC HW Calibration */
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
96062306a36Sopenharmony_ci	config |= CORE_SW_TRIG_FULL_CALIB;
96162306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
96462306a36Sopenharmony_ci	config &= ~CORE_SW_TRIG_FULL_CALIB;
96562306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
96862306a36Sopenharmony_ci	config |= CORE_HW_AUTOCAL_ENA;
96962306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
97262306a36Sopenharmony_ci	config |= CORE_TIMER_ENA;
97362306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0,
97662306a36Sopenharmony_ci					 calib_done,
97762306a36Sopenharmony_ci					 (calib_done & CORE_CALIBRATION_DONE),
97862306a36Sopenharmony_ci					 1, 50);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (ret == -ETIMEDOUT) {
98162306a36Sopenharmony_ci		pr_err("%s: %s: CDC calibration was not completed\n",
98262306a36Sopenharmony_ci		       mmc_hostname(host->mmc), __func__);
98362306a36Sopenharmony_ci		goto out;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	ret = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
98762306a36Sopenharmony_ci			& CORE_CDC_ERROR_CODE_MASK;
98862306a36Sopenharmony_ci	if (ret) {
98962306a36Sopenharmony_ci		pr_err("%s: %s: CDC error code %d\n",
99062306a36Sopenharmony_ci		       mmc_hostname(host->mmc), __func__, ret);
99162306a36Sopenharmony_ci		ret = -EINVAL;
99262306a36Sopenharmony_ci		goto out;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg);
99662306a36Sopenharmony_ci	config |= CORE_START_CDC_TRAFFIC;
99762306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg);
99862306a36Sopenharmony_ciout:
99962306a36Sopenharmony_ci	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
100062306a36Sopenharmony_ci		 __func__, ret);
100162306a36Sopenharmony_ci	return ret;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
100762306a36Sopenharmony_ci	u32 dll_status, config, ddr_cfg_offset;
100862306a36Sopenharmony_ci	int ret;
100962306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
101062306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
101162306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
101262306a36Sopenharmony_ci					sdhci_priv_msm_offset(host);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	/*
101762306a36Sopenharmony_ci	 * Currently the core_ddr_config register defaults to desired
101862306a36Sopenharmony_ci	 * configuration on reset. Currently reprogramming the power on
101962306a36Sopenharmony_ci	 * reset (POR) value in case it might have been modified by
102062306a36Sopenharmony_ci	 * bootloaders. In the future, if this changes, then the desired
102162306a36Sopenharmony_ci	 * values will need to be programmed appropriately.
102262306a36Sopenharmony_ci	 */
102362306a36Sopenharmony_ci	if (msm_host->updated_ddr_cfg)
102462306a36Sopenharmony_ci		ddr_cfg_offset = msm_offset->core_ddr_config;
102562306a36Sopenharmony_ci	else
102662306a36Sopenharmony_ci		ddr_cfg_offset = msm_offset->core_ddr_config_old;
102762306a36Sopenharmony_ci	writel_relaxed(msm_host->ddr_config, host->ioaddr + ddr_cfg_offset);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (mmc->ios.enhanced_strobe) {
103062306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
103162306a36Sopenharmony_ci				msm_offset->core_ddr_200_cfg);
103262306a36Sopenharmony_ci		config |= CORE_CMDIN_RCLK_EN;
103362306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
103462306a36Sopenharmony_ci				msm_offset->core_ddr_200_cfg);
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2);
103862306a36Sopenharmony_ci	config |= CORE_DDR_CAL_EN;
103962306a36Sopenharmony_ci	writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config_2);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(host->ioaddr +
104262306a36Sopenharmony_ci					msm_offset->core_dll_status,
104362306a36Sopenharmony_ci					dll_status,
104462306a36Sopenharmony_ci					(dll_status & CORE_DDR_DLL_LOCK),
104562306a36Sopenharmony_ci					10, 1000);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	if (ret == -ETIMEDOUT) {
104862306a36Sopenharmony_ci		pr_err("%s: %s: CM_DLL_SDC4 calibration was not completed\n",
104962306a36Sopenharmony_ci		       mmc_hostname(host->mmc), __func__);
105062306a36Sopenharmony_ci		goto out;
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/*
105462306a36Sopenharmony_ci	 * Set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3.
105562306a36Sopenharmony_ci	 * When MCLK is gated OFF, it is not gated for less than 0.5us
105662306a36Sopenharmony_ci	 * and MCLK must be switched on for at-least 1us before DATA
105762306a36Sopenharmony_ci	 * starts coming. Controllers with 14lpp and later tech DLL cannot
105862306a36Sopenharmony_ci	 * guarantee above requirement. So PWRSAVE_DLL should not be
105962306a36Sopenharmony_ci	 * turned on for host controllers using this DLL.
106062306a36Sopenharmony_ci	 */
106162306a36Sopenharmony_ci	if (!msm_host->use_14lpp_dll_reset) {
106262306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
106362306a36Sopenharmony_ci				msm_offset->core_vendor_spec3);
106462306a36Sopenharmony_ci		config |= CORE_PWRSAVE_DLL;
106562306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
106662306a36Sopenharmony_ci				msm_offset->core_vendor_spec3);
106762306a36Sopenharmony_ci	}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	/*
107062306a36Sopenharmony_ci	 * Drain writebuffer to ensure above DLL calibration
107162306a36Sopenharmony_ci	 * and PWRSAVE DLL is enabled.
107262306a36Sopenharmony_ci	 */
107362306a36Sopenharmony_ci	wmb();
107462306a36Sopenharmony_ciout:
107562306a36Sopenharmony_ci	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
107662306a36Sopenharmony_ci		 __func__, ret);
107762306a36Sopenharmony_ci	return ret;
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
108362306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
108462306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
108562306a36Sopenharmony_ci	int ret;
108662306a36Sopenharmony_ci	u32 config;
108762306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
108862306a36Sopenharmony_ci					msm_host->offset;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	/*
109362306a36Sopenharmony_ci	 * Retuning in HS400 (DDR mode) will fail, just reset the
109462306a36Sopenharmony_ci	 * tuning block and restore the saved tuning phase.
109562306a36Sopenharmony_ci	 */
109662306a36Sopenharmony_ci	ret = msm_init_cm_dll(host);
109762306a36Sopenharmony_ci	if (ret)
109862306a36Sopenharmony_ci		goto out;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (!mmc->ios.enhanced_strobe) {
110162306a36Sopenharmony_ci		/* Set the selected phase in delay line hw block */
110262306a36Sopenharmony_ci		ret = msm_config_cm_dll_phase(host,
110362306a36Sopenharmony_ci					      msm_host->saved_tuning_phase);
110462306a36Sopenharmony_ci		if (ret)
110562306a36Sopenharmony_ci			goto out;
110662306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
110762306a36Sopenharmony_ci				msm_offset->core_dll_config);
110862306a36Sopenharmony_ci		config |= CORE_CMD_DAT_TRACK_SEL;
110962306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
111062306a36Sopenharmony_ci				msm_offset->core_dll_config);
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (msm_host->use_cdclp533)
111462306a36Sopenharmony_ci		ret = sdhci_msm_cdclp533_calibration(host);
111562306a36Sopenharmony_ci	else
111662306a36Sopenharmony_ci		ret = sdhci_msm_cm_dll_sdc4_calibration(host);
111762306a36Sopenharmony_ciout:
111862306a36Sopenharmony_ci	pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
111962306a36Sopenharmony_ci		 __func__, ret);
112062306a36Sopenharmony_ci	return ret;
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic bool sdhci_msm_is_tuning_needed(struct sdhci_host *host)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	struct mmc_ios *ios = &host->mmc->ios;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	/*
112862306a36Sopenharmony_ci	 * Tuning is required for SDR104, HS200 and HS400 cards and
112962306a36Sopenharmony_ci	 * if clock frequency is greater than 100MHz in these modes.
113062306a36Sopenharmony_ci	 */
113162306a36Sopenharmony_ci	if (host->clock <= CORE_FREQ_100MHZ ||
113262306a36Sopenharmony_ci	    !(ios->timing == MMC_TIMING_MMC_HS400 ||
113362306a36Sopenharmony_ci	    ios->timing == MMC_TIMING_MMC_HS200 ||
113462306a36Sopenharmony_ci	    ios->timing == MMC_TIMING_UHS_SDR104) ||
113562306a36Sopenharmony_ci	    ios->enhanced_strobe)
113662306a36Sopenharmony_ci		return false;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return true;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic int sdhci_msm_restore_sdr_dll_config(struct sdhci_host *host)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
114462306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
114562306a36Sopenharmony_ci	int ret;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/*
114862306a36Sopenharmony_ci	 * SDR DLL comes into picture only for timing modes which needs
114962306a36Sopenharmony_ci	 * tuning.
115062306a36Sopenharmony_ci	 */
115162306a36Sopenharmony_ci	if (!sdhci_msm_is_tuning_needed(host))
115262306a36Sopenharmony_ci		return 0;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	/* Reset the tuning block */
115562306a36Sopenharmony_ci	ret = msm_init_cm_dll(host);
115662306a36Sopenharmony_ci	if (ret)
115762306a36Sopenharmony_ci		return ret;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	/* Restore the tuning block */
116062306a36Sopenharmony_ci	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	return ret;
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable)
116662306a36Sopenharmony_ci{
116762306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset = sdhci_priv_msm_offset(host);
116862306a36Sopenharmony_ci	u32 config, oldconfig = readl_relaxed(host->ioaddr +
116962306a36Sopenharmony_ci					      msm_offset->core_dll_config);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	config = oldconfig;
117262306a36Sopenharmony_ci	if (enable) {
117362306a36Sopenharmony_ci		config |= CORE_CDR_EN;
117462306a36Sopenharmony_ci		config &= ~CORE_CDR_EXT_EN;
117562306a36Sopenharmony_ci	} else {
117662306a36Sopenharmony_ci		config &= ~CORE_CDR_EN;
117762306a36Sopenharmony_ci		config |= CORE_CDR_EXT_EN;
117862306a36Sopenharmony_ci	}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	if (config != oldconfig) {
118162306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
118262306a36Sopenharmony_ci			       msm_offset->core_dll_config);
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
118962306a36Sopenharmony_ci	int tuning_seq_cnt = 10;
119062306a36Sopenharmony_ci	u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
119162306a36Sopenharmony_ci	int rc;
119262306a36Sopenharmony_ci	struct mmc_ios ios = host->mmc->ios;
119362306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
119462306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	if (!sdhci_msm_is_tuning_needed(host)) {
119762306a36Sopenharmony_ci		msm_host->use_cdr = false;
119862306a36Sopenharmony_ci		sdhci_msm_set_cdr(host, false);
119962306a36Sopenharmony_ci		return 0;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* Clock-Data-Recovery used to dynamically adjust RX sampling point */
120362306a36Sopenharmony_ci	msm_host->use_cdr = true;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/*
120662306a36Sopenharmony_ci	 * Clear tuning_done flag before tuning to ensure proper
120762306a36Sopenharmony_ci	 * HS400 settings.
120862306a36Sopenharmony_ci	 */
120962306a36Sopenharmony_ci	msm_host->tuning_done = 0;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	/*
121262306a36Sopenharmony_ci	 * For HS400 tuning in HS200 timing requires:
121362306a36Sopenharmony_ci	 * - select MCLK/2 in VENDOR_SPEC
121462306a36Sopenharmony_ci	 * - program MCLK to 400MHz (or nearest supported) in GCC
121562306a36Sopenharmony_ci	 */
121662306a36Sopenharmony_ci	if (host->flags & SDHCI_HS400_TUNING) {
121762306a36Sopenharmony_ci		sdhci_msm_hc_select_mode(host);
121862306a36Sopenharmony_ci		msm_set_clock_rate_for_bus_mode(host, ios.clock);
121962306a36Sopenharmony_ci		host->flags &= ~SDHCI_HS400_TUNING;
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ciretry:
122362306a36Sopenharmony_ci	/* First of all reset the tuning block */
122462306a36Sopenharmony_ci	rc = msm_init_cm_dll(host);
122562306a36Sopenharmony_ci	if (rc)
122662306a36Sopenharmony_ci		return rc;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	phase = 0;
122962306a36Sopenharmony_ci	do {
123062306a36Sopenharmony_ci		/* Set the phase in delay line hw block */
123162306a36Sopenharmony_ci		rc = msm_config_cm_dll_phase(host, phase);
123262306a36Sopenharmony_ci		if (rc)
123362306a36Sopenharmony_ci			return rc;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		rc = mmc_send_tuning(mmc, opcode, NULL);
123662306a36Sopenharmony_ci		if (!rc) {
123762306a36Sopenharmony_ci			/* Tuning is successful at this tuning point */
123862306a36Sopenharmony_ci			tuned_phases[tuned_phase_cnt++] = phase;
123962306a36Sopenharmony_ci			dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
124062306a36Sopenharmony_ci				 mmc_hostname(mmc), phase);
124162306a36Sopenharmony_ci		}
124262306a36Sopenharmony_ci	} while (++phase < ARRAY_SIZE(tuned_phases));
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (tuned_phase_cnt) {
124562306a36Sopenharmony_ci		if (tuned_phase_cnt == ARRAY_SIZE(tuned_phases)) {
124662306a36Sopenharmony_ci			/*
124762306a36Sopenharmony_ci			 * All phases valid is _almost_ as bad as no phases
124862306a36Sopenharmony_ci			 * valid.  Probably all phases are not really reliable
124962306a36Sopenharmony_ci			 * but we didn't detect where the unreliable place is.
125062306a36Sopenharmony_ci			 * That means we'll essentially be guessing and hoping
125162306a36Sopenharmony_ci			 * we get a good phase.  Better to try a few times.
125262306a36Sopenharmony_ci			 */
125362306a36Sopenharmony_ci			dev_dbg(mmc_dev(mmc), "%s: All phases valid; try again\n",
125462306a36Sopenharmony_ci				mmc_hostname(mmc));
125562306a36Sopenharmony_ci			if (--tuning_seq_cnt) {
125662306a36Sopenharmony_ci				tuned_phase_cnt = 0;
125762306a36Sopenharmony_ci				goto retry;
125862306a36Sopenharmony_ci			}
125962306a36Sopenharmony_ci		}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci		rc = msm_find_most_appropriate_phase(host, tuned_phases,
126262306a36Sopenharmony_ci						     tuned_phase_cnt);
126362306a36Sopenharmony_ci		if (rc < 0)
126462306a36Sopenharmony_ci			return rc;
126562306a36Sopenharmony_ci		else
126662306a36Sopenharmony_ci			phase = rc;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		/*
126962306a36Sopenharmony_ci		 * Finally set the selected phase in delay
127062306a36Sopenharmony_ci		 * line hw block.
127162306a36Sopenharmony_ci		 */
127262306a36Sopenharmony_ci		rc = msm_config_cm_dll_phase(host, phase);
127362306a36Sopenharmony_ci		if (rc)
127462306a36Sopenharmony_ci			return rc;
127562306a36Sopenharmony_ci		msm_host->saved_tuning_phase = phase;
127662306a36Sopenharmony_ci		dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
127762306a36Sopenharmony_ci			 mmc_hostname(mmc), phase);
127862306a36Sopenharmony_ci	} else {
127962306a36Sopenharmony_ci		if (--tuning_seq_cnt)
128062306a36Sopenharmony_ci			goto retry;
128162306a36Sopenharmony_ci		/* Tuning failed */
128262306a36Sopenharmony_ci		dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
128362306a36Sopenharmony_ci		       mmc_hostname(mmc));
128462306a36Sopenharmony_ci		rc = -EIO;
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	if (!rc)
128862306a36Sopenharmony_ci		msm_host->tuning_done = true;
128962306a36Sopenharmony_ci	return rc;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci/*
129362306a36Sopenharmony_ci * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation.
129462306a36Sopenharmony_ci * This needs to be done for both tuning and enhanced_strobe mode.
129562306a36Sopenharmony_ci * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz
129662306a36Sopenharmony_ci * fixed feedback clock is used.
129762306a36Sopenharmony_ci */
129862306a36Sopenharmony_cistatic void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
130162306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
130262306a36Sopenharmony_ci	int ret;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	if (host->clock > CORE_FREQ_100MHZ &&
130562306a36Sopenharmony_ci	    (msm_host->tuning_done || ios->enhanced_strobe) &&
130662306a36Sopenharmony_ci	    !msm_host->calibration_done) {
130762306a36Sopenharmony_ci		ret = sdhci_msm_hs400_dll_calibration(host);
130862306a36Sopenharmony_ci		if (!ret)
130962306a36Sopenharmony_ci			msm_host->calibration_done = true;
131062306a36Sopenharmony_ci		else
131162306a36Sopenharmony_ci			pr_err("%s: Failed to calibrate DLL for hs400 mode (%d)\n",
131262306a36Sopenharmony_ci			       mmc_hostname(host->mmc), ret);
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
131762306a36Sopenharmony_ci					unsigned int uhs)
131862306a36Sopenharmony_ci{
131962306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
132062306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
132162306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
132262306a36Sopenharmony_ci	u16 ctrl_2;
132362306a36Sopenharmony_ci	u32 config;
132462306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
132562306a36Sopenharmony_ci					msm_host->offset;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
132862306a36Sopenharmony_ci	/* Select Bus Speed Mode for host */
132962306a36Sopenharmony_ci	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
133062306a36Sopenharmony_ci	switch (uhs) {
133162306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR12:
133262306a36Sopenharmony_ci		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
133362306a36Sopenharmony_ci		break;
133462306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR25:
133562306a36Sopenharmony_ci		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
133662306a36Sopenharmony_ci		break;
133762306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR50:
133862306a36Sopenharmony_ci		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
133962306a36Sopenharmony_ci		break;
134062306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS400:
134162306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS200:
134262306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR104:
134362306a36Sopenharmony_ci		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
134462306a36Sopenharmony_ci		break;
134562306a36Sopenharmony_ci	case MMC_TIMING_UHS_DDR50:
134662306a36Sopenharmony_ci	case MMC_TIMING_MMC_DDR52:
134762306a36Sopenharmony_ci		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
134862306a36Sopenharmony_ci		break;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	/*
135262306a36Sopenharmony_ci	 * When clock frequency is less than 100MHz, the feedback clock must be
135362306a36Sopenharmony_ci	 * provided and DLL must not be used so that tuning can be skipped. To
135462306a36Sopenharmony_ci	 * provide feedback clock, the mode selection can be any value less
135562306a36Sopenharmony_ci	 * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
135662306a36Sopenharmony_ci	 */
135762306a36Sopenharmony_ci	if (host->clock <= CORE_FREQ_100MHZ) {
135862306a36Sopenharmony_ci		if (uhs == MMC_TIMING_MMC_HS400 ||
135962306a36Sopenharmony_ci		    uhs == MMC_TIMING_MMC_HS200 ||
136062306a36Sopenharmony_ci		    uhs == MMC_TIMING_UHS_SDR104)
136162306a36Sopenharmony_ci			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
136262306a36Sopenharmony_ci		/*
136362306a36Sopenharmony_ci		 * DLL is not required for clock <= 100MHz
136462306a36Sopenharmony_ci		 * Thus, make sure DLL it is disabled when not required
136562306a36Sopenharmony_ci		 */
136662306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
136762306a36Sopenharmony_ci				msm_offset->core_dll_config);
136862306a36Sopenharmony_ci		config |= CORE_DLL_RST;
136962306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
137062306a36Sopenharmony_ci				msm_offset->core_dll_config);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
137362306a36Sopenharmony_ci				msm_offset->core_dll_config);
137462306a36Sopenharmony_ci		config |= CORE_DLL_PDN;
137562306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
137662306a36Sopenharmony_ci				msm_offset->core_dll_config);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci		/*
137962306a36Sopenharmony_ci		 * The DLL needs to be restored and CDCLP533 recalibrated
138062306a36Sopenharmony_ci		 * when the clock frequency is set back to 400MHz.
138162306a36Sopenharmony_ci		 */
138262306a36Sopenharmony_ci		msm_host->calibration_done = false;
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
138662306a36Sopenharmony_ci		mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
138762306a36Sopenharmony_ci	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	if (mmc->ios.timing == MMC_TIMING_MMC_HS400)
139062306a36Sopenharmony_ci		sdhci_msm_hs400(host, &mmc->ios);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic int sdhci_msm_set_pincfg(struct sdhci_msm_host *msm_host, bool level)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct platform_device *pdev = msm_host->pdev;
139662306a36Sopenharmony_ci	int ret;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	if (level)
139962306a36Sopenharmony_ci		ret = pinctrl_pm_select_default_state(&pdev->dev);
140062306a36Sopenharmony_ci	else
140162306a36Sopenharmony_ci		ret = pinctrl_pm_select_sleep_state(&pdev->dev);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	return ret;
140462306a36Sopenharmony_ci}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_cistatic int sdhci_msm_set_vmmc(struct mmc_host *mmc)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	if (IS_ERR(mmc->supply.vmmc))
140962306a36Sopenharmony_ci		return 0;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	return mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, mmc->ios.vdd);
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_cistatic int msm_toggle_vqmmc(struct sdhci_msm_host *msm_host,
141562306a36Sopenharmony_ci			      struct mmc_host *mmc, bool level)
141662306a36Sopenharmony_ci{
141762306a36Sopenharmony_ci	int ret;
141862306a36Sopenharmony_ci	struct mmc_ios ios;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (msm_host->vqmmc_enabled == level)
142162306a36Sopenharmony_ci		return 0;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	if (level) {
142462306a36Sopenharmony_ci		/* Set the IO voltage regulator to default voltage level */
142562306a36Sopenharmony_ci		if (msm_host->caps_0 & CORE_3_0V_SUPPORT)
142662306a36Sopenharmony_ci			ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330;
142762306a36Sopenharmony_ci		else if (msm_host->caps_0 & CORE_1_8V_SUPPORT)
142862306a36Sopenharmony_ci			ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
143162306a36Sopenharmony_ci			ret = mmc_regulator_set_vqmmc(mmc, &ios);
143262306a36Sopenharmony_ci			if (ret < 0) {
143362306a36Sopenharmony_ci				dev_err(mmc_dev(mmc), "%s: vqmmc set volgate failed: %d\n",
143462306a36Sopenharmony_ci					mmc_hostname(mmc), ret);
143562306a36Sopenharmony_ci				goto out;
143662306a36Sopenharmony_ci			}
143762306a36Sopenharmony_ci		}
143862306a36Sopenharmony_ci		ret = regulator_enable(mmc->supply.vqmmc);
143962306a36Sopenharmony_ci	} else {
144062306a36Sopenharmony_ci		ret = regulator_disable(mmc->supply.vqmmc);
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	if (ret)
144462306a36Sopenharmony_ci		dev_err(mmc_dev(mmc), "%s: vqmm %sable failed: %d\n",
144562306a36Sopenharmony_ci			mmc_hostname(mmc), level ? "en":"dis", ret);
144662306a36Sopenharmony_ci	else
144762306a36Sopenharmony_ci		msm_host->vqmmc_enabled = level;
144862306a36Sopenharmony_ciout:
144962306a36Sopenharmony_ci	return ret;
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cistatic int msm_config_vqmmc_mode(struct sdhci_msm_host *msm_host,
145362306a36Sopenharmony_ci			      struct mmc_host *mmc, bool hpm)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	int load, ret;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	load = hpm ? MMC_VQMMC_MAX_LOAD_UA : 0;
145862306a36Sopenharmony_ci	ret = regulator_set_load(mmc->supply.vqmmc, load);
145962306a36Sopenharmony_ci	if (ret)
146062306a36Sopenharmony_ci		dev_err(mmc_dev(mmc), "%s: vqmmc set load failed: %d\n",
146162306a36Sopenharmony_ci			mmc_hostname(mmc), ret);
146262306a36Sopenharmony_ci	return ret;
146362306a36Sopenharmony_ci}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_cistatic int sdhci_msm_set_vqmmc(struct sdhci_msm_host *msm_host,
146662306a36Sopenharmony_ci			      struct mmc_host *mmc, bool level)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	int ret;
146962306a36Sopenharmony_ci	bool always_on;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	if (IS_ERR(mmc->supply.vqmmc) ||
147262306a36Sopenharmony_ci			(mmc->ios.power_mode == MMC_POWER_UNDEFINED))
147362306a36Sopenharmony_ci		return 0;
147462306a36Sopenharmony_ci	/*
147562306a36Sopenharmony_ci	 * For eMMC don't turn off Vqmmc, Instead just configure it in LPM
147662306a36Sopenharmony_ci	 * and HPM modes by setting the corresponding load.
147762306a36Sopenharmony_ci	 *
147862306a36Sopenharmony_ci	 * Till eMMC is initialized (i.e. always_on == 0), just turn on/off
147962306a36Sopenharmony_ci	 * Vqmmc. Vqmmc gets turned off only if init fails and mmc_power_off
148062306a36Sopenharmony_ci	 * gets invoked. Once eMMC is initialized (i.e. always_on == 1),
148162306a36Sopenharmony_ci	 * Vqmmc should remain ON, So just set the load instead of turning it
148262306a36Sopenharmony_ci	 * off/on.
148362306a36Sopenharmony_ci	 */
148462306a36Sopenharmony_ci	always_on = !mmc_card_is_removable(mmc) &&
148562306a36Sopenharmony_ci			mmc->card && mmc_card_mmc(mmc->card);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (always_on)
148862306a36Sopenharmony_ci		ret = msm_config_vqmmc_mode(msm_host, mmc, level);
148962306a36Sopenharmony_ci	else
149062306a36Sopenharmony_ci		ret = msm_toggle_vqmmc(msm_host, mmc, level);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	return ret;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	init_waitqueue_head(&msm_host->pwr_irq_wait);
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cistatic inline void sdhci_msm_complete_pwr_irq_wait(
150162306a36Sopenharmony_ci		struct sdhci_msm_host *msm_host)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	wake_up(&msm_host->pwr_irq_wait);
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci/*
150762306a36Sopenharmony_ci * sdhci_msm_check_power_status API should be called when registers writes
150862306a36Sopenharmony_ci * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
150962306a36Sopenharmony_ci * To what state the register writes will change the IO lines should be passed
151062306a36Sopenharmony_ci * as the argument req_type. This API will check whether the IO line's state
151162306a36Sopenharmony_ci * is already the expected state and will wait for power irq only if
151262306a36Sopenharmony_ci * power irq is expected to be triggered based on the current IO line state
151362306a36Sopenharmony_ci * and expected IO line state.
151462306a36Sopenharmony_ci */
151562306a36Sopenharmony_cistatic void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
151862306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
151962306a36Sopenharmony_ci	bool done = false;
152062306a36Sopenharmony_ci	u32 val = SWITCHABLE_SIGNALING_VOLTAGE;
152162306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
152262306a36Sopenharmony_ci					msm_host->offset;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
152562306a36Sopenharmony_ci			mmc_hostname(host->mmc), __func__, req_type,
152662306a36Sopenharmony_ci			msm_host->curr_pwr_state, msm_host->curr_io_level);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	/*
152962306a36Sopenharmony_ci	 * The power interrupt will not be generated for signal voltage
153062306a36Sopenharmony_ci	 * switches if SWITCHABLE_SIGNALING_VOLTAGE in MCI_GENERICS is not set.
153162306a36Sopenharmony_ci	 * Since sdhci-msm-v5, this bit has been removed and SW must consider
153262306a36Sopenharmony_ci	 * it as always set.
153362306a36Sopenharmony_ci	 */
153462306a36Sopenharmony_ci	if (!msm_host->mci_removed)
153562306a36Sopenharmony_ci		val = msm_host_readl(msm_host, host,
153662306a36Sopenharmony_ci				msm_offset->core_generics);
153762306a36Sopenharmony_ci	if ((req_type & REQ_IO_HIGH || req_type & REQ_IO_LOW) &&
153862306a36Sopenharmony_ci	    !(val & SWITCHABLE_SIGNALING_VOLTAGE)) {
153962306a36Sopenharmony_ci		return;
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	/*
154362306a36Sopenharmony_ci	 * The IRQ for request type IO High/LOW will be generated when -
154462306a36Sopenharmony_ci	 * there is a state change in 1.8V enable bit (bit 3) of
154562306a36Sopenharmony_ci	 * SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
154662306a36Sopenharmony_ci	 * which indicates 3.3V IO voltage. So, when MMC core layer tries
154762306a36Sopenharmony_ci	 * to set it to 3.3V before card detection happens, the
154862306a36Sopenharmony_ci	 * IRQ doesn't get triggered as there is no state change in this bit.
154962306a36Sopenharmony_ci	 * The driver already handles this case by changing the IO voltage
155062306a36Sopenharmony_ci	 * level to high as part of controller power up sequence. Hence, check
155162306a36Sopenharmony_ci	 * for host->pwr to handle a case where IO voltage high request is
155262306a36Sopenharmony_ci	 * issued even before controller power up.
155362306a36Sopenharmony_ci	 */
155462306a36Sopenharmony_ci	if ((req_type & REQ_IO_HIGH) && !host->pwr) {
155562306a36Sopenharmony_ci		pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n",
155662306a36Sopenharmony_ci				mmc_hostname(host->mmc), req_type);
155762306a36Sopenharmony_ci		return;
155862306a36Sopenharmony_ci	}
155962306a36Sopenharmony_ci	if ((req_type & msm_host->curr_pwr_state) ||
156062306a36Sopenharmony_ci			(req_type & msm_host->curr_io_level))
156162306a36Sopenharmony_ci		done = true;
156262306a36Sopenharmony_ci	/*
156362306a36Sopenharmony_ci	 * This is needed here to handle cases where register writes will
156462306a36Sopenharmony_ci	 * not change the current bus state or io level of the controller.
156562306a36Sopenharmony_ci	 * In this case, no power irq will be triggerred and we should
156662306a36Sopenharmony_ci	 * not wait.
156762306a36Sopenharmony_ci	 */
156862306a36Sopenharmony_ci	if (!done) {
156962306a36Sopenharmony_ci		if (!wait_event_timeout(msm_host->pwr_irq_wait,
157062306a36Sopenharmony_ci				msm_host->pwr_irq_flag,
157162306a36Sopenharmony_ci				msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
157262306a36Sopenharmony_ci			dev_warn(&msm_host->pdev->dev,
157362306a36Sopenharmony_ci				 "%s: pwr_irq for req: (%d) timed out\n",
157462306a36Sopenharmony_ci				 mmc_hostname(host->mmc), req_type);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci	pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
157762306a36Sopenharmony_ci			__func__, req_type);
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_cistatic void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
158362306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
158462306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset =
158562306a36Sopenharmony_ci					msm_host->offset;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
158862306a36Sopenharmony_ci		mmc_hostname(host->mmc),
158962306a36Sopenharmony_ci		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_status),
159062306a36Sopenharmony_ci		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_mask),
159162306a36Sopenharmony_ci		msm_host_readl(msm_host, host, msm_offset->core_pwrctl_ctl));
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
159762306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
159862306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
159962306a36Sopenharmony_ci	u32 irq_status, irq_ack = 0;
160062306a36Sopenharmony_ci	int retry = 10, ret;
160162306a36Sopenharmony_ci	u32 pwr_state = 0, io_level = 0;
160262306a36Sopenharmony_ci	u32 config;
160362306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	irq_status = msm_host_readl(msm_host, host,
160662306a36Sopenharmony_ci			msm_offset->core_pwrctl_status);
160762306a36Sopenharmony_ci	irq_status &= INT_MASK;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	msm_host_writel(msm_host, irq_status, host,
161062306a36Sopenharmony_ci			msm_offset->core_pwrctl_clear);
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	/*
161362306a36Sopenharmony_ci	 * There is a rare HW scenario where the first clear pulse could be
161462306a36Sopenharmony_ci	 * lost when actual reset and clear/read of status register is
161562306a36Sopenharmony_ci	 * happening at a time. Hence, retry for at least 10 times to make
161662306a36Sopenharmony_ci	 * sure status register is cleared. Otherwise, this will result in
161762306a36Sopenharmony_ci	 * a spurious power IRQ resulting in system instability.
161862306a36Sopenharmony_ci	 */
161962306a36Sopenharmony_ci	while (irq_status & msm_host_readl(msm_host, host,
162062306a36Sopenharmony_ci				msm_offset->core_pwrctl_status)) {
162162306a36Sopenharmony_ci		if (retry == 0) {
162262306a36Sopenharmony_ci			pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
162362306a36Sopenharmony_ci					mmc_hostname(host->mmc), irq_status);
162462306a36Sopenharmony_ci			sdhci_msm_dump_pwr_ctrl_regs(host);
162562306a36Sopenharmony_ci			WARN_ON(1);
162662306a36Sopenharmony_ci			break;
162762306a36Sopenharmony_ci		}
162862306a36Sopenharmony_ci		msm_host_writel(msm_host, irq_status, host,
162962306a36Sopenharmony_ci			msm_offset->core_pwrctl_clear);
163062306a36Sopenharmony_ci		retry--;
163162306a36Sopenharmony_ci		udelay(10);
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	/* Handle BUS ON/OFF*/
163562306a36Sopenharmony_ci	if (irq_status & CORE_PWRCTL_BUS_ON) {
163662306a36Sopenharmony_ci		pwr_state = REQ_BUS_ON;
163762306a36Sopenharmony_ci		io_level = REQ_IO_HIGH;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci	if (irq_status & CORE_PWRCTL_BUS_OFF) {
164062306a36Sopenharmony_ci		pwr_state = REQ_BUS_OFF;
164162306a36Sopenharmony_ci		io_level = REQ_IO_LOW;
164262306a36Sopenharmony_ci	}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (pwr_state) {
164562306a36Sopenharmony_ci		ret = sdhci_msm_set_vmmc(mmc);
164662306a36Sopenharmony_ci		if (!ret)
164762306a36Sopenharmony_ci			ret = sdhci_msm_set_vqmmc(msm_host, mmc,
164862306a36Sopenharmony_ci					pwr_state & REQ_BUS_ON);
164962306a36Sopenharmony_ci		if (!ret)
165062306a36Sopenharmony_ci			ret = sdhci_msm_set_pincfg(msm_host,
165162306a36Sopenharmony_ci					pwr_state & REQ_BUS_ON);
165262306a36Sopenharmony_ci		if (!ret)
165362306a36Sopenharmony_ci			irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
165462306a36Sopenharmony_ci		else
165562306a36Sopenharmony_ci			irq_ack |= CORE_PWRCTL_BUS_FAIL;
165662306a36Sopenharmony_ci	}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	/* Handle IO LOW/HIGH */
165962306a36Sopenharmony_ci	if (irq_status & CORE_PWRCTL_IO_LOW)
166062306a36Sopenharmony_ci		io_level = REQ_IO_LOW;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	if (irq_status & CORE_PWRCTL_IO_HIGH)
166362306a36Sopenharmony_ci		io_level = REQ_IO_HIGH;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (io_level)
166662306a36Sopenharmony_ci		irq_ack |= CORE_PWRCTL_IO_SUCCESS;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (io_level && !IS_ERR(mmc->supply.vqmmc) && !pwr_state) {
166962306a36Sopenharmony_ci		ret = mmc_regulator_set_vqmmc(mmc, &mmc->ios);
167062306a36Sopenharmony_ci		if (ret < 0) {
167162306a36Sopenharmony_ci			dev_err(mmc_dev(mmc), "%s: IO_level setting failed(%d). signal_voltage: %d, vdd: %d irq_status: 0x%08x\n",
167262306a36Sopenharmony_ci					mmc_hostname(mmc), ret,
167362306a36Sopenharmony_ci					mmc->ios.signal_voltage, mmc->ios.vdd,
167462306a36Sopenharmony_ci					irq_status);
167562306a36Sopenharmony_ci			irq_ack |= CORE_PWRCTL_IO_FAIL;
167662306a36Sopenharmony_ci		}
167762306a36Sopenharmony_ci	}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	/*
168062306a36Sopenharmony_ci	 * The driver has to acknowledge the interrupt, switch voltages and
168162306a36Sopenharmony_ci	 * report back if it succeded or not to this register. The voltage
168262306a36Sopenharmony_ci	 * switches are handled by the sdhci core, so just report success.
168362306a36Sopenharmony_ci	 */
168462306a36Sopenharmony_ci	msm_host_writel(msm_host, irq_ack, host,
168562306a36Sopenharmony_ci			msm_offset->core_pwrctl_ctl);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	/*
168862306a36Sopenharmony_ci	 * If we don't have info regarding the voltage levels supported by
168962306a36Sopenharmony_ci	 * regulators, don't change the IO PAD PWR SWITCH.
169062306a36Sopenharmony_ci	 */
169162306a36Sopenharmony_ci	if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
169262306a36Sopenharmony_ci		u32 new_config;
169362306a36Sopenharmony_ci		/*
169462306a36Sopenharmony_ci		 * We should unset IO PAD PWR switch only if the register write
169562306a36Sopenharmony_ci		 * can set IO lines high and the regulator also switches to 3 V.
169662306a36Sopenharmony_ci		 * Else, we should keep the IO PAD PWR switch set.
169762306a36Sopenharmony_ci		 * This is applicable to certain targets where eMMC vccq supply
169862306a36Sopenharmony_ci		 * is only 1.8V. In such targets, even during REQ_IO_HIGH, the
169962306a36Sopenharmony_ci		 * IO PAD PWR switch must be kept set to reflect actual
170062306a36Sopenharmony_ci		 * regulator voltage. This way, during initialization of
170162306a36Sopenharmony_ci		 * controllers with only 1.8V, we will set the IO PAD bit
170262306a36Sopenharmony_ci		 * without waiting for a REQ_IO_LOW.
170362306a36Sopenharmony_ci		 */
170462306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
170562306a36Sopenharmony_ci				msm_offset->core_vendor_spec);
170662306a36Sopenharmony_ci		new_config = config;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		if ((io_level & REQ_IO_HIGH) &&
170962306a36Sopenharmony_ci				(msm_host->caps_0 & CORE_3_0V_SUPPORT))
171062306a36Sopenharmony_ci			new_config &= ~CORE_IO_PAD_PWR_SWITCH;
171162306a36Sopenharmony_ci		else if ((io_level & REQ_IO_LOW) ||
171262306a36Sopenharmony_ci				(msm_host->caps_0 & CORE_1_8V_SUPPORT))
171362306a36Sopenharmony_ci			new_config |= CORE_IO_PAD_PWR_SWITCH;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci		if (config ^ new_config)
171662306a36Sopenharmony_ci			writel_relaxed(new_config, host->ioaddr +
171762306a36Sopenharmony_ci					msm_offset->core_vendor_spec);
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	if (pwr_state)
172162306a36Sopenharmony_ci		msm_host->curr_pwr_state = pwr_state;
172262306a36Sopenharmony_ci	if (io_level)
172362306a36Sopenharmony_ci		msm_host->curr_io_level = io_level;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	dev_dbg(mmc_dev(mmc), "%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
172662306a36Sopenharmony_ci		mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
172762306a36Sopenharmony_ci		irq_ack);
172862306a36Sopenharmony_ci}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_cistatic irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
173162306a36Sopenharmony_ci{
173262306a36Sopenharmony_ci	struct sdhci_host *host = (struct sdhci_host *)data;
173362306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
173462306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	sdhci_msm_handle_pwr_irq(host, irq);
173762306a36Sopenharmony_ci	msm_host->pwr_irq_flag = 1;
173862306a36Sopenharmony_ci	sdhci_msm_complete_pwr_irq_wait(msm_host);
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	return IRQ_HANDLED;
174262306a36Sopenharmony_ci}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_cistatic unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host)
174562306a36Sopenharmony_ci{
174662306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
174762306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
174862306a36Sopenharmony_ci	struct clk *core_clk = msm_host->bulk_clks[0].clk;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	return clk_round_rate(core_clk, ULONG_MAX);
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
175462306a36Sopenharmony_ci{
175562306a36Sopenharmony_ci	return SDHCI_MSM_MIN_CLOCK;
175662306a36Sopenharmony_ci}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci/*
175962306a36Sopenharmony_ci * __sdhci_msm_set_clock - sdhci_msm clock control.
176062306a36Sopenharmony_ci *
176162306a36Sopenharmony_ci * Description:
176262306a36Sopenharmony_ci * MSM controller does not use internal divider and
176362306a36Sopenharmony_ci * instead directly control the GCC clock as per
176462306a36Sopenharmony_ci * HW recommendation.
176562306a36Sopenharmony_ci **/
176662306a36Sopenharmony_cistatic void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
176762306a36Sopenharmony_ci{
176862306a36Sopenharmony_ci	u16 clk;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	if (clock == 0)
177362306a36Sopenharmony_ci		return;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	/*
177662306a36Sopenharmony_ci	 * MSM controller do not use clock divider.
177762306a36Sopenharmony_ci	 * Thus read SDHCI_CLOCK_CONTROL and only enable
177862306a36Sopenharmony_ci	 * clock with no divider value programmed.
177962306a36Sopenharmony_ci	 */
178062306a36Sopenharmony_ci	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
178162306a36Sopenharmony_ci	sdhci_enable_clk(host, clk);
178262306a36Sopenharmony_ci}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci/* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */
178562306a36Sopenharmony_cistatic void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
178662306a36Sopenharmony_ci{
178762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
178862306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	if (!clock) {
179162306a36Sopenharmony_ci		host->mmc->actual_clock = msm_host->clk_rate = 0;
179262306a36Sopenharmony_ci		goto out;
179362306a36Sopenharmony_ci	}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	sdhci_msm_hc_select_mode(host);
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	msm_set_clock_rate_for_bus_mode(host, clock);
179862306a36Sopenharmony_ciout:
179962306a36Sopenharmony_ci	__sdhci_msm_set_clock(host, clock);
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci/*****************************************************************************\
180362306a36Sopenharmony_ci *                                                                           *
180462306a36Sopenharmony_ci * Inline Crypto Engine (ICE) support                                        *
180562306a36Sopenharmony_ci *                                                                           *
180662306a36Sopenharmony_ci\*****************************************************************************/
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci#ifdef CONFIG_MMC_CRYPTO
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
181162306a36Sopenharmony_ci			      struct cqhci_host *cq_host)
181262306a36Sopenharmony_ci{
181362306a36Sopenharmony_ci	struct mmc_host *mmc = msm_host->mmc;
181462306a36Sopenharmony_ci	struct device *dev = mmc_dev(mmc);
181562306a36Sopenharmony_ci	struct qcom_ice *ice;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS))
181862306a36Sopenharmony_ci		return 0;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	ice = of_qcom_ice_get(dev);
182162306a36Sopenharmony_ci	if (ice == ERR_PTR(-EOPNOTSUPP)) {
182262306a36Sopenharmony_ci		dev_warn(dev, "Disabling inline encryption support\n");
182362306a36Sopenharmony_ci		ice = NULL;
182462306a36Sopenharmony_ci	}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(ice))
182762306a36Sopenharmony_ci		return PTR_ERR_OR_ZERO(ice);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	msm_host->ice = ice;
183062306a36Sopenharmony_ci	mmc->caps2 |= MMC_CAP2_CRYPTO;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	return 0;
183362306a36Sopenharmony_ci}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_cistatic void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
183862306a36Sopenharmony_ci		qcom_ice_enable(msm_host->ice);
183962306a36Sopenharmony_ci}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_cistatic __maybe_unused int sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
184262306a36Sopenharmony_ci{
184362306a36Sopenharmony_ci	if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
184462306a36Sopenharmony_ci		return qcom_ice_resume(msm_host->ice);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	return 0;
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_cistatic __maybe_unused int sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
185262306a36Sopenharmony_ci		return qcom_ice_suspend(msm_host->ice);
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	return 0;
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci/*
185862306a36Sopenharmony_ci * Program a key into a QC ICE keyslot, or evict a keyslot.  QC ICE requires
185962306a36Sopenharmony_ci * vendor-specific SCM calls for this; it doesn't support the standard way.
186062306a36Sopenharmony_ci */
186162306a36Sopenharmony_cistatic int sdhci_msm_program_key(struct cqhci_host *cq_host,
186262306a36Sopenharmony_ci				 const union cqhci_crypto_cfg_entry *cfg,
186362306a36Sopenharmony_ci				 int slot)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(cq_host->mmc);
186662306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
186762306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
186862306a36Sopenharmony_ci	union cqhci_crypto_cap_entry cap;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	/* Only AES-256-XTS has been tested so far. */
187162306a36Sopenharmony_ci	cap = cq_host->crypto_cap_array[cfg->crypto_cap_idx];
187262306a36Sopenharmony_ci	if (cap.algorithm_id != CQHCI_CRYPTO_ALG_AES_XTS ||
187362306a36Sopenharmony_ci		cap.key_size != CQHCI_CRYPTO_KEY_SIZE_256)
187462306a36Sopenharmony_ci		return -EINVAL;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	if (cfg->config_enable & CQHCI_CRYPTO_CONFIGURATION_ENABLE)
187762306a36Sopenharmony_ci		return qcom_ice_program_key(msm_host->ice,
187862306a36Sopenharmony_ci					    QCOM_ICE_CRYPTO_ALG_AES_XTS,
187962306a36Sopenharmony_ci					    QCOM_ICE_CRYPTO_KEY_SIZE_256,
188062306a36Sopenharmony_ci					    cfg->crypto_key,
188162306a36Sopenharmony_ci					    cfg->data_unit_size, slot);
188262306a36Sopenharmony_ci	else
188362306a36Sopenharmony_ci		return qcom_ice_evict_key(msm_host->ice, slot);
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci#else /* CONFIG_MMC_CRYPTO */
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_cistatic inline int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
188962306a36Sopenharmony_ci				     struct cqhci_host *cq_host)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	return 0;
189262306a36Sopenharmony_ci}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_cistatic inline void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host)
189562306a36Sopenharmony_ci{
189662306a36Sopenharmony_ci}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_cistatic inline __maybe_unused int
189962306a36Sopenharmony_cisdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
190062306a36Sopenharmony_ci{
190162306a36Sopenharmony_ci	return 0;
190262306a36Sopenharmony_ci}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_cistatic inline __maybe_unused int
190562306a36Sopenharmony_cisdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
190662306a36Sopenharmony_ci{
190762306a36Sopenharmony_ci	return 0;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci#endif /* !CONFIG_MMC_CRYPTO */
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci/*****************************************************************************\
191262306a36Sopenharmony_ci *                                                                           *
191362306a36Sopenharmony_ci * MSM Command Queue Engine (CQE)                                            *
191462306a36Sopenharmony_ci *                                                                           *
191562306a36Sopenharmony_ci\*****************************************************************************/
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_cistatic u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask)
191862306a36Sopenharmony_ci{
191962306a36Sopenharmony_ci	int cmd_error = 0;
192062306a36Sopenharmony_ci	int data_error = 0;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
192362306a36Sopenharmony_ci		return intmask;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
192662306a36Sopenharmony_ci	return 0;
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_cistatic void sdhci_msm_cqe_enable(struct mmc_host *mmc)
193062306a36Sopenharmony_ci{
193162306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
193262306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
193362306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	sdhci_cqe_enable(mmc);
193662306a36Sopenharmony_ci	sdhci_msm_ice_enable(msm_host);
193762306a36Sopenharmony_ci}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_cistatic void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
194262306a36Sopenharmony_ci	unsigned long flags;
194362306a36Sopenharmony_ci	u32 ctrl;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	/*
194662306a36Sopenharmony_ci	 * When CQE is halted, the legacy SDHCI path operates only
194762306a36Sopenharmony_ci	 * on 16-byte descriptors in 64bit mode.
194862306a36Sopenharmony_ci	 */
194962306a36Sopenharmony_ci	if (host->flags & SDHCI_USE_64_BIT_DMA)
195062306a36Sopenharmony_ci		host->desc_sz = 16;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	spin_lock_irqsave(&host->lock, flags);
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	/*
195562306a36Sopenharmony_ci	 * During CQE command transfers, command complete bit gets latched.
195662306a36Sopenharmony_ci	 * So s/w should clear command complete interrupt status when CQE is
195762306a36Sopenharmony_ci	 * either halted or disabled. Otherwise unexpected SDCHI legacy
195862306a36Sopenharmony_ci	 * interrupt gets triggered when CQE is halted/disabled.
195962306a36Sopenharmony_ci	 */
196062306a36Sopenharmony_ci	ctrl = sdhci_readl(host, SDHCI_INT_ENABLE);
196162306a36Sopenharmony_ci	ctrl |= SDHCI_INT_RESPONSE;
196262306a36Sopenharmony_ci	sdhci_writel(host,  ctrl, SDHCI_INT_ENABLE);
196362306a36Sopenharmony_ci	sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	spin_unlock_irqrestore(&host->lock, flags);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	sdhci_cqe_disable(mmc, recovery);
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_cistatic void sdhci_msm_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
197162306a36Sopenharmony_ci{
197262306a36Sopenharmony_ci	u32 count, start = 15;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	__sdhci_set_timeout(host, cmd);
197562306a36Sopenharmony_ci	count = sdhci_readb(host, SDHCI_TIMEOUT_CONTROL);
197662306a36Sopenharmony_ci	/*
197762306a36Sopenharmony_ci	 * Update software timeout value if its value is less than hardware data
197862306a36Sopenharmony_ci	 * timeout value. Qcom SoC hardware data timeout value was calculated
197962306a36Sopenharmony_ci	 * using 4 * MCLK * 2^(count + 13). where MCLK = 1 / host->clock.
198062306a36Sopenharmony_ci	 */
198162306a36Sopenharmony_ci	if (cmd && cmd->data && host->clock > 400000 &&
198262306a36Sopenharmony_ci	    host->clock <= 50000000 &&
198362306a36Sopenharmony_ci	    ((1 << (count + start)) > (10 * host->clock)))
198462306a36Sopenharmony_ci		host->data_timeout = 22LL * NSEC_PER_SEC;
198562306a36Sopenharmony_ci}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_cistatic const struct cqhci_host_ops sdhci_msm_cqhci_ops = {
198862306a36Sopenharmony_ci	.enable		= sdhci_msm_cqe_enable,
198962306a36Sopenharmony_ci	.disable	= sdhci_msm_cqe_disable,
199062306a36Sopenharmony_ci#ifdef CONFIG_MMC_CRYPTO
199162306a36Sopenharmony_ci	.program_key	= sdhci_msm_program_key,
199262306a36Sopenharmony_ci#endif
199362306a36Sopenharmony_ci};
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_cistatic int sdhci_msm_cqe_add_host(struct sdhci_host *host,
199662306a36Sopenharmony_ci				struct platform_device *pdev)
199762306a36Sopenharmony_ci{
199862306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
199962306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
200062306a36Sopenharmony_ci	struct cqhci_host *cq_host;
200162306a36Sopenharmony_ci	bool dma64;
200262306a36Sopenharmony_ci	u32 cqcfg;
200362306a36Sopenharmony_ci	int ret;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	/*
200662306a36Sopenharmony_ci	 * When CQE is halted, SDHC operates only on 16byte ADMA descriptors.
200762306a36Sopenharmony_ci	 * So ensure ADMA table is allocated for 16byte descriptors.
200862306a36Sopenharmony_ci	 */
200962306a36Sopenharmony_ci	if (host->caps & SDHCI_CAN_64BIT)
201062306a36Sopenharmony_ci		host->alloc_desc_sz = 16;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	ret = sdhci_setup_host(host);
201362306a36Sopenharmony_ci	if (ret)
201462306a36Sopenharmony_ci		return ret;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	cq_host = cqhci_pltfm_init(pdev);
201762306a36Sopenharmony_ci	if (IS_ERR(cq_host)) {
201862306a36Sopenharmony_ci		ret = PTR_ERR(cq_host);
201962306a36Sopenharmony_ci		dev_err(&pdev->dev, "cqhci-pltfm init: failed: %d\n", ret);
202062306a36Sopenharmony_ci		goto cleanup;
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	msm_host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
202462306a36Sopenharmony_ci	cq_host->ops = &sdhci_msm_cqhci_ops;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	ret = sdhci_msm_ice_init(msm_host, cq_host);
202962306a36Sopenharmony_ci	if (ret)
203062306a36Sopenharmony_ci		goto cleanup;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	ret = cqhci_init(cq_host, host->mmc, dma64);
203362306a36Sopenharmony_ci	if (ret) {
203462306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s: CQE init: failed (%d)\n",
203562306a36Sopenharmony_ci				mmc_hostname(host->mmc), ret);
203662306a36Sopenharmony_ci		goto cleanup;
203762306a36Sopenharmony_ci	}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	/* Disable cqe reset due to cqe enable signal */
204062306a36Sopenharmony_ci	cqcfg = cqhci_readl(cq_host, CQHCI_VENDOR_CFG1);
204162306a36Sopenharmony_ci	cqcfg |= CQHCI_VENDOR_DIS_RST_ON_CQ_EN;
204262306a36Sopenharmony_ci	cqhci_writel(cq_host, cqcfg, CQHCI_VENDOR_CFG1);
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	/*
204562306a36Sopenharmony_ci	 * SDHC expects 12byte ADMA descriptors till CQE is enabled.
204662306a36Sopenharmony_ci	 * So limit desc_sz to 12 so that the data commands that are sent
204762306a36Sopenharmony_ci	 * during card initialization (before CQE gets enabled) would
204862306a36Sopenharmony_ci	 * get executed without any issues.
204962306a36Sopenharmony_ci	 */
205062306a36Sopenharmony_ci	if (host->flags & SDHCI_USE_64_BIT_DMA)
205162306a36Sopenharmony_ci		host->desc_sz = 12;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	ret = __sdhci_add_host(host);
205462306a36Sopenharmony_ci	if (ret)
205562306a36Sopenharmony_ci		goto cleanup;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	dev_info(&pdev->dev, "%s: CQE init: success\n",
205862306a36Sopenharmony_ci			mmc_hostname(host->mmc));
205962306a36Sopenharmony_ci	return ret;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cicleanup:
206262306a36Sopenharmony_ci	sdhci_cleanup_host(host);
206362306a36Sopenharmony_ci	return ret;
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci/*
206762306a36Sopenharmony_ci * Platform specific register write functions. This is so that, if any
206862306a36Sopenharmony_ci * register write needs to be followed up by platform specific actions,
206962306a36Sopenharmony_ci * they can be added here. These functions can go to sleep when writes
207062306a36Sopenharmony_ci * to certain registers are done.
207162306a36Sopenharmony_ci * These functions are relying on sdhci_set_ios not using spinlock.
207262306a36Sopenharmony_ci */
207362306a36Sopenharmony_cistatic int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
207462306a36Sopenharmony_ci{
207562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
207662306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
207762306a36Sopenharmony_ci	u32 req_type = 0;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	switch (reg) {
208062306a36Sopenharmony_ci	case SDHCI_HOST_CONTROL2:
208162306a36Sopenharmony_ci		req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
208262306a36Sopenharmony_ci			REQ_IO_HIGH;
208362306a36Sopenharmony_ci		break;
208462306a36Sopenharmony_ci	case SDHCI_SOFTWARE_RESET:
208562306a36Sopenharmony_ci		if (host->pwr && (val & SDHCI_RESET_ALL))
208662306a36Sopenharmony_ci			req_type = REQ_BUS_OFF;
208762306a36Sopenharmony_ci		break;
208862306a36Sopenharmony_ci	case SDHCI_POWER_CONTROL:
208962306a36Sopenharmony_ci		req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
209062306a36Sopenharmony_ci		break;
209162306a36Sopenharmony_ci	case SDHCI_TRANSFER_MODE:
209262306a36Sopenharmony_ci		msm_host->transfer_mode = val;
209362306a36Sopenharmony_ci		break;
209462306a36Sopenharmony_ci	case SDHCI_COMMAND:
209562306a36Sopenharmony_ci		if (!msm_host->use_cdr)
209662306a36Sopenharmony_ci			break;
209762306a36Sopenharmony_ci		if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
209862306a36Sopenharmony_ci		    !mmc_op_tuning(SDHCI_GET_CMD(val)))
209962306a36Sopenharmony_ci			sdhci_msm_set_cdr(host, true);
210062306a36Sopenharmony_ci		else
210162306a36Sopenharmony_ci			sdhci_msm_set_cdr(host, false);
210262306a36Sopenharmony_ci		break;
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	if (req_type) {
210662306a36Sopenharmony_ci		msm_host->pwr_irq_flag = 0;
210762306a36Sopenharmony_ci		/*
210862306a36Sopenharmony_ci		 * Since this register write may trigger a power irq, ensure
210962306a36Sopenharmony_ci		 * all previous register writes are complete by this point.
211062306a36Sopenharmony_ci		 */
211162306a36Sopenharmony_ci		mb();
211262306a36Sopenharmony_ci	}
211362306a36Sopenharmony_ci	return req_type;
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci/* This function may sleep*/
211762306a36Sopenharmony_cistatic void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci	u32 req_type = 0;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	req_type = __sdhci_msm_check_write(host, val, reg);
212262306a36Sopenharmony_ci	writew_relaxed(val, host->ioaddr + reg);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	if (req_type)
212562306a36Sopenharmony_ci		sdhci_msm_check_power_status(host, req_type);
212662306a36Sopenharmony_ci}
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci/* This function may sleep*/
212962306a36Sopenharmony_cistatic void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
213062306a36Sopenharmony_ci{
213162306a36Sopenharmony_ci	u32 req_type = 0;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	req_type = __sdhci_msm_check_write(host, val, reg);
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	writeb_relaxed(val, host->ioaddr + reg);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	if (req_type)
213862306a36Sopenharmony_ci		sdhci_msm_check_power_status(host, req_type);
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_cistatic void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)
214262306a36Sopenharmony_ci{
214362306a36Sopenharmony_ci	struct mmc_host *mmc = msm_host->mmc;
214462306a36Sopenharmony_ci	struct regulator *supply = mmc->supply.vqmmc;
214562306a36Sopenharmony_ci	u32 caps = 0, config;
214662306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
214762306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	if (!IS_ERR(mmc->supply.vqmmc)) {
215062306a36Sopenharmony_ci		if (regulator_is_supported_voltage(supply, 1700000, 1950000))
215162306a36Sopenharmony_ci			caps |= CORE_1_8V_SUPPORT;
215262306a36Sopenharmony_ci		if (regulator_is_supported_voltage(supply, 2700000, 3600000))
215362306a36Sopenharmony_ci			caps |= CORE_3_0V_SUPPORT;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci		if (!caps)
215662306a36Sopenharmony_ci			pr_warn("%s: 1.8/3V not supported for vqmmc\n",
215762306a36Sopenharmony_ci					mmc_hostname(mmc));
215862306a36Sopenharmony_ci	}
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	if (caps) {
216162306a36Sopenharmony_ci		/*
216262306a36Sopenharmony_ci		 * Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH
216362306a36Sopenharmony_ci		 * bit can be used as required later on.
216462306a36Sopenharmony_ci		 */
216562306a36Sopenharmony_ci		u32 io_level = msm_host->curr_io_level;
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr +
216862306a36Sopenharmony_ci				msm_offset->core_vendor_spec);
216962306a36Sopenharmony_ci		config |= CORE_IO_PAD_PWR_SWITCH_EN;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci		if ((io_level & REQ_IO_HIGH) && (caps &	CORE_3_0V_SUPPORT))
217262306a36Sopenharmony_ci			config &= ~CORE_IO_PAD_PWR_SWITCH;
217362306a36Sopenharmony_ci		else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT))
217462306a36Sopenharmony_ci			config |= CORE_IO_PAD_PWR_SWITCH;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci		writel_relaxed(config,
217762306a36Sopenharmony_ci				host->ioaddr + msm_offset->core_vendor_spec);
217862306a36Sopenharmony_ci	}
217962306a36Sopenharmony_ci	msm_host->caps_0 |= caps;
218062306a36Sopenharmony_ci	pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
218162306a36Sopenharmony_ci}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_cistatic int sdhci_msm_register_vreg(struct sdhci_msm_host *msm_host)
218462306a36Sopenharmony_ci{
218562306a36Sopenharmony_ci	int ret;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	ret = mmc_regulator_get_supply(msm_host->mmc);
218862306a36Sopenharmony_ci	if (ret)
218962306a36Sopenharmony_ci		return ret;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	sdhci_msm_set_regulator_caps(msm_host);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	return 0;
219462306a36Sopenharmony_ci}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_cistatic int sdhci_msm_start_signal_voltage_switch(struct mmc_host *mmc,
219762306a36Sopenharmony_ci				      struct mmc_ios *ios)
219862306a36Sopenharmony_ci{
219962306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
220062306a36Sopenharmony_ci	u16 ctrl, status;
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	/*
220362306a36Sopenharmony_ci	 * Signal Voltage Switching is only applicable for Host Controllers
220462306a36Sopenharmony_ci	 * v3.00 and above.
220562306a36Sopenharmony_ci	 */
220662306a36Sopenharmony_ci	if (host->version < SDHCI_SPEC_300)
220762306a36Sopenharmony_ci		return 0;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	switch (ios->signal_voltage) {
221262306a36Sopenharmony_ci	case MMC_SIGNAL_VOLTAGE_330:
221362306a36Sopenharmony_ci		if (!(host->flags & SDHCI_SIGNALING_330))
221462306a36Sopenharmony_ci			return -EINVAL;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci		/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
221762306a36Sopenharmony_ci		ctrl &= ~SDHCI_CTRL_VDD_180;
221862306a36Sopenharmony_ci		break;
221962306a36Sopenharmony_ci	case MMC_SIGNAL_VOLTAGE_180:
222062306a36Sopenharmony_ci		if (!(host->flags & SDHCI_SIGNALING_180))
222162306a36Sopenharmony_ci			return -EINVAL;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		/* Enable 1.8V Signal Enable in the Host Control2 register */
222462306a36Sopenharmony_ci		ctrl |= SDHCI_CTRL_VDD_180;
222562306a36Sopenharmony_ci		break;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	default:
222862306a36Sopenharmony_ci		return -EINVAL;
222962306a36Sopenharmony_ci	}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	/* Wait for 5ms */
223462306a36Sopenharmony_ci	usleep_range(5000, 5500);
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	/* regulator output should be stable within 5 ms */
223762306a36Sopenharmony_ci	status = ctrl & SDHCI_CTRL_VDD_180;
223862306a36Sopenharmony_ci	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
223962306a36Sopenharmony_ci	if ((ctrl & SDHCI_CTRL_VDD_180) == status)
224062306a36Sopenharmony_ci		return 0;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	dev_warn(mmc_dev(mmc), "%s: Regulator output did not became stable\n",
224362306a36Sopenharmony_ci		mmc_hostname(mmc));
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	return -EAGAIN;
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci#define DRIVER_NAME "sdhci_msm"
224962306a36Sopenharmony_ci#define SDHCI_MSM_DUMP(f, x...) \
225062306a36Sopenharmony_ci	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_cistatic void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
225362306a36Sopenharmony_ci{
225462306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
225562306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
225662306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset = msm_host->offset;
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	SDHCI_MSM_DUMP("----------- VENDOR REGISTER DUMP -----------\n");
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	SDHCI_MSM_DUMP(
226162306a36Sopenharmony_ci			"DLL sts: 0x%08x | DLL cfg:  0x%08x | DLL cfg2: 0x%08x\n",
226262306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_dll_status),
226362306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_dll_config),
226462306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2));
226562306a36Sopenharmony_ci	SDHCI_MSM_DUMP(
226662306a36Sopenharmony_ci			"DLL cfg3: 0x%08x | DLL usr ctl:  0x%08x | DDR cfg: 0x%08x\n",
226762306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_dll_config_3),
226862306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_dll_usr_ctl),
226962306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_ddr_config));
227062306a36Sopenharmony_ci	SDHCI_MSM_DUMP(
227162306a36Sopenharmony_ci			"Vndr func: 0x%08x | Vndr func2 : 0x%08x Vndr func3: 0x%08x\n",
227262306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec),
227362306a36Sopenharmony_ci		readl_relaxed(host->ioaddr +
227462306a36Sopenharmony_ci			msm_offset->core_vendor_spec_func2),
227562306a36Sopenharmony_ci		readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec3));
227662306a36Sopenharmony_ci}
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_cistatic const struct sdhci_msm_variant_ops mci_var_ops = {
227962306a36Sopenharmony_ci	.msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed,
228062306a36Sopenharmony_ci	.msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed,
228162306a36Sopenharmony_ci};
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_cistatic const struct sdhci_msm_variant_ops v5_var_ops = {
228462306a36Sopenharmony_ci	.msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed,
228562306a36Sopenharmony_ci	.msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed,
228662306a36Sopenharmony_ci};
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_cistatic const struct sdhci_msm_variant_info sdhci_msm_mci_var = {
228962306a36Sopenharmony_ci	.var_ops = &mci_var_ops,
229062306a36Sopenharmony_ci	.offset = &sdhci_msm_mci_offset,
229162306a36Sopenharmony_ci};
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_cistatic const struct sdhci_msm_variant_info sdhci_msm_v5_var = {
229462306a36Sopenharmony_ci	.mci_removed = true,
229562306a36Sopenharmony_ci	.var_ops = &v5_var_ops,
229662306a36Sopenharmony_ci	.offset = &sdhci_msm_v5_offset,
229762306a36Sopenharmony_ci};
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_cistatic const struct sdhci_msm_variant_info sdm845_sdhci_var = {
230062306a36Sopenharmony_ci	.mci_removed = true,
230162306a36Sopenharmony_ci	.restore_dll_config = true,
230262306a36Sopenharmony_ci	.var_ops = &v5_var_ops,
230362306a36Sopenharmony_ci	.offset = &sdhci_msm_v5_offset,
230462306a36Sopenharmony_ci};
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_cistatic const struct of_device_id sdhci_msm_dt_match[] = {
230762306a36Sopenharmony_ci	/*
230862306a36Sopenharmony_ci	 * Do not add new variants to the driver which are compatible with
230962306a36Sopenharmony_ci	 * generic ones, unless they need customization.
231062306a36Sopenharmony_ci	 */
231162306a36Sopenharmony_ci	{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
231262306a36Sopenharmony_ci	{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
231362306a36Sopenharmony_ci	{.compatible = "qcom,sdm670-sdhci", .data = &sdm845_sdhci_var},
231462306a36Sopenharmony_ci	{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
231562306a36Sopenharmony_ci	{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
231662306a36Sopenharmony_ci	{},
231762306a36Sopenharmony_ci};
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_cistatic const struct sdhci_ops sdhci_msm_ops = {
232262306a36Sopenharmony_ci	.reset = sdhci_and_cqhci_reset,
232362306a36Sopenharmony_ci	.set_clock = sdhci_msm_set_clock,
232462306a36Sopenharmony_ci	.get_min_clock = sdhci_msm_get_min_clock,
232562306a36Sopenharmony_ci	.get_max_clock = sdhci_msm_get_max_clock,
232662306a36Sopenharmony_ci	.set_bus_width = sdhci_set_bus_width,
232762306a36Sopenharmony_ci	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
232862306a36Sopenharmony_ci	.write_w = sdhci_msm_writew,
232962306a36Sopenharmony_ci	.write_b = sdhci_msm_writeb,
233062306a36Sopenharmony_ci	.irq	= sdhci_msm_cqe_irq,
233162306a36Sopenharmony_ci	.dump_vendor_regs = sdhci_msm_dump_vendor_regs,
233262306a36Sopenharmony_ci	.set_power = sdhci_set_power_noreg,
233362306a36Sopenharmony_ci	.set_timeout = sdhci_msm_set_timeout,
233462306a36Sopenharmony_ci};
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_msm_pdata = {
233762306a36Sopenharmony_ci	.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
233862306a36Sopenharmony_ci		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
233962306a36Sopenharmony_ci		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
234062306a36Sopenharmony_ci		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
234362306a36Sopenharmony_ci	.ops = &sdhci_msm_ops,
234462306a36Sopenharmony_ci};
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_cistatic inline void sdhci_msm_get_of_property(struct platform_device *pdev,
234762306a36Sopenharmony_ci		struct sdhci_host *host)
234862306a36Sopenharmony_ci{
234962306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
235062306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
235162306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	if (of_property_read_u32(node, "qcom,ddr-config",
235462306a36Sopenharmony_ci				&msm_host->ddr_config))
235562306a36Sopenharmony_ci		msm_host->ddr_config = DDR_CONFIG_POR_VAL;
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	of_property_read_u32(node, "qcom,dll-config", &msm_host->dll_config);
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	if (of_device_is_compatible(node, "qcom,msm8916-sdhci"))
236062306a36Sopenharmony_ci		host->quirks2 |= SDHCI_QUIRK2_BROKEN_64_BIT_DMA;
236162306a36Sopenharmony_ci}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_cistatic int sdhci_msm_gcc_reset(struct device *dev, struct sdhci_host *host)
236462306a36Sopenharmony_ci{
236562306a36Sopenharmony_ci	struct reset_control *reset;
236662306a36Sopenharmony_ci	int ret = 0;
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	reset = reset_control_get_optional_exclusive(dev, NULL);
236962306a36Sopenharmony_ci	if (IS_ERR(reset))
237062306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(reset),
237162306a36Sopenharmony_ci				"unable to acquire core_reset\n");
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	if (!reset)
237462306a36Sopenharmony_ci		return ret;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	ret = reset_control_assert(reset);
237762306a36Sopenharmony_ci	if (ret) {
237862306a36Sopenharmony_ci		reset_control_put(reset);
237962306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "core_reset assert failed\n");
238062306a36Sopenharmony_ci	}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	/*
238362306a36Sopenharmony_ci	 * The hardware requirement for delay between assert/deassert
238462306a36Sopenharmony_ci	 * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
238562306a36Sopenharmony_ci	 * ~125us (4/32768). To be on the safe side add 200us delay.
238662306a36Sopenharmony_ci	 */
238762306a36Sopenharmony_ci	usleep_range(200, 210);
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	ret = reset_control_deassert(reset);
239062306a36Sopenharmony_ci	if (ret) {
239162306a36Sopenharmony_ci		reset_control_put(reset);
239262306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "core_reset deassert failed\n");
239362306a36Sopenharmony_ci	}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	usleep_range(200, 210);
239662306a36Sopenharmony_ci	reset_control_put(reset);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	return ret;
239962306a36Sopenharmony_ci}
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_cistatic int sdhci_msm_probe(struct platform_device *pdev)
240262306a36Sopenharmony_ci{
240362306a36Sopenharmony_ci	struct sdhci_host *host;
240462306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host;
240562306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host;
240662306a36Sopenharmony_ci	struct clk *clk;
240762306a36Sopenharmony_ci	int ret;
240862306a36Sopenharmony_ci	u16 host_version, core_minor;
240962306a36Sopenharmony_ci	u32 core_version, config;
241062306a36Sopenharmony_ci	u8 core_major;
241162306a36Sopenharmony_ci	const struct sdhci_msm_offset *msm_offset;
241262306a36Sopenharmony_ci	const struct sdhci_msm_variant_info *var_info;
241362306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
241662306a36Sopenharmony_ci	if (IS_ERR(host))
241762306a36Sopenharmony_ci		return PTR_ERR(host);
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	host->sdma_boundary = 0;
242062306a36Sopenharmony_ci	pltfm_host = sdhci_priv(host);
242162306a36Sopenharmony_ci	msm_host = sdhci_pltfm_priv(pltfm_host);
242262306a36Sopenharmony_ci	msm_host->mmc = host->mmc;
242362306a36Sopenharmony_ci	msm_host->pdev = pdev;
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	ret = mmc_of_parse(host->mmc);
242662306a36Sopenharmony_ci	if (ret)
242762306a36Sopenharmony_ci		goto pltfm_free;
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	/*
243062306a36Sopenharmony_ci	 * Based on the compatible string, load the required msm host info from
243162306a36Sopenharmony_ci	 * the data associated with the version info.
243262306a36Sopenharmony_ci	 */
243362306a36Sopenharmony_ci	var_info = of_device_get_match_data(&pdev->dev);
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	msm_host->mci_removed = var_info->mci_removed;
243662306a36Sopenharmony_ci	msm_host->restore_dll_config = var_info->restore_dll_config;
243762306a36Sopenharmony_ci	msm_host->var_ops = var_info->var_ops;
243862306a36Sopenharmony_ci	msm_host->offset = var_info->offset;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	msm_offset = msm_host->offset;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	sdhci_get_of_property(pdev);
244362306a36Sopenharmony_ci	sdhci_msm_get_of_property(pdev, host);
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	msm_host->saved_tuning_phase = INVALID_TUNING_PHASE;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	ret = sdhci_msm_gcc_reset(&pdev->dev, host);
244862306a36Sopenharmony_ci	if (ret)
244962306a36Sopenharmony_ci		goto pltfm_free;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	/* Setup SDCC bus voter clock. */
245262306a36Sopenharmony_ci	msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
245362306a36Sopenharmony_ci	if (!IS_ERR(msm_host->bus_clk)) {
245462306a36Sopenharmony_ci		/* Vote for max. clk rate for max. performance */
245562306a36Sopenharmony_ci		ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
245662306a36Sopenharmony_ci		if (ret)
245762306a36Sopenharmony_ci			goto pltfm_free;
245862306a36Sopenharmony_ci		ret = clk_prepare_enable(msm_host->bus_clk);
245962306a36Sopenharmony_ci		if (ret)
246062306a36Sopenharmony_ci			goto pltfm_free;
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	/* Setup main peripheral bus clock */
246462306a36Sopenharmony_ci	clk = devm_clk_get(&pdev->dev, "iface");
246562306a36Sopenharmony_ci	if (IS_ERR(clk)) {
246662306a36Sopenharmony_ci		ret = PTR_ERR(clk);
246762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
246862306a36Sopenharmony_ci		goto bus_clk_disable;
246962306a36Sopenharmony_ci	}
247062306a36Sopenharmony_ci	msm_host->bulk_clks[1].clk = clk;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	/* Setup SDC MMC clock */
247362306a36Sopenharmony_ci	clk = devm_clk_get(&pdev->dev, "core");
247462306a36Sopenharmony_ci	if (IS_ERR(clk)) {
247562306a36Sopenharmony_ci		ret = PTR_ERR(clk);
247662306a36Sopenharmony_ci		dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
247762306a36Sopenharmony_ci		goto bus_clk_disable;
247862306a36Sopenharmony_ci	}
247962306a36Sopenharmony_ci	msm_host->bulk_clks[0].clk = clk;
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	 /* Check for optional interconnect paths */
248262306a36Sopenharmony_ci	ret = dev_pm_opp_of_find_icc_paths(&pdev->dev, NULL);
248362306a36Sopenharmony_ci	if (ret)
248462306a36Sopenharmony_ci		goto bus_clk_disable;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	ret = devm_pm_opp_set_clkname(&pdev->dev, "core");
248762306a36Sopenharmony_ci	if (ret)
248862306a36Sopenharmony_ci		goto bus_clk_disable;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	/* OPP table is optional */
249162306a36Sopenharmony_ci	ret = devm_pm_opp_of_add_table(&pdev->dev);
249262306a36Sopenharmony_ci	if (ret && ret != -ENODEV) {
249362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Invalid OPP table in Device tree\n");
249462306a36Sopenharmony_ci		goto bus_clk_disable;
249562306a36Sopenharmony_ci	}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	/* Vote for maximum clock rate for maximum performance */
249862306a36Sopenharmony_ci	ret = dev_pm_opp_set_rate(&pdev->dev, INT_MAX);
249962306a36Sopenharmony_ci	if (ret)
250062306a36Sopenharmony_ci		dev_warn(&pdev->dev, "core clock boost failed\n");
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	clk = devm_clk_get(&pdev->dev, "cal");
250362306a36Sopenharmony_ci	if (IS_ERR(clk))
250462306a36Sopenharmony_ci		clk = NULL;
250562306a36Sopenharmony_ci	msm_host->bulk_clks[2].clk = clk;
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	clk = devm_clk_get(&pdev->dev, "sleep");
250862306a36Sopenharmony_ci	if (IS_ERR(clk))
250962306a36Sopenharmony_ci		clk = NULL;
251062306a36Sopenharmony_ci	msm_host->bulk_clks[3].clk = clk;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
251362306a36Sopenharmony_ci				      msm_host->bulk_clks);
251462306a36Sopenharmony_ci	if (ret)
251562306a36Sopenharmony_ci		goto bus_clk_disable;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	/*
251862306a36Sopenharmony_ci	 * xo clock is needed for FLL feature of cm_dll.
251962306a36Sopenharmony_ci	 * In case if xo clock is not mentioned in DT, warn and proceed.
252062306a36Sopenharmony_ci	 */
252162306a36Sopenharmony_ci	msm_host->xo_clk = devm_clk_get(&pdev->dev, "xo");
252262306a36Sopenharmony_ci	if (IS_ERR(msm_host->xo_clk)) {
252362306a36Sopenharmony_ci		ret = PTR_ERR(msm_host->xo_clk);
252462306a36Sopenharmony_ci		dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret);
252562306a36Sopenharmony_ci	}
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (!msm_host->mci_removed) {
252862306a36Sopenharmony_ci		msm_host->core_mem = devm_platform_ioremap_resource(pdev, 1);
252962306a36Sopenharmony_ci		if (IS_ERR(msm_host->core_mem)) {
253062306a36Sopenharmony_ci			ret = PTR_ERR(msm_host->core_mem);
253162306a36Sopenharmony_ci			goto clk_disable;
253262306a36Sopenharmony_ci		}
253362306a36Sopenharmony_ci	}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	/* Reset the vendor spec register to power on reset state */
253662306a36Sopenharmony_ci	writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
253762306a36Sopenharmony_ci			host->ioaddr + msm_offset->core_vendor_spec);
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci	if (!msm_host->mci_removed) {
254062306a36Sopenharmony_ci		/* Set HC_MODE_EN bit in HC_MODE register */
254162306a36Sopenharmony_ci		msm_host_writel(msm_host, HC_MODE_EN, host,
254262306a36Sopenharmony_ci				msm_offset->core_hc_mode);
254362306a36Sopenharmony_ci		config = msm_host_readl(msm_host, host,
254462306a36Sopenharmony_ci				msm_offset->core_hc_mode);
254562306a36Sopenharmony_ci		config |= FF_CLK_SW_RST_DIS;
254662306a36Sopenharmony_ci		msm_host_writel(msm_host, config, host,
254762306a36Sopenharmony_ci				msm_offset->core_hc_mode);
254862306a36Sopenharmony_ci	}
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
255162306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
255262306a36Sopenharmony_ci		host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
255362306a36Sopenharmony_ci			       SDHCI_VENDOR_VER_SHIFT));
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	core_version = msm_host_readl(msm_host, host,
255662306a36Sopenharmony_ci			msm_offset->core_mci_version);
255762306a36Sopenharmony_ci	core_major = (core_version & CORE_VERSION_MAJOR_MASK) >>
255862306a36Sopenharmony_ci		      CORE_VERSION_MAJOR_SHIFT;
255962306a36Sopenharmony_ci	core_minor = core_version & CORE_VERSION_MINOR_MASK;
256062306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
256162306a36Sopenharmony_ci		core_version, core_major, core_minor);
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	if (core_major == 1 && core_minor >= 0x42)
256462306a36Sopenharmony_ci		msm_host->use_14lpp_dll_reset = true;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	/*
256762306a36Sopenharmony_ci	 * SDCC 5 controller with major version 1, minor version 0x34 and later
256862306a36Sopenharmony_ci	 * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL.
256962306a36Sopenharmony_ci	 */
257062306a36Sopenharmony_ci	if (core_major == 1 && core_minor < 0x34)
257162306a36Sopenharmony_ci		msm_host->use_cdclp533 = true;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	/*
257462306a36Sopenharmony_ci	 * Support for some capabilities is not advertised by newer
257562306a36Sopenharmony_ci	 * controller versions and must be explicitly enabled.
257662306a36Sopenharmony_ci	 */
257762306a36Sopenharmony_ci	if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) {
257862306a36Sopenharmony_ci		config = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES);
257962306a36Sopenharmony_ci		config |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT;
258062306a36Sopenharmony_ci		writel_relaxed(config, host->ioaddr +
258162306a36Sopenharmony_ci				msm_offset->core_vendor_spec_capabilities0);
258262306a36Sopenharmony_ci	}
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	if (core_major == 1 && core_minor >= 0x49)
258562306a36Sopenharmony_ci		msm_host->updated_ddr_cfg = true;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	if (core_major == 1 && core_minor >= 0x71)
258862306a36Sopenharmony_ci		msm_host->uses_tassadar_dll = true;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	ret = sdhci_msm_register_vreg(msm_host);
259162306a36Sopenharmony_ci	if (ret)
259262306a36Sopenharmony_ci		goto clk_disable;
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	/*
259562306a36Sopenharmony_ci	 * Power on reset state may trigger power irq if previous status of
259662306a36Sopenharmony_ci	 * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
259762306a36Sopenharmony_ci	 * interrupt in GIC, any pending power irq interrupt should be
259862306a36Sopenharmony_ci	 * acknowledged. Otherwise power irq interrupt handler would be
259962306a36Sopenharmony_ci	 * fired prematurely.
260062306a36Sopenharmony_ci	 */
260162306a36Sopenharmony_ci	sdhci_msm_handle_pwr_irq(host, 0);
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	/*
260462306a36Sopenharmony_ci	 * Ensure that above writes are propogated before interrupt enablement
260562306a36Sopenharmony_ci	 * in GIC.
260662306a36Sopenharmony_ci	 */
260762306a36Sopenharmony_ci	mb();
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	/* Setup IRQ for handling power/voltage tasks with PMIC */
261062306a36Sopenharmony_ci	msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
261162306a36Sopenharmony_ci	if (msm_host->pwr_irq < 0) {
261262306a36Sopenharmony_ci		ret = msm_host->pwr_irq;
261362306a36Sopenharmony_ci		goto clk_disable;
261462306a36Sopenharmony_ci	}
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	sdhci_msm_init_pwr_irq_wait(msm_host);
261762306a36Sopenharmony_ci	/* Enable pwr irq interrupts */
261862306a36Sopenharmony_ci	msm_host_writel(msm_host, INT_MASK, host,
261962306a36Sopenharmony_ci		msm_offset->core_pwrctl_mask);
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
262262306a36Sopenharmony_ci					sdhci_msm_pwr_irq, IRQF_ONESHOT,
262362306a36Sopenharmony_ci					dev_name(&pdev->dev), host);
262462306a36Sopenharmony_ci	if (ret) {
262562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
262662306a36Sopenharmony_ci		goto clk_disable;
262762306a36Sopenharmony_ci	}
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	msm_host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	/* Set the timeout value to max possible */
263262306a36Sopenharmony_ci	host->max_timeout_count = 0xF;
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	pm_runtime_get_noresume(&pdev->dev);
263562306a36Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
263662306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
263762306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev,
263862306a36Sopenharmony_ci					 MSM_MMC_AUTOSUSPEND_DELAY_MS);
263962306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	host->mmc_host_ops.start_signal_voltage_switch =
264262306a36Sopenharmony_ci		sdhci_msm_start_signal_voltage_switch;
264362306a36Sopenharmony_ci	host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning;
264462306a36Sopenharmony_ci	if (of_property_read_bool(node, "supports-cqe"))
264562306a36Sopenharmony_ci		ret = sdhci_msm_cqe_add_host(host, pdev);
264662306a36Sopenharmony_ci	else
264762306a36Sopenharmony_ci		ret = sdhci_add_host(host);
264862306a36Sopenharmony_ci	if (ret)
264962306a36Sopenharmony_ci		goto pm_runtime_disable;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&pdev->dev);
265262306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&pdev->dev);
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	return 0;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_cipm_runtime_disable:
265762306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
265862306a36Sopenharmony_ci	pm_runtime_set_suspended(&pdev->dev);
265962306a36Sopenharmony_ci	pm_runtime_put_noidle(&pdev->dev);
266062306a36Sopenharmony_ciclk_disable:
266162306a36Sopenharmony_ci	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
266262306a36Sopenharmony_ci				   msm_host->bulk_clks);
266362306a36Sopenharmony_cibus_clk_disable:
266462306a36Sopenharmony_ci	if (!IS_ERR(msm_host->bus_clk))
266562306a36Sopenharmony_ci		clk_disable_unprepare(msm_host->bus_clk);
266662306a36Sopenharmony_cipltfm_free:
266762306a36Sopenharmony_ci	sdhci_pltfm_free(pdev);
266862306a36Sopenharmony_ci	return ret;
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_cistatic void sdhci_msm_remove(struct platform_device *pdev)
267262306a36Sopenharmony_ci{
267362306a36Sopenharmony_ci	struct sdhci_host *host = platform_get_drvdata(pdev);
267462306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
267562306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
267662306a36Sopenharmony_ci	int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
267762306a36Sopenharmony_ci		    0xffffffff);
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	sdhci_remove_host(host, dead);
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
268262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
268362306a36Sopenharmony_ci	pm_runtime_put_noidle(&pdev->dev);
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
268662306a36Sopenharmony_ci				   msm_host->bulk_clks);
268762306a36Sopenharmony_ci	if (!IS_ERR(msm_host->bus_clk))
268862306a36Sopenharmony_ci		clk_disable_unprepare(msm_host->bus_clk);
268962306a36Sopenharmony_ci	sdhci_pltfm_free(pdev);
269062306a36Sopenharmony_ci}
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_cistatic __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
269362306a36Sopenharmony_ci{
269462306a36Sopenharmony_ci	struct sdhci_host *host = dev_get_drvdata(dev);
269562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
269662306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	/* Drop the performance vote */
269962306a36Sopenharmony_ci	dev_pm_opp_set_rate(dev, 0);
270062306a36Sopenharmony_ci	clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
270162306a36Sopenharmony_ci				   msm_host->bulk_clks);
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	return sdhci_msm_ice_suspend(msm_host);
270462306a36Sopenharmony_ci}
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_cistatic __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
270762306a36Sopenharmony_ci{
270862306a36Sopenharmony_ci	struct sdhci_host *host = dev_get_drvdata(dev);
270962306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
271062306a36Sopenharmony_ci	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
271162306a36Sopenharmony_ci	int ret;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
271462306a36Sopenharmony_ci				       msm_host->bulk_clks);
271562306a36Sopenharmony_ci	if (ret)
271662306a36Sopenharmony_ci		return ret;
271762306a36Sopenharmony_ci	/*
271862306a36Sopenharmony_ci	 * Whenever core-clock is gated dynamically, it's needed to
271962306a36Sopenharmony_ci	 * restore the SDR DLL settings when the clock is ungated.
272062306a36Sopenharmony_ci	 */
272162306a36Sopenharmony_ci	if (msm_host->restore_dll_config && msm_host->clk_rate) {
272262306a36Sopenharmony_ci		ret = sdhci_msm_restore_sdr_dll_config(host);
272362306a36Sopenharmony_ci		if (ret)
272462306a36Sopenharmony_ci			return ret;
272562306a36Sopenharmony_ci	}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	dev_pm_opp_set_rate(dev, msm_host->clk_rate);
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	return sdhci_msm_ice_resume(msm_host);
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_cistatic const struct dev_pm_ops sdhci_msm_pm_ops = {
273362306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
273462306a36Sopenharmony_ci				pm_runtime_force_resume)
273562306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend,
273662306a36Sopenharmony_ci			   sdhci_msm_runtime_resume,
273762306a36Sopenharmony_ci			   NULL)
273862306a36Sopenharmony_ci};
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_cistatic struct platform_driver sdhci_msm_driver = {
274162306a36Sopenharmony_ci	.probe = sdhci_msm_probe,
274262306a36Sopenharmony_ci	.remove_new = sdhci_msm_remove,
274362306a36Sopenharmony_ci	.driver = {
274462306a36Sopenharmony_ci		   .name = "sdhci_msm",
274562306a36Sopenharmony_ci		   .of_match_table = sdhci_msm_dt_match,
274662306a36Sopenharmony_ci		   .pm = &sdhci_msm_pm_ops,
274762306a36Sopenharmony_ci		   .probe_type = PROBE_PREFER_ASYNCHRONOUS,
274862306a36Sopenharmony_ci	},
274962306a36Sopenharmony_ci};
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_cimodule_platform_driver(sdhci_msm_driver);
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
275462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2755