Re: [PATCH v1 0/3] mmc: dw_mmc-rockchip: Add stability quirk for NanoPi R76S
From: Shawn Lin <shawn.lin@rock-chips.com>
Date: 2026-01-16 05:07:56
Also in:
linux-devicetree, linux-mmc, linux-rockchip
在 2026/01/16 星期五 3:39, Marco Schirrmeister 写道:
Hello Shawn, On Thu, Jan 15, 2026 at 1:25 AM Shawn Lin [off-list ref] wrote:quoted
quoted
Based on this, it makes me believe that power to the sd card is completely cut and when it wakes up and knows how to continue, it still must go through the retraining phase.This is another mistake for your NanoPi R76S board. Before sent this patch, I already checked the dts and saw sdmmc uses vmmc-supply = <&vcc_3v3_s3> which is marked as regulator-always-on, but it's *NOT* actually per the shcematic[1][2]. So need another fix for your board to make it actually gpio-based power controller instaed of function IO based, as when powering off the power domain, the power control bit will not be able to maintain. [1] https://wiki.friendlyelec.com/wiki/images/6/60/NanoPi_R76S_LP4X_2411_SCH.pdf [2] https://wiki.friendlyelec.com/wiki/images/9/90/NanoPi_R76S_LP5_2411_SCH.pdf Except for the patches you have tested, please append the blow patch as well to test.Bingo. These DTS additions fixed the power stability for the SD card. I have verified that the card now wakes up instantly with no errors and no retraining delay.
Thanks, I will fold these two patches into my thread of V4 to fix all these problems.
I tested this both with and without your driver patch (the save/restore phases logic). This confirms the issue was indeed the power rail being cut during idle periods. Great find on the schematic!quoted
--- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-r76s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-r76s.dts@@ -192,6 +192,18 @@ regulator-name = "vcc_3v3_s0"; vin-supply = <&vcc_3v3_s3>; }; + + vcc3v3_sd: regulator-vcc-3v3-sd { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_pwren>; + regulator-name = "vcc3v3_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s0>; + }; }; &combphy0_ps {@@ -726,6 +738,12 @@ }; }; + sdmmc { + sdmmc_pwren: sdmmc-pwren { + rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO&pcfg_pull_none>; + }; + }; + usb { usb_otg0_pwren_h: usb-otg0-pwren-h { rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;@@ -751,11 +769,14 @@ bus-width = <4>; cap-mmc-highspeed; cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; disable-wp; no-mmc; no-sdio; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; sd-uhs-sdr104; - vmmc-supply = <&vcc_3v3_s3>; + vmmc-supply = <&vcc3v3_sd>; vqmmc-supply = <&vccio_sd_s0>; status = "okay";quoted
quoted
--- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c@@ -36,6 +36,8 @@ struct dw_mci_rockchip_priv_data { int default_sample_phase; int num_phases; bool internal_phase; + int sample_phase; + int drv_phase; }; /*@@ -573,9 +575,43 @@ static void dw_mci_rockchip_remove(structplatform_device *pdev) dw_mci_pltfm_remove(pdev); } +static int dw_mci_rockchip_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct dw_mci *host = platform_get_drvdata(pdev); + struct dw_mci_rockchip_priv_data *priv = host->priv; + + if (priv->internal_phase) { + priv->sample_phase = rockchip_mmc_get_phase(host, true); + priv->drv_phase = rockchip_mmc_get_phase(host, false); + } + + return dw_mci_runtime_suspend(dev); +} + +static int dw_mci_rockchip_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct dw_mci *host = platform_get_drvdata(pdev); + struct dw_mci_rockchip_priv_data *priv = host->priv; + int ret; + + ret = dw_mci_runtime_resume(dev); + if (ret) + return ret; + + if (priv->internal_phase) { + rockchip_mmc_set_phase(host, true, priv->sample_phase); + rockchip_mmc_set_phase(host, false, priv->drv_phase); + mci_writel(host, MISC_CON, MEM_CLK_AUTOGATE_ENABLE); + } + + return ret; +} + static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = { SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) - RUNTIME_PM_OPS(dw_mci_runtime_suspend, dw_mci_runtime_resume, NULL) + RUNTIME_PM_OPS(dw_mci_rockchip_runtime_suspend, dw_mci_rockchip_runtime_resume, NULL) }; static struct platform_driver dw_mci_rockchip_pltfm_driver = {