Skip to contentSkip to conversation

a few sdhci/imx clean up and fix patches

PATCH Superseded Dong Aisheng 6 participants 85 messages Apr 15, 2016 – May 31, 2016

Subsystems (6)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover a few sdhci/imx clean up and fix patches

Patch 1~10 are mainly sdhci cleanup patches while patch 7,9,10 are fixes which seems needed for stable tree as well.

The main work is:
1) a few minor cleanups
2) re-factor sdhci_start_signal_voltage()
3) fix not checking SDHCI_QUIRK2_NO_1_8_V when do voltage switch
4) fix get wrong data interrupt during no data transfer
5) fix unneeded retuning during card remove

Patch 17 added sdhci auto retune support (TUNING_MODE_3) Many controller support hw auto retune, with it we do not need do the frequent retuning after each runtime suspend/resume.

Patch 11~23 are imx esdhc driver clean up and fixes.
1) remove SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
I also tried clean up all SDHCI_QUIRK_BROKEN_TIMEOUT_VAL in the tree, seems a lot work that many controllers are affected, planned to do it later.
2) support setting tuning start point
This can make us bypass a few meaningless tuning commands at the start
3) add hw state restore function after system resume for low power mode like LPSR on IMX7D which the controller state got lost. Without it, the controller may not work after resume.
4) Patch 17~19 added hw auto retune support
5) fix strobe DLL lock wrong clock issue
This makes the eMMC HS400 mode strobe locks the correct clock rate
6) a few other reorgnization to make code more concentrate and maintainable

Dong Aisheng (23):
mmc: sdhci: removed unneeded function wrappers
mmc: sdhci: move sdhci_get_cd() forward to avoid declaration
mmc: core: fix a comment typo
mmc: sdhci: re-factor sdhci_start_signal_voltage()
mmc: core: mmc_regulator_set_vqmmc not return error if vqmmc/vmmc not
exist
mmc: sdhci: using common mmc_regulator_set_vqmmc()
mmc: sdhci: check SDHCI_QUIRK2_NO_1_8_V when do voltage switch
mmc: sdhci: rename quirk SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12
mmc: sdhci: fix incorrect get data interrupt during no data transfer
mmc: core: disable auto retune during card detection process
mmc: sdhci-esdhci-imx: remove SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
mmc: sdhci-esdhc-imx: add esdhc specific suspend resume callback
mmc: sdhci-esdhc-imx: restore watermark level setting after resume
mmc: sdhci-esdhci-imx: disable DLL delay line settings explicitly
mmc: sdhci-esdhc-imx: support setting tuning start point
doc: dt: fsl-imx-esdhc: add set tuning start point binding
mmc: sdhci: add standard hw auto retuning support
mmc: sdhci-esdhc-imx: enable hw auto retuning for STD_TUNING
mmc: sdhci-esdhc-imx: enable hw auto retuning for MAN_TUNING
mmc: sdhci-esdhc-imx: fix strobe DLL lock wrong clock issue
mmc: sdhci-esdhc-imx: factor out hw related intialization into
function
mmc: sdhci-esdhc-imx: move tuning static configuration into hwinit
function
mmc: sdhci-esdhc-imx: clear tuning bits during hwinit

 .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |   2 +
 drivers/mmc/core/core.c                            |   3 +-
 drivers/mmc/core/mmc_ops.c                         |   2 +-
 drivers/mmc/host/sdhci-esdhc-imx.c                 | 150 +++++++++++------
 drivers/mmc/host/sdhci-pci-o2micro.c               |   2 +-
 drivers/mmc/host/sdhci-pltfm.c                     |   2 +-
 drivers/mmc/host/sdhci-s3c.c                       |   2 +-
 drivers/mmc/host/sdhci.c                           | 186 +++++++++------------
 drivers/mmc/host/sdhci.h                           |   5 +-
 include/linux/platform_data/mmc-esdhc-imx.h        |   1 +
 10 files changed, 194 insertions(+), 161 deletions(-)
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/23 mmc: sdhci: removed unneeded function wrappers

After commit d6463f170cf0 ("mmc: sdhci: Remove redundant runtime PM calls"), some of original sdhci_do_xx() function wrappers becomes meaningless, so remove them.

---
 drivers/mmc/host/sdhci.c | 60 ++++++++++++------------------------------------
 1 file changed, 15 insertions(+), 45 deletions(-)
drivers/mmc/host/sdhci.c +15 -45
index 8e74e75..be52a3a 100644
@@ -53,7 +53,7 @@ static void sdhci_finish_data(struct sdhci_host *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static int sdhci_do_get_cd(struct sdhci_host *host);
+static int sdhci_get_cd(struct mmc_host *mmc);
 
 #ifdef CONFIG_PM
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
 static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
 {
 	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-		if (!sdhci_do_get_cd(host))
+		if (!sdhci_get_cd(host->mmc))
 			return;
 	}
 
@@ -1393,11 +1393,11 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
-static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
+	struct sdhci_host *host = mmc_priv(mmc);
 	unsigned long flags;
 	u8 ctrl;
-	struct mmc_host *mmc = host->mmc;
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -1551,16 +1551,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+static int sdhci_get_cd(struct mmc_host *mmc)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
-
-	sdhci_do_set_ios(host, ios);
-}
-
-static int sdhci_do_get_cd(struct sdhci_host *host)
-{
-	int gpio_cd = mmc_gpio_get_cd(host->mmc);
+	int gpio_cd = mmc_gpio_get_cd(mmc);
 
 	if (host->flags & SDHCI_DEVICE_DEAD)
 		return 0;
@@ -1584,13 +1578,6 @@ static int sdhci_do_get_cd(struct sdhci_host *host)
 	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
 }
 
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
-	struct sdhci_host *host = mmc_priv(mmc);
-
-	return sdhci_do_get_cd(host);
-}
-
 static int sdhci_check_ro(struct sdhci_host *host)
 {
 	unsigned long flags;
@@ -1615,8 +1602,9 @@ static int sdhci_check_ro(struct sdhci_host *host)
 
 #define SAMPLE_COUNT	5
 
-static int sdhci_do_get_ro(struct sdhci_host *host)
+static int sdhci_get_ro(struct mmc_host *mmc)
 {
+	struct sdhci_host *host = mmc_priv(mmc);
 	int i, ro_count;
 
 	if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
@@ -1641,13 +1629,6 @@ static void sdhci_hw_reset(struct mmc_host *mmc)
 		host->ops->hw_reset(host);
 }
 
-static int sdhci_get_ro(struct mmc_host *mmc)
-{
-	struct sdhci_host *host = mmc_priv(mmc);
-
-	return sdhci_do_get_ro(host);
-}
-
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
 	if (!(host->flags & SDHCI_DEVICE_DEAD)) {
@@ -1677,10 +1658,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
-						struct mmc_ios *ios)
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+					     struct mmc_ios *ios)
 {
-	struct mmc_host *mmc = host->mmc;
+	struct sdhci_host *host = mmc_priv(mmc);
 	u16 ctrl;
 	int ret;
 
@@ -1768,17 +1749,6 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 	}
 }
 
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
-	struct mmc_ios *ios)
-{
-	struct sdhci_host *host = mmc_priv(mmc);
-
-	if (host->version < SDHCI_SPEC_300)
-		return 0;
-
-	return sdhci_do_start_signal_voltage_switch(host, ios);
-}
-
 static int sdhci_card_busy(struct mmc_host *mmc)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
@@ -2070,7 +2040,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
 	if (host->ops->card_event)
 		host->ops->card_event(host);
 
-	present = sdhci_do_get_cd(host);
+	present = sdhci_get_cd(host->mmc);
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -2643,7 +2613,7 @@ int sdhci_resume_host(struct sdhci_host *host)
 		sdhci_init(host, 0);
 		host->pwr = 0;
 		host->clock = 0;
-		sdhci_do_set_ios(host, &host->mmc->ios);
+		sdhci_set_ios(host->mmc, &host->mmc->ios);
 	} else {
 		sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
 		mmiowb();
@@ -2721,8 +2691,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
 	/* Force clock and power re-program */
 	host->pwr = 0;
 	host->clock = 0;
-	sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
-	sdhci_do_set_ios(host, &host->mmc->ios);
+	sdhci_start_signal_voltage_switch(host->mmc, &host->mmc->ios);
+	sdhci_set_ios(host->mmc, &host->mmc->ios);
 
 	if ((host_flags & SDHCI_PV_ENABLED) &&
 		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
Signature · 1 line
1.9.1
maintainer
#3 lore raw

PATCH 1/23 mmc: sdhci: removed unneeded function wrappers

Quoted 10 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

After commit d6463f170cf0 ("mmc: sdhci: Remove redundant runtime PM calls"), some of original sdhci_do_xx() function wrappers becomes meaningless, so remove them.

Didn't apply cleanly, otherwise:

Ulf, will you apply this one?

Applied
#4 lore raw

PATCH 1/23 mmc: sdhci: removed unneeded function wrappers

In reply to Dong Aisheng
Quoted 5 lines · Dong Aisheng

After commit d6463f170cf0 ("mmc: sdhci: Remove redundant runtime PM calls"), some of original sdhci_do_xx() function wrappers becomes meaningless, so remove them.

Thanks, applied for next!

Kind regards
Uffe

Quoted 162 lines
---
 drivers/mmc/host/sdhci.c | 60 ++++++++++++------------------------------------
 1 file changed, 15 insertions(+), 45 deletions(-)
drivers/mmc/host/sdhci.c +15 -46
index 8e74e75..be52a3a 100644
@@ -53,7 +53,7 @@ static void sdhci_finish_data(struct sdhci_host *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static int sdhci_do_get_cd(struct sdhci_host *host);
+static int sdhci_get_cd(struct mmc_host *mmc);
 
 #ifdef CONFIG_PM
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
 static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
 {
        if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-               if (!sdhci_do_get_cd(host))
+               if (!sdhci_get_cd(host->mmc))
                        return;
        }
 
@@ -1393,11 +1393,11 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
-static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
+       struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
        u8 ctrl;
-       struct mmc_host *mmc = host->mmc;
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -1551,16 +1551,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+static int sdhci_get_cd(struct mmc_host *mmc)
 {
        struct sdhci_host *host = mmc_priv(mmc);
-
-       sdhci_do_set_ios(host, ios);
-}
-
-static int sdhci_do_get_cd(struct sdhci_host *host)
-{
-       int gpio_cd = mmc_gpio_get_cd(host->mmc);
+       int gpio_cd = mmc_gpio_get_cd(mmc);
 
        if (host->flags & SDHCI_DEVICE_DEAD)
                return 0;
@@ -1584,13 +1578,6 @@ static int sdhci_do_get_cd(struct sdhci_host *host)
        return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
 }
 
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-
-       return sdhci_do_get_cd(host);
-}
-
 static int sdhci_check_ro(struct sdhci_host *host)
 {
        unsigned long flags;
@@ -1615,8 +1602,9 @@ static int sdhci_check_ro(struct sdhci_host *host)
 
 #define SAMPLE_COUNT   5
 
-static int sdhci_do_get_ro(struct sdhci_host *host)
+static int sdhci_get_ro(struct mmc_host *mmc)
 {
+       struct sdhci_host *host = mmc_priv(mmc);
        int i, ro_count;
 
        if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
@@ -1641,13 +1629,6 @@ static void sdhci_hw_reset(struct mmc_host *mmc)
                host->ops->hw_reset(host);
 }
 
-static int sdhci_get_ro(struct mmc_host *mmc)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-
-       return sdhci_do_get_ro(host);
-}
-
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
        if (!(host->flags & SDHCI_DEVICE_DEAD)) {
@@ -1677,10 +1658,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
-                                               struct mmc_ios *ios)
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+                                            struct mmc_ios *ios)
 {
-       struct mmc_host *mmc = host->mmc;
+       struct sdhci_host *host = mmc_priv(mmc);
        u16 ctrl;
        int ret;
 
@@ -1768,17 +1749,6 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
        }
 }
 
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
-       struct mmc_ios *ios)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-
-       if (host->version < SDHCI_SPEC_300)
-               return 0;
-
-       return sdhci_do_start_signal_voltage_switch(host, ios);
-}
-
 static int sdhci_card_busy(struct mmc_host *mmc)
 {
        struct sdhci_host *host = mmc_priv(mmc);
@@ -2070,7 +2040,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
        if (host->ops->card_event)
                host->ops->card_event(host);
 
-       present = sdhci_do_get_cd(host);
+       present = sdhci_get_cd(host->mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -2643,7 +2613,7 @@ int sdhci_resume_host(struct sdhci_host *host)
                sdhci_init(host, 0);
                host->pwr = 0;
                host->clock = 0;
-               sdhci_do_set_ios(host, &host->mmc->ios);
+               sdhci_set_ios(host->mmc, &host->mmc->ios);
        } else {
                sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
                mmiowb();
@@ -2721,8 +2691,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
        /* Force clock and power re-program */
        host->pwr = 0;
        host->clock = 0;
-       sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
-       sdhci_do_set_ios(host, &host->mmc->ios);
+       sdhci_start_signal_voltage_switch(host->mmc, &host->mmc->ios);
+       sdhci_set_ios(host->mmc, &host->mmc->ios);
 
        if ((host_flags & SDHCI_PV_ENABLED) &&
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
--

1.9.1

#5 lore raw

PATCH 2/23 mmc: sdhci: move sdhci_get_cd() forward to avoid declaration

In reply to Dong Aisheng

Move sdhci_get_cd() to avoid needing to declare this function before use.

---
 drivers/mmc/host/sdhci.c | 55 ++++++++++++++++++++++++------------------------
 1 file changed, 27 insertions(+), 28 deletions(-)
drivers/mmc/host/sdhci.c +27 -28
index be52a3a..839aa4c 100644
@@ -53,7 +53,6 @@ static void sdhci_finish_data(struct sdhci_host *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static int sdhci_get_cd(struct mmc_host *mmc);
 
 #ifdef CONFIG_PM
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
@@ -161,6 +160,33 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 	sdhci_set_card_detection(host, false);
 }
 
+static int sdhci_get_cd(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int gpio_cd = mmc_gpio_get_cd(mmc);
+
+	if (host->flags & SDHCI_DEVICE_DEAD)
+		return 0;
+
+	/* If nonremovable, assume that the card is always present. */
+	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+		return 1;
+
+	/*
+	 * Try slot gpio detect, if defined it take precedence
+	 * over build in controller functionality
+	 */
+	if (!IS_ERR_VALUE(gpio_cd))
+		return !!gpio_cd;
+
+	/* If polling, assume that the card is always present. */
+	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+		return 1;
+
+	/* Host native card detect */
+	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+}
+
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	unsigned long timeout;
@@ -1551,33 +1577,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
-	struct sdhci_host *host = mmc_priv(mmc);
-	int gpio_cd = mmc_gpio_get_cd(mmc);
-
-	if (host->flags & SDHCI_DEVICE_DEAD)
-		return 0;
-
-	/* If nonremovable, assume that the card is always present. */
-	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
-		return 1;
-
-	/*
-	 * Try slot gpio detect, if defined it take precedence
-	 * over build in controller functionality
-	 */
-	if (!IS_ERR_VALUE(gpio_cd))
-		return !!gpio_cd;
-
-	/* If polling, assume that the card is always present. */
-	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-		return 1;
-
-	/* Host native card detect */
-	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
-}
-
 static int sdhci_check_ro(struct sdhci_host *host)
 {
 	unsigned long flags;
Signature · 1 line
1.9.1
maintainer
#6 lore raw

PATCH 2/23 mmc: sdhci: move sdhci_get_cd() forward to avoid declaration

Quoted 2 lines · Dong Aisheng

Move sdhci_get_cd() to avoid needing to declare this function before use.

In fact, we shouldn't be calling host functions directly. i.e. the call should be host->mmc->ops->get_cd().

However the caller sdhci_do_reset() is called under spinlock so it should not be calling ->get_cd at all.

What that means is that we really need to get rid of SDHCI_QUIRK_NO_CARD_NO_RESET, after which this patch wouldn't be needed, so let's leave it for now.

Quoted 87 lines
---
 drivers/mmc/host/sdhci.c | 55 ++++++++++++++++++++++++------------------------
 1 file changed, 27 insertions(+), 28 deletions(-)
drivers/mmc/host/sdhci.c +27 -28
index be52a3a..839aa4c 100644
@@ -53,7 +53,6 @@ static void sdhci_finish_data(struct sdhci_host *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static int sdhci_get_cd(struct mmc_host *mmc);
 
 #ifdef CONFIG_PM
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
@@ -161,6 +160,33 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 	sdhci_set_card_detection(host, false);
 }
 
+static int sdhci_get_cd(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int gpio_cd = mmc_gpio_get_cd(mmc);
+
+	if (host->flags & SDHCI_DEVICE_DEAD)
+		return 0;
+
+	/* If nonremovable, assume that the card is always present. */
+	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+		return 1;
+
+	/*
+	 * Try slot gpio detect, if defined it take precedence
+	 * over build in controller functionality
+	 */
+	if (!IS_ERR_VALUE(gpio_cd))
+		return !!gpio_cd;
+
+	/* If polling, assume that the card is always present. */
+	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+		return 1;
+
+	/* Host native card detect */
+	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+}
+
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	unsigned long timeout;
@@ -1551,33 +1577,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
-	struct sdhci_host *host = mmc_priv(mmc);
-	int gpio_cd = mmc_gpio_get_cd(mmc);
-
-	if (host->flags & SDHCI_DEVICE_DEAD)
-		return 0;
-
-	/* If nonremovable, assume that the card is always present. */
-	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
-		return 1;
-
-	/*
-	 * Try slot gpio detect, if defined it take precedence
-	 * over build in controller functionality
-	 */
-	if (!IS_ERR_VALUE(gpio_cd))
-		return !!gpio_cd;
-
-	/* If polling, assume that the card is always present. */
-	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-		return 1;
-
-	/* Host native card detect */
-	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
-}
-
 static int sdhci_check_ro(struct sdhci_host *host)
 {
 	unsigned long flags;
#7 lore raw

PATCH 2/23 mmc: sdhci: move sdhci_get_cd() forward to avoid declaration

Quoted 7 lines · Adrian Hunter
Quoted 2 lines · Dong Aisheng

Move sdhci_get_cd() to avoid needing to declare this function before use.

In fact, we shouldn't be calling host functions directly. i.e. the call should be host->mmc->ops->get_cd().

Quoted 7 lines

However the caller sdhci_do_reset() is called under spinlock so it should not be calling ->get_cd at all.

What that means is that we really need to get rid of SDHCI_QUIRK_NO_CARD_NO_RESET, after which this patch wouldn't be needed, so let's leave it for now.

Yes, i agree we need get rid of SDHCI_QUIRK_NO_CARD_NO_RESET. However, after that, we still need to remove the sdhci_get_cd pre-declaration, right?

Regards
Dong Aisheng

Quoted 88 lines
Quoted 87 lines
---
 drivers/mmc/host/sdhci.c | 55 ++++++++++++++++++++++++------------------------
 1 file changed, 27 insertions(+), 28 deletions(-)
drivers/mmc/host/sdhci.c +27 -28
index be52a3a..839aa4c 100644
@@ -53,7 +53,6 @@ static void sdhci_finish_data(struct sdhci_host *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static int sdhci_get_cd(struct mmc_host *mmc);
 
 #ifdef CONFIG_PM
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
@@ -161,6 +160,33 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
      sdhci_set_card_detection(host, false);
 }
 
+static int sdhci_get_cd(struct mmc_host *mmc)
+{
+     struct sdhci_host *host = mmc_priv(mmc);
+     int gpio_cd = mmc_gpio_get_cd(mmc);
+
+     if (host->flags & SDHCI_DEVICE_DEAD)
+             return 0;
+
+     /* If nonremovable, assume that the card is always present. */
+     if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+             return 1;
+
+     /*
+      * Try slot gpio detect, if defined it take precedence
+      * over build in controller functionality
+      */
+     if (!IS_ERR_VALUE(gpio_cd))
+             return !!gpio_cd;
+
+     /* If polling, assume that the card is always present. */
+     if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+             return 1;
+
+     /* Host native card detect */
+     return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+}
+
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
      unsigned long timeout;
@@ -1551,33 +1577,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
      spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
-     struct sdhci_host *host = mmc_priv(mmc);
-     int gpio_cd = mmc_gpio_get_cd(mmc);
-
-     if (host->flags & SDHCI_DEVICE_DEAD)
-             return 0;
-
-     /* If nonremovable, assume that the card is always present. */
-     if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
-             return 1;
-
-     /*
-      * Try slot gpio detect, if defined it take precedence
-      * over build in controller functionality
-      */
-     if (!IS_ERR_VALUE(gpio_cd))
-             return !!gpio_cd;
-
-     /* If polling, assume that the card is always present. */
-     if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-             return 1;
-
-     /* Host native card detect */
-     return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
-}
-
 static int sdhci_check_ro(struct sdhci_host *host)
 {
      unsigned long flags;
maintainer
#8 lore raw

PATCH 2/23 mmc: sdhci: move sdhci_get_cd() forward to avoid declaration

Quoted 11 lines · Dong Aisheng
Quoted 10 lines · Adrian Hunter
Quoted 2 lines · Dong Aisheng

Move sdhci_get_cd() to avoid needing to declare this function before use.

In fact, we shouldn't be calling host functions directly. i.e. the call should be host->mmc->ops->get_cd().

However the caller sdhci_do_reset() is called under spinlock so it should not be calling ->get_cd at all.

Quoted 8 lines
Quoted 4 lines

What that means is that we really need to get rid of SDHCI_QUIRK_NO_CARD_NO_RESET, after which this patch wouldn't be needed, so let's leave it for now.

Yes, i agree we need get rid of SDHCI_QUIRK_NO_CARD_NO_RESET. However, after that, we still need to remove the sdhci_get_cd pre-declaration, right?

Sure

Quoted 92 lines

Regards
Dong Aisheng

Quoted 88 lines
Quoted 87 lines
---
  drivers/mmc/host/sdhci.c | 55 ++++++++++++++++++++++++------------------------
  1 file changed, 27 insertions(+), 28 deletions(-)
drivers/mmc/host/sdhci.c +27 -28
index be52a3a..839aa4c 100644
@@ -53,7 +53,6 @@ static void sdhci_finish_data(struct sdhci_host *);
  static void sdhci_finish_command(struct sdhci_host *);
  static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
  static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static int sdhci_get_cd(struct mmc_host *mmc);
 
  #ifdef CONFIG_PM
  static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
@@ -161,6 +160,33 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
       sdhci_set_card_detection(host, false);
  }
 
+static int sdhci_get_cd(struct mmc_host *mmc)
+{
+     struct sdhci_host *host = mmc_priv(mmc);
+     int gpio_cd = mmc_gpio_get_cd(mmc);
+
+     if (host->flags & SDHCI_DEVICE_DEAD)
+             return 0;
+
+     /* If nonremovable, assume that the card is always present. */
+     if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+             return 1;
+
+     /*
+      * Try slot gpio detect, if defined it take precedence
+      * over build in controller functionality
+      */
+     if (!IS_ERR_VALUE(gpio_cd))
+             return !!gpio_cd;
+
+     /* If polling, assume that the card is always present. */
+     if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+             return 1;
+
+     /* Host native card detect */
+     return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+}
+
  void sdhci_reset(struct sdhci_host *host, u8 mask)
  {
       unsigned long timeout;
@@ -1551,33 +1577,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
       spin_unlock_irqrestore(&host->lock, flags);
  }
 
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
-     struct sdhci_host *host = mmc_priv(mmc);
-     int gpio_cd = mmc_gpio_get_cd(mmc);
-
-     if (host->flags & SDHCI_DEVICE_DEAD)
-             return 0;
-
-     /* If nonremovable, assume that the card is always present. */
-     if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
-             return 1;
-
-     /*
-      * Try slot gpio detect, if defined it take precedence
-      * over build in controller functionality
-      */
-     if (!IS_ERR_VALUE(gpio_cd))
-             return !!gpio_cd;
-
-     /* If polling, assume that the card is always present. */
-     if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-             return 1;
-
-     /* Host native card detect */
-     return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
-}
-
  static int sdhci_check_ro(struct sdhci_host *host)
  {
       unsigned long flags;
#9 lore raw

PATCH 3/23 mmc: core: fix a comment typo

In reply to Dong Aisheng
---
 drivers/mmc/core/mmc_ops.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/core/mmc_ops.c +1 -1
index 62355bd..d220bbd 100644
@@ -553,7 +553,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 
 		/*
 		 * We are not allowed to issue a status command and the host
-		 * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
+		 * doesn't support MMC_CAP_WAIT_WHILE_BUSY, then we can only
 		 * rely on waiting for the stated timeout to be sufficient.
 		 */
 		if (!send_status) {
Signature · 1 line
1.9.1
maintainer
#10 lore raw

PATCH 3/23 mmc: core: fix a comment typo

Quoted 1 line · Dong Aisheng

I'll leave this one up to Ulf.

Quoted 18 lines
---
 drivers/mmc/core/mmc_ops.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/core/mmc_ops.c +1 -1
index 62355bd..d220bbd 100644
@@ -553,7 +553,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 
 		/*
 		 * We are not allowed to issue a status command and the host
-		 * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
+		 * doesn't support MMC_CAP_WAIT_WHILE_BUSY, then we can only
 		 * rely on waiting for the stated timeout to be sufficient.
 		 */
 		if (!send_status) {
#11 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

In reply to Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

---
 drivers/mmc/host/sdhci.c | 97 ++++++++++++++++++++++++++++--------------------
 1 file changed, 57 insertions(+), 40 deletions(-)
drivers/mmc/host/sdhci.c +57 -40
index 839aa4c..7f63f5d 100644
@@ -1657,19 +1657,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
-					     struct mmc_ios *ios)
+static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
+					  struct mmc_ios *ios)
 {
-	struct sdhci_host *host = mmc_priv(mmc);
 	u16 ctrl;
-	int ret;
-
-	/*
-	 * Signal Voltage Switching is only applicable for Host Controllers
-	 * v3.00 and above.
-	 */
-	if (host->version < SDHCI_SPEC_300)
-		return 0;
 
 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
@@ -1679,15 +1670,6 @@ static 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)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
-			if (ret) {
-				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
-					mmc_hostname(mmc));
-				return -EIO;
-			}
-		}
 		/* Wait for 5ms */
 		usleep_range(5000, 5500);
 
@@ -1697,20 +1679,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 			return 0;
 
 		pr_warn("%s: 3.3V regulator output did not became stable\n",
-			mmc_hostname(mmc));
+			mmc_hostname(host->mmc));
 
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
-		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
-			if (ret) {
-				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
-					mmc_hostname(mmc));
-				return -EIO;
-			}
-		}
-
 		/*
 		 * Enable 1.8V Signal Enable in the Host Control2
 		 * register
@@ -1728,18 +1700,63 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 			return 0;
 
 		pr_warn("%s: 1.8V regulator output did not became stable\n",
-			mmc_hostname(mmc));
+			mmc_hostname(host->mmc));
 
 		return -EAGAIN;
+	default:
+		/* No signal voltage switch required */
+		return 0;
+	}
+}
+
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+					     struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int ret;
+
+	/*
+	 * Signal Voltage Switching is only applicable for Host Controllers
+	 * v3.00 and above.
+	 */
+	if (host->version < SDHCI_SPEC_300)
+		return 0;
+
+	ret = sdhci_do_signal_voltage_switch(host, ios);
+	if (ret)
+		return ret;
+
+	if (IS_ERR(mmc->supply.vqmmc))
+		return 0;
+
+	switch (ios->signal_voltage) {
+	case MMC_SIGNAL_VOLTAGE_330:
+		ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
+					    3600000);
+		if (ret) {
+			pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
+				mmc_hostname(mmc));
+			return -EIO;
+		}
+
+		return 0;
+	case MMC_SIGNAL_VOLTAGE_180:
+		ret = regulator_set_voltage(mmc->supply.vqmmc,
+				1700000, 1950000);
+		if (ret) {
+			pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
+				mmc_hostname(mmc));
+			return -EIO;
+		}
+
+		return 0;
 	case MMC_SIGNAL_VOLTAGE_120:
-		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
-			if (ret) {
-				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
-					mmc_hostname(mmc));
-				return -EIO;
-			}
+		ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
+					    1300000);
+		if (ret) {
+			pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
+				mmc_hostname(mmc));
+			return -EIO;
 		}
 		return 0;
 	default:
Signature · 1 line
1.9.1
maintainer
#12 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done. There is no way to know what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Quoted 144 lines
---
 drivers/mmc/host/sdhci.c | 97 ++++++++++++++++++++++++++++--------------------
 1 file changed, 57 insertions(+), 40 deletions(-)
drivers/mmc/host/sdhci.c +57 -40
index 839aa4c..7f63f5d 100644
@@ -1657,19 +1657,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
-					     struct mmc_ios *ios)
+static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
+					  struct mmc_ios *ios)
 {
-	struct sdhci_host *host = mmc_priv(mmc);
 	u16 ctrl;
-	int ret;
-
-	/*
-	 * Signal Voltage Switching is only applicable for Host Controllers
-	 * v3.00 and above.
-	 */
-	if (host->version < SDHCI_SPEC_300)
-		return 0;
 
 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
@@ -1679,15 +1670,6 @@ static 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)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
-			if (ret) {
-				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
-					mmc_hostname(mmc));
-				return -EIO;
-			}
-		}
 		/* Wait for 5ms */
 		usleep_range(5000, 5500);
 
@@ -1697,20 +1679,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 			return 0;
 
 		pr_warn("%s: 3.3V regulator output did not became stable\n",
-			mmc_hostname(mmc));
+			mmc_hostname(host->mmc));
 
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
-		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
-			if (ret) {
-				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
-					mmc_hostname(mmc));
-				return -EIO;
-			}
-		}
-
 		/*
 		 * Enable 1.8V Signal Enable in the Host Control2
 		 * register
@@ -1728,18 +1700,63 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 			return 0;
 
 		pr_warn("%s: 1.8V regulator output did not became stable\n",
-			mmc_hostname(mmc));
+			mmc_hostname(host->mmc));
 
 		return -EAGAIN;
+	default:
+		/* No signal voltage switch required */
+		return 0;
+	}
+}
+
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+					     struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int ret;
+
+	/*
+	 * Signal Voltage Switching is only applicable for Host Controllers
+	 * v3.00 and above.
+	 */
+	if (host->version < SDHCI_SPEC_300)
+		return 0;
+
+	ret = sdhci_do_signal_voltage_switch(host, ios);
+	if (ret)
+		return ret;
+
+	if (IS_ERR(mmc->supply.vqmmc))
+		return 0;
+
+	switch (ios->signal_voltage) {
+	case MMC_SIGNAL_VOLTAGE_330:
+		ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
+					    3600000);
+		if (ret) {
+			pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
+				mmc_hostname(mmc));
+			return -EIO;
+		}
+
+		return 0;
+	case MMC_SIGNAL_VOLTAGE_180:
+		ret = regulator_set_voltage(mmc->supply.vqmmc,
+				1700000, 1950000);
+		if (ret) {
+			pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
+				mmc_hostname(mmc));
+			return -EIO;
+		}
+
+		return 0;
 	case MMC_SIGNAL_VOLTAGE_120:
-		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
-			if (ret) {
-				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
-					mmc_hostname(mmc));
-				return -EIO;
-			}
+		ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
+					    1300000);
+		if (ret) {
+			pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
+				mmc_hostname(mmc));
+			return -EIO;
 		}
 		return 0;
 	default:
#13 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

Furthermore, i think sdhci_start_signal_voltage_switch() interface should not be order dependant, if yes, then the issue should be fixed at a higher level.

The main purpose of this patch and next patch is to make sdhci_signal_voltage_swithc()
more clear since we already have a more robust mmc_regulator_set_vqmmc() and for host without vqmmc, we event do not need run that part of code.

BTW changing regulator_set_voltage() to mmc_regulator_set_vqmmc() is the same situation here.

Anyway, more test from others will be a great help and appreciated.

Regards
Dong Aisheng

Quoted 145 lines
Quoted 144 lines
---
 drivers/mmc/host/sdhci.c | 97 ++++++++++++++++++++++++++++--------------------
 1 file changed, 57 insertions(+), 40 deletions(-)
drivers/mmc/host/sdhci.c +57 -40
index 839aa4c..7f63f5d 100644
@@ -1657,19 +1657,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
      spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
-                                          struct mmc_ios *ios)
+static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
+                                       struct mmc_ios *ios)
 {
-     struct sdhci_host *host = mmc_priv(mmc);
      u16 ctrl;
-     int ret;
-
-     /*
-      * Signal Voltage Switching is only applicable for Host Controllers
-      * v3.00 and above.
-      */
-     if (host->version < SDHCI_SPEC_300)
-             return 0;
 
      ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
@@ -1679,15 +1670,6 @@ static 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)) {
-                     ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-                                                 3600000);
-                     if (ret) {
-                             pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
-                                     mmc_hostname(mmc));
-                             return -EIO;
-                     }
-             }
              /* Wait for 5ms */
              usleep_range(5000, 5500);
 
@@ -1697,20 +1679,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
                      return 0;
 
              pr_warn("%s: 3.3V regulator output did not became stable\n",
-                     mmc_hostname(mmc));
+                     mmc_hostname(host->mmc));
 
              return -EAGAIN;
      case MMC_SIGNAL_VOLTAGE_180:
-             if (!IS_ERR(mmc->supply.vqmmc)) {
-                     ret = regulator_set_voltage(mmc->supply.vqmmc,
-                                     1700000, 1950000);
-                     if (ret) {
-                             pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
-                                     mmc_hostname(mmc));
-                             return -EIO;
-                     }
-             }
-
              /*
               * Enable 1.8V Signal Enable in the Host Control2
               * register
@@ -1728,18 +1700,63 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
                      return 0;
 
              pr_warn("%s: 1.8V regulator output did not became stable\n",
-                     mmc_hostname(mmc));
+                     mmc_hostname(host->mmc));
 
              return -EAGAIN;
+     default:
+             /* No signal voltage switch required */
+             return 0;
+     }
+}
+
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+                                          struct mmc_ios *ios)
+{
+     struct sdhci_host *host = mmc_priv(mmc);
+     int ret;
+
+     /*
+      * Signal Voltage Switching is only applicable for Host Controllers
+      * v3.00 and above.
+      */
+     if (host->version < SDHCI_SPEC_300)
+             return 0;
+
+     ret = sdhci_do_signal_voltage_switch(host, ios);
+     if (ret)
+             return ret;
+
+     if (IS_ERR(mmc->supply.vqmmc))
+             return 0;
+
+     switch (ios->signal_voltage) {
+     case MMC_SIGNAL_VOLTAGE_330:
+             ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
+                                         3600000);
+             if (ret) {
+                     pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
+                             mmc_hostname(mmc));
+                     return -EIO;
+             }
+
+             return 0;
+     case MMC_SIGNAL_VOLTAGE_180:
+             ret = regulator_set_voltage(mmc->supply.vqmmc,
+                             1700000, 1950000);
+             if (ret) {
+                     pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
+                             mmc_hostname(mmc));
+                     return -EIO;
+             }
+
+             return 0;
      case MMC_SIGNAL_VOLTAGE_120:
-             if (!IS_ERR(mmc->supply.vqmmc)) {
-                     ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-                                                 1300000);
-                     if (ret) {
-                             pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
-                                     mmc_hostname(mmc));
-                             return -EIO;
-                     }
+             ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
+                                         1300000);
+             if (ret) {
+                     pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
+                             mmc_hostname(mmc));
+                     return -EIO;
              }
              return 0;
      default:
maintainer
#14 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 60 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

Quoted 3 lines

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

#15 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 61 lines · Adrian Hunter
Quoted 60 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

Quoted 7 lines
Quoted 3 lines

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

Quoted 2 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

Regards
Dong Aisheng

Quoted 4 lines

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

maintainer
#16 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 64 lines · Dong Aisheng
Quoted 63 lines · Adrian Hunter
Quoted 62 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

We have to move forward *and* avoid potential breakage.

In this case it seems me that the risk of breakage outweighs the value of prettier code.

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 6 lines
Quoted 3 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
maintainer
#17 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Hi Adrian,

Quoted 99 lines · Adrian Hunter
Quoted 64 lines · Dong Aisheng
Quoted 63 lines · Adrian Hunter
Quoted 62 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

We have to move forward *and* avoid potential breakage.

In this case it seems me that the risk of breakage outweighs the value of prettier code.

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 1 line
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

maybe.. this question should not be related with this discussion..
But i have one question..sdhci_do_start_signal_voltage_switch() returned 0 or EAGAIN, when IS_ERR(mmc->supply.vqmmc) is ture. It there any problem?

I'm also checking on core side. but just wondering this. (Because i'm fixing dwmmc controller for this.)

Best Regards,
Jaehoon Chung

Quoted 44 lines
drivers/mmc/host/sdhci.c +3 -7
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
 
 
 
--

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

maintainer
#18 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 105 lines · Jaehoon Chung

Hi Adrian,

Quoted 102 lines · Adrian Hunter
Quoted 64 lines · Dong Aisheng
Quoted 63 lines · Adrian Hunter
Quoted 62 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

We have to move forward *and* avoid potential breakage.

In this case it seems me that the risk of breakage outweighs the value of prettier code.

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 4 lines
Quoted 3 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

maybe.. this question should not be related with this discussion..
But i have one question..sdhci_do_start_signal_voltage_switch() returned 0 or EAGAIN, when IS_ERR(mmc->supply.vqmmc) is ture. It there any problem?

Not that I am aware of.

Quoted 3 lines

I'm also checking on core side. but just wondering this. (Because i'm fixing dwmmc controller for this.)

What is the problem?

Quoted 50 lines

Best Regards,
Jaehoon Chung

Quoted 44 lines
drivers/mmc/host/sdhci.c +3 -7
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
 
 
 
--

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

maintainer
#19 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 115 lines · Adrian Hunter
Quoted 105 lines · Jaehoon Chung

Hi Adrian,

Quoted 102 lines · Adrian Hunter
Quoted 64 lines · Dong Aisheng
Quoted 63 lines · Adrian Hunter
Quoted 62 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

We have to move forward *and* avoid potential breakage.

In this case it seems me that the risk of breakage outweighs the value of prettier code.

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 4 lines
Quoted 3 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

maybe.. this question should not be related with this discussion..
But i have one question..sdhci_do_start_signal_voltage_switch() returned 0 or EAGAIN, when IS_ERR(mmc->supply.vqmmc) is ture. It there any problem?

Quoted 7 lines

Not that I am aware of.

Quoted 3 lines

I'm also checking on core side. but just wondering this. (Because i'm fixing dwmmc controller for this.)

What is the problem?

It should be difference with dwmmc controller.
if mmc->supply.vqmmc is not assigned, it didn't change the voltage..
(I'm not sure that HOST_CONTROL2 register can internally change the voltage..because i didn't have SDHC 3.0 spec.)

__mmc_set_signal_voltage()
-> host->ops->start_signal_voltage_switch()
-> host controller just set the bits for v1.8 or v3.3..(if vqmmc didn't use.)
if return -EAGAIN or 0 , the bits that was set for v1.8 or v3.3 should be maintained.

And do mmc_power_cycle() -> mmc_power_off and mmc_set_initial_state()

But host controller didn't initialize.

That is dwmmc controller's side..

As my understanding, if voltage switch(UHS-I mode) is failed, it should be set to HS mode. but dwmmc controller didn't work this case..so i will fix.
(Some parts are code bugs in dwmmc controller.)

I don't know sdhci is working fine or not..just wondering. :)

I'm going to analyze the sequence and other thing..so i may miss something.

Best Regards,
Jaehoon Chung

Quoted 58 lines
Quoted 43 lines

Best Regards,
Jaehoon Chung

Quoted 38 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
Quoted 8 lines
Quoted 6 lines

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

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

#20 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 135 lines · Jaehoon Chung
Quoted 115 lines · Adrian Hunter
Quoted 105 lines · Jaehoon Chung

Hi Adrian,

Quoted 102 lines · Adrian Hunter
Quoted 64 lines · Dong Aisheng
Quoted 63 lines · Adrian Hunter
Quoted 62 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

We have to move forward *and* avoid potential breakage.

In this case it seems me that the risk of breakage outweighs the value of prettier code.

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 4 lines
Quoted 3 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

maybe.. this question should not be related with this discussion..
But i have one question..sdhci_do_start_signal_voltage_switch() returned 0 or EAGAIN, when IS_ERR(mmc->supply.vqmmc) is ture. It there any problem?

Quoted 7 lines

Not that I am aware of.

Quoted 3 lines

I'm also checking on core side. but just wondering this. (Because i'm fixing dwmmc controller for this.)

What is the problem?

It should be difference with dwmmc controller.
if mmc->supply.vqmmc is not assigned, it didn't change the voltage..
(I'm not sure that HOST_CONTROL2 register can internally change the voltage..because i didn't have SDHC 3.0 spec.)

__mmc_set_signal_voltage()
-> host->ops->start_signal_voltage_switch()
-> host controller just set the bits for v1.8 or v3.3..(if vqmmc didn't use.)
if return -EAGAIN or 0 , the bits that was set for v1.8 or v3.3 should be maintained.

And do mmc_power_cycle() -> mmc_power_off and mmc_set_initial_state()

Quoted 8 lines

But host controller didn't initialize.

That is dwmmc controller's side..

As my understanding, if voltage switch(UHS-I mode) is failed, it should be set to HS mode. but dwmmc controller didn't work this case..so i will fix.
(Some parts are code bugs in dwmmc controller.)

MMC core will retry HS mode initialization if voltage switch reach 10 times failure.
See: mmc_sd_get_cid()

Quoted 2 lines

I don't know sdhci is working fine or not..just wondering. :)

I tested sdhci is working fine.

Quoted 2 lines

I'm going to analyze the sequence and other thing..so i may miss something.

Probably you may need check if the IO voltage is correctly back up after failure.

Regards
Dong Aisheng

Quoted 62 lines

Best Regards,
Jaehoon Chung

Quoted 58 lines
Quoted 43 lines

Best Regards,
Jaehoon Chung

Quoted 38 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
Quoted 8 lines
Quoted 6 lines

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

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

maintainer
#21 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 140 lines · Dong Aisheng
Quoted 139 lines · Jaehoon Chung
Quoted 115 lines · Adrian Hunter
Quoted 105 lines · Jaehoon Chung

Hi Adrian,

Quoted 102 lines · Adrian Hunter
Quoted 64 lines · Dong Aisheng
Quoted 63 lines · Adrian Hunter
Quoted 62 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

We have to move forward *and* avoid potential breakage.

In this case it seems me that the risk of breakage outweighs the value of prettier code.

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 4 lines
Quoted 3 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

maybe.. this question should not be related with this discussion..
But i have one question..sdhci_do_start_signal_voltage_switch() returned 0 or EAGAIN, when IS_ERR(mmc->supply.vqmmc) is ture. It there any problem?

Quoted 7 lines

Not that I am aware of.

Quoted 3 lines

I'm also checking on core side. but just wondering this. (Because i'm fixing dwmmc controller for this.)

What is the problem?

It should be difference with dwmmc controller.
if mmc->supply.vqmmc is not assigned, it didn't change the voltage..
(I'm not sure that HOST_CONTROL2 register can internally change the voltage..because i didn't have SDHC 3.0 spec.)

__mmc_set_signal_voltage()
-> host->ops->start_signal_voltage_switch()
-> host controller just set the bits for v1.8 or v3.3..(if vqmmc didn't use.)
if return -EAGAIN or 0 , the bits that was set for v1.8 or v3.3 should be maintained.

And do mmc_power_cycle() -> mmc_power_off and mmc_set_initial_state()

But host controller didn't initialize.

That is dwmmc controller's side..

Quoted 8 lines
Quoted 4 lines

As my understanding, if voltage switch(UHS-I mode) is failed, it should be set to HS mode. but dwmmc controller didn't work this case..so i will fix.
(Some parts are code bugs in dwmmc controller.)

MMC core will retry HS mode initialization if voltage switch reach 10 times failure.
See: mmc_sd_get_cid()

Yes, i knew.

Quoted 11 lines
Quoted 3 lines

I don't know sdhci is working fine or not..just wondering. :)

I tested sdhci is working fine.

Quoted 2 lines

I'm going to analyze the sequence and other thing..so i may miss something.

Probably you may need check if the IO voltage is correctly back up after failure.

As i mentioned, this is dwmmc controller's problem..there is some bugs. :) So i'm fixing. Thanks!

Best Regards,
Jaehoon Chung

Quoted 68 lines

Regards
Dong Aisheng

Quoted 62 lines

Best Regards,
Jaehoon Chung

Quoted 58 lines
Quoted 43 lines

Best Regards,
Jaehoon Chung

Quoted 38 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
Quoted 8 lines
Quoted 6 lines

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

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

#22 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

In reply to Adrian Hunter
Quoted 71 lines · Adrian Hunter
Quoted 70 lines · Dong Aisheng
Quoted 68 lines · Adrian Hunter
Quoted 60 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

Quoted 3 lines

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Quoted 9 lines
Quoted 2 lines

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2

Yes, now i understand your concern.

Quoted 10 lines
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

The "correct way" i mean here is .start_signal_voltage_switch() shouldn't be order dependant, would you agree?

Quoted 2 lines

We have to move forward *and* avoid potential breakage.

If really break happens, fix platform driver, not common SDHCI. That's the same thing you done for sdhci_set_power().

Quoted 3 lines

In this case it seems me that the risk of breakage outweighs the value of prettier code.

Actually my main purpose is patch 6: using mmc_regulator_set_vqmmc() which is worth and it does improve the stability and eliminate the potential signal issue.
However it's not the same way as you proposed.
See below.

Quoted 4 lines

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

Sorry, i did not get that you want to change like below. However, it looks that it does not make too much sense to call mmc_regulator_set_vqmmc() for each VOLTAGE type like 3.3v/1.8v/1.2v which introduces ugliness because mmc_regulator_set_vqmmc() already handles it internally, right?
Only because we want to keep an "ASSUMED" order as before?

Regards
Dong Aisheng

Quoted 37 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
maintainer
#23 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 91 lines · Dong Aisheng
Quoted 71 lines · Adrian Hunter
Quoted 70 lines · Dong Aisheng
Quoted 68 lines · Adrian Hunter
Quoted 60 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

Quoted 3 lines

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Quoted 9 lines
Quoted 2 lines

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2

Yes, now i understand your concern.

Quoted 7 lines
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

Quoted 6 lines
Quoted 3 lines

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

The "correct way" i mean here is .start_signal_voltage_switch() shouldn't be order dependant, would you agree?

No. There is no way to know if the regulator must be switched before or after the host controller register is changed.

Quoted 6 lines
Quoted 3 lines

We have to move forward *and* avoid potential breakage.

If really break happens, fix platform driver, not common SDHCI. That's the same thing you done for sdhci_set_power().

In that case the original behaviour was kept in the common SDHCI code and the driver had to provide its own way.

Quoted 24 lines
Quoted 4 lines

In this case it seems me that the risk of breakage outweighs the value of prettier code.

Actually my main purpose is patch 6: using mmc_regulator_set_vqmmc() which is worth and it does improve the stability and eliminate the potential signal issue.
However it's not the same way as you proposed.
See below.

Quoted 4 lines

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

Quoted 6 lines

Sorry, i did not get that you want to change like below. However, it looks that it does not make too much sense to call mmc_regulator_set_vqmmc() for each VOLTAGE type like 3.3v/1.8v/1.2v which introduces ugliness because mmc_regulator_set_vqmmc() already handles it internally, right?
Only because we want to keep an "ASSUMED" order as before?

Yes

Quoted 42 lines

Regards
Dong Aisheng

Quoted 37 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
#24 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 96 lines · Adrian Hunter
Quoted 95 lines · Dong Aisheng
Quoted 71 lines · Adrian Hunter
Quoted 70 lines · Dong Aisheng
Quoted 68 lines · Adrian Hunter
Quoted 60 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

Quoted 3 lines

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Quoted 9 lines
Quoted 2 lines

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2

Yes, now i understand your concern.

Quoted 10 lines
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

Quoted 6 lines
Quoted 2 lines

The "correct way" i mean here is .start_signal_voltage_switch() shouldn't be order dependant, would you agree?

No. There is no way to know if the regulator must be switched before or after the host controller register is changed.

Hmm... If there is no way to know the correct order, how can we assume the exist order is correct?
And i already pointed out, the exist order is also confused that it switch controller first then vqmmc for 3.3v and switch vqmmc first, then controller for 1.8v

If we can't sure the exist order is correct, why do we block the changing to correctly use mmc_regulator_set_vqmmc() to improve the driver stability?

And actually the change is not made arbitrarily, i already list all possibilities based on my knowledge. People can raise more if any.
The target is correct that we make start_signal_voltage_switch() order independant.
It's worth a try even there's a potential very low possibility break IMHO.

Or else if we can find a better way to switch to
mmc_regulator_set_vqmmc i would also love to try.

Maybe we need more people's thought on it!

Ulf,
Would you give some inputs?

Regards
Dong Aisheng

Quoted 86 lines
Quoted 6 lines
Quoted 3 lines

We have to move forward *and* avoid potential breakage.

If really break happens, fix platform driver, not common SDHCI. That's the same thing you done for sdhci_set_power().

In that case the original behaviour was kept in the common SDHCI code and the driver had to provide its own way.

Quoted 24 lines
Quoted 4 lines

In this case it seems me that the risk of breakage outweighs the value of prettier code.

Actually my main purpose is patch 6: using mmc_regulator_set_vqmmc() which is worth and it does improve the stability and eliminate the potential signal issue.
However it's not the same way as you proposed.
See below.

Quoted 4 lines

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

Quoted 6 lines

Sorry, i did not get that you want to change like below. However, it looks that it does not make too much sense to call mmc_regulator_set_vqmmc() for each VOLTAGE type like 3.3v/1.8v/1.2v which introduces ugliness because mmc_regulator_set_vqmmc() already handles it internally, right?
Only because we want to keep an "ASSUMED" order as before?

Yes

Quoted 42 lines

Regards
Dong Aisheng

Quoted 37 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
maintainer
#25 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 100 lines · Dong Aisheng
Quoted 99 lines · Adrian Hunter
Quoted 97 lines · Dong Aisheng
Quoted 71 lines · Adrian Hunter
Quoted 70 lines · Dong Aisheng
Quoted 68 lines · Adrian Hunter
Quoted 60 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

Quoted 3 lines

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Quoted 9 lines
Quoted 2 lines

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2

Yes, now i understand your concern.

Quoted 10 lines
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

The "correct way" i mean here is .start_signal_voltage_switch() shouldn't be order dependant, would you agree?

Quoted 6 lines
Quoted 3 lines

No. There is no way to know if the regulator must be switched before or after the host controller register is changed.

Hmm... If there is no way to know the correct order, how can we assume the exist order is correct?

There is no correct order. This is outside the SDHCI spec. and so belongs to individual drivers.

If it mattered we could push the ugly code down onto the drivers, and then driver maintainers could opt to use the new pretty code. However at the moment there is a lot more important work, so I would want to avoid that code churn.

Quoted 7 lines

And i already pointed out, the exist order is also confused that it switch controller first then vqmmc for 3.3v and switch vqmmc first, then controller for 1.8v

If we can't sure the exist order is correct, why do we block the changing to correctly use mmc_regulator_set_vqmmc() to improve the driver stability?

Not sure what you mean here. I have already showed how we can use mmc_regulator_set_vqmmc().

Quoted 4 lines

And actually the change is not made arbitrarily, i already list all possibilities based on my knowledge. People can raise more if any.

You are assuming every driver has a maintainer and every maintainer is following this thread, and understands how it might affect all the different versions of their hardware. That is extremely unlikely.

Quoted 4 lines

The target is correct that we make start_signal_voltage_switch() order independant.
It's worth a try even there's a potential very low possibility break IMHO.

And so we disagree.

Aren't your needs met by changing to use mmc_regulator_set_vqmmc() the way I suggested?

Quoted 99 lines

Or else if we can find a better way to switch to
mmc_regulator_set_vqmmc i would also love to try.

Maybe we need more people's thought on it!

Ulf,
Would you give some inputs?

Regards
Dong Aisheng

Quoted 86 lines
Quoted 6 lines
Quoted 3 lines

We have to move forward *and* avoid potential breakage.

If really break happens, fix platform driver, not common SDHCI. That's the same thing you done for sdhci_set_power().

In that case the original behaviour was kept in the common SDHCI code and the driver had to provide its own way.

Quoted 24 lines
Quoted 4 lines

In this case it seems me that the risk of breakage outweighs the value of prettier code.

Actually my main purpose is patch 6: using mmc_regulator_set_vqmmc() which is worth and it does improve the stability and eliminate the potential signal issue.
However it's not the same way as you proposed.
See below.

Quoted 4 lines

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

Quoted 6 lines

Sorry, i did not get that you want to change like below. However, it looks that it does not make too much sense to call mmc_regulator_set_vqmmc() for each VOLTAGE type like 3.3v/1.8v/1.2v which introduces ugliness because mmc_regulator_set_vqmmc() already handles it internally, right?
Only because we want to keep an "ASSUMED" order as before?

Yes

Quoted 42 lines

Regards
Dong Aisheng

Quoted 37 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
#26 lore raw

PATCH 4/23 mmc: sdhci: re-factor sdhci_start_signal_voltage()

Quoted 128 lines · Adrian Hunter
Quoted 100 lines · Dong Aisheng
Quoted 99 lines · Adrian Hunter
Quoted 97 lines · Dong Aisheng
Quoted 71 lines · Adrian Hunter
Quoted 70 lines · Dong Aisheng
Quoted 68 lines · Adrian Hunter
Quoted 60 lines · Dong Aisheng

Hi Adrian,

Thanks for the review first.

Quoted 8 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Handle host and regulator signal voltage switch separately. Move host signal voltage switch code into a separated function sdhci_do_signal_voltage_switch() first, the following patches will remove the regulator voltage switch code and use the common mmc_regulator_set_vqmmc() instead.

You have changed the order that things are done.

Yes, the oder changes a bit that we always do controller voltage switch first. I suppose the order is irrelevant here since i don't recall any requirement from card.

Actually the original order is also a bit mass.
e.g.
For MMC_SIGNAL_VOLTAGE_330, switch controller first, then vqmmc. But for MMC_SIGNAL_VOLTAGE_180, switch vqmmc first, then controller. It looks to us the original one also order irrelevant.

Quoted 4 lines

There is no way to know
what that will break, so let's not do that. What about just changing regulator_set_voltage() to mmc_regulator_set_vqmmc()?

Currently what i can think out VIO switch using are three cases: (Pls help add if any)
1) Both host IO and card IO use external vqmmc to do switch (e.g eMMC 1.8V DDR/HS200/HS400 mode)

eMMC has no IO voltage switch protocol and requirement, so usually board designed
using fixed 1.8V for eMMC and host IO.
Event it's switchable, it should be done in the first mmc_power_up(). Dynamical switch later may cause eMMC unable to work properly. (We have been confirmed about this issue by many eMMC vendors like Micron and Sandisk. I'm not sure if any exceptions in the community still doing VIO dynamical switch for eMMC, if yes, please help share the experience!).

Event some people still do dynamical IO switch for eMMC, since eMMC spec has no requirement, so the order should also not care.

2) Host using controller IO switch while card using standard CMD (SD/SDIO3.0)

SD/SDIO 3.0 spec defines the standard IO switch process and using it's internal regulator to do card IO voltage switch. It does not use external vqmmc regulator.
So order irrelevant too.

3) Host using controller IO switch while card using external vqmmc (special SDIO3.0 or eMMC)
I have met some special SDIO3.0 card like Broadcom WiFi which does not follow the spec and using external regulator for card IO voltage. Usually it's required to fix to 1.8v and also not order irrelevant.

Quoted 3 lines

For eMMC, refer to case 1), it should be fixed to 1.8v at power up.

So it looks all cases seems are not order required.

I don't agree that there is any way to know that other host controllers are not affected. I don't want a repeat of sdhci_set_power().

Quoted 9 lines
Quoted 2 lines

Can you share some more info about sdhci_set_power() issue? I'd like to see if we are same the issue.

Not the same issue, but the same concept. People changing the code under the impression that their way was correct, and then breaking other people's drivers. Check the git history and mailing list.

	http://marc.info/?l=linux-mmc&m=145880454106474&w=2

Yes, now i understand your concern.

Quoted 10 lines
Quoted 6 lines

BTW, IMHO i don't think we should stop keep moving only afraid of potential break if it's correct way. Because .start_signal_voltage_switch() interface seems shouldn't be order dependant.
If it is, then it should be fixed and handled in high layer like MMC core rather than in host driver. Right?

The SDHCI spec. does not define how to use external regulators, so there is no "correct way".

The "correct way" i mean here is .start_signal_voltage_switch() shouldn't be order dependant, would you agree?

Quoted 6 lines
Quoted 3 lines

No. There is no way to know if the regulator must be switched before or after the host controller register is changed.

Hmm... If there is no way to know the correct order, how can we assume the exist order is correct?

There is no correct order. This is outside the SDHCI spec. and so belongs to individual drivers.

If it mattered we could push the ugly code down onto the drivers, and then driver maintainers could opt to use the new pretty code. However at the moment there is a lot more important work, so I would want to avoid that code churn.

Quoted 7 lines

And i already pointed out, the exist order is also confused that it switch controller first then vqmmc for 3.3v and switch vqmmc first, then controller for 1.8v

If we can't sure the exist order is correct, why do we block the changing to correctly use mmc_regulator_set_vqmmc() to improve the driver stability?

Not sure what you mean here. I have already showed how we can use mmc_regulator_set_vqmmc().

Quoted 1 line
Quoted 8 lines
Quoted 3 lines

And actually the change is not made arbitrarily, i already list all possibilities based on my knowledge. People can raise more if any.

You are assuming every driver has a maintainer and every maintainer is following this thread, and understands how it might affect all the different versions of their hardware. That is extremely unlikely.

Yes, we can't sure it.
All we can do on breaking old rules is do it early and test people. Potential break shouldn't block us to going forward IMHO. But i understand at this time you may not want it.

Quoted 10 lines
Quoted 4 lines

The target is correct that we make start_signal_voltage_switch() order independant.
It's worth a try even there's a potential very low possibility break IMHO.

And so we disagree.

Aren't your needs met by changing to use mmc_regulator_set_vqmmc() the way I suggested?

Well, although i'm not in favor of that way.
But as you insist, i will re-cook the patch to fix the issue first.

Regards
Dong Aisheng

Quoted 100 lines
Quoted 99 lines

Or else if we can find a better way to switch to
mmc_regulator_set_vqmmc i would also love to try.

Maybe we need more people's thought on it!

Ulf,
Would you give some inputs?

Regards
Dong Aisheng

Quoted 86 lines
Quoted 6 lines
Quoted 3 lines

We have to move forward *and* avoid potential breakage.

If really break happens, fix platform driver, not common SDHCI. That's the same thing you done for sdhci_set_power().

In that case the original behaviour was kept in the common SDHCI code and the driver had to provide its own way.

Quoted 24 lines
Quoted 4 lines

In this case it seems me that the risk of breakage outweighs the value of prettier code.

Actually my main purpose is patch 6: using mmc_regulator_set_vqmmc() which is worth and it does improve the stability and eliminate the potential signal issue.
However it's not the same way as you proposed.
See below.

Quoted 4 lines

By the way, there are ways to get rid of the ugliness - such as pushing it down into individual drivers.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Please instead send a patch for just using mmc_regulator_set_vqmmc() in place of regulator_set_voltage().

Just using mmc_regulator_set_vqmmc() also changes the order which is the same situation.

How so? It looks like a drop-in replacement to me:

Quoted 6 lines

Sorry, i did not get that you want to change like below. However, it looks that it does not make too much sense to call mmc_regulator_set_vqmmc() for each VOLTAGE type like 3.3v/1.8v/1.2v which introduces ugliness because mmc_regulator_set_vqmmc() already handles it internally, right?
Only because we want to keep an "ASSUMED" order as before?

Yes

Quoted 42 lines

Regards
Dong Aisheng

Quoted 37 lines
drivers/mmc/host/sdhci.c +3 -6
index 94cffa77490a..69b4d48aff87 100644
@@ -1757,8 +1757,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-						    3600000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1779,8 +1778,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc,
-					1700000, 1950000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
 					mmc_hostname(mmc));
@@ -1810,8 +1808,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_120:
 		if (!IS_ERR(mmc->supply.vqmmc)) {
-			ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-						    1300000);
+			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
 				pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
 					mmc_hostname(mmc));
#27 lore raw

PATCH 5/23 mmc: core: mmc_regulator_set_vqmmc not return error if vqmmc/vmmc not exist

In reply to Dong Aisheng

Treat vqmmc/vmmc regulator the same way as mmc_regulator_get_supply() in mmc_regulator_set_vqmmc(), since they're optional, do not return an error if not exist.

---
 drivers/mmc/core/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/core/core.c +1 -1
index 99275e4..52bfaf0 100644
@@ -1440,7 +1440,7 @@ int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
 
 	/* If no vqmmc supply then we can't change the voltage */
 	if (IS_ERR(mmc->supply.vqmmc))
-		return -EINVAL;
+		return 0;
 
 	switch (ios->signal_voltage) {
 	case MMC_SIGNAL_VOLTAGE_120:
Signature · 1 line
1.9.1
#28 lore raw

PATCH 6/23 mmc: sdhci: using common mmc_regulator_set_vqmmc()

In reply to Dong Aisheng

Instead of using private VCCQ regulator signal voltage switch code, we switch to use the more robust common function mmc_regulator_set_vqmmc() in MMC core which set the target voltage as close as possible to target voltage.

---
Don't have a board to test mmc_regulator_set_vqmmc() switch way, need others to help verify.

---
 drivers/mmc/host/sdhci.c | 39 ++-------------------------------------
 1 file changed, 2 insertions(+), 37 deletions(-)
drivers/mmc/host/sdhci.c +2 -37
index 7f63f5d..2338aab 100644
@@ -1726,43 +1726,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 	if (ret)
 		return ret;
 
-	if (IS_ERR(mmc->supply.vqmmc))
-		return 0;
-
-	switch (ios->signal_voltage) {
-	case MMC_SIGNAL_VOLTAGE_330:
-		ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-					    3600000);
-		if (ret) {
-			pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
-				mmc_hostname(mmc));
-			return -EIO;
-		}
-
-		return 0;
-	case MMC_SIGNAL_VOLTAGE_180:
-		ret = regulator_set_voltage(mmc->supply.vqmmc,
-				1700000, 1950000);
-		if (ret) {
-			pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
-				mmc_hostname(mmc));
-			return -EIO;
-		}
-
-		return 0;
-	case MMC_SIGNAL_VOLTAGE_120:
-		ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-					    1300000);
-		if (ret) {
-			pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
-				mmc_hostname(mmc));
-			return -EIO;
-		}
-		return 0;
-	default:
-		/* No signal voltage switch required */
-		return 0;
-	}
+	/* do regulator signal voltage switch if exist */
+	return mmc_regulator_set_vqmmc(mmc, ios);
 }
 
 static int sdhci_card_busy(struct mmc_host *mmc)
Signature · 1 line
1.9.1
maintainer
#29 lore raw

PATCH 6/23 mmc: sdhci: using common mmc_regulator_set_vqmmc()

Quoted 9 lines · Dong Aisheng

Instead of using private VCCQ regulator signal voltage switch code, we switch to use the more robust common function mmc_regulator_set_vqmmc() in MMC core which set the target voltage as close as possible to target voltage.

---
Don't have a board to test mmc_regulator_set_vqmmc() switch way, need others to help verify.

So was there a reason you wanted to change it?

I agree mmc_regulator_set_vqmmc() looks superior, but we really need feedback from people using this code..

Quoted 55 lines
---
 drivers/mmc/host/sdhci.c | 39 ++-------------------------------------
 1 file changed, 2 insertions(+), 37 deletions(-)
drivers/mmc/host/sdhci.c +2 -37
index 7f63f5d..2338aab 100644
@@ -1726,43 +1726,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 	if (ret)
 		return ret;
 
-	if (IS_ERR(mmc->supply.vqmmc))
-		return 0;
-
-	switch (ios->signal_voltage) {
-	case MMC_SIGNAL_VOLTAGE_330:
-		ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-					    3600000);
-		if (ret) {
-			pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
-				mmc_hostname(mmc));
-			return -EIO;
-		}
-
-		return 0;
-	case MMC_SIGNAL_VOLTAGE_180:
-		ret = regulator_set_voltage(mmc->supply.vqmmc,
-				1700000, 1950000);
-		if (ret) {
-			pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
-				mmc_hostname(mmc));
-			return -EIO;
-		}
-
-		return 0;
-	case MMC_SIGNAL_VOLTAGE_120:
-		ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-					    1300000);
-		if (ret) {
-			pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
-				mmc_hostname(mmc));
-			return -EIO;
-		}
-		return 0;
-	default:
-		/* No signal voltage switch required */
-		return 0;
-	}
+	/* do regulator signal voltage switch if exist */
+	return mmc_regulator_set_vqmmc(mmc, ios);
 }
 
 static int sdhci_card_busy(struct mmc_host *mmc)
#30 lore raw

PATCH 6/23 mmc: sdhci: using common mmc_regulator_set_vqmmc()

Quoted 6 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Instead of using private VCCQ regulator signal voltage switch code, we switch to use the more robust common function mmc_regulator_set_vqmmc() in MMC core which set the target voltage as close as possible to target voltage.

Quoted 7 lines
Quoted 4 lines

---
Don't have a board to test mmc_regulator_set_vqmmc() switch way, need others to help verify.

So was there a reason you wanted to change it?

Yes, main reason is we already have common mmc_regulator_set_vqmmc(), we don't want to maintain two copies of it. And the common one is more robust.

The original one is more error prone since it may set a margine IO voltage which may more easy to lead an potential IO error.
e.g. if vqmmc is capable of 1.7V, then our host will set to 1.7v rather than 1.8v
which is a mininum allowed IO voltage range(1.7v ~ 1.95v) defined by spec.

Quoted 3 lines

I agree mmc_regulator_set_vqmmc() looks superior, but we really need feedback from people using this code..

Yes, although from code inspection, there's no functionality change, but tests from others using it will be appreciated.

Regards
Dong Aisheng

Quoted 56 lines
Quoted 55 lines
---
 drivers/mmc/host/sdhci.c | 39 ++-------------------------------------
 1 file changed, 2 insertions(+), 37 deletions(-)
drivers/mmc/host/sdhci.c +2 -37
index 7f63f5d..2338aab 100644
@@ -1726,43 +1726,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
      if (ret)
              return ret;
 
-     if (IS_ERR(mmc->supply.vqmmc))
-             return 0;
-
-     switch (ios->signal_voltage) {
-     case MMC_SIGNAL_VOLTAGE_330:
-             ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-                                         3600000);
-             if (ret) {
-                     pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
-                             mmc_hostname(mmc));
-                     return -EIO;
-             }
-
-             return 0;
-     case MMC_SIGNAL_VOLTAGE_180:
-             ret = regulator_set_voltage(mmc->supply.vqmmc,
-                             1700000, 1950000);
-             if (ret) {
-                     pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
-                             mmc_hostname(mmc));
-                     return -EIO;
-             }
-
-             return 0;
-     case MMC_SIGNAL_VOLTAGE_120:
-             ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-                                         1300000);
-             if (ret) {
-                     pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
-                             mmc_hostname(mmc));
-                     return -EIO;
-             }
-             return 0;
-     default:
-             /* No signal voltage switch required */
-             return 0;
-     }
+     /* do regulator signal voltage switch if exist */
+     return mmc_regulator_set_vqmmc(mmc, ios);
 }
 
 static int sdhci_card_busy(struct mmc_host *mmc)
#31 lore raw

PATCH 7/23 mmc: sdhci: check SDHCI_QUIRK2_NO_1_8_V when do voltage switch

In reply to Dong Aisheng

Currently when card type supports EXT_CSD_CARD_TYPE_DDR_1_8V which means it can work on DDR mode with either 3.3v IO or 1.8v IO voltage. MMC core will first try 1.8v then 3.3v if host claims MMC_CAP_1_8V_DDR support.
However the host driver voltage switch code does not check NO_1_8_V quirk which may set a wrong 1.8v and causes the card fixed to 3.3v VIO un-work.

Checking 1.8V quirk before setting it to avoid such issue.

---
 drivers/mmc/host/sdhci.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/mmc/host/sdhci.c +2 -0
index 2338aab..96ccb15 100644
@@ -1683,6 +1683,8 @@ static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
 
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
+		if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
+			return -EINVAL;
 		/*
 		 * Enable 1.8V Signal Enable in the Host Control2
 		 * register
Signature · 1 line
1.9.1
maintainer
#32 lore raw

PATCH 7/23 mmc: sdhci: check SDHCI_QUIRK2_NO_1_8_V when do voltage switch

Quoted 9 lines · Dong Aisheng

Currently when card type supports EXT_CSD_CARD_TYPE_DDR_1_8V which means it can work on DDR mode with either 3.3v IO or 1.8v IO voltage. MMC core will first try 1.8v then 3.3v if host claims MMC_CAP_1_8V_DDR support.
However the host driver voltage switch code does not check NO_1_8_V quirk which may set a wrong 1.8v and causes the card fixed to 3.3v VIO un-work.

Checking 1.8V quirk before setting it to avoid such issue.

We need to look forward to when SDHCI_QUIRK2_NO_1_8_V doesn't exist.

There are two possibilities:

1. Add MMC_CAP_3_3V_DDR and support to core and use that instead of MMC_CAP_1_8V_DDR. You'll need Ulf's feedback on that.

2. Replace ->start_signal_voltage_switch() i.e.

host->mmc_host_ops.start_signal_voltage_switch =
esdhci_start_signal_voltage_switch;

You will also need to change all calls to sdhci_start_signal_voltage_switch() with host->mmc->ops->start_signal_voltage_switch(), but that needs to be done anyway.

Quoted 21 lines
---
 drivers/mmc/host/sdhci.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/mmc/host/sdhci.c +2 -0
index 2338aab..96ccb15 100644
@@ -1683,6 +1683,8 @@ static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
 
 		return -EAGAIN;
 	case MMC_SIGNAL_VOLTAGE_180:
+		if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
+			return -EINVAL;
 		/*
 		 * Enable 1.8V Signal Enable in the Host Control2
 		 * register
#33 lore raw

PATCH 7/23 mmc: sdhci: check SDHCI_QUIRK2_NO_1_8_V when do voltage switch

Quoted 9 lines · Adrian Hunter
Quoted 8 lines · Dong Aisheng

Currently when card type supports EXT_CSD_CARD_TYPE_DDR_1_8V which means it can work on DDR mode with either 3.3v IO or 1.8v IO voltage. MMC core will first try 1.8v then 3.3v if host claims MMC_CAP_1_8V_DDR support.
However the host driver voltage switch code does not check NO_1_8_V quirk which may set a wrong 1.8v and causes the card fixed to 3.3v VIO un-work.

Quoted 4 lines
Quoted 1 line

Checking 1.8V quirk before setting it to avoid such issue.

We need to look forward to when SDHCI_QUIRK2_NO_1_8_V doesn't exist.

Yes, i did try to clean up SDHCI_QUIRK2_NO_1_8_V. However, it seems not that simply.
Currently we may still need it before we got a better way.

My point is whether we should stop fixing the exist issue in SDHCI driver just caused by we want to clean up it later?

Quoted 5 lines

There are two possibilities:

1. Add MMC_CAP_3_3V_DDR and support to core and use that instead of MMC_CAP_1_8V_DDR. You'll need Ulf's feedback on that.

Yes, we can do it.
But the point is for DDR50/SD3.0/SDIO3.0/HS200/HS400 cards we have the same situation and still need QUIRK2_NO_1_8_V.

And i somehow a bit wonder whether we should retrieve the speed mode support from device tree since it's actually controller capability. IO range capability is another thing.

Probably we may start another topic to discuss it specificly.

Quoted 9 lines

2. Replace ->start_signal_voltage_switch() i.e.

host->mmc_host_ops.start_signal_voltage_switch =
esdhci_start_signal_voltage_switch;

You will also need to change all calls to sdhci_start_signal_voltage_switch() with host->mmc->ops->start_signal_voltage_switch(), but that needs to be done anyway.

esdhc can fully use the common sdhci_start_signal_voltag_switch. Since it's already support QUIRK_NO_1_8_V, we don't want to invent imx voltage swith currently, but fix and use it first.

Regards
Dong Aisheng

Quoted 22 lines
Quoted 21 lines
---
 drivers/mmc/host/sdhci.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/mmc/host/sdhci.c +2 -0
index 2338aab..96ccb15 100644
@@ -1683,6 +1683,8 @@ static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
 
              return -EAGAIN;
      case MMC_SIGNAL_VOLTAGE_180:
+             if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
+                     return -EINVAL;
              /*
               * Enable 1.8V Signal Enable in the Host Control2
               * register
maintainer
#34 lore raw

PATCH 7/23 mmc: sdhci: check SDHCI_QUIRK2_NO_1_8_V when do voltage switch

Quoted 15 lines · Dong Aisheng
Quoted 9 lines · Adrian Hunter
Quoted 8 lines · Dong Aisheng

Currently when card type supports EXT_CSD_CARD_TYPE_DDR_1_8V which means it can work on DDR mode with either 3.3v IO or 1.8v IO voltage. MMC core will first try 1.8v then 3.3v if host claims MMC_CAP_1_8V_DDR support.
However the host driver voltage switch code does not check NO_1_8_V quirk which may set a wrong 1.8v and causes the card fixed to 3.3v VIO un-work.

Quoted 4 lines
Quoted 1 line

Checking 1.8V quirk before setting it to avoid such issue.

We need to look forward to when SDHCI_QUIRK2_NO_1_8_V doesn't exist.

Quoted 6 lines

Yes, i did try to clean up SDHCI_QUIRK2_NO_1_8_V. However, it seems not that simply.
Currently we may still need it before we got a better way.

My point is whether we should stop fixing the exist issue in SDHCI driver just caused by we want to clean up it later?

If you want a fix for stable kernels, then I guess it is OK. In that case it is better to have a fix that applies cleanly to older kernels i.e. not on top of re-factoring

Quoted 56 lines
Quoted 6 lines

There are two possibilities:

1. Add MMC_CAP_3_3V_DDR and support to core and use that instead of MMC_CAP_1_8V_DDR. You'll need Ulf's feedback on that.

Yes, we can do it.
But the point is for DDR50/SD3.0/SDIO3.0/HS200/HS400 cards we have the same situation and still need QUIRK2_NO_1_8_V.

And i somehow a bit wonder whether we should retrieve the speed mode support from device tree since it's actually controller capability. IO range capability is another thing.

Probably we may start another topic to discuss it specificly.

Quoted 9 lines

2. Replace ->start_signal_voltage_switch() i.e.

host->mmc_host_ops.start_signal_voltage_switch =
esdhci_start_signal_voltage_switch;

You will also need to change all calls to sdhci_start_signal_voltage_switch() with host->mmc->ops->start_signal_voltage_switch(), but that needs to be done anyway.

esdhc can fully use the common sdhci_start_signal_voltag_switch. Since it's already support QUIRK_NO_1_8_V, we don't want to invent imx voltage swith currently, but fix and use it first.

Regards
Dong Aisheng

Quoted 22 lines
Quoted 21 lines
---
  drivers/mmc/host/sdhci.c | 2 ++
  1 file changed, 2 insertions(+)
drivers/mmc/host/sdhci.c +2 -0
index 2338aab..96ccb15 100644
@@ -1683,6 +1683,8 @@ static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
 
               return -EAGAIN;
       case MMC_SIGNAL_VOLTAGE_180:
+             if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
+                     return -EINVAL;
               /*
                * Enable 1.8V Signal Enable in the Host Control2
                * register
#35 lore raw

PATCH 7/23 mmc: sdhci: check SDHCI_QUIRK2_NO_1_8_V when do voltage switch

Quoted 20 lines · Adrian Hunter
Quoted 19 lines · Dong Aisheng
Quoted 9 lines · Adrian Hunter
Quoted 8 lines · Dong Aisheng

Currently when card type supports EXT_CSD_CARD_TYPE_DDR_1_8V which means it can work on DDR mode with either 3.3v IO or 1.8v IO voltage. MMC core will first try 1.8v then 3.3v if host claims MMC_CAP_1_8V_DDR support.
However the host driver voltage switch code does not check NO_1_8_V quirk which may set a wrong 1.8v and causes the card fixed to 3.3v VIO un-work.

Quoted 4 lines
Quoted 1 line

Checking 1.8V quirk before setting it to avoid such issue.

We need to look forward to when SDHCI_QUIRK2_NO_1_8_V doesn't exist.

Yes, i did try to clean up SDHCI_QUIRK2_NO_1_8_V. However, it seems not that simply.
Currently we may still need it before we got a better way.

Quoted 7 lines
Quoted 2 lines

My point is whether we should stop fixing the exist issue in SDHCI driver just caused by we want to clean up it later?

If you want a fix for stable kernels, then I guess it is OK. In that case it is better to have a fix that applies cleanly to older kernels i.e. not on top of re-factoring

Okay, i would think more about how to remove SDHCI_QUIRK2_NO_1_8_V first.

Regards
Dong Aisheng

Quoted 56 lines
Quoted 56 lines
Quoted 6 lines

There are two possibilities:

1. Add MMC_CAP_3_3V_DDR and support to core and use that instead of MMC_CAP_1_8V_DDR. You'll need Ulf's feedback on that.

Yes, we can do it.
But the point is for DDR50/SD3.0/SDIO3.0/HS200/HS400 cards we have the same situation and still need QUIRK2_NO_1_8_V.

And i somehow a bit wonder whether we should retrieve the speed mode support from device tree since it's actually controller capability. IO range capability is another thing.

Probably we may start another topic to discuss it specificly.

Quoted 9 lines

2. Replace ->start_signal_voltage_switch() i.e.

host->mmc_host_ops.start_signal_voltage_switch =
esdhci_start_signal_voltage_switch;

You will also need to change all calls to sdhci_start_signal_voltage_switch() with host->mmc->ops->start_signal_voltage_switch(), but that needs to be done anyway.

esdhc can fully use the common sdhci_start_signal_voltag_switch. Since it's already support QUIRK_NO_1_8_V, we don't want to invent imx voltage swith currently, but fix and use it first.

Regards
Dong Aisheng

Quoted 22 lines
Quoted 21 lines
---
 drivers/mmc/host/sdhci.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/mmc/host/sdhci.c +2 -0
index 2338aab..96ccb15 100644
@@ -1683,6 +1683,8 @@ static int sdhci_do_signal_voltage_switch(struct sdhci_host *host,
 
              return -EAGAIN;
      case MMC_SIGNAL_VOLTAGE_180:
+             if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
+                     return -EINVAL;
              /*
               * Enable 1.8V Signal Enable in the Host Control2
               * register
#36 lore raw

PATCH 8/23 mmc: sdhci: rename quirk SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12

In reply to Dong Aisheng

Rename ACMD12 quirk to SDHCI_QUIRK_MULTIBLOCK_ACMD12 to avoid confusion since it's needed for both read and write.

---
 drivers/mmc/host/sdhci-pci-o2micro.c | 2 +-
 drivers/mmc/host/sdhci-pltfm.c       | 2 +-
 drivers/mmc/host/sdhci-s3c.c         | 2 +-
 drivers/mmc/host/sdhci.c             | 2 +-
 drivers/mmc/host/sdhci.h             | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
drivers/mmc/host/sdhci-pci-o2micro.c +1 -1
index d48f031..1ed1f995 100644
@@ -162,7 +162,7 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
 	case PCI_DEVICE_ID_O2_FUJIN2:
 		reg = sdhci_readl(host, O2_SD_VENDOR_SETTING);
 		if (reg & 0x1)
-			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
 		if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
 			break;
drivers/mmc/host/sdhci-pltfm.c +1 -1
index 072bb27..206057a 100644
@@ -74,7 +74,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
 	u32 bus_width;
 
 	if (of_get_property(np, "sdhci,auto-cmd12", NULL))
-		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
 	if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
 	    (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
drivers/mmc/host/sdhci-s3c.c +1 -1
index 70c724b..756b9bb 100644
@@ -564,7 +564,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
 	host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
 
 	/* This host supports the Auto CMD12 */
-	host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+	host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
 	/* Samsung SoCs need BROKEN_ADMA_ZEROLEN_DESC */
 	host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;
drivers/mmc/host/sdhci.c +1 -1
index 96ccb15..40e3551 100644
@@ -2988,7 +2988,7 @@ int sdhci_add_host(struct sdhci_host *host)
 	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 	mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
-	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_ACMD12)
 		host->flags |= SDHCI_AUTO_CMD12;
 
 	/* Auto-CMD23 stuff only works in ADMA or PIO. */
drivers/mmc/host/sdhci.h +1 -1
index 0f39f4f..afa4de8 100644
@@ -379,7 +379,7 @@ struct sdhci_host {
 /* Controller is missing device caps. Use caps provided by host */
 #define SDHCI_QUIRK_MISSING_CAPS			(1<<27)
 /* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12		(1<<28)
+#define SDHCI_QUIRK_MULTIBLOCK_ACMD12			(1<<28)
 /* Controller doesn't have HISPD bit field in HI-SPEED SD card */
 #define SDHCI_QUIRK_NO_HISPD_BIT			(1<<29)
 /* Controller treats ADMA descriptors with length 0000h incorrectly */
Signature · 1 line
1.9.1
maintainer
#37 lore raw

PATCH 8/23 mmc: sdhci: rename quirk SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12

Quoted 2 lines · Dong Aisheng

Rename ACMD12 quirk to SDHCI_QUIRK_MULTIBLOCK_ACMD12 to avoid confusion since it's needed for both read and write.

I am not in favour of renaming unless the original name is really really bad. In this case it is a quirk which we anyway expect to remove at some point, so let's leave it alone for now.

Quoted 76 lines
---
 drivers/mmc/host/sdhci-pci-o2micro.c | 2 +-
 drivers/mmc/host/sdhci-pltfm.c       | 2 +-
 drivers/mmc/host/sdhci-s3c.c         | 2 +-
 drivers/mmc/host/sdhci.c             | 2 +-
 drivers/mmc/host/sdhci.h             | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
drivers/mmc/host/sdhci-pci-o2micro.c +1 -1
index d48f031..1ed1f995 100644
@@ -162,7 +162,7 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
 	case PCI_DEVICE_ID_O2_FUJIN2:
 		reg = sdhci_readl(host, O2_SD_VENDOR_SETTING);
 		if (reg & 0x1)
-			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
 		if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
 			break;
drivers/mmc/host/sdhci-pltfm.c +1 -1
index 072bb27..206057a 100644
@@ -74,7 +74,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
 	u32 bus_width;
 
 	if (of_get_property(np, "sdhci,auto-cmd12", NULL))
-		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
 	if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
 	    (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
drivers/mmc/host/sdhci-s3c.c +1 -1
index 70c724b..756b9bb 100644
@@ -564,7 +564,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
 	host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
 
 	/* This host supports the Auto CMD12 */
-	host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+	host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
 	/* Samsung SoCs need BROKEN_ADMA_ZEROLEN_DESC */
 	host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;
drivers/mmc/host/sdhci.c +1 -1
index 96ccb15..40e3551 100644
@@ -2988,7 +2988,7 @@ int sdhci_add_host(struct sdhci_host *host)
 	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 	mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
-	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_ACMD12)
 		host->flags |= SDHCI_AUTO_CMD12;
 
 	/* Auto-CMD23 stuff only works in ADMA or PIO. */
drivers/mmc/host/sdhci.h +1 -1
index 0f39f4f..afa4de8 100644
@@ -379,7 +379,7 @@ struct sdhci_host {
 /* Controller is missing device caps. Use caps provided by host */
 #define SDHCI_QUIRK_MISSING_CAPS			(1<<27)
 /* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12		(1<<28)
+#define SDHCI_QUIRK_MULTIBLOCK_ACMD12			(1<<28)
 /* Controller doesn't have HISPD bit field in HI-SPEED SD card */
 #define SDHCI_QUIRK_NO_HISPD_BIT			(1<<29)
 /* Controller treats ADMA descriptors with length 0000h incorrectly */
#38 lore raw

PATCH 8/23 mmc: sdhci: rename quirk SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12

Quoted 8 lines · Adrian Hunter
Quoted 2 lines · Dong Aisheng

Rename ACMD12 quirk to SDHCI_QUIRK_MULTIBLOCK_ACMD12 to avoid confusion since it's needed for both read and write.

I am not in favour of renaming unless the original name is really really bad. In this case it is a quirk which we anyway expect to remove at some point, so let's leave it alone for now.

It is really confusing when i first see it. So i made this patch. We could clear it later.
And i think it's more like a capability rather than a quirk.

Anyway, it's up to you whether we should pick it.

Regards
Dong Aisheng

Quoted 77 lines
Quoted 76 lines
---
 drivers/mmc/host/sdhci-pci-o2micro.c | 2 +-
 drivers/mmc/host/sdhci-pltfm.c       | 2 +-
 drivers/mmc/host/sdhci-s3c.c         | 2 +-
 drivers/mmc/host/sdhci.c             | 2 +-
 drivers/mmc/host/sdhci.h             | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
drivers/mmc/host/sdhci-pci-o2micro.c +1 -1
index d48f031..1ed1f995 100644
@@ -162,7 +162,7 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
      case PCI_DEVICE_ID_O2_FUJIN2:
              reg = sdhci_readl(host, O2_SD_VENDOR_SETTING);
              if (reg & 0x1)
-                     host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+                     host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
              if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
                      break;
drivers/mmc/host/sdhci-pltfm.c +1 -1
index 072bb27..206057a 100644
@@ -74,7 +74,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
      u32 bus_width;
 
      if (of_get_property(np, "sdhci,auto-cmd12", NULL))
-             host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+             host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
      if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
          (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
drivers/mmc/host/sdhci-s3c.c +1 -1
index 70c724b..756b9bb 100644
@@ -564,7 +564,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
      host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
 
      /* This host supports the Auto CMD12 */
-     host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+     host->quirks |= SDHCI_QUIRK_MULTIBLOCK_ACMD12;
 
      /* Samsung SoCs need BROKEN_ADMA_ZEROLEN_DESC */
      host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;
drivers/mmc/host/sdhci.c +1 -1
index 96ccb15..40e3551 100644
@@ -2988,7 +2988,7 @@ int sdhci_add_host(struct sdhci_host *host)
      mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
      mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
-     if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+     if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_ACMD12)
              host->flags |= SDHCI_AUTO_CMD12;
 
      /* Auto-CMD23 stuff only works in ADMA or PIO. */
drivers/mmc/host/sdhci.h +1 -1
index 0f39f4f..afa4de8 100644
@@ -379,7 +379,7 @@ struct sdhci_host {
 /* Controller is missing device caps. Use caps provided by host */
 #define SDHCI_QUIRK_MISSING_CAPS                     (1<<27)
 /* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12           (1<<28)
+#define SDHCI_QUIRK_MULTIBLOCK_ACMD12                        (1<<28)
 /* Controller doesn't have HISPD bit field in HI-SPEED SD card */
 #define SDHCI_QUIRK_NO_HISPD_BIT                     (1<<29)
 /* Controller treats ADMA descriptors with length 0000h incorrectly */
#39 lore raw

PATCH 9/23 mmc: sdhci: fix incorrect get data interrupt during no data transfer

In reply to Dong Aisheng

Current code will report the wrong data interrupt got when no data operation in progress assumed by getting !host->data in sdhci_data_irq().

For a data command handling process, the driver will call sdhci_finish_data() and clear host->data in case any data error, then card finish_tasklet will do the rest controller reset work.

Before the tasklet got run, however, controllers may report the TC(Transfer Complete) interrupt (SDHCI_INT_DATA_END) a bit later than data CRC error and data end bit error interrupts for single block transfer or the last block of multiblock transfer.

Controller usually detects and generates data CRC/end bit error interrupts once one block on the bus is transferred completely. For single block transfer, since there's only one bock to transfer, the controller will report transfer complete interrupt as well, but until the data in controller FIFO has been successfully transferred to memory. The time gap of TC and CRC interrupt depends on the system busy state at that point and memory bus access speed.

So it is possible when TC interrupt generated, host->data is already equal to NULL due to cleared by former CRC/Data End Bit error which is reasonable.

Thus we DO NOT report the weird data interrupt event for this case.

Else we may easily see warning below during SD3.0 card manually tuning process (calling mmc_send_tuning() which is a single block transfer)
mmc0: Got data interrupt 0x00000002 even though no data operation was in progress

The detailed command log is as follows:

[ 1657.920983] mmc0: starting CMD19 arg 00000000 flags 00000035
[ 1657.921009] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[ 1657.921085] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00200001
[ 1657.921112] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00000002
[ 1657.921131] mmc0: Got data interrupt 0x00000002 even though no data operation was in progress.
[ 1657.929761] sdhci: =========== REGISTER DUMP (mmc0)===========
[ 1657.929780] sdhci: Sys addr: 0x3d5d6380 | Version:  0x00000002
[ 1657.929796] sdhci: Blk size: 0x00000040 | Blk cnt:  0x00000001
[ 1657.929814] sdhci: Argument: 0x00000000 | Trn mode: 0x00000013
[ 1657.929831] sdhci: Present:  0x01fd8008 | Host ctl: 0x00000023
[ 1657.929847] sdhci: Power:    0x00000002 | Blk gap:  0x00000080
[ 1657.929863] sdhci: Wake-up:  0x00000008 | Clock:    0x0000000f
[ 1657.929879] sdhci: Timeout:  0x0000000f | Int stat: 0x00000000
[ 1657.929896] sdhci: Int enab: 0x107f008b | Sig enab: 0x107f008b
[ 1657.929914] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000003
[ 1657.929932] sdhci: Caps:     0x07eb0000 | Caps_1:   0x00002007
[ 1657.929949] sdhci: Cmd:      0x0000133a | Max curr: 0x00ffffff
[ 1657.929965] sdhci: Host ctl2: 0x000000c8
[ 1657.929981] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x8f042208
[ 1657.929995] sdhci: ===========================================
[ 1657.930156] mmc0: req done (CMD19): 0: 00000900 00000000 00000000 00000000
[ 1657.930179] mmc0:     0 bytes transferred: -84

It shows we first have a data CRC error interrupt then a data transfer complete interrupt.
Then we got the !host->data case in sdhci_data_irq().

---
 drivers/mmc/host/sdhci.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/mmc/host/sdhci.c +11 -0
index 40e3551..2eb0e34 100644
@@ -2325,6 +2325,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 			}
 		}
 
+		/*
+		 * The "data complete" interrupt is possible to happen a bit
+		 * later than CRC error and data end bit error interrupts
+		 * separately for single block transfer or the last block of
+		 * multiblock transfer. For this case, we DO NOT report the
+		 * weird data interrupt event.
+		 */
+		if ((intmask & SDHCI_INT_DATA_END) &&
+		    (host->mrq && host->mrq->data && host->mrq->data->error))
+			return;
+
 		pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
 		       mmc_hostname(host->mmc), (unsigned)intmask);
 		sdhci_dumpregs(host);
Signature · 1 line
1.9.1
maintainer
#40 lore raw

PATCH 9/23 mmc: sdhci: fix incorrect get data interrupt during no data transfer

Quoted 73 lines · Dong Aisheng

Current code will report the wrong data interrupt got when no data operation in progress assumed by getting !host->data in sdhci_data_irq().

For a data command handling process, the driver will call sdhci_finish_data() and clear host->data in case any data error, then card finish_tasklet will do the rest controller reset work.

Before the tasklet got run, however, controllers may report the TC(Transfer Complete) interrupt (SDHCI_INT_DATA_END) a bit later than data CRC error and data end bit error interrupts for single block transfer or the last block of multiblock transfer.

Controller usually detects and generates data CRC/end bit error interrupts once one block on the bus is transferred completely. For single block transfer, since there's only one bock to transfer, the controller will report transfer complete interrupt as well, but until the data in controller FIFO has been successfully transferred to memory. The time gap of TC and CRC interrupt depends on the system busy state at that point and memory bus access speed.

So it is possible when TC interrupt generated, host->data is already equal to NULL due to cleared by former CRC/Data End Bit error which is reasonable.

Thus we DO NOT report the weird data interrupt event for this case.

Else we may easily see warning below during SD3.0 card manually tuning process (calling mmc_send_tuning() which is a single block transfer)
mmc0: Got data interrupt 0x00000002 even though no data operation was in progress

The detailed command log is as follows:

[ 1657.920983] mmc0: starting CMD19 arg 00000000 flags 00000035
[ 1657.921009] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[ 1657.921085] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00200001
[ 1657.921112] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00000002
[ 1657.921131] mmc0: Got data interrupt 0x00000002 even though no data operation was in progress.
[ 1657.929761] sdhci: =========== REGISTER DUMP (mmc0)===========
[ 1657.929780] sdhci: Sys addr: 0x3d5d6380 | Version:  0x00000002
[ 1657.929796] sdhci: Blk size: 0x00000040 | Blk cnt:  0x00000001
[ 1657.929814] sdhci: Argument: 0x00000000 | Trn mode: 0x00000013
[ 1657.929831] sdhci: Present:  0x01fd8008 | Host ctl: 0x00000023
[ 1657.929847] sdhci: Power:    0x00000002 | Blk gap:  0x00000080
[ 1657.929863] sdhci: Wake-up:  0x00000008 | Clock:    0x0000000f
[ 1657.929879] sdhci: Timeout:  0x0000000f | Int stat: 0x00000000
[ 1657.929896] sdhci: Int enab: 0x107f008b | Sig enab: 0x107f008b
[ 1657.929914] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000003
[ 1657.929932] sdhci: Caps:     0x07eb0000 | Caps_1:   0x00002007
[ 1657.929949] sdhci: Cmd:      0x0000133a | Max curr: 0x00ffffff
[ 1657.929965] sdhci: Host ctl2: 0x000000c8
[ 1657.929981] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x8f042208
[ 1657.929995] sdhci: ===========================================
[ 1657.930156] mmc0: req done (CMD19): 0: 00000900 00000000 00000000 00000000
[ 1657.930179] mmc0:     0 bytes transferred: -84

It shows we first have a data CRC error interrupt then a data transfer complete interrupt.
Then we got the !host->data case in sdhci_data_irq().

---
 drivers/mmc/host/sdhci.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/mmc/host/sdhci.c +0 -0
index 40e3551..2eb0e34 100644
@@ -2325,6 +2325,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 			}
 		}
 

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2337

Quoted 10 lines
drivers/mmc/host/sdhci.c +10 -0
+		/*
+		 * The "data complete" interrupt is possible to happen a bit
+		 * later than CRC error and data end bit error interrupts
+		 * separately for single block transfer or the last block of
+		 * multiblock transfer. For this case, we DO NOT report the
+		 * weird data interrupt event.
+		 */
+		if ((intmask & SDHCI_INT_DATA_END) &&
+		    (host->mrq && host->mrq->data && host->mrq->data->error))
+			return;

This could be generalized a bit more i.e. what about:

		/*
		 * After an error and before the the data circuit is reset in
		 * sdhci_tasklet_finish, we could get more interrupts, but we
		 * already have an error, so ignore them.
		 */
		if (host->mrq && host->mrq->data && host->mrq->data->error)
			return;
Quoted 5 lines
drivers/mmc/host/sdhci.c +1 -0
+
 		pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
 		       mmc_hostname(host->mmc), (unsigned)intmask);
 		sdhci_dumpregs(host);
#41 lore raw

PATCH 9/23 mmc: sdhci: fix incorrect get data interrupt during no data transfer

Quoted 5 lines · Adrian Hunter
Quoted 4 lines · Dong Aisheng

Current code will report the wrong data interrupt got when no data operation in progress assumed by getting !host->data in sdhci_data_irq().

Quoted 8 lines
Quoted 8 lines

For a data command handling process, the driver will call sdhci_finish_data() and clear host->data in case any data error, then card finish_tasklet will do the rest controller reset work.

Before the tasklet got run, however, controllers may report the TC(Transfer Complete) interrupt (SDHCI_INT_DATA_END) a bit later than data CRC error and data end bit error interrupts for single block transfer or the last block of multiblock transfer.

What if the controller generates Transfer complete interrupt bit more slower and the tasklet do get a chance to run. In that case even host->mrq will become NULL.
Actually if that happens it's even more worse since the driver may start issuing other commands to controller.

Are we covering that case here? Do you think that this case is possible?

Quoted 92 lines
Quoted 61 lines

Controller usually detects and generates data CRC/end bit error interrupts once one block on the bus is transferred completely. For single block transfer, since there's only one bock to transfer, the controller will report transfer complete interrupt as well, but until the data in controller FIFO has been successfully transferred to memory. The time gap of TC and CRC interrupt depends on the system busy state at that point and memory bus access speed.

So it is possible when TC interrupt generated, host->data is already equal to NULL due to cleared by former CRC/Data End Bit error which is reasonable.

Thus we DO NOT report the weird data interrupt event for this case.

Else we may easily see warning below during SD3.0 card manually tuning process (calling mmc_send_tuning() which is a single block transfer)
mmc0: Got data interrupt 0x00000002 even though no data operation was in progress

The detailed command log is as follows:

[ 1657.920983] mmc0: starting CMD19 arg 00000000 flags 00000035
[ 1657.921009] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[ 1657.921085] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00200001
[ 1657.921112] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00000002
[ 1657.921131] mmc0: Got data interrupt 0x00000002 even though no data operation was in progress.
[ 1657.929761] sdhci: =========== REGISTER DUMP (mmc0)===========
[ 1657.929780] sdhci: Sys addr: 0x3d5d6380 | Version:  0x00000002
[ 1657.929796] sdhci: Blk size: 0x00000040 | Blk cnt:  0x00000001
[ 1657.929814] sdhci: Argument: 0x00000000 | Trn mode: 0x00000013
[ 1657.929831] sdhci: Present:  0x01fd8008 | Host ctl: 0x00000023
[ 1657.929847] sdhci: Power:    0x00000002 | Blk gap:  0x00000080
[ 1657.929863] sdhci: Wake-up:  0x00000008 | Clock:    0x0000000f
[ 1657.929879] sdhci: Timeout:  0x0000000f | Int stat: 0x00000000
[ 1657.929896] sdhci: Int enab: 0x107f008b | Sig enab: 0x107f008b
[ 1657.929914] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000003
[ 1657.929932] sdhci: Caps:     0x07eb0000 | Caps_1:   0x00002007
[ 1657.929949] sdhci: Cmd:      0x0000133a | Max curr: 0x00ffffff
[ 1657.929965] sdhci: Host ctl2: 0x000000c8
[ 1657.929981] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x8f042208
[ 1657.929995] sdhci: ===========================================
[ 1657.930156] mmc0: req done (CMD19): 0: 00000900 00000000 00000000 00000000
[ 1657.930179] mmc0:     0 bytes transferred: -84

It shows we first have a data CRC error interrupt then a data transfer complete interrupt.
Then we got the !host->data case in sdhci_data_irq().

---
 drivers/mmc/host/sdhci.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/mmc/host/sdhci.c +0 -0
index 40e3551..2eb0e34 100644
@@ -2325,6 +2325,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                      }
              }
 

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2337

Quoted 10 lines
drivers/mmc/host/sdhci.c +10 -0
+             /*
+              * The "data complete" interrupt is possible to happen a bit
+              * later than CRC error and data end bit error interrupts
+              * separately for single block transfer or the last block of
+              * multiblock transfer. For this case, we DO NOT report the
+              * weird data interrupt event.
+              */
+             if ((intmask & SDHCI_INT_DATA_END) &&
+                 (host->mrq && host->mrq->data && host->mrq->data->error))
+                     return;

This could be generalized a bit more i.e. what about:

                /*
                 * After an error and before the the data circuit is reset in
                 * sdhci_tasklet_finish, we could get more interrupts, but we
                 * already have an error, so ignore them.
                 */
                if (host->mrq && host->mrq->data && host->mrq->data->error)
                        return;

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2341

Quoted 5 lines
drivers/mmc/host/sdhci.c +1 -0
+
              pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
                     mmc_hostname(host->mmc), (unsigned)intmask);
              sdhci_dumpregs(host);

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

maintainer
#42 lore raw

PATCH 9/23 mmc: sdhci: fix incorrect get data interrupt during no data transfer

Quoted 15 lines · Ritesh Harjani
Quoted 5 lines · Adrian Hunter
Quoted 4 lines · Dong Aisheng

Current code will report the wrong data interrupt got when no data operation in progress assumed by getting !host->data in sdhci_data_irq().

Quoted 8 lines
Quoted 8 lines

For a data command handling process, the driver will call sdhci_finish_data() and clear host->data in case any data error, then card finish_tasklet will do the rest controller reset work.

Before the tasklet got run, however, controllers may report the TC(Transfer Complete) interrupt (SDHCI_INT_DATA_END) a bit later than data CRC error and data end bit error interrupts for single block transfer or the last block of multiblock transfer.

Quoted 7 lines

What if the controller generates Transfer complete interrupt bit more slower and the tasklet do get a chance to run. In that case even host->mrq will become NULL.
Actually if that happens it's even more worse since the driver may start issuing other commands to controller.

Are we covering that case here? Do you think that this case is possible?

After data error, the host driver resets the controller so there will be no more interrupts relating to that mrq.

This patch is avoiding unnecessary warnings until that happens.

Quoted 95 lines
Quoted 94 lines
Quoted 63 lines

Controller usually detects and generates data CRC/end bit error interrupts once one block on the bus is transferred completely. For single block transfer, since there's only one bock to transfer, the controller will report transfer complete interrupt as well, but until the data in controller FIFO has been successfully transferred to memory. The time gap of TC and CRC interrupt depends on the system busy state at that point and memory bus access speed.

So it is possible when TC interrupt generated, host->data is already equal to NULL due to cleared by former CRC/Data End Bit error which is reasonable.

Thus we DO NOT report the weird data interrupt event for this case.

Else we may easily see warning below during SD3.0 card manually tuning process (calling mmc_send_tuning() which is a single block transfer)
mmc0: Got data interrupt 0x00000002 even though no data operation was in progress

The detailed command log is as follows:

[ 1657.920983] mmc0: starting CMD19 arg 00000000 flags 00000035
[ 1657.921009] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[ 1657.921085] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00200001
[ 1657.921112] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00000002
[ 1657.921131] mmc0: Got data interrupt 0x00000002 even though no data operation was in progress.
[ 1657.929761] sdhci: =========== REGISTER DUMP (mmc0)===========
[ 1657.929780] sdhci: Sys addr: 0x3d5d6380 | Version:  0x00000002
[ 1657.929796] sdhci: Blk size: 0x00000040 | Blk cnt:  0x00000001
[ 1657.929814] sdhci: Argument: 0x00000000 | Trn mode: 0x00000013
[ 1657.929831] sdhci: Present:  0x01fd8008 | Host ctl: 0x00000023
[ 1657.929847] sdhci: Power:    0x00000002 | Blk gap:  0x00000080
[ 1657.929863] sdhci: Wake-up:  0x00000008 | Clock:    0x0000000f
[ 1657.929879] sdhci: Timeout:  0x0000000f | Int stat: 0x00000000
[ 1657.929896] sdhci: Int enab: 0x107f008b | Sig enab: 0x107f008b
[ 1657.929914] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000003
[ 1657.929932] sdhci: Caps:     0x07eb0000 | Caps_1:   0x00002007
[ 1657.929949] sdhci: Cmd:      0x0000133a | Max curr: 0x00ffffff
[ 1657.929965] sdhci: Host ctl2: 0x000000c8
[ 1657.929981] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x8f042208
[ 1657.929995] sdhci: ===========================================
[ 1657.930156] mmc0: req done (CMD19): 0: 00000900 00000000 00000000 00000000
[ 1657.930179] mmc0:     0 bytes transferred: -84

It shows we first have a data CRC error interrupt then a data transfer complete interrupt.
Then we got the !host->data case in sdhci_data_irq().

---
 drivers/mmc/host/sdhci.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/mmc/host/sdhci.c +0 -0
index 40e3551..2eb0e34 100644
@@ -2325,6 +2325,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                      }
              }
 

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2337

Quoted 10 lines
drivers/mmc/host/sdhci.c +10 -0
+             /*
+              * The "data complete" interrupt is possible to happen a bit
+              * later than CRC error and data end bit error interrupts
+              * separately for single block transfer or the last block of
+              * multiblock transfer. For this case, we DO NOT report the
+              * weird data interrupt event.
+              */
+             if ((intmask & SDHCI_INT_DATA_END) &&
+                 (host->mrq && host->mrq->data && host->mrq->data->error))
+                     return;

This could be generalized a bit more i.e. what about:

                /*
                 * After an error and before the the data circuit is reset in
                 * sdhci_tasklet_finish, we could get more interrupts, but we
                 * already have an error, so ignore them.
                 */
                if (host->mrq && host->mrq->data && host->mrq->data->error)
                        return;

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2341

Quoted 5 lines
drivers/mmc/host/sdhci.c +1 -0
+
              pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
                     mmc_hostname(host->mmc), (unsigned)intmask);
              sdhci_dumpregs(host);

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

#43 lore raw

PATCH 9/23 mmc: sdhci: fix incorrect get data interrupt during no data transfer

Hi Adrian,

Quoted 22 lines · Adrian Hunter
Quoted 21 lines · Ritesh Harjani
Quoted 5 lines · Adrian Hunter
Quoted 4 lines · Dong Aisheng

Current code will report the wrong data interrupt got when no data operation in progress assumed by getting !host->data in sdhci_data_irq().

Quoted 8 lines
Quoted 8 lines

For a data command handling process, the driver will call sdhci_finish_data() and clear host->data in case any data error, then card finish_tasklet will do the rest controller reset work.

Before the tasklet got run, however, controllers may report the TC(Transfer Complete) interrupt (SDHCI_INT_DATA_END) a bit later than data CRC error and data end bit error interrupts for single block transfer or the last block of multiblock transfer.

What if the controller generates Transfer complete interrupt bit more slower and the tasklet do get a chance to run. In that case even host->mrq will become NULL.
Actually if that happens it's even more worse since the driver may start issuing other commands to controller.

Quoted 4 lines
Quoted 1 line

Are we covering that case here? Do you think that this case is possible?

After data error, the host driver resets the controller so there will be no more interrupts relating to that mrq.

Resetting will happen in sdhci_tasklet_finish.
My case was -
1. Controller raised a Data CRC error.
2. sdhci_irq made host->data = NULL in sdhci_finish_data and scheduled the finish_tasklet.
3. while the tasklet is running and before resetting CMD and Data machine, TC interrupt is raised by controller.
4. sdhci_irq will call for sdhci_data_irq.

But I get it that the second interrupt will end up printing the same error since host->data will be found as NULL in sdhci_data_irq and will return.
So below patch should do the job :)

Quoted 2 lines

This patch is avoiding unnecessary warnings until that happens.

Yes.

Quoted 97 lines
Quoted 96 lines
Quoted 95 lines
Quoted 64 lines

Controller usually detects and generates data CRC/end bit error interrupts once one block on the bus is transferred completely. For single block transfer, since there's only one bock to transfer, the controller will report transfer complete interrupt as well, but until the data in controller FIFO has been successfully transferred to memory. The time gap of TC and CRC interrupt depends on the system busy state at that point and memory bus access speed.

So it is possible when TC interrupt generated, host->data is already equal to NULL due to cleared by former CRC/Data End Bit error which is reasonable.

Thus we DO NOT report the weird data interrupt event for this case.

Else we may easily see warning below during SD3.0 card manually tuning process (calling mmc_send_tuning() which is a single block transfer)
mmc0: Got data interrupt 0x00000002 even though no data operation was in progress

The detailed command log is as follows:

[ 1657.920983] mmc0: starting CMD19 arg 00000000 flags 00000035
[ 1657.921009] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[ 1657.921085] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00200001
[ 1657.921112] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00000002
[ 1657.921131] mmc0: Got data interrupt 0x00000002 even though no data operation was in progress.
[ 1657.929761] sdhci: =========== REGISTER DUMP (mmc0)===========
[ 1657.929780] sdhci: Sys addr: 0x3d5d6380 | Version:  0x00000002
[ 1657.929796] sdhci: Blk size: 0x00000040 | Blk cnt:  0x00000001
[ 1657.929814] sdhci: Argument: 0x00000000 | Trn mode: 0x00000013
[ 1657.929831] sdhci: Present:  0x01fd8008 | Host ctl: 0x00000023
[ 1657.929847] sdhci: Power:    0x00000002 | Blk gap:  0x00000080
[ 1657.929863] sdhci: Wake-up:  0x00000008 | Clock:    0x0000000f
[ 1657.929879] sdhci: Timeout:  0x0000000f | Int stat: 0x00000000
[ 1657.929896] sdhci: Int enab: 0x107f008b | Sig enab: 0x107f008b
[ 1657.929914] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000003
[ 1657.929932] sdhci: Caps:     0x07eb0000 | Caps_1:   0x00002007
[ 1657.929949] sdhci: Cmd:      0x0000133a | Max curr: 0x00ffffff
[ 1657.929965] sdhci: Host ctl2: 0x000000c8
[ 1657.929981] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x8f042208
[ 1657.929995] sdhci: ===========================================
[ 1657.930156] mmc0: req done (CMD19): 0: 00000900 00000000 00000000 00000000
[ 1657.930179] mmc0:     0 bytes transferred: -84

It shows we first have a data CRC error interrupt then a data transfer complete interrupt.
Then we got the !host->data case in sdhci_data_irq().

---
 drivers/mmc/host/sdhci.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/mmc/host/sdhci.c +0 -0
index 40e3551..2eb0e34 100644
@@ -2325,6 +2325,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                      }
              }
 

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2337

Quoted 10 lines
drivers/mmc/host/sdhci.c +10 -0
+             /*
+              * The "data complete" interrupt is possible to happen a bit
+              * later than CRC error and data end bit error interrupts
+              * separately for single block transfer or the last block of
+              * multiblock transfer. For this case, we DO NOT report the
+              * weird data interrupt event.
+              */
+             if ((intmask & SDHCI_INT_DATA_END) &&
+                 (host->mrq && host->mrq->data && host->mrq->data->error))
+                     return;

This could be generalized a bit more i.e. what about:

                /*
                 * After an error and before the the data circuit is reset in
                 * sdhci_tasklet_finish, we could get more interrupts, but we
                 * already have an error, so ignore them.
                 */
                if (host->mrq && host->mrq->data && host->mrq->data->error)
                        return;

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2341

Quoted 5 lines
drivers/mmc/host/sdhci.c +1 -0
+
              pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
                     mmc_hostname(host->mmc), (unsigned)intmask);
              sdhci_dumpregs(host);

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

#44 lore raw

PATCH 9/23 mmc: sdhci: fix incorrect get data interrupt during no data transfer

In reply to Adrian Hunter
Quoted 87 lines · Adrian Hunter
Quoted 73 lines · Dong Aisheng

Current code will report the wrong data interrupt got when no data operation in progress assumed by getting !host->data in sdhci_data_irq().

For a data command handling process, the driver will call sdhci_finish_data() and clear host->data in case any data error, then card finish_tasklet will do the rest controller reset work.

Before the tasklet got run, however, controllers may report the TC(Transfer Complete) interrupt (SDHCI_INT_DATA_END) a bit later than data CRC error and data end bit error interrupts for single block transfer or the last block of multiblock transfer.

Controller usually detects and generates data CRC/end bit error interrupts once one block on the bus is transferred completely. For single block transfer, since there's only one bock to transfer, the controller will report transfer complete interrupt as well, but until the data in controller FIFO has been successfully transferred to memory. The time gap of TC and CRC interrupt depends on the system busy state at that point and memory bus access speed.

So it is possible when TC interrupt generated, host->data is already equal to NULL due to cleared by former CRC/Data End Bit error which is reasonable.

Thus we DO NOT report the weird data interrupt event for this case.

Else we may easily see warning below during SD3.0 card manually tuning process (calling mmc_send_tuning() which is a single block transfer)
mmc0: Got data interrupt 0x00000002 even though no data operation was in progress

The detailed command log is as follows:

[ 1657.920983] mmc0: starting CMD19 arg 00000000 flags 00000035
[ 1657.921009] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[ 1657.921085] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00200001
[ 1657.921112] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00000002
[ 1657.921131] mmc0: Got data interrupt 0x00000002 even though no data operation was in progress.
[ 1657.929761] sdhci: =========== REGISTER DUMP (mmc0)===========
[ 1657.929780] sdhci: Sys addr: 0x3d5d6380 | Version:  0x00000002
[ 1657.929796] sdhci: Blk size: 0x00000040 | Blk cnt:  0x00000001
[ 1657.929814] sdhci: Argument: 0x00000000 | Trn mode: 0x00000013
[ 1657.929831] sdhci: Present:  0x01fd8008 | Host ctl: 0x00000023
[ 1657.929847] sdhci: Power:    0x00000002 | Blk gap:  0x00000080
[ 1657.929863] sdhci: Wake-up:  0x00000008 | Clock:    0x0000000f
[ 1657.929879] sdhci: Timeout:  0x0000000f | Int stat: 0x00000000
[ 1657.929896] sdhci: Int enab: 0x107f008b | Sig enab: 0x107f008b
[ 1657.929914] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000003
[ 1657.929932] sdhci: Caps:     0x07eb0000 | Caps_1:   0x00002007
[ 1657.929949] sdhci: Cmd:      0x0000133a | Max curr: 0x00ffffff
[ 1657.929965] sdhci: Host ctl2: 0x000000c8
[ 1657.929981] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x8f042208
[ 1657.929995] sdhci: ===========================================
[ 1657.930156] mmc0: req done (CMD19): 0: 00000900 00000000 00000000 00000000
[ 1657.930179] mmc0:     0 bytes transferred: -84

It shows we first have a data CRC error interrupt then a data transfer complete interrupt.
Then we got the !host->data case in sdhci_data_irq().

---
 drivers/mmc/host/sdhci.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/mmc/host/sdhci.c +0 -0
index 40e3551..2eb0e34 100644
@@ -2325,6 +2325,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 			}
 		}
 

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2337

Quoted 10 lines
drivers/mmc/host/sdhci.c +10 -0
+		/*
+		 * The "data complete" interrupt is possible to happen a bit
+		 * later than CRC error and data end bit error interrupts
+		 * separately for single block transfer or the last block of
+		 * multiblock transfer. For this case, we DO NOT report the
+		 * weird data interrupt event.
+		 */
+		if ((intmask & SDHCI_INT_DATA_END) &&
+		    (host->mrq && host->mrq->data && host->mrq->data->error))
+			return;

This could be generalized a bit more i.e. what about:

Quoted 8 lines
		/*
		 * After an error and before the the data circuit is reset in
		 * sdhci_tasklet_finish, we could get more interrupts, but we
		 * already have an error, so ignore them.
		 */
		if (host->mrq && host->mrq->data && host->mrq->data->error)
			return;

Sounds good to me.
If you wouldn't mind, i'd like to add a bit more:
/*
* After an error and before the data circuit is reset in
* sdhci_tasklet_finish, we could get more interrupts
* e.g. "data complete" interrupt, but we already have
* an error, so ignore them.
*/

Regards
Dong Aisheng

Quoted 6 lines
Quoted 5 lines
drivers/mmc/host/sdhci.c +1 -0
+
 		pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
 		       mmc_hostname(host->mmc), (unsigned)intmask);
 		sdhci_dumpregs(host);
maintainer
#45 lore raw

PATCH 9/23 mmc: sdhci: fix incorrect get data interrupt during no data transfer

Quoted 97 lines · Dong Aisheng
Quoted 87 lines · Adrian Hunter
Quoted 73 lines · Dong Aisheng

Current code will report the wrong data interrupt got when no data operation in progress assumed by getting !host->data in sdhci_data_irq().

For a data command handling process, the driver will call sdhci_finish_data() and clear host->data in case any data error, then card finish_tasklet will do the rest controller reset work.

Before the tasklet got run, however, controllers may report the TC(Transfer Complete) interrupt (SDHCI_INT_DATA_END) a bit later than data CRC error and data end bit error interrupts for single block transfer or the last block of multiblock transfer.

Controller usually detects and generates data CRC/end bit error interrupts once one block on the bus is transferred completely. For single block transfer, since there's only one bock to transfer, the controller will report transfer complete interrupt as well, but until the data in controller FIFO has been successfully transferred to memory. The time gap of TC and CRC interrupt depends on the system busy state at that point and memory bus access speed.

So it is possible when TC interrupt generated, host->data is already equal to NULL due to cleared by former CRC/Data End Bit error which is reasonable.

Thus we DO NOT report the weird data interrupt event for this case.

Else we may easily see warning below during SD3.0 card manually tuning process (calling mmc_send_tuning() which is a single block transfer)
mmc0: Got data interrupt 0x00000002 even though no data operation was in progress

The detailed command log is as follows:

[ 1657.920983] mmc0: starting CMD19 arg 00000000 flags 00000035
[ 1657.921009] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[ 1657.921085] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00200001
[ 1657.921112] sdhci [sdhci_irq()]: *** mmc0 got interrupt: 0x00000002
[ 1657.921131] mmc0: Got data interrupt 0x00000002 even though no data operation was in progress.
[ 1657.929761] sdhci: =========== REGISTER DUMP (mmc0)===========
[ 1657.929780] sdhci: Sys addr: 0x3d5d6380 | Version:  0x00000002
[ 1657.929796] sdhci: Blk size: 0x00000040 | Blk cnt:  0x00000001
[ 1657.929814] sdhci: Argument: 0x00000000 | Trn mode: 0x00000013
[ 1657.929831] sdhci: Present:  0x01fd8008 | Host ctl: 0x00000023
[ 1657.929847] sdhci: Power:    0x00000002 | Blk gap:  0x00000080
[ 1657.929863] sdhci: Wake-up:  0x00000008 | Clock:    0x0000000f
[ 1657.929879] sdhci: Timeout:  0x0000000f | Int stat: 0x00000000
[ 1657.929896] sdhci: Int enab: 0x107f008b | Sig enab: 0x107f008b
[ 1657.929914] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000003
[ 1657.929932] sdhci: Caps:     0x07eb0000 | Caps_1:   0x00002007
[ 1657.929949] sdhci: Cmd:      0x0000133a | Max curr: 0x00ffffff
[ 1657.929965] sdhci: Host ctl2: 0x000000c8
[ 1657.929981] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x8f042208
[ 1657.929995] sdhci: ===========================================
[ 1657.930156] mmc0: req done (CMD19): 0: 00000900 00000000 00000000 00000000
[ 1657.930179] mmc0:     0 bytes transferred: -84

It shows we first have a data CRC error interrupt then a data transfer complete interrupt.
Then we got the !host->data case in sdhci_data_irq().

---
 drivers/mmc/host/sdhci.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/mmc/host/sdhci.c +0 -0
index 40e3551..2eb0e34 100644
@@ -2325,6 +2325,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 			}
 		}
 

drivers/mmc/host/sdhci.c static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) · line 2337

Quoted 10 lines
drivers/mmc/host/sdhci.c +10 -0
+		/*
+		 * The "data complete" interrupt is possible to happen a bit
+		 * later than CRC error and data end bit error interrupts
+		 * separately for single block transfer or the last block of
+		 * multiblock transfer. For this case, we DO NOT report the
+		 * weird data interrupt event.
+		 */
+		if ((intmask & SDHCI_INT_DATA_END) &&
+		    (host->mrq && host->mrq->data && host->mrq->data->error))
+			return;

This could be generalized a bit more i.e. what about:

Quoted 8 lines
		/*
		 * After an error and before the the data circuit is reset in
		 * sdhci_tasklet_finish, we could get more interrupts, but we
		 * already have an error, so ignore them.
		 */
		if (host->mrq && host->mrq->data && host->mrq->data->error)
			return;
Quoted 9 lines

Sounds good to me.
If you wouldn't mind, i'd like to add a bit more:
/*
* After an error and before the data circuit is reset in
* sdhci_tasklet_finish, we could get more interrupts
* e.g. "data complete" interrupt, but we already have
* an error, so ignore them.
*/

Fine by me

#46 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

In reply to Dong Aisheng

During card detection process, mmc core may sends commands to detect if card is still exist in mmc_rescan for removable card which may trigger mmc retuning process after a bit time of runtime pm suspend.
Obviously this retuning process is meaningless for card remove case, so we disable mmc_retune in mmc_detect_change() for it. For card insert case, the mmc_retune will be enabled normally in its card initialization process later in mmc_execute_tuning(). So disable it at first has no side effection.

---
 drivers/mmc/core/core.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/core.c +1 -0
index 52bfaf0..76d0802 100644
@@ -1888,6 +1888,7 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
 		pm_wakeup_event(mmc_dev(host), 5000);
 
 	host->detect_change = 1;
+	mmc_retune_disable(host);
 	mmc_schedule_delayed_work(&host->detect, delay);
 }
 
Signature · 1 line
1.9.1
maintainer
#47 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 9 lines · Dong Aisheng

During card detection process, mmc core may sends commands to detect if card is still exist in mmc_rescan for removable card which may trigger mmc retuning process after a bit time of runtime pm suspend.
Obviously this retuning process is meaningless for card remove case, so we disable mmc_retune in mmc_detect_change() for it. For card insert case, the mmc_retune will be enabled normally in its card initialization process later in mmc_execute_tuning(). So disable it at first has no side effection.

We don't assume that the card has been removed, which is why we send commands to find out if it is still there. If it is still there, this change will have incorrectly disabled re-tuning.

Do you have an actual problem with the way it works now?

Quoted 20 lines
---
 drivers/mmc/core/core.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/core.c +1 -0
index 52bfaf0..76d0802 100644
@@ -1888,6 +1888,7 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
 		pm_wakeup_event(mmc_dev(host), 5000);
 
 	host->detect_change = 1;
+	mmc_retune_disable(host);
 	mmc_schedule_delayed_work(&host->detect, delay);
 }
 
#48 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 11 lines · Adrian Hunter
Quoted 9 lines · Dong Aisheng

During card detection process, mmc core may sends commands to detect if card is still exist in mmc_rescan for removable card which may trigger mmc retuning process after a bit time of runtime pm suspend.
Obviously this retuning process is meaningless for card remove case, so we disable mmc_retune in mmc_detect_change() for it. For card insert case, the mmc_retune will be enabled normally in its card initialization process later in mmc_execute_tuning(). So disable it at first has no side effection.

Quoted 4 lines

We don't assume that the card has been removed, which is why we send commands to find out if it is still there. If it is still there, this change will have incorrectly disabled re-tuning.

Do you mean the 'fake' card remove interrupt like caused by glitch? Yes, if that the card is still exist and re-tuning is wrongly disabled.

So we could re-enable re-tuning for this special case? Something like:

drivers/mmc/core/core.c +2 -0
index 41b1e76..e1990a8 100644
@@ -2607,6 +2607,8 @@ void mmc_rescan(struct work_struct *work)
 
        /* if there still is a card present, stop here */
        if (host->bus_ops != NULL) {
+               if (tuning_is_enabled_before())
+                       mmc_retune_enable(host);
                mmc_bus_put(host);
                goto out;
        }
Quoted 2 lines

Do you have an actual problem with the way it works now?

No actual problems now.
I just observe a lot tuning commands keep sending although the card is already removed which seems a bit meaningless.
And most tuning execution process is executed with sin_lock_irqsave, i'm not sure if the mass tuning commands may affect the system when CPU is busy. What do you think?

Regards
Dong Aisheng

Quoted 21 lines
Quoted 20 lines
---
 drivers/mmc/core/core.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/core.c +1 -0
index 52bfaf0..76d0802 100644
@@ -1888,6 +1888,7 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
              pm_wakeup_event(mmc_dev(host), 5000);
 
      host->detect_change = 1;
+     mmc_retune_disable(host);
      mmc_schedule_delayed_work(&host->detect, delay);
 }
 
maintainer
#49 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 12 lines · Dong Aisheng
Quoted 11 lines · Adrian Hunter
Quoted 9 lines · Dong Aisheng

During card detection process, mmc core may sends commands to detect if card is still exist in mmc_rescan for removable card which may trigger mmc retuning process after a bit time of runtime pm suspend.
Obviously this retuning process is meaningless for card remove case, so we disable mmc_retune in mmc_detect_change() for it. For card insert case, the mmc_retune will be enabled normally in its card initialization process later in mmc_execute_tuning(). So disable it at first has no side effection.

Quoted 6 lines
Quoted 4 lines

We don't assume that the card has been removed, which is why we send commands to find out if it is still there. If it is still there, this change will have incorrectly disabled re-tuning.

Do you mean the 'fake' card remove interrupt like caused by glitch?

Sure

Quoted 19 lines

Yes, if that the card is still exist and re-tuning is wrongly disabled.

So we could re-enable re-tuning for this special case? Something like:

drivers/mmc/core/core.c +2 -0
index 41b1e76..e1990a8 100644
@@ -2607,6 +2607,8 @@ void mmc_rescan(struct work_struct *work)
 
        /* if there still is a card present, stop here */
        if (host->bus_ops != NULL) {
+               if (tuning_is_enabled_before())
+                       mmc_retune_enable(host);
                mmc_bus_put(host);
                goto out;
        }
Quoted 4 lines
Quoted 2 lines

Do you have an actual problem with the way it works now?

No actual problems now.

So let's not spend time on it.

Quoted 5 lines

I just observe a lot tuning commands keep sending although the card is already removed which seems a bit meaningless.
And most tuning execution process is executed with sin_lock_irqsave, i'm not sure if the mass tuning commands may affect the system when CPU is busy. What do you think?

sdhci spin lock is unlocked while waiting for tuning commands.

Quoted 26 lines

Regards
Dong Aisheng

Quoted 21 lines
Quoted 20 lines
---
 drivers/mmc/core/core.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/core.c +1 -0
index 52bfaf0..76d0802 100644
@@ -1888,6 +1888,7 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
              pm_wakeup_event(mmc_dev(host), 5000);
 
      host->detect_change = 1;
+     mmc_retune_disable(host);
      mmc_schedule_delayed_work(&host->detect, delay);
 }
 
#50 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 48 lines · Adrian Hunter
Quoted 12 lines · Dong Aisheng
Quoted 11 lines · Adrian Hunter
Quoted 9 lines · Dong Aisheng

During card detection process, mmc core may sends commands to detect if card is still exist in mmc_rescan for removable card which may trigger mmc retuning process after a bit time of runtime pm suspend.
Obviously this retuning process is meaningless for card remove case, so we disable mmc_retune in mmc_detect_change() for it. For card insert case, the mmc_retune will be enabled normally in its card initialization process later in mmc_execute_tuning(). So disable it at first has no side effection.

Quoted 6 lines
Quoted 4 lines

We don't assume that the card has been removed, which is why we send commands to find out if it is still there. If it is still there, this change will have incorrectly disabled re-tuning.

Do you mean the 'fake' card remove interrupt like caused by glitch?

Sure

Quoted 19 lines

Yes, if that the card is still exist and re-tuning is wrongly disabled.

So we could re-enable re-tuning for this special case? Something like:

drivers/mmc/core/core.c +2 -0
index 41b1e76..e1990a8 100644
@@ -2607,6 +2607,8 @@ void mmc_rescan(struct work_struct *work)
 
        /* if there still is a card present, stop here */
        if (host->bus_ops != NULL) {
+               if (tuning_is_enabled_before())
+                       mmc_retune_enable(host);
                mmc_bus_put(host);
                goto out;
        }
Quoted 4 lines
Quoted 2 lines

Do you have an actual problem with the way it works now?

No actual problems now.

So let's not spend time on it.

Quoted 8 lines
Quoted 5 lines

I just observe a lot tuning commands keep sending although the card is already removed which seems a bit meaningless.
And most tuning execution process is executed with sin_lock_irqsave, i'm not sure if the mass tuning commands may affect the system when CPU is busy. What do you think?

sdhci spin lock is unlocked while waiting for tuning commands.

It's 40 commands continuously and only cmd transfer time is unlocked.

Hmm.. I can't sure it's no affection.
e.g we did have customers reporting cd plug in/out causing jitters when system is busy playing audio or video.
Maybe we need to do those tests.

Anyway, what's your point to keep sending tuning commands after card is already removed?

Regards
Dong Aisheng

Quoted 31 lines
Quoted 26 lines

Regards
Dong Aisheng

Quoted 21 lines
Quoted 20 lines
---
 drivers/mmc/core/core.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/core.c +1 -0
index 52bfaf0..76d0802 100644
@@ -1888,6 +1888,7 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
              pm_wakeup_event(mmc_dev(host), 5000);
 
      host->detect_change = 1;
+     mmc_retune_disable(host);
      mmc_schedule_delayed_work(&host->detect, delay);
 }
 

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

maintainer
#51 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 55 lines · Dong Aisheng
Quoted 54 lines · Adrian Hunter
Quoted 12 lines · Dong Aisheng
Quoted 11 lines · Adrian Hunter
Quoted 9 lines · Dong Aisheng

During card detection process, mmc core may sends commands to detect if card is still exist in mmc_rescan for removable card which may trigger mmc retuning process after a bit time of runtime pm suspend.
Obviously this retuning process is meaningless for card remove case, so we disable mmc_retune in mmc_detect_change() for it. For card insert case, the mmc_retune will be enabled normally in its card initialization process later in mmc_execute_tuning(). So disable it at first has no side effection.

Quoted 6 lines
Quoted 4 lines

We don't assume that the card has been removed, which is why we send commands to find out if it is still there. If it is still there, this change will have incorrectly disabled re-tuning.

Do you mean the 'fake' card remove interrupt like caused by glitch?

Sure

Quoted 19 lines

Yes, if that the card is still exist and re-tuning is wrongly disabled.

So we could re-enable re-tuning for this special case? Something like:

drivers/mmc/core/core.c +2 -0
index 41b1e76..e1990a8 100644
@@ -2607,6 +2607,8 @@ void mmc_rescan(struct work_struct *work)
 
        /* if there still is a card present, stop here */
        if (host->bus_ops != NULL) {
+               if (tuning_is_enabled_before())
+                       mmc_retune_enable(host);
                mmc_bus_put(host);
                goto out;
        }
Quoted 4 lines
Quoted 2 lines

Do you have an actual problem with the way it works now?

No actual problems now.

So let's not spend time on it.

Quoted 5 lines

I just observe a lot tuning commands keep sending although the card is already removed which seems a bit meaningless.
And most tuning execution process is executed with sin_lock_irqsave, i'm not sure if the mass tuning commands may affect the system when CPU is busy. What do you think?

Quoted 4 lines
Quoted 2 lines

sdhci spin lock is unlocked while waiting for tuning commands.

It's 40 commands continuously and only cmd transfer time is unlocked.

Not for sdhci_execute_tuning() it's not. Only one command is sent. Currently we don't even send the CMD13 because we check card detect first. I added prints for sdhci_execute_tuning and got this:

[  255.536326] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000080
[  255.743653] mmc1: starting CMD13 arg 59b40000 flags 00000195
[  255.750093] mmc1: sdhci_execute_tuning
[  255.754358] mmc1: sdhci_execute_tuning: send command
[  255.809638] sdhci: Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock
[  255.824810] mmc1: req failed (CMD13): -123, retrying...
[  255.832766] mmc1: req failed (CMD13): -123, retrying...
[  255.840722] mmc1: req failed (CMD13): -123, retrying...
[  255.848672] mmc1: req done (CMD13): -123: 00000000 00000000 00000000 00000000
[  255.856773] mmc1: card remove detected
[  255.861056] mmc1: card 59b4 removed
[  255.872872] mmc1: clock 0Hz busmode 2 powermode 0 cs 0 Vdd 0 width 0 timing 0
Quoted 8 lines

Hmm.. I can't sure it's no affection.
e.g we did have customers reporting cd plug in/out causing jitters when system is busy playing audio or video.
Maybe we need to do those tests.

Anyway, what's your point to keep sending tuning commands after card is already removed?

Seems like a problem for your driver not the core. Why not check card detect after the first error in esdhc_executing_tuning().

Quoted 36 lines

Regards
Dong Aisheng

Quoted 31 lines
Quoted 26 lines

Regards
Dong Aisheng

Quoted 21 lines
Quoted 20 lines
---
 drivers/mmc/core/core.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/core.c +1 -0
index 52bfaf0..76d0802 100644
@@ -1888,6 +1888,7 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
              pm_wakeup_event(mmc_dev(host), 5000);
 
      host->detect_change = 1;
+     mmc_retune_disable(host);
      mmc_schedule_delayed_work(&host->detect, delay);
 }
 

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

#52 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 56 lines · Adrian Hunter
Quoted 55 lines · Dong Aisheng
Quoted 54 lines · Adrian Hunter
Quoted 12 lines · Dong Aisheng
Quoted 11 lines · Adrian Hunter
Quoted 9 lines · Dong Aisheng

During card detection process, mmc core may sends commands to detect if card is still exist in mmc_rescan for removable card which may trigger mmc retuning process after a bit time of runtime pm suspend.
Obviously this retuning process is meaningless for card remove case, so we disable mmc_retune in mmc_detect_change() for it. For card insert case, the mmc_retune will be enabled normally in its card initialization process later in mmc_execute_tuning(). So disable it at first has no side effection.

Quoted 6 lines
Quoted 4 lines

We don't assume that the card has been removed, which is why we send commands to find out if it is still there. If it is still there, this change will have incorrectly disabled re-tuning.

Do you mean the 'fake' card remove interrupt like caused by glitch?

Sure

Quoted 19 lines

Yes, if that the card is still exist and re-tuning is wrongly disabled.

So we could re-enable re-tuning for this special case? Something like:

drivers/mmc/core/core.c +2 -0
index 41b1e76..e1990a8 100644
@@ -2607,6 +2607,8 @@ void mmc_rescan(struct work_struct *work)
 
        /* if there still is a card present, stop here */
        if (host->bus_ops != NULL) {
+               if (tuning_is_enabled_before())
+                       mmc_retune_enable(host);
                mmc_bus_put(host);
                goto out;
        }
Quoted 4 lines
Quoted 2 lines

Do you have an actual problem with the way it works now?

No actual problems now.

So let's not spend time on it.

Quoted 5 lines

I just observe a lot tuning commands keep sending although the card is already removed which seems a bit meaningless.
And most tuning execution process is executed with sin_lock_irqsave, i'm not sure if the mass tuning commands may affect the system when CPU is busy. What do you think?

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

sdhci spin lock is unlocked while waiting for tuning commands.

It's 40 commands continuously and only cmd transfer time is unlocked.

Not for sdhci_execute_tuning() it's not. Only one command is sent.

IMX case is different.
Please see below log on MX6SX SDB.

For IMX6SX SDB:
root at imx6qdlsolo:~# [ 39.649322] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000

[   39.661452] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 6
[   39.668295] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[   39.679146] mmc1: starting CMD13 arg e6240000 flags 00000195
[   39.684908] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.693359] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.701654] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.709717] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.717718] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.725057] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.734818] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.744197] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.752316] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.760363] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.778296] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.788348] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.795731] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.803932] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.811865] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.819801] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.827710] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.835046] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.843384] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.851293] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.859209] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.867111] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.874450] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.882725] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.890610] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.898615] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.905953] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.913821] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.922283] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.930177] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.938082] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.945676] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.953696] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.961914] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.969792] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.977682] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.985018] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   39.992898] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   40.001107] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   40.009125] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000020
[   40.018058] mmc1: req failed (CMD13): -123, retrying...
[   40.023435] mmc1: req failed (CMD13): -123, retrying...
[   40.029614] mmc1: req failed (CMD13): -123, retrying...
[   40.034981] mmc1: req done (CMD13): -123: 00000000 00000000 00000000 00000000
[   40.042891] mmc1: card remove detected
[   40.047446] mmc1: card e624 removed
[   40.208083] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[   40.222000] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 6
[   40.228813] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[   40.238175] mmc1: clock 0Hz busmode 2 powermode 0 cs 0 Vdd 0 width 1 timing 0
[   40.247693] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 0

And IMX6DL ARD is even worser due to it's using common mmc_send_tuning() function.
root at imx6qdlsolo:~#
root at imx6qdlsolo:~# [ 129.462564] sysrq: SysRq : Changing Loglevel

[  129.466902] sysrq: Loglevel set to 8
[  131.616078] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  131.625311] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 6
[  131.632133] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  131.642121] mmc0: starting CMD13 arg 59b40000 flags 00000195
[  131.648925] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x0 ESDHC_TUNE_CTRL_STATUS 0x0
[  131.657818] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.663518] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.670835] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.678069] mmc0:     0 bytes transferred: 0
[  131.683433] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x1 ESDHC_TUNE_CTRL_STATUS 0x1000100
[  131.692940] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.698709] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.705625] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.712854] mmc0:     0 bytes transferred: 0
[  131.718251] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x2 ESDHC_TUNE_CTRL_STATUS 0x2000200
[  131.727375] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.733074] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.740043] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.747256] mmc0:     0 bytes transferred: 0
[  131.752611] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x3 ESDHC_TUNE_CTRL_STATUS 0x3000300
[  131.761751] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.767506] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.774419] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.781642] mmc0:     0 bytes transferred: 0
[  131.787035] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x4 ESDHC_TUNE_CTRL_STATUS 0x4000400
[  131.796156] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.801851] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.808832] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.816037] mmc0:     0 bytes transferred: 0
[  131.821389] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x5 ESDHC_TUNE_CTRL_STATUS 0x5000500
[  131.830503] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.836254] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.843162] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.850385] mmc0:     0 bytes transferred: 0
[  131.855737] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x6 ESDHC_TUNE_CTRL_STATUS 0x6000600
[  131.864863] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.870613] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.877565] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.884728] mmc0:     0 bytes transferred: 0
[  131.890133] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x7 ESDHC_TUNE_CTRL_STATUS 0x7000700
[  131.899247] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.904939] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.911903] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.919122] mmc0:     0 bytes transferred: 0
[  131.924474] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x8 ESDHC_TUNE_CTRL_STATUS 0x8000800
[  131.933591] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.939340] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.946300] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.953464] mmc0:     0 bytes transferred: 0
[  131.958869] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x9 ESDHC_TUNE_CTRL_STATUS 0x9000900
[  131.967965] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.973657] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.980621] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  131.987831] mmc0:     0 bytes transferred: 0
[  131.993183] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0xa ESDHC_TUNE_CTRL_STATUS 0xa000a00
[  132.002295] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.008039] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.014945] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.022167] mmc0:     0 bytes transferred: 0
[  132.027555] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0xb ESDHC_TUNE_CTRL_STATUS 0xb000b00
[  132.036682] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.042376] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.049341] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.056555] mmc0:     0 bytes transferred: 0
[  132.061905] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0xc ESDHC_TUNE_CTRL_STATUS 0xc000c00
[  132.071020] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.076760] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.083663] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.090886] mmc0:     0 bytes transferred: 0
[  132.096237] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0xd ESDHC_TUNE_CTRL_STATUS 0xd000d00
[  132.105233] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.110981] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.117911] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.125072] mmc0:     0 bytes transferred: 0
[  132.130494] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0xe ESDHC_TUNE_CTRL_STATUS 0xe000e00
[  132.139538] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.145227] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.152185] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.159403] mmc0:     0 bytes transferred: 0
[  132.164755] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0xf ESDHC_TUNE_CTRL_STATUS 0xf000f00
[  132.173884] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.179622] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.186579] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.193743] mmc0:     0 bytes transferred: 0
[  132.199157] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x10 ESDHC_TUNE_CTRL_STATUS 0x10001000
[  132.208432] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.214124] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.221088] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.228308] mmc0:     0 bytes transferred: 0
[  132.233658] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x11 ESDHC_TUNE_CTRL_STATUS 0x11001100
[  132.242930] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.248677] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.255584] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.262803] mmc0:     0 bytes transferred: 0
[  132.268190] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x12 ESDHC_TUNE_CTRL_STATUS 0x12001200
[  132.277483] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.283184] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.290171] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.297385] mmc0:     0 bytes transferred: 0
[  132.302737] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x13 ESDHC_TUNE_CTRL_STATUS 0x13001300
[  132.312043] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.317786] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.324697] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.331920] mmc0:     0 bytes transferred: 0
[  132.337308] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x14 ESDHC_TUNE_CTRL_STATUS 0x14001400
[  132.346604] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.352297] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.359271] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.366482] mmc0:     0 bytes transferred: 0
[  132.371833] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x15 ESDHC_TUNE_CTRL_STATUS 0x15001500
[  132.381125] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.386867] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.393773] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.400990] mmc0:     0 bytes transferred: 0
[  132.406344] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x16 ESDHC_TUNE_CTRL_STATUS 0x16001600
[  132.415517] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.421265] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.428214] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.435375] mmc0:     0 bytes transferred: 0
[  132.440827] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x17 ESDHC_TUNE_CTRL_STATUS 0x17001700
[  132.450046] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.455736] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.462696] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.469914] mmc0:     0 bytes transferred: 0
[  132.475264] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x18 ESDHC_TUNE_CTRL_STATUS 0x18001800
[  132.484554] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.490299] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.497255] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.504419] mmc0:     0 bytes transferred: 0
[  132.509826] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x19 ESDHC_TUNE_CTRL_STATUS 0x19001900
[  132.519096] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.524786] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.531751] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.538971] mmc0:     0 bytes transferred: 0
[  132.544322] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x1a ESDHC_TUNE_CTRL_STATUS 0x1a001a00
[  132.553609] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.559357] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.566325] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.573488] mmc0:     0 bytes transferred: 0
[  132.578898] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x1b ESDHC_TUNE_CTRL_STATUS 0x1b001b00
[  132.588168] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.593861] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.600820] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.608037] mmc0:     0 bytes transferred: 0
[  132.613390] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x1c ESDHC_TUNE_CTRL_STATUS 0x1c001c00
[  132.622680] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.628428] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.635334] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.642556] mmc0:     0 bytes transferred: 0
[  132.647945] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x1d ESDHC_TUNE_CTRL_STATUS 0x1d001d00
[  132.657231] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.662930] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.669892] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.677099] mmc0:     0 bytes transferred: 0
[  132.682450] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x1e ESDHC_TUNE_CTRL_STATUS 0x1e001e00
[  132.691737] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.697490] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.704403] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.711624] mmc0:     0 bytes transferred: 0
[  132.717010] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x1f ESDHC_TUNE_CTRL_STATUS 0x1f001f00
[  132.726301] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.731998] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.738960] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.746169] mmc0:     0 bytes transferred: 0
[  132.751525] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x20 ESDHC_TUNE_CTRL_STATUS 0x20002000
[  132.760817] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.766577] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.773491] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.780714] mmc0:     0 bytes transferred: 0
[  132.786069] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x21 ESDHC_TUNE_CTRL_STATUS 0x21002100
[  132.795243] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.800992] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.807923] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.815084] mmc0:     0 bytes transferred: 0
[  132.820546] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x22 ESDHC_TUNE_CTRL_STATUS 0x22002200
[  132.829787] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.835477] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.842441] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.849663] mmc0:     0 bytes transferred: 0
[  132.855016] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x23 ESDHC_TUNE_CTRL_STATUS 0x23002300
[  132.864305] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.870056] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.877015] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.884179] mmc0:     0 bytes transferred: 0
[  132.889584] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x24 ESDHC_TUNE_CTRL_STATUS 0x24002400
[  132.898860] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.904551] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.911512] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.918731] mmc0:     0 bytes transferred: 0
[  132.924080] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x25 ESDHC_TUNE_CTRL_STATUS 0x25002500
[  132.933368] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.939114] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.946071] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.953235] mmc0:     0 bytes transferred: 0
[  132.958640] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x26 ESDHC_TUNE_CTRL_STATUS 0x26002600
[  132.967924] mmc0: starting CMD19 arg 00000000 flags 00000035
[  132.973614] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  132.980584] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  132.987796] mmc0:     0 bytes transferred: 0
[  132.993147] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x27 ESDHC_TUNE_CTRL_STATUS 0x27002700
[  133.002433] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.008181] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.015089] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.022310] mmc0:     0 bytes transferred: 0
[  133.027699] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x28 ESDHC_TUNE_CTRL_STATUS 0x28002800
[  133.037014] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.042712] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.049679] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.056890] mmc0:     0 bytes transferred: 0
[  133.062237] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x29 ESDHC_TUNE_CTRL_STATUS 0x29002900
[  133.071525] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.077267] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.084172] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.091392] mmc0:     0 bytes transferred: 0
[  133.096746] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x2a ESDHC_TUNE_CTRL_STATUS 0x2a002a00
[  133.106021] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.111714] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.118679] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.125889] mmc0:     0 bytes transferred: 0
[  133.131241] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x2b ESDHC_TUNE_CTRL_STATUS 0x2b002b00
[  133.140530] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.146272] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.153184] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.160409] mmc0:     0 bytes transferred: 0
[  133.165762] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x2c ESDHC_TUNE_CTRL_STATUS 0x2c002c00
[  133.175059] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.180798] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.187759] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.194922] mmc0:     0 bytes transferred: 0
[  133.200329] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x2d ESDHC_TUNE_CTRL_STATUS 0x2d002d00
[  133.209600] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.215291] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.222254] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.229474] mmc0:     0 bytes transferred: 0
[  133.234823] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x2e ESDHC_TUNE_CTRL_STATUS 0x2e002e00
[  133.244124] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.249865] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.256828] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.263991] mmc0:     0 bytes transferred: 0
[  133.269395] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x2f ESDHC_TUNE_CTRL_STATUS 0x2f002f00
[  133.278668] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.284361] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.291340] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.298566] mmc0:     0 bytes transferred: 0
[  133.303922] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x30 ESDHC_TUNE_CTRL_STATUS 0x30003000
[  133.313213] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.318975] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.325939] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.333103] mmc0:     0 bytes transferred: 0
[  133.338506] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x31 ESDHC_TUNE_CTRL_STATUS 0x31003100
[  133.347792] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.353484] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.360450] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.367661] mmc0:     0 bytes transferred: 0
[  133.373010] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x32 ESDHC_TUNE_CTRL_STATUS 0x32003200
[  133.382312] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.388059] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.394965] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.402178] mmc0:     0 bytes transferred: 0
[  133.407573] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x33 ESDHC_TUNE_CTRL_STATUS 0x33003300
[  133.416864] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.422560] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.429523] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.436727] mmc0:     0 bytes transferred: 0
[  133.442079] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x34 ESDHC_TUNE_CTRL_STATUS 0x34003400
[  133.451364] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.457116] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.464027] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.471251] mmc0:     0 bytes transferred: 0
[  133.476608] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x35 ESDHC_TUNE_CTRL_STATUS 0x35003500
[  133.485780] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.491574] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.498529] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.505693] mmc0:     0 bytes transferred: 0
[  133.511177] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x36 ESDHC_TUNE_CTRL_STATUS 0x36003600
[  133.520407] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.526149] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.533061] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.540285] mmc0:     0 bytes transferred: 0
[  133.545638] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x37 ESDHC_TUNE_CTRL_STATUS 0x37003700
[  133.554931] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.560681] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.567639] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.574802] mmc0:     0 bytes transferred: 0
[  133.580206] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x38 ESDHC_TUNE_CTRL_STATUS 0x38003800
[  133.589493] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.595185] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.602144] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.609359] mmc0:     0 bytes transferred: 0
[  133.614712] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x39 ESDHC_TUNE_CTRL_STATUS 0x39003900
[  133.624000] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.629754] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.636727] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.643891] mmc0:     0 bytes transferred: 0
[  133.649293] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x3a ESDHC_TUNE_CTRL_STATUS 0x3a003a00
[  133.658567] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.664259] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.671225] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.678445] mmc0:     0 bytes transferred: 0
[  133.683798] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x3b ESDHC_TUNE_CTRL_STATUS 0x3b003b00
[  133.693086] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.698824] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.705728] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.712950] mmc0:     0 bytes transferred: 0
[  133.718336] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x3c ESDHC_TUNE_CTRL_STATUS 0x3c003c00
[  133.727625] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.733322] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.740287] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.747498] mmc0:     0 bytes transferred: 0
[  133.752851] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x3d ESDHC_TUNE_CTRL_STATUS 0x3d003d00
[  133.762139] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.767913] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.774827] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.782051] mmc0:     0 bytes transferred: 0
[  133.787438] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x3e ESDHC_TUNE_CTRL_STATUS 0x3e003e00
[  133.796727] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.802421] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.809397] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.816617] mmc0:     0 bytes transferred: 0
[  133.821967] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x3f ESDHC_TUNE_CTRL_STATUS 0x3f003f00
[  133.831258] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.837001] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.843909] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.851122] mmc0:     0 bytes transferred: 0
[  133.856476] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x40 ESDHC_TUNE_CTRL_STATUS 0x40004000
[  133.865647] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.871395] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.878332] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.885495] mmc0:     0 bytes transferred: 0
[  133.890922] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x41 ESDHC_TUNE_CTRL_STATUS 0x41004100
[  133.900145] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.905886] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.912795] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.920018] mmc0:     0 bytes transferred: 0
[  133.925371] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x42 ESDHC_TUNE_CTRL_STATUS 0x42004200
[  133.934662] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.940411] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.947371] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.954536] mmc0:     0 bytes transferred: 0
[  133.959943] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x43 ESDHC_TUNE_CTRL_STATUS 0x43004300
[  133.969217] mmc0: starting CMD19 arg 00000000 flags 00000035
[  133.974908] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  133.981871] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  133.989092] mmc0:     0 bytes transferred: 0
[  133.994441] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x44 ESDHC_TUNE_CTRL_STATUS 0x44004400
[  134.003714] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.009465] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.016434] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.023598] mmc0:     0 bytes transferred: 0
[  134.029006] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x45 ESDHC_TUNE_CTRL_STATUS 0x45004500
[  134.038294] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.043984] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.050936] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.058150] mmc0:     0 bytes transferred: 0
[  134.063501] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x46 ESDHC_TUNE_CTRL_STATUS 0x46004600
[  134.072790] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.078541] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.085447] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.092664] mmc0:     0 bytes transferred: 0
[  134.098068] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x47 ESDHC_TUNE_CTRL_STATUS 0x47004700
[  134.107355] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.113053] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.120021] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.127231] mmc0:     0 bytes transferred: 0
[  134.132580] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x48 ESDHC_TUNE_CTRL_STATUS 0x48004800
[  134.141866] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.147617] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.154527] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.161749] mmc0:     0 bytes transferred: 0
[  134.167137] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x49 ESDHC_TUNE_CTRL_STATUS 0x49004900
[  134.176430] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.182129] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.189101] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.196310] mmc0:     0 bytes transferred: 0
[  134.201660] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x4a ESDHC_TUNE_CTRL_STATUS 0x4a004a00
[  134.210944] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.216683] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.223586] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.230807] mmc0:     0 bytes transferred: 0
[  134.236162] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x4b ESDHC_TUNE_CTRL_STATUS 0x4b004b00
[  134.245335] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.251076] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.258013] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.265177] mmc0:     0 bytes transferred: 0
[  134.270609] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x4c ESDHC_TUNE_CTRL_STATUS 0x4c004c00
[  134.279849] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.285539] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.292509] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.299730] mmc0:     0 bytes transferred: 0
[  134.305087] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x4d ESDHC_TUNE_CTRL_STATUS 0x4d004d00
[  134.314397] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.320147] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.327115] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.334281] mmc0:     0 bytes transferred: 0
[  134.339692] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x4e ESDHC_TUNE_CTRL_STATUS 0x4e004e00
[  134.348979] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.354671] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.361642] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.368858] mmc0:     0 bytes transferred: 0
[  134.374209] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x4f ESDHC_TUNE_CTRL_STATUS 0x4f004f00
[  134.383503] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.389253] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.396215] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.403378] mmc0:     0 bytes transferred: 0
[  134.408785] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x50 ESDHC_TUNE_CTRL_STATUS 0x50005000
[  134.418057] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.423747] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.430706] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.437930] mmc0:     0 bytes transferred: 0
[  134.443285] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x51 ESDHC_TUNE_CTRL_STATUS 0x51005100
[  134.452586] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.458348] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.465259] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.472479] mmc0:     0 bytes transferred: 0
[  134.477873] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x52 ESDHC_TUNE_CTRL_STATUS 0x52005200
[  134.487159] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.492855] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.499830] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.507051] mmc0:     0 bytes transferred: 0
[  134.512400] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x53 ESDHC_TUNE_CTRL_STATUS 0x53005300
[  134.521693] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.527433] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.534342] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.541563] mmc0:     0 bytes transferred: 0
[  134.546952] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x54 ESDHC_TUNE_CTRL_STATUS 0x54005400
[  134.556236] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.561935] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.568899] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.576107] mmc0:     0 bytes transferred: 0
[  134.581455] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x55 ESDHC_TUNE_CTRL_STATUS 0x55005500
[  134.590757] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.596497] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.603405] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.610625] mmc0:     0 bytes transferred: 0
[  134.615978] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x56 ESDHC_TUNE_CTRL_STATUS 0x56005600
[  134.625152] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.630900] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.637831] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.644992] mmc0:     0 bytes transferred: 0
[  134.650416] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x57 ESDHC_TUNE_CTRL_STATUS 0x57005700
[  134.659636] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.665325] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.672284] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.679498] mmc0:     0 bytes transferred: 0
[  134.684849] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x58 ESDHC_TUNE_CTRL_STATUS 0x58005800
[  134.694145] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.699896] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.706858] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.714022] mmc0:     0 bytes transferred: 0
[  134.719434] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x59 ESDHC_TUNE_CTRL_STATUS 0x59005900
[  134.728722] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.734413] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.741380] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.748608] mmc0:     0 bytes transferred: 0
[  134.753963] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x5a ESDHC_TUNE_CTRL_STATUS 0x5a005a00
[  134.763253] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.769011] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.775986] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.783153] mmc0:     0 bytes transferred: 0
[  134.788564] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x5b ESDHC_TUNE_CTRL_STATUS 0x5b005b00
[  134.797852] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.803543] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.810512] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.817723] mmc0:     0 bytes transferred: 0
[  134.823075] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x5c ESDHC_TUNE_CTRL_STATUS 0x5c005c00
[  134.832368] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.838117] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.845029] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.852241] mmc0:     0 bytes transferred: 0
[  134.857633] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x5d ESDHC_TUNE_CTRL_STATUS 0x5d005d00
[  134.866932] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.872626] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.879595] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.886806] mmc0:     0 bytes transferred: 0
[  134.892156] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x5e ESDHC_TUNE_CTRL_STATUS 0x5e005e00
[  134.901443] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.907182] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.914092] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.921315] mmc0:     0 bytes transferred: 0
[  134.926673] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x5f ESDHC_TUNE_CTRL_STATUS 0x5f005f00
[  134.935947] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.941639] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.948607] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.955772] mmc0:     0 bytes transferred: 0
[  134.961210] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x60 ESDHC_TUNE_CTRL_STATUS 0x60006000
[  134.970504] mmc0: starting CMD19 arg 00000000 flags 00000035
[  134.976244] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  134.983152] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  134.990374] mmc0:     0 bytes transferred: 0
[  134.995734] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x61 ESDHC_TUNE_CTRL_STATUS 0x61006100
[  135.005021] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.010768] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.017753] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.024919] mmc0:     0 bytes transferred: 0
[  135.030320] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x62 ESDHC_TUNE_CTRL_STATUS 0x62006200
[  135.039604] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.045295] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.052271] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.059486] mmc0:     0 bytes transferred: 0
[  135.064837] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x63 ESDHC_TUNE_CTRL_STATUS 0x63006300
[  135.074125] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.079884] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.086848] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.094012] mmc0:     0 bytes transferred: 0
[  135.099418] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x64 ESDHC_TUNE_CTRL_STATUS 0x64006400
[  135.108707] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.114399] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.121366] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.128591] mmc0:     0 bytes transferred: 0
[  135.133943] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x65 ESDHC_TUNE_CTRL_STATUS 0x65006500
[  135.143236] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.148988] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.155949] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.163114] mmc0:     0 bytes transferred: 0
[  135.168523] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x66 ESDHC_TUNE_CTRL_STATUS 0x66006600
[  135.177798] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.183489] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.190452] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.197662] mmc0:     0 bytes transferred: 0
[  135.203010] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x67 ESDHC_TUNE_CTRL_STATUS 0x67006700
[  135.212295] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.218043] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.224949] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.232173] mmc0:     0 bytes transferred: 0
[  135.237560] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x68 ESDHC_TUNE_CTRL_STATUS 0x68006800
[  135.246843] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.252540] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.259505] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.266712] mmc0:     0 bytes transferred: 0
[  135.272060] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x69 ESDHC_TUNE_CTRL_STATUS 0x69006900
[  135.281350] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.287101] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.294008] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.301231] mmc0:     0 bytes transferred: 0
[  135.306589] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x6a ESDHC_TUNE_CTRL_STATUS 0x6a006a00
[  135.315763] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.321523] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.328479] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.335640] mmc0:     0 bytes transferred: 0
[  135.341099] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x6b ESDHC_TUNE_CTRL_STATUS 0x6b006b00
[  135.350324] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.356063] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.362976] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.370198] mmc0:     0 bytes transferred: 0
[  135.375553] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x6c ESDHC_TUNE_CTRL_STATUS 0x6c006c00
[  135.384848] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.390597] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.397554] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.404717] mmc0:     0 bytes transferred: 0
[  135.410125] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x6d ESDHC_TUNE_CTRL_STATUS 0x6d006d00
[  135.419424] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.425117] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.432086] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.439313] mmc0:     0 bytes transferred: 0
[  135.444664] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x6e ESDHC_TUNE_CTRL_STATUS 0x6e006e00
[  135.453948] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.459709] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.466672] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.473836] mmc0:     0 bytes transferred: 0
[  135.479239] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x6f ESDHC_TUNE_CTRL_STATUS 0x6f006f00
[  135.488521] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.494213] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.501177] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.508392] mmc0:     0 bytes transferred: 0
[  135.513742] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x70 ESDHC_TUNE_CTRL_STATUS 0x70007000
[  135.523027] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.528777] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.535683] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.542902] mmc0:     0 bytes transferred: 0
[  135.548295] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x71 ESDHC_TUNE_CTRL_STATUS 0x71007100
[  135.557587] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.563280] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.570241] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.577451] mmc0:     0 bytes transferred: 0
[  135.582802] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x72 ESDHC_TUNE_CTRL_STATUS 0x72007200
[  135.592096] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.597839] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.604746] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.611968] mmc0:     0 bytes transferred: 0
[  135.617357] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x73 ESDHC_TUNE_CTRL_STATUS 0x73007300
[  135.626650] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.632347] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.639314] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.646523] mmc0:     0 bytes transferred: 0
[  135.651872] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x74 ESDHC_TUNE_CTRL_STATUS 0x74007400
[  135.661160] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.666903] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.673811] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.681033] mmc0:     0 bytes transferred: 0
[  135.686388] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x75 ESDHC_TUNE_CTRL_STATUS 0x75007500
[  135.695558] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.701309] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.708245] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.715406] mmc0:     0 bytes transferred: 0
[  135.720832] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x76 ESDHC_TUNE_CTRL_STATUS 0x76007600
[  135.730053] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.735742] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.742700] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.749929] mmc0:     0 bytes transferred: 0
[  135.755283] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x77 ESDHC_TUNE_CTRL_STATUS 0x77007700
[  135.764573] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.770334] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.777303] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.784468] mmc0:     0 bytes transferred: 0
[  135.789882] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x78 ESDHC_TUNE_CTRL_STATUS 0x78007800
[  135.799170] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.804863] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.811831] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.819052] mmc0:     0 bytes transferred: 0
[  135.824404] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x79 ESDHC_TUNE_CTRL_STATUS 0x79007900
[  135.833708] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.839457] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.846418] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.853582] mmc0:     0 bytes transferred: 0
[  135.858990] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x7a ESDHC_TUNE_CTRL_STATUS 0x7a007a00
[  135.868280] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.873973] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.880955] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.888190] mmc0:     0 bytes transferred: 0
[  135.893542] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x7b ESDHC_TUNE_CTRL_STATUS 0x7b007b00
[  135.902832] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.908590] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.915500] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.922722] mmc0:     0 bytes transferred: 0
[  135.928115] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x7c ESDHC_TUNE_CTRL_STATUS 0x7c007c00
[  135.937409] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.943108] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.950080] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.957288] mmc0:     0 bytes transferred: 0
[  135.962637] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x7d ESDHC_TUNE_CTRL_STATUS 0x7d007d00
[  135.971935] mmc0: starting CMD19 arg 00000000 flags 00000035
[  135.977695] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  135.984873] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  135.992111] mmc0:     0 bytes transferred: 0
[  135.997536] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x7e ESDHC_TUNE_CTRL_STATUS 0x7e007e00
[  136.006774] mmc0: starting CMD19 arg 00000000 flags 00000035
[  136.012466] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  136.019444] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  136.026656] mmc0:     0 bytes transferred: 0
[  136.032008] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x7f ESDHC_TUNE_CTRL_STATUS 0x7f00
[  136.040939] mmc0: starting CMD19 arg 00000000 flags 00000035
[  136.046687] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  136.053600] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[  136.060826] mmc0:     0 bytes transferred: 0
[  136.065180] sdhci-esdhc-imx 2198000.usdhc: tunning failed at 0x7f ret -123
[  136.072151] mmc0: tuning execution failed: -123
[  136.076816] mmc0: req failed (CMD13): -123, retrying...
[  136.082738] mmc0: req failed (CMD13): -123, retrying...
[  136.088413] mmc0: req failed (CMD13): -123, retrying...
[  136.093743] mmc0: req done (CMD13): -123: 00000000 00000000 00000000 00000000
[  136.100994] mmc0: card remove detected
[  136.104984] mmc0: card 59b4 removed
[  136.113392] mmc0: clock 0Hz busmode 2 powermode 0 cs 0 Vdd 0 width 1 timing 0
[  136.120648] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 0
[  136.373709] FAT-fs (mmcblk0p1): FAT read failed (blocknr 942)

So it's a bit hard for me to believe it has no affection.

Quoted 8 lines

Currently we don't even send the CMD13 because we check card detect first. I added prints for sdhci_execute_tuning and got this:

[  255.536326] sdhci [sdhci_irq()]: *** mmc1 got interrupt: 0x00000080
[  255.743653] mmc1: starting CMD13 arg 59b40000 flags 00000195
[  255.750093] mmc1: sdhci_execute_tuning
[  255.754358] mmc1: sdhci_execute_tuning: send command
[  255.809638] sdhci: Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock

I double checked the code, it seems why your platform only sends one tuning command is because your controller did not generate buffer ready interrupt if card is already removed.

Quoted 14 lines
[  255.824810] mmc1: req failed (CMD13): -123, retrying...
[  255.832766] mmc1: req failed (CMD13): -123, retrying...
[  255.840722] mmc1: req failed (CMD13): -123, retrying...
[  255.848672] mmc1: req done (CMD13): -123: 00000000 00000000 00000000 00000000
[  255.856773] mmc1: card remove detected
[  255.861056] mmc1: card 59b4 removed
[  255.872872] mmc1: clock 0Hz busmode 2 powermode 0 cs 0 Vdd 0 width 0 timing 0
Quoted 6 lines

Hmm.. I can't sure it's no affection.
e.g we did have customers reporting cd plug in/out causing jitters when system is busy playing audio or video.
Maybe we need to do those tests.

Quoted 6 lines
Quoted 2 lines

Anyway, what's your point to keep sending tuning commands after card is already removed?

Seems like a problem for your driver not the core. Why not check card detect after the first error in esdhc_executing_tuning().

It is not IMX driver problem.
IMX is based on SDHCI driver and it does check card detect for CMD13, but sdhci_execute_tuning not.

We may either check CD in sdhci_execute_tuning() or disable tuning for card remove case.

Personally i'd like to disable it in core since i really can't see the meaning to keep it for card remove.

What's your idea?

Regards
Dong Aisheng

Quoted 37 lines
Quoted 36 lines

Regards
Dong Aisheng

Quoted 31 lines
Quoted 26 lines

Regards
Dong Aisheng

Quoted 21 lines
Quoted 20 lines
---
 drivers/mmc/core/core.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/core.c +1 -0
index 52bfaf0..76d0802 100644
@@ -1888,6 +1888,7 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
              pm_wakeup_event(mmc_dev(host), 5000);
 
      host->detect_change = 1;
+     mmc_retune_disable(host);
      mmc_schedule_delayed_work(&host->detect, delay);
 }
 

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

maintainer
#53 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 4 lines · Dong Aisheng

And IMX6DL ARD is even worser due to it's using common mmc_send_tuning() function.
root at imx6qdlsolo:~#
root at imx6qdlsolo:~# [ 129.462564] sysrq: SysRq : Changing Loglevel

Quoted 9 lines
[  129.466902] sysrq: Loglevel set to 8
[  131.616078] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  131.625311] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 6
[  131.632133] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  131.642121] mmc0: starting CMD13 arg 59b40000 flags 00000195
[  131.648925] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x0 ESDHC_TUNE_CTRL_STATUS 0x0
[  131.657818] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.663518] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.670835] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000

You should stop here because -123 is -ENOMEDIUM

#54 lore raw

PATCH 10/23 mmc: core: disable auto retune during card detection process

Quoted 15 lines · Adrian Hunter
Quoted 4 lines · Dong Aisheng

And IMX6DL ARD is even worser due to it's using common mmc_send_tuning() function.
root at imx6qdlsolo:~#
root at imx6qdlsolo:~# [ 129.462564] sysrq: SysRq : Changing Loglevel

Quoted 9 lines
[  129.466902] sysrq: Loglevel set to 8
[  131.616078] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  131.625311] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 6
[  131.632133] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  131.642121] mmc0: starting CMD13 arg 59b40000 flags 00000195
[  131.648925] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x0 ESDHC_TUNE_CTRL_STATUS 0x0
[  131.657818] mmc0: starting CMD19 arg 00000000 flags 00000035
[  131.663518] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[  131.670835] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
Quoted 2 lines

You should stop here because -123 is -ENOMEDIUM

Hi Adrian,

This is the last issue before V2.
I just tried the way you proposed (see detailed log below).

A few questions if we decide to let tuning routine to handle the card remove case:
1) we may have to fix it for all platforms tuning code.

Below is the example i did for IMX uSDHC and common SDHCI.

drivers/mmc/host/sdhci-esdhc-imx.c +5 -1
@@ -757,7 +757,11 @@ static void esdhc_post_tuning(struct sdhci_host *host)
 
 static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 {
-       int min, max, avg, ret;
+       int min, max, avg, ret, present;
+
+       present = host->mmc->ops->get_cd(host->mmc);
+       if (!present)
+               return -ENOMEDIUM;
 
        /* find the mininum delay first which can pass tuning */
        min = ESDHC_TUNE_CTRL_MIN;
drivers/mmc/host/sdhci.c +5 -0
index 0027b8707ebd..7b7545dd1a4b 100644
@@ -1767,6 +1767,11 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        unsigned long flags;
        unsigned int tuning_count = 0;
        bool hs400_tuning;
+       int present;
+
+       present = mmc->ops->get_cd(mmc);
+       if (!present)
+               return -ENOMEDIUM;
 

And if we need fix all platforms, do you think we should do it in MMC core mmc_execute_tuning()?

If yes, then we probably could move all the normal host CD check before sending CMD in MMC core (__mmc_start_request()) as well?

2) MMC core will print out tuning error for card remove case which is not before.
e.g

[   98.730597] mmc0: tuning execution failed: -123

We probably may need make it debug level since it's meaningless for card removed case.

Detailed log below:
After the fix, card remove with calling mmc_send_tuning():
root at imx6qdlsolo:~# [ 98.664049] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000

[   98.673280] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 6
[   98.680102] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[   98.689560] mmc0: starting CMD13 arg aaaa0000 flags 00000195
[   98.696336] sdhci-esdhc-imx 2198000.usdhc: tunning with delay 0x0 ESDHC_TUNE_CTRL_STATUS 0x0
[   98.705407] mmc0: starting CMD19 arg 00000000 flags 00000035
[   98.711121] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 150 ms nsac 0
[   98.718144] mmc0: req done (CMD19): -123: 00000000 00000000 00000000 00000000
[   98.725351] mmc0:     0 bytes transferred: 0
[   98.730597] mmc0: tuning execution failed: -123
[   98.735255] mmc0: req failed (CMD13): -123, retrying...
[   98.740921] mmc0: req failed (CMD13): -123, retrying...
[   98.746344] mmc0: req failed (CMD13): -123, retrying...
[   98.751909] mmc0: req done (CMD13): -123: 00000000 00000000 00000000 00000000
[   98.759206] mmc0: card remove detected
[   98.763514] mmc0: card aaaa removed
[   98.780475] mmc0: clock 0Hz busmode 2 powermode 0 cs 0 Vdd 0 width 1 timing 0
[   98.787730] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 0
[   99.028432] FAT-fs (mmcblk0p1): FAT read failed (blocknr 32)q

card remove with calling standard sdhci_execute_tuning():
root at imx6qdlsolo:~# [ 210.555330] sysrq: SysRq : Changing Loglevel

[  210.559665] sysrq: Loglevel set to 8
[  212.244148] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  212.253376] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 6
[  212.260199] sdhci-esdhc-imx 2198000.usdhc: desired SD clock: 198000000, actual: 198000000
[  212.269637] mmc0: starting CMD13 arg aaaa0000 flags 00000195
[  212.275399] mmc0: tuning execution failed: -123
[  212.280601] mmc0: req failed (CMD13): -123, retrying...
[  212.286094] mmc0: req failed (CMD13): -123, retrying...
[  212.291763] mmc0: req failed (CMD13): -123, retrying...
[  212.297226] mmc0: req done (CMD13): -123: 00000000 00000000 00000000 00000000
[  212.304899] mmc0: card remove detected
[  212.308948] mmc0: card aaaa removed
[  212.318162] mmc0: clock 0Hz busmode 2 powermode 0 cs 0 Vdd 0 width 1 timing 0
[  212.325415] sdhci-esdhc-imx 2198000.usdhc: change pinctrl state for uhs 0
[  212.580621] FAT-fs (mmcblk0p1): FAT read failed (blocknr 32)

Regards
Dong Aisheng

#55 lore raw

PATCH 11/23 mmc: sdhci-esdhci-imx: remove SDHCI_QUIRK_BROKEN_TIMEOUT_VAL

In reply to Dong Aisheng

The driver has already implemented the private .set_timeout() callback for common SDHCI code to do correct timeout value setting, it does not need call sdhci_calc_timeout(), so this quirk actually is not working. Remove it now.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 2 --
 1 file changed, 2 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +0 -2
index 2d300d8..03980db 100644
@@ -1147,8 +1147,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	if (IS_ERR(imx_data->pins_default))
 		dev_warn(mmc_dev(host->mmc), "could not get default state\n");
 
-	host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
-
 	if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207)
 		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
Signature · 1 line
1.9.1
maintainer
#56 lore raw

PATCH 11/23 mmc: sdhci-esdhci-imx: remove SDHCI_QUIRK_BROKEN_TIMEOUT_VAL

Quoted 6 lines · Dong Aisheng

The driver has already implemented the private .set_timeout() callback for common SDHCI code to do correct timeout value setting, it does not need call sdhci_calc_timeout(), so this quirk actually is not working. Remove it now.

Pedantically, the subject needs:

	sdhci-esdhci-imx -> sdhci-esdhc-imx

Otherwise:

Quoted 18 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 2 --
 1 file changed, 2 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +0 -2
index 2d300d8..03980db 100644
@@ -1147,8 +1147,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	if (IS_ERR(imx_data->pins_default))
 		dev_warn(mmc_dev(host->mmc), "could not get default state\n");
 
-	host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
-
 	if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207)
 		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
#57 lore raw

PATCH 12/23 mmc: sdhci-esdhc-imx: add esdhc specific suspend resume callback

In reply to Dong Aisheng

It will be used for platform specific suspend/resume state save/restore work for some low power mode like Mega/Fast or LPSR mode.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-esdhc-imx.c +11 -1
index 03980db..6fef6bc 100644
@@ -1254,6 +1254,16 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
+static int sdhci_esdhc_suspend(struct device *dev)
+{
+	return sdhci_pltfm_suspend(dev);
+}
+
+static int sdhci_esdhc_resume(struct device *dev)
+{
+	return sdhci_pltfm_resume(dev);
+}
+
 static int sdhci_esdhc_runtime_suspend(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
@@ -1289,7 +1299,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops sdhci_esdhc_pmops = {
-	SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
 	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
 				sdhci_esdhc_runtime_resume, NULL)
 };
Signature · 1 line
1.9.1
maintainer
#58 lore raw

PATCH 12/23 mmc: sdhci-esdhc-imx: add esdhc specific suspend resume callback

Quoted 4 lines · Dong Aisheng

It will be used for platform specific suspend/resume state save/restore work for some low power mode like Mega/Fast or LPSR mode.

Quoted 35 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-esdhc-imx.c +11 -1
index 03980db..6fef6bc 100644
@@ -1254,6 +1254,16 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
+static int sdhci_esdhc_suspend(struct device *dev)
+{
+	return sdhci_pltfm_suspend(dev);
+}
+
+static int sdhci_esdhc_resume(struct device *dev)
+{
+	return sdhci_pltfm_resume(dev);
+}
+
 static int sdhci_esdhc_runtime_suspend(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
@@ -1289,7 +1299,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops sdhci_esdhc_pmops = {
-	SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
 	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
 				sdhci_esdhc_runtime_resume, NULL)
 };
#59 lore raw

PATCH 13/23 mmc: sdhci-esdhc-imx: restore watermark level setting after resume

In reply to Dong Aisheng

Currently, we config the watermark_level register only in probe. This will cause the mmc write operation timeout issue after system resume back in LPSR mode. Because in LPSR mode, after system resume back, the watermark_level register(0x44) changes to 0x08000880, which set the write watermark level as 0, and set the read watermark level as 128. This value is incorrect.

This patch restores the setting of watermark level register after system resume back.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +5 -0
index 6fef6bc..4c28fbb 100644
@@ -1261,6 +1261,11 @@ static int sdhci_esdhc_suspend(struct device *dev)
 
 static int sdhci_esdhc_resume(struct device *dev)
 {
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	/* restore watermark setting in case it's lost in low power mode */
+	writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+
 	return sdhci_pltfm_resume(dev);
 }
 
Signature · 1 line
1.9.1
maintainer
#60 lore raw

PATCH 13/23 mmc: sdhci-esdhc-imx: restore watermark level setting after resume

Quoted 9 lines · Dong Aisheng

Currently, we config the watermark_level register only in probe. This will cause the mmc write operation timeout issue after system resume back in LPSR mode. Because in LPSR mode, after system resume back, the watermark_level register(0x44) changes to 0x08000880, which set the write watermark level as 0, and set the read watermark level as 128. This value is incorrect.

This patch restores the setting of watermark level register after system resume back.

In sdhci_esdhc_imx_probe() the watermark setting is conditional on esdhc_is_usdhc(imx_data), but in the resume it is not. Is that intended? If so, maybe explain that in the commit message.

Might be worth pulling out the constant 0x10401040 and #defining it since it is used in more than one place too.

Quoted 23 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +5 -0
index 6fef6bc..4c28fbb 100644
@@ -1261,6 +1261,11 @@ static int sdhci_esdhc_suspend(struct device *dev)
 
 static int sdhci_esdhc_resume(struct device *dev)
 {
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	/* restore watermark setting in case it's lost in low power mode */
+	writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+
 	return sdhci_pltfm_resume(dev);
 }
 
#61 lore raw

PATCH 13/23 mmc: sdhci-esdhc-imx: restore watermark level setting after resume

Quoted 8 lines · Adrian Hunter
Quoted 7 lines · Dong Aisheng

Currently, we config the watermark_level register only in probe. This will cause the mmc write operation timeout issue after system resume back in LPSR mode. Because in LPSR mode, after system resume back, the watermark_level register(0x44) changes to 0x08000880, which set the write watermark level as 0, and set the read watermark level as 128. This value is incorrect.

Quoted 7 lines
Quoted 2 lines

This patch restores the setting of watermark level register after system resume back.

In sdhci_esdhc_imx_probe() the watermark setting is conditional on esdhc_is_usdhc(imx_data), but in the resume it is not. Is that intended? If so, maybe explain that in the commit message.

Good catch!
I think we'd probably better keep that condition check. Will update it in V2.

Quoted 3 lines

Might be worth pulling out the constant 0x10401040 and #defining it since it is used in more than one place too.

Good point!
Will do it.

Regards
Dong Aisheng

Quoted 24 lines
Quoted 23 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +5 -0
index 6fef6bc..4c28fbb 100644
@@ -1261,6 +1261,11 @@ static int sdhci_esdhc_suspend(struct device *dev)
 
 static int sdhci_esdhc_resume(struct device *dev)
 {
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	/* restore watermark setting in case it's lost in low power mode */
+	writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+
 	return sdhci_pltfm_resume(dev);
 }
 
#62 lore raw

PATCH 14/23 mmc: sdhci-esdhci-imx: disable DLL delay line settings explicitly

In reply to Dong Aisheng

From: Dong Aisheng <[email protected]>

Disable DLL delay line settings explicitly during driver initialization in case ROM/uBoot had set an invalid delay.
e.g. MX6DL ROM has set the default delay line(DLLCTRL) to 0x1000021, the uSDHC clock timing will become marginal when works on DDR mode due to default delay and will possibly see CRC errors in case the board is not perfectly designed on the eMMC chip layout.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +3 -0
index 4c28fbb..d02db66 100644
@@ -1186,6 +1186,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		*/
 		writel(readl(host->ioaddr + 0x6c) | BIT(7),
 			host->ioaddr + 0x6c);
+
+		/* disable DLL_CTRL delay line settings */
+		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
 	}
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
Signature · 1 line
1.9.1
maintainer
#63 lore raw

PATCH 14/23 mmc: sdhci-esdhci-imx: disable DLL delay line settings explicitly

Quoted 10 lines · Dong Aisheng

From: Dong Aisheng <[email protected]>

Disable DLL delay line settings explicitly during driver initialization in case ROM/uBoot had set an invalid delay.
e.g. MX6DL ROM has set the default delay line(DLLCTRL) to 0x1000021, the uSDHC clock timing will become marginal when works on DDR mode due to default delay and will possibly see CRC errors in case the board is not perfectly designed on the eMMC chip layout.

Quoted 19 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +3 -0
index 4c28fbb..d02db66 100644
@@ -1186,6 +1186,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		*/
 		writel(readl(host->ioaddr + 0x6c) | BIT(7),
 			host->ioaddr + 0x6c);
+
+		/* disable DLL_CTRL delay line settings */
+		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
 	}
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
#64 lore raw

PATCH 15/23 mmc: sdhci-esdhc-imx: support setting tuning start point

In reply to Dong Aisheng

The delay cells of some SoCs may have less delay per one cell, for such SoCs, user could set the start delay cell point to bypass the first a few meaningless tuning commands.

---
 drivers/mmc/host/sdhci-esdhc-imx.c          | 14 +++++++++++---
 include/linux/platform_data/mmc-esdhc-imx.h |  1 +
 2 files changed, 12 insertions(+), 3 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +11 -3
index d02db66..9f9be3f 100644
@@ -75,7 +75,8 @@
 #define ESDHC_TUNING_CTRL		0xcc
 #define ESDHC_STD_TUNING_EN		(1 << 24)
 /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
-#define ESDHC_TUNING_START_TAP		0x1
+#define ESDHC_TUNING_START_TAP_DEFAULT	0x1
+#define ESDHC_TUNING_START_TAP_MASK	0xff
 #define ESDHC_TUNING_STEP_MASK		0x00070000
 #define ESDHC_TUNING_STEP_SHIFT		16
 
@@ -489,7 +490,12 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
 				tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
-				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP;
+				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT;
+				if (imx_data->boarddata.tuning_start_tap) {
+					tuning_ctrl &= ~ESDHC_TUNING_START_TAP_MASK;
+					tuning_ctrl |= imx_data->boarddata.tuning_start_tap;
+				}
+
 				if (imx_data->boarddata.tuning_step) {
 					tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK;
 					tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
@@ -975,6 +981,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 		boarddata->wp_type = ESDHC_WP_GPIO;
 
 	of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
+	of_property_read_u32(np, "fsl,tuning-start-tap",
+			     &boarddata->tuning_start_tap);
 
 	if (of_find_property(np, "no-1-8-v", NULL))
 		boarddata->support_vsel = false;
@@ -1197,7 +1205,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
 		writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) |
-			ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP,
+			ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT,
 			host->ioaddr + ESDHC_TUNING_CTRL);
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
include/linux/platform_data/mmc-esdhc-imx.h +1 -0
index 95ccab3..7daa78a 100644
@@ -46,5 +46,6 @@ struct esdhc_platform_data {
 	bool support_vsel;
 	unsigned int delay_line;
 	unsigned int tuning_step;       /* The delay cell steps in tuning procedure */
+	unsigned int tuning_start_tap;	/* The start delay cell point in tuning procedure */
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
Signature · 1 line
1.9.1
maintainer
#65 lore raw

PATCH 15/23 mmc: sdhci-esdhc-imx: support setting tuning start point

Quoted 5 lines · Dong Aisheng

The delay cells of some SoCs may have less delay per one cell, for such SoCs, user could set the start delay cell point to bypass the first a few meaningless tuning commands.

Quoted 63 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c          | 14 +++++++++++---
 include/linux/platform_data/mmc-esdhc-imx.h |  1 +
 2 files changed, 12 insertions(+), 3 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +11 -3
index d02db66..9f9be3f 100644
@@ -75,7 +75,8 @@
 #define ESDHC_TUNING_CTRL		0xcc
 #define ESDHC_STD_TUNING_EN		(1 << 24)
 /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
-#define ESDHC_TUNING_START_TAP		0x1
+#define ESDHC_TUNING_START_TAP_DEFAULT	0x1
+#define ESDHC_TUNING_START_TAP_MASK	0xff
 #define ESDHC_TUNING_STEP_MASK		0x00070000
 #define ESDHC_TUNING_STEP_SHIFT		16
 
@@ -489,7 +490,12 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
 				tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
-				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP;
+				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT;
+				if (imx_data->boarddata.tuning_start_tap) {
+					tuning_ctrl &= ~ESDHC_TUNING_START_TAP_MASK;
+					tuning_ctrl |= imx_data->boarddata.tuning_start_tap;
+				}
+
 				if (imx_data->boarddata.tuning_step) {
 					tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK;
 					tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
@@ -975,6 +981,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 		boarddata->wp_type = ESDHC_WP_GPIO;
 
 	of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
+	of_property_read_u32(np, "fsl,tuning-start-tap",
+			     &boarddata->tuning_start_tap);
 
 	if (of_find_property(np, "no-1-8-v", NULL))
 		boarddata->support_vsel = false;
@@ -1197,7 +1205,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
 		writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) |
-			ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP,
+			ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT,
 			host->ioaddr + ESDHC_TUNING_CTRL);
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
include/linux/platform_data/mmc-esdhc-imx.h +1 -0
index 95ccab3..7daa78a 100644
@@ -46,5 +46,6 @@ struct esdhc_platform_data {
 	bool support_vsel;
 	unsigned int delay_line;
 	unsigned int tuning_step;       /* The delay cell steps in tuning procedure */
+	unsigned int tuning_start_tap;	/* The start delay cell point in tuning procedure */
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
#66 lore raw

PATCH 16/23 doc: dt: fsl-imx-esdhc: add set tuning start point binding

In reply to Dong Aisheng

add tuning start point binding

---
 Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt | 2 ++
 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt +2 -0
index dca56d6..3e29050 100644
@@ -28,6 +28,8 @@ Optional properties:
   transparent level shifters on the outputs of the controller. Two cells are
   required, first cell specifies minimum slot voltage (mV), second cell
   specifies maximum slot voltage (mV). Several ranges could be specified.
+- fsl,tuning-start-tap: Specify the start dealy cell point when send first CMD19
+  in tuning procedure.
 - fsl,tuning-step: Specify the increasing delay cell steps in tuning procedure.
   The uSDHC use one delay cell as default increasing step to do tuning process.
   This property allows user to change the tuning step to more than one delay
Signature · 1 line
1.9.1
#67 lore raw

PATCH 17/23 mmc: sdhci: add standard hw auto retuning support

In reply to Dong Aisheng

If HW supports SDHCI_TUNING_MODE_3 which is auto retuning, we won't retune during runtime suspend and resume, instead we use Re-tuning Request signaled via SDHCI_INT_RETUNE interrupt to do retuning and hw auto retuning during data transfer to guarantee the signal sample window correction.

This can avoid a mass of repeatly retuning during small file system data access and improve the performance.

---
 drivers/mmc/host/sdhci.c | 18 ++++++++++++++----
 drivers/mmc/host/sdhci.h |  3 +++
 2 files changed, 17 insertions(+), 4 deletions(-)
drivers/mmc/host/sdhci.c +14 -4
index 2eb0e34..0027b87 100644
@@ -252,6 +252,9 @@ static void sdhci_init(struct sdhci_host *host, int soft)
 		    SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
 		    SDHCI_INT_RESPONSE;
 
+	if (host->tuning_mode == SDHCI_TUNING_MODE_3)
+		host->ier |= SDHCI_INT_RETUNE;
+
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
@@ -2477,6 +2480,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			pr_err("%s: Card is consuming too much power!\n",
 				mmc_hostname(host->mmc));
 
+		if (intmask & SDHCI_INT_RETUNE)
+			mmc_retune_needed(host->mmc);
+
 		if (intmask & SDHCI_INT_CARD_INT) {
 			sdhci_enable_sdio_irq_nolock(host, false);
 			host->thread_isr |= SDHCI_INT_CARD_INT;
@@ -2575,8 +2581,10 @@ int sdhci_suspend_host(struct sdhci_host *host)
 {
 	sdhci_disable_card_detection(host);
 
-	mmc_retune_timer_stop(host->mmc);
-	mmc_retune_needed(host->mmc);
+	if (host->tuning_mode == SDHCI_TUNING_MODE_1) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}
 
 	if (!device_may_wakeup(mmc_dev(host->mmc))) {
 		host->ier = 0;
@@ -2651,8 +2659,10 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
 {
 	unsigned long flags;
 
-	mmc_retune_timer_stop(host->mmc);
-	mmc_retune_needed(host->mmc);
+	if (host->tuning_mode == SDHCI_TUNING_MODE_1) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}
 
 	spin_lock_irqsave(&host->lock, flags);
 	host->ier &= SDHCI_INT_CARD_INT;
drivers/mmc/host/sdhci.h +3 -0
index afa4de8..2c2404f 100644
@@ -128,6 +128,7 @@
 #define  SDHCI_INT_CARD_INSERT	0x00000040
 #define  SDHCI_INT_CARD_REMOVE	0x00000080
 #define  SDHCI_INT_CARD_INT	0x00000100
+#define  SDHCI_INT_RETUNE	0x00001000
 #define  SDHCI_INT_ERROR	0x00008000
 #define  SDHCI_INT_TIMEOUT	0x00010000
 #define  SDHCI_INT_CRC		0x00020000
@@ -514,6 +515,8 @@ struct sdhci_host {
 	unsigned int		tuning_count;	/* Timer count for re-tuning */
 	unsigned int		tuning_mode;	/* Re-tuning mode supported by host */
 #define SDHCI_TUNING_MODE_1	0
+#define SDHCI_TUNING_MODE_2	1
+#define SDHCI_TUNING_MODE_3	2
 
 	unsigned long private[0] ____cacheline_aligned;
 };
Signature · 1 line
1.9.1
maintainer
#68 lore raw

PATCH 17/23 mmc: sdhci: add standard hw auto retuning support

Quoted 1 line · Dong Aisheng

If HW supports SDHCI_TUNING_MODE_3 which is auto retuning, we won't

Since this is about tuning mode 3, could you put that in the subject e.g. "Add support for auto re-tuning (tuning mode 3)"

Quoted 6 lines

retune during runtime suspend and resume, instead we use Re-tuning Request signaled via SDHCI_INT_RETUNE interrupt to do retuning and hw auto retuning during data transfer to guarantee the signal sample window correction.

This can avoid a mass of repeatly retuning during small file system

repeatly -> repeatedly

Quoted 13 lines

data access and improve the performance.

---
 drivers/mmc/host/sdhci.c | 18 ++++++++++++++----
 drivers/mmc/host/sdhci.h |  3 +++
 2 files changed, 17 insertions(+), 4 deletions(-)
drivers/mmc/host/sdhci.c +0 -0
index 2eb0e34..0027b87 100644

drivers/mmc/host/sdhci.c static void sdhci_init(struct sdhci_host *host, int soft) · line 255

Quoted 4 lines
drivers/mmc/host/sdhci.c +1 -0
@@ -252,6 +252,9 @@ static void sdhci_init(struct sdhci_host *host, int soft)
 		    SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
 		    SDHCI_INT_RESPONSE;
 
+	if (host->tuning_mode == SDHCI_TUNING_MODE_3)

Tuning mode 2 uses this as well. Might as well add it here.

drivers/mmc/host/sdhci.c static irqreturn_t sdhci_irq(int irq, void *dev_id) · line 2485

Quoted 12 lines
drivers/mmc/host/sdhci.c +5 -0
+		host->ier |= SDHCI_INT_RETUNE;
+
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
@@ -2477,6 +2480,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			pr_err("%s: Card is consuming too much power!\n",
 				mmc_hostname(host->mmc));
 
+		if (intmask & SDHCI_INT_RETUNE)
+			mmc_retune_needed(host->mmc);
+

Also need to add SDHCI_INT_RETUNE to the bits cleared further on, otherwise it will show up in the "Unexpected interrupt" message

drivers/mmc/host/sdhci.c int sdhci_suspend_host(struct sdhci_host *host) · line 2587

Quoted 13 lines
drivers/mmc/host/sdhci.c +4 -2
 		if (intmask & SDHCI_INT_CARD_INT) {
 			sdhci_enable_sdio_irq_nolock(host, false);
 			host->thread_isr |= SDHCI_INT_CARD_INT;
@@ -2575,8 +2581,10 @@ int sdhci_suspend_host(struct sdhci_host *host)
 {
 	sdhci_disable_card_detection(host);
 
-	mmc_retune_timer_stop(host->mmc);
-	mmc_retune_needed(host->mmc);
+	if (host->tuning_mode == SDHCI_TUNING_MODE_1) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}

Probably wouldn't hurt to stop the timer always whether it's going or not. And tuning mode 2 is not auto re-tuning, so I would still expect to need re-tuning after power loss i.e.

	mmc_retune_timer_stop(host->mmc);
	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
		mmc_retune_needed(host->mmc);

drivers/mmc/host/sdhci.c int sdhci_runtime_suspend_host(struct sdhci_host *host) · line 2665

Quoted 13 lines
drivers/mmc/host/sdhci.c +4 -2
 	if (!device_may_wakeup(mmc_dev(host->mmc))) {
 		host->ier = 0;
@@ -2651,8 +2659,10 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
 {
 	unsigned long flags;
 
-	mmc_retune_timer_stop(host->mmc);
-	mmc_retune_needed(host->mmc);
+	if (host->tuning_mode == SDHCI_TUNING_MODE_1) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}

Ditto

Quoted 25 lines
drivers/mmc/host/sdhci.c +0 -0
 	spin_lock_irqsave(&host->lock, flags);
 	host->ier &= SDHCI_INT_CARD_INT;
drivers/mmc/host/sdhci.h +3 -0
index afa4de8..2c2404f 100644
@@ -128,6 +128,7 @@
 #define  SDHCI_INT_CARD_INSERT	0x00000040
 #define  SDHCI_INT_CARD_REMOVE	0x00000080
 #define  SDHCI_INT_CARD_INT	0x00000100
+#define  SDHCI_INT_RETUNE	0x00001000
 #define  SDHCI_INT_ERROR	0x00008000
 #define  SDHCI_INT_TIMEOUT	0x00010000
 #define  SDHCI_INT_CRC		0x00020000
@@ -514,6 +515,8 @@ struct sdhci_host {
 	unsigned int		tuning_count;	/* Timer count for re-tuning */
 	unsigned int		tuning_mode;	/* Re-tuning mode supported by host */
 #define SDHCI_TUNING_MODE_1	0
+#define SDHCI_TUNING_MODE_2	1
+#define SDHCI_TUNING_MODE_3	2
 
 	unsigned long private[0] ____cacheline_aligned;
 };
#69 lore raw

PATCH 17/23 mmc: sdhci: add standard hw auto retuning support

Quoted 6 lines · Adrian Hunter
Quoted 1 line · Dong Aisheng

If HW supports SDHCI_TUNING_MODE_3 which is auto retuning, we won't

Since this is about tuning mode 3, could you put that in the subject e.g. "Add support for auto re-tuning (tuning mode 3)"

Quoted 9 lines
Quoted 6 lines

retune during runtime suspend and resume, instead we use Re-tuning Request signaled via SDHCI_INT_RETUNE interrupt to do retuning and hw auto retuning during data transfer to guarantee the signal sample window correction.

This can avoid a mass of repeatly retuning during small file system

repeatly -> repeatedly

Got it.

Quoted 16 lines
Quoted 16 lines

data access and improve the performance.

---
 drivers/mmc/host/sdhci.c | 18 ++++++++++++++----
 drivers/mmc/host/sdhci.h |  3 +++
 2 files changed, 17 insertions(+), 4 deletions(-)
drivers/mmc/host/sdhci.c +0 -0
index 2eb0e34..0027b87 100644
@@ -252,6 +252,9 @@ static void sdhci_init(struct sdhci_host *host, int soft)
 		    SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
 		    SDHCI_INT_RESPONSE;
 
Quoted 4 lines

drivers/mmc/host/sdhci.c static void sdhci_init(struct sdhci_host *host, int soft) · line 255

Quoted 1 line
drivers/mmc/host/sdhci.c +1 -0
+	if (host->tuning_mode == SDHCI_TUNING_MODE_3)

Tuning mode 2 uses this as well. Might as well add it here.

The origin plan is adding only mode 3 support here to make life a bit easier. Seems mode 2 does not need much more things added. So i can add it here too.

Quoted 9 lines
Quoted 9 lines
drivers/mmc/host/sdhci.c +2 -0
+		host->ier |= SDHCI_INT_RETUNE;
+
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
@@ -2477,6 +2480,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			pr_err("%s: Card is consuming too much power!\n",
 				mmc_hostname(host->mmc));
 
Quoted 7 lines

drivers/mmc/host/sdhci.c static irqreturn_t sdhci_irq(int irq, void *dev_id) · line 2485

Quoted 3 lines
drivers/mmc/host/sdhci.c +3 -0
+		if (intmask & SDHCI_INT_RETUNE)
+			mmc_retune_needed(host->mmc);
+

Also need to add SDHCI_INT_RETUNE to the bits cleared further on, otherwise it will show up in the "Unexpected interrupt" message

That's true.

Quoted 7 lines
Quoted 7 lines
drivers/mmc/host/sdhci.c +0 -0
 		if (intmask & SDHCI_INT_CARD_INT) {
 			sdhci_enable_sdio_irq_nolock(host, false);
 			host->thread_isr |= SDHCI_INT_CARD_INT;
@@ -2575,8 +2581,10 @@ int sdhci_suspend_host(struct sdhci_host *host)
 {
 	sdhci_disable_card_detection(host);
 
Quoted 8 lines

drivers/mmc/host/sdhci.c int sdhci_suspend_host(struct sdhci_host *host) · line 2587

Quoted 6 lines
drivers/mmc/host/sdhci.c +4 -2
-	mmc_retune_timer_stop(host->mmc);
-	mmc_retune_needed(host->mmc);
+	if (host->tuning_mode == SDHCI_TUNING_MODE_1) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}

Probably wouldn't hurt to stop the timer always whether it's going or not.

Sounds correct.

Quoted 7 lines

And tuning mode 2 is not auto re-tuning, so I would still expect to need re-tuning after power loss i.e.

	mmc_retune_timer_stop(host->mmc);
	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
		mmc_retune_needed(host->mmc);

I agree with you.
Will get it in v2.

Regards
Dong Aisheng

Quoted 42 lines

drivers/mmc/host/sdhci.c int sdhci_runtime_suspend_host(struct sdhci_host *host) · line 2665

Quoted 13 lines
drivers/mmc/host/sdhci.c +4 -2
 	if (!device_may_wakeup(mmc_dev(host->mmc))) {
 		host->ier = 0;
@@ -2651,8 +2659,10 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
 {
 	unsigned long flags;
 
-	mmc_retune_timer_stop(host->mmc);
-	mmc_retune_needed(host->mmc);
+	if (host->tuning_mode == SDHCI_TUNING_MODE_1) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}

Ditto

Quoted 25 lines
drivers/mmc/host/sdhci.c +0 -0
 	spin_lock_irqsave(&host->lock, flags);
 	host->ier &= SDHCI_INT_CARD_INT;
drivers/mmc/host/sdhci.h +3 -0
index afa4de8..2c2404f 100644
@@ -128,6 +128,7 @@
 #define  SDHCI_INT_CARD_INSERT	0x00000040
 #define  SDHCI_INT_CARD_REMOVE	0x00000080
 #define  SDHCI_INT_CARD_INT	0x00000100
+#define  SDHCI_INT_RETUNE	0x00001000
 #define  SDHCI_INT_ERROR	0x00008000
 #define  SDHCI_INT_TIMEOUT	0x00010000
 #define  SDHCI_INT_CRC		0x00020000
@@ -514,6 +515,8 @@ struct sdhci_host {
 	unsigned int		tuning_count;	/* Timer count for re-tuning */
 	unsigned int		tuning_mode;	/* Re-tuning mode supported by host */
 #define SDHCI_TUNING_MODE_1	0
+#define SDHCI_TUNING_MODE_2	1
+#define SDHCI_TUNING_MODE_3	2
 
 	unsigned long private[0] ____cacheline_aligned;
 };
#70 lore raw

PATCH 18/23 mmc: sdhci-esdhc-imx: enable hw auto retuning for STD_TUNING

In reply to Dong Aisheng

Enable HW auto retuning when set SDHCI_CTRL_EXEC_TUNING and clear it when clear SDHCI_CTRL_TUNED_CLK.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +3 -0
index 9f9be3f..a582a83 100644
@@ -44,6 +44,7 @@
 #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
 #define  ESDHC_MIX_CTRL_EXE_TUNE	(1 << 22)
 #define  ESDHC_MIX_CTRL_SMPCLK_SEL	(1 << 23)
+#define  ESDHC_MIX_CTRL_AUTO_TUNE_EN	(1 << 24)
 #define  ESDHC_MIX_CTRL_FBCLK_SEL	(1 << 25)
 #define  ESDHC_MIX_CTRL_HS400_EN	(1 << 26)
 /* Bits 3 and 6 are not SDHCI standard definitions */
@@ -484,11 +485,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 			} else {
 				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
 				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+				m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 			}
 
 			if (val & SDHCI_CTRL_EXEC_TUNING) {
 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
+				m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 				tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
 				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT;
 				if (imx_data->boarddata.tuning_start_tap) {
Signature · 1 line
1.9.1
maintainer
#71 lore raw

PATCH 18/23 mmc: sdhci-esdhc-imx: enable hw auto retuning for STD_TUNING

Quoted 4 lines · Dong Aisheng

Enable HW auto retuning when set SDHCI_CTRL_EXEC_TUNING and clear it when clear SDHCI_CTRL_TUNED_CLK.

I presume this patch should wait for patch 17, but nevertheless:

Quoted 31 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +3 -0
index 9f9be3f..a582a83 100644
@@ -44,6 +44,7 @@
 #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
 #define  ESDHC_MIX_CTRL_EXE_TUNE	(1 << 22)
 #define  ESDHC_MIX_CTRL_SMPCLK_SEL	(1 << 23)
+#define  ESDHC_MIX_CTRL_AUTO_TUNE_EN	(1 << 24)
 #define  ESDHC_MIX_CTRL_FBCLK_SEL	(1 << 25)
 #define  ESDHC_MIX_CTRL_HS400_EN	(1 << 26)
 /* Bits 3 and 6 are not SDHCI standard definitions */
@@ -484,11 +485,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 			} else {
 				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
 				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+				m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 			}
 
 			if (val & SDHCI_CTRL_EXEC_TUNING) {
 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
+				m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 				tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
 				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT;
 				if (imx_data->boarddata.tuning_start_tap) {
#72 lore raw

PATCH 18/23 mmc: sdhci-esdhc-imx: enable hw auto retuning for STD_TUNING

Quoted 10 lines · Adrian Hunter
Quoted 4 lines · Dong Aisheng

Enable HW auto retuning when set SDHCI_CTRL_EXEC_TUNING and clear it when clear SDHCI_CTRL_TUNED_CLK.

I presume this patch should wait for patch 17, but nevertheless:

Actually the interesting thing here is patch 18 and 19 do not need patch 17 since our IC guy told me IMX uSDHC auto-tuning will not Retuning request for mode 3.

Thanks for the pre-ACK.

Regards
Dong Aisheng

Quoted 32 lines
Quoted 31 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +3 -0
index 9f9be3f..a582a83 100644
@@ -44,6 +44,7 @@
 #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
 #define  ESDHC_MIX_CTRL_EXE_TUNE	(1 << 22)
 #define  ESDHC_MIX_CTRL_SMPCLK_SEL	(1 << 23)
+#define  ESDHC_MIX_CTRL_AUTO_TUNE_EN	(1 << 24)
 #define  ESDHC_MIX_CTRL_FBCLK_SEL	(1 << 25)
 #define  ESDHC_MIX_CTRL_HS400_EN	(1 << 26)
 /* Bits 3 and 6 are not SDHCI standard definitions */
@@ -484,11 +485,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 			} else {
 				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
 				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+				m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 			}
 
 			if (val & SDHCI_CTRL_EXEC_TUNING) {
 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
+				m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 				tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
 				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT;
 				if (imx_data->boarddata.tuning_start_tap) {
#73 lore raw

PATCH 19/23 mmc: sdhci-esdhc-imx: enable hw auto retuning for MAN_TUNING

In reply to Dong Aisheng

Indicating hw auto retuning support for mx6qdl in the fake caps_1 register and enable auto retuning in post_tuning process after tuning completes.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +8 -3
index a582a83..07b1144 100644
@@ -301,7 +301,8 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 				/* imx6q/dl does not have cap_1 register, fake one */
 				val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
 					| SDHCI_SUPPORT_SDR50
-					| SDHCI_USE_SDR50_TUNING;
+					| SDHCI_USE_SDR50_TUNING
+					| (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT);
 
 			if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
 				val |= SDHCI_SUPPORT_HS400;
@@ -471,10 +472,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
 		if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
 			new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
-			if (val & SDHCI_CTRL_TUNED_CLK)
+			if (val & SDHCI_CTRL_TUNED_CLK) {
 				new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL;
-			else
+				new_val |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
+			} else {
 				new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+				new_val &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
+			}
 			writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
 		} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
 			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
@@ -760,6 +764,7 @@ static void esdhc_post_tuning(struct sdhci_host *host)
 
 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
 	reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
+	reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
 }
 
Signature · 1 line
1.9.1
maintainer
#74 lore raw

PATCH 19/23 mmc: sdhci-esdhc-imx: enable hw auto retuning for MAN_TUNING

Quoted 5 lines · Dong Aisheng

Indicating hw auto retuning support for mx6qdl in the fake caps_1 register and enable auto retuning in post_tuning process after tuning completes.

I presume this patch should wait for patch 17, but nevertheless:

Quoted 43 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +8 -3
index a582a83..07b1144 100644
@@ -301,7 +301,8 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 				/* imx6q/dl does not have cap_1 register, fake one */
 				val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
 					| SDHCI_SUPPORT_SDR50
-					| SDHCI_USE_SDR50_TUNING;
+					| SDHCI_USE_SDR50_TUNING
+					| (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT);
 
 			if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
 				val |= SDHCI_SUPPORT_HS400;
@@ -471,10 +472,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
 		if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
 			new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
-			if (val & SDHCI_CTRL_TUNED_CLK)
+			if (val & SDHCI_CTRL_TUNED_CLK) {
 				new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL;
-			else
+				new_val |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
+			} else {
 				new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+				new_val &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
+			}
 			writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
 		} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
 			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
@@ -760,6 +764,7 @@ static void esdhc_post_tuning(struct sdhci_host *host)
 
 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
 	reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
+	reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
 }
 
#75 lore raw

PATCH 20/23 mmc: sdhci-esdhc-imx: fix strobe DLL lock wrong clock issue

In reply to Dong Aisheng

When enable DDR, the clock factor definition is changed. e.g. original 200Mhz will become 100Mhz one MIX_CTRL_DDREN bit is set So we need to update the clock setting then the strobe dll can lock the correct clock rate.

Additionally we also need disable the clock before locking strobe dll.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +7 -0
index 07b1144..3ff213f 100644
@@ -852,6 +852,11 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
 	u32 v;
 
 	if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+		/* disable clock before enabling strobe dll */
+		writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
+		       (~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON),
+		       host->ioaddr + ESDHC_VENDOR_SPEC);
+
 		/* force a reset on strobe dll */
 		writel(ESDHC_STROBE_DLL_CTRL_RESET,
 			host->ioaddr + ESDHC_STROBE_DLL_CTRL);
@@ -913,6 +918,8 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 		m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
 		imx_data->is_ddr = 1;
+		/* update clock after enable DDR for strobe DLL lock */
+		host->ops->set_clock(host, host->clock);
 		esdhc_set_strobe_dll(host);
 		break;
 	}
Signature · 1 line
1.9.1
maintainer
#76 lore raw

PATCH 20/23 mmc: sdhci-esdhc-imx: fix strobe DLL lock wrong clock issue

Quoted 8 lines · Dong Aisheng

When enable DDR, the clock factor definition is changed. e.g. original 200Mhz will become 100Mhz one MIX_CTRL_DDREN bit is set So we need to update the clock setting then the strobe dll can lock the correct clock rate.

Additionally we also need disable the clock before locking strobe dll.

Apart from redundant parentheses (refer below):

Quoted 9 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +0 -0
index 07b1144..3ff213f 100644

drivers/mmc/host/sdhci-esdhc-imx.c static void esdhc_set_strobe_dll(struct sdhci_host *host) · line 857

Quoted 6 lines
drivers/mmc/host/sdhci-esdhc-imx.c +3 -0
@@ -852,6 +852,11 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
 	u32 v;
 
 	if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+		/* disable clock before enabling strobe dll */
+		writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
+		       (~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON),

Parentheses look redundant

Quoted 15 lines
drivers/mmc/host/sdhci-esdhc-imx.c +4 -0
+		       host->ioaddr + ESDHC_VENDOR_SPEC);
+
 		/* force a reset on strobe dll */
 		writel(ESDHC_STROBE_DLL_CTRL_RESET,
 			host->ioaddr + ESDHC_STROBE_DLL_CTRL);
@@ -913,6 +918,8 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 		m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
 		imx_data->is_ddr = 1;
+		/* update clock after enable DDR for strobe DLL lock */
+		host->ops->set_clock(host, host->clock);
 		esdhc_set_strobe_dll(host);
 		break;
 	}
#77 lore raw

PATCH 20/23 mmc: sdhci-esdhc-imx: fix strobe DLL lock wrong clock issue

Quoted 6 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

When enable DDR, the clock factor definition is changed. e.g. original 200Mhz will become 100Mhz one MIX_CTRL_DDREN bit is set So we need to update the clock setting then the strobe dll can lock the correct clock rate.

Quoted 8 lines
Quoted 3 lines

Additionally we also need disable the clock before locking strobe dll.

Apart from redundant parentheses (refer below):

Could remove in V2.
Thanks for the suggestion.

Regards
Dong Aisheng

Quoted 34 lines
Quoted 9 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +0 -0
index 07b1144..3ff213f 100644

drivers/mmc/host/sdhci-esdhc-imx.c static void esdhc_set_strobe_dll(struct sdhci_host *host) · line 857

Quoted 6 lines
drivers/mmc/host/sdhci-esdhc-imx.c +3 -0
@@ -852,6 +852,11 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
 	u32 v;
 
 	if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+		/* disable clock before enabling strobe dll */
+		writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
+		       (~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON),

Parentheses look redundant

Quoted 15 lines
drivers/mmc/host/sdhci-esdhc-imx.c +4 -0
+		       host->ioaddr + ESDHC_VENDOR_SPEC);
+
 		/* force a reset on strobe dll */
 		writel(ESDHC_STROBE_DLL_CTRL_RESET,
 			host->ioaddr + ESDHC_STROBE_DLL_CTRL);
@@ -913,6 +918,8 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 		m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
 		imx_data->is_ddr = 1;
+		/* update clock after enable DDR for strobe DLL lock */
+		host->ops->set_clock(host, host->clock);
 		esdhc_set_strobe_dll(host);
 		break;
 	}
#78 lore raw

PATCH 21/23 mmc: sdhci-esdhc-imx: factor out hw related intialization into function

In reply to Dong Aisheng

Factor out hw related intialization into a separate function which has two benifits:
1) concentrate hw related intialization at one place
2) ease the hw state restore after resume by simply calling this function

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 76 +++++++++++++++++++++-----------------
 1 file changed, 42 insertions(+), 34 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +42 -34
index 3ff213f..95f3632 100644
@@ -978,6 +978,44 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
 	.ops = &sdhci_esdhc_ops,
 };
 
+static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+
+	if (esdhc_is_usdhc(imx_data)) {
+		/*
+		 * The imx6q ROM code will change the default watermark
+		 * level setting to something insane.  Change it back here.
+		 */
+		writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+
+		/*
+		 * ROM code will change the bit burst_length_enable setting
+		 * to zero if this usdhc is choosed to boot system. Change
+		 * it back here, otherwise it will impact the performance a
+		 * lot. This bit is used to enable/disable the burst length
+		 * for the external AHB2AXI bridge, it's usefully especially
+		 * for INCR transfer because without burst length indicator,
+		 * the AHB2AXI bridge does not know the burst length in
+		 * advance. And without burst length indicator, AHB INCR
+		 * transfer can only be converted to singles on the AXI side.
+		 */
+		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
+			| ESDHC_BURST_LEN_EN_INCR,
+			host->ioaddr + SDHCI_HOST_CONTROL);
+		/*
+		* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
+		* TO1.1, it's harmless for MX6SL
+		*/
+		writel(readl(host->ioaddr + 0x6c) | BIT(7),
+			host->ioaddr + 0x6c);
+
+		/* disable DLL_CTRL delay line settings */
+		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
+	}
+}
+
 #ifdef CONFIG_OF
 static int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
@@ -1175,43 +1213,13 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
 			| SDHCI_QUIRK_BROKEN_ADMA;
 
-	/*
-	 * The imx6q ROM code will change the default watermark level setting
-	 * to something insane.  Change it back here.
-	 */
-	if (esdhc_is_usdhc(imx_data)) {
-		writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+	sdhci_esdhc_imx_hwinit(host);
 
+	if (esdhc_is_usdhc(imx_data)) {
 		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
 		host->mmc->caps |= MMC_CAP_1_8V_DDR;
-
-		/*
-		 * ROM code will change the bit burst_length_enable setting
-		 * to zero if this usdhc is choosed to boot system. Change
-		 * it back here, otherwise it will impact the performance a
-		 * lot. This bit is used to enable/disable the burst length
-		 * for the external AHB2AXI bridge, it's usefully especially
-		 * for INCR transfer because without burst length indicator,
-		 * the AHB2AXI bridge does not know the burst length in
-		 * advance. And without burst length indicator, AHB INCR
-		 * transfer can only be converted to singles on the AXI side.
-		 */
-		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
-			| ESDHC_BURST_LEN_EN_INCR,
-			host->ioaddr + SDHCI_HOST_CONTROL);
-
 		if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
 			host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
-
-		/*
-		* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
-		* TO1.1, it's harmless for MX6SL
-		*/
-		writel(readl(host->ioaddr + 0x6c) | BIT(7),
-			host->ioaddr + 0x6c);
-
-		/* disable DLL_CTRL delay line settings */
-		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
 	}
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
@@ -1289,8 +1297,8 @@ static int sdhci_esdhc_resume(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
 
-	/* restore watermark setting in case it's lost in low power mode */
-	writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+	/* reinitialize hw state in case it's lost in low power mode */
+	sdhci_esdhc_imx_hwinit(host);
 
 	return sdhci_pltfm_resume(dev);
 }
Signature · 1 line
1.9.1
maintainer
#79 lore raw

PATCH 21/23 mmc: sdhci-esdhc-imx: factor out hw related intialization into function

Quoted 5 lines · Dong Aisheng

Factor out hw related intialization into a separate function which has two benifits:
1) concentrate hw related intialization at one place
2) ease the hw state restore after resume by simply calling this function

There are really 2 changes here, please make it 2 patches.

Quoted 113 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 76 +++++++++++++++++++++-----------------
 1 file changed, 42 insertions(+), 34 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +42 -34
index 3ff213f..95f3632 100644
@@ -978,6 +978,44 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
 	.ops = &sdhci_esdhc_ops,
 };
 
+static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+
+	if (esdhc_is_usdhc(imx_data)) {
+		/*
+		 * The imx6q ROM code will change the default watermark
+		 * level setting to something insane.  Change it back here.
+		 */
+		writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+
+		/*
+		 * ROM code will change the bit burst_length_enable setting
+		 * to zero if this usdhc is choosed to boot system. Change
+		 * it back here, otherwise it will impact the performance a
+		 * lot. This bit is used to enable/disable the burst length
+		 * for the external AHB2AXI bridge, it's usefully especially
+		 * for INCR transfer because without burst length indicator,
+		 * the AHB2AXI bridge does not know the burst length in
+		 * advance. And without burst length indicator, AHB INCR
+		 * transfer can only be converted to singles on the AXI side.
+		 */
+		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
+			| ESDHC_BURST_LEN_EN_INCR,
+			host->ioaddr + SDHCI_HOST_CONTROL);
+		/*
+		* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
+		* TO1.1, it's harmless for MX6SL
+		*/
+		writel(readl(host->ioaddr + 0x6c) | BIT(7),
+			host->ioaddr + 0x6c);
+
+		/* disable DLL_CTRL delay line settings */
+		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
+	}
+}
+
 #ifdef CONFIG_OF
 static int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
@@ -1175,43 +1213,13 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
 			| SDHCI_QUIRK_BROKEN_ADMA;
 
-	/*
-	 * The imx6q ROM code will change the default watermark level setting
-	 * to something insane.  Change it back here.
-	 */
-	if (esdhc_is_usdhc(imx_data)) {
-		writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+	sdhci_esdhc_imx_hwinit(host);
 
+	if (esdhc_is_usdhc(imx_data)) {
 		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
 		host->mmc->caps |= MMC_CAP_1_8V_DDR;
-
-		/*
-		 * ROM code will change the bit burst_length_enable setting
-		 * to zero if this usdhc is choosed to boot system. Change
-		 * it back here, otherwise it will impact the performance a
-		 * lot. This bit is used to enable/disable the burst length
-		 * for the external AHB2AXI bridge, it's usefully especially
-		 * for INCR transfer because without burst length indicator,
-		 * the AHB2AXI bridge does not know the burst length in
-		 * advance. And without burst length indicator, AHB INCR
-		 * transfer can only be converted to singles on the AXI side.
-		 */
-		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
-			| ESDHC_BURST_LEN_EN_INCR,
-			host->ioaddr + SDHCI_HOST_CONTROL);
-
 		if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
 			host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
-
-		/*
-		* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
-		* TO1.1, it's harmless for MX6SL
-		*/
-		writel(readl(host->ioaddr + 0x6c) | BIT(7),
-			host->ioaddr + 0x6c);
-
-		/* disable DLL_CTRL delay line settings */
-		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
 	}
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
@@ -1289,8 +1297,8 @@ static int sdhci_esdhc_resume(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
 
-	/* restore watermark setting in case it's lost in low power mode */
-	writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+	/* reinitialize hw state in case it's lost in low power mode */
+	sdhci_esdhc_imx_hwinit(host);
 
 	return sdhci_pltfm_resume(dev);
 }
#80 lore raw

PATCH 21/23 mmc: sdhci-esdhc-imx: factor out hw related intialization into function

Quoted 9 lines · Adrian Hunter
Quoted 5 lines · Dong Aisheng

Factor out hw related intialization into a separate function which has two benifits:
1) concentrate hw related intialization at one place
2) ease the hw state restore after resume by simply calling this function

There are really 2 changes here, please make it 2 patches.

Okay i will do it in V2.
Thanks for the suggestion.

Regards
Dong Aisheng

Quoted 114 lines
Quoted 113 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 76 +++++++++++++++++++++-----------------
 1 file changed, 42 insertions(+), 34 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +42 -34
index 3ff213f..95f3632 100644
@@ -978,6 +978,44 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
 	.ops = &sdhci_esdhc_ops,
 };
 
+static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+
+	if (esdhc_is_usdhc(imx_data)) {
+		/*
+		 * The imx6q ROM code will change the default watermark
+		 * level setting to something insane.  Change it back here.
+		 */
+		writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+
+		/*
+		 * ROM code will change the bit burst_length_enable setting
+		 * to zero if this usdhc is choosed to boot system. Change
+		 * it back here, otherwise it will impact the performance a
+		 * lot. This bit is used to enable/disable the burst length
+		 * for the external AHB2AXI bridge, it's usefully especially
+		 * for INCR transfer because without burst length indicator,
+		 * the AHB2AXI bridge does not know the burst length in
+		 * advance. And without burst length indicator, AHB INCR
+		 * transfer can only be converted to singles on the AXI side.
+		 */
+		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
+			| ESDHC_BURST_LEN_EN_INCR,
+			host->ioaddr + SDHCI_HOST_CONTROL);
+		/*
+		* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
+		* TO1.1, it's harmless for MX6SL
+		*/
+		writel(readl(host->ioaddr + 0x6c) | BIT(7),
+			host->ioaddr + 0x6c);
+
+		/* disable DLL_CTRL delay line settings */
+		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
+	}
+}
+
 #ifdef CONFIG_OF
 static int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
@@ -1175,43 +1213,13 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
 			| SDHCI_QUIRK_BROKEN_ADMA;
 
-	/*
-	 * The imx6q ROM code will change the default watermark level setting
-	 * to something insane.  Change it back here.
-	 */
-	if (esdhc_is_usdhc(imx_data)) {
-		writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+	sdhci_esdhc_imx_hwinit(host);
 
+	if (esdhc_is_usdhc(imx_data)) {
 		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
 		host->mmc->caps |= MMC_CAP_1_8V_DDR;
-
-		/*
-		 * ROM code will change the bit burst_length_enable setting
-		 * to zero if this usdhc is choosed to boot system. Change
-		 * it back here, otherwise it will impact the performance a
-		 * lot. This bit is used to enable/disable the burst length
-		 * for the external AHB2AXI bridge, it's usefully especially
-		 * for INCR transfer because without burst length indicator,
-		 * the AHB2AXI bridge does not know the burst length in
-		 * advance. And without burst length indicator, AHB INCR
-		 * transfer can only be converted to singles on the AXI side.
-		 */
-		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
-			| ESDHC_BURST_LEN_EN_INCR,
-			host->ioaddr + SDHCI_HOST_CONTROL);
-
 		if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
 			host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
-
-		/*
-		* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
-		* TO1.1, it's harmless for MX6SL
-		*/
-		writel(readl(host->ioaddr + 0x6c) | BIT(7),
-			host->ioaddr + 0x6c);
-
-		/* disable DLL_CTRL delay line settings */
-		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
 	}
 
 	if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
@@ -1289,8 +1297,8 @@ static int sdhci_esdhc_resume(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
 
-	/* restore watermark setting in case it's lost in low power mode */
-	writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+	/* reinitialize hw state in case it's lost in low power mode */
+	sdhci_esdhc_imx_hwinit(host);
 
 	return sdhci_pltfm_resume(dev);
 }
#81 lore raw

PATCH 22/23 mmc: sdhci-esdhc-imx: move tuning static configuration into hwinit function

In reply to Dong Aisheng

Move tuning static configuration into hwinit function. Tuning configuration may also be lost in low power mode, so need restore in hwinit().

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +18 -18
index 95f3632..98aa6b5 100644
@@ -483,7 +483,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 		} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
 			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
-			u32 tuning_ctrl;
 			if (val & SDHCI_CTRL_TUNED_CLK) {
 				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
 			} else {
@@ -496,18 +495,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
 				m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
-				tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
-				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT;
-				if (imx_data->boarddata.tuning_start_tap) {
-					tuning_ctrl &= ~ESDHC_TUNING_START_TAP_MASK;
-					tuning_ctrl |= imx_data->boarddata.tuning_start_tap;
-				}
-
-				if (imx_data->boarddata.tuning_step) {
-					tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK;
-					tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
-				}
-				writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
 			} else {
 				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
 			}
@@ -982,6 +969,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+	int tmp;
 
 	if (esdhc_is_usdhc(imx_data)) {
 		/*
@@ -1013,6 +1001,23 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
 
 		/* disable DLL_CTRL delay line settings */
 		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
+
+		if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
+			tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
+			tmp |= ESDHC_STD_TUNING_EN |
+				ESDHC_TUNING_START_TAP_DEFAULT;
+			if (imx_data->boarddata.tuning_start_tap) {
+				tmp &= ~ESDHC_TUNING_START_TAP_MASK;
+				tmp |= imx_data->boarddata.tuning_start_tap;
+			}
+
+			if (imx_data->boarddata.tuning_step) {
+				tmp &= ~ESDHC_TUNING_STEP_MASK;
+				tmp |= imx_data->boarddata.tuning_step
+					<< ESDHC_TUNING_STEP_SHIFT;
+			}
+			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
+		}
 	}
 }
 
@@ -1226,11 +1231,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		sdhci_esdhc_ops.platform_execute_tuning =
 					esdhc_executing_tuning;
 
-	if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
-		writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) |
-			ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT,
-			host->ioaddr + ESDHC_TUNING_CTRL);
-
 	if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
 		host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 
Signature · 1 line
1.9.1
maintainer
#82 lore raw

PATCH 22/23 mmc: sdhci-esdhc-imx: move tuning static configuration into hwinit function

Quoted 5 lines · Dong Aisheng

Move tuning static configuration into hwinit function. Tuning configuration may also be lost in low power mode, so need restore in hwinit().

Quoted 80 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)
drivers/mmc/host/sdhci-esdhc-imx.c +18 -18
index 95f3632..98aa6b5 100644
@@ -483,7 +483,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 		} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
 			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
-			u32 tuning_ctrl;
 			if (val & SDHCI_CTRL_TUNED_CLK) {
 				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
 			} else {
@@ -496,18 +495,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
 				m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
-				tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
-				tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT;
-				if (imx_data->boarddata.tuning_start_tap) {
-					tuning_ctrl &= ~ESDHC_TUNING_START_TAP_MASK;
-					tuning_ctrl |= imx_data->boarddata.tuning_start_tap;
-				}
-
-				if (imx_data->boarddata.tuning_step) {
-					tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK;
-					tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
-				}
-				writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
 			} else {
 				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
 			}
@@ -982,6 +969,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+	int tmp;
 
 	if (esdhc_is_usdhc(imx_data)) {
 		/*
@@ -1013,6 +1001,23 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
 
 		/* disable DLL_CTRL delay line settings */
 		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
+
+		if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
+			tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
+			tmp |= ESDHC_STD_TUNING_EN |
+				ESDHC_TUNING_START_TAP_DEFAULT;
+			if (imx_data->boarddata.tuning_start_tap) {
+				tmp &= ~ESDHC_TUNING_START_TAP_MASK;
+				tmp |= imx_data->boarddata.tuning_start_tap;
+			}
+
+			if (imx_data->boarddata.tuning_step) {
+				tmp &= ~ESDHC_TUNING_STEP_MASK;
+				tmp |= imx_data->boarddata.tuning_step
+					<< ESDHC_TUNING_STEP_SHIFT;
+			}
+			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
+		}
 	}
 }
 
@@ -1226,11 +1231,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		sdhci_esdhc_ops.platform_execute_tuning =
 					esdhc_executing_tuning;
 
-	if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
-		writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) |
-			ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP_DEFAULT,
-			host->ioaddr + ESDHC_TUNING_CTRL);
-
 	if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
 		host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 
#83 lore raw

PATCH 23/23 mmc: sdhci-esdhc-imx: clear tuning bits during hwinit

In reply to Dong Aisheng

The tuning bits like FBCLK_SEL, SMP_CLK_SEL and DLY_CELL which affects timing may have already been set by ROM if booting from SD3.0 mode like SDR104. Let's clear it first during hw initialization before do the new card enumeration.

For system resume case, it's safe to clear them too since the following card re-initialization in mmc_xx_init_card() will do retuning and set correct value again.

---
 drivers/mmc/host/sdhci-esdhc-imx.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +5 -0
index 98aa6b5..6a699d1 100644
@@ -1018,6 +1018,11 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
 			}
 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
 		}
+
+		/* clear tuning bits in case ROM has set it already */
+		writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
+		writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR);
+		writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
 	}
 }
 
Signature · 1 line
1.9.1
maintainer
#84 lore raw

PATCH 23/23 mmc: sdhci-esdhc-imx: clear tuning bits during hwinit

Quoted 10 lines · Dong Aisheng

The tuning bits like FBCLK_SEL, SMP_CLK_SEL and DLY_CELL which affects timing may have already been set by ROM if booting from SD3.0 mode like SDR104. Let's clear it first during hw initialization before do the new card enumeration.

For system resume case, it's safe to clear them too since the following card re-initialization in mmc_xx_init_card() will do retuning and set correct value again.

Quoted 21 lines
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mmc/host/sdhci-esdhc-imx.c +5 -0
index 98aa6b5..6a699d1 100644
@@ -1018,6 +1018,11 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
 			}
 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
 		}
+
+		/* clear tuning bits in case ROM has set it already */
+		writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
+		writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR);
+		writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
 	}
 }