Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching

From: Vijay Viswanath
Date: Tue Jul 17 2018 - 06:22:12 EST




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 <vviswana@xxxxxxxxxxxxxx>
---
ÂÂÂ 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 making SDHCI do everything.


ok will incorporate the changes in next version.


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 your view/suggestions.

Let's try without the quirk.


+ÂÂÂÂÂÂÂÂÂÂÂ ret = regulator_enable(mmc->supply.vqmmc);
+ÂÂÂÂÂÂÂ else
+ÂÂÂÂÂÂÂÂÂÂÂ ret = 0;
ÂÂÂÂÂÂÂÂÂÂÂ if (!regulator_is_supported_voltage(mmc->supply.vqmmc,
1700000,
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 1950000))
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 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)

So maybe the quirk is not needed.

ÂÂÂ ÂÂÂÂÂ int irq;ÂÂÂÂÂÂÂ /* Device IRQ */
ÂÂÂÂÂÂÂ void __iomem *ioaddr;ÂÂÂ /* Mapped address */



Thanks for the review & suggestions!
Vijay




--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html




Thanks,
Vijay