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