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