blob: eaca0af5d5f364a567641edcf6938064b35b3815 [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
Andre Przywara7f3c0792018-09-15 01:18:49 +01008#include <allwinner/sunxi_rsb.h>
Icenowy Zhengbd57eb52018-07-22 21:52:50 +08009#include <arch_helpers.h>
Icenowy Zheng7508bef2018-07-21 20:41:12 +080010#include <debug.h>
Andre Przywaraa920a772018-10-02 00:21:49 +010011#include <delay_timer.h>
12#include <errno.h>
13#include <mmio.h>
14#include <platform_def.h>
15#include <sunxi_def.h>
16#include <sunxi_mmap.h>
Andre Przywara456208a2018-10-14 12:02:02 +010017#include <sunxi_private.h>
Icenowy Zheng7508bef2018-07-21 20:41:12 +080018
Andre Przywaraa920a772018-10-02 00:21:49 +010019static enum pmic_type {
20 GENERIC_H5,
21 GENERIC_A64,
Andre Przywara74f7a952018-10-02 00:21:53 +010022 REF_DESIGN_H5, /* regulators controlled by GPIO pins on port L */
Andre Przywara7f3c0792018-09-15 01:18:49 +010023 AXP803_RSB, /* PMIC connected via RSB on most A64 boards */
Andre Przywaraa920a772018-10-02 00:21:49 +010024} pmic;
25
Andre Przywara7f3c0792018-09-15 01:18:49 +010026#define AXP803_HW_ADDR 0x3a3
27#define AXP803_RT_ADDR 0x2d
28
Andre Przywaraa920a772018-10-02 00:21:49 +010029/*
30 * On boards without a proper PMIC we struggle to turn off the system properly.
31 * Try to turn off as much off the system as we can, to reduce power
32 * consumption. This should be entered with only one core running and SMP
33 * disabled.
34 * This function only cares about peripherals.
35 */
36void sunxi_turn_off_soc(uint16_t socid)
Icenowy Zheng7508bef2018-07-21 20:41:12 +080037{
Andre Przywaraa920a772018-10-02 00:21:49 +010038 int i;
39
40 /** Turn off most peripherals, most importantly DRAM users. **/
41 /* Keep DRAM controller running for now. */
42 mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
43 mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
44 /* Contains msgbox (bit 21) and spinlock (bit 22) */
45 mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
46 mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
47 mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
48 /* Keep PIO controller running for now. */
49 mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
50 mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
51 /* Contains UART0 (bit 16) */
52 mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
53 mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
54 mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
55
56 /** Turn off DRAM controller. **/
57 mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
58 mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
59
60 /** Migrate CPU and bus clocks away from the PLLs. **/
61 /* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
62 mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
63 /* APB2: use OSC24M */
64 mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
65 /* AHB2: use AHB1 clock */
66 mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
67 /* CPU: use OSC24M */
68 mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
Icenowy Zheng7508bef2018-07-21 20:41:12 +080069
Andre Przywaraa920a772018-10-02 00:21:49 +010070 /** Turn off PLLs. **/
71 for (i = 0; i < 6; i++)
72 mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
73 switch (socid) {
74 case SUNXI_SOC_H5:
75 mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
76 break;
77 case SUNXI_SOC_A64:
78 mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
79 mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
80 break;
81 }
82}
83
Andre Przywara7f3c0792018-09-15 01:18:49 +010084static int rsb_init(void)
85{
86 int ret;
87
88 ret = rsb_init_controller();
89 if (ret)
90 return ret;
91
92 /* Start with 400 KHz to issue the I2C->RSB switch command. */
93 ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 400000);
94 if (ret)
95 return ret;
96
97 /*
98 * Initiate an I2C transaction to write 0x7c into register 0x3e,
99 * switching the PMIC to RSB mode.
100 */
101 ret = rsb_set_device_mode(0x7c3e00);
102 if (ret)
103 return ret;
104
105 /* Now in RSB mode, switch to the recommended 3 MHz. */
106 ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
107 if (ret)
108 return ret;
109
110 /* Associate the 8-bit runtime address with the 12-bit bus address. */
111 return rsb_assign_runtime_address(AXP803_HW_ADDR,
112 AXP803_RT_ADDR);
113}
114
115static int axp_setbits(uint8_t reg, uint8_t set_mask)
116{
117 uint8_t regval;
118 int ret;
119
120 ret = rsb_read(AXP803_RT_ADDR, reg);
121 if (ret < 0)
122 return ret;
123
124 regval = ret | set_mask;
125
126 return rsb_write(AXP803_RT_ADDR, reg, regval);
127}
128
Andre Przywaraa920a772018-10-02 00:21:49 +0100129int sunxi_pmic_setup(uint16_t socid)
130{
Andre Przywara7f3c0792018-09-15 01:18:49 +0100131 int ret;
132
Andre Przywaraa920a772018-10-02 00:21:49 +0100133 switch (socid) {
134 case SUNXI_SOC_H5:
Andre Przywara74f7a952018-10-02 00:21:53 +0100135 pmic = REF_DESIGN_H5;
136 NOTICE("BL31: PMIC: Defaulting to PortL GPIO according to H5 reference design.\n");
Andre Przywaraa920a772018-10-02 00:21:49 +0100137 break;
138 case SUNXI_SOC_A64:
139 pmic = GENERIC_A64;
Andre Przywara7f3c0792018-09-15 01:18:49 +0100140 ret = sunxi_init_platform_r_twi(socid, true);
141 if (ret)
142 return ret;
143
144 ret = rsb_init();
145 if (ret)
146 return ret;
147
148 pmic = AXP803_RSB;
149 NOTICE("BL31: PMIC: Detected AXP803 on RSB.\n");
150
Andre Przywaraa920a772018-10-02 00:21:49 +0100151 break;
152 default:
153 NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid);
154 return -ENODEV;
155 }
Icenowy Zheng7508bef2018-07-21 20:41:12 +0800156 return 0;
157}
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800158
159void __dead2 sunxi_power_down(void)
160{
Andre Przywaraa920a772018-10-02 00:21:49 +0100161 switch (pmic) {
162 case GENERIC_H5:
163 /* Turn off as many peripherals and clocks as we can. */
164 sunxi_turn_off_soc(SUNXI_SOC_H5);
165 /* Turn off the pin controller now. */
166 mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
167 break;
168 case GENERIC_A64:
169 /* Turn off as many peripherals and clocks as we can. */
170 sunxi_turn_off_soc(SUNXI_SOC_A64);
171 /* Turn off the pin controller now. */
172 mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
173 break;
Andre Przywara74f7a952018-10-02 00:21:53 +0100174 case REF_DESIGN_H5:
175 sunxi_turn_off_soc(SUNXI_SOC_H5);
176
177 /*
178 * Switch PL pins to power off the board:
179 * - PL5 (VCC_IO) -> high
180 * - PL8 (PWR-STB = CPU power supply) -> low
181 * - PL9 (PWR-DRAM) ->low
182 * - PL10 (power LED) -> low
183 * Note: Clearing PL8 will reset the board, so keep it up.
184 */
185 sunxi_set_gpio_out('L', 5, 1);
186 sunxi_set_gpio_out('L', 9, 0);
187 sunxi_set_gpio_out('L', 10, 0);
188
189 /* Turn off pin controller now. */
190 mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
191
192 break;
Andre Przywara7f3c0792018-09-15 01:18:49 +0100193 case AXP803_RSB:
194 /* (Re-)init RSB in case the rich OS has disabled it. */
195 sunxi_init_platform_r_twi(SUNXI_SOC_A64, true);
196 rsb_init();
197
198 /* Set "power disable control" bit */
199 axp_setbits(0x32, BIT(7));
200 break;
Andre Przywaraa920a772018-10-02 00:21:49 +0100201 default:
202 break;
203 }
204
205 udelay(1000);
206 ERROR("PSCI: Cannot turn off system, halting.\n");
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800207 wfi();
208 panic();
209}