summaryrefslogtreecommitdiffstats
path: root/plat/rockchip/common
diff options
context:
space:
mode:
Diffstat (limited to 'plat/rockchip/common')
-rw-r--r--plat/rockchip/common/aarch32/plat_helpers.S164
-rw-r--r--plat/rockchip/common/aarch32/platform_common.c57
-rw-r--r--plat/rockchip/common/aarch32/pmu_sram_cpus_on.S56
-rw-r--r--plat/rockchip/common/aarch64/plat_helpers.S163
-rw-r--r--plat/rockchip/common/aarch64/platform_common.c87
-rw-r--r--plat/rockchip/common/aarch64/pmu_sram_cpus_on.S52
-rw-r--r--plat/rockchip/common/bl31_plat_setup.c102
-rw-r--r--plat/rockchip/common/drivers/parameter/ddr_parameter.c135
-rw-r--r--plat/rockchip/common/drivers/parameter/ddr_parameter.h44
-rw-r--r--plat/rockchip/common/drivers/pmu/pmu_com.h122
-rw-r--r--plat/rockchip/common/include/plat_macros.S118
-rw-r--r--plat/rockchip/common/include/plat_params.h14
-rw-r--r--plat/rockchip/common/include/plat_private.h155
-rw-r--r--plat/rockchip/common/include/rockchip_sip_svc.h27
-rw-r--r--plat/rockchip/common/params_setup.c256
-rw-r--r--plat/rockchip/common/plat_pm.c413
-rw-r--r--plat/rockchip/common/plat_topology.c39
-rw-r--r--plat/rockchip/common/pmusram/cpus_on_fixed_addr.S48
-rw-r--r--plat/rockchip/common/pmusram/cpus_on_fixed_addr.h55
-rw-r--r--plat/rockchip/common/rockchip_gicv2.c81
-rw-r--r--plat/rockchip/common/rockchip_gicv3.c95
-rw-r--r--plat/rockchip/common/rockchip_sip_svc.c84
-rw-r--r--plat/rockchip/common/rockchip_stack_protector.c24
-rw-r--r--plat/rockchip/common/sp_min_plat_setup.c103
24 files changed, 2494 insertions, 0 deletions
diff --git a/plat/rockchip/common/aarch32/plat_helpers.S b/plat/rockchip/common/aarch32/plat_helpers.S
new file mode 100644
index 0000000..9f49cbd
--- /dev/null
+++ b/plat/rockchip/common/aarch32/plat_helpers.S
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a12.h>
+#include <plat_private.h>
+#include <plat_pmu_macros.S>
+
+ .globl cpuson_entry_point
+ .globl cpuson_flags
+ .globl platform_cpu_warmboot
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_report_exception
+ .globl plat_is_my_cpu_primary
+ .globl plat_my_core_pos
+ .globl plat_reset_handler
+ .globl plat_panic_handler
+
+ /*
+ * void plat_reset_handler(void);
+ *
+ * Determine the SOC type and call the appropriate reset
+ * handler.
+ *
+ */
+func plat_reset_handler
+ bx lr
+endfunc plat_reset_handler
+
+func plat_my_core_pos
+ ldcopr r0, MPIDR
+ and r1, r0, #MPIDR_CPU_MASK
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+ and r0, r0, #PLAT_RK_MPIDR_CLUSTER_MASK
+#else
+ and r0, r0, #MPIDR_CLUSTER_MASK
+#endif
+ add r0, r1, r0, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT
+ bx lr
+endfunc plat_my_core_pos
+
+ /* --------------------------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ * --------------------------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ /* rk3288 does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+ ldcopr r0, MPIDR
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+ ldr r1, =(PLAT_RK_MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+#else
+ ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+#endif
+ and r0, r1
+ cmp r0, #PLAT_RK_PRIMARY_CPU
+ moveq r0, #1
+ movne r0, #0
+ bx lr
+endfunc plat_is_my_cpu_primary
+
+ /* --------------------------------------------------------------------
+ * void plat_panic_handler(void)
+ * Call system reset function on panic. Set up an emergency stack so we
+ * can run C functions (it only needs to last for a few calls until we
+ * reboot anyway).
+ * --------------------------------------------------------------------
+ */
+func plat_panic_handler
+ bl plat_set_my_stack
+ b rockchip_soc_soft_reset
+endfunc plat_panic_handler
+
+ /* --------------------------------------------------------------------
+ * void platform_cpu_warmboot (void);
+ * cpus online or resume entrypoint
+ * --------------------------------------------------------------------
+ */
+func platform_cpu_warmboot _align=16
+ push { r4 - r7, lr }
+ ldcopr r0, MPIDR
+ and r5, r0, #MPIDR_CPU_MASK
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+ and r6, r0, #PLAT_RK_MPIDR_CLUSTER_MASK
+#else
+ and r6, r0, #MPIDR_CLUSTER_MASK
+#endif
+ mov r0, r6
+
+ func_rockchip_clst_warmboot
+ /* --------------------------------------------------------------------
+ * big cluster id is 1
+ * big cores id is from 0-3, little cores id 4-7
+ * --------------------------------------------------------------------
+ */
+ add r7, r5, r6, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT
+ /* --------------------------------------------------------------------
+ * get per cpuup flag
+ * --------------------------------------------------------------------
+ */
+ ldr r4, =cpuson_flags
+ add r4, r4, r7, lsl #2
+ ldr r1, [r4]
+ /* --------------------------------------------------------------------
+ * check cpuon reason
+ * --------------------------------------------------------------------
+ */
+ cmp r1, #PMU_CPU_AUTO_PWRDN
+ beq boot_entry
+ cmp r1, #PMU_CPU_HOTPLUG
+ beq boot_entry
+ /* --------------------------------------------------------------------
+ * If the boot core cpuson_flags or cpuson_entry_point is not
+ * expection. force the core into wfe.
+ * --------------------------------------------------------------------
+ */
+wfe_loop:
+ wfe
+ b wfe_loop
+boot_entry:
+ mov r1, #0
+ str r1, [r4]
+ /* --------------------------------------------------------------------
+ * get per cpuup boot addr
+ * --------------------------------------------------------------------
+ */
+ ldr r5, =cpuson_entry_point
+ ldr r2, [r5, r7, lsl #2] /* ehem. #3 */
+ pop { r4 - r7, lr }
+
+ bx r2
+endfunc platform_cpu_warmboot
+
+ /* --------------------------------------------------------------------
+ * Per-CPU Secure entry point - resume or power up
+ * --------------------------------------------------------------------
+ */
+ .section .tzfw_coherent_mem, "a"
+ .align 3
+cpuson_entry_point:
+ .rept PLATFORM_CORE_COUNT
+ .quad 0
+ .endr
+cpuson_flags:
+ .rept PLATFORM_CORE_COUNT
+ .word 0
+ .endr
+rockchip_clst_warmboot_data
diff --git a/plat/rockchip/common/aarch32/platform_common.c b/plat/rockchip/common/aarch32/platform_common.c
new file mode 100644
index 0000000..9030951
--- /dev/null
+++ b/plat/rockchip/common/aarch32/platform_common.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <plat_private.h>
+
+void plat_configure_mmu_svc_mon(unsigned long total_base,
+ unsigned long total_size,
+ unsigned long ro_start,
+ unsigned long ro_limit,
+ unsigned long coh_start,
+ unsigned long coh_limit)
+{
+ mmap_add_region(total_base, total_base, total_size,
+ MT_MEMORY | MT_RW | MT_SECURE);
+ mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+ MT_MEMORY | MT_RO | MT_SECURE);
+ mmap_add_region(coh_start, coh_start, coh_limit - coh_start,
+ MT_DEVICE | MT_RW | MT_SECURE);
+ mmap_add(plat_rk_mmap);
+ rockchip_plat_mmu_svc_mon();
+ init_xlat_tables();
+ enable_mmu_svc_mon(0);
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+/*
+ * generic pm code does cci handling, but rockchip arm32 platforms
+ * have ever only 1 cluster, so nothing to do.
+ */
+void plat_cci_init(void)
+{
+}
+
+void plat_cci_enable(void)
+{
+}
+
+void plat_cci_disable(void)
+{
+}
diff --git a/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S b/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S
new file mode 100644
index 0000000..a05ae54
--- /dev/null
+++ b/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .globl pmu_cpuson_entrypoint
+ .macro pmusram_entry_func _name
+ .section .pmusram.entry, "ax"
+ .type \_name, %function
+ .cfi_startproc
+ \_name:
+ .endm
+
+pmusram_entry_func pmu_cpuson_entrypoint
+
+#if PSRAM_CHECK_WAKEUP_CPU
+check_wake_cpus:
+ ldcopr r0, MPIDR
+ and r1, r0, #MPIDR_CPU_MASK
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+ and r0, r0, #PLAT_RK_MPIDR_CLUSTER_MASK
+#else
+ and r0, r0, #MPIDR_CLUSTER_MASK
+#endif
+ orr r0, r0, r1
+
+ /* primary_cpu */
+ ldr r1, boot_mpidr
+ cmp r0, r1
+ beq sys_wakeup
+
+ /*
+ * If the core is not the primary cpu,
+ * force the core into wfe.
+ */
+wfe_loop:
+ wfe
+ b wfe_loop
+sys_wakeup:
+#endif
+
+#if PSRAM_DO_DDR_RESUME
+ddr_resume:
+ ldr r2, =__bl32_sram_stack_end
+ mov sp, r2
+ bl dmc_resume
+#endif
+ bl sram_restore
+sys_resume:
+ bl sp_min_warm_entrypoint
+endfunc pmu_cpuson_entrypoint
diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..c4c0dec
--- /dev/null
+++ b/plat/rockchip/common/aarch64/plat_helpers.S
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a53.h>
+#include <cortex_a72.h>
+#include <plat_private.h>
+#include <plat_pmu_macros.S>
+
+ .globl cpuson_entry_point
+ .globl cpuson_flags
+ .globl platform_cpu_warmboot
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_report_exception
+ .globl plat_is_my_cpu_primary
+ .globl plat_my_core_pos
+ .globl plat_reset_handler
+ .globl plat_panic_handler
+
+ /*
+ * void plat_reset_handler(void);
+ *
+ * Determine the SOC type and call the appropriate reset
+ * handler.
+ *
+ */
+func plat_reset_handler
+ mrs x0, midr_el1
+ ubfx x0, x0, MIDR_PN_SHIFT, #12
+ cmp w0, #((CORTEX_A72_MIDR >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+ b.eq handler_a72
+ b handler_end
+handler_a72:
+ /*
+ * This handler does the following:
+ * Set the L2 Data RAM latency for Cortex-A72.
+ * Set the L2 Tag RAM latency to for Cortex-A72.
+ */
+ mov x0, #((5 << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \
+ (0x1 << 5))
+ msr CORTEX_A72_L2CTLR_EL1, x0
+ isb
+handler_end:
+ ret
+endfunc plat_reset_handler
+
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT
+ ret
+endfunc plat_my_core_pos
+
+ /* --------------------------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ * --------------------------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ /* rk3368 does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, #PLAT_RK_PRIMARY_CPU
+ cset x0, eq
+ ret
+endfunc plat_is_my_cpu_primary
+
+ /* --------------------------------------------------------------------
+ * void plat_panic_handler(void)
+ * Call system reset function on panic. Set up an emergency stack so we
+ * can run C functions (it only needs to last for a few calls until we
+ * reboot anyway).
+ * --------------------------------------------------------------------
+ */
+func plat_panic_handler
+ msr spsel, #0
+ bl plat_set_my_stack
+ b rockchip_soc_soft_reset
+endfunc plat_panic_handler
+
+ /* --------------------------------------------------------------------
+ * void platform_cpu_warmboot (void);
+ * cpus online or resume enterpoint
+ * --------------------------------------------------------------------
+ */
+func platform_cpu_warmboot _align=16
+ mrs x0, MPIDR_EL1
+ and x19, x0, #MPIDR_CPU_MASK
+ and x20, x0, #MPIDR_CLUSTER_MASK
+ mov x0, x20
+ func_rockchip_clst_warmboot
+ /* --------------------------------------------------------------------
+ * big cluster id is 1
+ * big cores id is from 0-3, little cores id 4-7
+ * --------------------------------------------------------------------
+ */
+ add x21, x19, x20, lsr #PLAT_RK_CLST_TO_CPUID_SHIFT
+ /* --------------------------------------------------------------------
+ * get per cpuup flag
+ * --------------------------------------------------------------------
+ */
+ adr x4, cpuson_flags
+ add x4, x4, x21, lsl #2
+ ldr w1, [x4]
+ /* --------------------------------------------------------------------
+ * check cpuon reason
+ * --------------------------------------------------------------------
+ */
+ cmp w1, PMU_CPU_AUTO_PWRDN
+ b.eq boot_entry
+ cmp w1, PMU_CPU_HOTPLUG
+ b.eq boot_entry
+ /* --------------------------------------------------------------------
+ * If the boot core cpuson_flags or cpuson_entry_point is not
+ * expection. force the core into wfe.
+ * --------------------------------------------------------------------
+ */
+wfe_loop:
+ wfe
+ b wfe_loop
+boot_entry:
+ str wzr, [x4]
+ /* --------------------------------------------------------------------
+ * get per cpuup boot addr
+ * --------------------------------------------------------------------
+ */
+ adr x5, cpuson_entry_point
+ ldr x2, [x5, x21, lsl #3]
+ br x2
+endfunc platform_cpu_warmboot
+
+ /* --------------------------------------------------------------------
+ * Per-CPU Secure entry point - resume or power up
+ * --------------------------------------------------------------------
+ */
+ .section .tzfw_coherent_mem, "a"
+ .align 3
+cpuson_entry_point:
+ .rept PLATFORM_CORE_COUNT
+ .quad 0
+ .endr
+cpuson_flags:
+ .rept PLATFORM_CORE_COUNT
+ .word 0
+ .endr
+rockchip_clst_warmboot_data
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
new file mode 100644
index 0000000..81e8520
--- /dev/null
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <plat_private.h>
+
+#ifdef PLAT_RK_CCI_BASE
+static const int cci_map[] = {
+ PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX,
+ PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX
+};
+#endif
+
+/******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+#define DEFINE_CONFIGURE_MMU_EL(_el) \
+ void plat_configure_mmu_el ## _el(unsigned long total_base, \
+ unsigned long total_size, \
+ unsigned long ro_start, \
+ unsigned long ro_limit, \
+ unsigned long coh_start, \
+ unsigned long coh_limit) \
+ { \
+ mmap_add_region(total_base, total_base, \
+ total_size, \
+ MT_MEMORY | MT_RW | MT_SECURE); \
+ mmap_add_region(ro_start, ro_start, \
+ ro_limit - ro_start, \
+ MT_MEMORY | MT_RO | MT_SECURE); \
+ mmap_add_region(coh_start, coh_start, \
+ coh_limit - coh_start, \
+ MT_DEVICE | MT_RW | MT_SECURE); \
+ mmap_add(plat_rk_mmap); \
+ rockchip_plat_mmu_el##_el(); \
+ init_xlat_tables(); \
+ \
+ enable_mmu_el ## _el(0); \
+ }
+
+/* Define EL3 variants of the function initialising the MMU */
+DEFINE_CONFIGURE_MMU_EL(3)
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+void plat_cci_init(void)
+{
+#ifdef PLAT_RK_CCI_BASE
+ /* Initialize CCI driver */
+ cci_init(PLAT_RK_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+#endif
+}
+
+void plat_cci_enable(void)
+{
+ /*
+ * Enable CCI coherency for this cluster.
+ * No need for locks as no other cpu is active at the moment.
+ */
+#ifdef PLAT_RK_CCI_BASE
+ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+#endif
+}
+
+void plat_cci_disable(void)
+{
+#ifdef PLAT_RK_CCI_BASE
+ cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+#endif
+}
diff --git a/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S b/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
new file mode 100644
index 0000000..d91ee0e
--- /dev/null
+++ b/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .globl pmu_cpuson_entrypoint
+ .macro pmusram_entry_func _name
+ .section .pmusram.entry, "ax"
+ .type \_name, %function
+ .cfi_startproc
+ \_name:
+ .endm
+
+pmusram_entry_func pmu_cpuson_entrypoint
+
+#if PSRAM_CHECK_WAKEUP_CPU
+check_wake_cpus:
+ mrs x0, MPIDR_EL1
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ orr x0, x0, x1
+
+ /* primary_cpu */
+ ldr w1, boot_mpidr
+ cmp w0, w1
+ b.eq sys_wakeup
+
+ /*
+ * If the core is not the primary cpu,
+ * force the core into wfe.
+ */
+wfe_loop:
+ wfe
+ b wfe_loop
+sys_wakeup:
+#endif
+
+#if PSRAM_DO_DDR_RESUME
+ddr_resume:
+ ldr x2, =__bl31_sram_stack_end
+ mov sp, x2
+ bl dmc_resume
+#endif
+ bl sram_restore
+sys_resume:
+ bl bl31_warm_entrypoint
+endfunc pmu_cpuson_entrypoint
diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
new file mode 100644
index 0000000..59db3d8
--- /dev/null
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ entry_point_info_t *next_image_info;
+
+ next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+ assert(next_image_info->h.type == PARAM_EP);
+
+ /* None of the images on this platform can have 0x0 as the entrypoint */
+ if (next_image_info->pc)
+ return next_image_info;
+ else
+ return NULL;
+}
+
+#pragma weak params_early_setup
+void params_early_setup(u_register_t plat_param_from_bl2)
+{
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ * BL2 has flushed this information to memory, so we are guaranteed to pick up
+ * good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ static console_t console;
+
+ params_early_setup(arg1);
+
+ if (rockchip_get_uart_base() != 0)
+ console_16550_register(rockchip_get_uart_base(),
+ rockchip_get_uart_clock(),
+ rockchip_get_uart_baudrate(), &console);
+
+ VERBOSE("bl31_setup\n");
+
+ bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info);
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+ generic_delay_timer_init();
+ plat_rockchip_soc_init();
+
+ /* Initialize the gic cpu and distributor interfaces */
+ plat_rockchip_gic_driver_init();
+ plat_rockchip_gic_init();
+ plat_rockchip_pmu_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+ plat_cci_init();
+ plat_cci_enable();
+ plat_configure_mmu_el3(BL_CODE_BASE,
+ BL_COHERENT_RAM_END - BL_CODE_BASE,
+ BL_CODE_BASE,
+ BL_CODE_END,
+ BL_COHERENT_RAM_BASE,
+ BL_COHERENT_RAM_END);
+}
diff --git a/plat/rockchip/common/drivers/parameter/ddr_parameter.c b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
new file mode 100644
index 0000000..e89fe1e
--- /dev/null
+++ b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+#include "ddr_parameter.h"
+
+/*
+ * The miniloader delivers the parameters about ddr usage info from address
+ * 0x02000000 and the data format is defined as below figure. It tells ATF the
+ * areas of ddr that are used by platform, we treat them as non-secure regions
+ * by default. Then we should parse the other part regions and configurate them
+ * as secure regions to avoid illegal access.
+ *
+ * [ddr usage info data format]
+ * 0x02000000
+ * -----------------------------------------------------------------------------
+ * | <name> | <size> | <description> |
+ * -----------------------------------------------------------------------------
+ * | count | 4byte | the array numbers of the |
+ * | | | 'addr_array' and 'size_array' |
+ * -----------------------------------------------------------------------------
+ * | reserved | 4byte | just for 'addr_array' 8byte aligned |
+ * -----------------------------------------------------------------------------
+ * | addr_array[count] | per 8byte | memory region base address |
+ * -----------------------------------------------------------------------------
+ * | size_array[count] | per 8byte | memory region size (byte) |
+ * -----------------------------------------------------------------------------
+ */
+
+/*
+ * function: read parameters info(ns-regions) and try to parse s-regions info
+ *
+ * @addr: head address to the ddr usage struct from miniloader
+ * @max_mb: the max ddr capacity(MB) that the platform support
+ */
+struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb)
+{
+ uint64_t base, top;
+ uint32_t i, addr_offset, size_offset;
+ struct param_ddr_usage p;
+
+ memset(&p, 0, sizeof(p));
+
+ /* read how many blocks of ns-regions, read from offset: 0x0 */
+ p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET);
+ if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) {
+ ERROR("over or zero region, nr=%d, max=%d\n",
+ p.ns_nr, DDR_REGION_NR_MAX);
+ return p;
+ }
+
+ /* whole ddr regions boundary, it will be used when parse s-regions */
+ p.boundary = max_mb;
+
+ /* calculate ns-region base addr and size offset */
+ addr_offset = REGION_ADDR_OFFSET;
+ size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES;
+
+ /* read all ns-regions base and top address */
+ for (i = 0; i < p.ns_nr; i++) {
+ base = mmio_read_64(addr + addr_offset);
+ top = base + mmio_read_64(addr + size_offset);
+ /*
+ * translate byte to MB and store info,
+ * Miniloader will promise every ns-region is MB aligned.
+ */
+ p.ns_base[i] = RG_SIZE_MB(base);
+ p.ns_top[i] = RG_SIZE_MB(top);
+
+ addr_offset += REGION_DATA_PER_BYTES;
+ size_offset += REGION_DATA_PER_BYTES;
+ }
+
+ /*
+ * a s-region's base starts from previous ns-region's top, and a
+ * s-region's top ends with next ns-region's base. maybe like this:
+ *
+ * case1: ns-regison start from 0MB
+ * -----------------------------------------------
+ * | ns0 | S0 | ns1 | S1 | ns2 |
+ * 0----------------------------------------------- max_mb
+ *
+ *
+ * case2: ns-regison not start from 0MB
+ * -----------------------------------------------
+ * | S0 | ns0 | ns1 | ns2 | S1 |
+ * 0----------------------------------------------- max_mb
+ */
+
+ /* like above case2 figure, ns-region is not start from 0MB */
+ if (p.ns_base[0] != 0) {
+ p.s_base[p.s_nr] = 0;
+ p.s_top[p.s_nr] = p.ns_base[0];
+ p.s_nr++;
+ }
+
+ /*
+ * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0
+ */
+ for (i = 0; i < p.ns_nr; i++) {
+ /*
+ * if current ns-regions top covers boundary,
+ * that means s-regions are all parsed yet, so finsh.
+ */
+ if (p.ns_top[i] == p.boundary)
+ goto out;
+
+ /* s-region's base starts from previous ns-region's top */
+ p.s_base[p.s_nr] = p.ns_top[i];
+
+ /* s-region's top ends with next ns-region's base */
+ if (i + 1 < p.ns_nr)
+ p.s_top[p.s_nr] = p.ns_base[i + 1];
+ else
+ p.s_top[p.s_nr] = p.boundary;
+ p.s_nr++;
+ }
+out:
+ return p;
+}
diff --git a/plat/rockchip/common/drivers/parameter/ddr_parameter.h b/plat/rockchip/common/drivers/parameter/ddr_parameter.h
new file mode 100644
index 0000000..25c93a1
--- /dev/null
+++ b/plat/rockchip/common/drivers/parameter/ddr_parameter.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DDR_PARAMETER_H
+#define DDR_PARAMETER_H
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+#define DDR_REGION_NR_MAX 10
+#define REGION_NR_OFFSET 0
+#define REGION_ADDR_OFFSET 8
+#define REGION_DATA_PER_BYTES 8
+#define RG_SIZE_MB(byte) ((byte) >> 20)
+
+/* unit: MB */
+struct param_ddr_usage {
+ uint64_t boundary;
+
+ uint32_t ns_nr;
+ uint64_t ns_base[DDR_REGION_NR_MAX];
+ uint64_t ns_top[DDR_REGION_NR_MAX];
+
+ uint32_t s_nr;
+ uint64_t s_base[DDR_REGION_NR_MAX + 1];
+ uint64_t s_top[DDR_REGION_NR_MAX + 1];
+};
+
+struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb);
+
+#endif /* DDR_PARAMETER_H */
diff --git a/plat/rockchip/common/drivers/pmu/pmu_com.h b/plat/rockchip/common/drivers/pmu/pmu_com.h
new file mode 100644
index 0000000..022bb02
--- /dev/null
+++ b/plat/rockchip/common/drivers/pmu/pmu_com.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_COM_H
+#define PMU_COM_H
+
+#ifndef CHECK_CPU_WFIE_BASE
+#define CHECK_CPU_WFIE_BASE (PMU_BASE + PMU_CORE_PWR_ST)
+#endif
+/*
+ * Use this macro to instantiate lock before it is used in below
+ * rockchip_pd_lock_xxx() macros
+ */
+DECLARE_BAKERY_LOCK(rockchip_pd_lock);
+
+/*
+ * These are wrapper macros to the powe domain Bakery Lock API.
+ */
+#define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock)
+#define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock)
+#define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock)
+
+/*****************************************************************************
+ * power domain on or off
+ *****************************************************************************/
+enum pmu_pd_state {
+ pmu_pd_on = 0,
+ pmu_pd_off = 1
+};
+
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak pmu_power_domain_ctr
+#pragma weak check_cpu_wfie
+
+static inline uint32_t pmu_power_domain_st(uint32_t pd)
+{
+ uint32_t pwrdn_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd);
+
+ if (pwrdn_st)
+ return pmu_pd_off;
+ else
+ return pmu_pd_on;
+}
+
+static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
+{
+ uint32_t val;
+ uint32_t loop = 0;
+ int ret = 0;
+
+ rockchip_pd_lock_get();
+
+ val = mmio_read_32(PMU_BASE + PMU_PWRDN_CON);
+ if (pd_state == pmu_pd_off)
+ val |= BIT(pd);
+ else
+ val &= ~BIT(pd);
+
+ mmio_write_32(PMU_BASE + PMU_PWRDN_CON, val);
+ dsb();
+
+ while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
+ udelay(1);
+ loop++;
+ }
+
+ if (pmu_power_domain_st(pd) != pd_state) {
+ WARN("%s: %d, %d, error!\n", __func__, pd, pd_state);
+ ret = -EINVAL;
+ }
+
+ rockchip_pd_lock_rls();
+
+ return ret;
+}
+
+static int check_cpu_wfie(uint32_t cpu_id, uint32_t wfie_msk)
+{
+ uint32_t cluster_id, loop = 0;
+
+ if (cpu_id >= PLATFORM_CLUSTER0_CORE_COUNT) {
+ cluster_id = 1;
+ cpu_id -= PLATFORM_CLUSTER0_CORE_COUNT;
+ } else {
+ cluster_id = 0;
+ }
+
+ /*
+ * wfe/wfi tracking not possible, hopefully the host
+ * was successful in enabling wfe/wfi.
+ * We'll give a bit of additional time, like the kernel does.
+ */
+ if ((cluster_id && clstb_cpu_wfe < 0) ||
+ (!cluster_id && clstl_cpu_wfe < 0)) {
+ mdelay(1);
+ return 0;
+ }
+
+ if (cluster_id)
+ wfie_msk <<= (clstb_cpu_wfe + cpu_id);
+ else
+ wfie_msk <<= (clstl_cpu_wfe + cpu_id);
+
+ while (!(mmio_read_32(CHECK_CPU_WFIE_BASE) & wfie_msk) &&
+ (loop < CHK_CPU_LOOP)) {
+ udelay(1);
+ loop++;
+ }
+
+ if ((mmio_read_32(CHECK_CPU_WFIE_BASE) & wfie_msk) == 0) {
+ WARN("%s: %d, %d, %d, error!\n", __func__,
+ cluster_id, cpu_id, wfie_msk);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#endif /* PMU_COM_H */
diff --git a/plat/rockchip/common/include/plat_macros.S b/plat/rockchip/common/include/plat_macros.S
new file mode 100644
index 0000000..691beeb
--- /dev/null
+++ b/plat/rockchip/common/include/plat_macros.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ROCKCHIP_PLAT_MACROS_S
+#define ROCKCHIP_PLAT_MACROS_S
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+ .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+ .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+ .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \
+ " Offset:\t\t\tvalue\n"
+newline:
+ .asciz "\n"
+spacer:
+ .asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+ .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+ /* ---------------------------------------------
+ * The below utility macro prints out relevant GIC
+ * and CCI registers whenever an unhandled
+ * exception is taken in BL31.
+ * Expects: GICD base in x26, GICC base in x27
+ * Clobbers: x0 - x10, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+
+ mov_imm x26, PLAT_RK_GICD_BASE
+ mov_imm x27, PLAT_RK_GICC_BASE
+
+ /* Check for GICv3 system register access */
+ mrs x7, id_aa64pfr0_el1
+ ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+ cmp x7, #1
+ b.ne print_gicv2
+
+ /* Check for SRE enable */
+ mrs x8, ICC_SRE_EL3
+ tst x8, #ICC_SRE_SRE_BIT
+ b.eq print_gicv2
+
+ /* Load the icc reg list to x6 */
+ adr x6, icc_regs
+ /* Load the icc regs to gp regs used by str_in_crash_buf_print */
+ mrs x8, ICC_HPPIR0_EL1
+ mrs x9, ICC_HPPIR1_EL1
+ mrs x10, ICC_CTLR_EL3
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+ b print_gic_common
+
+print_gicv2:
+ /* Load the gicc reg list to x6 */
+ adr x6, gicc_regs
+ /* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+ ldr w8, [x27, #GICC_HPPIR]
+ ldr w9, [x27, #GICC_AHPPIR]
+ ldr w10, [x27, #GICC_CTLR]
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+
+print_gic_common:
+ /* Print the GICD_ISPENDR regs */
+ add x7, x26, #GICD_ISPENDR
+ adr x4, gicd_pend_reg
+ bl asm_print_str
+gicd_ispendr_loop:
+ sub x4, x7, x26
+ cmp x4, #0x280
+ b.eq exit_print_gic_regs
+ bl asm_print_hex
+
+ adr x4, spacer
+ bl asm_print_str
+
+ ldr x4, [x7], #8
+ bl asm_print_hex
+
+ adr x4, newline
+ bl asm_print_str
+ b gicd_ispendr_loop
+exit_print_gic_regs:
+
+#if PLATFORM_CLUSTER_COUNT > 1
+ adr x6, cci_iface_regs
+ /* Store in x7 the base address of the first interface */
+ mov_imm x7, (PLAT_RK_CCI_BASE + SLAVE_IFACE_OFFSET( \
+ PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX))
+ ldr w8, [x7, #SNOOP_CTRL_REG]
+ /* Store in x7 the base address of the second interface */
+ mov_imm x7, (PLAT_RK_CCI_BASE + SLAVE_IFACE_OFFSET( \
+ PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX))
+ ldr w9, [x7, #SNOOP_CTRL_REG]
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+#endif
+ .endm
+
+#endif /* ROCKCHIP_PLAT_MACROS_S */
diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h
new file mode 100644
index 0000000..95b850f
--- /dev/null
+++ b/plat/rockchip/common/include/plat_params.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PARAMS_H
+#define PLAT_PARAMS_H
+
+#include <stdint.h>
+
+#include <export/plat/rockchip/common/plat_params_exp.h>
+
+#endif /* PLAT_PARAMS_H */
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
new file mode 100644
index 0000000..990d106
--- /dev/null
+++ b/plat/rockchip/common/include/plat_private.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <lib/mmio.h>
+#include <plat_params.h>
+
+#define __sramdata __attribute__((section(".sram.data")))
+#define __sramconst __attribute__((section(".sram.rodata")))
+#define __sramfunc __attribute__((section(".sram.text")))
+
+#define __pmusramdata __attribute__((section(".pmusram.data")))
+#define __pmusramconst __attribute__((section(".pmusram.rodata")))
+#define __pmusramfunc __attribute__((section(".pmusram.text")))
+
+extern uint32_t __bl31_sram_text_start, __bl31_sram_text_end;
+extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end;
+extern uint32_t __bl31_sram_stack_start, __bl31_sram_stack_end;
+extern uint32_t __bl31_sram_text_real_end, __bl31_sram_data_real_end;
+extern uint32_t __sram_incbin_start, __sram_incbin_end;
+extern uint32_t __sram_incbin_real_end;
+
+/******************************************************************************
+ * The register have write-mask bits, it is mean, if you want to set the bits,
+ * you needs set the write-mask bits at the same time,
+ * The write-mask bits is in high 16-bits.
+ * The fllowing macro definition helps access write-mask bits reg efficient!
+ ******************************************************************************/
+#define REG_MSK_SHIFT 16
+
+#ifndef WMSK_BIT
+#define WMSK_BIT(nr) BIT((nr) + REG_MSK_SHIFT)
+#endif
+
+/* set one bit with write mask */
+#ifndef BIT_WITH_WMSK
+#define BIT_WITH_WMSK(nr) (BIT(nr) | WMSK_BIT(nr))
+#endif
+
+#ifndef BITS_SHIFT
+#define BITS_SHIFT(bits, shift) (bits << (shift))
+#endif
+
+#ifndef BITS_WITH_WMASK
+#define BITS_WITH_WMASK(bits, msk, shift)\
+ (BITS_SHIFT(bits, shift) | BITS_SHIFT(msk, (shift + REG_MSK_SHIFT)))
+#endif
+
+/******************************************************************************
+ * Function and variable prototypes
+ *****************************************************************************/
+#ifdef __aarch64__
+void plat_configure_mmu_el3(unsigned long total_base,
+ unsigned long total_size,
+ unsigned long,
+ unsigned long,
+ unsigned long,
+ unsigned long);
+
+void rockchip_plat_mmu_el3(void);
+#else
+void plat_configure_mmu_svc_mon(unsigned long total_base,
+ unsigned long total_size,
+ unsigned long,
+ unsigned long,
+ unsigned long,
+ unsigned long);
+
+void rockchip_plat_mmu_svc_mon(void);
+#endif
+
+void plat_cci_init(void);
+void plat_cci_enable(void);
+void plat_cci_disable(void);
+
+void plat_delay_timer_init(void);
+
+void params_early_setup(u_register_t plat_params_from_bl2);
+
+void plat_rockchip_gic_driver_init(void);
+void plat_rockchip_gic_init(void);
+void plat_rockchip_gic_cpuif_enable(void);
+void plat_rockchip_gic_cpuif_disable(void);
+void plat_rockchip_gic_pcpu_init(void);
+
+void plat_rockchip_pmu_init(void);
+void plat_rockchip_soc_init(void);
+uintptr_t plat_get_sec_entrypoint(void);
+
+void platform_cpu_warmboot(void);
+
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void);
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void);
+struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count);
+struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void);
+void plat_rockchip_gpio_init(void);
+void plat_rockchip_save_gpio(void);
+void plat_rockchip_restore_gpio(void);
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint);
+int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl,
+ plat_local_state_t lvl_state);
+int rockchip_soc_cores_pwr_dm_off(void);
+int rockchip_soc_sys_pwr_dm_suspend(void);
+int rockchip_soc_cores_pwr_dm_suspend(void);
+int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl,
+ plat_local_state_t lvl_state);
+int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl,
+ plat_local_state_t lvl_state);
+int rockchip_soc_cores_pwr_dm_on_finish(void);
+int rockchip_soc_sys_pwr_dm_resume(void);
+
+int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl,
+ plat_local_state_t lvl_state);
+int rockchip_soc_cores_pwr_dm_resume(void);
+void __dead2 rockchip_soc_soft_reset(void);
+void __dead2 rockchip_soc_system_off(void);
+void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(
+ const psci_power_state_t *target_state);
+void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void);
+
+extern const unsigned char rockchip_power_domain_tree_desc[];
+
+extern void *pmu_cpuson_entrypoint;
+extern u_register_t cpuson_entry_point[PLATFORM_CORE_COUNT];
+extern uint32_t cpuson_flags[PLATFORM_CORE_COUNT];
+
+extern const mmap_region_t plat_rk_mmap[];
+
+uint32_t rockchip_get_uart_base(void);
+uint32_t rockchip_get_uart_baudrate(void);
+uint32_t rockchip_get_uart_clock(void);
+
+#endif /* __ASSEMBLER__ */
+
+/******************************************************************************
+ * cpu up status
+ * The bits of macro value is not more than 12 bits for cmp instruction!
+ ******************************************************************************/
+#define PMU_CPU_HOTPLUG 0xf00
+#define PMU_CPU_AUTO_PWRDN 0xf0
+#define PMU_CLST_RET 0xa5
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/rockchip/common/include/rockchip_sip_svc.h b/plat/rockchip/common/include/rockchip_sip_svc.h
new file mode 100644
index 0000000..340d653
--- /dev/null
+++ b/plat/rockchip/common/include/rockchip_sip_svc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ROCKCHIP_SIP_SVC_H
+#define ROCKCHIP_SIP_SVC_H
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT 0x8200ff00
+#define SIP_SVC_UID 0x8200ff01
+#define SIP_SVC_VERSION 0x8200ff03
+
+/* rockchip SiP Service Calls version numbers */
+#define RK_SIP_SVC_VERSION_MAJOR 0x0
+#define RK_SIP_SVC_VERSION_MINOR 0x1
+
+/* Number of ROCKCHIP SiP Calls implemented */
+#define RK_COMMON_SIP_NUM_CALLS 0x3
+
+enum {
+ RK_SIP_E_SUCCESS = 0,
+ RK_SIP_E_INVALID_PARAM = -1
+};
+
+#endif /* ROCKCHIP_SIP_SVC_H */
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
new file mode 100644
index 0000000..68054ad
--- /dev/null
+++ b/plat/rockchip/common/params_setup.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+
+#include <lib/bl_aux_params/bl_aux_params.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/gpio.h>
+#include <libfdt.h>
+#include <lib/coreboot.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_params.h>
+#include <plat_private.h>
+
+static struct bl_aux_gpio_info rst_gpio = { .index = UINT_MAX } ;
+static struct bl_aux_gpio_info poweroff_gpio = { .index = UINT_MAX };
+static struct bl_aux_gpio_info suspend_gpio[10];
+uint32_t suspend_gpio_cnt;
+static struct bl_aux_rk_apio_info suspend_apio;
+
+#if COREBOOT
+static int dt_process_fdt(u_register_t param_from_bl2)
+{
+ return -ENODEV;
+}
+#else
+static uint32_t rk_uart_base = PLAT_RK_UART_BASE;
+static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE;
+static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK;
+#define FDT_BUFFER_SIZE 0x20000
+static uint64_t fdt_buffer[FDT_BUFFER_SIZE / 8];
+
+void *plat_get_fdt(void)
+{
+ return &fdt_buffer[0];
+}
+
+static void plat_rockchip_dt_process_fdt_uart(void *fdt)
+{
+ const char *path_name = "/chosen";
+ const char *prop_name = "stdout-path";
+ int node_offset;
+ int stdout_path_len;
+ const char *stdout_path;
+ const char *separator;
+ const char *baud_start;
+ char serial_char;
+ int serial_no;
+ uint32_t uart_base;
+ uint32_t baud;
+
+ node_offset = fdt_path_offset(fdt, path_name);
+ if (node_offset < 0)
+ return;
+
+ stdout_path = fdt_getprop(fdt, node_offset, prop_name,
+ &stdout_path_len);
+ if (stdout_path == NULL)
+ return;
+
+ /*
+ * We expect something like:
+ * "serial0:baudrate"
+ */
+ if (strncmp("serial", stdout_path, 6) != 0)
+ return;
+
+ serial_char = stdout_path[6];
+ serial_no = serial_char - '0';
+
+ switch (serial_no) {
+ case 0:
+ uart_base = UART0_BASE;
+ break;
+ case 1:
+ uart_base = UART1_BASE;
+ break;
+ case 2:
+ uart_base = UART2_BASE;
+ break;
+#ifdef UART3_BASE
+ case 3:
+ uart_base = UART3_BASE;
+ break;
+#endif
+#ifdef UART4_BASE
+ case 4:
+ uart_base = UART4_BASE;
+ break;
+#endif
+#ifdef UART5_BASE
+ case 5:
+ uart_base = UART5_BASE;
+ break;
+#endif
+ default:
+ return;
+ }
+
+ rk_uart_base = uart_base;
+
+ separator = strchr(stdout_path, ':');
+ if (!separator)
+ return;
+
+ baud = 0;
+ baud_start = separator + 1;
+ while (*baud_start != '\0') {
+ /*
+ * uart binding is <baud>{<parity>{<bits>{...}}}
+ * So the baudrate either is the whole string, or
+ * we end in the parity characters.
+ */
+ if (*baud_start == 'n' || *baud_start == 'o' ||
+ *baud_start == 'e')
+ break;
+
+ baud = baud * 10 + (*baud_start - '0');
+ baud_start++;
+ }
+
+ rk_uart_baudrate = baud;
+}
+
+static int dt_process_fdt(u_register_t param_from_bl2)
+{
+ void *fdt = plat_get_fdt();
+ int ret;
+
+ ret = fdt_open_into((void *)param_from_bl2, fdt, FDT_BUFFER_SIZE);
+ if (ret < 0)
+ return ret;
+
+ plat_rockchip_dt_process_fdt_uart(fdt);
+
+ return 0;
+}
+#endif
+
+uint32_t rockchip_get_uart_base(void)
+{
+#if COREBOOT
+ return coreboot_serial.baseaddr;
+#else
+ return rk_uart_base;
+#endif
+}
+
+uint32_t rockchip_get_uart_baudrate(void)
+{
+#if COREBOOT
+ return coreboot_serial.baud;
+#else
+ return rk_uart_baudrate;
+#endif
+}
+
+uint32_t rockchip_get_uart_clock(void)
+{
+#if COREBOOT
+ return coreboot_serial.input_hertz;
+#else
+ return rk_uart_clock;
+#endif
+}
+
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void)
+{
+ if (rst_gpio.index == UINT_MAX)
+ return NULL;
+
+ return &rst_gpio;
+}
+
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void)
+{
+ if (poweroff_gpio.index == UINT_MAX)
+ return NULL;
+
+ return &poweroff_gpio;
+}
+
+struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count)
+{
+ *count = suspend_gpio_cnt;
+
+ return &suspend_gpio[0];
+}
+
+struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void)
+{
+ return &suspend_apio;
+}
+
+static bool rk_aux_param_handler(struct bl_aux_param_header *param)
+{
+ /* Store platform parameters for later processing if needed. */
+ switch (param->type) {
+ case BL_AUX_PARAM_RK_RESET_GPIO:
+ rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
+ return true;
+ case BL_AUX_PARAM_RK_POWEROFF_GPIO:
+ poweroff_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
+ return true;
+ case BL_AUX_PARAM_RK_SUSPEND_GPIO:
+ if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) {
+ ERROR("Exceeded the supported suspend GPIO number.\n");
+ return true;
+ }
+ suspend_gpio[suspend_gpio_cnt++] =
+ ((struct bl_aux_param_gpio *)param)->gpio;
+ return true;
+ case BL_AUX_PARAM_RK_SUSPEND_APIO:
+ suspend_apio = ((struct bl_aux_param_rk_apio *)param)->apio;
+ return true;
+ }
+
+ return false;
+}
+
+void params_early_setup(u_register_t plat_param_from_bl2)
+{
+ int ret;
+
+ /*
+ * Test if this is a FDT passed as a platform-specific parameter
+ * block.
+ */
+ ret = dt_process_fdt(plat_param_from_bl2);
+ if (!ret) {
+ return;
+ } else if (ret != -FDT_ERR_BADMAGIC) {
+ /*
+ * If we found an FDT but couldn't parse it (e.g. corrupt, not
+ * enough space), return and don't attempt to parse the param
+ * as something else, since we know that will also fail. All
+ * we're doing is setting up UART, this doesn't need to be
+ * fatal.
+ */
+ WARN("%s: found FDT but could not parse: error %d\n",
+ __func__, ret);
+ return;
+ }
+
+ bl_aux_params_parse(plat_param_from_bl2, rk_aux_param_handler);
+}
diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c
new file mode 100644
index 0000000..6926887
--- /dev/null
+++ b/plat/rockchip/common/plat_pm.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/psci/psci.h>
+
+#include <plat_private.h>
+
+/* Macros to read the rk power domain state */
+#define RK_CORE_PWR_STATE(state) \
+ ((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define RK_CLUSTER_PWR_STATE(state) \
+ ((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define RK_SYSTEM_PWR_STATE(state) \
+ ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+static uintptr_t rockchip_sec_entrypoint;
+
+#pragma weak rockchip_soc_cores_pwr_dm_on
+#pragma weak rockchip_soc_hlvl_pwr_dm_off
+#pragma weak rockchip_soc_cores_pwr_dm_off
+#pragma weak rockchip_soc_sys_pwr_dm_suspend
+#pragma weak rockchip_soc_cores_pwr_dm_suspend
+#pragma weak rockchip_soc_hlvl_pwr_dm_suspend
+#pragma weak rockchip_soc_hlvl_pwr_dm_on_finish
+#pragma weak rockchip_soc_cores_pwr_dm_on_finish
+#pragma weak rockchip_soc_sys_pwr_dm_resume
+#pragma weak rockchip_soc_hlvl_pwr_dm_resume
+#pragma weak rockchip_soc_cores_pwr_dm_resume
+#pragma weak rockchip_soc_soft_reset
+#pragma weak rockchip_soc_system_off
+#pragma weak rockchip_soc_sys_pd_pwr_dn_wfi
+#pragma weak rockchip_soc_cores_pd_pwr_dn_wfi
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl,
+ plat_local_state_t lvl_state)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_off(void)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_suspend(void)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl,
+ plat_local_state_t lvl_state)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl,
+ plat_local_state_t lvl_state)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl,
+ plat_local_state_t lvl_state)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_resume(void)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+ while (1)
+ ;
+}
+
+void __dead2 rockchip_soc_system_off(void)
+{
+ while (1)
+ ;
+}
+
+void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(
+ const psci_power_state_t *target_state)
+{
+ psci_power_down_wfi();
+}
+
+void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
+{
+ psci_power_down_wfi();
+}
+
+/*******************************************************************************
+ * Rockchip standard platform handler called to check the validity of the power
+ * state parameter.
+ ******************************************************************************/
+int rockchip_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ int pstate = psci_get_pstate_type(power_state);
+ int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+ int i;
+
+ assert(req_state);
+
+ if (pwr_lvl > PLAT_MAX_PWR_LVL)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Sanity check the requested state */
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ /*
+ * It's probably to enter standby only on power level 0
+ * ignore any other power level.
+ */
+ if (pwr_lvl != MPIDR_AFFLVL0)
+ return PSCI_E_INVALID_PARAMS;
+
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] =
+ PLAT_MAX_RET_STATE;
+ } else {
+ for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+ req_state->pwr_domain_state[i] =
+ PLAT_MAX_OFF_STATE;
+
+ for (i = (pwr_lvl + 1); i <= PLAT_MAX_PWR_LVL; i++)
+ req_state->pwr_domain_state[i] =
+ PLAT_MAX_RET_STATE;
+ }
+
+ /* We expect the 'state id' to be zero */
+ if (psci_get_pstate_id(power_state))
+ return PSCI_E_INVALID_PARAMS;
+
+ return PSCI_E_SUCCESS;
+}
+
+void rockchip_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ int i;
+
+ for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+ req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+/*******************************************************************************
+ * RockChip handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+void rockchip_cpu_standby(plat_local_state_t cpu_state)
+{
+ u_register_t scr;
+
+ assert(cpu_state == PLAT_MAX_RET_STATE);
+
+ scr = read_scr_el3();
+ /* Enable PhysicalIRQ bit for NS world to wake the CPU */
+ write_scr_el3(scr | SCR_IRQ_BIT);
+ isb();
+ dsb();
+ wfi();
+
+ /*
+ * Restore SCR to the original value, synchronisation of scr_el3 is
+ * done by eret while el3_exit to save some execution cycles.
+ */
+ write_scr_el3(scr);
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+int rockchip_pwr_domain_on(u_register_t mpidr)
+{
+ return rockchip_soc_cores_pwr_dm_on(mpidr, rockchip_sec_entrypoint);
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void rockchip_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ uint32_t lvl;
+ plat_local_state_t lvl_state;
+ int ret;
+
+ assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE);
+
+ plat_rockchip_gic_cpuif_disable();
+
+ if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+ plat_cci_disable();
+
+ rockchip_soc_cores_pwr_dm_off();
+
+ for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+ lvl_state = target_state->pwr_domain_state[lvl];
+ ret = rockchip_soc_hlvl_pwr_dm_off(lvl, lvl_state);
+ if (ret == PSCI_E_NOT_SUPPORTED)
+ break;
+ }
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void rockchip_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ uint32_t lvl;
+ plat_local_state_t lvl_state;
+ int ret;
+
+ if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+ return;
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ plat_rockchip_gic_cpuif_disable();
+
+ if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+ rockchip_soc_sys_pwr_dm_suspend();
+ else
+ rockchip_soc_cores_pwr_dm_suspend();
+
+ /* Perform the common cluster specific operations */
+ if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+ plat_cci_disable();
+
+ if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+ return;
+
+ for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+ lvl_state = target_state->pwr_domain_state[lvl];
+ ret = rockchip_soc_hlvl_pwr_dm_suspend(lvl, lvl_state);
+ if (ret == PSCI_E_NOT_SUPPORTED)
+ break;
+ }
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void rockchip_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ uint32_t lvl;
+ plat_local_state_t lvl_state;
+ int ret;
+
+ assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE);
+
+ for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+ lvl_state = target_state->pwr_domain_state[lvl];
+ ret = rockchip_soc_hlvl_pwr_dm_on_finish(lvl, lvl_state);
+ if (ret == PSCI_E_NOT_SUPPORTED)
+ break;
+ }
+
+ rockchip_soc_cores_pwr_dm_on_finish();
+
+ /* Perform the common cluster specific operations */
+ if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+ /* Enable coherency if this cluster was off */
+ plat_cci_enable();
+ }
+
+ /* Enable the gic cpu interface */
+ plat_rockchip_gic_pcpu_init();
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ plat_rockchip_gic_cpuif_enable();
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ ******************************************************************************/
+void rockchip_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ uint32_t lvl;
+ plat_local_state_t lvl_state;
+ int ret;
+
+ /* Nothing to be done on waking up from retention from CPU level */
+ if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+ return;
+
+ if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+ rockchip_soc_sys_pwr_dm_resume();
+ goto comm_finish;
+ }
+
+ for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+ lvl_state = target_state->pwr_domain_state[lvl];
+ ret = rockchip_soc_hlvl_pwr_dm_resume(lvl, lvl_state);
+ if (ret == PSCI_E_NOT_SUPPORTED)
+ break;
+ }
+
+ rockchip_soc_cores_pwr_dm_resume();
+
+ /*
+ * Program the gic per-cpu distributor or re-distributor interface.
+ * For sys power domain operation, resuming of the gic needs to operate
+ * in rockchip_soc_sys_pwr_dm_resume(), according to the sys power mode
+ * implements.
+ */
+ plat_rockchip_gic_cpuif_enable();
+
+comm_finish:
+ /* Perform the common cluster specific operations */
+ if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+ /* Enable coherency if this cluster was off */
+ plat_cci_enable();
+ }
+}
+
+/*******************************************************************************
+ * RockChip handlers to reboot the system
+ ******************************************************************************/
+static void __dead2 rockchip_system_reset(void)
+{
+ rockchip_soc_soft_reset();
+}
+
+/*******************************************************************************
+ * RockChip handlers to power off the system
+ ******************************************************************************/
+static void __dead2 rockchip_system_poweroff(void)
+{
+ rockchip_soc_system_off();
+}
+
+static void __dead2 rockchip_pd_pwr_down_wfi(
+ const psci_power_state_t *target_state)
+{
+ if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+ rockchip_soc_sys_pd_pwr_dn_wfi();
+ else
+ rockchip_soc_cores_pd_pwr_dn_wfi(target_state);
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_rockchip_psci_pm_ops. The rockchip
+ * standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+const plat_psci_ops_t plat_rockchip_psci_pm_ops = {
+ .cpu_standby = rockchip_cpu_standby,
+ .pwr_domain_on = rockchip_pwr_domain_on,
+ .pwr_domain_off = rockchip_pwr_domain_off,
+ .pwr_domain_suspend = rockchip_pwr_domain_suspend,
+ .pwr_domain_on_finish = rockchip_pwr_domain_on_finish,
+ .pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish,
+ .pwr_domain_pwr_down_wfi = rockchip_pd_pwr_down_wfi,
+ .system_reset = rockchip_system_reset,
+ .system_off = rockchip_system_poweroff,
+ .validate_power_state = rockchip_validate_power_state,
+ .get_sys_suspend_power_state = rockchip_get_sys_suspend_power_state
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &plat_rockchip_psci_pm_ops;
+ rockchip_sec_entrypoint = sec_entrypoint;
+ return 0;
+}
+
+uintptr_t plat_get_sec_entrypoint(void)
+{
+ assert(rockchip_sec_entrypoint);
+ return rockchip_sec_entrypoint;
+}
diff --git a/plat/rockchip/common/plat_topology.c b/plat/rockchip/common/plat_topology.c
new file mode 100644
index 0000000..4987eeb
--- /dev/null
+++ b/plat/rockchip/common/plat_topology.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+#include <plat_private.h>
+
+/*******************************************************************************
+ * This function returns the RockChip default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return rockchip_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ unsigned int cluster_id, cpu_id;
+
+ cpu_id = mpidr & MPIDR_AFFLVL_MASK;
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+ cluster_id = mpidr & PLAT_RK_MPIDR_CLUSTER_MASK;
+#else
+ cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+#endif
+
+ cpu_id += (cluster_id >> PLAT_RK_CLST_TO_CPUID_SHIFT);
+
+ if (cpu_id >= PLATFORM_CORE_COUNT)
+ return -1;
+
+ return cpu_id;
+}
diff --git a/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S
new file mode 100644
index 0000000..6cea2ea
--- /dev/null
+++ b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cpus_on_fixed_addr.h>
+
+ .globl sys_sleep_flag_sram
+ .globl pmu_cpuson_entrypoint
+
+ .macro pmusram_entry_func _name
+ .section .pmusram.entry, "ax"
+ .type \_name, %function
+ .cfi_startproc
+ \_name:
+ .endm
+
+pmusram_entry_func pmu_cpuson_entrypoint
+ adr x5, sys_sleep_flag_sram
+ ldr w2, [x5, #PSRAM_DT_PM_FLAG]
+
+ tbz w2, #PM_WARM_BOOT_SHT, sys_resume_sp
+ ldr x1, =platform_cpu_warmboot
+ br x1
+sys_resume_sp:
+ adr x5, sys_sleep_flag_sram
+ ldr x1, [x5, #PSRAM_DT_SP]
+ mov sp, x1
+ddr_resume:
+ ldr x1, [x5, #PSRAM_DT_DDR_FUNC]
+ cmp x1, #0
+ b.eq sys_resume
+ blr x1
+sys_resume:
+ ldr x1, =bl31_warm_entrypoint
+ br x1
+endfunc pmu_cpuson_entrypoint
+
+ .section .pmusram.data, "a"
+ .align 3
+sys_sleep_flag_sram:
+ .rept PSRAM_DT_SIZE_WORDS
+ .word 0
+ .endr
diff --git a/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h
new file mode 100644
index 0000000..bcd2a7c
--- /dev/null
+++ b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CPU_ON_FIXED_ADDR_H__
+#define __CPU_ON_FIXED_ADDR_H__
+
+/*****************************************************************************
+ * define data offset in struct psram_data
+ *****************************************************************************/
+#define PSRAM_DT_SP 0x0
+#define PSRAM_DT_DDR_FUNC 0x8
+#define PSRAM_DT_DDR_DATA 0x10
+#define PSRAM_DT_DDRFLAG 0x18
+#define PSRAM_DT_MPIDR 0x1c
+#define PSRAM_DT_PM_FLAG 0x20
+#define PSRAM_DT_END 0x24
+
+/* reserve 4 byte */
+#define PSRAM_DT_END_RES4 (PSRAM_DT_END + 4)
+
+#define PSRAM_DT_SIZE_WORDS (PSRAM_DT_END_RES4 / 4)
+
+#define PM_WARM_BOOT_SHT 0
+#define PM_WARM_BOOT_BIT (1 << PM_WARM_BOOT_SHT)
+
+#ifndef __ASSEMBLER__
+
+struct psram_data_t {
+ uint64_t sp;
+ uint64_t ddr_func;
+ uint64_t ddr_data;
+ uint32_t ddr_flag;
+ uint32_t boot_mpidr;
+ uint32_t pm_flag;
+};
+
+CASSERT(__builtin_offsetof(struct psram_data_t, sp) == PSRAM_DT_SP,
+ assert_psram_dt_sp_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, ddr_func) == PSRAM_DT_DDR_FUNC,
+ assert_psram_dt_ddr_func_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, ddr_data) == PSRAM_DT_DDR_DATA,
+ assert_psram_dt_ddr_data_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, ddr_flag) == PSRAM_DT_DDRFLAG,
+ assert_psram_dt_ddr_flag_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, boot_mpidr) == PSRAM_DT_MPIDR,
+ assert_psram_dt_mpidr_offset_mistmatch);
+
+extern struct psram_data_t sys_sleep_flag_sram;
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/plat/rockchip/common/rockchip_gicv2.c b/plat/rockchip/common/rockchip_gicv2.c
new file mode 100644
index 0000000..8db2b30
--- /dev/null
+++ b/plat/rockchip/common/rockchip_gicv2.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/utils.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv2 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_rockchip_gic_driver_init
+#pragma weak plat_rockchip_gic_init
+#pragma weak plat_rockchip_gic_cpuif_enable
+#pragma weak plat_rockchip_gic_cpuif_disable
+#pragma weak plat_rockchip_gic_pcpu_init
+
+/******************************************************************************
+ * List of interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t g0_interrupt_props[] = {
+ PLAT_RK_GICV2_G0_IRQS
+};
+
+/*
+ * Ideally `rockchip_gic_data` structure definition should be a `const` but it
+ * is kept as modifiable for overwriting with different GICD and GICC base when
+ * running on FVP with VE memory map.
+ */
+gicv2_driver_data_t rockchip_gic_data = {
+ .gicd_base = PLAT_RK_GICD_BASE,
+ .gicc_base = PLAT_RK_GICC_BASE,
+ .interrupt_props = g0_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+/******************************************************************************
+ * RockChip common helper to initialize the GICv2 only driver.
+ *****************************************************************************/
+void plat_rockchip_gic_driver_init(void)
+{
+ gicv2_driver_init(&rockchip_gic_data);
+}
+
+void plat_rockchip_gic_init(void)
+{
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * RockChip common helper to enable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_enable(void)
+{
+ gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * RockChip common helper to disable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_disable(void)
+{
+ gicv2_cpuif_disable();
+}
+
+/******************************************************************************
+ * RockChip common helper to initialize the per cpu distributor interface
+ * in GICv2
+ *****************************************************************************/
+void plat_rockchip_gic_pcpu_init(void)
+{
+ gicv2_pcpu_distif_init();
+}
diff --git a/plat/rockchip/common/rockchip_gicv3.c b/plat/rockchip/common/rockchip_gicv3.c
new file mode 100644
index 0000000..edae2ef
--- /dev/null
+++ b/plat/rockchip/common/rockchip_gicv3.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_rockchip_gic_driver_init
+#pragma weak plat_rockchip_gic_init
+#pragma weak plat_rockchip_gic_cpuif_enable
+#pragma weak plat_rockchip_gic_cpuif_disable
+#pragma weak plat_rockchip_gic_pcpu_init
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t g01s_interrupt_props[] = {
+ PLAT_RK_GICV3_G0_IRQS,
+ PLAT_RK_GICV3_G1S_IRQS
+};
+
+static unsigned int plat_rockchip_mpidr_to_core_pos(unsigned long mpidr)
+{
+ return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+const gicv3_driver_data_t rockchip_gic_data = {
+ .gicd_base = PLAT_RK_GICD_BASE,
+ .gicr_base = PLAT_RK_GICR_BASE,
+ .interrupt_props = g01s_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(g01s_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = rdistif_base_addrs,
+ .mpidr_to_core_pos = plat_rockchip_mpidr_to_core_pos,
+};
+
+void plat_rockchip_gic_driver_init(void)
+{
+ /*
+ * The GICv3 driver is initialized in EL3 and does not need
+ * to be initialized again in SEL1. This is because the S-EL1
+ * can use GIC system registers to manage interrupts and does
+ * not need GIC interface base addresses to be configured.
+ */
+#ifdef IMAGE_BL31
+ gicv3_driver_init(&rockchip_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * RockChip common helper to initialize the GIC. Only invoked
+ * by BL31
+ *****************************************************************************/
+void plat_rockchip_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * RockChip common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * RockChip common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * RockChip common helper to initialize the per-cpu redistributor interface
+ * in GICv3
+ *****************************************************************************/
+void plat_rockchip_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/rockchip/common/rockchip_sip_svc.c b/plat/rockchip/common/rockchip_sip_svc.c
new file mode 100644
index 0000000..27ef042
--- /dev/null
+++ b/plat/rockchip/common/rockchip_sip_svc.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+/* Rockchip SiP Service UUID */
+DEFINE_SVC_UUID2(rk_sip_svc_uid,
+ 0xe2c76fe8, 0x3e31, 0xe611, 0xb7, 0x0d,
+ 0x8f, 0x88, 0xee, 0x74, 0x7b, 0x72);
+
+#pragma weak rockchip_plat_sip_handler
+uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+}
+
+/*
+ * This function is responsible for handling all SiP calls from the NS world
+ */
+uintptr_t sip_smc_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ uint32_t ns;
+
+ /* Determine which security state this SMC originated from */
+ ns = is_caller_non_secure(flags);
+ if (!ns)
+ SMC_RET1(handle, SMC_UNK);
+
+ switch (smc_fid) {
+ case SIP_SVC_CALL_COUNT:
+ /* Return the number of Rockchip SiP Service Calls. */
+ SMC_RET1(handle,
+ RK_COMMON_SIP_NUM_CALLS + RK_PLAT_SIP_NUM_CALLS);
+
+ case SIP_SVC_UID:
+ /* Return UID to the caller */
+ SMC_UUID_RET(handle, rk_sip_svc_uid);
+
+ case SIP_SVC_VERSION:
+ /* Return the version of current implementation */
+ SMC_RET2(handle, RK_SIP_SVC_VERSION_MAJOR,
+ RK_SIP_SVC_VERSION_MINOR);
+
+ default:
+ return rockchip_plat_sip_handler(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+ rockchip_sip_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ NULL,
+ sip_smc_handler
+);
diff --git a/plat/rockchip/common/rockchip_stack_protector.c b/plat/rockchip/common/rockchip_stack_protector.c
new file mode 100644
index 0000000..1898977
--- /dev/null
+++ b/plat/rockchip/common/rockchip_stack_protector.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL)
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+ /*
+ * Ideally, a random number should be returned instead of the
+ * combination of a timer's value and a compile-time constant.
+ * As the virt platform does not have any random number generator,
+ * this is better than nothing but not necessarily really secure.
+ */
+ return RANDOM_CANARY_VALUE ^ read_cntpct_el0();
+}
+
diff --git a/plat/rockchip/common/sp_min_plat_setup.c b/plat/rockchip/common/sp_min_plat_setup.c
new file mode 100644
index 0000000..8fb3f8e
--- /dev/null
+++ b/plat/rockchip/common/sp_min_plat_setup.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+static entry_point_info_t bl33_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type.
+ * A NULL pointer is returned if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
+{
+ entry_point_info_t *next_image_info;
+
+ next_image_info = &bl33_ep_info;
+
+ if (next_image_info->pc == 0U) {
+ return NULL;
+ }
+
+ return next_image_info;
+}
+
+#pragma weak params_early_setup
+void params_early_setup(u_register_t plat_param_from_bl2)
+{
+}
+
+unsigned int plat_is_my_cpu_primary(void);
+
+/*******************************************************************************
+ * Perform any BL32 specific platform actions.
+ ******************************************************************************/
+void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ static console_t console;
+
+ params_early_setup(arg1);
+
+ if (rockchip_get_uart_base() != 0)
+ console_16550_register(rockchip_get_uart_base(),
+ rockchip_get_uart_clock(),
+ rockchip_get_uart_baudrate(), &console);
+
+ VERBOSE("sp_min_setup\n");
+
+ bl31_params_parse_helper(arg0, NULL, &bl33_ep_info);
+}
+
+/*******************************************************************************
+ * Perform any sp_min platform setup code
+ ******************************************************************************/
+void sp_min_platform_setup(void)
+{
+ generic_delay_timer_init();
+ plat_rockchip_soc_init();
+
+ /* Initialize the gic cpu and distributor interfaces */
+ plat_rockchip_gic_driver_init();
+ plat_rockchip_gic_init();
+ plat_rockchip_pmu_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void sp_min_plat_arch_setup(void)
+{
+ plat_cci_init();
+ plat_cci_enable();
+
+ plat_configure_mmu_svc_mon(BL_CODE_BASE,
+ BL_COHERENT_RAM_END - BL_CODE_BASE,
+ BL_CODE_BASE,
+ BL_CODE_END,
+ BL_COHERENT_RAM_BASE,
+ BL_COHERENT_RAM_END);
+}
+
+void sp_min_plat_fiq_handler(uint32_t id)
+{
+ VERBOSE("[sp_min] interrupt #%d\n", id);
+}