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