From patchwork Thu Jan 23 15:24:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239979 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:26 +0530 Subject: [PATCH 01/10] mmc: Add a saved_clock member In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-2-faiz_abbas@ti.com> Add a saved_clock member to struct mmc to store the previous clock speed in the clock needs to be stopped for some time. Signed-off-by: Faiz Abbas --- include/mmc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mmc.h b/include/mmc.h index b5cb514f57..2f21dbf1b7 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -602,6 +602,7 @@ struct mmc { bool clk_disable; /* true if the clock can be turned off */ uint bus_width; uint clock; + uint saved_clock; enum mmc_voltage signal_voltage; uint card_caps; uint host_caps; From patchwork Thu Jan 23 15:24:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239980 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:27 +0530 Subject: [PATCH 02/10] arm: K3: sysfw-loader: Add a config_pm_pre_callback() In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-3-faiz_abbas@ti.com> System firmware does not guarantee that clocks going out of the device will be stable during power management configuration. There are some DCRC errors when SPL tries to get the next stage during eMMC boot after sysfw pm configuration. Therefore add a config_pm_pre_callback() to switch off the eMMC clock before power management and restart it after it is done. Signed-off-by: Faiz Abbas --- arch/arm/mach-k3/am6_init.c | 33 +++++++++++++++++++- arch/arm/mach-k3/include/mach/sysfw-loader.h | 2 +- arch/arm/mach-k3/j721e_init.c | 33 +++++++++++++++++++- arch/arm/mach-k3/sysfw-loader.c | 6 +++- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c index 8d107b870b..9d3c62b3f4 100644 --- a/arch/arm/mach-k3/am6_init.c +++ b/arch/arm/mach-k3/am6_init.c @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_SPL_BUILD #ifdef CONFIG_K3_LOAD_SYSFW @@ -86,6 +87,33 @@ static void store_boot_index_from_rom(void) bootindex = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX); } +#if defined(CONFIG_K3_LOAD_SYSFW) +void k3_mmc_stop_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc->saved_clock = mmc->clock; + mmc_set_clock(mmc, 0, true); + } +} + +void k3_mmc_restart_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc_set_clock(mmc, mmc->saved_clock, false); + } +} +#endif + void board_init_f(ulong dummy) { #if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS) @@ -128,7 +156,10 @@ void board_init_f(ulong dummy) * callback hook, effectively switching on (or over) the console * output. */ - k3_sysfw_loader(preloader_console_init); + k3_sysfw_loader(k3_mmc_stop_clock, k3_mmc_restart_clock); + + /* Prepare console output */ + preloader_console_init(); /* Disable ROM configured firewalls right after loading sysfw */ #ifdef CONFIG_TI_SECURE_DEVICE diff --git a/arch/arm/mach-k3/include/mach/sysfw-loader.h b/arch/arm/mach-k3/include/mach/sysfw-loader.h index 36eb265348..6f5612b4fd 100644 --- a/arch/arm/mach-k3/include/mach/sysfw-loader.h +++ b/arch/arm/mach-k3/include/mach/sysfw-loader.h @@ -7,6 +7,6 @@ #ifndef _SYSFW_LOADER_H_ #define _SYSFW_LOADER_H_ -void k3_sysfw_loader(void (*config_pm_done_callback)(void)); +void k3_sysfw_loader(void (*config_pm_pre_callback)(void), void (*config_pm_done_callback)(void)); #endif diff --git a/arch/arm/mach-k3/j721e_init.c b/arch/arm/mach-k3/j721e_init.c index f7f7398081..0994522f6c 100644 --- a/arch/arm/mach-k3/j721e_init.c +++ b/arch/arm/mach-k3/j721e_init.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_SPL_BUILD #ifdef CONFIG_K3_LOAD_SYSFW @@ -100,6 +101,33 @@ static void ctrl_mmr_unlock(void) mmr_unlock(CTRL_MMR0_BASE, 7); } +#if defined(CONFIG_K3_LOAD_SYSFW) +void k3_mmc_stop_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc->saved_clock = mmc->clock; + mmc_set_clock(mmc, 0, true); + } +} + +void k3_mmc_restart_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc_set_clock(mmc, mmc->saved_clock, false); + } +} +#endif + /* * This uninitialized global variable would normal end up in the .bss section, * but the .bss is cleared between writing and reading this variable, so move @@ -154,7 +182,10 @@ void board_init_f(ulong dummy) * callback hook, effectively switching on (or over) the console * output. */ - k3_sysfw_loader(preloader_console_init); + k3_sysfw_loader(k3_mmc_stop_clock, k3_mmc_restart_clock); + + /* Prepare console output */ + preloader_console_init(); /* Disable ROM configured firewalls right after loading sysfw */ #ifdef CONFIG_TI_SECURE_DEVICE diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c index 5903bbe12a..8386499ed6 100644 --- a/arch/arm/mach-k3/sysfw-loader.c +++ b/arch/arm/mach-k3/sysfw-loader.c @@ -172,7 +172,8 @@ static void k3_sysfw_configure_using_fit(void *fit, ret); } -void k3_sysfw_loader(void (*config_pm_done_callback)(void)) +void k3_sysfw_loader(void (*config_pm_pre_callback) (void), + void (*config_pm_done_callback)(void)) { struct spl_image_info spl_image = { 0 }; struct spl_boot_device bootdev = { 0 }; @@ -264,6 +265,9 @@ void k3_sysfw_loader(void (*config_pm_done_callback)(void)) /* Parse and apply the different SYSFW configuration fragments */ k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci); + if (config_pm_pre_callback) + config_pm_pre_callback(); + /* * Now that all clocks and PM aspects are setup, invoke a user- * provided callback function. Usually this callback would be used From patchwork Thu Jan 23 15:24:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239981 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:28 +0530 Subject: [PATCH 03/10] configs: am65x_evm: Add CONFIG_SUPPORT_EMMC_BOOT In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-4-faiz_abbas@ti.com> With CONFIG_SUPPORT_EMMC_BOOT moved to Kconfig, move it to defconfig files. Signed-off-by: Faiz Abbas --- configs/am65x_evm_a53_defconfig | 1 + configs/am65x_evm_r5_defconfig | 1 + include/configs/am65x_evm.h | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig index 30c1047024..4ee13d05e1 100644 --- a/configs/am65x_evm_a53_defconfig +++ b/configs/am65x_evm_a53_defconfig @@ -75,6 +75,7 @@ CONFIG_DM_KEYBOARD=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ADMA=y CONFIG_SPL_MMC_SDHCI_ADMA=y diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig index 4247f8df28..4d77cf510f 100644 --- a/configs/am65x_evm_r5_defconfig +++ b/configs/am65x_evm_r5_defconfig @@ -73,6 +73,7 @@ CONFIG_K3_SEC_PROXY=y CONFIG_MISC=y CONFIG_K3_AVS0=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_SPL_MMC_SDHCI_ADMA=y CONFIG_MMC_SDHCI_AM654=y diff --git a/include/configs/am65x_evm.h b/include/configs/am65x_evm.h index 7d7f86a059..23ee2254ed 100644 --- a/include/configs/am65x_evm.h +++ b/include/configs/am65x_evm.h @@ -127,8 +127,6 @@ #define CONFIG_SYS_MMC_ENV_PART 1 #endif -#define CONFIG_SUPPORT_EMMC_BOOT - /* Now for the remaining common defines */ #include From patchwork Thu Jan 23 15:24:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239982 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:29 +0530 Subject: [PATCH 04/10] spl: mmc: Fix spl_mmc_get_uboot_raw_sector() implementation In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-5-faiz_abbas@ti.com> The call to spl_mmc_get_uboot_raw_sector() completely ignores and overwrites the raw_sect value passed from the caller of spl_mmc_load(). Fix this by passing raw_sect to the function and returning the same value in the default case. Signed-off-by: Faiz Abbas --- arch/arm/mach-imx/imx8/image.c | 3 ++- common/spl/spl_mmc.c | 11 ++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-imx/imx8/image.c b/arch/arm/mach-imx/imx8/image.c index 58a29e8a03..08b0050f57 100644 --- a/arch/arm/mach-imx/imx8/image.c +++ b/arch/arm/mach-imx/imx8/image.c @@ -196,7 +196,8 @@ unsigned long spl_spi_get_uboot_offs(struct spi_flash *flash) #endif #ifdef CONFIG_SPL_MMC_SUPPORT -unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc) +unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, + unsigned long raw_sect) { int end; diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 3e6a17c110..a2ea363e96 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -317,13 +317,10 @@ int spl_boot_partition(const u32 boot_device) } #endif -unsigned long __weak spl_mmc_get_uboot_raw_sector(struct mmc *mmc) +unsigned long __weak spl_mmc_get_uboot_raw_sector(struct mmc *mmc, + unsigned long raw_sect) { -#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR; -#else - return 0; -#endif + return raw_sect; } int spl_mmc_load(struct spl_image_info *spl_image, @@ -392,7 +389,7 @@ int spl_mmc_load(struct spl_image_info *spl_image, return err; } - raw_sect = spl_mmc_get_uboot_raw_sector(mmc); + raw_sect = spl_mmc_get_uboot_raw_sector(mmc, raw_sect); #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION err = mmc_load_image_raw_partition(spl_image, mmc, raw_part, From patchwork Thu Jan 23 15:24:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239983 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:30 +0530 Subject: [PATCH 05/10] mmc: Merge SD_LEGACY and MMC_LEGACY bus modes In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-6-faiz_abbas@ti.com> MMC_LEGACY & SD_LEGACY are not differentiated timings in the spec and don't have any meaningful differences. Therefore, get rid of all references to SD_LEGACY and use MMC_LEGACY to mean both of them. Signed-off-by: Faiz Abbas --- drivers/mmc/fsl_esdhc_imx.c | 1 - drivers/mmc/mmc.c | 18 ++++++++---------- drivers/mmc/omap_hsmmc.c | 1 - drivers/mmc/zynq_sdhci.c | 1 - include/mmc.h | 1 - 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 462ad2878a..6555639fdf 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -741,7 +741,6 @@ static int esdhc_set_timing(struct mmc *mmc) switch (mmc->selected_mode) { case MMC_LEGACY: - case SD_LEGACY: esdhc_reset_tuning(mmc); writel(mixctrl, ®s->mixctrl); break; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d43983d4a6..364d39bf3b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -136,7 +136,6 @@ const char *mmc_mode_name(enum bus_mode mode) { static const char *const names[] = { [MMC_LEGACY] = "MMC legacy", - [SD_LEGACY] = "SD Legacy", [MMC_HS] = "MMC High Speed (26MHz)", [SD_HS] = "SD High Speed (50MHz)", [UHS_SDR12] = "UHS SDR12 (25MHz)", @@ -162,7 +161,6 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) { static const int freqs[] = { [MMC_LEGACY] = 25000000, - [SD_LEGACY] = 25000000, [MMC_HS] = 26000000, [SD_HS] = 50000000, [MMC_HS_52] = 52000000, @@ -1241,7 +1239,7 @@ static int sd_get_capabilities(struct mmc *mmc) u32 sd3_bus_mode; #endif - mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); + mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); if (mmc_host_is_spi(mmc)) return 0; @@ -1354,7 +1352,7 @@ static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) return 0; switch (mode) { - case SD_LEGACY: + case MMC_LEGACY: speed = UHS_SDR12_BUS_SPEED; break; case SD_HS: @@ -1697,7 +1695,7 @@ static const struct mode_width_tuning sd_modes_by_pref[] = { }, #endif { - .mode = SD_LEGACY, + .mode = MMC_LEGACY, .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, } }; @@ -1727,7 +1725,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) if (mmc_host_is_spi(mmc)) { mmc_set_bus_width(mmc, 1); - mmc_select_mode(mmc, SD_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); return 0; } @@ -1786,7 +1784,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) error: /* revert to a safer bus speed */ - mmc_select_mode(mmc, SD_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); } @@ -2563,7 +2561,7 @@ static int mmc_startup(struct mmc *mmc) #if CONFIG_IS_ENABLED(MMC_TINY) mmc_set_clock(mmc, mmc->legacy_speed, false); - mmc_select_mode(mmc, IS_SD(mmc) ? SD_LEGACY : MMC_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_bus_width(mmc, 1); #else if (IS_SD(mmc)) { @@ -2845,8 +2843,8 @@ int mmc_start_init(struct mmc *mmc) * 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; + mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(MMC_LEGACY) | + MMC_MODE_1BIT; #if !defined(CONFIG_MMC_BROKEN_CD) no_card = mmc_getcd(mmc) == 0; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 5d0cfb2ebd..5e79fa517d 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -390,7 +390,6 @@ static void omap_hsmmc_set_timing(struct mmc *mmc) break; case MMC_LEGACY: case MMC_HS: - case SD_LEGACY: case UHS_SDR12: val |= AC12_UHSMC_SDR12; break; diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 529eec9c45..fc638649bd 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -35,7 +35,6 @@ struct arasan_sdhci_priv { static const u8 mode2timing[] = { [MMC_LEGACY] = UHS_SDR12_BUS_SPEED, - [SD_LEGACY] = UHS_SDR12_BUS_SPEED, [MMC_HS] = HIGH_SPEED_BUS_SPEED, [SD_HS] = HIGH_SPEED_BUS_SPEED, [MMC_HS_52] = HIGH_SPEED_BUS_SPEED, diff --git a/include/mmc.h b/include/mmc.h index 2f21dbf1b7..3c763670f2 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -532,7 +532,6 @@ struct sd_ssr { enum bus_mode { MMC_LEGACY, - SD_LEGACY, MMC_HS, SD_HS, MMC_HS_52, From patchwork Thu Jan 23 15:24:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239984 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:31 +0530 Subject: [PATCH 06/10] mmc: sdhci_am654: Update output tap delay writes In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-7-faiz_abbas@ti.com> With the latest RIOT, there is a different otap delay value for each speed mode. Add a new binding with every supported speed mode. Also disable a given speed mode in the host caps if its corresponding otap-del-sel is not present. Signed-off-by: Faiz Abbas --- arch/arm/dts/k3-am65-main.dtsi | 12 +++- arch/arm/dts/k3-am654-base-board-u-boot.dtsi | 11 ++- arch/arm/dts/k3-j721e-main.dtsi | 15 ++++- drivers/mmc/am654_sdhci.c | 70 +++++++++++++++++--- 4 files changed, 95 insertions(+), 13 deletions(-) diff --git a/arch/arm/dts/k3-am65-main.dtsi b/arch/arm/dts/k3-am65-main.dtsi index ab40dafceb..028f57379b 100644 --- a/arch/arm/dts/k3-am65-main.dtsi +++ b/arch/arm/dts/k3-am65-main.dtsi @@ -98,7 +98,17 @@ interrupts = ; mmc-ddr-1_8v; mmc-hs200-1_8v; - ti,otap-del-sel = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0x0>; + ti,otap-del-sel-sdr25 = <0x0>; + ti,otap-del-sel-sdr50 = <0x8>; + ti,otap-del-sel-sdr104 = <0x5>; + ti,otap-del-sel-ddr50 = <0x5>; + ti,otap-del-sel-ddr52 = <0x5>; + ti,otap-del-sel-hs200 = <0x5>; + ti,otap-del-sel-hs400 = <0x0>; ti,trm-icp = <0x8>; dma-coherent; }; diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index a349edcfa5..54ecb3d444 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -29,7 +29,16 @@ clock-names = "clk_ahb", "clk_xin"; power-domains = <&k3_pds 48 TI_SCI_PD_EXCLUSIVE>; max-frequency = <25000000>; - ti,otap-del-sel = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0x0>; + ti,otap-del-sel-sdr25 = <0x0>; + ti,otap-del-sel-sdr50 = <0x8>; + ti,otap-del-sel-sdr104 = <0x7>; + ti,otap-del-sel-ddr50 = <0x4>; + ti,otap-del-sel-ddr52 = <0x4>; + ti,otap-del-sel-hs200 = <0x7>; ti,trm-icp = <0x8>; }; diff --git a/arch/arm/dts/k3-j721e-main.dtsi b/arch/arm/dts/k3-j721e-main.dtsi index 5083a0c3ae..86304015c4 100644 --- a/arch/arm/dts/k3-j721e-main.dtsi +++ b/arch/arm/dts/k3-j721e-main.dtsi @@ -210,9 +210,14 @@ assigned-clocks = <&k3_clks 91 1>; assigned-clock-parents = <&k3_clks 91 2>; bus-width = <8>; - ti,otap-del-sel = <0x2>; ti,trm-icp = <0x8>; dma-coherent; + mmc-ddr-1_8v; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x5>; + ti,otap-del-sel-hs200 = <0x6>; + ti,otap-del-sel-hs400 = <0x0>; }; main_sdhci1: sdhci at 4fb0000 { @@ -224,7 +229,13 @@ clocks = <&k3_clks 92 0>, <&k3_clks 92 5>; assigned-clocks = <&k3_clks 92 0>; assigned-clock-parents = <&k3_clks 92 1>; - ti,otap-del-sel = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-sd-hs = <0xf>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x5>; + ti,otap-del-sel-ddr50 = <0xc>; ti,trm-icp = <0x8>; dma-coherent; }; diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 41a90834ff..ff0a81eaab 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -72,7 +72,7 @@ struct am654_sdhci_plat { struct mmc mmc; struct regmap *base; bool non_removable; - u32 otap_del_sel; + u32 otap_del_sel[11]; u32 trm_icp; u32 drv_strength; u32 strb_sel; @@ -84,6 +84,25 @@ struct am654_sdhci_plat { bool dll_on; }; +struct timing_data { + const char *binding; + u32 capability; +}; + +static const struct timing_data td[] = { + [MMC_LEGACY] = {"ti,otap-del-sel-legacy", 0}, + [MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP(MMC_HS)}, + [SD_HS] = {"ti,otap-del-sel-sd-hs", MMC_CAP(SD_HS)}, + [UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP(UHS_SDR12)}, + [UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP(UHS_SDR25)}, + [UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP(UHS_SDR50)}, + [UHS_SDR104] = {"ti,otap-del-sel-sdr104", MMC_CAP(UHS_SDR104)}, + [UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP(UHS_DDR50)}, + [MMC_DDR_52] = {"ti,otap-del-sel-ddr52", MMC_CAP(MMC_DDR_52)}, + [MMC_HS_200] = {"ti,otap-del-sel-hs200", MMC_CAP(MMC_HS_200)}, + [MMC_HS_400] = {"ti,otap-del-sel-hs400", MMC_CAP(MMC_HS_400)}, +}; + struct am654_driver_data { const struct sdhci_ops *ops; u32 flags; @@ -110,6 +129,7 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) struct am654_sdhci_plat *plat = dev_get_platdata(dev); unsigned int speed = host->mmc->clock; int sel50, sel100, freqsel; + u32 otap_del_sel; u32 mask, val; int ret; @@ -130,9 +150,10 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) /* switch phy back on */ if (speed > AM654_SDHCI_MIN_FREQ) { + otap_del_sel = plat->otap_del_sel[host->mmc->selected_mode]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; val = (1 << OTAPDLYENA_SHIFT) | - (plat->otap_del_sel << OTAPDLYSEL_SHIFT); + (otap_del_sel << OTAPDLYSEL_SHIFT); /* Write to STRBSEL for HS400 speed mode */ if (host->mmc->selected_mode == MMC_HS_400) { @@ -214,11 +235,11 @@ static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host) { struct udevice *dev = host->mmc->dev; struct am654_sdhci_plat *plat = dev_get_platdata(dev); - u32 mask, val; + u32 otap_del_sel, mask, val; + otap_del_sel = plat->otap_del_sel[host->mmc->selected_mode]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; - val = (1 << OTAPDLYENA_SHIFT) | - (plat->otap_del_sel << OTAPDLYSEL_SHIFT); + val = (1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); regmap_update_bits(plat->base, PHY_CTRL4, mask, val); return 0; @@ -279,6 +300,37 @@ int am654_sdhci_init(struct am654_sdhci_plat *plat) return 0; } +static int sdhci_am654_get_otap_delay(struct udevice *dev, + struct mmc_config *cfg) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + int ret; + int i; + + /* ti,otap-del-sel-legacy is mandatory */ + ret = dev_read_u32(dev, "ti,otap-del-sel-legacy", + &plat->otap_del_sel[0]); + if (ret) + return ret; + /* + * Remove the corresponding capability if an otap-del-sel + * value is not found + */ + for (i = MMC_HS; i <= MMC_HS_400; i++) { + ret = dev_read_u32(dev, td[i].binding, &plat->otap_del_sel[i]); + if (ret) { + dev_dbg(dev, "Couldn't find %s\n", td[i].binding); + /* + * Remove the corresponding capability + * if an otap-del-sel value is not found + */ + cfg->host_caps &= ~td[i].capability; + } + } + + return 0; +} + static int am654_sdhci_probe(struct udevice *dev) { struct am654_driver_data *drv_data = @@ -311,6 +363,10 @@ static int am654_sdhci_probe(struct udevice *dev) if (ret) return ret; + ret = sdhci_am654_get_otap_delay(dev, cfg); + if (ret) + return ret; + host->ops = drv_data->ops; host->mmc->priv = host; upriv->mmc = host->mmc; @@ -334,10 +390,6 @@ static int am654_sdhci_ofdata_to_platdata(struct udevice *dev) host->ioaddr = (void *)dev_read_addr(dev); plat->non_removable = dev_read_bool(dev, "non-removable"); - ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel); - if (ret) - return ret; - if (plat->flags & DLL_PRESENT) { ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp); if (ret) From patchwork Thu Jan 23 15:24:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239985 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:32 +0530 Subject: [PATCH 07/10] configs: j721e_evm: Add Support for eMMC boot In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-8-faiz_abbas@ti.com> Enable configs to support eMMC boot support. Signed-off-by: Faiz Abbas --- configs/j721e_evm_a72_defconfig | 3 +++ configs/j721e_evm_r5_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig index 1cc75ce18a..553608c2fd 100644 --- a/configs/j721e_evm_a72_defconfig +++ b/configs/j721e_evm_a72_defconfig @@ -26,6 +26,8 @@ CONFIG_SPL_BOARD_INIT=y CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y @@ -91,6 +93,7 @@ CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_MISC=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ADMA=y CONFIG_SPL_MMC_SDHCI_ADMA=y diff --git a/configs/j721e_evm_r5_defconfig b/configs/j721e_evm_r5_defconfig index cb6c74d7bf..f423db9bad 100644 --- a/configs/j721e_evm_r5_defconfig +++ b/configs/j721e_evm_r5_defconfig @@ -24,6 +24,8 @@ CONFIG_USE_BOOTCOMMAND=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y CONFIG_SPL_EARLY_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y @@ -72,6 +74,7 @@ CONFIG_MISC=y CONFIG_FS_LOADER=y CONFIG_K3_AVS0=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_SPL_MMC_SDHCI_ADMA=y CONFIG_MMC_SDHCI_AM654=y From patchwork Thu Jan 23 15:24:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239986 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:33 +0530 Subject: [PATCH 08/10] mmc: Add init() API In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-9-faiz_abbas@ti.com> Add an init() API for platform specific init() operations. Signed-off-by: Faiz Abbas --- drivers/mmc/mmc.c | 15 +++++++-------- include/mmc.h | 7 +++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 364d39bf3b..a055ecbc9d 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2752,6 +2752,7 @@ static int mmc_power_cycle(struct mmc *mmc) int mmc_get_op_cond(struct mmc *mmc) { + struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev); bool uhs_en = supports_uhs(mmc->cfg->host_caps); int err; @@ -2786,14 +2787,12 @@ int mmc_get_op_cond(struct mmc *mmc) if (err) return err; -#if CONFIG_IS_ENABLED(DM_MMC) - /* The device has already been probed ready for use */ -#else - /* made sure it's not NULL earlier */ - err = mmc->cfg->ops->init(mmc); - if (err) - return err; -#endif + if (ops->init) { + err = ops->init(mmc->dev); + if (err) + return err; + } + mmc->ddr_mode = 0; retry: diff --git a/include/mmc.h b/include/mmc.h index 3c763670f2..a96833c1ca 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -406,6 +406,13 @@ struct mmc; #if CONFIG_IS_ENABLED(DM_MMC) struct dm_mmc_ops { + /** + * init() - platform specific initialization for the host controller + * + * @dev: Device to init + * @return 0 if Ok, -ve if error + */ + int (*init)(struct udevice *dev); /** * send_cmd() - Send a command to the MMC device * From patchwork Thu Jan 23 15:24:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239987 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:34 +0530 Subject: [PATCH 09/10] mmc: sdhci: Expose sdhci_init() as non-static In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-10-faiz_abbas@ti.com> Expose sdhci_init() as non-static. Signed-off-by: Faiz Abbas --- drivers/mmc/sdhci.c | 2 +- include/sdhci.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 01fa5a9d4d..4fce85a0ea 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -618,7 +618,7 @@ static int sdhci_set_ios(struct mmc *mmc) return 0; } -static int sdhci_init(struct mmc *mmc) +int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = mmc->priv; #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_GPIO) diff --git a/include/sdhci.h b/include/sdhci.h index 01addb7a60..0830e05d53 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -487,6 +487,7 @@ void sdhci_set_uhs_timing(struct sdhci_host *host); #ifdef CONFIG_DM_MMC /* Export the operations to drivers */ int sdhci_probe(struct udevice *dev); +int sdhci_init(struct mmc *mmc); int sdhci_set_clock(struct mmc *mmc, unsigned int clock); extern const struct dm_mmc_ops sdhci_ops; #else From patchwork Thu Jan 23 15:24:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 239988 List-Id: U-Boot discussion From: faiz_abbas at ti.com (Faiz Abbas) Date: Thu, 23 Jan 2020 20:54:35 +0530 Subject: [PATCH 10/10] mmc: am654_sdhci: Implement workaround for card detect In-Reply-To: <20200123152435.6793-1-faiz_abbas@ti.com> References: <20200123152435.6793-1-faiz_abbas@ti.com> Message-ID: <20200123152435.6793-11-faiz_abbas@ti.com> The 4 bit MMC controllers have an internal debounce for the SDCD line with a debounce delay of 1 second. Therefore, after clocks to the IP are enabled, software has to wait for this time before it can power on the controller. Add an init() callback which polls on sdcd for a maximum of 2 seconds before switching on power to the controller or (in the case of no card) returning a ENOMEDIUM. This pushes the 1 second wait time to when the card is actually needed rather than at every probe() making sure that users who don't insert an SD card in the slot don't have to wait such a long time. Signed-off-by: Faiz Abbas --- drivers/mmc/am654_sdhci.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index ff0a81eaab..ccae3fea31 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -254,7 +254,7 @@ const struct am654_driver_data j721e_4bit_drv_data = { .flags = IOMUX_PRESENT, }; -int am654_sdhci_init(struct am654_sdhci_plat *plat) +int am654_sdhci_init_phy(struct am654_sdhci_plat *plat) { u32 ctl_cfg_2 = 0; u32 mask, val; @@ -331,8 +331,37 @@ static int sdhci_am654_get_otap_delay(struct udevice *dev, return 0; } +#define MAX_SDCD_DEBOUNCE_TIME 2000 +int am654_sdhci_init(struct udevice *dev) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + unsigned long start; + int val; + + /* + * The controller takes about 1 second to debounce the card detect line + * and doesn't let us power on until that time is up. Instead of waiting + * for 1 second at every stage, poll on the CARD_PRESENT bit upto a + * maximum of 2 seconds to be safe.. + */ + start = get_timer(0); + do { + if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME) + return -ENOMEDIUM; + + val = mmc_getcd(host->mmc); + } while (!val); + + am654_sdhci_init_phy(plat); + + return sdhci_init(mmc); +} + static int am654_sdhci_probe(struct udevice *dev) { + struct dm_mmc_ops *ops = mmc_get_ops(dev); struct am654_driver_data *drv_data = (struct am654_driver_data *)dev_get_driver_data(dev); struct am654_sdhci_plat *plat = dev_get_platdata(dev); @@ -373,9 +402,9 @@ static int am654_sdhci_probe(struct udevice *dev) regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1); - am654_sdhci_init(plat); + ops->init = am654_sdhci_init; - return sdhci_probe(dev); + return 0; } static int am654_sdhci_ofdata_to_platdata(struct udevice *dev)