129 lines
5.0 KiB
Diff
129 lines
5.0 KiB
Diff
From 848beabc268b0e12a5bc0dbe71c45c5db7a12b43 Mon Sep 17 00:00:00 2001
|
|
From: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
|
|
Date: Wed, 30 Jul 2025 11:35:43 +0530
|
|
Subject: mmc: sdhci-of-arasan: Ensure CD logic stabilization before power-up
|
|
|
|
During SD suspend/resume without a full card rescan (when using
|
|
non-removable SD cards for rootfs), the SD card initialization may fail
|
|
after resume. This occurs because, after a host controller reset, the
|
|
card detect logic may take time to stabilize due to debounce logic.
|
|
Without waiting for stabilization, the host may attempt powering up the
|
|
card prematurely, leading to command timeouts during resume flow.
|
|
Add sdhci_arasan_set_power_and_bus_voltage() to wait for the card detect
|
|
stable bit before power up the card. Since the stabilization time
|
|
is not fixed, a maximum timeout of one second is used to ensure
|
|
sufficient wait time for the card detect signal to stabilize.
|
|
|
|
Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
|
|
Cc: stable@vger.kernel.org
|
|
Link: https://lore.kernel.org/r/20250730060543.1735971-1-sai.krishna.potthuri@amd.com
|
|
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
|
---
|
|
drivers/mmc/host/sdhci-of-arasan.c | 33 ++++++++++++++++++++++++++++--
|
|
1 file changed, 31 insertions(+), 2 deletions(-)
|
|
|
|
--- a/drivers/mmc/host/sdhci-of-arasan.c
|
|
+++ b/drivers/mmc/host/sdhci-of-arasan.c
|
|
@@ -99,6 +99,9 @@
|
|
#define HIWORD_UPDATE(val, mask, shift) \
|
|
((val) << (shift) | (mask) << ((shift) + 16))
|
|
|
|
+#define CD_STABLE_TIMEOUT_US 1000000
|
|
+#define CD_STABLE_MAX_SLEEP_US 10
|
|
+
|
|
/**
|
|
* struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map
|
|
*
|
|
@@ -206,12 +209,15 @@ struct sdhci_arasan_data {
|
|
* 19MHz instead
|
|
*/
|
|
#define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2)
|
|
+/* Enable CD stable check before power-up */
|
|
+#define SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE BIT(3)
|
|
};
|
|
|
|
struct sdhci_arasan_of_data {
|
|
const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
|
|
const struct sdhci_pltfm_data *pdata;
|
|
const struct sdhci_arasan_clk_ops *clk_ops;
|
|
+ u32 quirks;
|
|
};
|
|
|
|
static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
|
|
@@ -514,6 +520,24 @@ static int sdhci_arasan_voltage_switch(s
|
|
return -EINVAL;
|
|
}
|
|
|
|
+static void sdhci_arasan_set_power_and_bus_voltage(struct sdhci_host *host, unsigned char mode,
|
|
+ unsigned short vdd)
|
|
+{
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
|
|
+ u32 reg;
|
|
+
|
|
+ /*
|
|
+ * Ensure that the card detect logic has stabilized before powering up, this is
|
|
+ * necessary after a host controller reset.
|
|
+ */
|
|
+ if (mode == MMC_POWER_UP && sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE)
|
|
+ read_poll_timeout(sdhci_readl, reg, reg & SDHCI_CD_STABLE, CD_STABLE_MAX_SLEEP_US,
|
|
+ CD_STABLE_TIMEOUT_US, false, host, SDHCI_PRESENT_STATE);
|
|
+
|
|
+ sdhci_set_power_and_bus_voltage(host, mode, vdd);
|
|
+}
|
|
+
|
|
static const struct sdhci_ops sdhci_arasan_ops = {
|
|
.set_clock = sdhci_arasan_set_clock,
|
|
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
|
@@ -521,7 +545,7 @@ static const struct sdhci_ops sdhci_aras
|
|
.set_bus_width = sdhci_set_bus_width,
|
|
.reset = sdhci_arasan_reset,
|
|
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
|
- .set_power = sdhci_set_power_and_bus_voltage,
|
|
+ .set_power = sdhci_arasan_set_power_and_bus_voltage,
|
|
.hw_reset = sdhci_arasan_hw_reset,
|
|
};
|
|
|
|
@@ -570,7 +594,7 @@ static const struct sdhci_ops sdhci_aras
|
|
.set_bus_width = sdhci_set_bus_width,
|
|
.reset = sdhci_arasan_reset,
|
|
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
|
- .set_power = sdhci_set_power_and_bus_voltage,
|
|
+ .set_power = sdhci_arasan_set_power_and_bus_voltage,
|
|
.irq = sdhci_arasan_cqhci_irq,
|
|
};
|
|
|
|
@@ -1447,6 +1471,7 @@ static const struct sdhci_arasan_clk_ops
|
|
static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = {
|
|
.pdata = &sdhci_arasan_zynqmp_pdata,
|
|
.clk_ops = &zynqmp_clk_ops,
|
|
+ .quirks = SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE,
|
|
};
|
|
|
|
static const struct sdhci_arasan_clk_ops versal_clk_ops = {
|
|
@@ -1457,6 +1482,7 @@ static const struct sdhci_arasan_clk_ops
|
|
static struct sdhci_arasan_of_data sdhci_arasan_versal_data = {
|
|
.pdata = &sdhci_arasan_zynqmp_pdata,
|
|
.clk_ops = &versal_clk_ops,
|
|
+ .quirks = SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE,
|
|
};
|
|
|
|
static const struct sdhci_arasan_clk_ops versal_net_clk_ops = {
|
|
@@ -1467,6 +1493,7 @@ static const struct sdhci_arasan_clk_ops
|
|
static struct sdhci_arasan_of_data sdhci_arasan_versal_net_data = {
|
|
.pdata = &sdhci_arasan_versal_net_pdata,
|
|
.clk_ops = &versal_net_clk_ops,
|
|
+ .quirks = SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE,
|
|
};
|
|
|
|
static struct sdhci_arasan_of_data intel_keembay_emmc_data = {
|
|
@@ -1945,6 +1972,8 @@ static int sdhci_arasan_probe(struct pla
|
|
if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1"))
|
|
sdhci_arasan_update_clockmultiplier(host, 0x0);
|
|
|
|
+ sdhci_arasan->quirks |= data->quirks;
|
|
+
|
|
if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") ||
|
|
of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") ||
|
|
of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) {
|