Skip to content

Instantly share code, notes, and snippets.

@apritzel
Created May 16, 2016 08:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apritzel/dd882e8e03ca2a49ad8f24d030d4b368 to your computer and use it in GitHub Desktop.
Save apritzel/dd882e8e03ca2a49ad8f24d030d4b368 to your computer and use it in GitHub Desktop.
AXP RSB setup (as part of ATF)
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
index eb043b1..34f1c6e 100644
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
@@ -190,6 +190,9 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2,
* present.
*/
sunxi_security_setup();
+
+ sunxi_power_setup();
+
/*
* Tell BL31 where the non-trusted software image
* is located and the entry state information
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
index 0123a04..4fa5098 100644
--- a/plat/sun50iw1p1/platform.mk
+++ b/plat/sun50iw1p1/platform.mk
@@ -47,6 +47,7 @@ BL31_SOURCES += drivers/arm/gic/arm_gic.c \
plat/sun50iw1p1/bl31_sunxi_setup.c \
plat/sun50iw1p1/plat_pm.c \
plat/sun50iw1p1/sunxi_security.c \
+ plat/sun50iw1p1/sunxi_power.c \
plat/sun50iw1p1/sunxi_cpu_ops.c \
plat/sun50iw1p1/plat_topology.c \
plat/sun50iw1p1/aarch64/plat_helpers.S \
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
new file mode 100644
index 0000000..f4bc68f
--- /dev/null
+++ b/plat/sun50iw1p1/sunxi_power.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <plat_config.h>
+#include <mmio.h>
+#include "sunxi_def.h"
+#include "sunxi_private.h"
+
+#define R_PIO_BASE 0x1f02c00ULL
+#define R_PRCM_BASE 0x1f01400ULL
+
+#define RSB_BASE 0x1f03400ULL
+#define RSB_CTRL 0x00
+#define RSB_CCR 0x04
+#define RSB_INTE 0x08
+#define RSB_STAT 0x0c
+#define RSB_DADDR0 0x10
+#define RSB_DLEN 0x18
+#define RSB_DATA0 0x1c
+#define RSB_LCR 0x24
+#define RSB_PMCR 0x28
+#define RSB_CMD 0x2c
+#define RSB_SADDR 0x30
+
+#define RSBCMD_SRTA 0xE8
+#define RSBCMD_RD8 0x8B
+#define RSBCMD_RD16 0x9C
+#define RSBCMD_RD32 0xA6
+#define RSBCMD_WR8 0x4E
+#define RSBCMD_WR16 0x59
+#define RSBCMD_WR32 0x63
+
+
+static int init_rsb(void)
+{
+ uint32_t reg;
+
+ return 0; /* avoid this for now, it's already set up */
+
+ /* switch pins PL0 and PL1 to RSB */
+ reg = mmio_read_32(R_PIO_BASE + 0x00);
+ mmio_write_32(R_PIO_BASE + 0, (reg & ~0xff) | 0x22);
+ /* TODO: program no-pull and 10mA drive strength */
+
+ /* un-gate RSB clock */
+ reg = mmio_read_32(R_PRCM_BASE + 0x28);
+ mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x40);
+
+ /* de-assert reset of RSB */
+ reg = mmio_read_32(R_PRCM_BASE + 0xb0);
+ mmio_write_32(R_PRCM_BASE + 0xb0, reg | 0x40);
+}
+
+static void set_rsb_address(uint8_t rta)
+{
+ uint32_t reg = mmio_read_32(RSB_BASE + RSB_SADDR);
+
+ return; /* we can just use the programmed address for now */
+
+ mmio_write_32(RSB_BASE + RSB_SADDR, (reg & 0xffff) | ((int)rta << 16));
+}
+
+static int read_rsb_byte(uint8_t address)
+{
+ uint32_t reg;
+
+ mmio_write_32(RSB_BASE + RSB_DLEN, 0x10); /* read a byte, snake oil? */
+ mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_RD8); /* read a byte */
+ mmio_write_32(RSB_BASE + RSB_DADDR0, address);
+ mmio_write_32(RSB_BASE + RSB_CTRL, 0x80); /* start transaction */
+ do {
+ reg = mmio_read_32(RSB_BASE + RSB_CTRL);
+ } while (reg & 0x80); /* transaction in progress */
+
+ reg = mmio_read_32(RSB_BASE + RSB_STAT);
+ if (reg == 0x01) { /* transaction complete */
+ reg = mmio_read_32(RSB_BASE + RSB_DATA0); /* result register */
+ return reg & 0xff;
+ }
+
+ return -reg;
+}
+
+static int write_rsb_byte(uint8_t address, uint8_t value)
+{
+ uint32_t reg;
+
+ mmio_write_32(RSB_BASE + RSB_DLEN, 0x00); /* write a byte, snake oil? */
+ mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_WR8); /* write a byte */
+ mmio_write_32(RSB_BASE + RSB_DADDR0, address);
+ mmio_write_32(RSB_BASE + RSB_DATA0, value);
+ mmio_write_32(RSB_BASE + RSB_CTRL, 0x80); /* start transaction */
+ do {
+ reg = mmio_read_32(RSB_BASE + RSB_CTRL);
+ } while (reg & 0x80); /* transaction in progress */
+
+ reg = mmio_read_32(RSB_BASE + RSB_STAT);
+ if (reg == 0x01) /* transaction complete */
+ return 0;
+
+ return -reg;
+}
+
+/*
+ * Program the AXP803 via the RSB bus.
+ */
+int sunxi_power_setup(void)
+{
+ int ret;
+
+ NOTICE("Configuring AXP PMIC\n");
+
+ ret = init_rsb();
+ if (ret) {
+ NOTICE("");
+ return -1;
+ }
+ set_rsb_address(0x2d); /* TODO: give rationale for this value */
+
+ ret = read_rsb_byte(0x03);
+ if (ret < 0) {
+ NOTICE("PMIC: error %d reading PMIC type\n", ret);
+ return -2;
+ }
+
+ if ((ret & 0xcf) != 0x41) {
+ NOTICE("PMIC: unknown PMIC type number 0x%x\n", ret);
+ return -3;
+ }
+
+ ret = read_rsb_byte(0x20);
+ if (ret != 0x0e && ret != 0x11) {
+ int voltage = (ret & 0x1f) * 10 + 16;
+
+ NOTICE("PMIC: DCDC1 voltage is an unexpected %.%dV\n",
+ voltage / 10, voltage % 10);
+ return -4;
+ }
+
+ if (ret != 0x11) {
+ ret = write_rsb_byte(0x20, 0x11);
+ if (ret < 0) {
+ NOTICE("PMIC: error %d writing DCDC1 voltage\n", ret);
+ return -5;
+ }
+ }
+
+ ret = read_rsb_byte(0x12);
+ if (ret != 0x01 && ret != 0x81) {
+ NOTICE("PMIC: Output power control 2 is an unexpected 0x%x\n",
+ ret);
+ return -6;
+ }
+
+ if (ret != 0x81) {
+ ret = write_rsb_byte(0x12, 0x81);
+ if (ret < 0) {
+ NOTICE("PMIC: error %d enabling DC1SW\n", ret);
+ return -7;
+ }
+ }
+
+ NOTICE("PMIC: successfully set up\n");
+
+ return 0;
+}
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
index afb5943..77f10a3 100644
--- a/plat/sun50iw1p1/sunxi_private.h
+++ b/plat/sun50iw1p1/sunxi_private.h
@@ -65,6 +65,9 @@ void sunxi_io_setup(void);
/* Declarations for sunxi_security.c */
void sunxi_security_setup(void);
+/* Declarations for sunxi_power.c */
+int sunxi_power_setup(void);
+
/* Gets the SPSR for BL33 entry */
uint32_t sunxi_get_spsr_for_bl33_entry(int aarch);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment