xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h616/sunxi_power.c (revision 044458981f986b03445185b646bebbea1d90f11f)
126123ca3SAndre Przywara /*
226123ca3SAndre Przywara  * Copyright (c) 2017-2020, ARM Limited. All rights reserved.
326123ca3SAndre Przywara  * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
426123ca3SAndre Przywara  *
526123ca3SAndre Przywara  * SPDX-License-Identifier: BSD-3-Clause
626123ca3SAndre Przywara  */
726123ca3SAndre Przywara 
826123ca3SAndre Przywara #include <errno.h>
926123ca3SAndre Przywara #include <string.h>
1026123ca3SAndre Przywara 
1126123ca3SAndre Przywara #include <arch_helpers.h>
1226123ca3SAndre Przywara #include <common/debug.h>
13a0597ba2SAndre Przywara #include <common/fdt_wrappers.h>
1426123ca3SAndre Przywara #include <drivers/allwinner/axp.h>
1526123ca3SAndre Przywara #include <drivers/allwinner/sunxi_rsb.h>
16*04445898SAndre Przywara #include <drivers/mentor/mi2cv.h>
1726123ca3SAndre Przywara #include <lib/mmio.h>
18a0597ba2SAndre Przywara #include <libfdt.h>
1926123ca3SAndre Przywara 
2026123ca3SAndre Przywara #include <sunxi_cpucfg.h>
2126123ca3SAndre Przywara #include <sunxi_def.h>
2226123ca3SAndre Przywara #include <sunxi_mmap.h>
2326123ca3SAndre Przywara #include <sunxi_private.h>
2426123ca3SAndre Przywara 
25a0597ba2SAndre Przywara static uint16_t pmic_bus_addr;
26a0597ba2SAndre Przywara static uint8_t rsb_rt_addr;
2726123ca3SAndre Przywara 
28*04445898SAndre Przywara static bool is_using_rsb(void)
29*04445898SAndre Przywara {
30*04445898SAndre Przywara 	return rsb_rt_addr != 0;
31*04445898SAndre Przywara }
32*04445898SAndre Przywara 
3326123ca3SAndre Przywara static enum pmic_type {
3426123ca3SAndre Przywara 	UNKNOWN,
3526123ca3SAndre Przywara 	AXP305,
3626123ca3SAndre Przywara } pmic;
3726123ca3SAndre Przywara 
38a0597ba2SAndre Przywara static uint8_t get_rsb_rt_address(uint16_t hw_addr)
3926123ca3SAndre Przywara {
40a0597ba2SAndre Przywara 	switch (hw_addr) {
41a0597ba2SAndre Przywara 	case 0x745: return 0x3a;
4226123ca3SAndre Przywara 	}
4326123ca3SAndre Przywara 
4426123ca3SAndre Przywara 	return 0;
4526123ca3SAndre Przywara }
4626123ca3SAndre Przywara 
47a0597ba2SAndre Przywara int axp_read(uint8_t reg)
48a0597ba2SAndre Przywara {
49*04445898SAndre Przywara 	uint8_t val;
50*04445898SAndre Przywara 	int ret;
51*04445898SAndre Przywara 
52*04445898SAndre Przywara 	if (is_using_rsb()) {
53a0597ba2SAndre Przywara 		return rsb_read(rsb_rt_addr, reg);
54a0597ba2SAndre Przywara 	}
55a0597ba2SAndre Przywara 
56*04445898SAndre Przywara 	ret = i2c_write(pmic_bus_addr, 0, 0, &reg, 1);
57*04445898SAndre Przywara 	if (ret == 0) {
58*04445898SAndre Przywara 		ret = i2c_read(pmic_bus_addr, 0, 0, &val, 1);
59*04445898SAndre Przywara 	}
60*04445898SAndre Przywara 	if (ret) {
61*04445898SAndre Przywara 		ERROR("PMIC: Cannot read PMIC register %02x\n", reg);
62*04445898SAndre Przywara 		return ret;
63*04445898SAndre Przywara 	}
64*04445898SAndre Przywara 
65*04445898SAndre Przywara 	return val;
66*04445898SAndre Przywara }
67*04445898SAndre Przywara 
68a0597ba2SAndre Przywara int axp_write(uint8_t reg, uint8_t val)
69a0597ba2SAndre Przywara {
70*04445898SAndre Przywara 	int ret;
71*04445898SAndre Przywara 
72*04445898SAndre Przywara 	if (is_using_rsb()) {
73a0597ba2SAndre Przywara 		return rsb_write(rsb_rt_addr, reg, val);
74a0597ba2SAndre Przywara 	}
75a0597ba2SAndre Przywara 
76*04445898SAndre Przywara 	ret = i2c_write(pmic_bus_addr, reg, 1, &val, 1);
77*04445898SAndre Przywara 	if (ret) {
78*04445898SAndre Przywara 		ERROR("PMIC: Cannot write PMIC register %02x\n", reg);
79*04445898SAndre Przywara 	}
80*04445898SAndre Przywara 
81*04445898SAndre Przywara 	return ret;
82*04445898SAndre Przywara }
83*04445898SAndre Przywara 
84a0597ba2SAndre Przywara static int rsb_init(int rsb_hw_addr)
85a0597ba2SAndre Przywara {
86a0597ba2SAndre Przywara 	int ret;
87a0597ba2SAndre Przywara 
88a0597ba2SAndre Przywara 	ret = rsb_init_controller();
89a0597ba2SAndre Przywara 	if (ret) {
90a0597ba2SAndre Przywara 		return ret;
91a0597ba2SAndre Przywara 	}
92a0597ba2SAndre Przywara 
93a0597ba2SAndre Przywara 	/* Switch to the recommended 3 MHz bus clock. */
94a0597ba2SAndre Przywara 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
95a0597ba2SAndre Przywara 	if (ret) {
96a0597ba2SAndre Przywara 		return ret;
97a0597ba2SAndre Przywara 	}
98a0597ba2SAndre Przywara 
99a0597ba2SAndre Przywara 	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
100a0597ba2SAndre Przywara 	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
101a0597ba2SAndre Przywara 	if (ret) {
102a0597ba2SAndre Przywara 		return ret;
103a0597ba2SAndre Przywara 	}
104a0597ba2SAndre Przywara 
105a0597ba2SAndre Przywara 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
106a0597ba2SAndre Przywara 	ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr);
107a0597ba2SAndre Przywara 	if (ret) {
108a0597ba2SAndre Przywara 		return ret;
109a0597ba2SAndre Przywara 	}
110a0597ba2SAndre Przywara 
111a0597ba2SAndre Przywara 	return 0;
112a0597ba2SAndre Przywara }
113a0597ba2SAndre Przywara 
114a0597ba2SAndre Przywara static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr)
115a0597ba2SAndre Przywara {
116a0597ba2SAndre Przywara 	int ret;
117a0597ba2SAndre Przywara 
118*04445898SAndre Przywara 	ret = sunxi_init_platform_r_twi(socid, is_using_rsb());
119a0597ba2SAndre Przywara 	if (ret) {
120a0597ba2SAndre Przywara 		INFO("Could not init platform bus: %d\n", ret);
121a0597ba2SAndre Przywara 		pmic = UNKNOWN;
122a0597ba2SAndre Przywara 		return ret;
123a0597ba2SAndre Przywara 	}
124a0597ba2SAndre Przywara 
125*04445898SAndre Przywara 	if (is_using_rsb()) {
126a0597ba2SAndre Przywara 		ret = rsb_init(rsb_hw_addr);
127a0597ba2SAndre Przywara 		if (ret) {
128a0597ba2SAndre Przywara 			pmic = UNKNOWN;
129a0597ba2SAndre Przywara 			return ret;
130a0597ba2SAndre Przywara 		}
131*04445898SAndre Przywara 	} else {
132*04445898SAndre Przywara 		/* initialise mi2cv driver */
133*04445898SAndre Przywara 		i2c_init((void *)SUNXI_R_I2C_BASE);
134*04445898SAndre Przywara 	}
135a0597ba2SAndre Przywara 
136a0597ba2SAndre Przywara 	return 0;
137a0597ba2SAndre Przywara }
138a0597ba2SAndre Przywara 
139a0597ba2SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt)
140a0597ba2SAndre Przywara {
141*04445898SAndre Przywara 	int node, parent, ret;
142a0597ba2SAndre Przywara 	uint32_t reg;
143a0597ba2SAndre Przywara 
144a0597ba2SAndre Przywara 	node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806");
145a0597ba2SAndre Przywara 	if (node >= 0) {
146a0597ba2SAndre Przywara 		pmic = AXP305;
147a0597ba2SAndre Przywara 	}
148a0597ba2SAndre Przywara 
149a0597ba2SAndre Przywara 	if (pmic == UNKNOWN) {
150a0597ba2SAndre Przywara 		INFO("PMIC: No known PMIC in DT, skipping setup.\n");
151a0597ba2SAndre Przywara 		return -ENODEV;
152a0597ba2SAndre Przywara 	}
153a0597ba2SAndre Przywara 
154a0597ba2SAndre Przywara 	if (fdt_read_uint32(fdt, node, "reg", &reg)) {
155a0597ba2SAndre Przywara 		ERROR("PMIC: PMIC DT node does not contain reg property.\n");
156a0597ba2SAndre Przywara 		return -EINVAL;
157a0597ba2SAndre Przywara 	}
158a0597ba2SAndre Przywara 
159a0597ba2SAndre Przywara 	pmic_bus_addr = reg;
160*04445898SAndre Przywara 	parent = fdt_parent_offset(fdt, node);
161*04445898SAndre Przywara 	ret = fdt_node_check_compatible(fdt, parent, "allwinner,sun8i-a23-rsb");
162*04445898SAndre Przywara 	if (ret == 0) {
163a0597ba2SAndre Przywara 		rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr);
164a0597ba2SAndre Przywara 		if (rsb_rt_addr == 0) {
165*04445898SAndre Przywara 			ERROR("PMIC: no mapping for RSB address 0x%x\n",
166*04445898SAndre Przywara 			      pmic_bus_addr);
167a0597ba2SAndre Przywara 			return -EINVAL;
168a0597ba2SAndre Przywara 		}
169*04445898SAndre Przywara 	}
170a0597ba2SAndre Przywara 
171*04445898SAndre Przywara 	INFO("Probing for PMIC on %s:\n", is_using_rsb() ? "RSB" : "I2C");
172a0597ba2SAndre Przywara 
173a0597ba2SAndre Przywara 	ret = pmic_bus_init(socid, pmic_bus_addr);
174a0597ba2SAndre Przywara 	if (ret) {
175a0597ba2SAndre Przywara 		return ret;
176a0597ba2SAndre Przywara 	}
177a0597ba2SAndre Przywara 
178a0597ba2SAndre Przywara 	ret = axp_read(0x03);
179a0597ba2SAndre Przywara 	switch (ret & 0xcf) {
180a0597ba2SAndre Przywara 	case 0x40:				/* AXP305 */
181a0597ba2SAndre Przywara 		if (pmic == AXP305) {
182a0597ba2SAndre Przywara 			INFO("PMIC: found AXP305, setting up regulators\n");
183a0597ba2SAndre Przywara 			axp_setup_regulators(fdt);
184a0597ba2SAndre Przywara 		} else {
185a0597ba2SAndre Przywara 			pmic = UNKNOWN;
186a0597ba2SAndre Przywara 		}
187a0597ba2SAndre Przywara 		break;
188a0597ba2SAndre Przywara 	}
189a0597ba2SAndre Przywara 
190*04445898SAndre Przywara 	if (is_using_rsb()) {
191a0597ba2SAndre Przywara 		/* Switch the PMIC back to I2C mode. */
192a0597ba2SAndre Przywara 		return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C);
193a0597ba2SAndre Przywara 	}
194a0597ba2SAndre Przywara 
195*04445898SAndre Przywara 	if (pmic == UNKNOWN) {
196*04445898SAndre Przywara 		INFO("Incompatible or unknown PMIC found.\n");
197*04445898SAndre Przywara 		return -ENODEV;
198*04445898SAndre Przywara 	}
199*04445898SAndre Przywara 
200*04445898SAndre Przywara 	return 0;
201*04445898SAndre Przywara }
202*04445898SAndre Przywara 
20326123ca3SAndre Przywara void sunxi_power_down(void)
20426123ca3SAndre Przywara {
205a0597ba2SAndre Przywara 	int ret;
206a0597ba2SAndre Przywara 
207a0597ba2SAndre Przywara 	if (pmic == UNKNOWN) {
208a0597ba2SAndre Przywara 		return;
209a0597ba2SAndre Przywara 	}
210a0597ba2SAndre Przywara 
211a0597ba2SAndre Przywara 	/* Re-initialise after rich OS might have used it. */
212a0597ba2SAndre Przywara 	ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr);
213a0597ba2SAndre Przywara 	if (ret) {
214a0597ba2SAndre Przywara 		return;
215a0597ba2SAndre Przywara 	}
216a0597ba2SAndre Przywara 
21726123ca3SAndre Przywara 	switch (pmic) {
21826123ca3SAndre Przywara 	case AXP305:
219a0597ba2SAndre Przywara 		axp_setbits(0x32, BIT(7));
22026123ca3SAndre Przywara 		break;
22126123ca3SAndre Przywara 	default:
22226123ca3SAndre Przywara 		break;
22326123ca3SAndre Przywara 	}
22426123ca3SAndre Przywara }
22526123ca3SAndre Przywara 
22626123ca3SAndre Przywara void sunxi_cpu_power_off_self(void)
22726123ca3SAndre Przywara {
22826123ca3SAndre Przywara 	u_register_t mpidr = read_mpidr();
22926123ca3SAndre Przywara 	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
23026123ca3SAndre Przywara 
23126123ca3SAndre Przywara 	/* Enable the CPUIDLE hardware (only really needs to be done once). */
23226123ca3SAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
23326123ca3SAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
23426123ca3SAndre Przywara 
23526123ca3SAndre Przywara 	/* Trigger power off for this core. */
23626123ca3SAndre Przywara 	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
23726123ca3SAndre Przywara }
238