diff options
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_psci_handlers.c | 48 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_secondary.c | 37 |
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); } |