Re: [PATCH V1 1/3] mmc: sdhci: Allow platform controlled voltage switching
Hi Adrian, On 7/25/2018 5:23 PM, Adrian Hunter wrote: On 20/07/18 13:46, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. During setup/cleanup of host, check whether regulator enable/disable was already done by platform driver. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 21 - 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..494a1e2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3472,6 +3472,7 @@ int sdhci_setup_host(struct sdhci_host *host) unsigned int override_timeout_clk; u32 max_clk; int ret; + bool enable_vqmmc = false; WARN_ON(host == NULL); if (host == NULL) @@ -3485,7 +3486,12 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!mmc->supply.vmmc) { + ret = mmc_regulator_get_supply(mmc); + enable_vqmmc = true; + } else { + ret = 0; + } if (ret) return ret; Why not if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); if (ret) return ret; enable_vqmmc = true; } looks neater. Will do. @@ -3736,7 +3742,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (enable_vqmmc) + ret = regulator_enable(mmc->supply.vqmmc); Please introduce host->vqmmc_enabled = !ret; Any reason to introduce vqmmc_enabled variable in sdhci_host structure ? We can get around with a local variable and using regulator_is_enabled API. + else + ret = 0; if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170, 195)) host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | @@ -3984,7 +3993,7 @@ int sdhci_setup_host(struct sdhci_host *host) return 0; unreg: - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && enable_vqmmc) And just make this if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); undma: if (host->align_buffer) @@ -4002,7 +4011,8 @@ void sdhci_cleanup_host(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) @@ -4135,7 +4145,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(>finish_tasklet); - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Thanks, Vijay
Re: [PATCH V1 1/3] mmc: sdhci: Allow platform controlled voltage switching
Hi Adrian, On 7/25/2018 5:23 PM, Adrian Hunter wrote: On 20/07/18 13:46, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. During setup/cleanup of host, check whether regulator enable/disable was already done by platform driver. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 21 - 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..494a1e2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3472,6 +3472,7 @@ int sdhci_setup_host(struct sdhci_host *host) unsigned int override_timeout_clk; u32 max_clk; int ret; + bool enable_vqmmc = false; WARN_ON(host == NULL); if (host == NULL) @@ -3485,7 +3486,12 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!mmc->supply.vmmc) { + ret = mmc_regulator_get_supply(mmc); + enable_vqmmc = true; + } else { + ret = 0; + } if (ret) return ret; Why not if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); if (ret) return ret; enable_vqmmc = true; } looks neater. Will do. @@ -3736,7 +3742,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (enable_vqmmc) + ret = regulator_enable(mmc->supply.vqmmc); Please introduce host->vqmmc_enabled = !ret; Any reason to introduce vqmmc_enabled variable in sdhci_host structure ? We can get around with a local variable and using regulator_is_enabled API. + else + ret = 0; if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170, 195)) host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | @@ -3984,7 +3993,7 @@ int sdhci_setup_host(struct sdhci_host *host) return 0; unreg: - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && enable_vqmmc) And just make this if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); undma: if (host->align_buffer) @@ -4002,7 +4011,8 @@ void sdhci_cleanup_host(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) @@ -4135,7 +4145,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(>finish_tasklet); - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Thanks, Vijay
Re: [PATCH RFC 2/7] mmc: core: devfreq: Add devfreq based clock scaling support
Hi Sayali, On 7/13/2018 3:22 PM, Sayali Lokhande wrote: This change adds the use of devfreq to MMC. Both eMMC and SD card will use it. For some workloads, such as video playback, it isn't necessary for these cards to run at high speed. Running at lower frequency, for example 52MHz, in such cases can still meet the deadlines for data transfers. Scaling down the clock frequency dynamically has power savings not only because the bus is running at lower frequency but also has an advantage of scaling down the system core voltage, if supported. Provide an ondemand clock scaling support similar to the cpufreq ondemand governor having two thresholds, up_threshold and down_threshold to decide whether to increase the frequency or scale it down respectively. The sampling interval is in the order of milliseconds. If sampling interval is too low, frequent switching of frequencies can lead to high power consumption and if sampling interval is too high, the clock scaling logic would take long time to realize that the underlying hardware (controller and card) is busy and scale up the clocks. Signed-off-by: Talel Shenhar Signed-off-by: Sayali Lokhande --- .../devicetree/bindings/mmc/sdhci-msm.txt | 10 + drivers/mmc/core/core.c| 560 + drivers/mmc/core/core.h| 7 + drivers/mmc/core/debugfs.c | 46 ++ drivers/mmc/core/host.c| 8 + drivers/mmc/core/mmc.c | 200 +++- drivers/mmc/core/sd.c | 72 ++- drivers/mmc/host/sdhci-msm.c | 37 ++ drivers/mmc/host/sdhci-pltfm.c | 11 + drivers/mmc/host/sdhci.c | 27 + drivers/mmc/host/sdhci.h | 8 + include/linux/mmc/card.h | 5 + include/linux/mmc/host.h | 70 +++ 13 files changed, 1059 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 502b3b8..bd8470a 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -26,6 +26,15 @@ Required properties: "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +Optional Properties: +- qcom,devfreq,freq-table - specifies supported frequencies for clock scaling. + Clock scaling logic shall toggle between these frequencies based + on card load. In case the defined frequencies are over or below + the supported card frequencies, they will be overridden + during card init. In case this entry is not supplied, + the driver will construct one based on the card + supported max and min frequencies. + The frequencies must be ordered from lowest to highest. Example: sdhc_1: sdhci@f9824900 { @@ -43,6 +52,7 @@ Example: clocks = < GCC_SDCC1_APPS_CLK>, < GCC_SDCC1_AHB_CLK>; clock-names = "core", "iface"; + qcom,devfreq,freq-table = <5200 2>; }; sdhc_2: sdhci@f98a4900 { diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 281826d..0eaee42 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,556 @@ static inline void mmc_should_fail_request(struct mmc_host *host, #endif /* CONFIG_FAIL_MMC_REQUEST */ +static bool mmc_is_data_request(struct mmc_request *mmc_request) +{ + switch (mmc_request->cmd->opcode) { + case MMC_READ_SINGLE_BLOCK: + case MMC_READ_MULTIPLE_BLOCK: + case MMC_WRITE_BLOCK: + case MMC_WRITE_MULTIPLE_BLOCK: + return true; + default: + return false; + } +} + +static void mmc_clk_scaling_start_busy(struct mmc_host *host, bool lock_needed) +{ + struct mmc_devfeq_clk_scaling *clk_scaling = >clk_scaling; + + if (!clk_scaling->enable) + return; + + if (lock_needed) + spin_lock_bh(_scaling->lock); + + clk_scaling->start_busy = ktime_get(); + clk_scaling->is_busy_started = true; + + if (lock_needed) + spin_unlock_bh(_scaling->lock); +} + +static void mmc_clk_scaling_stop_busy(struct mmc_host *host, bool lock_needed) +{ + struct mmc_devfeq_clk_scaling *clk_scaling = >clk_scaling; + + if (!clk_scaling->enable) + return; + + if (lock_needed) +
Re: [PATCH RFC 2/7] mmc: core: devfreq: Add devfreq based clock scaling support
Hi Sayali, On 7/13/2018 3:22 PM, Sayali Lokhande wrote: This change adds the use of devfreq to MMC. Both eMMC and SD card will use it. For some workloads, such as video playback, it isn't necessary for these cards to run at high speed. Running at lower frequency, for example 52MHz, in such cases can still meet the deadlines for data transfers. Scaling down the clock frequency dynamically has power savings not only because the bus is running at lower frequency but also has an advantage of scaling down the system core voltage, if supported. Provide an ondemand clock scaling support similar to the cpufreq ondemand governor having two thresholds, up_threshold and down_threshold to decide whether to increase the frequency or scale it down respectively. The sampling interval is in the order of milliseconds. If sampling interval is too low, frequent switching of frequencies can lead to high power consumption and if sampling interval is too high, the clock scaling logic would take long time to realize that the underlying hardware (controller and card) is busy and scale up the clocks. Signed-off-by: Talel Shenhar Signed-off-by: Sayali Lokhande --- .../devicetree/bindings/mmc/sdhci-msm.txt | 10 + drivers/mmc/core/core.c| 560 + drivers/mmc/core/core.h| 7 + drivers/mmc/core/debugfs.c | 46 ++ drivers/mmc/core/host.c| 8 + drivers/mmc/core/mmc.c | 200 +++- drivers/mmc/core/sd.c | 72 ++- drivers/mmc/host/sdhci-msm.c | 37 ++ drivers/mmc/host/sdhci-pltfm.c | 11 + drivers/mmc/host/sdhci.c | 27 + drivers/mmc/host/sdhci.h | 8 + include/linux/mmc/card.h | 5 + include/linux/mmc/host.h | 70 +++ 13 files changed, 1059 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 502b3b8..bd8470a 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -26,6 +26,15 @@ Required properties: "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +Optional Properties: +- qcom,devfreq,freq-table - specifies supported frequencies for clock scaling. + Clock scaling logic shall toggle between these frequencies based + on card load. In case the defined frequencies are over or below + the supported card frequencies, they will be overridden + during card init. In case this entry is not supplied, + the driver will construct one based on the card + supported max and min frequencies. + The frequencies must be ordered from lowest to highest. Example: sdhc_1: sdhci@f9824900 { @@ -43,6 +52,7 @@ Example: clocks = < GCC_SDCC1_APPS_CLK>, < GCC_SDCC1_AHB_CLK>; clock-names = "core", "iface"; + qcom,devfreq,freq-table = <5200 2>; }; sdhc_2: sdhci@f98a4900 { diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 281826d..0eaee42 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,556 @@ static inline void mmc_should_fail_request(struct mmc_host *host, #endif /* CONFIG_FAIL_MMC_REQUEST */ +static bool mmc_is_data_request(struct mmc_request *mmc_request) +{ + switch (mmc_request->cmd->opcode) { + case MMC_READ_SINGLE_BLOCK: + case MMC_READ_MULTIPLE_BLOCK: + case MMC_WRITE_BLOCK: + case MMC_WRITE_MULTIPLE_BLOCK: + return true; + default: + return false; + } +} + +static void mmc_clk_scaling_start_busy(struct mmc_host *host, bool lock_needed) +{ + struct mmc_devfeq_clk_scaling *clk_scaling = >clk_scaling; + + if (!clk_scaling->enable) + return; + + if (lock_needed) + spin_lock_bh(_scaling->lock); + + clk_scaling->start_busy = ktime_get(); + clk_scaling->is_busy_started = true; + + if (lock_needed) + spin_unlock_bh(_scaling->lock); +} + +static void mmc_clk_scaling_stop_busy(struct mmc_host *host, bool lock_needed) +{ + struct mmc_devfeq_clk_scaling *clk_scaling = >clk_scaling; + + if (!clk_scaling->enable) + return; + + if (lock_needed) +
[PATCH V1 3/3] mmc: sdhci-msm: Use internal voltage control
Some sdhci-msm controllers require that voltage switching be done after the HW is ready for it. The HW informs its readiness through power irq. The voltage switching should happen only then. Use the quirk for internal voltage switching and then control the voltage switching using power irq. Signed-off-by: Asutosh Das Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Veerabhadrarao Badiganti Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 220 --- 1 file changed, 209 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a0dc3e1..47732a2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -43,7 +43,9 @@ #define CORE_PWRCTL_IO_LOW BIT(2) #define CORE_PWRCTL_IO_HIGHBIT(3) #define CORE_PWRCTL_BUS_SUCCESS BIT(0) +#define CORE_PWRCTL_BUS_FAILBIT(1) #define CORE_PWRCTL_IO_SUCCESS BIT(2) +#define CORE_PWRCTL_IO_FAIL BIT(3) #define REQ_BUS_OFFBIT(0) #define REQ_BUS_ON BIT(1) #define REQ_IO_LOW BIT(2) @@ -236,6 +238,14 @@ struct sdhci_msm_variant_info { const struct sdhci_msm_offset *offset; }; +/* Holds voltage regulator information to be used by the driver*/ +struct sdhci_msm_vreg_info { + bool vmmc_load; + u32 vmmc_level[2]; + bool vqmmc_load; + u32 vqmmc_level[2]; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -258,6 +268,8 @@ struct sdhci_msm_host { bool mci_removed; const struct sdhci_msm_variant_ops *var_ops; const struct sdhci_msm_offset *offset; + struct sdhci_msm_vreg_info vreg_info; + bool pltfm_init_done; }; static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) @@ -1314,11 +1326,13 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) { 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; u32 irq_status, irq_ack = 0; - int retry = 10; + int retry = 10, ret = 0; u32 pwr_state = 0, io_level = 0; u32 config; const struct sdhci_msm_offset *msm_offset = msm_host->offset; + struct sdhci_msm_vreg_info vreg_info = msm_host->vreg_info; irq_status = msm_host_readl(msm_host, host, msm_offset->core_pwrctl_status); @@ -1351,14 +1365,91 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { - pwr_state = REQ_BUS_ON; - io_level = REQ_IO_HIGH; - irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + if (!IS_ERR(mmc->supply.vmmc)) { + if (vreg_info.vmmc_load) + ret = regulator_set_load(mmc->supply.vmmc, + vreg_info.vmmc_level[1]); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + mmc->ios.vdd); + if (ret) + pr_err("%s: vmmc enable failed: %d\n", + mmc_hostname(mmc), ret); + } + + if (!IS_ERR(mmc->supply.vqmmc) && !ret) { + struct mmc_ios ios; + + if (vreg_info.vqmmc_load) + ret = regulator_set_load(mmc->supply.vqmmc, + vreg_info.vqmmc_level[1]); + /* +* The IO voltage regulator maynot always support +* a voltage close to vdd. Set IO voltage based on +* capability of the regulator. +*/ + if (msm_host->caps_0 & CORE_3_0V_SUPPORT) + ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330; + else if (msm_host->caps_0 & CORE_1_8V_SUPPORT) + ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180; + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + pr_err("%s: %s: setting signal voltage: %d\n", + mmc_hostname(mmc), __func__, + ios.signal_voltage); + ret |= mmc_regulator_set_vqmmc(mmc, ); + } + + if (!ret) + ret = regulator_enable(mmc->supply.vqmmc); + if (ret) + pr_err("%s: vqmmc e
[PATCH V1 3/3] mmc: sdhci-msm: Use internal voltage control
Some sdhci-msm controllers require that voltage switching be done after the HW is ready for it. The HW informs its readiness through power irq. The voltage switching should happen only then. Use the quirk for internal voltage switching and then control the voltage switching using power irq. Signed-off-by: Asutosh Das Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Veerabhadrarao Badiganti Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 220 --- 1 file changed, 209 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a0dc3e1..47732a2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -43,7 +43,9 @@ #define CORE_PWRCTL_IO_LOW BIT(2) #define CORE_PWRCTL_IO_HIGHBIT(3) #define CORE_PWRCTL_BUS_SUCCESS BIT(0) +#define CORE_PWRCTL_BUS_FAILBIT(1) #define CORE_PWRCTL_IO_SUCCESS BIT(2) +#define CORE_PWRCTL_IO_FAIL BIT(3) #define REQ_BUS_OFFBIT(0) #define REQ_BUS_ON BIT(1) #define REQ_IO_LOW BIT(2) @@ -236,6 +238,14 @@ struct sdhci_msm_variant_info { const struct sdhci_msm_offset *offset; }; +/* Holds voltage regulator information to be used by the driver*/ +struct sdhci_msm_vreg_info { + bool vmmc_load; + u32 vmmc_level[2]; + bool vqmmc_load; + u32 vqmmc_level[2]; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -258,6 +268,8 @@ struct sdhci_msm_host { bool mci_removed; const struct sdhci_msm_variant_ops *var_ops; const struct sdhci_msm_offset *offset; + struct sdhci_msm_vreg_info vreg_info; + bool pltfm_init_done; }; static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) @@ -1314,11 +1326,13 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) { 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; u32 irq_status, irq_ack = 0; - int retry = 10; + int retry = 10, ret = 0; u32 pwr_state = 0, io_level = 0; u32 config; const struct sdhci_msm_offset *msm_offset = msm_host->offset; + struct sdhci_msm_vreg_info vreg_info = msm_host->vreg_info; irq_status = msm_host_readl(msm_host, host, msm_offset->core_pwrctl_status); @@ -1351,14 +1365,91 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { - pwr_state = REQ_BUS_ON; - io_level = REQ_IO_HIGH; - irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + if (!IS_ERR(mmc->supply.vmmc)) { + if (vreg_info.vmmc_load) + ret = regulator_set_load(mmc->supply.vmmc, + vreg_info.vmmc_level[1]); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + mmc->ios.vdd); + if (ret) + pr_err("%s: vmmc enable failed: %d\n", + mmc_hostname(mmc), ret); + } + + if (!IS_ERR(mmc->supply.vqmmc) && !ret) { + struct mmc_ios ios; + + if (vreg_info.vqmmc_load) + ret = regulator_set_load(mmc->supply.vqmmc, + vreg_info.vqmmc_level[1]); + /* +* The IO voltage regulator maynot always support +* a voltage close to vdd. Set IO voltage based on +* capability of the regulator. +*/ + if (msm_host->caps_0 & CORE_3_0V_SUPPORT) + ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330; + else if (msm_host->caps_0 & CORE_1_8V_SUPPORT) + ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180; + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + pr_err("%s: %s: setting signal voltage: %d\n", + mmc_hostname(mmc), __func__, + ios.signal_voltage); + ret |= mmc_regulator_set_vqmmc(mmc, ); + } + + if (!ret) + ret = regulator_enable(mmc->supply.vqmmc); + if (ret) + pr_err("%s: vqmmc e
[PATCH V1 2/3] Documentation: sdhci-msm: Add entries for passing load values
The load a particular sdhc controller should request from a regulator is device specific and hence each device should individually vote for the required load. Signed-off-by: Vijay Viswanath --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 6 ++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 502b3b8..ee34f28 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -26,6 +26,11 @@ Required properties: "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +Optional properties: +- -current-level - specifies load levels for supply during BUS_ON + and BUS_OFF states in power irq. Should be specified in + pairs (lpm, hpm), for BUS_OFF and BUS_ON respectively. + Units uA. Example: sdhc_1: sdhci@f9824900 { @@ -37,6 +42,7 @@ Example: vmmc-supply = <_l20>; vqmmc-supply = <_s3>; + vqmmc-current-level = <200 22000>; pinctrl-names = "default"; pinctrl-0 = <_clk _cmd _data>; -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 2/3] Documentation: sdhci-msm: Add entries for passing load values
The load a particular sdhc controller should request from a regulator is device specific and hence each device should individually vote for the required load. Signed-off-by: Vijay Viswanath --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 6 ++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 502b3b8..ee34f28 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -26,6 +26,11 @@ Required properties: "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +Optional properties: +- -current-level - specifies load levels for supply during BUS_ON + and BUS_OFF states in power irq. Should be specified in + pairs (lpm, hpm), for BUS_OFF and BUS_ON respectively. + Units uA. Example: sdhc_1: sdhci@f9824900 { @@ -37,6 +42,7 @@ Example: vmmc-supply = <_l20>; vqmmc-supply = <_s3>; + vqmmc-current-level = <200 22000>; pinctrl-names = "default"; pinctrl-0 = <_clk _cmd _data>; -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 1/3] mmc: sdhci: Allow platform controlled voltage switching
Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. During setup/cleanup of host, check whether regulator enable/disable was already done by platform driver. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 21 - 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..494a1e2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3472,6 +3472,7 @@ int sdhci_setup_host(struct sdhci_host *host) unsigned int override_timeout_clk; u32 max_clk; int ret; + bool enable_vqmmc = false; WARN_ON(host == NULL); if (host == NULL) @@ -3485,7 +3486,12 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!mmc->supply.vmmc) { + ret = mmc_regulator_get_supply(mmc); + enable_vqmmc = true; + } else { + ret = 0; + } if (ret) return ret; @@ -3736,7 +3742,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (enable_vqmmc) + ret = regulator_enable(mmc->supply.vqmmc); + else + ret = 0; if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170, 195)) host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | @@ -3984,7 +3993,7 @@ int sdhci_setup_host(struct sdhci_host *host) return 0; unreg: - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && enable_vqmmc) regulator_disable(mmc->supply.vqmmc); undma: if (host->align_buffer) @@ -4002,7 +4011,8 @@ void sdhci_cleanup_host(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) @@ -4135,7 +4145,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(>finish_tasklet); - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 1/3] mmc: sdhci: Allow platform controlled voltage switching
Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. During setup/cleanup of host, check whether regulator enable/disable was already done by platform driver. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 21 - 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..494a1e2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3472,6 +3472,7 @@ int sdhci_setup_host(struct sdhci_host *host) unsigned int override_timeout_clk; u32 max_clk; int ret; + bool enable_vqmmc = false; WARN_ON(host == NULL); if (host == NULL) @@ -3485,7 +3486,12 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!mmc->supply.vmmc) { + ret = mmc_regulator_get_supply(mmc); + enable_vqmmc = true; + } else { + ret = 0; + } if (ret) return ret; @@ -3736,7 +3742,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (enable_vqmmc) + ret = regulator_enable(mmc->supply.vqmmc); + else + ret = 0; if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170, 195)) host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | @@ -3984,7 +3993,7 @@ int sdhci_setup_host(struct sdhci_host *host) return 0; unreg: - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && enable_vqmmc) regulator_disable(mmc->supply.vqmmc); undma: if (host->align_buffer) @@ -4002,7 +4011,8 @@ void sdhci_cleanup_host(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) @@ -4135,7 +4145,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(>finish_tasklet); - if (!IS_ERR(mmc->supply.vqmmc)) + if (!IS_ERR(mmc->supply.vqmmc) && + (regulator_is_enabled(mmc->supply.vqmmc) > 0)) regulator_disable(mmc->supply.vqmmc); if (host->align_buffer) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 0/3] Internal voltage control for platform drivers
Certain SDHC controllers may require that voltage switching happen after sepcial conditions. Added a QUIRK for such controllers to use. For SDHCI-MSM controllers, power irq is a signal from controller to SW that it is ready for voltage switch. So added support to register voltage regulators from the msm driver and use them. Voltage switching from core layer is causing CRC/cmd timeout errors in some chipsets. Changes since RFC: - Added DT option to pass regulator load values the sdhci-msm driver should vote during BUS_ON and BUS_OFF power irq. - Removed quirk and used local flags in sdhci_add_host to to avoid scenario of both sdhci & sdhci-msm layer controlling the regulators. - Introduced two sdhci msm layer APIs to replace the respective sdhci layer APIs. This is again to stop sdhci layer from controlling regulators if sdhci_msm layer is present. Tested on: sdm845 Requies patch series:"[PATCH V3 0/4] Changes for SDCC5 version" Vijay Viswanath (3): mmc: sdhci: Allow platform controlled voltage switching Documentation: sdhci-msm: Add entries for passing load values mmc: sdhci-msm: Use internal voltage control .../devicetree/bindings/mmc/sdhci-msm.txt | 6 + drivers/mmc/host/sdhci-msm.c | 220 +++-- drivers/mmc/host/sdhci.c | 21 +- 3 files changed, 231 insertions(+), 16 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 0/3] Internal voltage control for platform drivers
Certain SDHC controllers may require that voltage switching happen after sepcial conditions. Added a QUIRK for such controllers to use. For SDHCI-MSM controllers, power irq is a signal from controller to SW that it is ready for voltage switch. So added support to register voltage regulators from the msm driver and use them. Voltage switching from core layer is causing CRC/cmd timeout errors in some chipsets. Changes since RFC: - Added DT option to pass regulator load values the sdhci-msm driver should vote during BUS_ON and BUS_OFF power irq. - Removed quirk and used local flags in sdhci_add_host to to avoid scenario of both sdhci & sdhci-msm layer controlling the regulators. - Introduced two sdhci msm layer APIs to replace the respective sdhci layer APIs. This is again to stop sdhci layer from controlling regulators if sdhci_msm layer is present. Tested on: sdm845 Requies patch series:"[PATCH V3 0/4] Changes for SDCC5 version" Vijay Viswanath (3): mmc: sdhci: Allow platform controlled voltage switching Documentation: sdhci-msm: Add entries for passing load values mmc: sdhci-msm: Use internal voltage control .../devicetree/bindings/mmc/sdhci-msm.txt | 6 + drivers/mmc/host/sdhci-msm.c | 220 +++-- drivers/mmc/host/sdhci.c | 21 +- 3 files changed, 231 insertions(+), 16 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/17/2018 3:24 PM, Adrian Hunter wrote: On 17/07/18 12:45, Vijay Viswanath wrote: On 7/17/2018 2:12 PM, Adrian Hunter wrote: On 17/07/18 11:40, Vijay Viswanath wrote: On 7/17/2018 1:00 PM, Adrian Hunter wrote: On 17/07/18 08:14, Vijay Viswanath wrote: On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating You do not need to duplicate sdhci_remove_host(), just change it so that it only disables what was enabled i.e. if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ? Yes Ok. Any particular reason why we are avoiding quirk and instead adding a new flag ? It moves more in the direction of letting drivers do what they want, rather than trying to make mak
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/17/2018 3:24 PM, Adrian Hunter wrote: On 17/07/18 12:45, Vijay Viswanath wrote: On 7/17/2018 2:12 PM, Adrian Hunter wrote: On 17/07/18 11:40, Vijay Viswanath wrote: On 7/17/2018 1:00 PM, Adrian Hunter wrote: On 17/07/18 08:14, Vijay Viswanath wrote: On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating You do not need to duplicate sdhci_remove_host(), just change it so that it only disables what was enabled i.e. if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ? Yes Ok. Any particular reason why we are avoiding quirk and instead adding a new flag ? It moves more in the direction of letting drivers do what they want, rather than trying to make mak
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/17/2018 2:12 PM, Adrian Hunter wrote: On 17/07/18 11:40, Vijay Viswanath wrote: On 7/17/2018 1:00 PM, Adrian Hunter wrote: On 17/07/18 08:14, Vijay Viswanath wrote: On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating You do not need to duplicate sdhci_remove_host(), just change it so that it only disables what was enabled i.e. if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ? Yes Ok. Any particular reason why we are avoiding quirk and instead adding a new flag ? Just wanted to clarify 2 new functions in sdhci_msm layer which would do the exact same as above, with just the regulator parts removed. This looks messy (considering any future changes to the 2 sdhci API will need to be co
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/17/2018 2:12 PM, Adrian Hunter wrote: On 17/07/18 11:40, Vijay Viswanath wrote: On 7/17/2018 1:00 PM, Adrian Hunter wrote: On 17/07/18 08:14, Vijay Viswanath wrote: On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating You do not need to duplicate sdhci_remove_host(), just change it so that it only disables what was enabled i.e. if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ? Yes Ok. Any particular reason why we are avoiding quirk and instead adding a new flag ? Just wanted to clarify 2 new functions in sdhci_msm layer which would do the exact same as above, with just the regulator parts removed. This looks messy (considering any future changes to the 2 sdhci API will need to be co
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/17/2018 1:00 PM, Adrian Hunter wrote: On 17/07/18 08:14, Vijay Viswanath wrote: On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating You do not need to duplicate sdhci_remove_host(), just change it so that it only disables what was enabled i.e. if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ? Just wanted to clarify 2 new functions in sdhci_msm layer which would do the exact same as above, with just the regulator parts removed. This looks messy (considering any future changes to the 2 sdhci API will need to be copied to their duplicate sdhci_msm API) and a bit overkill to avoid quirk. At the same time, I don't know how useful such a quirk would be to other platform drivers. Please let me know yo
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/17/2018 1:00 PM, Adrian Hunter wrote: On 17/07/18 08:14, Vijay Viswanath wrote: On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating You do not need to duplicate sdhci_remove_host(), just change it so that it only disables what was enabled i.e. if (host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ? Just wanted to clarify 2 new functions in sdhci_msm layer which would do the exact same as above, with just the regulator parts removed. This looks messy (considering any future changes to the 2 sdhci API will need to be copied to their duplicate sdhci_msm API) and a bit overkill to avoid quirk. At the same time, I don't know how useful such a quirk would be to other platform drivers. Please let me know yo
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } >> + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating 2 new functions in sdhci_msm layer which would do the exact same as above, with just the regulator parts removed. This looks messy (considering any future changes to the 2 sdhci API will need to be copied to their duplicate sdhci_msm API) and a bit overkill to avoid quirk. At the same time, I don't know how useful such a quirk would be to other platform drivers. Please let me know your view/suggestions. + ret = regulator_enable(mmc->supply.v
Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
On 7/10/2018 4:37 PM, Adrian Hunter wrote: On 21/06/18 15:23, Vijay Viswanath wrote: Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) I think you should provide your own ->set_power() instead of this will do sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { And your own ->start_signal_voltage_switch() sdhci_msm_start_signal_voltage_switch() would be an exact copy of sdhci_start_signal_voltage_switch(). will incorporate this if not using quirk. ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) Since we expect mmc_regulator_get_supply() to have been called, this could be: if (!mmc->supply.vmmc) { ret = mmc_regulator_get_supply(mmc); enable_vqmmc = true; } else { ret = 0; } >> + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) And this could be: if (enable_vqmmc) ret = regulator_enable(mmc->supply.vqmmc); else ret = 0; > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is only called if regulator_enable() was called. I missed this. Will cover it. Also I missed one more place where we are doing regulator_disable. During sdhci-msm unbinding, we would end up doing an extra regulator disable (thanks Evan for pointing it out) in sdhci_remove_host. To avoid the quirk( or having any flag), it would require copying the code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating 2 new functions in sdhci_msm layer which would do the exact same as above, with just the regulator parts removed. This looks messy (considering any future changes to the 2 sdhci API will need to be copied to their duplicate sdhci_msm API) and a bit overkill to avoid quirk. At the same time, I don't know how useful such a quirk would be to other platform drivers. Please let me know your view/suggestions. + ret = regulator_enable(mmc->supply.v
[PATCH RFC 2/2] mmc: sdhci-msm: Use internal voltage control
Some sdhci-msm controllers require that voltage switching be done after the HW is ready for it. The HW informs its readiness through power irq. The voltage switching should happen only then. Use the quirk for internal voltage switching and then control the voltage switching using power irq. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 99 ++-- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a0dc3e1..ebdde29 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -43,7 +43,9 @@ #define CORE_PWRCTL_IO_LOW BIT(2) #define CORE_PWRCTL_IO_HIGHBIT(3) #define CORE_PWRCTL_BUS_SUCCESS BIT(0) +#define CORE_PWRCTL_BUS_FAILBIT(1) #define CORE_PWRCTL_IO_SUCCESS BIT(2) +#define CORE_PWRCTL_IO_FAIL BIT(3) #define REQ_BUS_OFFBIT(0) #define REQ_BUS_ON BIT(1) #define REQ_IO_LOW BIT(2) @@ -258,6 +260,7 @@ struct sdhci_msm_host { bool mci_removed; const struct sdhci_msm_variant_ops *var_ops; const struct sdhci_msm_offset *offset; + bool pltfm_init_done; }; static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) @@ -1314,8 +1317,9 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) { 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; u32 irq_status, irq_ack = 0; - int retry = 10; + int retry = 10, ret = 0; u32 pwr_state = 0, io_level = 0; u32 config; const struct sdhci_msm_offset *msm_offset = msm_host->offset; @@ -1351,14 +1355,59 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { - pwr_state = REQ_BUS_ON; - io_level = REQ_IO_HIGH; - irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + if (mmc->supply.vmmc) { + ret = regulator_set_load(mmc->supply.vmmc, 80); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + mmc->ios.vdd); + if (ret) + pr_err("%s: vmmc enable failed: %d\n", + mmc_hostname(mmc), ret); + } + if (mmc->supply.vqmmc && !ret) { + ret = regulator_set_load(mmc->supply.vqmmc, 22000); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vqmmc, + mmc->ios.vdd); + if (!ret) + ret = regulator_enable(mmc->supply.vqmmc); + if (ret) + pr_err("%s: vqmmc enable failed: %d\n", + mmc_hostname(mmc), ret); + } + if (!ret) { + pwr_state = REQ_BUS_ON; + io_level = REQ_IO_HIGH; + irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + } else { + pr_err("%s: BUS_ON req failed(%d). irq_status: 0x%08x\n", + mmc_hostname(mmc), ret, irq_status); + irq_ack |= CORE_PWRCTL_BUS_FAIL; + } } if (irq_status & CORE_PWRCTL_BUS_OFF) { - pwr_state = REQ_BUS_OFF; - io_level = REQ_IO_LOW; - irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + if (mmc->supply.vmmc && msm_host->pltfm_init_done) { + ret = regulator_set_load(mmc->supply.vmmc, 0); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + mmc->ios.vdd); + if (ret) + pr_err("%s: vqmmc disabling failed: %d\n", + mmc_hostname(mmc), ret); + } + if (mmc->supply.vqmmc && msm_host->pltfm_init_done && !ret) { + ret = regulator_set_load(mmc->supply.vqmmc, 0); + ret |= regulator_disable(mmc->supply.vqmmc); + if (ret) + pr_err("%s: vqmmc disabling failed: %d\n", + mmc_hostname(mmc), ret); + } + if (!ret) { + pwr_state = REQ_BUS_OFF; + io_level = REQ_IO_LOW; + irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + } el
[PATCH RFC 2/2] mmc: sdhci-msm: Use internal voltage control
Some sdhci-msm controllers require that voltage switching be done after the HW is ready for it. The HW informs its readiness through power irq. The voltage switching should happen only then. Use the quirk for internal voltage switching and then control the voltage switching using power irq. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 99 ++-- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a0dc3e1..ebdde29 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -43,7 +43,9 @@ #define CORE_PWRCTL_IO_LOW BIT(2) #define CORE_PWRCTL_IO_HIGHBIT(3) #define CORE_PWRCTL_BUS_SUCCESS BIT(0) +#define CORE_PWRCTL_BUS_FAILBIT(1) #define CORE_PWRCTL_IO_SUCCESS BIT(2) +#define CORE_PWRCTL_IO_FAIL BIT(3) #define REQ_BUS_OFFBIT(0) #define REQ_BUS_ON BIT(1) #define REQ_IO_LOW BIT(2) @@ -258,6 +260,7 @@ struct sdhci_msm_host { bool mci_removed; const struct sdhci_msm_variant_ops *var_ops; const struct sdhci_msm_offset *offset; + bool pltfm_init_done; }; static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) @@ -1314,8 +1317,9 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) { 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; u32 irq_status, irq_ack = 0; - int retry = 10; + int retry = 10, ret = 0; u32 pwr_state = 0, io_level = 0; u32 config; const struct sdhci_msm_offset *msm_offset = msm_host->offset; @@ -1351,14 +1355,59 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { - pwr_state = REQ_BUS_ON; - io_level = REQ_IO_HIGH; - irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + if (mmc->supply.vmmc) { + ret = regulator_set_load(mmc->supply.vmmc, 80); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + mmc->ios.vdd); + if (ret) + pr_err("%s: vmmc enable failed: %d\n", + mmc_hostname(mmc), ret); + } + if (mmc->supply.vqmmc && !ret) { + ret = regulator_set_load(mmc->supply.vqmmc, 22000); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vqmmc, + mmc->ios.vdd); + if (!ret) + ret = regulator_enable(mmc->supply.vqmmc); + if (ret) + pr_err("%s: vqmmc enable failed: %d\n", + mmc_hostname(mmc), ret); + } + if (!ret) { + pwr_state = REQ_BUS_ON; + io_level = REQ_IO_HIGH; + irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + } else { + pr_err("%s: BUS_ON req failed(%d). irq_status: 0x%08x\n", + mmc_hostname(mmc), ret, irq_status); + irq_ack |= CORE_PWRCTL_BUS_FAIL; + } } if (irq_status & CORE_PWRCTL_BUS_OFF) { - pwr_state = REQ_BUS_OFF; - io_level = REQ_IO_LOW; - irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + if (mmc->supply.vmmc && msm_host->pltfm_init_done) { + ret = regulator_set_load(mmc->supply.vmmc, 0); + ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + mmc->ios.vdd); + if (ret) + pr_err("%s: vqmmc disabling failed: %d\n", + mmc_hostname(mmc), ret); + } + if (mmc->supply.vqmmc && msm_host->pltfm_init_done && !ret) { + ret = regulator_set_load(mmc->supply.vqmmc, 0); + ret |= regulator_disable(mmc->supply.vqmmc); + if (ret) + pr_err("%s: vqmmc disabling failed: %d\n", + mmc_hostname(mmc), ret); + } + if (!ret) { + pwr_state = REQ_BUS_OFF; + io_level = REQ_IO_LOW; + irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + } el
[PATCH RFC 0/2] Internal voltage control for platform drivers
Certain SDHC controllers may require that voltage switching happen after sepcial conditions. Added a QUIRK for such controllers to use. For SDHCI-MSM controllers, power irq is a signal from controller to SW that it is ready for voltage switch. So added support to register voltage regulators from the msm driver and use them. Voltage switching from core layer is causing CRC/cmd timeout errors in some chipsets. Tested on: sdm845, db410c Requies patch series:"[PATCH V3 0/4] Changes for SDCC5 version" Vijay Viswanath (2): mmc: sdhci: Allow platform controlled voltage switching mmc: sdhci-msm: Use internal voltage control drivers/mmc/host/sdhci-msm.c | 99 ++-- drivers/mmc/host/sdhci.c | 20 ++--- drivers/mmc/host/sdhci.h | 2 + 3 files changed, 104 insertions(+), 17 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) + ret = regulator_enable(mmc->supply.vqmmc); + else + ret = 0; if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170, 195)) host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 23966f8..3b0c97a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -450,6 +450,8 @@ struct sdhci_host { * obtainable timeout. */ #define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT(1<<17) +/* Regulator voltage changes are being done from platform layer */ +#define SDHCI_QUIRK2_INTERNAL_PWR_CTL (1<<18) int irq;/* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 0/2] Internal voltage control for platform drivers
Certain SDHC controllers may require that voltage switching happen after sepcial conditions. Added a QUIRK for such controllers to use. For SDHCI-MSM controllers, power irq is a signal from controller to SW that it is ready for voltage switch. So added support to register voltage regulators from the msm driver and use them. Voltage switching from core layer is causing CRC/cmd timeout errors in some chipsets. Tested on: sdm845, db410c Requies patch series:"[PATCH V3 0/4] Changes for SDCC5 version" Vijay Viswanath (2): mmc: sdhci: Allow platform controlled voltage switching mmc: sdhci-msm: Use internal voltage control drivers/mmc/host/sdhci-msm.c | 99 ++-- drivers/mmc/host/sdhci.c | 20 ++--- drivers/mmc/host/sdhci.h | 2 + 3 files changed, 104 insertions(+), 17 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching
Some controllers can have internal mechanism to inform the SW that it is ready for voltage switching. For such controllers, changing voltage before the HW is ready can result in various issues. Add a quirk, which can be used by drivers of such controllers. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci.c | 20 +++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1c828e0..f0346d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { - if (IS_ERR(host->mmc->supply.vmmc)) + if (IS_ERR(host->mmc->supply.vmmc) || + (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) sdhci_set_power_noreg(host, mode, vdd); else sdhci_set_power_reg(host, mode, vdd); @@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & + SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", @@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, case MMC_SIGNAL_VOLTAGE_180: if (!(host->flags & SDHCI_SIGNALING_180)) return -EINVAL; - if (!IS_ERR(mmc->supply.vqmmc)) { + if (!IS_ERR(mmc->supply.vqmmc) && + !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) { ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", @@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host) * the host can take the appropriate action if regulators are not * available. */ - ret = mmc_regulator_get_supply(mmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) + ret = mmc_regulator_get_supply(mmc); + else + ret = 0; if (ret) return ret; @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); + if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) + ret = regulator_enable(mmc->supply.vqmmc); + else + ret = 0; if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170, 195)) host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 23966f8..3b0c97a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -450,6 +450,8 @@ struct sdhci_host { * obtainable timeout. */ #define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT(1<<17) +/* Regulator voltage changes are being done from platform layer */ +#define SDHCI_QUIRK2_INTERNAL_PWR_CTL (1<<18) int irq;/* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 4/4] mmc: host: Register changes for sdcc V5
From: Sayali Lokhande Add support to use the new compatible string "qcom,sdhci-msm-v5". Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Reviewed-by: Evan Green --- drivers/mmc/host/sdhci-msm.c | 347 +++ 1 file changed, 221 insertions(+), 126 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 3d01bc2..418dbb0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -137,6 +125,12 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +#define msm_host_readl(msm_host, host, offset) \ + msm_host->var_ops->msm_readl_relaxed(host, offset) + +#define msm_host_writel(msm_host, val, host, offset) \ + msm_host->var_ops->msm_writel_relaxed(val, host, offset) + struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; @@ -266,6 +260,14 @@ struct sdhci_msm_host { const struct sdhci_msm_offset *offset; }; +static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return msm_host->offset; +} + /* * APIs to read/write to vendor specific registers which were there in the * core_mem region before MCI was removed. @@ -347,10 +349,12 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); while (ck_out_en != poll) { if (--wait_cnt == 0) { @@ -360,8 +364,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) } udelay(1); - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); } return 0; @@ -377,16 +381,18 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) unsigned long flags; u32 config; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); if (phase > 0xf) return -EINVAL; spin_lock_irqsav
[PATCH V3 4/4] mmc: host: Register changes for sdcc V5
From: Sayali Lokhande Add support to use the new compatible string "qcom,sdhci-msm-v5". Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Reviewed-by: Evan Green --- drivers/mmc/host/sdhci-msm.c | 347 +++ 1 file changed, 221 insertions(+), 126 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 3d01bc2..418dbb0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -137,6 +125,12 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +#define msm_host_readl(msm_host, host, offset) \ + msm_host->var_ops->msm_readl_relaxed(host, offset) + +#define msm_host_writel(msm_host, val, host, offset) \ + msm_host->var_ops->msm_writel_relaxed(val, host, offset) + struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; @@ -266,6 +260,14 @@ struct sdhci_msm_host { const struct sdhci_msm_offset *offset; }; +static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return msm_host->offset; +} + /* * APIs to read/write to vendor specific registers which were there in the * core_mem region before MCI was removed. @@ -347,10 +349,12 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); while (ck_out_en != poll) { if (--wait_cnt == 0) { @@ -360,8 +364,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) } udelay(1); - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); } return 0; @@ -377,16 +381,18 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) unsigned long flags; u32 config; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); if (phase > 0xf) return -EINVAL; spin_lock_irqsav
[PATCH V3 3/4] Documentation: sdhci-msm: Add new compatible string for SDCC v5
From: Sayali Lokhande For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Acked-by: Rob Herring --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..502b3b8 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,12 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain: + "qcom,sdhci-msm-v4" for sdcc versions less than 5.0 + "qcom,sdhci-msm-v5" for sdcc versions >= 5.0 + For SDCC version 5.0.0, MCI registers are removed from SDCC + interface and some registers are moved to HC. New compatible + string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 3/4] Documentation: sdhci-msm: Add new compatible string for SDCC v5
From: Sayali Lokhande For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Acked-by: Rob Herring --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..502b3b8 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,12 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain: + "qcom,sdhci-msm-v4" for sdcc versions less than 5.0 + "qcom,sdhci-msm-v5" for sdcc versions >= 5.0 + For SDCC version 5.0.0, MCI registers are removed from SDCC + interface and some registers are moved to HC. New compatible + string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures
In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Reviewed-by: Evan Green --- drivers/mmc/host/sdhci-msm.c | 75 1 file changed, 75 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4050c99..3d01bc2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,22 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1bc, }; +struct sdhci_msm_variant_ops { + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +261,45 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1534,28 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_mci_var = { + .mci_removed = false, + .var_ops = _var_ops, + .offset = _msm_mci_offset, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_v5_var = { + .mci_removed = true, + .var_ops = _var_ops, + .offset = _msm_v5_offset, +}; + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures
In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Reviewed-by: Evan Green --- drivers/mmc/host/sdhci-msm.c | 75 1 file changed, 75 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4050c99..3d01bc2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,22 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1bc, }; +struct sdhci_msm_variant_ops { + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +261,45 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1534,28 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_mci_var = { + .mci_removed = false, + .var_ops = _var_ops, + .offset = _msm_mci_offset, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_v5_var = { + .mci_removed = true, + .var_ops = _var_ops, + .offset = _msm_v5_offset, +}; + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 1/4] mmc: sdhci-msm: Define new Register address map
From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Reviewed-by: Evan Green Acked-by: Adrian Hunter --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..4050c99 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0cc, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xdc, + .core_pwrctl_mask = 0xe0, + .core_pwrctl_clear = 0xe4, + .core_pwrctl_ctl = 0xe8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10c, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11c, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1b0, + .core_dll_config_2 = 0x1b4, + .core_ddr_config = 0x1b8, + .core_ddr_config_2 = 0x1bc, +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 0/4] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Depends on patch series: "[PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm" Changes since RFC: Dropped voltage regulator changes in sdhci-msm Split the "Register changes for sdcc V5" patch Instead of checking mci removal for deciding which base addr to use, new function pointers are defined for the 2 variants of sdcc: 1) MCI present 2) V5 (mci removed) Instead of string comparing with the compatible string from DT file, the sdhci_msm_probe will now pick the data associated with the compatible entry and use it to load variant specific address offsets and msm variant specific read/write ops. Changes since V1: Removed unused msm_reab & msm_writeb APIs Changed certain register addresses from uppercase to lowercase hex letters Removed extra lines and spaces Split "[PATCH V1 0/3] Changes for SDCC5 version" patch into two, one for Documentation and other for the driver changes. Changes since V2: Used lower case for macro function defenitions Removed unused function pointers for msm_readb & msm_writeb Sayali Lokhande (3): mmc: sdhci-msm: Define new Register address map Documentation: sdhci-msm: Add new compatible string for SDCC v5 mmc: host: Register changes for sdcc V5 Vijay Viswanath (1): mmc: sdhci-msm: Add msm version specific ops and data structures .../devicetree/bindings/mmc/sdhci-msm.txt | 7 +- drivers/mmc/host/sdhci-msm.c | 511 - 2 files changed, 391 insertions(+), 127 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 1/4] mmc: sdhci-msm: Define new Register address map
From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath Reviewed-by: Evan Green Acked-by: Adrian Hunter --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..4050c99 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0cc, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xdc, + .core_pwrctl_mask = 0xe0, + .core_pwrctl_clear = 0xe4, + .core_pwrctl_ctl = 0xe8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10c, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11c, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1b0, + .core_dll_config_2 = 0x1b4, + .core_ddr_config = 0x1b8, + .core_ddr_config_2 = 0x1bc, +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 0/4] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Depends on patch series: "[PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm" Changes since RFC: Dropped voltage regulator changes in sdhci-msm Split the "Register changes for sdcc V5" patch Instead of checking mci removal for deciding which base addr to use, new function pointers are defined for the 2 variants of sdcc: 1) MCI present 2) V5 (mci removed) Instead of string comparing with the compatible string from DT file, the sdhci_msm_probe will now pick the data associated with the compatible entry and use it to load variant specific address offsets and msm variant specific read/write ops. Changes since V1: Removed unused msm_reab & msm_writeb APIs Changed certain register addresses from uppercase to lowercase hex letters Removed extra lines and spaces Split "[PATCH V1 0/3] Changes for SDCC5 version" patch into two, one for Documentation and other for the driver changes. Changes since V2: Used lower case for macro function defenitions Removed unused function pointers for msm_readb & msm_writeb Sayali Lokhande (3): mmc: sdhci-msm: Define new Register address map Documentation: sdhci-msm: Add new compatible string for SDCC v5 mmc: host: Register changes for sdcc V5 Vijay Viswanath (1): mmc: sdhci-msm: Add msm version specific ops and data structures .../devicetree/bindings/mmc/sdhci-msm.txt | 7 +- drivers/mmc/host/sdhci-msm.c | 511 - 2 files changed, 391 insertions(+), 127 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH V2 4/4] mmc: host: Register changes for sdcc V5
On 6/13/2018 4:55 AM, Stephen Boyd wrote: Quoting Vijay Viswanath (2018-05-29 02:52:41) @@ -137,6 +125,12 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +#define MSM_HOST_READL(msm_host, host, offset) \ + msm_host->var_ops->msm_readl_relaxed(host, offset) + +#define MSM_HOST_WRITEL(msm_host, val, host, offset) \ + msm_host->var_ops->msm_writel_relaxed(val, host, offset) Is there a reason these macros are capitalized? We don't have READL and WRITEL macros in the kernel because function-like macros are typically lowercase. will change them to lower case. Didn't notice that... + struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; @@ -268,6 +262,14 @@ struct sdhci_msm_host { const struct sdhci_msm_offset *offset; }; +const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) static? will do +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return msm_host->offset; +} + -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH V2 4/4] mmc: host: Register changes for sdcc V5
On 6/13/2018 4:55 AM, Stephen Boyd wrote: Quoting Vijay Viswanath (2018-05-29 02:52:41) @@ -137,6 +125,12 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +#define MSM_HOST_READL(msm_host, host, offset) \ + msm_host->var_ops->msm_readl_relaxed(host, offset) + +#define MSM_HOST_WRITEL(msm_host, val, host, offset) \ + msm_host->var_ops->msm_writel_relaxed(val, host, offset) Is there a reason these macros are capitalized? We don't have READL and WRITEL macros in the kernel because function-like macros are typically lowercase. will change them to lower case. Didn't notice that... + struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; @@ -268,6 +262,14 @@ struct sdhci_msm_host { const struct sdhci_msm_offset *offset; }; +const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) static? will do +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return msm_host->offset; +} + -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH V2 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures
Hi Stephen, On 6/13/2018 5:06 AM, Stephen Boyd wrote: Quoting Vijay Viswanath (2018-05-29 02:52:39) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4050c99..2a66aa0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,24 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1bc, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ This is sort of odd. Usually we have a read/write function that swizzles based on register variants, and that's contained with that function. Now it's the other way. +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +263,45 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); Is core_mem assigned in the new hardware? Maybe that needs to be 'repurposed' for vendor specific registers on v5 and renamed to something like msm_host::vendor_base or something like that. There is no core_mem in the new hardware. We can assign hc_mem address to core_mem variable (if SDCC5) and do away with the need of special read/write functions, but I feel thats a bad approach and misleading. +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1536,28 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_mci_var = { + .mci_removed = 0, Please use true and false instead of 0 and 1 when the type is bool. Will do + .var_ops = _var_ops, + .offset = _msm_mci_offset, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_v5_var = { + .mci_removed = 1, + .var_ops = _var_ops, + .offset = _msm_v5_offset, +}; -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH V2 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures
Hi Stephen, On 6/13/2018 5:06 AM, Stephen Boyd wrote: Quoting Vijay Viswanath (2018-05-29 02:52:39) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4050c99..2a66aa0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,24 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1bc, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ This is sort of odd. Usually we have a read/write function that swizzles based on register variants, and that's contained with that function. Now it's the other way. +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +263,45 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); Is core_mem assigned in the new hardware? Maybe that needs to be 'repurposed' for vendor specific registers on v5 and renamed to something like msm_host::vendor_base or something like that. There is no core_mem in the new hardware. We can assign hc_mem address to core_mem variable (if SDCC5) and do away with the need of special read/write functions, but I feel thats a bad approach and misleading. +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1536,28 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_mci_var = { + .mci_removed = 0, Please use true and false instead of 0 and 1 when the type is bool. Will do + .var_ops = _var_ops, + .offset = _msm_mci_offset, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_v5_var = { + .mci_removed = 1, + .var_ops = _var_ops, + .offset = _msm_v5_offset, +}; -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 4/4] mmc: sdhci-msm: Add sdhci msm register write APIs which wait for pwr irq
Hi Georgi, Thanks for testing the patch on 8096 and pointing out this issue. The issue is coming because, when card is removed, the HOST_CONTROL2 register is retaining the 1.8V Signalling enable bit till SDHCI reset happens after a new card is inserted. Adding the change you suggested can avoid this wait, but I feel a better solution is to clear the 1.8V signalling bit when the card is removed. When a new card is inserted, we shouldn't be keeping the 1.8V bit set until we send cmd11 to the SD card. A new SD card should start with 3V. One solution is to explicitly clear the HOST_CONTROL2 register when card is removed. Other way is to revert the commit: 9718f84b85396e090ca42fafa730410d286d61e3 "mmc: sdhci-msm: Do not reset the controller if no card in the slot" The sdhci-msm doesn't require "SDHCI_QUIRK_NO_CARD_NO_RESET". The issue which above commit is trying to avoid is fixed by the pwr-irq patches. Resetting the controller will clear the HOST_CONTROL2 register and avoid this issue. Can you please try this ? I tested reverting the QUIRK on two platforms: db410c(8916) and sdm845. SD card insert/remove worked fine after that and I didn't get any "Reset 0x1 never completed" error during card insert/remove or shutdown. Thanks, Vijay On 5/29/2018 5:49 PM, Georgi Djakov wrote: Hello Vijay, On 09/27/2017 08:34 AM, Vijay Viswanath wrote: Register writes which change voltage of IO lines or turn the IO bus on/off require controller to be ready before progressing further. When the controller is ready, it will generate a power irq which needs to be handled. The thread which initiated the register write should wait for power irq to complete. This will be done through the new sdhc msm write APIs which will check whether the particular write can trigger a power irq and wait for it with a timeout if it is expected. The SDHC core power control IRQ gets triggered when - * There is a state change in power control bit (bit 0) of SDHCI_POWER_CONTROL register. * There is a state change in 1.8V enable bit (bit 3) of SDHCI_HOST_CONTROL2 register. * Bit 1 of SDHCI_SOFTWARE_RESET is set. Also add support APIs which are used by sdhc msm write APIs to check if power irq is expected to be generated and wait for the power irq to come and complete if the irq is expected. This patch requires CONFIG_MMC_SDHCI_IO_ACCESSORS to be enabled. Signed-off-by: Sahitya Tummala Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 173 ++- 1 file changed, 171 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c [..] +/* + * sdhci_msm_check_power_status API should be called when registers writes + * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens. + * To what state the register writes will change the IO lines should be passed + * as the argument req_type. This API will check whether the IO line's state + * is already the expected state and will wait for power irq only if + * power irq is expected to be trigerred based on the current IO line state + * and expected IO line state. + */ +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); + bool done = false; + + pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n", + mmc_hostname(host->mmc), __func__, req_type, + msm_host->curr_pwr_state, msm_host->curr_io_level); + + /* +* The IRQ for request type IO High/LOW will be generated when - +* there is a state change in 1.8V enable bit (bit 3) of +* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0 +* which indicates 3.3V IO voltage. So, when MMC core layer tries +* to set it to 3.3V before card detection happens, the +* IRQ doesn't get triggered as there is no state change in this bit. +* The driver already handles this case by changing the IO voltage +* level to high as part of controller power up sequence. Hence, check +* for host->pwr to handle a case where IO voltage high request is +* issued even before controller power up. +*/ + if ((req_type & REQ_IO_HIGH) && !host->pwr) { + pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n", + mmc_hostname(host->mmc), req_type); + return; + } + if ((req_type & msm_host->curr_pwr_state) || + (req_type & msm_host->curr_io_level)) + done = true; + /* +* This is needed here to handle cases where register writes will +* not change the current bus state or io l
Re: [PATCH v2 4/4] mmc: sdhci-msm: Add sdhci msm register write APIs which wait for pwr irq
Hi Georgi, Thanks for testing the patch on 8096 and pointing out this issue. The issue is coming because, when card is removed, the HOST_CONTROL2 register is retaining the 1.8V Signalling enable bit till SDHCI reset happens after a new card is inserted. Adding the change you suggested can avoid this wait, but I feel a better solution is to clear the 1.8V signalling bit when the card is removed. When a new card is inserted, we shouldn't be keeping the 1.8V bit set until we send cmd11 to the SD card. A new SD card should start with 3V. One solution is to explicitly clear the HOST_CONTROL2 register when card is removed. Other way is to revert the commit: 9718f84b85396e090ca42fafa730410d286d61e3 "mmc: sdhci-msm: Do not reset the controller if no card in the slot" The sdhci-msm doesn't require "SDHCI_QUIRK_NO_CARD_NO_RESET". The issue which above commit is trying to avoid is fixed by the pwr-irq patches. Resetting the controller will clear the HOST_CONTROL2 register and avoid this issue. Can you please try this ? I tested reverting the QUIRK on two platforms: db410c(8916) and sdm845. SD card insert/remove worked fine after that and I didn't get any "Reset 0x1 never completed" error during card insert/remove or shutdown. Thanks, Vijay On 5/29/2018 5:49 PM, Georgi Djakov wrote: Hello Vijay, On 09/27/2017 08:34 AM, Vijay Viswanath wrote: Register writes which change voltage of IO lines or turn the IO bus on/off require controller to be ready before progressing further. When the controller is ready, it will generate a power irq which needs to be handled. The thread which initiated the register write should wait for power irq to complete. This will be done through the new sdhc msm write APIs which will check whether the particular write can trigger a power irq and wait for it with a timeout if it is expected. The SDHC core power control IRQ gets triggered when - * There is a state change in power control bit (bit 0) of SDHCI_POWER_CONTROL register. * There is a state change in 1.8V enable bit (bit 3) of SDHCI_HOST_CONTROL2 register. * Bit 1 of SDHCI_SOFTWARE_RESET is set. Also add support APIs which are used by sdhc msm write APIs to check if power irq is expected to be generated and wait for the power irq to come and complete if the irq is expected. This patch requires CONFIG_MMC_SDHCI_IO_ACCESSORS to be enabled. Signed-off-by: Sahitya Tummala Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 173 ++- 1 file changed, 171 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c [..] +/* + * sdhci_msm_check_power_status API should be called when registers writes + * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens. + * To what state the register writes will change the IO lines should be passed + * as the argument req_type. This API will check whether the IO line's state + * is already the expected state and will wait for power irq only if + * power irq is expected to be trigerred based on the current IO line state + * and expected IO line state. + */ +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); + bool done = false; + + pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n", + mmc_hostname(host->mmc), __func__, req_type, + msm_host->curr_pwr_state, msm_host->curr_io_level); + + /* +* The IRQ for request type IO High/LOW will be generated when - +* there is a state change in 1.8V enable bit (bit 3) of +* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0 +* which indicates 3.3V IO voltage. So, when MMC core layer tries +* to set it to 3.3V before card detection happens, the +* IRQ doesn't get triggered as there is no state change in this bit. +* The driver already handles this case by changing the IO voltage +* level to high as part of controller power up sequence. Hence, check +* for host->pwr to handle a case where IO voltage high request is +* issued even before controller power up. +*/ + if ((req_type & REQ_IO_HIGH) && !host->pwr) { + pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n", + mmc_hostname(host->mmc), req_type); + return; + } + if ((req_type & msm_host->curr_pwr_state) || + (req_type & msm_host->curr_io_level)) + done = true; + /* +* This is needed here to handle cases where register writes will +* not change the current bus state or io l
[PATCH V2 4/4] mmc: host: Register changes for sdcc V5
Add support to use the new compatible string "qcom,sdhci-msm-v5". Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 347 +++ 1 file changed, 221 insertions(+), 126 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2a66aa0..4d0fd2d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -137,6 +125,12 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +#define MSM_HOST_READL(msm_host, host, offset) \ + msm_host->var_ops->msm_readl_relaxed(host, offset) + +#define MSM_HOST_WRITEL(msm_host, val, host, offset) \ + msm_host->var_ops->msm_writel_relaxed(val, host, offset) + struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; @@ -268,6 +262,14 @@ struct sdhci_msm_host { const struct sdhci_msm_offset *offset; }; +const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return msm_host->offset; +} + /* * APIs to read/write to vendor specific registers which were there in the * core_mem region before MCI was removed. @@ -349,10 +351,12 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); while (ck_out_en != poll) { if (--wait_cnt == 0) { @@ -362,8 +366,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) } udelay(1); - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); } return 0; @@ -379,16 +383,18 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) unsigned long flags; u32 config; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); if (phase > 0xf) return -EINVAL; spin_lock_irqsave(>lock, flags); - config = readl_relaxed(host-&
[PATCH V2 4/4] mmc: host: Register changes for sdcc V5
Add support to use the new compatible string "qcom,sdhci-msm-v5". Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 347 +++ 1 file changed, 221 insertions(+), 126 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2a66aa0..4d0fd2d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -137,6 +125,12 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +#define MSM_HOST_READL(msm_host, host, offset) \ + msm_host->var_ops->msm_readl_relaxed(host, offset) + +#define MSM_HOST_WRITEL(msm_host, val, host, offset) \ + msm_host->var_ops->msm_writel_relaxed(val, host, offset) + struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; @@ -268,6 +262,14 @@ struct sdhci_msm_host { const struct sdhci_msm_offset *offset; }; +const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return msm_host->offset; +} + /* * APIs to read/write to vendor specific registers which were there in the * core_mem region before MCI was removed. @@ -349,10 +351,12 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); while (ck_out_en != poll) { if (--wait_cnt == 0) { @@ -362,8 +366,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) } udelay(1); - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); } return 0; @@ -379,16 +383,18 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) unsigned long flags; u32 config; struct mmc_host *mmc = host->mmc; + const struct sdhci_msm_offset *msm_offset = + sdhci_priv_msm_offset(host); if (phase > 0xf) return -EINVAL; spin_lock_irqsave(>lock, flags); - config = readl_relaxed(host-&
[PATCH V2 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures
In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 77 1 file changed, 77 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4050c99..2a66aa0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,24 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1bc, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +263,45 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1536,28 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_mci_var = { + .mci_removed = 0, + .var_ops = _var_ops, + .offset = _msm_mci_offset, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_v5_var = { + .mci_removed = 1, + .var_ops = _var_ops, + .offset = _msm_v5_offset, +}; + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V2 3/4] Documentation: sdhci-msm: Add new compatible string for SDCC v5
From: Sayali Lokhande For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..502b3b8 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,12 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain: + "qcom,sdhci-msm-v4" for sdcc versions less than 5.0 + "qcom,sdhci-msm-v5" for sdcc versions >= 5.0 + For SDCC version 5.0.0, MCI registers are removed from SDCC + interface and some registers are moved to HC. New compatible + string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V2 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures
In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 77 1 file changed, 77 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4050c99..2a66aa0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,24 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1bc, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +263,45 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1536,28 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_mci_var = { + .mci_removed = 0, + .var_ops = _var_ops, + .offset = _msm_mci_offset, +}; + +static const struct sdhci_msm_variant_info sdhci_msm_v5_var = { + .mci_removed = 1, + .var_ops = _var_ops, + .offset = _msm_v5_offset, +}; + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V2 3/4] Documentation: sdhci-msm: Add new compatible string for SDCC v5
From: Sayali Lokhande For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..502b3b8 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,12 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain: + "qcom,sdhci-msm-v4" for sdcc versions less than 5.0 + "qcom,sdhci-msm-v5" for sdcc versions >= 5.0 + For SDCC version 5.0.0, MCI registers are removed from SDCC + interface and some registers are moved to HC. New compatible + string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V2 1/4] mmc: sdhci-msm: Define new Register address map
From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..4050c99 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0cc, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xdc, + .core_pwrctl_mask = 0xe0, + .core_pwrctl_clear = 0xe4, + .core_pwrctl_ctl = 0xe8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10c, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11c, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1b0, + .core_dll_config_2 = 0x1b4, + .core_ddr_config = 0x1b8, + .core_ddr_config_2 = 0x1bc, +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V2 1/4] mmc: sdhci-msm: Define new Register address map
From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..4050c99 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0cc, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xdc, + .core_pwrctl_mask = 0xe0, + .core_pwrctl_clear = 0xe4, + .core_pwrctl_ctl = 0xe8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10c, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11c, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1b0, + .core_dll_config_2 = 0x1b4, + .core_ddr_config = 0x1b8, + .core_ddr_config_2 = 0x1bc, +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V2 0/4] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Changes since RFC: Dropped voltage regulator changes in sdhci-msm Split the "Register changes for sdcc V5" patch Instead of checking mci removal for deciding which base addr to use, new function pointers are defined for the 2 variants of sdcc: 1) MCI present 2) V5 (mci removed) Instead of string comparing with the compatible string from DT file, the sdhci_msm_probe will now pick the data associated with the compatible entry and use it to load variant specific address offsets and msm variant specific read/write ops. Changes since V1: Removed unused msm_reab & msm_writeb APIs Changed certain register addresses from uppercase to lowercase hex letters Removed extra lines and spaces Split "[PATCH V1 0/3] Changes for SDCC5 version" patch into two, one for Documentation and other for the driver changes. Sayali Lokhande (2): mmc: sdhci-msm: Define new Register address map Documentation: sdhci-msm: Add new compatible string for SDCC v5 Vijay Viswanath (2): mmc: sdhci-msm: Add msm version specific ops and data structures mmc: host: Register changes for sdcc V5 .../devicetree/bindings/mmc/sdhci-msm.txt | 7 +- drivers/mmc/host/sdhci-msm.c | 513 - 2 files changed, 393 insertions(+), 127 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V2 0/4] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Changes since RFC: Dropped voltage regulator changes in sdhci-msm Split the "Register changes for sdcc V5" patch Instead of checking mci removal for deciding which base addr to use, new function pointers are defined for the 2 variants of sdcc: 1) MCI present 2) V5 (mci removed) Instead of string comparing with the compatible string from DT file, the sdhci_msm_probe will now pick the data associated with the compatible entry and use it to load variant specific address offsets and msm variant specific read/write ops. Changes since V1: Removed unused msm_reab & msm_writeb APIs Changed certain register addresses from uppercase to lowercase hex letters Removed extra lines and spaces Split "[PATCH V1 0/3] Changes for SDCC5 version" patch into two, one for Documentation and other for the driver changes. Sayali Lokhande (2): mmc: sdhci-msm: Define new Register address map Documentation: sdhci-msm: Add new compatible string for SDCC v5 Vijay Viswanath (2): mmc: sdhci-msm: Add msm version specific ops and data structures mmc: host: Register changes for sdcc V5 .../devicetree/bindings/mmc/sdhci-msm.txt | 7 +- drivers/mmc/host/sdhci-msm.c | 513 - 2 files changed, 393 insertions(+), 127 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH V1 3/3] mmc: host: Register changes for sdcc V5
On 5/22/2018 11:42 PM, Evan Green wrote: Hi Vijay. Thanks for this patch. On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath <vvisw...@codeaurora.org> wrote: From: Sayali Lokhande <saya...@codeaurora.org> For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 344 + 2 files changed, 222 insertions(+), 127 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb2bb59..408e6b2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 Remove CORE_MCI_VERSION as well. Missed it. Will remove #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -380,10 +368,14 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + 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; I notice this pattern is pasted all over the place in order to get to the offsets. Maybe a macro or inlined function would be cleaner to get you to directly to the sdhci_msm_offset struct from sdhci_host, rather than this blob of paste soup everywhere. In some places you do seem to use the intermediate locals, so those cases wouldn't need to use the new helper. /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!
Re: [PATCH V1 3/3] mmc: host: Register changes for sdcc V5
On 5/22/2018 11:42 PM, Evan Green wrote: Hi Vijay. Thanks for this patch. On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath wrote: From: Sayali Lokhande For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 344 + 2 files changed, 222 insertions(+), 127 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb2bb59..408e6b2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 Remove CORE_MCI_VERSION as well. Missed it. Will remove #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -380,10 +368,14 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + 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; I notice this pattern is pasted all over the place in order to get to the offsets. Maybe a macro or inlined function would be cleaner to get you to directly to the sdhci_msm_offset struct from sdhci_host, rather than this blob of paste soup everywhere. In some places you do seem to use the intermediate locals, so those cases wouldn't need to use the new helper. /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN);
Re: [PATCH V1 2/3] mmc: sdhci-msm: Add msm version specific ops and data structures
On 5/22/2018 11:40 PM, Evan Green wrote: On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath <vvisw...@codeaurora.org> wrote: In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 112 +++ 1 file changed, 112 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2524455..bb2bb59 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,25 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1BC, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); I don't see any uses of msm_readb_relaxed or msm_writeb_relaxed in this patch or the next one. Are these needed? They are not used as of now. Kept them since they can have use later. Felt it better to define base functions and addresses now itself. + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + + Remove extra blank line. struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +264,75 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u8 sdhci_msm_mci_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readb_relaxed(msm_host->core_mem + offset); +} + +static u8 sdhci_msm_v5_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readb_relaxed(host->ioaddr + offset); +} + +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writeb_relaxed(u8 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writeb_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writeb_relaxed(u8 val, struct sdhci_host *host, + u32 offset) +{ + writeb_relaxed(val, host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, struct sdhci_host *host, You squeaked over 80 characters here. Move the second parameter down with the third. -Evan Thanks for going through the patch thoroughly. Will address the comments. Thanks, Vijay
Re: [PATCH V1 2/3] mmc: sdhci-msm: Add msm version specific ops and data structures
On 5/22/2018 11:40 PM, Evan Green wrote: On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath wrote: In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 112 +++ 1 file changed, 112 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2524455..bb2bb59 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,25 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1BC, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); I don't see any uses of msm_readb_relaxed or msm_writeb_relaxed in this patch or the next one. Are these needed? They are not used as of now. Kept them since they can have use later. Felt it better to define base functions and addresses now itself. + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + + Remove extra blank line. struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +264,75 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u8 sdhci_msm_mci_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readb_relaxed(msm_host->core_mem + offset); +} + +static u8 sdhci_msm_v5_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readb_relaxed(host->ioaddr + offset); +} + +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writeb_relaxed(u8 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writeb_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writeb_relaxed(u8 val, struct sdhci_host *host, + u32 offset) +{ + writeb_relaxed(val, host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, struct sdhci_host *host, You squeaked over 80 characters here. Move the second parameter down with the third. -Evan Thanks for going through the patch thoroughly. Will address the comments. Thanks, Vijay
Re: [PATCH V1 1/3] mmc: sdhci-msm: Define new Register address map
On 5/22/2018 11:39 PM, Evan Green wrote: Hi Vijay, On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath <vvisw...@codeaurora.org> wrote: From: Sayali Lokhande <saya...@codeaurora.org> For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..2524455 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0CC, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xDC, + .core_pwrctl_mask = 0xE0, + .core_pwrctl_clear = 0xE4, + .core_pwrctl_ctl = 0xE8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10C, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11C, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1B0, + .core_dll_config_2 = 0x1B4, + .core_ddr_config = 0x1B8, + .core_ddr_config_2 = 0x1BC, +}; + I notice a lot of these are never used in the subsequent patches of this series. I guess more register definitions are always better than fewer, it's just a shame that they take up space now. Did you just add everything that was different between v4 and v5, or how did you come up with this set? Also, I think lowercase hex letters are preferred. I verified that the v5 register offsets look good, at least for the registers I have documentation for. Yeah, felt it better to include all registers even they are not used currently. Will change to use lowercase hex letters -Evan
Re: [PATCH V1 1/3] mmc: sdhci-msm: Define new Register address map
On 5/22/2018 11:39 PM, Evan Green wrote: Hi Vijay, On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath wrote: From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..2524455 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0CC, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xDC, + .core_pwrctl_mask = 0xE0, + .core_pwrctl_clear = 0xE4, + .core_pwrctl_ctl = 0xE8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10C, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11C, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1B0, + .core_dll_config_2 = 0x1B4, + .core_ddr_config = 0x1B8, + .core_ddr_config_2 = 0x1BC, +}; + I notice a lot of these are never used in the subsequent patches of this series. I guess more register definitions are always better than fewer, it's just a shame that they take up space now. Did you just add everything that was different between v4 and v5, or how did you come up with this set? Also, I think lowercase hex letters are preferred. I verified that the v5 register offsets look good, at least for the registers I have documentation for. Yeah, felt it better to include all registers even they are not used currently. Will change to use lowercase hex letters -Evan
[PATCH V1 2/3] mmc: sdhci-msm: Add msm version specific ops and data structures
In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 112 +++ 1 file changed, 112 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2524455..bb2bb59 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,25 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1BC, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +264,75 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u8 sdhci_msm_mci_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readb_relaxed(msm_host->core_mem + offset); +} + +static u8 sdhci_msm_v5_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readb_relaxed(host->ioaddr + offset); +} + +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writeb_relaxed(u8 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writeb_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writeb_relaxed(u8 val, struct sdhci_host *host, + u32 offset) +{ + writeb_relaxed(val, host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, struct sdhci_host *host, + u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1567,32 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readb_relaxed = sdhci_msm_mci_variant_readb_relaxed, + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writeb_relaxed = sdhci_msm_mci_variant_writeb_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readb_relaxed = sdhci_msm_v5_variant_readb_relaxed, + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writeb_relaxed = sdhci_msm_v5_variant_writeb_relaxed, + .msm_writel_relaxed = sdhci_msm_
[PATCH V1 2/3] mmc: sdhci-msm: Add msm version specific ops and data structures
In addition to offsets of certain registers changing, the registers in core_mem have been shifted to HC mem as well. To access these registers, define msm version specific functions. These functions can be loaded into the function pointers at the time of probe based on the msm version detected. Also defind new data structure to hold version specific Ops and register addresses. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 112 +++ 1 file changed, 112 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2524455..bb2bb59 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -226,6 +226,25 @@ struct sdhci_msm_offset { .core_ddr_config_2 = 0x1BC, }; +struct sdhci_msm_variant_ops { + u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset); + u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); + void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset); + void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, + u32 offset); +}; + +/* + * From V5, register spaces have changed. Wrap this info in a structure + * and choose the data_structure based on version info mentioned in DT. + */ +struct sdhci_msm_variant_info { + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; +}; + + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -245,8 +264,75 @@ struct sdhci_msm_host { wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; + bool mci_removed; + const struct sdhci_msm_variant_ops *var_ops; + const struct sdhci_msm_offset *offset; }; +/* + * APIs to read/write to vendor specific registers which were there in the + * core_mem region before MCI was removed. + */ +static u8 sdhci_msm_mci_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readb_relaxed(msm_host->core_mem + offset); +} + +static u8 sdhci_msm_v5_variant_readb_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readb_relaxed(host->ioaddr + offset); +} + +static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + return readl_relaxed(msm_host->core_mem + offset); +} + +static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host, + u32 offset) +{ + return readl_relaxed(host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writeb_relaxed(u8 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writeb_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writeb_relaxed(u8 val, struct sdhci_host *host, + u32 offset) +{ + writeb_relaxed(val, host->ioaddr + offset); +} + +static void sdhci_msm_mci_variant_writel_relaxed(u32 val, + struct sdhci_host *host, u32 offset) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + writel_relaxed(val, msm_host->core_mem + offset); +} + +static void sdhci_msm_v5_variant_writel_relaxed(u32 val, struct sdhci_host *host, + u32 offset) +{ + writel_relaxed(val, host->ioaddr + offset); +} + static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, unsigned int clock) { @@ -1481,6 +1567,32 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } +static const struct sdhci_msm_variant_ops mci_var_ops = { + .msm_readb_relaxed = sdhci_msm_mci_variant_readb_relaxed, + .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, + .msm_writeb_relaxed = sdhci_msm_mci_variant_writeb_relaxed, + .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, +}; + +static const struct sdhci_msm_variant_ops v5_var_ops = { + .msm_readb_relaxed = sdhci_msm_v5_variant_readb_relaxed, + .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed, + .msm_writeb_relaxed = sdhci_msm_v5_variant_writeb_relaxed, + .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed, +}; + +static const struct sdhci_
[PATCH V1 0/3] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Changes since RFC: Dropped voltage regulator changes in sdhci-msm Split the "Register changes for sdcc V5" patch Instead of checking mci removal for deciding which base addr to use, new function pointers are defined for the 2 variants of sdcc: 1) MCI present 2) V5 (mci removed) Instead of string comparing with the compatible string from DT file, the sdhci_msm_probe will now pick the data associated with the compatible entry and use it to load variant specific address offsets and msm variant specific read/write ops. Sayali Lokhande (2): mmc: sdhci-msm: Define new Register address map mmc: host: Register changes for sdcc V5 Vijay Viswanath (1): mmc: sdhci-msm: Add msm version specific ops and data structures .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 545 - 2 files changed, 423 insertions(+), 127 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 0/3] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Changes since RFC: Dropped voltage regulator changes in sdhci-msm Split the "Register changes for sdcc V5" patch Instead of checking mci removal for deciding which base addr to use, new function pointers are defined for the 2 variants of sdcc: 1) MCI present 2) V5 (mci removed) Instead of string comparing with the compatible string from DT file, the sdhci_msm_probe will now pick the data associated with the compatible entry and use it to load variant specific address offsets and msm variant specific read/write ops. Sayali Lokhande (2): mmc: sdhci-msm: Define new Register address map mmc: host: Register changes for sdcc V5 Vijay Viswanath (1): mmc: sdhci-msm: Add msm version specific ops and data structures .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 545 - 2 files changed, 423 insertions(+), 127 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 1/3] mmc: sdhci-msm: Define new Register address map
From: Sayali Lokhande <saya...@codeaurora.org> For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..2524455 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0CC, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xDC, + .core_pwrctl_mask = 0xE0, + .core_pwrctl_clear = 0xE4, + .core_pwrctl_ctl = 0xE8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10C, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11C, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1B0, + .core_dll_config_2 = 0x1B4, + .core_ddr_config = 0x1B8, + .core_ddr_config_2 = 0x1BC, +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 3/3] mmc: host: Register changes for sdcc V5
From: Sayali Lokhande <saya...@codeaurora.org> For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 344 + 2 files changed, 222 insertions(+), 127 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb2bb59..408e6b2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -380,10 +368,14 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + 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; /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); while (ck_out_en != poll) { if (--wait_cnt == 0) { @@ -393,8 +385,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) } udelay(1); - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); } return 0; @@ -410,16 +402,20 @@ static int msm_config_cm_dll_phase(struc
[PATCH V1 1/3] mmc: sdhci-msm: Define new Register address map
From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. Define a new data structure where we can statically define the address offsets for the registers in different SDCC versions. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 89 1 file changed, 89 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..2524455 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -137,6 +137,95 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_hc_mode; + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +static const struct sdhci_msm_offset sdhci_msm_v5_offset = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +static const struct sdhci_msm_offset sdhci_msm_mci_offset = { + .core_hc_mode = 0x78, + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0CC, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xDC, + .core_pwrctl_mask = 0xE0, + .core_pwrctl_clear = 0xE4, + .core_pwrctl_ctl = 0xE8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10C, + .core_vendor_spec_adma_err_addr0 = 0x114, + .core_vendor_spec_adma_err_addr1 = 0x118, + .core_vendor_spec_func2 = 0x110, + .core_vendor_spec_capabilities0 = 0x11C, + .core_ddr_200_cfg = 0x184, + .core_vendor_spec3 = 0x1B0, + .core_dll_config_2 = 0x1B4, + .core_ddr_config = 0x1B8, + .core_ddr_config_2 = 0x1BC, +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V1 3/3] mmc: host: Register changes for sdcc V5
From: Sayali Lokhande For SDCC version 5.0.0 and higher, new compatible string "qcom,sdhci-msm-v5" is added. Based on the msm variant, pick the relevant variant data and use it for register read/write to msm specific registers. Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 344 + 2 files changed, 222 insertions(+), 127 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb2bb59..408e6b2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -33,16 +33,11 @@ #define CORE_MCI_GENERICS 0x70 #define SWITCHABLE_SIGNALING_VOLTAGE BIT(29) -#define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +58,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +102,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -380,10 +368,14 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) u32 wait_cnt = 50; u8 ck_out_en; struct mmc_host *mmc = host->mmc; + 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; /* Poll for CK_OUT_EN bit. max. poll time = 50us */ - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); while (ck_out_en != poll) { if (--wait_cnt == 0) { @@ -393,8 +385,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) } udelay(1); - ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & - CORE_CK_OUT_EN); + ck_out_en = !!(readl_relaxed(host->ioaddr + + msm_offset->core_dll_config) & CORE_CK_OUT_EN); } return 0; @@ -410,16 +402,20 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) unsigned long flags; u32 config; struct mmc
Re: [PATCH RFC 2/4] mmc: sdhci-msm: Add and use voltage regulator related APIs
On 5/2/2018 2:19 PM, Ulf Hansson wrote: On 1 May 2018 at 12:39, Vijay Viswanath <vvisw...@codeaurora.org> wrote: From: Asutosh Das <asuto...@codeaurora.org> Some platforms require that the voltage switching happen only after the register write occurs and controller is ready for the switch. When the controller is ready, it will inform through power irq. Add voltage regulator APIs and use them during power irq to switch voltage instead of relying on core layer voltage switching. This is way to simplified. 529 lines of new code deserves some more explanations. Change-Id: Iaa98686e71a5bfe0092c68e9ffa563b060c5ac60 Remove this. Signed-off-by: Asutosh Das <asuto...@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org> Signed-off-by: Subhash Jadavani <subha...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- .../devicetree/bindings/mmc/sdhci-msm.txt | 27 +- Split DT changes and add DT maintainers. Will do drivers/mmc/host/sdhci-msm.c | 537 +++-- 2 files changed, 529 insertions(+), 35 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index c2b7b2b..c454046 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -23,6 +23,22 @@ Required properties: "xo"- TCXO clock (optional) "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +- -supply: phandle to the regulator device tree node if voltage + regulators needs to be handled from within sdhci-msm layer. + Supported "supply-name" are "vdd" and "vdd-io". + +Optional Properties: + - qcom,-always-on - specifies whether supply should be kept + "on" always. + - qcom,-lpm_sup - specifies whether supply can be kept in low + power mode (lpm). + - qcom,-voltage_level - specifies voltage levels for supply. + Should be specified in pairs (min, max), units uV. + - qcom,-current_level - specifies load levels for supply in lpm + or high power mode (hpm). Should be specified in + pairs (lpm, hpm), units uA. + + This looks really weird. What's so special here that requires you to have your own specific regulator bindings? Example: @@ -33,8 +49,15 @@ Example: bus-width = <8>; non-removable; - vmmc-supply = <_l20>; - vqmmc-supply = <_s3>; + vdd-supply = <_l20>; + qcom,vdd-voltage-level = <295 295>; + qcom,vdd-current-level = <9000 80>; + + vdd-io-supply = <_s3>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <180 295>; + qcom,vdd-io-current-level = <6 22000>; pinctrl-names = "default"; pinctrl-0 = <_clk _cmd _data>; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index d4d432b..0e0f12d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -213,6 +213,33 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_present = { .core_ddr_config_2 = 0x1BC, }; +/* This structure keeps information per regulator */ +struct sdhci_msm_reg_data { + /* voltage regulator handle */ + struct regulator *reg; + /* regulator name */ + const char *name; + /* voltage level to be set */ + u32 low_vol_level; + u32 high_vol_level; + /* Load values for low power and high power mode */ + u32 lpm_uA; + u32 hpm_uA; + /* is this regulator enabled? */ + bool is_enabled; + /* is this regulator needs to be always on? */ + bool is_always_on; + /* is low power mode setting required for this regulator? */ + bool lpm_sup; + bool set_voltage_sup; +}; + +struct sdhci_msm_pltfm_data { + /* Change-Id: Ide3a658ad51a3c3d4a05c47c0e8f013f647c9516 */ + struct sdhci_msm_reg_data *vdd_data; + struct sdhci_msm_reg_data *vdd_io_data; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -234,6 +261,8 @@ struct sdhci_msm_host { u32 caps_0; bool mci_removed; const struct sdhci_msm_offset *offset; + bool pltfm_init_done; + struct sdhci_msm_pltfm_data pdata; }; /* @@ -298,6 +327,336 @@ void sdhci_msm_vendor_writel_relaxed(u32 val, struct sdhci_host *host, writel_relaxed(val, b
Re: [PATCH RFC 2/4] mmc: sdhci-msm: Add and use voltage regulator related APIs
On 5/2/2018 2:19 PM, Ulf Hansson wrote: On 1 May 2018 at 12:39, Vijay Viswanath wrote: From: Asutosh Das Some platforms require that the voltage switching happen only after the register write occurs and controller is ready for the switch. When the controller is ready, it will inform through power irq. Add voltage regulator APIs and use them during power irq to switch voltage instead of relying on core layer voltage switching. This is way to simplified. 529 lines of new code deserves some more explanations. Change-Id: Iaa98686e71a5bfe0092c68e9ffa563b060c5ac60 Remove this. Signed-off-by: Asutosh Das Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Vijay Viswanath --- .../devicetree/bindings/mmc/sdhci-msm.txt | 27 +- Split DT changes and add DT maintainers. Will do drivers/mmc/host/sdhci-msm.c | 537 +++-- 2 files changed, 529 insertions(+), 35 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index c2b7b2b..c454046 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -23,6 +23,22 @@ Required properties: "xo"- TCXO clock (optional) "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +- -supply: phandle to the regulator device tree node if voltage + regulators needs to be handled from within sdhci-msm layer. + Supported "supply-name" are "vdd" and "vdd-io". + +Optional Properties: + - qcom,-always-on - specifies whether supply should be kept + "on" always. + - qcom,-lpm_sup - specifies whether supply can be kept in low + power mode (lpm). + - qcom,-voltage_level - specifies voltage levels for supply. + Should be specified in pairs (min, max), units uV. + - qcom,-current_level - specifies load levels for supply in lpm + or high power mode (hpm). Should be specified in + pairs (lpm, hpm), units uA. + + This looks really weird. What's so special here that requires you to have your own specific regulator bindings? Example: @@ -33,8 +49,15 @@ Example: bus-width = <8>; non-removable; - vmmc-supply = <_l20>; - vqmmc-supply = <_s3>; + vdd-supply = <_l20>; + qcom,vdd-voltage-level = <295 295>; + qcom,vdd-current-level = <9000 80>; + + vdd-io-supply = <_s3>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <180 295>; + qcom,vdd-io-current-level = <6 22000>; pinctrl-names = "default"; pinctrl-0 = <_clk _cmd _data>; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index d4d432b..0e0f12d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -213,6 +213,33 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_present = { .core_ddr_config_2 = 0x1BC, }; +/* This structure keeps information per regulator */ +struct sdhci_msm_reg_data { + /* voltage regulator handle */ + struct regulator *reg; + /* regulator name */ + const char *name; + /* voltage level to be set */ + u32 low_vol_level; + u32 high_vol_level; + /* Load values for low power and high power mode */ + u32 lpm_uA; + u32 hpm_uA; + /* is this regulator enabled? */ + bool is_enabled; + /* is this regulator needs to be always on? */ + bool is_always_on; + /* is low power mode setting required for this regulator? */ + bool lpm_sup; + bool set_voltage_sup; +}; + +struct sdhci_msm_pltfm_data { + /* Change-Id: Ide3a658ad51a3c3d4a05c47c0e8f013f647c9516 */ + struct sdhci_msm_reg_data *vdd_data; + struct sdhci_msm_reg_data *vdd_io_data; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -234,6 +261,8 @@ struct sdhci_msm_host { u32 caps_0; bool mci_removed; const struct sdhci_msm_offset *offset; + bool pltfm_init_done; + struct sdhci_msm_pltfm_data pdata; }; /* @@ -298,6 +327,336 @@ void sdhci_msm_vendor_writel_relaxed(u32 val, struct sdhci_host *host, writel_relaxed(val, base_addr + offset); } +enum vdd_io_level { + /* set vdd_io_data->low_vol_level */ + VDD_IO_LOW, + /* set vdd_io_data->high_vol_level */ + VDD_IO_HIGH, + /* +
Re: [PATCH RFC 1/4] mmc: host: Register changes for sdcc V5
On 5/2/2018 1:58 PM, Ulf Hansson wrote: On 1 May 2018 at 12:39, Vijay Viswanath <vvisw...@codeaurora.org> wrote: From: Sayali Lokhande <saya...@codeaurora.org> For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. This change is to support MCI register removal for msmfalcon. New compatible string "qcom,sdhci-msm-v5" is added for msmfalcon to support this change. To simplify review, I would recommend to split this up in a few more pieces, a few re-factoring while the final change adds the qcom,sdhci-msm-v5 support. Will do Change-Id: I0febfd9bb436a8eff20c20107dd4180c9781 Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- Please move DT changes into separate patches and make sure to sent it to DT maintainers as well. drivers/mmc/host/sdhci-msm.c | 485 +++-- 2 files changed, 365 insertions(+), 125 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..d4d432b 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c [...] +struct sdhci_msm_offset { I think a better idea is to create a struct sdhci_msm_variant and make it contain all the variant specific data. So, not only the offsets, but other variant data as well. More comments below. + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +struct sdhci_msm_offset sdhci_msm_offset_mci_removed = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +struct sdhci_msm_offset sdhci_msm_offset_mci_present = { + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0CC, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xDC, + .core_pwrctl_mask = 0xE0, + .core_pwrctl_clear = 0xE4, + .core_pwrctl_ctl = 0xE8, + .core_sdcc_debug_reg = 0x124, +
Re: [PATCH RFC 1/4] mmc: host: Register changes for sdcc V5
On 5/2/2018 1:58 PM, Ulf Hansson wrote: On 1 May 2018 at 12:39, Vijay Viswanath wrote: From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. This change is to support MCI register removal for msmfalcon. New compatible string "qcom,sdhci-msm-v5" is added for msmfalcon to support this change. To simplify review, I would recommend to split this up in a few more pieces, a few re-factoring while the final change adds the qcom,sdhci-msm-v5 support. Will do Change-Id: I0febfd9bb436a8eff20c20107dd4180c9781 Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- Please move DT changes into separate patches and make sure to sent it to DT maintainers as well. drivers/mmc/host/sdhci-msm.c | 485 +++-- 2 files changed, 365 insertions(+), 125 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..d4d432b 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c [...] +struct sdhci_msm_offset { I think a better idea is to create a struct sdhci_msm_variant and make it contain all the variant specific data. So, not only the offsets, but other variant data as well. More comments below. + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +struct sdhci_msm_offset sdhci_msm_offset_mci_removed = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x24c, + .core_sdcc_debug_reg = 0x358, + .core_dll_config = 0x200, + .core_dll_status = 0x208, + .core_vendor_spec = 0x20c, + .core_vendor_spec_adma_err_addr0 = 0x214, + .core_vendor_spec_adma_err_addr1 = 0x218, + .core_vendor_spec_func2 = 0x210, + .core_vendor_spec_capabilities0 = 0x21c, + .core_ddr_200_cfg = 0x224, + .core_vendor_spec3 = 0x250, + .core_dll_config_2 = 0x254, + .core_ddr_config = 0x258, + .core_ddr_config_2 = 0x25c, +}; + +struct sdhci_msm_offset sdhci_msm_offset_mci_present = { + .core_mci_data_cnt = 0x30, + .core_mci_status = 0x34, + .core_mci_fifo_cnt = 0x44, + .core_mci_version = 0x050, + .core_generics = 0x70, + .core_testbus_config = 0x0CC, + .core_testbus_sel2_bit = 4, + .core_testbus_ena = (1 << 3), + .core_testbus_sel2 = (1 << 4), + .core_pwrctl_status = 0xDC, + .core_pwrctl_mask = 0xE0, + .core_pwrctl_clear = 0xE4, + .core_pwrctl_ctl = 0xE8, + .core_sdcc_debug_reg = 0x124, + .core_dll_config = 0x100, + .core_dll_status = 0x108, + .core_vendor_spec = 0x10C, + .core_vendor_spe
[PATCH RFC 2/4] mmc: sdhci-msm: Add and use voltage regulator related APIs
From: Asutosh Das <asuto...@codeaurora.org> Some platforms require that the voltage switching happen only after the register write occurs and controller is ready for the switch. When the controller is ready, it will inform through power irq. Add voltage regulator APIs and use them during power irq to switch voltage instead of relying on core layer voltage switching. Change-Id: Iaa98686e71a5bfe0092c68e9ffa563b060c5ac60 Signed-off-by: Asutosh Das <asuto...@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org> Signed-off-by: Subhash Jadavani <subha...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- .../devicetree/bindings/mmc/sdhci-msm.txt | 27 +- drivers/mmc/host/sdhci-msm.c | 537 +++-- 2 files changed, 529 insertions(+), 35 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index c2b7b2b..c454046 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -23,6 +23,22 @@ Required properties: "xo"- TCXO clock (optional) "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +- -supply: phandle to the regulator device tree node if voltage + regulators needs to be handled from within sdhci-msm layer. + Supported "supply-name" are "vdd" and "vdd-io". + +Optional Properties: + - qcom,-always-on - specifies whether supply should be kept + "on" always. + - qcom,-lpm_sup - specifies whether supply can be kept in low + power mode (lpm). + - qcom,-voltage_level - specifies voltage levels for supply. + Should be specified in pairs (min, max), units uV. + - qcom,-current_level - specifies load levels for supply in lpm + or high power mode (hpm). Should be specified in + pairs (lpm, hpm), units uA. + + Example: @@ -33,8 +49,15 @@ Example: bus-width = <8>; non-removable; - vmmc-supply = <_l20>; - vqmmc-supply = <_s3>; + vdd-supply = <_l20>; + qcom,vdd-voltage-level = <295 295>; + qcom,vdd-current-level = <9000 80>; + + vdd-io-supply = <_s3>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <180 295>; + qcom,vdd-io-current-level = <6 22000>; pinctrl-names = "default"; pinctrl-0 = <_clk _cmd _data>; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index d4d432b..0e0f12d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -213,6 +213,33 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_present = { .core_ddr_config_2 = 0x1BC, }; +/* This structure keeps information per regulator */ +struct sdhci_msm_reg_data { + /* voltage regulator handle */ + struct regulator *reg; + /* regulator name */ + const char *name; + /* voltage level to be set */ + u32 low_vol_level; + u32 high_vol_level; + /* Load values for low power and high power mode */ + u32 lpm_uA; + u32 hpm_uA; + /* is this regulator enabled? */ + bool is_enabled; + /* is this regulator needs to be always on? */ + bool is_always_on; + /* is low power mode setting required for this regulator? */ + bool lpm_sup; + bool set_voltage_sup; +}; + +struct sdhci_msm_pltfm_data { + /* Change-Id: Ide3a658ad51a3c3d4a05c47c0e8f013f647c9516 */ + struct sdhci_msm_reg_data *vdd_data; + struct sdhci_msm_reg_data *vdd_io_data; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -234,6 +261,8 @@ struct sdhci_msm_host { u32 caps_0; bool mci_removed; const struct sdhci_msm_offset *offset; + bool pltfm_init_done; + struct sdhci_msm_pltfm_data pdata; }; /* @@ -298,6 +327,336 @@ void sdhci_msm_vendor_writel_relaxed(u32 val, struct sdhci_host *host, writel_relaxed(val, base_addr + offset); } +enum vdd_io_level { + /* set vdd_io_data->low_vol_level */ + VDD_IO_LOW, + /* set vdd_io_data->high_vol_level */ + VDD_IO_HIGH, + /* +* set whatever there in voltage_level (third argument) of +* sdhci_msm_set_vdd_io_vol() function. +*/ + VDD_IO_SET_LEVEL, +}; + +#define MAX_PROP_SIZE 32 +static int sdhci_msm_dt_parse_vreg_info(struct device *
[PATCH RFC 4/4] host: sdhci-msm: implement get_current_limit() host op
From: Sahitya Tummala <stumm...@codeaurora.org> This is needed to get the current capabilities of vdd regulator that is not managed by SDHCI driver. Change-Id: I927c14b9890f1d672fe8a3e89d0b334f43463b36 Signed-off-by: Sahitya Tummala <stumm...@codeaurora.org> Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 13 + 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 0e0f12d..083b4a5 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2079,6 +2079,18 @@ static void sdhci_msm_set_default_hw_caps(struct device *dev, {}, }; +static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct sdhci_msm_reg_data *vdd_data = msm_host->pdata.vdd_data; + u32 max_curr = 0; + + if (vdd_data) + max_curr = vdd_data->hpm_uA; + return max_curr; +} + MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); static const struct sdhci_ops sdhci_msm_ops = { @@ -2090,6 +2102,7 @@ static void sdhci_msm_set_default_hw_caps(struct device *dev, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, .write_w = sdhci_msm_writew, .write_b = sdhci_msm_writeb, + .get_current_limit = sdhci_msm_get_current_limit, }; static const struct sdhci_pltfm_data sdhci_msm_pdata = { -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 3/4] host: sdhci: fix current caps when there is no host->vmmc
From: Sahitya Tummala <stumm...@codeaurora.org> When the regulators are not managed by SDHCI host driver (i.e., when host->vmmc and host->vmmcq are absent), get the regulator current capabilities through a new host op get_current_limit(). Signed-off-by: Sahitya Tummala <stumm...@codeaurora.org> Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> [vvisw...@codeaurora.org: fixed trivial merge conflicts] Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> Change-Id: I3370a2411beec1f03cc5f102bf95cd816c60351e --- drivers/mmc/host/sdhci.c | 11 --- drivers/mmc/host/sdhci.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0d5fcca..edc2ccd 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3570,10 +3570,15 @@ int sdhci_setup_host(struct sdhci_host *host) * value. */ max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); - if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) { - int curr = regulator_get_current_limit(mmc->supply.vmmc); - if (curr > 0) { + if (!max_current_caps) { + u32 curr = 0; + + if (!IS_ERR(mmc->supply.vmmc)) + curr = regulator_get_current_limit(mmc->supply.vmmc); + else if (host->ops->get_current_limit) + curr = host->ops->get_current_limit(host); + if (curr > 0) { /* convert to SDHCI_MAX_CURRENT format */ curr = curr/1000; /* convert to mA */ curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 54bc444..a01af78 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -584,6 +584,7 @@ struct sdhci_ops { void(*adma_workaround)(struct sdhci_host *host, u32 intmask); void(*card_event)(struct sdhci_host *host); void(*voltage_switch)(struct sdhci_host *host); + unsigned int(*get_current_limit)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 3/4] host: sdhci: fix current caps when there is no host->vmmc
From: Sahitya Tummala When the regulators are not managed by SDHCI host driver (i.e., when host->vmmc and host->vmmcq are absent), get the regulator current capabilities through a new host op get_current_limit(). Signed-off-by: Sahitya Tummala Signed-off-by: Sayali Lokhande [vvisw...@codeaurora.org: fixed trivial merge conflicts] Signed-off-by: Vijay Viswanath Change-Id: I3370a2411beec1f03cc5f102bf95cd816c60351e --- drivers/mmc/host/sdhci.c | 11 --- drivers/mmc/host/sdhci.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0d5fcca..edc2ccd 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3570,10 +3570,15 @@ int sdhci_setup_host(struct sdhci_host *host) * value. */ max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); - if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) { - int curr = regulator_get_current_limit(mmc->supply.vmmc); - if (curr > 0) { + if (!max_current_caps) { + u32 curr = 0; + + if (!IS_ERR(mmc->supply.vmmc)) + curr = regulator_get_current_limit(mmc->supply.vmmc); + else if (host->ops->get_current_limit) + curr = host->ops->get_current_limit(host); + if (curr > 0) { /* convert to SDHCI_MAX_CURRENT format */ curr = curr/1000; /* convert to mA */ curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 54bc444..a01af78 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -584,6 +584,7 @@ struct sdhci_ops { void(*adma_workaround)(struct sdhci_host *host, u32 intmask); void(*card_event)(struct sdhci_host *host); void(*voltage_switch)(struct sdhci_host *host); + unsigned int(*get_current_limit)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 4/4] host: sdhci-msm: implement get_current_limit() host op
From: Sahitya Tummala This is needed to get the current capabilities of vdd regulator that is not managed by SDHCI driver. Change-Id: I927c14b9890f1d672fe8a3e89d0b334f43463b36 Signed-off-by: Sahitya Tummala Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 13 + 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 0e0f12d..083b4a5 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2079,6 +2079,18 @@ static void sdhci_msm_set_default_hw_caps(struct device *dev, {}, }; +static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct sdhci_msm_reg_data *vdd_data = msm_host->pdata.vdd_data; + u32 max_curr = 0; + + if (vdd_data) + max_curr = vdd_data->hpm_uA; + return max_curr; +} + MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); static const struct sdhci_ops sdhci_msm_ops = { @@ -2090,6 +2102,7 @@ static void sdhci_msm_set_default_hw_caps(struct device *dev, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, .write_w = sdhci_msm_writew, .write_b = sdhci_msm_writeb, + .get_current_limit = sdhci_msm_get_current_limit, }; static const struct sdhci_pltfm_data sdhci_msm_pdata = { -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 2/4] mmc: sdhci-msm: Add and use voltage regulator related APIs
From: Asutosh Das Some platforms require that the voltage switching happen only after the register write occurs and controller is ready for the switch. When the controller is ready, it will inform through power irq. Add voltage regulator APIs and use them during power irq to switch voltage instead of relying on core layer voltage switching. Change-Id: Iaa98686e71a5bfe0092c68e9ffa563b060c5ac60 Signed-off-by: Asutosh Das Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Vijay Viswanath --- .../devicetree/bindings/mmc/sdhci-msm.txt | 27 +- drivers/mmc/host/sdhci-msm.c | 537 +++-- 2 files changed, 529 insertions(+), 35 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index c2b7b2b..c454046 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -23,6 +23,22 @@ Required properties: "xo"- TCXO clock (optional) "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +- -supply: phandle to the regulator device tree node if voltage + regulators needs to be handled from within sdhci-msm layer. + Supported "supply-name" are "vdd" and "vdd-io". + +Optional Properties: + - qcom,-always-on - specifies whether supply should be kept + "on" always. + - qcom,-lpm_sup - specifies whether supply can be kept in low + power mode (lpm). + - qcom,-voltage_level - specifies voltage levels for supply. + Should be specified in pairs (min, max), units uV. + - qcom,-current_level - specifies load levels for supply in lpm + or high power mode (hpm). Should be specified in + pairs (lpm, hpm), units uA. + + Example: @@ -33,8 +49,15 @@ Example: bus-width = <8>; non-removable; - vmmc-supply = <_l20>; - vqmmc-supply = <_s3>; + vdd-supply = <_l20>; + qcom,vdd-voltage-level = <295 295>; + qcom,vdd-current-level = <9000 80>; + + vdd-io-supply = <_s3>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <180 295>; + qcom,vdd-io-current-level = <6 22000>; pinctrl-names = "default"; pinctrl-0 = <_clk _cmd _data>; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index d4d432b..0e0f12d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -213,6 +213,33 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_present = { .core_ddr_config_2 = 0x1BC, }; +/* This structure keeps information per regulator */ +struct sdhci_msm_reg_data { + /* voltage regulator handle */ + struct regulator *reg; + /* regulator name */ + const char *name; + /* voltage level to be set */ + u32 low_vol_level; + u32 high_vol_level; + /* Load values for low power and high power mode */ + u32 lpm_uA; + u32 hpm_uA; + /* is this regulator enabled? */ + bool is_enabled; + /* is this regulator needs to be always on? */ + bool is_always_on; + /* is low power mode setting required for this regulator? */ + bool lpm_sup; + bool set_voltage_sup; +}; + +struct sdhci_msm_pltfm_data { + /* Change-Id: Ide3a658ad51a3c3d4a05c47c0e8f013f647c9516 */ + struct sdhci_msm_reg_data *vdd_data; + struct sdhci_msm_reg_data *vdd_io_data; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -234,6 +261,8 @@ struct sdhci_msm_host { u32 caps_0; bool mci_removed; const struct sdhci_msm_offset *offset; + bool pltfm_init_done; + struct sdhci_msm_pltfm_data pdata; }; /* @@ -298,6 +327,336 @@ void sdhci_msm_vendor_writel_relaxed(u32 val, struct sdhci_host *host, writel_relaxed(val, base_addr + offset); } +enum vdd_io_level { + /* set vdd_io_data->low_vol_level */ + VDD_IO_LOW, + /* set vdd_io_data->high_vol_level */ + VDD_IO_HIGH, + /* +* set whatever there in voltage_level (third argument) of +* sdhci_msm_set_vdd_io_vol() function. +*/ + VDD_IO_SET_LEVEL, +}; + +#define MAX_PROP_SIZE 32 +static int sdhci_msm_dt_parse_vreg_info(struct device *dev, + struct sdhci_msm_reg_data **vreg_data, const char *vreg_name) +{ + int len, ret = 0; + const __be32 *prop; + c
[PATCH RFC 1/4] mmc: host: Register changes for sdcc V5
From: Sayali Lokhande <saya...@codeaurora.org> For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. This change is to support MCI register removal for msmfalcon. New compatible string "qcom,sdhci-msm-v5" is added for msmfalcon to support this change. Change-Id: I0febfd9bb436a8eff20c20107dd4180c9781 Signed-off-by: Sayali Lokhande <saya...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 485 +++-- 2 files changed, 365 insertions(+), 125 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..d4d432b 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -39,10 +39,6 @@ #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +59,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +103,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -137,6 +126,93 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +struct sdhci_msm_offset sdhci_msm_offset_mci_removed = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .co
[PATCH RFC 1/4] mmc: host: Register changes for sdcc V5
From: Sayali Lokhande For SDCC version 5.0.0, MCI registers are removed from SDCC interface and some registers are moved to HC. This change is to support MCI register removal for msmfalcon. New compatible string "qcom,sdhci-msm-v5" is added for msmfalcon to support this change. Change-Id: I0febfd9bb436a8eff20c20107dd4180c9781 Signed-off-by: Sayali Lokhande Signed-off-by: Vijay Viswanath --- .../devicetree/bindings/mmc/sdhci-msm.txt | 5 +- drivers/mmc/host/sdhci-msm.c | 485 +++-- 2 files changed, 365 insertions(+), 125 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index bfdcdc4..c2b7b2b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties in mmc.txt and the properties used by the sdhci-msm driver. Required properties: -- compatible: Should contain "qcom,sdhci-msm-v4". +- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5". +For SDCC version 5.0.0, MCI registers are removed from SDCC +interface and some registers are moved to HC. New compatible +string is added to support this change - "qcom,sdhci-msm-v5". - reg: Base address and length of the register in the following order: - Host controller register map (required) - SD Core register map (required) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index bb11916..d4d432b 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -39,10 +39,6 @@ #define CORE_SW_RSTBIT(7) #define FF_CLK_SW_RST_DIS BIT(13) -#define CORE_PWRCTL_STATUS 0xdc -#define CORE_PWRCTL_MASK 0xe0 -#define CORE_PWRCTL_CLEAR 0xe4 -#define CORE_PWRCTL_CTL0xe8 #define CORE_PWRCTL_BUS_OFFBIT(0) #define CORE_PWRCTL_BUS_ON BIT(1) #define CORE_PWRCTL_IO_LOW BIT(2) @@ -63,17 +59,13 @@ #define CORE_CDR_EXT_ENBIT(19) #define CORE_DLL_PDN BIT(29) #define CORE_DLL_RST BIT(30) -#define CORE_DLL_CONFIG0x100 #define CORE_CMD_DAT_TRACK_SEL BIT(0) -#define CORE_DLL_STATUS0x108 -#define CORE_DLL_CONFIG_2 0x1b4 #define CORE_DDR_CAL_ENBIT(0) #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC 0x10c -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -111,17 +103,14 @@ #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) #define CORE_CDC_SWITCH_RC_EN BIT(1) -#define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SELBIT(0) #define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) -#define CORE_VENDOR_SPEC3 0x1b0 + #define CORE_PWRSAVE_DLL BIT(3) -#define CORE_DDR_CONFIG0x1b8 #define DDR_CONFIG_POR_VAL 0x80040853 -#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c #define INVALID_TUNING_PHASE -1 #define SDHCI_MSM_MIN_CLOCK40 @@ -137,6 +126,93 @@ /* Timeout value to avoid infinite waiting for pwr_irq */ #define MSM_PWR_IRQ_TIMEOUT_MS 5000 +struct sdhci_msm_offset { + u32 core_mci_data_cnt; + u32 core_mci_status; + u32 core_mci_fifo_cnt; + u32 core_mci_version; + u32 core_generics; + u32 core_testbus_config; + u32 core_testbus_sel2_bit; + u32 core_testbus_ena; + u32 core_testbus_sel2; + u32 core_pwrctl_status; + u32 core_pwrctl_mask; + u32 core_pwrctl_clear; + u32 core_pwrctl_ctl; + u32 core_sdcc_debug_reg; + u32 core_dll_config; + u32 core_dll_status; + u32 core_vendor_spec; + u32 core_vendor_spec_adma_err_addr0; + u32 core_vendor_spec_adma_err_addr1; + u32 core_vendor_spec_func2; + u32 core_vendor_spec_capabilities0; + u32 core_ddr_200_cfg; + u32 core_vendor_spec3; + u32 core_dll_config_2; + u32 core_ddr_config; + u32 core_ddr_config_2; +}; + +struct sdhci_msm_offset sdhci_msm_offset_mci_removed = { + .core_mci_data_cnt = 0x35c, + .core_mci_status = 0x324, + .core_mci_fifo_cnt = 0x308, + .core_mci_version = 0x318, + .core_generics = 0x320, + .core_testbus_config = 0x32c, + .core_testbus_sel2_bit = 3, + .core_testbus_ena = (1 << 31), + .core_testbus_sel2 = (1 << 3), + .core_pwrctl_status = 0x240, + .core_pwrctl_mask = 0x244, + .core_pwrctl_clear = 0x248, + .core_pwrctl_ctl = 0x2
[PATCH RFC 0/4] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Also power irq is a signal from controller to SW that it is ready for voltage switch. So added support to register voltage regulators in the msm driver and use them. With this core layer will not have to take care of voltage regulators. Chips which are currently using core layer regulator APIs can continue to do so, while newer chips can utilize power irq for voltage switch. Depends on patch series: [PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm https://lkml.org/lkml/2018/4/20/370 Asutosh Das (1): mmc: sdhci-msm: Add and use voltage regulator related APIs Sahitya Tummala (2): host: sdhci: fix current caps when there is no host->vmmc host: sdhci-msm: implement get_current_limit() host op Sayali Lokhande (1): mmc: host: Register changes for sdcc V5 .../devicetree/bindings/mmc/sdhci-msm.txt | 32 +- drivers/mmc/host/sdhci-msm.c | 1027 +--- drivers/mmc/host/sdhci.c | 11 +- drivers/mmc/host/sdhci.h |1 + 4 files changed, 912 insertions(+), 159 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH RFC 0/4] Changes for SDCC5 version
With SDCC5, the MCI register space got removed and the offset/order of several registers have changed. Based on SDCC version used and the register, we need to pick the base address and offset. Also power irq is a signal from controller to SW that it is ready for voltage switch. So added support to register voltage regulators in the msm driver and use them. With this core layer will not have to take care of voltage regulators. Chips which are currently using core layer regulator APIs can continue to do so, while newer chips can utilize power irq for voltage switch. Depends on patch series: [PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm https://lkml.org/lkml/2018/4/20/370 Asutosh Das (1): mmc: sdhci-msm: Add and use voltage regulator related APIs Sahitya Tummala (2): host: sdhci: fix current caps when there is no host->vmmc host: sdhci-msm: implement get_current_limit() host op Sayali Lokhande (1): mmc: host: Register changes for sdcc V5 .../devicetree/bindings/mmc/sdhci-msm.txt | 32 +- drivers/mmc/host/sdhci-msm.c | 1027 +--- drivers/mmc/host/sdhci.c | 11 +- drivers/mmc/host/sdhci.h |1 + 4 files changed, 912 insertions(+), 159 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V5 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages
During probe check whether the vdd-io regulator of sdhc platform device can support 1.8V and 3V and store this information as a capability of platform device. Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> Reviewed-by: Douglas Anderson <diand...@chromium.org> --- drivers/mmc/host/sdhci-msm.c | 29 - 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c283291..edd30a2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -81,6 +82,9 @@ #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_3_0V_SUPPORT (1 << 25) +#define CORE_1_8V_SUPPORT (1 << 26) + #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) #define CORE_HW_AUTOCAL_ENABIT(17) @@ -148,6 +152,7 @@ struct sdhci_msm_host { u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; + u32 caps_0; }; static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, @@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 irq_status, irq_ack = 0; int retry = 10; - int pwr_state = 0, io_level = 0; + u32 pwr_state = 0, io_level = 0; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); @@ -1313,6 +1318,27 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_msm_check_power_status(host, req_type); } +static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) +{ + struct mmc_host *mmc = msm_host->mmc; + struct regulator *supply = mmc->supply.vqmmc; + u32 caps = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { + if (regulator_is_supported_voltage(supply, 170, 195)) + caps |= CORE_1_8V_SUPPORT; + if (regulator_is_supported_voltage(supply, 270, 360)) + caps |= CORE_3_0V_SUPPORT; + + if (!caps) + pr_warn("%s: 1.8/3V not supported for vqmmc\n", + mmc_hostname(mmc)); + } + + msm_host->caps_0 |= caps; + pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -1530,6 +1556,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; + sdhci_msm_set_regulator_caps(msm_host); pm_runtime_mark_last_busy(>dev); pm_runtime_put_autosuspend(>dev); -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V5 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages
During probe check whether the vdd-io regulator of sdhc platform device can support 1.8V and 3V and store this information as a capability of platform device. Signed-off-by: Vijay Viswanath Reviewed-by: Douglas Anderson --- drivers/mmc/host/sdhci-msm.c | 29 - 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c283291..edd30a2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -81,6 +82,9 @@ #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_3_0V_SUPPORT (1 << 25) +#define CORE_1_8V_SUPPORT (1 << 26) + #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) #define CORE_HW_AUTOCAL_ENABIT(17) @@ -148,6 +152,7 @@ struct sdhci_msm_host { u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; + u32 caps_0; }; static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, @@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 irq_status, irq_ack = 0; int retry = 10; - int pwr_state = 0, io_level = 0; + u32 pwr_state = 0, io_level = 0; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); @@ -1313,6 +1318,27 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_msm_check_power_status(host, req_type); } +static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) +{ + struct mmc_host *mmc = msm_host->mmc; + struct regulator *supply = mmc->supply.vqmmc; + u32 caps = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { + if (regulator_is_supported_voltage(supply, 170, 195)) + caps |= CORE_1_8V_SUPPORT; + if (regulator_is_supported_voltage(supply, 270, 360)) + caps |= CORE_3_0V_SUPPORT; + + if (!caps) + pr_warn("%s: 1.8/3V not supported for vqmmc\n", + mmc_hostname(mmc)); + } + + msm_host->caps_0 |= caps; + pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -1530,6 +1556,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; + sdhci_msm_set_regulator_caps(msm_host); pm_runtime_mark_last_busy(>dev); pm_runtime_put_autosuspend(>dev); -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V5 2/2] mmc: sdhci-msm: support voltage pad switching
The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda <kko...@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> Reviewed-by: Douglas Anderson <diand...@chromium.org> --- drivers/mmc/host/sdhci-msm.c | 57 ++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index edd30a2..bb11916 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,38 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + u32 new_config; + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + new_config = config; + + if ((io_level & REQ_IO_HIGH) && + (msm_host->caps_0 & CORE_3_0V_SUPPORT)) + new_config &= ~CORE_IO_PAD_PWR_SWITCH; + else if ((io_level & REQ_IO_LOW) || + (msm_host->caps_0 & CORE_1_8V_SUPPORT)) + new_config |= CORE_IO_PAD_PWR_SWITCH; + + if (config ^ new_config) + writel_relaxed(new_config, + host->ioaddr + CORE_VENDOR_SPEC); + } + if (pwr_state) msm_host->curr_pwr_state = pwr_state; if (io_level) @@ -1322,7 +1357,8 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) { struct mmc_host *mmc = msm_host->mmc; struct regulator *supply = mmc->supply.vqmmc; - u32 caps = 0; + u32 caps = 0, config; + struct sdhci_host *host = mmc_priv(mmc); if (!IS_ERR(mmc->supply.vqmmc)) { if (regulator_is_supported_voltage(supply, 170, 195)) @@ -1335,6 +1371,23 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) mmc_hostname(mmc)); } + if (caps) { + /* +* Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH +* bit can be used as required later on. +*/ + u32 io_level = msm_host->curr_io_level; + + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + config |= CORE_IO_PAD_PWR_SWITCH_EN; + + if ((io_level & REQ_IO_HIGH) &&
[PATCH V5 2/2] mmc: sdhci-msm: support voltage pad switching
The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Vijay Viswanath Reviewed-by: Douglas Anderson --- drivers/mmc/host/sdhci-msm.c | 57 ++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index edd30a2..bb11916 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,38 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + u32 new_config; + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + new_config = config; + + if ((io_level & REQ_IO_HIGH) && + (msm_host->caps_0 & CORE_3_0V_SUPPORT)) + new_config &= ~CORE_IO_PAD_PWR_SWITCH; + else if ((io_level & REQ_IO_LOW) || + (msm_host->caps_0 & CORE_1_8V_SUPPORT)) + new_config |= CORE_IO_PAD_PWR_SWITCH; + + if (config ^ new_config) + writel_relaxed(new_config, + host->ioaddr + CORE_VENDOR_SPEC); + } + if (pwr_state) msm_host->curr_pwr_state = pwr_state; if (io_level) @@ -1322,7 +1357,8 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) { struct mmc_host *mmc = msm_host->mmc; struct regulator *supply = mmc->supply.vqmmc; - u32 caps = 0; + u32 caps = 0, config; + struct sdhci_host *host = mmc_priv(mmc); if (!IS_ERR(mmc->supply.vqmmc)) { if (regulator_is_supported_voltage(supply, 170, 195)) @@ -1335,6 +1371,23 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) mmc_hostname(mmc)); } + if (caps) { + /* +* Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH +* bit can be used as required later on. +*/ + u32 io_level = msm_host->curr_io_level; + + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + config |= CORE_IO_PAD_PWR_SWITCH_EN; + + if ((io_level & REQ_IO_HIGH) && (caps & CORE_3_0V_SUPPORT)) + config &= ~CORE_IO_PAD_PWR_SWITCH; + else if ((io_level & R
[PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm
>From the HPG: In some platform, SDCC controller can be connected to either an eMMC device or an SD card. The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. For SD usage the default value of this signal is ???0???, and SD driver changes it to ???1??? as a part of voltage switching sequence. For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to PADs before starting any activity on the eMMC BUS. To set this signal, write the following in the SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register: HC_IO_PAD_PWR_SWITCH: bit 16 HC_IO_PAD_PWR_SWITCH_EN: bit 15 Changes since v1: Modified comments on io_pad related changes. Split some read+modify+write commands to multiple lines Changes since v2: IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what voltage is supported by the regulators. Replaced regulator_list_voltage() API with regulator_is_supported_voltage(). Changes since v3: Removed unnecessary prints and extra lines. Changes since v4: Removed unnecessary mb() within sdhci_msm_handle_pwr_irq() since wakeup calls have implicit write barriers. Krishna Konda (1): mmc: sdhci-msm: support voltage pad switching Vijay Viswanath (1): mmc: sdhci-msm: Add support to store supported vdd-io voltages drivers/mmc/host/sdhci-msm.c | 99 +++- 1 file changed, 97 insertions(+), 2 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm
>From the HPG: In some platform, SDCC controller can be connected to either an eMMC device or an SD card. The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. For SD usage the default value of this signal is ???0???, and SD driver changes it to ???1??? as a part of voltage switching sequence. For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to PADs before starting any activity on the eMMC BUS. To set this signal, write the following in the SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register: HC_IO_PAD_PWR_SWITCH: bit 16 HC_IO_PAD_PWR_SWITCH_EN: bit 15 Changes since v1: Modified comments on io_pad related changes. Split some read+modify+write commands to multiple lines Changes since v2: IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what voltage is supported by the regulators. Replaced regulator_list_voltage() API with regulator_is_supported_voltage(). Changes since v3: Removed unnecessary prints and extra lines. Changes since v4: Removed unnecessary mb() within sdhci_msm_handle_pwr_irq() since wakeup calls have implicit write barriers. Krishna Konda (1): mmc: sdhci-msm: support voltage pad switching Vijay Viswanath (1): mmc: sdhci-msm: Add support to store supported vdd-io voltages drivers/mmc/host/sdhci-msm.c | 99 +++- 1 file changed, 97 insertions(+), 2 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching
On 4/13/2018 10:38 PM, Doug Anderson wrote: Hi, On Fri, Apr 6, 2018 at 2:48 AM, Vijay Viswanath <vvisw...@codeaurora.org> wrote: On 3/29/2018 4:23 AM, Doug Anderson wrote: Hi, On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath <vvisw...@codeaurora.org> wrote: From: Krishna Konda <kko...@codeaurora.org> The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda <kko...@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 64 ++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2fcd9010..bbf9626 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + /* Ensure order between core_mem and hc_mem */ + mb(); Like in v2, I don't understand why you need a mb() before the read from CORE_VENDOR_SPEC. No reads or writes to the core_mem will affect the value you're reading here, so you need no barrier. If you need a barrier before the _write_ to CORE_VENDOR_SPEC then add it below. Then in the case where the config doesn't change you have no barriers. + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ For the above comment, what about just: new_config = config if (msm_host->caps_0 == CORE_1_8V_SUPPORT) { new_config |= CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 == CORE_3_3V_SUPPORT) { new_config &= ~CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { if (io_level & REQ_IO_HIGH) new_config &= ~CORE_IO_PAD_PWR_SWITCH; else if (io_level & REQ_IO_LOW) new_config |= CORE_IO_PAD_PWR_SWITCH; } This looks a big mess of if/else. Does the above implementation have better performance compared to having two if/else with bit operations inside ? The latter looks much cleaner and faster. If regulator only supports 3V and we get a io_low from BUS_OFF ( REQ_IO_LOW should never come if we don't support 1.8V), it is ok to set io pad. Yeah, I think it's ugly no matter what. Personally I find the if/then/else easier to follow than the complicated conditions split across multiple lines. I seem to remember there was something that my version did differently than yours too (hence the "this might be more important if you get rid of the initial setting"
Re: [PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching
On 4/13/2018 10:38 PM, Doug Anderson wrote: Hi, On Fri, Apr 6, 2018 at 2:48 AM, Vijay Viswanath wrote: On 3/29/2018 4:23 AM, Doug Anderson wrote: Hi, On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath wrote: From: Krishna Konda The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 64 ++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2fcd9010..bbf9626 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + /* Ensure order between core_mem and hc_mem */ + mb(); Like in v2, I don't understand why you need a mb() before the read from CORE_VENDOR_SPEC. No reads or writes to the core_mem will affect the value you're reading here, so you need no barrier. If you need a barrier before the _write_ to CORE_VENDOR_SPEC then add it below. Then in the case where the config doesn't change you have no barriers. + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ For the above comment, what about just: new_config = config if (msm_host->caps_0 == CORE_1_8V_SUPPORT) { new_config |= CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 == CORE_3_3V_SUPPORT) { new_config &= ~CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { if (io_level & REQ_IO_HIGH) new_config &= ~CORE_IO_PAD_PWR_SWITCH; else if (io_level & REQ_IO_LOW) new_config |= CORE_IO_PAD_PWR_SWITCH; } This looks a big mess of if/else. Does the above implementation have better performance compared to having two if/else with bit operations inside ? The latter looks much cleaner and faster. If regulator only supports 3V and we get a io_low from BUS_OFF ( REQ_IO_LOW should never come if we don't support 1.8V), it is ok to set io pad. Yeah, I think it's ugly no matter what. Personally I find the if/then/else easier to follow than the complicated conditions split across multiple lines. I seem to remember there was something that my version did differently than yours too (hence the "this might be more important if you get rid of the initial setting"), let's see if I can figure it out again. Mine says: - if it has exactly 1.8 or 3.3 support: set that. - else if it supports both: set whatever is requested - else (it support neith
Re: [PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching
On 3/29/2018 4:23 AM, Doug Anderson wrote: Hi, On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath <vvisw...@codeaurora.org> wrote: From: Krishna Konda <kko...@codeaurora.org> The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda <kko...@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 64 ++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2fcd9010..bbf9626 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + /* Ensure order between core_mem and hc_mem */ + mb(); Like in v2, I don't understand why you need a mb() before the read from CORE_VENDOR_SPEC. No reads or writes to the core_mem will affect the value you're reading here, so you need no barrier. If you need a barrier before the _write_ to CORE_VENDOR_SPEC then add it below. Then in the case where the config doesn't change you have no barriers. + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ For the above comment, what about just: new_config = config if (msm_host->caps_0 == CORE_1_8V_SUPPORT) { new_config |= CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 == CORE_3_3V_SUPPORT) { new_config &= ~CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { if (io_level & REQ_IO_HIGH) new_config &= ~CORE_IO_PAD_PWR_SWITCH; else if (io_level & REQ_IO_LOW) new_config |= CORE_IO_PAD_PWR_SWITCH; } This looks a big mess of if/else. Does the above implementation have better performance compared to having two if/else with bit operations inside ? The latter looks much cleaner and faster. If regulator only supports 3V and we get a io_low from BUS_OFF ( REQ_IO_LOW should never come if we don't support 1.8V), it is ok to set io pad. if (config != new_config) { ... } AKA: first check if it only supports one voltage and pick that one. Else if it supports both you can use the request. This might be more important if you get rid of the initial setting in sdhci_msm_set_regulator_caps() as I'm suggesting. + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + + if (((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & +
Re: [PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching
On 3/29/2018 4:23 AM, Doug Anderson wrote: Hi, On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath wrote: From: Krishna Konda The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 64 ++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2fcd9010..bbf9626 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + /* Ensure order between core_mem and hc_mem */ + mb(); Like in v2, I don't understand why you need a mb() before the read from CORE_VENDOR_SPEC. No reads or writes to the core_mem will affect the value you're reading here, so you need no barrier. If you need a barrier before the _write_ to CORE_VENDOR_SPEC then add it below. Then in the case where the config doesn't change you have no barriers. + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ For the above comment, what about just: new_config = config if (msm_host->caps_0 == CORE_1_8V_SUPPORT) { new_config |= CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 == CORE_3_3V_SUPPORT) { new_config &= ~CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { if (io_level & REQ_IO_HIGH) new_config &= ~CORE_IO_PAD_PWR_SWITCH; else if (io_level & REQ_IO_LOW) new_config |= CORE_IO_PAD_PWR_SWITCH; } This looks a big mess of if/else. Does the above implementation have better performance compared to having two if/else with bit operations inside ? The latter looks much cleaner and faster. If regulator only supports 3V and we get a io_low from BUS_OFF ( REQ_IO_LOW should never come if we don't support 1.8V), it is ok to set io pad. if (config != new_config) { ... } AKA: first check if it only supports one voltage and pick that one. Else if it supports both you can use the request. This might be more important if you get rid of the initial setting in sdhci_msm_set_regulator_caps() as I'm suggesting. + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + + if (((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & + CORE_3_0V_SUPPORT)) && + (config & CORE_IO_PAD_PWR_SWITCH)) { + config &= ~CORE
Re: [PATCH V4 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages
On 3/29/2018 4:22 AM, Doug Anderson wrote: Hi, On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath <vvisw...@codeaurora.org> wrote: During probe check whether the vdd-io regulator of sdhc platform device can support 1.8V and 3V and store this information as a capability of platform device. Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 35 ++- 1 file changed, 34 insertions(+), 1 deletion(-) Since I commented on v2, please copy me for this series going forward. Thanks. Will do. Sorry I missed. diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c283291..2fcd9010 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -81,6 +82,9 @@ #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_3_0V_SUPPORT (1 << 25) +#define CORE_1_8V_SUPPORT (1 << 26) + #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) #define CORE_HW_AUTOCAL_ENABIT(17) @@ -148,6 +152,7 @@ struct sdhci_msm_host { u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; + u32 caps_0; }; static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, @@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 irq_status, irq_ack = 0; int retry = 10; - int pwr_state = 0, io_level = 0; + u32 pwr_state = 0, io_level = 0; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); @@ -1313,6 +1318,30 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_msm_check_power_status(host, req_type); } +static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) This function always returns 0. Make it void. +{ + struct mmc_host *mmc = msm_host->mmc; + struct regulator *supply = mmc->supply.vqmmc; + u32 caps = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { + if (regulator_is_supported_voltage(supply, 170, 195)) + caps |= CORE_1_8V_SUPPORT; + if (regulator_is_supported_voltage(supply, 270, 360)) + caps |= CORE_3_0V_SUPPORT; + + if (!caps) + pr_warn("%s: %s: 1.8/3V not supported for vqmmc\n", + mmc_hostname(mmc), __func__); Please remove __func__. You already have the unique thing to find the right driver (AKA mmc_hostname(mmc)) and the string itself should be enough from there. + } + + msm_host->caps_0 |= caps; + pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc), + __func__, caps); Same, no need for __func__. will remove all unnecessary __func__ references. + + return 0; +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -1530,6 +1559,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; + ret = sdhci_msm_set_regulator_caps(msm_host); + if (ret) + dev_err(>dev, "Failed to set regulator caps: %d\n", + ret); If you find some reason _not_ to make sdhci_msm_set_regulator_caps() return "void" as per above, you should actually do something about this error. You've used "dev_err" which makes me feel like you consider this a serious error. Presumably it should cause the probe to fail? > -Doug yeah, we don't need to print anything here as a warning is printed in sdhci_msm_set_regulator_caps() anyway.
Re: [PATCH V4 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages
On 3/29/2018 4:22 AM, Doug Anderson wrote: Hi, On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath wrote: During probe check whether the vdd-io regulator of sdhc platform device can support 1.8V and 3V and store this information as a capability of platform device. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 35 ++- 1 file changed, 34 insertions(+), 1 deletion(-) Since I commented on v2, please copy me for this series going forward. Thanks. Will do. Sorry I missed. diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c283291..2fcd9010 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -81,6 +82,9 @@ #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_3_0V_SUPPORT (1 << 25) +#define CORE_1_8V_SUPPORT (1 << 26) + #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) #define CORE_HW_AUTOCAL_ENABIT(17) @@ -148,6 +152,7 @@ struct sdhci_msm_host { u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; + u32 caps_0; }; static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, @@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 irq_status, irq_ack = 0; int retry = 10; - int pwr_state = 0, io_level = 0; + u32 pwr_state = 0, io_level = 0; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); @@ -1313,6 +1318,30 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_msm_check_power_status(host, req_type); } +static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) This function always returns 0. Make it void. +{ + struct mmc_host *mmc = msm_host->mmc; + struct regulator *supply = mmc->supply.vqmmc; + u32 caps = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { + if (regulator_is_supported_voltage(supply, 170, 195)) + caps |= CORE_1_8V_SUPPORT; + if (regulator_is_supported_voltage(supply, 270, 360)) + caps |= CORE_3_0V_SUPPORT; + + if (!caps) + pr_warn("%s: %s: 1.8/3V not supported for vqmmc\n", + mmc_hostname(mmc), __func__); Please remove __func__. You already have the unique thing to find the right driver (AKA mmc_hostname(mmc)) and the string itself should be enough from there. + } + + msm_host->caps_0 |= caps; + pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc), + __func__, caps); Same, no need for __func__. will remove all unnecessary __func__ references. + + return 0; +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -1530,6 +1559,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; + ret = sdhci_msm_set_regulator_caps(msm_host); + if (ret) + dev_err(>dev, "Failed to set regulator caps: %d\n", + ret); If you find some reason _not_ to make sdhci_msm_set_regulator_caps() return "void" as per above, you should actually do something about this error. You've used "dev_err" which makes me feel like you consider this a serious error. Presumably it should cause the probe to fail? > -Doug yeah, we don't need to print anything here as a warning is printed in sdhci_msm_set_regulator_caps() anyway.
[PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching
From: Krishna Konda <kko...@codeaurora.org> The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda <kko...@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 64 ++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2fcd9010..bbf9626 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + /* Ensure order between core_mem and hc_mem */ + mb(); + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + + if (((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & + CORE_3_0V_SUPPORT)) && + (config & CORE_IO_PAD_PWR_SWITCH)) { + config &= ~CORE_IO_PAD_PWR_SWITCH; + writel_relaxed(config, + host->ioaddr + CORE_VENDOR_SPEC); + /* IO PAD register is in different memory space */ + mb(); + } else if (((io_level & REQ_IO_LOW) || + (msm_host->caps_0 & CORE_1_8V_SUPPORT)) && + !(config & CORE_IO_PAD_PWR_SWITCH)) { + config |= CORE_IO_PAD_PWR_SWITCH; + writel_relaxed(config, + host->ioaddr + CORE_VENDOR_SPEC); + /* IO PAD bit is in different memory space */ + mb(); + } + } + if (pwr_state) msm_host->curr_pwr_state = pwr_state; if (io_level) @@ -1322,7 +1364,8 @@ static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) { struct mmc_host *mmc = msm_host->mmc; struct regulator *supply = mmc->supply.vqmmc; - u32 caps = 0; + u32 caps = 0, config; + struct sdhci_host *host = mmc_priv(mmc); if (!IS_ERR(mmc->supply.vqmmc)) { if (regulator_is_supported_voltage(supply, 170, 195)) @@ -1335,6 +1378,23 @@ static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) mmc_hostname(mmc)
[PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching
From: Krishna Konda The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 64 ++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2fcd9010..bbf9626 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,6 +1169,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + /* Ensure order between core_mem and hc_mem */ + mb(); + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + + if (((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & + CORE_3_0V_SUPPORT)) && + (config & CORE_IO_PAD_PWR_SWITCH)) { + config &= ~CORE_IO_PAD_PWR_SWITCH; + writel_relaxed(config, + host->ioaddr + CORE_VENDOR_SPEC); + /* IO PAD register is in different memory space */ + mb(); + } else if (((io_level & REQ_IO_LOW) || + (msm_host->caps_0 & CORE_1_8V_SUPPORT)) && + !(config & CORE_IO_PAD_PWR_SWITCH)) { + config |= CORE_IO_PAD_PWR_SWITCH; + writel_relaxed(config, + host->ioaddr + CORE_VENDOR_SPEC); + /* IO PAD bit is in different memory space */ + mb(); + } + } + if (pwr_state) msm_host->curr_pwr_state = pwr_state; if (io_level) @@ -1322,7 +1364,8 @@ static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) { struct mmc_host *mmc = msm_host->mmc; struct regulator *supply = mmc->supply.vqmmc; - u32 caps = 0; + u32 caps = 0, config; + struct sdhci_host *host = mmc_priv(mmc); if (!IS_ERR(mmc->supply.vqmmc)) { if (regulator_is_supported_voltage(supply, 170, 195)) @@ -1335,6 +1378,23 @@ static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) mmc_hostname(mmc), __func__); } + if (caps) { + /* +* Set the PAD_PWR_SWITCH_EN bit so that
[PATCH V4 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages
During probe check whether the vdd-io regulator of sdhc platform device can support 1.8V and 3V and store this information as a capability of platform device. Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 35 ++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c283291..2fcd9010 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -81,6 +82,9 @@ #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_3_0V_SUPPORT (1 << 25) +#define CORE_1_8V_SUPPORT (1 << 26) + #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) #define CORE_HW_AUTOCAL_ENABIT(17) @@ -148,6 +152,7 @@ struct sdhci_msm_host { u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; + u32 caps_0; }; static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, @@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 irq_status, irq_ack = 0; int retry = 10; - int pwr_state = 0, io_level = 0; + u32 pwr_state = 0, io_level = 0; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); @@ -1313,6 +1318,30 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_msm_check_power_status(host, req_type); } +static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) +{ + struct mmc_host *mmc = msm_host->mmc; + struct regulator *supply = mmc->supply.vqmmc; + u32 caps = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { + if (regulator_is_supported_voltage(supply, 170, 195)) + caps |= CORE_1_8V_SUPPORT; + if (regulator_is_supported_voltage(supply, 270, 360)) + caps |= CORE_3_0V_SUPPORT; + + if (!caps) + pr_warn("%s: %s: 1.8/3V not supported for vqmmc\n", + mmc_hostname(mmc), __func__); + } + + msm_host->caps_0 |= caps; + pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc), + __func__, caps); + + return 0; +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -1530,6 +1559,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; + ret = sdhci_msm_set_regulator_caps(msm_host); + if (ret) + dev_err(>dev, "Failed to set regulator caps: %d\n", + ret); pm_runtime_mark_last_busy(>dev); pm_runtime_put_autosuspend(>dev); -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V4 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages
During probe check whether the vdd-io regulator of sdhc platform device can support 1.8V and 3V and store this information as a capability of platform device. Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 35 ++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c283291..2fcd9010 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -81,6 +82,9 @@ #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_3_0V_SUPPORT (1 << 25) +#define CORE_1_8V_SUPPORT (1 << 26) + #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) #define CORE_HW_AUTOCAL_ENABIT(17) @@ -148,6 +152,7 @@ struct sdhci_msm_host { u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; + u32 caps_0; }; static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, @@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 irq_status, irq_ack = 0; int retry = 10; - int pwr_state = 0, io_level = 0; + u32 pwr_state = 0, io_level = 0; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); @@ -1313,6 +1318,30 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_msm_check_power_status(host, req_type); } +static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) +{ + struct mmc_host *mmc = msm_host->mmc; + struct regulator *supply = mmc->supply.vqmmc; + u32 caps = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { + if (regulator_is_supported_voltage(supply, 170, 195)) + caps |= CORE_1_8V_SUPPORT; + if (regulator_is_supported_voltage(supply, 270, 360)) + caps |= CORE_3_0V_SUPPORT; + + if (!caps) + pr_warn("%s: %s: 1.8/3V not supported for vqmmc\n", + mmc_hostname(mmc), __func__); + } + + msm_host->caps_0 |= caps; + pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc), + __func__, caps); + + return 0; +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -1530,6 +1559,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; + ret = sdhci_msm_set_regulator_caps(msm_host); + if (ret) + dev_err(>dev, "Failed to set regulator caps: %d\n", + ret); pm_runtime_mark_last_busy(>dev); pm_runtime_put_autosuspend(>dev); -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V4 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm
>From the HPG: In some platform, SDCC controller can be connected to either an eMMC device or an SD card. The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. For SD usage the default value of this signal is ???0???, and SD driver changes it to ???1??? as a part of voltage switching sequence. For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to PADs before starting any activity on the eMMC BUS. To set this signal, write the following in the SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register: HC_IO_PAD_PWR_SWITCH: bit 16 HC_IO_PAD_PWR_SWITCH_EN: bit 15 Changes since v1: Modified comments on io_pad related changes. Split some read+modify+write commands to multiple lines Changes since v2: IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what voltage is supported by the regulators. Replaced regulator_list_voltage() API with regulator_is_supported_voltage(). Changes since v3: Removed unnecessary prints and extra lines. Krishna Konda (1): mmc: sdhci-msm: support voltage pad switching Vijay Viswanath (1): mmc: sdhci-msm: Add support to store supported vdd-io voltages drivers/mmc/host/sdhci-msm.c | 99 +++- 1 file changed, 97 insertions(+), 2 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V4 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm
>From the HPG: In some platform, SDCC controller can be connected to either an eMMC device or an SD card. The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. For SD usage the default value of this signal is ???0???, and SD driver changes it to ???1??? as a part of voltage switching sequence. For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to PADs before starting any activity on the eMMC BUS. To set this signal, write the following in the SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register: HC_IO_PAD_PWR_SWITCH: bit 16 HC_IO_PAD_PWR_SWITCH_EN: bit 15 Changes since v1: Modified comments on io_pad related changes. Split some read+modify+write commands to multiple lines Changes since v2: IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what voltage is supported by the regulators. Replaced regulator_list_voltage() API with regulator_is_supported_voltage(). Changes since v3: Removed unnecessary prints and extra lines. Krishna Konda (1): mmc: sdhci-msm: support voltage pad switching Vijay Viswanath (1): mmc: sdhci-msm: Add support to store supported vdd-io voltages drivers/mmc/host/sdhci-msm.c | 99 +++- 1 file changed, 97 insertions(+), 2 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm
>From the HPG: In some platform, SDCC controller can be connected to either an eMMC device or an SD card. The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. For SD usage the default value of this signal is ???0???, and SD driver changes it to ???1??? as a part of voltage switching sequence. For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to PADs before starting any activity on the eMMC BUS. To set this signal, write the following in the SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register: HC_IO_PAD_PWR_SWITCH: bit 16 HC_IO_PAD_PWR_SWITCH_EN: bit 15 Changes since v1: Modified comments on io_pad related changes. Split some read+modify+write commands to multiple lines Changes since v2: IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what voltage is suported by the regulators. Replaced regulator_list_voltage() API with regulator_is_supported_voltage(). Krishna Konda (1): mmc: sdhci-msm: support voltage pad switching Vijay Viswanath (1): mmc: sdhci-msm: Add support to store supported vdd-io voltages drivers/mmc/host/sdhci-msm.c | 99 +++- 1 file changed, 97 insertions(+), 2 deletions(-) -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
[PATCH V3 2/2] mmc: sdhci-msm: support voltage pad switching
From: Krishna Konda <kko...@codeaurora.org> The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs have a control signal (io_pad_pwr_switch/mode18 ) that indicates whether the PAD works in 3v or 1.8v. SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset based on actual voltage used for IO lines. So when power irq is triggered for io high or io low, the driver should check the voltages supported and set the pad accordingly. Signed-off-by: Krishna Konda <kko...@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org> Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org> --- drivers/mmc/host/sdhci-msm.c | 65 ++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a822f10..2ffb7bb 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -78,12 +78,15 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400(6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) #define CORE_3_0V_SUPPORT (1 << 25) #define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIBBIT(16) @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) u32 irq_status, irq_ack = 0; int retry = 10; u32 pwr_state = 0, io_level = 0; - + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1166,11 +1169,51 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* +* If we don't have info regarding the voltage levels supported by +* regulators, don't change the IO PAD PWR SWITCH. +*/ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + /* Ensure order between core_mem and hc_mem */ + mb(); + /* +* We should unset IO PAD PWR switch only if the register write +* can set IO lines high and the regulator also switches to 3 V. +* Else, we should keep the IO PAD PWR switch set. +* This is applicable to certain targets where eMMC vccq supply +* is only 1.8V. In such targets, even during REQ_IO_HIGH, the +* IO PAD PWR switch must be kept set to reflect actual +* regulator voltage. This way, during initialization of +* controllers with only 1.8V, we will set the IO PAD bit +* without waiting for a REQ_IO_LOW. +*/ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + + if (((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & + CORE_3_0V_SUPPORT)) && + (config & CORE_IO_PAD_PWR_SWITCH)) { + config &= ~CORE_IO_PAD_PWR_SWITCH; + writel_relaxed(config, + host->ioaddr + CORE_VENDOR_SPEC); + /* IO PAD register is in different memory space */ + mb(); + } else if (((io_level & REQ_IO_LOW) || + (msm_host->caps_0 & CORE_1_8V_SUPPORT)) && + !(config & CORE_IO_PAD_PWR_SWITCH)) { + config |= CORE_IO_PAD_PWR_SWITCH; + writel_relaxed(config, + host->ioaddr + CORE_VENDOR_SPEC); + /* IO PAD bit is in different memory space */ + mb(); + } + } + if (pwr_state) msm_host->curr_pwr_state = pwr_state; if (io_level) msm_host->curr_io_level = io_level; + pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n", mmc_hostname(msm_host->mmc), __func__, irq, irq_status, irq_ack); @@ -1322,7 +1365,8 @@ static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) { struct mmc_host *mmc = msm_host->mmc; struct regulator *supply = mmc->supply.vqmmc; - u32 caps = 0; + u32 caps = 0, config; + struct sdhci_host *host = mmc_priv(mmc); if (!IS_ERR(mmc->