diff --git a/plat/allwinner/sun50i_a64/platform.mk b/plat/allwinner/sun50i_a64/platform.mk index b032499..b46fbc2 100644 --- a/plat/allwinner/sun50i_a64/platform.mk +++ b/plat/allwinner/sun50i_a64/platform.mk @@ -6,3 +6,5 @@ # The differences between the platform are covered by the include files. include plat/allwinner/common/allwinner-common.mk + +PLAT_BL_COMMON_SOURCES += drivers/allwinner/sunxi_rsb.c diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c index 535831e..eaca0af 100644 --- a/plat/allwinner/sun50i_a64/sunxi_power.c +++ b/plat/allwinner/sun50i_a64/sunxi_power.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include #include #include #include @@ -19,8 +20,12 @@ GENERIC_H5, GENERIC_A64, REF_DESIGN_H5, /* regulators controlled by GPIO pins on port L */ + AXP803_RSB, /* PMIC connected via RSB on most A64 boards */ } pmic; +#define AXP803_HW_ADDR 0x3a3 +#define AXP803_RT_ADDR 0x2d + /* * On boards without a proper PMIC we struggle to turn off the system properly. * Try to turn off as much off the system as we can, to reduce power @@ -76,8 +81,55 @@ } } +static int rsb_init(void) +{ + int ret; + + ret = rsb_init_controller(); + if (ret) + return ret; + + /* Start with 400 KHz to issue the I2C->RSB switch command. */ + ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 400000); + if (ret) + return ret; + + /* + * Initiate an I2C transaction to write 0x7c into register 0x3e, + * switching the PMIC to RSB mode. + */ + ret = rsb_set_device_mode(0x7c3e00); + if (ret) + return ret; + + /* Now in RSB mode, switch to the recommended 3 MHz. */ + ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); + if (ret) + return ret; + + /* Associate the 8-bit runtime address with the 12-bit bus address. */ + return rsb_assign_runtime_address(AXP803_HW_ADDR, + AXP803_RT_ADDR); +} + +static int axp_setbits(uint8_t reg, uint8_t set_mask) +{ + uint8_t regval; + int ret; + + ret = rsb_read(AXP803_RT_ADDR, reg); + if (ret < 0) + return ret; + + regval = ret | set_mask; + + return rsb_write(AXP803_RT_ADDR, reg, regval); +} + int sunxi_pmic_setup(uint16_t socid) { + int ret; + switch (socid) { case SUNXI_SOC_H5: pmic = REF_DESIGN_H5; @@ -85,6 +137,17 @@ break; case SUNXI_SOC_A64: pmic = GENERIC_A64; + ret = sunxi_init_platform_r_twi(socid, true); + if (ret) + return ret; + + ret = rsb_init(); + if (ret) + return ret; + + pmic = AXP803_RSB; + NOTICE("BL31: PMIC: Detected AXP803 on RSB.\n"); + break; default: NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid); @@ -127,6 +190,14 @@ mmio_write_32(SUNXI_CCU_BASE + 0x68, 0); break; + case AXP803_RSB: + /* (Re-)init RSB in case the rich OS has disabled it. */ + sunxi_init_platform_r_twi(SUNXI_SOC_A64, true); + rsb_init(); + + /* Set "power disable control" bit */ + axp_setbits(0x32, BIT(7)); + break; default: break; }