Skip to content

Commit 08f9597

Browse files
Nicolas Frattarolistorulf
authored andcommitted
mmc: sdhci-of-dwcmshc: add PD workaround on RK3576
RK3576's power domains have a peculiar design where the PD_NVM power domain, of which the sdhci controller is a part, seemingly does not have idempotent runtime disable/enable. The end effect is that if PD_NVM gets turned off by the generic power domain logic because all the devices depending on it are suspended, then the next time the sdhci device is unsuspended, it'll hang the SoC as soon as it tries accessing the CQHCI registers. RK3576's UFS support needed a new dev_pm_genpd_rpm_always_on function added to the generic power domains API to handle what appears to be a similar hardware design. Use this new function to ask for the same treatment in the sdhci controller by giving rk3576 its own platform data with its own postinit function. The benefit of doing this instead of marking the power domains always on in the power domain core is that we only do this if we know the platform we're running on actually uses the sdhci controller. For others, keeping PD_NVM always on would be a waste, as they won't run into this specific issue. The only other IP in PD_NVM that could be affected is FSPI0. If it gets a mainline driver, it will probably want to do the same thing. Acked-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com> Fixes: cfee1b5 ("pmdomain: rockchip: Add support for RK3576 SoC") Cc: <stable@vger.kernel.org> # v6.15+ Link: https://lore.kernel.org/r/20250423-rk3576-emmc-fix-v3-1-0bf80e29967f@collabora.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 82f2b0b commit 08f9597

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

drivers/mmc/host/sdhci-of-dwcmshc.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/module.h>
1818
#include <linux/of.h>
1919
#include <linux/platform_device.h>
20+
#include <linux/pm_domain.h>
2021
#include <linux/pm_runtime.h>
2122
#include <linux/reset.h>
2223
#include <linux/sizes.h>
@@ -745,6 +746,29 @@ static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv
745746
}
746747
}
747748

749+
static void dwcmshc_rk3576_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
750+
{
751+
struct device *dev = mmc_dev(host->mmc);
752+
int ret;
753+
754+
/*
755+
* This works around the design of the RK3576's power domains, which
756+
* makes the PD_NVM power domain, which the sdhci controller on the
757+
* RK3576 is in, never come back the same way once it's run-time
758+
* suspended once. This can happen during early kernel boot if no driver
759+
* is using either PD_NVM or its child power domain PD_SDGMAC for a
760+
* short moment, leading to it being turned off to save power. By
761+
* keeping it on, sdhci suspending won't lead to PD_NVM becoming a
762+
* candidate for getting turned off.
763+
*/
764+
ret = dev_pm_genpd_rpm_always_on(dev, true);
765+
if (ret && ret != -EOPNOTSUPP)
766+
dev_warn(dev, "failed to set PD rpm always on, SoC may hang later: %pe\n",
767+
ERR_PTR(ret));
768+
769+
dwcmshc_rk35xx_postinit(host, dwc_priv);
770+
}
771+
748772
static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode)
749773
{
750774
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -1176,6 +1200,18 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
11761200
.postinit = dwcmshc_rk35xx_postinit,
11771201
};
11781202

1203+
static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk3576_pdata = {
1204+
.pdata = {
1205+
.ops = &sdhci_dwcmshc_rk35xx_ops,
1206+
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
1207+
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
1208+
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
1209+
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
1210+
},
1211+
.init = dwcmshc_rk35xx_init,
1212+
.postinit = dwcmshc_rk3576_postinit,
1213+
};
1214+
11791215
static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = {
11801216
.pdata = {
11811217
.ops = &sdhci_dwcmshc_th1520_ops,
@@ -1274,6 +1310,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
12741310
.compatible = "rockchip,rk3588-dwcmshc",
12751311
.data = &sdhci_dwcmshc_rk35xx_pdata,
12761312
},
1313+
{
1314+
.compatible = "rockchip,rk3576-dwcmshc",
1315+
.data = &sdhci_dwcmshc_rk3576_pdata,
1316+
},
12771317
{
12781318
.compatible = "rockchip,rk3568-dwcmshc",
12791319
.data = &sdhci_dwcmshc_rk35xx_pdata,

0 commit comments

Comments
 (0)