[PATCH 1/3] remoteproc: renesas: Add Renesas R-Car Gen4 remote processor driver

Add R-Car Gen4 APMU controller remoteproc driver capable of starting the Cortex-R52 cores in Renesas R8A779G0 V4H/V4M SoC. The APMU IP is in fact a power management unit capable of additional operations, but those are not used by U-Boot so far.
This requires slight adjustment to the SPL entry point code, as that is being executed on the Cortex-R52 #0 and the Cortex-R52 #0 enters an endless loop once it starts the rest of the SPL on Cortex-A76 core. The endless loop now checks for content of APMU CRBARP registers and tests whether valid VLD_BARP and BAREN_VALID bits are set, if so, the Cortex-R52 core exits the endless loop and jumps to address started in CRBARP[31:18] register in ARM mode, which is a trampoline code to jump to the final entry point.
The trampoline code is in place to avoid limitation of CRBARP[31:18] address field, which limits the core start address to memory addresses aligned to 0x40000 or 256 kiB . The trampoline is placed at 0x40000 aligned address and jumps to the final entry point, which can be at an address with arbitrary alignment at instruction granularity.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Adam Ford aford173@gmail.com Cc: MD Danish Anwar danishanwar@ti.com Cc: Nobuhiro Iwamatsu iwamatsu@nigauri.org Cc: Paul Barker paul.barker.ct@bp.renesas.com Cc: Ravi Gunasekaran r-gunasekaran@ti.com Cc: Roger Quadros rogerq@kernel.org Cc: Simon Glass sjg@chromium.org Cc: Sumit Garg sumit.garg@linaro.org Cc: Tom Rini trini@konsulko.com Cc: u-boot@lists.denx.de --- arch/arm/mach-renesas/include/mach/boot0.h | 28 ++- drivers/remoteproc/Kconfig | 8 + drivers/remoteproc/Makefile | 1 + drivers/remoteproc/renesas_apmu.c | 266 +++++++++++++++++++++ 4 files changed, 293 insertions(+), 10 deletions(-) create mode 100644 drivers/remoteproc/renesas_apmu.c
diff --git a/arch/arm/mach-renesas/include/mach/boot0.h b/arch/arm/mach-renesas/include/mach/boot0.h index 9cc0b819e4d..f7886d8c300 100644 --- a/arch/arm/mach-renesas/include/mach/boot0.h +++ b/arch/arm/mach-renesas/include/mach/boot0.h @@ -28,19 +28,19 @@ _start: /* r1=0xe6170800 */ .inst 0xe3a004e6 /* mov r0, #0xe6000000 */ .inst 0xe3801817 /* orr r1, r0, #0x170000 */ - .inst 0xe3811b02 /* orr r1, r1, #0x800 */ + .inst 0xe3814b02 /* orr r4, r1, #0x800 */
/* r0=0xe6280000 */ .inst 0xe380070a /* orr r0, r0, #0x280000 */
/* APMU_RVBARPLC0 = (address of 'b reset' below) | CA_CORE0_VLD_RVBARP */ - .inst 0xe28f3068 /* add r3, pc, #0x68 */ + .inst 0xe28f3088 /* add r3, pc, #0x88 */ .inst 0xe3833001 /* orr r3, r3, #1 */ - .inst 0xe5813038 /* str r3, [r1, #56] @ 0x38 */ + .inst 0xe5843038 /* str r3, [r4, #56] @ 0x38 */
/* APMU_RVBARPHC0 = 0 */ - .inst 0xe3a03000 /* mov r3, #0 */ - .inst 0xe581303c /* str r3, [r1, #60] @ 0x3c */ + .inst 0xe3a05000 /* mov r5, #0 */ + .inst 0xe584503c /* str r5, [r4, #60] @ 0x3c */
/* PRR & 0xff00 ?= 0x5c00, test if this is V4H or V4M */ .inst 0xe3a024ff /* mov r2, #0xff000000 */ @@ -67,13 +67,21 @@ _start: /* } */ /* APMU_PWRCTRLC0 = CA_CORE0_WUP_REQ */ .inst 0xe3a03001 /* mov r3, #1 */ - .inst 0xe5813000 /* str r3, [r1] */ - /* Endless loop */ + .inst 0xe5843000 /* str r3, [r4] */ + /* Test for APMU_CRBARP valid BAR flags and jump to CR entry point */ + .inst 0xe3814c03 /* orr r4, r1, #768 @ 0x300 */ + .inst 0xe584503c /* str r5, [r4, #60] @ 0x3c */ + .inst 0xe594203c /* ldr r2, [r4, #60] @ 0x3c */ + .inst 0xe20230ff /* and r3, r2, #255 @ 0xff */ + .inst 0xe3530011 /* cmp r3, #17 */ + .inst 0x1afffffb /* bne 78 <reset-0x28> */ + .inst 0xe1a02922 /* lsr r2, r2, #18 */ + .inst 0xe1a02902 /* lsl r2, r2, #18 */ + .inst 0xe1a0f002 /* mov pc, r2 */ + .inst 0xeafffffe /* b 94 <reset-0xc> */ .inst 0xe1a00000 /* nop @ (mov r0, r0) */ - .inst 0xeafffffd /* b 70 <reset-0x10> */ .inst 0xe1a00000 /* nop @ (mov r0, r0) */ - .inst 0xe1a00000 /* nop @ (mov r0, r0) */ - /* Offset 0x80 */ + /* Offset 0xa0 */ #endif b reset #endif 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, +};

Describe APMU controller as a remoteproc device capable of starting the Cortex-R52 cores in Renesas R8A779G0 V4H SoC DT. The APMU IP is in fact a power management unit capable of additional operations, but those are not used by U-Boot so far.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Adam Ford aford173@gmail.com Cc: MD Danish Anwar danishanwar@ti.com Cc: Nobuhiro Iwamatsu iwamatsu@nigauri.org Cc: Paul Barker paul.barker.ct@bp.renesas.com Cc: Ravi Gunasekaran r-gunasekaran@ti.com Cc: Roger Quadros rogerq@kernel.org Cc: Simon Glass sjg@chromium.org Cc: Sumit Garg sumit.garg@linaro.org Cc: Tom Rini trini@konsulko.com Cc: u-boot@lists.denx.de --- arch/arm/dts/r8a779g0-u-boot.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/r8a779g0-u-boot.dtsi b/arch/arm/dts/r8a779g0-u-boot.dtsi index 90f021299c5..2e731b628b3 100644 --- a/arch/arm/dts/r8a779g0-u-boot.dtsi +++ b/arch/arm/dts/r8a779g0-u-boot.dtsi @@ -165,6 +165,13 @@ };
&soc { + apmu@e6170000 { /* Remoteproc */ + compatible = "renesas,r8a779g0-cr52"; + reg = <0 0xe6170000 0 0x80000>; + power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; + status = "okay"; + }; + ram@e6780000 { /* DBSC5 */ compatible = "renesas,r8a779g0-dbsc"; reg = <0 0xe6780000 0 0x80000>;

Enable remoteproc command and APMU remoteproc driver to start Cortex-R52 cores from U-Boot command line. Code on the Cortex-R52 #0 can be started as follows, code on other cores can be started by passing the correct ID to 'rproc load' and 'rproc start' to select the core:
" => rproc init => rproc list 0 - Name:'rcar-apmu-cr52.0-apmu@e6170000' type:'internal memory mapped' supports: load start stop reset is_running 1 - Name:'rcar-apmu-cr52.1-apmu@e6170000' type:'internal memory mapped' supports: load start stop reset is_running 2 - Name:'rcar-apmu-cr52.2-apmu@e6170000' type:'internal memory mapped' supports: load start stop reset is_running => rproc load 0 0xeb200000 0x10000 Load Remote Processor 0 with data@addr=0xeb200000 65536 bytes: Success! => rproc start 0 "
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Adam Ford aford173@gmail.com Cc: MD Danish Anwar danishanwar@ti.com Cc: Nobuhiro Iwamatsu iwamatsu@nigauri.org Cc: Paul Barker paul.barker.ct@bp.renesas.com Cc: Ravi Gunasekaran r-gunasekaran@ti.com Cc: Roger Quadros rogerq@kernel.org Cc: Simon Glass sjg@chromium.org Cc: Sumit Garg sumit.garg@linaro.org Cc: Tom Rini trini@konsulko.com Cc: u-boot@lists.denx.de --- configs/r8a779g0_whitehawk_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/r8a779g0_whitehawk_defconfig b/configs/r8a779g0_whitehawk_defconfig index dc6fd6333f7..c74051d1af9 100644 --- a/configs/r8a779g0_whitehawk_defconfig +++ b/configs/r8a779g0_whitehawk_defconfig @@ -13,6 +13,8 @@ CONFIG_SYS_BARGSIZE=2048 CONFIG_BINMAN=y CONFIG_BOOTCOMMAND="tftp 0x48080000 Image && tftp 0x48000000 Image-r8a779g0-white-hawk.dtb && booti 0x48080000 - 0x48000000" CONFIG_DEFAULT_FDT_FILE="r8a779g0-white-hawk.dtb" +CONFIG_CMD_REMOTEPROC=y +CONFIG_REMOTEPROC_RENESAS_APMU=y CONFIG_SYS_CBSIZE=2048 CONFIG_ENV_IS_IN_MMC=y CONFIG_SYS_MMC_ENV_PART=2
participants (1)
-
Marek Vasut