memory@80000000 {
diff --git a/configs/am65x_evm_a53_defconfig
b/configs/am65x_evm_a53_defconfig
index 2755d7082f..c53e938abb 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -112,6 +112,7 @@ CONFIG_DM_I2C_GPIO=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
+CONFIG_FS_LOADER=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig
index b2f1e721b3..2d19935a41 100644
--- a/configs/am65x_evm_r5_defconfig
+++ b/configs/am65x_evm_r5_defconfig
@@ -98,6 +98,7 @@ CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
+CONFIG_FS_LOADER=y
CONFIG_K3_AVS0=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_HS200_SUPPORT=y
diff --git a/drivers/net/ti/icssg_prueth.c b/drivers/net/ti/icssg_prueth.c
index 40ad827e49..1c4edeb7b7 100644
--- a/drivers/net/ti/icssg_prueth.c
+++ b/drivers/net/ti/icssg_prueth.c
@@ -227,6 +227,10 @@ static int prueth_start(struct udevice *dev)
void *config;
int ret, i;
+ ret = icssg_start_pru_cores(dev);
+ if (ret)
+ return ret;
+
/* To differentiate channels for SLICE0 vs SLICE1 */
snprintf(chn_name, sizeof(chn_name), "tx%d-0", priv->slice);
@@ -355,9 +359,11 @@ static void prueth_stop(struct udevice *dev)
phy_shutdown(priv->phydev);
dma_disable(&priv->dma_tx);
- dma_free(&priv->dma_tx);
-
dma_disable(&priv->dma_rx);
+
+ icssg_stop_pru_cores(dev);
+
+ dma_free(&priv->dma_tx);
dma_free(&priv->dma_rx);
}
@@ -434,6 +440,181 @@ static const struct soc_attr k3_mdio_soc_data[] = {
{ /* sentinel */ },
};
+struct icssg_firmware_load_address {
+ u32 pru;
+ u32 rtu;
+ u32 txpru;
+};
+
+struct icssg_firmwares {
+ char *pru;
+ char *rtu;
+ char *txpru;
+};
+
+static struct icssg_firmwares icssg_emac_firmwares[] = {
+ {
+ .pru = "/lib/firmware/ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
+ .rtu = "/lib/firmware/ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
+ .txpru =
"/lib/firmware/ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
+ },
+ {
+ .pru = "/lib/firmware/ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
+ .rtu = "/lib/firmware/ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
+ .txpru =
"/lib/firmware/ti-pruss/am65x-sr2-txpru1-prueth-fw.elf",
+ }
+};
This information is contained in the DT.
firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
"ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
"ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
"ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
"ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
"ti-pruss/am65x-sr2-txpru1-prueth-fw.elf";
Yes it is. But the linux driver uses the firmware strcuture inside
driver only. The firmware-name property is not being used. The firmware
names for all applicable SoCs (AM65x and AM64x) is same so instead of
reading it from DT, the driver hardcodes the firmware names in linux. I
think the thought here was to use firmware-name property from DT when
different firmwares are needed for different SoCs. I am just following
the same here in uboot as well.
You will need to introduce a rproc_set_firmware() API so clients can
set their own firmware names.
Sure. I will add an element 'fw_name' in struct dm_rproc_uclass_pdata
and set this fw_name to the firmware name requested by client using
rproc_set_firmware().
The client drivers can call rproc_set_firmware(dev, firmware_name) to
set the firmware name.
+
+int load_firmware(char *name_fw, u32 *loadaddr)
+{
+ struct udevice *fsdev;
+ int size = 0;
+
+ if (!IS_ENABLED(CONFIG_FS_LOADER))
+ return -EINVAL;
+
+ if (!*loadaddr)
+ return -EINVAL;
+
+ if (!get_fs_loader(&fsdev))
+ size = request_firmware_into_buf(fsdev, name_fw, (void
*)*loadaddr,
40524, 0);
+
+ return size;
+}
On Linux rproc_boot() does both loading the firmware and starting the rproc
as that is farely generic.
You should introduce rproc_boot() API so loading is taken care of at rproc
driver.
All you need to do is call rproc_set_firmware() before rproc_boot().
Sure. I'll introduce rproc_boot() which will load the firmware to a
buffer and then load the firmware / buffer to rproc core usinig rproc_load.
For allocating memory for reading firmware we need to provide the size
of memory required as well. So rproc_boot will take two arguments.
1. dev (rproc device)
2. size (Maximum memory required to read firmware)
+
+static int icssg_get_instance(struct udevice *dev)
+{
+ if (!strcmp(dev->name, "icssg2-eth"))
+ return 2;
+ else if (!strcmp(dev->name, "icssg1-eth"))
+ return 1;
+ else if (!strcmp(dev->name, "icssg0-eth"))
+ return 0;
+
+ dev_err(dev, "Invalid icssg instance\n");
+ return -EINVAL;
+}
+
+static int icssg_get_pru_core_number(struct udevice *dev, int slice)
+{
+ int instance, num_r5_cores;
+
+ instance = icssg_get_instance(dev);
+ if (instance < 0)
+ return instance;
+
+ if (IS_ENABLED(CONFIG_REMOTEPROC_TI_K3_R5F))
+ num_r5_cores = 2;
+
+ return num_r5_cores +
+ instance * PRU_TYPE_MAX * PRUETH_NUM_MACS +
+ slice * PRU_TYPE_MAX;
All this doesn't look right. What we need is the rproc device
that matches the PRU/RTU rprocs that we are interested in.
The DT already has this information
ti,prus = <&pru2_0>, <&rtu2_0>, <&tx_pru2_0>,
<&pru2_1>, <&rtu2_1>, <&tx_pru2_1>;
All the current rproc APIs use the below to get rproc device from ID
ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
You just need to introduce APIs that takes rproc device directly as argument.
In your driver you can call uclass_get_device_by_phandle_id() to get the
rproc device from the rproc phandle?
Sure. I'll do that. Based on the icssg slice first I will get the
phandle for prus.
Index will be 0,1,2 for slice 0 and 3,4,5 for slice 1.
ofnode_read_u32_index(dev_ofnode(dev), "ti,prus", index, &phandle);
Then for each phandle I can call uclass_get_device_by_phandle_id() and
get the rproc device.
+}
+
+int icssg_start_pru_cores(struct udevice *dev)
+{
+ struct prueth *prueth = dev_get_priv(dev);
+ struct icssg_firmwares *firmwares;
+ u32 pru_fw_loadaddr = 0x80000000;
+ u32 rtu_fw_loadaddr = 0x89000000;
+ u32 txpru_fw_loadaddr = 0x90000000;
Please avoid hardcoding. You can use malloc to get a temporary buffer area?
Why do you need 3 different addresses?
Once you do a rproc_load isn't the buffer already copied to rproc's memory
so you can discard it or use it for the other rprocs?
Sure I'll use malloc to get temporary buffer. Only thing is that to get
temporary buffer I will need to provide size as well.
void *addr = malloc(fw_size);
User needs to provide this fw_size to rproc_boot(). In my case the max
size the firmware can have is 64KB so I will be passing 64K as size to
rproc driver.
+ int slice, ret, core_id;
+
+ firmwares = icssg_emac_firmwares;
+ slice = prueth->slice;
+
+ core_id = icssg_get_pru_core_number(dev, slice);
+ if (core_id < 0)
+ return core_id;
+
+ /* Initialize all rproc cores */
+ rproc_init();
+
+ /* Loading PRU firmware to PRU core */
+ ret = load_firmware(firmwares[slice].pru, &pru_fw_loadaddr);
On Linux, loading the firmware is the responsibility of the rproc driver.
Shouldn't it be the same in u-boot?
Sure I'll move this to rproc driver.
+
+ if (ret < 0) {
+ dev_err(dev, "Unable to load_firmware %s at addr 0x%x err %d\n",
+ firmwares[slice].pru, pru_fw_loadaddr, ret);
+ return ret;
+ }
+
+ dev_info(dev, "Loaded FW %s successfully at addr 0x%x Size = %d
Bytes\n",
+ firmwares[slice].pru, pru_fw_loadaddr, ret);
dev_dbg() here an at all dev_info().
+ rproc_load(core_id + PRU_TYPE_PRU, pru_fw_loadaddr, ret);
+
+ /* Loading RTU firmware to RTU core */
+ ret = load_firmware(firmwares[slice].rtu, &rtu_fw_loadaddr);
+
+ if (ret < 0) {
+ dev_err(dev, "Unable to load_firmware %s at addr 0x%x err %d\n",
+ firmwares[slice].rtu, rtu_fw_loadaddr, ret);
+ return ret;
+ }
+
+ dev_info(dev, "Loaded FW %s successfully at addr 0x%x Size = %d
Bytes\n",
+ firmwares[slice].rtu, rtu_fw_loadaddr, ret);
+ rproc_load(core_id + PRU_TYPE_RTU, rtu_fw_loadaddr, ret);
+
+ /* Loading TX_PRU firmware to TX_PRU core */
+ ret = load_firmware(firmwares[slice].txpru, &txpru_fw_loadaddr);
+
+ if (ret < 0) {
+ dev_err(dev, "Unable to load_firmware %s at addr 0x%x err %d\n",
+ firmwares[slice].txpru, txpru_fw_loadaddr, ret);
+ return ret;
+ }
+
+ dev_info(dev, "Loaded FW %s successfully at addr 0x%x Size = %d
Bytes\n",
+ firmwares[slice].txpru, txpru_fw_loadaddr, ret);
+ rproc_load(core_id + PRU_TYPE_TX_PRU, txpru_fw_loadaddr, ret);
+
+ ret = rproc_start(core_id + PRU_TYPE_PRU);
+ if (ret) {
+ dev_err(dev, "failed to start PRU%d: %d\n", slice, ret);
+ return ret;
+ }
+
+ ret = rproc_start(core_id + PRU_TYPE_RTU);
+ if (ret) {
+ dev_err(dev, "failed to start RTU%d: %d\n", slice, ret);
+ goto halt_pru;
+ }
+
+ ret = rproc_start(core_id + PRU_TYPE_TX_PRU);
+ if (ret) {
+ dev_err(dev, "failed to start TX_PRU%d: %d\n", slice, ret);
+ goto halt_rtu;
+ }
+
+ return 0;
+
+halt_rtu:
+ rproc_stop(core_id + PRU_TYPE_RTU);
+
+halt_pru:
+ rproc_stop(PRU_TYPE_PRU);
+ return ret;
+}
+
+int icssg_stop_pru_cores(struct udevice *dev)
+{
+ struct prueth *prueth = dev_get_priv(dev);
+ int slice, core_id;
+
+ slice = prueth->slice;
+
+ core_id = icssg_get_pru_core_number(dev, slice);
+ if (core_id < 0)
+ return core_id;
+
+ rproc_stop(core_id + PRU_TYPE_PRU);
+ rproc_stop(core_id + PRU_TYPE_RTU);
+ rproc_stop(core_id + PRU_TYPE_TX_PRU);
+
+ return 0;
+}
+
static int prueth_probe(struct udevice *dev)
{
ofnode eth_ports_node, eth0_node, eth1_node, eth_node;
diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h
index 25272e850e..f17fe8bf58 100644
--- a/include/linux/pruss_driver.h
+++ b/include/linux/pruss_driver.h
@@ -114,6 +114,21 @@ enum pru_ctable_idx {
PRU_C31,
};
+/**
+ * enum pru_type - PRU core type identifier
+ *
+ * @PRU_TYPE_PRU: Programmable Real-time Unit
+ * @PRU_TYPE_RTU: Auxiliary Programmable Real-Time Unit
+ * @PRU_TYPE_TX_PRU: Transmit Programmable Real-Time Unit
+ * @PRU_TYPE_MAX: just keep this one at the end
+ */
+enum pru_type {
+ PRU_TYPE_PRU,
+ PRU_TYPE_RTU,
+ PRU_TYPE_TX_PRU,
+ PRU_TYPE_MAX,
+};
+
/**
* enum pruss_mem - PRUSS memory range identifiers
*/
with this diff, user don't need to run any extra commands at u-boot.
Once u-boot prompt is reached, just running ping / dhcp will suffice.
Great!
<snip>
I have addressed all the above comments and made the changes needed.
below is the diff. Please have a look at it and let me know if it looks OK.
diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
index 11d83927ac..0b2b72b2c5 100644
--- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi
@@ -6,6 +6,18 @@
#include "k3-am654-r5-base-board-u-boot.dtsi"
#include "k3-am65x-binman.dtsi"
+/ {
+ chosen {
+ firmware-loader = <&fs_loader0>;
+ };
+
+ fs_loader0: fs-loader {
+ bootph-all;
+ compatible = "u-boot,fs-loader";
+ phandlepart = <&sdhci1 2>;
+ };
+};
+
&pru0_0 {
remoteproc-name = "pru0_0";
};
diff --git a/configs/am65x_evm_a53_defconfig
b/configs/am65x_evm_a53_defconfig
index 2755d7082f..c53e938abb 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -112,6 +112,7 @@ CONFIG_DM_I2C_GPIO=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
+CONFIG_FS_LOADER=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig
index b2f1e721b3..2d19935a41 100644
--- a/configs/am65x_evm_r5_defconfig
+++ b/configs/am65x_evm_r5_defconfig
@@ -98,6 +98,7 @@ CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
+CONFIG_FS_LOADER=y
CONFIG_K3_AVS0=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_HS200_SUPPORT=y
diff --git a/drivers/net/ti/icssg_prueth.c b/drivers/net/ti/icssg_prueth.c
index 40ad827e49..a2e3595956 100644
--- a/drivers/net/ti/icssg_prueth.c
+++ b/drivers/net/ti/icssg_prueth.c
@@ -62,6 +62,9 @@
/* Management packet type */
#define PRUETH_PKT_TYPE_CMD 0x10
+/* Number of PRU Cores per Slice */
+#define ICSSG_NUM_PRU_CORES 3
+
static int icssg_phy_init(struct udevice *dev)
{
struct prueth *priv = dev_get_priv(dev);
@@ -218,6 +221,116 @@ static int icssg_update_link(struct prueth *priv)
return phy->link;
}
+struct icssg_firmwares {
+ char *pru;
+ char *rtu;
+ char *txpru;
+};
+
+static struct icssg_firmwares icssg_emac_firmwares[] = {
+ {
+ .pru = "/lib/firmware/ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
+ .rtu = "/lib/firmware/ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
+ .txpru =
"/lib/firmware/ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
+ },
+ {
+ .pru = "/lib/firmware/ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
+ .rtu = "/lib/firmware/ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
+ .txpru =
"/lib/firmware/ti-pruss/am65x-sr2-txpru1-prueth-fw.elf",
+ }
+};
+
+static int icssg_start_pru_cores(struct udevice *dev)
+{
+ struct prueth *prueth = dev_get_priv(dev);
+ struct icssg_firmwares *firmwares;
+ struct udevice *rproc_dev = NULL;
+ int ret, slice;
+ u32 phandle;
+ u8 index;
+
+ slice = prueth->slice;
+ index = slice * ICSSG_NUM_PRU_CORES;
+ firmwares = icssg_emac_firmwares;
+
+ ofnode_read_u32_index(dev_ofnode(dev), "ti,prus", index, &phandle);
+ ret = uclass_get_device_by_phandle_id(UCLASS_REMOTEPROC, phandle,
&rproc_dev);
+ if (ret) {
+ dev_err(dev, "Unknown remote processor with phandle '0x%x'
requested(%d)\n",
+ phandle, ret);
+ return ret;
+ }
+
+ prueth->pru_core_id = dev_seq(rproc_dev);
+ ret = rproc_set_firmware(rproc_dev, firmwares[slice].pru);
+ if (ret)
+ return ret;
+
+ ret = rproc_boot(rproc_dev, SZ_64K);
+ if (ret) {
+ dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);
+ return -EINVAL;
+ }
+
+ ofnode_read_u32_index(dev_ofnode(dev), "ti,prus", index + 1, &phandle);
+ ret = uclass_get_device_by_phandle_id(UCLASS_REMOTEPROC, phandle,
&rproc_dev);
+ if (ret) {
+ dev_err(dev, "Unknown remote processor with phandle '0x%x'
requested(%d)\n",
+ phandle, ret);
+ goto halt_pru;
+ }
+
+ prueth->rtu_core_id = dev_seq(rproc_dev);
+ ret = rproc_set_firmware(rproc_dev, firmwares[slice].rtu);
+ if (ret)
+ goto halt_pru;
+
+ ret = rproc_boot(rproc_dev, SZ_64K);
+ if (ret) {
+ dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);
+ goto halt_pru;
+ }
+
+ ofnode_read_u32_index(dev_ofnode(dev), "ti,prus", index + 2, &phandle);
+ ret = uclass_get_device_by_phandle_id(UCLASS_REMOTEPROC, phandle,
&rproc_dev);
+ if (ret) {
+ dev_err(dev, "Unknown remote processor with phandle '0x%x'
requested(%d)\n",
+ phandle, ret);
+ goto halt_rtu;
+ }
+
+ prueth->txpru_core_id = dev_seq(rproc_dev);
+ ret = rproc_set_firmware(rproc_dev, firmwares[slice].txpru);
+ if (ret)
+ goto halt_rtu;
+
+ ret = rproc_boot(rproc_dev, SZ_64K);
+ if (ret) {
+ dev_err(dev, "failed to boot TXPRU%d: %d\n", slice, ret);
+ goto halt_rtu;
+ }
+
+ return 0;
+
+halt_rtu:
+ rproc_stop(prueth->rtu_core_id);
+
+halt_pru:
+ rproc_stop(prueth->pru_core_id);
+ return ret;
+}
+
+static int icssg_stop_pru_cores(struct udevice *dev)
+{
+ struct prueth *prueth = dev_get_priv(dev);
+
+ rproc_stop(prueth->pru_core_id);
+ rproc_stop(prueth->rtu_core_id);
+ rproc_stop(prueth->txpru_core_id);
+
+ return 0;
+}
+
static int prueth_start(struct udevice *dev)
{
struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data;
@@ -227,6 +340,10 @@ static int prueth_start(struct udevice *dev)
void *config;
int ret, i;
+ ret = icssg_start_pru_cores(dev);
+ if (ret)
+ return ret;
+
/* To differentiate channels for SLICE0 vs SLICE1 */
snprintf(chn_name, sizeof(chn_name), "tx%d-0", priv->slice);
@@ -355,9 +472,11 @@ static void prueth_stop(struct udevice *dev)
phy_shutdown(priv->phydev);
dma_disable(&priv->dma_tx);
- dma_free(&priv->dma_tx);
-
dma_disable(&priv->dma_rx);
+
+ icssg_stop_pru_cores(dev);
+
+ dma_free(&priv->dma_tx);
dma_free(&priv->dma_rx);
}
diff --git a/drivers/net/ti/icssg_prueth.h b/drivers/net/ti/icssg_prueth.h
index e41ed16a05..c92660401b 100644
--- a/drivers/net/ti/icssg_prueth.h
+++ b/drivers/net/ti/icssg_prueth.h
@@ -69,6 +69,9 @@ struct prueth {
int speed;
int duplex;
u8 icssg_hwcmdseq;
+ u8 pru_core_id;
+ u8 rtu_core_id;
+ u8 txpru_core_id;
};
/* config helpers */
diff --git a/drivers/remoteproc/rproc-uclass.c
b/drivers/remoteproc/rproc-uclass.c
index 28b362c887..a085c44eaa 100644
--- a/drivers/remoteproc/rproc-uclass.c
+++ b/drivers/remoteproc/rproc-uclass.c
@@ -13,6 +13,7 @@
#include <log.h>
#include <malloc.h>
#include <virtio_ring.h>
+#include <fs_loader.h>
#include <remoteproc.h>
#include <asm/io.h>
#include <dm/device-internal.h>
@@ -961,3 +962,90 @@ unsigned long rproc_parse_resource_table(struct
udevice *dev, struct rproc *cfg)
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);
+
+ len = strcspn(fw_name, "\n");
+ if (!len) {
+ debug("can't provide empty string for firmware name\n");
+ return -EINVAL;
+ }
+
+ p = strndup(fw_name, len);
+ if (!p)
+ return -ENOMEM;
+
+ uc_pdata->fw_name = p;
+
+ return 0;
+}
+
+int rproc_boot(struct udevice *rproc_dev, size_t fw_size)
+{
+ struct dm_rproc_uclass_pdata *uc_pdata;
+ struct udevice *fs_loader;
+ void *addr = malloc(fw_size);
+ int core_id, ret = 0;
+ char *firmware;
+ ulong rproc_addr;
+
+ if (!rproc_dev)
+ return -EINVAL;
+
+ if (!addr)
+ return -ENOMEM;
+
+ uc_pdata = dev_get_uclass_plat(rproc_dev);
+ core_id = dev_seq(rproc_dev);
+ firmware = uc_pdata->fw_name;
+
+ if (!firmware) {
+ debug("No firmware set for rproc core %d\n", core_id);
+ return -EINVAL;
+ }
+
+ /* Initialize all rproc cores */
+ rproc_init();
+
+ /* 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;
+ }
+
+ ret = request_firmware_into_buf(fs_loader, firmware, addr, fw_size, 0);
+ if (ret < 0) {
+ debug("could not request %s: %d\n", firmware, ret);
+ return ret;
+ }
+
+ rproc_addr = (ulong)addr;
+
+ debug("Loaded %s to 0x%08lX size = %d Bytes\n",
+ uc_pdata->fw_name, rproc_addr, ret);
+
+ ret = rproc_load(core_id, rproc_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, rproc_addr, ret);
+ return ret;
+ }
+
+ ret = rproc_start(core_id);
+ if (ret) {
+ debug("failed to start rproc core %d\n", core_id);
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/include/remoteproc.h b/include/remoteproc.h
index a11dc8a9b6..65b0ff7477 100644
--- a/include/remoteproc.h
+++ b/include/remoteproc.h
@@ -402,6 +402,7 @@ enum rproc_mem_type {
* @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.
+ * @fw_name: firmware name
*
* This can be accessed with dev_get_uclass_plat() for any
UCLASS_REMOTEPROC
* device.
@@ -411,6 +412,7 @@ struct dm_rproc_uclass_pdata {
const char *name;
enum rproc_mem_type mem_type;
void *driver_plat_data;
+ char *fw_name;
};
/**
@@ -704,6 +706,35 @@ unsigned long rproc_parse_resource_table(struct
udevice *dev,
struct resource_table *rproc_find_resource_table(struct udevice *dev,
unsigned int addr,
int *tablesz);
+/**
+ * rproc_set_firmware() - assign a new firmware
+ * @rproc_dev: device for wich new firmware 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
+ * @fw_size: Size of the memory to allocate for firmeware
+ *
+ * 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, size_t fw_size);
#else
static inline int rproc_init(void) { return -ENOSYS; }
static inline int rproc_dev_init(int id) { return -ENOSYS; }
@@ -743,6 +774,10 @@ static inline int rproc_elf_load_rsc_table(struct
udevice *dev, ulong fw_addr,
ulong fw_size, ulong *rsc_addr,
ulong *rsc_size)
{ 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, size_t fw_size)
+{ return -ENOSYS; }
#endif
#endif /* _RPROC_H_ */