xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h616/sunxi_power.c (revision 26123ca35313426b2f88a5983e5e69173d1d62d0)
1*26123ca3SAndre Przywara /*
2*26123ca3SAndre Przywara  * Copyright (c) 2017-2020, ARM Limited. All rights reserved.
3*26123ca3SAndre Przywara  * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
4*26123ca3SAndre Przywara  *
5*26123ca3SAndre Przywara  * SPDX-License-Identifier: BSD-3-Clause
6*26123ca3SAndre Przywara  */
7*26123ca3SAndre Przywara 
8*26123ca3SAndre Przywara #include <errno.h>
9*26123ca3SAndre Przywara #include <string.h>
10*26123ca3SAndre Przywara 
11*26123ca3SAndre Przywara #include <arch_helpers.h>
12*26123ca3SAndre Przywara #include <common/debug.h>
13*26123ca3SAndre Przywara #include <drivers/allwinner/axp.h>
14*26123ca3SAndre Przywara #include <drivers/allwinner/sunxi_rsb.h>
15*26123ca3SAndre Przywara #include <lib/mmio.h>
16*26123ca3SAndre Przywara 
17*26123ca3SAndre Przywara #include <sunxi_cpucfg.h>
18*26123ca3SAndre Przywara #include <sunxi_def.h>
19*26123ca3SAndre Przywara #include <sunxi_mmap.h>
20*26123ca3SAndre Przywara #include <sunxi_private.h>
21*26123ca3SAndre Przywara 
22*26123ca3SAndre Przywara #define AXP305_I2C_ADDR	0x36
23*26123ca3SAndre Przywara #define AXP305_HW_ADDR	0x745
24*26123ca3SAndre Przywara #define AXP305_RT_ADDR	0x3a
25*26123ca3SAndre Przywara 
26*26123ca3SAndre Przywara static enum pmic_type {
27*26123ca3SAndre Przywara 	UNKNOWN,
28*26123ca3SAndre Przywara 	AXP305,
29*26123ca3SAndre Przywara } pmic;
30*26123ca3SAndre Przywara 
31*26123ca3SAndre Przywara int axp_read(uint8_t reg)
32*26123ca3SAndre Przywara {
33*26123ca3SAndre Przywara 	return rsb_read(AXP305_RT_ADDR, reg);
34*26123ca3SAndre Przywara }
35*26123ca3SAndre Przywara 
36*26123ca3SAndre Przywara int axp_write(uint8_t reg, uint8_t val)
37*26123ca3SAndre Przywara {
38*26123ca3SAndre Przywara 	return rsb_write(AXP305_RT_ADDR, reg, val);
39*26123ca3SAndre Przywara }
40*26123ca3SAndre Przywara 
41*26123ca3SAndre Przywara static int rsb_init(void)
42*26123ca3SAndre Przywara {
43*26123ca3SAndre Przywara 	int ret;
44*26123ca3SAndre Przywara 
45*26123ca3SAndre Przywara 	ret = rsb_init_controller();
46*26123ca3SAndre Przywara 	if (ret)
47*26123ca3SAndre Przywara 		return ret;
48*26123ca3SAndre Przywara 
49*26123ca3SAndre Przywara 	/* Switch to the recommended 3 MHz bus clock. */
50*26123ca3SAndre Przywara 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
51*26123ca3SAndre Przywara 	if (ret)
52*26123ca3SAndre Przywara 		return ret;
53*26123ca3SAndre Przywara 
54*26123ca3SAndre Przywara 	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
55*26123ca3SAndre Przywara 	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
56*26123ca3SAndre Przywara 	if (ret)
57*26123ca3SAndre Przywara 		return ret;
58*26123ca3SAndre Przywara 
59*26123ca3SAndre Przywara 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
60*26123ca3SAndre Przywara 	ret = rsb_assign_runtime_address(AXP305_HW_ADDR, AXP305_RT_ADDR);
61*26123ca3SAndre Przywara 	if (ret)
62*26123ca3SAndre Przywara 		return ret;
63*26123ca3SAndre Przywara 
64*26123ca3SAndre Przywara 	return axp_check_id();
65*26123ca3SAndre Przywara }
66*26123ca3SAndre Przywara 
67*26123ca3SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt)
68*26123ca3SAndre Przywara {
69*26123ca3SAndre Przywara 	int ret;
70*26123ca3SAndre Przywara 
71*26123ca3SAndre Przywara 	INFO("PMIC: Probing AXP305 on RSB\n");
72*26123ca3SAndre Przywara 
73*26123ca3SAndre Przywara 	ret = sunxi_init_platform_r_twi(socid, true);
74*26123ca3SAndre Przywara 	if (ret) {
75*26123ca3SAndre Przywara 		INFO("Could not init platform bus: %d\n", ret);
76*26123ca3SAndre Przywara 		return ret;
77*26123ca3SAndre Przywara 	}
78*26123ca3SAndre Przywara 
79*26123ca3SAndre Przywara 	ret = rsb_init();
80*26123ca3SAndre Przywara 	if (ret) {
81*26123ca3SAndre Przywara 		INFO("Could not init RSB: %d\n", ret);
82*26123ca3SAndre Przywara 		return ret;
83*26123ca3SAndre Przywara 	}
84*26123ca3SAndre Przywara 
85*26123ca3SAndre Przywara 	pmic = AXP305;
86*26123ca3SAndre Przywara 	axp_setup_regulators(fdt);
87*26123ca3SAndre Przywara 
88*26123ca3SAndre Przywara 	/* Switch the PMIC back to I2C mode. */
89*26123ca3SAndre Przywara 	ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
90*26123ca3SAndre Przywara 	if (ret)
91*26123ca3SAndre Przywara 		return ret;
92*26123ca3SAndre Przywara 
93*26123ca3SAndre Przywara 	return 0;
94*26123ca3SAndre Przywara }
95*26123ca3SAndre Przywara 
96*26123ca3SAndre Przywara void sunxi_power_down(void)
97*26123ca3SAndre Przywara {
98*26123ca3SAndre Przywara 	switch (pmic) {
99*26123ca3SAndre Przywara 	case AXP305:
100*26123ca3SAndre Przywara 		/* Re-initialise after rich OS might have used it. */
101*26123ca3SAndre Przywara 		sunxi_init_platform_r_twi(SUNXI_SOC_H616, true);
102*26123ca3SAndre Przywara 		rsb_init();
103*26123ca3SAndre Przywara 		axp_power_off();
104*26123ca3SAndre Przywara 		break;
105*26123ca3SAndre Przywara 	default:
106*26123ca3SAndre Przywara 		break;
107*26123ca3SAndre Przywara 	}
108*26123ca3SAndre Przywara }
109*26123ca3SAndre Przywara 
110*26123ca3SAndre Przywara void sunxi_cpu_power_off_self(void)
111*26123ca3SAndre Przywara {
112*26123ca3SAndre Przywara 	u_register_t mpidr = read_mpidr();
113*26123ca3SAndre Przywara 	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
114*26123ca3SAndre Przywara 
115*26123ca3SAndre Przywara 	/* Enable the CPUIDLE hardware (only really needs to be done once). */
116*26123ca3SAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
117*26123ca3SAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
118*26123ca3SAndre Przywara 
119*26123ca3SAndre Przywara 	/* Trigger power off for this core. */
120*26123ca3SAndre Przywara 	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
121*26123ca3SAndre Przywara }
122