aboutsummaryrefslogtreecommitdiff
path: root/plat/common/plat_state_id.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/common/plat_state_id.c')
-rw-r--r--plat/common/plat_state_id.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/plat/common/plat_state_id.c b/plat/common/plat_state_id.c
new file mode 100644
index 000000000..ce43ba4a2
--- /dev/null
+++ b/plat/common/plat_state_id.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <tftf.h>
+
+static unsigned int pstate_initialized;
+
+/*
+ * Stores pointer to the state_prop_t for all implemented levels
+ */
+static const plat_state_prop_t *plat_state_ptr[PLAT_MAX_PWR_LEVEL + 1];
+
+/*
+ * Saves number of implemented power states per level
+ */
+static unsigned int power_states_per_level[PLAT_MAX_PWR_LEVEL + 1];
+
+void tftf_init_pstate_framework(void)
+{
+ int i, j;
+
+ if (pstate_initialized)
+ return;
+
+ /* Detect the PSCI power state format used. */
+ tftf_detect_psci_pstate_format();
+
+ /*
+ * Get and save the pointers to plat_state_prop_t values for all
+ * levels. Also, store the max number of local states possible for
+ * each level in power_states_per_level.
+ */
+ for (i = 0; i <= PLAT_MAX_PWR_LEVEL; i++) {
+ plat_state_ptr[i] = plat_get_state_prop(i);
+ assert(plat_state_ptr[i]);
+
+ for (j = 0; (plat_state_ptr[i]+j)->state_ID != 0; j++)
+ ;
+
+ power_states_per_level[i] = j;
+ }
+
+ pstate_initialized = 1;
+}
+
+void tftf_set_next_state_id_idx(unsigned int power_level,
+ unsigned int pstate_id_idx[])
+{
+ unsigned int i;
+#if ENABLE_ASSERTIONS
+ /* Verify that this is a valid power level. */
+ assert(power_level <= PLAT_MAX_PWR_LEVEL);
+
+ /*
+ * Verify if a level has PWR_STATE_INIT_INDEX index, all higher levels
+ * have to be in PWR_STATE_INIT_INDEX. Not needed to check the top
+ * power level in the outer loop.
+ */
+ for (i = 0; i < power_level; i++) {
+ if (pstate_id_idx[i] == PWR_STATE_INIT_INDEX) {
+ for ( ; i <= power_level; i++)
+ assert(pstate_id_idx[i] == PWR_STATE_INIT_INDEX);
+ }
+ }
+#endif
+
+ /* Increment the pstate_id_idx starting from the lowest power level */
+ for (i = 0; i <= power_level; i++) {
+ pstate_id_idx[i]++;
+
+ /*
+ * Wraparound index if the maximum power states available for
+ * that level is reached and proceed to next level.
+ */
+ if (pstate_id_idx[i] == power_states_per_level[i])
+ pstate_id_idx[i] = 0;
+ else
+ break;
+ }
+
+ /*
+ * Check if the requested power level has wrapped around. If it has,
+ * reset pstate_id_idx.
+ */
+ if (i > power_level) {
+ for (i = 0; i <= power_level; i++)
+ pstate_id_idx[i] = PWR_STATE_INIT_INDEX;
+ }
+}
+
+void tftf_set_deepest_pstate_idx(unsigned int power_level,
+ unsigned int pstate_id_idx[])
+{
+ int i;
+
+ /* Verify that this is a valid power level. */
+ assert(power_level <= PLAT_MAX_PWR_LEVEL);
+
+ /*
+ * Assign the highest pstate_id_idx starting from the lowest power
+ * level
+ */
+ for (i = 0; i <= power_level; i++)
+ pstate_id_idx[i] = power_states_per_level[i] - 1;
+}
+
+
+int tftf_get_pstate_vars(unsigned int *test_power_level,
+ unsigned int *test_suspend_type,
+ unsigned int *suspend_state_id,
+ unsigned int pstate_id_idx[])
+{
+ unsigned int i;
+ int state_id = 0;
+ int suspend_type;
+ int suspend_depth;
+ int psci_ret = PSCI_E_SUCCESS;
+ const plat_state_prop_t *local_state;
+
+ /* Atleast one entry should be valid to generate correct power state params */
+ assert(pstate_id_idx[0] != PWR_STATE_INIT_INDEX &&
+ pstate_id_idx[0] <= power_states_per_level[0]);
+
+ suspend_depth = (plat_state_ptr[0] + pstate_id_idx[0])->suspend_depth;
+ suspend_type = (plat_state_ptr[0] + pstate_id_idx[0])->is_pwrdown;
+
+ for (i = 0; i <= PLAT_MAX_PWR_LEVEL; i++) {
+
+ /* Reached all levels with the valid power index values */
+ if (pstate_id_idx[i] == PWR_STATE_INIT_INDEX)
+ break;
+
+ assert(pstate_id_idx[i] <= power_states_per_level[i]);
+
+ local_state = plat_state_ptr[i] + pstate_id_idx[i];
+ state_id |= (local_state->state_ID << i * PLAT_LOCAL_PSTATE_WIDTH);
+
+ if (local_state->is_pwrdown > suspend_type)
+ suspend_type = local_state->is_pwrdown;
+
+ if (local_state->suspend_depth > suspend_depth)
+ psci_ret = PSCI_E_INVALID_PARAMS;
+ else
+ suspend_depth = local_state->suspend_depth;
+ }
+
+ *test_suspend_type = suspend_type;
+ *suspend_state_id = state_id;
+ *test_power_level = --i;
+
+ return psci_ret;
+}
+
+void tftf_set_next_local_state_id_idx(unsigned int power_level,
+ unsigned int pstate_id_idx[])
+{
+ assert(power_level <= PLAT_MAX_PWR_LEVEL);
+
+ if (pstate_id_idx[power_level] + 1 >= power_states_per_level[power_level]) {
+ pstate_id_idx[power_level] = PWR_STATE_INIT_INDEX;
+ return;
+ }
+
+ pstate_id_idx[power_level]++;
+}