remoteproc: uclass: Add methods to load firmware to rproc and boot rproc
Add APIs to set a firmware_name to a rproc and boot the rproc with the same firmware. Clients can call rproc_set_firmware() API to set firmware_name for a rproc whereas rproc_boot() will load the firmware set by rproc_set_firmware() to a buffer by calling request_firmware_into_buf(). rproc_boot() will then load the firmware file to the remote processor and start the remote processor. Signed-off-by: MD Danish Anwar <danishanwar@ti.com> Acked-by: Ravi Gunasekaran <r-gunasekaran@ti.com> Reviewed-by: Roger Quadros <rogerq@kernel.org>
This commit is contained in:

committed by
Tom Rini

parent
df479dde31
commit
fb49d6c289
@@ -102,4 +102,11 @@ config REMOTEPROC_TI_IPU
|
|||||||
help
|
help
|
||||||
Say 'y' here to add support for TI' K3 remoteproc driver.
|
Say 'y' here to add support for TI' K3 remoteproc driver.
|
||||||
|
|
||||||
|
config REMOTEPROC_MAX_FW_SIZE
|
||||||
|
hex "Maximum size of firmware file that needs to be loaded to the remote processor"
|
||||||
|
default 0x10000
|
||||||
|
help
|
||||||
|
Maximum size of the firmware file (elf, binary) that needs to be
|
||||||
|
loaded to the remote processor.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <virtio_ring.h>
|
#include <virtio_ring.h>
|
||||||
|
#include <fs_loader.h>
|
||||||
#include <remoteproc.h>
|
#include <remoteproc.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <dm/device-internal.h>
|
#include <dm/device-internal.h>
|
||||||
@@ -961,3 +962,106 @@ unsigned long rproc_parse_resource_table(struct udevice *dev, struct rproc *cfg)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name)
|
||||||
|
{
|
||||||
|
struct dm_rproc_uclass_pdata *uc_pdata;
|
||||||
|
int len;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (!rproc_dev || !fw_name)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
uc_pdata = dev_get_uclass_plat(rproc_dev);
|
||||||
|
if (!uc_pdata)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
len = strcspn(fw_name, "\n");
|
||||||
|
if (!len) {
|
||||||
|
debug("invalid firmware name\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uc_pdata->fw_name)
|
||||||
|
free(uc_pdata->fw_name);
|
||||||
|
|
||||||
|
p = strndup(fw_name, len);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
uc_pdata->fw_name = p;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(FS_LOADER)
|
||||||
|
int rproc_boot(struct udevice *rproc_dev)
|
||||||
|
{
|
||||||
|
struct dm_rproc_uclass_pdata *uc_pdata;
|
||||||
|
struct udevice *fs_loader;
|
||||||
|
int core_id, ret = 0;
|
||||||
|
char *firmware;
|
||||||
|
void *addr;
|
||||||
|
|
||||||
|
if (!rproc_dev)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
uc_pdata = dev_get_uclass_plat(rproc_dev);
|
||||||
|
if (!uc_pdata)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
core_id = dev_seq(rproc_dev);
|
||||||
|
firmware = uc_pdata->fw_name;
|
||||||
|
if (!firmware) {
|
||||||
|
debug("No firmware name set for rproc core %d\n", core_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize all rproc cores */
|
||||||
|
if (!rproc_is_initialized()) {
|
||||||
|
ret = rproc_init();
|
||||||
|
if (ret) {
|
||||||
|
debug("rproc_init() failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading firmware to a given address */
|
||||||
|
ret = get_fs_loader(&fs_loader);
|
||||||
|
if (ret) {
|
||||||
|
debug("could not get fs loader: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CONFIG_REMOTEPROC_MAX_FW_SIZE) {
|
||||||
|
addr = malloc(CONFIG_REMOTEPROC_MAX_FW_SIZE);
|
||||||
|
if (!addr)
|
||||||
|
return -ENOMEM;
|
||||||
|
} else {
|
||||||
|
debug("CONFIG_REMOTEPROC_MAX_FW_SIZE not defined\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = request_firmware_into_buf(fs_loader, firmware, addr, CONFIG_REMOTEPROC_MAX_FW_SIZE,
|
||||||
|
0);
|
||||||
|
if (ret < 0) {
|
||||||
|
debug("could not request %s: %d\n", firmware, ret);
|
||||||
|
goto free_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rproc_load(core_id, (ulong)addr, ret);
|
||||||
|
if (ret) {
|
||||||
|
debug("failed to load %s to rproc core %d from addr 0x%08lX err %d\n",
|
||||||
|
uc_pdata->fw_name, core_id, (ulong)addr, ret);
|
||||||
|
goto free_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rproc_start(core_id);
|
||||||
|
if (ret)
|
||||||
|
debug("failed to start rproc core %d\n", core_id);
|
||||||
|
|
||||||
|
free_buffer:
|
||||||
|
free(addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -403,6 +403,7 @@ enum rproc_mem_type {
|
|||||||
* @name: Platform-specific way of naming the Remote proc
|
* @name: Platform-specific way of naming the Remote proc
|
||||||
* @mem_type: one of 'enum rproc_mem_type'
|
* @mem_type: one of 'enum rproc_mem_type'
|
||||||
* @driver_plat_data: driver specific platform data that may be needed.
|
* @driver_plat_data: driver specific platform data that may be needed.
|
||||||
|
* @fw_name: firmware name
|
||||||
*
|
*
|
||||||
* This can be accessed with dev_get_uclass_plat() for any UCLASS_REMOTEPROC
|
* This can be accessed with dev_get_uclass_plat() for any UCLASS_REMOTEPROC
|
||||||
* device.
|
* device.
|
||||||
@@ -412,6 +413,7 @@ struct dm_rproc_uclass_pdata {
|
|||||||
const char *name;
|
const char *name;
|
||||||
enum rproc_mem_type mem_type;
|
enum rproc_mem_type mem_type;
|
||||||
void *driver_plat_data;
|
void *driver_plat_data;
|
||||||
|
char *fw_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -705,6 +707,34 @@ unsigned long rproc_parse_resource_table(struct udevice *dev,
|
|||||||
struct resource_table *rproc_find_resource_table(struct udevice *dev,
|
struct resource_table *rproc_find_resource_table(struct udevice *dev,
|
||||||
unsigned int addr,
|
unsigned int addr,
|
||||||
int *tablesz);
|
int *tablesz);
|
||||||
|
/**
|
||||||
|
* rproc_set_firmware() - assign a new firmware name
|
||||||
|
* @rproc_dev: device for which new firmware name is being assigned
|
||||||
|
* @fw_name: new firmware name to be assigned
|
||||||
|
*
|
||||||
|
* This function allows remoteproc drivers or clients to configure a custom
|
||||||
|
* firmware name. The function does not trigger a remote processor boot,
|
||||||
|
* only sets the firmware name used for a subsequent boot.
|
||||||
|
*
|
||||||
|
* This function sets the fw_name field in uclass pdata of the Remote proc
|
||||||
|
*
|
||||||
|
* Return: 0 on success or a negative value upon failure
|
||||||
|
*/
|
||||||
|
int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rproc_boot() - boot a remote processor
|
||||||
|
* @rproc_dev: rproc device to boot
|
||||||
|
*
|
||||||
|
* Boot a remote processor (i.e. load its firmware, power it on, ...).
|
||||||
|
*
|
||||||
|
* This function first loads the firmware set in the uclass pdata of Remote
|
||||||
|
* processor to a buffer and then loads firmware to the remote processor
|
||||||
|
* using rproc_load().
|
||||||
|
*
|
||||||
|
* Return: 0 on success, and an appropriate error value otherwise
|
||||||
|
*/
|
||||||
|
int rproc_boot(struct udevice *rproc_dev);
|
||||||
#else
|
#else
|
||||||
static inline int rproc_init(void) { return -ENOSYS; }
|
static inline int rproc_init(void) { return -ENOSYS; }
|
||||||
static inline int rproc_dev_init(int id) { return -ENOSYS; }
|
static inline int rproc_dev_init(int id) { return -ENOSYS; }
|
||||||
@@ -744,6 +774,10 @@ static inline int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
|
|||||||
ulong fw_size, ulong *rsc_addr,
|
ulong fw_size, ulong *rsc_addr,
|
||||||
ulong *rsc_size)
|
ulong *rsc_size)
|
||||||
{ return -ENOSYS; }
|
{ return -ENOSYS; }
|
||||||
|
static inline int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name)
|
||||||
|
{ return -ENOSYS; }
|
||||||
|
static inline int rproc_boot(struct udevice *rproc_dev)
|
||||||
|
{ return -ENOSYS; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _RPROC_H_ */
|
#endif /* _RPROC_H_ */
|
||||||
|
Reference in New Issue
Block a user