aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/remoteproc
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/remoteproc')
-rw-r--r--roms/u-boot/drivers/remoteproc/Kconfig84
-rw-r--r--roms/u-boot/drivers/remoteproc/Makefile16
-rw-r--r--roms/u-boot/drivers/remoteproc/k3_system_controller.c326
-rw-r--r--roms/u-boot/drivers/remoteproc/rproc-elf-loader.c534
-rw-r--r--roms/u-boot/drivers/remoteproc/rproc-uclass.c437
-rw-r--r--roms/u-boot/drivers/remoteproc/sandbox_testproc.c358
-rw-r--r--roms/u-boot/drivers/remoteproc/stm32_copro.c227
-rw-r--r--roms/u-boot/drivers/remoteproc/ti_k3_arm64_rproc.c246
-rw-r--r--roms/u-boot/drivers/remoteproc/ti_k3_dsp_rproc.c460
-rw-r--r--roms/u-boot/drivers/remoteproc/ti_k3_r5f_rproc.c906
-rw-r--r--roms/u-boot/drivers/remoteproc/ti_power_proc.c182
-rw-r--r--roms/u-boot/drivers/remoteproc/ti_sci_proc.h148
12 files changed, 3924 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/remoteproc/Kconfig b/roms/u-boot/drivers/remoteproc/Kconfig
new file mode 100644
index 000000000..7c2e4804b
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/Kconfig
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2015
+# Texas Instruments Incorporated - http://www.ti.com/
+#
+
+menu "Remote Processor drivers"
+
+# REMOTEPROC gets selected by drivers as needed
+# All users should depend on DM
+config REMOTEPROC
+ bool
+ depends on DM
+
+# Please keep the configuration alphabetically sorted.
+config K3_SYSTEM_CONTROLLER
+ bool "Support for TI' K3 System Controller"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_K3
+ depends on OF_CONTROL
+ help
+ Say 'y' here to add support for TI' K3 System Controller.
+
+config REMOTEPROC_SANDBOX
+ bool "Support for Test processor for Sandbox"
+ select REMOTEPROC
+ depends on DM
+ depends on SANDBOX
+ help
+ Say 'y' here to add support for test processor which does dummy
+ operations for sandbox platform.
+
+config REMOTEPROC_STM32_COPRO
+ bool "Support for STM32 coprocessor"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_STM32MP
+ depends on OF_CONTROL
+ help
+ Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the
+ remoteproc framework.
+
+config REMOTEPROC_TI_K3_ARM64
+ bool "Support for TI's K3 based ARM64 remoteproc driver"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_K3
+ depends on OF_CONTROL
+ help
+ Say y here to support TI's ARM64 processor subsystems
+ on various TI K3 family of SoCs through the remote processor
+ framework.
+
+config REMOTEPROC_TI_K3_DSP
+ bool "TI K3 C66 and C71 remoteproc support"
+ select REMOTEPROC
+ depends on ARCH_K3
+ depends on TI_SCI_PROTOCOL
+ help
+ Say y here to support TI's C66/C71 remote processor subsystems
+ on various TI K3 family of SoCs through the remote processor
+ framework.
+
+config REMOTEPROC_TI_K3_R5F
+ bool "TI K3 R5F remoteproc support"
+ select REMOTEPROC
+ depends on ARCH_K3
+ depends on TI_SCI_PROTOCOL
+ help
+ Say y here to support TI's R5F remote processor subsystems
+ on various TI K3 family of SoCs through the remote processor
+ framework.
+
+config REMOTEPROC_TI_POWER
+ bool "Support for TI Power processor"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_KEYSTONE
+ depends on OF_CONTROL
+ help
+ Say 'y' here to add support for TI power processors such as those
+ found on certain TI keystone and OMAP generation SoCs.
+endmenu
diff --git a/roms/u-boot/drivers/remoteproc/Makefile b/roms/u-boot/drivers/remoteproc/Makefile
new file mode 100644
index 000000000..69ae7bd1e
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2015
+# Texas Instruments Incorporated - http://www.ti.com/
+#
+
+obj-$(CONFIG_$(SPL_)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_SANDBOX) += sandbox_testproc.o
+obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.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
+obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o
diff --git a/roms/u-boot/drivers/remoteproc/k3_system_controller.c b/roms/u-boot/drivers/remoteproc/k3_system_controller.c
new file mode 100644
index 000000000..89cb90207
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/k3_system_controller.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 System Controller Driver
+ *
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <remoteproc.h>
+#include <errno.h>
+#include <mailbox.h>
+#include <dm/device_compat.h>
+#include <linux/soc/ti/k3-sec-proxy.h>
+
+#define K3_MSG_R5_TO_M3_M3FW 0x8105
+#define K3_MSG_M3_TO_R5_CERT_RESULT 0x8805
+#define K3_MSG_M3_TO_R5_BOOT_NOTIFICATION 0x000A
+
+#define K3_FLAGS_MSG_CERT_AUTH_PASS 0x555555
+#define K3_FLAGS_MSG_CERT_AUTH_FAIL 0xffffff
+
+/**
+ * struct k3_sysctrler_msg_hdr - Generic Header for Messages and responses.
+ * @cmd_id: Message ID. One of K3_MSG_*
+ * @host_id: Host ID of the message
+ * @seq_ne: Message identifier indicating a transfer sequence.
+ * @flags: Flags for the message.
+ */
+struct k3_sysctrler_msg_hdr {
+ u16 cmd_id;
+ u8 host_id;
+ u8 seq_nr;
+ u32 flags;
+} __packed;
+
+/**
+ * struct k3_sysctrler_load_msg - Message format for Firmware loading
+ * @hdr: Generic message hdr
+ * @buffer_address: Address at which firmware is located.
+ * @buffer_size: Size of the firmware.
+ */
+struct k3_sysctrler_load_msg {
+ struct k3_sysctrler_msg_hdr hdr;
+ u32 buffer_address;
+ u32 buffer_size;
+} __packed;
+
+/**
+ * struct k3_sysctrler_boot_notification_msg - Message format for boot
+ * notification
+ * @checksum: Checksum for the entire message
+ * @reserved: Reserved for future use.
+ * @hdr: Generic message hdr
+ */
+struct k3_sysctrler_boot_notification_msg {
+ u16 checksum;
+ u16 reserved;
+ struct k3_sysctrler_msg_hdr hdr;
+} __packed;
+
+/**
+ * struct k3_sysctrler_desc - Description of SoC integration.
+ * @host_id: Host identifier representing the compute entity
+ * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
+ * @max_msg_size: Maximum size of data per message that can be handled.
+ */
+struct k3_sysctrler_desc {
+ u8 host_id;
+ int max_rx_timeout_us;
+ int max_msg_size;
+};
+
+/**
+ * struct k3_sysctrler_privdata - Structure representing System Controller data.
+ * @chan_tx: Transmit mailbox channel
+ * @chan_rx: Receive mailbox channel
+ * @desc: SoC description for this instance
+ * @seq_nr: Counter for number of messages sent.
+ */
+struct k3_sysctrler_privdata {
+ struct mbox_chan chan_tx;
+ struct mbox_chan chan_rx;
+ struct k3_sysctrler_desc *desc;
+ u32 seq_nr;
+};
+
+static inline
+void k3_sysctrler_load_msg_setup(struct k3_sysctrler_load_msg *fw,
+ struct k3_sysctrler_privdata *priv,
+ ulong addr, ulong size)
+{
+ fw->hdr.cmd_id = K3_MSG_R5_TO_M3_M3FW;
+ fw->hdr.host_id = priv->desc->host_id;
+ fw->hdr.seq_nr = priv->seq_nr++;
+ fw->hdr.flags = 0x0;
+ fw->buffer_address = addr;
+ fw->buffer_size = size;
+}
+
+static int k3_sysctrler_load_response(struct udevice *dev, u32 *buf)
+{
+ struct k3_sysctrler_load_msg *fw;
+
+ fw = (struct k3_sysctrler_load_msg *)buf;
+
+ /* Check for proper response ID */
+ if (fw->hdr.cmd_id != K3_MSG_M3_TO_R5_CERT_RESULT) {
+ dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
+ __func__, K3_MSG_M3_TO_R5_CERT_RESULT, fw->hdr.cmd_id);
+ return -EINVAL;
+ }
+
+ /* Check for certificate authentication result */
+ if (fw->hdr.flags == K3_FLAGS_MSG_CERT_AUTH_FAIL) {
+ dev_err(dev, "%s: Firmware certificate authentication failed\n",
+ __func__);
+ return -EINVAL;
+ } else if (fw->hdr.flags != K3_FLAGS_MSG_CERT_AUTH_PASS) {
+ dev_err(dev, "%s: Firmware Load response Invalid %d\n",
+ __func__, fw->hdr.flags);
+ return -EINVAL;
+ }
+
+ debug("%s: Firmware authentication passed\n", __func__);
+
+ return 0;
+}
+
+static int k3_sysctrler_boot_notification_response(struct udevice *dev,
+ u32 *buf)
+{
+ struct k3_sysctrler_boot_notification_msg *boot;
+
+ boot = (struct k3_sysctrler_boot_notification_msg *)buf;
+
+ /* ToDo: Verify checksum */
+
+ /* Check for proper response ID */
+ if (boot->hdr.cmd_id != K3_MSG_M3_TO_R5_BOOT_NOTIFICATION) {
+ dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
+ __func__, K3_MSG_M3_TO_R5_BOOT_NOTIFICATION,
+ boot->hdr.cmd_id);
+ return -EINVAL;
+ }
+
+ debug("%s: Boot notification received\n", __func__);
+
+ return 0;
+}
+
+/**
+ * k3_sysctrler_load() - Loadup the K3 remote processor
+ * @dev: corresponding K3 remote processor device
+ * @addr: Address in memory where image binary is stored
+ * @size: Size in bytes of the image binary
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_sysctrler_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
+ struct k3_sysctrler_load_msg firmware;
+ struct k3_sec_proxy_msg msg;
+ int ret;
+
+ debug("%s: Loading binary from 0x%08lX, size 0x%08lX\n",
+ __func__, addr, size);
+
+ memset(&firmware, 0, sizeof(firmware));
+ memset(&msg, 0, sizeof(msg));
+
+ /* Setup the message */
+ k3_sysctrler_load_msg_setup(&firmware, priv, addr, size);
+ msg.len = sizeof(firmware);
+ msg.buf = (u32 *)&firmware;
+
+ /* Send the message */
+ ret = mbox_send(&priv->chan_tx, &msg);
+ if (ret) {
+ dev_err(dev, "%s: Firmware Loading failed. ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Receive the response */
+ ret = mbox_recv(&priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
+ if (ret) {
+ dev_err(dev, "%s: Firmware Load response failed. ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Process the response */
+ ret = k3_sysctrler_load_response(dev, msg.buf);
+ if (ret)
+ return ret;
+
+ debug("%s: Firmware Loaded successfully on dev %s\n",
+ __func__, dev->name);
+
+ return 0;
+}
+
+/**
+ * k3_sysctrler_start() - Start the remote processor
+ * Note that while technically the K3 system controller starts up
+ * automatically after its firmware got loaded we still want to
+ * utilize the rproc start operation for other startup-related
+ * tasks.
+ * @dev: device to operate upon
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_sysctrler_start(struct udevice *dev)
+{
+ struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
+ struct k3_sec_proxy_msg msg;
+ int ret;
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ /* Receive the boot notification. Note that it is sent only once. */
+ ret = mbox_recv(&priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
+ if (ret) {
+ dev_err(dev, "%s: Boot Notification response failed. ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Process the response */
+ ret = k3_sysctrler_boot_notification_response(dev, msg.buf);
+ if (ret)
+ return ret;
+
+ debug("%s: Boot notification received successfully on dev %s\n",
+ __func__, dev->name);
+
+ return 0;
+}
+
+static const struct dm_rproc_ops k3_sysctrler_ops = {
+ .load = k3_sysctrler_load,
+ .start = k3_sysctrler_start,
+};
+
+/**
+ * k3_of_to_priv() - generate private data from device tree
+ * @dev: corresponding k3 remote processor device
+ * @priv: pointer to driver specific private data
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_of_to_priv(struct udevice *dev,
+ struct k3_sysctrler_privdata *priv)
+{
+ int ret;
+
+ ret = mbox_get_by_name(dev, "tx", &priv->chan_tx);
+ if (ret) {
+ dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = mbox_get_by_name(dev, "rx", &priv->chan_rx);
+ if (ret) {
+ dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * k3_sysctrler_probe() - Basic probe
+ * @dev: corresponding k3 remote processor device
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_sysctrler_probe(struct udevice *dev)
+{
+ struct k3_sysctrler_privdata *priv;
+ int ret;
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ priv = dev_get_priv(dev);
+
+ ret = k3_of_to_priv(dev, priv);
+ if (ret) {
+ dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
+ return ret;
+ }
+
+ priv->desc = (void *)dev_get_driver_data(dev);
+ priv->seq_nr = 0;
+
+ return 0;
+}
+
+static const struct k3_sysctrler_desc k3_sysctrler_am654_desc = {
+ .host_id = 4, /* HOST_ID_R5_1 */
+ .max_rx_timeout_us = 800000,
+ .max_msg_size = 60,
+};
+
+static const struct udevice_id k3_sysctrler_ids[] = {
+ {
+ .compatible = "ti,am654-system-controller",
+ .data = (ulong)&k3_sysctrler_am654_desc,
+ },
+ {}
+};
+
+U_BOOT_DRIVER(k3_sysctrler) = {
+ .name = "k3_system_controller",
+ .of_match = k3_sysctrler_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &k3_sysctrler_ops,
+ .probe = k3_sysctrler_probe,
+ .priv_auto = sizeof(struct k3_sysctrler_privdata),
+};
diff --git a/roms/u-boot/drivers/remoteproc/rproc-elf-loader.c b/roms/u-boot/drivers/remoteproc/rproc-elf-loader.c
new file mode 100644
index 000000000..b185a6caf
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/rproc-elf-loader.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <elf.h>
+#include <log.h>
+#include <remoteproc.h>
+#include <asm/cache.h>
+#include <dm/device_compat.h>
+#include <linux/compat.h>
+
+/**
+ * struct resource_table - firmware resource table header
+ * @ver: version number
+ * @num: number of resource entries
+ * @reserved: reserved (must be zero)
+ * @offset: array of offsets pointing at the various resource entries
+ *
+ * A resource table is essentially a list of system resources required
+ * by the remote processor. It may also include configuration entries.
+ * If needed, the remote processor firmware should contain this table
+ * as a dedicated ".resource_table" ELF section.
+ *
+ * Some resources entries are mere announcements, where the host is informed
+ * of specific remoteproc configuration. Other entries require the host to
+ * do something (e.g. allocate a system resource). Sometimes a negotiation
+ * is expected, where the firmware requests a resource, and once allocated,
+ * the host should provide back its details (e.g. address of an allocated
+ * memory region).
+ *
+ * The header of the resource table, as expressed by this structure,
+ * contains a version number (should we need to change this format in the
+ * future), the number of available resource entries, and their offsets
+ * in the table.
+ *
+ * Immediately following this header are the resource entries themselves.
+ */
+struct resource_table {
+ u32 ver;
+ u32 num;
+ u32 reserved[2];
+ u32 offset[0];
+} __packed;
+
+/* Basic function to verify ELF32 image format */
+int rproc_elf32_sanity_check(ulong addr, ulong size)
+{
+ Elf32_Ehdr *ehdr;
+ char class;
+
+ if (!addr) {
+ pr_debug("Invalid fw address?\n");
+ return -EFAULT;
+ }
+
+ if (size < sizeof(Elf32_Ehdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ ehdr = (Elf32_Ehdr *)addr;
+ class = ehdr->e_ident[EI_CLASS];
+
+ if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
+ pr_debug("Not an executable ELF32 image\n");
+ return -EPROTONOSUPPORT;
+ }
+
+ /* We assume the firmware has the same endianness as the host */
+# ifdef __LITTLE_ENDIAN
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+ pr_debug("Unsupported firmware endianness\n");
+ return -EILSEQ;
+ }
+
+ if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+ pr_debug("Image is corrupted (bad magic)\n");
+ return -EBADF;
+ }
+
+ if (ehdr->e_phnum == 0) {
+ pr_debug("No loadable segments\n");
+ return -ENOEXEC;
+ }
+
+ if (ehdr->e_phoff > size) {
+ pr_debug("Firmware size is too small\n");
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+/* Basic function to verify ELF64 image format */
+int rproc_elf64_sanity_check(ulong addr, ulong size)
+{
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
+ char class;
+
+ if (!addr) {
+ pr_debug("Invalid fw address?\n");
+ return -EFAULT;
+ }
+
+ if (size < sizeof(Elf64_Ehdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ class = ehdr->e_ident[EI_CLASS];
+
+ if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS64) {
+ pr_debug("Not an executable ELF64 image\n");
+ return -EPROTONOSUPPORT;
+ }
+
+ /* We assume the firmware has the same endianness as the host */
+# ifdef __LITTLE_ENDIAN
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+ pr_debug("Unsupported firmware endianness\n");
+ return -EILSEQ;
+ }
+
+ if (size < ehdr->e_shoff + sizeof(Elf64_Shdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+ pr_debug("Image is corrupted (bad magic)\n");
+ return -EBADF;
+ }
+
+ if (ehdr->e_phnum == 0) {
+ pr_debug("No loadable segments\n");
+ return -ENOEXEC;
+ }
+
+ if (ehdr->e_phoff > size) {
+ pr_debug("Firmware size is too small\n");
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
+{
+ Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+ Elf32_Phdr *phdr; /* Program header structure pointer */
+ const struct dm_rproc_ops *ops;
+ unsigned int i, ret;
+
+ ret = rproc_elf32_sanity_check(addr, size);
+ if (ret) {
+ dev_err(dev, "Invalid ELF32 Image %d\n", ret);
+ return ret;
+ }
+
+ ehdr = (Elf32_Ehdr *)addr;
+ phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
+
+ ops = rproc_get_ops(dev);
+
+ /* Load each program header */
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ void *dst = (void *)(uintptr_t)phdr->p_paddr;
+ void *src = (void *)addr + phdr->p_offset;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ if (ops->device_to_virt)
+ dst = ops->device_to_virt(dev, (ulong)dst,
+ phdr->p_memsz);
+
+ dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
+ i, dst, phdr->p_filesz);
+ if (phdr->p_filesz)
+ memcpy(dst, src, phdr->p_filesz);
+ 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,
+ ARCH_DMA_MINALIGN) -
+ rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ }
+
+ return 0;
+}
+
+int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
+{
+ const struct dm_rproc_ops *ops = rproc_get_ops(dev);
+ u64 da, memsz, filesz, offset;
+ Elf64_Ehdr *ehdr;
+ Elf64_Phdr *phdr;
+ int i, ret = 0;
+ void *ptr;
+
+ dev_dbg(dev, "%s: addr = 0x%lx size = 0x%lx\n", __func__, addr, size);
+
+ if (rproc_elf64_sanity_check(addr, size))
+ return -EINVAL;
+
+ ehdr = (Elf64_Ehdr *)addr;
+ phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
+
+ /* go through the available ELF segments */
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ da = phdr->p_paddr;
+ memsz = phdr->p_memsz;
+ filesz = phdr->p_filesz;
+ offset = phdr->p_offset;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ dev_dbg(dev, "%s:phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
+ __func__, phdr->p_type, da, memsz, filesz);
+
+ ptr = (void *)(uintptr_t)da;
+ if (ops->device_to_virt) {
+ ptr = ops->device_to_virt(dev, da, phdr->p_memsz);
+ if (!ptr) {
+ dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da,
+ memsz);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ if (filesz)
+ memcpy(ptr, (void *)addr + offset, filesz);
+ if (filesz != memsz)
+ memset(ptr + filesz, 0x00, memsz - filesz);
+
+ flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
+ roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
+ rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
+ }
+
+ return ret;
+}
+
+int rproc_elf_load_image(struct udevice *dev, ulong addr, ulong size)
+{
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
+
+ if (!addr) {
+ dev_err(dev, "Invalid firmware address\n");
+ return -EFAULT;
+ }
+
+ if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+ return rproc_elf64_load_image(dev, addr, size);
+ else
+ return rproc_elf32_load_image(dev, addr, size);
+}
+
+static ulong rproc_elf32_get_boot_addr(ulong addr)
+{
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
+
+ return ehdr->e_entry;
+}
+
+static ulong rproc_elf64_get_boot_addr(ulong addr)
+{
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
+
+ return ehdr->e_entry;
+}
+
+ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr)
+{
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
+
+ if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+ return rproc_elf64_get_boot_addr(addr);
+ else
+ return rproc_elf32_get_boot_addr(addr);
+}
+
+/*
+ * Search for the resource table in an ELF32 image.
+ * Returns the address of the resource table section if found, NULL if there is
+ * no resource table section, or error pointer.
+ */
+static Elf32_Shdr *rproc_elf32_find_rsc_table(struct udevice *dev,
+ ulong fw_addr, ulong fw_size)
+{
+ int ret;
+ unsigned int i;
+ const char *name_table;
+ struct resource_table *table;
+ const u8 *elf_data = (void *)fw_addr;
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr;
+ Elf32_Shdr *shdr;
+
+ ret = rproc_elf32_sanity_check(fw_addr, fw_size);
+ if (ret) {
+ pr_debug("Invalid ELF32 Image %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ /* look for the resource table and handle it */
+ shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff);
+ name_table = (const char *)(elf_data +
+ shdr[ehdr->e_shstrndx].sh_offset);
+
+ for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+ u32 size = shdr->sh_size;
+ u32 offset = shdr->sh_offset;
+
+ if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+ continue;
+
+ table = (struct resource_table *)(elf_data + offset);
+
+ /* make sure we have the entire table */
+ if (offset + size > fw_size) {
+ pr_debug("resource table truncated\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* make sure table has at least the header */
+ if (sizeof(*table) > size) {
+ pr_debug("header-less resource table\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* we don't support any version beyond the first */
+ if (table->ver != 1) {
+ pr_debug("unsupported fw ver: %d\n", table->ver);
+ return ERR_PTR(-EPROTONOSUPPORT);
+ }
+
+ /* make sure reserved bytes are zeroes */
+ if (table->reserved[0] || table->reserved[1]) {
+ pr_debug("non zero reserved bytes\n");
+ return ERR_PTR(-EBADF);
+ }
+
+ /* make sure the offsets array isn't truncated */
+ if (table->num * sizeof(table->offset[0]) +
+ sizeof(*table) > size) {
+ pr_debug("resource table incomplete\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ return shdr;
+ }
+
+ return NULL;
+}
+
+/* Load the resource table from an ELF32 image */
+int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
+{
+ const struct dm_rproc_ops *ops;
+ Elf32_Shdr *shdr;
+ void *src, *dst;
+
+ shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size);
+ if (!shdr)
+ return -ENODATA;
+ if (IS_ERR(shdr))
+ return PTR_ERR(shdr);
+
+ ops = rproc_get_ops(dev);
+ *rsc_addr = (ulong)shdr->sh_addr;
+ *rsc_size = (ulong)shdr->sh_size;
+
+ src = (void *)fw_addr + shdr->sh_offset;
+ if (ops->device_to_virt)
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ else
+ dst = (void *)rsc_addr;
+
+ dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
+ (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));
+
+ return 0;
+}
+
+/*
+ * Search for the resource table in an ELF64 image.
+ * Returns the address of the resource table section if found, NULL if there is
+ * no resource table section, or error pointer.
+ */
+static Elf64_Shdr *rproc_elf64_find_rsc_table(struct udevice *dev,
+ ulong fw_addr, ulong fw_size)
+{
+ int ret;
+ unsigned int i;
+ const char *name_table;
+ struct resource_table *table;
+ const u8 *elf_data = (void *)fw_addr;
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)fw_addr;
+ Elf64_Shdr *shdr;
+
+ ret = rproc_elf64_sanity_check(fw_addr, fw_size);
+ if (ret) {
+ pr_debug("Invalid ELF64 Image %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ /* look for the resource table and handle it */
+ shdr = (Elf64_Shdr *)(elf_data + ehdr->e_shoff);
+ name_table = (const char *)(elf_data +
+ shdr[ehdr->e_shstrndx].sh_offset);
+
+ for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+ u64 size = shdr->sh_size;
+ u64 offset = shdr->sh_offset;
+
+ if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+ continue;
+
+ table = (struct resource_table *)(elf_data + offset);
+
+ /* make sure we have the entire table */
+ if (offset + size > fw_size) {
+ pr_debug("resource table truncated\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* make sure table has at least the header */
+ if (sizeof(*table) > size) {
+ pr_debug("header-less resource table\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* we don't support any version beyond the first */
+ if (table->ver != 1) {
+ pr_debug("unsupported fw ver: %d\n", table->ver);
+ return ERR_PTR(-EPROTONOSUPPORT);
+ }
+
+ /* make sure reserved bytes are zeroes */
+ if (table->reserved[0] || table->reserved[1]) {
+ pr_debug("non zero reserved bytes\n");
+ return ERR_PTR(-EBADF);
+ }
+
+ /* make sure the offsets array isn't truncated */
+ if (table->num * sizeof(table->offset[0]) +
+ sizeof(*table) > size) {
+ pr_debug("resource table incomplete\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ return shdr;
+ }
+
+ return NULL;
+}
+
+/* Load the resource table from an ELF64 image */
+int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
+{
+ const struct dm_rproc_ops *ops;
+ Elf64_Shdr *shdr;
+ void *src, *dst;
+
+ shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size);
+ if (!shdr)
+ return -ENODATA;
+ if (IS_ERR(shdr))
+ return PTR_ERR(shdr);
+
+ ops = rproc_get_ops(dev);
+ *rsc_addr = (ulong)shdr->sh_addr;
+ *rsc_size = (ulong)shdr->sh_size;
+
+ src = (void *)fw_addr + shdr->sh_offset;
+ if (ops->device_to_virt)
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ else
+ dst = (void *)rsc_addr;
+
+ dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
+ (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));
+
+ return 0;
+}
+
+/* Load the resource table from an ELF32 or ELF64 image */
+int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
+
+{
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr;
+
+ if (!fw_addr)
+ return -EFAULT;
+
+ if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+ return rproc_elf64_load_rsc_table(dev, fw_addr, fw_size,
+ rsc_addr, rsc_size);
+ else
+ return rproc_elf32_load_rsc_table(dev, fw_addr, fw_size,
+ rsc_addr, rsc_size);
+}
diff --git a/roms/u-boot/drivers/remoteproc/rproc-uclass.c b/roms/u-boot/drivers/remoteproc/rproc-uclass.c
new file mode 100644
index 000000000..5919c8bb9
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/rproc-uclass.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated - http://www.ti.com/
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <remoteproc.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <dm.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * for_each_remoteproc_device() - iterate through the list of rproc devices
+ * @fn: check function to call per match, if this function returns fail,
+ * iteration is aborted with the resultant error value
+ * @skip_dev: Device to skip calling the callback about.
+ * @data: Data to pass to the callback function
+ *
+ * Return: 0 if none of the callback returned a non 0 result, else returns the
+ * result from the callback function
+ */
+static int for_each_remoteproc_device(int (*fn) (struct udevice *dev,
+ struct dm_rproc_uclass_pdata *uc_pdata,
+ const void *data),
+ struct udevice *skip_dev,
+ const void *data)
+{
+ struct udevice *dev;
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ int ret;
+
+ for (ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); dev;
+ ret = uclass_find_next_device(&dev)) {
+ if (ret || dev == skip_dev)
+ continue;
+ uc_pdata = dev_get_uclass_plat(dev);
+ ret = fn(dev, uc_pdata, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * _rproc_name_is_unique() - iteration helper to check if rproc name is unique
+ * @dev: device that we are checking name for
+ * @uc_pdata: uclass platform data
+ * @data: compare data (this is the name we want to ensure is unique)
+ *
+ * Return: 0 is there is no match(is unique); if there is a match(we dont
+ * have a unique name), return -EINVAL.
+ */
+static int _rproc_name_is_unique(struct udevice *dev,
+ struct dm_rproc_uclass_pdata *uc_pdata,
+ const void *data)
+{
+ const char *check_name = data;
+
+ /* devices not yet populated with data - so skip them */
+ if (!uc_pdata->name || !check_name)
+ return 0;
+
+ /* Return 0 to search further if we dont match */
+ if (strlen(uc_pdata->name) != strlen(check_name))
+ return 0;
+
+ if (!strcmp(uc_pdata->name, check_name))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * rproc_name_is_unique() - Check if the rproc name is unique
+ * @check_dev: Device we are attempting to ensure is unique
+ * @check_name: Name we are trying to ensure is unique.
+ *
+ * Return: true if we have a unique name, false if name is not unique.
+ */
+static bool rproc_name_is_unique(struct udevice *check_dev,
+ const char *check_name)
+{
+ int ret;
+
+ ret = for_each_remoteproc_device(_rproc_name_is_unique,
+ check_dev, check_name);
+ return ret ? false : true;
+}
+
+/**
+ * rproc_pre_probe() - Pre probe accessor for the uclass
+ * @dev: device for which we are preprobing
+ *
+ * Parses and fills up the uclass pdata for use as needed by core and
+ * remote proc drivers.
+ *
+ * Return: 0 if all wernt ok, else appropriate error value.
+ */
+static int rproc_pre_probe(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ const struct dm_rproc_ops *ops;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ /* See if we need to populate via fdt */
+
+ if (!dev_get_plat(dev)) {
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ int node = dev_of_offset(dev);
+ const void *blob = gd->fdt_blob;
+ bool tmp;
+ if (!blob) {
+ debug("'%s' no dt?\n", dev->name);
+ return -EINVAL;
+ }
+ debug("'%s': using fdt\n", dev->name);
+ uc_pdata->name = fdt_getprop(blob, node,
+ "remoteproc-name", NULL);
+
+ /* Default is internal memory mapped */
+ uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
+ tmp = fdtdec_get_bool(blob, node,
+ "remoteproc-internal-memory-mapped");
+ if (tmp)
+ uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
+#else
+ /* Nothing much we can do about this, can we? */
+ return -EINVAL;
+#endif
+
+ } else {
+ struct dm_rproc_uclass_pdata *pdata = dev_get_plat(dev);
+
+ debug("'%s': using legacy data\n", dev->name);
+ if (pdata->name)
+ uc_pdata->name = pdata->name;
+ uc_pdata->mem_type = pdata->mem_type;
+ uc_pdata->driver_plat_data = pdata->driver_plat_data;
+ }
+
+ /* Else try using device Name */
+ if (!uc_pdata->name)
+ uc_pdata->name = dev->name;
+ if (!uc_pdata->name) {
+ debug("Unnamed device!");
+ return -EINVAL;
+ }
+
+ if (!rproc_name_is_unique(dev, uc_pdata->name)) {
+ debug("%s duplicate name '%s'\n", dev->name, uc_pdata->name);
+ return -EINVAL;
+ }
+
+ ops = rproc_get_ops(dev);
+ if (!ops) {
+ debug("%s driver has no ops?\n", dev->name);
+ return -EINVAL;
+ }
+
+ if (!ops->load || !ops->start) {
+ debug("%s driver has missing mandatory ops?\n", dev->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * rproc_post_probe() - post probe accessor for the uclass
+ * @dev: deivce we finished probing
+ *
+ * initiate init function after the probe is completed. This allows
+ * the remote processor drivers to split up the initializations between
+ * probe and init as needed.
+ *
+ * Return: if the remote proc driver has a init routine, invokes it and
+ * hands over the return value. overall, 0 if all went well, else appropriate
+ * error value.
+ */
+static int rproc_post_probe(struct udevice *dev)
+{
+ const struct dm_rproc_ops *ops;
+
+ ops = rproc_get_ops(dev);
+ if (!ops) {
+ debug("%s driver has no ops?\n", dev->name);
+ return -EINVAL;
+ }
+
+ if (ops->init)
+ return ops->init(dev);
+
+ return 0;
+}
+
+UCLASS_DRIVER(rproc) = {
+ .id = UCLASS_REMOTEPROC,
+ .name = "remoteproc",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .pre_probe = rproc_pre_probe,
+ .post_probe = rproc_post_probe,
+ .per_device_plat_auto = sizeof(struct dm_rproc_uclass_pdata),
+};
+
+/* Remoteproc subsystem access functions */
+/**
+ * _rproc_probe_dev() - iteration helper to probe a rproc device
+ * @dev: device to probe
+ * @uc_pdata: uclass data allocated for the device
+ * @data: unused
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+static int _rproc_probe_dev(struct udevice *dev,
+ struct dm_rproc_uclass_pdata *uc_pdata,
+ const void *data)
+{
+ int ret;
+
+ ret = device_probe(dev);
+
+ if (ret)
+ debug("%s: Failed to initialize - %d\n", dev->name, ret);
+ return ret;
+}
+
+/**
+ * _rproc_dev_is_probed() - check if the device has been probed
+ * @dev: device to check
+ * @uc_pdata: unused
+ * @data: unused
+ *
+ * Return: -EAGAIN if not probed else return 0
+ */
+static int _rproc_dev_is_probed(struct udevice *dev,
+ struct dm_rproc_uclass_pdata *uc_pdata,
+ const void *data)
+{
+ if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
+ return 0;
+
+ return -EAGAIN;
+}
+
+bool rproc_is_initialized(void)
+{
+ int ret = for_each_remoteproc_device(_rproc_dev_is_probed, NULL, NULL);
+ return ret ? false : true;
+}
+
+int rproc_init(void)
+{
+ int ret;
+
+ if (rproc_is_initialized()) {
+ debug("Already initialized\n");
+ return -EINVAL;
+ }
+
+ ret = for_each_remoteproc_device(_rproc_probe_dev, NULL, NULL);
+ return ret;
+}
+
+int rproc_dev_init(int id)
+{
+ struct udevice *dev = NULL;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
+ if (ret) {
+ debug("Unknown remote processor id '%d' requested(%d)\n",
+ id, ret);
+ return ret;
+ }
+
+ ret = device_probe(dev);
+ if (ret)
+ debug("%s: Failed to initialize - %d\n", dev->name, ret);
+
+ return ret;
+}
+
+int rproc_load(int id, ulong addr, ulong size)
+{
+ struct udevice *dev = NULL;
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ const struct dm_rproc_ops *ops;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
+ if (ret) {
+ debug("Unknown remote processor id '%d' requested(%d)\n",
+ id, ret);
+ return ret;
+ }
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ops = rproc_get_ops(dev);
+ if (!ops) {
+ debug("%s driver has no ops?\n", dev->name);
+ return -EINVAL;
+ }
+
+ debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n",
+ uc_pdata->name, addr, size);
+ if (ops->load)
+ return ops->load(dev, addr, size);
+
+ debug("%s: data corruption?? mandatory function is missing!\n",
+ dev->name);
+
+ return -EINVAL;
+};
+
+/*
+ * Completely internal helper enums..
+ * Keeping this isolated helps this code evolve independent of other
+ * parts..
+ */
+enum rproc_ops {
+ RPROC_START,
+ RPROC_STOP,
+ RPROC_RESET,
+ RPROC_PING,
+ RPROC_RUNNING,
+};
+
+/**
+ * _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback
+ * @id: id of the remote processor
+ * @op: one of rproc_ops that indicate what operation to invoke
+ *
+ * Most of the checks and verification for remoteproc operations are more
+ * or less same for almost all operations. This allows us to put a wrapper
+ * and use the common checks to allow the driver to function appropriately.
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+static int _rproc_ops_wrapper(int id, enum rproc_ops op)
+{
+ struct udevice *dev = NULL;
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ const struct dm_rproc_ops *ops;
+ int (*fn)(struct udevice *dev);
+ bool mandatory = false;
+ char *op_str;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
+ if (ret) {
+ debug("Unknown remote processor id '%d' requested(%d)\n",
+ id, ret);
+ return ret;
+ }
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ops = rproc_get_ops(dev);
+ if (!ops) {
+ debug("%s driver has no ops?\n", dev->name);
+ return -EINVAL;
+ }
+ switch (op) {
+ case RPROC_START:
+ fn = ops->start;
+ mandatory = true;
+ op_str = "Starting";
+ break;
+ case RPROC_STOP:
+ fn = ops->stop;
+ op_str = "Stopping";
+ break;
+ case RPROC_RESET:
+ fn = ops->reset;
+ op_str = "Resetting";
+ break;
+ case RPROC_RUNNING:
+ fn = ops->is_running;
+ op_str = "Checking if running:";
+ break;
+ case RPROC_PING:
+ fn = ops->ping;
+ op_str = "Pinging";
+ break;
+ default:
+ debug("what is '%d' operation??\n", op);
+ return -EINVAL;
+ }
+
+ debug("%s %s...\n", op_str, uc_pdata->name);
+ if (fn)
+ return fn(dev);
+
+ if (mandatory)
+ debug("%s: data corruption?? mandatory function is missing!\n",
+ dev->name);
+
+ return -ENOSYS;
+}
+
+int rproc_start(int id)
+{
+ return _rproc_ops_wrapper(id, RPROC_START);
+};
+
+int rproc_stop(int id)
+{
+ return _rproc_ops_wrapper(id, RPROC_STOP);
+};
+
+int rproc_reset(int id)
+{
+ return _rproc_ops_wrapper(id, RPROC_RESET);
+};
+
+int rproc_ping(int id)
+{
+ return _rproc_ops_wrapper(id, RPROC_PING);
+};
+
+int rproc_is_running(int id)
+{
+ return _rproc_ops_wrapper(id, RPROC_RUNNING);
+};
diff --git a/roms/u-boot/drivers/remoteproc/sandbox_testproc.c b/roms/u-boot/drivers/remoteproc/sandbox_testproc.c
new file mode 100644
index 000000000..6836eca4c
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/sandbox_testproc.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated - http://www.ti.com/
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <remoteproc.h>
+#include <asm/io.h>
+
+/**
+ * enum sandbox_state - different device states
+ * @sb_booted: Entry condition, just booted
+ * @sb_init: Initialized (basic environment is ready)
+ * @sb_reset: Held in reset (accessible, but not running)
+ * @sb_loaded: Loaded with image (but not running)
+ * @sb_running: Processor is running
+ */
+enum sandbox_state {
+ sb_booted,
+ sb_init,
+ sb_reset,
+ sb_loaded,
+ sb_running
+};
+
+/**
+ * struct sandbox_test_devdata - private data per device
+ * @current_state: device current state
+ */
+struct sandbox_test_devdata {
+ enum sandbox_state current_state;
+};
+
+/**
+ * sandbox_dev_move_to_state() - statemachine for our dummy device
+ * @dev: device to switch state
+ * @next_state: next proposed state
+ *
+ * This tries to follow the following statemachine:
+ * Entry
+ * |
+ * v
+ * +-------+
+ * +---+ init |
+ * | | | <---------------------+
+ * | +-------+ |
+ * | |
+ * | |
+ * | +--------+ |
+ * Load| | reset | |
+ * | | | <----------+ |
+ * | +--------+ | |
+ * | |Load | |
+ * | | | |
+ * | +----v----+ reset | |
+ * +-> | | (opt) | |
+ * | Loaded +-----------+ |
+ * | | |
+ * +----+----+ |
+ * | Start |
+ * +---v-----+ (opt) |
+ * +->| Running | Stop |
+ * Ping +- | +--------------------+
+ * (opt) +---------+
+ *
+ * (is_running does not change state)
+ *
+ * Return: 0 when valid state transition is seen, else returns -EINVAL
+ */
+static int sandbox_dev_move_to_state(struct udevice *dev,
+ enum sandbox_state next_state)
+{
+ struct sandbox_test_devdata *ddata = dev_get_priv(dev);
+
+ /* No state transition is OK */
+ if (ddata->current_state == next_state)
+ return 0;
+
+ debug("current_state=%d, next_state=%d\n", ddata->current_state,
+ next_state);
+ switch (ddata->current_state) {
+ case sb_booted:
+ if (next_state == sb_init)
+ goto ok_state;
+ break;
+
+ case sb_init:
+ if (next_state == sb_reset || next_state == sb_loaded)
+ goto ok_state;
+ break;
+
+ case sb_reset:
+ if (next_state == sb_loaded || next_state == sb_init)
+ goto ok_state;
+ break;
+
+ case sb_loaded:
+ if (next_state == sb_reset || next_state == sb_init ||
+ next_state == sb_running)
+ goto ok_state;
+ break;
+
+ case sb_running:
+ if (next_state == sb_reset || next_state == sb_init)
+ goto ok_state;
+ break;
+ };
+ return -EINVAL;
+
+ok_state:
+ ddata->current_state = next_state;
+ return 0;
+}
+
+/**
+ * sandbox_testproc_probe() - basic probe function
+ * @dev: test proc device that is being probed.
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int sandbox_testproc_probe(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ struct sandbox_test_devdata *ddata;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ ddata = dev_get_priv(dev);
+ if (!ddata) {
+ debug("%s: platform private data missing\n", uc_pdata->name);
+ return -EINVAL;
+ }
+ ret = sandbox_dev_move_to_state(dev, sb_booted);
+ debug("%s: called(%d)\n", uc_pdata->name, ret);
+
+ return ret;
+}
+
+/**
+ * sandbox_testproc_init() - Simple initialization function
+ * @dev: device to operate upon
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int sandbox_testproc_init(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ret = sandbox_dev_move_to_state(dev, sb_init);
+
+ debug("%s: called(%d)\n", uc_pdata->name, ret);
+ if (ret)
+ debug("%s init failed\n", uc_pdata->name);
+
+ return ret;
+}
+
+/**
+ * sandbox_testproc_reset() - Reset the remote processor
+ * @dev: device to operate upon
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int sandbox_testproc_reset(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ret = sandbox_dev_move_to_state(dev, sb_reset);
+
+ debug("%s: called(%d)\n", uc_pdata->name, ret);
+
+ if (ret)
+ debug("%s reset failed\n", uc_pdata->name);
+ return ret;
+}
+
+/**
+ * sandbox_testproc_load() - (replace: short desc)
+ * @dev: device to operate upon
+ * @addr: Address of the binary image to load
+ * @size: Size (in bytes) of the binary image to load
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int sandbox_testproc_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ret = sandbox_dev_move_to_state(dev, sb_loaded);
+
+ debug("%s: called(%d) Loading to %08lX %lu size\n",
+ uc_pdata->name, ret, addr, size);
+
+ if (ret)
+ debug("%s load failed\n", uc_pdata->name);
+ return ret;
+}
+
+/**
+ * sandbox_testproc_start() - Start the remote processor
+ * @dev: device to operate upon
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int sandbox_testproc_start(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ret = sandbox_dev_move_to_state(dev, sb_running);
+
+ debug("%s: called(%d)\n", uc_pdata->name, ret);
+
+ if (ret)
+ debug("%s start failed\n", uc_pdata->name);
+ return ret;
+}
+
+/**
+ * sandbox_testproc_stop() - Stop the remote processor
+ * @dev: device to operate upon
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int sandbox_testproc_stop(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ret = sandbox_dev_move_to_state(dev, sb_init);
+
+ debug("%s: called(%d)\n", uc_pdata->name, ret);
+
+ if (ret)
+ debug("%s stop failed\n", uc_pdata->name);
+ return ret;
+}
+
+/**
+ * sandbox_testproc_is_running() - Check if remote processor is running
+ * @dev: device to operate upon
+ *
+ * Return: 0 if running, 1 if not running
+ */
+static int sandbox_testproc_is_running(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ struct sandbox_test_devdata *ddata;
+ int ret = 1;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ ddata = dev_get_priv(dev);
+
+ if (ddata->current_state == sb_running)
+ ret = 0;
+ debug("%s: called(%d)\n", uc_pdata->name, ret);
+
+ return ret;
+}
+
+/**
+ * sandbox_testproc_ping() - Try pinging remote processor
+ * @dev: device to operate upon
+ *
+ * Return: 0 if running, -EINVAL if not running
+ */
+static int sandbox_testproc_ping(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ struct sandbox_test_devdata *ddata;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ ddata = dev_get_priv(dev);
+
+ if (ddata->current_state == sb_running)
+ ret = 0;
+ else
+ ret = -EINVAL;
+
+ debug("%s: called(%d)\n", uc_pdata->name, ret);
+ if (ret)
+ debug("%s: No response.(Not started?)\n", uc_pdata->name);
+
+ return ret;
+}
+
+#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000
+/**
+ * sandbox_testproc_device_to_virt() - Convert device address to virtual address
+ * @dev: device to operate upon
+ * @da: device address
+ * @size: Size of the memory region @da is pointing to
+ * @return converted virtual address
+ */
+static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da,
+ ulong size)
+{
+ u64 paddr;
+
+ /* Use a simple offset conversion */
+ paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
+
+ return phys_to_virt(paddr);
+}
+
+static const struct dm_rproc_ops sandbox_testproc_ops = {
+ .init = sandbox_testproc_init,
+ .reset = sandbox_testproc_reset,
+ .load = sandbox_testproc_load,
+ .start = sandbox_testproc_start,
+ .stop = sandbox_testproc_stop,
+ .is_running = sandbox_testproc_is_running,
+ .ping = sandbox_testproc_ping,
+ .device_to_virt = sandbox_testproc_device_to_virt,
+};
+
+static const struct udevice_id sandbox_ids[] = {
+ {.compatible = "sandbox,test-processor"},
+ {}
+};
+
+U_BOOT_DRIVER(sandbox_testproc) = {
+ .name = "sandbox_test_proc",
+ .of_match = sandbox_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &sandbox_testproc_ops,
+ .probe = sandbox_testproc_probe,
+ .priv_auto = sizeof(struct sandbox_test_devdata),
+};
+
+/* TODO(nm@ti.com): Remove this along with non-DT support */
+static struct dm_rproc_uclass_pdata proc_3_test = {
+ .name = "proc_3_legacy",
+ .mem_type = RPROC_INTERNAL_MEMORY_MAPPED,
+};
+
+U_BOOT_DRVINFO(proc_3_demo) = {
+ .name = "sandbox_test_proc",
+ .plat = &proc_3_test,
+};
diff --git a/roms/u-boot/drivers/remoteproc/stm32_copro.c b/roms/u-boot/drivers/remoteproc/stm32_copro.c
new file mode 100644
index 000000000..4c5f24857
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/stm32_copro.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#define LOG_CATEGORY UCLASS_REMOTEPROC
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <remoteproc.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+
+/**
+ * struct stm32_copro_privdata - power processor private data
+ * @reset_ctl: reset controller handle
+ * @hold_boot: hold boot controller handle
+ * @rsc_table_addr: resource table address
+ */
+struct stm32_copro_privdata {
+ struct reset_ctl reset_ctl;
+ struct reset_ctl hold_boot;
+ ulong rsc_table_addr;
+};
+
+/**
+ * stm32_copro_probe() - Basic probe
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_probe(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = reset_get_by_name(dev, "mcu_rst", &priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "failed to get reset (%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "hold_boot", &priv->hold_boot);
+ if (ret) {
+ dev_err(dev, "failed to get hold boot (%d)\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "probed\n");
+
+ return 0;
+}
+
+/**
+ * stm32_copro_device_to_virt() - Convert device address to virtual address
+ * @dev: corresponding STM32 remote processor device
+ * @da: device address
+ * @size: Size of the memory region @da is pointing to
+ * @return converted virtual address
+ */
+static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da,
+ ulong size)
+{
+ fdt32_t in_addr = cpu_to_be32(da), end_addr;
+ u64 paddr;
+
+ paddr = dev_translate_dma_address(dev, &in_addr);
+ if (paddr == OF_BAD_ADDR) {
+ dev_err(dev, "Unable to convert address %ld\n", da);
+ return NULL;
+ }
+
+ end_addr = cpu_to_be32(da + size - 1);
+ if (dev_translate_dma_address(dev, &end_addr) == OF_BAD_ADDR) {
+ dev_err(dev, "Unable to convert address %ld\n", da + size - 1);
+ return NULL;
+ }
+
+ return phys_to_virt(paddr);
+}
+
+/**
+ * stm32_copro_load() - Loadup the STM32 remote processor
+ * @dev: corresponding STM32 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 stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct stm32_copro_privdata *priv;
+ ulong rsc_table_size;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = reset_assert(&priv->hold_boot);
+ if (ret) {
+ dev_err(dev, "Unable to assert hold boot (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_assert(&priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
+ return ret;
+ }
+
+ if (rproc_elf32_load_rsc_table(dev, addr, size, &priv->rsc_table_addr,
+ &rsc_table_size)) {
+ priv->rsc_table_addr = 0;
+ dev_warn(dev, "No valid resource table for this firmware\n");
+ }
+
+ return rproc_elf32_load_image(dev, addr, size);
+}
+
+/**
+ * stm32_copro_start() - Start the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_start(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = reset_deassert(&priv->hold_boot);
+ if (ret) {
+ dev_err(dev, "Unable to deassert hold boot (ret=%d)\n", ret);
+ return ret;
+ }
+
+ /*
+ * Once copro running, reset hold boot flag to avoid copro
+ * rebooting autonomously (error should never occur)
+ */
+ ret = reset_assert(&priv->hold_boot);
+ if (ret)
+ dev_err(dev, "Unable to assert hold boot (ret=%d)\n", ret);
+
+ /* indicates that copro is running */
+ writel(TAMP_COPRO_STATE_CRUN, TAMP_COPRO_STATE);
+ /* Store rsc_address in bkp register */
+ writel(priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS);
+
+ return 0;
+}
+
+/**
+ * stm32_copro_reset() - Reset the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_reset(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = reset_assert(&priv->hold_boot);
+ if (ret) {
+ dev_err(dev, "Unable to assert hold boot (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_assert(&priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
+ return ret;
+ }
+
+ writel(TAMP_COPRO_STATE_OFF, TAMP_COPRO_STATE);
+
+ return 0;
+}
+
+/**
+ * stm32_copro_stop() - Stop the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_stop(struct udevice *dev)
+{
+ return stm32_copro_reset(dev);
+}
+
+/**
+ * stm32_copro_is_running() - Is the STM32 remote processor running
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if the remote processor is running, 1 otherwise
+ */
+static int stm32_copro_is_running(struct udevice *dev)
+{
+ return (readl(TAMP_COPRO_STATE) == TAMP_COPRO_STATE_OFF);
+}
+
+static const struct dm_rproc_ops stm32_copro_ops = {
+ .load = stm32_copro_load,
+ .start = stm32_copro_start,
+ .stop = stm32_copro_stop,
+ .reset = stm32_copro_reset,
+ .is_running = stm32_copro_is_running,
+ .device_to_virt = stm32_copro_device_to_virt,
+};
+
+static const struct udevice_id stm32_copro_ids[] = {
+ {.compatible = "st,stm32mp1-m4"},
+ {}
+};
+
+U_BOOT_DRIVER(stm32_copro) = {
+ .name = "stm32_m4_proc",
+ .of_match = stm32_copro_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &stm32_copro_ops,
+ .probe = stm32_copro_probe,
+ .priv_auto = sizeof(struct stm32_copro_privdata),
+};
diff --git a/roms/u-boot/drivers/remoteproc/ti_k3_arm64_rproc.c b/roms/u-boot/drivers/remoteproc/ti_k3_arm64_rproc.c
new file mode 100644
index 000000000..1f2415dc1
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/ti_k3_arm64_rproc.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 ARM64 Remoteproc driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <remoteproc.h>
+#include <errno.h>
+#include <clk.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <power-domain.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include "ti_sci_proc.h"
+
+#define INVALID_ID 0xffff
+
+#define GTC_CNTCR_REG 0x0
+#define GTC_CNTFID0_REG 0x20
+#define GTC_CNTR_EN 0x3
+
+/**
+ * struct k3_arm64_privdata - Structure representing Remote processor data.
+ * @rproc_pwrdmn: rproc power domain data
+ * @rproc_rst: rproc reset control data
+ * @sci: Pointer to TISCI handle
+ * @tsp: TISCI processor control helper structure
+ * @gtc_clk: GTC clock description
+ * @gtc_base: Timer base address.
+ */
+struct k3_arm64_privdata {
+ struct power_domain rproc_pwrdmn;
+ struct power_domain gtc_pwrdmn;
+ struct reset_ctl rproc_rst;
+ struct ti_sci_proc tsp;
+ struct clk gtc_clk;
+ void *gtc_base;
+};
+
+/**
+ * k3_arm64_load() - Load up the Remote processor image
+ * @dev: rproc device pointer
+ * @addr: Address at which image is available
+ * @size: size of the image
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_arm64_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct k3_arm64_privdata *rproc = dev_get_priv(dev);
+ int ret;
+
+ dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
+
+ /* request for the processor */
+ ret = ti_sci_proc_request(&rproc->tsp);
+ if (ret)
+ return ret;
+
+ return ti_sci_proc_set_config(&rproc->tsp, addr, 0, 0);
+}
+
+/**
+ * k3_arm64_start() - Start the remote processor
+ * @dev: rproc device pointer
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_arm64_start(struct udevice *dev)
+{
+ struct k3_arm64_privdata *rproc = dev_get_priv(dev);
+ ulong gtc_rate;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = power_domain_on(&rproc->gtc_pwrdmn);
+ if (ret) {
+ dev_err(dev, "power_domain_on() failed: %d\n", ret);
+ return ret;
+ }
+
+ gtc_rate = clk_get_rate(&rproc->gtc_clk);
+ dev_dbg(dev, "GTC RATE= %d\n", (u32) gtc_rate);
+ /* Store the clock frequency down for GTC users to pick up */
+ writel((u32)gtc_rate, rproc->gtc_base + GTC_CNTFID0_REG);
+
+ /* Enable the timer before starting remote core */
+ writel(GTC_CNTR_EN, rproc->gtc_base + GTC_CNTCR_REG);
+
+ /*
+ * Setting the right clock frequency would have taken care by
+ * assigned-clock-rates during the device probe. So no need to
+ * set the frequency again here.
+ */
+ ret = power_domain_on(&rproc->rproc_pwrdmn);
+ if (ret) {
+ dev_err(dev, "power_domain_on() failed: %d\n", ret);
+ return ret;
+ }
+
+ return ti_sci_proc_release(&rproc->tsp);
+}
+
+/**
+ * k3_arm64_init() - Initialize the remote processor
+ * @dev: rproc device pointer
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_arm64_init(struct udevice *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* Enable the module */
+ dev_dbg(dev, "%s: rproc successfully initialized\n", __func__);
+
+ return 0;
+}
+
+static const struct dm_rproc_ops k3_arm64_ops = {
+ .init = k3_arm64_init,
+ .load = k3_arm64_load,
+ .start = k3_arm64_start,
+};
+
+static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
+{
+ dev_dbg(dev, "%s\n", __func__);
+
+ tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
+ if (IS_ERR(tsp->sci)) {
+ dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
+ return PTR_ERR(tsp->sci);
+ }
+
+ tsp->proc_id = dev_read_u32_default(dev, "ti,sci-proc-id", INVALID_ID);
+ if (tsp->proc_id == INVALID_ID) {
+ dev_err(dev, "proc id not populated\n");
+ return -ENOENT;
+ }
+ tsp->host_id = dev_read_u32_default(dev, "ti,sci-host-id", INVALID_ID);
+ tsp->ops = &tsp->sci->ops.proc_ops;
+
+ return 0;
+}
+
+/**
+ * k3_of_to_priv() - generate private data from device tree
+ * @dev: corresponding k3 remote processor device
+ * @priv: pointer to driver specific private data
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_arm64_of_to_priv(struct udevice *dev,
+ struct k3_arm64_privdata *rproc)
+{
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = power_domain_get_by_index(dev, &rproc->rproc_pwrdmn, 1);
+ if (ret) {
+ dev_err(dev, "power_domain_get() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = power_domain_get_by_index(dev, &rproc->gtc_pwrdmn, 0);
+ if (ret) {
+ dev_err(dev, "power_domain_get() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_index(dev, 0, &rproc->gtc_clk);
+ if (ret) {
+ dev_err(dev, "clk_get failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_index(dev, 0, &rproc->rproc_rst);
+ if (ret) {
+ dev_err(dev, "reset_get() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = ti_sci_proc_of_to_priv(dev, &rproc->tsp);
+ if (ret)
+ return ret;
+
+ rproc->gtc_base = dev_read_addr_ptr(dev);
+ if (!rproc->gtc_base) {
+ dev_err(dev, "Get address failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * k3_arm64_probe() - Basic probe
+ * @dev: corresponding k3 remote processor device
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_arm64_probe(struct udevice *dev)
+{
+ struct k3_arm64_privdata *priv;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ priv = dev_get_priv(dev);
+
+ ret = k3_arm64_of_to_priv(dev, priv);
+ if (ret) {
+ dev_dbg(dev, "%s: Probe failed with error %d\n", __func__, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "Remoteproc successfully probed\n");
+
+ return 0;
+}
+
+static const struct udevice_id k3_arm64_ids[] = {
+ { .compatible = "ti,am654-arm64"},
+ { .compatible = "ti,am654-rproc"},
+ {}
+};
+
+U_BOOT_DRIVER(k3_arm64) = {
+ .name = "k3_arm64",
+ .of_match = k3_arm64_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &k3_arm64_ops,
+ .probe = k3_arm64_probe,
+ .priv_auto = sizeof(struct k3_arm64_privdata),
+ .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/roms/u-boot/drivers/remoteproc/ti_k3_dsp_rproc.c b/roms/u-boot/drivers/remoteproc/ti_k3_dsp_rproc.c
new file mode 100644
index 000000000..1a2e9dd1f
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/ti_k3_dsp_rproc.c
@@ -0,0 +1,460 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 DSP Remoteproc driver
+ *
+ * Copyright (C) 2018-2020 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <remoteproc.h>
+#include <errno.h>
+#include <clk.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <power-domain.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/sizes.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include "ti_sci_proc.h"
+
+#define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1)
+
+/**
+ * struct k3_dsp_mem - internal memory structure
+ * @cpu_addr: MPU virtual address of the memory region
+ * @bus_addr: Bus address used to access the memory region
+ * @dev_addr: Device address from remoteproc view
+ * @size: Size of the memory region
+ */
+struct k3_dsp_mem {
+ void __iomem *cpu_addr;
+ phys_addr_t bus_addr;
+ phys_addr_t dev_addr;
+ size_t size;
+};
+
+/**
+ * struct k3_dsp_boot_data - internal data structure used for boot
+ * @boot_align_addr: Boot vector address alignment granularity
+ * @uses_lreset: Flag to denote the need for local reset management
+ */
+struct k3_dsp_boot_data {
+ u32 boot_align_addr;
+ bool uses_lreset;
+};
+
+/**
+ * struct k3_dsp_privdata - Structure representing Remote processor data.
+ * @rproc_rst: rproc reset control data
+ * @tsp: Pointer to TISCI proc contrl handle
+ * @data: Pointer to DSP specific boot data structure
+ * @mem: Array of available memories
+ * @num_mem: Number of available memories
+ */
+struct k3_dsp_privdata {
+ struct reset_ctl dsp_rst;
+ struct ti_sci_proc tsp;
+ struct k3_dsp_boot_data *data;
+ struct k3_dsp_mem *mem;
+ int num_mems;
+};
+
+/*
+ * The C66x DSP cores have a local reset that affects only the CPU, and a
+ * generic module reset that powers on the device and allows the DSP internal
+ * memories to be accessed while the local reset is asserted. This function is
+ * used to release the global reset on C66x DSPs to allow loading into the DSP
+ * internal RAMs. This helper function is invoked in k3_dsp_load() before any
+ * actual firmware loading and is undone only in k3_dsp_stop(). The local reset
+ * on C71x cores is a no-op and the global reset cannot be released on C71x
+ * cores until after the firmware images are loaded, so this function does
+ * nothing for C71x cores.
+ */
+static int k3_dsp_prepare(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+ int ret;
+
+ /* local reset is no-op on C71x processors */
+ if (!data->uses_lreset)
+ return 0;
+
+ ret = ti_sci_proc_power_domain_on(&dsp->tsp);
+ if (ret)
+ dev_err(dev, "cannot enable internal RAM loading, ret = %d\n",
+ ret);
+
+ return ret;
+}
+
+/*
+ * This function is the counterpart to k3_dsp_prepare() and is used to assert
+ * the global reset on C66x DSP cores (no-op for C71x DSP cores). This completes
+ * the second step of powering down the C66x DSP cores. The cores themselves
+ * are halted through the local reset in first step. This function is invoked
+ * in k3_dsp_stop() after the local reset is asserted.
+ */
+static int k3_dsp_unprepare(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+
+ /* local reset is no-op on C71x processors */
+ if (!data->uses_lreset)
+ return 0;
+
+ return ti_sci_proc_power_domain_off(&dsp->tsp);
+}
+
+/**
+ * k3_dsp_load() - Load up the Remote processor image
+ * @dev: rproc device pointer
+ * @addr: Address at which image is available
+ * @size: size of the image
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+ u32 boot_vector;
+ int ret;
+
+ dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
+ ret = ti_sci_proc_request(&dsp->tsp);
+ if (ret)
+ return ret;
+
+ ret = k3_dsp_prepare(dev);
+ if (ret) {
+ dev_err(dev, "DSP prepare failed for core %d\n",
+ dsp->tsp.proc_id);
+ goto proc_release;
+ }
+
+ ret = rproc_elf_load_image(dev, addr, size);
+ if (ret < 0) {
+ dev_err(dev, "Loading elf failed %d\n", ret);
+ goto unprepare;
+ }
+
+ boot_vector = rproc_elf_get_boot_addr(dev, addr);
+ if (boot_vector & (data->boot_align_addr - 1)) {
+ ret = -EINVAL;
+ dev_err(dev, "Boot vector 0x%x not aligned on 0x%x boundary\n",
+ boot_vector, data->boot_align_addr);
+ goto proc_release;
+ }
+
+ dev_dbg(dev, "%s: Boot vector = 0x%x\n", __func__, boot_vector);
+
+ ret = ti_sci_proc_set_config(&dsp->tsp, boot_vector, 0, 0);
+unprepare:
+ if (ret)
+ k3_dsp_unprepare(dev);
+proc_release:
+ ti_sci_proc_release(&dsp->tsp);
+ return ret;
+}
+
+/**
+ * k3_dsp_start() - Start the remote processor
+ * @dev: rproc device pointer
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_dsp_start(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = ti_sci_proc_request(&dsp->tsp);
+ if (ret)
+ return ret;
+
+ if (!data->uses_lreset) {
+ ret = ti_sci_proc_power_domain_on(&dsp->tsp);
+ if (ret)
+ goto proc_release;
+ }
+
+ ret = reset_deassert(&dsp->dsp_rst);
+ if (ret) {
+ if (!data->uses_lreset)
+ ti_sci_proc_power_domain_off(&dsp->tsp);
+ }
+
+proc_release:
+ ti_sci_proc_release(&dsp->tsp);
+
+ return ret;
+}
+
+static int k3_dsp_stop(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ti_sci_proc_request(&dsp->tsp);
+ reset_assert(&dsp->dsp_rst);
+ ti_sci_proc_power_domain_off(&dsp->tsp);
+ ti_sci_proc_release(&dsp->tsp);
+
+ return 0;
+}
+
+/**
+ * k3_dsp_init() - Initialize the remote processor
+ * @dev: rproc device pointer
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_dsp_init(struct udevice *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
+}
+
+static int k3_dsp_reset(struct udevice *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
+}
+
+static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ phys_addr_t bus_addr, dev_addr;
+ void __iomem *va = NULL;
+ size_t size;
+ u32 offset;
+ int i;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (len <= 0)
+ return NULL;
+
+ for (i = 0; i < dsp->num_mems; i++) {
+ bus_addr = dsp->mem[i].bus_addr;
+ dev_addr = dsp->mem[i].dev_addr;
+ size = dsp->mem[i].size;
+
+ if (da >= dev_addr && ((da + len) <= (dev_addr + size))) {
+ offset = da - dev_addr;
+ va = dsp->mem[i].cpu_addr + offset;
+ return (__force void *)va;
+ }
+
+ if (da >= bus_addr && (da + len) <= (bus_addr + size)) {
+ offset = da - bus_addr;
+ va = dsp->mem[i].cpu_addr + offset;
+ return (__force void *)va;
+ }
+ }
+
+ /* Assume it is DDR region and return da */
+ return map_physmem(da, len, MAP_NOCACHE);
+}
+
+static const struct dm_rproc_ops k3_dsp_ops = {
+ .init = k3_dsp_init,
+ .load = k3_dsp_load,
+ .start = k3_dsp_start,
+ .stop = k3_dsp_stop,
+ .reset = k3_dsp_reset,
+ .device_to_virt = k3_dsp_da_to_va,
+};
+
+static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
+{
+ u32 ids[2];
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
+ if (IS_ERR(tsp->sci)) {
+ dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
+ return PTR_ERR(tsp->sci);
+ }
+
+ ret = dev_read_u32_array(dev, "ti,sci-proc-ids", ids, 2);
+ if (ret) {
+ dev_err(dev, "Proc IDs not populated %d\n", ret);
+ return ret;
+ }
+
+ tsp->ops = &tsp->sci->ops.proc_ops;
+ tsp->proc_id = ids[0];
+ tsp->host_id = ids[1];
+ tsp->dev_id = dev_read_u32_default(dev, "ti,sci-dev-id",
+ TI_SCI_RESOURCE_NULL);
+ if (tsp->dev_id == TI_SCI_RESOURCE_NULL) {
+ dev_err(dev, "Device ID not populated %d\n", ret);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int k3_dsp_of_get_memories(struct udevice *dev)
+{
+ static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"};
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ int i;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ dsp->num_mems = ARRAY_SIZE(mem_names);
+ dsp->mem = calloc(dsp->num_mems, sizeof(*dsp->mem));
+ if (!dsp->mem)
+ return -ENOMEM;
+
+ for (i = 0; i < dsp->num_mems; i++) {
+ /* C71 cores only have a L1P Cache, there are no L1P SRAMs */
+ if (device_is_compatible(dev, "ti,j721e-c71-dsp") &&
+ !strcmp(mem_names[i], "l1pram")) {
+ dsp->mem[i].bus_addr = FDT_ADDR_T_NONE;
+ dsp->mem[i].dev_addr = FDT_ADDR_T_NONE;
+ dsp->mem[i].cpu_addr = NULL;
+ dsp->mem[i].size = 0;
+ continue;
+ }
+
+ dsp->mem[i].bus_addr = dev_read_addr_size_name(dev, mem_names[i],
+ (fdt_addr_t *)&dsp->mem[i].size);
+ if (dsp->mem[i].bus_addr == FDT_ADDR_T_NONE) {
+ dev_err(dev, "%s bus address not found\n", mem_names[i]);
+ return -EINVAL;
+ }
+ dsp->mem[i].cpu_addr = map_physmem(dsp->mem[i].bus_addr,
+ dsp->mem[i].size,
+ MAP_NOCACHE);
+ dsp->mem[i].dev_addr = dsp->mem[i].bus_addr &
+ KEYSTONE_RPROC_LOCAL_ADDRESS_MASK;
+
+ dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %p da %pa\n",
+ mem_names[i], &dsp->mem[i].bus_addr,
+ dsp->mem[i].size, dsp->mem[i].cpu_addr,
+ &dsp->mem[i].dev_addr);
+ }
+
+ return 0;
+}
+
+/**
+ * k3_of_to_priv() - generate private data from device tree
+ * @dev: corresponding k3 dsp processor device
+ * @dsp: pointer to driver specific private data
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_dsp_of_to_priv(struct udevice *dev, struct k3_dsp_privdata *dsp)
+{
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = reset_get_by_index(dev, 0, &dsp->dsp_rst);
+ if (ret) {
+ dev_err(dev, "reset_get() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = ti_sci_proc_of_to_priv(dev, &dsp->tsp);
+ if (ret)
+ return ret;
+
+ ret = k3_dsp_of_get_memories(dev);
+ if (ret)
+ return ret;
+
+ dsp->data = (struct k3_dsp_boot_data *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+/**
+ * k3_dsp_probe() - Basic probe
+ * @dev: corresponding k3 remote processor device
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_dsp_probe(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ dsp = dev_get_priv(dev);
+
+ ret = k3_dsp_of_to_priv(dev, dsp);
+ if (ret) {
+ dev_dbg(dev, "%s: Probe failed with error %d\n", __func__, ret);
+ return ret;
+ }
+
+ /*
+ * The DSP local resets are deasserted by default on Power-On-Reset.
+ * Assert the local resets to ensure the DSPs don't execute bogus code
+ * in .load() callback when the module reset is released to support
+ * internal memory loading. This is needed for C66x DSPs, and is a
+ * no-op on C71x DSPs.
+ */
+ reset_assert(&dsp->dsp_rst);
+
+ dev_dbg(dev, "Remoteproc successfully probed\n");
+
+ return 0;
+}
+
+static int k3_dsp_remove(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+
+ free(dsp->mem);
+
+ return 0;
+}
+
+static const struct k3_dsp_boot_data c66_data = {
+ .boot_align_addr = SZ_1K,
+ .uses_lreset = true,
+};
+
+static const struct k3_dsp_boot_data c71_data = {
+ .boot_align_addr = SZ_2M,
+ .uses_lreset = false,
+};
+
+static const struct udevice_id k3_dsp_ids[] = {
+ { .compatible = "ti,j721e-c66-dsp", .data = (ulong)&c66_data, },
+ { .compatible = "ti,j721e-c71-dsp", .data = (ulong)&c71_data, },
+ {}
+};
+
+U_BOOT_DRIVER(k3_dsp) = {
+ .name = "k3_dsp",
+ .of_match = k3_dsp_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &k3_dsp_ops,
+ .probe = k3_dsp_probe,
+ .remove = k3_dsp_remove,
+ .priv_auto = sizeof(struct k3_dsp_privdata),
+};
diff --git a/roms/u-boot/drivers/remoteproc/ti_k3_r5f_rproc.c b/roms/u-boot/drivers/remoteproc/ti_k3_r5f_rproc.c
new file mode 100644
index 000000000..3c569a3b7
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -0,0 +1,906 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 R5 Remoteproc driver
+ *
+ * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <remoteproc.h>
+#include <errno.h>
+#include <clk.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include "ti_sci_proc.h"
+
+/*
+ * R5F's view of this address can either be for ATCM or BTCM with the other
+ * at address 0x0 based on loczrama signal.
+ */
+#define K3_R5_TCM_DEV_ADDR 0x41010000
+
+/* R5 TI-SCI Processor Configuration Flags */
+#define PROC_BOOT_CFG_FLAG_R5_DBG_EN 0x00000001
+#define PROC_BOOT_CFG_FLAG_R5_DBG_NIDEN 0x00000002
+#define PROC_BOOT_CFG_FLAG_R5_LOCKSTEP 0x00000100
+#define PROC_BOOT_CFG_FLAG_R5_TEINIT 0x00000200
+#define PROC_BOOT_CFG_FLAG_R5_NMFI_EN 0x00000400
+#define PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE 0x00000800
+#define PROC_BOOT_CFG_FLAG_R5_BTCM_EN 0x00001000
+#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000
+#define PROC_BOOT_CFG_FLAG_GEN_IGN_BOOTVECTOR 0x10000000
+/* Available from J7200 SoCs onwards */
+#define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000
+
+/* R5 TI-SCI Processor Control Flags */
+#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
+
+/* R5 TI-SCI Processor Status Flags */
+#define PROC_BOOT_STATUS_FLAG_R5_WFE 0x00000001
+#define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002
+#define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004
+#define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100
+
+#define NR_CORES 2
+
+enum cluster_mode {
+ CLUSTER_MODE_SPLIT = 0,
+ CLUSTER_MODE_LOCKSTEP,
+};
+
+/**
+ * struct k3_r5f_ip_data - internal data structure used for IP variations
+ * @tcm_is_double: flag to denote the larger unified TCMs in certain modes
+ * @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC
+ */
+struct k3_r5f_ip_data {
+ bool tcm_is_double;
+ bool tcm_ecc_autoinit;
+};
+
+/**
+ * struct k3_r5_mem - internal memory structure
+ * @cpu_addr: MPU virtual address of the memory region
+ * @bus_addr: Bus address used to access the memory region
+ * @dev_addr: Device address from remoteproc view
+ * @size: Size of the memory region
+ */
+struct k3_r5f_mem {
+ void __iomem *cpu_addr;
+ phys_addr_t bus_addr;
+ u32 dev_addr;
+ size_t size;
+};
+
+/**
+ * struct k3_r5f_core - K3 R5 core structure
+ * @dev: cached device pointer
+ * @cluster: pointer to the parent cluster.
+ * @reset: reset control handle
+ * @tsp: TI-SCI processor control handle
+ * @ipdata: cached pointer to R5F IP specific feature data
+ * @mem: Array of available internal memories
+ * @num_mem: Number of available memories
+ * @atcm_enable: flag to control ATCM enablement
+ * @btcm_enable: flag to control BTCM enablement
+ * @loczrama: flag to dictate which TCM is at device address 0x0
+ * @in_use: flag to tell if the core is already in use.
+ */
+struct k3_r5f_core {
+ struct udevice *dev;
+ struct k3_r5f_cluster *cluster;
+ struct reset_ctl reset;
+ struct ti_sci_proc tsp;
+ struct k3_r5f_ip_data *ipdata;
+ struct k3_r5f_mem *mem;
+ int num_mems;
+ u32 atcm_enable;
+ u32 btcm_enable;
+ u32 loczrama;
+ bool in_use;
+};
+
+/**
+ * struct k3_r5f_cluster - K3 R5F Cluster structure
+ * @mode: Mode to configure the Cluster - Split or LockStep
+ * @cores: Array of pointers to R5 cores within the cluster
+ */
+struct k3_r5f_cluster {
+ enum cluster_mode mode;
+ struct k3_r5f_core *cores[NR_CORES];
+};
+
+static bool is_primary_core(struct k3_r5f_core *core)
+{
+ return core == core->cluster->cores[0];
+}
+
+static int k3_r5f_proc_request(struct k3_r5f_core *core)
+{
+ struct k3_r5f_cluster *cluster = core->cluster;
+ int i, ret;
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
+ for (i = 0; i < NR_CORES; i++) {
+ ret = ti_sci_proc_request(&cluster->cores[i]->tsp);
+ if (ret)
+ goto proc_release;
+ }
+ } else {
+ ret = ti_sci_proc_request(&core->tsp);
+ }
+
+ return 0;
+
+proc_release:
+ while (i >= 0) {
+ ti_sci_proc_release(&cluster->cores[i]->tsp);
+ i--;
+ }
+ return ret;
+}
+
+static void k3_r5f_proc_release(struct k3_r5f_core *core)
+{
+ struct k3_r5f_cluster *cluster = core->cluster;
+ int i;
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
+ for (i = 0; i < NR_CORES; i++)
+ ti_sci_proc_release(&cluster->cores[i]->tsp);
+ else
+ ti_sci_proc_release(&core->tsp);
+}
+
+static int k3_r5f_lockstep_release(struct k3_r5f_cluster *cluster)
+{
+ int ret, c;
+
+ debug("%s\n", __func__);
+
+ for (c = NR_CORES - 1; c >= 0; c--) {
+ ret = ti_sci_proc_power_domain_on(&cluster->cores[c]->tsp);
+ if (ret)
+ goto unroll_module_reset;
+ }
+
+ /* deassert local reset on all applicable cores */
+ for (c = NR_CORES - 1; c >= 0; c--) {
+ ret = reset_deassert(&cluster->cores[c]->reset);
+ if (ret)
+ goto unroll_local_reset;
+ }
+
+ return 0;
+
+unroll_local_reset:
+ while (c < NR_CORES) {
+ reset_assert(&cluster->cores[c]->reset);
+ c++;
+ }
+ c = 0;
+unroll_module_reset:
+ while (c < NR_CORES) {
+ ti_sci_proc_power_domain_off(&cluster->cores[c]->tsp);
+ c++;
+ }
+
+ return ret;
+}
+
+static int k3_r5f_split_release(struct k3_r5f_core *core)
+{
+ int ret;
+
+ dev_dbg(core->dev, "%s\n", __func__);
+
+ ret = ti_sci_proc_power_domain_on(&core->tsp);
+ if (ret) {
+ dev_err(core->dev, "module-reset deassert failed, ret = %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = reset_deassert(&core->reset);
+ if (ret) {
+ dev_err(core->dev, "local-reset deassert failed, ret = %d\n",
+ ret);
+ if (ti_sci_proc_power_domain_off(&core->tsp))
+ dev_warn(core->dev, "module-reset assert back failed\n");
+ }
+
+ return ret;
+}
+
+static int k3_r5f_prepare(struct udevice *dev)
+{
+ struct k3_r5f_core *core = dev_get_priv(dev);
+ struct k3_r5f_cluster *cluster = core->cluster;
+ int ret = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
+ ret = k3_r5f_lockstep_release(cluster);
+ else
+ ret = k3_r5f_split_release(core);
+
+ if (ret)
+ dev_err(dev, "Unable to enable cores for TCM loading %d\n",
+ ret);
+
+ return ret;
+}
+
+static int k3_r5f_core_sanity_check(struct k3_r5f_core *core)
+{
+ struct k3_r5f_cluster *cluster = core->cluster;
+
+ if (core->in_use) {
+ dev_err(core->dev,
+ "Invalid op: Trying to load/start on already running core %d\n",
+ core->tsp.proc_id);
+ return -EINVAL;
+ }
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !cluster->cores[1]) {
+ dev_err(core->dev,
+ "Secondary core is not probed in this cluster\n");
+ return -EAGAIN;
+ }
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !is_primary_core(core)) {
+ dev_err(core->dev,
+ "Invalid op: Trying to start secondary core %d in lockstep mode\n",
+ core->tsp.proc_id);
+ return -EINVAL;
+ }
+
+ if (cluster->mode == CLUSTER_MODE_SPLIT && !is_primary_core(core)) {
+ if (!core->cluster->cores[0]->in_use) {
+ dev_err(core->dev,
+ "Invalid seq: Enable primary core before loading secondary core\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/* Zero out TCMs so that ECC can be effective on all TCM addresses */
+void k3_r5f_init_tcm_memories(struct k3_r5f_core *core, bool auto_inited)
+{
+ if (core->ipdata->tcm_ecc_autoinit && auto_inited)
+ return;
+
+ if (core->atcm_enable)
+ memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size);
+ if (core->btcm_enable)
+ memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size);
+}
+
+/**
+ * k3_r5f_load() - Load up the Remote processor image
+ * @dev: rproc device pointer
+ * @addr: Address at which image is available
+ * @size: size of the image
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct k3_r5f_core *core = dev_get_priv(dev);
+ u64 boot_vector;
+ u32 ctrl, sts, cfg = 0;
+ bool mem_auto_init;
+ int ret;
+
+ dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
+
+ ret = k3_r5f_core_sanity_check(core);
+ if (ret)
+ return ret;
+
+ ret = k3_r5f_proc_request(core);
+ if (ret)
+ return ret;
+
+ ret = ti_sci_proc_get_status(&core->tsp, &boot_vector, &cfg, &ctrl,
+ &sts);
+ if (ret)
+ return ret;
+ mem_auto_init = !(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS);
+
+ ret = k3_r5f_prepare(dev);
+ if (ret) {
+ dev_err(dev, "R5f prepare failed for core %d\n",
+ core->tsp.proc_id);
+ goto proc_release;
+ }
+
+ k3_r5f_init_tcm_memories(core, mem_auto_init);
+
+ ret = rproc_elf_load_image(dev, addr, size);
+ if (ret < 0) {
+ dev_err(dev, "Loading elf failedi %d\n", ret);
+ goto proc_release;
+ }
+
+ boot_vector = rproc_elf_get_boot_addr(dev, addr);
+
+ dev_dbg(dev, "%s: Boot vector = 0x%llx\n", __func__, boot_vector);
+
+ ret = ti_sci_proc_set_config(&core->tsp, boot_vector, 0, 0);
+
+proc_release:
+ k3_r5f_proc_release(core);
+
+ return ret;
+}
+
+static int k3_r5f_core_halt(struct k3_r5f_core *core)
+{
+ int ret;
+
+ ret = ti_sci_proc_set_control(&core->tsp,
+ PROC_BOOT_CTRL_FLAG_R5_CORE_HALT, 0);
+ if (ret)
+ dev_err(core->dev, "Core %d failed to stop\n",
+ core->tsp.proc_id);
+
+ return ret;
+}
+
+static int k3_r5f_core_run(struct k3_r5f_core *core)
+{
+ int ret;
+
+ ret = ti_sci_proc_set_control(&core->tsp,
+ 0, PROC_BOOT_CTRL_FLAG_R5_CORE_HALT);
+ if (ret) {
+ dev_err(core->dev, "Core %d failed to start\n",
+ core->tsp.proc_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * k3_r5f_start() - Start the remote processor
+ * @dev: rproc device pointer
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_r5f_start(struct udevice *dev)
+{
+ struct k3_r5f_core *core = dev_get_priv(dev);
+ struct k3_r5f_cluster *cluster = core->cluster;
+ int ret, c;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = k3_r5f_core_sanity_check(core);
+ if (ret)
+ return ret;
+
+ ret = k3_r5f_proc_request(core);
+ if (ret)
+ return ret;
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
+ if (is_primary_core(core)) {
+ for (c = NR_CORES - 1; c >= 0; c--) {
+ ret = k3_r5f_core_run(cluster->cores[c]);
+ if (ret)
+ goto unroll_core_run;
+ }
+ } else {
+ dev_err(dev, "Invalid op: Trying to start secondary core %d in lockstep mode\n",
+ core->tsp.proc_id);
+ ret = -EINVAL;
+ goto proc_release;
+ }
+ } else {
+ ret = k3_r5f_core_run(core);
+ if (ret)
+ goto proc_release;
+ }
+
+ core->in_use = true;
+
+ k3_r5f_proc_release(core);
+ return 0;
+
+unroll_core_run:
+ while (c < NR_CORES) {
+ k3_r5f_core_halt(cluster->cores[c]);
+ c++;
+ }
+proc_release:
+ k3_r5f_proc_release(core);
+
+ return ret;
+}
+
+static int k3_r5f_split_reset(struct k3_r5f_core *core)
+{
+ int ret;
+
+ dev_dbg(core->dev, "%s\n", __func__);
+
+ if (reset_assert(&core->reset))
+ ret = -EINVAL;
+
+ if (ti_sci_proc_power_domain_off(&core->tsp))
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int k3_r5f_lockstep_reset(struct k3_r5f_cluster *cluster)
+{
+ int ret = 0, c;
+
+ debug("%s\n", __func__);
+
+ for (c = 0; c < NR_CORES; c++)
+ if (reset_assert(&cluster->cores[c]->reset))
+ ret = -EINVAL;
+
+ /* disable PSC modules on all applicable cores */
+ for (c = 0; c < NR_CORES; c++)
+ if (ti_sci_proc_power_domain_off(&cluster->cores[c]->tsp))
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int k3_r5f_unprepare(struct udevice *dev)
+{
+ struct k3_r5f_core *core = dev_get_priv(dev);
+ struct k3_r5f_cluster *cluster = core->cluster;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
+ if (is_primary_core(core))
+ ret = k3_r5f_lockstep_reset(cluster);
+ } else {
+ ret = k3_r5f_split_reset(core);
+ }
+
+ if (ret)
+ dev_warn(dev, "Unable to enable cores for TCM loading %d\n",
+ ret);
+
+ return 0;
+}
+
+static int k3_r5f_stop(struct udevice *dev)
+{
+ struct k3_r5f_core *core = dev_get_priv(dev);
+ struct k3_r5f_cluster *cluster = core->cluster;
+ int c, ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = k3_r5f_proc_request(core);
+ if (ret)
+ return ret;
+
+ core->in_use = false;
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
+ if (is_primary_core(core)) {
+ for (c = 0; c < NR_CORES; c++)
+ k3_r5f_core_halt(cluster->cores[c]);
+ } else {
+ dev_err(dev, "Invalid op: Trying to stop secondary core in lockstep mode\n");
+ ret = -EINVAL;
+ goto proc_release;
+ }
+ } else {
+ k3_r5f_core_halt(core);
+ }
+
+ ret = k3_r5f_unprepare(dev);
+proc_release:
+ k3_r5f_proc_release(core);
+ return ret;
+}
+
+static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size)
+{
+ struct k3_r5f_core *core = dev_get_priv(dev);
+ void __iomem *va = NULL;
+ phys_addr_t bus_addr;
+ u32 dev_addr, offset;
+ ulong mem_size;
+ int i;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (size <= 0)
+ return NULL;
+
+ for (i = 0; i < core->num_mems; i++) {
+ bus_addr = core->mem[i].bus_addr;
+ dev_addr = core->mem[i].dev_addr;
+ mem_size = core->mem[i].size;
+
+ if (da >= bus_addr && (da + size) <= (bus_addr + mem_size)) {
+ offset = da - bus_addr;
+ va = core->mem[i].cpu_addr + offset;
+ return (__force void *)va;
+ }
+
+ if (da >= dev_addr && (da + size) <= (dev_addr + mem_size)) {
+ offset = da - dev_addr;
+ va = core->mem[i].cpu_addr + offset;
+ return (__force void *)va;
+ }
+ }
+
+ /* Assume it is DDR region and return da */
+ return map_physmem(da, size, MAP_NOCACHE);
+}
+
+static int k3_r5f_init(struct udevice *dev)
+{
+ return 0;
+}
+
+static int k3_r5f_reset(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct dm_rproc_ops k3_r5f_rproc_ops = {
+ .init = k3_r5f_init,
+ .reset = k3_r5f_reset,
+ .start = k3_r5f_start,
+ .stop = k3_r5f_stop,
+ .load = k3_r5f_load,
+ .device_to_virt = k3_r5f_da_to_va,
+};
+
+static int k3_r5f_rproc_configure(struct k3_r5f_core *core)
+{
+ struct k3_r5f_cluster *cluster = core->cluster;
+ u32 set_cfg = 0, clr_cfg = 0, cfg, ctrl, sts;
+ bool lockstep_permitted;
+ u64 boot_vec = 0;
+ int ret;
+
+ dev_dbg(core->dev, "%s\n", __func__);
+
+ ret = ti_sci_proc_request(&core->tsp);
+ if (ret < 0)
+ return ret;
+
+ /* Do not touch boot vector now. Load will take care of it. */
+ clr_cfg |= PROC_BOOT_CFG_FLAG_GEN_IGN_BOOTVECTOR;
+
+ ret = ti_sci_proc_get_status(&core->tsp, &boot_vec, &cfg, &ctrl, &sts);
+ if (ret)
+ goto out;
+
+ /* Sanity check for Lockstep mode */
+ lockstep_permitted = !!(sts &
+ PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED);
+ if (cluster->mode && is_primary_core(core) && !lockstep_permitted) {
+ dev_err(core->dev, "LockStep mode not permitted on this device\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Primary core only configuration */
+ if (is_primary_core(core)) {
+ /* always enable ARM mode */
+ clr_cfg |= PROC_BOOT_CFG_FLAG_R5_TEINIT;
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
+ set_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
+ else if (lockstep_permitted)
+ clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
+ }
+
+ if (core->atcm_enable)
+ set_cfg |= PROC_BOOT_CFG_FLAG_R5_ATCM_EN;
+ else
+ clr_cfg |= PROC_BOOT_CFG_FLAG_R5_ATCM_EN;
+
+ if (core->btcm_enable)
+ set_cfg |= PROC_BOOT_CFG_FLAG_R5_BTCM_EN;
+ else
+ clr_cfg |= PROC_BOOT_CFG_FLAG_R5_BTCM_EN;
+
+ if (core->loczrama)
+ set_cfg |= PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE;
+ else
+ clr_cfg |= PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE;
+
+ ret = k3_r5f_core_halt(core);
+ if (ret)
+ goto out;
+
+ ret = ti_sci_proc_set_config(&core->tsp, boot_vec, set_cfg, clr_cfg);
+out:
+ ti_sci_proc_release(&core->tsp);
+ return ret;
+}
+
+static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
+{
+ u32 ids[2];
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
+ if (IS_ERR(tsp->sci)) {
+ dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
+ return PTR_ERR(tsp->sci);
+ }
+
+ ret = dev_read_u32_array(dev, "ti,sci-proc-ids", ids, 2);
+ if (ret) {
+ dev_err(dev, "Proc IDs not populated %d\n", ret);
+ return ret;
+ }
+
+ tsp->ops = &tsp->sci->ops.proc_ops;
+ tsp->proc_id = ids[0];
+ tsp->host_id = ids[1];
+ tsp->dev_id = dev_read_u32_default(dev, "ti,sci-dev-id",
+ TI_SCI_RESOURCE_NULL);
+ if (tsp->dev_id == TI_SCI_RESOURCE_NULL) {
+ dev_err(dev, "Device ID not populated %d\n", ret);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int k3_r5f_of_to_priv(struct k3_r5f_core *core)
+{
+ int ret;
+
+ dev_dbg(core->dev, "%s\n", __func__);
+
+ core->atcm_enable = dev_read_u32_default(core->dev, "ti,atcm-enable", 0);
+ core->btcm_enable = dev_read_u32_default(core->dev, "ti,btcm-enable", 1);
+ core->loczrama = dev_read_u32_default(core->dev, "ti,loczrama", 1);
+
+ ret = ti_sci_proc_of_to_priv(core->dev, &core->tsp);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_index(core->dev, 0, &core->reset);
+ if (ret) {
+ dev_err(core->dev, "Reset lines not available: %d\n", ret);
+ return ret;
+ }
+
+ core->ipdata = (struct k3_r5f_ip_data *)dev_get_driver_data(core->dev);
+
+ return 0;
+}
+
+static int k3_r5f_core_of_get_memories(struct k3_r5f_core *core)
+{
+ static const char * const mem_names[] = {"atcm", "btcm"};
+ struct udevice *dev = core->dev;
+ int i;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ core->num_mems = ARRAY_SIZE(mem_names);
+ core->mem = calloc(core->num_mems, sizeof(*core->mem));
+ if (!core->mem)
+ return -ENOMEM;
+
+ for (i = 0; i < core->num_mems; i++) {
+ core->mem[i].bus_addr = dev_read_addr_size_name(dev,
+ mem_names[i],
+ (fdt_addr_t *)&core->mem[i].size);
+ if (core->mem[i].bus_addr == FDT_ADDR_T_NONE) {
+ dev_err(dev, "%s bus address not found\n",
+ mem_names[i]);
+ return -EINVAL;
+ }
+ core->mem[i].cpu_addr = map_physmem(core->mem[i].bus_addr,
+ core->mem[i].size,
+ MAP_NOCACHE);
+ if (!strcmp(mem_names[i], "atcm")) {
+ core->mem[i].dev_addr = core->loczrama ?
+ 0 : K3_R5_TCM_DEV_ADDR;
+ } else {
+ core->mem[i].dev_addr = core->loczrama ?
+ K3_R5_TCM_DEV_ADDR : 0;
+ }
+
+ dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %p da 0x%x\n",
+ mem_names[i], &core->mem[i].bus_addr,
+ core->mem[i].size, core->mem[i].cpu_addr,
+ core->mem[i].dev_addr);
+ }
+
+ return 0;
+}
+
+/*
+ * Each R5F core within a typical R5FSS instance has a total of 64 KB of TCMs,
+ * split equally into two 32 KB banks between ATCM and BTCM. The TCMs from both
+ * cores are usable in Split-mode, but only the Core0 TCMs can be used in
+ * LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by
+ * leveraging the Core1 TCMs as well in certain modes where they would have
+ * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs). This is done by
+ * making a Core1 TCM visible immediately after the corresponding Core0 TCM.
+ * The SoC memory map uses the larger 64 KB sizes for the Core0 TCMs, and the
+ * dts representation reflects this increased size on supported SoCs. The Core0
+ * TCM sizes therefore have to be adjusted to only half the original size in
+ * Split mode.
+ */
+static void k3_r5f_core_adjust_tcm_sizes(struct k3_r5f_core *core)
+{
+ struct k3_r5f_cluster *cluster = core->cluster;
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
+ return;
+
+ if (!core->ipdata->tcm_is_double)
+ return;
+
+ if (core == cluster->cores[0]) {
+ core->mem[0].size /= 2;
+ core->mem[1].size /= 2;
+
+ dev_dbg(core->dev, "adjusted TCM sizes, ATCM = 0x%zx BTCM = 0x%zx\n",
+ core->mem[0].size, core->mem[1].size);
+ }
+}
+
+/**
+ * k3_r5f_probe() - Basic probe
+ * @dev: corresponding k3 remote processor device
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_r5f_probe(struct udevice *dev)
+{
+ struct k3_r5f_cluster *cluster = dev_get_priv(dev->parent);
+ struct k3_r5f_core *core = dev_get_priv(dev);
+ bool r_state;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ core->dev = dev;
+ ret = k3_r5f_of_to_priv(core);
+ if (ret)
+ return ret;
+
+ core->cluster = cluster;
+ /* Assume Primary core gets probed first */
+ if (!cluster->cores[0])
+ cluster->cores[0] = core;
+ else
+ cluster->cores[1] = core;
+
+ ret = k3_r5f_core_of_get_memories(core);
+ if (ret) {
+ dev_err(dev, "Rproc getting internal memories failed\n");
+ return ret;
+ }
+
+ ret = core->tsp.sci->ops.dev_ops.is_on(core->tsp.sci, core->tsp.dev_id,
+ &r_state, &core->in_use);
+ if (ret)
+ return ret;
+
+ if (core->in_use) {
+ dev_info(dev, "Core %d is already in use. No rproc commands work\n",
+ core->tsp.proc_id);
+ return 0;
+ }
+
+ /* Make sure Local reset is asserted. Redundant? */
+ reset_assert(&core->reset);
+
+ ret = k3_r5f_rproc_configure(core);
+ if (ret) {
+ dev_err(dev, "rproc configure failed %d\n", ret);
+ return ret;
+ }
+
+ k3_r5f_core_adjust_tcm_sizes(core);
+
+ dev_dbg(dev, "Remoteproc successfully probed\n");
+
+ return 0;
+}
+
+static int k3_r5f_remove(struct udevice *dev)
+{
+ struct k3_r5f_core *core = dev_get_priv(dev);
+
+ free(core->mem);
+
+ ti_sci_proc_release(&core->tsp);
+
+ return 0;
+}
+
+static const struct k3_r5f_ip_data k3_data = {
+ .tcm_is_double = false,
+ .tcm_ecc_autoinit = false,
+};
+
+static const struct k3_r5f_ip_data j7200_data = {
+ .tcm_is_double = true,
+ .tcm_ecc_autoinit = true,
+};
+
+static const struct udevice_id k3_r5f_rproc_ids[] = {
+ { .compatible = "ti,am654-r5f", .data = (ulong)&k3_data, },
+ { .compatible = "ti,j721e-r5f", .data = (ulong)&k3_data, },
+ { .compatible = "ti,j7200-r5f", .data = (ulong)&j7200_data, },
+ {}
+};
+
+U_BOOT_DRIVER(k3_r5f_rproc) = {
+ .name = "k3_r5f_rproc",
+ .of_match = k3_r5f_rproc_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &k3_r5f_rproc_ops,
+ .probe = k3_r5f_probe,
+ .remove = k3_r5f_remove,
+ .priv_auto = sizeof(struct k3_r5f_core),
+};
+
+static int k3_r5f_cluster_probe(struct udevice *dev)
+{
+ struct k3_r5f_cluster *cluster = dev_get_priv(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ cluster->mode = dev_read_u32_default(dev, "ti,cluster-mode",
+ CLUSTER_MODE_LOCKSTEP);
+
+ if (device_get_child_count(dev) != 2) {
+ dev_err(dev, "Invalid number of R5 cores");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "%s: Cluster successfully probed in %s mode\n",
+ __func__, cluster->mode ? "lockstep" : "split");
+
+ return 0;
+}
+
+static const struct udevice_id k3_r5fss_ids[] = {
+ { .compatible = "ti,am654-r5fss"},
+ { .compatible = "ti,j721e-r5fss"},
+ { .compatible = "ti,j7200-r5fss"},
+ {}
+};
+
+U_BOOT_DRIVER(k3_r5fss) = {
+ .name = "k3_r5fss",
+ .of_match = k3_r5fss_ids,
+ .id = UCLASS_MISC,
+ .probe = k3_r5f_cluster_probe,
+ .priv_auto = sizeof(struct k3_r5f_cluster),
+ .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/roms/u-boot/drivers/remoteproc/ti_power_proc.c b/roms/u-boot/drivers/remoteproc/ti_power_proc.c
new file mode 100644
index 000000000..86d544cc8
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/ti_power_proc.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015-2016
+ * Texas Instruments Incorporated - http://www.ti.com/
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <remoteproc.h>
+#include <asm/global_data.h>
+#include <mach/psc_defs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct ti_powerproc_privdata - power processor private data
+ * @loadaddr: base address for loading the power processor
+ * @psc_module: psc module address.
+ */
+struct ti_powerproc_privdata {
+ phys_addr_t loadaddr;
+ u32 psc_module;
+};
+
+/**
+ * ti_of_to_priv() - generate private data from device tree
+ * @dev: corresponding ti remote processor device
+ * @priv: pointer to driver specific private data
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int ti_of_to_priv(struct udevice *dev,
+ struct ti_powerproc_privdata *priv)
+{
+ int node = dev_of_offset(dev);
+ const void *blob = gd->fdt_blob;
+ int tmp;
+
+ if (!blob) {
+ debug("'%s' no dt?\n", dev->name);
+ return -EINVAL;
+ }
+
+ priv->loadaddr = fdtdec_get_addr(blob, node, "reg");
+ if (priv->loadaddr == FDT_ADDR_T_NONE) {
+ debug("'%s': no 'reg' property\n", dev->name);
+ return -EINVAL;
+ }
+
+ tmp = fdtdec_get_int(blob, node, "ti,lpsc_module", -EINVAL);
+ if (tmp < 0) {
+ debug("'%s': no 'ti,lpsc_module' property\n", dev->name);
+ return tmp;
+ }
+ priv->psc_module = tmp;
+
+ return 0;
+}
+
+/**
+ * ti_powerproc_probe() - Basic probe
+ * @dev: corresponding ti remote processor device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int ti_powerproc_probe(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ struct ti_powerproc_privdata *priv;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ priv = dev_get_priv(dev);
+
+ ret = ti_of_to_priv(dev, priv);
+
+ debug("%s probed with slave_addr=0x%08lX module=%d(%d)\n",
+ uc_pdata->name, priv->loadaddr, priv->psc_module, ret);
+
+ return ret;
+}
+
+/**
+ * ti_powerproc_load() - Loadup the TI remote processor
+ * @dev: corresponding ti remote processor device
+ * @addr: Address in memory where image binary is stored
+ * @size: Size in bytes of the image binary
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int ti_powerproc_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ struct ti_powerproc_privdata *priv;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata) {
+ debug("%s: no uc pdata!\n", dev->name);
+ return -EINVAL;
+ }
+
+ priv = dev_get_priv(dev);
+ ret = psc_module_keep_in_reset_enabled(priv->psc_module, false);
+ if (ret) {
+ debug("%s Unable to disable module '%d'(ret=%d)\n",
+ uc_pdata->name, priv->psc_module, ret);
+ return ret;
+ }
+
+ debug("%s: Loading binary from 0x%08lX, size 0x%08lX to 0x%08lX\n",
+ uc_pdata->name, addr, size, priv->loadaddr);
+
+ memcpy((void *)priv->loadaddr, (void *)addr, size);
+
+ debug("%s: Complete!\n", uc_pdata->name);
+ return 0;
+}
+
+/**
+ * ti_powerproc_start() - (replace: short desc)
+ * @dev: corresponding ti remote processor device
+ *
+ * Return: 0 if all went ok, else corresponding -ve error
+ */
+static int ti_powerproc_start(struct udevice *dev)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ struct ti_powerproc_privdata *priv;
+ int ret;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata) {
+ debug("%s: no uc pdata!\n", dev->name);
+ return -EINVAL;
+ }
+
+ priv = dev_get_priv(dev);
+ ret = psc_disable_module(priv->psc_module);
+ if (ret) {
+ debug("%s Unable to disable module '%d'(ret=%d)\n",
+ uc_pdata->name, priv->psc_module, ret);
+ return ret;
+ }
+
+ ret = psc_module_release_from_reset(priv->psc_module);
+ if (ret) {
+ debug("%s Failed to wait for module '%d'(ret=%d)\n",
+ uc_pdata->name, priv->psc_module, ret);
+ return ret;
+ }
+ ret = psc_enable_module(priv->psc_module);
+ if (ret) {
+ debug("%s Unable to disable module '%d'(ret=%d)\n",
+ uc_pdata->name, priv->psc_module, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_rproc_ops ti_powerproc_ops = {
+ .load = ti_powerproc_load,
+ .start = ti_powerproc_start,
+};
+
+static const struct udevice_id ti_powerproc_ids[] = {
+ {.compatible = "ti,power-processor"},
+ {}
+};
+
+U_BOOT_DRIVER(ti_powerproc) = {
+ .name = "ti_power_proc",
+ .of_match = ti_powerproc_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &ti_powerproc_ops,
+ .probe = ti_powerproc_probe,
+ .priv_auto = sizeof(struct ti_powerproc_privdata),
+};
diff --git a/roms/u-boot/drivers/remoteproc/ti_sci_proc.h b/roms/u-boot/drivers/remoteproc/ti_sci_proc.h
new file mode 100644
index 000000000..f8299d1af
--- /dev/null
+++ b/roms/u-boot/drivers/remoteproc/ti_sci_proc.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Texas Instruments TI-SCI Processor Controller Helper Functions
+ *
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ */
+
+#ifndef REMOTEPROC_TI_SCI_PROC_H
+#define REMOTEPROC_TI_SCI_PROC_H
+
+#define TISCI_INVALID_HOST 0xff
+
+/**
+ * struct ti_sci_proc - structure representing a processor control client
+ * @sci: cached TI-SCI protocol handle
+ * @ops: cached TI-SCI proc ops
+ * @proc_id: processor id for the consumer remoteproc device
+ * @host_id: host id to pass the control over for this consumer remoteproc
+ * device
+ * @dev_id: Device ID as identified by system controller.
+ */
+struct ti_sci_proc {
+ const struct ti_sci_handle *sci;
+ const struct ti_sci_proc_ops *ops;
+ u8 proc_id;
+ u8 host_id;
+ u16 dev_id;
+};
+
+static inline int ti_sci_proc_request(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
+
+ ret = tsp->ops->proc_request(tsp->sci, tsp->proc_id);
+ if (ret)
+ pr_err("ti-sci processor request failed: %d\n", ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_release(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
+
+ if (tsp->host_id != TISCI_INVALID_HOST)
+ ret = tsp->ops->proc_handover(tsp->sci, tsp->proc_id,
+ tsp->host_id);
+ else
+ ret = tsp->ops->proc_release(tsp->sci, tsp->proc_id);
+
+ if (ret)
+ pr_err("ti-sci processor release failed: %d\n", ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_handover(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
+
+ ret = tsp->ops->proc_handover(tsp->sci, tsp->proc_id, tsp->host_id);
+ if (ret)
+ pr_err("ti-sci processor handover of %d to %d failed: %d\n",
+ tsp->proc_id, tsp->host_id, ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_get_status(struct ti_sci_proc *tsp,
+ u64 *boot_vector, u32 *cfg_flags,
+ u32 *ctrl_flags, u32 *status_flags)
+{
+ int ret;
+
+ ret = tsp->ops->get_proc_boot_status(tsp->sci, tsp->proc_id,
+ boot_vector, cfg_flags, ctrl_flags,
+ status_flags);
+ if (ret)
+ pr_err("ti-sci processor get_status failed: %d\n", ret);
+
+ debug("%s: proc_id = %d, boot_vector = 0x%llx, cfg_flags = 0x%x, ctrl_flags = 0x%x, sts = 0x%x\n",
+ __func__, tsp->proc_id, *boot_vector, *cfg_flags, *ctrl_flags,
+ *status_flags);
+ return ret;
+}
+
+static inline int ti_sci_proc_set_config(struct ti_sci_proc *tsp,
+ u64 boot_vector,
+ u32 cfg_set, u32 cfg_clr)
+{
+ int ret;
+
+ debug("%s: proc_id = %d, boot_vector = 0x%llx, cfg_set = 0x%x, cfg_clr = 0x%x\n",
+ __func__, tsp->proc_id, boot_vector, cfg_set, cfg_clr);
+
+ ret = tsp->ops->set_proc_boot_cfg(tsp->sci, tsp->proc_id, boot_vector,
+ cfg_set, cfg_clr);
+ if (ret)
+ pr_err("ti-sci processor set_config failed: %d\n", ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_set_control(struct ti_sci_proc *tsp,
+ u32 ctrl_set, u32 ctrl_clr)
+{
+ int ret;
+
+ debug("%s: proc_id = %d, ctrl_set = 0x%x, ctrl_clr = 0x%x\n", __func__,
+ tsp->proc_id, ctrl_set, ctrl_clr);
+
+ ret = tsp->ops->set_proc_boot_ctrl(tsp->sci, tsp->proc_id, ctrl_set,
+ ctrl_clr);
+ if (ret)
+ pr_err("ti-sci processor set_control failed: %d\n", ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_power_domain_on(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: dev_id = %d\n", __func__, tsp->dev_id);
+
+ ret = tsp->sci->ops.dev_ops.get_device_exclusive(tsp->sci, tsp->dev_id);
+ if (ret)
+ pr_err("Power-domain on failed for dev = %d\n", tsp->dev_id);
+
+ return ret;
+}
+
+static inline int ti_sci_proc_power_domain_off(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: dev_id = %d\n", __func__, tsp->dev_id);
+
+ ret = tsp->sci->ops.dev_ops.put_device(tsp->sci, tsp->dev_id);
+ if (ret)
+ pr_err("Power-domain off failed for dev = %d\n", tsp->dev_id);
+
+ return ret;
+}
+#endif /* REMOTEPROC_TI_SCI_PROC_H */