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> 13*a0597ba2SAndre Przywara #include <common/fdt_wrappers.h> 1426123ca3SAndre Przywara #include <drivers/allwinner/axp.h> 1526123ca3SAndre Przywara #include <drivers/allwinner/sunxi_rsb.h> 1626123ca3SAndre Przywara #include <lib/mmio.h> 17*a0597ba2SAndre Przywara #include <libfdt.h> 1826123ca3SAndre Przywara 1926123ca3SAndre Przywara #include <sunxi_cpucfg.h> 2026123ca3SAndre Przywara #include <sunxi_def.h> 2126123ca3SAndre Przywara #include <sunxi_mmap.h> 2226123ca3SAndre Przywara #include <sunxi_private.h> 2326123ca3SAndre Przywara 24*a0597ba2SAndre Przywara static uint16_t pmic_bus_addr; 25*a0597ba2SAndre Przywara static uint8_t rsb_rt_addr; 2626123ca3SAndre Przywara 2726123ca3SAndre Przywara static enum pmic_type { 2826123ca3SAndre Przywara UNKNOWN, 2926123ca3SAndre Przywara AXP305, 3026123ca3SAndre Przywara } pmic; 3126123ca3SAndre Przywara 32*a0597ba2SAndre Przywara static uint8_t get_rsb_rt_address(uint16_t hw_addr) 3326123ca3SAndre Przywara { 34*a0597ba2SAndre Przywara switch (hw_addr) { 35*a0597ba2SAndre Przywara case 0x745: return 0x3a; 3626123ca3SAndre Przywara } 3726123ca3SAndre Przywara 3826123ca3SAndre Przywara return 0; 3926123ca3SAndre Przywara } 4026123ca3SAndre Przywara 41*a0597ba2SAndre Przywara int axp_read(uint8_t reg) 42*a0597ba2SAndre Przywara { 43*a0597ba2SAndre Przywara return rsb_read(rsb_rt_addr, reg); 44*a0597ba2SAndre Przywara } 45*a0597ba2SAndre Przywara 46*a0597ba2SAndre Przywara int axp_write(uint8_t reg, uint8_t val) 47*a0597ba2SAndre Przywara { 48*a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, reg, val); 49*a0597ba2SAndre Przywara } 50*a0597ba2SAndre Przywara 51*a0597ba2SAndre Przywara static int rsb_init(int rsb_hw_addr) 52*a0597ba2SAndre Przywara { 53*a0597ba2SAndre Przywara int ret; 54*a0597ba2SAndre Przywara 55*a0597ba2SAndre Przywara ret = rsb_init_controller(); 56*a0597ba2SAndre Przywara if (ret) { 57*a0597ba2SAndre Przywara return ret; 58*a0597ba2SAndre Przywara } 59*a0597ba2SAndre Przywara 60*a0597ba2SAndre Przywara /* Switch to the recommended 3 MHz bus clock. */ 61*a0597ba2SAndre Przywara ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 62*a0597ba2SAndre Przywara if (ret) { 63*a0597ba2SAndre Przywara return ret; 64*a0597ba2SAndre Przywara } 65*a0597ba2SAndre Przywara 66*a0597ba2SAndre Przywara /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 67*a0597ba2SAndre Przywara ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 68*a0597ba2SAndre Przywara if (ret) { 69*a0597ba2SAndre Przywara return ret; 70*a0597ba2SAndre Przywara } 71*a0597ba2SAndre Przywara 72*a0597ba2SAndre Przywara /* Associate the 8-bit runtime address with the 12-bit bus address. */ 73*a0597ba2SAndre Przywara ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr); 74*a0597ba2SAndre Przywara if (ret) { 75*a0597ba2SAndre Przywara return ret; 76*a0597ba2SAndre Przywara } 77*a0597ba2SAndre Przywara 78*a0597ba2SAndre Przywara return 0; 79*a0597ba2SAndre Przywara } 80*a0597ba2SAndre Przywara 81*a0597ba2SAndre Przywara static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr) 82*a0597ba2SAndre Przywara { 83*a0597ba2SAndre Przywara int ret; 84*a0597ba2SAndre Przywara 85*a0597ba2SAndre Przywara ret = sunxi_init_platform_r_twi(socid, true); 86*a0597ba2SAndre Przywara if (ret) { 87*a0597ba2SAndre Przywara INFO("Could not init platform bus: %d\n", ret); 88*a0597ba2SAndre Przywara pmic = UNKNOWN; 89*a0597ba2SAndre Przywara return ret; 90*a0597ba2SAndre Przywara } 91*a0597ba2SAndre Przywara 92*a0597ba2SAndre Przywara ret = rsb_init(rsb_hw_addr); 93*a0597ba2SAndre Przywara if (ret) { 94*a0597ba2SAndre Przywara pmic = UNKNOWN; 95*a0597ba2SAndre Przywara return ret; 96*a0597ba2SAndre Przywara } 97*a0597ba2SAndre Przywara 98*a0597ba2SAndre Przywara return 0; 99*a0597ba2SAndre Przywara } 100*a0597ba2SAndre Przywara 101*a0597ba2SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 102*a0597ba2SAndre Przywara { 103*a0597ba2SAndre Przywara int node, ret; 104*a0597ba2SAndre Przywara uint32_t reg; 105*a0597ba2SAndre Przywara 106*a0597ba2SAndre Przywara node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806"); 107*a0597ba2SAndre Przywara if (node >= 0) { 108*a0597ba2SAndre Przywara pmic = AXP305; 109*a0597ba2SAndre Przywara } 110*a0597ba2SAndre Przywara 111*a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 112*a0597ba2SAndre Przywara INFO("PMIC: No known PMIC in DT, skipping setup.\n"); 113*a0597ba2SAndre Przywara return -ENODEV; 114*a0597ba2SAndre Przywara } 115*a0597ba2SAndre Przywara 116*a0597ba2SAndre Przywara if (fdt_read_uint32(fdt, node, "reg", ®)) { 117*a0597ba2SAndre Przywara ERROR("PMIC: PMIC DT node does not contain reg property.\n"); 118*a0597ba2SAndre Przywara return -EINVAL; 119*a0597ba2SAndre Przywara } 120*a0597ba2SAndre Przywara 121*a0597ba2SAndre Przywara pmic_bus_addr = reg; 122*a0597ba2SAndre Przywara rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr); 123*a0597ba2SAndre Przywara if (rsb_rt_addr == 0) { 124*a0597ba2SAndre Przywara ERROR("PMIC: no mapping for RSB address 0x%x\n", reg); 125*a0597ba2SAndre Przywara return -EINVAL; 126*a0597ba2SAndre Przywara } 127*a0597ba2SAndre Przywara 128*a0597ba2SAndre Przywara INFO("Probing for PMIC on RSB:\n"); 129*a0597ba2SAndre Przywara 130*a0597ba2SAndre Przywara ret = pmic_bus_init(socid, pmic_bus_addr); 131*a0597ba2SAndre Przywara if (ret) { 132*a0597ba2SAndre Przywara return ret; 133*a0597ba2SAndre Przywara } 134*a0597ba2SAndre Przywara 135*a0597ba2SAndre Przywara ret = axp_read(0x03); 136*a0597ba2SAndre Przywara switch (ret & 0xcf) { 137*a0597ba2SAndre Przywara case 0x40: /* AXP305 */ 138*a0597ba2SAndre Przywara if (pmic == AXP305) { 139*a0597ba2SAndre Przywara INFO("PMIC: found AXP305, setting up regulators\n"); 140*a0597ba2SAndre Przywara axp_setup_regulators(fdt); 141*a0597ba2SAndre Przywara } else { 142*a0597ba2SAndre Przywara pmic = UNKNOWN; 143*a0597ba2SAndre Przywara } 144*a0597ba2SAndre Przywara break; 145*a0597ba2SAndre Przywara } 146*a0597ba2SAndre Przywara 147*a0597ba2SAndre Przywara /* Switch the PMIC back to I2C mode. */ 148*a0597ba2SAndre Przywara return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C); 149*a0597ba2SAndre Przywara } 150*a0597ba2SAndre Przywara 15126123ca3SAndre Przywara void sunxi_power_down(void) 15226123ca3SAndre Przywara { 153*a0597ba2SAndre Przywara int ret; 154*a0597ba2SAndre Przywara 155*a0597ba2SAndre Przywara if (pmic == UNKNOWN) { 156*a0597ba2SAndre Przywara return; 157*a0597ba2SAndre Przywara } 158*a0597ba2SAndre Przywara 159*a0597ba2SAndre Przywara /* Re-initialise after rich OS might have used it. */ 160*a0597ba2SAndre Przywara ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr); 161*a0597ba2SAndre Przywara if (ret) { 162*a0597ba2SAndre Przywara return; 163*a0597ba2SAndre Przywara } 164*a0597ba2SAndre Przywara 16526123ca3SAndre Przywara switch (pmic) { 16626123ca3SAndre Przywara case AXP305: 167*a0597ba2SAndre Przywara axp_setbits(0x32, BIT(7)); 16826123ca3SAndre Przywara break; 16926123ca3SAndre Przywara default: 17026123ca3SAndre Przywara break; 17126123ca3SAndre Przywara } 17226123ca3SAndre Przywara } 17326123ca3SAndre Przywara 17426123ca3SAndre Przywara void sunxi_cpu_power_off_self(void) 17526123ca3SAndre Przywara { 17626123ca3SAndre Przywara u_register_t mpidr = read_mpidr(); 17726123ca3SAndre Przywara unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 17826123ca3SAndre Przywara 17926123ca3SAndre Przywara /* Enable the CPUIDLE hardware (only really needs to be done once). */ 18026123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 18126123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 18226123ca3SAndre Przywara 18326123ca3SAndre Przywara /* Trigger power off for this core. */ 18426123ca3SAndre Przywara mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 18526123ca3SAndre Przywara } 186