diff options
-rw-r--r-- | queue-6.12/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch | 191 | ||||
-rw-r--r-- | queue-6.12/series | 1 | ||||
-rw-r--r-- | queue-6.15/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch | 191 | ||||
-rw-r--r-- | queue-6.15/series | 2 | ||||
-rw-r--r-- | queue-6.6/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch | 191 | ||||
-rw-r--r-- | queue-6.6/series | 1 |
6 files changed, 1 insertions, 576 deletions
diff --git a/queue-6.12/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch b/queue-6.12/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch deleted file mode 100644 index 76df4b3f96b..00000000000 --- a/queue-6.12/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch +++ /dev/null @@ -1,191 +0,0 @@ -From 3fb85d6675c9d765525e92b40edc296cfd7914ec Mon Sep 17 00:00:00 2001 -From: Sasha Levin <sashal@kernel.org> -Date: Fri, 28 Mar 2025 19:25:17 +0800 -Subject: mmc: sdhci-esdhc-imx: Save tuning value when card stays powered in - suspend - -From: Luke Wang <ziniu.wang_1@nxp.com> - -[ Upstream commit c63d25cdc59ae2891b39ba2da950910291d9bcbf ] - -For SoCs like i.MX6UL(L/Z) and i.MX7D, USDHC powers off completely during -system power management (PM), causing the internal tuning status to be -lost. To address this, save the tuning value when system suspend and -restore it for any command issued after system resume when re-tuning is -held. - -A typical case involves SDIO WiFi devices with the MMC_PM_KEEP_POWER and -MMC_PM_WAKE_SDIO_IRQ flag, which retain power during system PM. To -conserve power, WiFi switches to 1-bit mode and restores 4-bit mode upon -resume. As per the specification, tuning commands are not supported in -1-bit mode. When sending CMD52 to restore 4-bit mode, re-tuning must be -held. However, CMD52 still requires a correct sample point to avoid CRC -errors, necessitating preservation of the previous tuning value. - -Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com> -Acked-by: Adrian Hunter <adrian.hunter@intel.com> -Link: https://lore.kernel.org/r/20250328112517.2624806-1-ziniu.wang_1@nxp.com -Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> -Signed-off-by: Sasha Levin <sashal@kernel.org> ---- - drivers/mmc/host/sdhci-esdhc-imx.c | 88 +++++++++++++++++++++++++++++- - 1 file changed, 86 insertions(+), 2 deletions(-) - -diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c -index d84aa20f03589..7a0b7bfa1bb69 100644 ---- a/drivers/mmc/host/sdhci-esdhc-imx.c -+++ b/drivers/mmc/host/sdhci-esdhc-imx.c -@@ -80,6 +80,8 @@ - #define ESDHC_TUNE_CTRL_STEP 1 - #define ESDHC_TUNE_CTRL_MIN 0 - #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) -+#define ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK GENMASK(30, 24) -+#define ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK GENMASK(14, 8) - - /* strobe dll register */ - #define ESDHC_STROBE_DLL_CTRL 0x70 -@@ -234,6 +236,7 @@ struct esdhc_platform_data { - unsigned int tuning_step; /* The delay cell steps in tuning procedure */ - unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */ - unsigned int strobe_dll_delay_target; /* The delay cell for strobe pad (read clock) */ -+ unsigned int saved_tuning_delay_cell; /* save the value of tuning delay cell */ - }; - - struct esdhc_soc_data { -@@ -1056,7 +1059,7 @@ static void esdhc_reset_tuning(struct sdhci_host *host) - { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -- u32 ctrl; -+ u32 ctrl, tuning_ctrl; - int ret; - - /* Reset the tuning circuit */ -@@ -1070,6 +1073,16 @@ static void esdhc_reset_tuning(struct sdhci_host *host) - writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); - } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { - writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); -+ /* -+ * enable the std tuning just in case it cleared in -+ * sdhc_esdhc_tuning_restore. -+ */ -+ tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL); -+ if (!(tuning_ctrl & ESDHC_STD_TUNING_EN)) { -+ tuning_ctrl |= ESDHC_STD_TUNING_EN; -+ writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); -+ } -+ - ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); - ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; -@@ -1148,7 +1161,8 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) - reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | - ESDHC_MIX_CTRL_FBCLK_SEL; - writel(reg, host->ioaddr + ESDHC_MIX_CTRL); -- writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, val), -+ host->ioaddr + ESDHC_TUNE_CTRL_STATUS); - dev_dbg(mmc_dev(host->mmc), - "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", - val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); -@@ -1556,6 +1570,57 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) - } - } - -+static void sdhc_esdhc_tuning_save(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -+ u32 reg; -+ -+ /* -+ * SD/eMMC do not need this tuning save because it will re-init -+ * after system resume back. -+ * Here save the tuning delay value for SDIO device since it may -+ * keep power during system PM. And for usdhc, only SDR50 and -+ * SDR104 mode for SDIO device need to do tuning, and need to -+ * save/restore. -+ */ -+ if (host->timing == MMC_TIMING_UHS_SDR50 || -+ host->timing == MMC_TIMING_UHS_SDR104) { -+ reg = readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ reg = FIELD_GET(ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK, reg); -+ imx_data->boarddata.saved_tuning_delay_cell = reg; -+ } -+} -+ -+static void sdhc_esdhc_tuning_restore(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -+ u32 reg; -+ -+ if (host->timing == MMC_TIMING_UHS_SDR50 || -+ host->timing == MMC_TIMING_UHS_SDR104) { -+ /* -+ * restore the tuning delay value actually is a -+ * manual tuning method, so clear the standard -+ * tuning enable bit here. Will set back this -+ * ESDHC_STD_TUNING_EN in esdhc_reset_tuning() -+ * when trigger re-tuning. -+ */ -+ reg = readl(host->ioaddr + ESDHC_TUNING_CTRL); -+ reg &= ~ESDHC_STD_TUNING_EN; -+ writel(reg, host->ioaddr + ESDHC_TUNING_CTRL); -+ -+ reg = readl(host->ioaddr + ESDHC_MIX_CTRL); -+ reg |= ESDHC_MIX_CTRL_SMPCLK_SEL | ESDHC_MIX_CTRL_FBCLK_SEL; -+ writel(reg, host->ioaddr + ESDHC_MIX_CTRL); -+ -+ writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, -+ imx_data->boarddata.saved_tuning_delay_cell), -+ host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ } -+} -+ - static void esdhc_cqe_enable(struct mmc_host *mmc) - { - struct sdhci_host *host = mmc_priv(mmc); -@@ -1887,6 +1952,15 @@ static int sdhci_esdhc_suspend(struct device *dev) - if (host->tuning_mode != SDHCI_TUNING_MODE_3) - mmc_retune_needed(host->mmc); - -+ /* -+ * For the device need to keep power during system PM, need -+ * to save the tuning delay value just in case the usdhc -+ * lost power during system PM. -+ */ -+ if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && -+ esdhc_is_usdhc(imx_data)) -+ sdhc_esdhc_tuning_save(host); -+ - ret = sdhci_suspend_host(host); - if (ret) - return ret; -@@ -1903,6 +1977,8 @@ static int sdhci_esdhc_suspend(struct device *dev) - static int sdhci_esdhc_resume(struct device *dev) - { - struct sdhci_host *host = dev_get_drvdata(dev); -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - int ret; - - ret = pinctrl_pm_select_default_state(dev); -@@ -1916,6 +1992,14 @@ static int sdhci_esdhc_resume(struct device *dev) - if (ret) - return ret; - -+ /* -+ * restore the saved tuning delay value for the device which keep -+ * power during system PM. -+ */ -+ if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && -+ esdhc_is_usdhc(imx_data)) -+ sdhc_esdhc_tuning_restore(host); -+ - if (host->mmc->caps2 & MMC_CAP2_CQE) - ret = cqhci_resume(host->mmc); - --- -2.39.5 - diff --git a/queue-6.12/series b/queue-6.12/series index cffbf4a1539..e63740e55b5 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -170,7 +170,6 @@ clocksource-fix-the-cpus-choice-in-the-watchdog-per-.patch power-supply-collie-fix-wakeup-source-leaks-on-devic.patch mmc-add-quirk-to-disable-ddr50-tuning.patch acpica-avoid-sequence-overread-in-call-to-strncmp.patch -mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch asoc-tas2770-power-cycle-amp-on-isense-vsense-change.patch asoc-intel-sdw_utils-assign-initial-value-in-asoc_sd.patch acpi-bus-bail-out-if-acpi_kobj-registration-fails.patch diff --git a/queue-6.15/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch b/queue-6.15/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch deleted file mode 100644 index 7ee2c6df631..00000000000 --- a/queue-6.15/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch +++ /dev/null @@ -1,191 +0,0 @@ -From b1e8736ca5f1695ca4957444cf4351b16ae83fc9 Mon Sep 17 00:00:00 2001 -From: Sasha Levin <sashal@kernel.org> -Date: Fri, 28 Mar 2025 19:25:17 +0800 -Subject: mmc: sdhci-esdhc-imx: Save tuning value when card stays powered in - suspend - -From: Luke Wang <ziniu.wang_1@nxp.com> - -[ Upstream commit c63d25cdc59ae2891b39ba2da950910291d9bcbf ] - -For SoCs like i.MX6UL(L/Z) and i.MX7D, USDHC powers off completely during -system power management (PM), causing the internal tuning status to be -lost. To address this, save the tuning value when system suspend and -restore it for any command issued after system resume when re-tuning is -held. - -A typical case involves SDIO WiFi devices with the MMC_PM_KEEP_POWER and -MMC_PM_WAKE_SDIO_IRQ flag, which retain power during system PM. To -conserve power, WiFi switches to 1-bit mode and restores 4-bit mode upon -resume. As per the specification, tuning commands are not supported in -1-bit mode. When sending CMD52 to restore 4-bit mode, re-tuning must be -held. However, CMD52 still requires a correct sample point to avoid CRC -errors, necessitating preservation of the previous tuning value. - -Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com> -Acked-by: Adrian Hunter <adrian.hunter@intel.com> -Link: https://lore.kernel.org/r/20250328112517.2624806-1-ziniu.wang_1@nxp.com -Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> -Signed-off-by: Sasha Levin <sashal@kernel.org> ---- - drivers/mmc/host/sdhci-esdhc-imx.c | 88 +++++++++++++++++++++++++++++- - 1 file changed, 86 insertions(+), 2 deletions(-) - -diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c -index ff78a7c6a04c9..7e8addaed697e 100644 ---- a/drivers/mmc/host/sdhci-esdhc-imx.c -+++ b/drivers/mmc/host/sdhci-esdhc-imx.c -@@ -81,6 +81,8 @@ - #define ESDHC_TUNE_CTRL_STEP 1 - #define ESDHC_TUNE_CTRL_MIN 0 - #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) -+#define ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK GENMASK(30, 24) -+#define ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK GENMASK(14, 8) - - /* strobe dll register */ - #define ESDHC_STROBE_DLL_CTRL 0x70 -@@ -235,6 +237,7 @@ struct esdhc_platform_data { - unsigned int tuning_step; /* The delay cell steps in tuning procedure */ - unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */ - unsigned int strobe_dll_delay_target; /* The delay cell for strobe pad (read clock) */ -+ unsigned int saved_tuning_delay_cell; /* save the value of tuning delay cell */ - }; - - struct esdhc_soc_data { -@@ -1057,7 +1060,7 @@ static void esdhc_reset_tuning(struct sdhci_host *host) - { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -- u32 ctrl; -+ u32 ctrl, tuning_ctrl; - int ret; - - /* Reset the tuning circuit */ -@@ -1071,6 +1074,16 @@ static void esdhc_reset_tuning(struct sdhci_host *host) - writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); - } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { - writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); -+ /* -+ * enable the std tuning just in case it cleared in -+ * sdhc_esdhc_tuning_restore. -+ */ -+ tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL); -+ if (!(tuning_ctrl & ESDHC_STD_TUNING_EN)) { -+ tuning_ctrl |= ESDHC_STD_TUNING_EN; -+ writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); -+ } -+ - ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); - ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; -@@ -1149,7 +1162,8 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) - reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | - ESDHC_MIX_CTRL_FBCLK_SEL; - writel(reg, host->ioaddr + ESDHC_MIX_CTRL); -- writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, val), -+ host->ioaddr + ESDHC_TUNE_CTRL_STATUS); - dev_dbg(mmc_dev(host->mmc), - "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", - val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); -@@ -1569,6 +1583,57 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) - } - } - -+static void sdhc_esdhc_tuning_save(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -+ u32 reg; -+ -+ /* -+ * SD/eMMC do not need this tuning save because it will re-init -+ * after system resume back. -+ * Here save the tuning delay value for SDIO device since it may -+ * keep power during system PM. And for usdhc, only SDR50 and -+ * SDR104 mode for SDIO device need to do tuning, and need to -+ * save/restore. -+ */ -+ if (host->timing == MMC_TIMING_UHS_SDR50 || -+ host->timing == MMC_TIMING_UHS_SDR104) { -+ reg = readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ reg = FIELD_GET(ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK, reg); -+ imx_data->boarddata.saved_tuning_delay_cell = reg; -+ } -+} -+ -+static void sdhc_esdhc_tuning_restore(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -+ u32 reg; -+ -+ if (host->timing == MMC_TIMING_UHS_SDR50 || -+ host->timing == MMC_TIMING_UHS_SDR104) { -+ /* -+ * restore the tuning delay value actually is a -+ * manual tuning method, so clear the standard -+ * tuning enable bit here. Will set back this -+ * ESDHC_STD_TUNING_EN in esdhc_reset_tuning() -+ * when trigger re-tuning. -+ */ -+ reg = readl(host->ioaddr + ESDHC_TUNING_CTRL); -+ reg &= ~ESDHC_STD_TUNING_EN; -+ writel(reg, host->ioaddr + ESDHC_TUNING_CTRL); -+ -+ reg = readl(host->ioaddr + ESDHC_MIX_CTRL); -+ reg |= ESDHC_MIX_CTRL_SMPCLK_SEL | ESDHC_MIX_CTRL_FBCLK_SEL; -+ writel(reg, host->ioaddr + ESDHC_MIX_CTRL); -+ -+ writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, -+ imx_data->boarddata.saved_tuning_delay_cell), -+ host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ } -+} -+ - static void esdhc_cqe_enable(struct mmc_host *mmc) - { - struct sdhci_host *host = mmc_priv(mmc); -@@ -1900,6 +1965,15 @@ static int sdhci_esdhc_suspend(struct device *dev) - if (host->tuning_mode != SDHCI_TUNING_MODE_3) - mmc_retune_needed(host->mmc); - -+ /* -+ * For the device need to keep power during system PM, need -+ * to save the tuning delay value just in case the usdhc -+ * lost power during system PM. -+ */ -+ if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && -+ esdhc_is_usdhc(imx_data)) -+ sdhc_esdhc_tuning_save(host); -+ - ret = sdhci_suspend_host(host); - if (ret) - return ret; -@@ -1916,6 +1990,8 @@ static int sdhci_esdhc_suspend(struct device *dev) - static int sdhci_esdhc_resume(struct device *dev) - { - struct sdhci_host *host = dev_get_drvdata(dev); -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - int ret; - - ret = pinctrl_pm_select_default_state(dev); -@@ -1929,6 +2005,14 @@ static int sdhci_esdhc_resume(struct device *dev) - if (ret) - return ret; - -+ /* -+ * restore the saved tuning delay value for the device which keep -+ * power during system PM. -+ */ -+ if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && -+ esdhc_is_usdhc(imx_data)) -+ sdhc_esdhc_tuning_restore(host); -+ - if (host->mmc->caps2 & MMC_CAP2_CQE) - ret = cqhci_resume(host->mmc); - --- -2.39.5 - diff --git a/queue-6.15/series b/queue-6.15/series index e49b7900304..6f39856164d 100644 --- a/queue-6.15/series +++ b/queue-6.15/series @@ -210,7 +210,6 @@ power-supply-gpio-charger-fix-wakeup-source-leaks-on.patch power-supply-collie-fix-wakeup-source-leaks-on-devic.patch mmc-add-quirk-to-disable-ddr50-tuning.patch acpica-avoid-sequence-overread-in-call-to-strncmp.patch -mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch edac-igen6-skip-absent-memory-controllers.patch asoc-tas2770-power-cycle-amp-on-isense-vsense-change.patch asoc-intel-sdw_utils-assign-initial-value-in-asoc_sd.patch @@ -586,3 +585,4 @@ pci-pciehp-ignore-belated-presence-detect-changed-ca.patch cifs-remove-duplicate-fattr-cf_dtype-assignment-from.patch erofs-refuse-crafted-out-of-file-range-encoded-exten.patch erofs-remove-a-superfluous-check-for-encoded-extents.patch +revert-drm-amd-display-fix-vupdate-offset-calculations-for-dcn401.patch diff --git a/queue-6.6/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch b/queue-6.6/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch deleted file mode 100644 index 3d53ee02f94..00000000000 --- a/queue-6.6/mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch +++ /dev/null @@ -1,191 +0,0 @@ -From be50d4547d1bcaf10c2e69fdd87c90f10b1f326e Mon Sep 17 00:00:00 2001 -From: Sasha Levin <sashal@kernel.org> -Date: Fri, 28 Mar 2025 19:25:17 +0800 -Subject: mmc: sdhci-esdhc-imx: Save tuning value when card stays powered in - suspend - -From: Luke Wang <ziniu.wang_1@nxp.com> - -[ Upstream commit c63d25cdc59ae2891b39ba2da950910291d9bcbf ] - -For SoCs like i.MX6UL(L/Z) and i.MX7D, USDHC powers off completely during -system power management (PM), causing the internal tuning status to be -lost. To address this, save the tuning value when system suspend and -restore it for any command issued after system resume when re-tuning is -held. - -A typical case involves SDIO WiFi devices with the MMC_PM_KEEP_POWER and -MMC_PM_WAKE_SDIO_IRQ flag, which retain power during system PM. To -conserve power, WiFi switches to 1-bit mode and restores 4-bit mode upon -resume. As per the specification, tuning commands are not supported in -1-bit mode. When sending CMD52 to restore 4-bit mode, re-tuning must be -held. However, CMD52 still requires a correct sample point to avoid CRC -errors, necessitating preservation of the previous tuning value. - -Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com> -Acked-by: Adrian Hunter <adrian.hunter@intel.com> -Link: https://lore.kernel.org/r/20250328112517.2624806-1-ziniu.wang_1@nxp.com -Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> -Signed-off-by: Sasha Levin <sashal@kernel.org> ---- - drivers/mmc/host/sdhci-esdhc-imx.c | 88 +++++++++++++++++++++++++++++- - 1 file changed, 86 insertions(+), 2 deletions(-) - -diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c -index e4e9b84f210b2..28ece6839aead 100644 ---- a/drivers/mmc/host/sdhci-esdhc-imx.c -+++ b/drivers/mmc/host/sdhci-esdhc-imx.c -@@ -80,6 +80,8 @@ - #define ESDHC_TUNE_CTRL_STEP 1 - #define ESDHC_TUNE_CTRL_MIN 0 - #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) -+#define ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK GENMASK(30, 24) -+#define ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK GENMASK(14, 8) - - /* strobe dll register */ - #define ESDHC_STROBE_DLL_CTRL 0x70 -@@ -231,6 +233,7 @@ struct esdhc_platform_data { - unsigned int tuning_step; /* The delay cell steps in tuning procedure */ - unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */ - unsigned int strobe_dll_delay_target; /* The delay cell for strobe pad (read clock) */ -+ unsigned int saved_tuning_delay_cell; /* save the value of tuning delay cell */ - }; - - struct esdhc_soc_data { -@@ -1052,7 +1055,7 @@ static void esdhc_reset_tuning(struct sdhci_host *host) - { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -- u32 ctrl; -+ u32 ctrl, tuning_ctrl; - int ret; - - /* Reset the tuning circuit */ -@@ -1066,6 +1069,16 @@ static void esdhc_reset_tuning(struct sdhci_host *host) - writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); - } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { - writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); -+ /* -+ * enable the std tuning just in case it cleared in -+ * sdhc_esdhc_tuning_restore. -+ */ -+ tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL); -+ if (!(tuning_ctrl & ESDHC_STD_TUNING_EN)) { -+ tuning_ctrl |= ESDHC_STD_TUNING_EN; -+ writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); -+ } -+ - ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); - ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; -@@ -1144,7 +1157,8 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) - reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | - ESDHC_MIX_CTRL_FBCLK_SEL; - writel(reg, host->ioaddr + ESDHC_MIX_CTRL); -- writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, val), -+ host->ioaddr + ESDHC_TUNE_CTRL_STATUS); - dev_dbg(mmc_dev(host->mmc), - "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", - val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); -@@ -1532,6 +1546,57 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) - } - } - -+static void sdhc_esdhc_tuning_save(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -+ u32 reg; -+ -+ /* -+ * SD/eMMC do not need this tuning save because it will re-init -+ * after system resume back. -+ * Here save the tuning delay value for SDIO device since it may -+ * keep power during system PM. And for usdhc, only SDR50 and -+ * SDR104 mode for SDIO device need to do tuning, and need to -+ * save/restore. -+ */ -+ if (host->timing == MMC_TIMING_UHS_SDR50 || -+ host->timing == MMC_TIMING_UHS_SDR104) { -+ reg = readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ reg = FIELD_GET(ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK, reg); -+ imx_data->boarddata.saved_tuning_delay_cell = reg; -+ } -+} -+ -+static void sdhc_esdhc_tuning_restore(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); -+ u32 reg; -+ -+ if (host->timing == MMC_TIMING_UHS_SDR50 || -+ host->timing == MMC_TIMING_UHS_SDR104) { -+ /* -+ * restore the tuning delay value actually is a -+ * manual tuning method, so clear the standard -+ * tuning enable bit here. Will set back this -+ * ESDHC_STD_TUNING_EN in esdhc_reset_tuning() -+ * when trigger re-tuning. -+ */ -+ reg = readl(host->ioaddr + ESDHC_TUNING_CTRL); -+ reg &= ~ESDHC_STD_TUNING_EN; -+ writel(reg, host->ioaddr + ESDHC_TUNING_CTRL); -+ -+ reg = readl(host->ioaddr + ESDHC_MIX_CTRL); -+ reg |= ESDHC_MIX_CTRL_SMPCLK_SEL | ESDHC_MIX_CTRL_FBCLK_SEL; -+ writel(reg, host->ioaddr + ESDHC_MIX_CTRL); -+ -+ writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, -+ imx_data->boarddata.saved_tuning_delay_cell), -+ host->ioaddr + ESDHC_TUNE_CTRL_STATUS); -+ } -+} -+ - static void esdhc_cqe_enable(struct mmc_host *mmc) - { - struct sdhci_host *host = mmc_priv(mmc); -@@ -1856,6 +1921,15 @@ static int sdhci_esdhc_suspend(struct device *dev) - if (host->tuning_mode != SDHCI_TUNING_MODE_3) - mmc_retune_needed(host->mmc); - -+ /* -+ * For the device need to keep power during system PM, need -+ * to save the tuning delay value just in case the usdhc -+ * lost power during system PM. -+ */ -+ if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && -+ esdhc_is_usdhc(imx_data)) -+ sdhc_esdhc_tuning_save(host); -+ - ret = sdhci_suspend_host(host); - if (ret) - return ret; -@@ -1872,6 +1946,8 @@ static int sdhci_esdhc_suspend(struct device *dev) - static int sdhci_esdhc_resume(struct device *dev) - { - struct sdhci_host *host = dev_get_drvdata(dev); -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - int ret; - - ret = pinctrl_pm_select_default_state(dev); -@@ -1885,6 +1961,14 @@ static int sdhci_esdhc_resume(struct device *dev) - if (ret) - return ret; - -+ /* -+ * restore the saved tuning delay value for the device which keep -+ * power during system PM. -+ */ -+ if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && -+ esdhc_is_usdhc(imx_data)) -+ sdhc_esdhc_tuning_restore(host); -+ - if (host->mmc->caps2 & MMC_CAP2_CQE) - ret = cqhci_resume(host->mmc); - --- -2.39.5 - diff --git a/queue-6.6/series b/queue-6.6/series index 7fe38d705f5..c574e7b6eb9 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -119,7 +119,6 @@ clocksource-fix-the-cpus-choice-in-the-watchdog-per-.patch power-supply-collie-fix-wakeup-source-leaks-on-devic.patch mmc-add-quirk-to-disable-ddr50-tuning.patch acpica-avoid-sequence-overread-in-call-to-strncmp.patch -mmc-sdhci-esdhc-imx-save-tuning-value-when-card-stay.patch asoc-tas2770-power-cycle-amp-on-isense-vsense-change.patch acpi-bus-bail-out-if-acpi_kobj-registration-fails.patch acpi-add-missing-prototype-for-non-config_suspend-co.patch |