rockchip/rk3399: Split M0 binary into two

All the m0 code run in SRAM before, but we need to watch PMU_POWER_ST
when SOC enter into FSM, and SRAM will shutdown during this time, so
this code need run in PMUSRAM. But PMUSRAM only 8K space, we can not
put all the m0 binary into PMUSRAM, Split the M0 binary into two, dram
part still run in SRAM, and suspend part run in PMUSRAM.

Change-Id: Ie08bdf3e2b8838f12b9297fe60ab0aad219684b1
Signed-off-by: Lin Huang <hl@rock-chips.com>
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");
 }