xref: /rk3399_ARM-atf/plat/allwinner/sun50i_a64/sunxi_power.c (revision 4ec1a2399cf6e182ba2828a40795912d20eca1ab)
1 /*
2  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3  * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <arch_helpers.h>
9 #include <debug.h>
10 #include <delay_timer.h>
11 #include <errno.h>
12 #include <mmio.h>
13 #include <platform_def.h>
14 #include <sunxi_def.h>
15 #include <sunxi_mmap.h>
16 #include <sunxi_private.h>
17 
18 static enum pmic_type {
19 	GENERIC_H5,
20 	GENERIC_A64,
21 } pmic;
22 
23 /*
24  * On boards without a proper PMIC we struggle to turn off the system properly.
25  * Try to turn off as much off the system as we can, to reduce power
26  * consumption. This should be entered with only one core running and SMP
27  * disabled.
28  * This function only cares about peripherals.
29  */
30 void sunxi_turn_off_soc(uint16_t socid)
31 {
32 	int i;
33 
34 	/** Turn off most peripherals, most importantly DRAM users. **/
35 	/* Keep DRAM controller running for now. */
36 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
37 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
38 	/* Contains msgbox (bit 21) and spinlock (bit 22) */
39 	mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
40 	mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
41 	mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
42 	/* Keep PIO controller running for now. */
43 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
44 	mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
45 	/* Contains UART0 (bit 16) */
46 	mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
47 	mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
48 	mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
49 
50 	/** Turn off DRAM controller. **/
51 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
52 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
53 
54 	/** Migrate CPU and bus clocks away from the PLLs. **/
55 	/* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
56 	mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
57 	/* APB2: use OSC24M */
58 	mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
59 	/* AHB2: use AHB1 clock */
60 	mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
61 	/* CPU: use OSC24M */
62 	mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
63 
64 	/** Turn off PLLs. **/
65 	for (i = 0; i < 6; i++)
66 		mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
67 	switch (socid) {
68 	case SUNXI_SOC_H5:
69 		mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
70 		break;
71 	case SUNXI_SOC_A64:
72 		mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
73 		mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
74 		break;
75 	}
76 }
77 
78 int sunxi_pmic_setup(uint16_t socid)
79 {
80 	switch (socid) {
81 	case SUNXI_SOC_H5:
82 		pmic = GENERIC_H5;
83 		break;
84 	case SUNXI_SOC_A64:
85 		pmic = GENERIC_A64;
86 		break;
87 	default:
88 		NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid);
89 		return -ENODEV;
90 	}
91 	return 0;
92 }
93 
94 void __dead2 sunxi_power_down(void)
95 {
96 	switch (pmic) {
97 	case GENERIC_H5:
98 		/* Turn off as many peripherals and clocks as we can. */
99 		sunxi_turn_off_soc(SUNXI_SOC_H5);
100 		/* Turn off the pin controller now. */
101 		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
102 		break;
103 	case GENERIC_A64:
104 		/* Turn off as many peripherals and clocks as we can. */
105 		sunxi_turn_off_soc(SUNXI_SOC_A64);
106 		/* Turn off the pin controller now. */
107 		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
108 		break;
109 	default:
110 		break;
111 	}
112 
113 	udelay(1000);
114 	ERROR("PSCI: Cannot turn off system, halting.\n");
115 	wfi();
116 	panic();
117 }
118