xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h6/sunxi_power.c (revision 9227719dbf4d2da4163cebc740e1b6e582b8e05f)
17c26b6ecSIcenowy Zheng /*
2c0e109f2SSamuel Holland  * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
37c26b6ecSIcenowy Zheng  * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
47c26b6ecSIcenowy Zheng  *
57c26b6ecSIcenowy Zheng  * SPDX-License-Identifier: BSD-3-Clause
67c26b6ecSIcenowy Zheng  */
77c26b6ecSIcenowy Zheng 
86d372828SIcenowy Zheng #include <errno.h>
909d40e0eSAntonio Nino Diaz 
1009d40e0eSAntonio Nino Diaz #include <common/debug.h>
11fb23b104SSamuel Holland #include <drivers/allwinner/axp.h>
127060e0d8SSamuel Holland #include <drivers/allwinner/sunxi_rsb.h>
13*9227719dSAndre Przywara #include <lib/mmio.h>
1409d40e0eSAntonio Nino Diaz 
15*9227719dSAndre Przywara #include <sunxi_cpucfg.h>
16d5ddf67aSAndre Przywara #include <sunxi_def.h>
176d372828SIcenowy Zheng #include <sunxi_mmap.h>
184ec1a239SAndre Przywara #include <sunxi_private.h>
196d372828SIcenowy Zheng 
207060e0d8SSamuel Holland #define AXP805_HW_ADDR	0x745
217060e0d8SSamuel Holland #define AXP805_RT_ADDR	0x3a
226d372828SIcenowy Zheng 
23c0e109f2SSamuel Holland static enum pmic_type {
24c0e109f2SSamuel Holland 	UNKNOWN,
256d372828SIcenowy Zheng 	AXP805,
26c0e109f2SSamuel Holland } pmic;
276d372828SIcenowy Zheng 
28fb23b104SSamuel Holland int axp_read(uint8_t reg)
296d372828SIcenowy Zheng {
307060e0d8SSamuel Holland 	return rsb_read(AXP805_RT_ADDR, reg);
31fb23b104SSamuel Holland }
32fb23b104SSamuel Holland 
33fb23b104SSamuel Holland int axp_write(uint8_t reg, uint8_t val)
346d372828SIcenowy Zheng {
357060e0d8SSamuel Holland 	return rsb_write(AXP805_RT_ADDR, reg, val);
366d372828SIcenowy Zheng }
376d372828SIcenowy Zheng 
387060e0d8SSamuel Holland static int rsb_init(void)
396d372828SIcenowy Zheng {
406d372828SIcenowy Zheng 	int ret;
416d372828SIcenowy Zheng 
427060e0d8SSamuel Holland 	ret = rsb_init_controller();
434538c498SSamuel Holland 	if (ret)
444538c498SSamuel Holland 		return ret;
456d372828SIcenowy Zheng 
467060e0d8SSamuel Holland 	/* Switch to the recommended 3 MHz bus clock. */
477060e0d8SSamuel Holland 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
484538c498SSamuel Holland 	if (ret)
494538c498SSamuel Holland 		return ret;
506d372828SIcenowy Zheng 
517060e0d8SSamuel Holland 	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
527060e0d8SSamuel Holland 	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
537060e0d8SSamuel Holland 	if (ret)
547060e0d8SSamuel Holland 		return ret;
557060e0d8SSamuel Holland 
567060e0d8SSamuel Holland 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
577060e0d8SSamuel Holland 	ret = rsb_assign_runtime_address(AXP805_HW_ADDR, AXP805_RT_ADDR);
587060e0d8SSamuel Holland 	if (ret)
597060e0d8SSamuel Holland 		return ret;
607060e0d8SSamuel Holland 
617060e0d8SSamuel Holland 	return axp_check_id();
626d372828SIcenowy Zheng }
637c26b6ecSIcenowy Zheng 
64df301601SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt)
657c26b6ecSIcenowy Zheng {
666d372828SIcenowy Zheng 	int ret;
676d372828SIcenowy Zheng 
687060e0d8SSamuel Holland 	INFO("PMIC: Probing AXP805 on RSB\n");
694538c498SSamuel Holland 
707060e0d8SSamuel Holland 	ret = sunxi_init_platform_r_twi(socid, true);
714538c498SSamuel Holland 	if (ret)
724538c498SSamuel Holland 		return ret;
734538c498SSamuel Holland 
747060e0d8SSamuel Holland 	ret = rsb_init();
757060e0d8SSamuel Holland 	if (ret)
767060e0d8SSamuel Holland 		return ret;
776d372828SIcenowy Zheng 
787060e0d8SSamuel Holland 	/* Switch the AXP805 to master/single-PMIC mode. */
797060e0d8SSamuel Holland 	ret = axp_write(0xff, 0x0);
806d372828SIcenowy Zheng 	if (ret)
81c0e109f2SSamuel Holland 		return ret;
82c0e109f2SSamuel Holland 
836d372828SIcenowy Zheng 	pmic = AXP805;
84fb23b104SSamuel Holland 	axp_setup_regulators(fdt);
857c26b6ecSIcenowy Zheng 
867060e0d8SSamuel Holland 	/* Switch the PMIC back to I2C mode. */
877060e0d8SSamuel Holland 	ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
887060e0d8SSamuel Holland 	if (ret)
897060e0d8SSamuel Holland 		return ret;
907060e0d8SSamuel Holland 
917c26b6ecSIcenowy Zheng 	return 0;
927c26b6ecSIcenowy Zheng }
935069c1cfSIcenowy Zheng 
94818e6732SSamuel Holland void sunxi_power_down(void)
955069c1cfSIcenowy Zheng {
965069c1cfSIcenowy Zheng 	switch (pmic) {
975069c1cfSIcenowy Zheng 	case AXP805:
987060e0d8SSamuel Holland 		/* (Re-)init RSB in case the rich OS has disabled it. */
997060e0d8SSamuel Holland 		sunxi_init_platform_r_twi(SUNXI_SOC_H6, true);
1007060e0d8SSamuel Holland 		rsb_init();
101fb23b104SSamuel Holland 		axp_power_off();
1025069c1cfSIcenowy Zheng 		break;
1035069c1cfSIcenowy Zheng 	default:
1045069c1cfSIcenowy Zheng 		break;
1055069c1cfSIcenowy Zheng 	}
1065069c1cfSIcenowy Zheng }
107*9227719dSAndre Przywara 
108*9227719dSAndre Przywara void sunxi_cpu_power_off_self(void)
109*9227719dSAndre Przywara {
110*9227719dSAndre Przywara 	u_register_t mpidr = read_mpidr();
111*9227719dSAndre Przywara 	unsigned int core  = MPIDR_AFFLVL0_VAL(mpidr);
112*9227719dSAndre Przywara 
113*9227719dSAndre Przywara 	/* Enable the CPUIDLE hardware (only really needs to be done once). */
114*9227719dSAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
115*9227719dSAndre Przywara 	mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
116*9227719dSAndre Przywara 
117*9227719dSAndre Przywara 	/* Trigger power off for this core. */
118*9227719dSAndre Przywara 	mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
119*9227719dSAndre Przywara }
120