aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Royer <nroyer@baylibre.com>2020-09-27 17:47:45 +0200
committernicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com>2020-10-15 17:45:38 +0100
commit584c92b8a7642fcd4e8468ef8d6944bcd16762fd (patch)
tree82ec8d3bab779a1b93412e33a567653b13e8e525
parent7ad0b7b11b52e8898852f7fbc2c41d7c37d59809 (diff)
rcar/module: add rcar system module and config data
Change-Id: I8ec83b7f1c9c58c2937a990e8043a6aa7a0f4588 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_system/include/mod_rcar_system.h66
-rw-r--r--product/rcar/module/rcar_system/src/FreeRTOS_tick_config.c158
-rw-r--r--product/rcar/module/rcar_system/src/Makefile16
-rw-r--r--product/rcar/module/rcar_system/src/mod_rcar_system.c291
-rw-r--r--product/rcar/module/rcar_system/src/rcar_call_sram.S48
-rw-r--r--product/rcar/module/rcar_system/src/rcar_common.c68
-rw-r--r--product/rcar/module/rcar_system/src/rcar_iic_dvfs.c556
-rw-r--r--product/rcar/module/rcar_system/src/rcar_iic_dvfs.h24
-rw-r--r--product/rcar/module/rcar_system/src/rcar_pwc.c218
-rw-r--r--product/rcar/module/rcar_system/src/rcar_pwc.h16
-rw-r--r--product/rcar/scp_ramfw/config_rcar_system.c55
11 files changed, 1516 insertions, 0 deletions
diff --git a/product/rcar/module/rcar_system/include/mod_rcar_system.h b/product/rcar/module/rcar_system/include/mod_rcar_system.h
new file mode 100644
index 00000000..4f21b9cb
--- /dev/null
+++ b/product/rcar/module/rcar_system/include/mod_rcar_system.h
@@ -0,0 +1,66 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MOD_RCAR_SYSTEM_H
+#define MOD_RCAR_SYSTEM_H
+
+#include <fwk_id.h>
+
+/*!
+ * \addtogroup GroupRCARModule RCAR Product Modules
+ * @{
+ */
+
+/*!
+ * \defgroup GroupRCARSystem RCAR System Support
+ *
+ * @{
+ */
+
+/*!
+ * \brief System device configuration.
+ */
+struct mod_rcar_system_dev_config {
+ /*! Reference to the device element within the associated driver module */
+ const fwk_id_t driver_id;
+
+ /*! Reference to the API provided by the device driver module */
+ const fwk_id_t api_id;
+};
+
+/*!
+ * \brief API indices.
+ */
+enum mod_rcar_system_api_idx {
+ /*! API index for the driver interface of the SYSTEM POWER module */
+ MOD_RCAR_SYSTEM_API_IDX_SYSTEM_POWER_DRIVER,
+
+ /*! Number of defined APIs */
+ MOD_RCAR_SYSTEM_API_COUNT
+};
+
+/*!
+ * @cond
+ */
+
+void rcar_system_code_copy_to_system_ram(void);
+extern void vConfigureTickInterrupt(void);
+extern void _save_system(void);
+
+/*!
+ * @endcond
+ */
+
+/*!
+ * @}
+ */
+
+/*!
+ * @}
+ */
+
+#endif /* MOD_RCAR_SYSTEM_H */
diff --git a/product/rcar/module/rcar_system/src/FreeRTOS_tick_config.c b/product/rcar/module/rcar_system/src/FreeRTOS_tick_config.c
new file mode 100644
index 00000000..536ee615
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/FreeRTOS_tick_config.c
@@ -0,0 +1,158 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "FreeRTOS.h"
+#include "arch_gic.h"
+#include "mmio.h"
+#include "rcar_irq.h"
+#include "rcar_mmap.h"
+#include "task.h"
+
+uint32_t c_interrupt;
+
+/* ARM Generic Timer */
+#define CORE0_TIMER_IRQCNTL ((volatile uint32_t *)(0x40000040))
+static uint32_t timer_cntfrq = 0;
+static uint32_t timer_tick = 0;
+
+static void init_generic_timer(void)
+{
+ uint32_t reg;
+ uint32_t reg_cntfid;
+ uint32_t modemr;
+ uint32_t modemr_pll;
+
+ uint32_t pll_table[] = {
+ EXTAL_MD14_MD13_TYPE_0, /* MD14/MD13 : 0b00 */
+ EXTAL_MD14_MD13_TYPE_1, /* MD14/MD13 : 0b01 */
+ EXTAL_MD14_MD13_TYPE_2, /* MD14/MD13 : 0b10 */
+ EXTAL_MD14_MD13_TYPE_3 /* MD14/MD13 : 0b11 */
+ };
+
+ modemr = mmio_read_32(RCAR_MODEMR);
+ modemr_pll = (modemr & MODEMR_BOOT_PLL_MASK);
+
+ /* Set frequency data in CNTFID0 */
+ reg_cntfid = pll_table[modemr_pll >> MODEMR_BOOT_PLL_SHIFT];
+ reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+ switch (modemr_pll) {
+ case MD14_MD13_TYPE_0:
+#ifdef SALVATORE_XS
+ reg_cntfid = EXTAL_SALVATOR_XS;
+#endif
+ break;
+ case MD14_MD13_TYPE_3:
+ if (RCAR_PRODUCT_H3_CUT10 == reg) {
+ reg_cntfid = reg_cntfid >> 1U;
+ }
+ break;
+ default:
+ /* none */
+ break;
+ }
+ /* Update memory mapped and register based freqency */
+ __asm__ volatile("msr cntfrq_el0, %0" ::"r"(reg_cntfid));
+}
+
+void disable_cntv(void)
+{
+ uint32_t cntv_ctl;
+ cntv_ctl = 0;
+ __asm__ volatile("msr cntv_ctl_el0, %0" ::"r"(cntv_ctl));
+}
+/*-----------------------------------------------------------*/
+
+void enable_cntv(void)
+{
+ uint32_t cntv_ctl;
+ cntv_ctl = 1;
+ __asm__ volatile("msr cntv_ctl_el0, %0" ::"r"(cntv_ctl));
+}
+/*-----------------------------------------------------------*/
+
+void write_cntv_tval(uint32_t val)
+{
+ __asm__ volatile("msr cntv_tval_el0, %0" ::"r"(val));
+ return;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t read_cntfrq(void)
+{
+ uint32_t val;
+ __asm__ volatile("mrs %0, cntfrq_el0" : "=r"(val));
+ return val;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t read_cntv_tval(void)
+{
+ uint32_t val;
+ __asm__ volatile("mrs %0, cntvct_el0" : "=r"(val));
+ return val;
+}
+/*-----------------------------------------------------------*/
+
+void init_timer(void)
+{
+ timer_cntfrq = timer_tick = read_cntfrq();
+ /* clear cntv interrupt and set next 1 sec timer. */
+ write_cntv_tval(timer_cntfrq);
+ return;
+}
+/*-----------------------------------------------------------*/
+
+void timer_set_tick_rate_hz(uint32_t rate)
+{
+ timer_tick = timer_cntfrq / rate;
+ write_cntv_tval(timer_tick);
+}
+/*-----------------------------------------------------------*/
+
+void vConfigureTickInterrupt(void)
+{
+ /* disable timer */
+ disable_cntv();
+
+ /* init timer device. */
+ init_generic_timer();
+ init_timer();
+
+ /* set tick rate. */
+ timer_set_tick_rate_hz(configTICK_RATE_HZ);
+
+ /* start & enable interrupts in the timer. */
+ enable_cntv();
+}
+/*-----------------------------------------------------------*/
+
+void vClearTickInterrupt(void)
+{
+ /* clear cntv interrupt and set next timer. */
+ write_cntv_tval(timer_tick);
+ return;
+}
+/*-----------------------------------------------------------*/
+
+void vApplicationIRQHandler(void)
+{
+ uint32_t ulInterruptID;
+
+ c_interrupt = mmio_read_32(RCAR_GICC_BASE + GICC_IAR);
+ mmio_write_32(RCAR_GICC_BASE + GICC_EOIR, c_interrupt);
+ ulInterruptID = c_interrupt & 0x00000FFFUL;
+
+ /* call handler function */
+ if (ulInterruptID == VIRTUAL_TIMER_IRQ) {
+ /* Generic Timer */
+ FreeRTOS_Tick_Handler();
+ } else {
+ /* Peripherals */
+ irq_global(ulInterruptID);
+ }
+ c_interrupt = 0;
+}
diff --git a/product/rcar/module/rcar_system/src/Makefile b/product/rcar/module/rcar_system/src/Makefile
new file mode 100644
index 00000000..9337ca36
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/Makefile
@@ -0,0 +1,16 @@
+#
+# Renesas SCP/MCP Software
+# Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := RCAR SYSTEM
+BS_LIB_SOURCES = mod_rcar_system.c \
+ rcar_common.c \
+ rcar_iic_dvfs.c \
+ rcar_pwc.c \
+ rcar_call_sram.S \
+ FreeRTOS_tick_config.c
+
+include $(BS_DIR)/lib.mk
diff --git a/product/rcar/module/rcar_system/src/mod_rcar_system.c b/product/rcar/module/rcar_system/src/mod_rcar_system.c
new file mode 100644
index 00000000..7be94471
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/mod_rcar_system.c
@@ -0,0 +1,291 @@
+/*
+ * 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_pwc.h>
+#include <rcar_scmi.h>
+
+#include <mod_clock.h>
+#include <mod_rcar_clock.h>
+#include <mod_rcar_reg_sensor.h>
+#include <mod_rcar_scif.h>
+#include <mod_rcar_system.h>
+#include <mod_scmi.h>
+#include <mod_system_power.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 <fwk_notification.h>
+#include <fwk_status.h>
+#include <fwk_thread.h>
+
+#include <arch_gic.h>
+#include <arch_helpers.h>
+#include <arch_system.h>
+
+/* Device context */
+struct rcar_system_dev_ctx {
+ const struct mod_rcar_system_dev_config *config;
+ struct mod_rcar_clock_drv_api *api;
+};
+
+/* Module context */
+struct rcar_system_ctx {
+ struct rcar_system_dev_ctx *dev_ctx_table;
+ unsigned int dev_count;
+};
+
+static struct rcar_system_ctx module_ctx;
+
+/*-----------------------------------------------------------*/
+#define P_STATUS (_shutdown_request)
+
+/* SCMI services required to enable the messaging stack */
+static unsigned int scmi_notification_table[] = {
+ RCAR_SCMI_SERVICE_IDX_PSCI,
+ RCAR_SCMI_SERVICE_IDX_OSPM_0,
+};
+
+IMPORT_SYM(unsigned long, __system_ram_start__, SYSTEM_RAM_START);
+IMPORT_SYM(unsigned long, __system_ram_end__, SYSTEM_RAM_END);
+IMPORT_SYM(unsigned long, __sram_copy_start__, SRAM_COPY_START);
+
+/*
+ * Static helpers
+ */
+
+static int messaging_stack_ready(void)
+{
+ return 0;
+}
+
+bool is_available_shutdown_req(uint32_t req)
+{
+ bool ret;
+
+ switch (req) {
+ case R_WARMBOOT:
+ case R_SUSPEND:
+ case R_RESET:
+ case R_OFF:
+ ret = true;
+ break;
+ default:
+ ret = false;
+ break;
+ }
+ return ret;
+}
+
+void rcar_system_code_copy_to_system_ram(void)
+{
+ memcpy(
+ (void *)SCP_SRAM_BASE,
+ (void *)SRAM_COPY_START,
+ (SYSTEM_RAM_END - SYSTEM_RAM_START));
+}
+
+void vApplicationIdleHook(void)
+{
+ uint32_t req;
+ struct rcar_system_dev_ctx *ctx;
+ fwk_id_t element_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, 0);
+ uint32_t i;
+
+ if (is_available_shutdown_req(P_STATUS)) {
+ fwk_interrupt_global_disable();
+ req = P_STATUS;
+ P_STATUS = R_CLEAR;
+ switch (req) {
+ case R_SUSPEND:
+ _boot_flag = R_WARMBOOT;
+ while (!(mmio_read_32(RCAR_CA57PSTR) & 0x0f))
+ continue;
+
+ _save_system();
+
+ rcar_system_code_copy_to_system_ram();
+
+ for (i = 0; i < module_ctx.dev_count; i++) {
+ element_id.element.element_idx = i;
+ ctx = module_ctx.dev_ctx_table +
+ fwk_id_get_element_idx(element_id);
+ if (ctx->api->resume)
+ ctx->api->resume();
+ }
+
+ reg_sensor_resume();
+ mod_rcar_scif_resume();
+ gic_init();
+ vConfigureTickInterrupt();
+ fwk_interrupt_global_enable();
+ break;
+ case R_RESET:
+ rcar_system_reset();
+ break;
+ case R_OFF:
+ rcar_system_off();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Functions fulfilling the framework's module interface
+ */
+
+static int rcar_system_shutdown(enum mod_pd_system_shutdown system_shutdown)
+{
+ switch (system_shutdown) {
+ case MOD_PD_SYSTEM_SHUTDOWN:
+ _shutdown_request = R_OFF;
+ break;
+ case MOD_PD_SYSTEM_COLD_RESET:
+ _shutdown_request = R_RESET;
+ break;
+ default:
+ break;
+ }
+
+ return FWK_SUCCESS;
+}
+
+static const struct mod_system_power_driver_api
+ rcar_system_system_power_driver_api = { .system_shutdown =
+ rcar_system_shutdown };
+
+/*
+ * Functions fulfilling the framework's module interface
+ */
+
+static int rcar_system_init(
+ fwk_id_t module_id,
+ unsigned int element_count,
+ const void *data)
+{
+ module_ctx.dev_count = element_count;
+
+ if (element_count == 0)
+ return FWK_SUCCESS;
+
+ module_ctx.dev_ctx_table =
+ fwk_mm_calloc(element_count, sizeof(struct rcar_system_dev_ctx));
+ if (module_ctx.dev_ctx_table == NULL)
+ return FWK_E_NOMEM;
+
+ return FWK_SUCCESS;
+}
+static int rcar_system_element(
+ fwk_id_t element_id,
+ unsigned int sub_element_count,
+ const void *data)
+{
+ struct rcar_system_dev_ctx *ctx;
+ const struct mod_rcar_system_dev_config *dev_config = data;
+
+ ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(element_id);
+ ctx->config = dev_config;
+
+ return FWK_SUCCESS;
+}
+
+static int rcar_system_bind(fwk_id_t id, unsigned int round)
+{
+ struct rcar_system_dev_ctx *ctx;
+
+ if (round == 1)
+ return FWK_SUCCESS;
+
+ if (!fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT))
+ /* Only element binding is supported */
+ return FWK_SUCCESS;
+
+ ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(id);
+
+ return fwk_module_bind(
+ ctx->config->driver_id, ctx->config->api_id, &ctx->api);
+}
+
+static int rcar_system_process_bind_request(
+ fwk_id_t source_id,
+ fwk_id_t target_id,
+ fwk_id_t api_id,
+ const void **api)
+{
+ *api = &rcar_system_system_power_driver_api;
+
+ return FWK_SUCCESS;
+}
+
+static int rcar_system_start(fwk_id_t id)
+{
+ int status;
+ unsigned int i;
+
+ /*
+ * Subscribe to these SCMI channels in order to know when they have all
+ * initialized.
+ * At that point we can consider the SCMI stack to be initialized from
+ * the point of view of the PSCI agent.
+ */
+ if (fwk_id_get_type(id) != FWK_ID_TYPE_MODULE)
+ return FWK_SUCCESS;
+
+ for (i = 0; i < FWK_ARRAY_SIZE(scmi_notification_table); i++) {
+ status = fwk_notification_subscribe(
+ mod_scmi_notification_id_initialized,
+ fwk_id_build_element_id(
+ fwk_module_id_scmi, scmi_notification_table[i]),
+ id);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+
+ return FWK_SUCCESS;
+}
+
+static int rcar_system_process_notification(
+ const struct fwk_event *event,
+ struct fwk_event *resp_event)
+{
+ static unsigned int scmi_notification_count = 0;
+
+ if (!fwk_expect(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE)))
+ return FWK_E_PARAM;
+
+ if (fwk_id_is_equal(event->id, mod_scmi_notification_id_initialized))
+ scmi_notification_count++;
+
+ if (scmi_notification_count == FWK_ARRAY_SIZE(scmi_notification_table)) {
+ messaging_stack_ready();
+
+ scmi_notification_count = 0;
+ }
+
+ return FWK_SUCCESS;
+}
+
+const struct fwk_module module_rcar_system = {
+ .name = "RCAR_SYSTEM",
+ .api_count = MOD_RCAR_SYSTEM_API_COUNT,
+ .type = FWK_MODULE_TYPE_DRIVER,
+ .init = rcar_system_init,
+ .element_init = rcar_system_element,
+ .bind = rcar_system_bind,
+ .start = rcar_system_start,
+ .process_bind_request = rcar_system_process_bind_request,
+ .process_notification = rcar_system_process_notification,
+};
diff --git a/product/rcar/module/rcar_system/src/rcar_call_sram.S b/product/rcar/module/rcar_system/src/rcar_call_sram.S
new file mode 100644
index 00000000..3519222b
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/rcar_call_sram.S
@@ -0,0 +1,48 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+.global rcar_pwrc_switch_stack
+
+/*
+ * x0 : jump address,
+ * x1 : stack address,
+ * x2 : arg,
+ * x3 : stack address (temporary)
+ */
+func rcar_pwrc_switch_stack
+
+ /* lr to stack */
+ stp x29, x30, [sp,#-16]
+
+ /* change stack pointer */
+ mov x3, sp
+ mov sp, x1
+
+ /* save stack pointer */
+ sub sp, sp, #16
+ stp x0, x3, [sp]
+
+ /* data synchronization barrier */
+ dsb sy
+
+ /* jump to code */
+ mov x1, x0
+ mov x0, x2
+ blr x1
+
+ /* load stack pointer */
+ ldp x0, x2, [sp,#0]
+
+ /* change stack pointer */
+ mov sp, x2
+
+ /* return */
+ ldp x29, x30, [sp,#-16]
+ ret
+endfunc rcar_pwrc_switch_stack
diff --git a/product/rcar/module/rcar_system/src/rcar_common.c b/product/rcar/module/rcar_system/src/rcar_common.c
new file mode 100644
index 00000000..0732a1d1
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/rcar_common.c
@@ -0,0 +1,68 @@
+/*
+ * 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 <fwk_attributes.h>
+
+void FWK_SECTION(".system_ram") cpg_write(uintptr_t regadr, uint32_t regval)
+{
+ uint32_t value = (regval);
+ mmio_write_32((uintptr_t)RCAR_CPGWPR, ~value);
+ mmio_write_32(regadr, value);
+}
+
+void FWK_SECTION(".system_ram")
+ mstpcr_write(uint32_t mstpcr, uint32_t mstpsr, uint32_t target_bit)
+{
+ uint32_t reg;
+ reg = mmio_read_32(mstpcr);
+ reg &= ~target_bit;
+ cpg_write(mstpcr, reg);
+ while ((mmio_read_32(mstpsr) & target_bit) != 0U)
+ continue;
+}
+
+static inline void cpu_relax(void)
+{
+ __asm__ volatile("yield" ::: "memory");
+}
+
+static uint64_t FWK_SECTION(".system_ram") get_cntfrq(void)
+{
+ uint64_t val;
+ __asm__ volatile("mrs %0, cntfrq_el0" : "=r"(val));
+ return val;
+}
+
+static uint64_t FWK_SECTION(".system_ram") get_cntvct(void)
+{
+ uint64_t val;
+ __asm__ volatile("mrs %0, cntvct_el0" : "=r"(val));
+ return val;
+}
+
+static void FWK_SECTION(".system_ram") delay(uint64_t cycles)
+{
+ uint64_t start = get_cntvct();
+
+ while ((get_cntvct() - start) < cycles)
+ cpu_relax();
+}
+
+void FWK_SECTION(".system_ram") udelay(unsigned long usec)
+{
+ delay((uint64_t)usec * get_cntfrq() / 1000000);
+}
+
+void FWK_SECTION(".system_ram") mdelay(unsigned long msecs)
+{
+ while (msecs--)
+ udelay(1000);
+}
diff --git a/product/rcar/module/rcar_system/src/rcar_iic_dvfs.c b/product/rcar/module/rcar_system/src/rcar_iic_dvfs.c
new file mode 100644
index 00000000..8bfc9ec4
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/rcar_iic_dvfs.c
@@ -0,0 +1,556 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rcar_common.h"
+#include "rcar_iic_dvfs.h"
+#include "rcar_mmap.h"
+
+#include <mmio.h>
+
+#include <fwk_attributes.h>
+
+#define DVFS_RETRY_MAX (2U)
+
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_0 (0x07)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_1 (0x09)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_2 (0x0B)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_3 (0x0E)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_E (0x15)
+
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_0 (0x01)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_1 (0x02)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_2 (0x03)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_3 (0x05)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_E (0x07)
+
+#define CPG_BIT_SMSTPCR9_DVFS (0x04000000)
+
+#define IIC_DVFS_REG_BASE (0xE60B0000)
+#define IIC_DVFS_REG_ICDR (IIC_DVFS_REG_BASE + 0x0000)
+#define IIC_DVFS_REG_ICCR (IIC_DVFS_REG_BASE + 0x0004)
+#define IIC_DVFS_REG_ICSR (IIC_DVFS_REG_BASE + 0x0008)
+#define IIC_DVFS_REG_ICIC (IIC_DVFS_REG_BASE + 0x000C)
+#define IIC_DVFS_REG_ICCL (IIC_DVFS_REG_BASE + 0x0010)
+#define IIC_DVFS_REG_ICCH (IIC_DVFS_REG_BASE + 0x0014)
+
+#define IIC_DVFS_BIT_ICSR_BUSY (0x10)
+#define IIC_DVFS_BIT_ICSR_AL (0x08)
+#define IIC_DVFS_BIT_ICSR_TACK (0x04)
+#define IIC_DVFS_BIT_ICSR_WAIT (0x02)
+#define IIC_DVFS_BIT_ICSR_DTE (0x01)
+
+#define IIC_DVFS_BIT_ICCR_ENABLE (0x80)
+#define IIC_DVFS_SET_ICCR_START (0x94)
+#define IIC_DVFS_SET_ICCR_STOP (0x90)
+#define IIC_DVFS_SET_ICCR_RETRANSMISSION (0x94)
+#define IIC_DVFS_SET_ICCR_CHANGE (0x81)
+#define IIC_DVFS_SET_ICCR_STOP_READ (0xC0)
+
+#define IIC_DVFS_BIT_ICIC_TACKE (0x04)
+#define IIC_DVFS_BIT_ICIC_WAITE (0x02)
+#define IIC_DVFS_BIT_ICIC_DTEE (0x01)
+
+#define DVFS_READ_MODE (0x01)
+#define DVFS_WRITE_MODE (0x00)
+
+#define IIC_DVFS_SET_DUMMY (0x52)
+#define IIC_DVFS_SET_BUSY_LOOP (500000000U)
+
+typedef enum {
+ DVFS_START = 0,
+ DVFS_STOP,
+ DVFS_RETRANSMIT,
+ DVFS_READ,
+ DVFS_STOP_READ,
+ DVFS_SET_SLAVE_READ,
+ DVFS_SET_SLAVE,
+ DVFS_WRITE_ADDR,
+ DVFS_WRITE_DATA,
+ DVFS_CHANGE_SEND_TO_RECIEVE,
+ DVFS_DONE,
+} DVFS_STATE_T;
+
+#define DVFS_PROCESS (1)
+#define DVFS_COMPLETE (0)
+#define DVFS_ERROR (-1)
+
+#define IIC_DVFS_FUNC(__name, ...) \
+ static int32_t FWK_SECTION(".system_ram") dvfs_##__name(__VA_ARGS__)
+
+#define RCAR_DVFS_API(__name, ...) \
+ int32_t FWK_SECTION(".system_ram") rcar_iic_dvfs_##__name(__VA_ARGS__)
+
+extern void panic(void);
+
+IIC_DVFS_FUNC(check_error, DVFS_STATE_T *state, uint32_t *err, uint8_t mode)
+{
+ uint8_t icsr_al = 0, icsr_tack = 0;
+ uint8_t reg, stop;
+ uint32_t i = 0;
+
+ stop = mode == DVFS_READ_MODE ? IIC_DVFS_SET_ICCR_STOP_READ :
+ IIC_DVFS_SET_ICCR_STOP;
+
+ reg = mmio_read_8(IIC_DVFS_REG_ICSR);
+ icsr_al = (reg & IIC_DVFS_BIT_ICSR_AL) == IIC_DVFS_BIT_ICSR_AL;
+ icsr_tack = (reg & IIC_DVFS_BIT_ICSR_TACK) == IIC_DVFS_BIT_ICSR_TACK;
+
+ if (icsr_al == 0 && icsr_tack == 0)
+ return DVFS_PROCESS;
+
+ if (icsr_al) {
+ reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_AL;
+ mmio_write_8(IIC_DVFS_REG_ICSR, reg);
+
+ if (*state == DVFS_SET_SLAVE)
+ mmio_write_8(IIC_DVFS_REG_ICDR, IIC_DVFS_SET_DUMMY);
+
+ do {
+ reg = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ } while (reg == 0);
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, stop);
+
+ reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, reg);
+
+ i = 0;
+ do {
+ reg = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY;
+ if (reg == 0)
+ break;
+
+ if (i++ > IIC_DVFS_SET_BUSY_LOOP)
+ panic();
+
+ } while (1);
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, 0x00U);
+
+ (*err)++;
+ if (*err > DVFS_RETRY_MAX)
+ return DVFS_ERROR;
+
+ *state = DVFS_START;
+
+ return DVFS_PROCESS;
+ }
+
+ /* icsr_tack */
+ mmio_write_8(IIC_DVFS_REG_ICCR, stop);
+
+ reg = mmio_read_8(IIC_DVFS_REG_ICIC);
+ reg &= ~(IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE);
+ mmio_write_8(IIC_DVFS_REG_ICIC, reg);
+
+ reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_TACK;
+ mmio_write_8(IIC_DVFS_REG_ICSR, reg);
+
+ i = 0;
+ while ((mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) != 0) {
+ if (i++ > IIC_DVFS_SET_BUSY_LOOP)
+ panic();
+ }
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+ (*err)++;
+
+ if (*err > DVFS_RETRY_MAX)
+ return DVFS_ERROR;
+
+ *state = DVFS_START;
+
+ return DVFS_PROCESS;
+}
+
+IIC_DVFS_FUNC(start, DVFS_STATE_T *state)
+{
+ uint8_t iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_E;
+ uint8_t icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_E;
+ int32_t result = DVFS_PROCESS;
+ uint32_t reg, lsi_product;
+ uint8_t mode;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICCR) | IIC_DVFS_BIT_ICCR_ENABLE;
+ mmio_write_8(IIC_DVFS_REG_ICCR, mode);
+
+ lsi_product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
+ if (lsi_product != RCAR_PRODUCT_E3) {
+ reg = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14;
+ switch (reg) {
+ case MD14_MD13_TYPE_0:
+ iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_0;
+ icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_0;
+ break;
+ case MD14_MD13_TYPE_1:
+ iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_1;
+ icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_1;
+ break;
+ case MD14_MD13_TYPE_2:
+ iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_2;
+ icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_2;
+ break;
+ default:
+ iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_3;
+ icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_3;
+ break;
+ }
+ }
+
+ mmio_write_8(IIC_DVFS_REG_ICCL, iccl);
+ mmio_write_8(IIC_DVFS_REG_ICCH, icch);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_TACKE |
+ IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE;
+
+ mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+ mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_START);
+
+ *state = DVFS_SET_SLAVE;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(set_slave, DVFS_STATE_T *state, uint32_t *err, uint8_t slave)
+{
+ uint8_t mode;
+ int32_t result;
+ uint8_t address;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
+ if (mode != IIC_DVFS_BIT_ICSR_DTE)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
+ mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+ address = slave << 1;
+ mmio_write_8(IIC_DVFS_REG_ICDR, address);
+
+ *state = DVFS_WRITE_ADDR;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(write_addr, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_addr)
+{
+ uint8_t mode;
+ int32_t result;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+ return result;
+
+ mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+ *state = DVFS_WRITE_DATA;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(write_data, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_data)
+{
+ int32_t result;
+ uint8_t mode;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+ return result;
+
+ mmio_write_8(IIC_DVFS_REG_ICDR, reg_data);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+ *state = DVFS_STOP;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(stop, DVFS_STATE_T *state, uint32_t *err)
+{
+ int32_t result;
+ uint8_t mode;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+ return result;
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+ *state = DVFS_DONE;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(done, void)
+{
+ uint32_t i;
+
+ for (i = 0; i < IIC_DVFS_SET_BUSY_LOOP; i++) {
+ if (mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY)
+ continue;
+ goto done;
+ }
+
+ panic();
+done:
+ mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+
+ return DVFS_COMPLETE;
+}
+
+IIC_DVFS_FUNC(
+ write_reg_addr_read,
+ DVFS_STATE_T *state,
+ uint32_t *err,
+ uint8_t reg_addr)
+{
+ int32_t result;
+ uint8_t mode;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+ return result;
+
+ mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+ *state = DVFS_RETRANSMIT;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(retransmit, DVFS_STATE_T *state, uint32_t *err)
+{
+ int32_t result;
+ uint8_t mode;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+ return result;
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_RETRANSMISSION);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE;
+ mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+ *state = DVFS_SET_SLAVE_READ;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(set_slave_read, DVFS_STATE_T *state, uint32_t *err, uint8_t slave)
+{
+ uint8_t address;
+ int32_t result;
+ uint8_t mode;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
+ if (mode != IIC_DVFS_BIT_ICSR_DTE)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
+ mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+ address = ((uint8_t)(slave << 1) + DVFS_READ_MODE);
+ mmio_write_8(IIC_DVFS_REG_ICDR, address);
+
+ *state = DVFS_CHANGE_SEND_TO_RECIEVE;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(change_send_to_recieve, DVFS_STATE_T *state, uint32_t *err)
+{
+ int32_t result;
+ uint8_t mode;
+
+ result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+ return result;
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_CHANGE);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+ *state = DVFS_STOP_READ;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(stop_read, DVFS_STATE_T *state, uint32_t *err)
+{
+ int32_t result;
+ uint8_t mode;
+
+ result = dvfs_check_error(state, err, DVFS_READ_MODE);
+ if (result == DVFS_ERROR)
+ return result;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+ if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+ return result;
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP_READ);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+ mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE;
+ mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+ *state = DVFS_READ;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(read, DVFS_STATE_T *state, uint8_t *reg_data)
+{
+ uint8_t mode;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
+ if (mode != IIC_DVFS_BIT_ICSR_DTE)
+ return DVFS_PROCESS;
+
+ mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
+ mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+ *reg_data = mmio_read_8(IIC_DVFS_REG_ICDR);
+ *state = DVFS_DONE;
+
+ return DVFS_PROCESS;
+}
+
+RCAR_DVFS_API(send, uint8_t slave, uint8_t reg_addr, uint8_t reg_data)
+{
+ DVFS_STATE_T state = DVFS_START;
+ int32_t result = DVFS_PROCESS;
+ uint32_t err = 0;
+
+ mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
+ mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+
+ do {
+ switch (state) {
+ case DVFS_START:
+ result = dvfs_start(&state);
+ break;
+ case DVFS_SET_SLAVE:
+ result = dvfs_set_slave(&state, &err, slave);
+ break;
+ case DVFS_WRITE_ADDR:
+ result = dvfs_write_addr(&state, &err, reg_addr);
+ break;
+ case DVFS_WRITE_DATA:
+ result = dvfs_write_data(&state, &err, reg_data);
+ break;
+ case DVFS_STOP:
+ result = dvfs_stop(&state, &err);
+ break;
+ case DVFS_DONE:
+ result = dvfs_done();
+ break;
+ default:
+ panic();
+ break;
+ }
+ } while (result == DVFS_PROCESS);
+
+ return result;
+}
+
+RCAR_DVFS_API(receive, uint8_t slave, uint8_t reg, uint8_t *data)
+{
+ DVFS_STATE_T state = DVFS_START;
+ int32_t result = DVFS_PROCESS;
+ uint32_t err = 0;
+
+ mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
+ mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+
+ do {
+ switch (state) {
+ case DVFS_START:
+ result = dvfs_start(&state);
+ break;
+ case DVFS_SET_SLAVE:
+ result = dvfs_set_slave(&state, &err, slave);
+ break;
+ case DVFS_WRITE_ADDR:
+ result = dvfs_write_reg_addr_read(&state, &err, reg);
+ break;
+ case DVFS_RETRANSMIT:
+ result = dvfs_retransmit(&state, &err);
+ break;
+ case DVFS_SET_SLAVE_READ:
+ result = dvfs_set_slave_read(&state, &err, slave);
+ break;
+ case DVFS_CHANGE_SEND_TO_RECIEVE:
+ result = dvfs_change_send_to_recieve(&state, &err);
+ break;
+ case DVFS_STOP_READ:
+ result = dvfs_stop_read(&state, &err);
+ break;
+ case DVFS_READ:
+ result = dvfs_read(&state, data);
+ break;
+ case DVFS_DONE:
+ result = dvfs_done();
+ break;
+ default:
+ panic();
+ break;
+ }
+ } while (result == DVFS_PROCESS);
+
+ return result;
+}
diff --git a/product/rcar/module/rcar_system/src/rcar_iic_dvfs.h b/product/rcar/module/rcar_system/src/rcar_iic_dvfs.h
new file mode 100644
index 00000000..03239c5d
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/rcar_iic_dvfs.h
@@ -0,0 +1,24 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_IIC_DVFS_H
+#define RCAR_IIC_DVFS_H
+
+/* PMIC slave */
+#define PMIC (0x30)
+#define BKUP_MODE_CNT (0x20)
+#define DVFS_SET_VID (0x54)
+#define REG_KEEP10 (0x79)
+
+/* EEPROM slave */
+#define EEPROM (0x50)
+#define BOARD_ID (0x70)
+
+int32_t rcar_iic_dvfs_receive(uint8_t slave, uint8_t reg, uint8_t *data);
+int32_t rcar_iic_dvfs_send(uint8_t slave, uint8_t regr, uint8_t data);
+
+#endif /* RCAR_IIC_DVFS_H */
diff --git a/product/rcar/module/rcar_system/src/rcar_pwc.c b/product/rcar/module/rcar_system/src/rcar_pwc.c
new file mode 100644
index 00000000..ff7d2aca
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/rcar_pwc.c
@@ -0,0 +1,218 @@
+/*
+ * 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_iic_dvfs.h>
+#include <rcar_mmap.h>
+#include <rcar_pwc.h>
+
+#include <fwk_attributes.h>
+
+#include <arch_helpers.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#define PMIC_ROHM_BD9571 1
+
+/* Suspend to ram */
+#define DBSC4_REG_BASE (0xE6790000U)
+#define DBSC4_REG_DBSYSCNT0 (DBSC4_REG_BASE + 0x0100U)
+#define DBSC4_REG_DBACEN (DBSC4_REG_BASE + 0x0200U)
+#define DBSC4_REG_DBCMD (DBSC4_REG_BASE + 0x0208U)
+#define DBSC4_REG_DBWAIT (DBSC4_REG_BASE + 0x0210U)
+#define DBSC4_REG_DBRFEN (DBSC4_REG_BASE + 0x0204U)
+
+#define DBSC4_REG_DBCALCNF (DBSC4_REG_BASE + 0x0424U)
+#define DBSC4_REG_DBDFIPMSTRCNF (DBSC4_REG_BASE + 0x0520U)
+
+#define DBSC4_REG_DBCAM0CTRL0 (DBSC4_REG_BASE + 0x0940U)
+#define DBSC4_REG_DBCAM0STAT0 (DBSC4_REG_BASE + 0x0980U)
+#define DBSC4_REG_DBCAM1STAT0 (DBSC4_REG_BASE + 0x0990U)
+#define DBSC4_REG_DBCAM2STAT0 (DBSC4_REG_BASE + 0x09A0U)
+#define DBSC4_REG_DBCAM3STAT0 (DBSC4_REG_BASE + 0x09B0U)
+
+#define DBSC4_BIT_DBCAMxSTAT0 (0x00000001U)
+#define DBSC4_BIT_DBDFIPMSTRCNF_PMSTREN (0x00000001U)
+#define DBSC4_SET_DBCMD_OPC_PRE (0x04000000U)
+#define DBSC4_SET_DBCMD_OPC_SR (0x0A000000U)
+#define DBSC4_SET_DBCMD_OPC_PD (0x08000000U)
+#define DBSC4_SET_DBCMD_OPC_MRW (0x0E000000U)
+#define DBSC4_SET_DBCMD_ARG_ENTER (0x00000000U)
+#define DBSC4_SET_DBCMD_ARG_MRW_ODTC (0x00000B00U)
+#define DBSC4_SET_DBCMD_CH_ALL (0x00800000U)
+#define DBSC4_SET_DBCMD_RANK_ALL (0x00040000U)
+#define DBSC4_SET_DBCMD_ARG_ALL (0x00000010U)
+#define DBSC4_SET_DBSYSCNT0_WRITE_ENABLE (0x00001234U)
+#define DBSC4_SET_DBSYSCNT0_WRITE_DISABLE (0x00000000U)
+
+#if PMIC_ROHM_BD9571
+# define BIT_BKUP_CTRL_OUT ((uint8_t)(1U << 4))
+# define PMIC_RETRY_MAX (100U)
+# define PMIC_BKUP_MODE_CNT (0x20U)
+# define PMIC_QLLM_CNT (0x27U)
+# define DVFS_SET_VID_0V (0x00)
+# define P_ALL_OFF (0x80)
+#endif /* PMIC_ROHM_BD9571 */
+
+#define SCTLR_EL3_M_BIT ((uint32_t)1U << 0)
+#define RCAR_CONV_MICROSEC (1000000U)
+
+#define DBCAM_FLUSH(__bit) \
+ do { \
+ ; \
+ } while (!( \
+ mmio_read_32(DBSC4_REG_DBCAM##__bit##STAT0) & DBSC4_BIT_DBCAMxSTAT0))
+
+extern uint32_t rcar_pwrc_switch_stack(
+ uintptr_t jump,
+ uintptr_t stack,
+ void *arg);
+
+extern void panic(void);
+
+static void FWK_SECTION(".system_ram") rcar_pwrc_set_self_refresh(void)
+{
+ uint32_t reg = mmio_read_32(RCAR_PRR);
+ uint32_t cut, product;
+
+ product = reg & RCAR_PRODUCT_MASK;
+ cut = reg & RCAR_CUT_MASK;
+
+ if (!((product == RCAR_PRODUCT_M3 && cut < RCAR_CUT_VER30) ||
+ (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)))
+ mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE);
+
+ /* DFI_PHYMSTR_ACK setting */
+ mmio_write_32(
+ DBSC4_REG_DBDFIPMSTRCNF,
+ mmio_read_32(DBSC4_REG_DBDFIPMSTRCNF) &
+ (~DBSC4_BIT_DBDFIPMSTRCNF_PMSTREN));
+
+ /* Set the Self-Refresh mode */
+ mmio_write_32(DBSC4_REG_DBACEN, 0);
+
+ if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
+ udelay(100);
+ else if (product == RCAR_PRODUCT_H3) {
+ mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
+ DBCAM_FLUSH(0);
+ DBCAM_FLUSH(1);
+ DBCAM_FLUSH(2);
+ DBCAM_FLUSH(3);
+ mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
+ } else if (product == RCAR_PRODUCT_M3) {
+ mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
+ DBCAM_FLUSH(0);
+ DBCAM_FLUSH(1);
+ mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
+ } else {
+ mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
+ DBCAM_FLUSH(0);
+ mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
+ }
+
+ /* Set the SDRAM calibration configuration register */
+ mmio_write_32(DBSC4_REG_DBCALCNF, 0);
+
+ reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL |
+ DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL;
+ mmio_write_32(DBSC4_REG_DBCMD, reg);
+ while (mmio_read_32(DBSC4_REG_DBWAIT))
+ continue;
+
+ /* Self-Refresh entry command */
+ reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL |
+ DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
+ mmio_write_32(DBSC4_REG_DBCMD, reg);
+ while (mmio_read_32(DBSC4_REG_DBWAIT))
+ continue;
+
+ /* Mode Register Write command. (ODT disabled) */
+ reg = DBSC4_SET_DBCMD_OPC_MRW | DBSC4_SET_DBCMD_CH_ALL |
+ DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_MRW_ODTC;
+ mmio_write_32(DBSC4_REG_DBCMD, reg);
+ while (mmio_read_32(DBSC4_REG_DBWAIT))
+ continue;
+
+ /* Power Down entry command */
+ reg = DBSC4_SET_DBCMD_OPC_PD | DBSC4_SET_DBCMD_CH_ALL |
+ DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
+ mmio_write_32(DBSC4_REG_DBCMD, reg);
+ while (mmio_read_32(DBSC4_REG_DBWAIT))
+ continue;
+
+ /* Set the auto-refresh enable register */
+ mmio_write_32(DBSC4_REG_DBRFEN, 0U);
+ udelay(1);
+
+ if (product == RCAR_PRODUCT_M3 && cut < RCAR_CUT_VER30)
+ return;
+
+ if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
+ return;
+
+ mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE);
+}
+
+void FWK_SECTION(".system_ram") FWK_NOINLINE rcar_pwrc_go_suspend_to_ram(void)
+{
+#if PMIC_ROHM_BD9571
+ int32_t rc = -1, qllm = -1;
+ uint8_t mode;
+ uint32_t i;
+#endif /* PMIC_ROHM_BD9571 */
+
+ rcar_pwrc_set_self_refresh();
+
+#if PMIC_ROHM_BD9571
+ /* Set QLLM Cnt Disable */
+ for (i = 0; (i < PMIC_RETRY_MAX) && (qllm != 0); i++)
+ qllm = rcar_iic_dvfs_send(PMIC, PMIC_QLLM_CNT, 0);
+
+ /* Set trigger of power down to PMIV */
+ for (i = 0; (i < PMIC_RETRY_MAX) && (rc != 0) && (qllm == 0); i++) {
+ rc = rcar_iic_dvfs_receive(PMIC, PMIC_BKUP_MODE_CNT, &mode);
+ if (rc == 0) {
+ mode |= BIT_BKUP_CTRL_OUT;
+ rc = rcar_iic_dvfs_send(PMIC, PMIC_BKUP_MODE_CNT, mode);
+ }
+ }
+#endif /* PMIC_ROHM_BD9571 */
+
+ wfi();
+
+ while (1)
+ continue;
+}
+
+void rcar_pwrc_set_suspend_to_ram(void)
+{
+ uintptr_t jump = (uintptr_t)&rcar_pwrc_go_suspend_to_ram;
+ uintptr_t stack = (uintptr_t)(SCP_SRAM_STACK_BASE + SCP_SRAM_STACK_SIZE);
+ uint32_t sctlr;
+
+ /* disable MMU */
+ sctlr = (uint32_t)read_sctlr_el3();
+ sctlr &= (uint32_t)~SCTLR_EL3_M_BIT;
+ write_sctlr_el3((uint64_t)sctlr);
+
+ rcar_pwrc_switch_stack(jump, stack, NULL);
+}
+
+void rcar_system_off(void)
+{
+ if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
+ panic();
+}
+
+void rcar_system_reset(void)
+{
+ if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
+ panic();
+}
diff --git a/product/rcar/module/rcar_system/src/rcar_pwc.h b/product/rcar/module/rcar_system/src/rcar_pwc.h
new file mode 100644
index 00000000..f2c1b54b
--- /dev/null
+++ b/product/rcar/module/rcar_system/src/rcar_pwc.h
@@ -0,0 +1,16 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_PWC_H
+#define RCAR_PWC_H
+
+void rcar_pwrc_go_suspend_to_ram(void);
+void rcar_pwrc_set_suspend_to_ram(void);
+void rcar_system_off(void);
+void rcar_system_reset(void);
+
+#endif /* RCAR_PWC_H */
diff --git a/product/rcar/scp_ramfw/config_rcar_system.c b/product/rcar/scp_ramfw/config_rcar_system.c
new file mode 100644
index 00000000..b1f1bcab
--- /dev/null
+++ b/product/rcar/scp_ramfw/config_rcar_system.c
@@ -0,0 +1,55 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <clock_devices.h>
+#include <clock_mstp_devices.h>
+#include <clock_sd_devices.h>
+#include <config_rcar_power_domain.h>
+#include <rcar_core.h>
+
+#include <mod_clock.h>
+#include <mod_rcar_clock.h>
+#include <mod_rcar_power_domain.h>
+#include <mod_rcar_system.h>
+
+#include <fwk_element.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+
+#include <stddef.h>
+
+static struct fwk_element rcar_system_element_table[] = {
+ {
+ .name = "sd_closk",
+ .data = &((struct mod_rcar_system_dev_config){
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_RCAR_SD_CLOCK, 0),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_RCAR_SD_CLOCK,
+ MOD_RCAR_CLOCK_API_TYPE_CLOCK),
+ }),
+ },
+ {
+ .name = "mstp_clock",
+ .data = &((struct mod_rcar_system_dev_config){
+ .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_RCAR_MSTP_CLOCK, 0),
+ .api_id = FWK_ID_API_INIT(
+ FWK_MODULE_IDX_RCAR_MSTP_CLOCK,
+ MOD_RCAR_CLOCK_API_TYPE_CLOCK),
+ }),
+ },
+ { 0 }, /* Termination description. */
+};
+
+static const struct fwk_element *get_element_table(fwk_id_t module_id)
+{
+ return rcar_system_element_table;
+}
+
+struct fwk_module_config config_rcar_system = {
+ .elements = FWK_MODULE_DYNAMIC_ELEMENTS(get_element_table),
+ .data = NULL,
+};