diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-msm.c')
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 438 |
1 files changed, 226 insertions, 212 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 8ac81d57a3df..3b85233131b3 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -6,19 +6,20 @@ */ #include <linux/module.h> -#include <linux/of_device.h> #include <linux/delay.h> #include <linux/mmc/mmc.h> #include <linux/pm_runtime.h> #include <linux/pm_opp.h> #include <linux/slab.h> #include <linux/iopoll.h> -#include <linux/firmware/qcom/qcom_scm.h> #include <linux/regulator/consumer.h> #include <linux/interconnect.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/reset.h> +#include <soc/qcom/ice.h> + #include "sdhci-cqhci.h" #include "sdhci-pltfm.h" #include "cqhci.h" @@ -80,6 +81,7 @@ #define CORE_IO_PAD_PWR_SWITCH_EN BIT(15) #define CORE_IO_PAD_PWR_SWITCH BIT(16) #define CORE_HC_SELECT_IN_EN BIT(18) +#define CORE_HC_SELECT_IN_SDR50 (4 << 19) #define CORE_HC_SELECT_IN_HS400 (6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) @@ -133,9 +135,18 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +/* Max load for eMMC Vdd supply */ +#define MMC_VMMC_MAX_LOAD_UA 570000 + /* Max load for eMMC Vdd-io supply */ #define MMC_VQMMC_MAX_LOAD_UA 325000 +/* Max load for SD Vdd supply */ +#define SD_VMMC_MAX_LOAD_UA 800000 + +/* Max load for SD Vdd-io supply */ +#define SD_VQMMC_MAX_LOAD_UA 22000 + #define msm_host_readl(msm_host, host, offset) \ msm_host->var_ops->msm_readl_relaxed(host, offset) @@ -258,12 +269,14 @@ struct sdhci_msm_variant_info { struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ - void __iomem *ice_mem; /* MSM ICE mapped address (if available) */ int pwr_irq; /* power irq */ struct clk *bus_clk; /* SDHC bus voter clock */ struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/ - /* core, iface, cal, sleep, and ice clocks */ - struct clk_bulk_data bulk_clks[5]; + /* core, iface, cal and sleep clocks */ + struct clk_bulk_data bulk_clks[4]; +#ifdef CONFIG_MMC_CRYPTO + struct qcom_ice *ice; +#endif unsigned long clk_rate; struct mmc_host *mmc; bool use_14lpp_dll_reset; @@ -331,41 +344,43 @@ static void sdhci_msm_v5_variant_writel_relaxed(u32 val, writel_relaxed(val, host->ioaddr + offset); } -static unsigned int msm_get_clock_mult_for_bus_mode(struct sdhci_host *host) +static unsigned int msm_get_clock_mult_for_bus_mode(struct sdhci_host *host, + unsigned int clock, + unsigned int timing) { - struct mmc_ios ios = host->mmc->ios; /* * The SDHC requires internal clock frequency to be double the * actual clock that will be set for DDR mode. The controller * uses the faster clock(100/400MHz) for some of its parts and * send the actual required clock (50/200MHz) to the card. */ - if (ios.timing == MMC_TIMING_UHS_DDR50 || - ios.timing == MMC_TIMING_MMC_DDR52 || - ios.timing == MMC_TIMING_MMC_HS400 || + if (timing == MMC_TIMING_UHS_DDR50 || + timing == MMC_TIMING_MMC_DDR52 || + (timing == MMC_TIMING_MMC_HS400 && + clock == MMC_HS200_MAX_DTR) || host->flags & SDHCI_HS400_TUNING) return 2; return 1; } static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, - unsigned int clock) + unsigned int clock, + unsigned int timing) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); - struct mmc_ios curr_ios = host->mmc->ios; struct clk *core_clk = msm_host->bulk_clks[0].clk; unsigned long achieved_rate; unsigned int desired_rate; unsigned int mult; int rc; - mult = msm_get_clock_mult_for_bus_mode(host); + mult = msm_get_clock_mult_for_bus_mode(host, clock, timing); desired_rate = clock * mult; rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), desired_rate); if (rc) { pr_err("%s: Failed to set clock at rate %u at timing %d\n", - mmc_hostname(host->mmc), desired_rate, curr_ios.timing); + mmc_hostname(host->mmc), desired_rate, timing); return; } @@ -384,7 +399,7 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, msm_host->clk_rate = desired_rate; pr_debug("%s: Setting clock at rate %lu at timing %d\n", - mmc_hostname(host->mmc), achieved_rate, curr_ios.timing); + mmc_hostname(host->mmc), achieved_rate, timing); } /* Platform specific tuning */ @@ -1121,6 +1136,10 @@ static bool sdhci_msm_is_tuning_needed(struct sdhci_host *host) { struct mmc_ios *ios = &host->mmc->ios; + if (ios->timing == MMC_TIMING_UHS_SDR50 && + host->flags & SDHCI_SDR50_NEEDS_TUNING) + return true; + /* * Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. @@ -1189,6 +1208,8 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) struct mmc_ios ios = host->mmc->ios; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_msm_offset *msm_offset = msm_host->offset; + u32 config; if (!sdhci_msm_is_tuning_needed(host)) { msm_host->use_cdr = false; @@ -1205,6 +1226,14 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) */ msm_host->tuning_done = 0; + if (ios.timing == MMC_TIMING_UHS_SDR50 && + host->flags & SDHCI_SDR50_NEEDS_TUNING) { + config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec); + config &= ~CORE_HC_SELECT_IN_MASK; + config |= CORE_HC_SELECT_IN_EN | CORE_HC_SELECT_IN_SDR50; + writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec); + } + /* * For HS400 tuning in HS200 timing requires: * - select MCLK/2 in VENDOR_SPEC @@ -1212,7 +1241,7 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) */ if (host->flags & SDHCI_HS400_TUNING) { sdhci_msm_hc_select_mode(host); - msm_set_clock_rate_for_bus_mode(host, ios.clock); + msm_set_clock_rate_for_bus_mode(host, ios.clock, ios.timing); host->flags &= ~SDHCI_HS400_TUNING; } @@ -1400,11 +1429,48 @@ static int sdhci_msm_set_pincfg(struct sdhci_msm_host *msm_host, bool level) return ret; } -static int sdhci_msm_set_vmmc(struct mmc_host *mmc) +static void msm_config_vmmc_regulator(struct mmc_host *mmc, bool hpm) +{ + int load; + + if (!hpm) + load = 0; + else if (!mmc->card) + load = max(MMC_VMMC_MAX_LOAD_UA, SD_VMMC_MAX_LOAD_UA); + else if (mmc_card_mmc(mmc->card)) + load = MMC_VMMC_MAX_LOAD_UA; + else if (mmc_card_sd(mmc->card)) + load = SD_VMMC_MAX_LOAD_UA; + else + return; + + regulator_set_load(mmc->supply.vmmc, load); +} + +static void msm_config_vqmmc_regulator(struct mmc_host *mmc, bool hpm) +{ + int load; + + if (!hpm) + load = 0; + else if (!mmc->card) + load = max(MMC_VQMMC_MAX_LOAD_UA, SD_VQMMC_MAX_LOAD_UA); + else if (mmc_card_sd(mmc->card)) + load = SD_VQMMC_MAX_LOAD_UA; + else + return; + + regulator_set_load(mmc->supply.vqmmc, load); +} + +static int sdhci_msm_set_vmmc(struct sdhci_msm_host *msm_host, + struct mmc_host *mmc, bool hpm) { if (IS_ERR(mmc->supply.vmmc)) return 0; + msm_config_vmmc_regulator(mmc, hpm); + return mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, mmc->ios.vdd); } @@ -1417,6 +1483,8 @@ static int msm_toggle_vqmmc(struct sdhci_msm_host *msm_host, if (msm_host->vqmmc_enabled == level) return 0; + msm_config_vqmmc_regulator(mmc, level); + if (level) { /* Set the IO voltage regulator to default voltage level */ if (msm_host->caps_0 & CORE_3_0V_SUPPORT) @@ -1513,6 +1581,7 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_host *mmc = host->mmc; bool done = false; u32 val = SWITCHABLE_SIGNALING_VOLTAGE; const struct sdhci_msm_offset *msm_offset = @@ -1570,6 +1639,12 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) "%s: pwr_irq for req: (%d) timed out\n", mmc_hostname(host->mmc), req_type); } + + if ((req_type & REQ_BUS_ON) && mmc->card && !mmc->ops->get_cd(mmc)) { + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + host->pwr = 0; + } + pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc), __func__, req_type); } @@ -1628,6 +1703,13 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) udelay(10); } + if ((irq_status & CORE_PWRCTL_BUS_ON) && mmc->card && + !mmc->ops->get_cd(mmc)) { + msm_host_writel(msm_host, CORE_PWRCTL_BUS_FAIL, host, + msm_offset->core_pwrctl_ctl); + return; + } + /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { pwr_state = REQ_BUS_ON; @@ -1639,7 +1721,8 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) } if (pwr_state) { - ret = sdhci_msm_set_vmmc(mmc); + ret = sdhci_msm_set_vmmc(msm_host, mmc, + pwr_state & REQ_BUS_ON); if (!ret) ret = sdhci_msm_set_vqmmc(msm_host, mmc, pwr_state & REQ_BUS_ON); @@ -1783,6 +1866,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_ios ios = host->mmc->ios; if (!clock) { host->mmc->actual_clock = msm_host->clk_rate = 0; @@ -1791,7 +1875,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_msm_hc_select_mode(host); - msm_set_clock_rate_for_bus_mode(host, clock); + msm_set_clock_rate_for_bus_mode(host, ios.clock, ios.timing); out: __sdhci_msm_set_clock(host, clock); } @@ -1804,216 +1888,136 @@ out: #ifdef CONFIG_MMC_CRYPTO -#define AES_256_XTS_KEY_SIZE 64 - -/* QCOM ICE registers */ - -#define QCOM_ICE_REG_VERSION 0x0008 - -#define QCOM_ICE_REG_FUSE_SETTING 0x0010 -#define QCOM_ICE_FUSE_SETTING_MASK 0x1 -#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 -#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 - -#define QCOM_ICE_REG_BIST_STATUS 0x0070 -#define QCOM_ICE_BIST_STATUS_MASK 0xF0000000 - -#define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000 - -#define sdhci_msm_ice_writel(host, val, reg) \ - writel((val), (host)->ice_mem + (reg)) -#define sdhci_msm_ice_readl(host, reg) \ - readl((host)->ice_mem + (reg)) - -static bool sdhci_msm_ice_supported(struct sdhci_msm_host *msm_host) -{ - struct device *dev = mmc_dev(msm_host->mmc); - u32 regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_VERSION); - int major = regval >> 24; - int minor = (regval >> 16) & 0xFF; - int step = regval & 0xFFFF; - - /* For now this driver only supports ICE version 3. */ - if (major != 3) { - dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n", - major, minor, step); - return false; - } - - dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", - major, minor, step); - - /* If fuses are blown, ICE might not work in the standard way. */ - regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_FUSE_SETTING); - if (regval & (QCOM_ICE_FUSE_SETTING_MASK | - QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK | - QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) { - dev_warn(dev, "Fuses are blown; ICE is unusable!\n"); - return false; - } - return true; -} - -static inline struct clk *sdhci_msm_ice_get_clk(struct device *dev) -{ - return devm_clk_get(dev, "ice"); -} +static const struct blk_crypto_ll_ops sdhci_msm_crypto_ops; /* forward decl */ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, struct cqhci_host *cq_host) { struct mmc_host *mmc = msm_host->mmc; + struct blk_crypto_profile *profile = &mmc->crypto_profile; struct device *dev = mmc_dev(mmc); - struct resource *res; + struct qcom_ice *ice; + union cqhci_crypto_capabilities caps; + union cqhci_crypto_cap_entry cap; + int err; + int i; if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS)) return 0; - res = platform_get_resource_byname(msm_host->pdev, IORESOURCE_MEM, - "ice"); - if (!res) { - dev_warn(dev, "ICE registers not found\n"); - goto disable; + ice = devm_of_qcom_ice_get(dev); + if (ice == ERR_PTR(-EOPNOTSUPP)) { + dev_warn(dev, "Disabling inline encryption support\n"); + ice = NULL; } - if (!qcom_scm_ice_available()) { - dev_warn(dev, "ICE SCM interface not found\n"); - goto disable; + if (IS_ERR_OR_NULL(ice)) + return PTR_ERR_OR_ZERO(ice); + + if (qcom_ice_get_supported_key_type(ice) != BLK_CRYPTO_KEY_TYPE_RAW) { + dev_warn(dev, "Wrapped keys not supported. Disabling inline encryption support.\n"); + return 0; } - msm_host->ice_mem = devm_ioremap_resource(dev, res); - if (IS_ERR(msm_host->ice_mem)) - return PTR_ERR(msm_host->ice_mem); + msm_host->ice = ice; - if (!sdhci_msm_ice_supported(msm_host)) - goto disable; + /* Initialize the blk_crypto_profile */ - mmc->caps2 |= MMC_CAP2_CRYPTO; - return 0; + caps.reg_val = cpu_to_le32(cqhci_readl(cq_host, CQHCI_CCAP)); -disable: - dev_warn(dev, "Disabling inline encryption support\n"); - return 0; -} + /* The number of keyslots supported is (CFGC+1) */ + err = devm_blk_crypto_profile_init(dev, profile, caps.config_count + 1); + if (err) + return err; -static void sdhci_msm_ice_low_power_mode_enable(struct sdhci_msm_host *msm_host) -{ - u32 regval; + profile->ll_ops = sdhci_msm_crypto_ops; + profile->max_dun_bytes_supported = 4; + profile->key_types_supported = BLK_CRYPTO_KEY_TYPE_RAW; + profile->dev = dev; - regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_ADVANCED_CONTROL); /* - * Enable low power mode sequence - * [0]-0, [1]-0, [2]-0, [3]-E, [4]-0, [5]-0, [6]-0, [7]-0 + * Currently this driver only supports AES-256-XTS. All known versions + * of ICE support it, but to be safe make sure it is really declared in + * the crypto capability registers. The crypto capability registers + * also give the supported data unit size(s). */ - regval |= 0x7000; - sdhci_msm_ice_writel(msm_host, regval, QCOM_ICE_REG_ADVANCED_CONTROL); + for (i = 0; i < caps.num_crypto_cap; i++) { + cap.reg_val = cpu_to_le32(cqhci_readl(cq_host, + CQHCI_CRYPTOCAP + + i * sizeof(__le32))); + if (cap.algorithm_id == CQHCI_CRYPTO_ALG_AES_XTS && + cap.key_size == CQHCI_CRYPTO_KEY_SIZE_256) + profile->modes_supported[BLK_ENCRYPTION_MODE_AES_256_XTS] |= + cap.sdus_mask * 512; + } + + mmc->caps2 |= MMC_CAP2_CRYPTO; + return 0; } -static void sdhci_msm_ice_optimization_enable(struct sdhci_msm_host *msm_host) +static void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host) { - u32 regval; - - /* ICE Optimizations Enable Sequence */ - regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_ADVANCED_CONTROL); - regval |= 0xD807100; - /* ICE HPG requires delay before writing */ - udelay(5); - sdhci_msm_ice_writel(msm_host, regval, QCOM_ICE_REG_ADVANCED_CONTROL); - udelay(5); + if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO) + qcom_ice_enable(msm_host->ice); } -/* - * Wait until the ICE BIST (built-in self-test) has completed. - * - * This may be necessary before ICE can be used. - * - * Note that we don't really care whether the BIST passed or failed; we really - * just want to make sure that it isn't still running. This is because (a) the - * BIST is a FIPS compliance thing that never fails in practice, (b) ICE is - * documented to reject crypto requests if the BIST fails, so we needn't do it - * in software too, and (c) properly testing storage encryption requires testing - * the full storage stack anyway, and not relying on hardware-level self-tests. - */ -static int sdhci_msm_ice_wait_bist_status(struct sdhci_msm_host *msm_host) +static int sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host) { - u32 regval; - int err; + if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO) + return qcom_ice_resume(msm_host->ice); - err = readl_poll_timeout(msm_host->ice_mem + QCOM_ICE_REG_BIST_STATUS, - regval, !(regval & QCOM_ICE_BIST_STATUS_MASK), - 50, 5000); - if (err) - dev_err(mmc_dev(msm_host->mmc), - "Timed out waiting for ICE self-test to complete\n"); - return err; + return 0; } -static void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host) +static int sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host) { - if (!(msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)) - return; - sdhci_msm_ice_low_power_mode_enable(msm_host); - sdhci_msm_ice_optimization_enable(msm_host); - sdhci_msm_ice_wait_bist_status(msm_host); + if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO) + return qcom_ice_suspend(msm_host->ice); + + return 0; } -static int __maybe_unused sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host) +static inline struct sdhci_msm_host * +sdhci_msm_host_from_crypto_profile(struct blk_crypto_profile *profile) { - if (!(msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)) - return 0; - return sdhci_msm_ice_wait_bist_status(msm_host); + struct mmc_host *mmc = mmc_from_crypto_profile(profile); + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return msm_host; } /* - * Program a key into a QC ICE keyslot, or evict a keyslot. QC ICE requires - * vendor-specific SCM calls for this; it doesn't support the standard way. + * Program a key into a QC ICE keyslot. QC ICE requires a QC-specific SCM call + * for this; it doesn't support the standard way. */ -static int sdhci_msm_program_key(struct cqhci_host *cq_host, - const union cqhci_crypto_cfg_entry *cfg, - int slot) +static int sdhci_msm_ice_keyslot_program(struct blk_crypto_profile *profile, + const struct blk_crypto_key *key, + unsigned int slot) { - struct device *dev = mmc_dev(cq_host->mmc); - union cqhci_crypto_cap_entry cap; - union { - u8 bytes[AES_256_XTS_KEY_SIZE]; - u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)]; - } key; - int i; - int err; + struct sdhci_msm_host *msm_host = + sdhci_msm_host_from_crypto_profile(profile); - if (!(cfg->config_enable & CQHCI_CRYPTO_CONFIGURATION_ENABLE)) - return qcom_scm_ice_invalidate_key(slot); + return qcom_ice_program_key(msm_host->ice, slot, key); +} - /* Only AES-256-XTS has been tested so far. */ - cap = cq_host->crypto_cap_array[cfg->crypto_cap_idx]; - if (cap.algorithm_id != CQHCI_CRYPTO_ALG_AES_XTS || - cap.key_size != CQHCI_CRYPTO_KEY_SIZE_256) { - dev_err_ratelimited(dev, - "Unhandled crypto capability; algorithm_id=%d, key_size=%d\n", - cap.algorithm_id, cap.key_size); - return -EINVAL; - } +static int sdhci_msm_ice_keyslot_evict(struct blk_crypto_profile *profile, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct sdhci_msm_host *msm_host = + sdhci_msm_host_from_crypto_profile(profile); - memcpy(key.bytes, cfg->crypto_key, AES_256_XTS_KEY_SIZE); + return qcom_ice_evict_key(msm_host->ice, slot); +} - /* - * The SCM call byte-swaps the 32-bit words of the key. So we have to - * do the same, in order for the final key be correct. - */ - for (i = 0; i < ARRAY_SIZE(key.words); i++) - __cpu_to_be32s(&key.words[i]); +static const struct blk_crypto_ll_ops sdhci_msm_crypto_ops = { + .keyslot_program = sdhci_msm_ice_keyslot_program, + .keyslot_evict = sdhci_msm_ice_keyslot_evict, +}; - err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, - QCOM_SCM_ICE_CIPHER_AES_256_XTS, - cfg->data_unit_size); - memzero_explicit(&key, sizeof(key)); - return err; -} #else /* CONFIG_MMC_CRYPTO */ -static inline struct clk *sdhci_msm_ice_get_clk(struct device *dev) -{ - return NULL; -} static inline int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, struct cqhci_host *cq_host) @@ -2025,11 +2029,17 @@ static inline void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host) { } -static inline int __maybe_unused +static inline int sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host) { return 0; } + +static inline int +sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host) +{ + return 0; +} #endif /* !CONFIG_MMC_CRYPTO */ /*****************************************************************************\ @@ -2112,7 +2122,7 @@ static const struct cqhci_host_ops sdhci_msm_cqhci_ops = { .enable = sdhci_msm_cqe_enable, .disable = sdhci_msm_cqe_disable, #ifdef CONFIG_MMC_CRYPTO - .program_key = sdhci_msm_program_key, + .uses_custom_crypto_profile = true, #endif }; @@ -2479,6 +2489,9 @@ static inline void sdhci_msm_get_of_property(struct platform_device *pdev, msm_host->ddr_config = DDR_CONFIG_POR_VAL; of_property_read_u32(node, "qcom,dll-config", &msm_host->dll_config); + + if (of_device_is_compatible(node, "qcom,msm8916-sdhci")) + host->quirks2 |= SDHCI_QUIRK2_BROKEN_64_BIT_DMA; } static int sdhci_msm_gcc_reset(struct device *dev, struct sdhci_host *host) @@ -2545,7 +2558,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto pltfm_free; + return ret; /* * Based on the compatible string, load the required msm host info from @@ -2567,7 +2580,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_msm_gcc_reset(&pdev->dev, host); if (ret) - goto pltfm_free; + return ret; /* Setup SDCC bus voter clock. */ msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus"); @@ -2575,10 +2588,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) /* Vote for max. clk rate for max. performance */ ret = clk_set_rate(msm_host->bus_clk, INT_MAX); if (ret) - goto pltfm_free; + return ret; ret = clk_prepare_enable(msm_host->bus_clk); if (ret) - goto pltfm_free; + return ret; } /* Setup main peripheral bus clock */ @@ -2630,11 +2643,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) clk = NULL; msm_host->bulk_clks[3].clk = clk; - clk = sdhci_msm_ice_get_clk(&pdev->dev); - if (IS_ERR(clk)) - clk = NULL; - msm_host->bulk_clks[4].clk = clk; - ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); if (ret) @@ -2727,7 +2735,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) sdhci_msm_handle_pwr_irq(host, 0); /* - * Ensure that above writes are propogated before interrupt enablement + * Ensure that above writes are propagated before interrupt enablement * in GIC. */ mb(); @@ -2774,7 +2782,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (ret) goto pm_runtime_disable; - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); return 0; @@ -2789,12 +2796,10 @@ clk_disable: bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); -pltfm_free: - sdhci_pltfm_free(pdev); return ret; } -static int sdhci_msm_remove(struct platform_device *pdev) +static void sdhci_msm_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -2812,29 +2817,33 @@ static int sdhci_msm_remove(struct platform_device *pdev) msm_host->bulk_clks); if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); - sdhci_pltfm_free(pdev); - return 0; } -static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev) +static int sdhci_msm_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = true; + spin_unlock_irqrestore(&host->lock, flags); /* Drop the performance vote */ dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); - return 0; + return sdhci_msm_ice_suspend(msm_host); } -static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) +static int sdhci_msm_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + unsigned long flags; int ret; ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), @@ -2853,15 +2862,20 @@ static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) dev_pm_opp_set_rate(dev, msm_host->clk_rate); - return sdhci_msm_ice_resume(msm_host); + ret = sdhci_msm_ice_resume(msm_host); + if (ret) + return ret; + + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = false; + spin_unlock_irqrestore(&host->lock, flags); + + return ret; } static const struct dev_pm_ops sdhci_msm_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, - sdhci_msm_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume, NULL) }; static struct platform_driver sdhci_msm_driver = { @@ -2870,7 +2884,7 @@ static struct platform_driver sdhci_msm_driver = { .driver = { .name = "sdhci_msm", .of_match_table = sdhci_msm_dt_match, - .pm = &sdhci_msm_pm_ops, + .pm = pm_ptr(&sdhci_msm_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; |
