Merge "Cortex-A53: Fix reporting of missing errata when not needed" into integration
diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S
index 83b7860..4559903 100644
--- a/bl32/sp_min/sp_min.ld.S
+++ b/bl32/sp_min/sp_min.ld.S
@@ -16,6 +16,9 @@
     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
 {
diff --git a/bl32/sp_min/sp_min_private.h b/bl32/sp_min/sp_min_private.h
index 6b5d792..628581a 100644
--- a/bl32/sp_min/sp_min_private.h
+++ b/bl32/sp_min/sp_min_private.h
@@ -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);
diff --git a/docs/auth-framework.rst b/docs/auth-framework.rst
index 317ac18..0142fbd 100644
--- a/docs/auth-framework.rst
+++ b/docs/auth-framework.rst
@@ -80,7 +80,7 @@
 A CoT is basically a sequence of authentication images which usually starts with
 a root of trust and culminates in a single data image. The following diagram
 illustrates how this maps to a CoT for the BL31 image described in the
-TBBR-Client specification.
+`TBBR-Client specification`_.
 
 ::
 
@@ -969,3 +969,4 @@
 
 .. _Trusted Board Boot: ./trusted-board-boot.rst
 .. _Platform Porting Guide: ./porting-guide.rst
+.. _TBBR-Client specification: https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst
index 66b16fa..8384c9c 100644
--- a/docs/firmware-design.rst
+++ b/docs/firmware-design.rst
@@ -2655,8 +2655,7 @@
 References
 ----------
 
-.. [#] Trusted Board Boot Requirements CLIENT PDD (Arm DEN0006C-1). Available
-       under NDA through your Arm account representative.
+.. [#] `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT) Armv8-A (ARM DEN0006D)`_
 .. [#] `Power State Coordination Interface PDD`_
 .. [#] `SMC Calling Convention PDD`_
 .. [#] `TF-A Interrupt Management Design guide`_.
@@ -2684,5 +2683,6 @@
 .. _Xlat_tables design: xlat-tables-lib-v2-design.rst
 .. _Exception Handling Framework: exception-handling.rst
 .. _ROMLIB Design: romlib-design.rst
+.. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT) Armv8-A (ARM DEN0006D): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
 
 .. |Image 1| image:: diagrams/rt-svc-descs-layout.png?raw=true
diff --git a/docs/plat/rockchip.rst b/docs/plat/rockchip.rst
new file mode 100644
index 0000000..e88706b
--- /dev/null
+++ b/docs/plat/rockchip.rst
@@ -0,0 +1,54 @@
+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.
diff --git a/docs/trusted-board-boot.rst b/docs/trusted-board-boot.rst
index 1ca6fef..3ba9636 100644
--- a/docs/trusted-board-boot.rst
+++ b/docs/trusted-board-boot.rst
@@ -12,9 +12,9 @@
 normal world bootloader. It does this by establishing a Chain of Trust using
 Public-Key-Cryptography Standards (PKCS).
 
-This document describes the design of Trusted Firmware-A (TF-A) TBB, which is
-an implementation of the Trusted Board Boot Requirements (TBBR) specification,
-Arm DEN0006C-1. It should be used in conjunction with the `Firmware Update`_
+This document describes the design of Trusted Firmware-A (TF-A) TBB, which is an
+implementation of the `Trusted Board Boot Requirements (TBBR)`_ specification,
+Arm DEN0006D. It should be used in conjunction with the `Firmware Update`_
 design document, which implements a specific aspect of the TBBR.
 
 Chain of Trust
@@ -206,7 +206,7 @@
 
 The authentication framework included in TF-A provides support to implement
 the desired trusted boot sequence. Arm platforms use this framework to
-implement the boot requirements specified in the TBBR-client document.
+implement the boot requirements specified in the `TBBR-client`_ document.
 
 More information about the authentication framework can be found in the
 `Auth Framework`_ document.
@@ -230,9 +230,11 @@
 
 --------------
 
-*Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.*
 
 .. _Firmware Update: firmware-update.rst
 .. _X.509 v3: https://tools.ietf.org/rfc/rfc5280.txt
 .. _User Guide: user-guide.rst
 .. _Auth Framework: auth-framework.rst
+.. _TBBR-client: https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
+.. _Trusted Board Boot Requirements (TBBR): `TBBR-client`_
diff --git a/drivers/ti/uart/aarch32/16550_console.S b/drivers/ti/uart/aarch32/16550_console.S
new file mode 100644
index 0000000..6921884
--- /dev/null
+++ b/drivers/ti/uart/aarch32/16550_console.S
@@ -0,0 +1,267 @@
+/*
+ * 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
diff --git a/include/bl32/sp_min/platform_sp_min.h b/include/bl32/sp_min/platform_sp_min.h
index feb4ec3..971f661 100644
--- a/include/bl32/sp_min/platform_sp_min.h
+++ b/include/bl32/sp_min/platform_sp_min.h
@@ -18,6 +18,7 @@
 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);
diff --git a/maintainers.rst b/maintainers.rst
index 52c3dac..4bee64c 100644
--- a/maintainers.rst
+++ b/maintainers.rst
@@ -208,6 +208,8 @@
 :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 @@
 .. _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
diff --git a/plat/rockchip/common/aarch32/plat_helpers.S b/plat/rockchip/common/aarch32/plat_helpers.S
new file mode 100644
index 0000000..475c297
--- /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/pmusram/pmu_sram_cpus_on.S b/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
similarity index 100%
rename from plat/rockchip/common/pmusram/pmu_sram_cpus_on.S
rename to plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
diff --git a/plat/rockchip/common/drivers/pmu/pmu_com.h b/plat/rockchip/common/drivers/pmu/pmu_com.h
index 4b4b00f..5359f73 100644
--- a/plat/rockchip/common/drivers/pmu/pmu_com.h
+++ b/plat/rockchip/common/drivers/pmu/pmu_com.h
@@ -88,6 +88,17 @@
 		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
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index e8750a5..f9470e5 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -68,6 +68,16 @@
 /******************************************************************************
  * 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 @@
 			    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 @@
 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__ */
 
 /******************************************************************************
diff --git a/plat/rockchip/common/plat_topology.c b/plat/rockchip/common/plat_topology.c
index a31e410..4987eeb 100644
--- a/plat/rockchip/common/plat_topology.c
+++ b/plat/rockchip/common/plat_topology.c
@@ -24,7 +24,11 @@
 	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);
 
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..7250919
--- /dev/null
+++ b/plat/rockchip/common/sp_min_plat_setup.c
@@ -0,0 +1,116 @@
+/*
+ * 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);
+}
diff --git a/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..2003749
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,17 @@
+/*
+ * 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
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.c b/plat/rockchip/rk3288/drivers/pmu/pmu.c
new file mode 100644
index 0000000..d6d7098
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.c
@@ -0,0 +1,391 @@
+/*
+ * 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();
+}
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.h b/plat/rockchip/rk3288/drivers/pmu/pmu.h
new file mode 100644
index 0000000..06d5528
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.h
@@ -0,0 +1,151 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.c b/plat/rockchip/rk3288/drivers/secure/secure.c
new file mode 100644
index 0000000..68994e4
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.c
@@ -0,0 +1,162 @@
+/*
+ * 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);
+}
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.h b/plat/rockchip/rk3288/drivers/secure/secure.h
new file mode 100644
index 0000000..6c0b2b7
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.h
@@ -0,0 +1,102 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.c b/plat/rockchip/rk3288/drivers/soc/soc.c
new file mode 100644
index 0000000..db90ae4
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.c
@@ -0,0 +1,215 @@
+/*
+ * 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)
+		;
+}
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.h b/plat/rockchip/rk3288/drivers/soc/soc.h
new file mode 100644
index 0000000..b96c4dc
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+enum plls_id {
+	APLL_ID = 0,
+	DPLL_ID,
+	CPLL_ID,
+	GPLL_ID,
+	NPLL_ID,
+	END_PLL_ID,
+};
+
+
+#define CYCL_24M_CNT_US(us)	(24 * (us))
+#define CYCL_24M_CNT_MS(ms)	((ms) * CYCL_24M_CNT_US(1000))
+
+/*****************************************************************************
+ * grf regs
+ *****************************************************************************/
+#define GRF_UOC0_CON0		0x320
+#define GRF_UOC1_CON0		0x334
+#define GRF_UOC2_CON0		0x348
+#define GRF_SIDDQ		BIT(13)
+
+/*****************************************************************************
+ * cru reg, offset
+ *****************************************************************************/
+#define CRU_SOFTRST_CON		0x1b8
+#define CRU_SOFTRSTS_CON(n)	(CRU_SOFTRST_CON + ((n) * 4))
+#define CRU_SOFTRSTS_CON_CNT	11
+
+#define RST_DMA1_MSK		0x4
+#define RST_DMA2_MSK		0x1
+
+#define CRU_CLKSEL_CON		0x60
+#define CRU_CLKSELS_CON(i)	(CRU_CLKSEL_CON + ((i) * 4))
+#define CRU_CLKSELS_CON_CNT	42
+
+#define CRU_CLKGATE_CON		0x160
+#define CRU_CLKGATES_CON(i)	(CRU_CLKGATE_CON + ((i) * 4))
+#define CRU_CLKGATES_CON_CNT	18
+
+#define CRU_GLB_SRST_FST	0x1b0
+#define CRU_GLB_SRST_SND	0x1b4
+#define CRU_GLB_RST_CON		0x1f0
+
+#define CRU_CONS_GATEID(i)	(16 * (i))
+#define GATE_ID(reg, bit)	(((reg) * 16) + (bit))
+
+#define PMU_RST_MASK		0x3
+#define PMU_RST_BY_FIRST_SFT	(0 << 2)
+#define PMU_RST_BY_SECOND_SFT	(1 << 2)
+#define PMU_RST_NOT_BY_SFT	(2 << 2)
+
+/***************************************************************************
+ * pll
+ ***************************************************************************/
+#define PLL_CON_COUNT		4
+#define PLL_CONS(id, i)		((id) * 0x10 + ((i) * 4))
+#define PLL_PWR_DN_MSK		BIT(1)
+#define PLL_PWR_DN		REG_WMSK_BITS(1, 1, 0x1)
+#define PLL_PWR_ON		REG_WMSK_BITS(0, 1, 0x1)
+#define PLL_RESET		REG_WMSK_BITS(1, 5, 0x1)
+#define PLL_RESET_RESUME	REG_WMSK_BITS(0, 5, 0x1)
+#define PLL_BYPASS_MSK		BIT(0)
+#define PLL_BYPASS_W_MSK	(PLL_BYPASS_MSK << 16)
+#define PLL_BYPASS		REG_WMSK_BITS(1, 0, 0x1)
+#define PLL_NO_BYPASS		REG_WMSK_BITS(0, 0, 0x1)
+
+#define PLL_MODE_CON		0x50
+
+struct deepsleep_data_s {
+	uint32_t pll_con[END_PLL_ID][PLL_CON_COUNT];
+	uint32_t pll_mode;
+	uint32_t cru_sel_con[CRU_CLKSELS_CON_CNT];
+	uint32_t cru_gate_con[CRU_CLKGATES_CON_CNT];
+};
+
+#define REG_W_MSK(bits_shift, msk) \
+		((msk) << ((bits_shift) + 16))
+#define REG_VAL_CLRBITS(val, bits_shift, msk) \
+		((val) & (~((msk) << bits_shift)))
+#define REG_SET_BITS(bits, bits_shift, msk) \
+		(((bits) & (msk)) << (bits_shift))
+#define REG_WMSK_BITS(bits, bits_shift, msk) \
+		(REG_W_MSK(bits_shift, msk) | \
+		REG_SET_BITS(bits, bits_shift, msk))
+#define REG_SOC_WMSK		0xffff0000
+
+#define regs_update_bit_set(addr, shift) \
+		regs_update_bits((addr), 0x1, 0x1, (shift))
+#define regs_update_bit_clr(addr, shift) \
+		regs_update_bits((addr), 0x0, 0x1, (shift))
+
+void regs_update_bits(uintptr_t addr, uint32_t val,
+		      uint32_t mask, uint32_t shift);
+void clk_plls_suspend(void);
+void clk_plls_resume(void);
+void clk_gate_con_save(void);
+void clk_gate_con_disable(void);
+void clk_gate_con_restore(void);
+void clk_sel_con_save(void);
+void clk_sel_con_restore(void);
+#endif /* SOC_H */
diff --git a/plat/rockchip/rk3288/include/plat_sip_calls.h b/plat/rockchip/rk3288/include/plat_sip_calls.h
new file mode 100644
index 0000000..66c4868
--- /dev/null
+++ b/plat/rockchip/rk3288/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SIP_CALLS_H
+#define PLAT_SIP_CALLS_H
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/rockchip/rk3288/include/plat_sp_min.ld.S b/plat/rockchip/rk3288/include/plat_sp_min.ld.S
new file mode 100644
index 0000000..2878437
--- /dev/null
+++ b/plat/rockchip/rk3288/include/plat_sp_min.ld.S
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ROCKCHIP_PLAT_LD_S
+#define ROCKCHIP_PLAT_LD_S
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+MEMORY {
+    SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = SRAM_BASE;
+	ASSERT(. == ALIGN(PAGE_SIZE),
+		"SRAM_BASE address is not aligned on a page boundary.")
+
+	.text_sram : ALIGN(PAGE_SIZE) {
+		__bl32_sram_text_start = .;
+		*(.sram.text)
+		*(.sram.rodata)
+		__bl32_sram_text_real_end = .;
+		. = ALIGN(PAGE_SIZE);
+		__bl32_sram_text_end = .;
+	} >SRAM
+	ASSERT((__bl32_sram_text_real_end - __bl32_sram_text_start) <=
+		SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit")
+
+	.data_sram : ALIGN(PAGE_SIZE) {
+		__bl32_sram_data_start = .;
+		*(.sram.data)
+		__bl32_sram_data_real_end = .;
+		. = ALIGN(PAGE_SIZE);
+		__bl32_sram_data_end = .;
+	} >SRAM
+	ASSERT((__bl32_sram_data_real_end - __bl32_sram_data_start) <=
+		SRAM_DATA_LIMIT, ".data_sram has exceeded its limit")
+
+	.stack_sram : ALIGN(PAGE_SIZE) {
+		__bl32_sram_stack_start = .;
+		. += PAGE_SIZE;
+		__bl32_sram_stack_end = .;
+	} >SRAM
+
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+
+		__bl32_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl32_pmusram_text_end = .;
+
+		__bl32_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl32_pmusram_data_end = .;
+	} >PMUSRAM
+}
+
+#endif /* ROCKCHIP_PLAT_LD_S */
diff --git a/plat/rockchip/rk3288/include/platform_def.h b/plat/rockchip/rk3288/include/platform_def.h
new file mode 100644
index 0000000..d9e0bc6
--- /dev/null
+++ b/plat/rockchip/rk3288/include/platform_def.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <bl32_param.h>
+#include <rk3288_def.h>
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf32-littlearm"
+#define PLATFORM_LINKER_ARCH		arm
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE 0x800
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_RK_CLST_TO_CPUID_SHIFT	6
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		U(1)
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		18
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Define GICD and GICC and GICR base
+ */
+#define PLAT_RK_GICD_BASE		RK3288_GICD_BASE
+#define PLAT_RK_GICC_BASE		RK3288_GICC_BASE
+
+#define PLAT_RK_UART_BASE		RK3288_UART2_BASE
+#define PLAT_RK_UART_CLOCK		RK3288_UART_CLOCK
+#define PLAT_RK_UART_BAUDRATE		RK3288_BAUDRATE
+
+/* ClusterId is always 0x5 on rk3288, filter it */
+#define PLAT_RK_MPIDR_CLUSTER_MASK	0
+#define PLAT_RK_PRIMARY_CPU		0x0
+
+#define PSRAM_DO_DDR_RESUME		0
+#define PSRAM_CHECK_WAKEUP_CPU		0
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rockchip/rk3288/include/shared/bl32_param.h b/plat/rockchip/rk3288/include/shared/bl32_param.h
new file mode 100644
index 0000000..743dad4
--- /dev/null
+++ b/plat/rockchip/rk3288/include/shared/bl32_param.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL32_PARAM_H
+#define BL32_PARAM_H
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF txet, ro, rw, Size: 2MB */
+#define TZRAM_BASE		(0x0)
+#define TZRAM_SIZE		(0x200000)
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL32 at the top of the Trusted RAM
+ */
+#define BL32_BASE			(TZRAM_BASE + 0x100000)
+#define BL32_LIMIT			(TZRAM_BASE + TZRAM_SIZE)
+
+#endif /* BL32_PARAM_H */
diff --git a/plat/rockchip/rk3288/plat_sip_calls.c b/plat/rockchip/rk3288/plat_sip_calls.c
new file mode 100644
index 0000000..5918d58
--- /dev/null
+++ b/plat/rockchip/rk3288/plat_sip_calls.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+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);
+}
diff --git a/plat/rockchip/rk3288/platform.mk b/plat/rockchip/rk3288/platform.mk
new file mode 100644
index 0000000..1a0a617
--- /dev/null
+++ b/plat/rockchip/rk3288/platform.mk
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ARM_CORTEX_A12		:=	yes
+ARM_ARCH_MAJOR		:=	7
+
+RK_PLAT			:=	plat/rockchip
+RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON		:=	${RK_PLAT}/common
+
+include lib/libfdt/libfdt.mk
+
+PLAT_INCLUDES		:=	-I${RK_PLAT_COMMON}/				\
+				-I${RK_PLAT_COMMON}/include/			\
+				-I${RK_PLAT_COMMON}/aarch32/			\
+				-I${RK_PLAT_COMMON}/drivers/pmu/		\
+				-I${RK_PLAT_SOC}/				\
+				-I${RK_PLAT_SOC}/drivers/pmu/			\
+				-I${RK_PLAT_SOC}/drivers/secure/		\
+				-I${RK_PLAT_SOC}/drivers/soc/			\
+				-I${RK_PLAT_SOC}/include/			\
+				-I${RK_PLAT_SOC}/include/shared/		\
+
+RK_GIC_SOURCES         :=	drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				${RK_PLAT}/common/rockchip_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	plat/common/aarch32/crash_console_helpers.S	\
+				plat/common/plat_psci_common.c
+
+PLAT_BL_COMMON_SOURCES	+=	lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/aarch32/xlat_tables.c
+
+BL32_SOURCES		+=	${RK_GIC_SOURCES}				\
+				drivers/arm/cci/cci.c				\
+				drivers/ti/uart/aarch32/16550_console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				lib/cpus/aarch32/cortex_a12.S			\
+				$(LIBFDT_SRCS)					\
+				${RK_PLAT_COMMON}/aarch32/plat_helpers.S	\
+				${RK_PLAT_COMMON}/params_setup.c		\
+				${RK_PLAT_COMMON}/aarch32/pmu_sram_cpus_on.S	\
+				${RK_PLAT_COMMON}/plat_pm.c			\
+				${RK_PLAT_COMMON}/plat_topology.c		\
+				${RK_PLAT_COMMON}/aarch32/platform_common.c	\
+				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+				${RK_PLAT_SOC}/plat_sip_calls.c			\
+				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+				${RK_PLAT_SOC}/drivers/secure/secure.c		\
+				${RK_PLAT_SOC}/drivers/soc/soc.c		\
+
+MULTI_CONSOLE_API	:=	1
+
+include lib/coreboot/coreboot.mk
+
+$(eval $(call add_define,PLAT_SP_MIN_EXTRA_LD_SCRIPT))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
+
+WORKAROUND_CVE_2017_5715	:=	0
diff --git a/plat/rockchip/rk3288/rk3288_def.h b/plat/rockchip/rk3288/rk3288_def.h
new file mode 100644
index 0000000..7b5018c
--- /dev/null
+++ b/plat/rockchip/rk3288/rk3288_def.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RK3288_DEF_H
+#define RK3288_DEF_H
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define SIZE_K(n)		((n) * 1024)
+#define SIZE_M(n)		((n) * 1024 * 1024)
+
+#define SRAM_TEXT_LIMIT		(4 * 1024)
+#define SRAM_DATA_LIMIT		(4 * 1024)
+
+#define DDR_PCTL0_BASE		0xff610000
+#define DDR_PCTL0_SIZE		SIZE_K(64)
+
+#define DDR_PHY0_BASE		0xff620000
+#define DDR_PHY0_SIZE		SIZE_K(64)
+
+#define DDR_PCTL1_BASE		0xff630000
+#define DDR_PCTL1_SIZE		SIZE_K(64)
+
+#define DDR_PHY1_BASE		0xff640000
+#define DDR_PHY1_SIZE		SIZE_K(64)
+
+#define UART_DBG_BASE		0xff690000
+#define UART_DBG_SIZE		SIZE_K(64)
+
+/* 96k instead of 64k? */
+#define SRAM_BASE		0xff700000
+#define SRAM_SIZE		SIZE_K(64)
+
+#define PMUSRAM_BASE		0xff720000
+#define PMUSRAM_SIZE		SIZE_K(4)
+#define PMUSRAM_RSIZE		SIZE_K(4)
+
+#define PMU_BASE		0xff730000
+#define PMU_SIZE		SIZE_K(64)
+
+#define SGRF_BASE		0xff740000
+#define SGRF_SIZE		SIZE_K(64)
+
+#define CRU_BASE		0xff760000
+#define CRU_SIZE		SIZE_K(64)
+
+#define GRF_BASE		0xff770000
+#define GRF_SIZE		SIZE_K(64)
+
+/* timer 6+7 can be set as secure in SGRF */
+#define STIME_BASE		0xff810000
+#define STIME_SIZE		SIZE_K(64)
+
+#define SERVICE_BUS_BASE	0xffac0000
+#define SERVICE_BUS_SIZE	SIZE_K(64)
+
+#define TZPC_BASE		0xffb00000
+#define TZPC_SIZE		SIZE_K(64)
+
+#define GIC400_BASE		0xffc00000
+#define GIC400_SIZE		SIZE_K(64)
+
+#define CORE_AXI_BUS_BASE	0xffd00000
+#define CORE_AXI_BUS_SIZE	SIZE_M(1)
+
+#define COLD_BOOT_BASE		0xffff0000
+/**************************************************************************
+ * UART related constants
+ **************************************************************************/
+#define RK3288_UART2_BASE	UART_DBG_BASE
+#define RK3288_BAUDRATE		115200
+#define RK3288_UART_CLOCK	24000000
+
+/******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	24000000
+
+/******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base rk_platform compatible GIC memory map */
+#define RK3288_GICD_BASE		(GIC400_BASE + 0x1000)
+#define RK3288_GICC_BASE		(GIC400_BASE + 0x2000)
+#define RK3288_GICR_BASE		0	/* no GICR in GIC-400 */
+
+/******************************************************************************
+ * sgi, ppi
+ ******************************************************************************/
+#define RK_IRQ_SEC_PHY_TIMER	29
+
+/* what are these, and are they present on rk3288? */
+#define RK_IRQ_SEC_SGI_0	8
+#define RK_IRQ_SEC_SGI_1	9
+#define RK_IRQ_SEC_SGI_2	10
+#define RK_IRQ_SEC_SGI_3	11
+#define RK_IRQ_SEC_SGI_4	12
+#define RK_IRQ_SEC_SGI_5	13
+#define RK_IRQ_SEC_SGI_6	14
+#define RK_IRQ_SEC_SGI_7	15
+
+/*
+ * Define a list of Group 0 interrupts.
+ */
+#define PLAT_RK_GICV2_G0_IRQS						\
+	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),		\
+	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+
+#endif /* RK3288_DEF_H */
diff --git a/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk b/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk
new file mode 100644
index 0000000..befdca3
--- /dev/null
+++ b/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_SOURCES		+=	plat/common/aarch32/platform_mp_stack.S		\
+				plat/rockchip/common/sp_min_plat_setup.c
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.h b/plat/rockchip/rk3328/drivers/pmu/pmu.h
index d98f53c..dfb8912 100644
--- a/plat/rockchip/rk3328/drivers/pmu/pmu.h
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.h
@@ -49,8 +49,6 @@
 
 extern void *pmu_cpuson_entrypoint_start;
 extern void *pmu_cpuson_entrypoint_end;
-extern uint64_t cpuson_entry_point[PLATFORM_CORE_COUNT];
-extern uint32_t cpuson_flags[PLATFORM_CORE_COUNT];
 
 #define CORES_PM_DISABLE	0x0
 
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
index 18b1b94..ce8693a 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -14,7 +14,7 @@
 				-Idrivers/arm/gic/v2/			\
 				-I${RK_PLAT_COMMON}/                            \
 				-I${RK_PLAT_COMMON}/include/                    \
-				-I${RK_PLAT_COMMON}/pmusram                     \
+				-I${RK_PLAT_COMMON}/aarch64/			\
 				-I${RK_PLAT_COMMON}/drivers/pmu/                \
 				-I${RK_PLAT_COMMON}/drivers/parameter/		\
 				-I${RK_PLAT_SOC}/				\
@@ -44,7 +44,7 @@
 				${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c	\
 				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
 				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
-				${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S	\
+				${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S	\
 				${RK_PLAT_COMMON}/plat_pm.c			\
 				${RK_PLAT_COMMON}/plat_topology.c		\
 				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
index d1315fc..8988dc5 100644
--- a/plat/rockchip/rk3368/platform.mk
+++ b/plat/rockchip/rk3368/platform.mk
@@ -12,7 +12,7 @@
 
 PLAT_INCLUDES		:=	-I${RK_PLAT_COMMON}/				\
 				-I${RK_PLAT_COMMON}/include/			\
-				-I${RK_PLAT_COMMON}/pmusram			\
+				-I${RK_PLAT_COMMON}/aarch64/			\
 				-I${RK_PLAT_COMMON}/drivers/pmu/			\
 				-I${RK_PLAT_SOC}/				\
 				-I${RK_PLAT_SOC}/drivers/pmu/			\
@@ -41,7 +41,7 @@
 				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
 				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
 				${RK_PLAT_COMMON}/params_setup.c                \
-				${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S		\
+				${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S	\
 				${RK_PLAT_COMMON}/plat_pm.c			\
 				${RK_PLAT_COMMON}/plat_topology.c		\
 				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 1013598..3dfafc9 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -12,7 +12,7 @@
 
 PLAT_INCLUDES		:=	-I${RK_PLAT_COMMON}/			\
 				-I${RK_PLAT_COMMON}/include/		\
-				-I${RK_PLAT_COMMON}/pmusram		\
+				-I${RK_PLAT_COMMON}/aarch64/		\
 				-I${RK_PLAT_COMMON}/drivers/pmu/	\
 				-I${RK_PLAT_SOC}/			\
 				-I${RK_PLAT_SOC}/drivers/pmu/		\
@@ -49,7 +49,7 @@
 			${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
 			${RK_PLAT_COMMON}/bl31_plat_setup.c		\
 			${RK_PLAT_COMMON}/params_setup.c		\
-			${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S	\
+			${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S	\
 			${RK_PLAT_COMMON}/plat_pm.c			\
 			${RK_PLAT_COMMON}/plat_topology.c		\
 			${RK_PLAT_COMMON}/aarch64/platform_common.c	\
diff --git a/readme.rst b/readme.rst
index 998369f..fc03555 100644
--- a/readme.rst
+++ b/readme.rst
@@ -12,7 +12,7 @@
 such as:
 
 -  The `Power State Coordination Interface (PSCI)`_
--  Trusted Board Boot Requirements (TBBR, Arm DEN0006C-1)
+-  `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT)`_
 -  `SMC Calling Convention`_
 -  `System Control and Management Interface (SCMI)`_
 -  `Software Delegated Exception Interface (SDEI)`_
@@ -320,6 +320,7 @@
 .. _Secure Monitor: http://www.arm.com/products/processors/technologies/trustzone/tee-smc.php
 .. _Power State Coordination Interface (PSCI): PSCI_
 .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
 .. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
 .. _System Control and Management Interface (SCMI): SCMI_
 .. _SCMI: http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/DEN0056A_System_Control_and_Management_Interface.pdf