[U-Boot] [PATCH 0/6] mx6cuboxi: Add support for SOMs with eMMC

The newer rev 1.5 of the SolidRun i.MX6 SOM can optionally come with eMMC on the SOM. This series adds support for the eMMC device on these SOMs.
Since eMMC has card detect signal this series uses the new mmc_get_op_cond() function that is broken out of mmc_init_start(). Successful completion of mmc_get_op_cond() indicates that the eMMC is present.
Finally, the last patch in this series constructs the name of the kernel device tree to load. This name is compatible with recent mainline kernels.
This series depends on the patches adding support for SOM rev 1.5 that were posted earlier:
https://patchwork.ozlabs.org/patch/926302/ https://patchwork.ozlabs.org/patch/926301/
Baruch Siach (2): mmc: drop mention of IN_PROGRESS status mx6cuboxi: drop CONFIG_SYS_FSL_USDHC_NUM
Jon Nettleton (4): mmc: break out get_op_cond code to its own function mx6cuboxi: Add support for eMMC booting mx6cuboxi: Use mmc_get_op_cond() to check for an eMMC mx6cuboxi: Add emmc device tree suffix
board/solidrun/mx6cuboxi/mx6cuboxi.c | 115 +++++++++++++++++++++++++-- drivers/mmc/mmc.c | 61 ++++++++------ include/configs/mx6cuboxi.h | 25 +++--- include/mmc.h | 12 ++- 4 files changed, 167 insertions(+), 46 deletions(-)

The IN_PROGRESS macro has been removed in commit bd47c13583f (mmc: Fix splitting device initialization). Remove it from the mmc_start_init() function description.
Signed-off-by: Baruch Siach baruch@tkos.co.il --- include/mmc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/mmc.h b/include/mmc.h index 534c317b43c4..1729292d27bd 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -759,7 +759,7 @@ int mmc_set_bkops_enable(struct mmc *mmc); * initializatin. * * @param mmc Pointer to a MMC device struct - * @return 0 on success, IN_PROGRESS on waiting for OCR status, <0 on error. + * @return 0 on success, <0 on error. */ int mmc_start_init(struct mmc *mmc);

From: Jon Nettleton jon@solid-run.com
This code is useful for testing the existance of devices that do not have card detect capabilities. This breaks out the core functionality and leaves the actual init logic and error reporting in mmc_start_init().
Signed-off-by: Jon Nettleton jon@solid-run.com Signed-off-by: Baruch Siach baruch@tkos.co.il --- drivers/mmc/mmc.c | 61 +++++++++++++++++++++++++++-------------------- include/mmc.h | 10 ++++++++ 2 files changed, 45 insertions(+), 26 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index f7827f527aa5..ad429f49c992 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2491,36 +2491,11 @@ static int mmc_power_cycle(struct mmc *mmc) return mmc_power_on(mmc); }
-int mmc_start_init(struct mmc *mmc) +int mmc_get_op_cond(struct mmc *mmc) { - bool no_card; bool uhs_en = supports_uhs(mmc->cfg->host_caps); int err;
- /* - * all hosts are capable of 1 bit bus-width and able to use the legacy - * timings. - */ - mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | - MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; - -#if !defined(CONFIG_MMC_BROKEN_CD) - /* we pretend there's no card when init is NULL */ - no_card = mmc_getcd(mmc) == 0; -#else - no_card = 0; -#endif -#if !CONFIG_IS_ENABLED(DM_MMC) - no_card = no_card || (mmc->cfg->ops->init == NULL); -#endif - if (no_card) { - mmc->has_init = 0; -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("MMC: no card present\n"); -#endif - return -ENOMEDIUM; - } - if (mmc->has_init) return 0;
@@ -2597,6 +2572,40 @@ retry: } }
+ return err; +} + +int mmc_start_init(struct mmc *mmc) +{ + bool no_card; + int err = 0; + + /* + * all hosts are capable of 1 bit bus-width and able to use the legacy + * timings. + */ + mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | + MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; + +#if !defined(CONFIG_MMC_BROKEN_CD) + /* we pretend there's no card when init is NULL */ + no_card = mmc_getcd(mmc) == 0; +#else + no_card = 0; +#endif +#if !CONFIG_IS_ENABLED(DM_MMC) + no_card = no_card || (mmc->cfg->ops->init == NULL); +#endif + if (no_card) { + mmc->has_init = 0; +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) + pr_err("MMC: no card present\n"); +#endif + return -ENOMEDIUM; + } + + err = mmc_get_op_cond(mmc); + if (!err) mmc->init_in_progress = 1;
diff --git a/include/mmc.h b/include/mmc.h index 1729292d27bd..df4255b828a7 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -752,6 +752,16 @@ int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, int mmc_set_bkops_enable(struct mmc *mmc); #endif
+/** + * Start device initialization and return immediately; it does not block on + * polling OCR (operation condition register) status. Useful for checking + * the presence of SD/eMMC when no card detect logic is available. + * + * @param mmc Pointer to a MMC device struct + * @return 0 on success, <0 on error. + */ +int mmc_get_op_cond(struct mmc *mmc); + /** * Start device initialization and return immediately; it does not block on * polling OCR (operation condition register) status. Then you should call

Hi Baruch,
On 11/06/2018 14:26, Baruch Siach wrote:
From: Jon Nettleton jon@solid-run.com
This code is useful for testing the existance of devices that do not have card detect capabilities. This breaks out the core functionality and leaves the actual init logic and error reporting in mmc_start_init().
Signed-off-by: Jon Nettleton jon@solid-run.com Signed-off-by: Baruch Siach baruch@tkos.co.il
drivers/mmc/mmc.c | 61 +++++++++++++++++++++++++++-------------------- include/mmc.h | 10 ++++++++ 2 files changed, 45 insertions(+), 26 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index f7827f527aa5..ad429f49c992 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2491,36 +2491,11 @@ static int mmc_power_cycle(struct mmc *mmc) return mmc_power_on(mmc); }
-int mmc_start_init(struct mmc *mmc) +int mmc_get_op_cond(struct mmc *mmc) {
bool no_card; bool uhs_en = supports_uhs(mmc->cfg->host_caps); int err;
/*
* all hosts are capable of 1 bit bus-width and able to use the legacy
* timings.
*/
mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
-#if !defined(CONFIG_MMC_BROKEN_CD)
- /* we pretend there's no card when init is NULL */
- no_card = mmc_getcd(mmc) == 0;
-#else
- no_card = 0;
-#endif -#if !CONFIG_IS_ENABLED(DM_MMC)
- no_card = no_card || (mmc->cfg->ops->init == NULL);
-#endif
- if (no_card) {
mmc->has_init = 0;
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
pr_err("MMC: no card present\n");
-#endif
return -ENOMEDIUM;
- }
- if (mmc->has_init) return 0;
@@ -2597,6 +2572,40 @@ retry: } }
- return err;
+}
+int mmc_start_init(struct mmc *mmc) +{
- bool no_card;
- int err = 0;
- /*
* all hosts are capable of 1 bit bus-width and able to use the legacy
* timings.
*/
- mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
+#if !defined(CONFIG_MMC_BROKEN_CD)
- /* we pretend there's no card when init is NULL */
- no_card = mmc_getcd(mmc) == 0;
+#else
- no_card = 0;
+#endif +#if !CONFIG_IS_ENABLED(DM_MMC)
- no_card = no_card || (mmc->cfg->ops->init == NULL);
+#endif
- if (no_card) {
mmc->has_init = 0;
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
pr_err("MMC: no card present\n");
+#endif
return -ENOMEDIUM;
- }
- err = mmc_get_op_cond(mmc);
- if (!err) mmc->init_in_progress = 1;
diff --git a/include/mmc.h b/include/mmc.h index 1729292d27bd..df4255b828a7 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -752,6 +752,16 @@ int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, int mmc_set_bkops_enable(struct mmc *mmc); #endif
+/**
- Start device initialization and return immediately; it does not block on
- polling OCR (operation condition register) status. Useful for checking
- the presence of SD/eMMC when no card detect logic is available.
- @param mmc Pointer to a MMC device struct
- @return 0 on success, <0 on error.
- */
+int mmc_get_op_cond(struct mmc *mmc);
/**
- Start device initialization and return immediately; it does not block on
- polling OCR (operation condition register) status. Then you should call
Reviewed-by: Stefano Babic sbabic@denx.de
Anyway, this is related to MMC subsystem. I added Jaehoon in CC for his review / ACK. I will hold on the series (related to i.MX) until then.
Best regards, Stefano Babic

From: Jon Nettleton jon@solid-run.com
The HB2 boards as well as rev 1.5 soms support eMMC booting as well as SDHC. Add the infrastructure to support booting these devices.
Signed-off-by: Jon Nettleton jon@solid-run.com Signed-off-by: Baruch Siach baruch@tkos.co.il --- board/solidrun/mx6cuboxi/mx6cuboxi.c | 102 ++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 8 deletions(-)
diff --git a/board/solidrun/mx6cuboxi/mx6cuboxi.c b/board/solidrun/mx6cuboxi/mx6cuboxi.c index 38d89f0130bb..932465011971 100644 --- a/board/solidrun/mx6cuboxi/mx6cuboxi.c +++ b/board/solidrun/mx6cuboxi/mx6cuboxi.c @@ -126,6 +126,20 @@ static iomux_v3_cfg_t const usdhc2_pads[] = { IOMUX_PADS(PAD_SD2_DAT3__SD2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), };
+static iomux_v3_cfg_t const usdhc3_pads[] = { + IOMUX_PADS(PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT4__SD3_DATA4 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT5__SD3_DATA5 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT6__SD3_DATA6 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT7__SD3_DATA7 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_RST__SD3_RESET | MUX_PAD_CTRL(USDHC_PAD_CTRL)), +}; + static iomux_v3_cfg_t const board_detect[] = { /* These pins are for sensing if it is a CuBox-i or a HummingBoard */ IOMUX_PADS(PAD_KEY_ROW1__GPIO4_IO09 | MUX_PAD_CTRL(UART_PAD_CTRL)), @@ -148,23 +162,95 @@ static void setup_iomux_uart(void) SETUP_IOMUX_PADS(uart1_pads); }
-static struct fsl_esdhc_cfg usdhc_cfg[1] = { - {USDHC2_BASE_ADDR}, +static struct fsl_esdhc_cfg usdhc_cfg = { + .esdhc_base = USDHC2_BASE_ADDR, + .max_bus_width = 4, };
+static struct fsl_esdhc_cfg emmc_cfg = { + .esdhc_base = USDHC3_BASE_ADDR, + .max_bus_width = 8, +}; + +int board_mmc_get_env_dev(int devno) +{ + return devno - 1; +} + +#define USDHC2_CD_GPIO IMX_GPIO_NR(1, 4) + int board_mmc_getcd(struct mmc *mmc) { - return 1; /* uSDHC2 is always present */ + struct fsl_esdhc_cfg *cfg = mmc->priv; + int ret = 0; + + switch (cfg->esdhc_base) { + case USDHC2_BASE_ADDR: + ret = !gpio_get_value(USDHC2_CD_GPIO); + break; + case USDHC3_BASE_ADDR: + ret = 1; /* eMMC/uSDHC3 has no CD GPIO */ + break; + } + + return ret; }
-int board_mmc_init(bd_t *bis) +static int mmc_init_main(bd_t *bis) { + int ret; + + /* + * Following map is done: + * (U-Boot device node) (Physical Port) + * mmc0 Carrier board MicroSD + * mmc1 SOM eMMC + */ SETUP_IOMUX_PADS(usdhc2_pads); - usdhc_cfg[0].esdhc_base = USDHC2_BASE_ADDR; - usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); - gd->arch.sdhc_clk = usdhc_cfg[0].sdhc_clk; + usdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); + ret = fsl_esdhc_initialize(bis, &usdhc_cfg); + if (ret) + return ret; + + SETUP_IOMUX_PADS(usdhc3_pads); + emmc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); + return fsl_esdhc_initialize(bis, &emmc_cfg); +} + +static int mmc_init_spl(bd_t *bis) +{ + struct src *psrc = (struct src *)SRC_BASE_ADDR; + unsigned reg = readl(&psrc->sbmr1) >> 11; + + /* + * Upon reading BOOT_CFG register the following map is done: + * Bit 11 and 12 of BOOT_CFG register can determine the current + * mmc port + * 0x1 SD2 + * 0x2 SD3 + */ + switch (reg & 0x3) { + case 0x1: + SETUP_IOMUX_PADS(usdhc2_pads); + usdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); + gd->arch.sdhc_clk = usdhc_cfg.sdhc_clk; + return fsl_esdhc_initialize(bis, &usdhc_cfg); + case 0x2: + SETUP_IOMUX_PADS(usdhc3_pads); + emmc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); + gd->arch.sdhc_clk = emmc_cfg.sdhc_clk; + return fsl_esdhc_initialize(bis, &emmc_cfg); + } + + return -ENODEV; +} + +int board_mmc_init(bd_t *bis) +{ + if (IS_ENABLED(CONFIG_SPL_BUILD)) + return mmc_init_spl(bis);
- return fsl_esdhc_initialize(bis, &usdhc_cfg[0]); + return mmc_init_main(bis); }
static iomux_v3_cfg_t const enet_pads[] = {

This macro is not used.
Signed-off-by: Baruch Siach baruch@tkos.co.il --- include/configs/mx6cuboxi.h | 1 - 1 file changed, 1 deletion(-)
diff --git a/include/configs/mx6cuboxi.h b/include/configs/mx6cuboxi.h index 803661cfa843..1f7297d11463 100644 --- a/include/configs/mx6cuboxi.h +++ b/include/configs/mx6cuboxi.h @@ -67,7 +67,6 @@
#define CONFIG_MXC_UART_BASE UART1_BASE #define CONSOLE_DEV "ttymxc0" -#define CONFIG_SYS_FSL_USDHC_NUM 1 #define CONFIG_SYS_MMC_ENV_DEV 0 /* SDHC2 */
#ifndef CONFIG_SPL_BUILD

From: Jon Nettleton jon@solid-run.com
Previously we had just made broad assumptions with which of our boards had an eMMC or not even though this is a manufacturing time assembly option. This takes the guessing away and actually checks for the existence of an eMMC and sets up the has_emmc environment variable.
Signed-off-by: Jon Nettleton jon@solid-run.com Signed-off-by: Baruch Siach baruch@tkos.co.il --- board/solidrun/mx6cuboxi/mx6cuboxi.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/board/solidrun/mx6cuboxi/mx6cuboxi.c b/board/solidrun/mx6cuboxi/mx6cuboxi.c index 932465011971..cf63427e52f1 100644 --- a/board/solidrun/mx6cuboxi/mx6cuboxi.c +++ b/board/solidrun/mx6cuboxi/mx6cuboxi.c @@ -189,7 +189,7 @@ int board_mmc_getcd(struct mmc *mmc) ret = !gpio_get_value(USDHC2_CD_GPIO); break; case USDHC3_BASE_ADDR: - ret = 1; /* eMMC/uSDHC3 has no CD GPIO */ + ret = (mmc_get_op_cond(mmc) < 0) ? 0 : 1; /* eMMC/uSDHC3 has no CD GPIO */ break; }
@@ -527,6 +527,15 @@ static bool is_rev_15_som(void) return false; }
+static bool has_emmc(void) +{ + struct mmc *mmc; + mmc = find_mmc_device(1); + if (!mmc) + return 0; + return (mmc_get_op_cond(mmc) < 0) ? 0 : 1; +} + int checkboard(void) { switch (board_type()) { @@ -579,6 +588,10 @@ int board_late_init(void)
if (is_rev_15_som()) env_set("som_rev", "V15"); + + if (has_emmc()) + env_set("has_emmc", "yes"); + #endif
return 0;

From: Jon Nettleton jon@solid-run.com
Mainline and now the SolidRun 4.9 nxp based tree use the new reorganization of device-tree files that separate out the emmc into its own dtb. u-boot will now look for -emmc in the device tree name if one is detected.
Signed-off-by: Jon Nettleton jon@solid-run.com Signed-off-by: Baruch Siach baruch@tkos.co.il --- include/configs/mx6cuboxi.h | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/include/configs/mx6cuboxi.h b/include/configs/mx6cuboxi.h index 1f7297d11463..a647aaba685c 100644 --- a/include/configs/mx6cuboxi.h +++ b/include/configs/mx6cuboxi.h @@ -71,6 +71,8 @@
#ifndef CONFIG_SPL_BUILD #define CONFIG_EXTRA_ENV_SETTINGS \ + "som_rev=undefined\0" \ + "has_emmc=undefined\0" \ "fdtfile=undefined\0" \ "fdt_addr_r=0x18000000\0" \ "fdt_addr=0x18000000\0" \ @@ -100,19 +102,21 @@ "fi; " \ "fi\0" \ "findfdt="\ - "if test $board_rev = MX6Q ; then " \ + "if test ${board_rev} = MX6Q; then " \ "setenv fdtprefix imx6q; fi; " \ - "if test $board_rev = MX6DL ; then " \ + "if test ${board_rev} = MX6DL; then " \ "setenv fdtprefix imx6dl; fi; " \ - "if test $som_rev = V15 ; then " \ + "if test ${som_rev} = V15; then " \ "setenv fdtsuffix -som-v15; fi; " \ - "if test $board_name = HUMMINGBOARD2 ; then " \ - "setenv fdtfile ${fdtprefix}-hummingboard2${fdtsuffix}.dtb; fi; " \ - "if test $board_name = HUMMINGBOARD ; then " \ - "setenv fdtfile ${fdtprefix}-hummingboard${fdtsuffix}.dtb; fi; " \ - "if test $board_name = CUBOXI ; then " \ - "setenv fdtfile ${fdtprefix}-cubox-i${fdtsuffix}.dtb; fi; " \ - "if test $fdtfile = undefined; then " \ + "if test ${has_emmc} = yes; then " \ + "setenv emmcsuffix -emmc; fi; " \ + "if test ${board_name} = HUMMINGBOARD2 ; then " \ + "setenv fdtfile ${fdtprefix}-hummingboard2${emmcsuffix}${fdtsuffix}.dtb; fi; " \ + "if test ${board_name} = HUMMINGBOARD ; then " \ + "setenv fdtfile ${fdtprefix}-hummingboard${emmcsuffix}${fdtsuffix}.dtb; fi; " \ + "if test ${board_name} = CUBOXI ; then " \ + "setenv fdtfile ${fdtprefix}-cubox-i${emmcsuffix}${fdtsuffix}.dtb; fi; " \ + "if test ${fdtfile} = undefined; then " \ "echo WARNING: Could not determine dtb to use; fi; \0" \ BOOTENV

On 11/06/2018 14:26, Baruch Siach wrote:
The newer rev 1.5 of the SolidRun i.MX6 SOM can optionally come with eMMC on the SOM. This series adds support for the eMMC device on these SOMs.
Since eMMC has card detect signal this series uses the new mmc_get_op_cond() function that is broken out of mmc_init_start(). Successful completion of mmc_get_op_cond() indicates that the eMMC is present.
Finally, the last patch in this series constructs the name of the kernel device tree to load. This name is compatible with recent mainline kernels.
This series depends on the patches adding support for SOM rev 1.5 that were posted earlier:
https://patchwork.ozlabs.org/patch/926302/ https://patchwork.ozlabs.org/patch/926301/
Baruch Siach (2): mmc: drop mention of IN_PROGRESS status mx6cuboxi: drop CONFIG_SYS_FSL_USDHC_NUM
Jon Nettleton (4): mmc: break out get_op_cond code to its own function mx6cuboxi: Add support for eMMC booting mx6cuboxi: Use mmc_get_op_cond() to check for an eMMC mx6cuboxi: Add emmc device tree suffix
board/solidrun/mx6cuboxi/mx6cuboxi.c | 115 +++++++++++++++++++++++++-- drivers/mmc/mmc.c | 61 ++++++++------ include/configs/mx6cuboxi.h | 25 +++--- include/mmc.h | 12 ++- 4 files changed, 167 insertions(+), 46 deletions(-)
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic
participants (2)
-
Baruch Siach
-
Stefano Babic