[PATCH v1 0/3] mmc: dw_mmc-rockchip: Add stability quirk for NanoPi R76S

Shawn Lin shawn.lin at rock-chips.com
Wed Jan 14 16:25:17 PST 2026


在 2026/01/15 星期四 3:51, Marco Schirrmeister 写道:
> Hello Shawn,
> 
> On Wed, Jan 14, 2026 at 9:08 AM Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>
>> Except for the patch mentioned above for fixing the hot-plug problem
>> which you confirmed to work fine. I looked the code a bit and see
>> a potential problem related to the runtime suspend + power-domain.
>> Please check the patch to see if it fixes your problem:
> 
> I tested your patch and the issue is still present. For verification I did
> add some debug statements and just to see what it saves and restores.
> 
> The symbols are there.
> root at nanopi-r76s ~# grep dw_mci_rockchip_runtime /proc/kallsyms
> ffff800080bf27a0 t dw_mci_rockchip_runtime_suspend
> ffff800080bf29c0 t dw_mci_rockchip_runtime_resume
> 
> # dmesg output
> [Wed Jan 14 20:13:46 2026] E220d: Restoring phases: sample=231, drv=180
> [Wed Jan 14 20:13:46 2026] mmc_host mmc1: Bus speed (slot 0) = 400000Hz
> [Wed Jan 14 20:13:47 2026] mmc_host mmc1: Bus speed (slot 0) = 198000000Hz
> [Wed Jan 14 20:13:47 2026] dwmmc_rockchip 2a310000.mmc: Successfully
> tuned phase to 232
> [Wed Jan 14 20:13:48 2026] E220d: Saving phases: sample=231, drv=180
> [Wed Jan 14 20:13:48 2026] E220d: Restoring phases: sample=231, drv=180
> [Wed Jan 14 20:13:48 2026] mmc_host mmc1: Bus speed (slot 0) = 400000Hz
> [Wed Jan 14 20:13:48 2026] mmc_host mmc1: Bus speed (slot 0) = 198000000Hz
> [Wed Jan 14 20:13:48 2026] dwmmc_rockchip 2a310000.mmc: Successfully
> tuned phase to 231
> [Wed Jan 14 20:13:48 2026] E220d: Saving phases: sample=231, drv=180
> 
> 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.

--- 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";




>> --- 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(struct
>> platform_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 = {
> 




More information about the linux-arm-kernel mailing list