Merge pull request #973 from danh-arm/dh/add-maintainers

Docs: Clarify copyright requirements
diff --git a/docs/plat/hikey960.md b/docs/plat/hikey960.md
new file mode 100644
index 0000000..786a54b
--- /dev/null
+++ b/docs/plat/hikey960.md
@@ -0,0 +1,134 @@
+
+Description
+====================
+  HiKey960 is one of 96boards. Hisilicon Hi3660 processor is installed on HiKey960.
+
+  More information are listed in [link](http://www.96boards.org/documentation/ConsumerEdition/HiKey960/README.md).
+
+
+How to build
+====================
+
+1. Code Locations
+-----------------
+
+   * ARM Trusted Firmware:
+   [link](https://github.com/ARM-software/arm-trusted-firmware)
+
+   * edk2:
+   [link](https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5)
+
+   * OpenPlatformPkg:
+   [link](https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4)
+
+   * l-loader:
+   [link](https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2)
+
+   * uefi-tools:
+   [link](https://github.com/96boards-hikey/uefi-tools/tree/hikey960_v1)
+
+
+2. Build Procedure
+------------------
+
+   * Fetch all the above 5 repositories into local host.
+     Make all the repositories in the same ${BUILD_PATH}.
+
+   * Create the symbol link to OpenPlatformPkg in edk2.
+     <br>`$cd ${BUILD_PATH}/edk2`</br>
+     <br>`$ln -sf ../OpenPlatformPkg`</br>
+
+   * Prepare AARCH64 toolchain.
+
+   * If your hikey960 hardware is v1, update _uefi-tools/platform.config_ first. _(optional)_
+     <br>__Uncomment the below sentence. Otherwise, UEFI can't output messages on serial
+     console on hikey960 v1.__</br>
+     <br>`BUILDFLAGS=-DSERIAL_BASE=0xFDF05000`</br>
+     <br>If your hikey960 hardware is v2 or newer, nothing to do.</br>
+
+   * Build it as debug mode. Create script file for build.
+     <br>`BUILD_OPTION=DEBUG`</br>
+     <br>`export AARCH64_TOOLCHAIN=GCC48`</br>
+     <br>`export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools`<br>
+     <br>`export EDK2_DIR=${BUILD_PATH}/edk2`</br>
+     <br>`EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey960/${BUILD_OPTION}_${AARCH64_TOOLCHAIN}`</br>
+     <br>`cd ${EDK2_DIR}`</br>
+     <br>`# Build UEFI & ARM Trust Firmware`</br>
+     <br>`${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware hikey960`</br>
+     <br>`# Generate l-loader.bin`</br>
+     <br>`cd ${BUILD_PATH}/l-loader`</br>
+     <br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin`</br>
+     <br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin`</br>
+     <br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd`</br>
+     <br>`python gen_loader.py -o l-loader.bin --img_bl1=bl1.bin --img_ns_bl1u=BL33_AP_UEFI.fd`</br>
+
+   * Generate partition table.
+     <br>_Make sure that you're using the sgdisk in the l-loader directory._</br>
+     <br>`$PTABLE=aosp-32g SECTOR_SIZE=4096 SGDISK=./sgdisk bash -x generate_ptable.sh`</br>
+
+
+3. Setup Console
+----------------
+
+   * Install ser2net. Use telnet as the console since UEFI will output window
+     that fails to display in minicom.
+     <br>`$sudo apt-get install ser2net`</br>
+
+   * Configure ser2net.
+     <br>`$sudo vi /etc/ser2net.conf`</br>
+     <br>Append one line for serial-over-USB in below.</br>
+     <br>_#ser2net.conf_</br>
+     <br>`2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner`</br>
+
+   * Open the console.
+     <br>`$telnet localhost 2004`</br>
+     <br>And you could open the console remotely, too.</br>
+
+
+4. Boot UEFI in recovery mode
+-----------------------------
+
+   * Fetch that are used in recovery mode. The code location is in below.
+     [link](https://github.com/96boards-hikey/tools-images-hikey960)
+
+   * Generate l-loader.bin.
+     <br>`$cd tools-images-hikey960`</br>
+     <br>`$ln -sf ${BUILD_PATH}/l-loader/l-loader.bin`</br>
+
+   * Prepare config file.
+     <br>_$vi config_</br>
+     <br>_# The content of config file_</br>
+     <br>`./sec_user_xloader.img 0x00020000`</br>
+     <br>`./sec_uce_boot.img 0x6A908000`</br>
+     <br>`./l-loader.bin 0x1AC00000`</br>
+
+   * Remove the modemmanager package. This package may causes hikey_idt tool failure.
+     <br>`$sudo apt-get purge modemmanager`</br>
+
+   * Run the command to download l-loader.bin into HiKey960.
+     <br>`$sudo ./hikey_idt -c config -p /dev/ttyUSB1`</br>
+
+   * UEFI running in recovery mode.
+     <br>When prompt '.' is displayed on console, press hotkey 'f' in keyboard. Then Android fastboot app is running.</br>
+     <br>The timeout of prompt '.' is 10 seconds.</br>
+
+   * Update images.
+     <br>`$sudo fastboot flash ptable prm_ptable.img`</br>
+     <br>`$sudo fastboot flash xloader sec_xloader.img`</br>
+     <br>`$sudo fastboot flash fastboot l-loader.bin`</br>
+     <br>`$sudo fastboot flash fip fip.bin`</br>
+     <br>`$sudo fastboot flash boot boot.img`</br>
+     <br>`$sudo fastboot flash cache cache.img`</br>
+     <br>`$sudo fastboot flash system system.img`</br>
+     <br>`$sudo fastboot flash userdata userdata.img`</br>
+
+   * Notice: UEFI could also boot kernel in recovery mode, but BL31 isn't loaded in
+     recovery mode.
+
+
+5. Boot UEFI in normal mode
+-----------------------------
+
+   * Make sure "Boot Mode" switch is OFF for normal boot mode. Then power on HiKey960.
+
+   * Reference [link](https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md)
diff --git a/drivers/auth/mbedtls/mbedtls_common.c b/drivers/auth/mbedtls/mbedtls_common.c
index 3799d41..e9aa409 100644
--- a/drivers/auth/mbedtls/mbedtls_common.c
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -9,6 +9,7 @@
 /* mbed TLS headers */
 #include <mbedtls/memory_buffer_alloc.h>
 #include <mbedtls/platform.h>
+#include <mbedtls_config.h>
 
 /*
  * mbed TLS heap
@@ -31,8 +32,10 @@
 		/* Initialize the mbed TLS heap */
 		mbedtls_memory_buffer_alloc_init(heap, MBEDTLS_HEAP_SIZE);
 
+#ifdef MBEDTLS_PLATFORM_SNPRINTF_ALT
 		/* Use reduced version of snprintf to save space. */
 		mbedtls_platform_set_snprintf(tf_snprintf);
+#endif
 
 		ready = 1;
 	}
diff --git a/include/lib/stdlib/machine/endian.h b/include/lib/stdlib/machine/endian.h
new file mode 100644
index 0000000..57e33b1
--- /dev/null
+++ b/include/lib/stdlib/machine/endian.h
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2001 David E. O'Brien
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)endian.h	8.1 (Berkeley) 6/10/93
+ * $NetBSD: endian.h,v 1.7 1999/08/21 05:53:51 simonb Exp $
+ * $FreeBSD$
+ */
+/*
+ * Portions copyright (c) 2017, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef _MACHINE_ENDIAN_H_
+#define	_MACHINE_ENDIAN_H_
+
+#include <sys/_types.h>
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define	_LITTLE_ENDIAN  1234    /* LSB first: i386, vax */
+#define	_BIG_ENDIAN     4321    /* MSB first: 68000, ibm, net */
+#define	_PDP_ENDIAN     3412    /* LSB first in word, MSW first in long */
+
+#define	_BYTE_ORDER	_LITTLE_ENDIAN
+
+#if __BSD_VISIBLE
+#define	LITTLE_ENDIAN   _LITTLE_ENDIAN
+#define	BIG_ENDIAN      _BIG_ENDIAN
+#define	PDP_ENDIAN      _PDP_ENDIAN
+#define	BYTE_ORDER      _BYTE_ORDER
+#endif
+
+#define	_QUAD_HIGHWORD  1
+#define	_QUAD_LOWWORD 0
+#define	__ntohl(x)        (__bswap32(x))
+#define	__ntohs(x)        (__bswap16(x))
+#define	__htonl(x)        (__bswap32(x))
+#define	__htons(x)        (__bswap16(x))
+
+#ifdef AARCH32
+static __inline __uint64_t
+__bswap64(__uint64_t _x)
+{
+
+	return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) |
+	    ((_x >> 8) & 0xff000000) | ((_x << 8) & ((__uint64_t)0xff << 32)) |
+	    ((_x << 24) & ((__uint64_t)0xff << 40)) |
+	    ((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56)));
+}
+
+static __inline __uint32_t
+__bswap32_var(__uint32_t v)
+{
+	__uint32_t t1;
+
+	__asm __volatile("eor %1, %0, %0, ror #16\n"
+			"bic %1, %1, #0x00ff0000\n"
+			"mov %0, %0, ror #8\n"
+			"eor %0, %0, %1, lsr #8\n"
+			 : "+r" (v), "=r" (t1));
+
+	return (v);
+}
+
+static __inline __uint16_t
+__bswap16_var(__uint16_t v)
+{
+	__uint32_t ret = v & 0xffff;
+
+	__asm __volatile(
+	    "mov    %0, %0, ror #8\n"
+	    "orr    %0, %0, %0, lsr #16\n"
+	    "bic    %0, %0, %0, lsl #16"
+	    : "+r" (ret));
+
+	return ((__uint16_t)ret);
+}
+#elif defined AARCH64
+static __inline __uint64_t
+__bswap64(__uint64_t x)
+{
+	__uint64_t ret;
+
+	__asm __volatile("rev %0, %1\n"
+			 : "=&r" (ret), "+r" (x));
+	
+	return (ret);
+}
+
+static __inline __uint32_t
+__bswap32_var(__uint32_t v)
+{
+	__uint32_t ret;
+
+	__asm __volatile("rev32 %x0, %x1\n"
+			 : "=&r" (ret), "+r" (v));
+	
+	return (ret);
+}
+
+static __inline __uint16_t
+__bswap16_var(__uint16_t v)
+{
+	__uint32_t ret;
+
+	__asm __volatile("rev16 %w0, %w1\n"
+			 : "=&r" (ret), "+r" (v));
+
+	return ((__uint16_t)ret);
+}		
+#else
+#error "Only AArch32 or AArch64 supported"
+#endif /* AARCH32 */
+
+#ifdef __OPTIMIZE__
+
+#define	__bswap32_constant(x)	\
+    ((((x) & 0xff000000U) >> 24) |	\
+     (((x) & 0x00ff0000U) >>  8) |	\
+     (((x) & 0x0000ff00U) <<  8) |	\
+     (((x) & 0x000000ffU) << 24))
+
+#define	__bswap16_constant(x)	\
+    ((((x) & 0xff00) >> 8) |		\
+     (((x) & 0x00ff) << 8))
+
+#define	__bswap16(x)	\
+    ((__uint16_t)(__builtin_constant_p(x) ?	\
+     __bswap16_constant(x) :			\
+     __bswap16_var(x)))
+
+#define	__bswap32(x)	\
+    ((__uint32_t)(__builtin_constant_p(x) ? 	\
+     __bswap32_constant(x) :			\
+     __bswap32_var(x)))
+
+#else
+#define	__bswap16(x)	__bswap16_var(x)
+#define	__bswap32(x)	__bswap32_var(x)
+
+#endif /* __OPTIMIZE__ */
+#endif /* !_MACHINE_ENDIAN_H_ */
diff --git a/include/lib/stdlib/sys/endian.h b/include/lib/stdlib/sys/endian.h
new file mode 100644
index 0000000..d50110c
--- /dev/null
+++ b/include/lib/stdlib/sys/endian.h
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_ENDIAN_H_
+#define _SYS_ENDIAN_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+#include <machine/endian.h>
+
+#ifndef _UINT8_T_DECLARED
+typedef	__uint8_t	uint8_t;
+#define	_UINT8_T_DECLARED
+#endif
+ 
+#ifndef _UINT16_T_DECLARED
+typedef	__uint16_t	uint16_t;
+#define	_UINT16_T_DECLARED
+#endif
+ 
+#ifndef _UINT32_T_DECLARED
+typedef	__uint32_t	uint32_t;
+#define	_UINT32_T_DECLARED
+#endif
+ 
+#ifndef _UINT64_T_DECLARED
+typedef	__uint64_t	uint64_t;
+#define	_UINT64_T_DECLARED
+#endif
+ 
+/*
+ * General byte order swapping functions.
+ */
+#define	bswap16(x)	__bswap16(x)
+#define	bswap32(x)	__bswap32(x)
+#define	bswap64(x)	__bswap64(x)
+
+/*
+ * Host to big endian, host to little endian, big endian to host, and little
+ * endian to host byte order functions as detailed in byteorder(9).
+ */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#define	htobe16(x)	bswap16((x))
+#define	htobe32(x)	bswap32((x))
+#define	htobe64(x)	bswap64((x))
+#define	htole16(x)	((uint16_t)(x))
+#define	htole32(x)	((uint32_t)(x))
+#define	htole64(x)	((uint64_t)(x))
+
+#define	be16toh(x)	bswap16((x))
+#define	be32toh(x)	bswap32((x))
+#define	be64toh(x)	bswap64((x))
+#define	le16toh(x)	((uint16_t)(x))
+#define	le32toh(x)	((uint32_t)(x))
+#define	le64toh(x)	((uint64_t)(x))
+#else /* _BYTE_ORDER != _LITTLE_ENDIAN */
+#define	htobe16(x)	((uint16_t)(x))
+#define	htobe32(x)	((uint32_t)(x))
+#define	htobe64(x)	((uint64_t)(x))
+#define	htole16(x)	bswap16((x))
+#define	htole32(x)	bswap32((x))
+#define	htole64(x)	bswap64((x))
+
+#define	be16toh(x)	((uint16_t)(x))
+#define	be32toh(x)	((uint32_t)(x))
+#define	be64toh(x)	((uint64_t)(x))
+#define	le16toh(x)	bswap16((x))
+#define	le32toh(x)	bswap32((x))
+#define	le64toh(x)	bswap64((x))
+#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
+
+/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
+
+static __inline uint16_t
+be16dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return ((p[0] << 8) | p[1]);
+}
+
+static __inline uint32_t
+be32dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static __inline uint64_t
+be64dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
+}
+
+static __inline uint16_t
+le16dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return ((p[1] << 8) | p[0]);
+}
+
+static __inline uint32_t
+le32dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+}
+
+static __inline uint64_t
+le64dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
+}
+
+static __inline void
+be16enc(void *pp, uint16_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = (u >> 8) & 0xff;
+	p[1] = u & 0xff;
+}
+
+static __inline void
+be32enc(void *pp, uint32_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = (u >> 24) & 0xff;
+	p[1] = (u >> 16) & 0xff;
+	p[2] = (u >> 8) & 0xff;
+	p[3] = u & 0xff;
+}
+
+static __inline void
+be64enc(void *pp, uint64_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	be32enc(p, (uint32_t)(u >> 32));
+	be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
+}
+
+static __inline void
+le16enc(void *pp, uint16_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+}
+
+static __inline void
+le32enc(void *pp, uint32_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+	p[2] = (u >> 16) & 0xff;
+	p[3] = (u >> 24) & 0xff;
+}
+
+static __inline void
+le64enc(void *pp, uint64_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	le32enc(p, (uint32_t)(u & 0xffffffffU));
+	le32enc(p + 4, (uint32_t)(u >> 32));
+}
+
+#endif	/* _SYS_ENDIAN_H_ */
diff --git a/plat/hisilicon/hikey/hisi_sip_svc.c b/plat/hisilicon/hikey/hisi_sip_svc.c
new file mode 100644
index 0000000..15953af
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_sip_svc.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <hisi_sip_svc.h>
+#include <debug.h>
+#include <pmf.h>
+#include <runtime_svc.h>
+#include <stdint.h>
+#include <uuid.h>
+
+
+/* Hisi SiP Service UUID */
+DEFINE_SVC_UUID(hisi_sip_svc_uid,
+		0xe599df74, 0x7682, 0x40aa, 0x9f, 0xf8,
+		0xc0, 0x85, 0x52, 0xbc, 0x39, 0x3f);
+
+static int hisi_sip_setup(void)
+{
+	if (pmf_setup() != 0)
+		return 1;
+	return 0;
+}
+
+/*
+ * This function handles Hisi defined SiP Calls
+ */
+static uintptr_t hisi_sip_handler(unsigned int 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)
+{
+	int call_count = 0;
+
+	/*
+	 * Dispatch PMF calls to PMF SMC handler and return its return
+	 * value
+	 */
+	if (is_pmf_fid(smc_fid)) {
+		return pmf_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+				handle, flags);
+	}
+
+	switch (smc_fid) {
+	case HISI_SIP_SVC_CALL_COUNT:
+		/* PMF calls */
+		call_count += PMF_NUM_SMC_CALLS;
+
+		/* State switch call */
+		call_count += 1;
+
+		SMC_RET1(handle, call_count);
+
+	case HISI_SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, hisi_sip_svc_uid);
+
+	case HISI_SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, HISI_SIP_SVC_VERSION_MAJOR, HISI_SIP_SVC_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented HISI SiP Service Call: 0x%x \n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+}
+
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	hisi_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	hisi_sip_setup,
+	hisi_sip_handler
+);
diff --git a/plat/hisilicon/hikey/include/hisi_sip_svc.h b/plat/hisilicon/hikey/include/hisi_sip_svc.h
new file mode 100644
index 0000000..662b6cc
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_sip_svc.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HISI_SIP_SVC_H__
+#define __HISI_SIP_SVC_H__
+
+/* SMC function IDs for SiP Service queries */
+
+#define HISI_SIP_SVC_CALL_COUNT		0x8200ff00
+#define HISI_SIP_SVC_UID			0x8200ff01
+/*					0x8200ff02 is reserved */
+#define HISI_SIP_SVC_VERSION			0x8200ff03
+
+/* HISI SiP Service Calls version numbers */
+#define HISI_SIP_SVC_VERSION_MAJOR		0x0
+#define HISI_SIP_SVC_VERSION_MINOR		0x1
+
+#endif /* __ARM_SIP_SVC_H__ */
diff --git a/plat/hisilicon/hikey/platform.mk b/plat/hisilicon/hikey/platform.mk
index fb5f852..85dc40d 100644
--- a/plat/hisilicon/hikey/platform.mk
+++ b/plat/hisilicon/hikey/platform.mk
@@ -77,3 +77,8 @@
 				plat/hisilicon/hikey/hisi_pwrc.c	\
 				plat/hisilicon/hikey/hisi_pwrc_sram.S	\
 				${HIKEY_GIC_SOURCES}
+ifeq (${ENABLE_PMF}, 1)
+BL31_SOURCES		+=	plat/hisilicon/hikey/hisi_sip_svc.c			\
+				lib/pmf/pmf_smc.c
+endif
+
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_common.c b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
new file mode 100644
index 0000000..d7894b3
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <xlat_tables.h>
+
+#include "../hikey960_def.h"
+#include "../hikey960_private.h"
+
+#define MAP_DDR		MAP_REGION_FLAT(DDR_BASE,			\
+					DDR_SIZE,			\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_DEVICE	MAP_REGION_FLAT(DEVICE_BASE,			\
+					DEVICE_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_BL1_RW	MAP_REGION_FLAT(BL1_RW_BASE,			\
+					BL1_RW_LIMIT - BL1_RW_BASE,	\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DATA	MAP_REGION_FLAT(HIKEY960_UFS_DATA_BASE,		\
+					HIKEY960_UFS_DATA_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DESC	MAP_REGION_FLAT(HIKEY960_UFS_DESC_BASE,		\
+					HIKEY960_UFS_DESC_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
+ * hikey960_init_mmu_elx() will give the available subset of that,
+ */
+#if IMAGE_BL1
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_UFS_DATA,
+	MAP_BL1_RW,
+	MAP_UFS_DESC,
+	MAP_DEVICE,
+	{0}
+};
+#endif
+
+#if IMAGE_BL2
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_DDR,
+	MAP_DEVICE,
+	{0}
+};
+#endif
+
+#if IMAGE_BL31
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_DEVICE,
+	{0}
+};
+#endif
+
+/*
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ */
+#define HIKEY960_CONFIGURE_MMU_EL(_el)					\
+	void hikey960_init_mmu_el##_el(unsigned long total_base,	\
+				unsigned long total_size,		\
+				unsigned long ro_start,			\
+				unsigned long ro_limit,			\
+				unsigned long coh_start,		\
+				unsigned long coh_limit)		\
+	{								\
+	       mmap_add_region(total_base, total_base,			\
+			       total_size,				\
+			       MT_MEMORY | MT_RW | MT_SECURE);		\
+	       mmap_add_region(ro_start, ro_start,			\
+			       ro_limit - ro_start,			\
+			       MT_MEMORY | MT_RO | MT_SECURE);		\
+	       mmap_add_region(coh_start, coh_start,			\
+			       coh_limit - coh_start,			\
+			       MT_DEVICE | MT_RW | MT_SECURE);		\
+	       mmap_add(hikey960_mmap);					\
+	       init_xlat_tables();					\
+									\
+	       enable_mmu_el##_el(0);					\
+	}
+
+/* Define EL1 and EL3 variants of the function initialising the MMU */
+HIKEY960_CONFIGURE_MMU_EL(1)
+HIKEY960_CONFIGURE_MMU_EL(3)
+
+unsigned long plat_get_ns_image_entrypoint(void)
+{
+	return NS_BL1U_BASE;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 1920000;
+}
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
new file mode 100644
index 0000000..2e24416
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <cortex_a73.h>
+#include "../hikey960_def.h"
+
+	.globl	plat_my_core_pos
+	.globl	platform_mem_init
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_report_exception
+	.globl	plat_reset_handler
+	.globl	set_retention_ticks
+	.globl	clr_retention_ticks
+	.globl	clr_ex
+	.globl	nop
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * void platform_mem_init(void);
+	 *
+	 * We don't need to carry out any memory initialization
+	 * on HIKEY. The Secure RAM is accessible straight away.
+	 * -----------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	mov_imm	x1, PL011_UART_CLK_IN_HZ
+	mov_imm	x2, PL011_BAUDRATE
+	b	console_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, CRASH_CONSOLE_BASE
+	b	console_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * void plat_report_exception(unsigned int type)
+	 * Function to report an unhandled exception
+	 * with platform-specific means.
+	 * On HIKEY platform, it updates the LEDs
+	 * to indicate where we are
+	 * ---------------------------------------------
+	 */
+func plat_report_exception
+	mov	x8, x30
+
+	/* Turn on LED according to x0 (0 -- f) */
+	ldr	x2, =0xf7020000
+	and	x1, x0, #1
+	str	w1, [x2, #4]
+	and	x1, x0, #2
+	str	w1, [x2, #8]
+	and	x1, x0, #4
+	str	w1, [x2, #16]
+	and	x1, x0, #8
+	str	w1, [x2, #32]
+
+	mrs	x2, currentel
+	and	x2, x2, #0x0c
+	/* Check EL1 */
+	cmp	x2, #0x04
+	beq	plat_report_el1
+
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el3
+	bl	asm_print_hex
+
+	adr	x4, elr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el3
+	bl	asm_print_hex
+	b	plat_report_end
+
+plat_report_el1:
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el1
+	bl	asm_print_hex
+
+	adr	x4, elr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el1
+	bl	asm_print_hex
+plat_report_end:
+	mov	x30, x8
+	ret
+endfunc plat_report_exception
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	ret
+endfunc plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * void set_retention_ticks(unsigned int val);
+	 * Clobber list : x0
+	 * -----------------------------------------------------
+	 */
+func set_retention_ticks
+	mrs	x0, CPUECTLR_EL1
+	bic	x0, x0, #CPUECTLR_CPU_RET_CTRL_MASK
+	orr	x0, x0, #RETENTION_ENTRY_TICKS_8
+	msr	CPUECTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+endfunc set_retention_ticks
+
+	/* -----------------------------------------------------
+	 * void clr_retention_ticks(unsigned int val);
+	 * Clobber list : x0
+	 * -----------------------------------------------------
+	 */
+func clr_retention_ticks
+	mrs	x0, CPUECTLR_EL1
+	bic	x0, x0, #CPUECTLR_CPU_RET_CTRL_MASK
+	msr	CPUECTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+endfunc clr_retention_ticks
+
+	/* -----------------------------------------------------
+	 * void clrex(void);
+	 * -----------------------------------------------------
+	 */
+func clr_ex
+	clrex
+	ret
+endfunc clr_ex
+
+	/* -----------------------------------------------------
+	 * void nop(void);
+	 * -----------------------------------------------------
+	 */
+func nop
+	nop
+	ret
+endfunc nop
+
+.section .rodata.rev_err_str, "aS"
+plat_err_str:
+	.asciz "\nPlatform exception reporting:"
+esr_el3_str:
+	.asciz "\nESR_EL3: "
+elr_el3_str:
+	.asciz "\nELR_EL3: "
+esr_el1_str:
+	.asciz "\nESR_EL1: "
+elr_el1_str:
+	.asciz "\nELR_EL1: "
diff --git a/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
new file mode 100644
index 0000000..8ce1e4f
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <hisi_ipc.h>
+#include <debug.h>
+
+#include "../../hikey960_private.h"
+
+#define IPC_MBX_SOURCE_REG(m)		(IPC_BASE + ((m) << 6))
+#define IPC_MBX_DSET_REG(m)		(IPC_BASE + ((m) << 6) + 0x04)
+#define IPC_MBX_DCLEAR_REG(m)		(IPC_BASE + ((m) << 6) + 0x08)
+#define IPC_MBX_DSTATUS_REG(m)		(IPC_BASE + ((m) << 6) + 0x0C)
+#define IPC_MBX_MODE_REG(m)		(IPC_BASE + ((m) << 6) + 0x10)
+#define IPC_MBX_IMASK_REG(m)		(IPC_BASE + ((m) << 6) + 0x14)
+#define IPC_MBX_ICLR_REG(m)		(IPC_BASE + ((m) << 6) + 0x18)
+#define IPC_MBX_SEND_REG(m)		(IPC_BASE + ((m) << 6) + 0x1C)
+#define IPC_MBX_DATA_REG(m, d)		(IPC_BASE + ((m) << 6) + 0x20 + \
+					 ((d) * 4))
+#define IPC_CPU_IMST_REG(m)		(IPC_BASE + ((m) << 3))
+#define IPC_LOCK_REG			(IPC_BASE + 0xA00)
+#define IPC_ACK_BIT_SHIFT		(1 << 7)
+#define IPC_UNLOCK_VALUE		(0x1ACCE551)
+
+/*********************************************************
+ *bit[31:24]:0~AP
+ *bit[23:16]:0x1~A15, 0x2~A7
+ *bit[15:8]:0~ON, 1~OFF
+ *bit[7:0]:0x3 cpu power mode
+ *********************************************************/
+#define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \
+	((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode))
+
+/*********************************************************
+ *bit[15:8]:0~no idle, 1~idle
+ *bit[7:0]:cpux
+ *********************************************************/
+
+#define IPC_CMD_PARA(is_idle, cpu) \
+	((is_idle << 8) | (cpu))
+
+#define IPC_STATE_IDLE			0x10
+
+enum src_id {
+	SRC_IDLE = 0,
+	SRC_A15 = 1 << 0,
+	SRC_A7 = 1 << 1,
+	SRC_IOM3 = 1 << 2,
+	SRC_LPM3 = 1 << 3
+};
+
+/*lpm3's mailboxs are 13~17*/
+enum lpm3_mbox_id {
+	LPM3_MBX0 = 13,
+	LPM3_MBX1,
+	LPM3_MBX2,
+	LPM3_MBX3,
+	LPM3_MBX4,
+};
+
+static void cpu_relax(void)
+{
+	volatile int i;
+
+	for (i = 0; i < 10; i++)
+		nop();
+}
+
+static inline void
+hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox)
+{
+	unsigned int int_status = 0;
+
+	do {
+		int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox));
+		int_status &= 0xF0;
+		cpu_relax();
+	} while (int_status != IPC_ACK_BIT_SHIFT);
+
+	mmio_write_32(IPC_MBX_ICLR_REG(mbox), source);
+}
+
+static void
+hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox,
+			   unsigned int cmdtype, unsigned int cmdpara)
+{
+	unsigned int regval;
+	unsigned int mask;
+	unsigned int state;
+
+	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
+	/* wait for idle and occupy */
+	do {
+		state = mmio_read_32(IPC_MBX_MODE_REG(mbox));
+		if (state == IPC_STATE_IDLE) {
+			mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
+			regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox));
+			if (regval == source)
+				break;
+		}
+		cpu_relax();
+
+	} while (1);
+
+	/* auto answer */
+	mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1);
+
+	mask = (~((int)source | SRC_LPM3) & 0x3F);
+	/* mask the other cpus */
+	mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask);
+	/* set data */
+	mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype);
+	mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara);
+	/* send cmd */
+	mmio_write_32(IPC_MBX_SEND_REG(mbox), source);
+	/* wait ack and clear */
+	hisi_ipc_clear_ack(source, mbox);
+
+	/* release mailbox */
+	mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
+}
+
+void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
+			enum pm_mode mode)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3);
+	cmdpara = IPC_CMD_PARA(0, core);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
+			 unsigned int affinity_level)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	if (affinity_level == 0x3)
+		cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level);
+	else
+		cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level);
+
+	cmdpara = IPC_CMD_PARA(1, core);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0);
+	cmdpara = IPC_CMD_PARA(0, 0);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
+				unsigned int cmd_id)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0);
+	cmdpara = cmd_id;
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+int hisi_ipc_init(void)
+{
+	int ret = 0;
+	enum lpm3_mbox_id  i = LPM3_MBX0;
+
+	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
+	for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) {
+		mmio_write_32(IPC_MBX_MODE_REG(i), 1);
+		mmio_write_32(IPC_MBX_IMASK_REG(i),
+			      ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7));
+		mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7);
+	}
+
+	return ret;
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
new file mode 100644
index 0000000..f82144a
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <../hikey960_def.h>
+#include <hisi_ipc.h>
+#include "hisi_pwrc.h"
+
+
+/* resource lock api */
+#define RES0_LOCK_BASE		(SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE))
+#define RES1_LOCK_BASE		(SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE))
+#define RES2_LOCK_BASE		(SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE))
+
+#define LOCK_BIT			(0x1 << 28)
+#define LOCK_ID_MASK			(0x7 << 29)
+#define CPUIDLE_LOCK_ID(core)		(0x6 - (core))
+#define LOCK_UNLOCK_OFFSET		0x4
+#define LOCK_STAT_OFFSET		0x8
+
+#define CLUSTER0_CPUS_ONLINE_MASK	(0xF << 16)
+#define	CLUSTER1_CPUS_ONLINE_MASK	(0xF << 20)
+
+/* cpu hotplug flag api */
+#define SCTRL_BASE			(SOC_ACPU_SCTRL_BASE_ADDR)
+#define REG_SCBAKDATA3_OFFSET		(SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE))
+#define REG_SCBAKDATA8_OFFSET		(SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE))
+#define REG_SCBAKDATA9_OFFSET		(SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE))
+
+#define CPUIDLE_FLAG_REG(cluster) \
+			((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \
+			 REG_SCBAKDATA9_OFFSET)
+#define CLUSTER_IDLE_BIT				BIT(8)
+#define CLUSTER_IDLE_MASK		(CLUSTER_IDLE_BIT | 0x0F)
+
+#define AP_SUSPEND_FLAG			(1 << 16)
+
+#define CLUSTER_PWDN_IDLE		(0<<28)
+#define CLUSTER_PWDN_HOTPLUG		(1<<28)
+#define CLUSTER_PWDN_SR			(2<<28)
+
+#define CLUSTER0_PDC_OFFSET			0x260
+#define CLUSTER1_PDC_OFFSET			0x300
+
+#define PDC_EN_OFFSET				0x0
+#define PDC_COREPWRINTEN_OFFSET		0x4
+#define PDC_COREPWRINTSTAT_OFFSET	0x8
+#define PDC_COREGICMASK_OFFSET		0xc
+#define PDC_COREPOWERUP_OFFSET		0x10
+#define PDC_COREPOWERDN_OFFSET		0x14
+#define PDC_COREPOWERSTAT_OFFSET	0x18
+
+#define PDC_COREPWRSTAT_MASK   (0XFFFF)
+
+enum pdc_gic_mask {
+	PDC_MASK_GIC_WAKE_IRQ,
+	PDC_UNMASK_GIC_WAKE_IRQ
+};
+
+enum pdc_finish_int_mask {
+	PDC_DISABLE_FINISH_INT,
+	PDC_ENABLE_FINISH_INT
+};
+
+static void hisi_resource_lock(unsigned int lockid, unsigned int offset)
+{
+	unsigned int lock_id = (lockid << 29);
+	unsigned int lock_val =  lock_id | LOCK_BIT;
+	unsigned int lock_state;
+
+	do {
+		mmio_write_32(offset, lock_val);
+		lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset);
+	} while ((lock_state & LOCK_ID_MASK) != lock_id);
+}
+
+static void hisi_resource_unlock(unsigned int lockid, unsigned int offset)
+{
+	unsigned int lock_val = (lockid << 29) | LOCK_BIT;
+
+	mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val);
+}
+
+
+static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core)
+{
+	unsigned int lock_id;
+
+	lock_id = (cluster << 2) + core;
+
+	hisi_resource_lock(lock_id, RES2_LOCK_BASE);
+}
+
+static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core)
+{
+	unsigned int lock_id;
+
+	lock_id = (cluster << 2) + core;
+
+	hisi_resource_unlock(lock_id, RES2_LOCK_BASE);
+}
+
+/* get the resource lock */
+void hisi_cpuidle_lock(unsigned int cluster, unsigned int core)
+{
+	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
+
+	hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset);
+}
+
+/* release the resource lock */
+void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core)
+{
+	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
+
+	hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset);
+}
+
+unsigned int hisi_get_cpuidle_flag(unsigned int cluster)
+{
+	unsigned int val;
+
+	val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
+	val &= 0xF;
+
+	return val;
+}
+
+void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
+{
+	mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
+}
+
+void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
+{
+	mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
+
+}
+
+int hisi_test_ap_suspend_flag(unsigned int cluster)
+{
+	unsigned int val;
+
+	val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
+	val &= AP_SUSPEND_FLAG;
+	return !!val;
+}
+
+void hisi_set_cluster_pwdn_flag(unsigned int cluster,
+				unsigned int core, unsigned int value)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = (value << (cluster << 1)) | (val & 0xFFFFFFF);
+	mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = val >> (16 + (cluster << 2));
+	val &= 0xF;
+	hisi_cpuhotplug_unlock(cluster, core);
+
+	return val;
+}
+
+unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = val >> (16 + (cluster << 2));
+	val &= 0xF;
+	hisi_cpuhotplug_unlock(cluster, core);
+
+	if (val)
+		return 0;
+	else
+		return 1;
+}
+
+void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int flag = BIT((cluster<<2) + core + 16);
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int flag = BIT((cluster<<2) + core + 16);
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+int cluster_is_powered_on(unsigned int cluster)
+{
+	unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	int ret;
+
+	if (cluster == 0)
+		ret = val & CLUSTER0_CPUS_ONLINE_MASK;
+	else
+		ret = val & CLUSTER1_CPUS_ONLINE_MASK;
+
+	return !!ret;
+}
+
+static void *hisi_get_pdc_addr(unsigned int cluster)
+{
+	void *pdc_base_addr;
+	uintptr_t addr;
+
+	if (cluster == 0)
+		addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE);
+	else
+		addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE);
+	pdc_base_addr = (void *)addr;
+
+	return pdc_base_addr;
+}
+
+static unsigned int hisi_get_pdc_stat(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET);
+
+	return val;
+}
+
+int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
+{
+	unsigned int mask = 0xf << (core * 4);
+	unsigned int pdc_stat = hisi_get_pdc_stat(cluster);
+	unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core);
+	unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster);
+
+	mask = (PDC_COREPWRSTAT_MASK & (~mask));
+	pdc_stat &= mask;
+
+	if ((boot_flag ^ cpuidle_flag) || pdc_stat)
+		return 0;
+	else
+		return 1;
+}
+
+void hisi_disable_pdc(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr, 0x0);
+}
+
+void hisi_enable_pdc(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr, 0x1);
+}
+
+static inline void hisi_pdc_set_intmask(void *pdc_base_addr,
+					unsigned int core,
+					enum pdc_finish_int_mask intmask)
+{
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET);
+	if (intmask == PDC_ENABLE_FINISH_INT)
+		val |= BIT(core);
+	else
+		val &= ~BIT(core);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val);
+}
+
+static inline void hisi_pdc_set_gicmask(void *pdc_base_addr,
+					unsigned int core,
+					enum pdc_gic_mask gicmask)
+{
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET);
+	if (gicmask == PDC_MASK_GIC_WAKE_IRQ)
+		val |= BIT(core);
+	else
+		val &= ~BIT(core);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val);
+}
+
+void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)
+{
+	int i;
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	for (i = 0; i < 4; i++)
+		hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ);
+}
+
+static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core,
+				  enum pdc_gic_mask gicmask,
+				  enum pdc_finish_int_mask intmask)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET,
+		      BIT(core));
+}
+
+static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core,
+				  enum pdc_gic_mask gicmask,
+				  enum pdc_finish_int_mask intmask)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_powerup_core(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_powerdn_core(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
+{
+	hisi_ipc_pm_on_off(core, cluster, PM_ON);
+}
+
+void hisi_powerdn_cluster(unsigned int cluster, unsigned int core)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG);
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
+		      (0x10001 << core));
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_enter_core_idle(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE);
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
+		      (0x10001 << core));
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
+{
+	hisi_ipc_pm_suspend(core, cluster, 0x3);
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
new file mode 100644
index 0000000..a4d887f
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HISI_PWRC_H__
+#define __HISI_PWRC_H__
+
+#include <hi3660.h>
+#include <hi3660_crg.h>
+
+#define PCTRL_BASE					(PCTRL_REG_BASE)
+#define CRG_BASE					(CRG_REG_BASE)
+
+#define SOC_CRGPERIPH_A53_PDCEN_ADDR(base)		((base) + (0x260))
+#define SOC_CRGPERIPH_MAIA_PDCEN_ADDR(base)		((base) + (0x300))
+
+#define SOC_PCTRL_RESOURCE0_LOCK_ADDR(base)		((base) + (0x400))
+#define SOC_PCTRL_RESOURCE0_UNLOCK_ADDR(base)		((base) + (0x404))
+#define SOC_PCTRL_RESOURCE0_LOCK_ST_ADDR(base)		((base) + (0x408))
+#define SOC_PCTRL_RESOURCE1_LOCK_ADDR(base)		((base) + (0x40C))
+#define SOC_PCTRL_RESOURCE1_UNLOCK_ADDR(base)		((base) + (0x410))
+#define SOC_PCTRL_RESOURCE1_LOCK_ST_ADDR(base)		((base) + (0x414))
+#define SOC_PCTRL_RESOURCE2_LOCK_ADDR(base)		((base) + (0x418))
+
+#define SOC_SCTRL_SCBAKDATA3_ADDR(base)			((base) + (0x418))
+#define SOC_SCTRL_SCBAKDATA8_ADDR(base)			((base) + (0x42C))
+#define SOC_SCTRL_SCBAKDATA9_ADDR(base)			((base) + (0x430))
+
+#define SOC_ACPU_SCTRL_BASE_ADDR			(0xFFF0A000)
+
+void hisi_cpuidle_lock(unsigned int cluster, unsigned int core);
+void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core);
+void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core);
+void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core);
+void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core);
+void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core);
+int cluster_is_powered_on(unsigned int cluster);
+void hisi_enter_core_idle(unsigned int cluster, unsigned int core);
+void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core);
+int hisi_test_ap_suspend_flag(unsigned int cluster);
+void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core);
+
+
+/* pdc api */
+void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster);
+int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core);
+void hisi_disable_pdc(unsigned int cluster);
+void hisi_enable_pdc(unsigned int cluster);
+void hisi_powerup_core(unsigned int cluster, unsigned int core);
+void hisi_powerdn_core(unsigned int cluster, unsigned int core);
+void hisi_powerup_cluster(unsigned int cluster, unsigned int core);
+void hisi_powerdn_cluster(unsigned int cluster, unsigned int core);
+unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core);
+
+#endif /* __HISI_PWRC_H__ */
diff --git a/plat/hisilicon/hikey960/hi3660_mailbox.c b/plat/hisilicon/hikey960/hi3660_mailbox.c
new file mode 100644
index 0000000..aa12932
--- /dev/null
+++ b/plat/hisilicon/hikey960/hi3660_mailbox.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <hi3660_mailbox.h>
+#include <mailbox.h>
+#include <mmio.h>
+#include <string.h>
+
+typedef struct hi3660_chan {
+	unsigned char	src;
+	unsigned char	dst;
+	unsigned char	used;
+} hi3660_chan_t;
+
+static hi3660_chan_t chan_map[MBX_MAX_CHANNELS];
+
+static void hi3660_mbox_check_state(int chan, unsigned int state)
+{
+	unsigned int data;
+
+	data = mmio_read_32(MBX_MODE(chan));
+	assert((data & (MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK)) == 0);
+
+	data &= MBX_MODE_STATE_STATUS_MASK;
+	assert(data == state);
+	(void)state;
+}
+
+static int hi3660_mbox_send(int chan, void *message, int len)
+{
+	int i;
+	unsigned int *buf;
+	unsigned int data;
+
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
+	       (message != NULL) && (len <= MBX_MAX_DATA_LEN));
+	assert((chan_map[chan].used != 0) &&
+	       (chan_map[chan].src != 0) &&
+	       (chan_map[chan].dst != 0));
+
+	buf = (unsigned int *)message;
+	len = ((len + 3) >> 2);		/* convert to word count */
+	for (i = 0; i < len; i++)
+		mmio_write_32(MBX_DATA0(chan) + (i << 2), *(buf + i));
+	/* send out */
+	mmio_write_32(MBX_SEND(chan), chan_map[chan].src);
+
+	do {
+		data = mmio_read_32(MBX_ICLR(chan));
+	} while ((data & chan_map[chan].src) == 0);
+	/* ack */
+	mmio_write_32(MBX_ICLR(chan), chan_map[chan].src);
+	return 0;
+}
+
+static int hi3660_mbox_recv(int chan, void *message, int *len)
+{
+	unsigned int *buf, data;
+	int i;
+
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
+	       (message != NULL) && (len != NULL));
+	assert((chan_map[chan].used != 0) &&
+	       (chan_map[chan].src != 0) &&
+	       (chan_map[chan].dst != 0));
+	/* wait IPC event */
+	do {
+		data = mmio_read_32(MBX_MODE(chan));
+	} while ((data & MBX_MODE_STATE_STATUS_MASK) != MBX_MODE_STATE_DEST);
+	/* wait to clear interrupt */
+	do {
+		data = mmio_read_32(MBX_ICLR(chan));
+	} while (data == 0);
+	do {
+		mmio_write_32(MBX_ICLR(chan), chan_map[chan].dst);
+		data = mmio_read_32(MBX_ICLR(chan));
+	} while (data);
+
+	/* read data from IPC */
+	buf = (unsigned int *)message;
+	for (i = 0; i < MBX_MAX_DATA_LEN; i += 4)
+		*(buf + (i >> 2)) = mmio_read_32(MBX_DATA0(chan) + i);
+	*len = MBX_MAX_DATA_LEN;
+	/* ack */
+	mmio_write_32(MBX_SEND(chan), chan_map[chan].dst);
+	return 0;
+}
+
+static int hi3660_mbox_request(int chan, int direction)
+{
+	unsigned int data;
+	unsigned int src, dst;
+
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
+
+	if (direction == MAILBOX_DIR_TX) {
+		src = CPU_A53;
+		dst = CPU_LPM3;
+	} else if (direction == MAILBOX_DIR_RX) {
+		src = CPU_LPM3;
+		dst = CPU_A53;
+	} else
+		assert(0);
+	mmio_write_32(MBX_SOURCE(chan), src);
+	data = mmio_read_32(MBX_SOURCE(chan));
+	assert(data == src);
+
+	/* mask all interrupts */
+	mmio_write_32(MBX_IMASK(chan), CPU_MASK);
+	/* unmask interrupt */
+	mmio_write_32(MBX_IMASK(chan), ~(src | dst));
+
+	/* set destination */
+	mmio_write_32(MBX_DCLEAR(chan), (~dst) & CPU_MASK);
+	mmio_write_32(MBX_DSET(chan), dst);
+	data = mmio_read_32(MBX_DSTATUS(chan));
+	assert((data & dst) != 0);
+
+	/* clear auto link & auto answer */
+	data = mmio_read_32(MBX_MODE(chan));
+	data &= ~(MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK);
+	mmio_write_32(MBX_MODE(chan), data);
+
+	hi3660_mbox_check_state(chan, MBX_MODE_STATE_SOURCE);
+	chan_map[chan].used = 1;
+	chan_map[chan].src = src;
+	chan_map[chan].dst = dst;
+	return 0;
+}
+
+static void hi3660_mbox_free(int chan)
+{
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
+}
+
+static mbox_ops_t hi3660_mbox_ops = {
+	.send		= hi3660_mbox_send,
+	.recv		= hi3660_mbox_recv,
+	.request	= hi3660_mbox_request,
+	.free		= hi3660_mbox_free,
+};
+
+int hi3660_mbox_init(mbox_params_t *params)
+{
+	int result;
+	unsigned int data;
+
+	assert(params != NULL);
+	result = mbox_init(&hi3660_mbox_ops, params);
+	assert(result == 0);
+	memset(&chan_map, 0, sizeof(chan_map));
+
+	/* unlock mailbox */
+	data = mmio_read_32(IPC_LOCK);
+	while (data == MBX_IPC_LOCKED) {
+		mmio_write_32(IPC_LOCK, MBX_IPC_UNLOCK_MAGIC);
+		data = mmio_read_32(IPC_LOCK);
+	}
+	(void)result;
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl1_setup.c b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
new file mode 100644
index 0000000..f9666df
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <dw_ufs.h>
+#include <errno.h>
+#include <gicv2.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <generic_delay_timer.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <string.h>
+#include <tbbr/tbbr_img_desc.h>
+#include <ufs.h>
+
+#include "../../bl1/bl1_private.h"
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+enum {
+	BOOT_MODE_RECOVERY = 0,
+	BOOT_MODE_NORMAL,
+	BOOT_MODE_MASK = 1,
+};
+
+/*
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted RAM
+ */
+extern unsigned long __COHERENT_RAM_START__;
+extern unsigned long __COHERENT_RAM_END__;
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL1_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL1_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+
+/* Data structure which holds the extents of the trusted RAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+const unsigned int g0_interrupt_array[] = {
+	IRQ_SEC_PHY_TIMER,
+	IRQ_SEC_SGI_0
+};
+
+const gicv2_driver_data_t hikey960_gic_data = {
+	.gicd_base = GICD_REG_BASE,
+	.gicc_base = GICC_REG_BASE,
+	.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+	.g0_interrupt_array = g0_interrupt_array,
+};
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*
+ * Perform any BL1 specific platform actions.
+ */
+void bl1_early_platform_setup(void)
+{
+	const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+	/* Initialize the console to provide early debug support */
+	console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL1_RW_BASE;
+	bl1_tzram_layout.total_size = BL1_RW_SIZE;
+
+	/* Calculate how much RAM BL1 is using and how much remains free */
+	bl1_tzram_layout.free_base = BL1_RW_BASE;
+	bl1_tzram_layout.free_size = BL1_RW_SIZE;
+	reserve_mem(&bl1_tzram_layout.free_base,
+		    &bl1_tzram_layout.free_size,
+		    BL1_RAM_BASE,
+		    bl1_size);
+
+	INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
+	     bl1_size);
+}
+
+/*
+ * Perform the very early platform specific architecture setup here. At the
+ * moment this only does basic initialization. Later architectural setup
+ * (bl1_arch_setup()) does not do anything platform specific.
+ */
+void bl1_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el3(bl1_tzram_layout.total_base,
+			      bl1_tzram_layout.total_size,
+			      BL1_RO_BASE,
+			      BL1_RO_LIMIT,
+			      BL1_COHERENT_RAM_BASE,
+			      BL1_COHERENT_RAM_LIMIT);
+}
+
+static void hikey960_clk_init(void)
+{
+	/* change ldi0 sel to ppll2 */
+	mmio_write_32(0xfff350b4, 0xf0002000);
+	/* ldi0 20' */
+	mmio_write_32(0xfff350bc, 0xfc004c00);
+}
+
+static void hikey960_pmu_init(void)
+{
+	/* clear np_xo_abb_dig_START bit in PMIC_CLK_TOP_CTRL7 register */
+	mmio_clrbits_32(PMU_SSI0_CLK_TOP_CTRL7_REG, NP_XO_ABB_DIG);
+}
+
+static void hikey960_enable_ppll3(void)
+{
+	/* enable ppll3 */
+	mmio_write_32(PMC_PPLL3_CTRL0_REG, 0x4904305);
+	mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x2300000);
+	mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x6300000);
+}
+
+static void bus_idle_clear(unsigned int value)
+{
+	unsigned int pmc_value, value1, value2;
+	int timeout = 100;
+
+	pmc_value = value << 16;
+	pmc_value &= ~value;
+	mmio_write_32(PMC_NOC_POWER_IDLEREQ_REG, pmc_value);
+
+	for (;;) {
+		value1 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLEACK_REG);
+		value2 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLE_REG);
+		if (((value1 & value) == 0) && ((value2 & value) == 0))
+			break;
+		udelay(1);
+		timeout--;
+		if (timeout <= 0) {
+			WARN("%s timeout\n", __func__);
+			break;
+		}
+	}
+}
+
+static void set_vivobus_power_up(void)
+{
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00020002);
+	mmio_write_32(CRG_PEREN0_REG, 0x00001000);
+}
+
+static void set_dss_power_up(void)
+{
+	/* set edc0 133MHz = 1600MHz / 12 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0x003f000b);
+	/* set ldi0 ppl0 */
+	mmio_write_32(CRG_CLKDIV3_REG, 0xf0001000);
+	/* set ldi0 133MHz, 1600MHz / 12 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0xfc002c00);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000020);
+	udelay(100);
+	/* DISP CRG */
+	mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000010);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+	mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+	mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x0003b000);
+	mmio_write_32(CRG_PERDIS0_REG, 0x00002000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000040);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000006);
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000c00);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+	mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+	mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_DSS);
+	/* set edc0 400MHz for 2K 1600MHz / 4 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0x003f0003);
+	/* set ldi 266MHz, 1600MHz / 6 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0xfc001400);
+}
+
+static void set_vcodec_power_up(void)
+{
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00040004);
+	mmio_write_32(CRG_PEREN0_REG, 0x00000060);
+	mmio_write_32(CRG_PEREN2_REG, 0x10000000);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS0_REG, 0x00000018);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VCODEC);
+}
+
+static void set_vdec_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000004);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+	mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x00000800);
+	mmio_write_32(CRG_PERDIS2_REG, 0x20080000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000004);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000200);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+	mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VDEC);
+}
+
+static void set_venc_power_up(void)
+{
+	/* set venc ppll3 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x18001000);
+	/* set venc 258MHz, 1290MHz / 5 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x07c00100);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000002);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+	mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x00000400);
+	mmio_write_32(CRG_PERDIS2_REG, 0x40000100);
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000002);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+	mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VENC);
+	/* set venc 645MHz, 1290MHz / 2 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x07c00040);
+}
+
+static void set_isp_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000001);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+	mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+	mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS5_REG, 0x01000010);
+	mmio_write_32(CRG_PERDIS3_REG, 0x0bf00000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70000000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000001);
+	/* unreset */
+	mmio_write_32(CRG_ISP_SEC_RSTDIS_REG, 0x0000002f);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+	mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+	mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_ISP);
+	/* csi clk enable */
+	mmio_write_32(CRG_PEREN3_REG, 0x00700000);
+}
+
+static void set_ivp_power_up(void)
+{
+	/* set ivp ppll0 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0xc0000000);
+	/* set ivp 267MHz, 1600MHz / 6 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0x3c001400);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00200000);
+	udelay(100);
+	/* IVP CRG unreset */
+	mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000001);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+	mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS4_REG, 0x000000a8);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x01000000);
+	/* unreset */
+	mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000002);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+	mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_IVP);
+	/* set ivp 533MHz, 1600MHz / 3 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0x3c000800);
+}
+
+static void set_audio_power_up(void)
+{
+	unsigned int ret;
+	int timeout = 100;
+	/* mtcmos on */
+	mmio_write_32(SCTRL_SCPWREN_REG, 0x00000001);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+	mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+	mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+	mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+	mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(SCTRL_SCPERDIS1_REG, 0x0000000f);
+	mmio_write_32(SCTRL_SCPERDIS0_REG, 0x0c000000);
+	mmio_write_32(CRG_PERDIS5_REG, 0x00000080);
+	mmio_write_32(CRG_PERDIS0_REG, 0x04000000);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010000);
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80100000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(SCTRL_SCISODIS_REG, 0x00000001);
+	udelay(1);
+	/* unreset */
+	mmio_write_32(SCTRL_PERRSTDIS1_SEC_REG, 0x00000001);
+	mmio_write_32(SCTRL_SCPERRSTDIS0_REG, 0x00000780);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+	mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+	mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+	mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+	mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+	/* bus idle clear */
+	mmio_write_32(SCTRL_SCPERCTRL7_REG, 0x00040000);
+	for (;;) {
+		ret = mmio_read_32(SCTRL_SCPERSTAT6_REG);
+		if (((ret & (1 << 5)) == 0) && ((ret & (1 << 8)) == 0))
+			break;
+		udelay(1);
+		timeout--;
+		if (timeout <= 0) {
+			WARN("%s timeout\n", __func__);
+			break;
+		}
+	}
+	mmio_write_32(ASP_CFG_MMBUF_CTRL_REG, 0x00ff0000);
+}
+
+static void set_pcie_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(SCTRL_SCPWREN_REG, 0x00000010);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+	mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+	mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(SCTRL_SCPERDIS2_REG, 0x00104000);
+	mmio_write_32(CRG_PERDIS7_REG, 0x000003a0);
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(SCTRL_SCISODIS_REG, 0x00000030);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x8c000000);
+	/* clk enable */
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+	mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+	mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+}
+
+static void ispfunc_enable(void)
+{
+	/* enable ispfunc. Otherwise powerup isp_srt causes exception. */
+	mmio_write_32(0xfff35000, 0x00000008);
+	mmio_write_32(0xfff35460, 0xc004ffff);
+	mmio_write_32(0xfff35030, 0x02000000);
+	mdelay(10);
+}
+
+static void isps_control_clock(int flag)
+{
+	unsigned int ret;
+
+	/* flag: 0 -- disable clock, 1 -- enable clock */
+	if (flag) {
+		ret = mmio_read_32(0xe8420364);
+		ret |= 1;
+		mmio_write_32(0xe8420364, ret);
+	} else {
+		ret = mmio_read_32(0xe8420364);
+		ret &= ~1;
+		mmio_write_32(0xe8420364, ret);
+	}
+}
+
+static void set_isp_srt_power_up(void)
+{
+	unsigned int ret;
+
+	ispfunc_enable();
+	/* reset */
+	mmio_write_32(0xe8420374, 0x00000001);
+	mmio_write_32(0xe8420350, 0x00000000);
+	mmio_write_32(0xe8420358, 0x00000000);
+	/* mtcmos on */
+	mmio_write_32(0xfff35150, 0x00400000);
+	udelay(100);
+	/* clk enable */
+	isps_control_clock(1);
+	udelay(1);
+	isps_control_clock(0);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(0xfff35148, 0x08000000);
+	/* unreset */
+	ret = mmio_read_32(0xe8420374);
+	ret &= ~0x1;
+	mmio_write_32(0xe8420374, ret);
+	/* clk enable */
+	isps_control_clock(1);
+	/* enable clock gating for accessing csi registers */
+	mmio_write_32(0xe8420010, ~0);
+}
+
+static void hikey960_regulator_enable(void)
+{
+	set_vivobus_power_up();
+	hikey960_enable_ppll3();
+	set_dss_power_up();
+	set_vcodec_power_up();
+	set_vdec_power_up();
+	set_venc_power_up();
+	set_isp_power_up();
+	set_ivp_power_up();
+	set_audio_power_up();
+	set_pcie_power_up();
+	set_isp_srt_power_up();
+}
+
+static void hikey960_ufs_reset(void)
+{
+	unsigned int data, mask;
+
+	mmio_write_32(CRG_PERDIS7_REG, 1 << 14);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+	do {
+		data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	} while (data & BIT_SYSCTRL_REF_CLOCK_EN);
+	/* use abb clk */
+	mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN);
+	mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16));
+	mdelay(1);
+	mmio_write_32(CRG_PEREN7_REG, 1 << 14);
+	mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+
+	mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while ((data & PERI_UFS_BIT) == 0);
+	mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN);
+	mdelay(1);
+	mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET);
+	/* clear SC_DIV_UFS_PERIBUS */
+	mask = SC_DIV_UFS_PERIBUS << 16;
+	mmio_write_32(CRG_CLKDIV17_REG, mask);
+	/* set SC_DIV_UFSPHY_CFG(3) */
+	mask = SC_DIV_UFSPHY_CFG_MASK << 16;
+	data = SC_DIV_UFSPHY_CFG(3);
+	mmio_write_32(CRG_CLKDIV16_REG, mask | data);
+	data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ;
+	data |= 0x39;
+	mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL);
+	mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG,
+			MASK_UFS_CLK_GATE_BYPASS);
+	mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS);
+
+	mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN);
+	mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN);
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT);
+	mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N);
+	mdelay(1);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET);
+	mdelay(20);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      0x03300330);
+
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while (data & PERI_UFS_BIT);
+}
+
+static void hikey960_ufs_init(void)
+{
+	dw_ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params));
+	ufs_params.reg_base = UFS_REG_BASE;
+	ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
+	ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
+
+	if ((ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0)
+		hikey960_ufs_reset();
+	dw_ufs_init(&ufs_params);
+}
+
+static void hikey960_tzc_init(void)
+{
+	mmio_write_32(TZC_EN0_REG, 0x7fbff066);
+	mmio_write_32(TZC_EN1_REG, 0xfffff5fc);
+	mmio_write_32(TZC_EN2_REG, 0x0007005c);
+	mmio_write_32(TZC_EN3_REG, 0x37030700);
+	mmio_write_32(TZC_EN4_REG, 0xf63fefae);
+	mmio_write_32(TZC_EN5_REG, 0x000410fd);
+	mmio_write_32(TZC_EN6_REG, 0x0063ff68);
+	mmio_write_32(TZC_EN7_REG, 0x030000f3);
+	mmio_write_32(TZC_EN8_REG, 0x00000007);
+}
+
+static void hikey960_peri_init(void)
+{
+	/* unreset */
+	mmio_setbits_32(CRG_PERRSTDIS4_REG, 1);
+}
+
+static void hikey960_pinmux_init(void)
+{
+	unsigned int id;
+
+	hikey960_read_boardid(&id);
+	if (id == 5301) {
+		/* hikey960 hardware v2 */
+		/* GPIO150: LED */
+		mmio_write_32(IOMG_FIX_006_REG, 0);
+		/* GPIO151: LED */
+		mmio_write_32(IOMG_FIX_007_REG, 0);
+		/* GPIO189: LED */
+		mmio_write_32(IOMG_AO_011_REG, 0);
+		/* GPIO190: LED */
+		mmio_write_32(IOMG_AO_012_REG, 0);
+		/* GPIO46 */
+		mmio_write_32(IOMG_044_REG, 0);
+		/* GPIO202 */
+		mmio_write_32(IOMG_AO_023_REG, 0);
+		/* GPIO206 */
+		mmio_write_32(IOMG_AO_026_REG, 0);
+		/* GPIO219 - PD pullup */
+		mmio_write_32(IOMG_AO_039_REG, 0);
+		mmio_write_32(IOCG_AO_043_REG, 1 << 0);
+	}
+	/* GPIO005 - PMU SSI, 10mA */
+	mmio_write_32(IOCG_006_REG, 2 << 4);
+}
+
+/*
+ * Function which will perform any remaining platform-specific setup that can
+ * occur after the MMU and data cache have been enabled.
+ */
+void bl1_platform_setup(void)
+{
+	hikey960_clk_init();
+	hikey960_pmu_init();
+	hikey960_regulator_enable();
+	hikey960_tzc_init();
+	hikey960_peri_init();
+	hikey960_ufs_init();
+	hikey960_pinmux_init();
+	hikey960_io_setup();
+}
+
+/*
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or not.
+ */
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	unsigned int mode, ret;
+
+	mode = mmio_read_32(SCTRL_BAK_DATA0_REG);
+	switch (mode & BOOT_MODE_MASK) {
+	case BOOT_MODE_RECOVERY:
+		ret = NS_BL1U_IMAGE_ID;
+		break;
+	case BOOT_MODE_NORMAL:
+		ret = BL2_IMAGE_ID;
+		break;
+	default:
+		WARN("Invalid boot mode is found:%d\n", mode);
+		panic();
+	}
+	return ret;
+}
+
+image_desc_t *bl1_plat_get_image_desc(unsigned int image_id)
+{
+	unsigned int index = 0;
+
+	while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) {
+		if (bl1_tbbr_image_descs[index].image_id == image_id)
+			return &bl1_tbbr_image_descs[index];
+		index++;
+	}
+
+	return NULL;
+}
+
+void bl1_plat_set_ep_info(unsigned int image_id,
+		entry_point_info_t *ep_info)
+{
+	unsigned int data = 0;
+	uintptr_t tmp = HIKEY960_NS_TMP_OFFSET;
+
+	if (image_id == BL2_IMAGE_ID)
+		return;
+	/* Copy NS BL1U from 0x1AC1_8000 to 0x1AC9_8000 */
+	memcpy((void *)tmp, (void *)HIKEY960_NS_IMAGE_OFFSET,
+		NS_BL1U_SIZE);
+	memcpy((void *)NS_BL1U_BASE, (void *)tmp, NS_BL1U_SIZE);
+	inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE);
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	gicv2_driver_init(&hikey960_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+	/* CNTFRQ is read-only in EL1 */
+	write_cntfrq_el0(plat_get_syscnt_freq2());
+	data = read_cpacr_el1();
+	do {
+		data |= 3 << 20;
+		write_cpacr_el1(data);
+		data = read_cpacr_el1();
+	} while ((data & (3 << 20)) != (3 << 20));
+	INFO("cpacr_el1:0x%x\n", data);
+
+	ep_info->args.arg0 = 0xffff & read_mpidr();
+	ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl2_setup.c b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
new file mode 100644
index 0000000..e225793
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <generic_delay_timer.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <string.h>
+#include <ufs.h>
+
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+/*
+ * The next 2 constants identify the extents of the code & RO data region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
+ */
+#define BL2_RO_BASE (unsigned long)(&__RO_START__)
+#define BL2_RO_LIMIT (unsigned long)(&__RO_END__)
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL2_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL2_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+typedef struct bl2_to_bl31_params_mem {
+	bl31_params_t		bl31_params;
+	image_info_t		bl31_image_info;
+	image_info_t		bl32_image_info;
+	image_info_t		bl33_image_info;
+	entry_point_info_t	bl33_ep_info;
+	entry_point_info_t	bl32_ep_info;
+	entry_point_info_t	bl31_ep_info;
+} bl2_to_bl31_params_mem_t;
+
+static bl2_to_bl31_params_mem_t bl31_params_mem;
+
+meminfo_t *bl2_plat_sec_mem_layout(void)
+{
+	return &bl2_tzram_layout;
+}
+
+bl31_params_t *bl2_plat_get_bl31_params(void)
+{
+	bl31_params_t *bl2_to_bl31_params = NULL;
+
+	/*
+	 * Initialise the memory for all the arguments that needs to
+	 * be passed to BL3-1
+	 */
+	memset(&bl31_params_mem, 0, sizeof(bl2_to_bl31_params_mem_t));
+
+	/* Assign memory for TF related information */
+	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
+	SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
+
+	/* Fill BL3-1 related information */
+	bl2_to_bl31_params->bl31_image_info = &bl31_params_mem.bl31_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+
+	/* Fill BL3-2 related information if it exists */
+#if BL32_BASE
+	bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
+		VERSION_1, 0);
+	bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+#endif
+
+	/* Fill BL3-3 related information */
+	bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info,
+		PARAM_EP, VERSION_1, 0);
+
+	/* BL3-3 expects to receive the primary CPU MPID (through x0) */
+	bl2_to_bl31_params->bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
+
+	bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+
+	return bl2_to_bl31_params;
+}
+
+/*******************************************************************************
+ * Populate the extents of memory available for loading SCP_BL2 (if used),
+ * i.e. anywhere in trusted RAM as long as it doesn't overwrite BL2.
+ ******************************************************************************/
+void bl2_plat_get_scp_bl2_meminfo(meminfo_t *scp_bl2_meminfo)
+{
+	ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params_t));
+	ufs_params.reg_base = UFS_REG_BASE;
+	ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
+	ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
+	ufs_params.flags = UFS_FLAGS_SKIPINIT;
+	ufs_init(NULL, &ufs_params);
+
+	hikey960_io_setup();
+
+	*scp_bl2_meminfo = bl2_tzram_layout;
+}
+
+extern int load_lpm3(void);
+
+int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+	int i;
+	int *buf;
+
+	assert(scp_bl2_image_info->image_size < SCP_MEM_SIZE);
+
+	INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
+
+	INFO("BL2: SCP_BL2: 0x%lx@0x%x\n",
+	     scp_bl2_image_info->image_base,
+	     scp_bl2_image_info->image_size);
+
+	buf = (int *)scp_bl2_image_info->image_base;
+
+	INFO("BL2: SCP_BL2 HEAD:\n");
+	for (i = 0; i < 64; i += 4)
+		INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
+			buf[i], buf[i+1], buf[i+2], buf[i+3]);
+
+	buf = (int *)(scp_bl2_image_info->image_base +
+		      scp_bl2_image_info->image_size - 256);
+
+	INFO("BL2: SCP_BL2 TAIL:\n");
+	for (i = 0; i < 64; i += 4)
+		INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
+			buf[i], buf[i+1], buf[i+2], buf[i+3]);
+
+	memcpy((void *)SCP_MEM_BASE,
+	       (void *)scp_bl2_image_info->image_base,
+	       scp_bl2_image_info->image_size);
+
+	INFO("BL2: SCP_BL2 transferred to SCP\n");
+
+	load_lpm3();
+	(void)buf;
+
+	return 0;
+}
+
+struct entry_point_info *bl2_plat_get_bl31_ep_info(void)
+{
+	return &bl31_params_mem.bl31_ep_info;
+}
+
+void bl2_plat_set_bl31_ep_info(image_info_t *image,
+			       entry_point_info_t *bl31_ep_info)
+{
+	SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE);
+	bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+				       DISABLE_ALL_EXCEPTIONS);
+}
+
+void bl2_plat_set_bl33_ep_info(image_info_t *image,
+			       entry_point_info_t *bl33_ep_info)
+{
+	unsigned long el_status;
+	unsigned int mode;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	if (el_status)
+		mode = MODE_EL2;
+	else
+		mode = MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	bl33_ep_info->spsr = SPSR_64(mode, MODE_SP_ELX,
+				       DISABLE_ALL_EXCEPTIONS);
+	SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE);
+}
+
+void bl2_plat_flush_bl31_params(void)
+{
+	flush_dcache_range((unsigned long)&bl31_params_mem,
+			   sizeof(bl2_to_bl31_params_mem_t));
+}
+
+void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo)
+{
+	bl33_meminfo->total_base = DDR_BASE;
+	bl33_meminfo->total_size = DDR_SIZE;
+	bl33_meminfo->free_base = DDR_BASE;
+	bl33_meminfo->free_size = DDR_SIZE;
+}
+
+void bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+
+	/* Initialize the console to provide early debug support */
+	console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+}
+
+void bl2_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el1(bl2_tzram_layout.total_base,
+			      bl2_tzram_layout.total_size,
+			      BL2_RO_BASE,
+			      BL2_RO_LIMIT,
+			      BL2_COHERENT_RAM_BASE,
+			      BL2_COHERENT_RAM_LIMIT);
+}
+
+void bl2_platform_setup(void)
+{
+	/* disable WDT0 */
+	if (mmio_read_32(WDT0_REG_BASE + WDT_LOCK_OFFSET) == WDT_LOCKED) {
+		mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, WDT_UNLOCK);
+		mmio_write_32(WDT0_REG_BASE + WDT_CONTROL_OFFSET, 0);
+		mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, 0);
+	}
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl31_setup.c b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
new file mode 100644
index 0000000..41c591b
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <cci.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <generic_delay_timer.h>
+#include <gicv2.h>
+#include <hi3660.h>
+#include <hisi_ipc.h>
+#include <platform_def.h>
+
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+/*
+ * The next 2 constants identify the extents of the code & RO data region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
+ */
+#define BL31_RO_BASE	(unsigned long)(&__RO_START__)
+#define BL31_RO_LIMIT	(unsigned long)(&__RO_END__)
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL31_COHERENT_RAM_BASE	(unsigned long)(&__COHERENT_RAM_START__)
+#define BL31_COHERENT_RAM_LIMIT	(unsigned long)(&__COHERENT_RAM_END__)
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+const unsigned int g0_interrupt_array[] = {
+	IRQ_SEC_PHY_TIMER,
+	IRQ_SEC_SGI_0
+};
+
+const gicv2_driver_data_t hikey960_gic_data = {
+	.gicd_base = GICD_REG_BASE,
+	.gicc_base = GICC_REG_BASE,
+	.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+	.g0_interrupt_array = g0_interrupt_array,
+};
+
+static const int cci_map[] = {
+	CCI400_SL_IFACE3_CLUSTER_IX,
+	CCI400_SL_IFACE4_CLUSTER_IX
+};
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	return NULL;
+}
+
+void bl31_early_platform_setup(bl31_params_t *from_bl2,
+		void *plat_params_from_bl2)
+{
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+
+	/* Initialize the console to provide early debug support */
+	console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
+
+	/* Initialize CCI driver */
+	cci_init(CCI400_REG_BASE, cci_map, ARRAY_SIZE(cci_map));
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+	/*
+	 * Copy BL3-2 and BL3-3 entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	bl32_ep_info = *from_bl2->bl32_ep_info;
+	bl33_ep_info = *from_bl2->bl33_ep_info;
+}
+
+void bl31_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el3(BL31_BASE,
+			BL31_LIMIT - BL31_BASE,
+			BL31_RO_BASE,
+			BL31_RO_LIMIT,
+			BL31_COHERENT_RAM_BASE,
+			BL31_COHERENT_RAM_LIMIT);
+}
+
+void bl31_platform_setup(void)
+{
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	gicv2_driver_init(&hikey960_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	hisi_ipc_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+}
diff --git a/plat/hisilicon/hikey960/hikey960_boardid.c b/plat/hisilicon/hikey960/hikey960_boardid.c
new file mode 100644
index 0000000..ac3e0385
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_boardid.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <hi3660.h>
+#include <mmio.h>
+
+#include "hikey960_private.h"
+
+#define ADC_ADCIN0				0
+#define ADC_ADCIN1				1
+#define ADC_ADCIN2				2
+
+#define HKADC_DATA_GRADE0			0
+#define HKADC_DATA_GRADE1			100
+#define HKADC_DATA_GRADE2			300
+#define HKADC_DATA_GRADE3			500
+#define HKADC_DATA_GRADE4			700
+#define HKADC_DATA_GRADE5			900
+#define HKADC_DATA_GRADE6			1100
+#define HKADC_DATA_GRADE7			1300
+#define HKADC_DATA_GRADE8			1500
+#define HKADC_DATA_GRADE9			1700
+#define HKADC_DATA_GRADE10			1800
+
+#define BOARDID_VALUE0				0
+#define BOARDID_VALUE1				1
+#define BOARDID_VALUE2				2
+#define BOARDID_VALUE3				3
+#define BOARDID_VALUE4				4
+#define BOARDID_VALUE5				5
+#define BOARDID_VALUE6				6
+#define BOARDID_VALUE7				7
+#define BOARDID_VALUE8				8
+#define BOARDID_VALUE9				9
+#define BOARDID_UNKNOWN				0xF
+
+#define BOARDID3_BASE				5
+
+
+static void init_adc(void)
+{
+	/* reset hkadc */
+	mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
+	/* wait a few clock cycles */
+	udelay(2);
+	mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
+	udelay(2);
+	/* enable hkadc clock */
+	mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
+	udelay(2);
+	mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
+	udelay(2);
+}
+
+static int get_adc(unsigned int channel, unsigned int *value)
+{
+	unsigned int	data, value1, value0;
+
+	if (channel > HKADC_CHANNEL_MAX) {
+		WARN("invalid channel:%d\n", channel);
+		return -EFAULT;
+	}
+	/* configure the read/write operation for external HKADC */
+	mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
+	mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
+	mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
+	/* configure the number of accessing registers */
+	mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
+	/* configure delay of accessing registers */
+	mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
+	mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
+
+	/* start HKADC */
+	mmio_write_32(HKADC_DSP_START_REG, 1);
+	do {
+		data = mmio_read_32(HKADC_DSP_START_REG);
+	} while (data & 1);
+
+	/* convert AD result */
+	value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
+	value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
+
+	data = ((value1 << 4) & HKADC_VALUE_HIGH) |
+	       ((value0 >> 4) & HKADC_VALUE_LOW);
+	*value = data;
+	return 0;
+}
+
+static int get_value(unsigned int channel, unsigned int *value)
+{
+	int ret;
+
+	ret = get_adc(channel, value);
+	if (ret)
+		return ret;
+
+	/* convert ADC value to micro-volt */
+	ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
+	*value = ret;
+	return 0;
+}
+
+static int adcin_data_remap(unsigned int adcin_value)
+{
+	int	ret;
+
+	if (adcin_value < HKADC_DATA_GRADE0)
+		ret = BOARDID_UNKNOWN;
+	else if (adcin_value < HKADC_DATA_GRADE1)
+		ret = BOARDID_VALUE0;
+	else if (adcin_value < HKADC_DATA_GRADE2)
+		ret = BOARDID_VALUE1;
+	else if (adcin_value < HKADC_DATA_GRADE3)
+		ret = BOARDID_VALUE2;
+	else if (adcin_value < HKADC_DATA_GRADE4)
+		ret = BOARDID_VALUE3;
+	else if (adcin_value < HKADC_DATA_GRADE5)
+		ret = BOARDID_VALUE4;
+	else if (adcin_value < HKADC_DATA_GRADE6)
+		ret = BOARDID_VALUE5;
+	else if (adcin_value < HKADC_DATA_GRADE7)
+		ret = BOARDID_VALUE6;
+	else if (adcin_value < HKADC_DATA_GRADE8)
+		ret = BOARDID_VALUE7;
+	else if (adcin_value < HKADC_DATA_GRADE9)
+		ret = BOARDID_VALUE8;
+	else if (adcin_value < HKADC_DATA_GRADE10)
+		ret = BOARDID_VALUE9;
+	else
+		ret = BOARDID_UNKNOWN;
+	return ret;
+}
+
+int hikey960_read_boardid(unsigned int *id)
+{
+	unsigned int	adcin0, adcin1, adcin2;
+	unsigned int	adcin0_remap, adcin1_remap, adcin2_remap;
+
+	assert(id != NULL);
+
+	init_adc();
+
+	/* read ADC channel0 data */
+	get_value(ADC_ADCIN0, &adcin0);
+	adcin0_remap = adcin_data_remap(adcin0);
+	INFO("[BDID]adcin0:%d adcin0_remap:%d\n", adcin0, adcin0_remap);
+	if (adcin0_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	/* read ADC channel1 data */
+	get_value(ADC_ADCIN1, &adcin1);
+	adcin1_remap = adcin_data_remap(adcin1);
+	INFO("[BDID]adcin1:%d adcin1_remap:%d\n", adcin1, adcin1_remap);
+	if (adcin1_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	/* read ADC channel2 data */
+	get_value(ADC_ADCIN2, &adcin2);
+	adcin2_remap = adcin_data_remap(adcin2);
+	INFO("[BDID]adcin2:%d adcin2_remap:%d\n", adcin2, adcin2_remap);
+	if (adcin2_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	*id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
+		(adcin1_remap * 10) + adcin0_remap;
+	INFO("[BDID]boardid: %d\n", *id);
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_def.h b/plat/hisilicon/hikey960/hikey960_def.h
new file mode 100644
index 0000000..e713e2e
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_def.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HIKEY960_DEF_H__
+#define __HIKEY960_DEF_H__
+
+#include <common_def.h>
+#include <tbbr_img_def.h>
+
+#define DDR_BASE			0x0
+#define DDR_SIZE			0xC0000000
+
+#define DEVICE_BASE			0xE0000000
+#define DEVICE_SIZE			0x20000000
+
+/*
+ * PL011 related constants
+ */
+#define PL011_UART5_BASE		0xFDF05000
+#define PL011_UART6_BASE		0xFFF32000
+#define PL011_BAUDRATE			115200
+#define PL011_UART_CLK_IN_HZ		19200000
+
+#define UFS_BASE			0
+/* FIP partition */
+#define HIKEY960_FIP_BASE		(UFS_BASE + 0x1400000)
+#define HIKEY960_FIP_MAX_SIZE		(12 << 20)
+
+#define HIKEY960_UFS_DESC_BASE		0x20000000
+#define HIKEY960_UFS_DESC_SIZE		0x00200000	/* 2MB */
+#define HIKEY960_UFS_DATA_BASE		0x10000000
+#define HIKEY960_UFS_DATA_SIZE		0x0A000000	/* 160MB */
+
+#endif /* __HIKEY960_DEF_H__ */
diff --git a/plat/hisilicon/hikey960/hikey960_io_storage.c b/plat/hisilicon/hikey960/hikey960_io_storage.c
new file mode 100644
index 0000000..de54e88
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_io_storage.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <firmware_image_package.h>
+#include <io_block.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <io_storage.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <semihosting.h>	/* For FOPEN_MODE_... */
+#include <string.h>
+#include <ufs.h>
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+static const io_dev_connector_t *ufs_dev_con, *fip_dev_con;
+static uintptr_t ufs_dev_handle, fip_dev_handle;
+
+static int check_ufs(const uintptr_t spec);
+static int check_fip(const uintptr_t spec);
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size);
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size);
+
+static const io_block_spec_t ufs_fip_spec = {
+	.offset		= HIKEY960_FIP_BASE,
+	.length		= HIKEY960_FIP_MAX_SIZE,
+};
+
+static const io_block_spec_t ufs_data_spec = {
+	.offset		= 0,
+	.length		= 256 << 20,
+};
+
+static const io_block_dev_spec_t ufs_dev_spec = {
+	/* It's used as temp buffer in block driver. */
+	.buffer		= {
+		.offset	= HIKEY960_UFS_DATA_BASE,
+		.length	= HIKEY960_UFS_DATA_SIZE,
+	},
+	.ops		= {
+		.read	= ufs_read_lun3_blks,
+		.write	= ufs_write_lun3_blks,
+	},
+	.block_size	= UFS_BLOCK_SIZE,
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t scp_bl2_uuid_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&ufs_dev_handle,
+		(uintptr_t)&ufs_fip_spec,
+		check_ufs
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		check_fip
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_bl2_uuid_spec,
+		check_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		check_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		check_fip
+	},
+	[BL2U_IMAGE_ID] = {
+		&ufs_dev_handle,
+		(uintptr_t)&ufs_data_spec,
+		check_ufs
+	}
+};
+
+static int check_ufs(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_handle;
+
+	result = io_dev_init(ufs_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(ufs_dev_handle, spec, &local_handle);
+		if (result == 0)
+			io_close(local_handle);
+	}
+	return result;
+}
+
+static int check_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void hikey960_io_setup(void)
+{
+	int result;
+
+	result = register_io_dev_block(&ufs_dev_con);
+	assert(result == 0);
+
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(ufs_dev_con, (uintptr_t)&ufs_dev_spec,
+			     &ufs_dev_handle);
+	assert(result == 0);
+
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
+	assert(result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)result;
+}
+
+/* Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return result;
+}
+
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size)
+{
+	return ufs_read_blocks(3, lba, buf, size);
+}
+
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size)
+{
+	return ufs_write_blocks(3, lba, buf, size);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_mcu_load.c b/plat/hisilicon/hikey960/hikey960_mcu_load.c
new file mode 100644
index 0000000..7bf9a3d
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_mcu_load.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <string.h>
+
+#define ADDR_CONVERT(addr)		((addr) < 0x40000 ?	\
+					 (addr) + 0xFFF30000 :	\
+					 (addr) + 0x40000000)
+
+static void fw_data_init(void)
+{
+	unsigned long data_head_addr;
+	unsigned int *data_addr;
+
+	data_head_addr = mmio_read_32((uintptr_t) HISI_DATA_HEAD_BASE) + 0x14;
+	data_addr = (unsigned int *) ADDR_CONVERT(data_head_addr);
+
+	memcpy((void *)HISI_DATA0_BASE,
+	       (const void *)(unsigned long)ADDR_CONVERT(data_addr[0]),
+	       HISI_DATA0_SIZE);
+	memcpy((void *)HISI_DATA1_BASE,
+	       (const void *)(unsigned long)ADDR_CONVERT(data_addr[1]),
+	       HISI_DATA1_SIZE);
+}
+
+int load_lpm3(void)
+{
+	INFO("start fw loading\n");
+
+	fw_data_init();
+
+	flush_dcache_range((uintptr_t)HISI_RESERVED_MEM_BASE,
+			   HISI_RESERVED_MEM_SIZE);
+
+	sev();
+	sev();
+
+	INFO("fw load success\n");
+
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_pm.c b/plat/hisilicon/hikey960/hikey960_pm.c
new file mode 100644
index 0000000..257299e
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_pm.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cci.h>
+#include <console.h>
+#include <debug.h>
+#include <gicv2.h>
+#include <hi3660.h>
+#include <hi3660_crg.h>
+#include <mmio.h>
+#include <psci.h>
+#include "drivers/pwrc/hisi_pwrc.h"
+
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+#define CORE_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) \
+	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+#define DMAC_GLB_REG_SEC	0x694
+#define AXI_CONF_BASE		0x820
+
+static uintptr_t hikey960_sec_entrypoint;
+
+static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
+{
+	unsigned long scr;
+	unsigned int val = 0;
+
+	assert(cpu_state == PLAT_MAX_RET_STATE);
+
+	scr = read_scr_el3();
+
+	/* Enable Physical IRQ and FIQ to wake the CPU*/
+	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+	set_retention_ticks(val);
+	wfi();
+	clr_retention_ticks(val);
+
+	/*
+	 * Restore SCR to the original value, synchronisazion of
+	 * scr_el3 is done by eret while el3_exit to save some
+	 * execution cycles.
+	 */
+	write_scr_el3(scr);
+}
+
+static int hikey960_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+	int cluster_stat = cluster_is_powered_on(cluster);
+
+	hisi_set_cpu_boot_flag(cluster, core);
+
+	mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
+		      hikey960_sec_entrypoint >> 2);
+
+	if (cluster_stat)
+		hisi_powerup_core(cluster, core);
+	else
+		hisi_powerup_cluster(cluster, core);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void
+hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	clr_ex();
+	isb();
+	dsbsy();
+
+	gicv2_cpuif_disable();
+
+	hisi_clear_cpu_boot_flag(cluster, core);
+	hisi_powerdn_core(cluster, core);
+
+	/* check if any core is powered up */
+	if (hisi_test_pwrdn_allcores(cluster, core)) {
+
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+		isb();
+		dsbsy();
+
+		hisi_powerdn_cluster(cluster, core);
+	}
+}
+
+static void __dead2 hikey960_system_reset(void)
+{
+	mmio_write_32(SCTRL_SCPEREN1_REG,
+		      SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
+	mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
+	panic();
+}
+
+int hikey960_validate_power_state(unsigned int power_state,
+			       psci_power_state_t *req_state)
+{
+	int pstate = psci_get_pstate_type(power_state);
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int i;
+
+	assert(req_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's possible to enter standby only on power level 0
+		 * Ignore any other power level.
+		 */
+		if (pwr_lvl != MPIDR_AFFLVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] =
+					PLAT_MAX_RET_STATE;
+	} else {
+		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					PLAT_MAX_OFF_STATE;
+	}
+
+	/*
+	 * We expect the 'state id' to be zero.
+	 */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
+		return PSCI_E_SUCCESS;
+
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		clr_ex();
+		isb();
+		dsbsy();
+
+		gicv2_cpuif_disable();
+
+		hisi_cpuidle_lock(cluster, core);
+		hisi_set_cpuidle_flag(cluster, core);
+		hisi_cpuidle_unlock(cluster, core);
+
+		mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
+		      hikey960_sec_entrypoint >> 2);
+
+		hisi_enter_core_idle(cluster, core);
+	}
+
+	/* Perform the common cluster specific operations */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		hisi_cpuidle_lock(cluster, core);
+		hisi_disable_pdc(cluster);
+
+		/* check if any core is powered up */
+		if (hisi_test_pwrdn_allcores(cluster, core)) {
+
+			cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+			isb();
+			dsbsy();
+
+			/* mask the pdc wakeup irq, then
+			 * enable pdc to power down the core
+			 */
+			hisi_pdc_mask_cluster_wakeirq(cluster);
+			hisi_enable_pdc(cluster);
+
+			hisi_cpuidle_unlock(cluster, core);
+
+			/* check the SR flag bit to determine
+			 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
+			 */
+			if (hisi_test_ap_suspend_flag(cluster))
+				hisi_enter_ap_suspend(cluster, core);
+			else
+				hisi_enter_cluster_idle(cluster, core);
+		} else {
+			/* enable pdc */
+			hisi_enable_pdc(cluster);
+			hisi_cpuidle_unlock(cluster, core);
+		}
+	}
+}
+
+static void hikey960_sr_dma_reinit(void)
+{
+	unsigned int ctr = 0;
+
+	mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
+
+	/* 1~15 channel is set non_secure */
+	for (ctr = 1; ctr <= 15; ctr++)
+		mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
+			      (1 << 6) | (1 << 18));
+}
+
+static void
+hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	/* Nothing to be done on waking up from retention from CPU level */
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (hisi_test_ap_suspend_flag(cluster)) {
+		hikey960_sr_dma_reinit();
+		gicv2_cpuif_enable();
+		console_init(PL011_UART6_BASE, PL011_UART_CLK_IN_HZ,
+			     PL011_BAUDRATE);
+	}
+
+	hikey960_pwr_domain_on_finish(target_state);
+}
+
+static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	int i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+static const plat_psci_ops_t hikey960_psci_ops = {
+	.cpu_standby			= hikey960_pwr_domain_standby,
+	.pwr_domain_on			= hikey960_pwr_domain_on,
+	.pwr_domain_on_finish		= hikey960_pwr_domain_on_finish,
+	.pwr_domain_off			= hikey960_pwr_domain_off,
+	.pwr_domain_suspend		= hikey960_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= hikey960_pwr_domain_suspend_finish,
+	.system_off			= NULL,
+	.system_reset			= hikey960_system_reset,
+	.validate_power_state		= hikey960_validate_power_state,
+	.validate_ns_entrypoint		= hikey960_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= hikey960_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	hikey960_sec_entrypoint = sec_entrypoint;
+
+	INFO("%s: sec_entrypoint=0x%lx\n", __func__,
+	     (unsigned long)hikey960_sec_entrypoint);
+
+	/*
+	 * Initialize PSCI ops struct
+	 */
+	*psci_ops = &hikey960_psci_ops;
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_private.h b/plat/hisilicon/hikey960/hikey960_private.h
new file mode 100644
index 0000000..8f2a842
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HIKEY960_PRIVATE_H__
+#define __HIKEY960_PRIVATE_H__
+
+#include <bl_common.h>
+
+/*
+ * Function and variable prototypes
+ */
+void hikey960_init_mmu_el1(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+void hikey960_init_mmu_el3(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+void hikey960_io_setup(void);
+int hikey960_read_boardid(unsigned int *id);
+void set_retention_ticks(unsigned int val);
+void clr_retention_ticks(unsigned int val);
+void clr_ex(void);
+void nop(void);
+
+#endif /* __HIKEY960_PRIVATE_H__ */
diff --git a/plat/hisilicon/hikey960/hikey960_topology.c b/plat/hisilicon/hikey960/hikey960_topology.c
new file mode 100644
index 0000000..3363724
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_topology.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <platform_def.h>
+#include <psci.h>
+
+/*
+ * The HiKey power domain tree descriptor. The cluster power domains
+ * are arranged so that when the PSCI generic code creates the power
+ * domain tree, the indices of the CPU power domain nodes it allocates
+ * match the linear indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char hikey960_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	1,
+	/* Number of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the second cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+/*******************************************************************************
+ * This function returns the HiKey topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return hikey960_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
diff --git a/plat/hisilicon/hikey960/include/hi3660.h b/plat/hisilicon/hikey960/include/hi3660.h
new file mode 100644
index 0000000..83d1b36
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_H__
+#define __HI3660_H__
+
+#include <hi3660_crg.h>
+#include <hi3660_hkadc.h>
+#include <hi3660_mem_map.h>
+
+#define ASP_CFG_REG_BASE		0xE804E000
+
+#define ASP_CFG_MMBUF_CTRL_REG		(ASP_CFG_REG_BASE + 0x148)
+
+#define LP_RAM_BASE			0xFFF50000
+
+#define SCTRL_REG_BASE			0xFFF0A000
+
+#define SCTRL_CONTROL_REG		(SCTRL_REG_BASE + 0x000)
+#define SCTRL_CONTROL_SYS_MODE(x)	(((x) & 0xf) << 3)
+#define SCTRL_CONTROL_SYS_MODE_NORMAL	((1 << 2) << 3)
+#define SCTRL_CONTROL_SYS_MODE_SLOW	((1 << 1) << 3)
+#define SCTRL_CONTROL_SYS_MODE_MASK	(0xf << 3)
+#define SCTRL_CONTROL_MODE_CTRL_NORMAL	(1 << 2)
+#define SCTRL_CONTROL_MODE_CTRL_SLOW	(1 << 1)
+#define SCTRL_CONTROL_MODE_CTRL_MASK	0x7
+
+#define SCTRL_SCSYSSTAT_REG		(SCTRL_REG_BASE + 0x004)
+
+#define SCTRL_DEEPSLEEPED_REG		(SCTRL_REG_BASE + 0x008)
+#define SCTRL_EFUSE_USB_MASK		(1 << 30)
+#define SCTRL_EFUSE_USB_PLL		(1 << 30)
+#define SCTRL_EFUSE_USB_ABB		(0 << 30)
+#define SCTRL_EFUSE_UFS_MASK		(3 << 6)
+#define SCTRL_EFUSE_UFS_PLL		(1 << 6)
+#define SCTRL_EFUSE_UFS_ABB		(0 << 6)
+
+#define SCTRL_SCISOEN_REG		(SCTRL_REG_BASE + 0x040)
+#define SCTRL_SCISODIS_REG		(SCTRL_REG_BASE + 0x044)
+#define SCISO_MMBUFISO			(1 << 3)
+
+#define SCTRL_SCPWREN_REG		(SCTRL_REG_BASE + 0x060)
+#define SCPWREN_MMBUFPWREN		(1 << 3)
+
+#define SCTRL_PLL_CTRL0_REG		(SCTRL_REG_BASE + 0x100)
+#define SCTRL_PLL0_POSTDIV2(x)		(((x) & 0x7) << 23)
+#define SCTRL_PLL0_POSTDIV1(x)		(((x) & 0x7) << 20)
+#define SCTRL_PLL0_FBDIV(x)		(((x) & 0xfff) << 8)
+#define SCTRL_PLL0_REFDIV(x)		(((x) & 0x3f) << 2)
+#define SCTRL_PLL0_EN			(1 << 0)
+
+#define SCTRL_PLL_CTRL1_REG		(SCTRL_REG_BASE + 0x104)
+#define SCTRL_PLL0_CLK_NO_GATE		(1 << 26)
+#define SCTRL_PLL0_CFG_VLD		(1 << 25)
+#define SCTRL_PLL0_FRACDIV(x)		((x) & 0xFFFFFF)
+
+#define SCTRL_PLL_STAT_REG		(SCTRL_REG_BASE + 0x10C)
+#define SCTRL_PLL0_STAT			(1 << 0)
+
+#define SCTRL_SCPEREN0_REG		(SCTRL_REG_BASE + 0x160)
+#define SCTRL_SCPERDIS0_REG		(SCTRL_REG_BASE + 0x164)
+#define SCTRL_SCPERSTAT0_REG		(SCTRL_REG_BASE + 0x168)
+
+#define SCTRL_SCPEREN1_REG		(SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG		(SCTRL_REG_BASE + 0x174)
+#define SCTRL_SCPEREN1_REG		(SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG		(SCTRL_REG_BASE + 0x174)
+#define SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS	(1 << 31)
+#define SCPEREN_GT_PCLK_MMBUFCFG	(1 << 25)
+#define SCPEREN_GT_PCLK_MMBUF		(1 << 23)
+#define SCPEREN_GT_ACLK_MMBUF		(1 << 22)
+#define SCPEREN_GT_CLK_NOC_AOBUS2MMBUF	(1 << 6)
+
+#define SCTRL_SCPEREN2_REG		(SCTRL_REG_BASE + 0x190)
+#define SCTRL_SCPERDIS2_REG		(SCTRL_REG_BASE + 0x194)
+#define SCTRL_SCPERSTAT2_REG		(SCTRL_REG_BASE + 0x198)
+#define SCTRL_SCPERRSTEN0_REG		(SCTRL_REG_BASE + 0x200)
+#define SCTRL_SCPERRSTDIS0_REG		(SCTRL_REG_BASE + 0x204)
+#define SCTRL_SCPERRSTSTAT0_REG		(SCTRL_REG_BASE + 0x208)
+#define SCTRL_SCPERRSTEN1_REG		(SCTRL_REG_BASE + 0x20C)
+#define SCTRL_SCPERRSTDIS1_REG		(SCTRL_REG_BASE + 0x210)
+#define SCTRL_SCPERRSTSTAT1_REG		(SCTRL_REG_BASE + 0x214)
+#define IP_RST_MMBUFCFG			(1 << 12)
+#define IP_RST_MMBUF			(1 << 11)
+
+#define SCTRL_SCPERRSTEN2_REG		(SCTRL_REG_BASE + 0x218)
+#define SCTRL_SCPERRSTDIS2_REG		(SCTRL_REG_BASE + 0x21C)
+#define SCTRL_SCPERRSTSTAT2_REG		(SCTRL_REG_BASE + 0x220)
+
+#define SCTRL_SCCLKDIV2_REG		(SCTRL_REG_BASE + 0x258)
+#define SEL_CLK_MMBUF_MASK		(0x3 << 8)
+#define SEL_CLK_MMBUF_PLL0		(0x3 << 8)
+#define SCCLKDIV2_GT_PCLK_MMBUF		(1 << 7)
+
+#define SCTRL_SCCLKDIV4_REG		(SCTRL_REG_BASE + 0x260)
+#define GT_MMBUF_SYS			(1 << 13)
+#define GT_MMBUF_FLL			(1 << 12)
+#define GT_PLL_CLK_MMBUF		(1 << 11)
+
+#define SCTRL_SCCLKDIV6_REG		(SCTRL_REG_BASE + 0x268)
+
+#define SCTRL_SCPERCTRL7_REG		(SCTRL_REG_BASE + 0x31C)
+#define SCTRL_SCPERSTAT6_REG		(SCTRL_REG_BASE + 0x378)
+
+#define SCTRL_SCINNERSTAT_REG		(SCTRL_REG_BASE + 0x3A0)
+#define EMMC_UFS_SEL			(1 << 15)
+
+#define SCTRL_BAK_DATA0_REG		(SCTRL_REG_BASE + 0x40C)
+#define SCTRL_BAK_DATA4_REG		(SCTRL_REG_BASE + 0x41C)
+
+#define SCTRL_LPMCU_CLKEN_REG		(SCTRL_REG_BASE + 0x480)
+#define SCTRL_LPMCU_CLKDIS_REG		(SCTRL_REG_BASE + 0x484)
+#define SCTRL_LPMCU_RSTEN_REG		(SCTRL_REG_BASE + 0x500)
+#define SCTRL_LPMCU_RSTDIS_REG		(SCTRL_REG_BASE + 0x504)
+#define DDRC_SOFT_BIT			(1 << 6)
+#define DDRC_CLK_BIT			(1 << 5)
+
+#define SCTRL_SCPEREN0_SEC_REG		(SCTRL_REG_BASE + 0x900)
+#define SCTRL_SCPERDIS0_SEC_REG		(SCTRL_REG_BASE + 0x904)
+#define MMBUF_SEC_CTRL_MASK		(0xfff << 20)
+#define MMBUF_SEC_CTRL(x)		(((x) & 0xfff) << 20)
+
+#define SCTRL_PERRSTEN1_SEC_REG		(SCTRL_REG_BASE + 0xA50)
+#define SCTRL_PERRSTDIS1_SEC_REG	(SCTRL_REG_BASE + 0xA54)
+#define SCTRL_PERRSTSTAT1_SEC_REG	(SCTRL_REG_BASE + 0xA58)
+#define RST_ASP_SUBSYS_BIT		(1 << 0)
+
+#define SCTRL_PERRSTEN2_SEC_REG		(SCTRL_REG_BASE + 0xB50)
+#define SCTRL_PERRSTDIS2_SEC_REG	(SCTRL_REG_BASE + 0xB54)
+#define SCTRL_PERRSTSTAT2_SEC_REG	(SCTRL_REG_BASE + 0xB58)
+
+#define SCTRL_HISEECLKDIV_REG		(SCTRL_REG_BASE + 0xC28)
+#define SC_SEL_HISEE_PLL_MASK		(1 << 4)
+#define SC_SEL_HISEE_PLL0		(1 << 4)
+#define SC_SEL_HISEE_PLL2		(0 << 4)
+#define SC_DIV_HISEE_PLL_MASK		(7 << 16)
+#define SC_DIV_HISEE_PLL(x)		((x) & 0x7)
+
+#define SCTRL_SCSOCID0_REG		(SCTRL_REG_BASE + 0xE00)
+
+#define PMC_REG_BASE			0xFFF31000
+#define PMC_PPLL1_CTRL0_REG		(PMC_REG_BASE + 0x038)
+#define PMC_PPLL1_CTRL1_REG		(PMC_REG_BASE + 0x03C)
+#define PMC_PPLL2_CTRL0_REG		(PMC_REG_BASE + 0x040)
+#define PMC_PPLL2_CTRL1_REG		(PMC_REG_BASE + 0x044)
+#define PMC_PPLL3_CTRL0_REG		(PMC_REG_BASE + 0x048)
+#define PMC_PPLL3_CTRL1_REG		(PMC_REG_BASE + 0x04C)
+#define PPLLx_LOCK			(1 << 26)
+#define PPLLx_WITHOUT_CLK_GATE		(1 << 26)
+#define PPLLx_CFG_VLD			(1 << 25)
+#define PPLLx_INT_MOD			(1 << 24)
+#define PPLLx_POSTDIV2_MASK		(0x7 << 23)
+#define PPLLx_POSTDIV2(x)		(((x) & 0x7) << 23)
+#define PPLLx_POSTDIV1_MASK		(0x7 << 20)
+#define PPLLx_POSTDIV1(x)		(((x) & 0x7) << 20)
+#define PPLLx_FRACDIV_MASK		(0x00FFFFFF)
+#define PPLLx_FRACDIV(x)		((x) & 0x00FFFFFF)
+#define PPLLx_FBDIV_MASK		(0xfff << 8)
+#define PPLLx_FBDIV(x)			(((x) & 0xfff) << 8)
+#define PPLLx_REFDIV_MASK		(0x3f << 2)
+#define PPLLx_REFDIV(x)			(((x) & 0x3f) << 2)
+#define PPLLx_BP			(1 << 1)
+#define PPLLx_EN			(1 << 0)
+
+#define PMC_DDRLP_CTRL_REG		(PMC_REG_BASE + 0x30C)
+#define DDRC_CSYSREQ_CFG(x)		((x) & 0xF)
+
+#define PMC_NOC_POWER_IDLEREQ_REG	(PMC_REG_BASE + 0x380)
+#define PMC_NOC_POWER_IDLEREQ_IVP	(1 << 14)
+#define PMC_NOC_POWER_IDLEREQ_DSS	(1 << 13)
+#define PMC_NOC_POWER_IDLEREQ_VENC	(1 << 11)
+#define PMC_NOC_POWER_IDLEREQ_VDEC	(1 << 10)
+#define PMC_NOC_POWER_IDLEREQ_ISP	(1 << 5)
+#define PMC_NOC_POWER_IDLEREQ_VCODEC	(1 << 4)
+#define DDRPHY_BYPASS_MODE		(1 << 0)
+
+#define PMC_NOC_POWER_IDLEACK_REG	(PMC_REG_BASE + 0x384)
+#define PMC_NOC_POWER_IDLE_REG		(PMC_REG_BASE + 0x388)
+
+#define PMU_SSI0_REG_BASE		0xFFF34000
+
+#define PMU_SSI0_LDO8_CTRL0_REG		(PMU_SSI0_REG_BASE + (0x68 << 2))
+#define LDO8_CTRL0_EN_1_8V		0x02
+
+#define PMU_SSI0_CLK_TOP_CTRL7_REG	(PMU_SSI0_REG_BASE + (0x10C << 2))
+#define NP_XO_ABB_DIG			(1 << 1)
+
+#define LP_CONFIG_REG_BASE		0xFFF3F000
+
+#define DMAC_BASE			0xFDF30000
+
+#define CCI400_REG_BASE			0xE8100000
+#define CCI400_SL_IFACE3_CLUSTER_IX	0
+#define CCI400_SL_IFACE4_CLUSTER_IX	1
+
+#define GICD_REG_BASE			0xE82B1000
+#define GICC_REG_BASE			0xE82B2000
+/*
+ * GIC400 interrupt handling related constants
+ */
+#define IRQ_SEC_PHY_TIMER		29
+#define IRQ_SEC_SGI_0			8
+#define IRQ_SEC_SGI_1			9
+#define IRQ_SEC_SGI_2			10
+#define IRQ_SEC_SGI_3			11
+#define IRQ_SEC_SGI_4			12
+#define IRQ_SEC_SGI_5			13
+#define IRQ_SEC_SGI_6			14
+#define IRQ_SEC_SGI_7			15
+#define IRQ_SEC_SGI_8			16
+
+#define IPC_REG_BASE			0xE896A000
+#define IPC_BASE			(IPC_REG_BASE)
+
+#define IOMG_REG_BASE			0xE896C000
+
+/* GPIO46: HUB 3.3V enable. active low */
+#define IOMG_044_REG			(IOMG_REG_BASE + 0x0B0)
+#define IOMG_UART5_RX_REG		(IOMG_REG_BASE + 0x0BC)
+#define IOMG_UART5_TX_REG		(IOMG_REG_BASE + 0x0C0)
+
+#define IOCG_REG_BASE			0xE896C800
+
+/* GPIO005: PMIC SSI. (2 << 4) */
+#define IOCG_006_REG			(IOCG_REG_BASE + 0x018)
+
+#define TIMER9_REG_BASE			0xE8A00000
+
+#define WDT0_REG_BASE			0xE8A06000
+#define WDT1_REG_BASE			0xE8A07000
+#define WDT_CONTROL_OFFSET		0x008
+#define WDT_LOCK_OFFSET			0xC00
+
+#define WDT_UNLOCK			0x1ACCE551
+#define WDT_LOCKED			1
+
+#define PCTRL_REG_BASE			0xE8A09000
+#define PCTRL_PERI_CTRL3_REG		(PCTRL_REG_BASE + 0x010)
+#define PCTRL_PERI_CTRL24_REG		(PCTRL_REG_BASE + 0x064)
+
+#define TZC_REG_BASE			0xE8A21000
+#define TZC_STAT0_REG			(TZC_REG_BASE + 0x800)
+#define TZC_EN0_REG			(TZC_REG_BASE + 0x804)
+#define TZC_DIS0_REG			(TZC_REG_BASE + 0x808)
+#define TZC_STAT1_REG			(TZC_REG_BASE + 0x80C)
+#define TZC_EN1_REG			(TZC_REG_BASE + 0x810)
+#define TZC_DIS1_REG			(TZC_REG_BASE + 0x814)
+#define TZC_STAT2_REG			(TZC_REG_BASE + 0x818)
+#define TZC_EN2_REG			(TZC_REG_BASE + 0x81C)
+#define TZC_DIS2_REG			(TZC_REG_BASE + 0x820)
+#define TZC_STAT3_REG			(TZC_REG_BASE + 0x824)
+#define TZC_EN3_REG			(TZC_REG_BASE + 0x828)
+#define TZC_DIS3_REG			(TZC_REG_BASE + 0x82C)
+#define TZC_STAT4_REG			(TZC_REG_BASE + 0x830)
+#define TZC_EN4_REG			(TZC_REG_BASE + 0x834)
+#define TZC_DIS4_REG			(TZC_REG_BASE + 0x838)
+#define TZC_STAT5_REG			(TZC_REG_BASE + 0x83C)
+#define TZC_EN5_REG			(TZC_REG_BASE + 0x840)
+#define TZC_DIS5_REG			(TZC_REG_BASE + 0x844)
+#define TZC_STAT6_REG			(TZC_REG_BASE + 0x848)
+#define TZC_EN6_REG			(TZC_REG_BASE + 0x84C)
+#define TZC_DIS6_REG			(TZC_REG_BASE + 0x850)
+#define TZC_STAT7_REG			(TZC_REG_BASE + 0x854)
+#define TZC_EN7_REG			(TZC_REG_BASE + 0x858)
+#define TZC_DIS7_REG			(TZC_REG_BASE + 0x85C)
+#define TZC_STAT8_REG			(TZC_REG_BASE + 0x860)
+#define TZC_EN8_REG			(TZC_REG_BASE + 0x864)
+#define TZC_DIS8_REG			(TZC_REG_BASE + 0x868)
+
+#define MMBUF_BASE			0xEA800000
+
+#define ACPU_DMCPACK0_BASE		0xEA900000
+
+#define ACPU_DMCPACK1_BASE		0xEA920000
+
+#define ACPU_DMCPACK2_BASE		0xEA940000
+
+#define ACPU_DMCPACK3_BASE		0xEA960000
+
+#define UART5_REG_BASE			0xFDF05000
+
+#define USB3OTG_REG_BASE		0xFF100000
+
+#define UFS_REG_BASE			0xFF3B0000
+
+#define UFS_SYS_REG_BASE		0xFF3B1000
+
+#define UFS_SYS_PSW_POWER_CTRL_REG	(UFS_SYS_REG_BASE + 0x004)
+#define UFS_SYS_PHY_ISO_EN_REG		(UFS_SYS_REG_BASE + 0x008)
+#define UFS_SYS_HC_LP_CTRL_REG		(UFS_SYS_REG_BASE + 0x00C)
+#define UFS_SYS_PHY_CLK_CTRL_REG	(UFS_SYS_REG_BASE + 0x010)
+#define UFS_SYS_PSW_CLK_CTRL_REG	(UFS_SYS_REG_BASE + 0x014)
+#define UFS_SYS_CLOCK_GATE_BYPASS_REG	(UFS_SYS_REG_BASE + 0x018)
+#define UFS_SYS_RESET_CTRL_EN_REG	(UFS_SYS_REG_BASE + 0x01C)
+#define UFS_SYS_MONITOR_HH_REG		(UFS_SYS_REG_BASE + 0x03C)
+#define UFS_SYS_UFS_SYSCTRL_REG		(UFS_SYS_REG_BASE + 0x05C)
+#define UFS_SYS_UFS_DEVICE_RESET_CTRL_REG	(UFS_SYS_REG_BASE + 0x060)
+#define UFS_SYS_UFS_APB_ADDR_MASK_REG	(UFS_SYS_REG_BASE + 0x064)
+
+#define BIT_UFS_PSW_ISO_CTRL			(1 << 16)
+#define BIT_UFS_PSW_MTCMOS_EN			(1 << 0)
+#define BIT_UFS_REFCLK_ISO_EN			(1 << 16)
+#define BIT_UFS_PHY_ISO_CTRL			(1 << 0)
+#define BIT_SYSCTRL_LP_ISOL_EN			(1 << 16)
+#define BIT_SYSCTRL_PWR_READY			(1 << 8)
+#define BIT_SYSCTRL_REF_CLOCK_EN		(1 << 24)
+#define MASK_SYSCTRL_REF_CLOCK_SEL		(3 << 8)
+#define MASK_SYSCTRL_CFG_CLOCK_FREQ		(0xFF)
+#define BIT_SYSCTRL_PSW_CLK_EN			(1 << 4)
+#define MASK_UFS_CLK_GATE_BYPASS		(0x3F)
+#define BIT_SYSCTRL_LP_RESET_N			(1 << 0)
+#define BIT_UFS_REFCLK_SRC_SE1			(1 << 0)
+#define MASK_UFS_SYSCTRL_BYPASS			(0x3F << 16)
+#define MASK_UFS_DEVICE_RESET			(1 << 16)
+#define BIT_UFS_DEVICE_RESET			(1 << 0)
+
+#define IOMG_FIX_REG_BASE		0xFF3B6000
+
+/* GPIO150: LED */
+#define IOMG_FIX_006_REG		(IOMG_FIX_REG_BASE + 0x018)
+/* GPIO151: LED */
+#define IOMG_FIX_007_REG		(IOMG_FIX_REG_BASE + 0x01C)
+
+#define IOMG_AO_REG_BASE		0xFFF11000
+
+/* GPIO189: LED */
+#define IOMG_AO_011_REG			(IOMG_AO_REG_BASE + 0x02C)
+/* GPIO190: LED */
+#define IOMG_AO_012_REG			(IOMG_AO_REG_BASE + 0x030)
+/* GPIO202: type C enable. active low */
+#define IOMG_AO_023_REG			(IOMG_AO_REG_BASE + 0x05C)
+/* GPIO206: USB switch. active low */
+#define IOMG_AO_026_REG			(IOMG_AO_REG_BASE + 0x068)
+/* GPIO219: PD interrupt. pull up */
+#define IOMG_AO_039_REG			(IOMG_AO_REG_BASE + 0x09C)
+
+#define IOCG_AO_REG_BASE		0xFFF1187C
+/* GPIO219: PD interrupt. pull up */
+#define IOCG_AO_043_REG			(IOCG_AO_REG_BASE + 0x030)
+
+#endif  /* __HI3660_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_crg.h b/plat/hisilicon/hikey960/include/hi3660_crg.h
new file mode 100644
index 0000000..db1df9e
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_crg.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_CRG_H__
+#define __HI3660_CRG_H__
+
+#define CRG_REG_BASE			0xFFF35000
+
+#define CRG_PEREN0_REG			(CRG_REG_BASE + 0x000)
+#define CRG_PERDIS0_REG			(CRG_REG_BASE + 0x004)
+#define CRG_PERSTAT0_REG		(CRG_REG_BASE + 0x008)
+#define PEREN0_GT_CLK_AOMM		(1 << 31)
+
+#define CRG_PEREN1_REG			(CRG_REG_BASE + 0x010)
+#define CRG_PERDIS1_REG			(CRG_REG_BASE + 0x014)
+#define CRG_PERSTAT1_REG		(CRG_REG_BASE + 0x018)
+#define CRG_PEREN2_REG			(CRG_REG_BASE + 0x020)
+#define CRG_PERDIS2_REG			(CRG_REG_BASE + 0x024)
+#define CRG_PERSTAT2_REG		(CRG_REG_BASE + 0x028)
+#define PEREN2_HKADCSSI			(1 << 24)
+
+#define CRG_PEREN3_REG			(CRG_REG_BASE + 0x030)
+#define CRG_PERDIS3_REG			(CRG_REG_BASE + 0x034)
+
+#define CRG_PEREN4_REG			(CRG_REG_BASE + 0x040)
+#define CRG_PERDIS4_REG			(CRG_REG_BASE + 0x044)
+#define CRG_PERCLKEN4_REG		(CRG_REG_BASE + 0x048)
+#define CRG_PERSTAT4_REG		(CRG_REG_BASE + 0x04C)
+#define GT_ACLK_USB3OTG			(1 << 1)
+#define GT_CLK_USB3OTG_REF		(1 << 0)
+
+#define CRG_PEREN5_REG			(CRG_REG_BASE + 0x050)
+#define CRG_PERDIS5_REG			(CRG_REG_BASE + 0x054)
+#define CRG_PERSTAT5_REG		(CRG_REG_BASE + 0x058)
+#define CRG_PERRSTEN0_REG		(CRG_REG_BASE + 0x060)
+#define CRG_PERRSTDIS0_REG		(CRG_REG_BASE + 0x064)
+#define CRG_PERRSTSTAT0_REG		(CRG_REG_BASE + 0x068)
+#define CRG_PERRSTEN1_REG		(CRG_REG_BASE + 0x06C)
+#define CRG_PERRSTDIS1_REG		(CRG_REG_BASE + 0x070)
+#define CRG_PERRSTSTAT1_REG		(CRG_REG_BASE + 0x074)
+#define CRG_PERRSTEN2_REG		(CRG_REG_BASE + 0x078)
+#define CRG_PERRSTDIS2_REG		(CRG_REG_BASE + 0x07C)
+#define CRG_PERRSTSTAT2_REG		(CRG_REG_BASE + 0x080)
+#define PERRSTEN2_HKADCSSI		(1 << 24)
+
+#define CRG_PERRSTEN3_REG		(CRG_REG_BASE + 0x084)
+#define CRG_PERRSTDIS3_REG		(CRG_REG_BASE + 0x088)
+#define CRG_PERRSTSTAT3_REG		(CRG_REG_BASE + 0x08C)
+#define CRG_PERRSTEN4_REG		(CRG_REG_BASE + 0x090)
+#define CRG_PERRSTDIS4_REG		(CRG_REG_BASE + 0x094)
+#define CRG_PERRSTSTAT4_REG		(CRG_REG_BASE + 0x098)
+#define IP_RST_USB3OTG_MUX		(1 << 8)
+#define IP_RST_USB3OTG_AHBIF		(1 << 7)
+#define IP_RST_USB3OTG_32K		(1 << 6)
+#define IP_RST_USB3OTG			(1 << 5)
+#define IP_RST_USB3OTGPHY_POR		(1 << 3)
+
+#define CRG_PERRSTEN5_REG		(CRG_REG_BASE + 0x09C)
+#define CRG_PERRSTDIS5_REG		(CRG_REG_BASE + 0x0A0)
+#define CRG_PERRSTSTAT5_REG		(CRG_REG_BASE + 0x0A4)
+
+/* bit fields in CRG_PERI */
+#define PERI_PCLK_PCTRL_BIT		(1 << 31)
+#define PERI_TIMER12_BIT		(1 << 25)
+#define PERI_TIMER11_BIT		(1 << 24)
+#define PERI_TIMER10_BIT		(1 << 23)
+#define PERI_TIMER9_BIT			(1 << 22)
+#define PERI_UART5_BIT			(1 << 15)
+#define PERI_UFS_BIT			(1 << 12)
+#define PERI_ARST_UFS_BIT		(1 << 7)
+#define PERI_PPLL2_EN_CPU		(1 << 3)
+#define PERI_PWM_BIT			(1 << 0)
+#define PERI_DDRC_BIT			(1 << 0)
+#define PERI_DDRC_D_BIT			(1 << 4)
+#define PERI_DDRC_C_BIT			(1 << 3)
+#define PERI_DDRC_B_BIT			(1 << 2)
+#define PERI_DDRC_A_BIT			(1 << 1)
+#define PERI_DDRC_DMUX_BIT		(1 << 0)
+
+#define CRG_CLKDIV0_REG			(CRG_REG_BASE + 0x0A0)
+#define SC_DIV_LPMCU_MASK		((0x1F << 5) << 16)
+#define SC_DIV_LPMCU(x)			(((x) & 0x1F) << 5)
+
+#define CRG_CLKDIV1_REG			(CRG_REG_BASE + 0x0B0)
+#define SEL_LPMCU_PLL_MASK		((1 << 1) << 16)
+#define SEL_SYSBUS_MASK			((1 << 0) << 16)
+#define SEL_LPMCU_PLL1			(1 << 1)
+#define SEL_LPMCU_PLL0			(0 << 1)
+#define SEL_SYSBUS_PLL0			(1 << 0)
+#define SEL_SYSBUS_PLL1			(0 << 0)
+
+#define CRG_CLKDIV3_REG			(CRG_REG_BASE + 0x0B4)
+#define CRG_CLKDIV5_REG			(CRG_REG_BASE + 0x0BC)
+#define CRG_CLKDIV8_REG			(CRG_REG_BASE + 0x0C8)
+
+#define CRG_CLKDIV12_REG		(CRG_REG_BASE + 0x0D8)
+#define SC_DIV_A53HPM_MASK		(0x7 << 13)
+#define SC_DIV_A53HPM(x)		(((x) & 0x7) << 13)
+
+#define CRG_CLKDIV16_REG		(CRG_REG_BASE + 0x0E8)
+#define DDRC_CLK_SW_REQ_CFG_MASK	(0x3 << 12)
+#define DDRC_CLK_SW_REQ_CFG(x)		(((x) & 0x3) << 12)
+#define SC_DIV_UFSPHY_CFG_MASK		(0x3 << 9)
+#define SC_DIV_UFSPHY_CFG(x)		(((x) & 0x3) << 9)
+#define DDRCPLL_SW			(1 << 8)
+
+#define CRG_CLKDIV17_REG		(CRG_REG_BASE + 0x0EC)
+#define SC_DIV_UFS_PERIBUS		(1 << 14)
+
+#define CRG_CLKDIV18_REG		(CRG_REG_BASE + 0x0F0)
+#define CRG_CLKDIV19_REG		(CRG_REG_BASE + 0x0F4)
+#define CRG_CLKDIV20_REG		(CRG_REG_BASE + 0x0F8)
+#define CLKDIV20_GT_CLK_AOMM		(1 << 3)
+
+#define CRG_CLKDIV22_REG		(CRG_REG_BASE + 0x100)
+#define SEL_PLL_320M_MASK		(1 << 16)
+#define SEL_PLL2_320M			(1 << 0)
+#define SEL_PLL0_320M			(0 << 0)
+
+#define CRG_CLKDIV23_REG		(CRG_REG_BASE + 0x104)
+#define PERI_DDRC_SW_BIT		(1 << 13)
+#define DIV_CLK_DDRSYS_MASK		(0x3 << 10)
+#define DIV_CLK_DDRSYS(x)		(((x) & 0x3) << 10)
+#define GET_DIV_CLK_DDRSYS(x)		(((x) & DIV_CLK_DDRSYS_MASK) >> 10)
+#define DIV_CLK_DDRCFG_MASK		(0x6 << 5)
+#define DIV_CLK_DDRCFG(x)		(((x) & 0x6) << 5)
+#define GET_DIV_CLK_DDRCFG(x)		(((x) & DIV_CLK_DDRCFG_MASK) >> 5)
+#define DIV_CLK_DDRC_MASK		0x1F
+#define DIV_CLK_DDRC(x)			((x) & DIV_CLK_DDRC_MASK)
+#define GET_DIV_CLK_DDRC(x)		((x) & DIV_CLK_DDRC_MASK)
+
+#define CRG_CLKDIV25_REG		(CRG_REG_BASE + 0x10C)
+#define DIV_SYSBUS_PLL_MASK		(0xF << 16)
+#define DIV_SYSBUS_PLL(x)		((x) & 0xF)
+
+#define CRG_PERI_CTRL2_REG		(CRG_REG_BASE + 0x128)
+#define PERI_TIME_STAMP_CLK_MASK	(0x7 << 28)
+#define PERI_TIME_STAMP_CLK_DIV(x)	(((x) & 0x7) << 22)
+
+#define CRG_ISODIS_REG			(CRG_REG_BASE + 0x148)
+#define CRG_PERPWREN_REG		(CRG_REG_BASE + 0x150)
+
+#define CRG_PEREN7_REG			(CRG_REG_BASE + 0x420)
+#define CRG_PERDIS7_REG			(CRG_REG_BASE + 0x424)
+#define CRG_PERSTAT7_REG		(CRG_REG_BASE + 0x428)
+#define GT_CLK_UFSPHY_CFG		(1 << 14)
+
+#define CRG_PEREN8_REG			(CRG_REG_BASE + 0x430)
+#define CRG_PERDIS8_REG			(CRG_REG_BASE + 0x434)
+#define CRG_PERSTAT8_REG		(CRG_REG_BASE + 0x438)
+#define PERI_DMC_D_BIT			(1 << 22)
+#define PERI_DMC_C_BIT			(1 << 21)
+#define PERI_DMC_B_BIT			(1 << 20)
+#define PERI_DMC_A_BIT			(1 << 19)
+#define PERI_DMC_BIT			(1 << 18)
+
+#define CRG_PEREN11_REG			(CRG_REG_BASE + 0x460)
+#define PPLL1_GATE_CPU			(1 << 18)
+
+#define CRG_PERSTAT11_REG		(CRG_REG_BASE + 0x46C)
+#define PPLL3_EN_STAT			(1 << 21)
+#define PPLL2_EN_STAT			(1 << 20)
+#define PPLL1_EN_STAT			(1 << 19)
+
+#define CRG_IVP_SEC_RSTDIS_REG		(CRG_REG_BASE + 0xC04)
+#define CRG_ISP_SEC_RSTDIS_REG		(CRG_REG_BASE + 0xC84)
+
+#define CRG_RVBAR(c, n)			(0xE00 + (0x10 * c) + (0x4 * n))
+#define CRG_GENERAL_SEC_RSTEN_REG	(CRG_REG_BASE + 0xE20)
+#define CRG_GENERAL_SEC_RSTDIS_REG	(CRG_REG_BASE + 0xE24)
+#define IP_RST_GPIO0_SEC		(1 << 2)
+
+#define CRG_GENERAL_SEC_CLKDIV0_REG	(CRG_REG_BASE + 0xE90)
+#define SC_DIV_AO_HISE_MASK		3
+#define SC_DIV_AO_HISE(x)		((x) & 0x3)
+
+#endif	/* __HI3660_CRG_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_hkadc.h b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
new file mode 100644
index 0000000..6e67114
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_HKADC_H__
+#define __HI3660_HKADC_H__
+
+#define HKADC_SSI_REG_BASE			0xE82B8000
+
+#define HKADC_DSP_START_REG			(HKADC_SSI_REG_BASE + 0x000)
+#define HKADC_WR_NUM_REG			(HKADC_SSI_REG_BASE + 0x008)
+#define HKADC_DSP_START_CLR_REG			(HKADC_SSI_REG_BASE + 0x01C)
+#define HKADC_WR01_DATA_REG			(HKADC_SSI_REG_BASE + 0x020)
+
+#define WR1_WRITE_MODE				(1 << 31)
+#define WR1_READ_MODE				(0 << 31)
+#define WR1_ADDR(x)				(((x) & 0x7F) << 24)
+#define WR1_DATA(x)				(((x) & 0xFF) << 16)
+#define WR0_WRITE_MODE				(1 << 15)
+#define WR0_READ_MODE				(0 << 15)
+#define WR0_ADDR(x)				(((x) & 0x7F) << 8)
+#define WR0_DATA(x)				((x) & 0xFF)
+
+#define HKADC_WR23_DATA_REG			(HKADC_SSI_REG_BASE + 0x024)
+#define HKADC_WR45_DATA_REG			(HKADC_SSI_REG_BASE + 0x028)
+#define HKADC_DELAY01_REG			(HKADC_SSI_REG_BASE + 0x030)
+#define HKADC_DELAY23_REG			(HKADC_SSI_REG_BASE + 0x034)
+#define HKADC_DELAY45_REG			(HKADC_SSI_REG_BASE + 0x038)
+#define HKADC_DSP_RD2_DATA_REG			(HKADC_SSI_REG_BASE + 0x048)
+#define HKADC_DSP_RD3_DATA_REG			(HKADC_SSI_REG_BASE + 0x04C)
+
+/* HKADC Internal Registers */
+#define HKADC_CTRL_ADDR				0x00
+#define HKADC_START_ADDR			0x01
+#define HKADC_DATA1_ADDR			0x03   /* high 8 bits */
+#define HKADC_DATA0_ADDR			0x04   /* low 8 bits */
+#define HKADC_MODE_CFG				0x0A
+
+#define HKADC_VALUE_HIGH			0x0FF0
+#define HKADC_VALUE_LOW				0x000F
+#define HKADC_VALID_VALUE			0x0FFF
+
+#define HKADC_CHANNEL_MAX			15
+#define HKADC_VREF_1V8				1800
+#define HKADC_ACCURACY				0x0FFF
+
+#define HKADC_WR01_VALUE			((HKADC_START_ADDR << 24) | \
+						 (0x1 << 16))
+#define HKADC_WR23_VALUE			((0x1 << 31) |		\
+						 (HKADC_DATA0_ADDR << 24) | \
+						 (1 << 15) |		\
+						 (HKADC_DATA1_ADDR << 8))
+#define HKADC_WR45_VALUE			(0x80)
+#define HKADC_CHANNEL0_DELAY01_VALUE		((0x0700 << 16) | 0xFFFF)
+#define HKADC_DELAY01_VALUE			((0x0700 << 16) | 0x0200)
+#define HKADC_DELAY23_VALUE			((0x00C8 << 16) | 0x00C8)
+#define START_DELAY_TIMEOUT			2000
+#define HKADC_WR_NUM_VALUE			4
+
+#endif /* __HI3660_HKADC_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_mem_map.h b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
new file mode 100644
index 0000000..db3efaf
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HI3660_MEM_MAP__
+#define __HI3660_MEM_MAP__
+
+#define HISI_DATA_HEAD_BASE		(0x89C44400)
+
+#define HISI_RESERVED_MEM_BASE		(0x89C80000)
+#define HISI_RESERVED_MEM_SIZE		(0x00040000)
+
+#define HISI_DATA0_BASE			(0x89C96180)
+#define HISI_DATA0_SIZE			(0x000003A0)
+#define HISI_DATA1_BASE			(0x89C93480)
+#define HISI_DATA1_SIZE			(0x00002D00)
+
+#endif /* __HI3660_MEM_MAP__ */
diff --git a/plat/hisilicon/hikey960/include/hisi_ipc.h b/plat/hisilicon/hikey960/include/hisi_ipc.h
new file mode 100644
index 0000000..9dda1a5
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hisi_ipc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HISI_IPC_H__
+#define __HISI_IPC_H__
+
+enum pm_mode {
+	PM_ON = 0,
+	PM_OFF,
+};
+
+void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
+			enum pm_mode mode);
+void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
+			 unsigned int affinity_level);
+void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster);
+void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
+				unsigned int cmd_id);
+int hisi_ipc_init(void);
+
+#endif /* __HISI_IPC_H__ */
diff --git a/plat/hisilicon/hikey960/include/plat_macros.S b/plat/hisilicon/hikey960/include/plat_macros.S
new file mode 100644
index 0000000..9f1befd
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/plat_macros.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+#include <cci.h>
+#include <hi3660.h>
+#include <gic_v2.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"    \
+                " Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+	mov_imm	x16, GICD_REG_BASE
+	mov_imm	x17, GICC_REG_BASE
+
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to cosole */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+2:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	1f
+	bl	asm_print_hex
+	adr	x4, spacer
+	bl	asm_print_str
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+	adr	x4, newline
+	bl	asm_print_str
+	b	2b
+1:
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET(	\
+	                CCI400_SL_IFACE3_CLUSTER_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET(	\
+	                CCI400_SL_IFACE4_CLUSTER_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+.endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
new file mode 100644
index 0000000..369117b
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, 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 "../hikey960_def.h"
+
+
+/*
+ * Generic platform constants
+ */
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE		0x800
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_CACHE_LINE_SIZE	64
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CORE_COUNT_PER_CLUSTER	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
+					 PLATFORM_CORE_COUNT_PER_CLUSTER)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CORE_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + 1)
+
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		2
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+/* UFS RPMB and UFS User Data */
+#define MAX_IO_BLOCK_DEVICES		2
+
+
+/*
+ * Platform memory map related constants
+ */
+
+/*
+ * BL1 specific defines.
+ */
+#define BL1_RO_BASE			(0x1AC00000)
+#define BL1_RO_LIMIT			(BL1_RO_BASE + 0x10000)
+#define BL1_RW_BASE			(BL1_RO_LIMIT)		/* 1AC1_0000 */
+#define BL1_RW_SIZE			(0x00188000)
+#define BL1_RW_LIMIT			(0x1B000000)
+
+/*
+ * BL2 specific defines.
+ */
+#define BL2_BASE			(BL1_RW_BASE + 0x8000)	/* 1AC1_8000 */
+#define BL2_LIMIT			(BL2_BASE + 0x40000)	/* 1AC5_8000 */
+
+/*
+ * BL31 specific defines.
+ */
+#define BL31_BASE			(BL2_LIMIT)		/* 1AC5_8000 */
+#define BL31_LIMIT			(BL31_BASE + 0x40000)	/* 1AC9_8000 */
+
+#define NS_BL1U_BASE			(BL31_LIMIT)		/* 1AC9_8000 */
+#define NS_BL1U_SIZE			(0x00100000)
+#define NS_BL1U_LIMIT			(NS_BL1U_BASE + NS_BL1U_SIZE)
+
+#define HIKEY960_NS_IMAGE_OFFSET	(0x1AC18000)	/* offset in l-loader */
+#define HIKEY960_NS_TMP_OFFSET		(0x1AE00000)
+
+#define SCP_BL2_BASE			BL31_BASE
+
+#define SCP_MEM_BASE			(0x89C80000)
+#define SCP_MEM_SIZE			(0x00040000)
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#define ADDR_SPACE_SIZE			(1ull << 32)
+
+#if IMAGE_BL1 || IMAGE_BL2 || IMAGE_BL31
+#define MAX_XLAT_TABLES			3
+#endif
+
+#define MAX_MMAP_REGIONS		16
+
+/*
+ * 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)
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/hisilicon/hikey960/platform.mk b/plat/hisilicon/hikey960/platform.mk
new file mode 100644
index 0000000..145eee0
--- /dev/null
+++ b/plat/hisilicon/hikey960/platform.mk
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+CRASH_CONSOLE_BASE		:=	PL011_UART6_BASE
+COLD_BOOT_SINGLE_CPU		:=	1
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+
+# Process flags
+$(eval $(call add_define,CRASH_CONSOLE_BASE))
+$(eval $(call FIP_ADD_IMG,SCP_BL2,--scp-fw))
+
+ENABLE_PLAT_COMPAT	:=	0
+
+USE_COHERENT_MEM	:=	1
+
+PLAT_INCLUDES		:=	-Iinclude/common/tbbr			\
+				-Iplat/hisilicon/hikey960/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/arm/pl011/pl011_console.S	\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				lib/aarch64/xlat_tables.c		\
+				plat/hisilicon/hikey960/aarch64/hikey960_common.c \
+				plat/hisilicon/hikey960/hikey960_boardid.c
+
+HIKEY960_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
+
+BL1_SOURCES		+=	bl1/tbbr/tbbr_img_desc.c		\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/synopsys/ufs/dw_ufs.c		\
+				drivers/ufs/ufs.c 			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+				plat/hisilicon/hikey960/hikey960_bl1_setup.c 	\
+				plat/hisilicon/hikey960/hikey960_io_storage.c \
+				${HIKEY960_GIC_SOURCES}
+
+BL2_SOURCES		+=	drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/ufs/ufs.c			\
+				plat/hisilicon/hikey960/hikey960_bl2_setup.c \
+				plat/hisilicon/hikey960/hikey960_io_storage.c \
+				plat/hisilicon/hikey960/hikey960_mcu_load.c
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
+				lib/cpus/aarch64/cortex_a53.S           \
+				lib/cpus/aarch64/cortex_a72.S		\
+				lib/cpus/aarch64/cortex_a73.S		\
+				plat/common/aarch64/plat_psci_common.c  \
+				plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+				plat/hisilicon/hikey960/hikey960_bl31_setup.c \
+				plat/hisilicon/hikey960/hikey960_pm.c	\
+				plat/hisilicon/hikey960/hikey960_topology.c \
+				plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c \
+				plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c \
+				${HIKEY960_GIC_SOURCES}
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
index 9c68b3b..a756f40 100644
--- a/plat/rockchip/common/aarch64/platform_common.c
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -44,7 +44,7 @@
 				coh_limit - coh_start,			\
 				MT_DEVICE | MT_RW | MT_SECURE);		\
 		mmap_add(plat_rk_mmap);					\
-		rockchip_plat_sram_mmu_el##_el();			\
+		rockchip_plat_mmu_el##_el();				\
 		init_xlat_tables();					\
 									\
 		enable_mmu_el ## _el(0);				\
diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
index 71d66c9..f7564e8 100644
--- a/plat/rockchip/common/bl31_plat_setup.c
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -83,8 +83,6 @@
 	bl32_ep_info = *from_bl2->bl32_ep_info;
 	bl33_ep_info = *from_bl2->bl33_ep_info;
 
-	plat_rockchip_pmusram_prepare();
-
 	/* there may have some board sepcific message need to initialize */
 	params_early_setup(plat_params_from_bl2);
 }
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index 867d9ad..b9540f2 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -15,12 +15,18 @@
 
 #define __sramdata __attribute__((section(".sram.data")))
 #define __sramconst __attribute__((section(".sram.rodata")))
-#define __sramfunc __attribute__((section(".sram.text")))	\
-			__attribute__((noinline))
+#define __sramfunc __attribute__((section(".sram.text")))
+
+#define __pmusramdata __attribute__((section(".pmusram.data")))
+#define __pmusramconst __attribute__((section(".pmusram.rodata")))
+#define __pmusramfunc __attribute__((section(".pmusram.text")))
 
 extern uint32_t __bl31_sram_text_start, __bl31_sram_text_end;
 extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end;
+extern uint32_t __bl31_sram_stack_start, __bl31_sram_stack_end;
+extern uint32_t __bl31_sram_text_real_end, __bl31_sram_data_real_end;
 extern uint32_t __sram_incbin_start, __sram_incbin_end;
+extern uint32_t __sram_incbin_real_end;
 
 
 /******************************************************************************
@@ -73,7 +79,6 @@
 void plat_rockchip_gic_cpuif_disable(void);
 void plat_rockchip_gic_pcpu_init(void);
 
-void plat_rockchip_pmusram_prepare(void);
 void plat_rockchip_pmu_init(void);
 void plat_rockchip_soc_init(void);
 uintptr_t plat_get_sec_entrypoint(void);
@@ -110,15 +115,13 @@
 
 extern const unsigned char rockchip_power_domain_tree_desc[];
 
-extern void *pmu_cpuson_entrypoint_start;
-extern void *pmu_cpuson_entrypoint_end;
+extern void *pmu_cpuson_entrypoint;
 extern uint64_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_sram_mmu_el3(void);
-void plat_rockchip_mem_prepare(void);
+void rockchip_plat_mmu_el3(void);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/plat/rockchip/common/pmusram/pmu_sram.c b/plat/rockchip/common/pmusram/pmu_sram.c
deleted file mode 100644
index 05ee762..0000000
--- a/plat/rockchip/common/pmusram/pmu_sram.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <console.h>
-#include <debug.h>
-#include <platform.h>
-#include <plat_private.h>
-
-/*****************************************************************************
- * sram only surpport 32-bits access
- ******************************************************************************/
-void u32_align_cpy(uint32_t *dst, const uint32_t *src, size_t bytes)
-{
-	uint32_t i;
-
-	for (i = 0; i < bytes; i++)
-		dst[i] = src[i];
-}
-
-void rockchip_plat_sram_mmu_el3(void)
-{
-#ifdef PLAT_EXTRA_LD_SCRIPT
-	size_t sram_size;
-
-	/* sram.text size */
-	sram_size = (char *)&__bl31_sram_text_end -
-		    (char *)&__bl31_sram_text_start;
-	mmap_add_region((unsigned long)&__bl31_sram_text_start,
-			(unsigned long)&__bl31_sram_text_start,
-			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
-
-	/* sram.data size */
-	sram_size = (char *)&__bl31_sram_data_end -
-		    (char *)&__bl31_sram_data_start;
-	mmap_add_region((unsigned long)&__bl31_sram_data_start,
-			(unsigned long)&__bl31_sram_data_start,
-			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
-
-	/* sram.incbin size */
-	sram_size = (char *)&__sram_incbin_end - (char *)&__sram_incbin_start;
-	mmap_add_region((unsigned long)&__sram_incbin_start,
-			(unsigned long)&__sram_incbin_start,
-			sram_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
-#else
-	/* TODO: Support other SoCs, Just support RK3399 now */
-	return;
-#endif
-}
-
-void plat_rockchip_mem_prepare(void)
-{
-	/* The code for resuming cpu from suspend must be excuted in pmusram */
-	plat_rockchip_pmusram_prepare();
-}
diff --git a/plat/rockchip/common/pmusram/pmu_sram.h b/plat/rockchip/common/pmusram/pmu_sram.h
deleted file mode 100644
index 24a1c25..0000000
--- a/plat/rockchip/common/pmusram/pmu_sram.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __PMU_SRAM_H__
-#define __PMU_SRAM_H__
-
-/*****************************************************************************
- * define data offset in struct psram_data
- *****************************************************************************/
-#define PSRAM_DT_SP		0x0
-#define PSRAM_DT_DDR_FUNC	0x8
-#define PSRAM_DT_DDR_DATA	0x10
-#define PSRAM_DT_DDRFLAG	0x18
-#define PSRAM_DT_MPIDR		0x1c
-#define PSRAM_DT_END		0x20
-/******************************************************************************
- * Allocate data region for struct psram_data_t in pmusram
- ******************************************************************************/
-/* Needed aligned 16 bytes for sp stack top */
-#define PSRAM_DT_SIZE		(((PSRAM_DT_END + 16) / 16) * 16)
-#define PSRAM_DT_BASE		((PMUSRAM_BASE + PMUSRAM_RSIZE) - PSRAM_DT_SIZE)
-#define PSRAM_SP_TOP		PSRAM_DT_BASE
-
-#ifndef __ASSEMBLY__
-
-struct psram_data_t {
-	uint64_t sp;
-	uint64_t ddr_func;
-	uint64_t ddr_data;
-	uint32_t ddr_flag;
-	uint32_t boot_mpidr;
-};
-
-CASSERT(sizeof(struct psram_data_t) <= PSRAM_DT_SIZE,
-	assert_psram_dt_size_mismatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, sp) == PSRAM_DT_SP,
-	assert_psram_dt_sp_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, ddr_func) == PSRAM_DT_DDR_FUNC,
-	assert_psram_dt_ddr_func_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, ddr_data) == PSRAM_DT_DDR_DATA,
-	assert_psram_dt_ddr_data_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, ddr_flag) == PSRAM_DT_DDRFLAG,
-	assert_psram_dt_ddr_flag_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, boot_mpidr) == PSRAM_DT_MPIDR,
-	assert_psram_dt_mpidr_offset_mistmatch);
-void u32_align_cpy(uint32_t *dst, const uint32_t *src, size_t bytes);
-
-#endif  /* __ASSEMBLY__ */
-
-#endif
diff --git a/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S b/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S
index 8f175c3..22bdffc 100644
--- a/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S
+++ b/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S
@@ -7,23 +7,30 @@
 #include <arch.h>
 #include <asm_macros.S>
 #include <platform_def.h>
-#include <pmu_sram.h>
 
-	.globl pmu_cpuson_entrypoint_start
-	.globl pmu_cpuson_entrypoint_end
+	.globl pmu_cpuson_entrypoint
+	.macro pmusram_entry_func _name
+	.section .pmusram.entry, "ax"
+	.type \_name, %function
+	.func \_name
+	.cfi_startproc
+	\_name:
+	.endm
 
-func pmu_cpuson_entrypoint
-pmu_cpuson_entrypoint_start:
-	ldr	x5, psram_data
+pmusram_entry_func pmu_cpuson_entrypoint
+
+#if PSRAM_CHECK_WAKEUP_CPU
 check_wake_cpus:
 	mrs	x0, MPIDR_EL1
 	and	x1, x0, #MPIDR_CPU_MASK
 	and	x0, x0, #MPIDR_CLUSTER_MASK
 	orr	x0, x0, x1
+
 	/* primary_cpu */
-	ldr	w1, [x5, #PSRAM_DT_MPIDR]
+	ldr	w1, boot_mpidr
 	cmp	w0, w1
 	b.eq	sys_wakeup
+
 	/*
 	 * If the core is not the primary cpu,
 	 * force the core into wfe.
@@ -32,25 +39,15 @@
 	wfe
 	b	wfe_loop
 sys_wakeup:
-	/* check ddr flag for resume ddr */
-	ldr	w2, [x5, #PSRAM_DT_DDRFLAG]
-	cmp	w2, #0x0
-	b.eq	sys_resume
-ddr_resume:
-	ldr	x2, [x5, #PSRAM_DT_SP]
-	mov	sp, x2
-	ldr	x1, [x5, #PSRAM_DT_DDR_FUNC]
-	ldr	x0, [x5, #PSRAM_DT_DDR_DATA]
-	blr	x1
-sys_resume:
-	ldr	x1, sys_wakeup_entry
-	br	x1
+#endif
 
-	.align	3
-psram_data:
-	.quad	PSRAM_DT_BASE
-sys_wakeup_entry:
-	.quad	psci_entrypoint
-pmu_cpuson_entrypoint_end:
-	.word	0
+#if PSRAM_DO_DDR_RESUME
+ddr_resume:
+	ldr	x2, =__bl31_sram_stack_end
+	mov     sp, x2
+	bl	dmc_restore
+#endif
+	bl	sram_restore
+sys_resume:
+	bl	psci_entrypoint
 endfunc pmu_cpuson_entrypoint
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.c b/plat/rockchip/rk3328/drivers/pmu/pmu.c
index 59d399b..60f36d3 100644
--- a/plat/rockchip/rk3328/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.c
@@ -16,16 +16,12 @@
 #include <platform.h>
 #include <platform_def.h>
 #include <plat_private.h>
-#include <pmu_sram.h>
 #include <pmu.h>
 #include <rk3328_def.h>
 #include <pmu_com.h>
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
-static struct psram_data_t *psram_sleep_cfg =
-		(struct psram_data_t *)PSRAM_DT_BASE;
-
 static struct rk3328_sleep_ddr_data ddr_data;
 static __sramdata struct rk3328_sleep_sram_data sram_data;
 
@@ -34,22 +30,6 @@
 #pragma weak rk3328_pmic_suspend
 #pragma weak rk3328_pmic_resume
 
-void plat_rockchip_pmusram_prepare(void)
-{
-	uint32_t *sram_dst, *sram_src;
-	size_t sram_size = 2;
-	/*
-	 * pmu sram code and data prepare
-	 */
-	sram_dst = (uint32_t *)PMUSRAM_BASE;
-	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
-	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
-		    (uint32_t *)sram_src;
-	u32_align_cpy(sram_dst, sram_src, sram_size);
-
-	psram_sleep_cfg->sp = PSRAM_DT_BASE;
-}
-
 static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
 {
 	uint32_t pd_reg, apm_reg;
@@ -140,6 +120,16 @@
 	}
 }
 
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3328 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3328 SoCs */
+}
+
 int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
 {
 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
@@ -495,11 +485,6 @@
 	sram_udelay(100);
 }
 
-static inline void rockchip_set_sram_sp(uint64_t set_sp)
-{
-	__asm volatile("mov sp, %0\n"::"r" (set_sp) : "sp");
-}
-
 static __sramfunc void ddr_suspend(void)
 {
 	sram_data.pd_sr_idle_save = mmio_read_32(DDR_UPCTL_BASE +
@@ -538,7 +523,7 @@
 	dpll_suspend();
 }
 
-static __sramfunc  void ddr_resume(void)
+__sramfunc  void dmc_restore(void)
 {
 	dpll_resume();
 
@@ -574,7 +559,7 @@
 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040004);
 }
 
-static __sramfunc void sram_dbg_uart_resume(void)
+__sramfunc void sram_dbg_uart_resume(void)
 {
 	/* restore uart clk and reset fifo */
 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20000000);
@@ -610,7 +595,7 @@
 	disable_mmu_icache_el3();
 
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
+		      ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) |
 		      CPU_BOOT_ADDR_WMASK);
 
 	/* ddr self-refresh and gating phy */
@@ -623,28 +608,8 @@
 	sram_soc_enter_lp();
 }
 
-static __sramfunc void sys_resume_first(void)
-{
-	sram_dbg_uart_resume();
-
-	rk3328_pmic_resume();
-
-	/* ddr self-refresh exit */
-	ddr_resume();
-
-	/* disable apm cfg */
-	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(0), CORES_PM_DISABLE);
-
-	/* the warm booting address of cpus */
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
-}
-
 void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
 {
-	rockchip_set_sram_sp(PSRAM_DT_BASE);
-
 	sram_suspend();
 
 	/* should never reach here */
@@ -671,6 +636,11 @@
 	return 0;
 }
 
+void rockchip_plat_mmu_el3(void)
+{
+	/* TODO: support the el3 for rk3328 SoCs */
+}
+
 void plat_rockchip_pmu_init(void)
 {
 	uint32_t cpu;
@@ -679,10 +649,6 @@
 		cpuson_flags[cpu] = 0;
 
 	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
-	psram_sleep_cfg->ddr_func = (uint64_t)sys_resume_first;
-	psram_sleep_cfg->ddr_data = 0x00;
-	psram_sleep_cfg->ddr_flag = 0x01;
-	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
 
 	/* the warm booting address of cpus */
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
diff --git a/plat/rockchip/rk3328/include/plat.ld.S b/plat/rockchip/rk3328/include/plat.ld.S
index ff17572..b3559b2 100644
--- a/plat/rockchip/rk3328/include/plat.ld.S
+++ b/plat/rockchip/rk3328/include/plat.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,39 +7,31 @@
 #define __ROCKCHIP_PLAT_LD_S__
 
 MEMORY {
-    SRAM (rwx): ORIGIN = SRAM_LDS_BASE, LENGTH = SRAM_LDS_SIZE
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
 }
 
 SECTIONS
 {
-	. = SRAM_LDS_BASE;
-	ASSERT(. == ALIGN(4096),
-		"SRAM_BASE address is not aligned on a page boundary.")
+	. = PMUSRAM_BASE;
 
 	/*
-	 * The SRAM space allocation for RK3328
-	 * ----------------
-	 * | sram text
-	 * ----------------
-	 * | sram data
-	 * ----------------
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
 	 */
-	.text_sram : ALIGN(4096) {
-		__bl31_sram_text_start = .;
-		*(.sram.text)
-		*(.sram.rodata)
-		. = ALIGN(4096);
-		__bl31_sram_text_end = .;
-	} >SRAM
+	.text_pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
 
-	.data_sram : ALIGN(4096) {
-		__bl31_sram_data_start = .;
-		*(.sram.data)
-		. = ALIGN(4096);
-		__bl31_sram_data_end = .;
-	} >SRAM
-	__sram_incbin_start = .;
-	__sram_incbin_end = .;
+	} >PMUSRAM
 }
 
 #endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/rk3328/include/platform_def.h b/plat/rockchip/rk3328/include/platform_def.h
index 1f49fcd..7304dcf 100644
--- a/plat/rockchip/rk3328/include/platform_def.h
+++ b/plat/rockchip/rk3328/include/platform_def.h
@@ -120,4 +120,7 @@
 
 #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/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
index b81d746..8863fb4 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -41,7 +41,6 @@
 				${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.c            \
 				${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S	\
 				${RK_PLAT_COMMON}/plat_pm.c			\
 				${RK_PLAT_COMMON}/plat_topology.c		\
diff --git a/plat/rockchip/rk3368/drivers/pmu/pmu.c b/plat/rockchip/rk3368/drivers/pmu/pmu.c
index e5e6805..1767967 100644
--- a/plat/rockchip/rk3368/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3368/drivers/pmu/pmu.c
@@ -14,7 +14,6 @@
 #include <platform_def.h>
 #include <plat_private.h>
 #include <rk3368_def.h>
-#include <pmu_sram.h>
 #include <soc.h>
 #include <pmu.h>
 #include <ddr_rk3368.h>
@@ -22,9 +21,6 @@
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
-static struct psram_data_t *psram_sleep_cfg =
-	(struct psram_data_t *)PSRAM_DT_BASE;
-
 static uint32_t cpu_warm_boot_addr;
 
 void rk3368_flash_l2_b(void)
@@ -223,54 +219,19 @@
 	dsb();
 }
 
-static void ddr_suspend_save(void)
-{
-	ddr_reg_save(1, psram_sleep_cfg->ddr_data);
-}
-
 static void pmu_set_sleep_mode(void)
 {
-	ddr_suspend_save();
 	pmu_sleep_mode_config();
 	soc_sleep_config();
 	regs_updata_bit_set(PMU_BASE + PMU_PWRMD_CORE, pmu_mdcr_global_int_dis);
 	regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_glbl_int_dis_b);
 	pmu_scu_b_pwrdn();
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
-}
-
-void plat_rockchip_pmusram_prepare(void)
-{
-	uint32_t *sram_dst, *sram_src;
-	size_t sram_size = 2;
-	uint32_t code_size;
-
-	/* pmu sram code and data prepare */
-	sram_dst = (uint32_t *)PMUSRAM_BASE;
-	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
-	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
-		    (uint32_t *)sram_src;
-	u32_align_cpy(sram_dst, sram_src, sram_size);
-
-	/* ddr code */
-	sram_dst += sram_size;
-	sram_src = ddr_get_resume_code_base();
-	code_size = ddr_get_resume_code_size();
-	u32_align_cpy(sram_dst, sram_src, code_size / 4);
-	psram_sleep_cfg->ddr_func = (uint64_t)sram_dst;
-
-	/* ddr data */
-	sram_dst += (code_size / 4);
-	psram_sleep_cfg->ddr_data = (uint64_t)sram_dst;
-
-	assert((uint64_t)(sram_dst + ddr_get_resume_data_size() / 4)
-						 < PSRAM_SP_BOTTOM);
-	psram_sleep_cfg->sp = PSRAM_SP_TOP;
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
 }
 
 static int cpus_id_power_domain(uint32_t cluster,
@@ -319,6 +280,16 @@
 	}
 }
 
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3368 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3368 SoCs */
+}
+
 int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
 {
 	uint32_t cpu, cluster;
@@ -375,11 +346,14 @@
 	nonboot_cpus_off();
 	pmu_set_sleep_mode();
 
-	psram_sleep_cfg->ddr_flag = 0;
-
 	return 0;
 }
 
+void rockchip_plat_mmu_el3(void)
+{
+	/* TODO: support the el3 for rk3368 SoCs */
+}
+
 void plat_rockchip_pmu_init(void)
 {
 	uint32_t cpu;
@@ -390,8 +364,6 @@
 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
 		cpuson_flags[cpu] = 0;
 
-	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
-
 	nonboot_cpus_off();
 	INFO("%s(%d): pd status %x\n", __func__, __LINE__,
 	     mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
diff --git a/plat/rockchip/rk3368/include/plat.ld.S b/plat/rockchip/rk3368/include/plat.ld.S
new file mode 100644
index 0000000..b3559b2
--- /dev/null
+++ b/plat/rockchip/rk3368/include/plat.ld.S
@@ -0,0 +1,37 @@
+/*
+ * 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__
+
+MEMORY {
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.text_pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+
+	} >PMUSRAM
+}
+
+#endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/rk3368/include/platform_def.h b/plat/rockchip/rk3368/include/platform_def.h
index 053f6fe..07b91e2 100644
--- a/plat/rockchip/rk3368/include/platform_def.h
+++ b/plat/rockchip/rk3368/include/platform_def.h
@@ -122,4 +122,7 @@
 
 #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/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
index 7837af9..f6960cf 100644
--- a/plat/rockchip/rk3368/platform.mk
+++ b/plat/rockchip/rk3368/platform.mk
@@ -39,7 +39,6 @@
 				${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}/pmusram/pmu_sram.c		\
 				${RK_PLAT_COMMON}/plat_pm.c			\
 				${RK_PLAT_COMMON}/plat_topology.c		\
 				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
@@ -50,3 +49,5 @@
 				${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c		\
 
 ENABLE_PLAT_COMPAT	:=      0
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.c b/plat/rockchip/rk3399/drivers/dram/dfs.c
index 28d0d6a..481dcc6 100644
--- a/plat/rockchip/rk3399/drivers/dram/dfs.c
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.c
@@ -54,6 +54,7 @@
 static struct rk3399_dram_status rk3399_dram_status;
 static struct rk3399_saved_status rk3399_suspend_status;
 static uint32_t wrdqs_delay_val[2][2][4];
+static uint32_t rddqs_delay_ps;
 
 static struct rk3399_sdram_default_config ddr3_default_config = {
 	.bl = 8,
@@ -1599,7 +1600,7 @@
 		mmio_clrsetbits_32(PHY_REG(i, 394), 0xf, tmp);
 		/* PHY_GTLVL_LAT_ADJ_START */
 		/* DENALI_PHY_80/208/336/464 4bits offset_16 */
-		tmp = delay_frac_ps / 1000;
+		tmp = rddqs_delay_ps / (1000000 / pdram_timing->mhz) + 2;
 		mmio_clrsetbits_32(PHY_REG(i, 80), 0xf << 16, tmp << 16);
 		mmio_clrsetbits_32(PHY_REG(i, 208), 0xf << 16, tmp << 16);
 		mmio_clrsetbits_32(PHY_REG(i, 336), 0xf << 16, tmp << 16);
@@ -1830,6 +1831,7 @@
 void dram_dfs_init(void)
 {
 	uint32_t trefi0, trefi1, boot_freq;
+	uint32_t rddqs_adjust, rddqs_slave;
 
 	/* get sdram config for os reg */
 	get_dram_drv_odt_val(sdram_config.dramtype,
@@ -1875,8 +1877,31 @@
 	/* Disable multicast */
 	mmio_clrbits_32(PHY_REG(0, 896), 1);
 	mmio_clrbits_32(PHY_REG(1, 896), 1);
-
 	dram_low_power_config();
+
+	/*
+	 * If boot_freq isn't in the bypass mode, it can get the
+	 * rddqs_delay_ps from the result of gate training
+	 */
+	if (((mmio_read_32(PHY_REG(0, 86)) >> 8) & 0xf) != 0xc) {
+
+		/*
+		 * Select PHY's frequency set to current_index
+		 * index for get the result of gate Training
+		 * from registers
+		 */
+		mmio_clrsetbits_32(PHY_REG(0, 896), 0x3 << 8,
+				   rk3399_dram_status.current_index << 8);
+		rddqs_slave = (mmio_read_32(PHY_REG(0, 77)) >> 16) & 0x3ff;
+		rddqs_slave = rddqs_slave * 1000000 / boot_freq / 512;
+
+		rddqs_adjust = mmio_read_32(PHY_REG(0, 78)) & 0xf;
+		rddqs_adjust = rddqs_adjust * 1000000 / boot_freq;
+		rddqs_delay_ps = rddqs_slave + rddqs_adjust -
+				(1000000 / boot_freq / 2);
+	} else {
+		rddqs_delay_ps = 3500;
+	}
 }
 
 /*
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
index fbf3110..ad79f9e 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -10,7 +10,7 @@
 #include <soc.h>
 #include <rk3399_def.h>
 
-__sramdata struct rk3399_sdram_params sdram_config;
+__pmusramdata struct rk3399_sdram_params sdram_config;
 
 void dram_init(void)
 {
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h
index 08893d4..fede7ee 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.h
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -24,7 +24,17 @@
 };
 
 struct rk3399_ddr_publ_regs {
-	uint32_t denali_phy[PHY_REG_NUM];
+	/*
+	 * PHY registers from 0 to 511.
+	 * Only registers 0-90 of each 128 register range are used.
+	 */
+	uint32_t phy0[4][91];
+	/*
+	 * PHY registers from 512 to 895.
+	 * Only registers 0-37 of each 128 register range are used.
+	 */
+	uint32_t phy512[3][38];
+	uint32_t phy896[63];
 };
 
 struct rk3399_ddr_pi_regs {
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.c b/plat/rockchip/rk3399/drivers/dram/suspend.c
index 1ed3f54..617e39b 100644
--- a/plat/rockchip/rk3399/drivers/dram/suspend.c
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.c
@@ -45,7 +45,8 @@
 /*
  * Copy @num registers from @src to @dst
  */
-__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num)
+static __pmusramfunc void sram_regcpy(uintptr_t dst, uintptr_t src,
+		uint32_t num)
 {
 	while (num--) {
 		mmio_write_32(dst, mmio_read_32(src));
@@ -54,7 +55,21 @@
 	}
 }
 
-static __sramfunc uint32_t sram_get_timer_value(void)
+/*
+ * Copy @num registers from @src to @dst
+ * This is intentionally a copy of the sram_regcpy function. PMUSRAM functions
+ * cannot be called from code running in DRAM.
+ */
+static void dram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num)
+{
+	while (num--) {
+		mmio_write_32(dst, mmio_read_32(src));
+		dst += sizeof(uint32_t);
+		src += sizeof(uint32_t);
+	}
+}
+
+static __pmusramfunc uint32_t sram_get_timer_value(void)
 {
 	/*
 	 * Generic delay timer implementation expects the timer to be a down
@@ -64,7 +79,7 @@
 	return (uint32_t)(~read_cntpct_el0());
 }
 
-static __sramfunc void sram_udelay(uint32_t usec)
+static __pmusramfunc void sram_udelay(uint32_t usec)
 {
 	uint32_t start, cnt, delta, delta_us;
 
@@ -81,7 +96,7 @@
 	} while (delta_us < usec);
 }
 
-static __sramfunc void configure_sgrf(void)
+static __pmusramfunc void configure_sgrf(void)
 {
 	/*
 	 * SGRF_DDR_RGN_DPLL_CLK and SGRF_DDR_RGN_RTC_CLK:
@@ -98,7 +113,7 @@
 		      SGRF_DDR_RGN_BYPS);
 }
 
-static __sramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl,
+static __pmusramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl,
 		uint32_t phy)
 {
 	channel &= 0x1;
@@ -109,7 +124,7 @@
 		      CRU_SFTRST_DDR_PHY(channel, phy));
 }
 
-static __sramfunc void phy_pctrl_reset(uint32_t ch)
+static __pmusramfunc void phy_pctrl_reset(uint32_t ch)
 {
 	rkclk_ddr_reset(ch, 1, 1);
 	sram_udelay(10);
@@ -119,76 +134,45 @@
 	sram_udelay(10);
 }
 
-static __sramfunc void phy_dll_bypass_set(uint32_t ch, uint32_t hz)
+static __pmusramfunc void set_cs_training_index(uint32_t ch, uint32_t rank)
 {
-	if (hz <= 125 * MHz) {
-		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
-		mmio_setbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
-		mmio_setbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
-		mmio_setbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
-		mmio_setbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
-		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
-		mmio_setbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
-		mmio_setbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
-		mmio_setbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
-	} else {
-		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
-		mmio_clrbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
-		mmio_clrbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
-		mmio_clrbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
-		mmio_clrbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
-		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
-		mmio_clrbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
-		mmio_clrbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
-		mmio_clrbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
-	}
-}
+	uint32_t byte;
 
-static __sramfunc void set_cs_training_index(uint32_t ch, uint32_t rank)
-{
 	/* PHY_8/136/264/392 phy_per_cs_training_index_X 1bit offset_24 */
-	mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 24, rank << 24);
-	mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 24, rank << 24);
-	mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 24, rank << 24);
-	mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 24, rank << 24);
+	for (byte = 0; byte < 4; byte++)
+		mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 24,
+				   rank << 24);
 }
 
-static __sramfunc void select_per_cs_training_index(uint32_t ch, uint32_t rank)
+static __pmusramfunc void select_per_cs_training_index(uint32_t ch,
+		uint32_t rank)
 {
 	/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
 	if ((mmio_read_32(PHY_REG(ch, 84)) >> 16) & 1)
 		set_cs_training_index(ch, rank);
 }
 
-static void override_write_leveling_value(uint32_t ch)
+static __pmusramfunc void override_write_leveling_value(uint32_t ch)
 {
 	uint32_t byte;
 
-	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
-	mmio_setbits_32(PHY_REG(ch, 896), 1);
-
-	/*
-	 * PHY_8/136/264/392
-	 * phy_per_cs_training_multicast_en_X 1bit offset_16
-	 */
-	mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 16, 1 << 16);
-	mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 16, 1 << 16);
-	mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 16, 1 << 16);
-	mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 16, 1 << 16);
-
-	for (byte = 0; byte < 4; byte++)
+	for (byte = 0; byte < 4; byte++) {
+		/*
+		 * PHY_8/136/264/392
+		 * phy_per_cs_training_multicast_en_X 1bit offset_16
+		 */
+		mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 16,
+				   1 << 16);
 		mmio_clrsetbits_32(PHY_REG(ch, 63 + (128 * byte)),
 				   0xffff << 16,
 				   0x200 << 16);
-
-	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
-	mmio_clrbits_32(PHY_REG(ch, 896), 1);
+	}
 
 	/* CTL_200 ctrlupd_req 1bit offset_8 */
 	mmio_clrsetbits_32(CTL_REG(ch, 200), 0x1 << 8, 0x1 << 8);
 }
 
-static __sramfunc int data_training(uint32_t ch,
+static __pmusramfunc int data_training(uint32_t ch,
 		struct rk3399_sdram_params *sdram_params,
 		uint32_t training_flag)
 {
@@ -433,7 +417,8 @@
 	return 0;
 }
 
-static __sramfunc void set_ddrconfig(struct rk3399_sdram_params *sdram_params,
+static __pmusramfunc void set_ddrconfig(
+		struct rk3399_sdram_params *sdram_params,
 		unsigned char channel, uint32_t ddrconfig)
 {
 	/* only need to set ddrconfig */
@@ -455,7 +440,8 @@
 		      ((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8));
 }
 
-static __sramfunc void dram_all_config(struct rk3399_sdram_params *sdram_params)
+static __pmusramfunc void dram_all_config(
+		struct rk3399_sdram_params *sdram_params)
 {
 	unsigned int i;
 
@@ -491,13 +477,13 @@
 	mmio_clrsetbits_32(CRU_BASE + CRU_GLB_RST_CON, 0x3, 0x3);
 }
 
-static __sramfunc void pctl_cfg(uint32_t ch,
+static __pmusramfunc void pctl_cfg(uint32_t ch,
 		struct rk3399_sdram_params *sdram_params)
 {
 	const uint32_t *params_ctl = sdram_params->pctl_regs.denali_ctl;
-	const uint32_t *params_phy = sdram_params->phy_regs.denali_phy;
 	const uint32_t *params_pi = sdram_params->pi_regs.denali_pi;
-	uint32_t tmp, tmp1, tmp2;
+	const struct rk3399_ddr_publ_regs *phy_regs = &sdram_params->phy_regs;
+	uint32_t tmp, tmp1, tmp2, i;
 
 	/*
 	 * Workaround controller bug:
@@ -509,9 +495,8 @@
 	sram_regcpy(PI_REG(ch, 0), (uintptr_t)&params_pi[0],
 		    PI_REG_NUM);
 
-	mmio_write_32(PHY_REG(ch, 910), params_phy[910]);
-	mmio_write_32(PHY_REG(ch, 911), params_phy[911]);
-	mmio_write_32(PHY_REG(ch, 912), params_phy[912]);
+	sram_regcpy(PHY_REG(ch, 910), (uintptr_t)&phy_regs->phy896[910 - 896],
+		    3);
 
 	mmio_clrsetbits_32(CTL_REG(ch, 68), PWRUP_SREFRESH_EXIT,
 				PWRUP_SREFRESH_EXIT);
@@ -538,17 +523,18 @@
 			break;
 	}
 
-	sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&params_phy[896], 63);
-	sram_regcpy(PHY_REG(ch, 0), (uintptr_t)&params_phy[0], 91);
-	sram_regcpy(PHY_REG(ch, 128), (uintptr_t)&params_phy[128], 91);
-	sram_regcpy(PHY_REG(ch, 256), (uintptr_t)&params_phy[256], 91);
-	sram_regcpy(PHY_REG(ch, 384), (uintptr_t)&params_phy[384], 91);
-	sram_regcpy(PHY_REG(ch, 512), (uintptr_t)&params_phy[512], 38);
-	sram_regcpy(PHY_REG(ch, 640), (uintptr_t)&params_phy[640], 38);
-	sram_regcpy(PHY_REG(ch, 768), (uintptr_t)&params_phy[768], 38);
+	sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&phy_regs->phy896[0], 63);
+
+	for (i = 0; i < 4; i++)
+		sram_regcpy(PHY_REG(ch, 128 * i),
+			    (uintptr_t)&phy_regs->phy0[i][0], 91);
+
+	for (i = 0; i < 3; i++)
+		sram_regcpy(PHY_REG(ch, 512 + 128 * i),
+				(uintptr_t)&phy_regs->phy512[i][0], 38);
 }
 
-static __sramfunc int dram_switch_to_next_index(
+static __pmusramfunc int dram_switch_to_next_index(
 		struct rk3399_sdram_params *sdram_params)
 {
 	uint32_t ch, ch_count;
@@ -583,7 +569,7 @@
  * Needs to be done for both channels at once in case of a shared reset signal
  * between channels.
  */
-static __sramfunc int pctl_start(uint32_t channel_mask,
+static __pmusramfunc int pctl_start(uint32_t channel_mask,
 		struct rk3399_sdram_params *sdram_params)
 {
 	uint32_t count;
@@ -652,15 +638,15 @@
 void dmc_save(void)
 {
 	struct rk3399_sdram_params *sdram_params = &sdram_config;
+	struct rk3399_ddr_publ_regs *phy_regs;
 	uint32_t *params_ctl;
 	uint32_t *params_pi;
-	uint32_t *params_phy;
 	uint32_t refdiv, postdiv2, postdiv1, fbdiv;
-	uint32_t tmp, ch, byte;
+	uint32_t tmp, ch, byte, i;
 
+	phy_regs = &sdram_params->phy_regs;
 	params_ctl = sdram_params->pctl_regs.denali_ctl;
 	params_pi = sdram_params->pi_regs.denali_pi;
-	params_phy = sdram_params->phy_regs.denali_phy;
 
 	fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
 	tmp = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1));
@@ -676,25 +662,26 @@
 			       0x7) != 0) ? 1 : 0;
 
 	/* copy the registers CTL PI and PHY */
-	sram_regcpy((uintptr_t)&params_ctl[0], CTL_REG(0, 0), CTL_REG_NUM);
+	dram_regcpy((uintptr_t)&params_ctl[0], CTL_REG(0, 0), CTL_REG_NUM);
 
 	/* mask DENALI_CTL_00_DATA.START, only copy here, will trigger later */
 	params_ctl[0] &= ~(0x1 << 0);
 
-	sram_regcpy((uintptr_t)&params_pi[0], PI_REG(0, 0),
+	dram_regcpy((uintptr_t)&params_pi[0], PI_REG(0, 0),
 		    PI_REG_NUM);
 
 	/* mask DENALI_PI_00_DATA.START, only copy here, will trigger later*/
 	params_pi[0] &= ~(0x1 << 0);
 
-	sram_regcpy((uintptr_t)&params_phy[0], PHY_REG(0, 0), 91);
-	sram_regcpy((uintptr_t)&params_phy[128], PHY_REG(0, 128), 91);
-	sram_regcpy((uintptr_t)&params_phy[256], PHY_REG(0, 256), 91);
-	sram_regcpy((uintptr_t)&params_phy[384], PHY_REG(0, 384), 91);
-	sram_regcpy((uintptr_t)&params_phy[512], PHY_REG(0, 512), 38);
-	sram_regcpy((uintptr_t)&params_phy[640], PHY_REG(0, 640), 38);
-	sram_regcpy((uintptr_t)&params_phy[768], PHY_REG(0, 768), 38);
-	sram_regcpy((uintptr_t)&params_phy[896], PHY_REG(0, 896), 63);
+	for (i = 0; i < 4; i++)
+		dram_regcpy((uintptr_t)&phy_regs->phy0[i][0],
+			    PHY_REG(0, 128 * i), 91);
+
+	for (i = 0; i < 3; i++)
+		dram_regcpy((uintptr_t)&phy_regs->phy512[i][0],
+			    PHY_REG(0, 512 + 128 * i), 38);
+
+	dram_regcpy((uintptr_t)&phy_regs->phy896[0], PHY_REG(0, 896), 63);
 
 	for (ch = 0; ch < sdram_params->num_channels; ch++) {
 		for (byte = 0; byte < 4; byte++)
@@ -703,13 +690,13 @@
 	}
 
 	/* set DENALI_PHY_957_DATA.PHY_DLL_RST_EN = 0x1 */
-	params_phy[957] &= ~(0x3 << 24);
-	params_phy[957] |= 1 << 24;
-	params_phy[896] |= 1;
-	params_phy[896] &= ~(0x3 << 8);
+	phy_regs->phy896[957 - 896] &= ~(0x3 << 24);
+	phy_regs->phy896[957 - 896] |= 1 << 24;
+	phy_regs->phy896[0] |= 1;
+	phy_regs->phy896[0] &= ~(0x3 << 8);
 }
 
-__sramfunc void dmc_restore(void)
+__pmusramfunc void dmc_restore(void)
 {
 	struct rk3399_sdram_params *sdram_params = &sdram_config;
 	uint32_t channel_mask = 0;
@@ -720,10 +707,6 @@
 retry:
 	for (channel = 0; channel < sdram_params->num_channels; channel++) {
 		phy_pctrl_reset(channel);
-		phy_dll_bypass_set(channel, sdram_params->ddr_freq);
-		if (channel >= sdram_params->num_channels)
-			continue;
-
 		pctl_cfg(channel, sdram_params);
 	}
 
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.h b/plat/rockchip/rk3399/drivers/dram/suspend.h
index 03df421..77f9c31 100644
--- a/plat/rockchip/rk3399/drivers/dram/suspend.h
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.h
@@ -20,7 +20,6 @@
 #define PI_FULL_TRAINING	(0xff)
 
 void dmc_save(void);
-__sramfunc void dmc_restore(void);
-__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num);
+__pmusramfunc void dmc_restore(void);
 
 #endif /* __DRAM_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 9c0a29c..f6c47f4 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -19,9 +19,9 @@
 #include <plat_params.h>
 #include <plat_private.h>
 #include <rk3399_def.h>
-#include <pmu_sram.h>
 #include <secure.h>
 #include <soc.h>
+#include <string.h>
 #include <pmu.h>
 #include <pmu_com.h>
 #include <pwm.h>
@@ -30,10 +30,8 @@
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
-static struct psram_data_t *psram_sleep_cfg =
-	(struct psram_data_t *)PSRAM_DT_BASE;
-
 static uint32_t cpu_warm_boot_addr;
+static char store_sram[SRAM_BIN_LIMIT + SRAM_TEXT_LIMIT + SRAM_DATA_LIMIT];
 
 /*
  * There are two ways to powering on or off on core.
@@ -411,24 +409,6 @@
 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
 }
 
-void plat_rockchip_pmusram_prepare(void)
-{
-	uint32_t *sram_dst, *sram_src;
-	size_t sram_size;
-
-	/*
-	 * pmu sram code and data prepare
-	 */
-	sram_dst = (uint32_t *)PMUSRAM_BASE;
-	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
-	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
-		    (uint32_t *)sram_src;
-
-	u32_align_cpy(sram_dst, sram_src, sram_size);
-
-	psram_sleep_cfg->sp = PSRAM_DT_BASE;
-}
-
 static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
 {
 	assert(cpu_id < PLATFORM_CORE_COUNT);
@@ -782,14 +762,24 @@
 	mmio_write_32(PMU_BASE + PMU_CENTER_PWRUP_CNT, CYCL_24M_CNT_MS(1));
 
 	/*
+	 * when we enable PMU_CLR_PERILP, it will shut down the SRAM, but
+	 * M0 code run in SRAM, and we need it to check whether cpu enter
+	 * FSM status, so we must wait M0 finish their code and enter WFI,
+	 * then we can shutdown SRAM, according FSM order:
+	 * ST_NORMAL->..->ST_SCU_L_PWRDN->..->ST_CENTER_PWRDN->ST_PERILP_PWRDN
+	 * we can add delay when shutdown ST_SCU_L_PWRDN to guarantee M0 get
+	 * the FSM status and enter WFI, then enable PMU_CLR_PERILP.
+	 */
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_MS(5));
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_US(1));
+
+	/*
 	 * Set CPU/GPU to 1 us.
 	 *
 	 * NOTE: Even though ATF doesn't configure the GPU we'll still setup
 	 * counts here.  After all ATF controls all these other bits and also
 	 * chooses which clock these counters use.
 	 */
-	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_US(1));
-	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_US(1));
 	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_24M_CNT_US(1));
 	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRUP_CNT, CYCL_24M_CNT_US(1));
 	mmio_write_32(PMU_BASE + PMU_GPU_PWRDN_CNT, CYCL_24M_CNT_US(1));
@@ -837,6 +827,8 @@
 		       BIT(PMU_DDRIO1_RET_EN) |
 		       BIT(PMU_DDRIO_RET_HW_DE_REQ) |
 		       BIT(PMU_CENTER_PD_EN) |
+		       BIT(PMU_PERILP_PD_EN) |
+		       BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
 		       BIT(PMU_PLL_PD_EN) |
 		       BIT(PMU_CLK_CENTER_SRC_GATE_EN) |
 		       BIT(PMU_OSC_DIS) |
@@ -1050,6 +1042,36 @@
 	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_FUNC, M0_FUNC_SUSPEND);
 }
 
+void sram_save(void)
+{
+	size_t text_size = (char *)&__bl31_sram_text_real_end -
+			   (char *)&__bl31_sram_text_start;
+	size_t data_size = (char *)&__bl31_sram_data_real_end -
+			   (char *)&__bl31_sram_data_start;
+	size_t incbin_size = (char *)&__sram_incbin_real_end -
+			     (char *)&__sram_incbin_start;
+
+	memcpy(&store_sram[0], &__bl31_sram_text_start, text_size);
+	memcpy(&store_sram[text_size], &__bl31_sram_data_start, data_size);
+	memcpy(&store_sram[text_size + data_size], &__sram_incbin_start,
+	       incbin_size);
+}
+
+void sram_restore(void)
+{
+	size_t text_size = (char *)&__bl31_sram_text_real_end -
+			   (char *)&__bl31_sram_text_start;
+	size_t data_size = (char *)&__bl31_sram_data_real_end -
+			   (char *)&__bl31_sram_data_start;
+	size_t incbin_size = (char *)&__sram_incbin_real_end -
+			     (char *)&__sram_incbin_start;
+
+	memcpy(&__bl31_sram_text_start, &store_sram[0], text_size);
+	memcpy(&__bl31_sram_data_start, &store_sram[text_size], data_size);
+	memcpy(&__sram_incbin_start, &store_sram[text_size + data_size],
+	       incbin_size);
+}
+
 int rockchip_soc_sys_pwr_dm_suspend(void)
 {
 	uint32_t wait_cnt = 0;
@@ -1067,6 +1089,8 @@
 		    BIT(PMU_CLR_CCIM0) |
 		    BIT(PMU_CLR_CCIM1) |
 		    BIT(PMU_CLR_CENTER) |
+		    BIT(PMU_CLR_PERILP) |
+		    BIT(PMU_CLR_PERILPM0) |
 		    BIT(PMU_CLR_GIC));
 
 	sys_slp_config();
@@ -1077,8 +1101,8 @@
 	pmu_sgrf_rst_hld();
 
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
 
 	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
 		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
@@ -1112,6 +1136,7 @@
 	suspend_apio();
 	suspend_gpio();
 
+	sram_save();
 	return 0;
 }
 
@@ -1193,6 +1218,8 @@
 				BIT(PMU_CLR_CCIM0) |
 				BIT(PMU_CLR_CCIM1) |
 				BIT(PMU_CLR_CENTER) |
+				BIT(PMU_CLR_PERILP) |
+				BIT(PMU_CLR_PERILPM0) |
 				BIT(PMU_CLR_GIC));
 
 	plat_rockchip_gic_cpuif_enable();
@@ -1245,6 +1272,36 @@
 		;
 }
 
+void rockchip_plat_mmu_el3(void)
+{
+	size_t sram_size;
+
+	/* sram.text size */
+	sram_size = (char *)&__bl31_sram_text_end -
+		    (char *)&__bl31_sram_text_start;
+	mmap_add_region((unsigned long)&__bl31_sram_text_start,
+			(unsigned long)&__bl31_sram_text_start,
+			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
+
+	/* sram.data size */
+	sram_size = (char *)&__bl31_sram_data_end -
+		    (char *)&__bl31_sram_data_start;
+	mmap_add_region((unsigned long)&__bl31_sram_data_start,
+			(unsigned long)&__bl31_sram_data_start,
+			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
+
+	sram_size = (char *)&__bl31_sram_stack_end -
+		    (char *)&__bl31_sram_stack_start;
+	mmap_add_region((unsigned long)&__bl31_sram_stack_start,
+			(unsigned long)&__bl31_sram_stack_start,
+			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
+
+	sram_size = (char *)&__sram_incbin_end - (char *)&__sram_incbin_start;
+	mmap_add_region((unsigned long)&__sram_incbin_start,
+			(unsigned long)&__sram_incbin_start,
+			sram_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
+}
+
 void plat_rockchip_pmu_init(void)
 {
 	uint32_t cpu;
@@ -1260,12 +1317,6 @@
 	for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++)
 		clst_warmboot_data[cpu] = 0;
 
-	psram_sleep_cfg->ddr_func = (uint64_t)dmc_restore;
-	psram_sleep_cfg->ddr_data = (uint64_t)&sdram_config;
-	psram_sleep_cfg->ddr_flag = 0x01;
-
-	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
-
 	/* config cpu's warm boot address */
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
diff --git a/plat/rockchip/rk3399/include/plat.ld.S b/plat/rockchip/rk3399/include/plat.ld.S
index 49206be..c42d9a9 100644
--- a/plat/rockchip/rk3399/include/plat.ld.S
+++ b/plat/rockchip/rk3399/include/plat.ld.S
@@ -8,6 +8,7 @@
 
 MEMORY {
     SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
 }
 
 SECTIONS
@@ -29,24 +30,60 @@
 	.incbin_sram : ALIGN(4096) {
 		__sram_incbin_start = .;
 		*(.sram.incbin)
+		 __sram_incbin_real_end = .;
 		. = ALIGN(4096);
 		__sram_incbin_end = .;
 	} >SRAM
+	ASSERT((__sram_incbin_real_end - __sram_incbin_start) <=
+		SRAM_BIN_LIMIT, ".incbin_sram has exceeded its limit")
 
 	.text_sram : ALIGN(4096) {
 		__bl31_sram_text_start = .;
 		*(.sram.text)
 		*(.sram.rodata)
+		__bl31_sram_text_real_end = .;
 		. = ALIGN(4096);
 		__bl31_sram_text_end = .;
 	} >SRAM
+	ASSERT((__bl31_sram_text_real_end - __bl31_sram_text_start) <=
+		SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit")
 
 	.data_sram : ALIGN(4096) {
 		__bl31_sram_data_start = .;
 		*(.sram.data)
+		__bl31_sram_data_real_end = .;
 		. = ALIGN(4096);
 		__bl31_sram_data_end = .;
 	} >SRAM
+	ASSERT((__bl31_sram_data_real_end - __bl31_sram_data_start) <=
+		SRAM_DATA_LIMIT, ".data_sram has exceeded its limit")
+
+	.stack_sram : ALIGN(4096) {
+		__bl31_sram_stack_start = .;
+		. += 4096;
+		__bl31_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)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+
+	} >PMUSRAM
 }
 
 #endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/rk3399/include/platform_def.h b/plat/rockchip/rk3399/include/platform_def.h
index f4427d0..3df2f7d 100644
--- a/plat/rockchip/rk3399/include/platform_def.h
+++ b/plat/rockchip/rk3399/include/platform_def.h
@@ -107,4 +107,7 @@
 
 #define PLAT_RK_PRIMARY_CPU		0x0
 
+#define PSRAM_DO_DDR_RESUME	1
+#define PSRAM_CHECK_WAKEUP_CPU	0
+
 #endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/rockchip/rk3399/include/shared/addressmap_shared.h b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
index d72633e..fe23e56 100644
--- a/plat/rockchip/rk3399/include/shared/addressmap_shared.h
+++ b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
@@ -9,6 +9,9 @@
 
 #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 SRAM_BIN_LIMIT		(4 * 1024)
 
 /*
  * The parts of the shared defined registers address with AP and M0,
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index be3e11b..cb7999b 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -44,7 +44,6 @@
 			${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}/pmusram/pmu_sram.c		\
 			${RK_PLAT_COMMON}/plat_pm.c			\
 			${RK_PLAT_COMMON}/plat_topology.c		\
 			${RK_PLAT_COMMON}/aarch64/platform_common.c	\