diff --git a/drivers/allwinner/axp/axp805.c b/drivers/allwinner/axp/axp805.c new file mode 100644 index 000000000..8d029c0bd --- /dev/null +++ b/drivers/allwinner/axp/axp805.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +const uint8_t axp_chip_id = AXP805_CHIP_ID; +const char *const axp_compatible = "x-powers,axp805"; + +/* + * The "dcdcd" split changes the step size by a factor of 5, not 2; + * disallow values above the split to maintain accuracy. + */ +const struct axp_regulator axp_regulators[] = { + {"dcdca", 600, 1520, 10, 50, 0x12, 0x10, 0}, + {"dcdcb", 1000, 2550, 50, NA, 0x13, 0x10, 1}, + {"dcdcc", 600, 1520, 10, 50, 0x14, 0x10, 2}, + {"dcdcd", 600, 1500, 20, NA, 0x15, 0x10, 3}, + {"dcdce", 1100, 3400, 100, NA, 0x16, 0x10, 4}, + {"aldo1", 700, 3300, 100, NA, 0x17, 0x10, 5}, + {"aldo2", 700, 3300, 100, NA, 0x18, 0x10, 6}, + {"aldo3", 700, 3300, 100, NA, 0x19, 0x10, 7}, + {"bldo1", 700, 1900, 100, NA, 0x20, 0x11, 0}, + {"bldo2", 700, 1900, 100, NA, 0x21, 0x11, 1}, + {"bldo3", 700, 1900, 100, NA, 0x22, 0x11, 2}, + {"bldo4", 700, 1900, 100, NA, 0x23, 0x11, 3}, + {"cldo1", 700, 3300, 100, NA, 0x24, 0x11, 4}, + {"cldo2", 700, 4200, 100, 27, 0x25, 0x11, 5}, + {"cldo3", 700, 3300, 100, NA, 0x26, 0x11, 6}, + {} +}; diff --git a/drivers/allwinner/axp/common.c b/drivers/allwinner/axp/common.c index a021e1c9d..13437fec8 100644 --- a/drivers/allwinner/axp/common.c +++ b/drivers/allwinner/axp/common.c @@ -108,7 +108,7 @@ static bool should_enable_regulator(const void *fdt, int node) void axp_setup_regulators(const void *fdt) { int node; - bool dc1sw = false; + bool sw = false; if (fdt == NULL) return; @@ -120,6 +120,7 @@ void axp_setup_regulators(const void *fdt) return; } + /* This applies to AXP803 only. */ if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) { axp_clrbits(0x8f, BIT(4)); axp_setbits(0x30, BIT(2)); @@ -144,26 +145,31 @@ void axp_setup_regulators(const void *fdt) continue; name = fdt_get_name(fdt, node, &length); + + /* Enable the switch last to avoid overheating. */ + if (!strncmp(name, "dc1sw", length) || + !strncmp(name, "sw", length)) { + sw = true; + continue; + } + for (reg = axp_regulators; reg->dt_name; reg++) { if (!strncmp(name, reg->dt_name, length)) { setup_regulator(fdt, node, reg); break; } } - - if (!strncmp(name, "dc1sw", length)) { - /* Delay DC1SW enablement to avoid overheating. */ - dc1sw = true; - continue; - } } /* - * If DLDO2 is enabled after DC1SW, the PMIC overheats and shuts - * down. So always enable DC1SW as the very last regulator. + * On the AXP803, if DLDO2 is enabled after DC1SW, the PMIC overheats + * and shuts down. So always enable DC1SW as the very last regulator. */ - if (dc1sw) { - INFO("PMIC: Enabling DC1SW\n"); - axp_setbits(0x12, BIT(7)); + if (sw) { + INFO("PMIC: Enabling DC SW\n"); + if (axp_chip_id == AXP803_CHIP_ID) + axp_setbits(0x12, BIT(7)); + if (axp_chip_id == AXP805_CHIP_ID) + axp_setbits(0x11, BIT(7)); } } diff --git a/include/drivers/allwinner/axp.h b/include/drivers/allwinner/axp.h index f3d6277cb..9c0035f96 100644 --- a/include/drivers/allwinner/axp.h +++ b/include/drivers/allwinner/axp.h @@ -13,6 +13,7 @@ enum { AXP803_CHIP_ID = 0x41, + AXP805_CHIP_ID = 0x40, }; struct axp_regulator { diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk index 6866bd65a..5e8885d7a 100644 --- a/plat/allwinner/common/allwinner-common.mk +++ b/plat/allwinner/common/allwinner-common.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -20,7 +20,8 @@ PLAT_BL_COMMON_SOURCES := drivers/ti/uart/${ARCH}/16550_console.S \ ${AW_PLAT}/common/plat_helpers.S \ ${AW_PLAT}/common/sunxi_common.c -BL31_SOURCES += drivers/arm/gic/common/gic_common.c \ +BL31_SOURCES += drivers/allwinner/axp/common.c \ + drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/delay_timer/delay_timer.c \ diff --git a/plat/allwinner/sun50i_a64/platform.mk b/plat/allwinner/sun50i_a64/platform.mk index a76a679ed..f6d5aa9f8 100644 --- a/plat/allwinner/sun50i_a64/platform.mk +++ b/plat/allwinner/sun50i_a64/platform.mk @@ -8,5 +8,4 @@ include plat/allwinner/common/allwinner-common.mk BL31_SOURCES += drivers/allwinner/axp/axp803.c \ - drivers/allwinner/axp/common.c \ drivers/allwinner/sunxi_rsb.c diff --git a/plat/allwinner/sun50i_h6/platform.mk b/plat/allwinner/sun50i_h6/platform.mk index fa1b0e598..4ecc57cf0 100644 --- a/plat/allwinner/sun50i_h6/platform.mk +++ b/plat/allwinner/sun50i_h6/platform.mk @@ -7,4 +7,5 @@ # The differences between the platform are covered by the include files. include plat/allwinner/common/allwinner-common.mk -BL31_SOURCES += drivers/mentor/i2c/mi2cv.c +BL31_SOURCES += drivers/allwinner/axp/axp805.c \ + drivers/mentor/i2c/mi2cv.c diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c index 7bb266b88..443015bac 100644 --- a/plat/allwinner/sun50i_h6/sunxi_power.c +++ b/plat/allwinner/sun50i_h6/sunxi_power.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -19,31 +20,33 @@ #include #define AXP805_ADDR 0x36 -#define AXP805_ID 0x03 static enum pmic_type { UNKNOWN, AXP805, } pmic; -int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) +int axp_read(uint8_t reg) { + uint8_t val; int ret; - ret = i2c_write(chip, 0, 0, ®, 1); + ret = i2c_write(AXP805_ADDR, 0, 0, ®, 1); if (ret == 0) - ret = i2c_read(chip, 0, 0, val, 1); - if (ret) + ret = i2c_read(AXP805_ADDR, 0, 0, &val, 1); + if (ret) { ERROR("PMIC: Cannot read AXP805 register %02x\n", reg); + return ret; + } - return ret; + return val; } -int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) +int axp_write(uint8_t reg, uint8_t val) { int ret; - ret = i2c_write(chip, reg, 1, &val, 1); + ret = i2c_write(AXP805_ADDR, reg, 1, &val, 1); if (ret) ERROR("PMIC: Cannot write AXP805 register %02x\n", reg); @@ -53,23 +56,16 @@ int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) static int axp805_probe(void) { int ret; - uint8_t val; /* Switch the AXP805 to master/single-PMIC mode. */ - ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); + ret = axp_write(0xff, 0x0); if (ret) return ret; - ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); + ret = axp_check_id(); if (ret) return ret; - val &= 0xcf; - if (val != 0x40) { - ERROR("PMIC: Found unknown PMIC %02x\n", val); - return -EINVAL; - } - return 0; } @@ -91,22 +87,20 @@ int sunxi_pmic_setup(uint16_t socid, const void *fdt) return ret; pmic = AXP805; + axp_setup_regulators(fdt); return 0; } void sunxi_power_down(void) { - uint8_t val; - switch (pmic) { case AXP805: /* Re-initialise after rich OS might have used it. */ sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); /* initialise mi2cv driver */ i2c_init((void *)SUNXI_R_I2C_BASE); - axp_i2c_read(AXP805_ADDR, 0x32, &val); - axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); + axp_power_off(); break; default: break;