Tegra: remove support for legacy platform APIs
authorVarun Wadekar <vwadekar@nvidia.com>
Fri, 7 Aug 2015 04:33:00 +0000 (10:03 +0530)
committerVarun Wadekar <vwadekar@nvidia.com>
Fri, 4 Dec 2015 23:41:20 +0000 (15:41 -0800)
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 <vwadekar@nvidia.com>
12 files changed:
plat/nvidia/tegra/common/aarch64/tegra_helpers.S
plat/nvidia/tegra/common/tegra_common.mk
plat/nvidia/tegra/common/tegra_pm.c
plat/nvidia/tegra/common/tegra_topology.c
plat/nvidia/tegra/include/platform_def.h
plat/nvidia/tegra/include/t132/tegra_def.h
plat/nvidia/tegra/include/tegra_private.h
plat/nvidia/tegra/platform.mk
plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
plat/nvidia/tegra/soc/t132/plat_setup.c
plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
plat/nvidia/tegra/soc/t210/plat_setup.c

index d9f287c9321d0692f92cdb64baf1351f51a96d8c..a4caf5ef215b6350381db85bbce168567b1d0e0e 100644 (file)
@@ -36,9 +36,9 @@
 #include <tegra_def.h>
 
        /* 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
 
 .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
index e1c0d84d641829247ab70fe6f9f400d1ae86497c..fcebde3031beec4f384575a6a2ac9cb684555585 100644 (file)
@@ -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                 \
index c2c73f63063f3076f500855fdd21850e468c7d0d..6fb3e9c6116e77271f2d3fbdd0a26f9a7cb50798 100644 (file)
 #include <tegra_private.h>
 
 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;
 }
index 220e697b7cc333cf92c0596a4ecd34793e9df591..0431d98a2cfdb3397d9f6f69b6e9ef02989597dc 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <arch_helpers.h>
+#include <arch.h>
 #include <platform_def.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
- * 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));
 }
index c59e2beb2072848bdf0069ce8225aba21331dacc..2a7935fd086ccb4728e052445102a0520ff47205 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <arch.h>
 #include <common_def.h>
+#include <tegra_def.h>
 
 /*******************************************************************************
  * Generic platform constants
 
 #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
  ******************************************************************************/
index 2fb9ed708c83adc9f69eb6beba0ae0583f8b3c34..683c903815082b637c1da24de7bdcaf8eaa93932 100644 (file)
@@ -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
index 952e2d8b373c656a4a9416d926bdb7684674777e..aca9db723dc9b6597160f0723751dc0406eb7daa 100644 (file)
@@ -31,8 +31,9 @@
 #ifndef __TEGRA_PRIVATE_H__
 #define __TEGRA_PRIVATE_H__
 
-#include <xlat_tables.h>
+#include <arch.h>
 #include <platform_def.h>
+#include <xlat_tables.h>
 
 /*******************************************************************************
  * 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);
index b90933547db70d7849cdc8f270ef6ae6175e119a..cec7caff36a1b3b3946854409683a61929f5378c 100644 (file)
 # 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
index 46e594096ff7c6853cd2b3cae55aa6d4ccc8fc9c..48a2fbaa37015b92030f2316d35218f04af069ae 100644 (file)
 
 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;
 }
index a76999c5b6649325d70fda942bff88430e32bf08..6ff2831f6ce435caff3dac8125804b35086d8570 100644 (file)
 #include <xlat_tables.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 */
 #define MMIO_RANGE_0_ADDR      0x50000000
 #define MMIO_RANGE_1_ADDR      0x60000000
index 73358d4d4ca0adf93406df2dbb742643ac7fa371..b184063d8f8042bebc9bdc07fb021d71b4883b85 100644 (file)
 
 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;
 }
 
index cbe7a0424086df616b953fa71ae51521b55ca3ab..3fce8a2a51a4d1e7d6fb1880e6e7b966956d6ca0 100644 (file)
 #include <tegra_def.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 */
 #define MMIO_RANGE_0_ADDR      0x50000000
 #define MMIO_RANGE_1_ADDR      0x60000000