Tegra186: power on/off secondary CPUs

This patch add code to power on/off the secondary CPUs on the Tegra186
chip. The MCE block is the actual hardware that takes care of the
power on/off sequence. We pass the constructed CPU #, depending on the
MIDR_IMPL field, to the MCE CPU handlers.

This patch also programs the reset vector addresses to allow the
CPUs to power on through the monitor and then jump to the linux
world.

Change-Id: Idc164586cda91c2009d66f3e09bf4464de9662db
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
This commit is contained in:
Varun Wadekar 2015-09-14 09:31:39 +05:30
parent bb844c1f0d
commit b47d97b395
2 changed files with 84 additions and 1 deletions

View File

@ -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);
}

View File

@ -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);
}