diff options
author | Nicolas Royer <nroyer@baylibre.com> | 2020-09-27 17:40:12 +0200 |
---|---|---|
committer | nicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com> | 2020-10-15 17:45:38 +0100 |
commit | adede9b959dcf97d585b67aa210081bbd89d2f47 (patch) | |
tree | 7486f040b5bd0298f3c068f56a722d462d27ab44 /product/rcar | |
parent | 0bc640fd693982bbadee44e6a0d50c95596f4dd1 (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>
Diffstat (limited to 'product/rcar')
-rw-r--r-- | product/rcar/module/rcar_pd_core/include/mod_rcar_pd_core.h | 191 | ||||
-rw-r--r-- | product/rcar/module/rcar_pd_core/src/Makefile | 11 | ||||
-rw-r--r-- | product/rcar/module/rcar_pd_core/src/mod_rcar_pd_core.c | 402 | ||||
-rw-r--r-- | product/rcar/module/rcar_pd_core/src/rcar_pd_core.c | 128 | ||||
-rw-r--r-- | product/rcar/module/rcar_pd_core/src/rcar_pd_core.h | 40 | ||||
-rw-r--r-- | product/rcar/scp_ramfw/config_rcar_pd_core.c | 156 | ||||
-rw-r--r-- | product/rcar/scp_ramfw/config_rcar_pd_core.h | 27 |
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 */ |