summaryrefslogtreecommitdiff
path: root/drivers/remoteproc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r--drivers/remoteproc/Kconfig8
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/renesas_apmu.c266
-rw-r--r--drivers/remoteproc/rproc-elf-loader.c18
4 files changed, 286 insertions, 7 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index a49802c1323..2790b168b19 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -22,6 +22,14 @@ config K3_SYSTEM_CONTROLLER
help
Say 'y' here to add support for TI' K3 System Controller.
+config REMOTEPROC_RENESAS_APMU
+ bool "Support for Renesas R-Car Gen4 APMU start of CR52 processor"
+ select REMOTEPROC
+ depends on ARCH_RENESAS && RCAR_GEN4 && DM && OF_CONTROL
+ help
+ Say 'y' here to add support for Renesas R-Car Gen4 Cortex-A52
+ processor via the remoteproc framework.
+
config REMOTEPROC_SANDBOX
bool "Support for Test processor for Sandbox"
select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 801b0965e4f..3a092b7660e 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_$(XPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
+obj-$(CONFIG_REMOTEPROC_RENESAS_APMU) += renesas_apmu.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
diff --git a/drivers/remoteproc/renesas_apmu.c b/drivers/remoteproc/renesas_apmu.c
new file mode 100644
index 00000000000..32d138e6487
--- /dev/null
+++ b/drivers/remoteproc/renesas_apmu.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <errno.h>
+#include <hang.h>
+#include <linux/iopoll.h>
+#include <linux/sizes.h>
+#include <malloc.h>
+#include <remoteproc.h>
+
+/* R-Car V4H/V4M contain 3 clusters / 3 cores */
+#define RCAR4_CR52_CORES 3
+
+/* Reset Control Register for Cortex-R52 #n */
+#define APMU_CRRSTCTRL(n) (0x304 + ((n) * 0x40))
+#define APMU_CRRSTCTRL_CR52RST BIT(0)
+
+/* Base Address Register for Cortex-R52 #n */
+#define APMU_CRBARP(n) (0x33c + ((n) * 0x40))
+#define APMU_CRBARP_CR_VLD_BARP BIT(0)
+#define APMU_CRBARP_CR_BAREN_VALID BIT(4)
+#define APMU_CRBARP_CR_RBAR_MASK 0xfffc0000
+#define APMU_CRBARP_CR_RBAR_ALIGN 0x40000
+
+/**
+ * struct renesas_apmu_rproc_privdata - remote processor private data
+ * @regs: controller registers
+ * @core_id: CPU core id
+ * @trampoline: jump trampoline code
+ */
+struct renesas_apmu_rproc_privdata {
+ void __iomem *regs;
+ ulong core_id;
+ u32 *trampoline;
+};
+
+/*
+ * CRBARP address is aligned to 0x40000 / 256 kiB , this trampoline
+ * allows arbitrary address alignment at instruction granularity.
+ */
+static const u32 renesas_apmu_rproc_trampoline[4] = {
+ 0xe59f0004, /* ldr r0, [pc, #4] */
+ 0xe1a0f000, /* mov pc, r0 */
+ 0xeafffffe, /* 1: b 1b */
+ 0xabcd1234 /* jump target (rewritten on load) */
+};
+
+/**
+ * renesas_apmu_rproc_load() - Load the remote processor
+ * @dev: corresponding remote processor device
+ * @addr: Address in memory where image is stored
+ * @size: Size in bytes of the image
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int renesas_apmu_rproc_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct renesas_apmu_rproc_privdata *priv = dev_get_priv(dev);
+ u32 trampolineaddr = (u32)(uintptr_t)(priv->trampoline);
+
+ priv->trampoline[3] = addr;
+ flush_dcache_range(trampolineaddr,
+ trampolineaddr +
+ sizeof(renesas_apmu_rproc_trampoline));
+
+ /* CR52 boot address set */
+ writel(trampolineaddr | APMU_CRBARP_CR_VLD_BARP,
+ priv->regs + APMU_CRBARP(priv->core_id));
+ writel(trampolineaddr | APMU_CRBARP_CR_VLD_BARP | APMU_CRBARP_CR_BAREN_VALID,
+ priv->regs + APMU_CRBARP(priv->core_id));
+
+ return 0;
+}
+
+/**
+ * renesas_apmu_rproc_start() - Start the remote processor
+ * @dev: corresponding remote processor device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int renesas_apmu_rproc_start(struct udevice *dev)
+{
+ struct renesas_apmu_rproc_privdata *priv = dev_get_priv(dev);
+
+ /* Clear APMU_CRRSTCTRL_CR52RST, the only bit in this register */
+ writel(0, priv->regs + APMU_CRRSTCTRL(priv->core_id));
+
+ return 0;
+}
+
+/**
+ * renesas_apmu_rproc_stop() - Stop the remote processor
+ * @dev: corresponding remote processor device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int renesas_apmu_rproc_stop(struct udevice *dev)
+{
+ struct renesas_apmu_rproc_privdata *priv = dev_get_priv(dev);
+
+ /* Set APMU_CRRSTCTRL_CR52RST, the only bit in this register */
+ writel(APMU_CRRSTCTRL_CR52RST,
+ priv->regs + APMU_CRRSTCTRL(priv->core_id));
+
+ return 0;
+}
+
+/**
+ * renesas_apmu_rproc_reset() - Reset the remote processor
+ * @dev: corresponding remote processor device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int renesas_apmu_rproc_reset(struct udevice *dev)
+{
+ renesas_apmu_rproc_stop(dev);
+ renesas_apmu_rproc_start(dev);
+ return 0;
+}
+
+/**
+ * renesas_apmu_rproc_is_running() - Is the remote processor running
+ * @dev: corresponding remote processor device
+ *
+ * Return: 0 if the remote processor is running, 1 otherwise
+ */
+static int renesas_apmu_rproc_is_running(struct udevice *dev)
+{
+ struct renesas_apmu_rproc_privdata *priv = dev_get_priv(dev);
+
+ return readl(priv->regs + APMU_CRRSTCTRL(priv->core_id)) &
+ APMU_CRRSTCTRL_CR52RST;
+}
+
+/**
+ * renesas_apmu_rproc_init() - Initialize the remote processor CRBAR registers
+ * @dev: corresponding remote processor device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int renesas_apmu_rproc_init(struct udevice *dev)
+{
+ struct renesas_apmu_rproc_privdata *priv = dev_get_priv(dev);
+
+ /* If the core is running already, do nothing. */
+ if (renesas_apmu_rproc_is_running(dev))
+ return 0;
+
+ /* Clear and invalidate CRBARP content */
+ writel(0, priv->regs + APMU_CRBARP(priv->core_id));
+
+ return 0;
+}
+
+/**
+ * renesas_apmu_rproc_device_to_virt() - Convert device address to virtual address
+ * @dev: corresponding remote processor device
+ * @da: device address
+ * @size: Size of the memory region @da is pointing to
+ *
+ * Return: converted virtual address
+ */
+static void *renesas_apmu_rproc_device_to_virt(struct udevice *dev, ulong da,
+ ulong size)
+{
+ /*
+ * The Cortex R52 and A76 share the same address space,
+ * this operation is a no-op.
+ */
+ return (void *)da;
+}
+
+static const struct dm_rproc_ops renesas_apmu_rproc_ops = {
+ .init = renesas_apmu_rproc_init,
+ .load = renesas_apmu_rproc_load,
+ .start = renesas_apmu_rproc_start,
+ .stop = renesas_apmu_rproc_stop,
+ .reset = renesas_apmu_rproc_reset,
+ .is_running = renesas_apmu_rproc_is_running,
+ .device_to_virt = renesas_apmu_rproc_device_to_virt,
+};
+
+/**
+ * renesas_apmu_rproc_of_to_plat() - Convert OF data to platform data
+ * @dev: corresponding remote processor device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int renesas_apmu_rproc_of_to_plat(struct udevice *dev)
+{
+ struct renesas_apmu_rproc_privdata *priv = dev_get_priv(dev);
+
+ priv->core_id = dev_get_driver_data(dev);
+
+ priv->regs = dev_read_addr_ptr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ priv->trampoline = memalign(APMU_CRBARP_CR_RBAR_ALIGN,
+ sizeof(renesas_apmu_rproc_trampoline));
+ if (!priv->trampoline)
+ return -ENOMEM;
+
+ memcpy(priv->trampoline, renesas_apmu_rproc_trampoline,
+ sizeof(renesas_apmu_rproc_trampoline));
+
+ return 0;
+}
+
+U_BOOT_DRIVER(renesas_apmu_cr52) = {
+ .name = "rcar-apmu-cr52",
+ .id = UCLASS_REMOTEPROC,
+ .ops = &renesas_apmu_rproc_ops,
+ .of_to_plat = renesas_apmu_rproc_of_to_plat,
+ .priv_auto = sizeof(struct renesas_apmu_rproc_privdata),
+};
+
+/**
+ * renesas_apmu_rproc_bind() - Bind rproc driver to each core control
+ * @dev: corresponding remote processor parent device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int renesas_apmu_rproc_bind(struct udevice *parent)
+{
+ const ulong cr52cores = RCAR4_CR52_CORES;
+ ofnode pnode = dev_ofnode(parent);
+ struct udevice *cdev;
+ struct driver *cdrv;
+ char name[32];
+ ulong i;
+ int ret;
+
+ cdrv = lists_driver_lookup_name("rcar-apmu-cr52");
+ if (!cdrv)
+ return -ENOENT;
+
+ for (i = 0; i < cr52cores; i++) {
+ snprintf(name, sizeof(name), "rcar-apmu-cr52.%ld", i);
+ ret = device_bind_with_driver_data(parent, cdrv, strdup(name),
+ i, pnode, &cdev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id renesas_apmu_rproc_ids[] = {
+ { .compatible = "renesas,r8a779g0-cr52" },
+ { .compatible = "renesas,r8a779h0-cr52" },
+ { }
+};
+
+U_BOOT_DRIVER(renesas_apmu_rproc) = {
+ .name = "rcar-apmu-rproc",
+ .of_match = renesas_apmu_rproc_ids,
+ .id = UCLASS_NOP,
+ .bind = renesas_apmu_rproc_bind,
+};
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
index ab1836b3f07..0b3941b7798 100644
--- a/drivers/remoteproc/rproc-elf-loader.c
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -6,6 +6,7 @@
#include <dm.h>
#include <elf.h>
#include <log.h>
+#include <mapmem.h>
#include <remoteproc.h>
#include <asm/cache.h>
#include <dm/device_compat.h>
@@ -180,6 +181,7 @@ int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
+ ulong dst_addr;
if (phdr->p_type != PT_LOAD)
continue;
@@ -195,10 +197,11 @@ int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
if (phdr->p_filesz != phdr->p_memsz)
memset(dst + phdr->p_filesz, 0x00,
phdr->p_memsz - phdr->p_filesz);
- flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
- roundup((unsigned long)dst + phdr->p_filesz,
+ dst_addr = map_to_sysmem(dst);
+ flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
+ roundup(dst_addr + phdr->p_filesz,
ARCH_DMA_MINALIGN) -
- rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ rounddown(dst_addr, ARCH_DMA_MINALIGN));
}
return 0;
@@ -377,6 +380,7 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
const struct dm_rproc_ops *ops;
Elf32_Shdr *shdr;
void *src, *dst;
+ ulong dst_addr;
shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size);
if (!shdr)
@@ -398,10 +402,10 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
(ulong)dst, *rsc_size);
memcpy(dst, src, *rsc_size);
- flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
- roundup((unsigned long)dst + *rsc_size,
- ARCH_DMA_MINALIGN) -
- rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ dst_addr = map_to_sysmem(dst);
+ flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
+ roundup(dst_addr + *rsc_size, ARCH_DMA_MINALIGN) -
+ rounddown(dst_addr, ARCH_DMA_MINALIGN));
return 0;
}