Merge pull request #766 from soby-mathew/sm/scpi_reorg

Introduce SCP power management abstraction
This commit is contained in:
danh-arm 2016-12-08 12:18:52 +00:00 committed by GitHub
commit 413a1a30c2
14 changed files with 269 additions and 113 deletions

View File

@ -220,4 +220,7 @@ int plat_arm_get_alt_image_source(
unsigned int plat_arm_calc_core_pos(u_register_t mpidr);
const mmap_region_t *plat_arm_get_mmap(void);
/* Allow platform to override psci_pm_ops during runtime */
const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops);
#endif /* __PLAT_ARM_H__ */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2016, 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:
@ -35,6 +35,12 @@
#include <psci.h>
#include <types.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)
int css_pwr_domain_on(u_register_t mpidr);
void css_pwr_domain_on_finish(const psci_power_state_t *target_state);
void css_pwr_domain_off(const psci_power_state_t *target_state);

View File

@ -327,7 +327,7 @@ static int fvp_node_hw_state(u_register_t target_cpu,
* Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
* platform layer 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 = {
.cpu_standby = fvp_cpu_standby,
.pwr_domain_on = fvp_pwr_domain_on,
.pwr_domain_off = fvp_pwr_domain_off,

View File

@ -76,7 +76,7 @@ static int juno_translate_power_state_by_mpidr(u_register_t mpidr,
* 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_off = css_pwr_domain_off,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2016, 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:
@ -38,8 +38,11 @@
#include <platform_def.h>
#include <psci.h>
/* Allow ARM Standard platforms to override this function */
#pragma weak plat_arm_psci_override_pm_ops
/* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */
extern const plat_psci_ops_t plat_arm_psci_pm_ops;
extern plat_psci_ops_t plat_arm_psci_pm_ops;
#if ARM_RECOM_STATE_ID_ENC
extern unsigned int arm_pm_idle_states[];
@ -150,6 +153,14 @@ int arm_validate_ns_entrypoint(uintptr_t entrypoint)
return PSCI_E_INVALID_ADDRESS;
}
/******************************************************************************
* Default definition on ARM standard platforms to override the plat_psci_ops.
*****************************************************************************/
const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
{
return ops;
}
/******************************************************************************
* Helper function to resume the platform from system suspend. Reinitialize
* the system components which are not in the Always ON power domain.
@ -201,7 +212,7 @@ void arm_program_trusted_mailbox(uintptr_t address)
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
*psci_ops = &plat_arm_psci_pm_ops;
*psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops);
/* Setup mailbox with entry point. */
arm_program_trusted_mailbox(sec_entrypoint);

View File

@ -41,18 +41,18 @@ PLAT_BL_COMMON_SOURCES += plat/arm/css/common/aarch64/css_helpers.S
BL1_SOURCES += plat/arm/css/common/css_bl1_setup.c
BL2_SOURCES += plat/arm/css/common/css_bl2_setup.c \
plat/arm/css/common/css_mhu.c \
plat/arm/css/common/css_scpi.c
plat/arm/css/drivers/scpi/css_mhu.c \
plat/arm/css/drivers/scpi/css_scpi.c
BL2U_SOURCES += plat/arm/css/common/css_bl2u_setup.c \
plat/arm/css/common/css_mhu.c \
plat/arm/css/common/css_scpi.c
BL31_SOURCES += plat/arm/css/common/css_mhu.c \
plat/arm/css/common/css_pm.c \
plat/arm/css/common/css_scpi.c \
plat/arm/css/common/css_topology.c
plat/arm/css/drivers/scpi/css_mhu.c \
plat/arm/css/drivers/scpi/css_scpi.c
BL31_SOURCES += plat/arm/css/common/css_pm.c \
plat/arm/css/common/css_topology.c \
plat/arm/css/drivers/scp/css_pm_scpi.c \
plat/arm/css/drivers/scpi/css_mhu.c \
plat/arm/css/drivers/scpi/css_scpi.c
ifneq (${RESET_TO_BL31},0)
$(error "Using BL31 as the reset vector is not supported on CSS platforms. \

View File

@ -37,13 +37,7 @@
#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 "../drivers/scp/css_scp.h"
/* Allow CSS platforms to override `plat_arm_psci_pm_ops` */
#pragma weak plat_arm_psci_pm_ops
@ -87,12 +81,7 @@ CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1,
******************************************************************************/
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;
}
@ -140,30 +129,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 +145,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);
}
/*******************************************************************************
@ -191,6 +163,7 @@ void css_pwr_domain_suspend(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_suspend(target_state);
}
/*******************************************************************************
@ -222,34 +195,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();
}
/*******************************************************************************
@ -303,43 +254,14 @@ 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;
/*
* The format of 'power_level' is implementation-defined, but 0 must
* mean a CPU. We also allow 1 to denote the cluster
*/
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;
/* 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;
}
return css_scp_get_power_state(mpidr, power_level);
}
/*******************************************************************************
* 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_off = css_pwr_domain_off,

View File

@ -34,9 +34,9 @@
#include <debug.h>
#include <platform.h>
#include <stdint.h>
#include "css_mhu.h"
#include "../drivers/scpi/css_mhu.h"
#include "../drivers/scpi/css_scpi.h"
#include "css_scp_bootloader.h"
#include "css_scpi.h"
/* ID of the MHU slot used for the BOM protocol */
#define BOM_MHU_SLOT_ID 0

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2016, 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.
*/
#include <arch_helpers.h>
#include <assert.h>
#include <css_pm.h>
#include <debug.h>
#include "../scpi/css_scpi.h"
#include "css_scp.h"
/*
* This file implements the SCP power management functions using SCPI protocol.
*/
/*
* Helper function to inform power down state to SCP.
*/
void css_scp_suspend(const psci_power_state_t *target_state)
{
uint32_t cluster_state = scpi_power_on;
uint32_t system_state = scpi_power_on;
/* 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)
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);
}
/*
* Helper function to turn off a CPU power domain and its parent power domains
* if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
* call the suspend helper here.
*/
void css_scp_off(const psci_power_state_t *target_state)
{
css_scp_suspend(target_state);
}
/*
* Helper function to turn ON a CPU power domain and its parent power domains
* if applicable.
*/
void css_scp_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);
}
/*
* Helper function to get the power state of a power domain node as reported
* by the SCP.
*/
int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
{
int rc, element;
unsigned int cpu_state, cluster_state;
/*
* The format of 'power_level' is implementation-defined, but 0 must
* mean a CPU. We also allow 1 to denote the cluster
*/
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;
/* 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;
}
}
/*
* Helper function to shutdown the system via SCPI.
*/
void __dead2 css_scp_sys_shutdown(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();
}
/*
* Helper function to reset the system via SCPI.
*/
void __dead2 css_scp_sys_reboot(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();
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2016, 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.
*/
#ifndef __CSS_SCP_H__
#define __CSS_SCP_H__
#include <psci.h>
void css_scp_suspend(const psci_power_state_t *target_state);
void css_scp_off(const psci_power_state_t *target_state);
void css_scp_on(u_register_t mpidr);
int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level);
void __dead2 css_scp_sys_shutdown(void);
void __dead2 css_scp_sys_reboot(void);
#endif /* __CSS_SCP_H__ */

View File

@ -33,8 +33,8 @@
#include <bakery_lock.h>
#include <css_def.h>
#include <mmio.h>
#include <platform_def.h>
#include <plat_arm.h>
#include <platform_def.h>
#include "css_mhu.h"
/* SCP MHU secure channel registers */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2016, 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:

View File

@ -63,9 +63,11 @@ static void scpi_secure_message_start(void)
static void scpi_secure_message_send(size_t payload_size)
{
/* Ensure that any write to the SCPI payload area is seen by SCP before
/*
* Ensure that any write to the SCPI payload area is seen by SCP before
* we write to the MHU register. If these 2 writes were reordered by
* the CPU then SCP would read stale payload data */
* the CPU then SCP would read stale payload data
*/
dmbst();
mhu_secure_message_send(SCPI_MHU_SLOT_ID);
@ -86,9 +88,11 @@ static void scpi_secure_message_receive(scpi_cmd_t *cmd)
panic();
}
/* Ensure that any read to the SCPI payload area is done after reading
/*
* Ensure that any read to the SCPI payload area is done after reading
* the MHU register. If these 2 reads were reordered then the CPU would
* read invalid payload data */
* read invalid payload data
*/
dmbld();
memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
@ -137,8 +141,9 @@ int scpi_wait_ready(void)
return status == SCP_OK ? 0 : -1;
}
void scpi_set_css_power_state(unsigned mpidr, scpi_power_state_t cpu_state,
scpi_power_state_t cluster_state, scpi_power_state_t css_state)
void scpi_set_css_power_state(unsigned int mpidr,
scpi_power_state_t cpu_state, scpi_power_state_t cluster_state,
scpi_power_state_t css_state)
{
scpi_cmd_t *cmd;
uint32_t state = 0;

View File

@ -122,7 +122,7 @@ typedef enum {
} scpi_system_state_t;
extern int scpi_wait_ready(void);
extern void scpi_set_css_power_state(unsigned mpidr,
extern void scpi_set_css_power_state(unsigned int mpidr,
scpi_power_state_t cpu_state,
scpi_power_state_t cluster_state,
scpi_power_state_t css_state);