diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h index 636daf294a567aea5cf8fae2c376c74694c6555c..173de1b4d32f9cfbb8d7e96a6887e1b13ee5c6ce 100644 --- a/include/plat/arm/css/common/css_def.h +++ b/include/plat/arm/css/common/css_def.h @@ -148,5 +148,15 @@ /* Trusted mailbox base address common to all CSS */ #define PLAT_ARM_TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE +/* + * Parsing of CPU and Cluster states, as returned by 'Get CSS Power State' SCP + * command + */ +#define CSS_CLUSTER_PWR_STATE_ON 0 +#define CSS_CLUSTER_PWR_STATE_OFF 3 + +#define CSS_CPU_PWR_STATE_ON 1 +#define CSS_CPU_PWR_STATE_OFF 0 +#define CSS_CPU_PWR_STATE(state, n) (((state) >> (n)) & 1) #endif /* __CSS_DEF_H__ */ diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h index ea6a5d251fd9a99822a78c13fd45f7f2f6b6ff87..4a6ca816162317c5328e895611962d280703acd5 100644 --- a/include/plat/arm/css/common/css_pm.h +++ b/include/plat/arm/css/common/css_pm.h @@ -45,5 +45,6 @@ void __dead2 css_system_off(void); void __dead2 css_system_reset(void); void css_cpu_standby(plat_local_state_t cpu_state); 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); #endif /* __CSS_PM_H__ */ diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c index cbf994a4713f0ff10a6b33b4c892520c245ab905..c355d94dfbbb4da985d6d2251c92f7c374537967 100644 --- a/plat/arm/board/juno/juno_pm.c +++ b/plat/arm/board/juno/juno_pm.c @@ -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: @@ -88,5 +88,6 @@ const plat_psci_ops_t plat_arm_psci_pm_ops = { .validate_power_state = juno_validate_power_state, .validate_ns_entrypoint = arm_validate_ns_entrypoint, .get_sys_suspend_power_state = css_get_sys_suspend_power_state, - .translate_power_state_by_mpidr = juno_translate_power_state_by_mpidr + .translate_power_state_by_mpidr = juno_translate_power_state_by_mpidr, + .get_node_hw_state = css_node_hw_state }; diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index 801d937578567e2823a42f583cb96da6e99eb1fb..7607f617762dcdb7be5fdb74a8d057b2551a39b5 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -298,6 +298,43 @@ void css_get_sys_suspend_power_state(psci_power_state_t *req_state) req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; } +/******************************************************************************* + * Handler to query CPU/cluster power states from SCP + ******************************************************************************/ +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; + } +} + /******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform will take care of registering the handlers with PSCI. @@ -312,5 +349,6 @@ const plat_psci_ops_t plat_arm_psci_pm_ops = { .system_off = css_system_off, .system_reset = css_system_reset, .validate_power_state = arm_validate_power_state, - .validate_ns_entrypoint = arm_validate_ns_entrypoint + .validate_ns_entrypoint = arm_validate_ns_entrypoint, + .get_node_hw_state = css_node_hw_state };