xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h616/sunxi_power.c (revision a0597ba2d824adc74ce250019f3d24d1a06ae144)
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 <lib/mmio.h>
17 #include <libfdt.h>
18 
19 #include <sunxi_cpucfg.h>
20 #include <sunxi_def.h>
21 #include <sunxi_mmap.h>
22 #include <sunxi_private.h>
23 
24 static uint16_t pmic_bus_addr;
25 static uint8_t rsb_rt_addr;
26 
27 static enum pmic_type {
28 	UNKNOWN,
29 	AXP305,
30 } pmic;
31 
32 static uint8_t get_rsb_rt_address(uint16_t hw_addr)
33 {
34 	switch (hw_addr) {
35 	case 0x745: return 0x3a;
36 	}
37 
38 	return 0;
39 }
40 
41 int axp_read(uint8_t reg)
42 {
43 	return rsb_read(rsb_rt_addr, reg);
44 }
45 
46 int axp_write(uint8_t reg, uint8_t val)
47 {
48 	return rsb_write(rsb_rt_addr, reg, val);
49 }
50 
51 static int rsb_init(int rsb_hw_addr)
52 {
53 	int ret;
54 
55 	ret = rsb_init_controller();
56 	if (ret) {
57 		return ret;
58 	}
59 
60 	/* Switch to the recommended 3 MHz bus clock. */
61 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
62 	if (ret) {
63 		return ret;
64 	}
65 
66 	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
67 	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
68 	if (ret) {
69 		return ret;
70 	}
71 
72 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
73 	ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr);
74 	if (ret) {
75 		return ret;
76 	}
77 
78 	return 0;
79 }
80 
81 static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr)
82 {
83 	int ret;
84 
85 	ret = sunxi_init_platform_r_twi(socid, true);
86 	if (ret) {
87 		INFO("Could not init platform bus: %d\n", ret);
88 		pmic = UNKNOWN;
89 		return ret;
90 	}
91 
92 	ret = rsb_init(rsb_hw_addr);
93 	if (ret) {
94 		pmic = UNKNOWN;
95 		return ret;
96 	}
97 
98 	return 0;
99 }
100 
101 int sunxi_pmic_setup(uint16_t socid, const void *fdt)
102 {
103 	int node, ret;
104 	uint32_t reg;
105 
106 	node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806");
107 	if (node >= 0) {
108 		pmic = AXP305;
109 	}
110 
111 	if (pmic == UNKNOWN) {
112 		INFO("PMIC: No known PMIC in DT, skipping setup.\n");
113 		return -ENODEV;
114 	}
115 
116 	if (fdt_read_uint32(fdt, node, "reg", &reg)) {
117 		ERROR("PMIC: PMIC DT node does not contain reg property.\n");
118 		return -EINVAL;
119 	}
120 
121 	pmic_bus_addr = reg;
122 	rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr);
123 	if (rsb_rt_addr == 0) {
124 		ERROR("PMIC: no mapping for RSB address 0x%x\n", reg);
125 		return -EINVAL;
126 	}
127 
128 	INFO("Probing for PMIC on RSB:\n");
129 
130 	ret = pmic_bus_init(socid, pmic_bus_addr);
131 	if (ret) {
132 		return ret;
133 	}
134 
135 	ret = axp_read(0x03);
136 	switch (ret & 0xcf) {
137 	case 0x40:				/* AXP305 */
138 		if (pmic == AXP305) {
139 			INFO("PMIC: found AXP305, setting up regulators\n");
140 			axp_setup_regulators(fdt);
141 		} else {
142 			pmic = UNKNOWN;
143 		}
144 		break;
145 	}
146 
147 	/* Switch the PMIC back to I2C mode. */
148 	return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C);
149 }
150 
151 void sunxi_power_down(void)
152 {
153 	int ret;
154 
155 	if (pmic == UNKNOWN) {
156 		return;
157 	}
158 
159 	/* Re-initialise after rich OS might have used it. */
160 	ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr);
161 	if (ret) {
162 		return;
163 	}
164 
165 	switch (pmic) {
166 	case AXP305:
167 		axp_setbits(0x32, BIT(7));
168 		break;
169 	default:
170 		break;
171 	}
172 }
173 
174 void sunxi_cpu_power_off_self(void)
175 {
176 	u_register_t mpidr = read_mpidr();
177 	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
178 
179 	/* Enable the CPUIDLE hardware (only really needs to be done once). */
180 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
181 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
182 
183 	/* Trigger power off for this core. */
184 	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
185 }
186