1 /* 2 * Copyright (c) 2017-2019, ARM Limited and Contributors. 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 10 #include <common/debug.h> 11 #include <common/fdt_wrappers.h> 12 #include <drivers/allwinner/axp.h> 13 #include <drivers/allwinner/sunxi_rsb.h> 14 #include <libfdt.h> 15 #include <lib/mmio.h> 16 17 #include <sunxi_cpucfg.h> 18 #include <sunxi_def.h> 19 #include <sunxi_mmap.h> 20 #include <sunxi_private.h> 21 22 #define AXP805_HW_ADDR 0x745 23 #define AXP805_RT_ADDR 0x3a 24 25 static enum pmic_type { 26 UNKNOWN, 27 AXP805, 28 } pmic; 29 30 int axp_read(uint8_t reg) 31 { 32 return rsb_read(AXP805_RT_ADDR, reg); 33 } 34 35 int axp_write(uint8_t reg, uint8_t val) 36 { 37 return rsb_write(AXP805_RT_ADDR, reg, val); 38 } 39 40 static int rsb_init(void) 41 { 42 int ret; 43 44 ret = rsb_init_controller(); 45 if (ret) 46 return ret; 47 48 /* Switch to the recommended 3 MHz bus clock. */ 49 ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 50 if (ret) 51 return ret; 52 53 /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 54 ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 55 if (ret) 56 return ret; 57 58 /* Associate the 8-bit runtime address with the 12-bit bus address. */ 59 ret = rsb_assign_runtime_address(AXP805_HW_ADDR, AXP805_RT_ADDR); 60 if (ret) 61 return ret; 62 63 return axp_check_id(); 64 } 65 66 int sunxi_pmic_setup(uint16_t socid, const void *fdt) 67 { 68 int node, ret; 69 70 node = fdt_node_offset_by_compatible(fdt, 0, "allwinner,sun8i-a23-rsb"); 71 if ((node < 0) || !fdt_node_is_enabled(fdt, node)) { 72 return -ENODEV; 73 } 74 75 INFO("PMIC: Probing AXP805 on RSB\n"); 76 77 ret = sunxi_init_platform_r_twi(socid, true); 78 if (ret) 79 return ret; 80 81 ret = rsb_init(); 82 if (ret) 83 return ret; 84 85 /* Switch the AXP805 to master/single-PMIC mode. */ 86 ret = axp_write(0xff, 0x0); 87 if (ret) 88 return ret; 89 90 pmic = AXP805; 91 axp_setup_regulators(fdt); 92 93 /* Switch the PMIC back to I2C mode. */ 94 ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C); 95 if (ret) 96 return ret; 97 98 return 0; 99 } 100 101 void sunxi_power_down(void) 102 { 103 switch (pmic) { 104 case AXP805: 105 /* (Re-)init RSB in case the rich OS has disabled it. */ 106 sunxi_init_platform_r_twi(SUNXI_SOC_H6, true); 107 rsb_init(); 108 axp_power_off(); 109 break; 110 default: 111 break; 112 } 113 } 114 115 void sunxi_cpu_power_off_self(void) 116 { 117 u_register_t mpidr = read_mpidr(); 118 unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 119 120 /* Enable the CPUIDLE hardware (only really needs to be done once). */ 121 mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 122 mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 123 124 /* Trigger power off for this core. */ 125 mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 126 } 127