1 /* 2 * Copyright (c) 2017-2020, ARM Limited. All rights reserved. 3 * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io> 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #include <errno.h> 9 #include <string.h> 10 11 #include <arch_helpers.h> 12 #include <common/debug.h> 13 #include <common/fdt_wrappers.h> 14 #include <drivers/allwinner/axp.h> 15 #include <drivers/allwinner/sunxi_rsb.h> 16 #include <drivers/mentor/mi2cv.h> 17 #include <lib/mmio.h> 18 #include <libfdt.h> 19 20 #include <sunxi_cpucfg.h> 21 #include <sunxi_def.h> 22 #include <sunxi_mmap.h> 23 #include <sunxi_private.h> 24 25 static uint16_t pmic_bus_addr; 26 static uint8_t rsb_rt_addr; 27 28 static bool is_using_rsb(void) 29 { 30 return rsb_rt_addr != 0; 31 } 32 33 static enum pmic_type { 34 UNKNOWN, 35 AXP305, 36 AXP313, 37 } pmic; 38 39 static uint8_t get_rsb_rt_address(uint16_t hw_addr) 40 { 41 switch (hw_addr) { 42 case 0x745: return 0x3a; 43 } 44 45 return 0; 46 } 47 48 int axp_read(uint8_t reg) 49 { 50 uint8_t val; 51 int ret; 52 53 if (is_using_rsb()) { 54 return rsb_read(rsb_rt_addr, reg); 55 } 56 57 ret = i2c_write(pmic_bus_addr, 0, 0, ®, 1); 58 if (ret == 0) { 59 ret = i2c_read(pmic_bus_addr, 0, 0, &val, 1); 60 } 61 if (ret) { 62 ERROR("PMIC: Cannot read PMIC register %02x\n", reg); 63 return ret; 64 } 65 66 return val; 67 } 68 69 int axp_write(uint8_t reg, uint8_t val) 70 { 71 int ret; 72 73 if (is_using_rsb()) { 74 return rsb_write(rsb_rt_addr, reg, val); 75 } 76 77 ret = i2c_write(pmic_bus_addr, reg, 1, &val, 1); 78 if (ret) { 79 ERROR("PMIC: Cannot write PMIC register %02x\n", reg); 80 } 81 82 return ret; 83 } 84 85 static int rsb_init(int rsb_hw_addr) 86 { 87 int ret; 88 89 ret = rsb_init_controller(); 90 if (ret) { 91 return ret; 92 } 93 94 /* Switch to the recommended 3 MHz bus clock. */ 95 ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 96 if (ret) { 97 return ret; 98 } 99 100 /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 101 ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 102 if (ret) { 103 return ret; 104 } 105 106 /* Associate the 8-bit runtime address with the 12-bit bus address. */ 107 ret = rsb_assign_runtime_address(rsb_hw_addr, rsb_rt_addr); 108 if (ret) { 109 return ret; 110 } 111 112 return 0; 113 } 114 115 static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr) 116 { 117 int ret; 118 119 ret = sunxi_init_platform_r_twi(socid, is_using_rsb()); 120 if (ret) { 121 INFO("Could not init platform bus: %d\n", ret); 122 pmic = UNKNOWN; 123 return ret; 124 } 125 126 if (is_using_rsb()) { 127 ret = rsb_init(rsb_hw_addr); 128 if (ret) { 129 pmic = UNKNOWN; 130 return ret; 131 } 132 } else { 133 /* initialise mi2cv driver */ 134 i2c_init((void *)SUNXI_R_I2C_BASE); 135 } 136 137 return 0; 138 } 139 140 int sunxi_pmic_setup(uint16_t socid, const void *fdt) 141 { 142 int node, parent, ret; 143 uint32_t reg; 144 145 node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806"); 146 if (node >= 0) { 147 pmic = AXP305; 148 } 149 150 if (pmic == UNKNOWN) { 151 node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp313a"); 152 if (node >= 0) { 153 pmic = AXP313; 154 } 155 } 156 157 if (pmic == UNKNOWN) { 158 INFO("PMIC: No known PMIC in DT, skipping setup.\n"); 159 return -ENODEV; 160 } 161 162 if (fdt_read_uint32(fdt, node, "reg", ®)) { 163 ERROR("PMIC: PMIC DT node does not contain reg property.\n"); 164 return -EINVAL; 165 } 166 167 pmic_bus_addr = reg; 168 parent = fdt_parent_offset(fdt, node); 169 ret = fdt_node_check_compatible(fdt, parent, "allwinner,sun8i-a23-rsb"); 170 if (ret == 0) { 171 rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr); 172 if (rsb_rt_addr == 0) { 173 ERROR("PMIC: no mapping for RSB address 0x%x\n", 174 pmic_bus_addr); 175 return -EINVAL; 176 } 177 } 178 179 INFO("Probing for PMIC on %s:\n", is_using_rsb() ? "RSB" : "I2C"); 180 181 ret = pmic_bus_init(socid, pmic_bus_addr); 182 if (ret) { 183 return ret; 184 } 185 186 ret = axp_read(0x03); 187 switch (ret & 0xcf) { 188 case 0x40: /* AXP305 */ 189 if (pmic == AXP305) { 190 INFO("PMIC: found AXP305, setting up regulators\n"); 191 axp_setup_regulators(fdt); 192 } else { 193 pmic = UNKNOWN; 194 } 195 break; 196 case 0x48: /* AXP1530 */ 197 case 0x4b: /* AXP313A */ 198 case 0x4c: /* AXP313B */ 199 if (pmic == AXP313) { 200 INFO("PMIC: found AXP313\n"); 201 /* no regulators to set up */ 202 } else { 203 pmic = UNKNOWN; 204 } 205 break; 206 } 207 208 if (is_using_rsb()) { 209 /* Switch the PMIC back to I2C mode. */ 210 return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C); 211 } 212 213 if (pmic == UNKNOWN) { 214 INFO("Incompatible or unknown PMIC found.\n"); 215 return -ENODEV; 216 } 217 218 return 0; 219 } 220 221 void sunxi_power_down(void) 222 { 223 int ret; 224 225 if (pmic == UNKNOWN) { 226 return; 227 } 228 229 /* Re-initialise after rich OS might have used it. */ 230 ret = pmic_bus_init(SUNXI_SOC_H616, pmic_bus_addr); 231 if (ret) { 232 return; 233 } 234 235 switch (pmic) { 236 case AXP305: 237 axp_setbits(0x32, BIT(7)); 238 break; 239 case AXP313: 240 axp_setbits(0x1a, BIT(7)); 241 break; 242 default: 243 break; 244 } 245 } 246 247 void sunxi_cpu_power_off_self(void) 248 { 249 u_register_t mpidr = read_mpidr(); 250 unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 251 252 /* Enable the CPUIDLE hardware (only really needs to be done once). */ 253 mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 254 mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 255 256 /* Trigger power off for this core. */ 257 mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 258 } 259