summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFaiz Abbas <faiz_abbas@ti.com>2020-02-26 13:44:36 +0530
committerPeng Fan <peng.fan@nxp.com>2020-03-09 08:33:16 +0800
commitd45ffb79376a9ab28ddfd2a61111a1732541289a (patch)
treea6e5559f6801d6a07c542055ec24e7ebd5d16f3a
parentcf0082559698765a96f96cb3811db6a91c02ca82 (diff)
downloadu-boot-d45ffb79376a9ab28ddfd2a61111a1732541289a.tar.gz
arm: K3: sysfw-loader: Add a config_pm_pre_callback()
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 <faiz_abbas@ti.com> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
-rw-r--r--arch/arm/mach-k3/am6_init.c33
-rw-r--r--arch/arm/mach-k3/include/mach/sysfw-loader.h2
-rw-r--r--arch/arm/mach-k3/j721e_init.c33
-rw-r--r--arch/arm/mach-k3/sysfw-loader.c6
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 63cd7e0458..d0b10e58ad 100644
--- a/arch/arm/mach-k3/am6_init.c
+++ b/arch/arm/mach-k3/am6_init.c
@@ -17,6 +17,7 @@
#include <dm/uclass-internal.h>
#include <dm/pinctrl.h>
#include <linux/soc/ti/ti_sci_protocol.h>
+#include <mmc.h>
#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)
@@ -138,7 +166,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 <dm.h>
#include <dm/uclass-internal.h>
#include <dm/pinctrl.h>
+#include <mmc.h>
#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 94dbeb9437..db02607b17 100644
--- a/arch/arm/mach-k3/sysfw-loader.c
+++ b/arch/arm/mach-k3/sysfw-loader.c
@@ -197,7 +197,8 @@ exit:
}
#endif
-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 };
@@ -291,6 +292,9 @@ void k3_sysfw_loader(void (*config_pm_done_callback)(void))
/* Get handle for accessing SYSFW services */
ti_sci = get_ti_sci_handle();
+ if (config_pm_pre_callback)
+ config_pm_pre_callback();
+
/* Parse and apply the different SYSFW configuration fragments */
k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci);