126123ca3SAndre Przywara /* 226123ca3SAndre Przywara * Copyright (c) 2017-2020, 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, 36*03851367SAndre Przywara AXP313, 3726123ca3SAndre Przywara } pmic; 3826123ca3SAndre Przywara 39a0597ba2SAndre Przywara static uint8_t get_rsb_rt_address(uint16_t hw_addr) 4026123ca3SAndre Przywara { 41a0597ba2SAndre Przywara switch (hw_addr) { 42a0597ba2SAndre Przywara case 0x745: return 0x3a; 4326123ca3SAndre Przywara } 4426123ca3SAndre Przywara 4526123ca3SAndre Przywara return 0; 4626123ca3SAndre Przywara } 4726123ca3SAndre Przywara 48a0597ba2SAndre Przywara int axp_read(uint8_t reg) 49a0597ba2SAndre Przywara { 5004445898SAndre Przywara uint8_t val; 5104445898SAndre Przywara int ret; 5204445898SAndre Przywara 5304445898SAndre Przywara if (is_using_rsb()) { 54a0597ba2SAndre Przywara return rsb_read(rsb_rt_addr, reg); 55a0597ba2SAndre Przywara } 56a0597ba2SAndre Przywara 5704445898SAndre Przywara ret = i2c_write(pmic_bus_addr, 0, 0, ®, 1); 5804445898SAndre Przywara if (ret == 0) { 5904445898SAndre Przywara ret = i2c_read(pmic_bus_addr, 0, 0, &val, 1); 6004445898SAndre Przywara } 6104445898SAndre Przywara if (ret) { 6204445898SAndre Przywara ERROR("PMIC: Cannot read PMIC register %02x\n", reg); 6304445898SAndre Przywara return ret; 6404445898SAndre Przywara } 6504445898SAndre Przywara 6604445898SAndre Przywara return val; 6704445898SAndre Przywara } 6804445898SAndre Przywara 69a0597ba2SAndre Przywara int axp_write(uint8_t reg, uint8_t val) 70a0597ba2SAndre Przywara { 7104445898SAndre Przywara int ret; 7204445898SAndre Przywara 7304445898SAndre Przywara if (is_using_rsb()) { 74a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, reg, val); 75a0597ba2SAndre Przywara } 76a0597ba2SAndre Przywara 7704445898SAndre Przywara ret = i2c_write(pmic_bus_addr, reg, 1, &val, 1); 7804445898SAndre Przywara if (ret) { 7904445898SAndre Przywara ERROR("PMIC: Cannot write PMIC register %02x\n", reg); 8004445898SAndre Przywara } 8104445898SAndre Przywara 8204445898SAndre Przywara return ret; 8304445898SAndre Przywara } 8404445898SAndre Przywara 85a0597ba2SAndre Przywara static int rsb_init(int rsb_hw_addr) 86a0597ba2SAndre Przywara { 87a0597ba2SAndre Przywara int ret; 88a0597ba2SAndre Przywara 89a0597ba2SAndre Przywara ret = rsb_init_controller(); 90a0597ba2SAndre Przywara if (ret) { 91a0597ba2SAndre Przywara return ret; 92a0597ba2SAndre Przywara } 93a0597ba2SAndre Przywara 94a0597ba2SAndre Przywara /* Switch to the recommended 3 MHz bus clock. */ 95a0597ba2SAndre Przywara ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 96a0597ba2SAndre Przywara if (ret) { 97a0597ba2SAndre Przywara return ret; 98a0597ba2SAndre Przywara } 99a0597ba2SAndre Przywara 100a0597ba2SAndre Przywara /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 101a0597ba2SAndre Przywara ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 102a0597ba2SAndre Przywara if (ret) { 103a0597ba2SAndre Przywara return ret; 104a0597ba2SAndre Przywara } 105a0597ba2SAndre Przywara 106a0597ba2SAndre Przywara /* Associate the 8-bit runtime address with the 12-bit bus address. */ 107a0597ba2SAndre Przywara ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr); 108a0597ba2SAndre Przywara if (ret) { 109a0597ba2SAndre Przywara return ret; 110a0597ba2SAndre Przywara } 111a0597ba2SAndre Przywara 112a0597ba2SAndre Przywara return 0; 113a0597ba2SAndre Przywara } 114a0597ba2SAndre Przywara 115a0597ba2SAndre Przywara static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr) 116a0597ba2SAndre Przywara { 117a0597ba2SAndre Przywara int ret; 118a0597ba2SAndre Przywara 11904445898SAndre Przywara ret = sunxi_init_platform_r_twi(socid, is_using_rsb()); 120a0597ba2SAndre Przywara if (ret) { 121a0597ba2SAndre Przywara INFO("Could not init platform bus: %d\n", ret); 122a0597ba2SAndre Przywara pmic = UNKNOWN; 123a0597ba2SAndre Przywara return ret; 124a0597ba2SAndre Przywara } 125a0597ba2SAndre Przywara 12604445898SAndre Przywara if (is_using_rsb()) { 127a0597ba2SAndre Przywara ret = rsb_init(rsb_hw_addr); 128a0597ba2SAndre Przywara if (ret) { 129a0597ba2SAndre Przywara pmic = UNKNOWN; 130a0597ba2SAndre Przywara return ret; 131a0597ba2SAndre Przywara } 13204445898SAndre Przywara } else { 13304445898SAndre Przywara /* initialise mi2cv driver */ 13404445898SAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 13504445898SAndre Przywara } 136a0597ba2SAndre Przywara 137a0597ba2SAndre Przywara return 0; 138a0597ba2SAndre Przywara } 139a0597ba2SAndre Przywara 140a0597ba2SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 141a0597ba2SAndre Przywara { 14204445898SAndre Przywara int node, parent, ret; 143a0597ba2SAndre Przywara uint32_t reg; 144a0597ba2SAndre Przywara 145a0597ba2SAndre Przywara node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806"); 146a0597ba2SAndre Przywara if (node >= 0) { 147a0597ba2SAndre Przywara pmic = AXP305; 148a0597ba2SAndre Przywara } 149a0597ba2SAndre Przywara 150a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 151*03851367SAndre Przywara node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp313a"); 152*03851367SAndre Przywara if (node >= 0) { 153*03851367SAndre Przywara pmic = AXP313; 154*03851367SAndre Przywara } 155*03851367SAndre Przywara } 156*03851367SAndre Przywara 157*03851367SAndre Przywara if (pmic == UNKNOWN) { 158a0597ba2SAndre Przywara INFO("PMIC: No known PMIC in DT, skipping setup.\n"); 159a0597ba2SAndre Przywara return -ENODEV; 160a0597ba2SAndre Przywara } 161a0597ba2SAndre Przywara 162a0597ba2SAndre Przywara if (fdt_read_uint32(fdt, node, "reg", ®)) { 163a0597ba2SAndre Przywara ERROR("PMIC: PMIC DT node does not contain reg property.\n"); 164a0597ba2SAndre Przywara return -EINVAL; 165a0597ba2SAndre Przywara } 166a0597ba2SAndre Przywara 167a0597ba2SAndre Przywara pmic_bus_addr = reg; 16804445898SAndre Przywara parent = fdt_parent_offset(fdt, node); 16904445898SAndre Przywara ret = fdt_node_check_compatible(fdt, parent, "allwinner,sun8i-a23-rsb"); 17004445898SAndre Przywara if (ret == 0) { 171a0597ba2SAndre Przywara rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr); 172a0597ba2SAndre Przywara if (rsb_rt_addr == 0) { 17304445898SAndre Przywara ERROR("PMIC: no mapping for RSB address 0x%x\n", 17404445898SAndre Przywara pmic_bus_addr); 175a0597ba2SAndre Przywara return -EINVAL; 176a0597ba2SAndre Przywara } 17704445898SAndre Przywara } 178a0597ba2SAndre Przywara 17904445898SAndre Przywara INFO("Probing for PMIC on %s:\n", is_using_rsb() ? "RSB" : "I2C"); 180a0597ba2SAndre Przywara 181a0597ba2SAndre Przywara ret = pmic_bus_init(socid, pmic_bus_addr); 182a0597ba2SAndre Przywara if (ret) { 183a0597ba2SAndre Przywara return ret; 184a0597ba2SAndre Przywara } 185a0597ba2SAndre Przywara 186a0597ba2SAndre Przywara ret = axp_read(0x03); 187a0597ba2SAndre Przywara switch (ret & 0xcf) { 188a0597ba2SAndre Przywara case 0x40: /* AXP305 */ 189a0597ba2SAndre Przywara if (pmic == AXP305) { 190a0597ba2SAndre Przywara INFO("PMIC: found AXP305, setting up regulators\n"); 191a0597ba2SAndre Przywara axp_setup_regulators(fdt); 192a0597ba2SAndre Przywara } else { 193a0597ba2SAndre Przywara pmic = UNKNOWN; 194a0597ba2SAndre Przywara } 195a0597ba2SAndre Przywara break; 196*03851367SAndre Przywara case 0x48: /* AXP1530 */ 197*03851367SAndre Przywara case 0x4b: /* AXP313A */ 198*03851367SAndre Przywara case 0x4c: /* AXP313B */ 199*03851367SAndre Przywara if (pmic == AXP313) { 200*03851367SAndre Przywara INFO("PMIC: found AXP313\n"); 201*03851367SAndre Przywara /* no regulators to set up */ 202*03851367SAndre Przywara } else { 203*03851367SAndre Przywara pmic = UNKNOWN; 204*03851367SAndre Przywara } 205*03851367SAndre Przywara break; 206a0597ba2SAndre Przywara } 207a0597ba2SAndre Przywara 20804445898SAndre Przywara if (is_using_rsb()) { 209a0597ba2SAndre Przywara /* Switch the PMIC back to I2C mode. */ 210a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C); 211a0597ba2SAndre Przywara } 212a0597ba2SAndre Przywara 21304445898SAndre Przywara if (pmic == UNKNOWN) { 21404445898SAndre Przywara INFO("Incompatible or unknown PMIC found.\n"); 21504445898SAndre Przywara return -ENODEV; 21604445898SAndre Przywara } 21704445898SAndre Przywara 21804445898SAndre Przywara return 0; 21904445898SAndre Przywara } 22004445898SAndre Przywara 22126123ca3SAndre Przywara void sunxi_power_down(void) 22226123ca3SAndre Przywara { 223a0597ba2SAndre Przywara int ret; 224a0597ba2SAndre Przywara 225a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 226a0597ba2SAndre Przywara return; 227a0597ba2SAndre Przywara } 228a0597ba2SAndre Przywara 229a0597ba2SAndre Przywara /* Re-initialise after rich OS might have used it. */ 230a0597ba2SAndre Przywara ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr); 231a0597ba2SAndre Przywara if (ret) { 232a0597ba2SAndre Przywara return; 233a0597ba2SAndre Przywara } 234a0597ba2SAndre Przywara 23526123ca3SAndre Przywara switch (pmic) { 23626123ca3SAndre Przywara case AXP305: 237a0597ba2SAndre Przywara axp_setbits(0x32, BIT(7)); 23826123ca3SAndre Przywara break; 239*03851367SAndre Przywara case AXP313: 240*03851367SAndre Przywara axp_setbits(0x1a, BIT(7)); 241*03851367SAndre Przywara break; 24226123ca3SAndre Przywara default: 24326123ca3SAndre Przywara break; 24426123ca3SAndre Przywara } 24526123ca3SAndre Przywara } 24626123ca3SAndre Przywara 24726123ca3SAndre Przywara void sunxi_cpu_power_off_self(void) 24826123ca3SAndre Przywara { 24926123ca3SAndre Przywara u_register_t mpidr = read_mpidr(); 25026123ca3SAndre Przywara unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 25126123ca3SAndre Przywara 25226123ca3SAndre Przywara /* Enable the CPUIDLE hardware (only really needs to be done once). */ 25326123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 25426123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 25526123ca3SAndre Przywara 25626123ca3SAndre Przywara /* Trigger power off for this core. */ 25726123ca3SAndre Przywara mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 25826123ca3SAndre Przywara } 259