summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_psci_handlers.c48
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_secondary.c37
2 files changed, 84 insertions, 1 deletions
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
index 01238548..35b7ee91 100644
--- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
@@ -28,6 +28,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <mce.h>
#include <psci.h>
#include <tegra_private.h>
@@ -45,3 +49,47 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state)
return PSCI_E_SUCCESS;
}
+
+int tegra_soc_prepare_cpu_on(unsigned long mpidr)
+{
+ int target_cpu = mpidr & MPIDR_CPU_MASK;
+ int target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
+ MPIDR_AFFINITY_BITS;
+
+ if (target_cluster > MPIDR_AFFLVL1) {
+ ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
+ return PSCI_E_NOT_PRESENT;
+ }
+
+ /* construct the target CPU # */
+ target_cpu |= (target_cluster << 2);
+
+ mce_command_handler(MCE_CMD_ONLINE_CORE, target_cpu, 0, 0);
+
+ return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
+{
+ /*
+ * Check if we are exiting from SOC_POWERDN.
+ */
+ if (tegra_system_suspended()) {
+
+ /*
+ * System resume complete.
+ */
+ tegra_pm_system_suspend_exit();
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_prepare_cpu_off(unsigned long mpidr)
+{
+ /* Turn off wake_mask */
+ mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, 0, 0, 1);
+
+ /* Turn off CPU */
+ return mce_command_handler(MCE_CMD_ENTER_CSTATE, ~0, 0, 0);
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_secondary.c b/plat/nvidia/tegra/soc/t186/plat_secondary.c
index 85cc32c8..df802891 100644
--- a/plat/nvidia/tegra/soc/t186/plat_secondary.c
+++ b/plat/nvidia/tegra/soc/t186/plat_secondary.c
@@ -28,10 +28,45 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <debug.h>
+#include <mce.h>
+#include <mmio.h>
+#include <tegra_def.h>
+
+#define MISCREG_CPU_RESET_VECTOR 0x2000
+#define MISCREG_AA64_RST_LOW 0x2004
+#define MISCREG_AA64_RST_HIGH 0x2008
+
+#define SCRATCH_SECURE_RSV1_SCRATCH_0 0x658
+#define SCRATCH_SECURE_RSV1_SCRATCH_1 0x65C
+
+#define CPU_RESET_MODE_AA64 1
+
+extern void tegra_secure_entrypoint(void);
+
/*******************************************************************************
* Setup secondary CPU vectors
******************************************************************************/
void plat_secondary_setup(void)
{
- ; /* do nothing */
+ uint32_t addr_low, addr_high;
+ uint64_t reset_addr = (uint64_t)tegra_secure_entrypoint;
+
+ INFO("Setting up secondary CPU boot\n");
+
+ addr_low = (uint32_t)reset_addr | CPU_RESET_MODE_AA64;
+ addr_high = (uint32_t)((reset_addr >> 32) & 0x7ff);
+
+ /* write lower 32 bits first, then the upper 11 bits */
+ mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW, addr_low);
+ mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH, addr_high);
+
+ /* save reset vector to be used during SYSTEM_SUSPEND exit */
+ mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_RSV1_SCRATCH_0,
+ addr_low);
+ mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_RSV1_SCRATCH_1,
+ addr_high);
+
+ /* update reset vector address to the CCPLEX */
+ mce_update_reset_vector(addr_low, addr_high);
}