17c26b6ecSIcenowy Zheng /* 2c0e109f2SSamuel Holland * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. 37c26b6ecSIcenowy Zheng * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io> 47c26b6ecSIcenowy Zheng * 57c26b6ecSIcenowy Zheng * SPDX-License-Identifier: BSD-3-Clause 67c26b6ecSIcenowy Zheng */ 77c26b6ecSIcenowy Zheng 86d372828SIcenowy Zheng #include <errno.h> 909d40e0eSAntonio Nino Diaz 1009d40e0eSAntonio Nino Diaz #include <common/debug.h> 11fb23b104SSamuel Holland #include <drivers/allwinner/axp.h> 127060e0d8SSamuel Holland #include <drivers/allwinner/sunxi_rsb.h> 13*9227719dSAndre Przywara #include <lib/mmio.h> 1409d40e0eSAntonio Nino Diaz 15*9227719dSAndre Przywara #include <sunxi_cpucfg.h> 16d5ddf67aSAndre Przywara #include <sunxi_def.h> 176d372828SIcenowy Zheng #include <sunxi_mmap.h> 184ec1a239SAndre Przywara #include <sunxi_private.h> 196d372828SIcenowy Zheng 207060e0d8SSamuel Holland #define AXP805_HW_ADDR 0x745 217060e0d8SSamuel Holland #define AXP805_RT_ADDR 0x3a 226d372828SIcenowy Zheng 23c0e109f2SSamuel Holland static enum pmic_type { 24c0e109f2SSamuel Holland UNKNOWN, 256d372828SIcenowy Zheng AXP805, 26c0e109f2SSamuel Holland } pmic; 276d372828SIcenowy Zheng 28fb23b104SSamuel Holland int axp_read(uint8_t reg) 296d372828SIcenowy Zheng { 307060e0d8SSamuel Holland return rsb_read(AXP805_RT_ADDR, reg); 31fb23b104SSamuel Holland } 32fb23b104SSamuel Holland 33fb23b104SSamuel Holland int axp_write(uint8_t reg, uint8_t val) 346d372828SIcenowy Zheng { 357060e0d8SSamuel Holland return rsb_write(AXP805_RT_ADDR, reg, val); 366d372828SIcenowy Zheng } 376d372828SIcenowy Zheng 387060e0d8SSamuel Holland static int rsb_init(void) 396d372828SIcenowy Zheng { 406d372828SIcenowy Zheng int ret; 416d372828SIcenowy Zheng 427060e0d8SSamuel Holland ret = rsb_init_controller(); 434538c498SSamuel Holland if (ret) 444538c498SSamuel Holland return ret; 456d372828SIcenowy Zheng 467060e0d8SSamuel Holland /* Switch to the recommended 3 MHz bus clock. */ 477060e0d8SSamuel Holland ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); 484538c498SSamuel Holland if (ret) 494538c498SSamuel Holland return ret; 506d372828SIcenowy Zheng 517060e0d8SSamuel Holland /* Initiate an I2C transaction to switch the PMIC to RSB mode. */ 527060e0d8SSamuel Holland ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8); 537060e0d8SSamuel Holland if (ret) 547060e0d8SSamuel Holland return ret; 557060e0d8SSamuel Holland 567060e0d8SSamuel Holland /* Associate the 8-bit runtime address with the 12-bit bus address. */ 577060e0d8SSamuel Holland ret = rsb_assign_runtime_address(AXP805_HW_ADDR, AXP805_RT_ADDR); 587060e0d8SSamuel Holland if (ret) 597060e0d8SSamuel Holland return ret; 607060e0d8SSamuel Holland 617060e0d8SSamuel Holland return axp_check_id(); 626d372828SIcenowy Zheng } 637c26b6ecSIcenowy Zheng 64df301601SAndre Przywara int sunxi_pmic_setup(uint16_t socid, const void *fdt) 657c26b6ecSIcenowy Zheng { 666d372828SIcenowy Zheng int ret; 676d372828SIcenowy Zheng 687060e0d8SSamuel Holland INFO("PMIC: Probing AXP805 on RSB\n"); 694538c498SSamuel Holland 707060e0d8SSamuel Holland ret = sunxi_init_platform_r_twi(socid, true); 714538c498SSamuel Holland if (ret) 724538c498SSamuel Holland return ret; 734538c498SSamuel Holland 747060e0d8SSamuel Holland ret = rsb_init(); 757060e0d8SSamuel Holland if (ret) 767060e0d8SSamuel Holland return ret; 776d372828SIcenowy Zheng 787060e0d8SSamuel Holland /* Switch the AXP805 to master/single-PMIC mode. */ 797060e0d8SSamuel Holland ret = axp_write(0xff, 0x0); 806d372828SIcenowy Zheng if (ret) 81c0e109f2SSamuel Holland return ret; 82c0e109f2SSamuel Holland 836d372828SIcenowy Zheng pmic = AXP805; 84fb23b104SSamuel Holland axp_setup_regulators(fdt); 857c26b6ecSIcenowy Zheng 867060e0d8SSamuel Holland /* Switch the PMIC back to I2C mode. */ 877060e0d8SSamuel Holland ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C); 887060e0d8SSamuel Holland if (ret) 897060e0d8SSamuel Holland return ret; 907060e0d8SSamuel Holland 917c26b6ecSIcenowy Zheng return 0; 927c26b6ecSIcenowy Zheng } 935069c1cfSIcenowy Zheng 94818e6732SSamuel Holland void sunxi_power_down(void) 955069c1cfSIcenowy Zheng { 965069c1cfSIcenowy Zheng switch (pmic) { 975069c1cfSIcenowy Zheng case AXP805: 987060e0d8SSamuel Holland /* (Re-)init RSB in case the rich OS has disabled it. */ 997060e0d8SSamuel Holland sunxi_init_platform_r_twi(SUNXI_SOC_H6, true); 1007060e0d8SSamuel Holland rsb_init(); 101fb23b104SSamuel Holland axp_power_off(); 1025069c1cfSIcenowy Zheng break; 1035069c1cfSIcenowy Zheng default: 1045069c1cfSIcenowy Zheng break; 1055069c1cfSIcenowy Zheng } 1065069c1cfSIcenowy Zheng } 107*9227719dSAndre Przywara 108*9227719dSAndre Przywara void sunxi_cpu_power_off_self(void) 109*9227719dSAndre Przywara { 110*9227719dSAndre Przywara u_register_t mpidr = read_mpidr(); 111*9227719dSAndre Przywara unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); 112*9227719dSAndre Przywara 113*9227719dSAndre Przywara /* Enable the CPUIDLE hardware (only really needs to be done once). */ 114*9227719dSAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000); 115*9227719dSAndre Przywara mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001); 116*9227719dSAndre Przywara 117*9227719dSAndre Przywara /* Trigger power off for this core. */ 118*9227719dSAndre Przywara mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core)); 119*9227719dSAndre Przywara } 120