Merge pull request #724 from rockchip-linux/support-rk3399-sdram

rockchip: optimize the link mechanism for SRAM code
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/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 d4c2b69..9693f57 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -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)