Merge pull request #452 from vwadekar/tegra-new-platform-apis-v2
Tegra new platform apis v2
This commit is contained in:
commit
05a91fb008
|
@ -36,9 +36,9 @@
|
||||||
#include <tegra_def.h>
|
#include <tegra_def.h>
|
||||||
|
|
||||||
/* Global functions */
|
/* Global functions */
|
||||||
.globl platform_is_primary_cpu
|
.globl plat_is_my_cpu_primary
|
||||||
.globl platform_get_core_pos
|
.globl plat_my_core_pos
|
||||||
.globl platform_get_entrypoint
|
.globl plat_get_my_entrypoint
|
||||||
.globl plat_secondary_cold_boot_setup
|
.globl plat_secondary_cold_boot_setup
|
||||||
.globl platform_mem_init
|
.globl platform_mem_init
|
||||||
.globl plat_crash_console_init
|
.globl plat_crash_console_init
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
.globl plat_reset_handler
|
.globl plat_reset_handler
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
.globl sec_entry_point
|
.globl tegra_sec_entry_point
|
||||||
.globl ns_image_entrypoint
|
.globl ns_image_entrypoint
|
||||||
.globl tegra_bl31_phys_base
|
.globl tegra_bl31_phys_base
|
||||||
|
|
||||||
|
@ -115,28 +115,47 @@
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/* -----------------------------------------------------
|
/* -----------------------------------------------------
|
||||||
* int platform_is_primary_cpu(int mpidr);
|
* unsigned int plat_is_my_cpu_primary(void);
|
||||||
*
|
*
|
||||||
* This function checks if this is the Primary CPU
|
* This function checks if this is the Primary CPU
|
||||||
* -----------------------------------------------------
|
* -----------------------------------------------------
|
||||||
*/
|
*/
|
||||||
func platform_is_primary_cpu
|
func plat_is_my_cpu_primary
|
||||||
|
mrs x0, mpidr_el1
|
||||||
and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
|
and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
|
||||||
cmp x0, #TEGRA_PRIMARY_CPU
|
cmp x0, #TEGRA_PRIMARY_CPU
|
||||||
cset x0, eq
|
cset x0, eq
|
||||||
ret
|
ret
|
||||||
endfunc platform_is_primary_cpu
|
endfunc plat_is_my_cpu_primary
|
||||||
|
|
||||||
/* -----------------------------------------------------
|
/* -----------------------------------------------------
|
||||||
* int platform_get_core_pos(int mpidr);
|
* unsigned int plat_my_core_pos(void);
|
||||||
*
|
*
|
||||||
* With this function: CorePos = CoreId
|
* result: CorePos = CoreId + (ClusterId << 2)
|
||||||
* -----------------------------------------------------
|
* -----------------------------------------------------
|
||||||
*/
|
*/
|
||||||
func platform_get_core_pos
|
func plat_my_core_pos
|
||||||
and x0, x0, #MPIDR_CPU_MASK
|
mrs x0, mpidr_el1
|
||||||
|
and x1, x0, #MPIDR_CPU_MASK
|
||||||
|
and x0, x0, #MPIDR_CLUSTER_MASK
|
||||||
|
add x0, x1, x0, LSR #6
|
||||||
ret
|
ret
|
||||||
endfunc platform_get_core_pos
|
endfunc plat_my_core_pos
|
||||||
|
|
||||||
|
/* -----------------------------------------------------
|
||||||
|
* unsigned long plat_get_my_entrypoint (void);
|
||||||
|
*
|
||||||
|
* Main job of this routine is to distinguish between
|
||||||
|
* a cold and warm boot. If the tegra_sec_entry_point for
|
||||||
|
* this CPU is present, then it's a warm boot.
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------
|
||||||
|
*/
|
||||||
|
func plat_get_my_entrypoint
|
||||||
|
adr x1, tegra_sec_entry_point
|
||||||
|
ldr x0, [x1]
|
||||||
|
ret
|
||||||
|
endfunc plat_get_my_entrypoint
|
||||||
|
|
||||||
/* -----------------------------------------------------
|
/* -----------------------------------------------------
|
||||||
* void plat_secondary_cold_boot_setup (void);
|
* void plat_secondary_cold_boot_setup (void);
|
||||||
|
@ -151,22 +170,6 @@ func plat_secondary_cold_boot_setup
|
||||||
ret
|
ret
|
||||||
endfunc plat_secondary_cold_boot_setup
|
endfunc plat_secondary_cold_boot_setup
|
||||||
|
|
||||||
/* -----------------------------------------------------
|
|
||||||
* void platform_get_entrypoint (unsigned int mpidr);
|
|
||||||
*
|
|
||||||
* Main job of this routine is to distinguish between
|
|
||||||
* a cold and warm boot. If the sec_entry_point for
|
|
||||||
* this CPU is present, then it's a warm boot.
|
|
||||||
*
|
|
||||||
* -----------------------------------------------------
|
|
||||||
*/
|
|
||||||
func platform_get_entrypoint
|
|
||||||
and x0, x0, #MPIDR_CPU_MASK
|
|
||||||
adr x1, sec_entry_point
|
|
||||||
ldr x0, [x1, x0, lsl #3]
|
|
||||||
ret
|
|
||||||
endfunc platform_get_entrypoint
|
|
||||||
|
|
||||||
/* --------------------------------------------------------
|
/* --------------------------------------------------------
|
||||||
* void platform_mem_init (void);
|
* void platform_mem_init (void);
|
||||||
*
|
*
|
||||||
|
@ -336,8 +339,7 @@ restore_oslock:
|
||||||
* Get secure world's entry point and jump to it
|
* Get secure world's entry point and jump to it
|
||||||
* --------------------------------------------------
|
* --------------------------------------------------
|
||||||
*/
|
*/
|
||||||
mrs x0, mpidr_el1
|
bl plat_get_my_entrypoint
|
||||||
bl platform_get_entrypoint
|
|
||||||
br x0
|
br x0
|
||||||
endfunc tegra_secure_entrypoint
|
endfunc tegra_secure_entrypoint
|
||||||
|
|
||||||
|
@ -345,13 +347,11 @@ endfunc tegra_secure_entrypoint
|
||||||
.align 3
|
.align 3
|
||||||
|
|
||||||
/* --------------------------------------------------
|
/* --------------------------------------------------
|
||||||
* Per-CPU Secure entry point - resume from suspend
|
* CPU Secure entry point - resume from suspend
|
||||||
* --------------------------------------------------
|
* --------------------------------------------------
|
||||||
*/
|
*/
|
||||||
sec_entry_point:
|
tegra_sec_entry_point:
|
||||||
.rept PLATFORM_CORE_COUNT
|
|
||||||
.quad 0
|
.quad 0
|
||||||
.endr
|
|
||||||
|
|
||||||
/* --------------------------------------------------
|
/* --------------------------------------------------
|
||||||
* NS world's cold boot entry point
|
* NS world's cold boot entry point
|
||||||
|
|
|
@ -98,9 +98,9 @@ static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Suspend the current CPU
|
* Powerdn the current CPU
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void tegra_fc_cpu_idle(uint32_t mpidr)
|
void tegra_fc_cpu_powerdn(uint32_t mpidr)
|
||||||
{
|
{
|
||||||
int cpu = mpidr & MPIDR_CPU_MASK;
|
int cpu = mpidr & MPIDR_CPU_MASK;
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ BL31_SOURCES += drivers/arm/gic/gic_v2.c \
|
||||||
drivers/delay_timer/delay_timer.c \
|
drivers/delay_timer/delay_timer.c \
|
||||||
drivers/ti/uart/16550_console.S \
|
drivers/ti/uart/16550_console.S \
|
||||||
plat/common/aarch64/platform_mp_stack.S \
|
plat/common/aarch64/platform_mp_stack.S \
|
||||||
|
plat/common/aarch64/plat_psci_common.c \
|
||||||
${COMMON_DIR}/aarch64/tegra_helpers.S \
|
${COMMON_DIR}/aarch64/tegra_helpers.S \
|
||||||
${COMMON_DIR}/drivers/memctrl/memctrl.c \
|
${COMMON_DIR}/drivers/memctrl/memctrl.c \
|
||||||
${COMMON_DIR}/drivers/pmc/pmc.c \
|
${COMMON_DIR}/drivers/pmc/pmc.c \
|
||||||
|
|
|
@ -44,35 +44,34 @@
|
||||||
#include <tegra_private.h>
|
#include <tegra_private.h>
|
||||||
|
|
||||||
extern uint64_t tegra_bl31_phys_base;
|
extern uint64_t tegra_bl31_phys_base;
|
||||||
extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT];
|
extern uint64_t tegra_sec_entry_point;
|
||||||
static int system_suspended;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following platform setup functions are weakly defined. They
|
* The following platform setup functions are weakly defined. They
|
||||||
* provide typical implementations that will be overridden by a SoC.
|
* provide typical implementations that will be overridden by a SoC.
|
||||||
*/
|
*/
|
||||||
#pragma weak tegra_soc_prepare_cpu_suspend
|
#pragma weak tegra_soc_pwr_domain_suspend
|
||||||
#pragma weak tegra_soc_prepare_cpu_on
|
#pragma weak tegra_soc_pwr_domain_on
|
||||||
#pragma weak tegra_soc_prepare_cpu_off
|
#pragma weak tegra_soc_pwr_domain_off
|
||||||
#pragma weak tegra_soc_prepare_cpu_on_finish
|
#pragma weak tegra_soc_pwr_domain_on_finish
|
||||||
#pragma weak tegra_soc_prepare_system_reset
|
#pragma weak tegra_soc_prepare_system_reset
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
|
int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
return PSCI_E_NOT_SUPPORTED;
|
return PSCI_E_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_on(unsigned long mpidr)
|
int tegra_soc_pwr_domain_on(u_register_t mpidr)
|
||||||
{
|
{
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_off(unsigned long mpidr)
|
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
|
int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -83,33 +82,25 @@ int tegra_soc_prepare_system_reset(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Track system suspend entry.
|
* This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
|
||||||
******************************************************************************/
|
* call to get the `power_state` parameter. This allows the platform to encode
|
||||||
void tegra_pm_system_suspend_entry(void)
|
* the appropriate State-ID field within the `power_state` parameter which can
|
||||||
|
* be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
|
||||||
|
******************************************************************************/
|
||||||
|
void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state)
|
||||||
{
|
{
|
||||||
system_suspended = 1;
|
/* lower affinities use PLAT_MAX_OFF_STATE */
|
||||||
}
|
for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
|
||||||
|
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
|
||||||
|
|
||||||
/*******************************************************************************
|
/* max affinity uses system suspend state id */
|
||||||
* Track system suspend exit.
|
req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN;
|
||||||
******************************************************************************/
|
|
||||||
void tegra_pm_system_suspend_exit(void)
|
|
||||||
{
|
|
||||||
system_suspended = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Get the system suspend state.
|
|
||||||
******************************************************************************/
|
|
||||||
int tegra_system_suspended(void)
|
|
||||||
{
|
|
||||||
return system_suspended;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Handler called when an affinity instance is about to enter standby.
|
* Handler called when an affinity instance is about to enter standby.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void tegra_affinst_standby(unsigned int power_state)
|
void tegra_cpu_standby(plat_local_state_t cpu_state)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Enter standby state
|
* Enter standby state
|
||||||
|
@ -119,132 +110,45 @@ void tegra_affinst_standby(unsigned int power_state)
|
||||||
wfi();
|
wfi();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
|
|
||||||
* call to get the `power_state` parameter. This allows the platform to encode
|
|
||||||
* the appropriate State-ID field within the `power_state` parameter which can
|
|
||||||
* be utilized in `affinst_suspend()` to suspend to system affinity level.
|
|
||||||
******************************************************************************/
|
|
||||||
unsigned int tegra_get_sys_suspend_power_state(void)
|
|
||||||
{
|
|
||||||
unsigned int power_state;
|
|
||||||
|
|
||||||
power_state = psci_make_powerstate(PLAT_SYS_SUSPEND_STATE_ID,
|
|
||||||
PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL2);
|
|
||||||
|
|
||||||
return power_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Handler called to check the validity of the power state parameter.
|
|
||||||
******************************************************************************/
|
|
||||||
int32_t tegra_validate_power_state(unsigned int power_state)
|
|
||||||
{
|
|
||||||
return tegra_soc_validate_power_state(power_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Handler called when an affinity instance is about to be turned on. The
|
* Handler called when an affinity instance is about to be turned on. The
|
||||||
* level and mpidr determine the affinity instance.
|
* level and mpidr determine the affinity instance.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int tegra_affinst_on(unsigned long mpidr,
|
int tegra_pwr_domain_on(u_register_t mpidr)
|
||||||
unsigned long sec_entrypoint,
|
|
||||||
unsigned int afflvl,
|
|
||||||
unsigned int state)
|
|
||||||
{
|
{
|
||||||
int cpu = mpidr & MPIDR_CPU_MASK;
|
return tegra_soc_pwr_domain_on(mpidr);
|
||||||
|
|
||||||
/*
|
|
||||||
* Support individual CPU power on only.
|
|
||||||
*/
|
|
||||||
if (afflvl > MPIDR_AFFLVL0)
|
|
||||||
return PSCI_E_SUCCESS;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Flush entrypoint variable to PoC since it will be
|
|
||||||
* accessed after a reset with the caches turned off.
|
|
||||||
*/
|
|
||||||
sec_entry_point[cpu] = sec_entrypoint;
|
|
||||||
flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
|
|
||||||
|
|
||||||
return tegra_soc_prepare_cpu_on(mpidr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Handler called when an affinity instance is about to be turned off. The
|
* Handler called when a power domain is about to be turned off. The
|
||||||
* level determines the affinity instance. The 'state' arg. allows the
|
* target_state encodes the power state that each level should transition to.
|
||||||
* platform to decide whether the cluster is being turned off and take apt
|
|
||||||
* actions.
|
|
||||||
*
|
|
||||||
* CAUTION: This function is called with coherent stacks so that caches can be
|
|
||||||
* turned off, flushed and coherency disabled. There is no guarantee that caches
|
|
||||||
* will remain turned on across calls to this function as each affinity level is
|
|
||||||
* dealt with. So do not write & read global variables across calls. It will be
|
|
||||||
* wise to do flush a write to the global to prevent unpredictable results.
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void tegra_affinst_off(unsigned int afflvl, unsigned int state)
|
void tegra_pwr_domain_off(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
/*
|
tegra_soc_pwr_domain_off(target_state);
|
||||||
* Support individual CPU power off only.
|
|
||||||
*/
|
|
||||||
if (afflvl > MPIDR_AFFLVL0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
tegra_soc_prepare_cpu_off(read_mpidr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Handler called when an affinity instance is about to be suspended. The
|
* Handler called when called when a power domain is about to be suspended. The
|
||||||
* level and mpidr determine the affinity instance. The 'state' arg. allows the
|
* target_state encodes the power state that each level should transition to.
|
||||||
* platform to decide whether the cluster is being turned off and take apt
|
|
||||||
* actions.
|
|
||||||
*
|
|
||||||
* CAUTION: This function is called with coherent stacks so that caches can be
|
|
||||||
* turned off, flushed and coherency disabled. There is no guarantee that caches
|
|
||||||
* will remain turned on across calls to this function as each affinity level is
|
|
||||||
* dealt with. So do not write & read global variables across calls. It will be
|
|
||||||
* wise to flush a write to the global variable, to prevent unpredictable
|
|
||||||
* results.
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void tegra_affinst_suspend(unsigned long sec_entrypoint,
|
void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
|
||||||
unsigned int afflvl,
|
|
||||||
unsigned int state)
|
|
||||||
{
|
{
|
||||||
int id = psci_get_suspend_stateid();
|
tegra_soc_pwr_domain_suspend(target_state);
|
||||||
int cpu = read_mpidr() & MPIDR_CPU_MASK;
|
|
||||||
|
|
||||||
if (afflvl > PLATFORM_MAX_AFFLVL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Flush entrypoint variable to PoC since it will be
|
|
||||||
* accessed after a reset with the caches turned off.
|
|
||||||
*/
|
|
||||||
sec_entry_point[cpu] = sec_entrypoint;
|
|
||||||
flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
|
|
||||||
|
|
||||||
tegra_soc_prepare_cpu_suspend(id, afflvl);
|
|
||||||
|
|
||||||
/* disable GICC */
|
/* disable GICC */
|
||||||
tegra_gic_cpuif_deactivate();
|
tegra_gic_cpuif_deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Handler called when an affinity instance has just been powered on after
|
* Handler called when a power domain has just been powered on after
|
||||||
* being turned off earlier. The level determines the affinity instance.
|
* being turned off earlier. The target_state encodes the low power state that
|
||||||
* The 'state' arg. allows the platform to decide whether the cluster was
|
* each level has woken up from.
|
||||||
* turned off prior to wakeup and do what's necessary to set it up.
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
|
void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
plat_params_from_bl2_t *plat_params;
|
plat_params_from_bl2_t *plat_params;
|
||||||
|
|
||||||
/*
|
|
||||||
* Support individual CPU power on only.
|
|
||||||
*/
|
|
||||||
if (afflvl > MPIDR_AFFLVL0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the GIC cpu and distributor interfaces
|
* Initialize the GIC cpu and distributor interfaces
|
||||||
*/
|
*/
|
||||||
|
@ -253,7 +157,8 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
|
||||||
/*
|
/*
|
||||||
* Check if we are exiting from deep sleep.
|
* Check if we are exiting from deep sleep.
|
||||||
*/
|
*/
|
||||||
if (tegra_system_suspended()) {
|
if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
|
||||||
|
PSTATE_ID_SOC_POWERDN) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock scratch registers which hold the CPU vectors.
|
* Lock scratch registers which hold the CPU vectors.
|
||||||
|
@ -276,18 +181,17 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
|
||||||
/*
|
/*
|
||||||
* Reset hardware settings.
|
* Reset hardware settings.
|
||||||
*/
|
*/
|
||||||
tegra_soc_prepare_cpu_on_finish(read_mpidr());
|
tegra_soc_pwr_domain_on_finish(target_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Handler called when an affinity instance has just been powered on after
|
* Handler called when a power domain has just been powered on after
|
||||||
* having been suspended earlier. The level and mpidr determine the affinity
|
* having been suspended earlier. The target_state encodes the low power state
|
||||||
* instance.
|
* that each level has woken up from.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state)
|
void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
if (afflvl == MPIDR_AFFLVL0)
|
tegra_pwr_domain_on_finish(target_state);
|
||||||
tegra_affinst_on_finish(afflvl, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -313,36 +217,78 @@ __dead2 void tegra_system_reset(void)
|
||||||
tegra_pmc_system_reset();
|
tegra_pmc_system_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Handler called to check the validity of the power state parameter.
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t tegra_validate_power_state(unsigned int power_state,
|
||||||
|
psci_power_state_t *req_state)
|
||||||
|
{
|
||||||
|
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
|
||||||
|
|
||||||
|
assert(req_state);
|
||||||
|
|
||||||
|
if (pwr_lvl > PLAT_MAX_PWR_LVL)
|
||||||
|
return PSCI_E_INVALID_PARAMS;
|
||||||
|
|
||||||
|
return tegra_soc_validate_power_state(power_state, req_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Platform handler called to check the validity of the non secure entrypoint.
|
||||||
|
******************************************************************************/
|
||||||
|
int tegra_validate_ns_entrypoint(uintptr_t entrypoint)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Check if the non secure entrypoint lies within the non
|
||||||
|
* secure DRAM.
|
||||||
|
*/
|
||||||
|
if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END))
|
||||||
|
return PSCI_E_SUCCESS;
|
||||||
|
|
||||||
|
return PSCI_E_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Export the platform handlers to enable psci to invoke them
|
* Export the platform handlers to enable psci to invoke them
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static const plat_pm_ops_t tegra_plat_pm_ops = {
|
static const plat_psci_ops_t tegra_plat_psci_ops = {
|
||||||
.affinst_standby = tegra_affinst_standby,
|
.cpu_standby = tegra_cpu_standby,
|
||||||
.affinst_on = tegra_affinst_on,
|
.pwr_domain_on = tegra_pwr_domain_on,
|
||||||
.affinst_off = tegra_affinst_off,
|
.pwr_domain_off = tegra_pwr_domain_off,
|
||||||
.affinst_suspend = tegra_affinst_suspend,
|
.pwr_domain_suspend = tegra_pwr_domain_suspend,
|
||||||
.affinst_on_finish = tegra_affinst_on_finish,
|
.pwr_domain_on_finish = tegra_pwr_domain_on_finish,
|
||||||
.affinst_suspend_finish = tegra_affinst_suspend_finish,
|
.pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish,
|
||||||
.system_off = tegra_system_off,
|
.system_off = tegra_system_off,
|
||||||
.system_reset = tegra_system_reset,
|
.system_reset = tegra_system_reset,
|
||||||
.validate_power_state = tegra_validate_power_state,
|
.validate_power_state = tegra_validate_power_state,
|
||||||
.get_sys_suspend_power_state = tegra_get_sys_suspend_power_state
|
.validate_ns_entrypoint = tegra_validate_ns_entrypoint,
|
||||||
|
.get_sys_suspend_power_state = tegra_get_sys_suspend_power_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Export the platform specific power ops & initialize the fvp power controller
|
* Export the platform specific power ops and initialize Power Controller
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int platform_setup_pm(const plat_pm_ops_t **plat_ops)
|
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
|
||||||
|
const plat_psci_ops_t **psci_ops)
|
||||||
{
|
{
|
||||||
|
psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush entrypoint variable to PoC since it will be
|
||||||
|
* accessed after a reset with the caches turned off.
|
||||||
|
*/
|
||||||
|
tegra_sec_entry_point = sec_entrypoint;
|
||||||
|
flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset hardware settings.
|
* Reset hardware settings.
|
||||||
*/
|
*/
|
||||||
tegra_soc_prepare_cpu_on_finish(read_mpidr());
|
tegra_soc_pwr_domain_on_finish(&target_state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize PM ops struct
|
* Initialize PSCI ops struct
|
||||||
*/
|
*/
|
||||||
*plat_ops = &tegra_plat_pm_ops;
|
*psci_ops = &tegra_plat_psci_ops;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,45 +28,47 @@
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <arch_helpers.h>
|
#include <arch.h>
|
||||||
#include <platform_def.h>
|
#include <platform_def.h>
|
||||||
#include <psci.h>
|
#include <psci.h>
|
||||||
|
|
||||||
|
extern const unsigned char tegra_power_domain_tree_desc[];
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* This function implements a part of the critical interface between the psci
|
* This function returns the Tegra default topology tree information.
|
||||||
* generic layer and the platform to allow the former to detect the platform
|
|
||||||
* topology. psci queries the platform to determine how many affinity instances
|
|
||||||
* are present at a particular level for a given mpidr.
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
unsigned int plat_get_aff_count(unsigned int aff_lvl,
|
const unsigned char *plat_get_power_domain_tree_desc(void)
|
||||||
unsigned long mpidr)
|
|
||||||
{
|
{
|
||||||
switch (aff_lvl) {
|
return tegra_power_domain_tree_desc;
|
||||||
case MPIDR_AFFLVL2:
|
|
||||||
/* Last supported affinity level */
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case MPIDR_AFFLVL1:
|
|
||||||
/* Return # of clusters */
|
|
||||||
return PLATFORM_CLUSTER_COUNT;
|
|
||||||
|
|
||||||
case MPIDR_AFFLVL0:
|
|
||||||
/* # of cpus per cluster */
|
|
||||||
return PLATFORM_MAX_CPUS_PER_CLUSTER;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return PSCI_AFF_ABSENT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* This function implements a part of the critical interface between the psci
|
* This function implements a part of the critical interface between the psci
|
||||||
* generic layer and the platform to allow the former to detect the state of a
|
* generic layer and the platform that allows the former to query the platform
|
||||||
* affinity instance in the platform topology. psci queries the platform to
|
* to convert an MPIDR to a unique linear index. An error code (-1) is returned
|
||||||
* determine whether an affinity instance is present or absent.
|
* in case the MPIDR is invalid.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
unsigned int plat_get_aff_state(unsigned int aff_lvl,
|
int plat_core_pos_by_mpidr(u_register_t mpidr)
|
||||||
unsigned long mpidr)
|
|
||||||
{
|
{
|
||||||
return (aff_lvl <= MPIDR_AFFLVL2) ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT;
|
unsigned int cluster_id, cpu_id;
|
||||||
|
|
||||||
|
mpidr &= MPIDR_AFFINITY_MASK;
|
||||||
|
|
||||||
|
if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
|
||||||
|
cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
|
||||||
|
|
||||||
|
if (cluster_id >= PLATFORM_CLUSTER_COUNT)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate cpu_id by checking whether it represents a CPU in
|
||||||
|
* one of the two clusters present on the platform.
|
||||||
|
*/
|
||||||
|
if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return (cpu_id + (cluster_id * 4));
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,8 @@ static inline void tegra_fc_write_32(uint32_t off, uint32_t val)
|
||||||
mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val);
|
mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tegra_fc_cpu_idle(uint32_t mpidr);
|
|
||||||
void tegra_fc_cluster_idle(uint32_t midr);
|
void tegra_fc_cluster_idle(uint32_t midr);
|
||||||
|
void tegra_fc_cpu_powerdn(uint32_t mpidr);
|
||||||
void tegra_fc_cluster_powerdn(uint32_t midr);
|
void tegra_fc_cluster_powerdn(uint32_t midr);
|
||||||
void tegra_fc_soc_powerdn(uint32_t midr);
|
void tegra_fc_soc_powerdn(uint32_t midr);
|
||||||
void tegra_fc_cpu_on(int cpu);
|
void tegra_fc_cpu_on(int cpu);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include <arch.h>
|
#include <arch.h>
|
||||||
#include <common_def.h>
|
#include <common_def.h>
|
||||||
|
#include <tegra_def.h>
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Generic platform constants
|
* Generic platform constants
|
||||||
|
@ -47,12 +48,18 @@
|
||||||
|
|
||||||
#define TEGRA_PRIMARY_CPU 0x0
|
#define TEGRA_PRIMARY_CPU 0x0
|
||||||
|
|
||||||
#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2
|
#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
|
||||||
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
|
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
|
||||||
PLATFORM_MAX_CPUS_PER_CLUSTER)
|
PLATFORM_MAX_CPUS_PER_CLUSTER)
|
||||||
#define PLATFORM_NUM_AFFS (PLATFORM_CORE_COUNT + \
|
#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
|
||||||
PLATFORM_CLUSTER_COUNT + 1)
|
PLATFORM_CLUSTER_COUNT + 1)
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Platform power states
|
||||||
|
******************************************************************************/
|
||||||
|
#define PLAT_MAX_RET_STATE 1
|
||||||
|
#define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1)
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Platform console related constants
|
* Platform console related constants
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* This value is used by the PSCI implementation during the `SYSTEM_SUSPEND`
|
* This value is used by the PSCI implementation during the `SYSTEM_SUSPEND`
|
||||||
* call as the `state-id` field in the 'power state' parameter.
|
* call as the `state-id` field in the 'power state' parameter.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#define PLAT_SYS_SUSPEND_STATE_ID 0xD
|
#define PSTATE_ID_SOC_POWERDN 0xD
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* GIC memory map
|
* GIC memory map
|
||||||
|
|
|
@ -31,8 +31,9 @@
|
||||||
#ifndef __TEGRA_PRIVATE_H__
|
#ifndef __TEGRA_PRIVATE_H__
|
||||||
#define __TEGRA_PRIVATE_H__
|
#define __TEGRA_PRIVATE_H__
|
||||||
|
|
||||||
#include <xlat_tables.h>
|
#include <arch.h>
|
||||||
#include <platform_def.h>
|
#include <platform_def.h>
|
||||||
|
#include <xlat_tables.h>
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Tegra DRAM memory base address
|
* Tegra DRAM memory base address
|
||||||
|
@ -45,7 +46,8 @@ typedef struct plat_params_from_bl2 {
|
||||||
} plat_params_from_bl2_t;
|
} plat_params_from_bl2_t;
|
||||||
|
|
||||||
/* Declarations for plat_psci_handlers.c */
|
/* Declarations for plat_psci_handlers.c */
|
||||||
int32_t tegra_soc_validate_power_state(unsigned int power_state);
|
int32_t tegra_soc_validate_power_state(unsigned int power_state,
|
||||||
|
psci_power_state_t *req_state);
|
||||||
|
|
||||||
/* Declarations for plat_setup.c */
|
/* Declarations for plat_setup.c */
|
||||||
const mmap_region_t *plat_get_mmio_map(void);
|
const mmap_region_t *plat_get_mmio_map(void);
|
||||||
|
|
|
@ -28,7 +28,10 @@
|
||||||
# POSSIBILITY OF SUCH DAMAGE.
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
#
|
#
|
||||||
|
|
||||||
SOC_DIR := plat/nvidia/tegra/soc/${TARGET_SOC}
|
SOC_DIR := plat/nvidia/tegra/soc/${TARGET_SOC}
|
||||||
|
|
||||||
|
# Disable the PSCI platform compatibility layer
|
||||||
|
ENABLE_PLAT_COMPAT := 0
|
||||||
|
|
||||||
include plat/nvidia/tegra/common/tegra_common.mk
|
include plat/nvidia/tegra/common/tegra_common.mk
|
||||||
include ${SOC_DIR}/platform_${TARGET_SOC}.mk
|
include ${SOC_DIR}/platform_${TARGET_SOC}.mk
|
||||||
|
|
|
@ -56,28 +56,55 @@
|
||||||
|
|
||||||
static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
|
static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
|
||||||
|
|
||||||
int32_t tegra_soc_validate_power_state(unsigned int power_state)
|
int32_t tegra_soc_validate_power_state(unsigned int power_state,
|
||||||
|
psci_power_state_t *req_state)
|
||||||
{
|
{
|
||||||
|
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
|
||||||
|
int state_id = psci_get_pstate_id(power_state);
|
||||||
|
int cpu = read_mpidr() & MPIDR_CPU_MASK;
|
||||||
|
|
||||||
|
if (pwr_lvl > PLAT_MAX_PWR_LVL)
|
||||||
|
return PSCI_E_INVALID_PARAMS;
|
||||||
|
|
||||||
/* Sanity check the requested afflvl */
|
/* Sanity check the requested afflvl */
|
||||||
if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
|
if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
|
||||||
/*
|
/*
|
||||||
* It's possible to enter standby only on affinity level 0 i.e.
|
* It's possible to enter standby only on affinity level 0 i.e.
|
||||||
* a cpu on Tegra. Ignore any other affinity level.
|
* a cpu on Tegra. Ignore any other affinity level.
|
||||||
*/
|
*/
|
||||||
if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0)
|
if (pwr_lvl != MPIDR_AFFLVL0)
|
||||||
return PSCI_E_INVALID_PARAMS;
|
return PSCI_E_INVALID_PARAMS;
|
||||||
|
|
||||||
|
/* power domain in standby state */
|
||||||
|
req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
|
||||||
|
|
||||||
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sanity check the requested state id */
|
/*
|
||||||
if (psci_get_pstate_id(power_state) != PLAT_SYS_SUSPEND_STATE_ID) {
|
* Sanity check the requested state id, power level and CPU number.
|
||||||
ERROR("unsupported state id\n");
|
* Currently T132 only supports SYSTEM_SUSPEND on last standing CPU
|
||||||
return PSCI_E_NOT_SUPPORTED;
|
* i.e. CPU 0
|
||||||
|
*/
|
||||||
|
if ((pwr_lvl != PLAT_MAX_PWR_LVL) ||
|
||||||
|
(state_id != PSTATE_ID_SOC_POWERDN) ||
|
||||||
|
(cpu != 0)) {
|
||||||
|
ERROR("unsupported state id @ power level\n");
|
||||||
|
return PSCI_E_INVALID_PARAMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set lower power states to PLAT_MAX_OFF_STATE */
|
||||||
|
for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
|
||||||
|
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
|
||||||
|
|
||||||
|
/* Set the SYSTEM_SUSPEND state-id */
|
||||||
|
req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
|
||||||
|
PSTATE_ID_SOC_POWERDN;
|
||||||
|
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_on(unsigned long mpidr)
|
int tegra_soc_pwr_domain_on(u_register_t mpidr)
|
||||||
{
|
{
|
||||||
int cpu = mpidr & MPIDR_CPU_MASK;
|
int cpu = mpidr & MPIDR_CPU_MASK;
|
||||||
uint32_t mask = CPU_CORE_RESET_MASK << cpu;
|
uint32_t mask = CPU_CORE_RESET_MASK << cpu;
|
||||||
|
@ -101,29 +128,29 @@ int tegra_soc_prepare_cpu_on(unsigned long mpidr)
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_off(unsigned long mpidr)
|
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
tegra_fc_cpu_off(mpidr & MPIDR_CPU_MASK);
|
tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
|
int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
/* Nothing to be done for lower affinity levels */
|
#if DEBUG
|
||||||
if (afflvl < MPIDR_AFFLVL2)
|
int cpu = read_mpidr() & MPIDR_CPU_MASK;
|
||||||
return PSCI_E_SUCCESS;
|
|
||||||
|
|
||||||
/* Enter system suspend state */
|
/* SYSTEM_SUSPEND only on CPU0 */
|
||||||
tegra_pm_system_suspend_entry();
|
assert(cpu == 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Allow restarting CPU #1 using PMC on suspend exit */
|
/* Allow restarting CPU #1 using PMC on suspend exit */
|
||||||
cpu_powergate_mask[1] = 0;
|
cpu_powergate_mask[1] = 0;
|
||||||
|
|
||||||
/* Program FC to enter suspend state */
|
/* Program FC to enter suspend state */
|
||||||
tegra_fc_cpu_idle(read_mpidr());
|
tegra_fc_cpu_powerdn(read_mpidr());
|
||||||
|
|
||||||
/* Suspend DCO operations */
|
/* Suspend DCO operations */
|
||||||
write_actlr_el1(id);
|
write_actlr_el1(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]);
|
||||||
|
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,21 @@
|
||||||
#include <xlat_tables.h>
|
#include <xlat_tables.h>
|
||||||
#include <tegra_def.h>
|
#include <tegra_def.h>
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* The Tegra power domain tree has a single system level power domain i.e. a
|
||||||
|
* single root node. The first entry in the power domain descriptor specifies
|
||||||
|
* the number of power domains at the highest power level.
|
||||||
|
*******************************************************************************
|
||||||
|
*/
|
||||||
|
const unsigned char tegra_power_domain_tree_desc[] = {
|
||||||
|
/* No of root nodes */
|
||||||
|
1,
|
||||||
|
/* No of clusters */
|
||||||
|
PLATFORM_CLUSTER_COUNT,
|
||||||
|
/* No of CPU cores */
|
||||||
|
PLATFORM_CORE_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
/* sets of MMIO ranges setup */
|
/* sets of MMIO ranges setup */
|
||||||
#define MMIO_RANGE_0_ADDR 0x50000000
|
#define MMIO_RANGE_0_ADDR 0x50000000
|
||||||
#define MMIO_RANGE_1_ADDR 0x60000000
|
#define MMIO_RANGE_1_ADDR 0x60000000
|
||||||
|
|
|
@ -55,83 +55,139 @@
|
||||||
|
|
||||||
static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
|
static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
|
||||||
|
|
||||||
int32_t tegra_soc_validate_power_state(unsigned int power_state)
|
int32_t tegra_soc_validate_power_state(unsigned int power_state,
|
||||||
|
psci_power_state_t *req_state)
|
||||||
{
|
{
|
||||||
|
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
|
||||||
|
int state_id = psci_get_pstate_id(power_state);
|
||||||
|
|
||||||
|
if (pwr_lvl > PLAT_MAX_PWR_LVL) {
|
||||||
|
ERROR("%s: unsupported power_state (0x%x)\n", __func__,
|
||||||
|
power_state);
|
||||||
|
return PSCI_E_INVALID_PARAMS;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sanity check the requested afflvl */
|
/* Sanity check the requested afflvl */
|
||||||
if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
|
if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
|
||||||
/*
|
/*
|
||||||
* It's possible to enter standby only on affinity level 0 i.e.
|
* It's possible to enter standby only on affinity level 0 i.e.
|
||||||
* a cpu on Tegra. Ignore any other affinity level.
|
* a cpu on Tegra. Ignore any other affinity level.
|
||||||
*/
|
*/
|
||||||
if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0)
|
if (pwr_lvl != MPIDR_AFFLVL0)
|
||||||
return PSCI_E_INVALID_PARAMS;
|
return PSCI_E_INVALID_PARAMS;
|
||||||
|
|
||||||
|
/* power domain in standby state */
|
||||||
|
req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
|
||||||
|
|
||||||
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sanity check the requested state id */
|
/* Sanity check the requested state id */
|
||||||
switch (psci_get_pstate_id(power_state)) {
|
switch (state_id) {
|
||||||
case PSTATE_ID_CORE_POWERDN:
|
case PSTATE_ID_CORE_POWERDN:
|
||||||
|
/*
|
||||||
|
* Core powerdown request only for afflvl 0
|
||||||
|
*/
|
||||||
|
if (pwr_lvl != MPIDR_AFFLVL0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case PSTATE_ID_CLUSTER_IDLE:
|
case PSTATE_ID_CLUSTER_IDLE:
|
||||||
case PSTATE_ID_CLUSTER_POWERDN:
|
case PSTATE_ID_CLUSTER_POWERDN:
|
||||||
|
/*
|
||||||
|
* Cluster powerdown/idle request only for afflvl 1
|
||||||
|
*/
|
||||||
|
if (pwr_lvl != MPIDR_AFFLVL1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
|
||||||
|
req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case PSTATE_ID_SOC_POWERDN:
|
case PSTATE_ID_SOC_POWERDN:
|
||||||
|
/*
|
||||||
|
* System powerdown request only for afflvl 2
|
||||||
|
*/
|
||||||
|
if (pwr_lvl != PLAT_MAX_PWR_LVL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
|
||||||
|
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
|
||||||
|
|
||||||
|
req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
|
||||||
|
PLAT_SYS_SUSPEND_STATE_ID;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR("unsupported state id\n");
|
ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
|
||||||
|
return PSCI_E_INVALID_PARAMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PSCI_E_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
|
||||||
|
return PSCI_E_INVALID_PARAMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
|
||||||
|
{
|
||||||
|
u_register_t mpidr = read_mpidr();
|
||||||
|
const plat_local_state_t *pwr_domain_state =
|
||||||
|
target_state->pwr_domain_state;
|
||||||
|
unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
|
||||||
|
unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
|
||||||
|
unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
|
||||||
|
|
||||||
|
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
|
||||||
|
|
||||||
|
assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
|
||||||
|
assert(stateid_afflvl1 == PLAT_MAX_OFF_STATE);
|
||||||
|
|
||||||
|
/* suspend the entire soc */
|
||||||
|
tegra_fc_soc_powerdn(mpidr);
|
||||||
|
|
||||||
|
} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
|
||||||
|
|
||||||
|
assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
|
||||||
|
|
||||||
|
/* Prepare for cluster idle */
|
||||||
|
tegra_fc_cluster_idle(mpidr);
|
||||||
|
|
||||||
|
} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) {
|
||||||
|
|
||||||
|
assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
|
||||||
|
|
||||||
|
/* Prepare for cluster powerdn */
|
||||||
|
tegra_fc_cluster_powerdn(mpidr);
|
||||||
|
|
||||||
|
} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
|
||||||
|
|
||||||
|
/* Prepare for cpu powerdn */
|
||||||
|
tegra_fc_cpu_powerdn(mpidr);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ERROR("%s: Unknown state id\n", __func__);
|
||||||
return PSCI_E_NOT_SUPPORTED;
|
return PSCI_E_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
|
int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
|
||||||
{
|
|
||||||
/* There's nothing to be done for affinity level 1 */
|
|
||||||
if (afflvl == MPIDR_AFFLVL1)
|
|
||||||
return PSCI_E_SUCCESS;
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
/* Prepare for cpu idle */
|
|
||||||
case PSTATE_ID_CORE_POWERDN:
|
|
||||||
tegra_fc_cpu_idle(read_mpidr());
|
|
||||||
return PSCI_E_SUCCESS;
|
|
||||||
|
|
||||||
/* Prepare for cluster idle */
|
|
||||||
case PSTATE_ID_CLUSTER_IDLE:
|
|
||||||
tegra_fc_cluster_idle(read_mpidr());
|
|
||||||
return PSCI_E_SUCCESS;
|
|
||||||
|
|
||||||
/* Prepare for cluster powerdn */
|
|
||||||
case PSTATE_ID_CLUSTER_POWERDN:
|
|
||||||
tegra_fc_cluster_powerdn(read_mpidr());
|
|
||||||
return PSCI_E_SUCCESS;
|
|
||||||
|
|
||||||
/* Prepare for system idle */
|
|
||||||
case PSTATE_ID_SOC_POWERDN:
|
|
||||||
|
|
||||||
/* Enter system suspend state */
|
|
||||||
tegra_pm_system_suspend_entry();
|
|
||||||
|
|
||||||
/* suspend the entire soc */
|
|
||||||
tegra_fc_soc_powerdn(read_mpidr());
|
|
||||||
|
|
||||||
return PSCI_E_SUCCESS;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR("Unknown state id (%d)\n", id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PSCI_E_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
|
|
||||||
{
|
{
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we are exiting from SOC_POWERDN.
|
* Check if we are exiting from SOC_POWERDN.
|
||||||
*/
|
*/
|
||||||
if (tegra_system_suspended()) {
|
if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
|
||||||
|
PLAT_SYS_SUSPEND_STATE_ID) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable WRAP to INCR burst type conversions for
|
* Enable WRAP to INCR burst type conversions for
|
||||||
|
@ -147,11 +203,6 @@ int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
|
||||||
* address and reset it.
|
* address and reset it.
|
||||||
*/
|
*/
|
||||||
tegra_fc_reset_bpmp();
|
tegra_fc_reset_bpmp();
|
||||||
|
|
||||||
/*
|
|
||||||
* System resume complete.
|
|
||||||
*/
|
|
||||||
tegra_pm_system_suspend_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -159,13 +210,12 @@ int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
|
||||||
* used for power management and boot purposes. Inform the BPMP that
|
* used for power management and boot purposes. Inform the BPMP that
|
||||||
* we have completed the cluster power up.
|
* we have completed the cluster power up.
|
||||||
*/
|
*/
|
||||||
if (psci_get_max_phys_off_afflvl() == MPIDR_AFFLVL1)
|
tegra_fc_lock_active_cluster();
|
||||||
tegra_fc_lock_active_cluster();
|
|
||||||
|
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_on(unsigned long mpidr)
|
int tegra_soc_pwr_domain_on(u_register_t mpidr)
|
||||||
{
|
{
|
||||||
int cpu = mpidr & MPIDR_CPU_MASK;
|
int cpu = mpidr & MPIDR_CPU_MASK;
|
||||||
uint32_t mask = CPU_CORE_RESET_MASK << cpu;
|
uint32_t mask = CPU_CORE_RESET_MASK << cpu;
|
||||||
|
@ -184,9 +234,9 @@ int tegra_soc_prepare_cpu_on(unsigned long mpidr)
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tegra_soc_prepare_cpu_off(unsigned long mpidr)
|
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
|
||||||
{
|
{
|
||||||
tegra_fc_cpu_off(mpidr & MPIDR_CPU_MASK);
|
tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
|
||||||
return PSCI_E_SUCCESS;
|
return PSCI_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,23 @@
|
||||||
#include <tegra_def.h>
|
#include <tegra_def.h>
|
||||||
#include <xlat_tables.h>
|
#include <xlat_tables.h>
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* The Tegra power domain tree has a single system level power domain i.e. a
|
||||||
|
* single root node. The first entry in the power domain descriptor specifies
|
||||||
|
* the number of power domains at the highest power level.
|
||||||
|
*******************************************************************************
|
||||||
|
*/
|
||||||
|
const unsigned char tegra_power_domain_tree_desc[] = {
|
||||||
|
/* No of root nodes */
|
||||||
|
1,
|
||||||
|
/* No of clusters */
|
||||||
|
PLATFORM_CLUSTER_COUNT,
|
||||||
|
/* No of CPU cores - cluster0 */
|
||||||
|
PLATFORM_MAX_CPUS_PER_CLUSTER,
|
||||||
|
/* No of CPU cores - cluster1 */
|
||||||
|
PLATFORM_MAX_CPUS_PER_CLUSTER
|
||||||
|
};
|
||||||
|
|
||||||
/* sets of MMIO ranges setup */
|
/* sets of MMIO ranges setup */
|
||||||
#define MMIO_RANGE_0_ADDR 0x50000000
|
#define MMIO_RANGE_0_ADDR 0x50000000
|
||||||
#define MMIO_RANGE_1_ADDR 0x60000000
|
#define MMIO_RANGE_1_ADDR 0x60000000
|
||||||
|
|
Loading…
Reference in New Issue