@@ -344,6 +344,11 @@ config CMD_FPGA
help
FPGA support.
+config CMD_REMOTEPROC
+ bool "remoteproc"
+ depends on REMOTEPROC
+ help
+ Support for Remote Processor control
endmenu
@@ -154,6 +154,7 @@ obj-$(CONFIG_CMD_PXE) += cmd_pxe.o
obj-$(CONFIG_CMD_READ) += cmd_read.o
obj-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o
obj-$(CONFIG_CMD_REISER) += cmd_reiser.o
+obj-$(CONFIG_CMD_REMOTEPROC) += cmd_remoteproc.o
obj-$(CONFIG_SANDBOX) += cmd_host.o
obj-$(CONFIG_CMD_SATA) += cmd_sata.o
obj-$(CONFIG_CMD_SF) += cmd_sf.o
new file mode 100644
@@ -0,0 +1,281 @@
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated - http://www.ti.com/
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <remoteproc.h>
+
+/**
+ * print_remoteproc_list() - print all the remote processor devices
+ *
+ * Return: 0 if no error, else returns appropriate error value.
+ */
+static int print_remoteproc_list(void)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+ char *type;
+
+ ret = uclass_get(UCLASS_REMOTEPROC, &uc);
+ if (ret) {
+ printf("Cannot find Remote processor class\n");
+ return ret;
+ }
+
+ uclass_foreach_dev(dev, uc) {
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ const struct dm_rproc_ops *ops = rproc_get_ops(dev);
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ switch (uc_pdata->mem_type) {
+ case RPROC_INTERNAL_MEMORY_MAPPED:
+ type = "internal memory mapped";
+ break;
+ default:
+ type = "unknown";
+ break;
+ }
+ printf("%d - Name:'%s' type:'%s' supports: %s%s%s%s%s%s\n",
+ dev->seq,
+ uc_pdata->name,
+ type,
+ ops->load ? "load " : "",
+ ops->start ? "start " : "",
+ ops->stop ? "stop " : "",
+ ops->reset ? "reset " : "",
+ ops->is_running ? "is_running " : "",
+ ops->ping ? "ping " : "");
+ }
+ return 0;
+}
+
+/**
+ * do_rproc_init() - do basic initialization
+ * @cmdtp: unused
+ * @flag: unused
+ * @argc: unused
+ * @argv: unused
+ *
+ * Return: 0 if no error, else returns appropriate error value.
+ */
+static int do_rproc_init(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ if (rproc_is_initialized()) {
+ printf("\tRemote Processors are already initialized\n");
+ } else {
+ if (!rproc_init())
+ return 0;
+ printf("Few Remote Processors failed to be initalized\n");
+ }
+
+ return CMD_RET_FAILURE;
+}
+
+/**
+ * do_remoteproc_list() - print list of remote proc devices.
+ * @cmdtp: unused
+ * @flag: unused
+ * @argc: unused
+ * @argv: unused
+ *
+ * Return: 0 if no error, else returns appropriate error value.
+ */
+static int do_remoteproc_list(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ if (!rproc_is_initialized()) {
+ printf("\t Remote Processors is not initialized\n");
+ return CMD_RET_USAGE;
+ }
+
+ if (print_remoteproc_list())
+ return CMD_RET_FAILURE;
+
+ return 0;
+}
+
+/**
+ * do_remoteproc_load() - Load a remote processor with binary image
+ * @cmdtp: unused
+ * @flag: unused
+ * @argc: argument count for the load function
+ * @argv: arguments for the load function
+ *
+ * Return: 0 if no error, else returns appropriate error value.
+ */
+static int do_remoteproc_load(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ ulong addr, size;
+ int id, ret;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ id = (int)simple_strtoul(argv[1], NULL, 3);
+ addr = simple_strtoul(argv[2], NULL, 16);
+
+ size = simple_strtoul(argv[3], NULL, 16);
+
+ if (!size) {
+ printf("\t Expect some size??\n");
+ return CMD_RET_USAGE;
+ }
+
+ if (!rproc_is_initialized()) {
+ printf("\tRemote Processors are not initialized\n");
+ return CMD_RET_USAGE;
+ }
+
+ ret = rproc_load(id, addr, size);
+ printf("Load Remote Processor %d with data@addr=0x%08lx %lu bytes:%s\n",
+ id, addr, size, ret ? " Failed!" : " Success!");
+
+ return ret ? CMD_RET_FAILURE : 0;
+}
+
+/**
+ * do_remoteproc_wrapper() - wrapper for various rproc commands
+ * @cmdtp: unused
+ * @flag: unused
+ * @argc: argument count for the rproc command
+ * @argv: arguments for the rproc command
+ *
+ * Most of the commands just take id as a parameter andinvoke various
+ * helper routines in remote processor core. by using a set of
+ * common checks, we can reduce the amount of code used for this.
+ *
+ * Return: 0 if no error, else returns appropriate error value.
+ */
+static int do_remoteproc_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int id, ret = CMD_RET_USAGE;
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ id = (int)simple_strtoul(argv[1], NULL, 3);
+
+ if (!rproc_is_initialized()) {
+ printf("\tRemote Processors are not initialized\n");
+ return CMD_RET_USAGE;
+ }
+
+ if (!strcmp(argv[0], "start")) {
+ ret = rproc_start(id);
+ } else if (!strcmp(argv[0], "stop")) {
+ ret = rproc_stop(id);
+ } else if (!strcmp(argv[0], "reset")) {
+ ret = rproc_reset(id);
+ } else if (!strcmp(argv[0], "is_running")) {
+ ret = rproc_is_running(id);
+ if (!ret) {
+ printf("Remote processor is Running\n");
+ } else if (ret == 1) {
+ printf("Remote processor is NOT Running\n");
+ ret = 0;
+ }
+ /* Else error.. */
+ } else if (!strcmp(argv[0], "ping")) {
+ ret = rproc_ping(id);
+ if (!ret) {
+ printf("Remote processor responds 'Pong'\n");
+ } else if (ret == 1) {
+ printf("No response from Remote processor\n");
+ ret = 0;
+ }
+ /* Else error.. */
+ }
+
+ if (ret < 0)
+ printf("Operation Failed with error (%d)\n", ret);
+
+ return ret ? CMD_RET_FAILURE : 0;
+}
+
+static cmd_tbl_t cmd_remoteproc_sub[] = {
+ U_BOOT_CMD_MKENT(init, 0, 1, do_rproc_init,
+ "Enumerate and initialize all processors", ""),
+ U_BOOT_CMD_MKENT(list, 0, 1, do_remoteproc_list,
+ "list remote processors", ""),
+ U_BOOT_CMD_MKENT(load, 5, 1, do_remoteproc_load,
+ "Load remote processor with provided image",
+ "<id> [addr] [size]\n"
+ "- id: ID of the remote processor(see 'list' cmd)\n"
+ "- addr: Address in memory of the image to loadup\n"
+ "- size: Size of the image to loadup\n"),
+ U_BOOT_CMD_MKENT(start, 1, 1, do_remoteproc_wrapper,
+ "Start remote processor",
+ "id - ID of the remote processor (see 'list' cmd)\n"),
+ U_BOOT_CMD_MKENT(stop, 1, 1, do_remoteproc_wrapper,
+ "Stop remote processor",
+ "id - ID of the remote processor (see 'list' cmd)\n"),
+ U_BOOT_CMD_MKENT(reset, 1, 1, do_remoteproc_wrapper,
+ "Reset remote processor",
+ "id - ID of the remote processor (see 'list' cmd)\n"),
+ U_BOOT_CMD_MKENT(is_running, 1, 1, do_remoteproc_wrapper,
+ "Check to see if remote processor is running\n",
+ "id - ID of the remote processor (see 'list' cmd)\n"),
+ U_BOOT_CMD_MKENT(ping, 1, 1, do_remoteproc_wrapper,
+ "Ping to communicate with remote processor\n",
+ "id - ID of the remote processor (see 'list' cmd)\n"),
+};
+
+/**
+ * do_remoteproc() - (replace: short desc)
+ * @cmdtp: unused
+ * @flag: unused
+ * @argc: argument count
+ * @argv: argument list
+ *
+ * parses up the command table to invoke the correct command.
+ *
+ * Return: 0 if no error, else returns appropriate error value.
+ */
+static int do_remoteproc(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ cmd_tbl_t *c = NULL;
+
+ /* Strip off leading 'rproc' command argument */
+ argc--;
+ argv++;
+
+ if (argc)
+ c = find_cmd_tbl(argv[0], cmd_remoteproc_sub,
+ ARRAY_SIZE(cmd_remoteproc_sub));
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+
+ return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(rproc, 5, 1, do_remoteproc,
+ "Control operation of remote processors in an SoC",
+ " [init|list|load|start|stop|reset|is_running|ping]\n"
+ "\t\t Where:\n"
+ "\t\t[addr] is a memory address\n"
+ "\t\t<id> is a numerical identifier for the remote processor\n"
+ "\t\t provided by 'list' command.\n"
+ "\t\tNote: Remote processors must be initalized prior to usage\n"
+ "\t\tNote: Services are dependent on the driver capability\n"
+ "\t\t 'list' command shows the capability of each device\n"
+ "\n\tSubcommands:\n"
+ "\tinit - Enumerate and initalize the remote processors\n"
+ "\tlist - list available remote processors\n"
+ "\tload <id> [addr] [size]- Load the remote processor with binary\n"
+ "\t image stored at address [addr] in memory\n"
+ "\tstart <id> - Start the remote processor(must be loaded)\n"
+ "\tstop <id> - Stop the remote processor\n"
+ "\treset <id> - Reset the remote processor\n"
+ "\tis_running <id> - Reports if the remote processor is running\n"
+ "\tping <id> - Ping the remote processor for communication\n");
new file mode 100644
@@ -0,0 +1,14 @@
+Remote Processor uclass
+
+Binding:
+
+Remoteproc devices shall have compatible corresponding to thier
+drivers. However the following generic properties will be supported
+
+Optional Properties:
+- remoteproc-name: a string, used if provided to describe the processor.
+ This must be unique in an operational system.
+- remoteproc-internal-memory-mapped: a bool, indicates that the remote
+ processor has internal memory that it uses to execute code and store
+ data. Such a device is not expected to have a MMU. If no type property
+ is provided, the device is assumed to map to such a model.
new file mode 100644
@@ -0,0 +1,168 @@
+#
+# (C) Copyright 2015
+# Texas Instruments Incorporated - http://www.ti.com/
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+Remote Processor Framework
+==========================
+TOC:
+1. Introduction
+2. How does it work - The driver
+3. Describing the device using platform data
+4. Describing the device using device tree
+
+1. Introduction
+===============
+
+This is an introduction to driver-model for Remote Processors found
+on various System on Chip(SoCs). The term remote processor is used to
+indicate that this is not the processor on which U-Boot is operating
+on, instead is yet another processing entity that may be controlled by
+the processor on which we are functional.
+
+The simplified model depends on a single UCLASS - UCLASS_REMOTEPROC
+
+UCLASS_REMOTEPROC:
+- drivers/remoteproc/rproc-uclass.c
+- include/remoteproc.h
+
+Commands:
+- common/cmd_remoteproc.c
+
+Configuration:
+CONFIG_REMOTEPROC is selected by drivers as needed
+CONFIG_CMD_REMOTEPROC for the commands if required.
+
+2. How does it work - The driver
+=================================
+
+Overall, the driver statemachine transitions are typically as follows:
+ (entry)
+ +-------+
+ +---+ init |
+ | | | <---------------------+
+ | +-------+ |
+ | |
+ | |
+ | +--------+ |
+Load| | reset | |
+ | | | <----------+ |
+ | +--------+ | |
+ | |Load | |
+ | | | |
+ | +----v----+ reset | |
+ +-> | | (opt) | |
+ | Loaded +-----------+ |
+ | | |
+ +----+----+ |
+ | Start |
+ +---v-----+ (opt) |
+ +->| Running | Stop |
+Ping +- | +--------------------+
+(opt) +---------+
+
+(is_running does not change state)
+opt: Optional state transition implemented by driver.
+
+NOTE: It depends on the remote processor as to the exact behavior
+of the statemachine, remoteproc core does not intent to implement
+statemachine logic. Certain processors may allow start/stop without
+reloading the image in the middle, certain other processors may only
+allow us to start the processor(image from a EEPROM/OTP) etc.
+
+It is hence the responsibility of the driver to handle the requisite
+state transitions of the device as necessary.
+
+Basic design assumptions:
+
+Remote processor can operate on a certain firmware that maybe loaded
+and released from reset.
+
+The driver follows a standard UCLASS DM.
+
+in the bare minimum form:
+
+static const struct dm_rproc_ops sandbox_testproc_ops = {
+ .load = sandbox_testproc_load,
+ .start = sandbox_testproc_start,
+};
+
+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,
+};
+
+This allows for the device to be probed as part of the "init" command
+or invocation of 'rproc_init()' function as the system dependencies define.
+
+The driver is expected to maintain it's own statemachine which is
+appropriate for the device it maintains. It must, at the very least
+provide a load and start function. We assume here that the device
+needs to be loaded and started, else, there is no real purpose of
+using the remoteproc framework.
+
+3. Describing the device using platform data
+============================================
+
+*IMPORTANT* NOTE: THIS SUPPORT IS NOT MEANT FOR USE WITH NEWER PLATFORM
+SUPPORT. THIS IS ONLY FOR LEGACY DEVICES. THIS MODE OF INITIALIZATION
+*WILL* BE EVENTUALLY REMOVED ONCE ALL NECESSARY PLATFORMS HAVE MOVED
+TO DM/FDT.
+
+Considering that many platforms are yet to move to device-tree model,
+a simplified definition of a device is as follows:
+
+struct dm_rproc_uclass_pdata proc_3_test = {
+ .name = "proc_3_legacy",
+ .mem_type = RPROC_INTERNAL_MEMORY_MAPPED,
+ .driver_plat_data = &mydriver_data;
+};
+
+U_BOOT_DEVICE(proc_3_demo) = {
+ .name = "sandbox_test_proc",
+ .platdata = &proc_3_test,
+};
+
+There can be additional data that may be desired depending on the
+remoteproc driver specific needs (for example: SoC integration
+details such as clock handle or something similar). See appropriate
+documentation for specific remoteproc driver for further details.
+These are passed via driver_plat_data.
+
+3. Describing the device using device tree
+==========================================
+/ {
+ ...
+ aliases {
+ ...
+ remoteproc0 = &rproc_1;
+ remoteproc1 = &rproc_2;
+
+ };
+ ...
+
+ rproc_1: rproc@1 {
+ compatible = "sandbox,test-processor";
+ remoteproc-name = "remoteproc-test-dev1";
+ };
+
+ rproc_2: rproc@2 {
+ compatible = "sandbox,test-processor";
+ internal-memory-mapped;
+ remoteproc-name = "remoteproc-test-dev2";
+ };
+ ...
+};
+
+aliases usage is optional, but it is usually recommended to ensure the
+users have a consistent usage model for a platform.
+the compatible string used here is specific to the remoteproc driver involved.
@@ -46,6 +46,8 @@ source "drivers/power/Kconfig"
source "drivers/ram/Kconfig"
+source "drivers/remoteproc/Kconfig"
+
source "drivers/rtc/Kconfig"
source "drivers/serial/Kconfig"
@@ -59,6 +59,7 @@ obj-y += pwm/
obj-y += input/
# SOC specific infrastructure drivers.
obj-y += soc/
+obj-$(CONFIG_REMOTEPROC) += remoteproc/
obj-y += thermal/
endif
new file mode 100644
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2015
+# Texas Instruments Incorporated - http://www.ti.com/
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+menu "Remote Processor drivers"
+
+# REMOTEPROC gets selected by drivers as needed
+# All users should depend on DM
+config REMOTEPROC
+ bool
+ depends on DM
+
+endmenu
new file mode 100644
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2015
+# Texas Instruments Incorporated - http://www.ti.com/
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_REMOTEPROC) += rproc-uclass.o
new file mode 100644
@@ -0,0 +1,417 @@
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated - http://www.ti.com/
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <remoteproc.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_platdata(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_platdata(dev);
+
+ /* See if we need to populate via fdt */
+
+ if (!dev->platdata) {
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ int node = dev->of_offset;
+ 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->platdata;
+
+ 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_platdata_auto_alloc_size =
+ 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->flags & 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_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_platdata(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_platdata(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);
+};
@@ -49,6 +49,7 @@ enum uclass_id {
UCLASS_PMIC, /* PMIC I/O device */
UCLASS_REGULATOR, /* Regulator device */
UCLASS_RESET, /* Reset device */
+ UCLASS_REMOTEPROC, /* Remote Processor device */
UCLASS_RTC, /* Real time clock device */
UCLASS_SERIAL, /* Serial UART */
UCLASS_SPI, /* SPI bus */
new file mode 100644
@@ -0,0 +1,162 @@
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated - http://www.ti.com/
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _RPROC_H_
+#define _RPROC_H_
+
+/*
+ * Note: The platform data support is not meant for use with newer
+ * platforms. This is meant only for legacy devices. This mode of
+ * initialization *will* be eventually removed once all necessary
+ * platforms have moved to dm/fdt.
+ */
+#include <dm/platdata.h> /* For platform data support - non dt world */
+
+/**
+ * enum rproc_mem_type - What type of memory model does the rproc use
+ * @RPROC_INTERNAL_MEMORY_MAPPED: Remote processor uses own memory and is memory
+ * mapped to the host processor over an address range.
+ *
+ * Please note that this is an enumeration of memory model of different types
+ * of remote processors. Few of the remote processors do have own internal
+ * memories, while others use external memory for instruction and data.
+ */
+enum rproc_mem_type {
+ RPROC_INTERNAL_MEMORY_MAPPED = 0,
+};
+
+/**
+ * struct dm_rproc_uclass_pdata - platform data for a CPU
+ * @name: Platform-specific way of naming the Remote proc
+ * @mem_type: one of 'enum rproc_mem_type'
+ * @driver_plat_data: driver specific platform data that may be needed.
+ *
+ * This can be accessed with dev_get_uclass_platdata() for any UCLASS_REMOTEPROC
+ * device.
+ *
+ */
+struct dm_rproc_uclass_pdata {
+ const char *name;
+ enum rproc_mem_type mem_type;
+ void *driver_plat_data;
+};
+
+/**
+ * struct dm_rproc_ops - Operations that are provided by remote proc driver
+ * @init: Initialize the remoteproc device invoked after probe (optional)
+ * Return 0 on success, -ve error on fail
+ * @load: Load the remoteproc device using data provided(mandatory)
+ * This takes the following additional arguments.
+ * addr- Address of the binary image to be loaded
+ * size- Size of the binary image to be loaded
+ * Return 0 on success, -ve error on fail
+ * @start: Start the remoteproc device (mandatory)
+ * Return 0 on success, -ve error on fail
+ * @stop: Stop the remoteproc device (optional)
+ * Return 0 on success, -ve error on fail
+ * @reset: Reset the remote proc device (optional)
+ * Return 0 on success, -ve error on fail
+ * @is_running: Check if the remote processor is running(optional)
+ * Return 0 on success, 1 if not running, -ve on others errors
+ * @ping: Ping the remote device for basic communication check(optional)
+ * Return 0 on success, 1 if not responding, -ve on other errors
+ */
+struct dm_rproc_ops {
+ int (*init)(struct udevice *dev);
+ int (*load)(struct udevice *dev, ulong addr, ulong size);
+ int (*start)(struct udevice *dev);
+ int (*stop)(struct udevice *dev);
+ int (*reset)(struct udevice *dev);
+ int (*is_running)(struct udevice *dev);
+ int (*ping)(struct udevice *dev);
+};
+
+/* Accessor */
+#define rproc_get_ops(dev) ((struct dm_rproc_ops *)(dev)->driver->ops)
+
+#ifdef CONFIG_REMOTEPROC
+/**
+ * rproc_init() - Initialize all bound remote proc devices
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+int rproc_init(void);
+
+/**
+ * rproc_is_initialized() - check to see if remoteproc devices are initialized
+ *
+ * Return: 0 if all devices are initialized, else appropriate error value.
+ */
+bool rproc_is_initialized(void);
+
+/**
+ * rproc_load() - load binary to a remote processor
+ * @id: id of the remote processor
+ * @addr: address in memory where the binary image is located
+ * @size: size of the binary image
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+int rproc_load(int id, ulong addr, ulong size);
+
+/**
+ * rproc_start() - Start a remote processor
+ * @id: id of the remote processor
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+int rproc_start(int id);
+
+/**
+ * rproc_stop() - Stop a remote processor
+ * @id: id of the remote processor
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+int rproc_stop(int id);
+
+/**
+ * rproc_reset() - reset a remote processor
+ * @id: id of the remote processor
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+int rproc_reset(int id);
+
+/**
+ * rproc_ping() - ping a remote processor to check if it can communicate
+ * @id: id of the remote processor
+ *
+ * NOTE: this might need communication path available, which is not implemented
+ * as part of remoteproc framework - hook on to appropriate bus architecture to
+ * do the same
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+int rproc_ping(int id);
+
+/**
+ * rproc_is_running() - check to see if remote processor is running
+ * @id: id of the remote processor
+ *
+ * NOTE: this may not involve actual communication capability of the remote
+ * processor, but just ensures that it is out of reset and executing code.
+ *
+ * Return: 0 if all ok, else appropriate error value.
+ */
+int rproc_is_running(int id);
+#else
+static inline int rproc_init(void) { return -ENOSYS; }
+static inline bool rproc_is_initialized(void) { return false; }
+static inline int rproc_load(int id, ulong addr, ulong size) { return -ENOSYS; }
+static inline int rproc_start(int id) { return -ENOSYS; }
+static inline int rproc_stop(int id) { return -ENOSYS; }
+static inline int rproc_reset(int id) { return -ENOSYS; }
+static inline int rproc_ping(int id) { return -ENOSYS; }
+static inline int rproc_is_running(int id) { return -ENOSYS; }
+#endif
+
+#endif /* _RPROC_H_ */