From 71cb26ea5b9908dfd04dc3048894e751ea8f4b99 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Fri, 7 Aug 2015 10:03:00 +0530 Subject: [PATCH] Tegra: remove support for legacy platform APIs This patch modifies the Tegra port to support the new platform APIs so that we can disable the compat layer. This includes modifications to the power management and platform topology code. Signed-off-by: Varun Wadekar --- .../tegra/common/aarch64/tegra_helpers.S | 68 ++--- plat/nvidia/tegra/common/tegra_common.mk | 1 + plat/nvidia/tegra/common/tegra_pm.c | 256 +++++++----------- plat/nvidia/tegra/common/tegra_topology.c | 60 ++-- plat/nvidia/tegra/include/platform_def.h | 11 +- plat/nvidia/tegra/include/t132/tegra_def.h | 2 +- plat/nvidia/tegra/include/tegra_private.h | 6 +- plat/nvidia/tegra/platform.mk | 5 +- .../tegra/soc/t132/plat_psci_handlers.c | 61 +++-- plat/nvidia/tegra/soc/t132/plat_setup.c | 15 + .../tegra/soc/t210/plat_psci_handlers.c | 140 +++++++--- plat/nvidia/tegra/soc/t210/plat_setup.c | 17 ++ 12 files changed, 356 insertions(+), 286 deletions(-) diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S index d9f287c9..a4caf5ef 100644 --- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S +++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S @@ -36,9 +36,9 @@ #include /* Global functions */ - .globl platform_is_primary_cpu - .globl platform_get_core_pos - .globl platform_get_entrypoint + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_get_my_entrypoint .globl plat_secondary_cold_boot_setup .globl platform_mem_init .globl plat_crash_console_init @@ -47,7 +47,7 @@ .globl plat_reset_handler /* Global variables */ - .globl sec_entry_point + .globl tegra_sec_entry_point .globl ns_image_entrypoint .globl tegra_bl31_phys_base @@ -115,28 +115,47 @@ .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 * ----------------------------------------------------- */ -func platform_is_primary_cpu +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #TEGRA_PRIMARY_CPU cset x0, eq 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); + * + * result: CorePos = CoreId + (ClusterId << 2) + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +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. * - * With this function: CorePos = CoreId * ----------------------------------------------------- */ -func platform_get_core_pos - and x0, x0, #MPIDR_CPU_MASK +func plat_get_my_entrypoint + adr x1, tegra_sec_entry_point + ldr x0, [x1] ret -endfunc platform_get_core_pos +endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); @@ -151,22 +170,6 @@ func plat_secondary_cold_boot_setup ret 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); * @@ -336,8 +339,7 @@ restore_oslock: * Get secure world's entry point and jump to it * -------------------------------------------------- */ - mrs x0, mpidr_el1 - bl platform_get_entrypoint + bl plat_get_my_entrypoint br x0 endfunc tegra_secure_entrypoint @@ -345,13 +347,11 @@ endfunc tegra_secure_entrypoint .align 3 /* -------------------------------------------------- - * Per-CPU Secure entry point - resume from suspend + * CPU Secure entry point - resume from suspend * -------------------------------------------------- */ -sec_entry_point: - .rept PLATFORM_CORE_COUNT +tegra_sec_entry_point: .quad 0 - .endr /* -------------------------------------------------- * NS world's cold boot entry point diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk index e1c0d84d..fcebde30 100644 --- a/plat/nvidia/tegra/common/tegra_common.mk +++ b/plat/nvidia/tegra/common/tegra_common.mk @@ -51,6 +51,7 @@ BL31_SOURCES += drivers/arm/gic/gic_v2.c \ drivers/delay_timer/delay_timer.c \ drivers/ti/uart/16550_console.S \ plat/common/aarch64/platform_mp_stack.S \ + plat/common/aarch64/plat_psci_common.c \ ${COMMON_DIR}/aarch64/tegra_helpers.S \ ${COMMON_DIR}/drivers/memctrl/memctrl.c \ ${COMMON_DIR}/drivers/pmc/pmc.c \ diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index c2c73f63..6fb3e9c6 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -44,35 +44,34 @@ #include extern uint64_t tegra_bl31_phys_base; -extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT]; -static int system_suspended; +extern uint64_t tegra_sec_entry_point; /* * The following platform setup functions are weakly defined. They * provide typical implementations that will be overridden by a SoC. */ -#pragma weak tegra_soc_prepare_cpu_suspend -#pragma weak tegra_soc_prepare_cpu_on -#pragma weak tegra_soc_prepare_cpu_off -#pragma weak tegra_soc_prepare_cpu_on_finish +#pragma weak tegra_soc_pwr_domain_suspend +#pragma weak tegra_soc_pwr_domain_on +#pragma weak tegra_soc_pwr_domain_off +#pragma weak tegra_soc_pwr_domain_on_finish #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; } -int tegra_soc_prepare_cpu_on(unsigned long mpidr) +int tegra_soc_pwr_domain_on(u_register_t mpidr) { 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; } -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; } @@ -83,33 +82,25 @@ int tegra_soc_prepare_system_reset(void) } /******************************************************************************* - * Track system suspend entry. - ******************************************************************************/ -void tegra_pm_system_suspend_entry(void) -{ - system_suspended = 1; -} - -/******************************************************************************* - * Track system suspend exit. - ******************************************************************************/ -void tegra_pm_system_suspend_exit(void) + * 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 `pwr_domain_suspend()` to suspend to system affinity level. +******************************************************************************/ +void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) { - system_suspended = 0; -} + /* 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; -/******************************************************************************* - * Get the system suspend state. - ******************************************************************************/ -int tegra_system_suspended(void) -{ - return system_suspended; + /* max affinity uses system suspend state id */ + req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; } /******************************************************************************* * 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 @@ -119,132 +110,45 @@ void tegra_affinst_standby(unsigned int power_state) 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 * level and mpidr determine the affinity instance. ******************************************************************************/ -int tegra_affinst_on(unsigned long mpidr, - unsigned long sec_entrypoint, - unsigned int afflvl, - unsigned int state) +int tegra_pwr_domain_on(u_register_t mpidr) { - int cpu = mpidr & MPIDR_CPU_MASK; - - /* - * 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); + return tegra_soc_pwr_domain_on(mpidr); } /******************************************************************************* - * Handler called when an affinity instance is about to be turned off. The - * level determines the affinity instance. The 'state' arg. allows the - * 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. + * Handler called when a power domain is about to be turned off. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_affinst_off(unsigned int afflvl, unsigned int state) +void tegra_pwr_domain_off(const psci_power_state_t *target_state) { - /* - * Support individual CPU power off only. - */ - if (afflvl > MPIDR_AFFLVL0) - return; - - tegra_soc_prepare_cpu_off(read_mpidr()); + tegra_soc_pwr_domain_off(target_state); } /******************************************************************************* - * Handler called when an affinity instance is about to be suspended. The - * level and mpidr determine the affinity instance. The 'state' arg. allows the - * 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. + * Handler called when called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_affinst_suspend(unsigned long sec_entrypoint, - unsigned int afflvl, - unsigned int state) +void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) { - int id = psci_get_suspend_stateid(); - 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); + tegra_soc_pwr_domain_suspend(target_state); /* disable GICC */ tegra_gic_cpuif_deactivate(); } /******************************************************************************* - * Handler called when an affinity instance has just been powered on after - * being turned off earlier. The level determines the affinity instance. - * The 'state' arg. allows the platform to decide whether the cluster was - * turned off prior to wakeup and do what's necessary to set it up. + * Handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. ******************************************************************************/ -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; - /* - * Support individual CPU power on only. - */ - if (afflvl > MPIDR_AFFLVL0) - return; - /* * 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. */ - 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. @@ -276,18 +181,17 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) /* * 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 - * having been suspended earlier. The level and mpidr determine the affinity - * instance. + * Handler called when a power domain has just been powered on after + * having been suspended earlier. The target_state encodes the low power state + * 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_affinst_on_finish(afflvl, state); + tegra_pwr_domain_on_finish(target_state); } /******************************************************************************* @@ -313,36 +217,78 @@ __dead2 void tegra_system_reset(void) 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 ******************************************************************************/ -static const plat_pm_ops_t tegra_plat_pm_ops = { - .affinst_standby = tegra_affinst_standby, - .affinst_on = tegra_affinst_on, - .affinst_off = tegra_affinst_off, - .affinst_suspend = tegra_affinst_suspend, - .affinst_on_finish = tegra_affinst_on_finish, - .affinst_suspend_finish = tegra_affinst_suspend_finish, - .system_off = tegra_system_off, - .system_reset = tegra_system_reset, - .validate_power_state = tegra_validate_power_state, - .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state +static const plat_psci_ops_t tegra_plat_psci_ops = { + .cpu_standby = tegra_cpu_standby, + .pwr_domain_on = tegra_pwr_domain_on, + .pwr_domain_off = tegra_pwr_domain_off, + .pwr_domain_suspend = tegra_pwr_domain_suspend, + .pwr_domain_on_finish = tegra_pwr_domain_on_finish, + .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, + .system_off = tegra_system_off, + .system_reset = tegra_system_reset, + .validate_power_state = tegra_validate_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. */ - 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; } diff --git a/plat/nvidia/tegra/common/tegra_topology.c b/plat/nvidia/tegra/common/tegra_topology.c index 220e697b..0431d98a 100644 --- a/plat/nvidia/tegra/common/tegra_topology.c +++ b/plat/nvidia/tegra/common/tegra_topology.c @@ -28,45 +28,47 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include #include +extern const unsigned char tegra_power_domain_tree_desc[]; + /******************************************************************************* - * This function implements a part of the critical interface between the psci - * 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. + * This function returns the Tegra default topology tree information. ******************************************************************************/ -unsigned int plat_get_aff_count(unsigned int aff_lvl, - unsigned long mpidr) +const unsigned char *plat_get_power_domain_tree_desc(void) { - switch (aff_lvl) { - 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; - } + return tegra_power_domain_tree_desc; } /******************************************************************************* * 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 - * affinity instance in the platform topology. psci queries the platform to - * determine whether an affinity instance is present or absent. + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. ******************************************************************************/ -unsigned int plat_get_aff_state(unsigned int aff_lvl, - unsigned long mpidr) +int plat_core_pos_by_mpidr(u_register_t 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)); } diff --git a/plat/nvidia/tegra/include/platform_def.h b/plat/nvidia/tegra/include/platform_def.h index c59e2beb..2a7935fd 100644 --- a/plat/nvidia/tegra/include/platform_def.h +++ b/plat/nvidia/tegra/include/platform_def.h @@ -33,6 +33,7 @@ #include #include +#include /******************************************************************************* * Generic platform constants @@ -47,12 +48,18 @@ #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 * \ 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 power states + ******************************************************************************/ +#define PLAT_MAX_RET_STATE 1 +#define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1) + /******************************************************************************* * Platform console related constants ******************************************************************************/ diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h index 2fb9ed70..683c9038 100644 --- a/plat/nvidia/tegra/include/t132/tegra_def.h +++ b/plat/nvidia/tegra/include/t132/tegra_def.h @@ -37,7 +37,7 @@ * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND` * 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 diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index 952e2d8b..aca9db72 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -31,8 +31,9 @@ #ifndef __TEGRA_PRIVATE_H__ #define __TEGRA_PRIVATE_H__ -#include +#include #include +#include /******************************************************************************* * Tegra DRAM memory base address @@ -45,7 +46,8 @@ typedef struct plat_params_from_bl2 { } plat_params_from_bl2_t; /* 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 */ const mmap_region_t *plat_get_mmio_map(void); diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk index b9093354..cec7caff 100644 --- a/plat/nvidia/tegra/platform.mk +++ b/plat/nvidia/tegra/platform.mk @@ -28,7 +28,10 @@ # 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 ${SOC_DIR}/platform_${TARGET_SOC}.mk diff --git a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c index 46e59409..48a2fbaa 100644 --- a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c @@ -56,28 +56,55 @@ 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 */ if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on affinity level 0 i.e. * 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; + + /* 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) { - ERROR("unsupported state id\n"); - return PSCI_E_NOT_SUPPORTED; + /* + * Sanity check the requested state id, power level and CPU number. + * Currently T132 only supports SYSTEM_SUSPEND on last standing CPU + * 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; } -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; 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; } -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; } -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 (afflvl < MPIDR_AFFLVL2) - return PSCI_E_SUCCESS; +#if DEBUG + int cpu = read_mpidr() & MPIDR_CPU_MASK; - /* Enter system suspend state */ - tegra_pm_system_suspend_entry(); + /* SYSTEM_SUSPEND only on CPU0 */ + assert(cpu == 0); +#endif /* Allow restarting CPU #1 using PMC on suspend exit */ cpu_powergate_mask[1] = 0; /* Program FC to enter suspend state */ - tegra_fc_cpu_idle(read_mpidr()); + tegra_fc_cpu_powerdn(read_mpidr()); /* Suspend DCO operations */ - write_actlr_el1(id); + write_actlr_el1(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]); return PSCI_E_SUCCESS; } diff --git a/plat/nvidia/tegra/soc/t132/plat_setup.c b/plat/nvidia/tegra/soc/t132/plat_setup.c index a76999c5..6ff2831f 100644 --- a/plat/nvidia/tegra/soc/t132/plat_setup.c +++ b/plat/nvidia/tegra/soc/t132/plat_setup.c @@ -31,6 +31,21 @@ #include #include +/******************************************************************************* + * 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 */ #define MMIO_RANGE_0_ADDR 0x50000000 #define MMIO_RANGE_1_ADDR 0x60000000 diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c index 73358d4d..b184063d 100644 --- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c @@ -55,83 +55,139 @@ 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 */ if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on affinity level 0 i.e. * 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; + + /* 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 */ - switch (psci_get_pstate_id(power_state)) { + switch (state_id) { 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_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: + /* + * 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; default: - ERROR("unsupported state id\n"); - return PSCI_E_NOT_SUPPORTED; + 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_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) +int tegra_soc_pwr_domain_suspend(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; + 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]; - switch (id) { - /* Prepare for cpu idle */ - case PSTATE_ID_CORE_POWERDN: - tegra_fc_cpu_idle(read_mpidr()); - return PSCI_E_SUCCESS; + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { - /* Prepare for cluster idle */ - case PSTATE_ID_CLUSTER_IDLE: - tegra_fc_cluster_idle(read_mpidr()); - return PSCI_E_SUCCESS; + assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE); + assert(stateid_afflvl1 == PLAT_MAX_OFF_STATE); - /* Prepare for cluster powerdn */ - case PSTATE_ID_CLUSTER_POWERDN: - tegra_fc_cluster_powerdn(read_mpidr()); - return PSCI_E_SUCCESS; + /* suspend the entire soc */ + tegra_fc_soc_powerdn(mpidr); - /* Prepare for system idle */ - case PSTATE_ID_SOC_POWERDN: + } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) { - /* Enter system suspend state */ - tegra_pm_system_suspend_entry(); + assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE); - /* suspend the entire soc */ - tegra_fc_soc_powerdn(read_mpidr()); + /* Prepare for cluster idle */ + tegra_fc_cluster_idle(mpidr); - return PSCI_E_SUCCESS; + } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) { - default: - ERROR("Unknown state id (%d)\n", id); - break; + 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; } -int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) +int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { uint32_t val; /* * 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 @@ -147,11 +203,6 @@ int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) * address and reset it. */ 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 * 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; } -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; 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; } -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; } diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c index cbe7a042..3fce8a2a 100644 --- a/plat/nvidia/tegra/soc/t210/plat_setup.c +++ b/plat/nvidia/tegra/soc/t210/plat_setup.c @@ -32,6 +32,23 @@ #include #include +/******************************************************************************* + * 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 */ #define MMIO_RANGE_0_ADDR 0x50000000 #define MMIO_RANGE_1_ADDR 0x60000000 -- 2.30.2