aboutsummaryrefslogtreecommitdiff
path: root/product/morello
diff options
context:
space:
mode:
authorAnurag Koul <anurag.koul@arm.com>2020-06-08 02:59:17 +0100
committerjimqui01 <54316584+jimqui01@users.noreply.github.com>2020-09-15 17:03:53 +0100
commitca4748098fda8e2a22d102e1f45c59ebe2c95d6c (patch)
treed0735ed336a981e9fe59712eed7cfbd9c47e58e5 /product/morello
parent413e91b737cd7a2e474baf165158097ed82249fc (diff)
morello/scp_ramfw_fvp: add power mgmt config data
Define and add configs for system power domains, PPUs, etc. Change-Id: Ibad28c2efc703837f32e0a1e76059aa53ff95320 Signed-off-by: Anurag Koul <anurag.koul@arm.com>
Diffstat (limited to 'product/morello')
-rw-r--r--product/morello/scp_ramfw_fvp/config_power_domain.c231
-rw-r--r--product/morello/scp_ramfw_fvp/config_power_domain.h29
-rw-r--r--product/morello/scp_ramfw_fvp/config_ppu_v0.c43
-rw-r--r--product/morello/scp_ramfw_fvp/config_ppu_v0.h13
-rw-r--r--product/morello/scp_ramfw_fvp/config_ppu_v1.c178
-rw-r--r--product/morello/scp_ramfw_fvp/config_system_power.c100
6 files changed, 594 insertions, 0 deletions
diff --git a/product/morello/scp_ramfw_fvp/config_power_domain.c b/product/morello/scp_ramfw_fvp/config_power_domain.c
new file mode 100644
index 00000000..a27c9a27
--- /dev/null
+++ b/product/morello/scp_ramfw_fvp/config_power_domain.c
@@ -0,0 +1,231 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "config_power_domain.h"
+#include "config_ppu_v0.h"
+#include "morello_core.h"
+#include "morello_power_domain.h"
+
+#include <mod_power_domain.h>
+#include <mod_ppu_v1.h>
+#include <mod_system_power.h>
+
+#include <fwk_element.h>
+#include <fwk_id.h>
+#include <fwk_macros.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Maximum power domain name size including the null terminator */
+#define PD_NAME_SIZE 16
+
+/* Mask of the allowed states for the systop power domain */
+static const uint32_t systop_allowed_state_mask_table[] = {
+ [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK,
+ [MOD_PD_STATE_ON] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_ON_MASK |
+ (1 << MOD_SYSTEM_POWER_POWER_STATE_SLEEP0) |
+ (1 << MOD_SYSTEM_POWER_POWER_STATE_SLEEP1)
+};
+
+/*
+ * Mask of the allowed states for the top level power domains
+ * (but the cluster power domains) depending on the system states.
+ */
+static const uint32_t toplevel_allowed_state_mask_table[] = {
+ [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK,
+ [MOD_PD_STATE_ON] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_ON_MASK,
+ [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = MOD_PD_STATE_OFF_MASK,
+ [MOD_SYSTEM_POWER_POWER_STATE_SLEEP1] = MOD_PD_STATE_OFF_MASK
+};
+
+/*
+ * Mask of the allowed states for the cluster power domain depending on the
+ * system states.
+ */
+static const uint32_t cluster_pd_allowed_state_mask_table[] = {
+ [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
+ [MOD_PD_STATE_ON] = MORELLO_CLUSTER_VALID_STATE_MASK,
+ [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = MOD_PD_STATE_OFF_MASK,
+ [MOD_SYSTEM_POWER_POWER_STATE_SLEEP1] = MOD_PD_STATE_OFF_MASK
+};
+
+/* Mask of the allowed states for a core depending on the cluster states. */
+static const uint32_t core_pd_allowed_state_mask_table[] = {
+ [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
+ [MOD_PD_STATE_ON] = MORELLO_CORE_VALID_STATE_MASK,
+ [MOD_PD_STATE_SLEEP] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
+ [MORELLO_POWER_DOMAIN_STATE_FUNC_RET] = MORELLO_CORE_VALID_STATE_MASK,
+ [MORELLO_POWER_DOMAIN_STATE_MEM_RET] = MOD_PD_STATE_OFF_MASK
+};
+
+/* Power module specific configuration data (none) */
+static const struct mod_power_domain_config morello_power_domain_config = { 0 };
+
+/* Power domain element table pointer */
+struct fwk_element *element_table = NULL;
+
+/* Power domain element configuration table pointer */
+struct mod_power_domain_element_config *pd_config_table = NULL;
+
+/*
+ * The SCP's view of PD tree in a single chip mode looks like below:
+ *
+ * ---SYSTOP0--
+ * / | \
+ * / | \
+ * / | \
+ * CLUS0 CLUS1 DBGTOP0
+ * / \ / \
+ * CPU0--CPU1--CPU2--CPU3
+ *
+ */
+
+static struct fwk_element morello_pd_single_chip_element_table[] = {
+ [PD_SINGLE_CHIP_IDX_CLUS0CORE0] =
+ {
+ .name = "CLUS0CORE0",
+ .data = &((struct mod_power_domain_element_config){
+ .attributes.pd_type = MOD_PD_TYPE_CORE,
+ .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER0,
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 0),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .allowed_state_mask_table = core_pd_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_CLUS0CORE1] =
+ {
+ .name = "CLUS0CORE1",
+ .data = &((struct mod_power_domain_element_config){
+ .attributes.pd_type = MOD_PD_TYPE_CORE,
+ .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER0,
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 1),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .allowed_state_mask_table = core_pd_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_CLUS1CORE0] =
+ {
+ .name = "CLUS1CORE0",
+ .data = &((struct mod_power_domain_element_config){
+ .attributes.pd_type = MOD_PD_TYPE_CORE,
+ .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER1,
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 2),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .allowed_state_mask_table = core_pd_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_CLUS1CORE1] =
+ {
+ .name = "CLUS1CORE1",
+ .data = &((struct mod_power_domain_element_config){
+ .attributes.pd_type = MOD_PD_TYPE_CORE,
+ .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER1,
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 3),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .allowed_state_mask_table = core_pd_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_CLUSTER0] =
+ {
+ .name = "CLUS0",
+ .data = &((struct mod_power_domain_element_config){
+ .attributes.pd_type = MOD_PD_TYPE_CLUSTER,
+ .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 4),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .allowed_state_mask_table = cluster_pd_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(cluster_pd_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_CLUSTER1] =
+ {
+ .name = "CLUS1",
+ .data = &((struct mod_power_domain_element_config){
+ .attributes.pd_type = MOD_PD_TYPE_CLUSTER,
+ .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 5),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .allowed_state_mask_table = cluster_pd_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(cluster_pd_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_DBGTOP0] =
+ {
+ .name = "DBGTOP0",
+ .data =
+ &(
+ (struct mod_power_domain_element_config){
+ .attributes.pd_type = MOD_PD_TYPE_DEVICE_DEBUG,
+ .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
+ .driver_id =
+ FWK_ID_ELEMENT_INIT(
+ FWK_MODULE_IDX_PPU_V0,
+ PPU_V0_ELEMENT_IDX_DBGTOP),
+ .api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_PPU_V0, 0),
+ .allowed_state_mask_table =
+ toplevel_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(
+ toplevel_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_SYSTOP0] =
+ {
+ .name = "SYSTOP0",
+ .data = &((struct mod_power_domain_element_config){ .attributes.pd_type = MOD_PD_TYPE_SYSTEM,
+ .parent_idx = PD_SINGLE_CHIP_IDX_NONE,
+ .driver_id =
+ FWK_ID_MODULE_INIT(
+ FWK_MODULE_IDX_SYSTEM_POWER),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_SYSTEM_POWER,
+ MOD_SYSTEM_POWER_API_IDX_PD_DRIVER),
+ .allowed_state_mask_table =
+ systop_allowed_state_mask_table,
+ .allowed_state_mask_table_size =
+ FWK_ARRAY_SIZE(
+ systop_allowed_state_mask_table) }),
+ },
+ [PD_SINGLE_CHIP_IDX_COUNT] = { 0 },
+};
+
+/*
+ * Function definitions with internal linkage
+ */
+static const struct fwk_element *morello_power_domain_get_element_table(
+ fwk_id_t module_id)
+{
+ return morello_pd_single_chip_element_table;
+}
+
+/*
+ * Power module configuration data
+ */
+const struct fwk_module_config config_power_domain = {
+ .elements =
+ FWK_MODULE_DYNAMIC_ELEMENTS(morello_power_domain_get_element_table),
+ .data = &morello_power_domain_config,
+};
diff --git a/product/morello/scp_ramfw_fvp/config_power_domain.h b/product/morello/scp_ramfw_fvp/config_power_domain.h
new file mode 100644
index 00000000..75b1bccd
--- /dev/null
+++ b/product/morello/scp_ramfw_fvp/config_power_domain.h
@@ -0,0 +1,29 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONFIG_POWER_DOMAIN_H
+#define CONFIG_POWER_DOMAIN_H
+
+#include <stdint.h>
+
+/*
+ * Power domain indices in single chip use case
+ */
+enum pd_single_chip_idx {
+ PD_SINGLE_CHIP_IDX_CLUS0CORE0,
+ PD_SINGLE_CHIP_IDX_CLUS0CORE1,
+ PD_SINGLE_CHIP_IDX_CLUS1CORE0,
+ PD_SINGLE_CHIP_IDX_CLUS1CORE1,
+ PD_SINGLE_CHIP_IDX_CLUSTER0,
+ PD_SINGLE_CHIP_IDX_CLUSTER1,
+ PD_SINGLE_CHIP_IDX_DBGTOP0,
+ PD_SINGLE_CHIP_IDX_SYSTOP0,
+ PD_SINGLE_CHIP_IDX_COUNT,
+ PD_SINGLE_CHIP_IDX_NONE = UINT32_MAX
+};
+
+#endif /* CONFIG_POWER_DOMAIN_H */
diff --git a/product/morello/scp_ramfw_fvp/config_ppu_v0.c b/product/morello/scp_ramfw_fvp/config_ppu_v0.c
new file mode 100644
index 00000000..8aa56118
--- /dev/null
+++ b/product/morello/scp_ramfw_fvp/config_ppu_v0.c
@@ -0,0 +1,43 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "config_ppu_v0.h"
+#include "morello_scp_mmap.h"
+
+#include <mod_power_domain.h>
+#include <mod_ppu_v0.h>
+
+#include <fwk_element.h>
+#include <fwk_id.h>
+#include <fwk_module.h>
+
+#include <stdbool.h>
+
+static struct fwk_element ppu_v0_element_table[] = {
+ [PPU_V0_ELEMENT_IDX_DBGTOP] =
+ {
+ .name = "DBGTOP",
+ .data = &((struct mod_ppu_v0_pd_config){
+ .pd_type = MOD_PD_TYPE_DEVICE_DEBUG,
+ .ppu.reg_base = SCP_PPU_DEBUG_BASE,
+ .default_power_on = true,
+ }),
+ },
+ [PPU_V0_ELEMENT_IDX_COUNT] = { 0 }, /* Termination entry */
+};
+
+static const struct fwk_element *ppu_v0_get_element_table(fwk_id_t module_id)
+{
+ return ppu_v0_element_table;
+}
+
+/*
+ * Power module configuration data
+ */
+const struct fwk_module_config config_ppu_v0 = {
+ .elements = FWK_MODULE_DYNAMIC_ELEMENTS(ppu_v0_get_element_table),
+};
diff --git a/product/morello/scp_ramfw_fvp/config_ppu_v0.h b/product/morello/scp_ramfw_fvp/config_ppu_v0.h
new file mode 100644
index 00000000..409d7cd0
--- /dev/null
+++ b/product/morello/scp_ramfw_fvp/config_ppu_v0.h
@@ -0,0 +1,13 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONFIG_PPU_V0_H
+#define CONFIG_PPU_V0_H
+
+enum ppu_v0_element_idx { PPU_V0_ELEMENT_IDX_DBGTOP, PPU_V0_ELEMENT_IDX_COUNT };
+
+#endif /* CONFIG_PPU_V0_H */
diff --git a/product/morello/scp_ramfw_fvp/config_ppu_v1.c b/product/morello/scp_ramfw_fvp/config_ppu_v1.c
new file mode 100644
index 00000000..21fc8b43
--- /dev/null
+++ b/product/morello/scp_ramfw_fvp/config_ppu_v1.c
@@ -0,0 +1,178 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "config_power_domain.h"
+#include "morello_core.h"
+#include "morello_scp_mmap.h"
+
+#include <mod_cmn_skeena.h>
+#include <mod_power_domain.h>
+#include <mod_ppu_v1.h>
+
+#include <fwk_assert.h>
+#include <fwk_element.h>
+#include <fwk_id.h>
+#include <fwk_interrupt.h>
+#include <fwk_macros.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Maximum PPU core name size including the null terminator */
+#define PPU_CORE_NAME_SIZE 16
+
+/* Maximum PPU cluster name size including the null terminator */
+#define PPU_CLUS_NAME_SIZE 8
+
+/* Lookup table for translating cluster indicies into CMN_SKEENA node IDs */
+static const unsigned int cluster_idx_to_node_id[] = { 192, 140 };
+
+/* Module configuration data */
+static struct mod_ppu_v1_config ppu_v1_config_data = {
+ .pd_notification_id = FWK_ID_NOTIFICATION_INIT(
+ FWK_MODULE_IDX_POWER_DOMAIN,
+ MOD_PD_NOTIFICATION_IDX_POWER_STATE_TRANSITION),
+};
+
+static struct fwk_element ppu_v1_system_element_table[] = {
+ [0] =
+ {
+ .name = "SYS0",
+ .data = &((struct mod_ppu_v1_pd_config){
+ .pd_type = MOD_PD_TYPE_SYSTEM,
+ .ppu.reg_base = SCP_PPU_SYS0_BASE,
+ .observer_id = FWK_ID_NONE_INIT,
+ .default_power_on = true,
+ }),
+ },
+ [1] =
+ {
+ .name = "SYS1",
+ .data = &((struct mod_ppu_v1_pd_config){
+ .pd_type = MOD_PD_TYPE_SYSTEM,
+ .ppu.reg_base = SCP_PPU_SYS1_BASE,
+ .observer_id = FWK_ID_NONE_INIT,
+ .default_power_on = true,
+ }),
+ },
+};
+
+static const struct fwk_element *ppu_v1_get_element_table(fwk_id_t module_id)
+{
+ struct fwk_element *element_table, *element;
+ struct mod_ppu_v1_pd_config *pd_config_table, *pd_config;
+ unsigned int core_idx;
+ unsigned int cluster_idx;
+ unsigned int core_count;
+ unsigned int cluster_count;
+ unsigned int core_element_count = 0;
+
+ core_count = morello_core_get_core_count();
+ cluster_count = morello_core_get_cluster_count();
+
+ assert(cluster_count == FWK_ARRAY_SIZE(cluster_idx_to_node_id));
+
+ /*
+ * Allocate element descriptors based on:
+ * Number of cores
+ * + Number of cluster descriptors
+ * + Number of system power domain descriptors
+ * + 1 terminator descriptor
+ */
+ element_table = fwk_mm_calloc(
+ core_count + cluster_count +
+ FWK_ARRAY_SIZE(ppu_v1_system_element_table) + 1,
+ sizeof(struct fwk_element));
+ if (element_table == NULL)
+ return NULL;
+
+ pd_config_table = fwk_mm_calloc(
+ core_count + cluster_count, sizeof(struct mod_ppu_v1_pd_config));
+ if (pd_config_table == NULL)
+ return NULL;
+
+ for (cluster_idx = 0; cluster_idx < cluster_count; cluster_idx++) {
+ for (core_idx = 0;
+ core_idx < morello_core_get_core_per_cluster_count(cluster_idx);
+ core_idx++) {
+ element = &element_table[core_element_count];
+ pd_config = &pd_config_table[core_element_count];
+
+ element->name = fwk_mm_alloc(PPU_CORE_NAME_SIZE, 1);
+ if (element->name == NULL)
+ return NULL;
+
+ snprintf(
+ (char *)element->name,
+ PPU_CORE_NAME_SIZE,
+ "CLUS%uCORE%u",
+ (uint8_t)cluster_idx,
+ (uint8_t)core_idx);
+
+ element->data = pd_config;
+
+ pd_config->pd_type = MOD_PD_TYPE_CORE;
+ pd_config->ppu.reg_base = SCP_PPU_CORE_BASE(cluster_idx, core_idx);
+ pd_config->ppu.irq = FWK_INTERRUPT_NONE;
+ pd_config->cluster_id = FWK_ID_ELEMENT(
+ FWK_MODULE_IDX_PPU_V1, (core_count + cluster_idx));
+ pd_config->observer_id = FWK_ID_NONE;
+ core_element_count++;
+ }
+
+ element = &element_table[core_count + cluster_idx];
+ pd_config = &pd_config_table[core_count + cluster_idx];
+
+ element->name = fwk_mm_alloc(PPU_CLUS_NAME_SIZE, 1);
+ if (element->name == NULL)
+ return NULL;
+
+ snprintf(
+ (char *)element->name,
+ PPU_CLUS_NAME_SIZE,
+ "CLUS%u",
+ (uint8_t)cluster_idx);
+
+ element->data = pd_config;
+
+ pd_config->pd_type = MOD_PD_TYPE_CLUSTER;
+ pd_config->ppu.reg_base = SCP_PPU_CLUSTER_BASE(cluster_idx);
+ pd_config->ppu.irq = FWK_INTERRUPT_NONE;
+ pd_config->observer_id = fwk_module_id_cmn_skeena;
+ pd_config->observer_api = FWK_ID_API(
+ FWK_MODULE_IDX_CMN_SKEENA, MOD_CMN_SKEENA_API_IDX_PPU_OBSERVER);
+ pd_config->post_ppu_on_param =
+ (void *)&cluster_idx_to_node_id[cluster_idx];
+ }
+
+ memcpy(
+ &element_table[core_count + cluster_count],
+ ppu_v1_system_element_table,
+ sizeof(ppu_v1_system_element_table));
+
+ /*
+ * Configure pd_source_id with the SYSTOP identifier from the power domain
+ * module which is dynamically defined based on the number of cores.
+ */
+ ppu_v1_config_data.pd_source_id = fwk_id_build_element_id(
+ fwk_module_id_power_domain, PD_SINGLE_CHIP_IDX_SYSTOP0);
+
+ return element_table;
+}
+
+/*
+ * Power module configuration data
+ */
+const struct fwk_module_config config_ppu_v1 = {
+ .elements = FWK_MODULE_DYNAMIC_ELEMENTS(ppu_v1_get_element_table),
+ .data = &ppu_v1_config_data,
+};
diff --git a/product/morello/scp_ramfw_fvp/config_system_power.c b/product/morello/scp_ramfw_fvp/config_system_power.c
new file mode 100644
index 00000000..2f4c79d9
--- /dev/null
+++ b/product/morello/scp_ramfw_fvp/config_system_power.c
@@ -0,0 +1,100 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "morello_core.h"
+
+#include <mod_morello_system.h>
+#include <mod_power_domain.h>
+#include <mod_ppu_v1.h>
+#include <mod_system_power.h>
+
+#include <fwk_element.h>
+#include <fwk_id.h>
+#include <fwk_macros.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+
+#include <fmw_cmsis.h>
+
+#include <stdint.h>
+
+static const uint8_t system_power_to_sys_ppu0_state[] = {
+ [MOD_PD_STATE_ON] = (uint8_t)MOD_PD_STATE_ON,
+ [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = (uint8_t)MOD_PD_STATE_OFF,
+ [MOD_PD_STATE_OFF] = (uint8_t)MOD_PD_STATE_OFF,
+};
+
+static const uint8_t system_power_to_sys_ppu1_state[] = {
+ [MOD_PD_STATE_ON] = (uint8_t)MOD_PD_STATE_ON,
+ [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = (uint8_t)MOD_PD_STATE_ON,
+ [MOD_PD_STATE_OFF] = (uint8_t)MOD_PD_STATE_OFF,
+};
+
+static struct fwk_element system_power_element_table[] = {
+ [0] =
+ {
+ .name = "SYS-PPU-0",
+ .data = &((struct mod_system_power_dev_config){
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .sys_state_table = system_power_to_sys_ppu0_state,
+ }),
+ },
+
+ [1] =
+ {
+ .name = "SYS-PPU-1",
+ .data = &((struct mod_system_power_dev_config){
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_PPU_V1,
+ MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
+ .sys_state_table = system_power_to_sys_ppu1_state,
+ }),
+ },
+
+ [2] = { 0 }, /* Termination description */
+};
+
+static struct mod_system_power_config system_power_config = {
+ .soc_wakeup_irq = SCP_EXT_IRQ,
+
+ /* System driver */
+ .driver_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_MORELLO_SYSTEM),
+ .driver_api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_MORELLO_SYSTEM,
+ MOD_MORELLO_SYSTEM_API_IDX_SYSTEM_POWER_DRIVER),
+
+ /* Initial system state */
+ .initial_system_power_state = MOD_PD_STATE_OFF,
+};
+
+static const struct fwk_element *morello_system_get_element_table(
+ fwk_id_t unused)
+{
+ struct mod_system_power_dev_config *dev_config_table;
+ unsigned int i;
+
+ /* The system PPUs are placed after the core and cluster PPUs */
+ unsigned int ppu_idx_base =
+ morello_core_get_core_count() + morello_core_get_cluster_count();
+
+ for (i = 0; i < (FWK_ARRAY_SIZE(system_power_element_table) - 1); i++) {
+ dev_config_table =
+ (struct mod_system_power_dev_config *)system_power_element_table[i]
+ .data;
+ dev_config_table->sys_ppu_id =
+ fwk_id_build_element_id(fwk_module_id_ppu_v1, ppu_idx_base + i);
+ }
+
+ return system_power_element_table;
+}
+
+const struct fwk_module_config config_system_power = {
+ .elements = FWK_MODULE_DYNAMIC_ELEMENTS(morello_system_get_element_table),
+ .data = &system_power_config,
+};