1 /*
2  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <pmu_regs.h>
8 #include "rk3399_mcu.h"
9 
10 #define M0_SCR			0xe000ed10  /* System Control Register (SCR) */
11 
12 #define SCR_SLEEPDEEP_SHIFT	(1 << 2)
13 
m0_main(void)14 __attribute__((noreturn)) void m0_main(void)
15 {
16 	unsigned int status_value;
17 
18 	/*
19 	 * PMU sometimes doesn't clear power mode bit as it's supposed to due
20 	 * to a hardware bug. Make the M0 clear it manually to be sure,
21 	 * otherwise interrupts some cases with concurrent wake interrupts
22 	 * we stay asleep forever.
23 	 */
24 	while (1) {
25 		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
26 		if (status_value) {
27 			mmio_clrbits_32(PMU_BASE + PMU_PWRMODE_CON, 0x01);
28 			break;
29 		}
30 	}
31 
32 	/*
33 	 * FSM power secquence is .. -> ST_INPUT_CLAMP(step.17) -> .. ->
34 	 * ST_WAKEUP_RESET -> ST_EXT_PWRUP-> ST_RELEASE_CLAMP ->
35 	 * ST_24M_OSC_EN -> .. -> ST_WAKEUP_RESET_CLR(step.26) -> ..,
36 	 * INPUT_CLAMP and WAKEUP_RESET will hold the SOC not affect by
37 	 * power or other single glitch, but WAKEUP_RESET need work with 24MHz,
38 	 * so between RELEASE_CLAMP and 24M_OSC_EN, there have a chance
39 	 * that glitch will affect SOC, and mess up SOC status, so we
40 	 * addressmap_shared software clamp between ST_INPUT_CLAMP and
41 	 * ST_WAKEUP_RESET_CLR to avoid this happen.
42 	 */
43 	while (1) {
44 		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
45 		if (status_value >= 17)  {
46 			mmio_setbits_32(PMU_BASE + PMU_SFT_CON, 0x02);
47 			break;
48 		}
49 
50 	}
51 
52 	while (1) {
53 		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
54 		if (status_value >= 26)  {
55 			mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 0x02);
56 			break;
57 		}
58 	}
59 
60 	for (;;)
61 		__asm__ volatile ("wfi");
62 }
63