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> 16*04445898SAndre 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 28*04445898SAndre Przywara static bool is_using_rsb(void) 29*04445898SAndre Przywara { 30*04445898SAndre Przywara return rsb_rt_addr != 0; 31*04445898SAndre Przywara } 32*04445898SAndre Przywara 3326123ca3SAndre Przywara static enum pmic_type { 3426123ca3SAndre Przywara UNKNOWN, 3526123ca3SAndre Przywara AXP305, 3626123ca3SAndre Przywara } pmic; 3726123ca3SAndre Przywara 38a0597ba2SAndre Przywara static uint8_t get_rsb_rt_address(uint16_t hw_addr) 3926123ca3SAndre Przywara { 40a0597ba2SAndre Przywara switch (hw_addr) { 41a0597ba2SAndre Przywara case 0x745: return 0x3a; 4226123ca3SAndre Przywara } 4326123ca3SAndre Przywara 4426123ca3SAndre Przywara return 0; 4526123ca3SAndre Przywara } 4626123ca3SAndre Przywara 47a0597ba2SAndre Przywara int axp_read(uint8_t reg) 48a0597ba2SAndre Przywara { 49*04445898SAndre Przywara uint8_t val; 50*04445898SAndre Przywara int ret; 51*04445898SAndre Przywara 52*04445898SAndre Przywara if (is_using_rsb()) { 53a0597ba2SAndre Przywara return rsb_read(rsb_rt_addr, reg); 54a0597ba2SAndre Przywara } 55a0597ba2SAndre Przywara 56*04445898SAndre Przywara ret = i2c_write(pmic_bus_addr, 0, 0, ®, 1); 57*04445898SAndre Przywara if (ret == 0) { 58*04445898SAndre Przywara ret = i2c_read(pmic_bus_addr, 0, 0, &val, 1); 59*04445898SAndre Przywara } 60*04445898SAndre Przywara if (ret) { 61*04445898SAndre Przywara ERROR("PMIC: Cannot read PMIC register %02x\n", reg); 62*04445898SAndre Przywara return ret; 63*04445898SAndre Przywara } 64*04445898SAndre Przywara 65*04445898SAndre Przywara return val; 66*04445898SAndre Przywara } 67*04445898SAndre Przywara 68a0597ba2SAndre Przywara int axp_write(uint8_t reg, uint8_t val) 69a0597ba2SAndre Przywara { 70*04445898SAndre Przywara int ret; 71*04445898SAndre Przywara 72*04445898SAndre Przywara if (is_using_rsb()) { 73a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, reg, val); 74a0597ba2SAndre Przywara } 75a0597ba2SAndre Przywara 76*04445898SAndre Przywara ret = i2c_write(pmic_bus_addr, reg, 1, &val, 1); 77*04445898SAndre Przywara if (ret) { 78*04445898SAndre Przywara ERROR("PMIC: Cannot write PMIC register %02x\n", reg); 79*04445898SAndre Przywara } 80*04445898SAndre Przywara 81*04445898SAndre Przywara return ret; 82*04445898SAndre Przywara } 83*04445898SAndre Przywara 84a0597ba2SAndre Przywara static int rsb_init(int rsb_hw_addr) 85a0597ba2SAndre Przywara { 86a0597ba2SAndre Przywara int ret; 87a0597ba2SAndre Przywara 88a0597ba2SAndre Przywara ret = rsb_init_controller(); 89a0597ba2SAndre Przywara if (ret) { 90a0597ba2SAndre Przywara return ret; 91a0597ba2SAndre Przywara } 92a0597ba2SAndre Przywara 93a0597ba2SAndre Przywara /* Switch to the recommended 3 MHz bus clock. */ 94a0597ba2SAndre Przywara ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 95a0597ba2SAndre Przywara if (ret) { 96a0597ba2SAndre Przywara return ret; 97a0597ba2SAndre Przywara } 98a0597ba2SAndre Przywara 99a0597ba2SAndre Przywara /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 100a0597ba2SAndre Przywara ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 101a0597ba2SAndre Przywara if (ret) { 102a0597ba2SAndre Przywara return ret; 103a0597ba2SAndre Przywara } 104a0597ba2SAndre Przywara 105a0597ba2SAndre Przywara /* Associate the 8-bit runtime address with the 12-bit bus address. */ 106a0597ba2SAndre Przywara ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr); 107a0597ba2SAndre Przywara if (ret) { 108a0597ba2SAndre Przywara return ret; 109a0597ba2SAndre Przywara } 110a0597ba2SAndre Przywara 111a0597ba2SAndre Przywara return 0; 112a0597ba2SAndre Przywara } 113a0597ba2SAndre Przywara 114a0597ba2SAndre Przywara static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr) 115a0597ba2SAndre Przywara { 116a0597ba2SAndre Przywara int ret; 117a0597ba2SAndre Przywara 118*04445898SAndre Przywara ret = sunxi_init_platform_r_twi(socid, is_using_rsb()); 119a0597ba2SAndre Przywara if (ret) { 120a0597ba2SAndre Przywara INFO("Could not init platform bus: %d\n", ret); 121a0597ba2SAndre Przywara pmic = UNKNOWN; 122a0597ba2SAndre Przywara return ret; 123a0597ba2SAndre Przywara } 124a0597ba2SAndre Przywara 125*04445898SAndre Przywara if (is_using_rsb()) { 126a0597ba2SAndre Przywara ret = rsb_init(rsb_hw_addr); 127a0597ba2SAndre Przywara if (ret) { 128a0597ba2SAndre Przywara pmic = UNKNOWN; 129a0597ba2SAndre Przywara return ret; 130a0597ba2SAndre Przywara } 131*04445898SAndre Przywara } else { 132*04445898SAndre Przywara /* initialise mi2cv driver */ 133*04445898SAndre Przywara i2c_init((void *)SUNXI_R_I2C_BASE); 134*04445898SAndre Przywara } 135a0597ba2SAndre Przywara 136a0597ba2SAndre Przywara return 0; 137a0597ba2SAndre Przywara } 138a0597ba2SAndre Przywara 139a0597ba2SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 140a0597ba2SAndre Przywara { 141*04445898SAndre Przywara int node, parent, ret; 142a0597ba2SAndre Przywara uint32_t reg; 143a0597ba2SAndre Przywara 144a0597ba2SAndre Przywara node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806"); 145a0597ba2SAndre Przywara if (node >= 0) { 146a0597ba2SAndre Przywara pmic = AXP305; 147a0597ba2SAndre Przywara } 148a0597ba2SAndre Przywara 149a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 150a0597ba2SAndre Przywara INFO("PMIC: No known PMIC in DT, skipping setup.\n"); 151a0597ba2SAndre Przywara return -ENODEV; 152a0597ba2SAndre Przywara } 153a0597ba2SAndre Przywara 154a0597ba2SAndre Przywara if (fdt_read_uint32(fdt, node, "reg", ®)) { 155a0597ba2SAndre Przywara ERROR("PMIC: PMIC DT node does not contain reg property.\n"); 156a0597ba2SAndre Przywara return -EINVAL; 157a0597ba2SAndre Przywara } 158a0597ba2SAndre Przywara 159a0597ba2SAndre Przywara pmic_bus_addr = reg; 160*04445898SAndre Przywara parent = fdt_parent_offset(fdt, node); 161*04445898SAndre Przywara ret = fdt_node_check_compatible(fdt, parent, "allwinner,sun8i-a23-rsb"); 162*04445898SAndre Przywara if (ret == 0) { 163a0597ba2SAndre Przywara rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr); 164a0597ba2SAndre Przywara if (rsb_rt_addr == 0) { 165*04445898SAndre Przywara ERROR("PMIC: no mapping for RSB address 0x%x\n", 166*04445898SAndre Przywara pmic_bus_addr); 167a0597ba2SAndre Przywara return -EINVAL; 168a0597ba2SAndre Przywara } 169*04445898SAndre Przywara } 170a0597ba2SAndre Przywara 171*04445898SAndre Przywara INFO("Probing for PMIC on %s:\n", is_using_rsb() ? "RSB" : "I2C"); 172a0597ba2SAndre Przywara 173a0597ba2SAndre Przywara ret = pmic_bus_init(socid, pmic_bus_addr); 174a0597ba2SAndre Przywara if (ret) { 175a0597ba2SAndre Przywara return ret; 176a0597ba2SAndre Przywara } 177a0597ba2SAndre Przywara 178a0597ba2SAndre Przywara ret = axp_read(0x03); 179a0597ba2SAndre Przywara switch (ret & 0xcf) { 180a0597ba2SAndre Przywara case 0x40: /* AXP305 */ 181a0597ba2SAndre Przywara if (pmic == AXP305) { 182a0597ba2SAndre Przywara INFO("PMIC: found AXP305, setting up regulators\n"); 183a0597ba2SAndre Przywara axp_setup_regulators(fdt); 184a0597ba2SAndre Przywara } else { 185a0597ba2SAndre Przywara pmic = UNKNOWN; 186a0597ba2SAndre Przywara } 187a0597ba2SAndre Przywara break; 188a0597ba2SAndre Przywara } 189a0597ba2SAndre Przywara 190*04445898SAndre Przywara if (is_using_rsb()) { 191a0597ba2SAndre Przywara /* Switch the PMIC back to I2C mode. */ 192a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C); 193a0597ba2SAndre Przywara } 194a0597ba2SAndre Przywara 195*04445898SAndre Przywara if (pmic == UNKNOWN) { 196*04445898SAndre Przywara INFO("Incompatible or unknown PMIC found.\n"); 197*04445898SAndre Przywara return -ENODEV; 198*04445898SAndre Przywara } 199*04445898SAndre Przywara 200*04445898SAndre Przywara return 0; 201*04445898SAndre Przywara } 202*04445898SAndre Przywara 20326123ca3SAndre Przywara void sunxi_power_down(void) 20426123ca3SAndre Przywara { 205a0597ba2SAndre Przywara int ret; 206a0597ba2SAndre Przywara 207a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 208a0597ba2SAndre Przywara return; 209a0597ba2SAndre Przywara } 210a0597ba2SAndre Przywara 211a0597ba2SAndre Przywara /* Re-initialise after rich OS might have used it. */ 212a0597ba2SAndre Przywara ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr); 213a0597ba2SAndre Przywara if (ret) { 214a0597ba2SAndre Przywara return; 215a0597ba2SAndre Przywara } 216a0597ba2SAndre Przywara 21726123ca3SAndre Przywara switch (pmic) { 21826123ca3SAndre Przywara case AXP305: 219a0597ba2SAndre Przywara axp_setbits(0x32, BIT(7)); 22026123ca3SAndre Przywara break; 22126123ca3SAndre Przywara default: 22226123ca3SAndre Przywara break; 22326123ca3SAndre Przywara } 22426123ca3SAndre Przywara } 22526123ca3SAndre Przywara 22626123ca3SAndre Przywara void sunxi_cpu_power_off_self(void) 22726123ca3SAndre Przywara { 22826123ca3SAndre Przywara u_register_t mpidr = read_mpidr(); 22926123ca3SAndre Przywara unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 23026123ca3SAndre Przywara 23126123ca3SAndre Przywara /* Enable the CPUIDLE hardware (only really needs to be done once). */ 23226123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 23326123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 23426123ca3SAndre Przywara 23526123ca3SAndre Przywara /* Trigger power off for this core. */ 23626123ca3SAndre Przywara mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 23726123ca3SAndre Przywara } 238