diff options
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r-- | drivers/remoteproc/Kconfig | 8 | ||||
-rw-r--r-- | drivers/remoteproc/Makefile | 1 | ||||
-rw-r--r-- | drivers/remoteproc/renesas_apmu.c | 266 | ||||
-rw-r--r-- | drivers/remoteproc/rproc-elf-loader.c | 18 |
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; } |