[PATCH] mmc: stm32_sdmmc2: Use mmc_of_parse() to read host capabilities

Patrick DELAUNAY patrick.delaunay at st.com
Thu Sep 10 18:04:11 CEST 2020


Hi Alexandru,

> Sent: mercredi 9 septembre 2020 23:54
> To: uboot-stm32 at st-md-mailman.stormreply.com
> Cc: Alexandru Gagniuc <mr.nuke.me at gmail.com>; Patrick DELAUNAY
> <patrick.delaunay at st.com>; Patrice CHOTARD <patrice.chotard at st.com>; Peng
> Fan <peng.fan at nxp.com>; u-boot at lists.denx.de
> Subject: [PATCH] mmc: stm32_sdmmc2: Use mmc_of_parse() to read host
> capabilities
> Importance: High
> 
> mmc_of_parse() can populate the 'f_max' and 'host_caps' fields of struct
> mmc_config from devicetree.
> The same logic is duplicated in stm32_sdmmc2_probe(). Use mmc_of_parse(),
> which is more generic.
> 
> Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
> ---

Thanks for the patch, I miss the addition of this new API.

>  drivers/mmc/stm32_sdmmc2.c | 18 ++----------------
>  1 file changed, 2 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index
> 6d50356217..77871d5afc 100644
> --- a/drivers/mmc/stm32_sdmmc2.c
> +++ b/drivers/mmc/stm32_sdmmc2.c
> @@ -676,27 +676,13 @@ static int stm32_sdmmc2_probe(struct udevice *dev)
>  			     GPIOD_IS_IN);
> 
>  	cfg->f_min = 400000;
> -	cfg->f_max = dev_read_u32_default(dev, "max-frequency", 52000000);
>  	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 |
> MMC_VDD_165_195;
>  	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
>  	cfg->name = "STM32 SD/MMC";
> 
>  	cfg->host_caps = 0;
> -	if (cfg->f_max > 25000000)
> -		cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
> -
> -	switch (dev_read_u32_default(dev, "bus-width", 1)) {
> -	case 8:
> -		cfg->host_caps |= MMC_MODE_8BIT;
> -		/* fall through */
> -	case 4:
> -		cfg->host_caps |= MMC_MODE_4BIT;
> -		break;
> -	case 1:
> -		break;
> -	default:
> -		pr_err("invalid \"bus-width\" property, force to 1\n");
> -	}
> +	cfg->f_max = 52000000;
> +	mmc_of_parse(dev, cfg);

Result of mmc_of_parse is not tested ?

I proposed:

+	ret = mmc_of_parse(dev, cfg);
+	if (ret)
+		return ret;

> 
>  	upriv->mmc = &plat->mmc;
> 
> --
> 2.25.4

I test this patch with a trace in stm32_sdmmc2_probe on STM32MP157C-EV1

Before the patch :
cfg->host_caps = 0x2000000e (SD card)
cfg->host_caps = 0x6000000e (eMMC)

After the patch:
cfg->host_caps = 0x300001e6 (SD card)
cfg->host_caps = 0x70004006 (eMMC)


I see 2 problem here :

1/ MMC_MODE_HS_52MHz = MMC_CAP(MMC_HS_52) is removed
    and the eMMC on EV1 use only at 26MHz instead 52MHz before the patch

	Mode: MMC High Speed (52MHz)
	=>
	Mode: MMC High Speed (26MHz)

The "cap-mmc-highspeed" is used in Linux for MMC HS at 26MHz or 52MHz

./Documentation/devicetree/bindings/mmc/mmc-controller.yaml:122: 
cap-mmc-highspeed:
    $ref: /schemas/types.yaml#/definitions/flag
    description:
      MMC high-speed timing is supported.

And in Linux mmc/core/mmc.c
	static void mmc_select_card_type(struct mmc_card *card)
	{
	.....

	if (caps & MMC_CAP_MMC_HIGHSPEED &&
	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
	}

	if (caps & MMC_CAP_MMC_HIGHSPEED &&
	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
	}
	....

include/linux/mmc/mmc.h:347:
	#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
	#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */

I think that it is a issue U-Boot, in mmc uclass in mmc_of_parse():

	if (dev_read_bool(dev, "cap-mmc-highspeed"))
-		cfg->host_caps |= MMC_CAP(MMC_HS);
+		cfg->host_caps |= MMC_CAP(MMC_HS) | MMC_CAP(MMC_HS_52);

In U-Boot this capability is splitted in 2 bits = one for 26MHz one for 52MHz
And  for card side it is managed on card side by mmc_get_capabilities()

include/mmc.h:254:
	#define EXT_CSD_CARD_TYPE_26	(1 << 0)	/* Card can run at 26MHz */
	#define EXT_CSD_CARD_TYPE_52	(1 << 1)	/* Card can run at 52MHz */

A other solution is to only impact the sdmmc driver..... 
and to activate 52MHZ mode support is frequency is >= 26MHz

	cfg->f_max = 52000000;
	ret = mmc_of_parse(dev, cfg);
	if (ret)
		return ret;

	if ((cfg->host_caps & MMC_HS) && 
	    cfg->f_max > 26000000)
		cfg->host_caps |= MMC_HS_52;

but I prefer the previous generic solution in u-class.


2) some host caps can be added in device tree (they are supported by SOC and by Linux driver)
    but they are not supported by U-Boot driver, for example:

#define MMC_MODE_DDR_52MHz	MMC_CAP(MMC_DDR_52)
#define MMC_MODE_HS200		MMC_CAP(MMC_HS_200)
#define MMC_MODE_HS400		MMC_CAP(MMC_HS_400)
#define MMC_MODE_HS400_ES	MMC_CAP(MMC_HS_400_ES)

MMC_CAP(UHS_SDR12)
MMC_CAP(UHS_SDR25) 
MMC_CAP(UHS_SDR50)
MMC_CAP(UHS_SDR104)
MMC_CAP(UHS_DDR50)

I afraid (I don't sure) that this added caps change the mmc core behavior in U-Boot =
U-Boot try to select  the high speed mode even if not supported by driver....

The host_caps bitfield should be limited by the supported features in the driver  (or remove the unsupported features)

#define SDMMC_SUPPORTED_CAPS (MMC_MODE_1BIT | MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_CAP_CD_ACTIVE_HIGH | MMC_CAP_NEEDS_POLL |  MMC_CAP_NONREMOVABLE | MMC_MODE_HS | MMC_MODE_HS_52MHz)
or
#define SDMMC_UNSUPPORTED_CAPS (MMC_MODE_DDR_52MHz | MMC_MODE_HS200 | MMC_MODE_HS400 | MMC_MODE_HS400_ES | UHS_CAPS)
 
	cfg->f_max = 52000000;
	ret = mmc_of_parse(dev, cfg);
	if (ret)
		return ret;

	cfg->host_caps &= SDMMC_SUPPORTED_CAPS;
or 
	cfg->host_caps |= ~SDMMC_UNSUPPORTED_CAPS;


Best Regards

Patrick


More information about the U-Boot mailing list