Merge pull request #1369 from sivadur/xilinxdiff

Xilinx platform mangement related changes
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
index e25e501..bbe73fb 100644
--- a/drivers/arm/gic/v2/gicv2_main.c
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -178,9 +178,6 @@
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 
-		/* The platform should provide a list of secure interrupts */
-		assert(plat_driver_data->g0_interrupt_array);
-
 		/*
 		 * If there are no interrupts of a particular type, then the
 		 * number of interrupts of that type should be 0 and vice-versa.
@@ -195,8 +192,8 @@
 		WARN("Please migrate to using an interrupt_prop_t array\n");
 	}
 #else
-	assert(plat_driver_data->interrupt_props != NULL);
-	assert(plat_driver_data->interrupt_props_num > 0);
+	assert(plat_driver_data->interrupt_props_num > 0 ?
+			plat_driver_data->interrupt_props != NULL : 1);
 #endif
 
 	/* Ensure that this is a GICv2 system */
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
index 69c6951..020ec1b 100644
--- a/drivers/arm/gic/v3/gicv3_helpers.c
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -433,8 +433,7 @@
 	unsigned int ctlr_enable = 0;
 
 	/* Make sure there's a valid property array */
-	assert(interrupt_props != NULL);
-	assert(interrupt_props_num > 0);
+	assert(interrupt_props_num > 0 ? interrupt_props != NULL : 1);
 
 	for (i = 0; i < interrupt_props_num; i++) {
 		current_prop = &interrupt_props[i];
@@ -556,8 +555,7 @@
 	unsigned int ctlr_enable = 0;
 
 	/* Make sure there's a valid property array */
-	assert(interrupt_props != NULL);
-	assert(interrupt_props_num > 0);
+	assert(interrupt_props_num > 0 ? interrupt_props != NULL : 1);
 
 	for (i = 0; i < interrupt_props_num; i++) {
 		current_prop = &interrupt_props[i];
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index d8fc7d6..82f43d0 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -103,8 +103,8 @@
 		WARN("Please migrate to using interrupt_prop_t arrays\n");
 	}
 #else
-	assert(plat_driver_data->interrupt_props != NULL);
-	assert(plat_driver_data->interrupt_props_num > 0);
+	assert(plat_driver_data->interrupt_props_num > 0 ?
+	       plat_driver_data->interrupt_props != NULL : 1);
 #endif
 
 	/* Check for system register support */
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.c b/plat/rockchip/rk3399/drivers/dram/dfs.c
index 70d9423..e6d39a1 100644
--- a/plat/rockchip/rk3399/drivers/dram/dfs.c
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.c
@@ -1964,9 +1964,6 @@
 
 static void m0_configure_ddr(struct pll_div pll_div, uint32_t ddr_index)
 {
-	/* set PARAM to M0_FUNC_DRAM */
-	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_FUNC, M0_FUNC_DRAM);
-
 	mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(pll_div.fbdiv));
 	mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON1,
 		      POSTDIV2(pll_div.postdiv2) | POSTDIV1(pll_div.postdiv1) |
@@ -1976,6 +1973,7 @@
 
 	mmio_write_32(M0_PARAM_ADDR + PARAM_FREQ_SELECT, ddr_index << 4);
 	dmbst();
+	m0_configure_execute_addr(M0_BINCODE_BASE);
 }
 
 static uint32_t prepare_ddr_timing(uint32_t mhz)
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.c b/plat/rockchip/rk3399/drivers/dram/suspend.c
index 2a80bcb..dd97581 100644
--- a/plat/rockchip/rk3399/drivers/dram/suspend.c
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.c
@@ -9,6 +9,8 @@
 #include <dram.h>
 #include <plat_private.h>
 #include <platform_def.h>
+#include <pmu.h>
+#include <pmu_bits.h>
 #include <pmu_regs.h>
 #include <rk3399_def.h>
 #include <secure.h>
@@ -656,6 +658,30 @@
 		;
 }
 
+__pmusramfunc static void pmusram_enable_watchdog(void)
+{
+	/* Make the watchdog use the first global reset. */
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, 1 << 1);
+
+	/*
+	 * This gives the system ~8 seconds before reset. The pclk for the
+	 * watchdog is 4MHz on reset. The value of 0x9 in WDT_TORR means that
+	 * the watchdog will wait for 0x1ffffff cycles before resetting.
+	 */
+	mmio_write_32(WDT0_BASE + 4, 0x9);
+
+	/* Enable the watchdog */
+	mmio_setbits_32(WDT0_BASE, 0x1);
+
+	/* Magic reset the watchdog timer value for WDT_CRR. */
+	mmio_write_32(WDT0_BASE + 0xc, 0x76);
+
+	secure_watchdog_ungate();
+
+	/* The watchdog is in PD_ALIVE, so deidle it. */
+	mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, PMU_CLR_ALIVE);
+}
+
 void dmc_suspend(void)
 {
 	struct rk3399_sdram_params *sdram_params = &sdram_config;
@@ -726,6 +752,9 @@
 	uint32_t channel_mask = 0;
 	uint32_t channel;
 
+	pmusram_enable_watchdog();
+	pmu_sgrf_rst_hld_release();
+	restore_pmu_rsthold();
 	sram_secure_timer_init();
 
 	/*
diff --git a/plat/rockchip/rk3399/drivers/m0/Makefile b/plat/rockchip/rk3399/drivers/m0/Makefile
index f6bdbf2..79e09f0 100644
--- a/plat/rockchip/rk3399/drivers/m0/Makefile
+++ b/plat/rockchip/rk3399/drivers/m0/Makefile
@@ -12,6 +12,7 @@
 
 # Build platform
 PLAT_M0		?= rk3399m0
+PLAT_M0_PMU	?= rk3399m0pmu
 
 ifeq (${V},0)
 	Q=@
@@ -26,11 +27,10 @@
 			   -I../../include/shared/
 
 # NOTE: Add C source files here
-C_SOURCES		:= src/startup.c \
-			   src/main.c	\
-			   src/suspend.c \
-			   src/dram.c	\
+C_SOURCES_COMMON	:= src/startup.c
+C_SOURCES		:= src/dram.c	\
 			   src/stopwatch.c
+C_SOURCES_PMU		:= src/suspend.c
 
 # Flags definition
 COMMON_FLAGS		:= -g -mcpu=$(ARCH) -mthumb -Wall -O3 -nostdlib -mfloat-abi=soft
@@ -54,12 +54,19 @@
 	$(notdir $(patsubst %.S,%.o,$(filter %.S,$(1))))
 endef
 
+SOURCES_COMMON		:= $(C_SOURCES_COMMON)
 SOURCES 		:= $(C_SOURCES)
+SOURCES_PMU		:= $(C_SOURCES_PMU)
+OBJS_COMMON		:= $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES_COMMON)))
 OBJS 			:= $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES)))
+OBJS_PMU 		:= $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES_PMU)))
 LINKERFILE		:= $(BUILD)/$(PLAT_M0).ld
 MAPFILE			:= $(BUILD)/$(PLAT_M0).map
+MAPFILE_PMU		:= $(BUILD)/$(PLAT_M0_PMU).map
 ELF 			:= $(BUILD)/$(PLAT_M0).elf
+ELF_PMU			:= $(BUILD)/$(PLAT_M0_PMU).elf
 BIN 			:= $(BUILD)/$(PLAT_M0).bin
+BIN_PMU			:= $(BUILD)/$(PLAT_M0_PMU).bin
 LINKERFILE_SRC		:= src/$(PLAT_M0).ld.S
 
 # Function definition related compilation
@@ -92,18 +99,27 @@
 	$(and $(REMAIN),$(error Unexpected source files present: $(REMAIN)))
 endef
 
-.DEFAULT_GOAL := $(BIN)
+.PHONY: all
+all: $(BIN) $(BIN_PMU)
+
+.DEFAULT_GOAL := all
 
 $(LINKERFILE): $(LINKERFILE_SRC)
 	$(CC) $(COMMON_FLAGS) $(INCLUDES) -P -E -D__LINKER__ -MMD -MF $@.d -MT $@ -o $@ $<
 -include $(LINKERFILE).d
 
-$(ELF) : $(OBJS) $(LINKERFILE)
+$(ELF) : $(OBJS) $(OBJS_COMMON) $(LINKERFILE)
 	@echo "  LD      $@"
-	$(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) $(OBJS)
+	$(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) $(OBJS) $(OBJS_COMMON)
 
-$(BIN) : $(ELF)
+%.bin : %.elf
 	@echo "  BIN     $@"
 	$(Q)$(OC) -O binary $< $@
 
+$(ELF_PMU) : $(OBJS_COMMON) $(OBJS_PMU) $(LINKERFILE)
+	@echo "  LD      $@"
+	$(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE_PMU) -Wl,-T$(LINKERFILE) $(OBJS_PMU) $(OBJS_COMMON)
+
+$(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES_COMMON),$(1)))
 $(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES),$(1)))
+$(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES_PMU),$(1)))
diff --git a/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
index 472cbc9..176af3a 100644
--- a/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
+++ b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
@@ -25,8 +25,6 @@
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 
-void handle_suspend(void);
-void handle_dram(void);
 void stopwatch_init_usecs_expire(unsigned int usecs);
 int stopwatch_expired(void);
 void stopwatch_reset(void);
diff --git a/plat/rockchip/rk3399/drivers/m0/src/dram.c b/plat/rockchip/rk3399/drivers/m0/src/dram.c
index c6a9259..b939a96 100644
--- a/plat/rockchip/rk3399/drivers/m0/src/dram.c
+++ b/plat/rockchip/rk3399/drivers/m0/src/dram.c
@@ -55,7 +55,7 @@
 	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_MODE(PLL_NORMAL_MODE));
 }
 
-void handle_dram(void)
+__attribute__((noreturn)) void main(void)
 {
 	mmio_setbits_32(PHY_REG(0, 927), (1 << 22));
 	mmio_setbits_32(PHY_REG(1, 927), (1 << 22));
@@ -76,4 +76,9 @@
 	deidle_port();
 	mmio_clrbits_32(PHY_REG(0, 927), (1 << 22));
 	mmio_clrbits_32(PHY_REG(1, 927), (1 << 22));
+
+	mmio_write_32(PARAM_ADDR + PARAM_M0_DONE, M0_DONE_FLAG);
+
+	for (;;)
+		__asm__ volatile ("wfi");
 }
diff --git a/plat/rockchip/rk3399/drivers/m0/src/main.c b/plat/rockchip/rk3399/drivers/m0/src/main.c
deleted file mode 100644
index 0ed818d..0000000
--- a/plat/rockchip/rk3399/drivers/m0/src/main.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <m0_param.h>
-#include "rk3399_mcu.h"
-
-__attribute__((noreturn)) void main(void)
-{
-	switch (mmio_read_32(PARAM_ADDR + PARAM_M0_FUNC)) {
-	case M0_FUNC_SUSPEND:
-		handle_suspend();
-		break;
-	case M0_FUNC_DRAM:
-		handle_dram();
-		break;
-	default:
-		break;
-	}
-
-	mmio_write_32(PARAM_ADDR + PARAM_M0_DONE, M0_DONE_FLAG);
-
-	for (;;)
-		__asm__ volatile ("wfi");
-}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/startup.c b/plat/rockchip/rk3399/drivers/m0/src/startup.c
index 68f5b2d..dba0313 100644
--- a/plat/rockchip/rk3399/drivers/m0/src/startup.c
+++ b/plat/rockchip/rk3399/drivers/m0/src/startup.c
@@ -7,7 +7,7 @@
 #include "rk3399_mcu.h"
 
 /* Stack configuration */
-#define STACK_SIZE	0x00000100
+#define STACK_SIZE	0x00000040
 __attribute__ ((section(".co_stack")))
 unsigned long pstack[STACK_SIZE];
 
diff --git a/plat/rockchip/rk3399/drivers/m0/src/suspend.c b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
index af29a11..39dfd11 100644
--- a/plat/rockchip/rk3399/drivers/m0/src/suspend.c
+++ b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
@@ -11,18 +11,52 @@
 
 #define SCR_SLEEPDEEP_SHIFT	(1 << 2)
 
-void handle_suspend(void)
+__attribute__((noreturn)) void main(void)
 {
 	unsigned int status_value;
 
+	/*
+	 * PMU sometimes doesn't clear power mode bit as it's supposed to due
+	 * to a hardware bug. Make the M0 clear it manually to be sure,
+	 * otherwise interrupts some cases with concurrent wake interrupts
+	 * we stay asleep forever.
+	 */
 	while (1) {
 		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
 		if (status_value) {
 			mmio_clrbits_32(PMU_BASE + PMU_PWRMODE_CON, 0x01);
-			return;
+			break;
 		}
 	}
 
-	/* m0 enter deep sleep mode */
-	mmio_setbits_32(M0_SCR, SCR_SLEEPDEEP_SHIFT);
+	/*
+	 * FSM power secquence is .. -> ST_INPUT_CLAMP(step.17) -> .. ->
+	 * ST_WAKEUP_RESET -> ST_EXT_PWRUP-> ST_RELEASE_CLAMP ->
+	 * ST_24M_OSC_EN -> .. -> ST_WAKEUP_RESET_CLR(step.26) -> ..,
+	 * INPUT_CLAMP and WAKEUP_RESET will hold the SOC not affect by
+	 * power or other single glitch, but WAKEUP_RESET need work with 24MHz,
+	 * so between RELEASE_CLAMP and 24M_OSC_EN, there have a chance
+	 * that glitch will affect SOC, and mess up SOC status, so we
+	 * addressmap_shared software clamp between ST_INPUT_CLAMP and
+	 * ST_WAKEUP_RESET_CLR to avoid this happen.
+	 */
+	while (1) {
+		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
+		if (status_value >= 17)  {
+			mmio_setbits_32(PMU_BASE + PMU_SFT_CON, 0x02);
+			break;
+		}
+
+	}
+
+	while (1) {
+		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
+		if (status_value >= 26)  {
+			mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 0x02);
+			break;
+		}
+	}
+
+	for (;;)
+		__asm__ volatile ("wfi");
 }
diff --git a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
index 61849e5..3f258b7 100644
--- a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
@@ -21,14 +21,6 @@
 	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(0), WMSK_BIT(7));
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), WMSK_BIT(12));
 
-	/* 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));
-
 	/* document is wrong, PMU_CRU_GATEDIS_CON0 do not need set MASK BIT */
 	mmio_setbits_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, 0x02);
 
@@ -46,6 +38,17 @@
 	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2, WMSK_BIT(5));
 }
 
+void m0_configure_execute_addr(uintptr_t addr)
+{
+	/* set the execute address for M0 */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(3),
+		      BITS_WITH_WMASK((addr >> 12) & 0xffff,
+				      0xffff, 0));
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(7),
+		      BITS_WITH_WMASK((addr >> 28) & 0xf,
+				      0xf, 0));
+}
+
 void m0_start(void)
 {
 	/* enable clocks for M0 */
diff --git a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
index b313ec6..cb323c4 100644
--- a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
@@ -11,13 +11,18 @@
 
 #define M0_BINCODE_BASE 	((uintptr_t)rk3399m0_bin)
 #define M0_PARAM_ADDR		(M0_BINCODE_BASE + PARAM_ADDR)
+#define M0PMU_BINCODE_BASE	((uintptr_t)rk3399m0pmu_bin)
 
 /* pmu_fw.c */
 extern char rk3399m0_bin[];
 extern char rk3399m0_bin_end[];
 
+extern char rk3399m0pmu_bin[];
+extern char rk3399m0pmu_bin_end[];
+
 extern void m0_init(void);
 extern void m0_start(void);
 extern void m0_stop(void);
 extern void m0_wait_done(void);
+extern void m0_configure_execute_addr(uintptr_t addr);
 #endif /* __M0_CTL_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index ed1ea8b..04446d6 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -836,6 +836,7 @@
 		      BIT_WITH_WMSK(PMU_CLR_GIC2_CORE_L_HW));
 
 	slp_mode_cfg = BIT(PMU_PWR_MODE_EN) |
+		       BIT(PMU_WKUP_RST_EN) |
 		       BIT(PMU_INPUT_CLAMP_EN) |
 		       BIT(PMU_POWER_OFF_REQ_CFG) |
 		       BIT(PMU_CPU0_PD_EN) |
@@ -853,7 +854,6 @@
 		       BIT(PMU_DDRIO0_RET_DE_REQ) |
 		       BIT(PMU_DDRIO1_RET_EN) |
 		       BIT(PMU_DDRIO1_RET_DE_REQ) |
-		       BIT(PMU_DDRIO_RET_HW_DE_REQ) |
 		       BIT(PMU_CENTER_PD_EN) |
 		       BIT(PMU_PERILP_PD_EN) |
 		       BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
@@ -1064,12 +1064,6 @@
 	}
 }
 
-static void m0_configure_suspend(void)
-{
-	/* set PARAM to M0_FUNC_SUSPEND */
-	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_FUNC, M0_FUNC_SUSPEND);
-}
-
 void sram_save(void)
 {
 	size_t text_size = (char *)&__bl31_sram_text_real_end -
@@ -1344,7 +1338,7 @@
 	set_pmu_rsthold();
 	sys_slp_config();
 
-	m0_configure_suspend();
+	m0_configure_execute_addr(M0PMU_BINCODE_BASE);
 	m0_start();
 
 	pmu_sgrf_rst_hld();
@@ -1374,7 +1368,7 @@
 	mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
 
 	wdt_register_save();
-	secure_watchdog_disable();
+	secure_watchdog_gate();
 
 	/*
 	 * Disabling PLLs/PWM/DVFS is approaching WFI which is
@@ -1403,6 +1397,7 @@
 	plat_rockchip_restore_gpio();
 	cru_register_restore();
 	grf_register_restore();
+	wdt_register_restore();
 	resume_uart();
 	resume_apio();
 	resume_gpio();
@@ -1412,10 +1407,8 @@
 	udelay(300);
 	enable_dvfs_plls();
 
-	secure_watchdog_enable();
 	secure_sgrf_init();
 	secure_sgrf_ddr_rgn_init();
-	wdt_register_restore();
 
 	/* restore clk_ddrc_bpll_src_en gate */
 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3),
@@ -1466,12 +1459,10 @@
 		udelay(1);
 	}
 
-	pmu_sgrf_rst_hld_release();
 	pmu_scu_b_pwrup();
 	pmu_power_domains_resume();
 
 	restore_abpll();
-	restore_pmu_rsthold();
 	clr_hw_idle(BIT(PMU_CLR_CENTER1) |
 				BIT(PMU_CLR_ALIVE) |
 				BIT(PMU_CLR_MSCH0) |
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
index d299116..a09ad21 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
@@ -5,9 +5,9 @@
  */
 
 /* convoluted way to make sure that the define is pasted just the right way */
-#define _INCBIN(file, sym) \
+#define _INCBIN(file, sym, sec) \
 	__asm__( \
-		".section .sram.incbin\n" \
+		".section " #sec "\n" \
 		".global " #sym "\n" \
 		".type " #sym ", %object\n" \
 		".align 4\n" \
@@ -18,6 +18,7 @@
 		#sym "_end:\n" \
 	)
 
-#define INCBIN(file, sym) _INCBIN(file, sym)
+#define INCBIN(file, sym, sec) _INCBIN(file, sym, sec)
 
-INCBIN(RK3399M0FW, rk3399m0_bin);
+INCBIN(RK3399M0FW, rk3399m0_bin, ".sram.incbin");
+INCBIN(RK3399M0PMUFW, rk3399m0pmu_bin, ".pmusram.incbin");
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.c b/plat/rockchip/rk3399/drivers/secure/secure.c
index 589d833..1937b13 100644
--- a/plat/rockchip/rk3399/drivers/secure/secure.c
+++ b/plat/rockchip/rk3399/drivers/secure/secure.c
@@ -77,7 +77,7 @@
 		      BIT_WITH_WMSK(rgn));
 }
 
-void secure_watchdog_disable(void)
+void secure_watchdog_gate(void)
 {
 	/**
 	 * Disable CA53 and CM0 wdt pclk
@@ -89,7 +89,7 @@
 		      BIT_WITH_WMSK(PCLK_WDT_CM0_GATE_SHIFT));
 }
 
-void secure_watchdog_enable(void)
+__pmusramfunc void secure_watchdog_ungate(void)
 {
 	/**
 	 * Enable CA53 and CM0 wdt pclk
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.h b/plat/rockchip/rk3399/drivers/secure/secure.h
index 334805d..8e80f2b 100644
--- a/plat/rockchip/rk3399/drivers/secure/secure.h
+++ b/plat/rockchip/rk3399/drivers/secure/secure.h
@@ -95,8 +95,8 @@
 #define PCLK_WDT_CM0_GATE_SHIFT		10
 
 /* export secure operating APIs */
-void secure_watchdog_disable(void);
-void secure_watchdog_enable(void);
+void secure_watchdog_gate(void);
+__pmusramfunc void secure_watchdog_ungate(void);
 void secure_timer_init(void);
 void secure_sgrf_init(void);
 void secure_sgrf_ddr_rgn_init(void);
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
index 7dd0b72..741adde 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.c
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -43,6 +43,9 @@
 /* sleep data for pll suspend */
 static struct deepsleep_data_s slp_data;
 
+/* sleep data that needs to be accessed from pmusram */
+__pmusramdata struct pmu_sleep_data pmu_slp_data;
+
 static void set_pll_slow_mode(uint32_t pll_id)
 {
 	if (pll_id == PPLL_ID)
@@ -229,9 +232,9 @@
 	uint32_t rstnhold_cofig0;
 	uint32_t rstnhold_cofig1;
 
-	slp_data.pmucru_rstnhold_con0 = mmio_read_32(PMUCRU_BASE +
+	pmu_slp_data.pmucru_rstnhold_con0 = mmio_read_32(PMUCRU_BASE +
 					    PMUCRU_RSTNHOLD_CON0);
-	slp_data.pmucru_rstnhold_con1 = mmio_read_32(PMUCRU_BASE +
+	pmu_slp_data.pmucru_rstnhold_con1 = mmio_read_32(PMUCRU_BASE +
 					    PMUCRU_RSTNHOLD_CON1);
 	rstnhold_cofig0 = BIT_WITH_WMSK(PRESETN_NOC_PMU_HOLD) |
 			  BIT_WITH_WMSK(PRESETN_INTMEM_PMU_HOLD) |
@@ -257,12 +260,33 @@
 	mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON1, rstnhold_cofig1);
 }
 
+void pmu_sgrf_rst_hld(void)
+{
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
+		      CRU_PMU_SGRF_RST_HOLD);
+}
+
-void restore_pmu_rsthold(void)
+/*
+ * When system reset in running state, we want the cpus to be reboot
+ * from maskrom (system reboot),
+ * the pmusgrf reset-hold bits needs to be released.
+ * When system wake up from system deep suspend, some soc will be reset
+ * when waked up,
+ * we want the bootcpu to be reboot from pmusram,
+ * the pmusgrf reset-hold bits needs to be held.
+ */
+__pmusramfunc void pmu_sgrf_rst_hld_release(void)
+{
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
+		      CRU_PMU_SGRF_RST_RLS);
+}
+
+__pmusramfunc void restore_pmu_rsthold(void)
 {
 	mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON0,
-		      slp_data.pmucru_rstnhold_con0 | REG_SOC_WMSK);
+		      pmu_slp_data.pmucru_rstnhold_con0 | REG_SOC_WMSK);
 	mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON1,
-		      slp_data.pmucru_rstnhold_con1 | REG_SOC_WMSK);
+		      pmu_slp_data.pmucru_rstnhold_con1 | REG_SOC_WMSK);
 }
 
 /**
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
index 6100d95..bc41933 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -134,6 +134,9 @@
 	uint32_t plls_con[END_PLL_ID][PLL_CON_COUNT];
 	uint32_t cru_gate_con[CRU_GATE_COUNT];
 	uint32_t pmucru_gate_con[PMUCRU_GATE_COUNT];
+};
+
+struct pmu_sleep_data {
 	uint32_t pmucru_rstnhold_con0;
 	uint32_t pmucru_rstnhold_con1;
 };
@@ -263,27 +266,6 @@
 #define PMUCRU_GATEDIS_CON0 0x0130
 #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),
- * the pmusgrf reset-hold bits needs to be released.
- * When system wake up from system deep suspend, some soc will be reset
- * when waked up,
- * we want the bootcpu to be reboot from pmusram,
- * the pmusgrf reset-hold bits needs to be held.
- */
-static inline void pmu_sgrf_rst_hld_release(void)
-{
-	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
-		      CRU_PMU_SGRF_RST_RLS);
-}
-
-static inline void pmu_sgrf_rst_hld(void)
-{
-	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
-		      CRU_PMU_SGRF_RST_HOLD);
-}
-
 /* export related and operating SoC APIs */
 void __dead2 soc_global_soft_reset(void);
 void disable_dvfs_plls(void);
@@ -296,5 +278,7 @@
 void clk_gate_con_disable(void);
 void clk_gate_con_restore(void);
 void set_pmu_rsthold(void);
-void restore_pmu_rsthold(void);
+void pmu_sgrf_rst_hld(void);
+__pmusramfunc void pmu_sgrf_rst_hld_release(void);
+__pmusramfunc void restore_pmu_rsthold(void);
 #endif /* __SOC_H__ */
diff --git a/plat/rockchip/rk3399/include/plat.ld.S b/plat/rockchip/rk3399/include/plat.ld.S
index 85f4dc3..528c150 100644
--- a/plat/rockchip/rk3399/include/plat.ld.S
+++ b/plat/rockchip/rk3399/include/plat.ld.S
@@ -77,14 +77,21 @@
 		ASSERT(. == ALIGN(64 * 1024),
 			".pmusram.entry request 64K aligned.");
 		*(.pmusram.entry)
+
 		__bl31_pmusram_text_start = .;
 		*(.pmusram.text)
 		*(.pmusram.rodata)
 		__bl31_pmusram_text_end = .;
+
+		/* M0 start address request 4K align */
+		. = ALIGN(4096);
+		__pmusram_incbin_start = .;
+		*(.pmusram.incbin)
+		__pmusram_incbin_end = .;
+
 		__bl31_pmusram_data_start = .;
 		*(.pmusram.data)
 		__bl31_pmusram_data_end = .;
-
 	} >PMUSRAM
 }
 
diff --git a/plat/rockchip/rk3399/include/shared/m0_param.h b/plat/rockchip/rk3399/include/shared/m0_param.h
index 3edbf89..044e797 100644
--- a/plat/rockchip/rk3399/include/shared/m0_param.h
+++ b/plat/rockchip/rk3399/include/shared/m0_param.h
@@ -7,13 +7,6 @@
 #ifndef __M0_PARAM_H__
 #define __M0_PARAM_H__
 
-#ifndef __LINKER__
-enum {
-	M0_FUNC_SUSPEND = 0,
-	M0_FUNC_DRAM	= 1,
-};
-#endif /* __LINKER__ */
-
 #define PARAM_ADDR		0xc0
 
 #define PARAM_M0_FUNC		0x00
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 1997dfc..fc386f0 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -82,12 +82,15 @@
 RK3399M0FW=${BUILD_M0}/${PLAT_M0}.bin
 $(eval $(call add_define,RK3399M0FW))
 
+RK3399M0PMUFW=${BUILD_M0}/${PLAT_M0}pmu.bin
+$(eval $(call add_define,RK3399M0PMUFW))
+
 HDCPFW=${RK_PLAT_SOC}/drivers/dp/hdcp.bin
 $(eval $(call add_define,HDCPFW))
 
 # CCACHE_EXTRAFILES is needed because ccache doesn't handle .incbin
 export CCACHE_EXTRAFILES
-${BUILD_PLAT}/bl31/pmu_fw.o: CCACHE_EXTRAFILES=$(RK3399M0FW)
+${BUILD_PLAT}/bl31/pmu_fw.o: CCACHE_EXTRAFILES=$(RK3399M0FW):$(RK3399M0PMUFW)
 ${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c: $(RK3399M0FW)
 
 ${BUILD_PLAT}/bl31/cdn_dp.o: CCACHE_EXTRAFILES=$(HDCPFW)