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