xref: /rk3399_ARM-atf/plat/allwinner/sun50i_a64/sunxi_power.c (revision d5ddf67a66d77d04a6f0f6856af02704f486fd73)
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 	REF_DESIGN_H5,	/* regulators controlled by GPIO pins on port L */
22 } pmic;
23 
24 /*
25  * On boards without a proper PMIC we struggle to turn off the system properly.
26  * Try to turn off as much off the system as we can, to reduce power
27  * consumption. This should be entered with only one core running and SMP
28  * disabled.
29  * This function only cares about peripherals.
30  */
31 void sunxi_turn_off_soc(uint16_t socid)
32 {
33 	int i;
34 
35 	/** Turn off most peripherals, most importantly DRAM users. **/
36 	/* Keep DRAM controller running for now. */
37 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
38 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
39 	/* Contains msgbox (bit 21) and spinlock (bit 22) */
40 	mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
41 	mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
42 	mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
43 	/* Keep PIO controller running for now. */
44 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
45 	mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
46 	/* Contains UART0 (bit 16) */
47 	mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
48 	mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
49 	mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
50 
51 	/** Turn off DRAM controller. **/
52 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
53 	mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
54 
55 	/** Migrate CPU and bus clocks away from the PLLs. **/
56 	/* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
57 	mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
58 	/* APB2: use OSC24M */
59 	mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
60 	/* AHB2: use AHB1 clock */
61 	mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
62 	/* CPU: use OSC24M */
63 	mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
64 
65 	/** Turn off PLLs. **/
66 	for (i = 0; i < 6; i++)
67 		mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
68 	switch (socid) {
69 	case SUNXI_SOC_H5:
70 		mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
71 		break;
72 	case SUNXI_SOC_A64:
73 		mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
74 		mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
75 		break;
76 	}
77 }
78 
79 int sunxi_pmic_setup(uint16_t socid)
80 {
81 	switch (socid) {
82 	case SUNXI_SOC_H5:
83 		pmic = REF_DESIGN_H5;
84 		NOTICE("BL31: PMIC: Defaulting to PortL GPIO according to H5 reference design.\n");
85 		break;
86 	case SUNXI_SOC_A64:
87 		pmic = GENERIC_A64;
88 		break;
89 	default:
90 		NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid);
91 		return -ENODEV;
92 	}
93 	return 0;
94 }
95 
96 void __dead2 sunxi_power_down(void)
97 {
98 	switch (pmic) {
99 	case GENERIC_H5:
100 		/* Turn off as many peripherals and clocks as we can. */
101 		sunxi_turn_off_soc(SUNXI_SOC_H5);
102 		/* Turn off the pin controller now. */
103 		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
104 		break;
105 	case GENERIC_A64:
106 		/* Turn off as many peripherals and clocks as we can. */
107 		sunxi_turn_off_soc(SUNXI_SOC_A64);
108 		/* Turn off the pin controller now. */
109 		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
110 		break;
111 	case REF_DESIGN_H5:
112 		sunxi_turn_off_soc(SUNXI_SOC_H5);
113 
114 		/*
115 		 * Switch PL pins to power off the board:
116 		 * - PL5 (VCC_IO) -> high
117 		 * - PL8 (PWR-STB = CPU power supply) -> low
118 		 * - PL9 (PWR-DRAM) ->low
119 		 * - PL10 (power LED) -> low
120 		 * Note: Clearing PL8 will reset the board, so keep it up.
121 		 */
122 		sunxi_set_gpio_out('L', 5, 1);
123 		sunxi_set_gpio_out('L', 9, 0);
124 		sunxi_set_gpio_out('L', 10, 0);
125 
126 		/* Turn off pin controller now. */
127 		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
128 
129 		break;
130 	default:
131 		break;
132 	}
133 
134 	udelay(1000);
135 	ERROR("PSCI: Cannot turn off system, halting.\n");
136 	wfi();
137 	panic();
138 }
139