From 7585a12ffec6e42c62222d8ee4085413b3a197f7 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 9 Oct 2021 14:58:27 -0500 Subject: [PATCH 38/90] remoteproc: Add a driver for the Allwinner AR100 Signed-off-by: Samuel Holland --- drivers/remoteproc/Kconfig | 9 ++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/sun6i_ar100_rproc.c | 111 +++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 drivers/remoteproc/sun6i_ar100_rproc.c --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -41,6 +41,15 @@ config REMOTEPROC_STM32_COPRO Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the remoteproc framework. +config REMOTEPROC_SUN6I_AR100 + bool "Support for Allwinner AR100 SCP" + select REMOTEPROC + depends on ARCH_SUNXI + help + Say 'y' here to support Allwinner's AR100 System Control Processor + (SCP), found in various sun6i/sun8i/sun50i family SoCs, through the + remoteproc framework. + config REMOTEPROC_TI_K3_ARM64 bool "Support for TI's K3 based ARM64 remoteproc driver" select REMOTEPROC --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o +obj-$(CONFIG_REMOTEPROC_SUN6I_AR100) += sun6i_ar100_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o --- /dev/null +++ b/drivers/remoteproc/sun6i_ar100_rproc.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +#define SUNXI_SCP_MAGIC 0xb4400012 + +#define OR1K_VEC_FIRST 0x01 +#define OR1K_VEC_LAST 0x0e +#define OR1K_VEC_ADDR(n) (0x100 * (n)) + +struct sun6i_ar100_rproc_priv { + void *cfg_base; + ulong sram_base; +}; + +static int sun6i_ar100_rproc_load(struct udevice *dev, ulong addr, ulong size) +{ + struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev); + + /* Check for a valid SCP firmware. */ + if (readl_relaxed(addr) != SUNXI_SCP_MAGIC) + return -ENOENT; + + /* Program exception vectors to the firmware entry point. */ + for (u32 i = OR1K_VEC_FIRST; i <= OR1K_VEC_LAST; ++i) { + ulong vector = priv->sram_base + OR1K_VEC_ADDR(i); + ulong offset = addr - vector; + + writel_relaxed(offset >> 2, vector); + } + + return 0; +} + +static int sun6i_ar100_rproc_start(struct udevice *dev) +{ + struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev); + + setbits_le32(priv->cfg_base, BIT(0)); + + return 0; +} + +static int sun6i_ar100_rproc_stop(struct udevice *dev) +{ + struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev); + + clrbits_le32(priv->cfg_base, BIT(0)); + + return 0; +} + +static int sun6i_ar100_rproc_reset(struct udevice *dev) +{ + int ret; + + ret = sun6i_ar100_rproc_stop(dev); + if (ret) + return ret; + + return sun6i_ar100_rproc_start(dev); +} + +static int sun6i_ar100_rproc_is_running(struct udevice *dev) +{ + struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev); + + return !(readl_relaxed(priv->cfg_base) & BIT(0)); +} + +static const struct dm_rproc_ops sun6i_ar100_rproc_ops = { + .load = sun6i_ar100_rproc_load, + .start = sun6i_ar100_rproc_start, + .stop = sun6i_ar100_rproc_stop, + .reset = sun6i_ar100_rproc_reset, + .is_running = sun6i_ar100_rproc_is_running, +}; + +static int sun6i_ar100_rproc_probe(struct udevice *dev) +{ + struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args sram_handle; + int ret; + + priv->cfg_base = dev_read_addr_ptr(dev); + + ret = dev_read_phandle_with_args(dev, "sram", NULL, 0, 0, &sram_handle); + if (ret) + return ret; + + priv->sram_base = ofnode_get_addr(sram_handle.node); + + return 0; +} + +static const struct udevice_id sun6i_ar100_rproc_ids[] = { + { .compatible = "allwinner,sun6i-a31-ar100" }, + { } +}; + +U_BOOT_DRIVER(sun6i_ar100_rproc) = { + .name = "sun6i_ar100_rproc", + .id = UCLASS_REMOTEPROC, + .of_match = sun6i_ar100_rproc_ids, + .probe = sun6i_ar100_rproc_probe, + .priv_auto = sizeof(struct sun6i_ar100_rproc_priv), + .ops = &sun6i_ar100_rproc_ops, +};