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> 13415b5a75SGeorgi Djakov #include <linux/slab.h> 14cc392c58SRitesh Harjani #include <linux/iopoll.h> 15ac06fba1SVijay Viswanath #include <linux/regulator/consumer.h> 160eb0d9f4SGeorgi Djakov 170eb0d9f4SGeorgi Djakov #include "sdhci-pltfm.h" 180eb0d9f4SGeorgi Djakov 193a3ad3e9SGeorgi Djakov #define CORE_MCI_VERSION 0x50 203a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_SHIFT 28 213a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_MASK (0xf << CORE_VERSION_MAJOR_SHIFT) 223a3ad3e9SGeorgi Djakov #define CORE_VERSION_MINOR_MASK 0xff 233a3ad3e9SGeorgi Djakov 2452884f8fSBjorn Andersson #define CORE_MCI_GENERICS 0x70 2552884f8fSBjorn Andersson #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) 2652884f8fSBjorn Andersson 270eb0d9f4SGeorgi Djakov #define HC_MODE_EN 0x1 280eb0d9f4SGeorgi Djakov #define CORE_POWER 0x0 290eb0d9f4SGeorgi Djakov #define CORE_SW_RST BIT(7) 30ff06ce41SVenkat Gopalakrishnan #define FF_CLK_SW_RST_DIS BIT(13) 310eb0d9f4SGeorgi Djakov 32ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_OFF BIT(0) 33ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_ON BIT(1) 34ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_LOW BIT(2) 35ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_HIGH BIT(3) 36ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_SUCCESS BIT(0) 37ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_SUCCESS BIT(2) 38ad81d387SGeorgi Djakov #define REQ_BUS_OFF BIT(0) 39ad81d387SGeorgi Djakov #define REQ_BUS_ON BIT(1) 40ad81d387SGeorgi Djakov #define REQ_IO_LOW BIT(2) 41ad81d387SGeorgi Djakov #define REQ_IO_HIGH BIT(3) 42ad81d387SGeorgi Djakov #define INT_MASK 0xf 43415b5a75SGeorgi Djakov #define MAX_PHASES 16 44415b5a75SGeorgi Djakov #define CORE_DLL_LOCK BIT(7) 4502e4293dSRitesh Harjani #define CORE_DDR_DLL_LOCK BIT(11) 46415b5a75SGeorgi Djakov #define CORE_DLL_EN BIT(16) 47415b5a75SGeorgi Djakov #define CORE_CDR_EN BIT(17) 48415b5a75SGeorgi Djakov #define CORE_CK_OUT_EN BIT(18) 49415b5a75SGeorgi Djakov #define CORE_CDR_EXT_EN BIT(19) 50415b5a75SGeorgi Djakov #define CORE_DLL_PDN BIT(29) 51415b5a75SGeorgi Djakov #define CORE_DLL_RST BIT(30) 52cc392c58SRitesh Harjani #define CORE_CMD_DAT_TRACK_SEL BIT(0) 53415b5a75SGeorgi Djakov 5402e4293dSRitesh Harjani #define CORE_DDR_CAL_EN BIT(0) 5583736352SVenkat Gopalakrishnan #define CORE_FLL_CYCLE_CNT BIT(18) 5683736352SVenkat Gopalakrishnan #define CORE_DLL_CLOCK_DISABLE BIT(21) 5783736352SVenkat Gopalakrishnan 585574ddccSVenkat Gopalakrishnan #define CORE_VENDOR_SPEC_POR_VAL 0xa1c 59415b5a75SGeorgi Djakov #define CORE_CLK_PWRSAVE BIT(1) 60ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_DFLT (2 << 8) 61ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_HS400 (3 << 8) 62ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_MASK (3 << 8) 635c132323SVijay Viswanath #define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) 645c132323SVijay Viswanath #define CORE_IO_PAD_PWR_SWITCH (1 << 16) 65ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_EN BIT(18) 66ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_HS400 (6 << 19) 67ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_MASK (7 << 19) 68415b5a75SGeorgi Djakov 69ac06fba1SVijay Viswanath #define CORE_3_0V_SUPPORT (1 << 25) 70ac06fba1SVijay Viswanath #define CORE_1_8V_SUPPORT (1 << 26) 715c132323SVijay Viswanath #define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) 72ac06fba1SVijay Viswanath 73cc392c58SRitesh Harjani #define CORE_CSR_CDC_CTLR_CFG0 0x130 74cc392c58SRitesh Harjani #define CORE_SW_TRIG_FULL_CALIB BIT(16) 75cc392c58SRitesh Harjani #define CORE_HW_AUTOCAL_ENA BIT(17) 76cc392c58SRitesh Harjani 77cc392c58SRitesh Harjani #define CORE_CSR_CDC_CTLR_CFG1 0x134 78cc392c58SRitesh Harjani #define CORE_CSR_CDC_CAL_TIMER_CFG0 0x138 79cc392c58SRitesh Harjani #define CORE_TIMER_ENA BIT(16) 80cc392c58SRitesh Harjani 81cc392c58SRitesh Harjani #define CORE_CSR_CDC_CAL_TIMER_CFG1 0x13C 82cc392c58SRitesh Harjani #define CORE_CSR_CDC_REFCOUNT_CFG 0x140 83cc392c58SRitesh Harjani #define CORE_CSR_CDC_COARSE_CAL_CFG 0x144 84cc392c58SRitesh Harjani #define CORE_CDC_OFFSET_CFG 0x14C 85cc392c58SRitesh Harjani #define CORE_CSR_CDC_DELAY_CFG 0x150 86cc392c58SRitesh Harjani #define CORE_CDC_SLAVE_DDA_CFG 0x160 87cc392c58SRitesh Harjani #define CORE_CSR_CDC_STATUS0 0x164 88cc392c58SRitesh Harjani #define CORE_CALIBRATION_DONE BIT(0) 89cc392c58SRitesh Harjani 90cc392c58SRitesh Harjani #define CORE_CDC_ERROR_CODE_MASK 0x7000000 91cc392c58SRitesh Harjani 92cc392c58SRitesh Harjani #define CORE_CSR_CDC_GEN_CFG 0x178 93cc392c58SRitesh Harjani #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) 94cc392c58SRitesh Harjani #define CORE_CDC_SWITCH_RC_EN BIT(1) 95cc392c58SRitesh Harjani 96cc392c58SRitesh Harjani #define CORE_CDC_T4_DLY_SEL BIT(0) 9744bf2312SRitesh Harjani #define CORE_CMDIN_RCLK_EN BIT(1) 98cc392c58SRitesh Harjani #define CORE_START_CDC_TRAFFIC BIT(6) 99bc99266bSSayali Lokhande 10002e4293dSRitesh Harjani #define CORE_PWRSAVE_DLL BIT(3) 10102e4293dSRitesh Harjani 10202e4293dSRitesh Harjani #define DDR_CONFIG_POR_VAL 0x80040853 103cc392c58SRitesh Harjani 1043a3ad3e9SGeorgi Djakov 105abf270e5SRitesh Harjani #define INVALID_TUNING_PHASE -1 10680031bdeSRitesh Harjani #define SDHCI_MSM_MIN_CLOCK 400000 107ff06ce41SVenkat Gopalakrishnan #define CORE_FREQ_100MHZ (100 * 1000 * 1000) 10880031bdeSRitesh Harjani 109415b5a75SGeorgi Djakov #define CDR_SELEXT_SHIFT 20 110415b5a75SGeorgi Djakov #define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT) 111415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_SHIFT 24 112415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_MASK (7 << CMUX_SHIFT_PHASE_SHIFT) 113415b5a75SGeorgi Djakov 11467e6db11SPramod Gurav #define MSM_MMC_AUTOSUSPEND_DELAY_MS 50 115c0309b38SVijay Viswanath 116c0309b38SVijay Viswanath /* Timeout value to avoid infinite waiting for pwr_irq */ 117c0309b38SVijay Viswanath #define MSM_PWR_IRQ_TIMEOUT_MS 5000 118c0309b38SVijay Viswanath 119bc99266bSSayali Lokhande #define msm_host_readl(msm_host, host, offset) \ 120bc99266bSSayali Lokhande msm_host->var_ops->msm_readl_relaxed(host, offset) 121bc99266bSSayali Lokhande 122bc99266bSSayali Lokhande #define msm_host_writel(msm_host, val, host, offset) \ 123bc99266bSSayali Lokhande msm_host->var_ops->msm_writel_relaxed(val, host, offset) 124bc99266bSSayali Lokhande 125f1535888SSayali Lokhande struct sdhci_msm_offset { 126f1535888SSayali Lokhande u32 core_hc_mode; 127f1535888SSayali Lokhande u32 core_mci_data_cnt; 128f1535888SSayali Lokhande u32 core_mci_status; 129f1535888SSayali Lokhande u32 core_mci_fifo_cnt; 130f1535888SSayali Lokhande u32 core_mci_version; 131f1535888SSayali Lokhande u32 core_generics; 132f1535888SSayali Lokhande u32 core_testbus_config; 133f1535888SSayali Lokhande u32 core_testbus_sel2_bit; 134f1535888SSayali Lokhande u32 core_testbus_ena; 135f1535888SSayali Lokhande u32 core_testbus_sel2; 136f1535888SSayali Lokhande u32 core_pwrctl_status; 137f1535888SSayali Lokhande u32 core_pwrctl_mask; 138f1535888SSayali Lokhande u32 core_pwrctl_clear; 139f1535888SSayali Lokhande u32 core_pwrctl_ctl; 140f1535888SSayali Lokhande u32 core_sdcc_debug_reg; 141f1535888SSayali Lokhande u32 core_dll_config; 142f1535888SSayali Lokhande u32 core_dll_status; 143f1535888SSayali Lokhande u32 core_vendor_spec; 144f1535888SSayali Lokhande u32 core_vendor_spec_adma_err_addr0; 145f1535888SSayali Lokhande u32 core_vendor_spec_adma_err_addr1; 146f1535888SSayali Lokhande u32 core_vendor_spec_func2; 147f1535888SSayali Lokhande u32 core_vendor_spec_capabilities0; 148f1535888SSayali Lokhande u32 core_ddr_200_cfg; 149f1535888SSayali Lokhande u32 core_vendor_spec3; 150f1535888SSayali Lokhande u32 core_dll_config_2; 151f1535888SSayali Lokhande u32 core_ddr_config; 152f1535888SSayali Lokhande u32 core_ddr_config_2; 153f1535888SSayali Lokhande }; 154f1535888SSayali Lokhande 155f1535888SSayali Lokhande static const struct sdhci_msm_offset sdhci_msm_v5_offset = { 156f1535888SSayali Lokhande .core_mci_data_cnt = 0x35c, 157f1535888SSayali Lokhande .core_mci_status = 0x324, 158f1535888SSayali Lokhande .core_mci_fifo_cnt = 0x308, 159f1535888SSayali Lokhande .core_mci_version = 0x318, 160f1535888SSayali Lokhande .core_generics = 0x320, 161f1535888SSayali Lokhande .core_testbus_config = 0x32c, 162f1535888SSayali Lokhande .core_testbus_sel2_bit = 3, 163f1535888SSayali Lokhande .core_testbus_ena = (1 << 31), 164f1535888SSayali Lokhande .core_testbus_sel2 = (1 << 3), 165f1535888SSayali Lokhande .core_pwrctl_status = 0x240, 166f1535888SSayali Lokhande .core_pwrctl_mask = 0x244, 167f1535888SSayali Lokhande .core_pwrctl_clear = 0x248, 168f1535888SSayali Lokhande .core_pwrctl_ctl = 0x24c, 169f1535888SSayali Lokhande .core_sdcc_debug_reg = 0x358, 170f1535888SSayali Lokhande .core_dll_config = 0x200, 171f1535888SSayali Lokhande .core_dll_status = 0x208, 172f1535888SSayali Lokhande .core_vendor_spec = 0x20c, 173f1535888SSayali Lokhande .core_vendor_spec_adma_err_addr0 = 0x214, 174f1535888SSayali Lokhande .core_vendor_spec_adma_err_addr1 = 0x218, 175f1535888SSayali Lokhande .core_vendor_spec_func2 = 0x210, 176f1535888SSayali Lokhande .core_vendor_spec_capabilities0 = 0x21c, 177f1535888SSayali Lokhande .core_ddr_200_cfg = 0x224, 178f1535888SSayali Lokhande .core_vendor_spec3 = 0x250, 179f1535888SSayali Lokhande .core_dll_config_2 = 0x254, 180f1535888SSayali Lokhande .core_ddr_config = 0x258, 181f1535888SSayali Lokhande .core_ddr_config_2 = 0x25c, 182f1535888SSayali Lokhande }; 183f1535888SSayali Lokhande 184f1535888SSayali Lokhande static const struct sdhci_msm_offset sdhci_msm_mci_offset = { 185f1535888SSayali Lokhande .core_hc_mode = 0x78, 186f1535888SSayali Lokhande .core_mci_data_cnt = 0x30, 187f1535888SSayali Lokhande .core_mci_status = 0x34, 188f1535888SSayali Lokhande .core_mci_fifo_cnt = 0x44, 189f1535888SSayali Lokhande .core_mci_version = 0x050, 190f1535888SSayali Lokhande .core_generics = 0x70, 191f1535888SSayali Lokhande .core_testbus_config = 0x0cc, 192f1535888SSayali Lokhande .core_testbus_sel2_bit = 4, 193f1535888SSayali Lokhande .core_testbus_ena = (1 << 3), 194f1535888SSayali Lokhande .core_testbus_sel2 = (1 << 4), 195f1535888SSayali Lokhande .core_pwrctl_status = 0xdc, 196f1535888SSayali Lokhande .core_pwrctl_mask = 0xe0, 197f1535888SSayali Lokhande .core_pwrctl_clear = 0xe4, 198f1535888SSayali Lokhande .core_pwrctl_ctl = 0xe8, 199f1535888SSayali Lokhande .core_sdcc_debug_reg = 0x124, 200f1535888SSayali Lokhande .core_dll_config = 0x100, 201f1535888SSayali Lokhande .core_dll_status = 0x108, 202f1535888SSayali Lokhande .core_vendor_spec = 0x10c, 203f1535888SSayali Lokhande .core_vendor_spec_adma_err_addr0 = 0x114, 204f1535888SSayali Lokhande .core_vendor_spec_adma_err_addr1 = 0x118, 205f1535888SSayali Lokhande .core_vendor_spec_func2 = 0x110, 206f1535888SSayali Lokhande .core_vendor_spec_capabilities0 = 0x11c, 207f1535888SSayali Lokhande .core_ddr_200_cfg = 0x184, 208f1535888SSayali Lokhande .core_vendor_spec3 = 0x1b0, 209f1535888SSayali Lokhande .core_dll_config_2 = 0x1b4, 210f1535888SSayali Lokhande .core_ddr_config = 0x1b8, 211f1535888SSayali Lokhande .core_ddr_config_2 = 0x1bc, 212f1535888SSayali Lokhande }; 213f1535888SSayali Lokhande 2146ed4bb43SVijay Viswanath struct sdhci_msm_variant_ops { 2156ed4bb43SVijay Viswanath u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); 2166ed4bb43SVijay Viswanath void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, 2176ed4bb43SVijay Viswanath u32 offset); 2186ed4bb43SVijay Viswanath }; 2196ed4bb43SVijay Viswanath 2206ed4bb43SVijay Viswanath /* 2216ed4bb43SVijay Viswanath * From V5, register spaces have changed. Wrap this info in a structure 2226ed4bb43SVijay Viswanath * and choose the data_structure based on version info mentioned in DT. 2236ed4bb43SVijay Viswanath */ 2246ed4bb43SVijay Viswanath struct sdhci_msm_variant_info { 2256ed4bb43SVijay Viswanath bool mci_removed; 22621f1e2d4SVeerabhadrarao Badiganti bool restore_dll_config; 2276ed4bb43SVijay Viswanath const struct sdhci_msm_variant_ops *var_ops; 2286ed4bb43SVijay Viswanath const struct sdhci_msm_offset *offset; 2296ed4bb43SVijay Viswanath }; 2306ed4bb43SVijay Viswanath 2310eb0d9f4SGeorgi Djakov struct sdhci_msm_host { 2320eb0d9f4SGeorgi Djakov struct platform_device *pdev; 2330eb0d9f4SGeorgi Djakov void __iomem *core_mem; /* MSM SDCC mapped address */ 234ad81d387SGeorgi Djakov int pwr_irq; /* power irq */ 2350eb0d9f4SGeorgi Djakov struct clk *bus_clk; /* SDHC bus voter clock */ 23683736352SVenkat Gopalakrishnan struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/ 2374946b3afSBjorn Andersson struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */ 238edc609fdSRitesh Harjani unsigned long clk_rate; 2390eb0d9f4SGeorgi Djakov struct mmc_host *mmc; 24083736352SVenkat Gopalakrishnan bool use_14lpp_dll_reset; 241ff06ce41SVenkat Gopalakrishnan bool tuning_done; 242ff06ce41SVenkat Gopalakrishnan bool calibration_done; 243abf270e5SRitesh Harjani u8 saved_tuning_phase; 24402e4293dSRitesh Harjani bool use_cdclp533; 245c0309b38SVijay Viswanath u32 curr_pwr_state; 246c0309b38SVijay Viswanath u32 curr_io_level; 247c0309b38SVijay Viswanath wait_queue_head_t pwr_irq_wait; 248c0309b38SVijay Viswanath bool pwr_irq_flag; 249ac06fba1SVijay Viswanath u32 caps_0; 2506ed4bb43SVijay Viswanath bool mci_removed; 25121f1e2d4SVeerabhadrarao Badiganti bool restore_dll_config; 2526ed4bb43SVijay Viswanath const struct sdhci_msm_variant_ops *var_ops; 2536ed4bb43SVijay Viswanath const struct sdhci_msm_offset *offset; 254a89e7bcbSLoic Poulain bool use_cdr; 255a89e7bcbSLoic Poulain u32 transfer_mode; 2560eb0d9f4SGeorgi Djakov }; 2570eb0d9f4SGeorgi Djakov 258bc99266bSSayali Lokhande static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) 259bc99266bSSayali Lokhande { 260bc99266bSSayali Lokhande struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 261bc99266bSSayali Lokhande struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 262bc99266bSSayali Lokhande 263bc99266bSSayali Lokhande return msm_host->offset; 264bc99266bSSayali Lokhande } 265bc99266bSSayali Lokhande 2666ed4bb43SVijay Viswanath /* 2676ed4bb43SVijay Viswanath * APIs to read/write to vendor specific registers which were there in the 2686ed4bb43SVijay Viswanath * core_mem region before MCI was removed. 2696ed4bb43SVijay Viswanath */ 2706ed4bb43SVijay Viswanath static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, 2716ed4bb43SVijay Viswanath u32 offset) 2726ed4bb43SVijay Viswanath { 2736ed4bb43SVijay Viswanath struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2746ed4bb43SVijay Viswanath struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 2756ed4bb43SVijay Viswanath 2766ed4bb43SVijay Viswanath return readl_relaxed(msm_host->core_mem + offset); 2776ed4bb43SVijay Viswanath } 2786ed4bb43SVijay Viswanath 2796ed4bb43SVijay Viswanath static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, 2806ed4bb43SVijay Viswanath u32 offset) 2816ed4bb43SVijay Viswanath { 2826ed4bb43SVijay Viswanath return readl_relaxed(host->ioaddr + offset); 2836ed4bb43SVijay Viswanath } 2846ed4bb43SVijay Viswanath 2856ed4bb43SVijay Viswanath static void sdhci_msm_mci_variant_writel_relaxed(u32 val, 2866ed4bb43SVijay Viswanath struct sdhci_host *host, u32 offset) 2876ed4bb43SVijay Viswanath { 2886ed4bb43SVijay Viswanath struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2896ed4bb43SVijay Viswanath struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 2906ed4bb43SVijay Viswanath 2916ed4bb43SVijay Viswanath writel_relaxed(val, msm_host->core_mem + offset); 2926ed4bb43SVijay Viswanath } 2936ed4bb43SVijay Viswanath 2946ed4bb43SVijay Viswanath static void sdhci_msm_v5_variant_writel_relaxed(u32 val, 2956ed4bb43SVijay Viswanath struct sdhci_host *host, u32 offset) 2966ed4bb43SVijay Viswanath { 2976ed4bb43SVijay Viswanath writel_relaxed(val, host->ioaddr + offset); 2986ed4bb43SVijay Viswanath } 2996ed4bb43SVijay Viswanath 3000fb8a3d4SRitesh Harjani static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, 3010fb8a3d4SRitesh Harjani unsigned int clock) 3020fb8a3d4SRitesh Harjani { 3030fb8a3d4SRitesh Harjani struct mmc_ios ios = host->mmc->ios; 3040fb8a3d4SRitesh Harjani /* 3050fb8a3d4SRitesh Harjani * The SDHC requires internal clock frequency to be double the 3060fb8a3d4SRitesh Harjani * actual clock that will be set for DDR mode. The controller 3070fb8a3d4SRitesh Harjani * uses the faster clock(100/400MHz) for some of its parts and 3080fb8a3d4SRitesh Harjani * send the actual required clock (50/200MHz) to the card. 3090fb8a3d4SRitesh Harjani */ 3100fb8a3d4SRitesh Harjani if (ios.timing == MMC_TIMING_UHS_DDR50 || 3110fb8a3d4SRitesh Harjani ios.timing == MMC_TIMING_MMC_DDR52 || 312d7507aa1SRitesh Harjani ios.timing == MMC_TIMING_MMC_HS400 || 313d7507aa1SRitesh Harjani host->flags & SDHCI_HS400_TUNING) 3140fb8a3d4SRitesh Harjani clock *= 2; 3150fb8a3d4SRitesh Harjani return clock; 3160fb8a3d4SRitesh Harjani } 3170fb8a3d4SRitesh Harjani 3180fb8a3d4SRitesh Harjani static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, 3190fb8a3d4SRitesh Harjani unsigned int clock) 3200fb8a3d4SRitesh Harjani { 3210fb8a3d4SRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 3220fb8a3d4SRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 3230fb8a3d4SRitesh Harjani struct mmc_ios curr_ios = host->mmc->ios; 324e4bf91f6SBjorn Andersson struct clk *core_clk = msm_host->bulk_clks[0].clk; 3250fb8a3d4SRitesh Harjani int rc; 3260fb8a3d4SRitesh Harjani 3270fb8a3d4SRitesh Harjani clock = msm_get_clock_rate_for_bus_mode(host, clock); 328e4bf91f6SBjorn Andersson rc = clk_set_rate(core_clk, clock); 3290fb8a3d4SRitesh Harjani if (rc) { 3300fb8a3d4SRitesh Harjani pr_err("%s: Failed to set clock at rate %u at timing %d\n", 3310fb8a3d4SRitesh Harjani mmc_hostname(host->mmc), clock, 3320fb8a3d4SRitesh Harjani curr_ios.timing); 3330fb8a3d4SRitesh Harjani return; 3340fb8a3d4SRitesh Harjani } 3350fb8a3d4SRitesh Harjani msm_host->clk_rate = clock; 3360fb8a3d4SRitesh Harjani pr_debug("%s: Setting clock at rate %lu at timing %d\n", 337e4bf91f6SBjorn Andersson mmc_hostname(host->mmc), clk_get_rate(core_clk), 3380fb8a3d4SRitesh Harjani curr_ios.timing); 3390fb8a3d4SRitesh Harjani } 3400fb8a3d4SRitesh Harjani 3410eb0d9f4SGeorgi Djakov /* Platform specific tuning */ 342415b5a75SGeorgi Djakov static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) 343415b5a75SGeorgi Djakov { 344415b5a75SGeorgi Djakov u32 wait_cnt = 50; 345415b5a75SGeorgi Djakov u8 ck_out_en; 346415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 347bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 348bc99266bSSayali Lokhande sdhci_priv_msm_offset(host); 349415b5a75SGeorgi Djakov 350415b5a75SGeorgi Djakov /* Poll for CK_OUT_EN bit. max. poll time = 50us */ 351bc99266bSSayali Lokhande ck_out_en = !!(readl_relaxed(host->ioaddr + 352bc99266bSSayali Lokhande msm_offset->core_dll_config) & CORE_CK_OUT_EN); 353415b5a75SGeorgi Djakov 354415b5a75SGeorgi Djakov while (ck_out_en != poll) { 355415b5a75SGeorgi Djakov if (--wait_cnt == 0) { 356415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n", 357415b5a75SGeorgi Djakov mmc_hostname(mmc), poll); 358415b5a75SGeorgi Djakov return -ETIMEDOUT; 359415b5a75SGeorgi Djakov } 360415b5a75SGeorgi Djakov udelay(1); 361415b5a75SGeorgi Djakov 362bc99266bSSayali Lokhande ck_out_en = !!(readl_relaxed(host->ioaddr + 363bc99266bSSayali Lokhande msm_offset->core_dll_config) & CORE_CK_OUT_EN); 364415b5a75SGeorgi Djakov } 365415b5a75SGeorgi Djakov 366415b5a75SGeorgi Djakov return 0; 367415b5a75SGeorgi Djakov } 368415b5a75SGeorgi Djakov 369415b5a75SGeorgi Djakov static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) 370415b5a75SGeorgi Djakov { 371415b5a75SGeorgi Djakov int rc; 372415b5a75SGeorgi Djakov static const u8 grey_coded_phase_table[] = { 373415b5a75SGeorgi Djakov 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 374415b5a75SGeorgi Djakov 0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8 375415b5a75SGeorgi Djakov }; 376415b5a75SGeorgi Djakov unsigned long flags; 377415b5a75SGeorgi Djakov u32 config; 378415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 379bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 380bc99266bSSayali Lokhande sdhci_priv_msm_offset(host); 381415b5a75SGeorgi Djakov 382abf270e5SRitesh Harjani if (phase > 0xf) 383abf270e5SRitesh Harjani return -EINVAL; 384abf270e5SRitesh Harjani 385415b5a75SGeorgi Djakov spin_lock_irqsave(&host->lock, flags); 386415b5a75SGeorgi Djakov 387bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); 388415b5a75SGeorgi Djakov config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN); 389415b5a75SGeorgi Djakov config |= (CORE_CDR_EXT_EN | CORE_DLL_EN); 390bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); 391415b5a75SGeorgi Djakov 392415b5a75SGeorgi Djakov /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */ 393415b5a75SGeorgi Djakov rc = msm_dll_poll_ck_out_en(host, 0); 394415b5a75SGeorgi Djakov if (rc) 395415b5a75SGeorgi Djakov goto err_out; 396415b5a75SGeorgi Djakov 397415b5a75SGeorgi Djakov /* 398415b5a75SGeorgi Djakov * Write the selected DLL clock output phase (0 ... 15) 399415b5a75SGeorgi Djakov * to CDR_SELEXT bit field of DLL_CONFIG register. 400415b5a75SGeorgi Djakov */ 401bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); 402415b5a75SGeorgi Djakov config &= ~CDR_SELEXT_MASK; 403415b5a75SGeorgi Djakov config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT; 404bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); 405415b5a75SGeorgi Djakov 406bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); 40729301f40SRitesh Harjani config |= CORE_CK_OUT_EN; 408bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); 409415b5a75SGeorgi Djakov 410415b5a75SGeorgi Djakov /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */ 411415b5a75SGeorgi Djakov rc = msm_dll_poll_ck_out_en(host, 1); 412415b5a75SGeorgi Djakov if (rc) 413415b5a75SGeorgi Djakov goto err_out; 414415b5a75SGeorgi Djakov 415bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); 416415b5a75SGeorgi Djakov config |= CORE_CDR_EN; 417415b5a75SGeorgi Djakov config &= ~CORE_CDR_EXT_EN; 418bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); 419415b5a75SGeorgi Djakov goto out; 420415b5a75SGeorgi Djakov 421415b5a75SGeorgi Djakov err_out: 422415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n", 423415b5a75SGeorgi Djakov mmc_hostname(mmc), phase); 424415b5a75SGeorgi Djakov out: 425415b5a75SGeorgi Djakov spin_unlock_irqrestore(&host->lock, flags); 426415b5a75SGeorgi Djakov return rc; 427415b5a75SGeorgi Djakov } 428415b5a75SGeorgi Djakov 429415b5a75SGeorgi Djakov /* 430415b5a75SGeorgi Djakov * Find out the greatest range of consecuitive selected 431415b5a75SGeorgi Djakov * DLL clock output phases that can be used as sampling 432415b5a75SGeorgi Djakov * setting for SD3.0 UHS-I card read operation (in SDR104 433ff06ce41SVenkat Gopalakrishnan * timing mode) or for eMMC4.5 card read operation (in 434ff06ce41SVenkat Gopalakrishnan * HS400/HS200 timing mode). 435415b5a75SGeorgi Djakov * Select the 3/4 of the range and configure the DLL with the 436415b5a75SGeorgi Djakov * selected DLL clock output phase. 437415b5a75SGeorgi Djakov */ 438415b5a75SGeorgi Djakov 439415b5a75SGeorgi Djakov static int msm_find_most_appropriate_phase(struct sdhci_host *host, 440415b5a75SGeorgi Djakov u8 *phase_table, u8 total_phases) 441415b5a75SGeorgi Djakov { 442415b5a75SGeorgi Djakov int ret; 443415b5a75SGeorgi Djakov u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} }; 444415b5a75SGeorgi Djakov u8 phases_per_row[MAX_PHASES] = { 0 }; 445415b5a75SGeorgi Djakov int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0; 446415b5a75SGeorgi Djakov int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0; 447415b5a75SGeorgi Djakov bool phase_0_found = false, phase_15_found = false; 448415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 449415b5a75SGeorgi Djakov 450415b5a75SGeorgi Djakov if (!total_phases || (total_phases > MAX_PHASES)) { 451415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n", 452415b5a75SGeorgi Djakov mmc_hostname(mmc), total_phases); 453415b5a75SGeorgi Djakov return -EINVAL; 454415b5a75SGeorgi Djakov } 455415b5a75SGeorgi Djakov 456415b5a75SGeorgi Djakov for (cnt = 0; cnt < total_phases; cnt++) { 457415b5a75SGeorgi Djakov ranges[row_index][col_index] = phase_table[cnt]; 458415b5a75SGeorgi Djakov phases_per_row[row_index] += 1; 459415b5a75SGeorgi Djakov col_index++; 460415b5a75SGeorgi Djakov 461415b5a75SGeorgi Djakov if ((cnt + 1) == total_phases) { 462415b5a75SGeorgi Djakov continue; 463415b5a75SGeorgi Djakov /* check if next phase in phase_table is consecutive or not */ 464415b5a75SGeorgi Djakov } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) { 465415b5a75SGeorgi Djakov row_index++; 466415b5a75SGeorgi Djakov col_index = 0; 467415b5a75SGeorgi Djakov } 468415b5a75SGeorgi Djakov } 469415b5a75SGeorgi Djakov 470415b5a75SGeorgi Djakov if (row_index >= MAX_PHASES) 471415b5a75SGeorgi Djakov return -EINVAL; 472415b5a75SGeorgi Djakov 473415b5a75SGeorgi Djakov /* Check if phase-0 is present in first valid window? */ 474415b5a75SGeorgi Djakov if (!ranges[0][0]) { 475415b5a75SGeorgi Djakov phase_0_found = true; 476415b5a75SGeorgi Djakov phase_0_raw_index = 0; 477415b5a75SGeorgi Djakov /* Check if cycle exist between 2 valid windows */ 478415b5a75SGeorgi Djakov for (cnt = 1; cnt <= row_index; cnt++) { 479415b5a75SGeorgi Djakov if (phases_per_row[cnt]) { 480415b5a75SGeorgi Djakov for (i = 0; i < phases_per_row[cnt]; i++) { 481415b5a75SGeorgi Djakov if (ranges[cnt][i] == 15) { 482415b5a75SGeorgi Djakov phase_15_found = true; 483415b5a75SGeorgi Djakov phase_15_raw_index = cnt; 484415b5a75SGeorgi Djakov break; 485415b5a75SGeorgi Djakov } 486415b5a75SGeorgi Djakov } 487415b5a75SGeorgi Djakov } 488415b5a75SGeorgi Djakov } 489415b5a75SGeorgi Djakov } 490415b5a75SGeorgi Djakov 491415b5a75SGeorgi Djakov /* If 2 valid windows form cycle then merge them as single window */ 492415b5a75SGeorgi Djakov if (phase_0_found && phase_15_found) { 493415b5a75SGeorgi Djakov /* number of phases in raw where phase 0 is present */ 494415b5a75SGeorgi Djakov u8 phases_0 = phases_per_row[phase_0_raw_index]; 495415b5a75SGeorgi Djakov /* number of phases in raw where phase 15 is present */ 496415b5a75SGeorgi Djakov u8 phases_15 = phases_per_row[phase_15_raw_index]; 497415b5a75SGeorgi Djakov 498415b5a75SGeorgi Djakov if (phases_0 + phases_15 >= MAX_PHASES) 499415b5a75SGeorgi Djakov /* 500415b5a75SGeorgi Djakov * If there are more than 1 phase windows then total 501415b5a75SGeorgi Djakov * number of phases in both the windows should not be 502415b5a75SGeorgi Djakov * more than or equal to MAX_PHASES. 503415b5a75SGeorgi Djakov */ 504415b5a75SGeorgi Djakov return -EINVAL; 505415b5a75SGeorgi Djakov 506415b5a75SGeorgi Djakov /* Merge 2 cyclic windows */ 507415b5a75SGeorgi Djakov i = phases_15; 508415b5a75SGeorgi Djakov for (cnt = 0; cnt < phases_0; cnt++) { 509415b5a75SGeorgi Djakov ranges[phase_15_raw_index][i] = 510415b5a75SGeorgi Djakov ranges[phase_0_raw_index][cnt]; 511415b5a75SGeorgi Djakov if (++i >= MAX_PHASES) 512415b5a75SGeorgi Djakov break; 513415b5a75SGeorgi Djakov } 514415b5a75SGeorgi Djakov 515415b5a75SGeorgi Djakov phases_per_row[phase_0_raw_index] = 0; 516415b5a75SGeorgi Djakov phases_per_row[phase_15_raw_index] = phases_15 + phases_0; 517415b5a75SGeorgi Djakov } 518415b5a75SGeorgi Djakov 519415b5a75SGeorgi Djakov for (cnt = 0; cnt <= row_index; cnt++) { 520415b5a75SGeorgi Djakov if (phases_per_row[cnt] > curr_max) { 521415b5a75SGeorgi Djakov curr_max = phases_per_row[cnt]; 522415b5a75SGeorgi Djakov selected_row_index = cnt; 523415b5a75SGeorgi Djakov } 524415b5a75SGeorgi Djakov } 525415b5a75SGeorgi Djakov 526415b5a75SGeorgi Djakov i = (curr_max * 3) / 4; 527415b5a75SGeorgi Djakov if (i) 528415b5a75SGeorgi Djakov i--; 529415b5a75SGeorgi Djakov 530415b5a75SGeorgi Djakov ret = ranges[selected_row_index][i]; 531415b5a75SGeorgi Djakov 532415b5a75SGeorgi Djakov if (ret >= MAX_PHASES) { 533415b5a75SGeorgi Djakov ret = -EINVAL; 534415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n", 535415b5a75SGeorgi Djakov mmc_hostname(mmc), ret); 536415b5a75SGeorgi Djakov } 537415b5a75SGeorgi Djakov 538415b5a75SGeorgi Djakov return ret; 539415b5a75SGeorgi Djakov } 540415b5a75SGeorgi Djakov 541415b5a75SGeorgi Djakov static inline void msm_cm_dll_set_freq(struct sdhci_host *host) 542415b5a75SGeorgi Djakov { 543415b5a75SGeorgi Djakov u32 mclk_freq = 0, config; 544bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 545bc99266bSSayali Lokhande sdhci_priv_msm_offset(host); 546415b5a75SGeorgi Djakov 547415b5a75SGeorgi Djakov /* Program the MCLK value to MCLK_FREQ bit field */ 548415b5a75SGeorgi Djakov if (host->clock <= 112000000) 549415b5a75SGeorgi Djakov mclk_freq = 0; 550415b5a75SGeorgi Djakov else if (host->clock <= 125000000) 551415b5a75SGeorgi Djakov mclk_freq = 1; 552415b5a75SGeorgi Djakov else if (host->clock <= 137000000) 553415b5a75SGeorgi Djakov mclk_freq = 2; 554415b5a75SGeorgi Djakov else if (host->clock <= 150000000) 555415b5a75SGeorgi Djakov mclk_freq = 3; 556415b5a75SGeorgi Djakov else if (host->clock <= 162000000) 557415b5a75SGeorgi Djakov mclk_freq = 4; 558415b5a75SGeorgi Djakov else if (host->clock <= 175000000) 559415b5a75SGeorgi Djakov mclk_freq = 5; 560415b5a75SGeorgi Djakov else if (host->clock <= 187000000) 561415b5a75SGeorgi Djakov mclk_freq = 6; 562415b5a75SGeorgi Djakov else if (host->clock <= 200000000) 563415b5a75SGeorgi Djakov mclk_freq = 7; 564415b5a75SGeorgi Djakov 565bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); 566415b5a75SGeorgi Djakov config &= ~CMUX_SHIFT_PHASE_MASK; 567415b5a75SGeorgi Djakov config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT; 568bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); 569415b5a75SGeorgi Djakov } 570415b5a75SGeorgi Djakov 571415b5a75SGeorgi Djakov /* Initialize the DLL (Programmable Delay Line) */ 572415b5a75SGeorgi Djakov static int msm_init_cm_dll(struct sdhci_host *host) 573415b5a75SGeorgi Djakov { 574415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 57583736352SVenkat Gopalakrishnan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 57683736352SVenkat Gopalakrishnan struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 577415b5a75SGeorgi Djakov int wait_cnt = 50; 5785e6b6651SJorge Ramirez-Ortiz unsigned long flags, xo_clk = 0; 57929301f40SRitesh Harjani u32 config; 580bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 581bc99266bSSayali Lokhande msm_host->offset; 582415b5a75SGeorgi Djakov 5835e6b6651SJorge Ramirez-Ortiz if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk)) 5845e6b6651SJorge Ramirez-Ortiz xo_clk = clk_get_rate(msm_host->xo_clk); 5855e6b6651SJorge Ramirez-Ortiz 586415b5a75SGeorgi Djakov spin_lock_irqsave(&host->lock, flags); 587415b5a75SGeorgi Djakov 588415b5a75SGeorgi Djakov /* 589415b5a75SGeorgi Djakov * Make sure that clock is always enabled when DLL 590415b5a75SGeorgi Djakov * tuning is in progress. Keeping PWRSAVE ON may 591415b5a75SGeorgi Djakov * turn off the clock. 592415b5a75SGeorgi Djakov */ 593bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec); 59429301f40SRitesh Harjani config &= ~CORE_CLK_PWRSAVE; 595bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec); 596415b5a75SGeorgi Djakov 59783736352SVenkat Gopalakrishnan if (msm_host->use_14lpp_dll_reset) { 598bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 599bc99266bSSayali Lokhande msm_offset->core_dll_config); 60083736352SVenkat Gopalakrishnan config &= ~CORE_CK_OUT_EN; 601bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 602bc99266bSSayali Lokhande msm_offset->core_dll_config); 60383736352SVenkat Gopalakrishnan 604bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 605bc99266bSSayali Lokhande msm_offset->core_dll_config_2); 60683736352SVenkat Gopalakrishnan config |= CORE_DLL_CLOCK_DISABLE; 607bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 608bc99266bSSayali Lokhande msm_offset->core_dll_config_2); 60983736352SVenkat Gopalakrishnan } 61083736352SVenkat Gopalakrishnan 611bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 612bc99266bSSayali Lokhande msm_offset->core_dll_config); 61329301f40SRitesh Harjani config |= CORE_DLL_RST; 614bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 615bc99266bSSayali Lokhande msm_offset->core_dll_config); 616415b5a75SGeorgi Djakov 617bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 618bc99266bSSayali Lokhande msm_offset->core_dll_config); 61929301f40SRitesh Harjani config |= CORE_DLL_PDN; 620bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 621bc99266bSSayali Lokhande msm_offset->core_dll_config); 622415b5a75SGeorgi Djakov msm_cm_dll_set_freq(host); 623415b5a75SGeorgi Djakov 62483736352SVenkat Gopalakrishnan if (msm_host->use_14lpp_dll_reset && 62583736352SVenkat Gopalakrishnan !IS_ERR_OR_NULL(msm_host->xo_clk)) { 62683736352SVenkat Gopalakrishnan u32 mclk_freq = 0; 62783736352SVenkat Gopalakrishnan 628bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 629bc99266bSSayali Lokhande msm_offset->core_dll_config_2); 63083736352SVenkat Gopalakrishnan config &= CORE_FLL_CYCLE_CNT; 63183736352SVenkat Gopalakrishnan if (config) 63283736352SVenkat Gopalakrishnan mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8), 6335e6b6651SJorge Ramirez-Ortiz xo_clk); 63483736352SVenkat Gopalakrishnan else 63583736352SVenkat Gopalakrishnan mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4), 6365e6b6651SJorge Ramirez-Ortiz xo_clk); 63783736352SVenkat Gopalakrishnan 638bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 639bc99266bSSayali Lokhande msm_offset->core_dll_config_2); 64083736352SVenkat Gopalakrishnan config &= ~(0xFF << 10); 64183736352SVenkat Gopalakrishnan config |= mclk_freq << 10; 64283736352SVenkat Gopalakrishnan 643bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 644bc99266bSSayali Lokhande msm_offset->core_dll_config_2); 64583736352SVenkat Gopalakrishnan /* wait for 5us before enabling DLL clock */ 64683736352SVenkat Gopalakrishnan udelay(5); 64783736352SVenkat Gopalakrishnan } 64883736352SVenkat Gopalakrishnan 649bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 650bc99266bSSayali Lokhande msm_offset->core_dll_config); 65129301f40SRitesh Harjani config &= ~CORE_DLL_RST; 652bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 653bc99266bSSayali Lokhande msm_offset->core_dll_config); 654415b5a75SGeorgi Djakov 655bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 656bc99266bSSayali Lokhande msm_offset->core_dll_config); 65729301f40SRitesh Harjani config &= ~CORE_DLL_PDN; 658bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 659bc99266bSSayali Lokhande msm_offset->core_dll_config); 660415b5a75SGeorgi Djakov 66183736352SVenkat Gopalakrishnan if (msm_host->use_14lpp_dll_reset) { 66283736352SVenkat Gopalakrishnan msm_cm_dll_set_freq(host); 663bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 664bc99266bSSayali Lokhande msm_offset->core_dll_config_2); 66583736352SVenkat Gopalakrishnan config &= ~CORE_DLL_CLOCK_DISABLE; 666bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 667bc99266bSSayali Lokhande msm_offset->core_dll_config_2); 66883736352SVenkat Gopalakrishnan } 66983736352SVenkat Gopalakrishnan 670bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 671bc99266bSSayali Lokhande msm_offset->core_dll_config); 67229301f40SRitesh Harjani config |= CORE_DLL_EN; 673bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 674bc99266bSSayali Lokhande msm_offset->core_dll_config); 675415b5a75SGeorgi Djakov 676bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 677bc99266bSSayali Lokhande msm_offset->core_dll_config); 67829301f40SRitesh Harjani config |= CORE_CK_OUT_EN; 679bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 680bc99266bSSayali Lokhande msm_offset->core_dll_config); 681415b5a75SGeorgi Djakov 682415b5a75SGeorgi Djakov /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ 683bc99266bSSayali Lokhande while (!(readl_relaxed(host->ioaddr + msm_offset->core_dll_status) & 684415b5a75SGeorgi Djakov CORE_DLL_LOCK)) { 685415b5a75SGeorgi Djakov /* max. wait for 50us sec for LOCK bit to be set */ 686415b5a75SGeorgi Djakov if (--wait_cnt == 0) { 687415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n", 688415b5a75SGeorgi Djakov mmc_hostname(mmc)); 689415b5a75SGeorgi Djakov spin_unlock_irqrestore(&host->lock, flags); 690415b5a75SGeorgi Djakov return -ETIMEDOUT; 691415b5a75SGeorgi Djakov } 692415b5a75SGeorgi Djakov udelay(1); 693415b5a75SGeorgi Djakov } 694415b5a75SGeorgi Djakov 695415b5a75SGeorgi Djakov spin_unlock_irqrestore(&host->lock, flags); 696415b5a75SGeorgi Djakov return 0; 697415b5a75SGeorgi Djakov } 698415b5a75SGeorgi Djakov 699b54aaa8aSRitesh Harjani static void msm_hc_select_default(struct sdhci_host *host) 700b54aaa8aSRitesh Harjani { 701b54aaa8aSRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 702b54aaa8aSRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 703b54aaa8aSRitesh Harjani u32 config; 704bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 705bc99266bSSayali Lokhande msm_host->offset; 706b54aaa8aSRitesh Harjani 707b54aaa8aSRitesh Harjani if (!msm_host->use_cdclp533) { 708b54aaa8aSRitesh Harjani config = readl_relaxed(host->ioaddr + 709bc99266bSSayali Lokhande msm_offset->core_vendor_spec3); 710b54aaa8aSRitesh Harjani config &= ~CORE_PWRSAVE_DLL; 711b54aaa8aSRitesh Harjani writel_relaxed(config, host->ioaddr + 712bc99266bSSayali Lokhande msm_offset->core_vendor_spec3); 713b54aaa8aSRitesh Harjani } 714b54aaa8aSRitesh Harjani 715bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec); 716b54aaa8aSRitesh Harjani config &= ~CORE_HC_MCLK_SEL_MASK; 717b54aaa8aSRitesh Harjani config |= CORE_HC_MCLK_SEL_DFLT; 718bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec); 719b54aaa8aSRitesh Harjani 720b54aaa8aSRitesh Harjani /* 721b54aaa8aSRitesh Harjani * Disable HC_SELECT_IN to be able to use the UHS mode select 722b54aaa8aSRitesh Harjani * configuration from Host Control2 register for all other 723b54aaa8aSRitesh Harjani * modes. 724b54aaa8aSRitesh Harjani * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field 725b54aaa8aSRitesh Harjani * in VENDOR_SPEC_FUNC 726b54aaa8aSRitesh Harjani */ 727bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec); 728b54aaa8aSRitesh Harjani config &= ~CORE_HC_SELECT_IN_EN; 729b54aaa8aSRitesh Harjani config &= ~CORE_HC_SELECT_IN_MASK; 730bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec); 731b54aaa8aSRitesh Harjani 732b54aaa8aSRitesh Harjani /* 733b54aaa8aSRitesh Harjani * Make sure above writes impacting free running MCLK are completed 734b54aaa8aSRitesh Harjani * before changing the clk_rate at GCC. 735b54aaa8aSRitesh Harjani */ 736b54aaa8aSRitesh Harjani wmb(); 737b54aaa8aSRitesh Harjani } 738b54aaa8aSRitesh Harjani 739b54aaa8aSRitesh Harjani static void msm_hc_select_hs400(struct sdhci_host *host) 740b54aaa8aSRitesh Harjani { 741b54aaa8aSRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 742b54aaa8aSRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 74344bf2312SRitesh Harjani struct mmc_ios ios = host->mmc->ios; 744b54aaa8aSRitesh Harjani u32 config, dll_lock; 745b54aaa8aSRitesh Harjani int rc; 746bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 747bc99266bSSayali Lokhande msm_host->offset; 748b54aaa8aSRitesh Harjani 749b54aaa8aSRitesh Harjani /* Select the divided clock (free running MCLK/2) */ 750bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec); 751b54aaa8aSRitesh Harjani config &= ~CORE_HC_MCLK_SEL_MASK; 752b54aaa8aSRitesh Harjani config |= CORE_HC_MCLK_SEL_HS400; 753b54aaa8aSRitesh Harjani 754bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec); 755b54aaa8aSRitesh Harjani /* 756b54aaa8aSRitesh Harjani * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC 757b54aaa8aSRitesh Harjani * register 758b54aaa8aSRitesh Harjani */ 75944bf2312SRitesh Harjani if ((msm_host->tuning_done || ios.enhanced_strobe) && 76044bf2312SRitesh Harjani !msm_host->calibration_done) { 761bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 762bc99266bSSayali Lokhande msm_offset->core_vendor_spec); 763b54aaa8aSRitesh Harjani config |= CORE_HC_SELECT_IN_HS400; 764b54aaa8aSRitesh Harjani config |= CORE_HC_SELECT_IN_EN; 765bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 766bc99266bSSayali Lokhande msm_offset->core_vendor_spec); 767b54aaa8aSRitesh Harjani } 768b54aaa8aSRitesh Harjani if (!msm_host->clk_rate && !msm_host->use_cdclp533) { 769b54aaa8aSRitesh Harjani /* 770b54aaa8aSRitesh Harjani * Poll on DLL_LOCK or DDR_DLL_LOCK bits in 771bc99266bSSayali Lokhande * core_dll_status to be set. This should get set 772b54aaa8aSRitesh Harjani * within 15 us at 200 MHz. 773b54aaa8aSRitesh Harjani */ 774b54aaa8aSRitesh Harjani rc = readl_relaxed_poll_timeout(host->ioaddr + 775bc99266bSSayali Lokhande msm_offset->core_dll_status, 776b54aaa8aSRitesh Harjani dll_lock, 777b54aaa8aSRitesh Harjani (dll_lock & 778b54aaa8aSRitesh Harjani (CORE_DLL_LOCK | 779b54aaa8aSRitesh Harjani CORE_DDR_DLL_LOCK)), 10, 780b54aaa8aSRitesh Harjani 1000); 781b54aaa8aSRitesh Harjani if (rc == -ETIMEDOUT) 782b54aaa8aSRitesh Harjani pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n", 783b54aaa8aSRitesh Harjani mmc_hostname(host->mmc), dll_lock); 784b54aaa8aSRitesh Harjani } 785b54aaa8aSRitesh Harjani /* 786b54aaa8aSRitesh Harjani * Make sure above writes impacting free running MCLK are completed 787b54aaa8aSRitesh Harjani * before changing the clk_rate at GCC. 788b54aaa8aSRitesh Harjani */ 789b54aaa8aSRitesh Harjani wmb(); 790b54aaa8aSRitesh Harjani } 791b54aaa8aSRitesh Harjani 792b54aaa8aSRitesh Harjani /* 793b54aaa8aSRitesh Harjani * sdhci_msm_hc_select_mode :- In general all timing modes are 794b54aaa8aSRitesh Harjani * controlled via UHS mode select in Host Control2 register. 795b54aaa8aSRitesh Harjani * eMMC specific HS200/HS400 doesn't have their respective modes 796b54aaa8aSRitesh Harjani * defined here, hence we use these values. 797b54aaa8aSRitesh Harjani * 798b54aaa8aSRitesh Harjani * HS200 - SDR104 (Since they both are equivalent in functionality) 799b54aaa8aSRitesh Harjani * HS400 - This involves multiple configurations 800b54aaa8aSRitesh Harjani * Initially SDR104 - when tuning is required as HS200 801b54aaa8aSRitesh Harjani * Then when switching to DDR @ 400MHz (HS400) we use 802b54aaa8aSRitesh Harjani * the vendor specific HC_SELECT_IN to control the mode. 803b54aaa8aSRitesh Harjani * 804b54aaa8aSRitesh Harjani * In addition to controlling the modes we also need to select the 805b54aaa8aSRitesh Harjani * correct input clock for DLL depending on the mode. 806b54aaa8aSRitesh Harjani * 807b54aaa8aSRitesh Harjani * HS400 - divided clock (free running MCLK/2) 808b54aaa8aSRitesh Harjani * All other modes - default (free running MCLK) 809b54aaa8aSRitesh Harjani */ 81030de038dSMasahiro Yamada static void sdhci_msm_hc_select_mode(struct sdhci_host *host) 811b54aaa8aSRitesh Harjani { 812b54aaa8aSRitesh Harjani struct mmc_ios ios = host->mmc->ios; 813b54aaa8aSRitesh Harjani 814d7507aa1SRitesh Harjani if (ios.timing == MMC_TIMING_MMC_HS400 || 815d7507aa1SRitesh Harjani host->flags & SDHCI_HS400_TUNING) 816b54aaa8aSRitesh Harjani msm_hc_select_hs400(host); 817b54aaa8aSRitesh Harjani else 818b54aaa8aSRitesh Harjani msm_hc_select_default(host); 819b54aaa8aSRitesh Harjani } 820b54aaa8aSRitesh Harjani 821cc392c58SRitesh Harjani static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) 822cc392c58SRitesh Harjani { 823cc392c58SRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 824cc392c58SRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 825cc392c58SRitesh Harjani u32 config, calib_done; 826cc392c58SRitesh Harjani int ret; 827bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 828bc99266bSSayali Lokhande msm_host->offset; 829cc392c58SRitesh Harjani 830cc392c58SRitesh Harjani pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__); 831cc392c58SRitesh Harjani 832cc392c58SRitesh Harjani /* 833cc392c58SRitesh Harjani * Retuning in HS400 (DDR mode) will fail, just reset the 834cc392c58SRitesh Harjani * tuning block and restore the saved tuning phase. 835cc392c58SRitesh Harjani */ 836cc392c58SRitesh Harjani ret = msm_init_cm_dll(host); 837cc392c58SRitesh Harjani if (ret) 838cc392c58SRitesh Harjani goto out; 839cc392c58SRitesh Harjani 840cc392c58SRitesh Harjani /* Set the selected phase in delay line hw block */ 841cc392c58SRitesh Harjani ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); 842cc392c58SRitesh Harjani if (ret) 843cc392c58SRitesh Harjani goto out; 844cc392c58SRitesh Harjani 845bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); 846cc392c58SRitesh Harjani config |= CORE_CMD_DAT_TRACK_SEL; 847bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); 848cc392c58SRitesh Harjani 849bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg); 850cc392c58SRitesh Harjani config &= ~CORE_CDC_T4_DLY_SEL; 851bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg); 852cc392c58SRitesh Harjani 853cc392c58SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG); 854cc392c58SRitesh Harjani config &= ~CORE_CDC_SWITCH_BYPASS_OFF; 855cc392c58SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG); 856cc392c58SRitesh Harjani 857cc392c58SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG); 858cc392c58SRitesh Harjani config |= CORE_CDC_SWITCH_RC_EN; 859cc392c58SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG); 860cc392c58SRitesh Harjani 861bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg); 862cc392c58SRitesh Harjani config &= ~CORE_START_CDC_TRAFFIC; 863bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg); 864cc392c58SRitesh Harjani 865543c576dSRitesh Harjani /* Perform CDC Register Initialization Sequence */ 866cc392c58SRitesh Harjani 867cc392c58SRitesh Harjani writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 868cc392c58SRitesh Harjani writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1); 869cc392c58SRitesh Harjani writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); 870cc392c58SRitesh Harjani writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1); 871cc392c58SRitesh Harjani writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG); 872cc392c58SRitesh Harjani writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG); 873083c9aa0SSubhash Jadavani writel_relaxed(0x4E2, host->ioaddr + CORE_CSR_CDC_DELAY_CFG); 874cc392c58SRitesh Harjani writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG); 875cc392c58SRitesh Harjani writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG); 876cc392c58SRitesh Harjani 877cc392c58SRitesh Harjani /* CDC HW Calibration */ 878cc392c58SRitesh Harjani 879cc392c58SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 880cc392c58SRitesh Harjani config |= CORE_SW_TRIG_FULL_CALIB; 881cc392c58SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 882cc392c58SRitesh Harjani 883cc392c58SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 884cc392c58SRitesh Harjani config &= ~CORE_SW_TRIG_FULL_CALIB; 885cc392c58SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 886cc392c58SRitesh Harjani 887cc392c58SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 888cc392c58SRitesh Harjani config |= CORE_HW_AUTOCAL_ENA; 889cc392c58SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 890cc392c58SRitesh Harjani 891cc392c58SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); 892cc392c58SRitesh Harjani config |= CORE_TIMER_ENA; 893cc392c58SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); 894cc392c58SRitesh Harjani 895cc392c58SRitesh Harjani ret = readl_relaxed_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0, 896cc392c58SRitesh Harjani calib_done, 897cc392c58SRitesh Harjani (calib_done & CORE_CALIBRATION_DONE), 898cc392c58SRitesh Harjani 1, 50); 899cc392c58SRitesh Harjani 900cc392c58SRitesh Harjani if (ret == -ETIMEDOUT) { 901cc392c58SRitesh Harjani pr_err("%s: %s: CDC calibration was not completed\n", 902cc392c58SRitesh Harjani mmc_hostname(host->mmc), __func__); 903cc392c58SRitesh Harjani goto out; 904cc392c58SRitesh Harjani } 905cc392c58SRitesh Harjani 906cc392c58SRitesh Harjani ret = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) 907cc392c58SRitesh Harjani & CORE_CDC_ERROR_CODE_MASK; 908cc392c58SRitesh Harjani if (ret) { 909cc392c58SRitesh Harjani pr_err("%s: %s: CDC error code %d\n", 910cc392c58SRitesh Harjani mmc_hostname(host->mmc), __func__, ret); 911cc392c58SRitesh Harjani ret = -EINVAL; 912cc392c58SRitesh Harjani goto out; 913cc392c58SRitesh Harjani } 914cc392c58SRitesh Harjani 915bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_ddr_200_cfg); 916cc392c58SRitesh Harjani config |= CORE_START_CDC_TRAFFIC; 917bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_ddr_200_cfg); 918cc392c58SRitesh Harjani out: 919cc392c58SRitesh Harjani pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), 920cc392c58SRitesh Harjani __func__, ret); 921cc392c58SRitesh Harjani return ret; 922cc392c58SRitesh Harjani } 923cc392c58SRitesh Harjani 92402e4293dSRitesh Harjani static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) 92502e4293dSRitesh Harjani { 92644bf2312SRitesh Harjani struct mmc_host *mmc = host->mmc; 92702e4293dSRitesh Harjani u32 dll_status, config; 92802e4293dSRitesh Harjani int ret; 929bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 930bc99266bSSayali Lokhande sdhci_priv_msm_offset(host); 93102e4293dSRitesh Harjani 93202e4293dSRitesh Harjani pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__); 93302e4293dSRitesh Harjani 93402e4293dSRitesh Harjani /* 935bc99266bSSayali Lokhande * Currently the core_ddr_config register defaults to desired 93602e4293dSRitesh Harjani * configuration on reset. Currently reprogramming the power on 93702e4293dSRitesh Harjani * reset (POR) value in case it might have been modified by 93802e4293dSRitesh Harjani * bootloaders. In the future, if this changes, then the desired 93902e4293dSRitesh Harjani * values will need to be programmed appropriately. 94002e4293dSRitesh Harjani */ 941bc99266bSSayali Lokhande writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + 942bc99266bSSayali Lokhande msm_offset->core_ddr_config); 94302e4293dSRitesh Harjani 94444bf2312SRitesh Harjani if (mmc->ios.enhanced_strobe) { 945bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 946bc99266bSSayali Lokhande msm_offset->core_ddr_200_cfg); 94744bf2312SRitesh Harjani config |= CORE_CMDIN_RCLK_EN; 948bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 949bc99266bSSayali Lokhande msm_offset->core_ddr_200_cfg); 95044bf2312SRitesh Harjani } 95144bf2312SRitesh Harjani 952bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2); 95302e4293dSRitesh Harjani config |= CORE_DDR_CAL_EN; 954bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config_2); 95502e4293dSRitesh Harjani 956bc99266bSSayali Lokhande ret = readl_relaxed_poll_timeout(host->ioaddr + 957bc99266bSSayali Lokhande msm_offset->core_dll_status, 95802e4293dSRitesh Harjani dll_status, 95902e4293dSRitesh Harjani (dll_status & CORE_DDR_DLL_LOCK), 96002e4293dSRitesh Harjani 10, 1000); 96102e4293dSRitesh Harjani 96202e4293dSRitesh Harjani if (ret == -ETIMEDOUT) { 96302e4293dSRitesh Harjani pr_err("%s: %s: CM_DLL_SDC4 calibration was not completed\n", 96402e4293dSRitesh Harjani mmc_hostname(host->mmc), __func__); 96502e4293dSRitesh Harjani goto out; 96602e4293dSRitesh Harjani } 96702e4293dSRitesh Harjani 968bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec3); 96902e4293dSRitesh Harjani config |= CORE_PWRSAVE_DLL; 970bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec3); 97102e4293dSRitesh Harjani 97202e4293dSRitesh Harjani /* 97302e4293dSRitesh Harjani * Drain writebuffer to ensure above DLL calibration 97402e4293dSRitesh Harjani * and PWRSAVE DLL is enabled. 97502e4293dSRitesh Harjani */ 97602e4293dSRitesh Harjani wmb(); 97702e4293dSRitesh Harjani out: 97802e4293dSRitesh Harjani pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), 97902e4293dSRitesh Harjani __func__, ret); 98002e4293dSRitesh Harjani return ret; 98102e4293dSRitesh Harjani } 98202e4293dSRitesh Harjani 98302e4293dSRitesh Harjani static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) 98402e4293dSRitesh Harjani { 98502e4293dSRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 98602e4293dSRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 98744bf2312SRitesh Harjani struct mmc_host *mmc = host->mmc; 98802e4293dSRitesh Harjani int ret; 98902e4293dSRitesh Harjani u32 config; 990bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 991bc99266bSSayali Lokhande msm_host->offset; 99202e4293dSRitesh Harjani 99302e4293dSRitesh Harjani pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__); 99402e4293dSRitesh Harjani 99502e4293dSRitesh Harjani /* 99602e4293dSRitesh Harjani * Retuning in HS400 (DDR mode) will fail, just reset the 99702e4293dSRitesh Harjani * tuning block and restore the saved tuning phase. 99802e4293dSRitesh Harjani */ 99902e4293dSRitesh Harjani ret = msm_init_cm_dll(host); 100002e4293dSRitesh Harjani if (ret) 100102e4293dSRitesh Harjani goto out; 100202e4293dSRitesh Harjani 100344bf2312SRitesh Harjani if (!mmc->ios.enhanced_strobe) { 100402e4293dSRitesh Harjani /* Set the selected phase in delay line hw block */ 100544bf2312SRitesh Harjani ret = msm_config_cm_dll_phase(host, 100644bf2312SRitesh Harjani msm_host->saved_tuning_phase); 100702e4293dSRitesh Harjani if (ret) 100802e4293dSRitesh Harjani goto out; 1009bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 1010bc99266bSSayali Lokhande msm_offset->core_dll_config); 101102e4293dSRitesh Harjani config |= CORE_CMD_DAT_TRACK_SEL; 1012bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 1013bc99266bSSayali Lokhande msm_offset->core_dll_config); 101444bf2312SRitesh Harjani } 101544bf2312SRitesh Harjani 101602e4293dSRitesh Harjani if (msm_host->use_cdclp533) 101702e4293dSRitesh Harjani ret = sdhci_msm_cdclp533_calibration(host); 101802e4293dSRitesh Harjani else 101902e4293dSRitesh Harjani ret = sdhci_msm_cm_dll_sdc4_calibration(host); 102002e4293dSRitesh Harjani out: 102102e4293dSRitesh Harjani pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), 102202e4293dSRitesh Harjani __func__, ret); 102302e4293dSRitesh Harjani return ret; 102402e4293dSRitesh Harjani } 102502e4293dSRitesh Harjani 102621f1e2d4SVeerabhadrarao Badiganti static bool sdhci_msm_is_tuning_needed(struct sdhci_host *host) 102721f1e2d4SVeerabhadrarao Badiganti { 102821f1e2d4SVeerabhadrarao Badiganti struct mmc_ios *ios = &host->mmc->ios; 102921f1e2d4SVeerabhadrarao Badiganti 103021f1e2d4SVeerabhadrarao Badiganti /* 103121f1e2d4SVeerabhadrarao Badiganti * Tuning is required for SDR104, HS200 and HS400 cards and 103221f1e2d4SVeerabhadrarao Badiganti * if clock frequency is greater than 100MHz in these modes. 103321f1e2d4SVeerabhadrarao Badiganti */ 103421f1e2d4SVeerabhadrarao Badiganti if (host->clock <= CORE_FREQ_100MHZ || 103521f1e2d4SVeerabhadrarao Badiganti !(ios->timing == MMC_TIMING_MMC_HS400 || 103621f1e2d4SVeerabhadrarao Badiganti ios->timing == MMC_TIMING_MMC_HS200 || 103721f1e2d4SVeerabhadrarao Badiganti ios->timing == MMC_TIMING_UHS_SDR104) || 103821f1e2d4SVeerabhadrarao Badiganti ios->enhanced_strobe) 103921f1e2d4SVeerabhadrarao Badiganti return false; 104021f1e2d4SVeerabhadrarao Badiganti 104121f1e2d4SVeerabhadrarao Badiganti return true; 104221f1e2d4SVeerabhadrarao Badiganti } 104321f1e2d4SVeerabhadrarao Badiganti 104421f1e2d4SVeerabhadrarao Badiganti static int sdhci_msm_restore_sdr_dll_config(struct sdhci_host *host) 104521f1e2d4SVeerabhadrarao Badiganti { 104621f1e2d4SVeerabhadrarao Badiganti struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 104721f1e2d4SVeerabhadrarao Badiganti struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 104821f1e2d4SVeerabhadrarao Badiganti int ret; 104921f1e2d4SVeerabhadrarao Badiganti 105021f1e2d4SVeerabhadrarao Badiganti /* 105121f1e2d4SVeerabhadrarao Badiganti * SDR DLL comes into picture only for timing modes which needs 105221f1e2d4SVeerabhadrarao Badiganti * tuning. 105321f1e2d4SVeerabhadrarao Badiganti */ 105421f1e2d4SVeerabhadrarao Badiganti if (!sdhci_msm_is_tuning_needed(host)) 105521f1e2d4SVeerabhadrarao Badiganti return 0; 105621f1e2d4SVeerabhadrarao Badiganti 105721f1e2d4SVeerabhadrarao Badiganti /* Reset the tuning block */ 105821f1e2d4SVeerabhadrarao Badiganti ret = msm_init_cm_dll(host); 105921f1e2d4SVeerabhadrarao Badiganti if (ret) 106021f1e2d4SVeerabhadrarao Badiganti return ret; 106121f1e2d4SVeerabhadrarao Badiganti 106221f1e2d4SVeerabhadrarao Badiganti /* Restore the tuning block */ 106321f1e2d4SVeerabhadrarao Badiganti ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); 106421f1e2d4SVeerabhadrarao Badiganti 106521f1e2d4SVeerabhadrarao Badiganti return ret; 106621f1e2d4SVeerabhadrarao Badiganti } 106721f1e2d4SVeerabhadrarao Badiganti 1068a89e7bcbSLoic Poulain static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable) 1069a89e7bcbSLoic Poulain { 1070a89e7bcbSLoic Poulain const struct sdhci_msm_offset *msm_offset = sdhci_priv_msm_offset(host); 1071a89e7bcbSLoic Poulain u32 config, oldconfig = readl_relaxed(host->ioaddr + 1072a89e7bcbSLoic Poulain msm_offset->core_dll_config); 1073a89e7bcbSLoic Poulain 1074a89e7bcbSLoic Poulain config = oldconfig; 1075a89e7bcbSLoic Poulain if (enable) { 1076a89e7bcbSLoic Poulain config |= CORE_CDR_EN; 1077a89e7bcbSLoic Poulain config &= ~CORE_CDR_EXT_EN; 1078a89e7bcbSLoic Poulain } else { 1079a89e7bcbSLoic Poulain config &= ~CORE_CDR_EN; 1080a89e7bcbSLoic Poulain config |= CORE_CDR_EXT_EN; 1081a89e7bcbSLoic Poulain } 1082a89e7bcbSLoic Poulain 1083a89e7bcbSLoic Poulain if (config != oldconfig) { 1084a89e7bcbSLoic Poulain writel_relaxed(config, host->ioaddr + 1085a89e7bcbSLoic Poulain msm_offset->core_dll_config); 1086a89e7bcbSLoic Poulain } 1087a89e7bcbSLoic Poulain } 1088a89e7bcbSLoic Poulain 10894436c535SRitesh Harjani static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) 10900eb0d9f4SGeorgi Djakov { 10914436c535SRitesh Harjani struct sdhci_host *host = mmc_priv(mmc); 1092415b5a75SGeorgi Djakov int tuning_seq_cnt = 3; 109333d73935SUlf Hansson u8 phase, tuned_phases[16], tuned_phase_cnt = 0; 1094415b5a75SGeorgi Djakov int rc; 1095415b5a75SGeorgi Djakov struct mmc_ios ios = host->mmc->ios; 1096abf270e5SRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1097abf270e5SRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1098415b5a75SGeorgi Djakov 1099a89e7bcbSLoic Poulain if (!sdhci_msm_is_tuning_needed(host)) { 1100a89e7bcbSLoic Poulain msm_host->use_cdr = false; 1101a89e7bcbSLoic Poulain sdhci_msm_set_cdr(host, false); 11020eb0d9f4SGeorgi Djakov return 0; 1103a89e7bcbSLoic Poulain } 1104a89e7bcbSLoic Poulain 1105a89e7bcbSLoic Poulain /* Clock-Data-Recovery used to dynamically adjust RX sampling point */ 1106a89e7bcbSLoic Poulain msm_host->use_cdr = true; 1107415b5a75SGeorgi Djakov 1108d7507aa1SRitesh Harjani /* 1109d7507aa1SRitesh Harjani * For HS400 tuning in HS200 timing requires: 1110d7507aa1SRitesh Harjani * - select MCLK/2 in VENDOR_SPEC 1111d7507aa1SRitesh Harjani * - program MCLK to 400MHz (or nearest supported) in GCC 1112d7507aa1SRitesh Harjani */ 1113d7507aa1SRitesh Harjani if (host->flags & SDHCI_HS400_TUNING) { 1114d7507aa1SRitesh Harjani sdhci_msm_hc_select_mode(host); 1115d7507aa1SRitesh Harjani msm_set_clock_rate_for_bus_mode(host, ios.clock); 11164436c535SRitesh Harjani host->flags &= ~SDHCI_HS400_TUNING; 1117d7507aa1SRitesh Harjani } 1118d7507aa1SRitesh Harjani 1119415b5a75SGeorgi Djakov retry: 1120415b5a75SGeorgi Djakov /* First of all reset the tuning block */ 1121415b5a75SGeorgi Djakov rc = msm_init_cm_dll(host); 1122415b5a75SGeorgi Djakov if (rc) 112333d73935SUlf Hansson return rc; 1124415b5a75SGeorgi Djakov 1125415b5a75SGeorgi Djakov phase = 0; 1126415b5a75SGeorgi Djakov do { 1127415b5a75SGeorgi Djakov /* Set the phase in delay line hw block */ 1128415b5a75SGeorgi Djakov rc = msm_config_cm_dll_phase(host, phase); 1129415b5a75SGeorgi Djakov if (rc) 113033d73935SUlf Hansson return rc; 1131415b5a75SGeorgi Djakov 11329979dbe5SChaotian Jing rc = mmc_send_tuning(mmc, opcode, NULL); 113333d73935SUlf Hansson if (!rc) { 1134415b5a75SGeorgi Djakov /* Tuning is successful at this tuning point */ 1135415b5a75SGeorgi Djakov tuned_phases[tuned_phase_cnt++] = phase; 1136415b5a75SGeorgi Djakov dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", 1137415b5a75SGeorgi Djakov mmc_hostname(mmc), phase); 1138415b5a75SGeorgi Djakov } 1139415b5a75SGeorgi Djakov } while (++phase < ARRAY_SIZE(tuned_phases)); 1140415b5a75SGeorgi Djakov 1141415b5a75SGeorgi Djakov if (tuned_phase_cnt) { 1142415b5a75SGeorgi Djakov rc = msm_find_most_appropriate_phase(host, tuned_phases, 1143415b5a75SGeorgi Djakov tuned_phase_cnt); 1144415b5a75SGeorgi Djakov if (rc < 0) 114533d73935SUlf Hansson return rc; 1146415b5a75SGeorgi Djakov else 1147415b5a75SGeorgi Djakov phase = rc; 1148415b5a75SGeorgi Djakov 1149415b5a75SGeorgi Djakov /* 1150415b5a75SGeorgi Djakov * Finally set the selected phase in delay 1151415b5a75SGeorgi Djakov * line hw block. 1152415b5a75SGeorgi Djakov */ 1153415b5a75SGeorgi Djakov rc = msm_config_cm_dll_phase(host, phase); 1154415b5a75SGeorgi Djakov if (rc) 115533d73935SUlf Hansson return rc; 115621f1e2d4SVeerabhadrarao Badiganti msm_host->saved_tuning_phase = phase; 1157415b5a75SGeorgi Djakov dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", 1158415b5a75SGeorgi Djakov mmc_hostname(mmc), phase); 1159415b5a75SGeorgi Djakov } else { 1160415b5a75SGeorgi Djakov if (--tuning_seq_cnt) 1161415b5a75SGeorgi Djakov goto retry; 1162415b5a75SGeorgi Djakov /* Tuning failed */ 1163415b5a75SGeorgi Djakov dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", 1164415b5a75SGeorgi Djakov mmc_hostname(mmc)); 1165415b5a75SGeorgi Djakov rc = -EIO; 1166415b5a75SGeorgi Djakov } 1167415b5a75SGeorgi Djakov 1168ff06ce41SVenkat Gopalakrishnan if (!rc) 1169ff06ce41SVenkat Gopalakrishnan msm_host->tuning_done = true; 1170415b5a75SGeorgi Djakov return rc; 11710eb0d9f4SGeorgi Djakov } 11720eb0d9f4SGeorgi Djakov 1173db9bd163SRitesh Harjani /* 1174db9bd163SRitesh Harjani * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation. 117544bf2312SRitesh Harjani * This needs to be done for both tuning and enhanced_strobe mode. 1176db9bd163SRitesh Harjani * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz 1177db9bd163SRitesh Harjani * fixed feedback clock is used. 1178db9bd163SRitesh Harjani */ 1179db9bd163SRitesh Harjani static void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios) 1180db9bd163SRitesh Harjani { 1181db9bd163SRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1182db9bd163SRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1183db9bd163SRitesh Harjani int ret; 1184db9bd163SRitesh Harjani 1185db9bd163SRitesh Harjani if (host->clock > CORE_FREQ_100MHZ && 118644bf2312SRitesh Harjani (msm_host->tuning_done || ios->enhanced_strobe) && 118744bf2312SRitesh Harjani !msm_host->calibration_done) { 1188db9bd163SRitesh Harjani ret = sdhci_msm_hs400_dll_calibration(host); 1189db9bd163SRitesh Harjani if (!ret) 1190db9bd163SRitesh Harjani msm_host->calibration_done = true; 1191db9bd163SRitesh Harjani else 1192db9bd163SRitesh Harjani pr_err("%s: Failed to calibrate DLL for hs400 mode (%d)\n", 1193db9bd163SRitesh Harjani mmc_hostname(host->mmc), ret); 1194db9bd163SRitesh Harjani } 1195db9bd163SRitesh Harjani } 1196db9bd163SRitesh Harjani 1197ee320674SRitesh Harjani static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, 1198ee320674SRitesh Harjani unsigned int uhs) 1199ee320674SRitesh Harjani { 1200ee320674SRitesh Harjani struct mmc_host *mmc = host->mmc; 1201ff06ce41SVenkat Gopalakrishnan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1202ff06ce41SVenkat Gopalakrishnan struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1203ee320674SRitesh Harjani u16 ctrl_2; 1204ff06ce41SVenkat Gopalakrishnan u32 config; 1205bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 1206bc99266bSSayali Lokhande msm_host->offset; 1207ee320674SRitesh Harjani 1208ee320674SRitesh Harjani ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 1209ee320674SRitesh Harjani /* Select Bus Speed Mode for host */ 1210ee320674SRitesh Harjani ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 1211ee320674SRitesh Harjani switch (uhs) { 1212ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR12: 1213ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR12; 1214ee320674SRitesh Harjani break; 1215ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR25: 1216ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 1217ee320674SRitesh Harjani break; 1218ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR50: 1219ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR50; 1220ee320674SRitesh Harjani break; 1221ff06ce41SVenkat Gopalakrishnan case MMC_TIMING_MMC_HS400: 1222ee320674SRitesh Harjani case MMC_TIMING_MMC_HS200: 1223ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR104: 1224ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR104; 1225ee320674SRitesh Harjani break; 1226ee320674SRitesh Harjani case MMC_TIMING_UHS_DDR50: 1227ee320674SRitesh Harjani case MMC_TIMING_MMC_DDR52: 1228ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_DDR50; 1229ee320674SRitesh Harjani break; 1230ee320674SRitesh Harjani } 1231ee320674SRitesh Harjani 1232ee320674SRitesh Harjani /* 1233ee320674SRitesh Harjani * When clock frequency is less than 100MHz, the feedback clock must be 1234ee320674SRitesh Harjani * provided and DLL must not be used so that tuning can be skipped. To 1235ee320674SRitesh Harjani * provide feedback clock, the mode selection can be any value less 1236ee320674SRitesh Harjani * than 3'b011 in bits [2:0] of HOST CONTROL2 register. 1237ee320674SRitesh Harjani */ 1238ff06ce41SVenkat Gopalakrishnan if (host->clock <= CORE_FREQ_100MHZ) { 1239ff06ce41SVenkat Gopalakrishnan if (uhs == MMC_TIMING_MMC_HS400 || 1240ee320674SRitesh Harjani uhs == MMC_TIMING_MMC_HS200 || 1241ff06ce41SVenkat Gopalakrishnan uhs == MMC_TIMING_UHS_SDR104) 1242ee320674SRitesh Harjani ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 1243ff06ce41SVenkat Gopalakrishnan /* 1244ff06ce41SVenkat Gopalakrishnan * DLL is not required for clock <= 100MHz 1245ff06ce41SVenkat Gopalakrishnan * Thus, make sure DLL it is disabled when not required 1246ff06ce41SVenkat Gopalakrishnan */ 1247bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 1248bc99266bSSayali Lokhande msm_offset->core_dll_config); 1249ff06ce41SVenkat Gopalakrishnan config |= CORE_DLL_RST; 1250bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 1251bc99266bSSayali Lokhande msm_offset->core_dll_config); 1252ff06ce41SVenkat Gopalakrishnan 1253bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 1254bc99266bSSayali Lokhande msm_offset->core_dll_config); 1255ff06ce41SVenkat Gopalakrishnan config |= CORE_DLL_PDN; 1256bc99266bSSayali Lokhande writel_relaxed(config, host->ioaddr + 1257bc99266bSSayali Lokhande msm_offset->core_dll_config); 1258ff06ce41SVenkat Gopalakrishnan 1259ff06ce41SVenkat Gopalakrishnan /* 1260ff06ce41SVenkat Gopalakrishnan * The DLL needs to be restored and CDCLP533 recalibrated 1261ff06ce41SVenkat Gopalakrishnan * when the clock frequency is set back to 400MHz. 1262ff06ce41SVenkat Gopalakrishnan */ 1263ff06ce41SVenkat Gopalakrishnan msm_host->calibration_done = false; 1264ff06ce41SVenkat Gopalakrishnan } 1265ee320674SRitesh Harjani 1266ee320674SRitesh Harjani dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", 1267ee320674SRitesh Harjani mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); 1268ee320674SRitesh Harjani sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 1269cc392c58SRitesh Harjani 1270db9bd163SRitesh Harjani if (mmc->ios.timing == MMC_TIMING_MMC_HS400) 1271db9bd163SRitesh Harjani sdhci_msm_hs400(host, &mmc->ios); 1272ee320674SRitesh Harjani } 1273ee320674SRitesh Harjani 1274c0309b38SVijay Viswanath static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host) 1275c0309b38SVijay Viswanath { 1276c0309b38SVijay Viswanath init_waitqueue_head(&msm_host->pwr_irq_wait); 1277c0309b38SVijay Viswanath } 1278c0309b38SVijay Viswanath 1279c0309b38SVijay Viswanath static inline void sdhci_msm_complete_pwr_irq_wait( 1280c0309b38SVijay Viswanath struct sdhci_msm_host *msm_host) 1281c0309b38SVijay Viswanath { 1282c0309b38SVijay Viswanath wake_up(&msm_host->pwr_irq_wait); 1283c0309b38SVijay Viswanath } 1284c0309b38SVijay Viswanath 1285c0309b38SVijay Viswanath /* 1286c0309b38SVijay Viswanath * sdhci_msm_check_power_status API should be called when registers writes 1287c0309b38SVijay Viswanath * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens. 1288c0309b38SVijay Viswanath * To what state the register writes will change the IO lines should be passed 1289c0309b38SVijay Viswanath * as the argument req_type. This API will check whether the IO line's state 1290c0309b38SVijay Viswanath * is already the expected state and will wait for power irq only if 1291c0309b38SVijay Viswanath * power irq is expected to be trigerred based on the current IO line state 1292c0309b38SVijay Viswanath * and expected IO line state. 1293c0309b38SVijay Viswanath */ 1294c0309b38SVijay Viswanath static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) 1295c0309b38SVijay Viswanath { 1296c0309b38SVijay Viswanath struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1297c0309b38SVijay Viswanath struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1298c0309b38SVijay Viswanath bool done = false; 1299bc99266bSSayali Lokhande u32 val = SWITCHABLE_SIGNALING_VOLTAGE; 1300bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 1301bc99266bSSayali Lokhande msm_host->offset; 1302c0309b38SVijay Viswanath 1303c0309b38SVijay Viswanath pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n", 1304c0309b38SVijay Viswanath mmc_hostname(host->mmc), __func__, req_type, 1305c0309b38SVijay Viswanath msm_host->curr_pwr_state, msm_host->curr_io_level); 1306c0309b38SVijay Viswanath 1307c0309b38SVijay Viswanath /* 130852884f8fSBjorn Andersson * The power interrupt will not be generated for signal voltage 130952884f8fSBjorn Andersson * switches if SWITCHABLE_SIGNALING_VOLTAGE in MCI_GENERICS is not set. 1310bc99266bSSayali Lokhande * Since sdhci-msm-v5, this bit has been removed and SW must consider 1311bc99266bSSayali Lokhande * it as always set. 131252884f8fSBjorn Andersson */ 1313bc99266bSSayali Lokhande if (!msm_host->mci_removed) 1314bc99266bSSayali Lokhande val = msm_host_readl(msm_host, host, 1315bc99266bSSayali Lokhande msm_offset->core_generics); 131652884f8fSBjorn Andersson if ((req_type & REQ_IO_HIGH || req_type & REQ_IO_LOW) && 131752884f8fSBjorn Andersson !(val & SWITCHABLE_SIGNALING_VOLTAGE)) { 131852884f8fSBjorn Andersson return; 131952884f8fSBjorn Andersson } 132052884f8fSBjorn Andersson 132152884f8fSBjorn Andersson /* 1322c0309b38SVijay Viswanath * The IRQ for request type IO High/LOW will be generated when - 1323c0309b38SVijay Viswanath * there is a state change in 1.8V enable bit (bit 3) of 1324c0309b38SVijay Viswanath * SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0 1325c0309b38SVijay Viswanath * which indicates 3.3V IO voltage. So, when MMC core layer tries 1326c0309b38SVijay Viswanath * to set it to 3.3V before card detection happens, the 1327c0309b38SVijay Viswanath * IRQ doesn't get triggered as there is no state change in this bit. 1328c0309b38SVijay Viswanath * The driver already handles this case by changing the IO voltage 1329c0309b38SVijay Viswanath * level to high as part of controller power up sequence. Hence, check 1330c0309b38SVijay Viswanath * for host->pwr to handle a case where IO voltage high request is 1331c0309b38SVijay Viswanath * issued even before controller power up. 1332c0309b38SVijay Viswanath */ 1333c0309b38SVijay Viswanath if ((req_type & REQ_IO_HIGH) && !host->pwr) { 1334c0309b38SVijay Viswanath pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n", 1335c0309b38SVijay Viswanath mmc_hostname(host->mmc), req_type); 1336c0309b38SVijay Viswanath return; 1337c0309b38SVijay Viswanath } 1338c0309b38SVijay Viswanath if ((req_type & msm_host->curr_pwr_state) || 1339c0309b38SVijay Viswanath (req_type & msm_host->curr_io_level)) 1340c0309b38SVijay Viswanath done = true; 1341c0309b38SVijay Viswanath /* 1342c0309b38SVijay Viswanath * This is needed here to handle cases where register writes will 1343c0309b38SVijay Viswanath * not change the current bus state or io level of the controller. 1344c0309b38SVijay Viswanath * In this case, no power irq will be triggerred and we should 1345c0309b38SVijay Viswanath * not wait. 1346c0309b38SVijay Viswanath */ 1347c0309b38SVijay Viswanath if (!done) { 1348c0309b38SVijay Viswanath if (!wait_event_timeout(msm_host->pwr_irq_wait, 1349c0309b38SVijay Viswanath msm_host->pwr_irq_flag, 1350c0309b38SVijay Viswanath msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS))) 13519ccfa817SArnd Bergmann dev_warn(&msm_host->pdev->dev, 13529ccfa817SArnd Bergmann "%s: pwr_irq for req: (%d) timed out\n", 1353c0309b38SVijay Viswanath mmc_hostname(host->mmc), req_type); 1354c0309b38SVijay Viswanath } 1355c0309b38SVijay Viswanath pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc), 1356c0309b38SVijay Viswanath __func__, req_type); 1357c0309b38SVijay Viswanath } 1358c0309b38SVijay Viswanath 1359401b2d06SSahitya Tummala static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host) 1360401b2d06SSahitya Tummala { 1361401b2d06SSahitya Tummala struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1362401b2d06SSahitya Tummala struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1363bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = 1364bc99266bSSayali Lokhande msm_host->offset; 1365401b2d06SSahitya Tummala 1366401b2d06SSahitya Tummala pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n", 1367401b2d06SSahitya Tummala mmc_hostname(host->mmc), 1368bc99266bSSayali Lokhande msm_host_readl(msm_host, host, msm_offset->core_pwrctl_status), 1369bc99266bSSayali Lokhande msm_host_readl(msm_host, host, msm_offset->core_pwrctl_mask), 1370bc99266bSSayali Lokhande msm_host_readl(msm_host, host, msm_offset->core_pwrctl_ctl)); 1371401b2d06SSahitya Tummala } 1372401b2d06SSahitya Tummala 1373401b2d06SSahitya Tummala static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) 1374ad81d387SGeorgi Djakov { 1375ad81d387SGeorgi Djakov struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1376ad81d387SGeorgi Djakov struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1377ad81d387SGeorgi Djakov u32 irq_status, irq_ack = 0; 1378401b2d06SSahitya Tummala int retry = 10; 1379ac06fba1SVijay Viswanath u32 pwr_state = 0, io_level = 0; 13805c132323SVijay Viswanath u32 config; 1381bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = msm_host->offset; 1382ad81d387SGeorgi Djakov 1383bc99266bSSayali Lokhande irq_status = msm_host_readl(msm_host, host, 1384bc99266bSSayali Lokhande msm_offset->core_pwrctl_status); 1385ad81d387SGeorgi Djakov irq_status &= INT_MASK; 1386ad81d387SGeorgi Djakov 1387bc99266bSSayali Lokhande msm_host_writel(msm_host, irq_status, host, 1388bc99266bSSayali Lokhande msm_offset->core_pwrctl_clear); 1389ad81d387SGeorgi Djakov 1390401b2d06SSahitya Tummala /* 1391401b2d06SSahitya Tummala * There is a rare HW scenario where the first clear pulse could be 1392401b2d06SSahitya Tummala * lost when actual reset and clear/read of status register is 1393401b2d06SSahitya Tummala * happening at a time. Hence, retry for at least 10 times to make 1394401b2d06SSahitya Tummala * sure status register is cleared. Otherwise, this will result in 1395401b2d06SSahitya Tummala * a spurious power IRQ resulting in system instability. 1396401b2d06SSahitya Tummala */ 1397bc99266bSSayali Lokhande while (irq_status & msm_host_readl(msm_host, host, 1398bc99266bSSayali Lokhande msm_offset->core_pwrctl_status)) { 1399401b2d06SSahitya Tummala if (retry == 0) { 1400401b2d06SSahitya Tummala pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n", 1401401b2d06SSahitya Tummala mmc_hostname(host->mmc), irq_status); 1402401b2d06SSahitya Tummala sdhci_msm_dump_pwr_ctrl_regs(host); 1403401b2d06SSahitya Tummala WARN_ON(1); 1404401b2d06SSahitya Tummala break; 1405401b2d06SSahitya Tummala } 1406bc99266bSSayali Lokhande msm_host_writel(msm_host, irq_status, host, 1407bc99266bSSayali Lokhande msm_offset->core_pwrctl_clear); 1408401b2d06SSahitya Tummala retry--; 1409401b2d06SSahitya Tummala udelay(10); 1410401b2d06SSahitya Tummala } 1411401b2d06SSahitya Tummala 1412c0309b38SVijay Viswanath /* Handle BUS ON/OFF*/ 1413c0309b38SVijay Viswanath if (irq_status & CORE_PWRCTL_BUS_ON) { 1414c0309b38SVijay Viswanath pwr_state = REQ_BUS_ON; 1415c0309b38SVijay Viswanath io_level = REQ_IO_HIGH; 1416ad81d387SGeorgi Djakov irq_ack |= CORE_PWRCTL_BUS_SUCCESS; 1417c0309b38SVijay Viswanath } 1418c0309b38SVijay Viswanath if (irq_status & CORE_PWRCTL_BUS_OFF) { 1419c0309b38SVijay Viswanath pwr_state = REQ_BUS_OFF; 1420c0309b38SVijay Viswanath io_level = REQ_IO_LOW; 1421c0309b38SVijay Viswanath irq_ack |= CORE_PWRCTL_BUS_SUCCESS; 1422c0309b38SVijay Viswanath } 1423c0309b38SVijay Viswanath /* Handle IO LOW/HIGH */ 1424c0309b38SVijay Viswanath if (irq_status & CORE_PWRCTL_IO_LOW) { 1425c0309b38SVijay Viswanath io_level = REQ_IO_LOW; 1426ad81d387SGeorgi Djakov irq_ack |= CORE_PWRCTL_IO_SUCCESS; 1427c0309b38SVijay Viswanath } 1428c0309b38SVijay Viswanath if (irq_status & CORE_PWRCTL_IO_HIGH) { 1429c0309b38SVijay Viswanath io_level = REQ_IO_HIGH; 1430c0309b38SVijay Viswanath irq_ack |= CORE_PWRCTL_IO_SUCCESS; 1431c0309b38SVijay Viswanath } 1432ad81d387SGeorgi Djakov 1433ad81d387SGeorgi Djakov /* 1434ad81d387SGeorgi Djakov * The driver has to acknowledge the interrupt, switch voltages and 1435ad81d387SGeorgi Djakov * report back if it succeded or not to this register. The voltage 1436ad81d387SGeorgi Djakov * switches are handled by the sdhci core, so just report success. 1437ad81d387SGeorgi Djakov */ 1438bc99266bSSayali Lokhande msm_host_writel(msm_host, irq_ack, host, 1439bc99266bSSayali Lokhande msm_offset->core_pwrctl_ctl); 1440401b2d06SSahitya Tummala 14415c132323SVijay Viswanath /* 14425c132323SVijay Viswanath * If we don't have info regarding the voltage levels supported by 14435c132323SVijay Viswanath * regulators, don't change the IO PAD PWR SWITCH. 14445c132323SVijay Viswanath */ 14455c132323SVijay Viswanath if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { 14465c132323SVijay Viswanath u32 new_config; 14475c132323SVijay Viswanath /* 14485c132323SVijay Viswanath * We should unset IO PAD PWR switch only if the register write 14495c132323SVijay Viswanath * can set IO lines high and the regulator also switches to 3 V. 14505c132323SVijay Viswanath * Else, we should keep the IO PAD PWR switch set. 14515c132323SVijay Viswanath * This is applicable to certain targets where eMMC vccq supply 14525c132323SVijay Viswanath * is only 1.8V. In such targets, even during REQ_IO_HIGH, the 14535c132323SVijay Viswanath * IO PAD PWR switch must be kept set to reflect actual 14545c132323SVijay Viswanath * regulator voltage. This way, during initialization of 14555c132323SVijay Viswanath * controllers with only 1.8V, we will set the IO PAD bit 14565c132323SVijay Viswanath * without waiting for a REQ_IO_LOW. 14575c132323SVijay Viswanath */ 1458bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 1459bc99266bSSayali Lokhande msm_offset->core_vendor_spec); 14605c132323SVijay Viswanath new_config = config; 14615c132323SVijay Viswanath 14625c132323SVijay Viswanath if ((io_level & REQ_IO_HIGH) && 14635c132323SVijay Viswanath (msm_host->caps_0 & CORE_3_0V_SUPPORT)) 14645c132323SVijay Viswanath new_config &= ~CORE_IO_PAD_PWR_SWITCH; 14655c132323SVijay Viswanath else if ((io_level & REQ_IO_LOW) || 14665c132323SVijay Viswanath (msm_host->caps_0 & CORE_1_8V_SUPPORT)) 14675c132323SVijay Viswanath new_config |= CORE_IO_PAD_PWR_SWITCH; 14685c132323SVijay Viswanath 14695c132323SVijay Viswanath if (config ^ new_config) 1470bc99266bSSayali Lokhande writel_relaxed(new_config, host->ioaddr + 1471bc99266bSSayali Lokhande msm_offset->core_vendor_spec); 14725c132323SVijay Viswanath } 14735c132323SVijay Viswanath 1474c0309b38SVijay Viswanath if (pwr_state) 1475c0309b38SVijay Viswanath msm_host->curr_pwr_state = pwr_state; 1476c0309b38SVijay Viswanath if (io_level) 1477c0309b38SVijay Viswanath msm_host->curr_io_level = io_level; 1478c0309b38SVijay Viswanath 1479401b2d06SSahitya Tummala pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n", 1480401b2d06SSahitya Tummala mmc_hostname(msm_host->mmc), __func__, irq, irq_status, 1481401b2d06SSahitya Tummala irq_ack); 1482ad81d387SGeorgi Djakov } 1483ad81d387SGeorgi Djakov 1484ad81d387SGeorgi Djakov static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) 1485ad81d387SGeorgi Djakov { 1486ad81d387SGeorgi Djakov struct sdhci_host *host = (struct sdhci_host *)data; 1487c0309b38SVijay Viswanath struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1488c0309b38SVijay Viswanath struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1489ad81d387SGeorgi Djakov 1490401b2d06SSahitya Tummala sdhci_msm_handle_pwr_irq(host, irq); 1491c0309b38SVijay Viswanath msm_host->pwr_irq_flag = 1; 1492c0309b38SVijay Viswanath sdhci_msm_complete_pwr_irq_wait(msm_host); 1493c0309b38SVijay Viswanath 1494ad81d387SGeorgi Djakov 1495ad81d387SGeorgi Djakov return IRQ_HANDLED; 1496ad81d387SGeorgi Djakov } 1497ad81d387SGeorgi Djakov 149880031bdeSRitesh Harjani static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host) 149980031bdeSRitesh Harjani { 150080031bdeSRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 150180031bdeSRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1502e4bf91f6SBjorn Andersson struct clk *core_clk = msm_host->bulk_clks[0].clk; 150380031bdeSRitesh Harjani 1504e4bf91f6SBjorn Andersson return clk_round_rate(core_clk, ULONG_MAX); 150580031bdeSRitesh Harjani } 150680031bdeSRitesh Harjani 150780031bdeSRitesh Harjani static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host) 150880031bdeSRitesh Harjani { 150980031bdeSRitesh Harjani return SDHCI_MSM_MIN_CLOCK; 151080031bdeSRitesh Harjani } 151180031bdeSRitesh Harjani 1512edc609fdSRitesh Harjani /** 1513edc609fdSRitesh Harjani * __sdhci_msm_set_clock - sdhci_msm clock control. 1514edc609fdSRitesh Harjani * 1515edc609fdSRitesh Harjani * Description: 1516edc609fdSRitesh Harjani * MSM controller does not use internal divider and 1517edc609fdSRitesh Harjani * instead directly control the GCC clock as per 1518edc609fdSRitesh Harjani * HW recommendation. 1519edc609fdSRitesh Harjani **/ 152030de038dSMasahiro Yamada static void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) 1521edc609fdSRitesh Harjani { 1522edc609fdSRitesh Harjani u16 clk; 1523edc609fdSRitesh Harjani /* 1524edc609fdSRitesh Harjani * Keep actual_clock as zero - 1525edc609fdSRitesh Harjani * - since there is no divider used so no need of having actual_clock. 1526edc609fdSRitesh Harjani * - MSM controller uses SDCLK for data timeout calculation. If 1527edc609fdSRitesh Harjani * actual_clock is zero, host->clock is taken for calculation. 1528edc609fdSRitesh Harjani */ 1529edc609fdSRitesh Harjani host->mmc->actual_clock = 0; 1530edc609fdSRitesh Harjani 1531edc609fdSRitesh Harjani sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 1532edc609fdSRitesh Harjani 1533edc609fdSRitesh Harjani if (clock == 0) 1534edc609fdSRitesh Harjani return; 1535edc609fdSRitesh Harjani 1536edc609fdSRitesh Harjani /* 1537edc609fdSRitesh Harjani * MSM controller do not use clock divider. 1538edc609fdSRitesh Harjani * Thus read SDHCI_CLOCK_CONTROL and only enable 1539edc609fdSRitesh Harjani * clock with no divider value programmed. 1540edc609fdSRitesh Harjani */ 1541edc609fdSRitesh Harjani clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 1542edc609fdSRitesh Harjani sdhci_enable_clk(host, clk); 1543edc609fdSRitesh Harjani } 1544edc609fdSRitesh Harjani 1545edc609fdSRitesh Harjani /* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */ 1546edc609fdSRitesh Harjani static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) 1547edc609fdSRitesh Harjani { 1548edc609fdSRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1549edc609fdSRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1550edc609fdSRitesh Harjani 1551edc609fdSRitesh Harjani if (!clock) { 1552edc609fdSRitesh Harjani msm_host->clk_rate = clock; 1553edc609fdSRitesh Harjani goto out; 1554edc609fdSRitesh Harjani } 1555edc609fdSRitesh Harjani 1556b54aaa8aSRitesh Harjani sdhci_msm_hc_select_mode(host); 1557edc609fdSRitesh Harjani 15580fb8a3d4SRitesh Harjani msm_set_clock_rate_for_bus_mode(host, clock); 1559edc609fdSRitesh Harjani out: 1560edc609fdSRitesh Harjani __sdhci_msm_set_clock(host, clock); 1561edc609fdSRitesh Harjani } 1562edc609fdSRitesh Harjani 1563c0309b38SVijay Viswanath /* 1564c0309b38SVijay Viswanath * Platform specific register write functions. This is so that, if any 1565c0309b38SVijay Viswanath * register write needs to be followed up by platform specific actions, 1566c0309b38SVijay Viswanath * they can be added here. These functions can go to sleep when writes 1567c0309b38SVijay Viswanath * to certain registers are done. 1568c0309b38SVijay Viswanath * These functions are relying on sdhci_set_ios not using spinlock. 1569c0309b38SVijay Viswanath */ 1570c0309b38SVijay Viswanath static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg) 1571c0309b38SVijay Viswanath { 1572c0309b38SVijay Viswanath struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1573c0309b38SVijay Viswanath struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1574c0309b38SVijay Viswanath u32 req_type = 0; 1575c0309b38SVijay Viswanath 1576c0309b38SVijay Viswanath switch (reg) { 1577c0309b38SVijay Viswanath case SDHCI_HOST_CONTROL2: 1578c0309b38SVijay Viswanath req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW : 1579c0309b38SVijay Viswanath REQ_IO_HIGH; 1580c0309b38SVijay Viswanath break; 1581c0309b38SVijay Viswanath case SDHCI_SOFTWARE_RESET: 1582c0309b38SVijay Viswanath if (host->pwr && (val & SDHCI_RESET_ALL)) 1583c0309b38SVijay Viswanath req_type = REQ_BUS_OFF; 1584c0309b38SVijay Viswanath break; 1585c0309b38SVijay Viswanath case SDHCI_POWER_CONTROL: 1586c0309b38SVijay Viswanath req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON; 1587c0309b38SVijay Viswanath break; 1588a89e7bcbSLoic Poulain case SDHCI_TRANSFER_MODE: 1589a89e7bcbSLoic Poulain msm_host->transfer_mode = val; 1590a89e7bcbSLoic Poulain break; 1591a89e7bcbSLoic Poulain case SDHCI_COMMAND: 1592a89e7bcbSLoic Poulain if (!msm_host->use_cdr) 1593a89e7bcbSLoic Poulain break; 1594a89e7bcbSLoic Poulain if ((msm_host->transfer_mode & SDHCI_TRNS_READ) && 1595a89e7bcbSLoic Poulain SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 && 1596a89e7bcbSLoic Poulain SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK) 1597a89e7bcbSLoic Poulain sdhci_msm_set_cdr(host, true); 1598a89e7bcbSLoic Poulain else 1599a89e7bcbSLoic Poulain sdhci_msm_set_cdr(host, false); 1600a89e7bcbSLoic Poulain break; 1601c0309b38SVijay Viswanath } 1602c0309b38SVijay Viswanath 1603c0309b38SVijay Viswanath if (req_type) { 1604c0309b38SVijay Viswanath msm_host->pwr_irq_flag = 0; 1605c0309b38SVijay Viswanath /* 1606c0309b38SVijay Viswanath * Since this register write may trigger a power irq, ensure 1607c0309b38SVijay Viswanath * all previous register writes are complete by this point. 1608c0309b38SVijay Viswanath */ 1609c0309b38SVijay Viswanath mb(); 1610c0309b38SVijay Viswanath } 1611c0309b38SVijay Viswanath return req_type; 1612c0309b38SVijay Viswanath } 1613c0309b38SVijay Viswanath 1614c0309b38SVijay Viswanath /* This function may sleep*/ 1615c0309b38SVijay Viswanath static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg) 1616c0309b38SVijay Viswanath { 1617c0309b38SVijay Viswanath u32 req_type = 0; 1618c0309b38SVijay Viswanath 1619c0309b38SVijay Viswanath req_type = __sdhci_msm_check_write(host, val, reg); 1620c0309b38SVijay Viswanath writew_relaxed(val, host->ioaddr + reg); 1621c0309b38SVijay Viswanath 1622c0309b38SVijay Viswanath if (req_type) 1623c0309b38SVijay Viswanath sdhci_msm_check_power_status(host, req_type); 1624c0309b38SVijay Viswanath } 1625c0309b38SVijay Viswanath 1626c0309b38SVijay Viswanath /* This function may sleep*/ 1627c0309b38SVijay Viswanath static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) 1628c0309b38SVijay Viswanath { 1629c0309b38SVijay Viswanath u32 req_type = 0; 1630c0309b38SVijay Viswanath 1631c0309b38SVijay Viswanath req_type = __sdhci_msm_check_write(host, val, reg); 1632c0309b38SVijay Viswanath 1633c0309b38SVijay Viswanath writeb_relaxed(val, host->ioaddr + reg); 1634c0309b38SVijay Viswanath 1635c0309b38SVijay Viswanath if (req_type) 1636c0309b38SVijay Viswanath sdhci_msm_check_power_status(host, req_type); 1637c0309b38SVijay Viswanath } 1638c0309b38SVijay Viswanath 1639ac06fba1SVijay Viswanath static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) 1640ac06fba1SVijay Viswanath { 1641ac06fba1SVijay Viswanath struct mmc_host *mmc = msm_host->mmc; 1642ac06fba1SVijay Viswanath struct regulator *supply = mmc->supply.vqmmc; 16435c132323SVijay Viswanath u32 caps = 0, config; 16445c132323SVijay Viswanath struct sdhci_host *host = mmc_priv(mmc); 1645bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset = msm_host->offset; 1646ac06fba1SVijay Viswanath 1647ac06fba1SVijay Viswanath if (!IS_ERR(mmc->supply.vqmmc)) { 1648ac06fba1SVijay Viswanath if (regulator_is_supported_voltage(supply, 1700000, 1950000)) 1649ac06fba1SVijay Viswanath caps |= CORE_1_8V_SUPPORT; 1650ac06fba1SVijay Viswanath if (regulator_is_supported_voltage(supply, 2700000, 3600000)) 1651ac06fba1SVijay Viswanath caps |= CORE_3_0V_SUPPORT; 1652ac06fba1SVijay Viswanath 1653ac06fba1SVijay Viswanath if (!caps) 1654ac06fba1SVijay Viswanath pr_warn("%s: 1.8/3V not supported for vqmmc\n", 1655ac06fba1SVijay Viswanath mmc_hostname(mmc)); 1656ac06fba1SVijay Viswanath } 1657ac06fba1SVijay Viswanath 16585c132323SVijay Viswanath if (caps) { 16595c132323SVijay Viswanath /* 16605c132323SVijay Viswanath * Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH 16615c132323SVijay Viswanath * bit can be used as required later on. 16625c132323SVijay Viswanath */ 16635c132323SVijay Viswanath u32 io_level = msm_host->curr_io_level; 16645c132323SVijay Viswanath 1665bc99266bSSayali Lokhande config = readl_relaxed(host->ioaddr + 1666bc99266bSSayali Lokhande msm_offset->core_vendor_spec); 16675c132323SVijay Viswanath config |= CORE_IO_PAD_PWR_SWITCH_EN; 16685c132323SVijay Viswanath 16695c132323SVijay Viswanath if ((io_level & REQ_IO_HIGH) && (caps & CORE_3_0V_SUPPORT)) 16705c132323SVijay Viswanath config &= ~CORE_IO_PAD_PWR_SWITCH; 16715c132323SVijay Viswanath else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT)) 16725c132323SVijay Viswanath config |= CORE_IO_PAD_PWR_SWITCH; 16735c132323SVijay Viswanath 1674bc99266bSSayali Lokhande writel_relaxed(config, 1675bc99266bSSayali Lokhande host->ioaddr + msm_offset->core_vendor_spec); 16765c132323SVijay Viswanath } 1677ac06fba1SVijay Viswanath msm_host->caps_0 |= caps; 1678ac06fba1SVijay Viswanath pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); 1679ac06fba1SVijay Viswanath } 1680ac06fba1SVijay Viswanath 16816ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_ops mci_var_ops = { 16826ed4bb43SVijay Viswanath .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, 16836ed4bb43SVijay Viswanath .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, 16846ed4bb43SVijay Viswanath }; 16856ed4bb43SVijay Viswanath 16866ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_ops v5_var_ops = { 16876ed4bb43SVijay Viswanath .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, 16886ed4bb43SVijay Viswanath .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, 16896ed4bb43SVijay Viswanath }; 16906ed4bb43SVijay Viswanath 16916ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_info sdhci_msm_mci_var = { 16926ed4bb43SVijay Viswanath .var_ops = &mci_var_ops, 16936ed4bb43SVijay Viswanath .offset = &sdhci_msm_mci_offset, 16946ed4bb43SVijay Viswanath }; 16956ed4bb43SVijay Viswanath 16966ed4bb43SVijay Viswanath static const struct sdhci_msm_variant_info sdhci_msm_v5_var = { 16976ed4bb43SVijay Viswanath .mci_removed = true, 16986ed4bb43SVijay Viswanath .var_ops = &v5_var_ops, 16996ed4bb43SVijay Viswanath .offset = &sdhci_msm_v5_offset, 17006ed4bb43SVijay Viswanath }; 17016ed4bb43SVijay Viswanath 170221f1e2d4SVeerabhadrarao Badiganti static const struct sdhci_msm_variant_info sdm845_sdhci_var = { 170321f1e2d4SVeerabhadrarao Badiganti .mci_removed = true, 170421f1e2d4SVeerabhadrarao Badiganti .restore_dll_config = true, 170521f1e2d4SVeerabhadrarao Badiganti .var_ops = &v5_var_ops, 170621f1e2d4SVeerabhadrarao Badiganti .offset = &sdhci_msm_v5_offset, 170721f1e2d4SVeerabhadrarao Badiganti }; 170821f1e2d4SVeerabhadrarao Badiganti 17090eb0d9f4SGeorgi Djakov static const struct of_device_id sdhci_msm_dt_match[] = { 1710bc99266bSSayali Lokhande {.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var}, 1711bc99266bSSayali Lokhande {.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var}, 171221f1e2d4SVeerabhadrarao Badiganti {.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var}, 17130eb0d9f4SGeorgi Djakov {}, 17140eb0d9f4SGeorgi Djakov }; 17150eb0d9f4SGeorgi Djakov 17160eb0d9f4SGeorgi Djakov MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); 17170eb0d9f4SGeorgi Djakov 1718a50396a4SJisheng Zhang static const struct sdhci_ops sdhci_msm_ops = { 1719ed1761d7SStephen Boyd .reset = sdhci_reset, 1720edc609fdSRitesh Harjani .set_clock = sdhci_msm_set_clock, 172180031bdeSRitesh Harjani .get_min_clock = sdhci_msm_get_min_clock, 172280031bdeSRitesh Harjani .get_max_clock = sdhci_msm_get_max_clock, 1723ed1761d7SStephen Boyd .set_bus_width = sdhci_set_bus_width, 1724ee320674SRitesh Harjani .set_uhs_signaling = sdhci_msm_set_uhs_signaling, 1725c0309b38SVijay Viswanath .write_w = sdhci_msm_writew, 1726c0309b38SVijay Viswanath .write_b = sdhci_msm_writeb, 17270eb0d9f4SGeorgi Djakov }; 17280eb0d9f4SGeorgi Djakov 1729a50396a4SJisheng Zhang static const struct sdhci_pltfm_data sdhci_msm_pdata = { 1730a50396a4SJisheng Zhang .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | 1731a0e31428SRitesh Harjani SDHCI_QUIRK_SINGLE_POWER_WRITE | 1732a0e31428SRitesh Harjani SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 1733a0e31428SRitesh Harjani .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 1734a50396a4SJisheng Zhang .ops = &sdhci_msm_ops, 1735a50396a4SJisheng Zhang }; 1736a50396a4SJisheng Zhang 17370eb0d9f4SGeorgi Djakov static int sdhci_msm_probe(struct platform_device *pdev) 17380eb0d9f4SGeorgi Djakov { 17390eb0d9f4SGeorgi Djakov struct sdhci_host *host; 17400eb0d9f4SGeorgi Djakov struct sdhci_pltfm_host *pltfm_host; 17410eb0d9f4SGeorgi Djakov struct sdhci_msm_host *msm_host; 17420eb0d9f4SGeorgi Djakov struct resource *core_memres; 1743e4bf91f6SBjorn Andersson struct clk *clk; 17440eb0d9f4SGeorgi Djakov int ret; 17453a3ad3e9SGeorgi Djakov u16 host_version, core_minor; 174629301f40SRitesh Harjani u32 core_version, config; 17473a3ad3e9SGeorgi Djakov u8 core_major; 1748bc99266bSSayali Lokhande const struct sdhci_msm_offset *msm_offset; 1749bc99266bSSayali Lokhande const struct sdhci_msm_variant_info *var_info; 17500eb0d9f4SGeorgi Djakov 17516f699531SJisheng Zhang host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host)); 17520eb0d9f4SGeorgi Djakov if (IS_ERR(host)) 17530eb0d9f4SGeorgi Djakov return PTR_ERR(host); 17540eb0d9f4SGeorgi Djakov 17552a641e53SSrinivas Kandagatla host->sdma_boundary = 0; 17560eb0d9f4SGeorgi Djakov pltfm_host = sdhci_priv(host); 17576f699531SJisheng Zhang msm_host = sdhci_pltfm_priv(pltfm_host); 17580eb0d9f4SGeorgi Djakov msm_host->mmc = host->mmc; 17590eb0d9f4SGeorgi Djakov msm_host->pdev = pdev; 17600eb0d9f4SGeorgi Djakov 17610eb0d9f4SGeorgi Djakov ret = mmc_of_parse(host->mmc); 17620eb0d9f4SGeorgi Djakov if (ret) 17630eb0d9f4SGeorgi Djakov goto pltfm_free; 17640eb0d9f4SGeorgi Djakov 1765bc99266bSSayali Lokhande /* 1766bc99266bSSayali Lokhande * Based on the compatible string, load the required msm host info from 1767bc99266bSSayali Lokhande * the data associated with the version info. 1768bc99266bSSayali Lokhande */ 1769bc99266bSSayali Lokhande var_info = of_device_get_match_data(&pdev->dev); 1770bc99266bSSayali Lokhande 1771bc99266bSSayali Lokhande msm_host->mci_removed = var_info->mci_removed; 177221f1e2d4SVeerabhadrarao Badiganti msm_host->restore_dll_config = var_info->restore_dll_config; 1773bc99266bSSayali Lokhande msm_host->var_ops = var_info->var_ops; 1774bc99266bSSayali Lokhande msm_host->offset = var_info->offset; 1775bc99266bSSayali Lokhande 1776bc99266bSSayali Lokhande msm_offset = msm_host->offset; 1777bc99266bSSayali Lokhande 17780eb0d9f4SGeorgi Djakov sdhci_get_of_property(pdev); 17790eb0d9f4SGeorgi Djakov 1780abf270e5SRitesh Harjani msm_host->saved_tuning_phase = INVALID_TUNING_PHASE; 1781abf270e5SRitesh Harjani 17820eb0d9f4SGeorgi Djakov /* Setup SDCC bus voter clock. */ 17830eb0d9f4SGeorgi Djakov msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus"); 17840eb0d9f4SGeorgi Djakov if (!IS_ERR(msm_host->bus_clk)) { 17850eb0d9f4SGeorgi Djakov /* Vote for max. clk rate for max. performance */ 17860eb0d9f4SGeorgi Djakov ret = clk_set_rate(msm_host->bus_clk, INT_MAX); 17870eb0d9f4SGeorgi Djakov if (ret) 17880eb0d9f4SGeorgi Djakov goto pltfm_free; 17890eb0d9f4SGeorgi Djakov ret = clk_prepare_enable(msm_host->bus_clk); 17900eb0d9f4SGeorgi Djakov if (ret) 17910eb0d9f4SGeorgi Djakov goto pltfm_free; 17920eb0d9f4SGeorgi Djakov } 17930eb0d9f4SGeorgi Djakov 17940eb0d9f4SGeorgi Djakov /* Setup main peripheral bus clock */ 1795e4bf91f6SBjorn Andersson clk = devm_clk_get(&pdev->dev, "iface"); 1796e4bf91f6SBjorn Andersson if (IS_ERR(clk)) { 1797e4bf91f6SBjorn Andersson ret = PTR_ERR(clk); 17982801b95eSColin Ian King dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret); 17990eb0d9f4SGeorgi Djakov goto bus_clk_disable; 18000eb0d9f4SGeorgi Djakov } 1801e4bf91f6SBjorn Andersson msm_host->bulk_clks[1].clk = clk; 18020eb0d9f4SGeorgi Djakov 18030eb0d9f4SGeorgi Djakov /* Setup SDC MMC clock */ 1804e4bf91f6SBjorn Andersson clk = devm_clk_get(&pdev->dev, "core"); 1805e4bf91f6SBjorn Andersson if (IS_ERR(clk)) { 1806e4bf91f6SBjorn Andersson ret = PTR_ERR(clk); 18070eb0d9f4SGeorgi Djakov dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret); 1808e4bf91f6SBjorn Andersson goto bus_clk_disable; 18090eb0d9f4SGeorgi Djakov } 1810e4bf91f6SBjorn Andersson msm_host->bulk_clks[0].clk = clk; 1811e4bf91f6SBjorn Andersson 1812e4bf91f6SBjorn Andersson /* Vote for maximum clock rate for maximum performance */ 1813e4bf91f6SBjorn Andersson ret = clk_set_rate(clk, INT_MAX); 1814e4bf91f6SBjorn Andersson if (ret) 1815e4bf91f6SBjorn Andersson dev_warn(&pdev->dev, "core clock boost failed\n"); 1816e4bf91f6SBjorn Andersson 18174946b3afSBjorn Andersson clk = devm_clk_get(&pdev->dev, "cal"); 18184946b3afSBjorn Andersson if (IS_ERR(clk)) 18194946b3afSBjorn Andersson clk = NULL; 18204946b3afSBjorn Andersson msm_host->bulk_clks[2].clk = clk; 18214946b3afSBjorn Andersson 18224946b3afSBjorn Andersson clk = devm_clk_get(&pdev->dev, "sleep"); 18234946b3afSBjorn Andersson if (IS_ERR(clk)) 18244946b3afSBjorn Andersson clk = NULL; 18254946b3afSBjorn Andersson msm_host->bulk_clks[3].clk = clk; 18264946b3afSBjorn Andersson 1827e4bf91f6SBjorn Andersson ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), 1828e4bf91f6SBjorn Andersson msm_host->bulk_clks); 1829e4bf91f6SBjorn Andersson if (ret) 1830e4bf91f6SBjorn Andersson goto bus_clk_disable; 18310eb0d9f4SGeorgi Djakov 183283736352SVenkat Gopalakrishnan /* 183383736352SVenkat Gopalakrishnan * xo clock is needed for FLL feature of cm_dll. 183483736352SVenkat Gopalakrishnan * In case if xo clock is not mentioned in DT, warn and proceed. 183583736352SVenkat Gopalakrishnan */ 183683736352SVenkat Gopalakrishnan msm_host->xo_clk = devm_clk_get(&pdev->dev, "xo"); 183783736352SVenkat Gopalakrishnan if (IS_ERR(msm_host->xo_clk)) { 183883736352SVenkat Gopalakrishnan ret = PTR_ERR(msm_host->xo_clk); 183983736352SVenkat Gopalakrishnan dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret); 184083736352SVenkat Gopalakrishnan } 184183736352SVenkat Gopalakrishnan 1842bc99266bSSayali Lokhande if (!msm_host->mci_removed) { 18430eb0d9f4SGeorgi Djakov core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1844bc99266bSSayali Lokhande msm_host->core_mem = devm_ioremap_resource(&pdev->dev, 1845bc99266bSSayali Lokhande core_memres); 18460eb0d9f4SGeorgi Djakov 18470eb0d9f4SGeorgi Djakov if (IS_ERR(msm_host->core_mem)) { 18480eb0d9f4SGeorgi Djakov ret = PTR_ERR(msm_host->core_mem); 18490eb0d9f4SGeorgi Djakov goto clk_disable; 18500eb0d9f4SGeorgi Djakov } 1851bc99266bSSayali Lokhande } 18520eb0d9f4SGeorgi Djakov 18535574ddccSVenkat Gopalakrishnan /* Reset the vendor spec register to power on reset state */ 18545574ddccSVenkat Gopalakrishnan writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, 1855bc99266bSSayali Lokhande host->ioaddr + msm_offset->core_vendor_spec); 18560eb0d9f4SGeorgi Djakov 1857bc99266bSSayali Lokhande if (!msm_host->mci_removed) { 18580eb0d9f4SGeorgi Djakov /* Set HC_MODE_EN bit in HC_MODE register */ 1859bc99266bSSayali Lokhande msm_host_writel(msm_host, HC_MODE_EN, host, 1860bc99266bSSayali Lokhande msm_offset->core_hc_mode); 1861bc99266bSSayali Lokhande config = msm_host_readl(msm_host, host, 1862bc99266bSSayali Lokhande msm_offset->core_hc_mode); 1863ff06ce41SVenkat Gopalakrishnan config |= FF_CLK_SW_RST_DIS; 1864bc99266bSSayali Lokhande msm_host_writel(msm_host, config, host, 1865bc99266bSSayali Lokhande msm_offset->core_hc_mode); 1866bc99266bSSayali Lokhande } 1867ff06ce41SVenkat Gopalakrishnan 18680eb0d9f4SGeorgi Djakov host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); 18690eb0d9f4SGeorgi Djakov dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", 18700eb0d9f4SGeorgi Djakov host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> 18710eb0d9f4SGeorgi Djakov SDHCI_VENDOR_VER_SHIFT)); 18720eb0d9f4SGeorgi Djakov 1873bc99266bSSayali Lokhande core_version = msm_host_readl(msm_host, host, 1874bc99266bSSayali Lokhande msm_offset->core_mci_version); 18753a3ad3e9SGeorgi Djakov core_major = (core_version & CORE_VERSION_MAJOR_MASK) >> 18763a3ad3e9SGeorgi Djakov CORE_VERSION_MAJOR_SHIFT; 18773a3ad3e9SGeorgi Djakov core_minor = core_version & CORE_VERSION_MINOR_MASK; 18783a3ad3e9SGeorgi Djakov dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n", 18793a3ad3e9SGeorgi Djakov core_version, core_major, core_minor); 18803a3ad3e9SGeorgi Djakov 188183736352SVenkat Gopalakrishnan if (core_major == 1 && core_minor >= 0x42) 188283736352SVenkat Gopalakrishnan msm_host->use_14lpp_dll_reset = true; 188383736352SVenkat Gopalakrishnan 18843a3ad3e9SGeorgi Djakov /* 188502e4293dSRitesh Harjani * SDCC 5 controller with major version 1, minor version 0x34 and later 188602e4293dSRitesh Harjani * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL. 188702e4293dSRitesh Harjani */ 188802e4293dSRitesh Harjani if (core_major == 1 && core_minor < 0x34) 188902e4293dSRitesh Harjani msm_host->use_cdclp533 = true; 189002e4293dSRitesh Harjani 189102e4293dSRitesh Harjani /* 18923a3ad3e9SGeorgi Djakov * Support for some capabilities is not advertised by newer 18933a3ad3e9SGeorgi Djakov * controller versions and must be explicitly enabled. 18943a3ad3e9SGeorgi Djakov */ 18953a3ad3e9SGeorgi Djakov if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) { 189629301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES); 189729301f40SRitesh Harjani config |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT; 189829301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + 1899bc99266bSSayali Lokhande msm_offset->core_vendor_spec_capabilities0); 19003a3ad3e9SGeorgi Djakov } 19013a3ad3e9SGeorgi Djakov 1902c7ccee22SSubhash Jadavani /* 1903c7ccee22SSubhash Jadavani * Power on reset state may trigger power irq if previous status of 1904c7ccee22SSubhash Jadavani * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq 1905c7ccee22SSubhash Jadavani * interrupt in GIC, any pending power irq interrupt should be 1906c7ccee22SSubhash Jadavani * acknowledged. Otherwise power irq interrupt handler would be 1907c7ccee22SSubhash Jadavani * fired prematurely. 1908c7ccee22SSubhash Jadavani */ 1909401b2d06SSahitya Tummala sdhci_msm_handle_pwr_irq(host, 0); 1910c7ccee22SSubhash Jadavani 1911c7ccee22SSubhash Jadavani /* 1912c7ccee22SSubhash Jadavani * Ensure that above writes are propogated before interrupt enablement 1913c7ccee22SSubhash Jadavani * in GIC. 1914c7ccee22SSubhash Jadavani */ 1915c7ccee22SSubhash Jadavani mb(); 1916c7ccee22SSubhash Jadavani 1917ad81d387SGeorgi Djakov /* Setup IRQ for handling power/voltage tasks with PMIC */ 1918ad81d387SGeorgi Djakov msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq"); 1919ad81d387SGeorgi Djakov if (msm_host->pwr_irq < 0) { 1920ad81d387SGeorgi Djakov dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n", 1921ad81d387SGeorgi Djakov msm_host->pwr_irq); 1922d1f63f0cSWei Yongjun ret = msm_host->pwr_irq; 1923ad81d387SGeorgi Djakov goto clk_disable; 1924ad81d387SGeorgi Djakov } 1925ad81d387SGeorgi Djakov 1926c0309b38SVijay Viswanath sdhci_msm_init_pwr_irq_wait(msm_host); 1927c7ccee22SSubhash Jadavani /* Enable pwr irq interrupts */ 1928bc99266bSSayali Lokhande msm_host_writel(msm_host, INT_MASK, host, 1929bc99266bSSayali Lokhande msm_offset->core_pwrctl_mask); 1930c7ccee22SSubhash Jadavani 1931ad81d387SGeorgi Djakov ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL, 1932ad81d387SGeorgi Djakov sdhci_msm_pwr_irq, IRQF_ONESHOT, 1933ad81d387SGeorgi Djakov dev_name(&pdev->dev), host); 1934ad81d387SGeorgi Djakov if (ret) { 1935ad81d387SGeorgi Djakov dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret); 1936ad81d387SGeorgi Djakov goto clk_disable; 1937ad81d387SGeorgi Djakov } 1938ad81d387SGeorgi Djakov 193967e6db11SPramod Gurav pm_runtime_get_noresume(&pdev->dev); 194067e6db11SPramod Gurav pm_runtime_set_active(&pdev->dev); 194167e6db11SPramod Gurav pm_runtime_enable(&pdev->dev); 194267e6db11SPramod Gurav pm_runtime_set_autosuspend_delay(&pdev->dev, 194367e6db11SPramod Gurav MSM_MMC_AUTOSUSPEND_DELAY_MS); 194467e6db11SPramod Gurav pm_runtime_use_autosuspend(&pdev->dev); 194567e6db11SPramod Gurav 19464436c535SRitesh Harjani host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning; 19470eb0d9f4SGeorgi Djakov ret = sdhci_add_host(host); 19480eb0d9f4SGeorgi Djakov if (ret) 194967e6db11SPramod Gurav goto pm_runtime_disable; 1950ac06fba1SVijay Viswanath sdhci_msm_set_regulator_caps(msm_host); 195167e6db11SPramod Gurav 195267e6db11SPramod Gurav pm_runtime_mark_last_busy(&pdev->dev); 195367e6db11SPramod Gurav pm_runtime_put_autosuspend(&pdev->dev); 19540eb0d9f4SGeorgi Djakov 19550eb0d9f4SGeorgi Djakov return 0; 19560eb0d9f4SGeorgi Djakov 195767e6db11SPramod Gurav pm_runtime_disable: 195867e6db11SPramod Gurav pm_runtime_disable(&pdev->dev); 195967e6db11SPramod Gurav pm_runtime_set_suspended(&pdev->dev); 196067e6db11SPramod Gurav pm_runtime_put_noidle(&pdev->dev); 19610eb0d9f4SGeorgi Djakov clk_disable: 1962e4bf91f6SBjorn Andersson clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), 1963e4bf91f6SBjorn Andersson msm_host->bulk_clks); 19640eb0d9f4SGeorgi Djakov bus_clk_disable: 19650eb0d9f4SGeorgi Djakov if (!IS_ERR(msm_host->bus_clk)) 19660eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->bus_clk); 19670eb0d9f4SGeorgi Djakov pltfm_free: 19680eb0d9f4SGeorgi Djakov sdhci_pltfm_free(pdev); 19690eb0d9f4SGeorgi Djakov return ret; 19700eb0d9f4SGeorgi Djakov } 19710eb0d9f4SGeorgi Djakov 19720eb0d9f4SGeorgi Djakov static int sdhci_msm_remove(struct platform_device *pdev) 19730eb0d9f4SGeorgi Djakov { 19740eb0d9f4SGeorgi Djakov struct sdhci_host *host = platform_get_drvdata(pdev); 19750eb0d9f4SGeorgi Djakov struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 19766f699531SJisheng Zhang struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 19770eb0d9f4SGeorgi Djakov int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 19780eb0d9f4SGeorgi Djakov 0xffffffff); 19790eb0d9f4SGeorgi Djakov 19800eb0d9f4SGeorgi Djakov sdhci_remove_host(host, dead); 198167e6db11SPramod Gurav 198267e6db11SPramod Gurav pm_runtime_get_sync(&pdev->dev); 198367e6db11SPramod Gurav pm_runtime_disable(&pdev->dev); 198467e6db11SPramod Gurav pm_runtime_put_noidle(&pdev->dev); 198567e6db11SPramod Gurav 1986e4bf91f6SBjorn Andersson clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), 1987e4bf91f6SBjorn Andersson msm_host->bulk_clks); 19880eb0d9f4SGeorgi Djakov if (!IS_ERR(msm_host->bus_clk)) 19890eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->bus_clk); 19906f699531SJisheng Zhang sdhci_pltfm_free(pdev); 19910eb0d9f4SGeorgi Djakov return 0; 19920eb0d9f4SGeorgi Djakov } 19930eb0d9f4SGeorgi Djakov 19946809a5f7SArnd Bergmann static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev) 199567e6db11SPramod Gurav { 199667e6db11SPramod Gurav struct sdhci_host *host = dev_get_drvdata(dev); 199767e6db11SPramod Gurav struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 199867e6db11SPramod Gurav struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 199967e6db11SPramod Gurav 2000e4bf91f6SBjorn Andersson clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), 2001e4bf91f6SBjorn Andersson msm_host->bulk_clks); 200267e6db11SPramod Gurav 200367e6db11SPramod Gurav return 0; 200467e6db11SPramod Gurav } 200567e6db11SPramod Gurav 20066809a5f7SArnd Bergmann static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) 200767e6db11SPramod Gurav { 200867e6db11SPramod Gurav struct sdhci_host *host = dev_get_drvdata(dev); 200967e6db11SPramod Gurav struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 201067e6db11SPramod Gurav struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 201121f1e2d4SVeerabhadrarao Badiganti int ret; 201267e6db11SPramod Gurav 201321f1e2d4SVeerabhadrarao Badiganti ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), 2014e4bf91f6SBjorn Andersson msm_host->bulk_clks); 201521f1e2d4SVeerabhadrarao Badiganti if (ret) 201621f1e2d4SVeerabhadrarao Badiganti return ret; 201721f1e2d4SVeerabhadrarao Badiganti /* 201821f1e2d4SVeerabhadrarao Badiganti * Whenever core-clock is gated dynamically, it's needed to 201921f1e2d4SVeerabhadrarao Badiganti * restore the SDR DLL settings when the clock is ungated. 202021f1e2d4SVeerabhadrarao Badiganti */ 202121f1e2d4SVeerabhadrarao Badiganti if (msm_host->restore_dll_config && msm_host->clk_rate) 202221f1e2d4SVeerabhadrarao Badiganti return sdhci_msm_restore_sdr_dll_config(host); 202321f1e2d4SVeerabhadrarao Badiganti 202421f1e2d4SVeerabhadrarao Badiganti return 0; 202567e6db11SPramod Gurav } 202667e6db11SPramod Gurav 202767e6db11SPramod Gurav static const struct dev_pm_ops sdhci_msm_pm_ops = { 202867e6db11SPramod Gurav SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 202967e6db11SPramod Gurav pm_runtime_force_resume) 203067e6db11SPramod Gurav SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, 203167e6db11SPramod Gurav sdhci_msm_runtime_resume, 203267e6db11SPramod Gurav NULL) 203367e6db11SPramod Gurav }; 203467e6db11SPramod Gurav 20350eb0d9f4SGeorgi Djakov static struct platform_driver sdhci_msm_driver = { 20360eb0d9f4SGeorgi Djakov .probe = sdhci_msm_probe, 20370eb0d9f4SGeorgi Djakov .remove = sdhci_msm_remove, 20380eb0d9f4SGeorgi Djakov .driver = { 20390eb0d9f4SGeorgi Djakov .name = "sdhci_msm", 20400eb0d9f4SGeorgi Djakov .of_match_table = sdhci_msm_dt_match, 204167e6db11SPramod Gurav .pm = &sdhci_msm_pm_ops, 20420eb0d9f4SGeorgi Djakov }, 20430eb0d9f4SGeorgi Djakov }; 20440eb0d9f4SGeorgi Djakov 20450eb0d9f4SGeorgi Djakov module_platform_driver(sdhci_msm_driver); 20460eb0d9f4SGeorgi Djakov 20470eb0d9f4SGeorgi Djakov MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver"); 20480eb0d9f4SGeorgi Djakov MODULE_LICENSE("GPL v2"); 2049