summaryrefslogtreecommitdiff
path: root/plat
diff options
context:
space:
mode:
Diffstat (limited to 'plat')
-rw-r--r--plat/sun50iw1p1/platform.mk3
-rw-r--r--plat/sun50iw1p1/sunxi_arisc_emulator.c324
2 files changed, 326 insertions, 1 deletions
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
index bc20110..e3aba37 100644
--- a/plat/sun50iw1p1/platform.mk
+++ b/plat/sun50iw1p1/platform.mk
@@ -51,5 +51,6 @@ BL31_SOURCES += drivers/arm/gic/arm_gic.c \
plat/sun50iw1p1/plat_topology.c \
plat/sun50iw1p1/aarch64/plat_helpers.S \
plat/sun50iw1p1/sunxi_clocks.c \
- plat/sun50iw1p1/aarch64/sunxi_common.c
+ plat/sun50iw1p1/aarch64/sunxi_common.c \
+ plat/sun50iw1p1/sunxi_arisc_emulator.c
diff --git a/plat/sun50iw1p1/sunxi_arisc_emulator.c b/plat/sun50iw1p1/sunxi_arisc_emulator.c
new file mode 100644
index 0000000..d2d116d
--- /dev/null
+++ b/plat/sun50iw1p1/sunxi_arisc_emulator.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2017, Theobroma Systems Design und Consulting GmbH
+ * 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 <string.h>
+#include <debug.h>
+#include <runtime_svc.h>
+#include <std_svc.h>
+#include <stdint.h>
+#include <uuid.h>
+
+#include "sunxi_private.h"
+
+#define SUNXI_ARISC_EMULATOR_SVC_BASE 0xc0000000 /* fast + SMC64 */
+
+/* Standby commands */
+#define ARM_SVC_ARISC_STANDBY_INFO_REQ \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x20)
+#define ARM_SVC_ARISC_QUERY_WAKEUP_SRC_REQ \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x23)
+
+/* DVFS commands */
+#define ARM_SVC_ARISC_CPUX_DVFS_REQ \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x30)
+
+/* PMU commands */
+#define ARM_SVC_ARISC_AXP_DISABLE_IRQ \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x51)
+#define ARM_SVC_ARISC_AXP_ENABLE_IRQ \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x52)
+#define ARM_SVC_ARISC_AXP_GET_CHIP_ID \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x53)
+#define ARM_SVC_ARISC_AXP_SET_PARAS \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x54)
+#define ARM_SVC_ARISC_SET_PMU_VOLT \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x55)
+#define ARM_SVC_ARISC_GET_PMU_VOLT \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x56)
+#define ARM_SVC_ARISC_SET_LED_BLN \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x57)
+#define ARM_SVC_ARISC_SET_PWR_TREE \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x59)
+#define ARM_SVC_ARISC_CLR_NMI_STATUS \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x5a)
+#define ARM_SVC_ARISC_SET_NMI_TRIGGER \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x5b)
+
+/* Debug commands */
+#define ARM_SVC_ARISC_SET_DEBUG_LEVEL \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x60)
+#define ARM_SVC_ARISC_MESSAGE_LOOPBACK \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x61)
+#define ARM_SVC_ARISC_SET_UART_BAUDRATE \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x62)
+#define ARM_SVC_ARISC_SET_DEBUG_DRAM_CRC_PARAS \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x64)
+
+/* RSB commands */
+#define ARM_SVC_ARISC_RSB_READ_BLOCK_DATA \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x80)
+#define ARM_SVC_ARISC_RSB_WRITE_BLOCK_DATA \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x81)
+#define ARM_SVC_ARISC_RSB_BITS_OPS_SYNC \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x82)
+#define ARM_SVC_ARISC_RSB_SET_INTERFACE_MODE \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x83)
+#define ARM_SVC_ARISC_RSB_SET_RTSADDR \
+ (SUNXI_ARISC_EMULATOR_SVC_BASE + 0x84)
+
+static int32_t sunxi_arisc_emulator_setup(void)
+{
+ return 0;
+}
+
+/* Syntactic sugar for CPU regulator */
+static inline int sunxi_pmic_set_cpu_mvolt(uint32_t mvolt)
+{
+ return sunxi_pmic_set_voltage(AXP803_DCDC2, mvolt);
+}
+
+/* Empirically derived operating points */
+static uint32_t mvolt_for_mhz(uint32_t mhz)
+{
+ if (mhz >= 1200)
+ return 1300;
+ else if (mhz >= 1008)
+ return 1200;
+ else if (mhz >= 816)
+ return 1100;
+ else
+ return 1040;
+}
+
+static uint64_t sunxi_arisc_emulator_handler(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ switch (smc_fid) {
+ case ARM_SVC_ARISC_STANDBY_INFO_REQ:
+ /* read/write power states information
+ * x1...&temp_paras (9 32-bit values)
+ * x2...op (0..READ, 1..WRITE)
+ *
+ * Dump from an Arisc-based ATF response. See files:
+ * - /sys/bus/platform/devices/arisc.3/sst_power_real_info
+ * - /sys/bus/platform/devices/arisc.3/dram_crc_result
+ *
+ * temp_paras:
+ * power_state:
+ * u32 enable -> 0
+ * u32 power_reg -> 0
+ * s32 system_power -> 0
+ * dram_state:
+ * u32 dram_crc_enable -> 0
+ * u32 dram_crc_src -> 0x40000000
+ * u32 dram_crc_len -> 0x100000
+ * u32 dram_crc_error -> 0
+ * u32 dram_crc_total_count -> 0
+ * u32 dram_crc_error_count -> 0
+ *
+ */
+ if (x2 == 0)
+ memset((void *)x1, 0, 36);
+ SMC_RET1(handle, 0);
+
+ case ARM_SVC_ARISC_QUERY_WAKEUP_SRC_REQ:
+ /* Return the resume-from-standby source
+ * x1...phys(&event_32)
+ * Set hard-coded to 0x1 (wakeup key)
+ */
+ *(uint32_t *)x1 = 0x1;
+ SMC_RET1(handle, 0);
+
+ case ARM_SVC_ARISC_CPUX_DVFS_REQ: {
+ /* Set CPU frequency
+ * x1...freq [kHz]
+ * x2...pll (1 for PLL1)
+ * x3...mode (alwasys 1)
+ * returns non-zero on error
+ *
+ * Exported via /sys/bus/platform/devices/arisc.3/freq
+ */
+ if (x2 != 1 || x3 != 1)
+ SMC_RET1(handle, 1);
+
+ uint32_t old_freq_mhz = sun50i_get_cpu_pll();
+ uint32_t new_freq_mhz = x1 / 1000;
+
+ if (old_freq_mhz < new_freq_mhz) {
+ sunxi_pmic_set_cpu_mvolt(mvolt_for_mhz(x1/1000));
+ sun50i_set_cpu_pll(x1 / 1000);
+ } else {
+ sun50i_set_cpu_pll(x1 / 1000);
+ sunxi_pmic_set_cpu_mvolt(mvolt_for_mhz(x1/1000));
+ }
+ SMC_RET1(handle, 0);
+ }
+
+ case ARM_SVC_ARISC_AXP_DISABLE_IRQ: /* fall through */
+ case ARM_SVC_ARISC_AXP_ENABLE_IRQ:
+ WARN("%s: function call (0x%x) ignored!\n", __func__, smc_fid);
+ SMC_RET1(handle, 0); /* We do nothing */
+
+ case ARM_SVC_ARISC_AXP_GET_CHIP_ID: {
+ uint8_t val;
+ sunxi_pmic_read(0x03, &val);
+ SMC_RET1(handle, val);
+ }
+
+ case ARM_SVC_ARISC_AXP_SET_PARAS:
+ WARN("%s: function call (0x%x) ignored!\n", __func__, smc_fid);
+ SMC_RET1(handle, 0); /* We do nothing */
+
+ case ARM_SVC_ARISC_SET_PMU_VOLT: /* fall through */
+ case ARM_SVC_ARISC_GET_PMU_VOLT:
+ WARN("%s: function call (0x%x) ignored!\n", __func__, smc_fid);
+ SMC_RET1(handle, 0); /* We do nothing */
+
+ case ARM_SVC_ARISC_SET_LED_BLN:
+ case ARM_SVC_ARISC_SET_PWR_TREE:
+ case ARM_SVC_ARISC_CLR_NMI_STATUS:
+ case ARM_SVC_ARISC_SET_NMI_TRIGGER:
+ WARN("%s: function call (0x%x) ignored!\n", __func__, smc_fid);
+ SMC_RET1(handle, 0); /* We do nothing */
+
+ case ARM_SVC_ARISC_SET_DEBUG_LEVEL: /* fall through */
+ case ARM_SVC_ARISC_MESSAGE_LOOPBACK: /* fall through */
+ case ARM_SVC_ARISC_SET_UART_BAUDRATE: /* fall through */
+ case ARM_SVC_ARISC_SET_DEBUG_DRAM_CRC_PARAS:
+ WARN("%s: function call (0x%x) ignored!\n", __func__, smc_fid);
+ SMC_RET1(handle, 0); /* We do nothing */
+
+ case ARM_SVC_ARISC_RSB_READ_BLOCK_DATA: {
+ /* Read RSB
+ * x1...phys(paras)
+ * returns non-zero on error
+ *
+ * paras: array of 32 bit values:
+ * paras[0]: (len16|datatype16)
+ * paras[1]: devaddr
+ * paras[2]: regaddr3..0
+ * paras[3]: data0
+ * paras[4]: data1
+ * paras[5]: data2
+ * paras[6]: data3
+ */
+ int ret;
+ size_t i;
+ uint32_t *paras = (uint32_t *)x1;
+ uint8_t rt_addr = (uint8_t)paras[1];
+ uint16_t len = paras[0] & 0xffff;
+ uint16_t datatype = (paras[0] >> 16) & 0xffff;
+
+ if (len > 4) {
+ ERROR("RSB Read with len %u not supported!\n", len);
+ SMC_RET1(handle, 1);
+ }
+
+ for (i = 0; i < len; i++) {
+ uint8_t addr = paras[2] >> (i*8);
+ uint32_t *data = &paras[3+i];
+
+ ret = rsb_read(rt_addr, addr, data, datatype);
+ if (ret) {
+ WARN("RSB read failed!\n");
+ SMC_RET1(handle, 1);
+ }
+ }
+ SMC_RET1(handle, 0);
+ }
+ case ARM_SVC_ARISC_RSB_WRITE_BLOCK_DATA: {
+ /* Write RSB
+ * x1...phys(paras)
+ * returns non-zero on error
+ *
+ * paras: array of 32 bit values:
+ * paras[0]: (len16|datatype16)
+ * paras[1]: devaddr
+ * paras[2]: regaddr3..0
+ * paras[3]: data0
+ * paras[4]: data1
+ * paras[5]: data2
+ * paras[6]: data3
+ */
+ int ret;
+ size_t i;
+ uint32_t *paras = (uint32_t *)x1;
+ uint8_t rt_addr = (uint8_t)paras[1];
+ uint16_t len = paras[0] & 0xffff;
+ uint16_t datatype = (paras[0] >> 16) & 0xffff;
+
+ if (len > 4) {
+ ERROR("RSB Read with len %u not supported!\n", len);
+ SMC_RET1(handle, 1);
+ }
+
+ for (i = 0; i < len; i++) {
+ uint8_t addr = paras[2] >> (i*8);
+ uint32_t data = paras[3+i];
+
+ ret = rsb_write(rt_addr, addr, data, datatype);
+ if (ret) {
+ WARN("RSB read failed!\n");
+ SMC_RET1(handle, 1);
+ }
+ }
+ SMC_RET1(handle, 0);
+ }
+
+ case ARM_SVC_ARISC_RSB_BITS_OPS_SYNC:
+ case ARM_SVC_ARISC_RSB_SET_INTERFACE_MODE:
+ case ARM_SVC_ARISC_RSB_SET_RTSADDR:
+ WARN("%s: function call (0x%x) ignored!\n", __func__, smc_fid);
+ SMC_RET1(handle, 0); /* We do nothing */
+
+ default:
+ WARN("sunxi_arisc_emulator: Not supported function: 0x%x.\n",
+ smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+/* Register service call as runtime service */
+DECLARE_RT_SVC(
+ sunxi_arisc_emulator,
+ OEN_ARM_START,
+ OEN_ARM_END,
+ SMC_TYPE_FAST,
+ sunxi_arisc_emulator_setup,
+ sunxi_arisc_emulator_handler
+);
+