aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Royer <nroyer@baylibre.com>2020-09-27 17:40:12 +0200
committernicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com>2020-10-15 17:45:38 +0100
commitadede9b959dcf97d585b67aa210081bbd89d2f47 (patch)
tree7486f040b5bd0298f3c068f56a722d462d27ab44
parent0bc640fd693982bbadee44e6a0d50c95596f4dd1 (diff)
rcar/module: add rcar pd_core module and config data
Change-Id: Iaec89b1b8d61222d836c02bc31313b3fc98a55f6 Signed-off-by: Tsutomu Muroya <tsutomu.muroya.jy@bp.renesas.com> Signed-off-by: Nicolas Royer <nroyer@baylibre.com>
-rw-r--r--product/rcar/module/rcar_pd_core/include/mod_rcar_pd_core.h191
-rw-r--r--product/rcar/module/rcar_pd_core/src/Makefile11
-rw-r--r--product/rcar/module/rcar_pd_core/src/mod_rcar_pd_core.c402
-rw-r--r--product/rcar/module/rcar_pd_core/src/rcar_pd_core.c128
-rw-r--r--product/rcar/module/rcar_pd_core/src/rcar_pd_core.h40
-rw-r--r--product/rcar/scp_ramfw/config_rcar_pd_core.c156
-rw-r--r--product/rcar/scp_ramfw/config_rcar_pd_core.h27
7 files changed, 955 insertions, 0 deletions
diff --git a/product/rcar/module/rcar_pd_core/include/mod_rcar_pd_core.h b/product/rcar/module/rcar_pd_core/include/mod_rcar_pd_core.h
new file mode 100644
index 00000000..31c2505c
--- /dev/null
+++ b/product/rcar/module/rcar_pd_core/include/mod_rcar_pd_core.h
@@ -0,0 +1,191 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MOD_RCAR_PD_CORE_H
+#define MOD_RCAR_PD_CORE_H
+
+#include <mod_rcar_power_domain.h>
+
+#include <fwk_id.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define CORE_PER_CLUSTER_COUNT_MAX 8
+
+/*!
+ * \addtogroup GroupRCARModule RCAR Product Modules
+ * @{
+ */
+
+/*!
+ * \defgroup GroupRCARPdCore PD Core
+ * @{
+ */
+
+/*!
+ * \brief Indexes of the interfaces exposed by the module.
+ */
+enum mod_rcar_ps_sysc_api_idx {
+ /*! Power domain driver API */
+ MOD_RCAR_PD_SYSC_API_IDX_POWER_DOMAIN_DRIVER,
+ /*! interrupt Service Routine driver API */
+ MOD_RCAR_PD_SYSC_API_IDX_ISR,
+ /*! System boot API */
+ MOD_RCAR_PD_SYSC_API_IDX_BOOT,
+ /*! Number of exposed interfaces */
+ MOD_RCAR_PD_SYSC_API_IDX_COUNT,
+};
+
+/*!
+ * \brief Power domain descriptor.
+ */
+struct mod_rcar_pd_sysc {
+ /*! Base address of the registers */
+ uintptr_t reg_base;
+};
+
+/*!
+ * \brief core module configuration
+ */
+struct mod_rcar_pd_core_config {
+ /*! Identifier of the power domain notification to register elements for */
+ const fwk_id_t pd_notification_id;
+
+ /*!
+ * Identifier of the source module or element that is expected to send power
+ * domain notifications.
+ */
+ fwk_id_t pd_source_id;
+};
+
+/*!
+ * \brief Configuration data of a power domain of the sysc driver module.
+ */
+struct mod_rcar_pd_core_pd_config {
+ /*! Power domain type */
+ enum mod_pd_type pd_type;
+
+ /*! descriptor */
+ struct mod_rcar_pd_sysc ppu;
+
+ /*!
+ * In the case of a core power domain, identifier of the cluster power
+ * domain it belongs to. If the power domain is not a core power domain,
+ * the value of this field is undefined.
+ */
+ fwk_id_t cluster_id;
+
+ /*!
+ * Flag indicating if this domain should be powered on during element
+ * init. This flag is only supported for device and system PPUs and should
+ * not be set for any other type.
+ */
+ bool default_power_on;
+
+ /*!
+ * \brief Identifier of an entity wishing to be notified when the
+ * transitions out of the OFF state.
+ *
+ * \note This field may be set to \ref FWK_ID_NONE, in which case no
+ * observer will be set.
+ */
+ fwk_id_t observer_id;
+
+ /*!
+ * \brief Identifier of the power state observer API implemented by
+ * \ref observer_id.
+ */
+ fwk_id_t observer_api;
+};
+
+/*!
+ * \brief SYSC Power State Observer API.
+ *
+ * \details This API should be implemented by any modules that should be
+ * notified when a changes state.
+ */
+struct mod_rcar_pd_sysc_power_state_observer_api {
+ /*!
+ * \brief Called after a has turned on.
+ *
+ * \param param Generic configurable parameter.
+ */
+ void (*post_ppu_on)(void *param);
+};
+
+/*!
+ * @cond
+ */
+
+/* Power domain context */
+struct rcar_pd_sysc_pd_ctx {
+ /* Power domain configuration data */
+ const struct mod_rcar_pd_core_pd_config *config;
+
+ /* Identifier of the entity bound to the power domain driver API */
+ fwk_id_t bound_id;
+
+ /* Power module driver input API */
+ struct mod_pd_driver_input_api *pd_driver_input_api;
+
+ /* Context of the parent power domain (used only for core power domains) */
+ struct rcar_pd_sysc_pd_ctx *parent_pd_ctx;
+
+ /* Pointer to the power state observer API */
+ const struct mod_rcar_pd_sysc_power_state_observer_api *observer_api;
+
+ /* Context data specific to the type of power domain */
+ void *data;
+ /* Power Domain current state*/
+ unsigned int current_state;
+};
+
+/* Cluster power domain specific context */
+struct rcar_pd_sysc_cluster_pd_ctx {
+ /*
+ * Table of pointers to the contexts of the cores being part of the
+ * cluster.
+ */
+ struct rcar_pd_sysc_pd_ctx *core_pd_ctx_table[CORE_PER_CLUSTER_COUNT_MAX];
+
+ /* Number of cores */
+ unsigned int core_count;
+};
+
+/* Module context */
+struct rcar_pd_sysc_ctx {
+ /* Table of the power domain contexts */
+ struct rcar_pd_sysc_pd_ctx *pd_ctx_table;
+
+ /* Number of power domains */
+ size_t pd_ctx_table_size;
+
+ /* Log API */
+ struct mod_log_api *log_api;
+};
+
+/*
+ * Internal variables
+ */
+
+#define MODE_UNSUPPORTED ~0U
+
+/*!
+ * @endcond
+ */
+
+/*!
+ * @}
+ */
+
+/*!
+ * @}
+ */
+
+#endif /* MOD_RCAR_PD_CORE_H */
diff --git a/product/rcar/module/rcar_pd_core/src/Makefile b/product/rcar/module/rcar_pd_core/src/Makefile
new file mode 100644
index 00000000..a0511412
--- /dev/null
+++ b/product/rcar/module/rcar_pd_core/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Renesas SCP/MCP Software
+# Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := RCAR_PD_CORE
+BS_LIB_SOURCES = rcar_pd_core.c mod_rcar_pd_core.c
+
+include $(BS_DIR)/lib.mk
diff --git a/product/rcar/module/rcar_pd_core/src/mod_rcar_pd_core.c b/product/rcar/module/rcar_pd_core/src/mod_rcar_pd_core.c
new file mode 100644
index 00000000..646d9f78
--- /dev/null
+++ b/product/rcar/module/rcar_pd_core/src/mod_rcar_pd_core.c
@@ -0,0 +1,402 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mmio.h>
+#include <rcar_mmap.h>
+#include <rcar_pd_core.h>
+
+#include <mod_rcar_pd_core.h>
+#include <mod_rcar_power_domain.h>
+#include <mod_system_power.h>
+
+#include <fwk_assert.h>
+#include <fwk_id.h>
+#include <fwk_interrupt.h>
+#include <fwk_log.h>
+#include <fwk_macros.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <fwk_notification.h>
+
+#include <arch_system.h>
+
+#include <stdbool.h>
+
+static struct rcar_pd_sysc_ctx rcar_pd_sysc_ctx;
+
+/*
+ * Functions not specific to any type of power domain
+ */
+
+static int rcar_pd_set_state(fwk_id_t pd_id, unsigned int state)
+{
+ struct rcar_pd_sysc_pd_ctx *pd_ctx;
+ unsigned int core;
+
+ pd_ctx = rcar_pd_sysc_ctx.pd_ctx_table + fwk_id_get_element_idx(pd_id);
+ core = fwk_id_get_element_idx(pd_id);
+
+ switch (state) {
+ case MOD_PD_STATE_ON:
+ rcar_pwrc_cpuon(core);
+ pd_ctx->current_state = state;
+ break;
+
+ case MOD_PD_STATE_OFF:
+ rcar_pwrc_cpuoff(core);
+ pd_ctx->current_state = state;
+ break;
+
+ default:
+ FWK_LOG_ERR("[PD] Requested power state (%i) is not supported.", state);
+ return FWK_E_PARAM;
+ }
+
+ return FWK_SUCCESS;
+}
+
+static int rcar_pd_get_state(fwk_id_t pd_id, unsigned int *state)
+{
+ struct rcar_pd_sysc_pd_ctx *pd_ctx;
+
+ pd_ctx = rcar_pd_sysc_ctx.pd_ctx_table + fwk_id_get_element_idx(pd_id);
+
+ *state = pd_ctx->current_state;
+ return FWK_SUCCESS;
+}
+
+static int rcar_pd_reset(fwk_id_t pd_id)
+{
+ return FWK_SUCCESS;
+}
+
+static const struct mod_pd_driver_api pd_driver = {
+ .set_state = rcar_pd_set_state,
+ .get_state = rcar_pd_get_state,
+ .reset = rcar_pd_reset,
+};
+
+/*
+ * Functions specific to core power domains
+ */
+static int rcar_core_pd_init(struct rcar_pd_sysc_pd_ctx *pd_ctx)
+{
+ return FWK_SUCCESS;
+}
+
+static int rcar_core_pd_set_state(fwk_id_t core_pd_id, unsigned int state)
+{
+ struct rcar_pd_sysc_pd_ctx *pd_ctx;
+ unsigned int core;
+
+ pd_ctx = rcar_pd_sysc_ctx.pd_ctx_table + fwk_id_get_element_idx(core_pd_id);
+ core = fwk_id_get_element_idx(core_pd_id);
+
+ switch (state) {
+ case MOD_PD_STATE_OFF:
+ rcar_pwrc_cpuoff(core);
+ pd_ctx->current_state = state;
+ break;
+
+ case MOD_PD_STATE_ON:
+ rcar_pwrc_cpuon(core);
+ pd_ctx->current_state = state;
+ break;
+
+ case MOD_PD_STATE_SLEEP:
+ pd_ctx->pd_driver_input_api->report_power_state_transition(
+ pd_ctx->bound_id, MOD_PD_STATE_ON);
+ break;
+ default:
+ FWK_LOG_ERR("[PD] Requested power state (%i) is not supported.", state);
+ return FWK_E_PARAM;
+ }
+
+ return FWK_SUCCESS;
+}
+
+static int rcar_core_pd_reset(fwk_id_t core_pd_id)
+{
+ return FWK_SUCCESS;
+}
+
+static int rcar_core_pd_prepare_for_system_suspend(fwk_id_t core_pd_id)
+{
+ mmio_write_32(RCAR_CPGWPR, ~CPU_PWR_OFF);
+ mmio_write_32(RCAR_CA57CPU0CR, CPU_PWR_OFF);
+
+ mmio_write_32(RCAR_CA57CPUCMCR, MODE_L2_DOWN);
+ _shutdown_request = R_SUSPEND;
+
+ return FWK_SUCCESS;
+}
+
+static const struct mod_pd_driver_api core_pd_driver = {
+ .set_state = rcar_core_pd_set_state,
+ .get_state = rcar_pd_get_state,
+ .reset = rcar_core_pd_reset,
+ .prepare_core_for_system_suspend = rcar_core_pd_prepare_for_system_suspend
+};
+
+/*
+ * Functions specific to cluster power domains
+ */
+
+static int rcar_cluster_pd_init(struct rcar_pd_sysc_pd_ctx *pd_ctx)
+{
+ return FWK_SUCCESS;
+}
+
+static int rcar_cluster_pd_set_state(fwk_id_t cluster_pd_id, unsigned int state)
+{
+ return FWK_SUCCESS;
+}
+
+static const struct mod_pd_driver_api cluster_pd_driver = {
+ .set_state = rcar_cluster_pd_set_state,
+ .get_state = rcar_pd_get_state,
+ .reset = rcar_pd_reset,
+};
+
+/*
+ * Framework handlers
+ */
+
+static int rcar_mod_init(
+ fwk_id_t module_id,
+ unsigned int pd_count,
+ const void *unused)
+{
+ rcar_pd_sysc_ctx.pd_ctx_table =
+ fwk_mm_calloc(pd_count, sizeof(struct rcar_pd_sysc_pd_ctx));
+ if (rcar_pd_sysc_ctx.pd_ctx_table == NULL)
+ return FWK_E_NOMEM;
+
+ rcar_pd_sysc_ctx.pd_ctx_table_size = pd_count;
+
+ return FWK_SUCCESS;
+}
+
+static int rcar_pd_init(fwk_id_t pd_id, unsigned int unused, const void *data)
+{
+ const struct mod_rcar_pd_core_pd_config *config = data;
+ struct rcar_pd_sysc_pd_ctx *pd_ctx;
+
+ if (config->pd_type >= MOD_PD_TYPE_COUNT)
+ return FWK_E_DATA;
+
+ pd_ctx = rcar_pd_sysc_ctx.pd_ctx_table + fwk_id_get_element_idx(pd_id);
+ pd_ctx->config = config;
+ pd_ctx->bound_id = FWK_ID_NONE;
+
+ if (config->pd_type == MOD_PD_TYPE_CLUSTER) {
+ pd_ctx->data =
+ fwk_mm_calloc(1, sizeof(struct rcar_pd_sysc_cluster_pd_ctx));
+ if (pd_ctx->data == NULL)
+ return FWK_E_NOMEM;
+ }
+
+ if (config->default_power_on) {
+ switch (config->pd_type) {
+ case MOD_PD_TYPE_DEVICE:
+ /* Fall through */
+ case MOD_PD_TYPE_DEVICE_DEBUG:
+ /* Fall through */
+ case MOD_PD_TYPE_SYSTEM:
+ break; // To Do. add (Default Power ON?)
+
+ default:
+ assert(false);
+ return FWK_E_SUPPORT;
+ }
+ }
+
+ return FWK_SUCCESS;
+}
+
+static int rcar_post_init(fwk_id_t module_id)
+{
+ return FWK_SUCCESS;
+}
+
+static int rcar_core_bind(fwk_id_t id, unsigned int round)
+{
+ int status = FWK_SUCCESS;
+ struct rcar_pd_sysc_pd_ctx *pd_ctx;
+
+ /* Nothing to do during the first round of calls where the power module
+ will bind to the power domains of this module. */
+ if (round == 0)
+ return FWK_SUCCESS;
+
+#if 0
+ /* In the case of the module, bind to the log component */
+ 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),
+ &rcar_pd_sysc_ctx.log_api);
+ return status;
+ }
+#endif
+
+ pd_ctx = rcar_pd_sysc_ctx.pd_ctx_table + fwk_id_get_element_idx(id);
+
+ if (!fwk_id_is_equal(pd_ctx->config->observer_id, FWK_ID_NONE)) {
+ if (pd_ctx->config->pd_type != MOD_PD_TYPE_CLUSTER) {
+ /* State observation only supported for clusters */
+ assert(false);
+ return FWK_E_SUPPORT;
+ }
+
+ status = fwk_module_bind(
+ pd_ctx->config->observer_id,
+ pd_ctx->config->observer_api,
+ &pd_ctx->observer_api);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+
+ if (fwk_id_is_equal(pd_ctx->bound_id, FWK_ID_NONE))
+ return FWK_SUCCESS;
+
+ switch (fwk_id_get_module_idx(pd_ctx->bound_id)) {
+ case FWK_MODULE_IDX_RCAR_POWER_DOMAIN:
+ return fwk_module_bind(
+ pd_ctx->bound_id,
+ mod_pd_api_id_driver_input,
+ &pd_ctx->pd_driver_input_api);
+ break;
+
+ case FWK_MODULE_IDX_SYSTEM_POWER:
+ return fwk_module_bind(
+ pd_ctx->bound_id,
+ mod_system_power_api_id_pd_driver_input,
+ &pd_ctx->pd_driver_input_api);
+ break;
+
+ default:
+ assert(false);
+ return FWK_E_SUPPORT;
+ }
+}
+
+static int rcar_core_process_bind_request(
+ fwk_id_t source_id,
+ fwk_id_t target_id,
+ fwk_id_t api_id,
+ const void **api)
+{
+ struct rcar_pd_sysc_pd_ctx *pd_ctx;
+ unsigned int api_idx;
+ bool is_power_domain_module = false;
+ bool is_system_power_module = false;
+
+ api_idx = fwk_id_get_api_idx(api_id);
+
+ if (api_idx != MOD_RCAR_PD_SYSC_API_IDX_POWER_DOMAIN_DRIVER)
+ return FWK_E_SUPPORT;
+
+ if (!fwk_module_is_valid_element_id(target_id))
+ return FWK_E_PARAM;
+
+ pd_ctx = rcar_pd_sysc_ctx.pd_ctx_table + fwk_id_get_element_idx(target_id);
+
+ /* Allow multiple binding only for device power domain for now */
+ if ((pd_ctx->config->pd_type != MOD_PD_TYPE_DEVICE) &&
+ (!fwk_id_is_equal(pd_ctx->bound_id, FWK_ID_NONE))) {
+ assert(false);
+ return FWK_E_ACCESS;
+ }
+
+ is_power_domain_module =
+ (fwk_id_get_module_idx(source_id) == FWK_MODULE_IDX_RCAR_POWER_DOMAIN);
+ is_system_power_module =
+ (fwk_id_get_module_idx(source_id) == FWK_MODULE_IDX_SYSTEM_POWER);
+
+ switch (pd_ctx->config->pd_type) {
+ case MOD_PD_TYPE_CORE:
+ if (is_power_domain_module) {
+ *api = &core_pd_driver;
+ pd_ctx->bound_id = source_id;
+ return FWK_SUCCESS;
+ }
+ break;
+
+ case MOD_PD_TYPE_CLUSTER:
+ if (is_power_domain_module) {
+ *api = &cluster_pd_driver;
+ pd_ctx->bound_id = source_id;
+ return FWK_SUCCESS;
+ }
+ break;
+
+ case MOD_PD_TYPE_SYSTEM:
+ if (is_power_domain_module || is_system_power_module) {
+ *api = &pd_driver;
+ pd_ctx->bound_id = source_id;
+ return FWK_SUCCESS;
+ }
+ break;
+
+ default:
+ if (is_power_domain_module)
+ pd_ctx->bound_id = source_id;
+ *api = &pd_driver;
+ return FWK_SUCCESS;
+ }
+
+ pd_ctx->bound_id = FWK_ID_NONE;
+ return FWK_E_ACCESS;
+}
+
+static int rcar_core_process_notification(
+ const struct fwk_event *event,
+ struct fwk_event *resp_event)
+{
+ const struct mod_rcar_pd_core_config *module_config;
+ struct rcar_pd_sysc_pd_ctx *pd_ctx;
+ struct mod_pd_power_state_transition_notification_params *params;
+
+ assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT));
+ module_config =
+ fwk_module_get_data(fwk_id_build_module_id(event->target_id));
+ assert(fwk_id_is_equal(event->id, module_config->pd_notification_id));
+ (void)module_config;
+
+ params = (struct mod_pd_power_state_transition_notification_params *)
+ event->params;
+
+ if (params->state != MOD_PD_STATE_ON)
+ return FWK_SUCCESS;
+
+ pd_ctx = rcar_pd_sysc_ctx.pd_ctx_table +
+ fwk_id_get_element_idx(event->target_id);
+
+ switch (pd_ctx->config->pd_type) {
+ case MOD_PD_TYPE_CORE:
+ return rcar_core_pd_init(pd_ctx);
+
+ case MOD_PD_TYPE_CLUSTER:
+ return rcar_cluster_pd_init(pd_ctx);
+
+ default:
+ return FWK_SUCCESS;
+ }
+}
+
+const struct fwk_module module_rcar_pd_core = {
+ .name = "RCAR_PD_CORE",
+ .type = FWK_MODULE_TYPE_DRIVER,
+ .api_count = MOD_RCAR_PD_SYSC_API_IDX_COUNT,
+ .init = rcar_mod_init,
+ .element_init = rcar_pd_init,
+ .post_init = rcar_post_init,
+ .bind = rcar_core_bind,
+ .process_bind_request = rcar_core_process_bind_request,
+ .process_notification = rcar_core_process_notification,
+};
diff --git a/product/rcar/module/rcar_pd_core/src/rcar_pd_core.c b/product/rcar/module/rcar_pd_core/src/rcar_pd_core.c
new file mode 100644
index 00000000..50738dbf
--- /dev/null
+++ b/product/rcar/module/rcar_pd_core/src/rcar_pd_core.c
@@ -0,0 +1,128 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mmio.h>
+#include <rcar_common.h>
+#include <rcar_mmap.h>
+#include <rcar_pd_core.h>
+
+#include <mod_rcar_power_domain.h>
+
+#include <fwk_assert.h>
+#include <fwk_status.h>
+
+#include <stddef.h>
+
+void rcar_pwrc_cpuoff(unsigned int core)
+{
+ uintptr_t off_reg;
+ uint32_t cpu_no;
+
+ mdelay(300);
+
+ if (core & CLUSTER_CPU_MASK) {
+ /* A53 side */
+ off_reg = (uintptr_t)RCAR_CA53CPU0CR;
+ cpu_no = (core & (~CLUSTER_CPU_MASK));
+ } else {
+ /* A57 side */
+ off_reg = (uintptr_t)RCAR_CA57CPU0CR;
+ cpu_no = core;
+ }
+ mmio_write_32(RCAR_CPGWPR, ~((uint32_t)CPU_PWR_OFF));
+ mmio_write_32(off_reg + (cpu_no * 0x0010U), (uint32_t)CPU_PWR_OFF);
+}
+
+void rcar_pwrc_cpuon(uint32_t core)
+{
+ uintptr_t res_reg;
+ uint32_t res_data;
+ uintptr_t on_reg;
+ uint32_t upper_value;
+ uint32_t wup_data;
+ uint32_t cpu_no;
+
+ if (core & CLUSTER_CPU_MASK) {
+ /* A53 side */
+ res_reg = (uintptr_t)RCAR_CA53RESCNT;
+ on_reg = (uintptr_t)RCAR_CA53WUPCR;
+ upper_value = 0x5A5A0000U;
+ cpu_no = (core & (~CLUSTER_CPU_MASK));
+ ;
+ } else {
+ /* A57 side */
+ res_reg = (uintptr_t)RCAR_CA57RESCNT;
+ on_reg = (uintptr_t)RCAR_CA57WUPCR;
+ upper_value = 0xA5A50000U;
+ cpu_no = core;
+ }
+
+ res_data = mmio_read_32(res_reg) | upper_value;
+ SCU_power_up(core);
+ wup_data = (uint32_t)((uint32_t)1U << cpu_no);
+ mmio_write_32(RCAR_CPGWPR, ~wup_data);
+ mmio_write_32(on_reg, wup_data);
+ /* Dessert to CPU reset */
+ mmio_write_32(res_reg, (res_data & (~((uint32_t)1U << (3U - cpu_no)))));
+}
+
+void SCU_power_up(uint32_t core)
+{
+ uint32_t reg_SYSC_bit;
+ uintptr_t reg_PWRONCR;
+ volatile uintptr_t reg_PWRER;
+ uintptr_t reg_PWRSR;
+ uintptr_t reg_CPUCMCR;
+ uintptr_t reg_SYSCIER = (uintptr_t)RCAR_SYSCIER;
+ uintptr_t reg_SYSCIMR = (uintptr_t)RCAR_SYSCIMR;
+ volatile uintptr_t reg_SYSCSR = (volatile uintptr_t)RCAR_SYSCSR;
+ volatile uintptr_t reg_SYSCISR = (volatile uintptr_t)RCAR_SYSCISR;
+ volatile uintptr_t reg_SYSCISCR = (volatile uintptr_t)RCAR_SYSCISCR;
+
+ if (core < 4) {
+ /* CA57-SCU */
+ reg_SYSC_bit = (uint32_t)BIT_CA57_SCU;
+ reg_PWRONCR = (uintptr_t)RCAR_PWRONCR5;
+ reg_PWRER = (volatile uintptr_t)RCAR_PWRER5;
+ reg_PWRSR = (uintptr_t)RCAR_PWRSR5;
+ reg_CPUCMCR = (uintptr_t)RCAR_CA57CPUCMCR;
+ } else {
+ /* CA53-SCU */
+ reg_SYSC_bit = (uint32_t)BIT_CA53_SCU;
+ reg_PWRONCR = (uintptr_t)RCAR_PWRONCR3;
+ reg_PWRER = (volatile uintptr_t)RCAR_PWRER3;
+ reg_PWRSR = (uintptr_t)RCAR_PWRSR3;
+ reg_CPUCMCR = (uintptr_t)RCAR_CA53CPUCMCR;
+ }
+ if ((mmio_read_32(reg_PWRSR) & (uint32_t)STATUS_PWRDOWN) != 0x0000U) {
+ if (mmio_read_32(reg_CPUCMCR) != 0U) {
+ mmio_write_32(reg_CPUCMCR, (uint32_t)0x00000000U);
+ }
+ /* set SYSCIER and SYSCIMR */
+ mmio_write_32(reg_SYSCIER, (mmio_read_32(reg_SYSCIER) | reg_SYSC_bit));
+ mmio_write_32(reg_SYSCIMR, (mmio_read_32(reg_SYSCIMR) | reg_SYSC_bit));
+ do {
+ /* SYSCSR[1]=1? */
+ while ((mmio_read_32(reg_SYSCSR) & (uint32_t)REQ_RESUME) == 0U)
+ continue;
+
+ /* If SYSCSR[1]=1 then set bit in PWRONCRn to 1 */
+ mmio_write_32(reg_PWRONCR, 0x0001U);
+ } while ((mmio_read_32(reg_PWRER) & 0x0001U) != 0U);
+
+ /* bit in SYSCISR=1 ? */
+ while ((mmio_read_32(reg_SYSCISR) & reg_SYSC_bit) == 0U)
+ continue;
+
+ /* clear bit in SYSCISR */
+ mmio_write_32(reg_SYSCISCR, reg_SYSC_bit);
+
+ /* Check the SCU power-up */
+ while ((mmio_read_32(reg_PWRSR) & (uint32_t)STATUS_PWRUP) == 0x0000U)
+ continue;
+ }
+}
diff --git a/product/rcar/module/rcar_pd_core/src/rcar_pd_core.h b/product/rcar/module/rcar_pd_core/src/rcar_pd_core.h
new file mode 100644
index 00000000..a16980ab
--- /dev/null
+++ b/product/rcar/module/rcar_pd_core/src/rcar_pd_core.h
@@ -0,0 +1,40 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_PD_CORE_H
+#define RCAR_PD_CORE_H
+
+/*!
+ * \cond
+ * @{
+ */
+
+#include <fwk_macros.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define CLUSTER_CPU_MASK 0x4
+#define REQ_RESUME ((uint32_t)1U << 1U)
+#define BIT_CA53_SCU ((uint32_t)1U << 21U)
+#define BIT_CA57_SCU ((uint32_t)1U << 12U)
+#define STATUS_PWRDOWN ((uint32_t)1U << 0U)
+#define STATUS_PWRUP ((uint32_t)1U << 4U)
+
+/*
+ * Interface
+ */
+void SCU_power_up(uint32_t mpidr);
+void rcar_pwrc_cpuoff(uint32_t mpidr);
+void rcar_pwrc_cpuon(uint32_t mpidr);
+
+/*!
+ * \endcond
+ * @}
+ */
+
+#endif /* RCAR_PD_CORE_H */
diff --git a/product/rcar/scp_ramfw/config_rcar_pd_core.c b/product/rcar/scp_ramfw/config_rcar_pd_core.c
new file mode 100644
index 00000000..66d5f788
--- /dev/null
+++ b/product/rcar/scp_ramfw/config_rcar_pd_core.c
@@ -0,0 +1,156 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <config_rcar_pd_core.h>
+#include <config_rcar_power_domain.h>
+#include <rcar_core.h>
+#include <rcar_mmap.h>
+
+#include <mod_rcar_pd_core.h>
+#include <mod_rcar_power_domain.h>
+
+#include <fwk_assert.h>
+#include <fwk_element.h>
+#include <fwk_macros.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+
+#include <stdio.h>
+#include <string.h>
+
+/* Maximum core name size including the null terminator */
+#define CORE_NAME_SIZE 12
+
+/* Maximum cluster name size including the null terminator */
+#define CLUS_NAME_SIZE 6
+
+static const char *core_pd_name_table[RCAR_CORE_PER_CLUSTER_MAX] = {
+ "CLUS0CORE0", "CLUS0CORE1", "CLUS0CORE2", "CLUS0CORE3",
+ "CLUS1CORE0", "CLUS1CORE1", "CLUS1CORE2", "CLUS1CORE3",
+};
+
+static const char *cluster_pd_name_table[2] = {
+ "CLUS0",
+ "CLUS1",
+};
+
+/* Module configuration data */
+static struct mod_rcar_pd_core_config rcar_pd_core_config_data = {
+ .pd_notification_id = FWK_ID_NOTIFICATION_INIT(
+ FWK_MODULE_IDX_RCAR_POWER_DOMAIN,
+ MOD_PD_NOTIFICATION_IDX_POWER_STATE_TRANSITION),
+};
+
+static struct fwk_element rcar_pd_core_system_element_table[] = {
+ [0] =
+ {
+ .name = "SYS0",
+ .data = &((struct mod_rcar_pd_core_pd_config){
+ .pd_type = MOD_PD_TYPE_SYSTEM,
+ .observer_id = FWK_ID_NONE_INIT,
+ }),
+ },
+ [1] =
+ {
+ .name = "SYS1",
+ .data = &((struct mod_rcar_pd_core_pd_config){
+ .pd_type = MOD_PD_TYPE_SYSTEM,
+ .observer_id = FWK_ID_NONE_INIT,
+ }),
+ },
+};
+
+static const struct fwk_element *rcar_pd_core_get_element_table(fwk_id_t mod)
+{
+ struct fwk_element *element_table, *element;
+ struct mod_rcar_pd_core_pd_config *pd_config_table, *pd_config;
+ unsigned int core_idx;
+ unsigned int cluster_idx = 0;
+ unsigned int core_count;
+ unsigned int cluster_count;
+ unsigned int core_element_count = 0;
+
+ core_count = CPU_CORE_MAX;
+ cluster_count = CPU_CLUSTER_MAX;
+
+ /*
+ * 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(rcar_pd_core_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_rcar_pd_core_pd_config));
+ if (pd_config_table == NULL)
+ return NULL;
+
+ for (core_idx = 0; core_idx < core_count; core_idx++) {
+ element = &element_table[core_element_count];
+ pd_config = &pd_config_table[core_element_count];
+
+ element->name = fwk_mm_alloc(CORE_NAME_SIZE, 1);
+ if (element->name == NULL)
+ return NULL;
+
+ element->name = core_pd_name_table[core_idx];
+ element->data = pd_config;
+
+ pd_config->pd_type = MOD_PD_TYPE_CORE;
+ pd_config->cluster_id =
+ FWK_ID_ELEMENT(FWK_MODULE_IDX_RCAR_PD_CORE, cluster_idx);
+ pd_config->observer_id = FWK_ID_NONE;
+ core_element_count++;
+ }
+
+ for (cluster_idx = 0; cluster_idx < cluster_count; cluster_idx++) {
+ element = &element_table[core_element_count];
+ pd_config = &pd_config_table[core_element_count];
+
+ element->name = fwk_mm_alloc(CLUS_NAME_SIZE, 1);
+ if (element->name == NULL)
+ return NULL;
+
+ element->name = cluster_pd_name_table[cluster_idx];
+ element->data = pd_config;
+ pd_config->pd_type = MOD_PD_TYPE_CLUSTER;
+ pd_config->observer_id = FWK_ID_NONE;
+ pd_config->observer_api = FWK_ID_NONE;
+ core_element_count++;
+ }
+
+ memcpy(
+ &element_table[core_count + cluster_count],
+ rcar_pd_core_system_element_table,
+ sizeof(rcar_pd_core_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.
+ */
+ rcar_pd_core_config_data.pd_source_id = fwk_id_build_element_id(
+ fwk_module_id_rcar_power_domain,
+ core_count + CONFIG_POWER_DOMAIN_CHILD_CLUSTER0);
+
+ return element_table;
+}
+
+/*
+ * Power module configuration data
+ */
+const struct fwk_module_config config_rcar_pd_core = {
+ .elements = FWK_MODULE_DYNAMIC_ELEMENTS(rcar_pd_core_get_element_table),
+ .data = &rcar_pd_core_config_data,
+};
diff --git a/product/rcar/scp_ramfw/config_rcar_pd_core.h b/product/rcar/scp_ramfw/config_rcar_pd_core.h
new file mode 100644
index 00000000..e2a140ae
--- /dev/null
+++ b/product/rcar/scp_ramfw/config_rcar_pd_core.h
@@ -0,0 +1,27 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONFIG_RCAR_PD_CORE_H
+#define CONFIG_RCAR_PD_CORE_H
+
+enum rcar_pd_core_element_idx {
+ RCAR_PD_CORE_ELEMENT_IDX_CPU0,
+ RCAR_PD_CORE_ELEMENT_IDX_CPU1,
+ RCAR_PD_CORE_ELEMENT_IDX_CPU2,
+ RCAR_PD_CORE_ELEMENT_IDX_CPU3,
+ RCAR_PD_CORE_ELEMENT_IDX_CPU4,
+ RCAR_PD_CORE_ELEMENT_IDX_CPU5,
+ RCAR_PD_CORE_ELEMENT_IDX_CPU6,
+ RCAR_PD_CORE_ELEMENT_IDX_CPU7,
+ RCAR_PD_CORE_ELEMENT_IDX_CLU0,
+ RCAR_PD_CORE_ELEMENT_IDX_CLU1
+};
+
+#define CPU_CORE_MAX 8
+#define CPU_CLUSTER_MAX 2
+
+#endif /* CONFIG_RCAR_PD_CORE_H */