arm: K3: sysfw-loader: Add a config_pm_pre_callback()
authorFaiz Abbas <faiz_abbas@ti.com>
Wed, 26 Feb 2020 08:14:36 +0000 (13:44 +0530)
committerPeng Fan <peng.fan@nxp.com>
Mon, 9 Mar 2020 00:33:16 +0000 (08:33 +0800)
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>
arch/arm/mach-k3/am6_init.c
arch/arm/mach-k3/include/mach/sysfw-loader.h
arch/arm/mach-k3/j721e_init.c
arch/arm/mach-k3/sysfw-loader.c

index 63cd7e04589772fbbaffdc785b35e5ecb593e541..d0b10e58ad3e176d7f35dcebcb3f5d20ef99b197 100644 (file)
@@ -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
index 36eb26534895fde9f67ba3ab119a96642f3021d9..6f5612b4fd3fdf46f1e4f584ebe554cc1bd27430 100644 (file)
@@ -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
index f7f7398081483f2025584198d12a020cb57a97a9..0994522f6c30ceed1e2bf345d32409081be8f1a8 100644 (file)
@@ -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
index 94dbeb9437d9472ca3e469a741c82156bf44c896..db02607b171ee52076edd98d8cecc6bd121a5aa0 100644 (file)
@@ -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);