[U-Boot] [PATCH v2 0/7] Add STM32 Cortex-M4 remoteproc driver

This patchset adds an STM32 remoteproc driver.
Patch 1 adds the xxx_translate_dma_address() API which is the equivalent of the xxx_translate_address() relying on the "dma-ranges" property instead of the "ranges" property.
Patch 2 fixes and completes function headers of remoteproc.h.
Patch 3 & 4 add the support of the ELF image loading (the current implementation supports only binary image loading).
Patch 5 is about the driver, and patches 6 & 7 are about MAINTAINERS and configs update.
Changes since v1: -Added tests for rproc_elf*() and *_translate_dma_address() -Changed memory translation ops from da_to_pa() to device_to_virt() : the name is updated and the translation now converts to virtual instead of physical. -Merged rproc_elf_is_valid() in rproc_elf_sanity_check() -Used explicit error values in rproc_elf_sanity_check() -Added and fix comments in various headers -Misc minor changes
Fabien Dessenne (7): dm: core: Introduce xxx_translate_dma_address() remoteproc: fix function headers remoteproc: add device_to_virt ops remoteproc: add elf file load support remoteproc: Introduce STM32 Cortex-M4 remoteproc driver MAINTAINERS: Add stm32 remoteproc driver configs: stm32mp15: enable stm32 remoteproc
MAINTAINERS | 1 + arch/sandbox/dts/test.dts | 4 + common/fdt_support.c | 6 + configs/stm32mp15_basic_defconfig | 2 + configs/stm32mp15_trusted_defconfig | 2 + drivers/core/of_addr.c | 4 + drivers/core/ofnode.c | 8 ++ drivers/core/read.c | 5 + drivers/remoteproc/Kconfig | 10 ++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/rproc-uclass.c | 99 +++++++++++++ drivers/remoteproc/sandbox_testproc.c | 19 +++ drivers/remoteproc/stm32_copro.c | 257 ++++++++++++++++++++++++++++++++++ include/dm/of_addr.h | 18 +++ include/dm/ofnode.h | 16 ++- include/dm/read.h | 20 ++- include/fdt_support.h | 24 ++++ include/remoteproc.h | 146 +++++++++++++------ test/dm/remoteproc.c | 122 ++++++++++++++++ test/dm/test-fdt.c | 12 ++ 20 files changed, 735 insertions(+), 41 deletions(-) create mode 100644 drivers/remoteproc/stm32_copro.c

Add the following functions to translate DMA address to CPU address: - dev_translate_dma_address() - ofnode_translate_dma_address() - of_translate_dma_address() - fdt_translate_dma_address() These functions work the same way as xxx_translate_address(), with the difference that the translation relies on the "dma-ranges" property instead of the "ranges" property.
Add related test. Test report: => ut dm fdt_translation Test: dm_test_fdt_translation: test-fdt.c Test: dm_test_fdt_translation: test-fdt.c (flat tree) Failures: 0
Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- arch/sandbox/dts/test.dts | 4 ++++ common/fdt_support.c | 6 ++++++ drivers/core/of_addr.c | 4 ++++ drivers/core/ofnode.c | 8 ++++++++ drivers/core/read.c | 5 +++++ include/dm/of_addr.h | 18 ++++++++++++++++++ include/dm/ofnode.h | 16 +++++++++++++++- include/dm/read.h | 20 +++++++++++++++++++- include/fdt_support.h | 24 ++++++++++++++++++++++++ test/dm/test-fdt.c | 12 ++++++++++++ 10 files changed, 115 insertions(+), 2 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8b2d645..a37e10c 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -732,6 +732,10 @@ 3 0x300 0xB000 0x1000 >;
+ dma-ranges = <0 0x000 0x10000000 0x1000 + 1 0x100 0x20000000 0x1000 + >; + dev@0,0 { compatible = "denx,u-boot-fdt-dummy"; reg = <0 0x0 0x1000>; diff --git a/common/fdt_support.c b/common/fdt_support.c index 4e7cf6e..6ec0742 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1279,6 +1279,12 @@ u64 fdt_translate_address(const void *blob, int node_offset, return __of_translate_address(blob, node_offset, in_addr, "ranges"); }
+u64 fdt_translate_dma_address(const void *blob, int node_offset, + const fdt32_t *in_addr) +{ + return __of_translate_address(blob, node_offset, in_addr, "dma-ranges"); +} + /** * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and * who's reg property matches a physical cpu address diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c index 1bfaaee..4e256d9 100644 --- a/drivers/core/of_addr.c +++ b/drivers/core/of_addr.c @@ -318,6 +318,10 @@ u64 of_translate_address(const struct device_node *dev, const __be32 *in_addr) return __of_translate_address(dev, in_addr, "ranges"); }
+u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_addr) +{ + return __of_translate_address(dev, in_addr, "dma-ranges"); +}
static int __of_address_to_resource(const struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index cc0c031..e68a735 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -763,6 +763,14 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr) return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr); }
+u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr) +{ + if (ofnode_is_np(node)) + return of_translate_dma_address(ofnode_to_np(node), in_addr); + else + return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr); +} + int ofnode_device_is_compatible(ofnode node, const char *compat) { if (ofnode_is_np(node)) diff --git a/drivers/core/read.c b/drivers/core/read.c index 6bda077..1a044b0 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -265,6 +265,11 @@ u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr) return ofnode_translate_address(dev_ofnode(dev), in_addr); }
+u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr) +{ + return ofnode_translate_dma_address(dev_ofnode(dev), in_addr); +} + int dev_read_alias_highest_id(const char *stem) { if (of_live_active()) diff --git a/include/dm/of_addr.h b/include/dm/of_addr.h index 12b1a99..3fa1ffc 100644 --- a/include/dm/of_addr.h +++ b/include/dm/of_addr.h @@ -27,6 +27,24 @@ u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
/** + * of_translate_dma_address() - translate a device-tree DMA address to a CPU + * address + * + * Translate a DMA address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + * + * @np: node to check + * @in_addr: pointer to input DMA address + * @return translated DMA address or OF_BAD_ADDR on error + */ +u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr); + +/** * of_get_address() - obtain an address from a node * * Extract an address from a node, returns the region size and the address diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index d206ee2..07a3f93 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -751,7 +751,7 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname, node = ofnode_next_subnode(node))
/** - * ofnode_translate_address() - Tranlate a device-tree address + * ofnode_translate_address() - Translate a device-tree address * * Translate an address from the device-tree into a CPU physical address. This * function walks up the tree and applies the various bus mappings along the @@ -765,6 +765,20 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname, u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
/** + * ofnode_translate_dma_address() - Translate a device-tree DMA address + * + * Translate a DMA address from the device-tree into a CPU physical address. + * This function walks up the tree and applies the various bus mappings along + * the way. + * + * @ofnode: Device tree node giving the context in which to translate the + * DMA address + * @in_addr: pointer to the DMA address to translate + * @return the translated DMA address; OF_BAD_ADDR on error + */ +u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr); + +/** * ofnode_device_is_compatible() - check if the node is compatible with compat * * This allows to check whether the node is comaptible with the compat. diff --git a/include/dm/read.h b/include/dm/read.h index 60b727c..62d4be6 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -499,7 +499,7 @@ int dev_read_resource_byname(struct udevice *dev, const char *name, struct resource *res);
/** - * dev_translate_address() - Tranlate a device-tree address + * dev_translate_address() - Translate a device-tree address * * Translate an address from the device-tree into a CPU physical address. This * function walks up the tree and applies the various bus mappings along the @@ -512,6 +512,19 @@ int dev_read_resource_byname(struct udevice *dev, const char *name, u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr);
/** + * dev_translate_dma_address() - Translate a device-tree DMA address + * + * Translate a DMA address from the device-tree into a CPU physical address. + * This function walks up the tree and applies the various bus mappings along + * the way. + * + * @dev: device giving the context in which to translate the DMA address + * @in_addr: pointer to the DMA address to translate + * @return the translated DMA address; OF_BAD_ADDR on error + */ +u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr); + +/** * dev_read_alias_highest_id - Get highest alias id for the given stem * @stem: Alias stem to be examined * @@ -751,6 +764,11 @@ static inline u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_a return ofnode_translate_address(dev_ofnode(dev), in_addr); }
+static inline u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr) +{ + return ofnode_translate_dma_address(dev_ofnode(dev), in_addr); +} + static inline int dev_read_alias_highest_id(const char *stem) { return fdtdec_get_alias_highest_id(gd->fdt_blob, stem); diff --git a/include/fdt_support.h b/include/fdt_support.h index 27fe564..cefb2b2 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -218,8 +218,32 @@ static inline void fdt_fixup_mtdparts(void *fdt, #endif
void fdt_del_node_and_alias(void *blob, const char *alias); + +/** + * Translate an address from the DT into a CPU physical address + * + * The translation relies on the "ranges" property. + * + * @param blob Pointer to device tree blob + * @param node_offset Node DT offset + * @param in_addr Pointer to the address to translate + * @return translated address or OF_BAD_ADDR on error + */ u64 fdt_translate_address(const void *blob, int node_offset, const __be32 *in_addr); +/** + * Translate a DMA address from the DT into a CPU physical address + * + * The translation relies on the "dma-ranges" property. + * + * @param blob Pointer to device tree blob + * @param node_offset Node DT offset + * @param in_addr Pointer to the DMA address to translate + * @return translated DMA address or OF_BAD_ADDR on error + */ +u64 fdt_translate_dma_address(const void *blob, int node_offset, + const __be32 *in_addr); + int fdt_node_offset_by_compat_reg(void *blob, const char *compat, phys_addr_t compat_off); int fdt_alloc_phandle(void *blob); diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index be16c99..ad85916 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -490,6 +490,7 @@ U_BOOT_DRIVER(fdt_dummy_drv) = { static int dm_test_fdt_translation(struct unit_test_state *uts) { struct udevice *dev; + fdt32_t dma_addr[2];
/* Some simple translations */ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev)); @@ -509,6 +510,17 @@ static int dm_test_fdt_translation(struct unit_test_state *uts) ut_asserteq_str("dev@42", dev->name); ut_asserteq(0x42, dev_read_addr(dev));
+ /* dma address translation */ + ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev)); + dma_addr[0] = cpu_to_be32(0); + dma_addr[1] = cpu_to_be32(0); + ut_asserteq(0x10000000, dev_translate_dma_address(dev, dma_addr)); + + ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 1, true, &dev)); + dma_addr[0] = cpu_to_be32(1); + dma_addr[1] = cpu_to_be32(0x100); + ut_asserteq(0x20000000, dev_translate_dma_address(dev, dma_addr)); + return 0; } DM_TEST(dm_test_fdt_translation, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

Add full function comment headers. Fix rproc_is_initialized() return value description.
Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- include/remoteproc.h | 104 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 36 deletions(-)
diff --git a/include/remoteproc.h b/include/remoteproc.h index a59dba8..aa90a67 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -45,32 +45,73 @@ struct dm_rproc_uclass_pdata { };
/** - * 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 - Driver model remote proc operations. + * + * This defines the operations provided by remote proc driver. */ struct dm_rproc_ops { + /** + * init() - Initialize the remoteproc device (optional) + * + * This is called after the probe is completed allowing the remote + * processor drivers to split up the initializations between probe and + * init if needed. + * + * @dev: Remote proc device + * @return 0 if all ok, else appropriate error value. + */ int (*init)(struct udevice *dev); + + /** + * load() - Load the remoteproc device using data provided (mandatory) + * + * Load the remoteproc device with an image, do not start the device. + * + * @dev: Remote proc device + * @addr: Address of the image to be loaded + * @size: Size of the image to be loaded + * @return 0 if all ok, else appropriate error value. + */ int (*load)(struct udevice *dev, ulong addr, ulong size); + + /** + * start() - Start the remoteproc device (mandatory) + * + * @dev: Remote proc device + * @return 0 if all ok, else appropriate error value. + */ int (*start)(struct udevice *dev); + + /** + * stop() - Stop the remoteproc device (optional) + * + * @dev: Remote proc device + * @return 0 if all ok, else appropriate error value. + */ int (*stop)(struct udevice *dev); + + /** + * reset() - Reset the remoteproc device (optional) + * + * @dev: Remote proc device + * @return 0 if all ok, else appropriate error value. + */ int (*reset)(struct udevice *dev); + + /** + * is_running() - Check if the remote processor is running (optional) + * + * @dev: Remote proc device + * @return 0 if running, 1 if not running, -ve on error. + */ int (*is_running)(struct udevice *dev); + + /** + * ping() - Ping the remote device for basic communication (optional) + * + * @dev: Remote proc device + * @return 0 on success, 1 if not responding, -ve on other errors. + */ int (*ping)(struct udevice *dev); };
@@ -80,23 +121,20 @@ struct dm_rproc_ops { #ifdef CONFIG_REMOTEPROC /** * rproc_init() - Initialize all bound remote proc devices - * - * Return: 0 if all ok, else appropriate error value. + * @return 0 if all ok, else appropriate error value. */ int rproc_init(void);
/** * rproc_dev_init() - Initialize a remote proc device based on id * @id: id of the remote processor - * - * Return: 0 if all ok, else appropriate error value. + * @return 0 if all ok, else appropriate error value. */ int rproc_dev_init(int id);
/** * rproc_is_initialized() - check to see if remoteproc devices are initialized - * - * Return: 0 if all devices are initialized, else appropriate error value. + * @return true if all devices are initialized, false otherwise. */ bool rproc_is_initialized(void);
@@ -105,55 +143,49 @@ bool rproc_is_initialized(void); * @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. + * @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. + * @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. + * @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. + * @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 + * @return 0 if all ok, else appropriate error value. * * 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 + * @return 0 if running, 1 if not running, -ve on error. * * 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

Introduce the device_to_virt function to allow translation between device address (remote processor view) and virtual address (main processor view).
Signed-off-by: Loic Pallardy loic.pallardy@st.com Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- include/remoteproc.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/include/remoteproc.h b/include/remoteproc.h index aa90a67..aef6ff2 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -113,6 +113,18 @@ struct dm_rproc_ops { * @return 0 on success, 1 if not responding, -ve on other errors. */ int (*ping)(struct udevice *dev); + + /** + * device_to_virt() - Return translated virtual address (optional) + * + * Translate a device address (remote processor view) to virtual + * address (main processor view). + * + * @dev: Remote proc device + * @da: Device address + * @return virtual address. + */ + void * (*device_to_virt)(struct udevice *dev, ulong da); };
/* Accessor */

The current implementation supports only binary file load. Add helpers to support ELF format (sanity check, and load). Note that since an ELF image is built for the remote processor, the load function uses the device_to_virt ops to translate the addresses. Implement a basic translation for sandbox_testproc.
Add related tests. Test result: => ut dm remoteproc_elf Test: dm_test_remoteproc_elf: remoteproc.c Test: dm_test_remoteproc_elf: remoteproc.c (flat tree) Failures: 0
Signed-off-by: Loic Pallardy loic.pallardy@st.com Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- drivers/remoteproc/rproc-uclass.c | 99 +++++++++++++++++++++++++++ drivers/remoteproc/sandbox_testproc.c | 19 ++++++ include/remoteproc.h | 30 ++++++++- test/dm/remoteproc.c | 122 ++++++++++++++++++++++++++++++++++ 4 files changed, 267 insertions(+), 3 deletions(-)
diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index c8a41a6..4d85732 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -5,6 +5,7 @@ */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include <common.h> +#include <elf.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> @@ -291,6 +292,104 @@ int rproc_dev_init(int id) return ret; }
+/* Basic function to verify ELF image format */ +int rproc_elf_sanity_check(ulong addr, ulong size) +{ + Elf32_Ehdr *ehdr; + char class; + + if (!addr) { + pr_debug("Invalid fw address?\n"); + return -EFAULT; + } + + if (size < sizeof(Elf32_Ehdr)) { + pr_debug("Image is too small\n"); + return -ENOSPC; + } + + ehdr = (Elf32_Ehdr *)addr; + class = ehdr->e_ident[EI_CLASS]; + + if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) { + pr_debug("Not an executable ELF32 image\n"); + return -EPROTONOSUPPORT; + } + + /* We assume the firmware has the same endianness as the host */ +# ifdef __LITTLE_ENDIAN + if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { +# else /* BIG ENDIAN */ + if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) { +# endif + pr_debug("Unsupported firmware endianness\n"); + return -EILSEQ; + } + + if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) { + pr_debug("Image is too small\n"); + return -ENOSPC; + } + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + pr_debug("Image is corrupted (bad magic)\n"); + return -EBADF; + } + + if (ehdr->e_phnum == 0) { + pr_debug("No loadable segments\n"); + return -ENOEXEC; + } + + if (ehdr->e_phoff > size) { + pr_debug("Firmware size is too small\n"); + return -ENOSPC; + } + + return 0; +} + +/* A very simple elf loader, assumes the image is valid */ +int rproc_elf_load_image(struct udevice *dev, unsigned long addr) +{ + Elf32_Ehdr *ehdr; /* Elf header structure pointer */ + Elf32_Phdr *phdr; /* Program header structure pointer */ + const struct dm_rproc_ops *ops; + unsigned int i; + + ehdr = (Elf32_Ehdr *)addr; + phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); + + ops = rproc_get_ops(dev); + + /* Load each program header */ + for (i = 0; i < ehdr->e_phnum; ++i) { + void *dst = (void *)(uintptr_t)phdr->p_paddr; + void *src = (void *)addr + phdr->p_offset; + + if (phdr->p_type != PT_LOAD) + continue; + + if (ops->device_to_virt) + dst = ops->device_to_virt(dev, (ulong)dst); + + dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n", + i, dst, phdr->p_filesz); + if (phdr->p_filesz) + memcpy(dst, src, phdr->p_filesz); + if (phdr->p_filesz != phdr->p_memsz) + memset(dst + phdr->p_filesz, 0x00, + phdr->p_memsz - phdr->p_filesz); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + phdr->p_filesz, + ARCH_DMA_MINALIGN) - + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); + ++phdr; + } + + return 0; +} + int rproc_load(int id, ulong addr, ulong size) { struct udevice *dev = NULL; diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c index 51a67e6..5f35119 100644 --- a/drivers/remoteproc/sandbox_testproc.c +++ b/drivers/remoteproc/sandbox_testproc.c @@ -8,6 +8,7 @@ #include <dm.h> #include <errno.h> #include <remoteproc.h> +#include <asm/io.h>
/** * enum sandbox_state - different device states @@ -300,6 +301,23 @@ static int sandbox_testproc_ping(struct udevice *dev) return ret; }
+#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000 +/** + * sandbox_testproc_device_to_virt() - Convert device address to virtual address + * @dev: device to operate upon + * @da: device address + * @return converted virtual address + */ +static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da) +{ + u64 paddr; + + /* Use a simple offset conversion */ + paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET; + + return phys_to_virt(paddr); +} + static const struct dm_rproc_ops sandbox_testproc_ops = { .init = sandbox_testproc_init, .reset = sandbox_testproc_reset, @@ -308,6 +326,7 @@ static const struct dm_rproc_ops sandbox_testproc_ops = { .stop = sandbox_testproc_stop, .is_running = sandbox_testproc_is_running, .ping = sandbox_testproc_ping, + .device_to_virt = sandbox_testproc_device_to_virt, };
static const struct udevice_id sandbox_ids[] = { diff --git a/include/remoteproc.h b/include/remoteproc.h index aef6ff2..f74ccc2 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -151,10 +151,10 @@ int rproc_dev_init(int id); bool rproc_is_initialized(void);
/** - * rproc_load() - load binary to a remote processor + * rproc_load() - load binary or elf 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 + * @addr: address in memory where the image is located + * @size: size of the image * @return 0 if all ok, else appropriate error value. */ int rproc_load(int id, ulong addr, ulong size); @@ -200,6 +200,26 @@ int rproc_ping(int id); * processor, but just ensures that it is out of reset and executing code. */ int rproc_is_running(int id); + +/** + * rproc_elf_sanity_check() - Verify if an image is a valid ELF one + * + * Check if a valid ELF image exists at the given memory location. Verify + * basic ELF format requirements like magic number and sections size. + * + * @addr: address of the image to verify + * @size: size of the image + * @return 0 if the image looks good, else appropriate error value. + */ +int rproc_elf_sanity_check(ulong addr, ulong size); + +/** + * rproc_elf_load_image() - load an ELF image + * @dev: device loading the ELF image + * @addr: valid ELF image address + * @return 0 if the image is successfully loaded, else appropriate error value. + */ +int rproc_elf_load_image(struct udevice *dev, unsigned long addr); #else static inline int rproc_init(void) { return -ENOSYS; } static inline int rproc_dev_init(int id) { return -ENOSYS; } @@ -210,6 +230,10 @@ 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; } +static inline int rproc_elf_sanity_check(ulong addr, + ulong size) { return -ENOSYS; } +static inline int rproc_elf_load_image(struct udevice *dev, + unsigned long addr) { return -ENOSYS; } #endif
#endif /* _RPROC_H_ */ diff --git a/test/dm/remoteproc.c b/test/dm/remoteproc.c index 3975c67..8d444fc 100644 --- a/test/dm/remoteproc.c +++ b/test/dm/remoteproc.c @@ -5,8 +5,10 @@ */ #include <common.h> #include <dm.h> +#include <elf.h> #include <errno.h> #include <remoteproc.h> +#include <asm/io.h> #include <dm/test.h> #include <test/ut.h> /** @@ -65,3 +67,123 @@ static int dm_test_remoteproc_base(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_remoteproc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +#define DEVICE_TO_PHYSICAL_OFFSET 0x1000 +/** + * dm_test_remoteproc_elf() - test the ELF operations + * @uts: unit test state + * + * Return: 0 if test passed, else error + */ +static int dm_test_remoteproc_elf(struct unit_test_state *uts) +{ + u8 valid_elf32[] = { + /* @0x00 - ELF HEADER - */ + /* ELF magic */ + 0x7f, 0x45, 0x4c, 0x46, + /* 32 Bits */ + 0x01, + /* Endianness */ +#ifdef __LITTLE_ENDIAN + 0x01, +#else + 0x02, +#endif + /* Version */ + 0x01, + /* Padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Type : executable */ + 0x02, 0x00, + /* Machine: ARM */ + 0x28, 0x00, + /* Version */ + 0x01, 0x00, 0x00, 0x00, + /* Entry */ + 0x00, 0x00, 0x00, 0x08, + /* phoff (program header offset @ 0x40)*/ + 0x40, 0x00, 0x00, 0x00, + /* shoff (section header offset : none) */ + 0x00, 0x00, 0x00, 0x00, + /* flags */ + 0x00, 0x00, 0x00, 0x00, + /* ehsize (elf header size = 0x34) */ + 0x34, 0x00, + /* phentsize (program header size = 0x20) */ + 0x20, 0x00, + /* phnum (program header number : 1) */ + 0x01, 0x00, + /* shentsize (section heade size : none) */ + 0x00, 0x00, + /* shnum (section header number: none) */ + 0x00, 0x00, + /* shstrndx (section header name section index: none) */ + 0x00, 0x00, + /* padding */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* @0x40 - PROGRAM HEADER TABLE - */ + /* type : PT_LOAD */ + 0x01, 0x00, 0x00, 0x00, + /* offset */ + 0x00, 0x00, 0x00, 0x00, + /* vaddr */ + 0x00, 0x00, 0x00, 0x00, + /* paddr : physical address */ + 0x00, 0x00, 0x00, 0x00, + /* filesz : 0x20 bytes (program header size) */ + 0x20, 0x00, 0x00, 0x00, + /* memsz = filesz */ + 0x20, 0x00, 0x00, 0x00, + /* flags : readable and exectuable */ + 0x05, 0x00, 0x00, 0x00, + /* padding */ + 0x00, 0x00, 0x00, 0x00, + }; + unsigned int size = ARRAY_SIZE(valid_elf32); + struct udevice *dev; + phys_addr_t loaded_firmware_paddr; + void *loaded_firmware; + u32 loaded_firmware_size; + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)valid_elf32; + Elf32_Phdr *phdr = (Elf32_Phdr *)(valid_elf32 + ehdr->e_phoff); + + ut_assertok(uclass_get_device(UCLASS_REMOTEPROC, 0, &dev)); + + /* + * In its Program Header Table, let the firmware specifies to be loaded + * at SDRAM_BASE *device* address (p_paddr field). + * Its size is defined by the p_filesz field. + */ + phdr->p_paddr = CONFIG_SYS_SDRAM_BASE; + loaded_firmware_size = phdr->p_filesz; + + /* + * This *device* address is converted to a *physical* address by the + * device_to_virt() operation of sandbox_test_rproc which returns + * DeviceAddress + DEVICE_TO_PHYSICAL_OFFSET. + * This is where we expect to get the firmware loaded. + */ + loaded_firmware_paddr = phdr->p_paddr + DEVICE_TO_PHYSICAL_OFFSET; + loaded_firmware = map_physmem(loaded_firmware_paddr, + loaded_firmware_size, MAP_NOCACHE); + ut_assertnonnull(loaded_firmware); + memset(loaded_firmware, 0, loaded_firmware_size); + + /* Verify valid ELF format */ + ut_assertok(rproc_elf_sanity_check((ulong)valid_elf32, size)); + + /* Load firmware in loaded_firmware, and verify it */ + ut_assertok(rproc_elf_load_image(dev, (unsigned long)valid_elf32)); + ut_assertok(memcmp(loaded_firmware, valid_elf32, loaded_firmware_size)); + unmap_physmem(loaded_firmware, MAP_NOCACHE); + + /* Invalid ELF Magic */ + valid_elf32[0] = 0; + ut_asserteq(-EPROTONOSUPPORT, + rproc_elf_sanity_check((ulong)valid_elf32, size)); + + return 0; +} +DM_TEST(dm_test_remoteproc_elf, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

On 27/05/19 5:53 PM, Fabien Dessenne wrote:
The current implementation supports only binary file load. Add helpers to support ELF format (sanity check, and load). Note that since an ELF image is built for the remote processor, the load function uses the device_to_virt ops to translate the addresses. Implement a basic translation for sandbox_testproc.
Add related tests. Test result: => ut dm remoteproc_elf Test: dm_test_remoteproc_elf: remoteproc.c Test: dm_test_remoteproc_elf: remoteproc.c (flat tree) Failures: 0
Signed-off-by: Loic Pallardy loic.pallardy@st.com Signed-off-by: Fabien Dessenne fabien.dessenne@st.com
Can you create a new file(rproc-elf-loader.c) or something similar for elf loading support. Ill be sending 64bit elf loading support soon. Instead of cluttering rproc-uclass, it is better to separate out elf loading support.
Thanks and regards, Lokesh
drivers/remoteproc/rproc-uclass.c | 99 +++++++++++++++++++++++++++ drivers/remoteproc/sandbox_testproc.c | 19 ++++++ include/remoteproc.h | 30 ++++++++- test/dm/remoteproc.c | 122 ++++++++++++++++++++++++++++++++++ 4 files changed, 267 insertions(+), 3 deletions(-)
diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index c8a41a6..4d85732 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -5,6 +5,7 @@ */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include <common.h> +#include <elf.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> @@ -291,6 +292,104 @@ int rproc_dev_init(int id) return ret; }
+/* Basic function to verify ELF image format */ +int rproc_elf_sanity_check(ulong addr, ulong size) +{
- Elf32_Ehdr *ehdr;
- char class;
- if (!addr) {
pr_debug("Invalid fw address?\n");
return -EFAULT;
- }
- if (size < sizeof(Elf32_Ehdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
- }
- ehdr = (Elf32_Ehdr *)addr;
- class = ehdr->e_ident[EI_CLASS];
- if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
pr_debug("Not an executable ELF32 image\n");
return -EPROTONOSUPPORT;
- }
- /* We assume the firmware has the same endianness as the host */
+# ifdef __LITTLE_ENDIAN
- if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
- if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
pr_debug("Unsupported firmware endianness\n");
return -EILSEQ;
- }
- if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
- }
- if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
pr_debug("Image is corrupted (bad magic)\n");
return -EBADF;
- }
- if (ehdr->e_phnum == 0) {
pr_debug("No loadable segments\n");
return -ENOEXEC;
- }
- if (ehdr->e_phoff > size) {
pr_debug("Firmware size is too small\n");
return -ENOSPC;
- }
- return 0;
+}
+/* A very simple elf loader, assumes the image is valid */ +int rproc_elf_load_image(struct udevice *dev, unsigned long addr) +{
- Elf32_Ehdr *ehdr; /* Elf header structure pointer */
- Elf32_Phdr *phdr; /* Program header structure pointer */
- const struct dm_rproc_ops *ops;
- unsigned int i;
- ehdr = (Elf32_Ehdr *)addr;
- phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
- ops = rproc_get_ops(dev);
- /* Load each program header */
- for (i = 0; i < ehdr->e_phnum; ++i) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
if (phdr->p_type != PT_LOAD)
continue;
if (ops->device_to_virt)
dst = ops->device_to_virt(dev, (ulong)dst);
dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
if (phdr->p_filesz)
memcpy(dst, src, phdr->p_filesz);
if (phdr->p_filesz != phdr->p_memsz)
memset(dst + phdr->p_filesz, 0x00,
phdr->p_memsz - phdr->p_filesz);
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
roundup((unsigned long)dst + phdr->p_filesz,
ARCH_DMA_MINALIGN) -
rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
++phdr;
- }
- return 0;
+}
int rproc_load(int id, ulong addr, ulong size) { struct udevice *dev = NULL; diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c index 51a67e6..5f35119 100644 --- a/drivers/remoteproc/sandbox_testproc.c +++ b/drivers/remoteproc/sandbox_testproc.c @@ -8,6 +8,7 @@ #include <dm.h> #include <errno.h> #include <remoteproc.h> +#include <asm/io.h>
/**
- enum sandbox_state - different device states
@@ -300,6 +301,23 @@ static int sandbox_testproc_ping(struct udevice *dev) return ret; }
+#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000 +/**
- sandbox_testproc_device_to_virt() - Convert device address to virtual address
- @dev: device to operate upon
- @da: device address
- @return converted virtual address
- */
+static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da) +{
- u64 paddr;
- /* Use a simple offset conversion */
- paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
- return phys_to_virt(paddr);
+}
static const struct dm_rproc_ops sandbox_testproc_ops = { .init = sandbox_testproc_init, .reset = sandbox_testproc_reset, @@ -308,6 +326,7 @@ static const struct dm_rproc_ops sandbox_testproc_ops = { .stop = sandbox_testproc_stop, .is_running = sandbox_testproc_is_running, .ping = sandbox_testproc_ping,
- .device_to_virt = sandbox_testproc_device_to_virt,
};
static const struct udevice_id sandbox_ids[] = { diff --git a/include/remoteproc.h b/include/remoteproc.h index aef6ff2..f74ccc2 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -151,10 +151,10 @@ int rproc_dev_init(int id); bool rproc_is_initialized(void);
/**
- rproc_load() - load binary to a remote processor
- rproc_load() - load binary or elf 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
- @addr: address in memory where the image is located
*/
- @size: size of the image
- @return 0 if all ok, else appropriate error value.
int rproc_load(int id, ulong addr, ulong size); @@ -200,6 +200,26 @@ int rproc_ping(int id);
- processor, but just ensures that it is out of reset and executing code.
*/ int rproc_is_running(int id);
+/**
- rproc_elf_sanity_check() - Verify if an image is a valid ELF one
- Check if a valid ELF image exists at the given memory location. Verify
- basic ELF format requirements like magic number and sections size.
- @addr: address of the image to verify
- @size: size of the image
- @return 0 if the image looks good, else appropriate error value.
- */
+int rproc_elf_sanity_check(ulong addr, ulong size);
+/**
- rproc_elf_load_image() - load an ELF image
- @dev: device loading the ELF image
- @addr: valid ELF image address
- @return 0 if the image is successfully loaded, else appropriate error value.
- */
+int rproc_elf_load_image(struct udevice *dev, unsigned long addr); #else static inline int rproc_init(void) { return -ENOSYS; } static inline int rproc_dev_init(int id) { return -ENOSYS; } @@ -210,6 +230,10 @@ 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; } +static inline int rproc_elf_sanity_check(ulong addr,
ulong size) { return -ENOSYS; }
+static inline int rproc_elf_load_image(struct udevice *dev,
unsigned long addr) { return -ENOSYS; }
#endif
#endif /* _RPROC_H_ */ diff --git a/test/dm/remoteproc.c b/test/dm/remoteproc.c index 3975c67..8d444fc 100644 --- a/test/dm/remoteproc.c +++ b/test/dm/remoteproc.c @@ -5,8 +5,10 @@ */ #include <common.h> #include <dm.h> +#include <elf.h> #include <errno.h> #include <remoteproc.h> +#include <asm/io.h> #include <dm/test.h> #include <test/ut.h> /** @@ -65,3 +67,123 @@ static int dm_test_remoteproc_base(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_remoteproc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+#define DEVICE_TO_PHYSICAL_OFFSET 0x1000 +/**
- dm_test_remoteproc_elf() - test the ELF operations
- @uts: unit test state
- Return: 0 if test passed, else error
- */
+static int dm_test_remoteproc_elf(struct unit_test_state *uts) +{
- u8 valid_elf32[] = {
/* @0x00 - ELF HEADER - */
/* ELF magic */
0x7f, 0x45, 0x4c, 0x46,
/* 32 Bits */
0x01,
/* Endianness */
+#ifdef __LITTLE_ENDIAN
0x01,
+#else
0x02,
+#endif
/* Version */
0x01,
/* Padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Type : executable */
0x02, 0x00,
/* Machine: ARM */
0x28, 0x00,
/* Version */
0x01, 0x00, 0x00, 0x00,
/* Entry */
0x00, 0x00, 0x00, 0x08,
/* phoff (program header offset @ 0x40)*/
0x40, 0x00, 0x00, 0x00,
/* shoff (section header offset : none) */
0x00, 0x00, 0x00, 0x00,
/* flags */
0x00, 0x00, 0x00, 0x00,
/* ehsize (elf header size = 0x34) */
0x34, 0x00,
/* phentsize (program header size = 0x20) */
0x20, 0x00,
/* phnum (program header number : 1) */
0x01, 0x00,
/* shentsize (section heade size : none) */
0x00, 0x00,
/* shnum (section header number: none) */
0x00, 0x00,
/* shstrndx (section header name section index: none) */
0x00, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
/* @0x40 - PROGRAM HEADER TABLE - */
/* type : PT_LOAD */
0x01, 0x00, 0x00, 0x00,
/* offset */
0x00, 0x00, 0x00, 0x00,
/* vaddr */
0x00, 0x00, 0x00, 0x00,
/* paddr : physical address */
0x00, 0x00, 0x00, 0x00,
/* filesz : 0x20 bytes (program header size) */
0x20, 0x00, 0x00, 0x00,
/* memsz = filesz */
0x20, 0x00, 0x00, 0x00,
/* flags : readable and exectuable */
0x05, 0x00, 0x00, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
- };
- unsigned int size = ARRAY_SIZE(valid_elf32);
- struct udevice *dev;
- phys_addr_t loaded_firmware_paddr;
- void *loaded_firmware;
- u32 loaded_firmware_size;
- Elf32_Ehdr *ehdr = (Elf32_Ehdr *)valid_elf32;
- Elf32_Phdr *phdr = (Elf32_Phdr *)(valid_elf32 + ehdr->e_phoff);
- ut_assertok(uclass_get_device(UCLASS_REMOTEPROC, 0, &dev));
- /*
* In its Program Header Table, let the firmware specifies to be loaded
* at SDRAM_BASE *device* address (p_paddr field).
* Its size is defined by the p_filesz field.
*/
- phdr->p_paddr = CONFIG_SYS_SDRAM_BASE;
- loaded_firmware_size = phdr->p_filesz;
- /*
* This *device* address is converted to a *physical* address by the
* device_to_virt() operation of sandbox_test_rproc which returns
* DeviceAddress + DEVICE_TO_PHYSICAL_OFFSET.
* This is where we expect to get the firmware loaded.
*/
- loaded_firmware_paddr = phdr->p_paddr + DEVICE_TO_PHYSICAL_OFFSET;
- loaded_firmware = map_physmem(loaded_firmware_paddr,
loaded_firmware_size, MAP_NOCACHE);
- ut_assertnonnull(loaded_firmware);
- memset(loaded_firmware, 0, loaded_firmware_size);
- /* Verify valid ELF format */
- ut_assertok(rproc_elf_sanity_check((ulong)valid_elf32, size));
- /* Load firmware in loaded_firmware, and verify it */
- ut_assertok(rproc_elf_load_image(dev, (unsigned long)valid_elf32));
- ut_assertok(memcmp(loaded_firmware, valid_elf32, loaded_firmware_size));
- unmap_physmem(loaded_firmware, MAP_NOCACHE);
- /* Invalid ELF Magic */
- valid_elf32[0] = 0;
- ut_asserteq(-EPROTONOSUPPORT,
rproc_elf_sanity_check((ulong)valid_elf32, size));
- return 0;
+} +DM_TEST(dm_test_remoteproc_elf, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

Hi Lokesh
On 29/05/2019 6:21 AM, Lokesh Vutla wrote:
On 27/05/19 5:53 PM, Fabien Dessenne wrote:
The current implementation supports only binary file load. Add helpers to support ELF format (sanity check, and load). Note that since an ELF image is built for the remote processor, the load function uses the device_to_virt ops to translate the addresses. Implement a basic translation for sandbox_testproc.
Add related tests. Test result: => ut dm remoteproc_elf Test: dm_test_remoteproc_elf: remoteproc.c Test: dm_test_remoteproc_elf: remoteproc.c (flat tree) Failures: 0
Signed-off-by: Loic Pallardy loic.pallardy@st.com Signed-off-by: Fabien Dessenne fabien.dessenne@st.com
Can you create a new file(rproc-elf-loader.c) or something similar for elf loading support.
It sounds good, I'll do that.
Ill be sending 64bit elf loading support soon. Instead of cluttering rproc-uclass, it is better to separate out elf loading support.
Since you plan support for elf64, I may consider renaming the elf functions in elf32. I'll check this too.
BR
Fabien
Thanks and regards, Lokesh
drivers/remoteproc/rproc-uclass.c | 99 +++++++++++++++++++++++++++ drivers/remoteproc/sandbox_testproc.c | 19 ++++++ include/remoteproc.h | 30 ++++++++- test/dm/remoteproc.c | 122 ++++++++++++++++++++++++++++++++++ 4 files changed, 267 insertions(+), 3 deletions(-)
diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index c8a41a6..4d85732 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -5,6 +5,7 @@ */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include <common.h> +#include <elf.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> @@ -291,6 +292,104 @@ int rproc_dev_init(int id) return ret; }
+/* Basic function to verify ELF image format */ +int rproc_elf_sanity_check(ulong addr, ulong size) +{
- Elf32_Ehdr *ehdr;
- char class;
- if (!addr) {
pr_debug("Invalid fw address?\n");
return -EFAULT;
- }
- if (size < sizeof(Elf32_Ehdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
- }
- ehdr = (Elf32_Ehdr *)addr;
- class = ehdr->e_ident[EI_CLASS];
- if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
pr_debug("Not an executable ELF32 image\n");
return -EPROTONOSUPPORT;
- }
- /* We assume the firmware has the same endianness as the host */
+# ifdef __LITTLE_ENDIAN
- if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
- if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
pr_debug("Unsupported firmware endianness\n");
return -EILSEQ;
- }
- if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
- }
- if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
pr_debug("Image is corrupted (bad magic)\n");
return -EBADF;
- }
- if (ehdr->e_phnum == 0) {
pr_debug("No loadable segments\n");
return -ENOEXEC;
- }
- if (ehdr->e_phoff > size) {
pr_debug("Firmware size is too small\n");
return -ENOSPC;
- }
- return 0;
+}
+/* A very simple elf loader, assumes the image is valid */ +int rproc_elf_load_image(struct udevice *dev, unsigned long addr) +{
- Elf32_Ehdr *ehdr; /* Elf header structure pointer */
- Elf32_Phdr *phdr; /* Program header structure pointer */
- const struct dm_rproc_ops *ops;
- unsigned int i;
- ehdr = (Elf32_Ehdr *)addr;
- phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
- ops = rproc_get_ops(dev);
- /* Load each program header */
- for (i = 0; i < ehdr->e_phnum; ++i) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
if (phdr->p_type != PT_LOAD)
continue;
if (ops->device_to_virt)
dst = ops->device_to_virt(dev, (ulong)dst);
dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
if (phdr->p_filesz)
memcpy(dst, src, phdr->p_filesz);
if (phdr->p_filesz != phdr->p_memsz)
memset(dst + phdr->p_filesz, 0x00,
phdr->p_memsz - phdr->p_filesz);
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
roundup((unsigned long)dst + phdr->p_filesz,
ARCH_DMA_MINALIGN) -
rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
++phdr;
- }
- return 0;
+}
- int rproc_load(int id, ulong addr, ulong size) { struct udevice *dev = NULL;
diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c index 51a67e6..5f35119 100644 --- a/drivers/remoteproc/sandbox_testproc.c +++ b/drivers/remoteproc/sandbox_testproc.c @@ -8,6 +8,7 @@ #include <dm.h> #include <errno.h> #include <remoteproc.h> +#include <asm/io.h>
/**
- enum sandbox_state - different device states
@@ -300,6 +301,23 @@ static int sandbox_testproc_ping(struct udevice *dev) return ret; }
+#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000 +/**
- sandbox_testproc_device_to_virt() - Convert device address to virtual address
- @dev: device to operate upon
- @da: device address
- @return converted virtual address
- */
+static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da) +{
- u64 paddr;
- /* Use a simple offset conversion */
- paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
- return phys_to_virt(paddr);
+}
- static const struct dm_rproc_ops sandbox_testproc_ops = { .init = sandbox_testproc_init, .reset = sandbox_testproc_reset,
@@ -308,6 +326,7 @@ static const struct dm_rproc_ops sandbox_testproc_ops = { .stop = sandbox_testproc_stop, .is_running = sandbox_testproc_is_running, .ping = sandbox_testproc_ping,
.device_to_virt = sandbox_testproc_device_to_virt, };
static const struct udevice_id sandbox_ids[] = {
diff --git a/include/remoteproc.h b/include/remoteproc.h index aef6ff2..f74ccc2 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -151,10 +151,10 @@ int rproc_dev_init(int id); bool rproc_is_initialized(void);
/**
- rproc_load() - load binary to a remote processor
- rproc_load() - load binary or elf 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
- @addr: address in memory where the image is located
*/ int rproc_load(int id, ulong addr, ulong size);
- @size: size of the image
- @return 0 if all ok, else appropriate error value.
@@ -200,6 +200,26 @@ int rproc_ping(int id);
- processor, but just ensures that it is out of reset and executing code.
*/ int rproc_is_running(int id);
+/**
- rproc_elf_sanity_check() - Verify if an image is a valid ELF one
- Check if a valid ELF image exists at the given memory location. Verify
- basic ELF format requirements like magic number and sections size.
- @addr: address of the image to verify
- @size: size of the image
- @return 0 if the image looks good, else appropriate error value.
- */
+int rproc_elf_sanity_check(ulong addr, ulong size);
+/**
- rproc_elf_load_image() - load an ELF image
- @dev: device loading the ELF image
- @addr: valid ELF image address
- @return 0 if the image is successfully loaded, else appropriate error value.
- */
+int rproc_elf_load_image(struct udevice *dev, unsigned long addr); #else static inline int rproc_init(void) { return -ENOSYS; } static inline int rproc_dev_init(int id) { return -ENOSYS; } @@ -210,6 +230,10 @@ 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; } +static inline int rproc_elf_sanity_check(ulong addr,
ulong size) { return -ENOSYS; }
+static inline int rproc_elf_load_image(struct udevice *dev,
unsigned long addr) { return -ENOSYS; }
#endif
#endif /* _RPROC_H_ */
diff --git a/test/dm/remoteproc.c b/test/dm/remoteproc.c index 3975c67..8d444fc 100644 --- a/test/dm/remoteproc.c +++ b/test/dm/remoteproc.c @@ -5,8 +5,10 @@ */ #include <common.h> #include <dm.h> +#include <elf.h> #include <errno.h> #include <remoteproc.h> +#include <asm/io.h> #include <dm/test.h> #include <test/ut.h> /** @@ -65,3 +67,123 @@ static int dm_test_remoteproc_base(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_remoteproc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+#define DEVICE_TO_PHYSICAL_OFFSET 0x1000 +/**
- dm_test_remoteproc_elf() - test the ELF operations
- @uts: unit test state
- Return: 0 if test passed, else error
- */
+static int dm_test_remoteproc_elf(struct unit_test_state *uts) +{
- u8 valid_elf32[] = {
/* @0x00 - ELF HEADER - */
/* ELF magic */
0x7f, 0x45, 0x4c, 0x46,
/* 32 Bits */
0x01,
/* Endianness */
+#ifdef __LITTLE_ENDIAN
0x01,
+#else
0x02,
+#endif
/* Version */
0x01,
/* Padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Type : executable */
0x02, 0x00,
/* Machine: ARM */
0x28, 0x00,
/* Version */
0x01, 0x00, 0x00, 0x00,
/* Entry */
0x00, 0x00, 0x00, 0x08,
/* phoff (program header offset @ 0x40)*/
0x40, 0x00, 0x00, 0x00,
/* shoff (section header offset : none) */
0x00, 0x00, 0x00, 0x00,
/* flags */
0x00, 0x00, 0x00, 0x00,
/* ehsize (elf header size = 0x34) */
0x34, 0x00,
/* phentsize (program header size = 0x20) */
0x20, 0x00,
/* phnum (program header number : 1) */
0x01, 0x00,
/* shentsize (section heade size : none) */
0x00, 0x00,
/* shnum (section header number: none) */
0x00, 0x00,
/* shstrndx (section header name section index: none) */
0x00, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
/* @0x40 - PROGRAM HEADER TABLE - */
/* type : PT_LOAD */
0x01, 0x00, 0x00, 0x00,
/* offset */
0x00, 0x00, 0x00, 0x00,
/* vaddr */
0x00, 0x00, 0x00, 0x00,
/* paddr : physical address */
0x00, 0x00, 0x00, 0x00,
/* filesz : 0x20 bytes (program header size) */
0x20, 0x00, 0x00, 0x00,
/* memsz = filesz */
0x20, 0x00, 0x00, 0x00,
/* flags : readable and exectuable */
0x05, 0x00, 0x00, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
- };
- unsigned int size = ARRAY_SIZE(valid_elf32);
- struct udevice *dev;
- phys_addr_t loaded_firmware_paddr;
- void *loaded_firmware;
- u32 loaded_firmware_size;
- Elf32_Ehdr *ehdr = (Elf32_Ehdr *)valid_elf32;
- Elf32_Phdr *phdr = (Elf32_Phdr *)(valid_elf32 + ehdr->e_phoff);
- ut_assertok(uclass_get_device(UCLASS_REMOTEPROC, 0, &dev));
- /*
* In its Program Header Table, let the firmware specifies to be loaded
* at SDRAM_BASE *device* address (p_paddr field).
* Its size is defined by the p_filesz field.
*/
- phdr->p_paddr = CONFIG_SYS_SDRAM_BASE;
- loaded_firmware_size = phdr->p_filesz;
- /*
* This *device* address is converted to a *physical* address by the
* device_to_virt() operation of sandbox_test_rproc which returns
* DeviceAddress + DEVICE_TO_PHYSICAL_OFFSET.
* This is where we expect to get the firmware loaded.
*/
- loaded_firmware_paddr = phdr->p_paddr + DEVICE_TO_PHYSICAL_OFFSET;
- loaded_firmware = map_physmem(loaded_firmware_paddr,
loaded_firmware_size, MAP_NOCACHE);
- ut_assertnonnull(loaded_firmware);
- memset(loaded_firmware, 0, loaded_firmware_size);
- /* Verify valid ELF format */
- ut_assertok(rproc_elf_sanity_check((ulong)valid_elf32, size));
- /* Load firmware in loaded_firmware, and verify it */
- ut_assertok(rproc_elf_load_image(dev, (unsigned long)valid_elf32));
- ut_assertok(memcmp(loaded_firmware, valid_elf32, loaded_firmware_size));
- unmap_physmem(loaded_firmware, MAP_NOCACHE);
- /* Invalid ELF Magic */
- valid_elf32[0] = 0;
- ut_asserteq(-EPROTONOSUPPORT,
rproc_elf_sanity_check((ulong)valid_elf32, size));
- return 0;
+} +DM_TEST(dm_test_remoteproc_elf, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

This patch introduces support of Cortex-M4 remote processor for STM32 MCU and MPU families.
Signed-off-by: Loic Pallardy loic.pallardy@st.com Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- drivers/remoteproc/Kconfig | 10 ++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/stm32_copro.c | 257 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 drivers/remoteproc/stm32_copro.c
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 9eb532b..fa6f111 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -40,6 +40,16 @@ config REMOTEPROC_SANDBOX Say 'y' here to add support for test processor which does dummy operations for sandbox platform.
+config REMOTEPROC_STM32_COPRO + bool "Support for STM32 coprocessor" + select REMOTEPROC + depends on DM + depends on ARCH_STM32MP + depends on OF_CONTROL + help + Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the + remoteproc framework. + config REMOTEPROC_TI_POWER bool "Support for TI Power processor" select REMOTEPROC diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 77eb708..5b120c1 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o obj-$(CONFIG_REMOTEPROC_K3) += k3_rproc.o obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o +obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c new file mode 100644 index 0000000..91e9d6f --- /dev/null +++ b/drivers/remoteproc/stm32_copro.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <regmap.h> +#include <remoteproc.h> +#include <reset.h> +#include <syscon.h> +#include <asm/io.h> + +#define RCC_GCR_HOLD_BOOT 0 +#define RCC_GCR_RELEASE_BOOT 1 + +/** + * struct stm32_copro_privdata - power processor private data + * @reset_ctl: reset controller handle + * @hold_boot_regmap: regmap for remote processor reset hold boot + * @hold_boot_offset: offset of the register controlling the hold boot setting + * @hold_boot_mask: bitmask of the register for the hold boot field + * @is_running: is the remote processor running + */ +struct stm32_copro_privdata { + struct reset_ctl reset_ctl; + struct regmap *hold_boot_regmap; + uint hold_boot_offset; + uint hold_boot_mask; + bool is_running; +}; + +/** + * stm32_copro_probe() - Basic probe + * @dev: corresponding STM32 remote processor device + * @return 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_probe(struct udevice *dev) +{ + struct stm32_copro_privdata *priv; + struct regmap *regmap; + const fdt32_t *cell; + int len, ret; + + priv = dev_get_priv(dev); + + regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-holdboot"); + if (IS_ERR(regmap)) { + dev_err(dev, "unable to find holdboot regmap (%ld)\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + cell = dev_read_prop(dev, "st,syscfg-holdboot", &len); + if (len < 3 * sizeof(fdt32_t)) { + dev_err(dev, "holdboot offset and mask not available\n"); + return -EINVAL; + } + + priv->hold_boot_regmap = regmap; + priv->hold_boot_offset = fdtdec_get_number(cell + 1, 1); + priv->hold_boot_mask = fdtdec_get_number(cell + 2, 1); + + ret = reset_get_by_index(dev, 0, &priv->reset_ctl); + if (ret) { + dev_err(dev, "failed to get reset (%d)\n", ret); + return ret; + } + + dev_dbg(dev, "probed\n"); + + return 0; +} + +/** + * stm32_copro_set_hold_boot() - Hold boot bit management + * @dev: corresponding STM32 remote processor device + * @hold: hold boot value + * @return 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold) +{ + struct stm32_copro_privdata *priv; + uint val; + int ret; + + priv = dev_get_priv(dev); + + val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT; + + /* + * Note: shall run an SMC call (STM32_SMC_RCC) if platform is secured. + * To be updated when the code for this SMC service is available which + * is not the case for the time being. + */ + ret = regmap_update_bits(priv->hold_boot_regmap, priv->hold_boot_offset, + priv->hold_boot_mask, val); + if (ret) + dev_err(dev, "failed to set hold boot\n"); + + return ret; +} + +/** + * stm32_copro_device_to_virt() - Convert device address to virtual address + * @dev: corresponding STM32 remote processor device + * @da: device address + * @return converted virtual address + */ +static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da) +{ + fdt32_t in_addr = cpu_to_be32(da); + u64 paddr; + + paddr = dev_translate_dma_address(dev, &in_addr); + if (paddr == OF_BAD_ADDR) { + dev_err(dev, "Unable to convert address %ld\n", da); + return NULL; + } + + return phys_to_virt(paddr); +} + +/** + * stm32_copro_load() - Loadup the STM32 remote processor + * @dev: corresponding STM32 remote processor device + * @addr: Address in memory where image is stored + * @size: Size in bytes of the image + * @return 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) +{ + struct stm32_copro_privdata *priv; + int ret; + + priv = dev_get_priv(dev); + + ret = stm32_copro_set_hold_boot(dev, true); + if (ret) + return ret; + + ret = reset_assert(&priv->reset_ctl); + if (ret) { + dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret); + return ret; + } + + /* Support only ELF image */ + ret = rproc_elf_sanity_check(addr, size); + if (ret) { + dev_err(dev, "Invalid ELF image (%d)\n", ret); + return ret; + } + + return rproc_elf_load_image(dev, addr); +} + +/** + * stm32_copro_start() - Start the STM32 remote processor + * @dev: corresponding STM32 remote processor device + * @return 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_start(struct udevice *dev) +{ + struct stm32_copro_privdata *priv; + int ret; + + priv = dev_get_priv(dev); + + /* move hold boot from true to false start the copro */ + ret = stm32_copro_set_hold_boot(dev, false); + if (ret) + return ret; + + /* + * Once copro running, reset hold boot flag to avoid copro + * rebooting autonomously + */ + ret = stm32_copro_set_hold_boot(dev, true); + priv->is_running = !ret; + return ret; +} + +/** + * stm32_copro_reset() - Reset the STM32 remote processor + * @dev: corresponding STM32 remote processor device + * @return 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_reset(struct udevice *dev) +{ + struct stm32_copro_privdata *priv; + int ret; + + priv = dev_get_priv(dev); + + ret = stm32_copro_set_hold_boot(dev, true); + if (ret) + return ret; + + ret = reset_assert(&priv->reset_ctl); + if (ret) { + dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret); + return ret; + } + + priv->is_running = false; + + return 0; +} + +/** + * stm32_copro_stop() - Stop the STM32 remote processor + * @dev: corresponding STM32 remote processor device + * @return 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_stop(struct udevice *dev) +{ + return stm32_copro_reset(dev); +} + +/** + * stm32_copro_is_running() - Is the STM32 remote processor running + * @dev: corresponding STM32 remote processor device + * @return 1 if the remote processor is running, 0 otherwise + */ +static int stm32_copro_is_running(struct udevice *dev) +{ + struct stm32_copro_privdata *priv; + + priv = dev_get_priv(dev); + return priv->is_running; +} + +static const struct dm_rproc_ops stm32_copro_ops = { + .load = stm32_copro_load, + .start = stm32_copro_start, + .stop = stm32_copro_stop, + .reset = stm32_copro_reset, + .is_running = stm32_copro_is_running, + .device_to_virt = stm32_copro_device_to_virt, +}; + +static const struct udevice_id stm32_copro_ids[] = { + {.compatible = "st,stm32mp1-rproc"}, + {} +}; + +U_BOOT_DRIVER(stm32_copro) = { + .name = "stm32_m4_proc", + .of_match = stm32_copro_ids, + .id = UCLASS_REMOTEPROC, + .ops = &stm32_copro_ops, + .probe = stm32_copro_probe, + .priv_auto_alloc_size = sizeof(struct stm32_copro_privdata), +};

Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS index 33fd465..5c505d9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -309,6 +309,7 @@ F: drivers/power/pmic/stpmic1.c F: drivers/power/regulator/stm32-vrefbuf.c F: drivers/power/regulator/stpmic1.c F: drivers/ram/stm32mp1/ +F: drivers/remoteproc/stm32_copro.c F: drivers/misc/stm32_rcc.c F: drivers/reset/stm32-reset.c F: drivers/spi/stm32_qspi.c

Activate the remote processor support for stm32mp15 configs.
Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- configs/stm32mp15_basic_defconfig | 2 ++ configs/stm32mp15_trusted_defconfig | 2 ++ 2 files changed, 4 insertions(+)
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 0ea9dff..5185072 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -67,6 +67,8 @@ CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y +CONFIG_REMOTEPROC=y +CONFIG_REMOTEPROC_STM32_COPRO=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y CONFIG_USB=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 3c2bb75..037d7e8 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -57,6 +57,8 @@ CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y +CONFIG_REMOTEPROC=y +CONFIG_REMOTEPROC_STM32_COPRO=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y CONFIG_USB=y
participants (3)
-
Fabien DESSENNE
-
Fabien Dessenne
-
Lokesh Vutla