summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plat/sun50iw1p1/bl31_sunxi_setup.c5
-rw-r--r--plat/sun50iw1p1/platform.mk1
-rw-r--r--plat/sun50iw1p1/sunxi_power.c199
-rw-r--r--plat/sun50iw1p1/sunxi_private.h5
-rw-r--r--plat/sun50iw1p1/sunxi_rsb.c292
5 files changed, 323 insertions, 179 deletions
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
index 3e30814..78d3edc 100644
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
@@ -235,6 +235,7 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2,
******************************************************************************/
void bl31_platform_setup(void)
{
+ int ret;
uint16_t socid;
/* Initialize the gic cpu and distributor interfaces */
@@ -248,6 +249,10 @@ void bl31_platform_setup(void)
switch (socid) {
case 0x1689:
+ ret = sunxi_rsb_init();
+ if (ret)
+ ERROR("Could not init RSB controller.\n");
+
sunxi_pmic_setup();
break;
case 0x1718:
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
index b788f81..bc20110 100644
--- a/plat/sun50iw1p1/platform.mk
+++ b/plat/sun50iw1p1/platform.mk
@@ -45,6 +45,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_rsb.c \
plat/sun50iw1p1/sunxi_power.c \
plat/sun50iw1p1/sunxi_cpu_ops.c \
plat/sun50iw1p1/plat_topology.c \
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
index 9ab605e..827f0d5 100644
--- a/plat/sun50iw1p1/sunxi_power.c
+++ b/plat/sun50iw1p1/sunxi_power.c
@@ -35,181 +35,22 @@
#include "sunxi_def.h"
#include "sunxi_private.h"
-#define R_PRCM_BASE 0x1f01400ULL
-#define R_TWI_BASE 0x1f02400ULL
-#define R_PIO_BASE 0x1f02c00ULL
+#define PMIC_RSB_RT_ADDR 0x2d
-#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
-
-#define BIT(n) (1U << (n))
-
-#define RUNTIME_ADDR 0x2d
-#define AXP803_HW_ADDR 0x3a3
-
-/* Initialize the RSB controller and its pins. */
-static int init_rsb(void)
-{
- uint32_t reg;
-
- /* un-gate PIO clock */
- reg = mmio_read_32(R_PRCM_BASE + 0x28);
- mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x01);
-
- /* get currently configured function for pins PL0 and PL1 */
- reg = mmio_read_32(R_PIO_BASE + 0x00);
- if ((reg & 0xff) == 0x33) {
- NOTICE("already configured for TWI\n");
- return -EBUSY;
- }
-
- if ((reg & 0xff) == 0x22) {
- NOTICE("PMIC: already configured for RSB\n");
- return -EEXIST; /* configured for RSB mode already */
- }
-
- /* switch pins PL0 and PL1 to RSB */
- mmio_write_32(R_PIO_BASE + 0, (reg & ~0xff) | 0x22);
-
- /* level 2 drive strength */
- reg = mmio_read_32(R_PIO_BASE + 0x14);
- mmio_write_32(R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
-
- /* set both ports to pull-up */
- reg = mmio_read_32(R_PIO_BASE + 0x1c);
- mmio_write_32(R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
-
- /* assert & de-assert reset of RSB */
- reg = mmio_read_32(R_PRCM_BASE + 0xb0);
- mmio_write_32(R_PRCM_BASE + 0xb0, reg & ~0x08);
- reg = mmio_read_32(R_PRCM_BASE + 0xb0);
- mmio_write_32(R_PRCM_BASE + 0xb0, reg | 0x08);
-
- /* un-gate RSB clock */
- reg = mmio_read_32(R_PRCM_BASE + 0x28);
- mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x08);
-
- mmio_write_32(RSB_BASE + RSB_CTRL, 0x01); /* soft reset */
-
- mmio_write_32(RSB_BASE + RSB_CCR, 0x11d); /* clock to 400 KHz */
-
- do {
- reg = mmio_read_32(RSB_BASE + RSB_CTRL);
- } while (reg & 1); /* transaction in progress */
-
- return 0;
-}
-
-int sunxi_pmic_read(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;
-}
-
-int sunxi_pmic_write(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;
-}
-
-static void rsb_wait(const char *desc)
+int sunxi_pmic_read(uint8_t reg)
{
- uint32_t reg;
- int cnt = 0;
-
- do {
- reg = mmio_read_32(RSB_BASE + RSB_CTRL);
- cnt++;
- } while (reg & 0x80); /* transaction in progress */
-
- reg = mmio_read_32(RSB_BASE + RSB_STAT);
- if (reg == 0x01)
- return;
+ uint32_t val;
+ int ret;
- ERROR("%s: 0x%x\n", desc, reg);
+ ret = rsb_read(PMIC_RSB_RT_ADDR, reg, &val, 1);
+ if (ret)
+ return ret;
+ return val;
}
-/* Initialize the RSB PMIC connection. */
-static int pmic_init(uint16_t hw_addr, uint8_t rt_addr)
+int sunxi_pmic_write(uint8_t reg, uint8_t value)
{
- int ret;
-
- /* Switch PMIC to RSB mode */
- mmio_write_32(RSB_BASE + RSB_PMCR,
- 0x00 | (0x3e << 8) | (0x7c << 16) | BIT(31));
- do {
- ret = mmio_read_32(RSB_BASE + RSB_PMCR);
- } while (ret & (1U << 31)); /* transaction in progress */
-
- mmio_write_32(RSB_BASE + RSB_CCR, 0x103); /* 3 MHz */
-
- mmio_write_32(RSB_BASE + RSB_SADDR, hw_addr | (rt_addr << 16));
- mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_SRTA);
- mmio_write_32(RSB_BASE + RSB_CTRL, 0x80);
- rsb_wait("set run-time address");
-
- /* Set slave runtime address */
- mmio_write_32(RSB_BASE + RSB_SADDR, rt_addr << 16);
-
- ret = sunxi_pmic_read(0x03);
- if (ret < 0) {
- ERROR("PMIC: error %d reading PMIC type\n", ret);
- return -2;
- }
-
- if ((ret & 0xcf) != 0x41) {
- ERROR("PMIC: unknown PMIC type number 0x%x\n", ret);
- return -3;
- }
-
- return 0;
+ return rsb_write(PMIC_RSB_RT_ADDR, reg, value, 1);
}
/* Setup the PMIC: DCDC1 to 3.3V, enable DC1SW and DLDO4 */
@@ -270,20 +111,20 @@ int sunxi_pmic_setup(void)
NOTICE("Configuring AXP PMIC\n");
- ret = init_rsb();
- if (ret && ret != -EEXIST) {
- ERROR("Could not init RSB controller.\n");
- return -1;
+ /* Test PMIC communication */
+ ret = sunxi_pmic_read(0x03);
+ if (ret < 0) {
+ ERROR("PMIC: error %d reading PMIC IC type register\n", ret);
+ return -2;
}
- if (ret != -EEXIST) {
- ret = pmic_init(AXP803_HW_ADDR, RUNTIME_ADDR);
- if (ret) {
- ERROR("Could not connect to AXP PMIC.\n");
- return -2;
- }
+ /* Check IC type number equals 0b01xx00001 */
+ if ((ret & 0xcf) != 0x41) {
+ ERROR("PMIC: unknown PMIC IC type 0x%x\n", ret);
+ return -3;
}
+ /* Setup the PMIC */
ret = pmic_setup();
if (!ret)
NOTICE("PMIC: setup successful\n");
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
index 4750056..34e36d8 100644
--- a/plat/sun50iw1p1/sunxi_private.h
+++ b/plat/sun50iw1p1/sunxi_private.h
@@ -67,6 +67,11 @@ void sunxi_io_setup(void);
/* Declarations for sunxi_security.c */
void sunxi_security_setup(void);
+/* Declarations for sunxi_rsb.c */
+int rsb_read(uint8_t rt_addr, uint8_t addr, uint32_t *val, size_t size);
+int rsb_write(uint8_t rt_addr, uint8_t addr, uint32_t val, size_t size);
+int sunxi_rsb_init(void);
+
/* Declarations for sunxi_power.c */
int sunxi_pmic_setup(void);
int sunxi_pmic_read(uint8_t address);
diff --git a/plat/sun50iw1p1/sunxi_rsb.c b/plat/sun50iw1p1/sunxi_rsb.c
new file mode 100644
index 0000000..7d7210e
--- /dev/null
+++ b/plat/sun50iw1p1/sunxi_rsb.c
@@ -0,0 +1,292 @@
+/*
+ * 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 <sys/errno.h>
+#include "sunxi_def.h"
+#include "sunxi_private.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define BIT(n) (1U << (n))
+
+#define AXP803_HW_ADDR 0x3a3
+
+/*
+ * RSB has 15 valid runtime addresses.
+ * Allwinner typically skips the first one for unknown reasons.
+ */
+#define RUNTIME_ADDR0 0x17
+#define RUNTIME_ADDR1 0x2d
+#define RUNTIME_ADDR2 0x3a
+#define RUNTIME_ADDR3 0x4e
+#define RUNTIME_ADDR4 0x59
+#define RUNTIME_ADDR5 0x63
+#define RUNTIME_ADDR6 0x74
+#define RUNTIME_ADDR7 0x8b
+#define RUNTIME_ADDR8 0x9c
+#define RUNTIME_ADDR9 0xa6
+#define RUNTIME_ADDR10 0xb1
+#define RUNTIME_ADDR11 0xc5
+#define RUNTIME_ADDR12 0xd2
+#define RUNTIME_ADDR13 0xe8
+#define RUNTIME_ADDR14 0xff
+
+#define R_PRCM_BASE 0x01f01400ULL
+#define R_PIO_BASE 0x01f02c00ULL
+#define R_RSB_BASE 0x01f03400ULL
+
+#define RSB_CTRL 0x00
+#define RSB_CCR 0x04
+#define RSB_INTE 0x08
+#define RSB_INTS 0x0c
+#define RSB_AR 0x10
+#define RSB_DATA 0x1c
+#define RSB_LCR 0x24
+#define RSB_DMCR 0x28
+#define RSB_CMD 0x2c
+#define RSB_DAR 0x30
+
+#define RSB_CTRL_START_TRANS BIT(7)
+#define RSB_CTRL_ABORT_TRANS BIT(6)
+#define RSB_CTRL_SOFT_RESET BIT(0)
+
+#define RSB_INTS_TRAS_OVER BIT(0)
+
+#define RSB_CMD_STRA 0xE8 /* SeT Run-time Address */
+#define RSB_CMD_RD8 0x8B /* ReaD 8 bit */
+#define RSB_CMD_RD16 0x9C
+#define RSB_CMD_RD32 0xA6
+#define RSB_CMD_WR8 0x4E
+#define RSB_CMD_WR16 0x59
+#define RSB_CMD_WR32 0x63
+
+#define RSB_DMCR_DEVICE_START BIT(31)
+#define RSB_DMCR_MODE_DATA (0x7c << 16)
+#define RSB_DMCR_MODE_REG (0x3e << 8)
+#define RSB_DMCR_DEV_ADDR 0x00
+
+struct rsb_slave {
+ uint16_t hw_addr;
+ uint8_t rt_addr;
+};
+
+static struct rsb_slave rsb_slaves[] = {
+ { AXP803_HW_ADDR, RUNTIME_ADDR1 }, /* PMIC */
+};
+
+static inline void rsb_cmd(uint8_t cmd)
+{
+ uint32_t reg;
+
+ /* Start the command */
+ mmio_write_32(R_RSB_BASE + RSB_CTRL, cmd);
+
+ /*
+ * The control register clears the set command bit,
+ * when the command has finished.
+ */
+ do {
+ reg = mmio_read_32(R_RSB_BASE + RSB_CTRL);
+ } while (reg & cmd);
+}
+
+int rsb_read(uint8_t rt_addr, uint8_t addr, uint32_t *val, size_t size)
+{
+ uint32_t reg, cmd, mask;
+
+ switch (size) {
+ case 1:
+ cmd = RSB_CMD_RD8;
+ mask = 0xff;
+ break;
+ case 2:
+ cmd = RSB_CMD_RD16;
+ mask = 0xffff;
+ break;
+ case 3:
+ cmd = RSB_CMD_RD32;
+ mask = 0xffffffff;
+ break;
+ default:
+ ERROR("Invalid RSB read size %u", size);
+ return -1;
+ }
+
+ mmio_write_32(R_RSB_BASE + RSB_CMD, cmd);
+ mmio_write_32(R_RSB_BASE + RSB_DAR, (rt_addr << 16));
+ mmio_write_32(R_RSB_BASE + RSB_AR, addr);
+
+ /* Start transaction and wait for completion */
+ rsb_cmd(RSB_CTRL_START_TRANS);
+
+ /* Read status */
+ reg = mmio_read_32(R_RSB_BASE + RSB_INTS);
+ if (reg != RSB_INTS_TRAS_OVER)
+ return -reg;
+
+ /* Get data */
+ reg = mmio_read_32(R_RSB_BASE + RSB_DATA);
+
+ if (val)
+ *val = reg & mask;
+
+ return 0;
+}
+
+int rsb_write(uint8_t rt_addr, uint8_t addr, uint32_t val, size_t size)
+{
+ uint32_t reg, cmd;
+
+ switch (size) {
+ case 1:
+ cmd = RSB_CMD_WR8;
+ break;
+ case 2:
+ cmd = RSB_CMD_WR16;
+ break;
+ case 3:
+ cmd = RSB_CMD_WR32;
+ break;
+ default:
+ ERROR("Invalid RSB read size %u", size);
+ return -1;
+ }
+
+ mmio_write_32(R_RSB_BASE + RSB_CMD, cmd);
+ mmio_write_32(R_RSB_BASE + RSB_DAR, (rt_addr << 16));
+ mmio_write_32(R_RSB_BASE + RSB_AR, addr);
+ mmio_write_32(R_RSB_BASE + RSB_DATA, val);
+
+ /* Start transaction and wait for completion */
+ rsb_cmd(RSB_CTRL_START_TRANS);
+
+ /* Read status */
+ reg = mmio_read_32(R_RSB_BASE + RSB_INTS);
+ if (reg != RSB_INTS_TRAS_OVER)
+ return -1;
+
+ return 0;
+}
+
+/* Initialize the RSB PMIC connection. */
+static int sunxi_rsb_setup_slaves(void)
+{
+ size_t i;
+ int ret;
+ uint32_t reg;
+
+ /* Initialize all devices on the bus into RSB mode */
+ reg = RSB_DMCR_DEVICE_START | RSB_DMCR_MODE_DATA |
+ RSB_DMCR_MODE_REG | RSB_DMCR_DEV_ADDR;
+ mmio_write_32(R_RSB_BASE + RSB_DMCR, reg);
+ do {
+ ret = mmio_read_32(R_RSB_BASE + RSB_DMCR);
+ } while (ret & RSB_DMCR_DEVICE_START);
+
+ /* Set clock speed to 3 Mhz */
+ mmio_write_32(R_RSB_BASE + RSB_CCR, 0x103);
+
+
+ for (i = 0; i < ARRAY_SIZE(rsb_slaves); i++) {
+ uint16_t hw_addr = rsb_slaves[i].hw_addr;
+ uint8_t rt_addr = rsb_slaves[i].rt_addr;
+
+ /* Set run-time address for given hardware address */
+ mmio_write_32(R_RSB_BASE + RSB_DAR, hw_addr | (rt_addr << 16));
+ /* Command: set the run-time address to the device */
+ mmio_write_32(R_RSB_BASE + RSB_CMD, RSB_CMD_STRA);
+
+ /* Start transaction and wait for completion */
+ rsb_cmd(RSB_CTRL_START_TRANS);
+
+ /* Read status */
+ reg = mmio_read_32(R_RSB_BASE + RSB_INTS);
+ if (reg != RSB_INTS_TRAS_OVER)
+ ERROR("Could not set run-time address: 0x%x\n", reg);
+ }
+
+ return 0;
+}
+
+/* Initialize the RSB controller and its pins. */
+int sunxi_rsb_init(void)
+{
+ uint32_t reg;
+
+ /* un-gate PIO clock */
+ reg = mmio_read_32(R_PRCM_BASE + 0x28);
+ mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x01);
+
+ /* get currently configured function for pins PL0 and PL1 */
+ reg = mmio_read_32(R_PIO_BASE + 0x00);
+ if ((reg & 0xff) == 0x33) {
+ NOTICE("RSB: already configured for TWI\n");
+ return -1;
+ }
+
+ if ((reg & 0xff) == 0x22) {
+ NOTICE("RSB: already configured for RSB\n");
+ return 0; /* configured for RSB mode already */
+ }
+
+ /* switch pins PL0 and PL1 to RSB */
+ mmio_write_32(R_PIO_BASE + 0, (reg & ~0xff) | 0x22);
+
+ /* level 2 drive strength */
+ reg = mmio_read_32(R_PIO_BASE + 0x14);
+ mmio_write_32(R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
+
+ /* set both ports to pull-up */
+ reg = mmio_read_32(R_PIO_BASE + 0x1c);
+ mmio_write_32(R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
+
+ /* assert & de-assert reset of RSB */
+ reg = mmio_read_32(R_PRCM_BASE + 0xb0);
+ mmio_write_32(R_PRCM_BASE + 0xb0, reg & ~0x08);
+ reg = mmio_read_32(R_PRCM_BASE + 0xb0);
+ mmio_write_32(R_PRCM_BASE + 0xb0, reg | 0x08);
+
+ /* un-gate RSB clock */
+ reg = mmio_read_32(R_PRCM_BASE + 0x28);
+ mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x08);
+
+ /* Soft reset of RSB block */
+ rsb_cmd(RSB_CTRL_SOFT_RESET);
+
+ /* Set clock to 400 kHz */
+ mmio_write_32(R_RSB_BASE + RSB_CCR, 0x11d);
+
+ sunxi_rsb_setup_slaves();
+
+ return 0;
+}
+