diff options
author | Nicolas Royer <nroyer@baylibre.com> | 2020-09-27 17:47:45 +0200 |
---|---|---|
committer | nicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com> | 2020-10-15 17:45:38 +0100 |
commit | 584c92b8a7642fcd4e8468ef8d6944bcd16762fd (patch) | |
tree | 82ec8d3bab779a1b93412e33a567653b13e8e525 | |
parent | 7ad0b7b11b52e8898852f7fbc2c41d7c37d59809 (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.h | 66 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/FreeRTOS_tick_config.c | 158 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/Makefile | 16 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/mod_rcar_system.c | 291 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/rcar_call_sram.S | 48 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/rcar_common.c | 68 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/rcar_iic_dvfs.c | 556 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/rcar_iic_dvfs.h | 24 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/rcar_pwc.c | 218 | ||||
-rw-r--r-- | product/rcar/module/rcar_system/src/rcar_pwc.h | 16 | ||||
-rw-r--r-- | product/rcar/scp_ramfw/config_rcar_system.c | 55 |
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, +}; |