blob: 535831e1122f342238faff1a1aacf0be2bda5225 [file] [log] [blame]
Icenowy Zheng7508bef2018-07-21 20:41:12 +08001/*
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
Icenowy Zhengbd57eb52018-07-22 21:52:50 +08008#include <arch_helpers.h>
Icenowy Zheng7508bef2018-07-21 20:41:12 +08009#include <debug.h>
Andre Przywaraa920a772018-10-02 00:21:49 +010010#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>
Andre Przywara456208a2018-10-14 12:02:02 +010016#include <sunxi_private.h>
Icenowy Zheng7508bef2018-07-21 20:41:12 +080017
Andre Przywaraa920a772018-10-02 00:21:49 +010018static enum pmic_type {
19 GENERIC_H5,
20 GENERIC_A64,
Andre Przywara74f7a952018-10-02 00:21:53 +010021 REF_DESIGN_H5, /* regulators controlled by GPIO pins on port L */
Andre Przywaraa920a772018-10-02 00:21:49 +010022} 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 */
31void sunxi_turn_off_soc(uint16_t socid)
Icenowy Zheng7508bef2018-07-21 20:41:12 +080032{
Andre Przywaraa920a772018-10-02 00:21:49 +010033 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);
Icenowy Zheng7508bef2018-07-21 20:41:12 +080064
Andre Przywaraa920a772018-10-02 00:21:49 +010065 /** 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
79int sunxi_pmic_setup(uint16_t socid)
80{
81 switch (socid) {
82 case SUNXI_SOC_H5:
Andre Przywara74f7a952018-10-02 00:21:53 +010083 pmic = REF_DESIGN_H5;
84 NOTICE("BL31: PMIC: Defaulting to PortL GPIO according to H5 reference design.\n");
Andre Przywaraa920a772018-10-02 00:21:49 +010085 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 }
Icenowy Zheng7508bef2018-07-21 20:41:12 +080093 return 0;
94}
Icenowy Zhengbd57eb52018-07-22 21:52:50 +080095
96void __dead2 sunxi_power_down(void)
97{
Andre Przywaraa920a772018-10-02 00:21:49 +010098 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;
Andre Przywara74f7a952018-10-02 00:21:53 +0100111 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;
Andre Przywaraa920a772018-10-02 00:21:49 +0100130 default:
131 break;
132 }
133
134 udelay(1000);
135 ERROR("PSCI: Cannot turn off system, halting.\n");
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800136 wfi();
137 panic();
138}