Merge pull request #746 from antonio-nino-diaz-arm/an/fix-checkpatch

Fix format of patches passed to checkpatch
diff --git a/.checkpatch.conf b/.checkpatch.conf
index c8a6084..0c84fcd 100644
--- a/.checkpatch.conf
+++ b/.checkpatch.conf
@@ -36,9 +36,6 @@
 # This is not Linux so don't expect a Linux tree!
 --no-tree
 
-# 'Signed-off-by' lines in commit messages are not mandated for TF.
---no-signoff
-
 # This clarifes the lines indications in the report.
 #
 # E.g.:
diff --git a/.gitignore b/.gitignore
index d2cff7c..c0d5183 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 cscope.*
 *.swp
 *.patch
+*~
 .project
 .cproject
 
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
index 743e65c..9a05e6c 100644
--- a/bl31/bl31.ld.S
+++ b/bl31/bl31.ld.S
@@ -39,6 +39,9 @@
     RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_LIMIT - BL31_BASE
 }
 
+#ifdef PLAT_EXTRA_LD_SCRIPT
+#include <plat.ld.S>
+#endif
 
 SECTIONS
 {
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index 8e913b9..aa014f1 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -501,6 +501,17 @@
     PLAT_PL061_MAX_GPIOS    :=      160
     $(eval $(call add_define,PLAT_PL061_MAX_GPIOS))
 
+If the platform port uses the partition driver, the following constant may
+optionally be defined:
+
+*   **PLAT_PARTITION_MAX_ENTRIES**
+    Maximum number of partition entries required by the platform. This allows
+    control how much memory is allocated for partition entries. The default
+    value is 128.
+    [For example, define the build flag in platform.mk]:
+    PLAT_PARTITION_MAX_ENTRIES	:=	12
+    $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
+
 
 ### File : plat_macros.S [mandatory]
 
@@ -547,7 +558,7 @@
     Argument : void
     Return   : uintptr_t
 
-This function is called with the called with the MMU and caches disabled
+This function is called with the MMU and caches disabled
 (`SCTLR_EL3.M` = 0 and `SCTLR_EL3.C` = 0). The function is responsible for
 distinguishing between a warm and cold reset for the current CPU using
 platform-specific means. If it's a warm reset, then it returns the warm
diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c
new file mode 100644
index 0000000..9240d5a
--- /dev/null
+++ b/drivers/partition/gpt.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <gpt.h>
+#include <string.h>
+
+static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out)
+{
+	uint8_t *name = (uint8_t *)str_in;
+	int i;
+
+	assert((str_in != NULL) && (str_out != NULL) && (name[0] != '\0'));
+
+	/* check whether the unicode string is valid */
+	for (i = 1; i < (EFI_NAMELEN << 1); i += 2) {
+		if (name[i] != '\0')
+			return -EINVAL;
+	}
+	/* convert the unicode string to ascii string */
+	for (i = 0; i < (EFI_NAMELEN << 1); i += 2) {
+		str_out[i >> 1] = name[i];
+		if (name[i] == '\0')
+			break;
+	}
+	return 0;
+}
+
+int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry)
+{
+	int result;
+
+	assert((gpt_entry != 0) && (entry != 0));
+
+	if ((gpt_entry->first_lba == 0) && (gpt_entry->last_lba == 0)) {
+		return -EINVAL;
+	}
+
+	memset(entry, 0, sizeof(partition_entry_t));
+	result = unicode_to_ascii(gpt_entry->name, (uint8_t *)entry->name);
+	if (result != 0) {
+		return result;
+	}
+	entry->start = (uint64_t)gpt_entry->first_lba * PARTITION_BLOCK_SIZE;
+	entry->length = (uint64_t)(gpt_entry->last_lba -
+				   gpt_entry->first_lba + 1) *
+			PARTITION_BLOCK_SIZE;
+	return 0;
+}
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
new file mode 100644
index 0000000..8bf6848
--- /dev/null
+++ b/drivers/partition/partition.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <io_storage.h>
+#include <gpt.h>
+#include <mbr.h>
+#include <partition.h>
+#include <platform.h>
+#include <string.h>
+
+static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
+partition_entry_list_t list;
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+static void dump_entries(int num)
+{
+	char name[EFI_NAMELEN];
+	int i, j, len;
+
+	VERBOSE("Partition table with %d entries:\n", num);
+	for (i = 0; i < num; i++) {
+		len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
+		for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
+			name[len + j] = ' ';
+		}
+		name[EFI_NAMELEN - 1] = '\0';
+		VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start,
+			list.list[i].start + list.list[i].length - 4);
+	}
+}
+#else
+#define dump_entries(num)	((void)num)
+#endif
+
+/*
+ * Load the first sector that carries MBR header.
+ * The MBR boot signature should be always valid whether it's MBR or GPT.
+ */
+static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
+{
+	size_t bytes_read;
+	uintptr_t offset;
+	int result;
+
+	assert(mbr_entry != NULL);
+	/* MBR partition table is in LBA0. */
+	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
+	if (result != 0) {
+		WARN("Failed to seek (%i)\n", result);
+		return result;
+	}
+	result = io_read(image_handle, (uintptr_t)&mbr_sector,
+			 PARTITION_BLOCK_SIZE, &bytes_read);
+	if (result != 0) {
+		WARN("Failed to read data (%i)\n", result);
+		return result;
+	}
+
+	/* Check MBR boot signature. */
+	if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
+	    (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+		return -ENOENT;
+	}
+	offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
+	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
+	return 0;
+}
+
+/*
+ * Load GPT header and check the GPT signature.
+ * If partiton numbers could be found, check & update it.
+ */
+static int load_gpt_header(uintptr_t image_handle)
+{
+	gpt_header_t header;
+	size_t bytes_read;
+	int result;
+
+	result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
+	if (result != 0) {
+		return result;
+	}
+	result = io_read(image_handle, (uintptr_t)&header,
+			 sizeof(gpt_header_t), &bytes_read);
+	if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
+		return result;
+	}
+	if (memcmp(header.signature, GPT_SIGNATURE,
+		   sizeof(header.signature)) != 0) {
+		return -EINVAL;
+	}
+
+	/* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
+	list.entry_count = header.list_num;
+	if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
+		list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
+	}
+	return 0;
+}
+
+static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
+{
+	size_t bytes_read;
+	int result;
+
+	assert(entry != NULL);
+	result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
+			 &bytes_read);
+	if (sizeof(gpt_entry_t) != bytes_read)
+		return -EINVAL;
+	return result;
+}
+
+static int verify_partition_gpt(uintptr_t image_handle)
+{
+	gpt_entry_t entry;
+	int result, i;
+
+	for (i = 0; i < list.entry_count; i++) {
+		result = load_gpt_entry(image_handle, &entry);
+		assert(result == 0);
+		result = parse_gpt_entry(&entry, &list.list[i]);
+		if (result != 0) {
+			break;
+		}
+	}
+	if (i == 0) {
+		return -EINVAL;
+	}
+	/*
+	 * Only records the valid partition number that is loaded from
+	 * partition table.
+	 */
+	list.entry_count = i;
+	dump_entries(list.entry_count);
+
+	return 0;
+}
+
+int load_partition_table(unsigned int image_id)
+{
+	uintptr_t dev_handle, image_handle, image_spec = 0;
+	mbr_entry_t mbr_entry;
+	int result;
+
+	result = plat_get_image_source(image_id, &dev_handle, &image_spec);
+	if (result != 0) {
+		WARN("Failed to obtain reference to image id=%u (%i)\n",
+			image_id, result);
+		return result;
+	}
+
+	result = io_open(dev_handle, image_spec, &image_handle);
+	if (result != 0) {
+		WARN("Failed to access image id=%u (%i)\n", image_id, result);
+		return result;
+	}
+
+	result = load_mbr_header(image_handle, &mbr_entry);
+	if (result != 0) {
+		WARN("Failed to access image id=%u (%i)\n", image_id, result);
+		return result;
+	}
+	if (mbr_entry.type == PARTITION_TYPE_GPT) {
+		result = load_gpt_header(image_handle);
+		assert(result == 0);
+		result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
+		assert(result == 0);
+		result = verify_partition_gpt(image_handle);
+	} else {
+		/* MBR type isn't supported yet. */
+		result = -EINVAL;
+		goto exit;
+	}
+exit:
+	io_close(image_handle);
+	return result;
+}
+
+const partition_entry_t *get_partition_entry(const char *name)
+{
+	int i;
+
+	for (i = 0; i < list.entry_count; i++) {
+		if (strcmp(name, list.list[i].name) == 0) {
+			return &list.list[i];
+		}
+	}
+	return NULL;
+}
+
+const partition_entry_list_t *get_partition_entry_list(void)
+{
+	return &list;
+}
+
+void partition_init(unsigned int image_id)
+{
+	load_partition_table(image_id);
+}
diff --git a/include/drivers/partition/gpt.h b/include/drivers/partition/gpt.h
new file mode 100644
index 0000000..bd0a7f0
--- /dev/null
+++ b/include/drivers/partition/gpt.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __GPT_H__
+#define __GPT_H__
+
+#include <partition.h>
+
+#define PARTITION_TYPE_GPT		0xee
+#define GPT_HEADER_OFFSET		PARTITION_BLOCK_SIZE
+#define GPT_ENTRY_OFFSET		(GPT_HEADER_OFFSET +		\
+					 PARTITION_BLOCK_SIZE)
+#define GUID_LEN			16
+
+#define GPT_SIGNATURE			"EFI PART"
+
+typedef struct gpt_entry {
+	unsigned char		type_uuid[GUID_LEN];
+	unsigned char		unique_uuid[GUID_LEN];
+	unsigned long long	first_lba;
+	unsigned long long	last_lba;
+	unsigned long long	attr;
+	unsigned short		name[EFI_NAMELEN];
+} gpt_entry_t;
+
+typedef struct gpt_header {
+	unsigned char		signature[8];
+	unsigned int		revision;
+	unsigned int		size;
+	unsigned int		header_crc;
+	unsigned int		reserved;
+	unsigned long long	current_lba;
+	unsigned long long	backup_lba;
+	unsigned long long	first_lba;
+	unsigned long long	last_lba;
+	unsigned char		disk_uuid[16];
+	/* starting LBA of array of partition entries */
+	unsigned long long	part_lba;
+	/* number of partition entries in array */
+	unsigned int		list_num;
+	/* size of a single partition entry (usually 128) */
+	unsigned int		part_size;
+	unsigned int		part_crc;
+} gpt_header_t;
+
+int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry);
+
+#endif	/* __GPT_H__ */
diff --git a/include/drivers/partition/mbr.h b/include/drivers/partition/mbr.h
new file mode 100644
index 0000000..5287e28
--- /dev/null
+++ b/include/drivers/partition/mbr.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __MBR_H__
+#define __MBR_H__
+
+#define MBR_OFFSET			0
+
+#define MBR_PRIMARY_ENTRY_OFFSET	0x1be
+#define MBR_PRIMARY_ENTRY_SIZE		0x10
+#define MBR_PRIMARY_ENTRY_NUMBER	4
+#define MBR_CHS_ADDRESS_LEN		3
+
+#define MBR_SIGNATURE_FIRST		0x55
+#define MBR_SIGNATURE_SECOND		0xAA
+
+typedef struct mbr_entry {
+	unsigned char		status;
+	unsigned char		first_sector[MBR_CHS_ADDRESS_LEN];
+	unsigned char		type;
+	unsigned char		last_sector[MBR_CHS_ADDRESS_LEN];
+	unsigned int		first_lba;
+	unsigned int		sector_nums;
+} mbr_entry_t;
+
+#endif	/* __MBR_H__ */
diff --git a/include/drivers/partition/partition.h b/include/drivers/partition/partition.h
new file mode 100644
index 0000000..9d7221d
--- /dev/null
+++ b/include/drivers/partition/partition.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __PARTITION_H__
+#define __PARTITION_H__
+
+#include <cassert.h>
+#include <types.h>
+
+#if !PLAT_PARTITION_MAX_ENTRIES
+# define PLAT_PARTITION_MAX_ENTRIES	128
+#endif	/* PLAT_PARTITION_MAX_ENTRIES */
+
+CASSERT(PLAT_PARTITION_MAX_ENTRIES <= 128, assert_plat_partition_max_entries);
+
+#define PARTITION_BLOCK_SIZE		512
+
+#define EFI_NAMELEN			36
+
+typedef struct partition_entry {
+	uint64_t		start;
+	uint64_t		length;
+	char			name[EFI_NAMELEN];
+} partition_entry_t;
+
+typedef struct partition_entry_list {
+	partition_entry_t	list[PLAT_PARTITION_MAX_ENTRIES];
+	int			entry_count;
+} partition_entry_list_t;
+
+int load_partition_table(unsigned int image_id);
+const partition_entry_t *get_partition_entry(const char *name);
+const partition_entry_list_t *get_partition_entry_list(void);
+void partition_init(unsigned int image_id);
+
+#endif	/* __PARTITION_H__ */
diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S
index a134ded..68bda22 100644
--- a/plat/common/aarch64/platform_helpers.S
+++ b/plat/common/aarch64/platform_helpers.S
@@ -98,7 +98,7 @@
 
 	/* -----------------------------------------------------
 	 * Placeholder function which should be redefined by
-	 * each platform. This function should preserve x10.
+	 * each platform. This function should preserve x19 - x29.
 	 * -----------------------------------------------------
 	 */
 func plat_reset_handler
diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S
index d06d4cb..a93b526 100644
--- a/plat/rockchip/common/aarch64/plat_helpers.S
+++ b/plat/rockchip/common/aarch64/plat_helpers.S
@@ -67,7 +67,7 @@
 	 * Set the L2 Data RAM latency for Cortex-A72.
 	 * Set the L2 Tag RAM latency to for Cortex-A72.
 	 */
-	mov x0, #((2 << L2CTLR_DATA_RAM_LATENCY_SHIFT) |	\
+	mov x0, #((5 << L2CTLR_DATA_RAM_LATENCY_SHIFT) |	\
 			 (0x1 << 5))
 	msr	L2CTLR_EL1, x0
 	isb
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
index 40cd29e..ff47016 100644
--- a/plat/rockchip/common/aarch64/platform_common.c
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -68,6 +68,7 @@
 				coh_limit - coh_start,			\
 				MT_DEVICE | MT_RW | MT_SECURE);		\
 		mmap_add(plat_rk_mmap);					\
+		rockchip_plat_sram_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 47a245a..b073bde 100644
--- a/plat/rockchip/common/bl31_plat_setup.c
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -115,10 +115,6 @@
 	bl32_ep_info = *from_bl2->bl32_ep_info;
 	bl33_ep_info = *from_bl2->bl33_ep_info;
 
-	/*
-	 * The code for resuming cpu from suspend must be excuted in pmusram.
-	 * Copy the code into pmusram.
-	 */
 	plat_rockchip_pmusram_prepare();
 
 	/* there may have some board sepcific message need to initialize */
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index ad01266..a093e79 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -37,6 +37,14 @@
 #include <xlat_tables.h>
 #include <psci.h>
 
+#define __sramdata __attribute__((section(".sram.data")))
+#define __sramconst __attribute__((section(".sram.rodata")))
+#define __sramfunc __attribute__((section(".sram.text")))	\
+			__attribute__((noinline))
+
+extern uint32_t __bl31_sram_text_start, __bl31_sram_text_end;
+extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end;
+
 /******************************************************************************
  * For rockchip socs pm ops
  ******************************************************************************/
@@ -135,6 +143,10 @@
 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);
+
 #endif /* __ASSEMBLY__ */
 
 /******************************************************************************
diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c
index d28100d..e926345 100644
--- a/plat/rockchip/common/plat_pm.c
+++ b/plat/rockchip/common/plat_pm.c
@@ -317,18 +317,6 @@
 	rockchip_ops->system_off();
 }
 
-static void
-__dead2 rockchip_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
-{
-	if ((RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) &&
-		(rockchip_ops)) {
-		if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE &&
-		    rockchip_ops->sys_pwr_down_wfi)
-			rockchip_ops->sys_pwr_down_wfi(target_state);
-	}
-	psci_power_down_wfi();
-}
-
 /*******************************************************************************
  * Export the platform handlers via plat_rockchip_psci_pm_ops. The rockchip
  * standard
@@ -341,7 +329,6 @@
 	.pwr_domain_suspend = rockchip_pwr_domain_suspend,
 	.pwr_domain_on_finish = rockchip_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = rockchip_pwr_domain_pwr_down_wfi,
 	.system_reset = rockchip_system_reset,
 	.system_off = rockchip_system_poweroff,
 	.validate_power_state = rockchip_validate_power_state,
diff --git a/plat/rockchip/common/pmusram/pmu_sram.c b/plat/rockchip/common/pmusram/pmu_sram.c
index bea4875..5c6a6e6 100644
--- a/plat/rockchip/common/pmusram/pmu_sram.c
+++ b/plat/rockchip/common/pmusram/pmu_sram.c
@@ -24,7 +24,10 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <console.h>
+#include <debug.h>
 #include <platform.h>
+#include <plat_private.h>
 
 /*****************************************************************************
  * sram only surpport 32-bits access
@@ -36,3 +39,33 @@
 	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);
+#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
index f290461..ec2d341 100644
--- a/plat/rockchip/common/pmusram/pmu_sram.h
+++ b/plat/rockchip/common/pmusram/pmu_sram.h
@@ -45,16 +45,6 @@
 
 #ifndef __ASSEMBLY__
 
-/*
- * The struct is used in pmu_cpus_on.S which
- * gets the data of the struct by the following index
- * #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_SYS_MODE	0x1c
- * #define PSRAM_DT_MPIDR	0x20
- */
 struct psram_data_t {
 	uint64_t sp;
 	uint64_t ddr_func;
@@ -76,6 +66,7 @@
 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/rk3399/drivers/m0/Makefile b/plat/rockchip/rk3399/drivers/m0/Makefile
new file mode 100644
index 0000000..8adc47e
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/Makefile
@@ -0,0 +1,156 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+#
+
+# Cross Compile
+M0_CROSS_COMPILE ?= arm-none-eabi-
+
+# Build architecture
+ARCH		:= cortex-m0
+
+# Build platform
+PLAT_M0		?= rk3399m0
+
+ifeq (${V},0)
+	Q=@
+	CHECKCODE_ARGS	+= --no-summary --terse
+else
+	Q=
+endif
+export Q
+
+# All PHONY definition
+.PHONY: all clean distclean ${ARCH}
+all: ${ARCH}
+
+.SUFFIXES:
+
+INCLUDES		+= -Iinclude/
+
+# NOTE: Add C source files here
+C_SOURCES		:= src/startup.c \
+			   src/main.c
+
+# Flags definition
+CFLAGS			:= -g
+ASFLAGS			:= -g -Wa,--gdwarf-2
+
+ASFLAGS			+= -mcpu=$(ARCH) -mthumb -Wall -ffunction-sections -O3
+CFLAGS			+= -mcpu=$(ARCH) -mthumb -Wall -ffunction-sections -O3
+
+LDFLAGS			:= -mcpu=$(ARCH) -mthumb -g -nostartfiles -O3
+LDFLAGS			+= -Wl,--gc-sections -Wl,--build-id=none
+
+# Cross tool
+CC			:= ${M0_CROSS_COMPILE}gcc
+CPP			:= ${M0_CROSS_COMPILE}cpp
+AS			:= ${M0_CROSS_COMPILE}gcc
+AR			:= ${M0_CROSS_COMPILE}ar
+LD			:= ${M0_CROSS_COMPILE}ld
+OC			:= ${M0_CROSS_COMPILE}objcopy
+OD			:= ${M0_CROSS_COMPILE}objdump
+NM			:= ${M0_CROSS_COMPILE}nm
+PP			:= ${M0_CROSS_COMPILE}gcc -E ${CFLAGS}
+
+# NOTE: The line continuation '\' is required in the next define otherwise we
+# end up with a line-feed characer at the end of the last c filename.
+# Also bare this issue in mind if extending the list of supported filetypes.
+define SOURCES_TO_OBJS
+	$(notdir $(patsubst %.c,%.o,$(filter %.c,$(1)))) \
+	$(notdir $(patsubst %.S,%.o,$(filter %.S,$(1))))
+endef
+
+BUILD_DIR		:= ${BUILD_PLAT}/obj
+BIN_DIR 		:= ${BUILD_PLAT}/bin
+SOURCES 		:= $(C_SOURCES)
+OBJS 			:= $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES)))
+LINKERFILE		:= src/rk3399m0.ld
+MAPFILE			:= $(BIN_DIR)/$(PLAT_M0).map
+ELF 			:= $(BIN_DIR)/$(PLAT_M0).elf
+BIN 			:= $(BIN_DIR)/$(PLAT_M0).bin
+
+# Function definition related compilation
+define MAKE_C
+$(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2))))
+
+$(OBJ) : $(2)
+	@echo "  CC      $$<"
+	$$(Q)$$(CC) $$(CFLAGS) $$(INCLUDES) -c $$< -o $$@
+endef
+
+define MAKE_S
+$(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2))))
+
+$(OBJ) : $(2)
+	@echo "  AS      $$<"
+	$$(Q)$$(AS) $$(ASFLAGS) -c $$< -o $$@
+endef
+
+define MAKE_OBJS
+	$(eval C_OBJS := $(filter %.c,$(2)))
+	$(eval REMAIN := $(filter-out %.c,$(2)))
+	$(eval $(foreach obj,$(C_OBJS),$(call MAKE_C,$(1),$(obj),$(3))))
+
+	$(eval S_OBJS := $(filter %.S,$(REMAIN)))
+	$(eval REMAIN := $(filter-out %.S,$(REMAIN)))
+	$(eval $(foreach obj,$(S_OBJS),$(call MAKE_S,$(1),$(obj),$(3))))
+
+	$(and $(REMAIN),$(error Unexpected source files present: $(REMAIN)))
+endef
+
+$(BIN_DIR) :
+	$(Q)mkdir -p "$@"
+
+$(BUILD_DIR) : $(BIN_DIR)
+	$(Q)mkdir -p "$@"
+
+$(ELF) : $(OBJS) $(LINKERFILE)
+	@echo "  LD      $@"
+	$(Q)$(CC) -o $@ $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) \
+		$(OBJS)
+
+$(BIN) : $(ELF)
+	@echo "  BIN     $@"
+	$(Q)$(OC) -O binary $< $@
+
+.PHONY : ${ARCH}
+${ARCH} : $(BUILD_DIR) $(BIN)
+
+$(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1)))
+
+# Other common compilation entries
+clean:
+	@echo "  CLEAN"
+	${Q}rm -rf ${BUILD_BASE}/${PLAT_M0}
+	${Q}rm -rf ${VER_BIN_DIR}/$(PLAT_M0)*
+
+distclean:
+	@echo "  DISTCLEAN"
+	${Q}rm -rf ${BUILD_BASE}/${PLAT_M0}
+	${Q}rm -rf ${VER_BIN_DIR}/$(PLAT_M0)*
diff --git a/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
new file mode 100644
index 0000000..7ea40fa
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __RK3399_MCU_H__
+#define __RK3399_MCU_H__
+
+#define readl(c)	({unsigned int __v =	\
+				(*(volatile unsigned int *)(c)); __v; })
+#define writel(v, c)	((*(volatile unsigned int *) (c)) = (v))
+
+#define MCU_BASE	0x40000000
+#define PMU_BASE	(MCU_BASE + 0x07310000)
+
+#endif /* __RK3399_MCU_H__ */
diff --git a/plat/rockchip/rk3399/drivers/m0/src/main.c b/plat/rockchip/rk3399/drivers/m0/src/main.c
new file mode 100644
index 0000000..2e583c7
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/main.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include "rk3399_mcu.h"
+
+#define PMU_PWRMODE_CON		0x20
+#define PMU_POWER_ST		0x78
+
+#define M0_SCR			0xe000ed10  /* System Control Register (SCR) */
+
+#define SCR_SLEEPDEEP_SHIFT	(1 << 2)
+
+static void system_wakeup(void)
+{
+	unsigned int status_value;
+	unsigned int mode_con;
+
+	while (1) {
+		status_value = readl(PMU_BASE + PMU_POWER_ST);
+		if (status_value) {
+			mode_con = readl(PMU_BASE + PMU_PWRMODE_CON);
+			writel(mode_con & (~0x01),
+			       PMU_BASE + PMU_PWRMODE_CON);
+			return;
+		}
+	}
+}
+
+int main(void)
+{
+	unsigned int reg_src;
+
+	system_wakeup();
+
+	reg_src = readl(M0_SCR);
+
+	/* m0 enter deep sleep mode */
+	writel(reg_src | SCR_SLEEPDEEP_SHIFT, M0_SCR);
+
+	for (;;)
+		__asm volatile("wfi");
+
+	return 0;
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld
new file mode 100644
index 0000000..0b7b124
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+OUTPUT_FORMAT("elf32-littlearm")
+
+SECTIONS {
+	.m0_bin 0 : {
+		KEEP(*(.isr_vector))
+		ASSERT(. == 0xc0, "ISR vector has the wrong size.");
+		*(.text*)
+		*(.rodata*)
+		*(.data*)
+		*(.bss*)
+		. = ALIGN(8);
+		*(.co_stack*)
+	}
+
+	/DISCARD/ : { *(.comment) *(.note*) }
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/startup.c b/plat/rockchip/rk3399/drivers/m0/src/startup.c
new file mode 100644
index 0000000..47561fd
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/startup.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include "rk3399_mcu.h"
+
+/* Stack configuration */
+#define STACK_SIZE	0x00000100
+__attribute__ ((section(".co_stack")))
+unsigned long pstack[STACK_SIZE];
+
+/* Macro definition */
+#define WEAK __attribute__ ((weak))
+
+/* System exception vector handler */
+__attribute__ ((used))
+void WEAK reset_handler(void);
+void WEAK nmi_handler(void);
+void WEAK hardware_fault_handler(void);
+void WEAK svc_handler(void);
+void WEAK pend_sv_handler(void);
+void WEAK systick_handler(void);
+
+extern int main(void);
+
+/* Function prototypes */
+static void default_reset_handler(void);
+static void default_handler(void);
+
+/*
+ * The minimal vector table for a Cortex M3.  Note that the proper constructs
+ * must be placed on this to ensure that it ends up at physical address
+ * 0x00000000.
+ */
+__attribute__ ((used, section(".isr_vector")))
+void (* const g_pfnVectors[])(void) = {
+	/* core Exceptions */
+	(void *)&pstack[STACK_SIZE], /* the initial stack pointer */
+	reset_handler,
+	nmi_handler,
+	hardware_fault_handler,
+	0, 0, 0, 0, 0, 0, 0,
+	svc_handler,
+	0, 0,
+	pend_sv_handler,
+	systick_handler,
+
+	/* external exceptions */
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0
+};
+
+/**
+ * This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ */
+static void default_reset_handler(void)
+{
+	/* call the application's entry point */
+	main();
+}
+
+/**
+ * Provide weak aliases for each Exception handler to the Default_Handler.
+ * As they are weak aliases, any function with the same name will override
+ * this definition.
+ */
+#pragma weak reset_handler = default_reset_handler
+#pragma weak nmi_handler = default_handler
+#pragma weak hardware_fault_handler = default_handler
+#pragma weak svc_handler = default_handler
+#pragma weak pend_sv_handler = default_handler
+#pragma weak systick_handler = default_handler
+
+/**
+ * This is the code that gets called when the processor receives
+ * an unexpected interrupt.  This simply enters an infinite loop,
+ * preserving the system state for examination by a debugger.
+ */
+static void default_handler(void)
+{
+    /* go into an infinite loop. */
+	while (1)
+		;
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 07a5b1e..8d3f482 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -48,6 +48,7 @@
 #include <pwm.h>
 #include <soc.h>
 #include <bl31.h>
+#include <rk3399m0.h>
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
@@ -436,7 +437,7 @@
 void plat_rockchip_pmusram_prepare(void)
 {
 	uint32_t *sram_dst, *sram_src;
-	size_t sram_size = 2;
+	size_t sram_size;
 
 	/*
 	 * pmu sram code and data prepare
@@ -840,8 +841,6 @@
 		       BIT(PMU_SCU_PD_EN) |
 		       BIT(PMU_CCI_PD_EN) |
 		       BIT(PMU_CLK_CORE_SRC_GATE_EN) |
-		       BIT(PMU_PERILP_PD_EN) |
-		       BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
 		       BIT(PMU_ALIVE_USE_LF) |
 		       BIT(PMU_SREF0_ENTER_EN) |
 		       BIT(PMU_SREF1_ENTER_EN) |
@@ -1058,6 +1057,38 @@
 	}
 }
 
+static void m0_clock_init(void)
+{
+	/* enable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0x0, 0x2f, 0));
+
+	/* switch the parent to xin24M and div == 1 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKSEL_CON0,
+		      BIT_WITH_WMSK(15) | BITS_WITH_WMASK(0x0, 0x1f, 8));
+
+	/* start M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x0, 0x24, 0));
+
+	/* gating disable for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, BIT_WITH_WMSK(1));
+}
+
+static void m0_reset(void)
+{
+	/* stop M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x24, 0x24, 0));
+
+	/* recover gating bit for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, WMSK_BIT(1));
+
+	/* disable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0x2f, 0x2f, 0));
+}
+
 static int sys_pwr_domain_suspend(void)
 {
 	uint32_t wait_cnt = 0;
@@ -1071,12 +1102,12 @@
 		    BIT(PMU_CLR_CCIM0) |
 		    BIT(PMU_CLR_CCIM1) |
 		    BIT(PMU_CLR_CENTER) |
-		    BIT(PMU_CLR_PERILP) |
-		    BIT(PMU_CLR_PMU) |
-		    BIT(PMU_CLR_PERILPM0) |
 		    BIT(PMU_CLR_GIC));
 
 	sys_slp_config();
+
+	m0_clock_init();
+
 	pmu_sgrf_rst_hld();
 
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
@@ -1111,6 +1142,7 @@
 	disable_dvfs_plls();
 	disable_pwms();
 	disable_nodvfs_plls();
+
 	suspend_apio();
 	suspend_gpio();
 
@@ -1186,12 +1218,12 @@
 				BIT(PMU_CLR_CCIM0) |
 				BIT(PMU_CLR_CCIM1) |
 				BIT(PMU_CLR_CENTER) |
-				BIT(PMU_CLR_PERILP) |
-				BIT(PMU_CLR_PMU) |
 				BIT(PMU_CLR_GIC));
 
 	plat_rockchip_gic_cpuif_enable();
 
+	m0_reset();
+
 	return 0;
 }
 
@@ -1236,42 +1268,6 @@
 	while (1)
 		;
 }
-static void __dead2 sys_pwr_down_wfi(const psci_power_state_t *target_state)
-{
-	uint32_t wakeup_status;
-
-	/*
-	 * Check wakeup status and abort suspend early if we see a wakeup
-	 * event.
-	 *
-	 * NOTE: technically I we're supposed to just execute a wfi here and
-	 * we'll either execute a normal suspend/resume or the wfi will be
-	 * treated as a no-op if a wake event was present and caused an abort
-	 * of the suspend/resume.  For some reason that's not happening and if
-	 * we execute the wfi while a wake event is pending then the whole
-	 * system wedges.
-	 *
-	 * Until the above is solved this extra check prevents system wedges in
-	 * most cases but there is still a small race condition between checking
-	 * PMU_WAKEUP_STATUS and executing wfi.  If a wake event happens in
-	 * there then we will die.
-	 */
-	wakeup_status = mmio_read_32(PMU_BASE + PMU_WAKEUP_STATUS);
-	if (wakeup_status) {
-		WARN("early wake, will not enter power mode.\n");
-
-		mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, 0);
-
-		disable_mmu_icache_el3();
-		bl31_warm_entrypoint();
-
-		while (1)
-			;
-	} else {
-		/* Enter WFI */
-		psci_power_down_wfi();
-	}
-}
 
 static struct rockchip_pm_ops_cb pm_ops = {
 	.cores_pwr_dm_on = cores_pwr_domain_on,
@@ -1287,7 +1283,6 @@
 	.sys_pwr_dm_resume = sys_pwr_domain_resume,
 	.sys_gbl_soft_reset = soc_soft_reset,
 	.system_off = soc_system_off,
-	.sys_pwr_down_wfi = sys_pwr_down_wfi,
 };
 
 void plat_rockchip_pmu_init(void)
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
new file mode 100644
index 0000000..01f08e6
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+/* convoluted way to make sure that the define is pasted just the right way */
+#define _INCBIN(file, sym) \
+	__asm__( \
+		".section .sram.incbin\n" \
+		".global " #sym "\n" \
+		".type " #sym ", %object\n" \
+		".align 4\n" \
+		#sym ":\n" \
+		".incbin \"" #file "\"\n" \
+		".size " #sym ", .-" #sym "\n" \
+		".global " #sym "_end\n" \
+		#sym "_end:\n" \
+	)
+
+#define INCBIN(file, sym) _INCBIN(file, sym)
+
+INCBIN(RK3399M0FW, rk3399m0_bin);
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
new file mode 100644
index 0000000..78b350a
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __RK3399M0_H__
+#define __RK3399M0_H__
+
+/* pmu_fw.c */
+extern char rk3399m0_bin[];
+extern char rk3399m0_bin_end[];
+
+#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
+
+#endif /* __RK3399M0_H__ */
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
index 6af7a2e..e99db19 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.c
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -35,6 +35,7 @@
 #include <platform_def.h>
 #include <plat_private.h>
 #include <rk3399_def.h>
+#include <rk3399m0.h>
 #include <soc.h>
 
 /* Table of regions to map using the MMU.  */
@@ -387,6 +388,20 @@
 		;
 }
 
+static void soc_m0_init(void)
+{
+	/* secure config for pmu M0 */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(0), WMSK_BIT(7));
+
+	/* set the execute address for M0 */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(3),
+		      BITS_WITH_WMASK((M0_BINCODE_BASE >> 12) & 0xffff,
+				      0xffff, 0));
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(7),
+		      BITS_WITH_WMASK((M0_BINCODE_BASE >> 28) & 0xf,
+				      0xf, 0));
+}
+
 void plat_rockchip_soc_init(void)
 {
 	secure_timer_init();
@@ -394,4 +409,5 @@
 	sgrf_init();
 	soc_global_soft_reset_init();
 	plat_rockchip_gpio_init();
+	soc_m0_init();
 }
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
index d99b380..9693f57 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -64,7 +64,7 @@
 #define PLL_NO_BYPASS_MODE		WMSK_BIT(PLL_BYPASS_SHIFT)
 
 #define PLL_CON_COUNT			0x06
-#define CRU_CLKSEL_COUNT		0x108
+#define CRU_CLKSEL_COUNT		108
 #define CRU_CLKSEL_CON(n)		(0x100 + (n) * 4)
 
 #define PMUCRU_CLKSEL_CONUT		0x06
@@ -293,6 +293,18 @@
 #define GRF_DDRC1_CON0		0xe388
 #define GRF_DDRC1_CON1		0xe38c
 
+#define PMUCRU_CLKSEL_CON0	0x0080
+#define PMUCRU_CLKGATE_CON2	0x0108
+#define PMUCRU_SOFTRST_CON0	0x0110
+#define PMUCRU_GATEDIS_CON0 0x0130
+
+#define SGRF_SOC_CON6     0x0e018
+#define SGRF_PERILP_CON0	0x08100
+#define SGRF_PERILP_CON(n)	(SGRF_PERILP_CON0 + (n) * 4)
+#define SGRF_PMU_CON0	0x0c100
+#define SGRF_PMU_CON(n)   (SGRF_PMU_CON0 + (n) * 4)
+#define PMUCRU_SOFTRST_CON(n)   (PMUCRU_SOFTRST_CON0 + (n) * 4)
+
 /*
  * When system reset in running state, we want the cpus to be reboot
  * from maskrom (system reboot),
diff --git a/plat/rockchip/rk3399/include/plat.ld.S b/plat/rockchip/rk3399/include/plat.ld.S
new file mode 100644
index 0000000..1614fba
--- /dev/null
+++ b/plat/rockchip/rk3399/include/plat.ld.S
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of ARM 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+#ifndef __ROCKCHIP_PLAT_LD_S__
+#define __ROCKCHIP_PLAT_LD_S__
+
+MEMORY {
+    SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE
+}
+
+SECTIONS
+{
+	. = SRAM_BASE;
+	ASSERT(. == ALIGN(4096),
+		"SRAM_BASE address is not aligned on a page boundary.")
+
+	/*
+	 * The SRAM space allocation for RK3399
+	 * ----------------
+	 * | m0 code bin
+	 * ----------------
+	 * | sram text
+	 * ----------------
+	 * | sram data
+	 * ----------------
+	 */
+	.incbin_sram : ALIGN(4096) {
+		__sram_incbin_start = .;
+		*(.sram.incbin)
+		. = ALIGN(4096);
+		__sram_incbin_end = .;
+	} >SRAM
+
+	.text_sram : ALIGN(4096) {
+		__bl31_sram_text_start = .;
+		*(.sram.text)
+		*(.sram.rodata)
+		. = ALIGN(4096);
+		__bl31_sram_text_end = .;
+	} >SRAM
+
+	.data_sram : ALIGN(4096) {
+		__bl31_sram_data_start = .;
+		*(.sram.data)
+		. = ALIGN(4096);
+		__bl31_sram_data_end = .;
+	} >SRAM
+}
+
+#endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 3627857..604de9c 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -76,9 +76,28 @@
 				${RK_PLAT_SOC}/plat_sip_calls.c			\
 				${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c	\
                                 ${RK_PLAT_SOC}/drivers/pmu/pmu.c                \
+                                ${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c             \
 				${RK_PLAT_SOC}/drivers/pwm/pwm.c	\
                                 ${RK_PLAT_SOC}/drivers/soc/soc.c		\
 				${RK_PLAT_SOC}/drivers/dram/dram.c		\
 				${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c
 
 ENABLE_PLAT_COMPAT      :=      0
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+# M0 source build
+PLAT_M0                 :=      ${PLAT}m0
+
+RK3399M0FW=${BUILD_PLAT}/m0/bin/${PLAT_M0}.bin
+$(eval $(call add_define,RK3399M0FW))
+
+# CCACHE_EXTRAFILES is needed because ccache doesn't handle .incbin
+export CCACHE_EXTRAFILES
+${BUILD_PLAT}/bl31/pmu_fw.o: CCACHE_EXTRAFILES=$(RK3399M0FW)
+${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c: $(RK3399M0FW)
+
+.PHONY: $(RK3399M0FW)
+$(RK3399M0FW):
+	$(MAKE) -C ${RK_PLAT_SOC}/drivers/m0 \
+		BUILD_PLAT=$(abspath ${BUILD_PLAT}/m0)
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index b3f02f6..0084edf 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -187,7 +187,7 @@
 	}
 }
 
-static toc_entry_t *get_entry_lookup_from_uuid(const uuid_t *uuid)
+static toc_entry_t *lookup_entry_from_uuid(uuid_t *uuid)
 {
 	toc_entry_t *toc_entry = toc_entries;
 
@@ -197,6 +197,19 @@
 	return NULL;
 }
 
+static image_t *lookup_image_from_uuid(uuid_t *uuid)
+{
+	image_t *image;
+	int i;
+
+	for (i = 0; i < nr_images; i++) {
+		image = images[i];
+		if (memcmp(&image->uuid, uuid, sizeof(uuid_t)) == 0)
+			return image;
+	}
+	return NULL;
+}
+
 static int parse_fip(char *filename, fip_toc_header_t *toc_header_out)
 {
 	struct stat st;
@@ -268,16 +281,6 @@
 		    toc_entry->size);
 		image->size = toc_entry->size;
 
-		image->toc_entry = get_entry_lookup_from_uuid(&toc_entry->uuid);
-		if (image->toc_entry == NULL) {
-			add_image(image);
-			toc_entry++;
-			continue;
-		}
-
-		assert(image->toc_entry->image == NULL);
-		/* Link backpointer from lookup entry. */
-		image->toc_entry->image = image;
 		add_image(image);
 
 		toc_entry++;
@@ -290,12 +293,14 @@
 	return 0;
 }
 
-static image_t *read_image_from_file(toc_entry_t *toc_entry, char *filename)
+static image_t *read_image_from_file(uuid_t *uuid, char *filename)
 {
 	struct stat st;
 	image_t *image;
 	FILE *fp;
 
+	assert(uuid != NULL);
+
 	fp = fopen(filename, "r");
 	if (fp == NULL)
 		log_err("fopen %s", filename);
@@ -307,7 +312,7 @@
 	if (image == NULL)
 		log_err("malloc");
 
-	memcpy(&image->uuid, &toc_entry->uuid, sizeof(uuid_t));
+	memcpy(&image->uuid, uuid, sizeof(uuid_t));
 
 	image->buffer = malloc(st.st_size);
 	if (image->buffer == NULL)
@@ -315,7 +320,6 @@
 	if (fread(image->buffer, 1, st.st_size, fp) != st.st_size)
 		log_errx("Failed to read %s", filename);
 	image->size = st.st_size;
-	image->toc_entry = toc_entry;
 
 	fclose(fp);
 	return image;
@@ -391,18 +395,21 @@
 	    (sizeof(fip_toc_entry_t) * (nr_images + 1));
 
 	for (i = 0; i < nr_images; i++) {
+		toc_entry_t *toc_entry;
+
 		image = images[i];
-		if (image->toc_entry != NULL)
-			printf("%s: ", image->toc_entry->name);
+		toc_entry = lookup_entry_from_uuid(&image->uuid);
+		if (toc_entry != NULL)
+			printf("%s: ", toc_entry->name);
 		else
 			printf("Unknown entry: ");
 		image_size = image->size;
 		printf("offset=0x%llX, size=0x%llX",
 		    (unsigned long long)image_offset,
 		    (unsigned long long)image_size);
-		if (image->toc_entry != NULL)
+		if (toc_entry != NULL)
 			printf(", cmdline=\"--%s\"",
-			    image->toc_entry->cmdline_name);
+			    toc_entry->cmdline_name);
 		if (verbose) {
 			unsigned char md[SHA256_DIGEST_LENGTH];
 
@@ -505,7 +512,7 @@
 static void update_fip(void)
 {
 	toc_entry_t *toc_entry;
-	image_t *image;
+	image_t *new_image, *old_image;
 
 	/* Add or replace images in the FIP file. */
 	for (toc_entry = toc_entries;
@@ -514,21 +521,21 @@
 		if (toc_entry->action != DO_PACK)
 			continue;
 
-		image = read_image_from_file(toc_entry, toc_entry->action_arg);
-		if (toc_entry->image != NULL) {
+		new_image = read_image_from_file(&toc_entry->uuid,
+		    toc_entry->action_arg);
+		old_image = lookup_image_from_uuid(&toc_entry->uuid);
+		if (old_image != NULL) {
 			if (verbose)
 				log_dbgx("Replacing image %s.bin with %s",
 				    toc_entry->cmdline_name,
 				    toc_entry->action_arg);
-			replace_image(toc_entry->image, image);
+			replace_image(old_image, new_image);
 		} else {
 			if (verbose)
 				log_dbgx("Adding image %s",
 				    toc_entry->action_arg);
-			add_image(image);
+			add_image(new_image);
 		}
-		/* Link backpointer from lookup entry. */
-		toc_entry->image = image;
 
 		free(toc_entry->action_arg);
 		toc_entry->action_arg = NULL;
@@ -758,23 +765,13 @@
 		if (chdir(outdir) == -1)
 			log_err("chdir %s", outdir);
 
-	/* Mark all images to be unpacked. */
-	if (unpack_all) {
-		for (toc_entry = toc_entries;
-		     toc_entry->cmdline_name != NULL;
-		     toc_entry++) {
-			if (toc_entry->image != NULL) {
-				toc_entry->action = DO_UNPACK;
-				toc_entry->action_arg = NULL;
-			}
-		}
-	}
-
 	/* Unpack all specified images. */
 	for (toc_entry = toc_entries;
 	     toc_entry->cmdline_name != NULL;
 	     toc_entry++) {
-		if (toc_entry->action != DO_UNPACK)
+		image_t *image;
+
+		if (!unpack_all && toc_entry->action != DO_UNPACK)
 			continue;
 
 		/* Build filename. */
@@ -785,9 +782,11 @@
 			snprintf(file, sizeof(file), "%s",
 			    toc_entry->action_arg);
 
-		if (toc_entry->image == NULL) {
-			log_warnx("Requested image %s is not in %s",
-			    file, argv[0]);
+		image = lookup_image_from_uuid(&toc_entry->uuid);
+		if (image == NULL) {
+			if (!unpack_all)
+				log_warnx("Requested image %s is not in %s",
+				    file, argv[0]);
 			free(toc_entry->action_arg);
 			toc_entry->action_arg = NULL;
 			continue;
@@ -796,7 +795,7 @@
 		if (access(file, F_OK) != 0 || fflag) {
 			if (verbose)
 				log_dbgx("Unpacking %s", file);
-			write_image_to_file(toc_entry->image, file);
+			write_image_to_file(image, file);
 		} else {
 			log_warnx("File %s already exists, use --force to overwrite it",
 			    file);
@@ -885,13 +884,16 @@
 	for (toc_entry = toc_entries;
 	     toc_entry->cmdline_name != NULL;
 	     toc_entry++) {
+		image_t *image;
+
 		if (toc_entry->action != DO_REMOVE)
 			continue;
-		if (toc_entry->image != NULL) {
+		image = lookup_image_from_uuid(&toc_entry->uuid);
+		if (image != NULL) {
 			if (verbose)
 				log_dbgx("Removing %s.bin",
 				    toc_entry->cmdline_name);
-			remove_image(toc_entry->image);
+			remove_image(image);
 		} else {
 			log_warnx("Requested image %s.bin is not in %s",
 			    toc_entry->cmdline_name, argv[0]);
@@ -983,6 +985,8 @@
 	    strcmp(argv[0], "--verbose") == 0) {
 		verbose = 1;
 		argc--, argv++;
+		if (argc < 1)
+			usage();
 	}
 
 	for (i = 0; i < NELEM(cmds); i++) {
diff --git a/tools/fiptool/fiptool.h b/tools/fiptool/fiptool.h
index 0fe64c0..7705107 100644
--- a/tools/fiptool/fiptool.h
+++ b/tools/fiptool/fiptool.h
@@ -57,7 +57,6 @@
 	uuid_t            uuid;
 	size_t            size;
 	void             *buffer;
-	struct toc_entry *toc_entry;
 } image_t;
 
 typedef struct cmd {
diff --git a/tools/fiptool/tbbr_config.c b/tools/fiptool/tbbr_config.c
index e8fbbba..b92e8da 100644
--- a/tools/fiptool/tbbr_config.c
+++ b/tools/fiptool/tbbr_config.c
@@ -35,49 +35,155 @@
 
 /* The images used depends on the platform. */
 toc_entry_t toc_entries[] = {
-	{ "SCP Firmware Updater Configuration FWU SCP_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
-	  "scp-fwu-cfg", NULL, 0, NULL },
-	{ "AP Firmware Updater Configuration BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
-	  "ap-fwu-cfg", NULL, 0, NULL },
-	{ "Firmware Updater NS_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
-	  "fwu", NULL, 0, NULL },
-	{ "Non-Trusted Firmware Updater certificate", UUID_TRUSTED_FWU_CERT,
-	  "fwu-cert", NULL, 0, NULL },
-	{ "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2,
-	  "tb-fw", NULL, 0, NULL },
-	{ "SCP Firmware SCP_BL2", UUID_SCP_FIRMWARE_SCP_BL2,
-	  "scp-fw", NULL, 0, NULL },
-	{ "EL3 Runtime Firmware BL31", UUID_EL3_RUNTIME_FIRMWARE_BL31,
-	  "soc-fw", NULL, 0, NULL },
-	{ "Secure Payload BL32 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32,
-	  "tos-fw", NULL, 0, NULL },
-	{ "Non-Trusted Firmware BL33", UUID_NON_TRUSTED_FIRMWARE_BL33,
-	  "nt-fw", NULL, 0, NULL },
+	{
+		.name = "SCP Firmware Updater Configuration FWU SCP_BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
+		.cmdline_name = "scp-fwu-cfg",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "AP Firmware Updater Configuration BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
+		.cmdline_name = "ap-fwu-cfg",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Firmware Updater NS_BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
+		.cmdline_name = "fwu",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Non-Trusted Firmware Updater certificate",
+		.uuid = UUID_TRUSTED_FWU_CERT,
+		.cmdline_name = "fwu-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Trusted Boot Firmware BL2",
+		.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+		.cmdline_name = "tb-fw",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "SCP Firmware SCP_BL2",
+		.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+		.cmdline_name = "scp-fw",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "EL3 Runtime Firmware BL31",
+		.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+		.cmdline_name = "soc-fw",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Secure Payload BL32 (Trusted OS)",
+		.uuid = UUID_SECURE_PAYLOAD_BL32,
+		.cmdline_name = "tos-fw",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Non-Trusted Firmware BL33",
+		.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+		.cmdline_name = "nt-fw",
+		.action = 0,
+		.action_arg = NULL
+	},
 	/* Key Certificates */
-	{ "Root Of Trust key certificate", UUID_ROT_KEY_CERT,
-	  "rot-cert", NULL, 0, NULL },
-	{ "Trusted key certificate", UUID_TRUSTED_KEY_CERT,
-	  "trusted-key-cert", NULL, 0, NULL },
-	{ "SCP Firmware key certificate", UUID_SCP_FW_KEY_CERT,
-	  "scp-fw-key-cert", NULL, 0, NULL },
-	{ "SoC Firmware key certificate", UUID_SOC_FW_KEY_CERT,
-	  "soc-fw-key-cert", NULL, 0, NULL },
-	{ "Trusted OS Firmware key certificate", UUID_TRUSTED_OS_FW_KEY_CERT,
-	  "tos-fw-key-cert", NULL, 0, NULL },
-	{ "Non-Trusted Firmware key certificate", UUID_NON_TRUSTED_FW_KEY_CERT,
-	  "nt-fw-key-cert", NULL, 0, NULL },
+	{
+		.name = "Root Of Trust key certificate",
+		.uuid = UUID_ROT_KEY_CERT,
+		.cmdline_name = "rot-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Trusted key certificate",
+		.uuid = UUID_TRUSTED_KEY_CERT,
+		.cmdline_name = "trusted-key-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "SCP Firmware key certificate",
+		.uuid = UUID_SCP_FW_KEY_CERT,
+		.cmdline_name = "scp-fw-key-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "SoC Firmware key certificate",
+		.uuid = UUID_SOC_FW_KEY_CERT,
+		.cmdline_name = "soc-fw-key-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Trusted OS Firmware key certificate",
+		.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+		.cmdline_name = "tos-fw-key-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Non-Trusted Firmware key certificate",
+		.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+		.cmdline_name = "nt-fw-key-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
 	/* Content certificates */
-	{ "Trusted Boot Firmware BL2 certificate", UUID_TRUSTED_BOOT_FW_CERT,
-	  "tb-fw-cert", NULL, 0, NULL },
-	{ "SCP Firmware content certificate", UUID_SCP_FW_CONTENT_CERT,
-	  "scp-fw-cert", NULL, 0, NULL },
-	{ "SoC Firmware content certificate", UUID_SOC_FW_CONTENT_CERT,
-	  "soc-fw-cert", NULL, 0, NULL },
-	{ "Trusted OS Firmware content certificate", UUID_TRUSTED_OS_FW_CONTENT_CERT,
-	  "tos-fw-cert", NULL, 0, NULL },
-	{ "Non-Trusted Firmware content certificate", UUID_NON_TRUSTED_FW_CONTENT_CERT,
-	  "nt-fw-cert", NULL, 0, NULL },
-	{ NULL, { 0 }, NULL, NULL, 0, NULL }
+	{
+		.name = "Trusted Boot Firmware BL2 certificate",
+		.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+		.cmdline_name = "tb-fw-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "SCP Firmware content certificate",
+		.uuid = UUID_SCP_FW_CONTENT_CERT,
+		.cmdline_name = "scp-fw-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "SoC Firmware content certificate",
+		.uuid = UUID_SOC_FW_CONTENT_CERT,
+		.cmdline_name = "soc-fw-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Trusted OS Firmware content certificate",
+		.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+		.cmdline_name = "tos-fw-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = "Non-Trusted Firmware content certificate",
+		.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+		.cmdline_name = "nt-fw-cert",
+		.action = 0,
+		.action_arg = NULL
+	},
+	{
+		.name = NULL,
+		.uuid = { 0 },
+		.cmdline_name = NULL,
+		.action = 0,
+		.action_arg = NULL
+	}
 };
 
 size_t toc_entries_len = sizeof(toc_entries) / sizeof(toc_entries[0]);
diff --git a/tools/fiptool/tbbr_config.h b/tools/fiptool/tbbr_config.h
index d771a9b..c459335 100644
--- a/tools/fiptool/tbbr_config.h
+++ b/tools/fiptool/tbbr_config.h
@@ -42,7 +42,6 @@
 	const char   *name;
 	uuid_t        uuid;
 	const char   *cmdline_name;
-	struct image *image;
 	int           action;
 	char         *action_arg;
 } toc_entry_t;