summaryrefslogtreecommitdiff
path: root/services/std_svc
diff options
context:
space:
mode:
authorSoby Mathew <soby.mathew@arm.com>2015-01-07 11:10:22 +0000
committerDan Handley <dan.handley@arm.com>2015-01-26 12:42:45 +0000
commit90e8258eec95bcad556426597489a34208232e39 (patch)
tree6dbd2e17c713c92cee5596be16d659cfd249c355 /services/std_svc
parent8991eed7439cb565da505a2bf88e9ac87ad79c1c (diff)
Implement PSCI_FEATURES API
This patch implements the PSCI_FEATURES function which is a mandatory API in the PSCI 1.0 specification. A capability variable is constructed during initialization by examining the plat_pm_ops and spd_pm_ops exported by the platform and the Secure Payload Dispatcher. This is used by the PSCI FEATURES function to determine which PSCI APIs are supported by the platform. Change-Id: I147ffc1bd5d90b469bd3cc4bbe0a20e95c247df7
Diffstat (limited to 'services/std_svc')
-rw-r--r--services/std_svc/psci/psci_common.c8
-rw-r--r--services/std_svc/psci/psci_main.c37
-rw-r--r--services/std_svc/psci/psci_private.h21
-rw-r--r--services/std_svc/psci/psci_setup.c20
4 files changed, 86 insertions, 0 deletions
diff --git a/services/std_svc/psci/psci_common.c b/services/std_svc/psci/psci_common.c
index 898a343d..a31643e4 100644
--- a/services/std_svc/psci/psci_common.c
+++ b/services/std_svc/psci/psci_common.c
@@ -558,7 +558,15 @@ void psci_afflvl_power_on_finish(int start_afflvl,
******************************************************************************/
void psci_register_spd_pm_hook(const spd_pm_ops_t *pm)
{
+ assert(pm);
psci_spd_pm = pm;
+
+ if (pm->svc_migrate)
+ psci_caps |= define_psci_cap(PSCI_MIG_AARCH64);
+
+ if (pm->svc_migrate_info)
+ psci_caps |= define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64)
+ | define_psci_cap(PSCI_MIG_INFO_TYPE);
}
/*******************************************************************************
diff --git a/services/std_svc/psci/psci_main.c b/services/std_svc/psci/psci_main.c
index af00551e..0e10ac05 100644
--- a/services/std_svc/psci/psci_main.c
+++ b/services/std_svc/psci/psci_main.c
@@ -32,6 +32,7 @@
#include <arch_helpers.h>
#include <assert.h>
#include <runtime_svc.h>
+#include <std_svc.h>
#include <debug.h>
#include "psci_private.h"
@@ -272,6 +273,39 @@ long psci_migrate_info_up_cpu(void)
return resident_cpu_mpidr;
}
+int psci_features(unsigned int psci_fid)
+{
+ uint32_t local_caps = psci_caps;
+
+ /* Check if it is a 64 bit function */
+ if (((psci_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)
+ local_caps &= PSCI_CAP_64BIT_MASK;
+
+ /* Check for invalid fid */
+ if (!(is_std_svc_call(psci_fid) && is_valid_fast_smc(psci_fid)
+ && is_psci_fid(psci_fid)))
+ return PSCI_E_NOT_SUPPORTED;
+
+
+ /* Check if the psci fid is supported or not */
+ if (!(local_caps & define_psci_cap(psci_fid)))
+ return PSCI_E_NOT_SUPPORTED;
+
+ /* Format the feature flags */
+ if (psci_fid == PSCI_CPU_SUSPEND_AARCH32 ||
+ psci_fid == PSCI_CPU_SUSPEND_AARCH64) {
+ /*
+ * The trusted firmware uses the original power state format
+ * and does not support OS Initiated Mode.
+ */
+ return (FF_PSTATE_ORIG << FF_PSTATE_SHIFT) |
+ ((!FF_SUPPORTS_OS_INIT_MODE) << FF_MODE_SUPPORT_SHIFT);
+ }
+
+ /* Return 0 for all other fid's */
+ return PSCI_E_SUCCESS;
+}
+
/*******************************************************************************
* PSCI top level handler for servicing SMCs.
******************************************************************************/
@@ -327,6 +361,9 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
psci_system_reset();
/* We should never return from psci_system_reset() */
+ case PSCI_FEATURES:
+ SMC_RET1(handle, psci_features(x1));
+
default:
break;
}
diff --git a/services/std_svc/psci/psci_private.h b/services/std_svc/psci/psci_private.h
index 62477702..54846656 100644
--- a/services/std_svc/psci/psci_private.h
+++ b/services/std_svc/psci/psci_private.h
@@ -52,6 +52,26 @@
CPU_DATA_PSCI_LOCK_OFFSET)
#endif
+/*
+ * The PSCI capability which are provided by the generic code but does not
+ * depend on the platform or spd capabilities.
+ */
+#define PSCI_GENERIC_CAP \
+ (define_psci_cap(PSCI_VERSION) | \
+ define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \
+ define_psci_cap(PSCI_FEATURES))
+
+/*
+ * The PSCI capabilities mask for 64 bit functions.
+ */
+#define PSCI_CAP_64BIT_MASK \
+ (define_psci_cap(PSCI_CPU_SUSPEND_AARCH64) | \
+ define_psci_cap(PSCI_CPU_ON_AARCH64) | \
+ define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \
+ define_psci_cap(PSCI_MIG_AARCH64) | \
+ define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64))
+
+
/*******************************************************************************
* The following two data structures hold the topology tree which in turn tracks
* the state of the all the affinity instances supported by the platform.
@@ -82,6 +102,7 @@ typedef void (*afflvl_power_on_finisher_t)(aff_map_node_t *);
******************************************************************************/
extern const plat_pm_ops_t *psci_plat_pm_ops;
extern aff_map_node_t psci_aff_map[PSCI_NUM_AFFS];
+extern uint32_t psci_caps;
/*******************************************************************************
* SPD's power management hooks registered with PSCI
diff --git a/services/std_svc/psci/psci_setup.c b/services/std_svc/psci/psci_setup.c
index be504e81..02a87865 100644
--- a/services/std_svc/psci/psci_setup.c
+++ b/services/std_svc/psci/psci_setup.c
@@ -57,6 +57,12 @@ static cpu_context_t psci_ns_context[PLATFORM_CORE_COUNT];
******************************************************************************/
static aff_limits_node_t psci_aff_limits[MPIDR_MAX_AFFLVL + 1];
+/******************************************************************************
+ * Define the psci capability variable.
+ *****************************************************************************/
+uint32_t psci_caps;
+
+
/*******************************************************************************
* Routines for retrieving the node corresponding to an affinity level instance
* in the mpidr. The first one uses binary search to find the node corresponding
@@ -372,5 +378,19 @@ int32_t psci_setup(void)
platform_setup_pm(&psci_plat_pm_ops);
assert(psci_plat_pm_ops);
+ /* Initialize the psci capability */
+ psci_caps = PSCI_GENERIC_CAP;
+
+ if (psci_plat_pm_ops->affinst_off)
+ psci_caps |= define_psci_cap(PSCI_CPU_OFF);
+ if (psci_plat_pm_ops->affinst_on && psci_plat_pm_ops->affinst_on_finish)
+ psci_caps |= define_psci_cap(PSCI_CPU_ON_AARCH64);
+ if (psci_plat_pm_ops->affinst_suspend && psci_plat_pm_ops->affinst_suspend_finish)
+ psci_caps |= define_psci_cap(PSCI_CPU_SUSPEND_AARCH64);
+ if (psci_plat_pm_ops->system_off)
+ psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF);
+ if (psci_plat_pm_ops->system_reset)
+ psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
+
return 0;
}