Commit 8742f857 authored by Soby Mathew's avatar Soby Mathew Committed by TrustedFirmware Code Review
Browse files

Merge changes from topic "rk3288" into integration

* changes:
  rockchip: document platform
  rockchip: add support for rk3288
  rockchip: add common aarch32 support
  rockchip: rk3328: drop double declaration of entry_point storage
  rockchip: Allow socs with undefined wfe check bits
  rockchip: move pmusram assembler code to a aarch64 subdir
  sp_min: allow inclusion of a platform-specific linker script
  sp_min: make sp_min_warm_entrypoint public
  drivers: ti: uart: add a aarch32 variant
parents 28dab587 55617251
......@@ -16,6 +16,9 @@ MEMORY {
RAM (rwx): ORIGIN = BL32_BASE, LENGTH = BL32_LIMIT - BL32_BASE
}
#ifdef PLAT_SP_MIN_EXTRA_LD_SCRIPT
#include <plat_sp_min.ld.S>
#endif
SECTIONS
{
......
......@@ -7,7 +7,6 @@
#ifndef SP_MIN_PRIVATE_H
#define SP_MIN_PRIVATE_H
void sp_min_warm_entrypoint(void);
void sp_min_main(void);
void sp_min_warm_boot(void);
void sp_min_fiq(void);
......
Trusted Firmware-A for Rockchip SoCs
====================================
Trusted Firmware-A supports a number of Rockchip ARM SoCs from both
AARCH32 and AARCH64 fields.
This includes right now:
- rk3288: Quad-Core Cortex-A17 (past A12)
- rk3328: Quad-Core Cortex-A53
- rk3368: Octa-Core Cortex-A53
- rk3399: Hexa-Core Cortex-A53/A72
Boot Sequence
=============
For AARCH32:
Bootrom --> BL1/BL2 --> BL32 --> BL33 --> Linux kernel
For AARCH64:
Bootrom --> BL1/BL2 --> BL31 --> BL33 --> Linux kernel
BL1/2 and BL33 can currently be supplied from either:
- Coreboot + Depthcharge
- U-Boot - either separately as TPL+SPL or only SPL
How to build
============
Rockchip SoCs expect TF-A's BL31 (AARCH64) or BL32 (AARCH32) to get
integrated with other boot software like U-Boot or Coreboot, so only
these images need to get build from the TF-A repository.
For AARCH64 architectures the build command looks like
make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3399 bl32
while AARCH32 needs a slightly different command
make ARCH=aarch32 CROSS_COMPILE=arm-linux-gnueabihf- PLAT=rk3288 AARCH32_SP=sp_min bl32
Both need replacing the PLAT argument with the platform from above you
want to build for and the CROSS_COMPILE argument with you cross-
compilation toolchain.
How to deploy
=============
Both upstream U-Boot and Coreboot projects contain instructions on where
to put the built images during their respective build process.
So after successfully building TF-A just follow their build instructions
to continue.
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <console_macros.S>
#include <drivers/ti/uart/uart_16550.h>
/*
* "core" functions are low-level implementations that don't require
* writable memory and are thus safe to call in BL1 crash context.
*/
.globl console_16550_core_init
.globl console_16550_core_putc
.globl console_16550_core_getc
.globl console_16550_core_flush
.globl console_16550_putc
.globl console_16550_getc
.globl console_16550_flush
/* -----------------------------------------------
* int console_16550_core_init(uintptr_t base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
* crash reporting.
* In: r0 - console base address
* r1 - Uart clock in Hz
* r2 - Baud rate
* Out: return 1 on success, 0 on error
* Clobber list : r1, r2, r3
* -----------------------------------------------
*/
func console_16550_core_init
/* Check the input base address */
cmp r0, #0
beq init_fail
/* Check baud rate and uart clock for sanity */
cmp r1, #0
beq init_fail
cmp r2, #0
beq init_fail
/* Program the baudrate */
/* Divisor = Uart clock / (16 * baudrate) */
lsl r2, r2, #4
udiv r2, r1, r2
and r1, r2, #0xff /* w1 = DLL */
lsr r2, r2, #8
and r2, r2, #0xff /* w2 = DLLM */
ldr r3, [r0, #UARTLCR]
orr r3, r3, #UARTLCR_DLAB
str r3, [r0, #UARTLCR] /* enable DLL, DLLM programming */
str r1, [r0, #UARTDLL] /* program DLL */
str r2, [r0, #UARTDLLM] /* program DLLM */
mov r2, #~UARTLCR_DLAB
and r3, r3, r2
str r3, [r0, #UARTLCR] /* disable DLL, DLLM programming */
/* 8n1 */
mov r3, #3
str r3, [r0, #UARTLCR]
/* no interrupt */
mov r3, #0
str r3, [r0, #UARTIER]
#ifdef TI_16550_MDR_QUIRK
/* UART must be enabled on some platforms via the MDR register */
str r3, [r0, #UARTMDR1]
#endif /* TI_16550_MDR_QUIRK */
/* enable fifo, DMA */
mov r3, #(UARTFCR_FIFOEN | UARTFCR_DMAEN)
str r3, [r0, #UARTFCR]
/* DTR + RTS */
mov r3, #3
str r3, [r0, #UARTMCR]
mov r0, #1
bx lr
init_fail:
mov r0, #0
bx lr
endfunc console_16550_core_init
.globl console_16550_register
/* -------------------------------------------------------
* int console_stm32_register(uintptr_t baseaddr,
* uint32_t clock, uint32_t baud,
* struct console_stm32 *console);
* Function to initialize and register a new STM32
* console. Storage passed in for the console struct
* *must* be persistent (i.e. not from the stack).
* In: r0 - UART register base address
* r1 - UART clock in Hz
* r2 - Baud rate
* r3 - pointer to empty console_stm32 struct
* Out: return 1 on success, 0 on error
* Clobber list : r0, r1, r2
* -------------------------------------------------------
*/
func console_16550_register
push {r4, lr}
mov r4, r3
cmp r4, #0
beq register_fail
str r0, [r4, #CONSOLE_T_16550_BASE]
bl console_16550_core_init
cmp r0, #0
beq register_fail
mov r0, r4
pop {r4, lr}
finish_console_register 16550 putc=1, getc=1, flush=1
register_fail:
pop {r4, pc}
endfunc console_16550_register
/* --------------------------------------------------------
* int console_16550_core_putc(int c, uintptr_t base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : r0 - character to be printed
* r1 - console base address
* Out : return -1 on error else return character.
* Clobber list : r2
* --------------------------------------------------------
*/
func console_16550_core_putc
#if ENABLE_ASSERTIONS
cmp r1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Prepend '\r' to '\n' */
cmp r0, #0xA
bne 2f
/* Check if the transmit FIFO is full */
1: ldr r2, [r1, #UARTLSR]
and r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
cmp r2, #(UARTLSR_TEMT | UARTLSR_THRE)
bne 1b
mov r2, #0xD /* '\r' */
str r2, [r1, #UARTTX]
/* Check if the transmit FIFO is full */
2: ldr r2, [r1, #UARTLSR]
and r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
cmp r2, #(UARTLSR_TEMT | UARTLSR_THRE)
bne 2b
str r0, [r1, #UARTTX]
bx lr
endfunc console_16550_core_putc
/* --------------------------------------------------------
* int console_16550_putc(int c, console_16550_t *console)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : r0 - character to be printed
* r1 - pointer to console_t structure
* Out : return -1 on error else return character.
* Clobber list : r2
* --------------------------------------------------------
*/
func console_16550_putc
#if ENABLE_ASSERTIONS
cmp r1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr r1, [r1, #CONSOLE_T_16550_BASE]
b console_16550_core_putc
endfunc console_16550_putc
/* ---------------------------------------------
* int console_16550_core_getc(uintptr_t base_addr)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on if no character is available.
* In : r0 - console base address
* Clobber list : r0, r1
* ---------------------------------------------
*/
func console_16550_core_getc
#if ENABLE_ASSERTIONS
cmp r0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Check if the receive FIFO is empty */
1: ldr r1, [r0, #UARTLSR]
tst r1, #UARTLSR_RDR_BIT
beq no_char
ldr r1, [r0, #UARTRX]
mov r0, r1
bx lr
no_char:
mov r0, #ERROR_NO_PENDING_CHAR
bx lr
endfunc console_16550_core_getc
/* ---------------------------------------------
* int console_16550_getc(console_16550_t *console)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on if no character is available.
* In : r0 - pointer to console_t stucture
* Out : r0 - character if available, else -1
* Clobber list : r0, r1
* ---------------------------------------------
*/
func console_16550_getc
#if ENABLE_ASSERTIONS
cmp r0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr r0, [r0, #CONSOLE_T_16550_BASE]
b console_16550_core_getc
endfunc console_16550_getc
/* ---------------------------------------------
* int console_16550_core_flush(uintptr_t base_addr)
* Function to force a write of all buffered
* data that hasn't been output.
* In : r0 - console base address
* Out : return -1 on error else return 0.
* Clobber list : r0, r1
* ---------------------------------------------
*/
func console_16550_core_flush
#if ENABLE_ASSERTIONS
cmp r0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Loop until the transmit FIFO is empty */
1: ldr r1, [r0, #UARTLSR]
and r1, r1, #(UARTLSR_TEMT | UARTLSR_THRE)
cmp r1, #(UARTLSR_TEMT | UARTLSR_THRE)
bne 1b
mov r0, #0
bx lr
endfunc console_16550_core_flush
/* ---------------------------------------------
* int console_16550_flush(console_pl011_t *console)
* Function to force a write of all buffered
* data that hasn't been output.
* In : r0 - pointer to console_t structure
* Out : return -1 on error else return 0.
* Clobber list : r0, r1
* ---------------------------------------------
*/
func console_16550_flush
#if ENABLE_ASSERTIONS
cmp r0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr r0, [r0, #CONSOLE_T_16550_BASE]
b console_16550_core_flush
endfunc console_16550_flush
......@@ -18,6 +18,7 @@ void sp_min_platform_setup(void);
void sp_min_plat_runtime_setup(void);
void sp_min_plat_arch_setup(void);
entry_point_info_t *sp_min_plat_get_bl33_ep_info(void);
void sp_min_warm_entrypoint(void);
/* Platforms that enable SP_MIN_WITH_SECURE_FIQ shall implement this api */
void sp_min_plat_fiq_handler(uint32_t id);
......
......@@ -208,6 +208,8 @@ RockChip platform port
:M: Tony Xie <tony.xie@rock-chips.com>
:G: `TonyXie06`_
:G: `rockchip-linux`_
:M: Heiko Stuebner <heiko@sntech.de>
:G: `mmind`_
:F: plat/rockchip/
STM32MP1 platform port
......@@ -277,6 +279,7 @@ Xilinx platform port
.. _niej: https://github.com/niej
.. _kostapr: https://github.com/kostapr
.. _masahir0y: https://github.com/masahir0y
.. _mmind: https://github.com/mmind
.. _mtk09422: https://github.com/mtk09422
.. _npoushin: https://github.com/npoushin
.. _qoriq-open-source: https://github.com/qoriq-open-source
......
/*
* 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
/*
* 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)
{
}
/*
* 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
......@@ -88,6 +88,17 @@ static int check_cpu_wfie(uint32_t cpu_id, uint32_t wfie_msk)
cluster_id = 0;
}
/*
* wfe/wfi tracking not possible, hopefully the host
* was sucessful 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
......
......@@ -68,6 +68,16 @@ struct rockchip_bl31_params {
/******************************************************************************
* Function and variable prototypes
*****************************************************************************/
#ifdef AARCH32
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);
#else
void plat_configure_mmu_el3(unsigned long total_base,
unsigned long total_size,
unsigned long,
......@@ -75,6 +85,9 @@ void plat_configure_mmu_el3(unsigned long total_base,
unsigned long,
unsigned long);
void rockchip_plat_mmu_el3(void);
#endif
void plat_cci_init(void);
void plat_cci_enable(void);
void plat_cci_disable(void);
......@@ -128,13 +141,11 @@ 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 uint64_t cpuson_entry_point[PLATFORM_CORE_COUNT];
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[];
void rockchip_plat_mmu_el3(void);
#endif /* __ASSEMBLY__ */
/******************************************************************************
......
......@@ -24,7 +24,11 @@ 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);
......
/*
* Copyright (c) 2016-2018, 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 <drivers/console.h>
#include <drivers/generic_delay_timer.h>
#include <drivers/ti/uart/uart_16550.h>
#include <lib/coreboot.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(void *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_16550_t console;
struct rockchip_bl31_params *arg_from_bl2 = (struct rockchip_bl31_params *) arg0;
void *plat_params_from_bl2 = (void *) arg1;
params_early_setup(plat_params_from_bl2);
#if COREBOOT
if (coreboot_serial.type)
console_16550_register(coreboot_serial.baseaddr,
coreboot_serial.input_hertz,
coreboot_serial.baud,
&console);
#else
console_16550_register(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK,
PLAT_RK_UART_BAUDRATE, &console);
#endif
VERBOSE("sp_min_setup\n");
/* Passing a NULL context is a critical programming error */
assert(arg_from_bl2);
assert(arg_from_bl2->h.type == PARAM_BL31);
assert(arg_from_bl2->h.version >= VERSION_1);
bl33_ep_info = *arg_from_bl2->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 intializes 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);
}
/*
* 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>
.macro func_rockchip_clst_warmboot
/* Nothing to do for rk3288 */
.endm
.macro rockchip_clst_warmboot_data
/* Nothing to do for rk3288 */
.endm
/*
* Copyright (c) 2016, 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/delay_timer.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <plat_private.h>
#include <pmu.h>
#include <pmu_com.h>
#include <rk3288_def.h>
#include <secure.h>
#include <soc.h>
DEFINE_BAKERY_LOCK(rockchip_pd_lock);
static uint32_t cpu_warm_boot_addr;
static uint32_t store_pmu_pwrmode_con;
static uint32_t store_sgrf_soc_con0;
static uint32_t store_sgrf_cpu_con0;
/* These enum are variants of low power mode */
enum {
ROCKCHIP_ARM_OFF_LOGIC_NORMAL = 0,
ROCKCHIP_ARM_OFF_LOGIC_DEEP = 1,
};
static inline int rk3288_pmu_bus_idle(uint32_t req, uint32_t idle)
{
uint32_t mask = BIT(req);
uint32_t idle_mask = 0;
uint32_t idle_target = 0;
uint32_t val;
uint32_t wait_cnt = 0;
switch (req) {
case bus_ide_req_gpu:
idle_mask = BIT(pmu_idle_ack_gpu) | BIT(pmu_idle_gpu);
idle_target = (idle << pmu_idle_ack_gpu) |
(idle << pmu_idle_gpu);
break;
case bus_ide_req_core:
idle_mask = BIT(pmu_idle_ack_core) | BIT(pmu_idle_core);
idle_target = (idle << pmu_idle_ack_core) |
(idle << pmu_idle_core);
break;
case bus_ide_req_cpup:
idle_mask = BIT(pmu_idle_ack_cpup) | BIT(pmu_idle_cpup);
idle_target = (idle << pmu_idle_ack_cpup) |
(idle << pmu_idle_cpup);
break;
case bus_ide_req_bus:
idle_mask = BIT(pmu_idle_ack_bus) | BIT(pmu_idle_bus);
idle_target = (idle << pmu_idle_ack_bus) |
(idle << pmu_idle_bus);
break;
case bus_ide_req_dma:
idle_mask = BIT(pmu_idle_ack_dma) | BIT(pmu_idle_dma);
idle_target = (idle << pmu_idle_ack_dma) |
(idle << pmu_idle_dma);
break;
case bus_ide_req_peri:
idle_mask = BIT(pmu_idle_ack_peri) | BIT(pmu_idle_peri);
idle_target = (idle << pmu_idle_ack_peri) |
(idle << pmu_idle_peri);
break;
case bus_ide_req_video:
idle_mask = BIT(pmu_idle_ack_video) | BIT(pmu_idle_video);
idle_target = (idle << pmu_idle_ack_video) |
(idle << pmu_idle_video);
break;
case bus_ide_req_hevc:
idle_mask = BIT(pmu_idle_ack_hevc) | BIT(pmu_idle_hevc);
idle_target = (idle << pmu_idle_ack_hevc) |
(idle << pmu_idle_hevc);
break;
case bus_ide_req_vio:
idle_mask = BIT(pmu_idle_ack_vio) | BIT(pmu_idle_vio);
idle_target = (pmu_idle_ack_vio) |
(idle << pmu_idle_vio);
break;
case bus_ide_req_alive:
idle_mask = BIT(pmu_idle_ack_alive) | BIT(pmu_idle_alive);
idle_target = (idle << pmu_idle_ack_alive) |
(idle << pmu_idle_alive);
break;
default:
ERROR("%s: Unsupported the idle request\n", __func__);
break;
}
val = mmio_read_32(PMU_BASE + PMU_BUS_IDE_REQ);
if (idle)
val |= mask;
else
val &= ~mask;
mmio_write_32(PMU_BASE + PMU_BUS_IDE_REQ, val);
while ((mmio_read_32(PMU_BASE +
PMU_BUS_IDE_ST) & idle_mask) != idle_target) {
wait_cnt++;
if (!(wait_cnt % MAX_WAIT_CONUT))
WARN("%s:st=%x(%x)\n", __func__,
mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST),
idle_mask);
}
return 0;
}
static bool rk3288_sleep_disable_osc(void)
{
static const uint32_t reg_offset[] = { GRF_UOC0_CON0, GRF_UOC1_CON0,
GRF_UOC2_CON0 };
uint32_t reg, i;
/*
* if any usb phy is still on(GRF_SIDDQ==0), that means we need the
* function of usb wakeup, so do not switch to 32khz, since the usb phy
* clk does not connect to 32khz osc
*/
for (i = 0; i < ARRAY_SIZE(reg_offset); i++) {
reg = mmio_read_32(GRF_BASE + reg_offset[i]);
if (!(reg & GRF_SIDDQ))
return false;
}
return true;
}
static void pmu_set_sleep_mode(int level)
{
uint32_t mode_set, mode_set1;
bool osc_disable = rk3288_sleep_disable_osc();
mode_set = BIT(pmu_mode_glb_int_dis) | BIT(pmu_mode_l2_flush_en) |
BIT(pmu_mode_sref0_enter) | BIT(pmu_mode_sref1_enter) |
BIT(pmu_mode_ddrc0_gt) | BIT(pmu_mode_ddrc1_gt) |
BIT(pmu_mode_en) | BIT(pmu_mode_chip_pd) |
BIT(pmu_mode_scu_pd);
mode_set1 = BIT(pmu_mode_clr_core) | BIT(pmu_mode_clr_cpup);
if (level == ROCKCHIP_ARM_OFF_LOGIC_DEEP) {
/* arm off, logic deep sleep */
mode_set |= BIT(pmu_mode_bus_pd) | BIT(pmu_mode_pmu_use_lf) |
BIT(pmu_mode_ddrio1_ret) |
BIT(pmu_mode_ddrio0_ret) |
BIT(pmu_mode_pmu_alive_use_lf) |
BIT(pmu_mode_pll_pd);
if (osc_disable)
mode_set |= BIT(pmu_mode_osc_dis);
mode_set1 |= BIT(pmu_mode_clr_alive) | BIT(pmu_mode_clr_bus) |
BIT(pmu_mode_clr_peri) | BIT(pmu_mode_clr_dma);
mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1,
pmu_armint_wakeup_en);
/*
* In deep suspend we use PMU_PMU_USE_LF to let the rk3288
* switch its main clock supply to the alternative 32kHz
* source. Therefore set 30ms on a 32kHz clock for pmic
* stabilization. Similar 30ms on 24MHz for the other
* mode below.
*/
mmio_write_32(PMU_BASE + PMU_STABL_CNT, 32 * 30);
/* only wait for stabilization, if we turned the osc off */
mmio_write_32(PMU_BASE + PMU_OSC_CNT,
osc_disable ? 32 * 30 : 0);
} else {
/*
* arm off, logic normal
* if pmu_clk_core_src_gate_en is not set,
* wakeup will be error
*/
mode_set |= BIT(pmu_mode_core_src_gt);
mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1,
BIT(pmu_armint_wakeup_en) |
BIT(pmu_gpioint_wakeup_en));
/* 30ms on a 24MHz clock for pmic stabilization */
mmio_write_32(PMU_BASE + PMU_STABL_CNT, 24000 * 30);
/* oscillator is still running, so no need to wait */
mmio_write_32(PMU_BASE + PMU_OSC_CNT, 0);
}
mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, mode_set);
mmio_write_32(PMU_BASE + PMU_PWRMODE_CON1, mode_set1);
}
static int cpus_power_domain_on(uint32_t cpu_id)
{
uint32_t cpu_pd;
cpu_pd = PD_CPU0 + cpu_id;
/* if the core has been on, power it off first */
if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
/* put core in reset - some sort of A12/A17 bug */
mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0),
BIT(cpu_id) | (BIT(cpu_id) << 16));
pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
}
pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
/* pull core out of reset */
mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0), BIT(cpu_id) << 16);
return 0;
}
static int cpus_power_domain_off(uint32_t cpu_id)
{
uint32_t cpu_pd = PD_CPU0 + cpu_id;
if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
return 0;
if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
return -EINVAL;
/* put core in reset - some sort of A12/A17 bug */
mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0),
BIT(cpu_id) | (BIT(cpu_id) << 16));
pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
return 0;
}
static void nonboot_cpus_off(void)
{
uint32_t boot_cpu, cpu;
boot_cpu = plat_my_core_pos();
boot_cpu = MPIDR_AFFLVL0_VAL(read_mpidr());
/* turn off noboot cpus */
for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
if (cpu == boot_cpu)
continue;
cpus_power_domain_off(cpu);
}
}
void sram_save(void)
{
/* TODO: support the sdram save for rk3288 SoCs*/
}
void sram_restore(void)
{
/* TODO: support the sdram restore for rk3288 SoCs */
}
int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
{
uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
assert(cpu_id < PLATFORM_CORE_COUNT);
assert(cpuson_flags[cpu_id] == 0);
cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
cpuson_entry_point[cpu_id] = entrypoint;
dsb();
cpus_power_domain_on(cpu_id);
/*
* We communicate with the bootrom to active the cpus other
* than cpu0, after a blob of initialize code, they will
* stay at wfe state, once they are actived, they will check
* the mailbox:
* sram_base_addr + 4: 0xdeadbeaf
* sram_base_addr + 8: start address for pc
* The cpu0 need to wait the other cpus other than cpu0 entering
* the wfe state.The wait time is affected by many aspects.
* (e.g: cpu frequency, bootrom frequency, sram frequency, ...)
*/
mdelay(1); /* ensure the cpus other than cpu0 to startup */
/* tell the bootrom mailbox where to start from */
mmio_write_32(SRAM_BASE + 8, cpu_warm_boot_addr);
mmio_write_32(SRAM_BASE + 4, 0xDEADBEAF);
dsb();
sev();
return 0;
}
int rockchip_soc_cores_pwr_dm_on_finish(void)
{
return 0;
}
int rockchip_soc_sys_pwr_dm_resume(void)
{
mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, store_pmu_pwrmode_con);
mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0),
store_sgrf_cpu_con0 | SGRF_DAPDEVICE_MSK);
/* disable fastboot mode */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0),
store_sgrf_soc_con0 | SGRF_FAST_BOOT_DIS);
secure_watchdog_ungate();
clk_gate_con_restore();
clk_sel_con_restore();
clk_plls_resume();
secure_gic_init();
plat_rockchip_gic_init();
return 0;
}
int rockchip_soc_sys_pwr_dm_suspend(void)
{
nonboot_cpus_off();
store_sgrf_cpu_con0 = mmio_read_32(SGRF_BASE + SGRF_CPU_CON(0));
store_sgrf_soc_con0 = mmio_read_32(SGRF_BASE + SGRF_SOC_CON(0));
store_pmu_pwrmode_con = mmio_read_32(PMU_BASE + PMU_PWRMODE_CON);
/* save clk-gates and ungate all for suspend */
clk_gate_con_save();
clk_gate_con_disable();
clk_sel_con_save();
pmu_set_sleep_mode(ROCKCHIP_ARM_OFF_LOGIC_NORMAL);
clk_plls_suspend();
secure_watchdog_gate();
/*
* The dapswjdp can not auto reset before resume, that cause it may
* access some illegal address during resume. Let's disable it before
* suspend, and the MASKROM will enable it back.
*/
mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0), SGRF_DAPDEVICE_MSK);
/*
* SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR
*/
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_FAST_BOOT_ENA);
/* boot-address of resuming system is from this register value */
mmio_write_32(SGRF_BASE + SGRF_FAST_BOOT_ADDR,
(uint32_t)&pmu_cpuson_entrypoint);
/* flush all caches - otherwise we might loose the resume address */
dcsw_op_all(DC_OP_CISW);
return 0;
}
void rockchip_plat_mmu_svc_mon(void)
{
}
void plat_rockchip_pmu_init(void)
{
uint32_t cpu;
cpu_warm_boot_addr = (uint32_t)platform_cpu_warmboot;
/* on boot all power-domains are on */
for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
cpuson_flags[cpu] = pmu_pd_on;
nonboot_cpus_off();
}
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PMU_H
#define PMU_H
/* Allocate sp reginon in pmusram */
#define PSRAM_SP_SIZE 0x80
#define PSRAM_SP_BOTTOM (PSRAM_SP_TOP - PSRAM_SP_SIZE)
/*****************************************************************************
* pmu con,reg
*****************************************************************************/
#define PMU_WAKEUP_CFG0 0x0
#define PMU_WAKEUP_CFG1 0x4
#define PMU_PWRDN_CON 0x8
#define PMU_PWRDN_ST 0xc
#define PMU_PWRMODE_CON 0x18
#define PMU_BUS_IDE_REQ 0x10
#define PMU_BUS_IDE_ST 0x14
#define PMU_OSC_CNT 0x20
#define PMU_PLL_CNT 0x24
#define PMU_STABL_CNT 0x28
#define PMU_DDRIO0_PWR_CNT 0x2c
#define PMU_DDRIO1_PWR_CNT 0x30
#define PMU_WKUPRST_CNT 0x44
#define PMU_SFT_CON 0x48
#define PMU_PWRMODE_CON1 0x90
enum pmu_pdid {
PD_CPU0 = 0,
PD_CPU1,
PD_CPU2,
PD_CPU3,
PD_BUS = 5,
PD_PERI,
PD_VIO,
PD_VIDEO,
PD_GPU,
PD_SCU = 11,
PD_HEVC = 14,
PD_END
};
enum pmu_bus_ide {
bus_ide_req_bus = 0,
bus_ide_req_peri,
bus_ide_req_gpu,
bus_ide_req_video,
bus_ide_req_vio,
bus_ide_req_core,
bus_ide_req_alive,
bus_ide_req_dma,
bus_ide_req_cpup,
bus_ide_req_hevc,
bus_ide_req_end
};
enum pmu_pwrmode {
pmu_mode_en = 0,
pmu_mode_core_src_gt,
pmu_mode_glb_int_dis,
pmu_mode_l2_flush_en,
pmu_mode_bus_pd,
pmu_mode_cpu0_pd,
pmu_mode_scu_pd,
pmu_mode_pll_pd = 7,
pmu_mode_chip_pd,
pmu_mode_pwr_off_comb,
pmu_mode_pmu_alive_use_lf,
pmu_mode_pmu_use_lf,
pmu_mode_osc_dis = 12,
pmu_mode_input_clamp,
pmu_mode_wkup_rst,
pmu_mode_sref0_enter,
pmu_mode_sref1_enter,
pmu_mode_ddrio0_ret,
pmu_mode_ddrio1_ret,
pmu_mode_ddrc0_gt,
pmu_mode_ddrc1_gt,
pmu_mode_ddrio0_ret_deq,
pmu_mode_ddrio1_ret_deq,
};
enum pmu_pwrmode1 {
pmu_mode_clr_bus = 0,
pmu_mode_clr_core,
pmu_mode_clr_cpup,
pmu_mode_clr_alive,
pmu_mode_clr_dma,
pmu_mode_clr_peri,
pmu_mode_clr_gpu,
pmu_mode_clr_video,
pmu_mode_clr_hevc,
pmu_mode_clr_vio
};
enum pmu_sft_con {
pmu_sft_ddrio0_ret_cfg = 6,
pmu_sft_ddrio1_ret_cfg = 9,
pmu_sft_l2flsh = 15,
};
enum pmu_wakeup_cfg1 {
pmu_armint_wakeup_en = 0,
pmu_gpio_wakeup_negedge,
pmu_sdmmc0_wakeup_en,
pmu_gpioint_wakeup_en,
};
enum pmu_bus_idle_st {
pmu_idle_bus = 0,
pmu_idle_peri,
pmu_idle_gpu,
pmu_idle_video,
pmu_idle_vio,
pmu_idle_core,
pmu_idle_alive,
pmu_idle_dma,
pmu_idle_cpup,
pmu_idle_hevc,
pmu_idle_ack_bus = 16,
pmu_idle_ack_peri,
pmu_idle_ack_gpu,
pmu_idle_ack_video,
pmu_idle_ack_vio,
pmu_idle_ack_core,
pmu_idle_ack_alive,
pmu_idle_ack_dma,
pmu_idle_ack_cpup,
pmu_idle_ack_hevc,
};
#define CHECK_CPU_WFIE_BASE (0)
#define clstl_cpu_wfe -1
#define clstb_cpu_wfe -1
#define CKECK_WFEI_MSK 0
#define PD_CTR_LOOP 500
#define CHK_CPU_LOOP 500
#define MAX_WAIT_CONUT 1000
#endif /* PMU_H */
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <plat_private.h>
#include <secure.h>
#include <soc.h>
static void sgrf_ddr_rgn_global_bypass(uint32_t bypass)
{
if (bypass)
/* set bypass (non-secure regions) for whole ddr regions */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21),
SGRF_DDR_RGN_BYPS);
else
/* cancel bypass for whole ddr regions */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21),
SGRF_DDR_RGN_NO_BYPS);
}
/**
* There are 8 + 1 regions for DDR secure control:
* DDR_RGN_0 ~ DDR_RGN_7: Per DDR_RGNs grain size is 1MB
* DDR_RGN_X - the memories of exclude DDR_RGN_0 ~ DDR_RGN_7
*
* SGRF_SOC_CON6 - start address of RGN_0 + control
* SGRF_SOC_CON7 - end address of RGN_0
* ...
* SGRF_SOC_CON20 - start address of the RGN_7 + control
* SGRF_SOC_CON21 - end address of the RGN_7 + RGN_X control
*
* @rgn - the DDR regions 0 ~ 7 which are can be configured.
* The @st and @ed indicate the start and end addresses for which to set
* the security, and the unit is byte. When the st_mb == 0, ed_mb == 0, the
* address range 0x0 ~ 0xfffff is secure.
*
* For example, if we would like to set the range [0, 32MB) is security via
* DDR_RGN0, then rgn == 0, st_mb == 0, ed_mb == 31.
*/
static void sgrf_ddr_rgn_config(uint32_t rgn, uintptr_t st, uintptr_t ed)
{
uintptr_t st_mb, ed_mb;
assert(rgn <= 7);
assert(st < ed);
/* check aligned 1MB */
assert(st % SIZE_M(1) == 0);
assert(ed % SIZE_M(1) == 0);
st_mb = st / SIZE_M(1);
ed_mb = ed / SIZE_M(1);
/* set ddr region addr start */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
BITS_WITH_WMASK(st_mb, SGRF_DDR_RGN_ADDR_WMSK, 0));
/* set ddr region addr end */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2) + 1),
BITS_WITH_WMASK((ed_mb - 1), SGRF_DDR_RGN_ADDR_WMSK, 0));
/* select region security */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
SGRF_DDR_RGN_SECURE_SEL);
/* enable region security */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
SGRF_DDR_RGN_SECURE_EN);
}
void secure_watchdog_gate(void)
{
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_GATE);
}
void secure_watchdog_ungate(void)
{
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_UNGATE);
}
__pmusramfunc void sram_secure_timer_init(void)
{
mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0);
mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff);
mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff);
/* auto reload & enable the timer */
mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN);
}
void secure_gic_init(void)
{
/* (re-)enable non-secure access to the gic*/
mmio_write_32(CORE_AXI_BUS_BASE + CORE_AXI_SECURITY0,
AXI_SECURITY0_GIC);
}
void secure_timer_init(void)
{
mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0);
mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff);
mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff);
/* auto reload & enable the timer */
mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN);
}
void secure_sgrf_init(void)
{
/*
* We use the first sram part to talk to the bootrom,
* so make it secure.
*/
mmio_write_32(TZPC_BASE + TZPC_R0SIZE, TZPC_SRAM_SECURE_4K(1));
secure_gic_init();
/* set all master ip to non-secure */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), SGRF_SOC_CON2_MST_NS);
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), SGRF_SOC_CON3_MST_NS);
/* setting all configurable ip into non-secure */
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4),
SGRF_SOC_CON4_SECURE_WMSK /*TODO:|SGRF_STIMER_SECURE*/);
mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SOC_CON5_SECURE_WMSK);
/* secure dma to non-secure */
mmio_write_32(TZPC_BASE + TZPC_DECPROT1SET, 0xff);
mmio_write_32(TZPC_BASE + TZPC_DECPROT2SET, 0xff);
mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(1), 0x3800);
dsb();
/* rst dma1 */
mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1),
RST_DMA1_MSK | (RST_DMA1_MSK << 16));
/* rst dma2 */
mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4),
RST_DMA2_MSK | (RST_DMA2_MSK << 16));
dsb();
/* release dma1 rst*/
mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), (RST_DMA1_MSK << 16));
/* release dma2 rst*/
mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), (RST_DMA2_MSK << 16));
}
void secure_sgrf_ddr_rgn_init(void)
{
sgrf_ddr_rgn_config(0, TZRAM_BASE, TZRAM_SIZE);
sgrf_ddr_rgn_global_bypass(0);
}
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SECURE_H
#define SECURE_H
/******************************************************************************
* TZPC TrustZone controller
******************************************************************************/
#define TZPC_R0SIZE 0x0
#define TZPC_SRAM_SECURE_4K(n) ((n) > 0x200 ? 0x200 : (n))
#define TZPC_DECPROT1STAT 0x80c
#define TZPC_DECPROT1SET 0x810
#define TZPC_DECPROT1CLR 0x814
#define TZPC_DECPROT2STAT 0x818
#define TZPC_DECPROT2SET 0x818
#define TZPC_DECPROT2CLR 0x820
/**************************************************
* sgrf reg, offset
**************************************************/
/*
* soc_con0-5 start at 0x0, soc_con6-... start art 0x50
* adjusted for the 5 lower registers
*/
#define SGRF_SOC_CON(n) ((((n) < 6) ? 0x0 : 0x38) + (n) * 4)
#define SGRF_BUSDMAC_CON(n) (0x20 + (n) * 4)
#define SGRF_CPU_CON(n) (0x40 + (n) * 4)
#define SGRF_SOC_STATUS(n) (0x100 + (n) * 4)
#define SGRF_FAST_BOOT_ADDR 0x120
/* SGRF_SOC_CON0 */
#define SGRF_FAST_BOOT_ENA BIT_WITH_WMSK(8)
#define SGRF_FAST_BOOT_DIS WMSK_BIT(8)
#define SGRF_PCLK_WDT_GATE BIT_WITH_WMSK(6)
#define SGRF_PCLK_WDT_UNGATE WMSK_BIT(6)
#define SGRF_PCLK_STIMER_GATE BIT_WITH_WMSK(4)
#define SGRF_SOC_CON2_MST_NS 0xffe0ffe0
#define SGRF_SOC_CON3_MST_NS 0x003f003f
/* SGRF_SOC_CON4 */
#define SGRF_SOC_CON4_SECURE_WMSK 0xffff0000
#define SGRF_DDRC1_SECURE BIT_WITH_WMSK(12)
#define SGRF_DDRC0_SECURE BIT_WITH_WMSK(11)
#define SGRF_PMUSRAM_SECURE BIT_WITH_WMSK(8)
#define SGRF_WDT_SECURE BIT_WITH_WMSK(7)
#define SGRF_STIMER_SECURE BIT_WITH_WMSK(6)
/* SGRF_SOC_CON5 */
#define SGRF_SLV_SEC_BYPS BIT_WITH_WMSK(15)
#define SGRF_SLV_SEC_NO_BYPS WMSK_BIT(15)
#define SGRF_SOC_CON5_SECURE_WMSK 0x00ff0000
/* ddr regions in SGRF_SOC_CON6 and following */
#define SGRF_DDR_RGN_SECURE_SEL BIT_WITH_WMSK(15)
#define SGRF_DDR_RGN_SECURE_EN BIT_WITH_WMSK(14)
#define SGRF_DDR_RGN_ADDR_WMSK 0x0fff
/* SGRF_SOC_CON21 */
/* All security of the DDR RGNs are bypassed */
#define SGRF_DDR_RGN_BYPS BIT_WITH_WMSK(15)
#define SGRF_DDR_RGN_NO_BYPS WMSK_BIT(15)
/* SGRF_CPU_CON0 */
#define SGRF_DAPDEVICE_ENA BIT_WITH_WMSK(0)
#define SGRF_DAPDEVICE_MSK WMSK_BIT(0)
/*****************************************************************************
* core-axi
*****************************************************************************/
#define CORE_AXI_SECURITY0 0x08
#define AXI_SECURITY0_GIC BIT(0)
/*****************************************************************************
* secure timer
*****************************************************************************/
#define TIMER_LOAD_COUNT0 0x00
#define TIMER_LOAD_COUNT1 0x04
#define TIMER_CURRENT_VALUE0 0x08
#define TIMER_CURRENT_VALUE1 0x0C
#define TIMER_CONTROL_REG 0x10
#define TIMER_INTSTATUS 0x18
#define TIMER_EN 0x1
#define STIMER1_BASE (STIME_BASE + 0x20)
/* export secure operating APIs */
void secure_watchdog_gate(void);
void secure_watchdog_ungate(void);
void secure_gic_init(void);
void secure_timer_init(void);
void secure_sgrf_init(void);
void secure_sgrf_ddr_rgn_init(void);
__pmusramfunc void sram_secure_timer_init(void);
#endif /* SECURE_H */
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <plat_private.h>
#include <rk3288_def.h>
#include <soc.h>
#include <secure.h>
/* sleep data for pll suspend */
static struct deepsleep_data_s slp_data;
/* Table of regions to map using the MMU. */
const mmap_region_t plat_rk_mmap[] = {
MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(STIME_BASE, STIME_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TZPC_BASE, TZPC_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
MT_MEMORY | MT_RW | MT_SECURE),
MAP_REGION_FLAT(SRAM_BASE, SRAM_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(PMU_BASE, PMU_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(UART_DBG_BASE, UART_DBG_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(CRU_BASE, CRU_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(GRF_BASE, GRF_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(DDR_PCTL0_BASE, DDR_PCTL0_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(DDR_PHY0_BASE, DDR_PHY0_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(DDR_PCTL1_BASE, DDR_PCTL1_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(DDR_PHY1_BASE, DDR_PHY1_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(SERVICE_BUS_BASE, SERVICE_BUS_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(CORE_AXI_BUS_BASE, CORE_AXI_BUS_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
{ 0 }
};
/* The RockChip power domain tree descriptor */
const unsigned char rockchip_power_domain_tree_desc[] = {
/* No of root nodes */
PLATFORM_SYSTEM_COUNT,
/* No of children for the root node */
PLATFORM_CLUSTER_COUNT,
/* No of children for the first cluster node */
PLATFORM_CLUSTER0_CORE_COUNT,
};
void plat_rockchip_soc_init(void)
{
secure_timer_init();
secure_sgrf_init();
/*
* We cannot enable ddr security at this point, as the kernel
* seems to have an issue with it even living in the same 128MB
* memory block. Only when moving the kernel to the second
* 128MB block does it not conflict, but then we'd loose this
* memory area for use. Late maybe enable
* secure_sgrf_ddr_rgn_init();
*/
}
void regs_update_bits(uintptr_t addr, uint32_t val,
uint32_t mask, uint32_t shift)
{
uint32_t tmp, orig;
orig = mmio_read_32(addr);
tmp = orig & ~(mask << shift);
tmp |= (val & mask) << shift;
if (tmp != orig)
mmio_write_32(addr, tmp);
dsb();
}
static void pll_save(uint32_t pll_id)
{
uint32_t *pll = slp_data.pll_con[pll_id];
pll[0] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 0));
pll[1] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 1));
pll[2] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 2));
pll[3] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 3));
}
void clk_plls_suspend(void)
{
pll_save(NPLL_ID);
pll_save(CPLL_ID);
pll_save(GPLL_ID);
pll_save(APLL_ID);
slp_data.pll_mode = mmio_read_32(CRU_BASE + PLL_MODE_CON);
/*
* Switch PLLs other than DPLL (for SDRAM) to slow mode to
* avoid crashes on resume. The Mask ROM on the system will
* put APLL, CPLL, and GPLL into slow mode at resume time
* anyway (which is why we restore them), but we might not
* even make it to the Mask ROM if this isn't done at suspend
* time.
*
* NOTE: only APLL truly matters here, but we'll do them all.
*/
mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
}
void clk_plls_resume(void)
{
/* restore pll-modes */
mmio_write_32(CRU_BASE + PLL_MODE_CON,
slp_data.pll_mode | REG_SOC_WMSK);
}
void clk_gate_con_save(void)
{
uint32_t i = 0;
for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
slp_data.cru_gate_con[i] =
mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
}
void clk_gate_con_disable(void)
{
uint32_t i;
for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), REG_SOC_WMSK);
}
void clk_gate_con_restore(void)
{
uint32_t i;
for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
REG_SOC_WMSK | slp_data.cru_gate_con[i]);
}
void clk_sel_con_save(void)
{
uint32_t i = 0;
for (i = 0; i < CRU_CLKSELS_CON_CNT; i++)
slp_data.cru_sel_con[i] =
mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(i));
}
void clk_sel_con_restore(void)
{
uint32_t i, val;
for (i = 0; i < CRU_CLKSELS_CON_CNT; i++) {
/* fractional dividers don't have write-masks */
if ((i >= 7 && i <= 9) ||
(i >= 17 && i <= 20) ||
(i == 23) || (i == 41))
val = slp_data.cru_sel_con[i];
else
val = slp_data.cru_sel_con[i] | REG_SOC_WMSK;
mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(i), val);
}
}
void __dead2 rockchip_soc_soft_reset(void)
{
uint32_t temp_val;
/*
* Switch PLLs other than DPLL (for SDRAM) to slow mode to
* avoid crashes on resume. The Mask ROM on the system will
* put APLL, CPLL, and GPLL into slow mode at resume time
* anyway (which is why we restore them), but we might not
* even make it to the Mask ROM if this isn't done at suspend
* time.
*
* NOTE: only APLL truly matters here, but we'll do them all.
*/
mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
temp_val &= ~PMU_RST_MASK;
temp_val |= PMU_RST_BY_SECOND_SFT;
mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val);
mmio_write_32(CRU_BASE + CRU_GLB_SRST_SND, 0xeca8);
/*
* Maybe the HW needs some times to reset the system,
* so we do not hope the core to excute valid codes.
*/
while (1)
;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment