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