126123ca3SAndre Przywara /* 2ce750f16SBoyan Karatotev * Copyright (c) 2017-2025, Arm Limited. All rights reserved. 326123ca3SAndre Przywara * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io> 426123ca3SAndre Przywara * 526123ca3SAndre Przywara * SPDX-License-Identifier: BSD-3-Clause 626123ca3SAndre Przywara */ 726123ca3SAndre Przywara 826123ca3SAndre Przywara #include <errno.h> 926123ca3SAndre Przywara #include <string.h> 1026123ca3SAndre Przywara 1126123ca3SAndre Przywara #include <arch_helpers.h> 1226123ca3SAndre Przywara #include <common/debug.h> 13a0597ba2SAndre Przywara #include <common/fdt_wrappers.h> 1426123ca3SAndre Przywara #include <drivers/allwinner/axp.h> 1526123ca3SAndre Przywara #include <drivers/allwinner/sunxi_rsb.h> 1604445898SAndre Przywara #include <drivers/mentor/mi2cv.h> 1726123ca3SAndre Przywara #include <lib/mmio.h> 18a0597ba2SAndre Przywara #include <libfdt.h> 1926123ca3SAndre Przywara 2026123ca3SAndre Przywara #include <sunxi_cpucfg.h> 2126123ca3SAndre Przywara #include <sunxi_def.h> 2226123ca3SAndre Przywara #include <sunxi_mmap.h> 2326123ca3SAndre Przywara #include <sunxi_private.h> 2426123ca3SAndre Przywara 25a0597ba2SAndre Przywara static uint16_t pmic_bus_addr; 26a0597ba2SAndre Przywara static uint8_t rsb_rt_addr; 2726123ca3SAndre Przywara 2804445898SAndre Przywara static bool is_using_rsb(void) 2904445898SAndre Przywara { 3004445898SAndre Przywara return rsb_rt_addr != 0; 3104445898SAndre Przywara } 3204445898SAndre Przywara 3326123ca3SAndre Przywara static enum pmic_type { 3426123ca3SAndre Przywara UNKNOWN, 3526123ca3SAndre Przywara AXP305, 3603851367SAndre Przywara AXP313, 37646d06b2SAndre Przywara AXP717, 3826123ca3SAndre Przywara } pmic; 3926123ca3SAndre Przywara 40a0597ba2SAndre Przywara static uint8_t get_rsb_rt_address(uint16_t hw_addr) 4126123ca3SAndre Przywara { 42a0597ba2SAndre Przywara switch (hw_addr) { 43646d06b2SAndre Przywara case 0x3a3: return 0x2d; 44a0597ba2SAndre Przywara case 0x745: return 0x3a; 4526123ca3SAndre Przywara } 4626123ca3SAndre Przywara 4726123ca3SAndre Przywara return 0; 4826123ca3SAndre Przywara } 4926123ca3SAndre Przywara 50a0597ba2SAndre Przywara int axp_read(uint8_t reg) 51a0597ba2SAndre Przywara { 52ce750f16SBoyan Karatotev uint8_t val = 0; 5304445898SAndre Przywara int ret; 5404445898SAndre Przywara 5504445898SAndre Przywara if (is_using_rsb()) { 56a0597ba2SAndre Przywara return rsb_read(rsb_rt_addr, reg); 57a0597ba2SAndre Przywara } 58a0597ba2SAndre Przywara 5904445898SAndre Przywara ret = i2c_write(pmic_bus_addr, 0, 0, ®, 1); 6004445898SAndre Przywara if (ret == 0) { 6104445898SAndre Przywara ret = i2c_read(pmic_bus_addr, 0, 0, &val, 1); 6204445898SAndre Przywara } 6304445898SAndre Przywara if (ret) { 6404445898SAndre Przywara ERROR("PMIC: Cannot read PMIC register %02x\n", reg); 6504445898SAndre Przywara return ret; 6604445898SAndre Przywara } 6704445898SAndre Przywara 6804445898SAndre Przywara return val; 6904445898SAndre Przywara } 7004445898SAndre Przywara 71a0597ba2SAndre Przywara int axp_write(uint8_t reg, uint8_t val) 72a0597ba2SAndre Przywara { 7304445898SAndre Przywara int ret; 7404445898SAndre Przywara 7504445898SAndre Przywara if (is_using_rsb()) { 76a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, reg, val); 77a0597ba2SAndre Przywara } 78a0597ba2SAndre Przywara 7904445898SAndre Przywara ret = i2c_write(pmic_bus_addr, reg, 1, &val, 1); 8004445898SAndre Przywara if (ret) { 8104445898SAndre Przywara ERROR("PMIC: Cannot write PMIC register %02x\n", reg); 8204445898SAndre Przywara } 8304445898SAndre Przywara 8404445898SAndre Przywara return ret; 8504445898SAndre Przywara } 8604445898SAndre Przywara 87a0597ba2SAndre Przywara static int rsb_init(int rsb_hw_addr) 88a0597ba2SAndre Przywara { 89a0597ba2SAndre Przywara int ret; 90a0597ba2SAndre Przywara 91a0597ba2SAndre Przywara ret = rsb_init_controller(); 92a0597ba2SAndre Przywara if (ret) { 93a0597ba2SAndre Przywara return ret; 94a0597ba2SAndre Przywara } 95a0597ba2SAndre Przywara 96a0597ba2SAndre Przywara /* Switch to the recommended 3 MHz bus clock. */ 97a0597ba2SAndre Przywara ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 98a0597ba2SAndre Przywara if (ret) { 99a0597ba2SAndre Przywara return ret; 100a0597ba2SAndre Przywara } 101a0597ba2SAndre Przywara 102a0597ba2SAndre Przywara /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 103a0597ba2SAndre Przywara ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 104a0597ba2SAndre Przywara if (ret) { 105a0597ba2SAndre Przywara return ret; 106a0597ba2SAndre Przywara } 107a0597ba2SAndre Przywara 108a0597ba2SAndre Przywara /* Associate the 8-bit runtime address with the 12-bit bus address. */ 109a0597ba2SAndre Przywara ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr); 110a0597ba2SAndre Przywara if (ret) { 111a0597ba2SAndre Przywara return ret; 112a0597ba2SAndre Przywara } 113a0597ba2SAndre Przywara 114a0597ba2SAndre Przywara return 0; 115a0597ba2SAndre Przywara } 116a0597ba2SAndre Przywara 117a0597ba2SAndre Przywara static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr) 118a0597ba2SAndre Przywara { 119a0597ba2SAndre Przywara int ret; 120a0597ba2SAndre Przywara 12104445898SAndre Przywara ret = sunxi_init_platform_r_twi(socid, is_using_rsb()); 122a0597ba2SAndre Przywara if (ret) { 123a0597ba2SAndre Przywara INFO("Could not init platform bus: %d\n", ret); 124a0597ba2SAndre Przywara pmic = UNKNOWN; 125a0597ba2SAndre Przywara return ret; 126a0597ba2SAndre Przywara } 127a0597ba2SAndre Przywara 12804445898SAndre Przywara if (is_using_rsb()) { 129a0597ba2SAndre Przywara ret = rsb_init(rsb_hw_addr); 130a0597ba2SAndre Przywara if (ret) { 131a0597ba2SAndre Przywara pmic = UNKNOWN; 132a0597ba2SAndre Przywara return ret; 133a0597ba2SAndre Przywara } 13404445898SAndre Przywara } else { 13504445898SAndre Przywara /* initialise mi2cv driver */ 13604445898SAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 13704445898SAndre Przywara } 138a0597ba2SAndre Przywara 139a0597ba2SAndre Przywara return 0; 140a0597ba2SAndre Przywara } 141a0597ba2SAndre Przywara 142a0597ba2SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 143a0597ba2SAndre Przywara { 14404445898SAndre Przywara int node, parent, ret; 145a0597ba2SAndre Przywara uint32_t reg; 146a0597ba2SAndre Przywara 147*69b4a591SAndre Przywara if (fdt == NULL) { 148*69b4a591SAndre Przywara INFO("No DTB, skipping PMIC detection and setup\n"); 149*69b4a591SAndre Przywara return -ENOENT; 150*69b4a591SAndre Przywara } 151*69b4a591SAndre Przywara 152a0597ba2SAndre Przywara node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806"); 153a0597ba2SAndre Przywara if (node >= 0) { 154a0597ba2SAndre Przywara pmic = AXP305; 155a0597ba2SAndre Przywara } 156a0597ba2SAndre Przywara 157a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 15803851367SAndre Przywara node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp313a"); 15903851367SAndre Przywara if (node >= 0) { 16003851367SAndre Przywara pmic = AXP313; 16103851367SAndre Przywara } 16203851367SAndre Przywara } 16303851367SAndre Przywara 16403851367SAndre Przywara if (pmic == UNKNOWN) { 165646d06b2SAndre Przywara node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp717"); 166646d06b2SAndre Przywara if (node >= 0) { 167646d06b2SAndre Przywara pmic = AXP717; 168646d06b2SAndre Przywara } 169646d06b2SAndre Przywara } 170646d06b2SAndre Przywara 171646d06b2SAndre Przywara if (pmic == UNKNOWN) { 172a0597ba2SAndre Przywara INFO("PMIC: No known PMIC in DT, skipping setup.\n"); 173a0597ba2SAndre Przywara return -ENODEV; 174a0597ba2SAndre Przywara } 175a0597ba2SAndre Przywara 176a0597ba2SAndre Przywara if (fdt_read_uint32(fdt, node, "reg", ®)) { 177a0597ba2SAndre Przywara ERROR("PMIC: PMIC DT node does not contain reg property.\n"); 178a0597ba2SAndre Przywara return -EINVAL; 179a0597ba2SAndre Przywara } 180a0597ba2SAndre Przywara 181a0597ba2SAndre Przywara pmic_bus_addr = reg; 18204445898SAndre Przywara parent = fdt_parent_offset(fdt, node); 18304445898SAndre Przywara ret = fdt_node_check_compatible(fdt, parent, "allwinner,sun8i-a23-rsb"); 18404445898SAndre Przywara if (ret == 0) { 185a0597ba2SAndre Przywara rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr); 186a0597ba2SAndre Przywara if (rsb_rt_addr == 0) { 18704445898SAndre Przywara ERROR("PMIC: no mapping for RSB address 0x%x\n", 18804445898SAndre Przywara pmic_bus_addr); 189a0597ba2SAndre Przywara return -EINVAL; 190a0597ba2SAndre Przywara } 19104445898SAndre Przywara } 192a0597ba2SAndre Przywara 19304445898SAndre Przywara INFO("Probing for PMIC on %s:\n", is_using_rsb() ? "RSB" : "I2C"); 194a0597ba2SAndre Przywara 195a0597ba2SAndre Przywara ret = pmic_bus_init(socid, pmic_bus_addr); 196a0597ba2SAndre Przywara if (ret) { 197a0597ba2SAndre Przywara return ret; 198a0597ba2SAndre Przywara } 199a0597ba2SAndre Przywara 200a0597ba2SAndre Przywara ret = axp_read(0x03); 201a0597ba2SAndre Przywara switch (ret & 0xcf) { 202a0597ba2SAndre Przywara case 0x40: /* AXP305 */ 203a0597ba2SAndre Przywara if (pmic == AXP305) { 204a0597ba2SAndre Przywara INFO("PMIC: found AXP305, setting up regulators\n"); 205a0597ba2SAndre Przywara axp_setup_regulators(fdt); 206a0597ba2SAndre Przywara } else { 207a0597ba2SAndre Przywara pmic = UNKNOWN; 208a0597ba2SAndre Przywara } 209a0597ba2SAndre Przywara break; 21003851367SAndre Przywara case 0x48: /* AXP1530 */ 21103851367SAndre Przywara case 0x4b: /* AXP313A */ 21203851367SAndre Przywara case 0x4c: /* AXP313B */ 21303851367SAndre Przywara if (pmic == AXP313) { 21403851367SAndre Przywara INFO("PMIC: found AXP313\n"); 21503851367SAndre Przywara /* no regulators to set up */ 21603851367SAndre Przywara } else { 21703851367SAndre Przywara pmic = UNKNOWN; 21803851367SAndre Przywara } 21903851367SAndre Przywara break; 220646d06b2SAndre Przywara case 0xcf: /* version reg not implemented on AXP717 */ 221646d06b2SAndre Przywara if (pmic == AXP717) { 222646d06b2SAndre Przywara INFO("PMIC: found AXP717\n"); 223646d06b2SAndre Przywara /* no regulators to set up, U-Boot takes care of this */ 224646d06b2SAndre Przywara } else { 225646d06b2SAndre Przywara pmic = UNKNOWN; 226646d06b2SAndre Przywara } 227646d06b2SAndre Przywara break; 228a0597ba2SAndre Przywara } 229a0597ba2SAndre Przywara 23004445898SAndre Przywara if (is_using_rsb()) { 231a0597ba2SAndre Przywara /* Switch the PMIC back to I2C mode. */ 232a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C); 233a0597ba2SAndre Przywara } 234a0597ba2SAndre Przywara 23504445898SAndre Przywara if (pmic == UNKNOWN) { 23604445898SAndre Przywara INFO("Incompatible or unknown PMIC found.\n"); 23704445898SAndre Przywara return -ENODEV; 23804445898SAndre Przywara } 23904445898SAndre Przywara 24004445898SAndre Przywara return 0; 24104445898SAndre Przywara } 24204445898SAndre Przywara 24326123ca3SAndre Przywara void sunxi_power_down(void) 24426123ca3SAndre Przywara { 245a0597ba2SAndre Przywara int ret; 246a0597ba2SAndre Przywara 247a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 248a0597ba2SAndre Przywara return; 249a0597ba2SAndre Przywara } 250a0597ba2SAndre Przywara 251a0597ba2SAndre Przywara /* Re-initialise after rich OS might have used it. */ 252a0597ba2SAndre Przywara ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr); 253a0597ba2SAndre Przywara if (ret) { 254a0597ba2SAndre Przywara return; 255a0597ba2SAndre Przywara } 256a0597ba2SAndre Przywara 25726123ca3SAndre Przywara switch (pmic) { 25826123ca3SAndre Przywara case AXP305: 259a0597ba2SAndre Przywara axp_setbits(0x32, BIT(7)); 26026123ca3SAndre Przywara break; 26103851367SAndre Przywara case AXP313: 26203851367SAndre Przywara axp_setbits(0x1a, BIT(7)); 26303851367SAndre Przywara break; 264646d06b2SAndre Przywara case AXP717: 265646d06b2SAndre Przywara axp_setbits(0x27, BIT(0)); 266646d06b2SAndre Przywara break; 26726123ca3SAndre Przywara default: 26826123ca3SAndre Przywara break; 26926123ca3SAndre Przywara } 27026123ca3SAndre Przywara } 27126123ca3SAndre Przywara 27226123ca3SAndre Przywara void sunxi_cpu_power_off_self(void) 27326123ca3SAndre Przywara { 27426123ca3SAndre Przywara u_register_t mpidr = read_mpidr(); 27526123ca3SAndre Przywara unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 27626123ca3SAndre Przywara 27726123ca3SAndre Przywara /* Enable the CPUIDLE hardware (only really needs to be done once). */ 27826123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 27926123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 28026123ca3SAndre Przywara 28126123ca3SAndre Przywara /* Trigger power off for this core. */ 28226123ca3SAndre Przywara mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 28326123ca3SAndre Przywara } 284