xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h616/sunxi_power.c (revision a0597ba2d824adc74ce250019f3d24d1a06ae144)
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>
13*a0597ba2SAndre Przywara #include <common/fdt_wrappers.h>
1426123ca3SAndre Przywara #include <drivers/allwinner/axp.h>
1526123ca3SAndre Przywara #include <drivers/allwinner/sunxi_rsb.h>
1626123ca3SAndre Przywara #include <lib/mmio.h>
17*a0597ba2SAndre Przywara #include <libfdt.h>
1826123ca3SAndre Przywara 
1926123ca3SAndre Przywara #include <sunxi_cpucfg.h>
2026123ca3SAndre Przywara #include <sunxi_def.h>
2126123ca3SAndre Przywara #include <sunxi_mmap.h>
2226123ca3SAndre Przywara #include <sunxi_private.h>
2326123ca3SAndre Przywara 
24*a0597ba2SAndre Przywara static uint16_t pmic_bus_addr;
25*a0597ba2SAndre Przywara static uint8_t rsb_rt_addr;
2626123ca3SAndre Przywara 
2726123ca3SAndre Przywara static enum pmic_type {
2826123ca3SAndre Przywara 	UNKNOWN,
2926123ca3SAndre Przywara 	AXP305,
3026123ca3SAndre Przywara } pmic;
3126123ca3SAndre Przywara 
32*a0597ba2SAndre Przywara static uint8_t get_rsb_rt_address(uint16_t hw_addr)
3326123ca3SAndre Przywara {
34*a0597ba2SAndre Przywara 	switch (hw_addr) {
35*a0597ba2SAndre Przywara 	case 0x745: return 0x3a;
3626123ca3SAndre Przywara 	}
3726123ca3SAndre Przywara 
3826123ca3SAndre Przywara 	return 0;
3926123ca3SAndre Przywara }
4026123ca3SAndre Przywara 
41*a0597ba2SAndre Przywara int axp_read(uint8_t reg)
42*a0597ba2SAndre Przywara {
43*a0597ba2SAndre Przywara 	return rsb_read(rsb_rt_addr, reg);
44*a0597ba2SAndre Przywara }
45*a0597ba2SAndre Przywara 
46*a0597ba2SAndre Przywara int axp_write(uint8_t reg, uint8_t val)
47*a0597ba2SAndre Przywara {
48*a0597ba2SAndre Przywara 	return rsb_write(rsb_rt_addr, reg, val);
49*a0597ba2SAndre Przywara }
50*a0597ba2SAndre Przywara 
51*a0597ba2SAndre Przywara static int rsb_init(int rsb_hw_addr)
52*a0597ba2SAndre Przywara {
53*a0597ba2SAndre Przywara 	int ret;
54*a0597ba2SAndre Przywara 
55*a0597ba2SAndre Przywara 	ret = rsb_init_controller();
56*a0597ba2SAndre Przywara 	if (ret) {
57*a0597ba2SAndre Przywara 		return ret;
58*a0597ba2SAndre Przywara 	}
59*a0597ba2SAndre Przywara 
60*a0597ba2SAndre Przywara 	/* Switch to the recommended 3 MHz bus clock. */
61*a0597ba2SAndre Przywara 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
62*a0597ba2SAndre Przywara 	if (ret) {
63*a0597ba2SAndre Przywara 		return ret;
64*a0597ba2SAndre Przywara 	}
65*a0597ba2SAndre Przywara 
66*a0597ba2SAndre Przywara 	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
67*a0597ba2SAndre Przywara 	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
68*a0597ba2SAndre Przywara 	if (ret) {
69*a0597ba2SAndre Przywara 		return ret;
70*a0597ba2SAndre Przywara 	}
71*a0597ba2SAndre Przywara 
72*a0597ba2SAndre Przywara 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
73*a0597ba2SAndre Przywara 	ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr);
74*a0597ba2SAndre Przywara 	if (ret) {
75*a0597ba2SAndre Przywara 		return ret;
76*a0597ba2SAndre Przywara 	}
77*a0597ba2SAndre Przywara 
78*a0597ba2SAndre Przywara 	return 0;
79*a0597ba2SAndre Przywara }
80*a0597ba2SAndre Przywara 
81*a0597ba2SAndre Przywara static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr)
82*a0597ba2SAndre Przywara {
83*a0597ba2SAndre Przywara 	int ret;
84*a0597ba2SAndre Przywara 
85*a0597ba2SAndre Przywara 	ret = sunxi_init_platform_r_twi(socid, true);
86*a0597ba2SAndre Przywara 	if (ret) {
87*a0597ba2SAndre Przywara 		INFO("Could not init platform bus: %d\n", ret);
88*a0597ba2SAndre Przywara 		pmic = UNKNOWN;
89*a0597ba2SAndre Przywara 		return ret;
90*a0597ba2SAndre Przywara 	}
91*a0597ba2SAndre Przywara 
92*a0597ba2SAndre Przywara 	ret = rsb_init(rsb_hw_addr);
93*a0597ba2SAndre Przywara 	if (ret) {
94*a0597ba2SAndre Przywara 		pmic = UNKNOWN;
95*a0597ba2SAndre Przywara 		return ret;
96*a0597ba2SAndre Przywara 	}
97*a0597ba2SAndre Przywara 
98*a0597ba2SAndre Przywara 	return 0;
99*a0597ba2SAndre Przywara }
100*a0597ba2SAndre Przywara 
101*a0597ba2SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt)
102*a0597ba2SAndre Przywara {
103*a0597ba2SAndre Przywara 	int node, ret;
104*a0597ba2SAndre Przywara 	uint32_t reg;
105*a0597ba2SAndre Przywara 
106*a0597ba2SAndre Przywara 	node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806");
107*a0597ba2SAndre Przywara 	if (node >= 0) {
108*a0597ba2SAndre Przywara 		pmic = AXP305;
109*a0597ba2SAndre Przywara 	}
110*a0597ba2SAndre Przywara 
111*a0597ba2SAndre Przywara 	if (pmic == UNKNOWN) {
112*a0597ba2SAndre Przywara 		INFO("PMIC: No known PMIC in DT, skipping setup.\n");
113*a0597ba2SAndre Przywara 		return -ENODEV;
114*a0597ba2SAndre Przywara 	}
115*a0597ba2SAndre Przywara 
116*a0597ba2SAndre Przywara 	if (fdt_read_uint32(fdt, node, "reg", &reg)) {
117*a0597ba2SAndre Przywara 		ERROR("PMIC: PMIC DT node does not contain reg property.\n");
118*a0597ba2SAndre Przywara 		return -EINVAL;
119*a0597ba2SAndre Przywara 	}
120*a0597ba2SAndre Przywara 
121*a0597ba2SAndre Przywara 	pmic_bus_addr = reg;
122*a0597ba2SAndre Przywara 	rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr);
123*a0597ba2SAndre Przywara 	if (rsb_rt_addr == 0) {
124*a0597ba2SAndre Przywara 		ERROR("PMIC: no mapping for RSB address 0x%x\n", reg);
125*a0597ba2SAndre Przywara 		return -EINVAL;
126*a0597ba2SAndre Przywara 	}
127*a0597ba2SAndre Przywara 
128*a0597ba2SAndre Przywara 	INFO("Probing for PMIC on RSB:\n");
129*a0597ba2SAndre Przywara 
130*a0597ba2SAndre Przywara 	ret = pmic_bus_init(socid, pmic_bus_addr);
131*a0597ba2SAndre Przywara 	if (ret) {
132*a0597ba2SAndre Przywara 		return ret;
133*a0597ba2SAndre Przywara 	}
134*a0597ba2SAndre Przywara 
135*a0597ba2SAndre Przywara 	ret = axp_read(0x03);
136*a0597ba2SAndre Przywara 	switch (ret & 0xcf) {
137*a0597ba2SAndre Przywara 	case 0x40:				/* AXP305 */
138*a0597ba2SAndre Przywara 		if (pmic == AXP305) {
139*a0597ba2SAndre Przywara 			INFO("PMIC: found AXP305, setting up regulators\n");
140*a0597ba2SAndre Przywara 			axp_setup_regulators(fdt);
141*a0597ba2SAndre Przywara 		} else {
142*a0597ba2SAndre Przywara 			pmic = UNKNOWN;
143*a0597ba2SAndre Przywara 		}
144*a0597ba2SAndre Przywara 		break;
145*a0597ba2SAndre Przywara 	}
146*a0597ba2SAndre Przywara 
147*a0597ba2SAndre Przywara 	/* Switch the PMIC back to I2C mode. */
148*a0597ba2SAndre Przywara 	return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C);
149*a0597ba2SAndre Przywara }
150*a0597ba2SAndre Przywara 
15126123ca3SAndre Przywara void sunxi_power_down(void)
15226123ca3SAndre Przywara {
153*a0597ba2SAndre Przywara 	int ret;
154*a0597ba2SAndre Przywara 
155*a0597ba2SAndre Przywara 	if (pmic == UNKNOWN) {
156*a0597ba2SAndre Przywara 		return;
157*a0597ba2SAndre Przywara 	}
158*a0597ba2SAndre Przywara 
159*a0597ba2SAndre Przywara 	/* Re-initialise after rich OS might have used it. */
160*a0597ba2SAndre Przywara 	ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr);
161*a0597ba2SAndre Przywara 	if (ret) {
162*a0597ba2SAndre Przywara 		return;
163*a0597ba2SAndre Przywara 	}
164*a0597ba2SAndre Przywara 
16526123ca3SAndre Przywara 	switch (pmic) {
16626123ca3SAndre Przywara 	case AXP305:
167*a0597ba2SAndre Przywara 		axp_setbits(0x32, BIT(7));
16826123ca3SAndre Przywara 		break;
16926123ca3SAndre Przywara 	default:
17026123ca3SAndre Przywara 		break;
17126123ca3SAndre Przywara 	}
17226123ca3SAndre Przywara }
17326123ca3SAndre Przywara 
17426123ca3SAndre Przywara void sunxi_cpu_power_off_self(void)
17526123ca3SAndre Przywara {
17626123ca3SAndre Przywara 	u_register_t mpidr = read_mpidr();
17726123ca3SAndre Przywara 	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
17826123ca3SAndre Przywara 
17926123ca3SAndre Przywara 	/* Enable the CPUIDLE hardware (only really needs to be done once). */
18026123ca3SAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
18126123ca3SAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
18226123ca3SAndre Przywara 
18326123ca3SAndre Przywara 	/* Trigger power off for this core. */
18426123ca3SAndre Przywara 	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
18526123ca3SAndre Przywara }
186