armv7R: K3: am654: Shut down R5 core after ATF startup on A53
[oweals/u-boot.git] / arch / arm / mach-k3 / am6_init.c
index a5553190b431e7292452aeed154cc4540e3e2f80..31fa1c8803c0dc3ad0665256a9523f7cd49193e7 100644 (file)
 #include <asm/io.h>
 #include <spl.h>
 #include <asm/arch/hardware.h>
+#include <asm/arch/sysfw-loader.h>
+#include <asm/arch/sys_proto.h>
 #include "common.h"
 #include <dm.h>
+#include <dm/uclass-internal.h>
+#include <dm/pinctrl.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
 
 #ifdef CONFIG_SPL_BUILD
 static void mmr_unlock(u32 base, u32 partition)
@@ -49,16 +54,21 @@ static void ctrl_mmr_unlock(void)
        mmr_unlock(CTRL_MMR0_BASE, 7);
 }
 
+/*
+ * 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
+ * it to the .data section.
+ */
+u32 bootindex __attribute__((section(".data")));
+
 static void store_boot_index_from_rom(void)
 {
-       u32 *boot_index = (u32 *)K3_BOOT_PARAM_TABLE_INDEX_VAL;
-
-       *boot_index = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX);
+       bootindex = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX);
 }
 
 void board_init_f(ulong dummy)
 {
-#if defined(CONFIG_K3_AM654_DDRSS)
+#if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS)
        struct udevice *dev;
        int ret;
 #endif
@@ -78,15 +88,38 @@ void board_init_f(ulong dummy)
        /* Init DM early in-order to invoke system controller */
        spl_early_init();
 
+#ifdef CONFIG_K3_LOAD_SYSFW
+       /*
+        * Process pinctrl for the serial0 a.k.a. WKUP_UART0 module and continue
+        * regardless of the result of pinctrl. Do this without probing the
+        * device, but instead by searching the device that would request the
+        * given sequence number if probed. The UART will be used by the system
+        * firmware (SYSFW) image for various purposes and SYSFW depends on us
+        * to initialize its pin settings.
+        */
+       ret = uclass_find_device_by_seq(UCLASS_SERIAL, 0, true, &dev);
+       if (!ret)
+               pinctrl_select_state(dev, "default");
+
+       /*
+        * Load, start up, and configure system controller firmware. Provide
+        * the U-Boot console init function to the SYSFW post-PM configuration
+        * callback hook, effectively switching on (or over) the console
+        * output.
+        */
+       k3_sysfw_loader(preloader_console_init);
+#else
        /* Prepare console output */
        preloader_console_init();
+#endif
+
+       /* Perform EEPROM-based board detection */
+       do_board_detect();
 
 #ifdef CONFIG_K3_AM654_DDRSS
        ret = uclass_get_device(UCLASS_RAM, 0, &dev);
-       if (ret) {
-               printf("DRAM init failed: %d\n", ret);
-               return;
-       }
+       if (ret)
+               panic("DRAM init failed: %d\n", ret);
 #endif
 }
 
@@ -94,7 +127,6 @@ u32 spl_boot_mode(const u32 boot_device)
 {
 #if defined(CONFIG_SUPPORT_EMMC_BOOT)
        u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT);
-       u32 bootindex = readl(K3_BOOT_PARAM_TABLE_INDEX_VAL);
 
        u32 bootmode = (devstat & CTRLMMR_MAIN_DEVSTAT_BOOTMODE_MASK) >>
                        CTRLMMR_MAIN_DEVSTAT_BOOTMODE_SHIFT;
@@ -170,7 +202,6 @@ static u32 __get_primary_bootmedia(u32 devstat)
 u32 spl_boot_device(void)
 {
        u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT);
-       u32 bootindex = readl(K3_BOOT_PARAM_TABLE_INDEX_VAL);
 
        if (bootindex == K3_PRIMARY_BOOTMODE)
                return __get_primary_bootmedia(devstat);
@@ -184,3 +215,64 @@ void reset_cpu(ulong ignored)
 {
 }
 #endif
+
+#ifdef CONFIG_SYS_K3_SPL_ATF
+
+#define AM6_DEV_MCU_RTI0                       134
+#define AM6_DEV_MCU_RTI1                       135
+#define AM6_DEV_MCU_ARMSS0_CPU0                        159
+#define AM6_DEV_MCU_ARMSS0_CPU1                        245
+
+void release_resources_for_core_shutdown(void)
+{
+       struct udevice *dev;
+       struct ti_sci_handle *ti_sci;
+       struct ti_sci_dev_ops *dev_ops;
+       struct ti_sci_proc_ops *proc_ops;
+       int ret;
+       u32 i;
+
+       const u32 put_device_ids[] = {
+               AM6_DEV_MCU_RTI0,
+               AM6_DEV_MCU_RTI1,
+       };
+
+       /* Get handle to Device Management and Security Controller (SYSFW) */
+       ret = uclass_get_device_by_name(UCLASS_FIRMWARE, "dmsc", &dev);
+       if (ret)
+               panic("Failed to get handle to SYSFW (%d)\n", ret);
+
+       ti_sci = (struct ti_sci_handle *)(ti_sci_get_handle_from_sysfw(dev));
+       dev_ops = &ti_sci->ops.dev_ops;
+       proc_ops = &ti_sci->ops.proc_ops;
+
+       /* Iterate through list of devices to put (shutdown) */
+       for (i = 0; i < ARRAY_SIZE(put_device_ids); i++) {
+               u32 id = put_device_ids[i];
+
+               ret = dev_ops->put_device(ti_sci, id);
+               if (ret)
+                       panic("Failed to put device %u (%d)\n", id, ret);
+       }
+
+       const u32 put_core_ids[] = {
+               AM6_DEV_MCU_ARMSS0_CPU1,
+               AM6_DEV_MCU_ARMSS0_CPU0,        /* Handle CPU0 after CPU1 */
+       };
+
+       /* Iterate through list of cores to put (shutdown) */
+       for (i = 0; i < ARRAY_SIZE(put_core_ids); i++) {
+               u32 id = put_core_ids[i];
+
+               /*
+                * Queue up the core shutdown request. Note that this call
+                * needs to be followed up by an actual invocation of an WFE
+                * or WFI CPU instruction.
+                */
+               ret = proc_ops->proc_shutdown_no_wait(ti_sci, id);
+               if (ret)
+                       panic("Failed sending core %u shutdown message (%d)\n",
+                             id, ret);
+       }
+}
+#endif