diff options
Diffstat (limited to 'plat')
-rw-r--r-- | plat/sun50iw1p1/platform.mk | 3 | ||||
-rw-r--r-- | plat/sun50iw1p1/sunxi_arisc_emulator.c | 324 |
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 = ¶s[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 +); + |