xref: /arm-trusted-firmware/plat/allwinner/sun50i_h6/sunxi_power.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2019, ARM Limited and Contributors. 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 
10*91f16700Schasinglulu #include <common/debug.h>
11*91f16700Schasinglulu #include <common/fdt_wrappers.h>
12*91f16700Schasinglulu #include <drivers/allwinner/axp.h>
13*91f16700Schasinglulu #include <drivers/allwinner/sunxi_rsb.h>
14*91f16700Schasinglulu #include <libfdt.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 AXP805_HW_ADDR	0x745
23*91f16700Schasinglulu #define AXP805_RT_ADDR	0x3a
24*91f16700Schasinglulu 
25*91f16700Schasinglulu static enum pmic_type {
26*91f16700Schasinglulu 	UNKNOWN,
27*91f16700Schasinglulu 	AXP805,
28*91f16700Schasinglulu } pmic;
29*91f16700Schasinglulu 
30*91f16700Schasinglulu int axp_read(uint8_t reg)
31*91f16700Schasinglulu {
32*91f16700Schasinglulu 	return rsb_read(AXP805_RT_ADDR, reg);
33*91f16700Schasinglulu }
34*91f16700Schasinglulu 
35*91f16700Schasinglulu int axp_write(uint8_t reg, uint8_t val)
36*91f16700Schasinglulu {
37*91f16700Schasinglulu 	return rsb_write(AXP805_RT_ADDR, reg, val);
38*91f16700Schasinglulu }
39*91f16700Schasinglulu 
40*91f16700Schasinglulu static int rsb_init(void)
41*91f16700Schasinglulu {
42*91f16700Schasinglulu 	int ret;
43*91f16700Schasinglulu 
44*91f16700Schasinglulu 	ret = rsb_init_controller();
45*91f16700Schasinglulu 	if (ret)
46*91f16700Schasinglulu 		return ret;
47*91f16700Schasinglulu 
48*91f16700Schasinglulu 	/* Switch to the recommended 3 MHz bus clock. */
49*91f16700Schasinglulu 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
50*91f16700Schasinglulu 	if (ret)
51*91f16700Schasinglulu 		return ret;
52*91f16700Schasinglulu 
53*91f16700Schasinglulu 	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
54*91f16700Schasinglulu 	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
55*91f16700Schasinglulu 	if (ret)
56*91f16700Schasinglulu 		return ret;
57*91f16700Schasinglulu 
58*91f16700Schasinglulu 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
59*91f16700Schasinglulu 	ret = rsb_assign_runtime_address(AXP805_HW_ADDR, AXP805_RT_ADDR);
60*91f16700Schasinglulu 	if (ret)
61*91f16700Schasinglulu 		return ret;
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 	return axp_check_id();
64*91f16700Schasinglulu }
65*91f16700Schasinglulu 
66*91f16700Schasinglulu int sunxi_pmic_setup(uint16_t socid, const void *fdt)
67*91f16700Schasinglulu {
68*91f16700Schasinglulu 	int node, ret;
69*91f16700Schasinglulu 
70*91f16700Schasinglulu 	node = fdt_node_offset_by_compatible(fdt, 0, "allwinner,sun8i-a23-rsb");
71*91f16700Schasinglulu 	if ((node < 0) || !fdt_node_is_enabled(fdt, node)) {
72*91f16700Schasinglulu 		return -ENODEV;
73*91f16700Schasinglulu 	}
74*91f16700Schasinglulu 
75*91f16700Schasinglulu 	INFO("PMIC: Probing AXP805 on RSB\n");
76*91f16700Schasinglulu 
77*91f16700Schasinglulu 	ret = sunxi_init_platform_r_twi(socid, true);
78*91f16700Schasinglulu 	if (ret)
79*91f16700Schasinglulu 		return ret;
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	ret = rsb_init();
82*91f16700Schasinglulu 	if (ret)
83*91f16700Schasinglulu 		return ret;
84*91f16700Schasinglulu 
85*91f16700Schasinglulu 	/* Switch the AXP805 to master/single-PMIC mode. */
86*91f16700Schasinglulu 	ret = axp_write(0xff, 0x0);
87*91f16700Schasinglulu 	if (ret)
88*91f16700Schasinglulu 		return ret;
89*91f16700Schasinglulu 
90*91f16700Schasinglulu 	pmic = AXP805;
91*91f16700Schasinglulu 	axp_setup_regulators(fdt);
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 	/* Switch the PMIC back to I2C mode. */
94*91f16700Schasinglulu 	ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
95*91f16700Schasinglulu 	if (ret)
96*91f16700Schasinglulu 		return ret;
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	return 0;
99*91f16700Schasinglulu }
100*91f16700Schasinglulu 
101*91f16700Schasinglulu void sunxi_power_down(void)
102*91f16700Schasinglulu {
103*91f16700Schasinglulu 	switch (pmic) {
104*91f16700Schasinglulu 	case AXP805:
105*91f16700Schasinglulu 		/* (Re-)init RSB in case the rich OS has disabled it. */
106*91f16700Schasinglulu 		sunxi_init_platform_r_twi(SUNXI_SOC_H6, true);
107*91f16700Schasinglulu 		rsb_init();
108*91f16700Schasinglulu 		axp_power_off();
109*91f16700Schasinglulu 		break;
110*91f16700Schasinglulu 	default:
111*91f16700Schasinglulu 		break;
112*91f16700Schasinglulu 	}
113*91f16700Schasinglulu }
114*91f16700Schasinglulu 
115*91f16700Schasinglulu void sunxi_cpu_power_off_self(void)
116*91f16700Schasinglulu {
117*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr();
118*91f16700Schasinglulu 	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
119*91f16700Schasinglulu 
120*91f16700Schasinglulu 	/* Enable the CPUIDLE hardware (only really needs to be done once). */
121*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
122*91f16700Schasinglulu 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
123*91f16700Schasinglulu 
124*91f16700Schasinglulu 	/* Trigger power off for this core. */
125*91f16700Schasinglulu 	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
126*91f16700Schasinglulu }
127