From 8ae82c4b12e71b9f114aeb18e2211ce1260012ca Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 26 Feb 2021 16:07:18 +0900 Subject: [PATCH 1/7] cmd: mmc: modify more readable about hwpartition usage Modified more readable about hwpartition usage. Because it's difficult to understand how to use its command. The arguments didn't optional. mmc hwpartition needs to pass as arguments. Description about each arguments what is required is the below: USER - <{on|off}> GP - <{gp1|gp2|gp3|gp4}> <{on|off}> MODE - <{check|set|complete}> Signed-off-by: Jaehoon Chung --- cmd/mmc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/mmc.c b/cmd/mmc.c index cb6b59f36a..c1c00d0f32 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -1008,11 +1008,14 @@ U_BOOT_CMD( "mmc list - lists available devices\n" "mmc wp - power on write protect boot partitions\n" #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) - "mmc hwpartition [args...] - does hardware partitioning\n" + "mmc hwpartition - does hardware partitioning\n" " arguments (sizes in 512-byte blocks):\n" - " [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n" - " [gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition\n" - " [check|set|complete] - mode, complete set partitioning completed\n" + " USER - <{on|off}>\n" + " : sets user data area attributes\n" + " GP - <{gp1|gp2|gp3|gp4}> <{on|off}>\n" + " : general purpose partition\n" + " MODE - <{check|set|complete}>\n" + " : mode, complete set partitioning completed\n" " WARNING: Partitioning is a write-once setting once it is set to complete.\n" " Power cycling is required to initialize partitions after set to complete.\n" #endif From e9978b17cd7bc19f0459b2829756f1d891382bf9 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 26 Feb 2021 18:38:20 +0900 Subject: [PATCH 2/7] cmd: mmc: check whether bootbus's arguments is valid or not According to Specification, each bit have valid value. But it doesn't check whether arguments is valid or not. It has potential bug with arguments passed by wrong value. Signed-off-by: Jaehoon Chung --- cmd/mmc.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/cmd/mmc.c b/cmd/mmc.c index c1c00d0f32..a10f137204 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -735,8 +735,45 @@ static int do_mmc_bootbus(struct cmd_tbl *cmdtp, int flag, return CMD_RET_FAILURE; } + /* + * BOOT_BUS_CONDITIONS[177] + * BOOT_MODE[4:3] + * 0x0 : Use SDR + Backward compatible timing in boot operation + * 0x1 : Use SDR + High Speed Timing in boot operation mode + * 0x2 : Use DDR in boot operation + * RESET_BOOT_BUS_CONDITIONS + * 0x0 : Reset bus width to x1, SDR, Backward compatible + * 0x1 : Retain BOOT_BUS_WIDTH and BOOT_MODE + * BOOT_BUS_WIDTH + * 0x0 : x1(sdr) or x4 (ddr) buswidth + * 0x1 : x4(sdr/ddr) buswith + * 0x2 : x8(sdr/ddr) buswith + * + */ + if (width >= 0x3) { + printf("boot_bus_width %d is invalid\n", width); + return CMD_RET_FAILURE; + } + + if (reset >= 0x2) { + printf("reset_boot_bus_width %d is invalid\n", reset); + return CMD_RET_FAILURE; + } + + if (mode >= 0x3) { + printf("reset_boot_bus_width %d is invalid\n", mode); + return CMD_RET_FAILURE; + } + /* acknowledge to be sent during boot operation */ - return mmc_set_boot_bus_width(mmc, width, reset, mode); + if (mmc_set_boot_bus_width(mmc, width, reset, mode)) { + puts("BOOT_BUS_WIDTH is failed to change.\n"); + return CMD_RET_FAILURE; + } + + printf("Set to BOOT_BUS_WIDTH = 0x%x, RESET = 0x%x, BOOT_MODE = 0x%x\n", + width, reset, mode); + return CMD_RET_SUCCESS; } static int do_mmc_boot_resize(struct cmd_tbl *cmdtp, int flag, From bd7b8505f2c0c87785488a040ff7d2711465b401 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 17 Mar 2021 15:01:36 +0100 Subject: [PATCH 3/7] mmc: fsl_esdhc: add workaround for erratum A-011334 LS1028A SoCs are restricted in what divider values are allowed for HS400 mode. This is basically a port from the corresponding linux driver. Signed-off-by: Michael Walle --- arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 1 + drivers/mmc/Kconfig | 3 +++ drivers/mmc/fsl_esdhc.c | 25 ++++++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index ae0b7b21e8..c0190a233e 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -47,6 +47,7 @@ config ARCH_LS1028A select SYS_FSL_ERRATUM_A009663 if !TFABOOT select SYS_FSL_ERRATUM_A009942 if !TFABOOT select SYS_FSL_ERRATUM_A050382 + select SYS_FSL_ERRATUM_A011334 select RESV_RAM if GIC_V3_ITS imply PANIC_HANG diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index c34fce370e..b0ff92b5fa 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -813,3 +813,6 @@ config SYS_FSL_ERRATUM_ESDHC135 config SYS_FSL_ERRATUM_ESDHC_A001 bool + +config SYS_FSL_ERRATUM_A011334 + bool diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 6014e1c5ca..09ea1a9de9 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -518,6 +518,24 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) while (sdhc_clk / (div * pre_div) > clock && div < 16) div++; + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) && + clock == 200000000 && mmc->selected_mode == MMC_HS_400) { + u32 div_ratio = pre_div * div; + + if (div_ratio <= 4) { + pre_div = 4; + div = 1; + } else if (div_ratio <= 8) { + pre_div = 4; + div = 2; + } else if (div_ratio <= 12) { + pre_div = 4; + div = 3; + } else { + printf("unsupported clock division.\n"); + } + } + mmc->clock = sdhc_clk / pre_div / div; priv->clock = mmc->clock; @@ -1063,9 +1081,14 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) struct fsl_esdhc_plat *plat = dev_get_plat(dev); struct fsl_esdhc_priv *priv = dev_get_priv(dev); struct fsl_esdhc *regs = priv->esdhc_regs; + struct mmc *mmc = &plat->mmc; u32 val, irqstaten; int i; + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) && + plat->mmc.hs400_tuning) + set_sysctl(priv, mmc, mmc->clock); + esdhc_tuning_block_enable(priv, true); esdhc_setbits32(®s->autoc12err, EXECUTE_TUNING); @@ -1073,7 +1096,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) esdhc_write32(®s->irqstaten, IRQSTATEN_BRR); for (i = 0; i < MAX_TUNING_LOOP; i++) { - mmc_send_tuning(&plat->mmc, opcode, NULL); + mmc_send_tuning(mmc, opcode, NULL); mdelay(1); val = esdhc_read32(®s->autoc12err); From d3b745f7d00d07767a0ed85a6b139feeb8df9aaf Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 17 Mar 2021 15:01:37 +0100 Subject: [PATCH 4/7] mmc: fsl_esdhc: add pulse width detection workaround HS400 mode on the LS1028A SoC isn't reliable. The linux driver has a workaroung for the pulse width detection. Apply this workaround in u-boot, too. This will make HS400 mode work reliably on the LS1028A SoC. Signed-off-by: Michael Walle Reviewed-by: Jaehoon Chung --- arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 1 + drivers/mmc/Kconfig | 3 +++ drivers/mmc/fsl_esdhc.c | 6 +++++- include/fsl_esdhc.h | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index c0190a233e..9d1ba4c771 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -48,6 +48,7 @@ config ARCH_LS1028A select SYS_FSL_ERRATUM_A009942 if !TFABOOT select SYS_FSL_ERRATUM_A050382 select SYS_FSL_ERRATUM_A011334 + select SYS_FSL_ESDHC_UNRELIABLE_PULSE_DETECTION_WORKAROUND select RESV_RAM if GIC_V3_ITS imply PANIC_HANG diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index b0ff92b5fa..492567575e 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -816,3 +816,6 @@ config SYS_FSL_ERRATUM_ESDHC_A001 config SYS_FSL_ERRATUM_A011334 bool + +config SYS_FSL_ESDHC_UNRELIABLE_PULSE_DETECTION_WORKAROUND + bool diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 09ea1a9de9..7501fdb71e 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -71,7 +71,8 @@ struct fsl_esdhc { uint sdtimingctl; /* SD timing control register */ char reserved8[20]; /* reserved */ uint dllcfg0; /* DLL config 0 register */ - char reserved9[12]; /* reserved */ + uint dllcfg1; /* DLL config 1 register */ + char reserved9[8]; /* reserved */ uint dllstat0; /* DLL status 0 register */ char reserved10[664];/* reserved */ uint esdhcctl; /* eSDHC control register */ @@ -767,6 +768,9 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); + if (IS_ENABLED(CONFIG_SYS_FSL_ESDHC_UNRELIABLE_PULSE_DETECTION_WORKAROUND)) + esdhc_clrbits32(®s->dllcfg1, DLL_PD_PULSE_STRETCH_SEL); + return 0; } diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index 850a304bd7..f86afe5dad 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -190,6 +190,9 @@ #define DLL_RESET 0x40000000 #define DLL_FREQ_SEL 0x08000000 +/* DLL config 1 register */ +#define DLL_PD_PULSE_STRETCH_SEL 0x80000000 + /* DLL status 0 register */ #define DLL_STS_SLV_LOCK 0x08000000 From 1fc9346af4256e2e33fc39f65c6006e04cddd806 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 17 Mar 2021 15:01:38 +0100 Subject: [PATCH 5/7] board: sl28: enable HS400 mode again Now that it is working reliable on the LS1028A SoC, reenable support for it. Signed-off-by: Michael Walle --- configs/kontron_sl28_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig index 0c6c1911d9..1c781e091c 100644 --- a/configs/kontron_sl28_defconfig +++ b/configs/kontron_sl28_defconfig @@ -70,7 +70,7 @@ CONFIG_I2C_SET_DEFAULT_BUS_NUM=y CONFIG_I2C_DEFAULT_BUS_NUMBER=0 CONFIG_I2C_MUX=y CONFIG_DM_MMC=y -CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_FSL_ESDHC=y CONFIG_FSL_ESDHC_SUPPORT_ADMA2=y CONFIG_DM_SPI_FLASH=y From 2153a08a24e807f229e492037ed81ca27c2e0c11 Mon Sep 17 00:00:00 2001 From: Aswath Govindraju Date: Thu, 25 Mar 2021 12:48:47 +0530 Subject: [PATCH 6/7] mmc: Check for device with a seq number equal to num before checking against index First check if there is an alias for the device tree node defined with the given num before checking against device index. Signed-off-by: Aswath Govindraju Reviewed-by: Lokesh Vutla Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b4c8e7f293..1e83007286 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -3052,9 +3052,11 @@ int mmc_init_device(int num) struct mmc *m; int ret; - ret = uclass_get_device(UCLASS_MMC, num, &dev); - if (ret) - return ret; + if (uclass_get_device_by_seq(UCLASS_MMC, num, &dev)) { + ret = uclass_get_device(UCLASS_MMC, num, &dev); + if (ret) + return ret; + } m = mmc_get_mmc_dev(dev); if (!m) From 2243d19e5618122d9d7aba23eb51f63f2719dba5 Mon Sep 17 00:00:00 2001 From: Aswath Govindraju Date: Thu, 25 Mar 2021 12:48:48 +0530 Subject: [PATCH 7/7] mmc: mmc-uclass: Use dev_seq() to read aliases node's index Use dev_seq() to read aliases node's index and pass it as device number for creating bulk device. Suggested-by: Grygorii Strashko Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc-uclass.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 53eabc9e61..d36aae367e 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -383,18 +383,16 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) { struct blk_desc *bdesc; struct udevice *bdev; - int ret, devnum = -1; + int ret; if (!mmc_get_ops(dev)) return -ENOSYS; -#ifndef CONFIG_SPL_BUILD - /* Use the fixed index with aliase node's index */ - ret = dev_read_alias_seq(dev, &devnum); - debug("%s: alias ret=%d, devnum=%d\n", __func__, ret, devnum); -#endif + + /* Use the fixed index with aliases node's index */ + debug("%s: alias devnum=%d\n", __func__, dev_seq(dev)); ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, - devnum, 512, 0, &bdev); + dev_seq(dev), 512, 0, &bdev); if (ret) { debug("Cannot create block device\n"); return ret;