1*26123ca3SAndre Przywara /* 2*26123ca3SAndre Przywara * Copyright (c) 2017-2020, ARM Limited. All rights reserved. 3*26123ca3SAndre Przywara * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io> 4*26123ca3SAndre Przywara * 5*26123ca3SAndre Przywara * SPDX-License-Identifier: BSD-3-Clause 6*26123ca3SAndre Przywara */ 7*26123ca3SAndre Przywara 8*26123ca3SAndre Przywara #include <errno.h> 9*26123ca3SAndre Przywara #include <string.h> 10*26123ca3SAndre Przywara 11*26123ca3SAndre Przywara #include <arch_helpers.h> 12*26123ca3SAndre Przywara #include <common/debug.h> 13*26123ca3SAndre Przywara #include <drivers/allwinner/axp.h> 14*26123ca3SAndre Przywara #include <drivers/allwinner/sunxi_rsb.h> 15*26123ca3SAndre Przywara #include <lib/mmio.h> 16*26123ca3SAndre Przywara 17*26123ca3SAndre Przywara #include <sunxi_cpucfg.h> 18*26123ca3SAndre Przywara #include <sunxi_def.h> 19*26123ca3SAndre Przywara #include <sunxi_mmap.h> 20*26123ca3SAndre Przywara #include <sunxi_private.h> 21*26123ca3SAndre Przywara 22*26123ca3SAndre Przywara #define AXP305_I2C_ADDR 0x36 23*26123ca3SAndre Przywara #define AXP305_HW_ADDR 0x745 24*26123ca3SAndre Przywara #define AXP305_RT_ADDR 0x3a 25*26123ca3SAndre Przywara 26*26123ca3SAndre Przywara static enum pmic_type { 27*26123ca3SAndre Przywara UNKNOWN, 28*26123ca3SAndre Przywara AXP305, 29*26123ca3SAndre Przywara } pmic; 30*26123ca3SAndre Przywara 31*26123ca3SAndre Przywara int axp_read(uint8_t reg) 32*26123ca3SAndre Przywara { 33*26123ca3SAndre Przywara return rsb_read(AXP305_RT_ADDR, reg); 34*26123ca3SAndre Przywara } 35*26123ca3SAndre Przywara 36*26123ca3SAndre Przywara int axp_write(uint8_t reg, uint8_t val) 37*26123ca3SAndre Przywara { 38*26123ca3SAndre Przywara return rsb_write(AXP305_RT_ADDR, reg, val); 39*26123ca3SAndre Przywara } 40*26123ca3SAndre Przywara 41*26123ca3SAndre Przywara static int rsb_init(void) 42*26123ca3SAndre Przywara { 43*26123ca3SAndre Przywara int ret; 44*26123ca3SAndre Przywara 45*26123ca3SAndre Przywara ret = rsb_init_controller(); 46*26123ca3SAndre Przywara if (ret) 47*26123ca3SAndre Przywara return ret; 48*26123ca3SAndre Przywara 49*26123ca3SAndre Przywara /* Switch to the recommended 3 MHz bus clock. */ 50*26123ca3SAndre Przywara ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 51*26123ca3SAndre Przywara if (ret) 52*26123ca3SAndre Przywara return ret; 53*26123ca3SAndre Przywara 54*26123ca3SAndre Przywara /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 55*26123ca3SAndre Przywara ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 56*26123ca3SAndre Przywara if (ret) 57*26123ca3SAndre Przywara return ret; 58*26123ca3SAndre Przywara 59*26123ca3SAndre Przywara /* Associate the 8-bit runtime address with the 12-bit bus address. */ 60*26123ca3SAndre Przywara ret = rsb_assign_runtime_address(AXP305_HW_ADDR, AXP305_RT_ADDR); 61*26123ca3SAndre Przywara if (ret) 62*26123ca3SAndre Przywara return ret; 63*26123ca3SAndre Przywara 64*26123ca3SAndre Przywara return axp_check_id(); 65*26123ca3SAndre Przywara } 66*26123ca3SAndre Przywara 67*26123ca3SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 68*26123ca3SAndre Przywara { 69*26123ca3SAndre Przywara int ret; 70*26123ca3SAndre Przywara 71*26123ca3SAndre Przywara INFO("PMIC: Probing AXP305 on RSB\n"); 72*26123ca3SAndre Przywara 73*26123ca3SAndre Przywara ret = sunxi_init_platform_r_twi(socid, true); 74*26123ca3SAndre Przywara if (ret) { 75*26123ca3SAndre Przywara INFO("Could not init platform bus: %d\n", ret); 76*26123ca3SAndre Przywara return ret; 77*26123ca3SAndre Przywara } 78*26123ca3SAndre Przywara 79*26123ca3SAndre Przywara ret = rsb_init(); 80*26123ca3SAndre Przywara if (ret) { 81*26123ca3SAndre Przywara INFO("Could not init RSB: %d\n", ret); 82*26123ca3SAndre Przywara return ret; 83*26123ca3SAndre Przywara } 84*26123ca3SAndre Przywara 85*26123ca3SAndre Przywara pmic = AXP305; 86*26123ca3SAndre Przywara axp_setup_regulators(fdt); 87*26123ca3SAndre Przywara 88*26123ca3SAndre Przywara /* Switch the PMIC back to I2C mode. */ 89*26123ca3SAndre Przywara ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C); 90*26123ca3SAndre Przywara if (ret) 91*26123ca3SAndre Przywara return ret; 92*26123ca3SAndre Przywara 93*26123ca3SAndre Przywara return 0; 94*26123ca3SAndre Przywara } 95*26123ca3SAndre Przywara 96*26123ca3SAndre Przywara void sunxi_power_down(void) 97*26123ca3SAndre Przywara { 98*26123ca3SAndre Przywara switch (pmic) { 99*26123ca3SAndre Przywara case AXP305: 100*26123ca3SAndre Przywara /* Re-initialise after rich OS might have used it. */ 101*26123ca3SAndre Przywara sunxi_init_platform_r_twi(SUNXI_SOC_H616, true); 102*26123ca3SAndre Przywara rsb_init(); 103*26123ca3SAndre Przywara axp_power_off(); 104*26123ca3SAndre Przywara break; 105*26123ca3SAndre Przywara default: 106*26123ca3SAndre Przywara break; 107*26123ca3SAndre Przywara } 108*26123ca3SAndre Przywara } 109*26123ca3SAndre Przywara 110*26123ca3SAndre Przywara void sunxi_cpu_power_off_self(void) 111*26123ca3SAndre Przywara { 112*26123ca3SAndre Przywara u_register_t mpidr = read_mpidr(); 113*26123ca3SAndre Przywara unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 114*26123ca3SAndre Przywara 115*26123ca3SAndre Przywara /* Enable the CPUIDLE hardware (only really needs to be done once). */ 116*26123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 117*26123ca3SAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 118*26123ca3SAndre Przywara 119*26123ca3SAndre Przywara /* Trigger power off for this core. */ 120*26123ca3SAndre Przywara mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 121*26123ca3SAndre Przywara } 122