xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h616/sunxi_power.c (revision 03851367dbd46f73708fa35da2b501489e44afa4)
1 /*
2  * Copyright (c) 2017-2020, ARM Limited. All rights reserved.
3  * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <errno.h>
9 #include <string.h>
10 
11 #include <arch_helpers.h>
12 #include <common/debug.h>
13 #include <common/fdt_wrappers.h>
14 #include <drivers/allwinner/axp.h>
15 #include <drivers/allwinner/sunxi_rsb.h>
16 #include <drivers/mentor/mi2cv.h>
17 #include <lib/mmio.h>
18 #include <libfdt.h>
19 
20 #include <sunxi_cpucfg.h>
21 #include <sunxi_def.h>
22 #include <sunxi_mmap.h>
23 #include <sunxi_private.h>
24 
25 static uint16_t pmic_bus_addr;
26 static uint8_t rsb_rt_addr;
27 
28 static bool is_using_rsb(void)
29 {
30 	return rsb_rt_addr != 0;
31 }
32 
33 static enum pmic_type {
34 	UNKNOWN,
35 	AXP305,
36 	AXP313,
37 } pmic;
38 
39 static uint8_t get_rsb_rt_address(uint16_t hw_addr)
40 {
41 	switch (hw_addr) {
42 	case 0x745: return 0x3a;
43 	}
44 
45 	return 0;
46 }
47 
48 int axp_read(uint8_t reg)
49 {
50 	uint8_t val;
51 	int ret;
52 
53 	if (is_using_rsb()) {
54 		return rsb_read(rsb_rt_addr, reg);
55 	}
56 
57 	ret = i2c_write(pmic_bus_addr, 0, 0, &reg, 1);
58 	if (ret == 0) {
59 		ret = i2c_read(pmic_bus_addr, 0, 0, &val, 1);
60 	}
61 	if (ret) {
62 		ERROR("PMIC: Cannot read PMIC register %02x\n", reg);
63 		return ret;
64 	}
65 
66 	return val;
67 }
68 
69 int axp_write(uint8_t reg, uint8_t val)
70 {
71 	int ret;
72 
73 	if (is_using_rsb()) {
74 		return rsb_write(rsb_rt_addr, reg, val);
75 	}
76 
77 	ret = i2c_write(pmic_bus_addr, reg, 1, &val, 1);
78 	if (ret) {
79 		ERROR("PMIC: Cannot write PMIC register %02x\n", reg);
80 	}
81 
82 	return ret;
83 }
84 
85 static int rsb_init(int rsb_hw_addr)
86 {
87 	int ret;
88 
89 	ret = rsb_init_controller();
90 	if (ret) {
91 		return ret;
92 	}
93 
94 	/* Switch to the recommended 3 MHz bus clock. */
95 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
96 	if (ret) {
97 		return ret;
98 	}
99 
100 	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
101 	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
102 	if (ret) {
103 		return ret;
104 	}
105 
106 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
107 	ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr);
108 	if (ret) {
109 		return ret;
110 	}
111 
112 	return 0;
113 }
114 
115 static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr)
116 {
117 	int ret;
118 
119 	ret = sunxi_init_platform_r_twi(socid, is_using_rsb());
120 	if (ret) {
121 		INFO("Could not init platform bus: %d\n", ret);
122 		pmic = UNKNOWN;
123 		return ret;
124 	}
125 
126 	if (is_using_rsb()) {
127 		ret = rsb_init(rsb_hw_addr);
128 		if (ret) {
129 			pmic = UNKNOWN;
130 			return ret;
131 		}
132 	} else {
133 		/* initialise mi2cv driver */
134 		i2c_init((void *)SUNXI_R_I2C_BASE);
135 	}
136 
137 	return 0;
138 }
139 
140 int sunxi_pmic_setup(uint16_t socid, const void *fdt)
141 {
142 	int node, parent, ret;
143 	uint32_t reg;
144 
145 	node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806");
146 	if (node >= 0) {
147 		pmic = AXP305;
148 	}
149 
150 	if (pmic == UNKNOWN) {
151 		node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp313a");
152 		if (node >= 0) {
153 			pmic = AXP313;
154 		}
155 	}
156 
157 	if (pmic == UNKNOWN) {
158 		INFO("PMIC: No known PMIC in DT, skipping setup.\n");
159 		return -ENODEV;
160 	}
161 
162 	if (fdt_read_uint32(fdt, node, "reg", &reg)) {
163 		ERROR("PMIC: PMIC DT node does not contain reg property.\n");
164 		return -EINVAL;
165 	}
166 
167 	pmic_bus_addr = reg;
168 	parent = fdt_parent_offset(fdt, node);
169 	ret = fdt_node_check_compatible(fdt, parent, "allwinner,sun8i-a23-rsb");
170 	if (ret == 0) {
171 		rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr);
172 		if (rsb_rt_addr == 0) {
173 			ERROR("PMIC: no mapping for RSB address 0x%x\n",
174 			      pmic_bus_addr);
175 			return -EINVAL;
176 		}
177 	}
178 
179 	INFO("Probing for PMIC on %s:\n", is_using_rsb() ? "RSB" : "I2C");
180 
181 	ret = pmic_bus_init(socid, pmic_bus_addr);
182 	if (ret) {
183 		return ret;
184 	}
185 
186 	ret = axp_read(0x03);
187 	switch (ret & 0xcf) {
188 	case 0x40:				/* AXP305 */
189 		if (pmic == AXP305) {
190 			INFO("PMIC: found AXP305, setting up regulators\n");
191 			axp_setup_regulators(fdt);
192 		} else {
193 			pmic = UNKNOWN;
194 		}
195 		break;
196 	case 0x48:				/* AXP1530 */
197 	case 0x4b:				/* AXP313A */
198 	case 0x4c:				/* AXP313B */
199 		if (pmic == AXP313) {
200 			INFO("PMIC: found AXP313\n");
201 			/* no regulators to set up */
202 		} else {
203 			pmic = UNKNOWN;
204 		}
205 		break;
206 	}
207 
208 	if (is_using_rsb()) {
209 		/* Switch the PMIC back to I2C mode. */
210 		return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C);
211 	}
212 
213 	if (pmic == UNKNOWN) {
214 		INFO("Incompatible or unknown PMIC found.\n");
215 		return -ENODEV;
216 	}
217 
218 	return 0;
219 }
220 
221 void sunxi_power_down(void)
222 {
223 	int ret;
224 
225 	if (pmic == UNKNOWN) {
226 		return;
227 	}
228 
229 	/* Re-initialise after rich OS might have used it. */
230 	ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr);
231 	if (ret) {
232 		return;
233 	}
234 
235 	switch (pmic) {
236 	case AXP305:
237 		axp_setbits(0x32, BIT(7));
238 		break;
239 	case AXP313:
240 		axp_setbits(0x1a, BIT(7));
241 		break;
242 	default:
243 		break;
244 	}
245 }
246 
247 void sunxi_cpu_power_off_self(void)
248 {
249 	u_register_t mpidr = read_mpidr();
250 	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
251 
252 	/* Enable the CPUIDLE hardware (only really needs to be done once). */
253 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
254 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
255 
256 	/* Trigger power off for this core. */
257 	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
258 }
259