diff options
-rw-r--r-- | common/Kconfig | 5 | ||||
-rw-r--r-- | common/Makefile | 1 | ||||
-rw-r--r-- | common/cmd_remoteproc.c | 281 | ||||
-rw-r--r-- | doc/device-tree-bindings/remoteproc/remoteproc.txt | 14 | ||||
-rw-r--r-- | doc/driver-model/remoteproc-framework.txt | 168 | ||||
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/remoteproc/Kconfig | 15 | ||||
-rw-r--r-- | drivers/remoteproc/Makefile | 7 | ||||
-rw-r--r-- | drivers/remoteproc/rproc-uclass.c | 417 | ||||
-rw-r--r-- | include/dm/uclass-id.h | 1 | ||||
-rw-r--r-- | include/remoteproc.h | 162 |
12 files changed, 1074 insertions, 0 deletions
diff --git a/common/Kconfig b/common/Kconfig index 0d44993800..0388a6c34d 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -350,6 +350,11 @@ config CMD_FPGA help FPGA support. +config CMD_REMOTEPROC + bool "remoteproc" + depends on REMOTEPROC + help + Support for Remote Processor control endmenu diff --git a/common/Makefile b/common/Makefile index 491c56552f..8c7775a783 100644 --- a/common/Makefile +++ b/common/Makefile @@ -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 diff --git a/common/cmd_remoteproc.c b/common/cmd_remoteproc.c new file mode 100644 index 0000000000..794a406b78 --- /dev/null +++ b/common/cmd_remoteproc.c @@ -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"); diff --git a/doc/device-tree-bindings/remoteproc/remoteproc.txt b/doc/device-tree-bindings/remoteproc/remoteproc.txt new file mode 100644 index 0000000000..031764f515 --- /dev/null +++ b/doc/device-tree-bindings/remoteproc/remoteproc.txt @@ -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. diff --git a/doc/driver-model/remoteproc-framework.txt b/doc/driver-model/remoteproc-framework.txt new file mode 100644 index 0000000000..094e98bba6 --- /dev/null +++ b/doc/driver-model/remoteproc-framework.txt @@ -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. diff --git a/drivers/Kconfig b/drivers/Kconfig index 63c92c594a..c02f3231e0 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -46,6 +46,8 @@ source "drivers/power/Kconfig" source "drivers/ram/Kconfig" +source "drivers/remoteproc/Kconfig" + source "drivers/rtc/Kconfig" source "drivers/serial/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 9d0a5959a8..1a30ad1d14 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -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 diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig new file mode 100644 index 0000000000..444682624a --- /dev/null +++ b/drivers/remoteproc/Kconfig @@ -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 diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile new file mode 100644 index 0000000000..14c27929b6 --- /dev/null +++ b/drivers/remoteproc/Makefile @@ -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 diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c new file mode 100644 index 0000000000..a421e12e5d --- /dev/null +++ b/drivers/remoteproc/rproc-uclass.c @@ -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); +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1eeec74964..da41499872 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -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 */ diff --git a/include/remoteproc.h b/include/remoteproc.h new file mode 100644 index 0000000000..c6e044d3b8 --- /dev/null +++ b/include/remoteproc.h @@ -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_ */ |