Migrate ARM platforms to use the new GICv3 API
[project/bcm63xx/atf.git] / plat / arm / css / common / css_pm.c
index 7607f617762dcdb7be5fdb74a8d057b2551a39b5..01c674f82e1483e65c004757c7d4342b2bf4e249 100644 (file)
@@ -1,49 +1,21 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of ARM nor the names of its contributors may be used
- * to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include <arch_helpers.h>
 #include <assert.h>
-#include <cassert.h>
-#include <css_pm.h>
-#include <debug.h>
 #include <errno.h>
-#include <plat_arm.h>
-#include <platform.h>
+
 #include <platform_def.h>
-#include "css_scpi.h"
 
-/* Macros to read the CSS power domain state */
-#define CSS_CORE_PWR_STATE(state)      (state)->pwr_domain_state[ARM_PWR_LVL0]
-#define CSS_CLUSTER_PWR_STATE(state)   (state)->pwr_domain_state[ARM_PWR_LVL1]
-#define CSS_SYSTEM_PWR_STATE(state)    ((PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) ?\
-                               (state)->pwr_domain_state[ARM_PWR_LVL2] : 0)
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <lib/cassert.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
 
 /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */
 #pragma weak plat_arm_psci_pm_ops
@@ -81,18 +53,20 @@ const unsigned int arm_pm_idle_states[] = {
 CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1,
                assert_max_pwr_lvl_supported_mismatch);
 
+/*
+ * Ensure that the PLAT_MAX_PWR_LVL is not greater than CSS_SYSTEM_PWR_DMN_LVL
+ * assumed by the CSS layer.
+ */
+CASSERT(PLAT_MAX_PWR_LVL <= CSS_SYSTEM_PWR_DMN_LVL,
+               assert_max_pwr_lvl_higher_than_css_sys_lvl);
+
 /*******************************************************************************
  * Handler called when a power domain is about to be turned on. The
  * level and mpidr determine the affinity instance.
  ******************************************************************************/
 int css_pwr_domain_on(u_register_t mpidr)
 {
-       /*
-        * SCP takes care of powering up parent power domains so we
-        * only need to care about level 0
-        */
-       scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
-                                scpi_power_on);
+       css_scp_on(mpidr);
 
        return PSCI_E_SUCCESS;
 }
@@ -121,10 +95,18 @@ static void css_pwr_domain_on_finisher_common(
 void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
        /* Assert that the system power domain need not be initialized */
-       assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN);
+       assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
 
        css_pwr_domain_on_finisher_common(target_state);
+}
 
+/*******************************************************************************
+ * Handler called when a power domain has just been powered on and the cpu
+ * and its cluster are fully participating in coherent transaction on the
+ * interconnect. Data cache must be enabled for CPU at this point.
+ ******************************************************************************/
+void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state)
+{
        /* Program the gic per-cpu distributor or re-distributor interface */
        plat_arm_gic_pcpu_init();
 
@@ -140,30 +122,12 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
  ******************************************************************************/
 static void css_power_down_common(const psci_power_state_t *target_state)
 {
-       uint32_t cluster_state = scpi_power_on;
-       uint32_t system_state = scpi_power_on;
-
        /* Prevent interrupts from spuriously waking up this cpu */
        plat_arm_gic_cpuif_disable();
 
-       /* Check if power down at system power domain level is requested */
-       if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
-                       system_state = scpi_power_retention;
-
        /* Cluster is to be turned off, so disable coherency */
-       if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
+       if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
                plat_arm_interconnect_exit_coherency();
-               cluster_state = scpi_power_off;
-       }
-
-       /*
-        * Ask the SCP to power down the appropriate components depending upon
-        * their state.
-        */
-       scpi_set_css_power_state(read_mpidr_el1(),
-                                scpi_power_off,
-                                cluster_state,
-                                system_state);
 }
 
 /*******************************************************************************
@@ -174,6 +138,7 @@ void css_pwr_domain_off(const psci_power_state_t *target_state)
 {
        assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
        css_power_down_common(target_state);
+       css_scp_off(target_state);
 }
 
 /*******************************************************************************
@@ -189,8 +154,19 @@ void css_pwr_domain_suspend(const psci_power_state_t *target_state)
        if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
                return;
 
+
        assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
        css_power_down_common(target_state);
+
+       /* Perform system domain state saving if issuing system suspend */
+       if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) {
+               arm_system_pwr_domain_save();
+
+               /* Power off the Redistributor after having saved its context */
+               plat_arm_gic_redistif_off();
+       }
+
+       css_scp_suspend(target_state);
 }
 
 /*******************************************************************************
@@ -208,13 +184,18 @@ void css_pwr_domain_suspend_finish(
                return;
 
        /* Perform system domain restore if woken up from system suspend */
-       if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+       if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF)
+               /*
+                * At this point, the Distributor must be powered on to be ready
+                * to have its state restored. The Redistributor will be powered
+                * on as part of gicv3_rdistif_init_restore.
+                */
                arm_system_pwr_domain_resume();
-       else
-               /* Enable the gic cpu interface */
-               plat_arm_gic_cpuif_enable();
 
        css_pwr_domain_on_finisher_common(target_state);
+
+       /* Enable the gic cpu interface */
+       plat_arm_gic_cpuif_enable();
 }
 
 /*******************************************************************************
@@ -222,34 +203,12 @@ void css_pwr_domain_suspend_finish(
  ******************************************************************************/
 void __dead2 css_system_off(void)
 {
-       uint32_t response;
-
-       /* Send the power down request to the SCP */
-       response = scpi_sys_power_state(scpi_system_shutdown);
-
-       if (response != SCP_OK) {
-               ERROR("CSS System Off: SCP error %u.\n", response);
-               panic();
-       }
-       wfi();
-       ERROR("CSS System Off: operation not handled.\n");
-       panic();
+       css_scp_sys_shutdown();
 }
 
 void __dead2 css_system_reset(void)
 {
-       uint32_t response;
-
-       /* Send the system reset request to the SCP */
-       response = scpi_sys_power_state(scpi_system_reboot);
-
-       if (response != SCP_OK) {
-               ERROR("CSS System Reset: SCP error %u.\n", response);
-               panic();
-       }
-       wfi();
-       ERROR("CSS System Reset: operation not handled.\n");
-       panic();
+       css_scp_sys_reboot();
 }
 
 /*******************************************************************************
@@ -292,7 +251,7 @@ void css_get_sys_suspend_power_state(psci_power_state_t *req_state)
         * System Suspend is supported only if the system power domain node
         * is implemented.
         */
-       assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
+       assert(PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL);
 
        for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
                req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
@@ -303,52 +262,80 @@ void css_get_sys_suspend_power_state(psci_power_state_t *req_state)
  ******************************************************************************/
 int css_node_hw_state(u_register_t mpidr, unsigned int power_level)
 {
-       int rc, element;
-       unsigned int cpu_state, cluster_state;
+       return css_scp_get_power_state(mpidr, power_level);
+}
+
+/*
+ * The system power domain suspend is only supported only via
+ * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
+ * will be downgraded to the lower level.
+ */
+static int css_validate_power_state(unsigned int power_state,
+                           psci_power_state_t *req_state)
+{
+       int rc;
+       rc = arm_validate_power_state(power_state, req_state);
 
        /*
-        * The format of 'power_level' is implementation-defined, but 0 must
-        * mean a CPU. We also allow 1 to denote the cluster
+        * Ensure that we don't overrun the pwr_domain_state array in the case
+        * where the platform supported max power level is less than the system
+        * power level
         */
-       if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
-               return PSCI_E_INVALID_PARAMS;
 
-       /* Query SCP */
-       rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
-       if (rc != 0)
-               return PSCI_E_INVALID_PARAMS;
+#if (PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL)
 
-       /* Map power states of CPU and cluster to expected PSCI return codes */
-       if (power_level == ARM_PWR_LVL0) {
-               /*
-                * The CPU state returned by SCP is an 8-bit bit mask
-                * corresponding to each CPU in the cluster
-                */
-               element = mpidr & MPIDR_AFFLVL_MASK;
-               return CSS_CPU_PWR_STATE(cpu_state, element) ==
-                       CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
-       } else {
-               assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
-                               cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
-               return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
-                       HW_OFF;
-       }
+       /*
+        * Ensure that the system power domain level is never suspended
+        * via PSCI CPU SUSPEND API. Currently system suspend is only
+        * supported via PSCI SYSTEM SUSPEND API.
+        */
+
+       req_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] =
+                                                       ARM_LOCAL_STATE_RUN;
+#endif
+
+       return rc;
+}
+
+/*
+ * Custom `translate_power_state_by_mpidr` handler for CSS. Unlike in the
+ * `css_validate_power_state`, we do not downgrade the system power
+ * domain level request in `power_state` as it will be used to query the
+ * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
+ */
+static int css_translate_power_state_by_mpidr(u_register_t mpidr,
+               unsigned int power_state,
+               psci_power_state_t *output_state)
+{
+       return arm_validate_power_state(power_state, output_state);
 }
 
 /*******************************************************************************
  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
  * platform will take care of registering the handlers with PSCI.
  ******************************************************************************/
-const plat_psci_ops_t plat_arm_psci_pm_ops = {
+plat_psci_ops_t plat_arm_psci_pm_ops = {
        .pwr_domain_on          = css_pwr_domain_on,
        .pwr_domain_on_finish   = css_pwr_domain_on_finish,
+       .pwr_domain_on_finish_late = css_pwr_domain_on_finish_late,
        .pwr_domain_off         = css_pwr_domain_off,
        .cpu_standby            = css_cpu_standby,
        .pwr_domain_suspend     = css_pwr_domain_suspend,
        .pwr_domain_suspend_finish      = css_pwr_domain_suspend_finish,
        .system_off             = css_system_off,
        .system_reset           = css_system_reset,
-       .validate_power_state   = arm_validate_power_state,
-       .validate_ns_entrypoint = arm_validate_ns_entrypoint,
-       .get_node_hw_state      = css_node_hw_state
+       .validate_power_state   = css_validate_power_state,
+       .validate_ns_entrypoint = arm_validate_psci_entrypoint,
+       .translate_power_state_by_mpidr = css_translate_power_state_by_mpidr,
+       .get_node_hw_state      = css_node_hw_state,
+       .get_sys_suspend_power_state = css_get_sys_suspend_power_state,
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+       .mem_protect_chk        = arm_psci_mem_protect_chk,
+       .read_mem_protect       = arm_psci_read_mem_protect,
+       .write_mem_protect      = arm_nor_psci_write_mem_protect,
+#endif
+#if CSS_USE_SCMI_SDS_DRIVER
+       .system_reset2          = css_system_reset2,
+#endif
 };