summaryrefslogtreecommitdiff
path: root/plat/allwinner
diff options
context:
space:
mode:
authorIcenowy Zheng <icenowy@aosc.io>2018-07-22 21:30:14 +0800
committerIcenowy Zheng <icenowy@aosc.io>2018-09-07 23:20:17 +0800
commit6d37282807c8540319777cb50f411a2e56607438 (patch)
tree969eb5dbcb01d19d5f69408500040a5e6ed7cfed /plat/allwinner
parent5686b2eca292c9e96c1f18c5b81848053a782ed2 (diff)
allwinner: sun50i_h6: add initial AXP805 PMIC code
The OTT reference design of Allwinner H6 SoC uses an X-Powers AXP805 PMIC. Add initial code for it. Currently it's only detected. Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Diffstat (limited to 'plat/allwinner')
-rw-r--r--plat/allwinner/sun50i_h6/platform.mk2
-rw-r--r--plat/allwinner/sun50i_h6/sunxi_power.c109
2 files changed, 109 insertions, 2 deletions
diff --git a/plat/allwinner/sun50i_h6/platform.mk b/plat/allwinner/sun50i_h6/platform.mk
index e9ee23d0..c3901d01 100644
--- a/plat/allwinner/sun50i_h6/platform.mk
+++ b/plat/allwinner/sun50i_h6/platform.mk
@@ -7,6 +7,7 @@
include lib/xlat_tables_v2/xlat_tables.mk
AW_PLAT := plat/allwinner
+AW_DRIVERS := drivers/allwinner
PLAT_INCLUDES := -Iinclude/plat/arm/common \
-Iinclude/plat/arm/common/aarch64 \
@@ -15,6 +16,7 @@ PLAT_INCLUDES := -Iinclude/plat/arm/common \
PLAT_BL_COMMON_SOURCES := drivers/console/${ARCH}/console.S \
drivers/ti/uart/${ARCH}/16550_console.S \
+ ${AW_DRIVERS}/sunxi_i2c.c \
${XLAT_TABLES_LIB_SRCS} \
${AW_PLAT}/common/plat_helpers.S \
${AW_PLAT}/common/sunxi_common.c
diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c
index 50eaa6b9..3638a199 100644
--- a/plat/allwinner/sun50i_h6/sunxi_power.c
+++ b/plat/allwinner/sun50i_h6/sunxi_power.c
@@ -6,11 +6,116 @@
*/
#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mmio.h>
+#include <mentor/mi2cv.h>
+#include <string.h>
+#include <sunxi_mmap.h>
+
+#define AXP805_ADDR 0x36
+#define AXP805_ID 0x03
+
+enum pmic_type {
+ NO_PMIC,
+ AXP805,
+};
+
+enum pmic_type pmic;
+
+static int sunxi_init_r_i2c(void)
+{
+ uint32_t reg;
+
+ /* get currently configured function for pins PL0 and PL1 */
+ reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00);
+ if ((reg & 0xff) == 0x33) {
+ NOTICE("PMIC: already configured for TWI\n");
+ }
+
+ /* switch pins PL0 and PL1 to I2C */
+ mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33);
+
+ /* level 2 drive strength */
+ reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14);
+ mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
+
+ /* set both ports to pull-up */
+ reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c);
+ mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
+
+ /* assert & de-assert reset of R_I2C */
+ reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+ mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0);
+ reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+ mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000);
+
+ /* un-gate R_I2C clock */
+ reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+ mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001);
+
+ /* call mi2cv driver */
+ i2c_init((void *)SUNXI_R_I2C_BASE);
+
+ return 0;
+}
+
+int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
+{
+ int ret;
+
+ ret = i2c_write(chip, 0, 0, &reg, 1);
+ if (ret)
+ return ret;
+
+ return i2c_read(chip, 0, 0, val, 1);
+}
+
+int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
+{
+ return i2c_write(chip, reg, 1, &val, 1);
+}
+
+static int axp805_probe(void)
+{
+ int ret;
+ uint8_t val;
+
+ ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
+ if (ret) {
+ ERROR("PMIC: Cannot put AXP805 to master mode.\n");
+ return -EPERM;
+ }
+
+ ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
+
+ if (!ret && ((val & 0xcf) == 0x40))
+ NOTICE("PMIC: AXP805 detected\n");
+ else if (ret) {
+ ERROR("PMIC: Cannot communicate with AXP805.\n");
+ return -EPERM;
+ } else {
+ ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
int sunxi_pmic_setup(void)
{
- /* STUB */
- NOTICE("BL31: STUB PMIC setup code called\n");
+ int ret;
+
+ sunxi_init_r_i2c();
+
+ NOTICE("PMIC: Probing AXP805\n");
+ pmic = AXP805;
+
+ ret = axp805_probe();
+ if (ret)
+ pmic = NO_PMIC;
+ else
+ pmic = AXP805;
return 0;
}