[PATCH] mmc: sdhci-of-dwcmshc: Refactor Rockchip platform data for controller revisions

Adrian Hunter adrian.hunter at intel.com
Fri Mar 27 06:43:15 PDT 2026


On 27/03/2026 15:33, Shawn Lin wrote:
> 在 2026/03/27 星期五 19:34, Adrian Hunter 写道:
>> On 27/03/2026 13:28, Shawn Lin wrote:
>>> Hi Adrian
>>>
>>> 在 2026/03/27 星期五 17:29, Adrian Hunter 写道:
>>>> On 27/03/2026 09:51, Shawn Lin wrote:
>>>>> The driver previously used an enum (dwcmshc_rk_type) to distinguish
>>>>> platforms like the RK3568 and RK3588 based on DT compatible names.
>>>>> This approach is inflexible, scales poorly for future revisions or
>>>>> mixed-revision platforms, and conflates SoC names with controller
>>>>> revisions.
>>>>>
>>>>> Introduces a new struct rockchip_pltfm_data containing a dedicated
>>>>> revision field. The old enum is removed, and all code paths are
>>>>> updated to use the revision-based data.
>>>>>
>>>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>>>> ---
>>>>>
>>>>>    drivers/mmc/host/sdhci-of-dwcmshc.c | 87 ++++++++++++++++++++++---------------
>>>>>    1 file changed, 52 insertions(+), 35 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
>>>>> index a91b3e7..6b43ba9 100644
>>>>> --- a/drivers/mmc/host/sdhci-of-dwcmshc.c
>>>>> +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
>>>>> @@ -278,14 +278,8 @@
>>>>>    #define PHY_DELAY_CODE_EMMC        0x17
>>>>>    #define PHY_DELAY_CODE_SD        0x55
>>>>>    -enum dwcmshc_rk_type {
>>>>> -    DWCMSHC_RK3568,
>>>>> -    DWCMSHC_RK3588,
>>>>> -};
>>>>> -
>>>>>    struct rk35xx_priv {
>>>>>        struct reset_control *reset;
>>>>> -    enum dwcmshc_rk_type devtype;
>>>>>        u8 txclk_tapnum;
>>>>>    };
>>>>>    @@ -330,6 +324,11 @@ struct k230_pltfm_data {
>>>>>        u32 write_prot_bit;
>>>>>    };
>>>>>    +struct rockchip_pltfm_data {
>>>>> +    struct dwcmshc_pltfm_data dwcmshc_pdata;
>>>>> +    int revision;
>>>>
>>>> Does this "revision" match HW specs, otherwise maybe need
>>>> to clarify where it comes from.
>>>>
>>>
>>> This "revision" originates from our internal IP development
>>> documentation, not the public chip specifications. The public manuals do not label these specific IP versions.
>>>
>>> Revision 0 (Initial IP): This is the initial version of the IP used in
>>> the RK3568 and RK3566. Post-silicon validation identified certain errata
>>> requiring workarounds, and this version lacks HS400 support.
>>>
>>> Revision 1 (Fixed IP): This is the updated IP version (with
>>> documentation number updated internally). It fixes the previous issues
>>> and adds HS400 support. This revision is used in all subsequent chips
>>> (RK3576, RK3588, etc.).
>>>
>>> Since the public specs do not expose this distinction, I believe using
>>> the internal IP development document revision is the most accurate way
>>> to differentiate the hardware behavior in software. I will add a comment
>>> in the code to clarify this origin and the specific differences between
>>> the revisions.
>>>
>>>>> +};
>>>>> +
>>>>>    static void dwcmshc_enable_card_clk(struct sdhci_host *host)
>>>>>    {
>>>>>        u16 ctrl;
>>>>> @@ -749,6 +748,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
>>>>>        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>>>>>        struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
>>>>>        struct rk35xx_priv *priv = dwc_priv->priv;
>>>>> +    const struct rockchip_pltfm_data *rockchip_pdata = to_pltfm_data(dwc_priv, rockchip);
>>>>>        u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
>>>>>        u32 extra, reg;
>>>>>        int err;
>>>>> @@ -816,7 +816,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
>>>>>         * we must set it in higher speed mode.
>>>>>         */
>>>>>        extra = DWCMSHC_EMMC_DLL_DLYENA;
>>>>> -    if (priv->devtype == DWCMSHC_RK3568)
>>>>> +    if (rockchip_pdata->revision == 0)
>>>>>            extra |= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
>>>>>        sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
>>>>>    @@ -842,7 +842,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
>>>>>            host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
>>>>>            txclk_tapnum = priv->txclk_tapnum;
>>>>>    -    if ((priv->devtype == DWCMSHC_RK3588) && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
>>>>> +    if ((rockchip_pdata->revision == 1) && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
>>>>>            txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES;
>>>>>              extra = DLL_CMDOUT_SRC_CLK_NEG |
>>>>> @@ -898,11 +898,6 @@ static int dwcmshc_rk35xx_init(struct device *dev, struct sdhci_host *host,
>>>>>        if (!priv)
>>>>>            return -ENOMEM;
>>>>>    -    if (of_device_is_compatible(dev->of_node, "rockchip,rk3588-dwcmshc"))
>>>>> -        priv->devtype = DWCMSHC_RK3588;
>>>>> -    else
>>>>> -        priv->devtype = DWCMSHC_RK3568;
>>>>> -
>>>>>        priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc));
>>>>>        if (IS_ERR(priv->reset)) {
>>>>>            err = PTR_ERR(priv->reset);
>>>>> @@ -2115,30 +2110,52 @@ static const struct cqhci_host_ops rk35xx_cqhci_ops = {
>>>>>        .set_tran_desc    = dwcmshc_set_tran_desc,
>>>>>    };
>>>>>    -static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
>>>>> -    .pdata = {
>>>>> -        .ops = &sdhci_dwcmshc_rk35xx_ops,
>>>>> -        .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
>>>>> -              SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
>>>>> -        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
>>>>> -               SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
>>>>> +static const struct rockchip_pltfm_data sdhci_dwcmshc_rk3568_pdata = {
>>>>> +    .dwcmshc_pdata = {
>>>>> +        .pdata = {
>>>>> +            .ops = &sdhci_dwcmshc_rk35xx_ops,
>>>>> +            .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
>>>>> +                  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
>>>>> +            .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
>>>>> +                   SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
>>>>> +        },
>>>>> +        .cqhci_host_ops = &rk35xx_cqhci_ops,
>>>>> +        .init = dwcmshc_rk35xx_init,
>>>>> +        .postinit = dwcmshc_rk35xx_postinit,
>>>>>        },
>>>>> -    .cqhci_host_ops = &rk35xx_cqhci_ops,
>>>>> -    .init = dwcmshc_rk35xx_init,
>>>>> -    .postinit = dwcmshc_rk35xx_postinit,
>>>>> +    .revision = 0,
>>>>>    };
>>>>>    -static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk3576_pdata = {
>>>>> -    .pdata = {
>>>>> -        .ops = &sdhci_dwcmshc_rk35xx_ops,
>>>>> -        .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
>>>>> -              SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
>>>>> -        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
>>>>> -               SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
>>>>> +static const struct rockchip_pltfm_data sdhci_dwcmshc_rk3588_pdata = {
>>>>
>>>> Better order: sdhci_dwcmshc_rk3568_pdata, sdhci_dwcmshc_rk3576_pdata,
>>>> sdhci_dwcmshc_rk3588_pdata
>>>
>>>
>>> Sure, will do.
>>>
>>>>
>>>>> +    .dwcmshc_pdata = {
>>>>> +        .pdata = {
>>>>> +            .ops = &sdhci_dwcmshc_rk35xx_ops,
>>>>> +            .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
>>>>> +                  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
>>>>> +            .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
>>>>> +                   SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
>>>>> +        },
>>>>> +        .cqhci_host_ops = &rk35xx_cqhci_ops,
>>>>> +        .init = dwcmshc_rk35xx_init,
>>>>> +        .postinit = dwcmshc_rk35xx_postinit,
>>>>> +    },
>>>>> +    .revision = 1,
>>>>> +};
>>>>> +
>>>>> +static const struct rockchip_pltfm_data sdhci_dwcmshc_rk3576_pdata = {
>>>>> +    .dwcmshc_pdata = {
>>>>> +        .pdata = {
>>>>> +            .ops = &sdhci_dwcmshc_rk35xx_ops,
>>>>> +            .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
>>>>> +                  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
>>>>> +            .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
>>>>> +                   SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
>>>>> +        },
>>>>> +        .cqhci_host_ops = &rk35xx_cqhci_ops,
>>>>> +        .init = dwcmshc_rk35xx_init,
>>>>> +        .postinit = dwcmshc_rk3576_postinit,
>>>>>        },
>>>>> -    .cqhci_host_ops = &rk35xx_cqhci_ops,
>>>>> -    .init = dwcmshc_rk35xx_init,
>>>>> -    .postinit = dwcmshc_rk3576_postinit,
>>>>> +    .revision = 1,
>>>>
>>>> Isn't rk3576 revision = 0 ?
>>>
>>> As explained above, rk3576 is revision 1.
>>
>> Ok, but was it behaving that way before, since the code was:
>>
>>       if (of_device_is_compatible(dev->of_node, "rockchip,rk3588-dwcmshc"))
>>           priv->devtype = DWCMSHC_RK3588;
>>       else
>>           priv->devtype = DWCMSHC_RK3568;
>>
> 
> Yes, you are absolutely right to be confused,the old code logic was indeed the root of the problem, which is why this cleanup is necessary.
> 
> As you can see in the Device Tree [1], RK3576 explicitly lists "rockchip,rk3588-dwcmshc" as a secondary compatible string to select
> DWCMSHC_RK3588(now revision 1) as the devtype.
> 
> [1] https://elixir.bootlin.com/linux/v7.0-rc5/source/arch/arm64/boot/dts/rockchip/rk3576.dtsi#L1922
> 

I guess you'll add something about that to the commit message

> 
> 
>>>
>>>>
>>>>>    };
>>>>>      static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = {
>>>>> @@ -2309,7 +2326,7 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
>>>>>        },
>>>>>        {
>>>>>            .compatible = "rockchip,rk3588-dwcmshc",
>>>>> -        .data = &sdhci_dwcmshc_rk35xx_pdata,
>>>>> +        .data = &sdhci_dwcmshc_rk3588_pdata,
>>>>>        },
>>>>>        {
>>>>>            .compatible = "rockchip,rk3576-dwcmshc",
>>>>> @@ -2317,7 +2334,7 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
>>>>>        },
>>>>>        {
>>>>>            .compatible = "rockchip,rk3568-dwcmshc",
>>>>> -        .data = &sdhci_dwcmshc_rk35xx_pdata,
>>>>> +        .data = &sdhci_dwcmshc_rk3568_pdata,
>>>>>        },
>>>>>        {
>>>>>            .compatible = "snps,dwcmshc-sdhci",
>>>>
>>>>
>>
>>




More information about the Linux-rockchip mailing list