aboutsummaryrefslogtreecommitdiff
path: root/module/system_power
diff options
context:
space:
mode:
authorNicola Mazzucato <nicola.mazzucato@arm.com>2019-05-02 16:27:27 +0100
committerronald-cron-arm <39518861+ronald-cron-arm@users.noreply.github.com>2019-06-04 12:00:40 +0200
commitc22a0b8fd5b6b2b986ab211c057f29f9466320de (patch)
tree7fda571953abbca615028dadb99caa440d8c4330 /module/system_power
parent6970a1eb436bec5750ba3c335f837be956632470 (diff)
system_power: Update module to a configurable number of system PPUs
This patch removes the constraint of a fixed number of system PPUs by expanding the module to support an adjustable number of elements. Change-Id: Ic52c2751fa32e5e267e0940255af0b1a1fc570d1 Signed-off-by: Nicola Mazzucato <nicola.mazzucato@arm.com>
Diffstat (limited to 'module/system_power')
-rw-r--r--module/system_power/include/mod_system_power.h27
-rw-r--r--module/system_power/src/mod_system_power.c242
2 files changed, 169 insertions, 100 deletions
diff --git a/module/system_power/include/mod_system_power.h b/module/system_power/include/mod_system_power.h
index 45d5aa12..eb12d490 100644
--- a/module/system_power/include/mod_system_power.h
+++ b/module/system_power/include/mod_system_power.h
@@ -37,20 +37,26 @@ struct mod_system_power_ext_ppu_config {
fwk_id_t api_id;
};
+/*! Element configuration */
+struct mod_system_power_dev_config {
+ /*! Identifier of the system PPU */
+ fwk_id_t sys_ppu_id;
+
+ /*! System PPU API identifier */
+ fwk_id_t api_id;
+
+ /*!
+ * \brief Pointer to a table defining the power states this system PPU will
+ * be set for each system state.
+ */
+ const uint8_t *sys_state_table;
+};
+
/*! Module configuration */
struct mod_system_power_config {
/*! SoC wakeup IRQ number */
unsigned int soc_wakeup_irq;
- /*! System 0 PPU element ID */
- fwk_id_t ppu_sys0_id;
-
- /*! System 1 PPU element ID */
- fwk_id_t ppu_sys1_id;
-
- /*! System PPUs API ID */
- fwk_id_t ppu_sys_api_id;
-
/*! Number of extended PPUs */
size_t ext_ppus_count;
@@ -67,6 +73,9 @@ struct mod_system_power_config {
/*! System shutdown driver API identifier */
fwk_id_t driver_api_id;
+
+ /*! Initial System Power state after power-on */
+ enum mod_pd_state initial_system_power_state;
};
/*! Platform-specific interrupt commands indices */
diff --git a/module/system_power/src/mod_system_power.c b/module/system_power/src/mod_system_power.c
index 26ba6a38..fbe980d6 100644
--- a/module/system_power/src/mod_system_power.c
+++ b/module/system_power/src/mod_system_power.c
@@ -32,16 +32,25 @@
static const fwk_id_t mod_system_power_soc_wakeup_pd_id =
FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_POWER_DOMAIN, 0);
+/* Element context */
+struct system_power_dev_ctx {
+ /* Element configuration data pointer */
+ const struct mod_system_power_dev_config *config;
+
+ /* Power domain driver API pointer */
+ const struct mod_pd_driver_api *sys_ppu_api;
+};
+
/* Module context */
struct system_power_ctx {
/* Log API pointer */
const struct mod_log_api *log_api;
- /* SYS0 power domain driver API pointer */
- const struct mod_pd_driver_api *sys0_api;
+ /* System power element context table */
+ struct system_power_dev_ctx *dev_ctx_table;
- /* SYS1 power domain driver API pointer*/
- const struct mod_pd_driver_api *sys1_api;
+ /* Number of elements */
+ unsigned int dev_count;
/* Pointer to array of extended PPU power domain driver APIs */
const struct mod_pd_driver_api **ext_ppu_apis;
@@ -61,6 +70,9 @@ struct system_power_ctx {
/* Current system-level power state */
unsigned int state;
+ /* Requested power state */
+ unsigned int requested_state;
+
/* Pointer to module config */
const struct mod_system_power_config *config;
};
@@ -82,6 +94,27 @@ static void ext_ppus_set_state(enum mod_pd_state state)
}
}
+static int set_system_power_state(unsigned int state)
+{
+ int status;
+ unsigned int i;
+ struct system_power_dev_ctx *dev_ctx;
+ const uint8_t *sys_state_table;
+
+ for (i = 0; i < system_power_ctx.dev_count; i++) {
+ dev_ctx = &system_power_ctx.dev_ctx_table[i];
+
+ sys_state_table = dev_ctx->config->sys_state_table;
+
+ status = dev_ctx->sys_ppu_api->set_state(dev_ctx->config->sys_ppu_id,
+ sys_state_table[state]);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+
+ return FWK_SUCCESS;
+}
+
/*
* Functions fulfilling the Power Domain module's driver API
*/
@@ -95,8 +128,13 @@ static int system_power_set_state(fwk_id_t pd_id, unsigned int state)
if (status != FWK_SUCCESS)
return status;
+ if (!fwk_expect(state < MOD_SYSTEM_POWER_POWER_STATE_COUNT))
+ return FWK_E_PARAM;
+
soc_wakeup_irq = system_power_ctx.config->soc_wakeup_irq;
+ system_power_ctx.requested_state = state;
+
switch (state) {
case MOD_PD_STATE_ON:
fwk_interrupt_disable(soc_wakeup_irq);
@@ -108,10 +146,9 @@ static int system_power_set_state(fwk_id_t pd_id, unsigned int state)
return FWK_E_DEVICE;
}
- system_power_ctx.sys0_api->set_state(
- system_power_ctx.config->ppu_sys0_id, MOD_PD_STATE_ON);
- system_power_ctx.sys0_api->set_state(
- system_power_ctx.config->ppu_sys1_id, MOD_PD_STATE_ON);
+ status = set_system_power_state(state);
+ if (status != FWK_SUCCESS)
+ return status;
ext_ppus_set_state(MOD_PD_STATE_ON);
@@ -130,10 +167,9 @@ static int system_power_set_state(fwk_id_t pd_id, unsigned int state)
return FWK_E_DEVICE;
}
- system_power_ctx.sys0_api->set_state(
- system_power_ctx.config->ppu_sys0_id, MOD_PD_STATE_OFF);
- system_power_ctx.sys0_api->set_state(
- system_power_ctx.config->ppu_sys1_id, MOD_PD_STATE_ON);
+ status = set_system_power_state(state);
+ if (status != FWK_SUCCESS)
+ return status;
fwk_interrupt_enable(soc_wakeup_irq);
@@ -158,10 +194,9 @@ static int system_power_set_state(fwk_id_t pd_id, unsigned int state)
ext_ppus_set_state(MOD_PD_STATE_OFF);
- system_power_ctx.sys0_api->set_state(
- system_power_ctx.config->ppu_sys0_id, MOD_PD_STATE_OFF);
- system_power_ctx.sys0_api->set_state(
- system_power_ctx.config->ppu_sys1_id, MOD_PD_STATE_OFF);
+ status = set_system_power_state(state);
+ if (status != FWK_SUCCESS)
+ return status;
break;
@@ -224,31 +259,28 @@ static const struct mod_pd_driver_api system_power_power_domain_driver_api = {
* Functions fulfilling the Power Domain module's driver input API
*/
-static int system_power_report_power_state_transition(fwk_id_t module_id,
+static int system_power_report_power_state_transition(fwk_id_t dev_id,
unsigned int state)
{
int status;
- unsigned int sys0_state, sys1_state;
+ static unsigned int sys_ppu_transition_count = 0;
- system_power_ctx.sys0_api->get_state(system_power_ctx.config->ppu_sys0_id,
- &sys0_state);
- system_power_ctx.sys1_api->get_state(system_power_ctx.config->ppu_sys1_id,
- &sys1_state);
+ status = fwk_module_check_call(dev_id);
+ if (status != FWK_SUCCESS)
+ return status;
- if ((sys0_state == MOD_PD_STATE_ON) && (sys1_state == MOD_PD_STATE_ON))
- system_power_ctx.state = MOD_PD_STATE_ON;
- else if ((sys0_state == MOD_PD_STATE_OFF) &&
- (sys1_state == MOD_PD_STATE_ON))
- system_power_ctx.state = MOD_SYSTEM_POWER_POWER_STATE_SLEEP0;
- else
- system_power_ctx.state = MOD_PD_STATE_OFF;
+ sys_ppu_transition_count++;
- status =
- system_power_ctx.mod_pd_driver_input_api->report_power_state_transition(
- system_power_ctx.mod_pd_system_id, system_power_ctx.state);
- fwk_expect(status == FWK_SUCCESS);
+ if (sys_ppu_transition_count < system_power_ctx.dev_count)
+ return FWK_SUCCESS;
- return FWK_SUCCESS;
+ system_power_ctx.state = system_power_ctx.requested_state;
+
+ sys_ppu_transition_count = 0;
+
+ return system_power_ctx.mod_pd_driver_input_api->
+ report_power_state_transition(system_power_ctx.mod_pd_system_id,
+ system_power_ctx.state);
}
static const struct mod_pd_driver_input_api
@@ -261,13 +293,22 @@ static const struct mod_pd_driver_input_api
*/
static int system_power_mod_init(fwk_id_t module_id,
- unsigned int unused,
+ unsigned int element_count,
const void *data)
{
+ const struct mod_system_power_config *config;
+
fwk_assert(data != NULL);
+ fwk_expect(element_count > 0);
- system_power_ctx.config = data;
+ system_power_ctx.config = config = data;
system_power_ctx.mod_pd_system_id = FWK_ID_NONE;
+ system_power_ctx.dev_count = element_count;
+
+ system_power_ctx.dev_ctx_table =
+ fwk_mm_calloc(element_count, sizeof(struct system_power_dev_ctx));
+ if (system_power_ctx.dev_ctx_table == NULL)
+ return FWK_E_NOMEM;
if (system_power_ctx.config->ext_ppus_count > 0) {
system_power_ctx.ext_ppu_apis = fwk_mm_calloc(
@@ -285,12 +326,37 @@ static int system_power_mod_init(fwk_id_t module_id,
return FWK_SUCCESS;
}
+static int system_power_mod_element_init(fwk_id_t element_id,
+ unsigned int unused,
+ const void *data)
+{
+ struct system_power_dev_ctx *dev_ctx;
+
+ fwk_assert(data != NULL);
+
+ dev_ctx =
+ system_power_ctx.dev_ctx_table + fwk_id_get_element_idx(element_id);
+
+ dev_ctx->config = data;
+
+ /* Ensure a system state table is provided */
+ if (dev_ctx->config->sys_state_table == NULL)
+ return FWK_E_DATA;
+
+ return FWK_SUCCESS;
+}
+
static int system_power_bind(fwk_id_t id, unsigned int round)
{
int status;
unsigned int i;
+ const struct mod_system_power_config *config;
+ struct system_power_dev_ctx *dev_ctx;
if (round == 1) {
+ if (!fwk_id_is_type(id, FWK_ID_TYPE_MODULE))
+ return FWK_SUCCESS;
+
/*
* During the first round of binding, the power domain module should
* have bound to the power domain driver API provided by the present
@@ -303,50 +369,49 @@ static int system_power_bind(fwk_id_t id, unsigned int round)
&system_power_ctx.mod_pd_driver_input_api);
}
- status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG),
- FWK_ID_API(FWK_MODULE_IDX_LOG, 0), &system_power_ctx.log_api);
- if (status != FWK_SUCCESS)
- return status;
+ if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
+ status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG),
+ FWK_ID_API(FWK_MODULE_IDX_LOG, 0), &system_power_ctx.log_api);
+ if (status != FWK_SUCCESS)
+ return status;
- status = fwk_module_bind(system_power_ctx.config->ppu_sys0_id,
- system_power_ctx.config->ppu_sys_api_id,
- &system_power_ctx.sys0_api);
- if (status != FWK_SUCCESS)
- return status;
+ config = system_power_ctx.config;
- status = fwk_module_bind(system_power_ctx.config->ppu_sys1_id,
- system_power_ctx.config->ppu_sys_api_id,
- &system_power_ctx.sys1_api);
- if (status != FWK_SUCCESS)
- return status;
+ for (i = 0; i < config->ext_ppus_count; i++) {
+ status = fwk_module_bind(
+ config->ext_ppus[i].ppu_id,
+ config->ext_ppus[i].api_id,
+ &system_power_ctx.ext_ppu_apis[i]);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
- for (i = 0; i < system_power_ctx.config->ext_ppus_count; i++) {
- status = fwk_module_bind(
- system_power_ctx.config->ext_ppus[i].ppu_id,
- system_power_ctx.config->ext_ppus[i].api_id,
- &system_power_ctx.ext_ppu_apis[i]);
+ status = fwk_module_bind(config->driver_id,
+ config->driver_api_id,
+ &system_power_ctx.driver_api);
if (status != FWK_SUCCESS)
return status;
- }
- status = fwk_module_bind(system_power_ctx.config->driver_id,
- system_power_ctx.config->driver_api_id, &system_power_ctx.driver_api);
- if (status != FWK_SUCCESS)
- return status;
+ return fwk_module_bind(fwk_module_id_power_domain,
+ mod_pd_api_id_restricted,
+ &system_power_ctx.mod_pd_restricted_api);
+ }
- status = fwk_module_bind(fwk_module_id_power_domain,
- mod_pd_api_id_restricted,
- &system_power_ctx.mod_pd_restricted_api);
- if (status != FWK_SUCCESS)
- return status;
+ dev_ctx = system_power_ctx.dev_ctx_table + fwk_id_get_element_idx(id);
- return FWK_SUCCESS;
+ return fwk_module_bind(dev_ctx->config->sys_ppu_id,
+ dev_ctx->config->api_id,
+ &dev_ctx->sys_ppu_api);
}
static int system_power_process_bind_request(fwk_id_t requester_id,
- fwk_id_t pd_id, fwk_id_t api_id,
- const void **api)
+ fwk_id_t pd_id,
+ fwk_id_t api_id,
+ const void **api)
{
+ unsigned int dev_idx;
+ struct system_power_dev_ctx *dev_ctx;
+
if (fwk_id_is_equal(api_id, mod_system_power_api_id_pd_driver)) {
if (!fwk_id_is_equal(fwk_id_build_module_id(requester_id),
@@ -356,11 +421,21 @@ static int system_power_process_bind_request(fwk_id_t requester_id,
*api = &system_power_power_domain_driver_api;
system_power_ctx.mod_pd_system_id = requester_id;
} else {
- if (!fwk_id_is_equal(requester_id,
- system_power_ctx.config->ppu_sys0_id) &&
- !fwk_id_is_equal(requester_id,
- system_power_ctx.config->ppu_sys1_id))
+ for (dev_idx = 0; dev_idx < system_power_ctx.dev_count; dev_idx++) {
+ dev_ctx = &system_power_ctx.dev_ctx_table[dev_idx];
+
+ /*
+ * If requester_id refers to a system PPU configured by any one of
+ * our elements, break when dev_idx reaches that element.
+ */
+ if (fwk_id_is_equal(requester_id, dev_ctx->config->sys_ppu_id))
+ break;
+ }
+ if (dev_idx >= system_power_ctx.dev_count) {
+ /* Requester_id does not refer to any configured system PPU */
return FWK_E_ACCESS;
+ }
+
*api = &system_power_power_domain_driver_input_api;
}
@@ -370,7 +445,6 @@ static int system_power_process_bind_request(fwk_id_t requester_id,
static int system_power_start(fwk_id_t id)
{
int status;
- unsigned int state;
if (system_power_ctx.driver_api->platform_interrupts != NULL) {
status = system_power_ctx.driver_api->platform_interrupts(
@@ -379,24 +453,9 @@ static int system_power_start(fwk_id_t id)
return status;
}
- status = system_power_ctx.sys1_api->get_state
- (system_power_ctx.config->ppu_sys1_id, &state);
- if (status != FWK_SUCCESS)
- return status;
-
- if (state == MOD_PD_STATE_OFF) {
- system_power_ctx.state = MOD_PD_STATE_OFF;
- return FWK_SUCCESS;
- }
-
- status = system_power_ctx.sys0_api->get_state
- (system_power_ctx.config->ppu_sys0_id, &state);
- if (status != FWK_SUCCESS)
- return status;
-
- system_power_ctx.state = (state == MOD_PD_STATE_ON) ?
- MOD_PD_STATE_ON :
- MOD_SYSTEM_POWER_POWER_STATE_SLEEP0;
+ /* Configure initial power state */
+ system_power_ctx.state =
+ (unsigned int)system_power_ctx.config->initial_system_power_state;
return FWK_SUCCESS;
}
@@ -406,6 +465,7 @@ const struct fwk_module module_system_power = {
.type = FWK_MODULE_TYPE_DRIVER,
.api_count = MOD_SYSTEM_POWER_API_COUNT,
.init = system_power_mod_init,
+ .element_init = system_power_mod_element_init,
.bind = system_power_bind,
.start = system_power_start,
.process_bind_request = system_power_process_bind_request,