* [PATCH v1 1/4] add syscon_regmap_lookup_by_phandle() support @ 2019-06-05 16:52 Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 2/4] elf: add missing elf32_shdr Oleksij Rempel ` (2 more replies) 0 siblings, 3 replies; 6+ messages in thread From: Oleksij Rempel @ 2019-06-05 16:52 UTC (permalink / raw) To: barebox; +Cc: Oleksij Rempel needed for remoteproc port Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> --- drivers/mfd/syscon.c | 19 +++++++++++++++++++ include/mfd/syscon.h | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index b1ff1b1ea..809941937 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -174,6 +174,25 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s) return regmap; } +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, + const char *property) +{ + struct device_node *syscon_np; + struct regmap *regmap; + + if (property) + syscon_np = of_parse_phandle(np, property, 0); + else + syscon_np = np; + + if (!syscon_np) + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); + + return regmap; +} + static int syscon_probe(struct device_d *dev) { struct syscon *syscon; diff --git a/include/mfd/syscon.h b/include/mfd/syscon.h index 902f9fa2f..3e39c333f 100644 --- a/include/mfd/syscon.h +++ b/include/mfd/syscon.h @@ -22,6 +22,8 @@ void __iomem *syscon_base_lookup_by_phandle (struct device_node *np, const char *property); struct regmap *syscon_node_to_regmap(struct device_node *np); struct regmap *syscon_regmap_lookup_by_compatible(const char *s); +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, + const char *property); #else static inline void __iomem *syscon_base_lookup_by_pdevname(const char *s) { @@ -42,6 +44,11 @@ static inline struct regmap *syscon_regmap_lookup_by_compatible(const char *s) { return ERR_PTR(-ENOSYS); } +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, + const char *property) +{ + return ERR_PTR(-ENOSYS); +} #endif #endif -- 2.20.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 2/4] elf: add missing elf32_shdr 2019-06-05 16:52 [PATCH v1 1/4] add syscon_regmap_lookup_by_phandle() support Oleksij Rempel @ 2019-06-05 16:52 ` Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 3/4] of: base: don't try to read cells_name property if no cells_name set Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 4/4] port reduced version of remoteproc framework from linux Oleksij Rempel 2 siblings, 0 replies; 6+ messages in thread From: Oleksij Rempel @ 2019-06-05 16:52 UTC (permalink / raw) To: barebox; +Cc: Oleksij Rempel needed for remoteproc port Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> --- include/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/elf.h b/include/elf.h index 92c8d9c12..e1deb3fe0 100644 --- a/include/elf.h +++ b/include/elf.h @@ -286,7 +286,7 @@ typedef struct elf64_phdr { #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff -typedef struct { +typedef struct elf32_shdr { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; -- 2.20.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 3/4] of: base: don't try to read cells_name property if no cells_name set 2019-06-05 16:52 [PATCH v1 1/4] add syscon_regmap_lookup_by_phandle() support Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 2/4] elf: add missing elf32_shdr Oleksij Rempel @ 2019-06-05 16:52 ` Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 4/4] port reduced version of remoteproc framework from linux Oleksij Rempel 2 siblings, 0 replies; 6+ messages in thread From: Oleksij Rempel @ 2019-06-05 16:52 UTC (permalink / raw) To: barebox; +Cc: Oleksij Rempel Some device tree node parsed by of_count_phandle_with_args() have no #*-cells parameter. To make linux device trees work with barebox, we should accept cells_name set to NULL, so sync this behavior with linux. Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> --- drivers/of/base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 838f530f8..d72c687ef 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1360,7 +1360,8 @@ static int __of_parse_phandle_with_args(const struct device_node *np, np->full_name); goto err; } - if (of_property_read_u32(node, cells_name, &count)) { + if (cells_name && + of_property_read_u32(node, cells_name, &count)) { pr_err("%s: could not get %s for %s\n", np->full_name, cells_name, node->full_name); -- 2.20.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 4/4] port reduced version of remoteproc framework from linux 2019-06-05 16:52 [PATCH v1 1/4] add syscon_regmap_lookup_by_phandle() support Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 2/4] elf: add missing elf32_shdr Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 3/4] of: base: don't try to read cells_name property if no cells_name set Oleksij Rempel @ 2019-06-05 16:52 ` Oleksij Rempel 2019-06-07 6:57 ` Sascha Hauer 2 siblings, 1 reply; 6+ messages in thread From: Oleksij Rempel @ 2019-06-05 16:52 UTC (permalink / raw) To: barebox; +Cc: Oleksij Rempel With this port it is possible to start same ELF firmware images as for linux remoteproc. Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> --- drivers/Kconfig | 1 + drivers/Makefile | 1 + drivers/remoteproc/Kconfig | 26 ++ drivers/remoteproc/Makefile | 7 + drivers/remoteproc/imx_rproc.c | 402 +++++++++++++++++++++ drivers/remoteproc/remoteproc_core.c | 166 +++++++++ drivers/remoteproc/remoteproc_elf_loader.c | 88 +++++ drivers/remoteproc/remoteproc_internal.h | 30 ++ include/linux/remoteproc.h | 51 +++ 9 files changed, 772 insertions(+) create mode 100644 drivers/remoteproc/Kconfig create mode 100644 drivers/remoteproc/Makefile create mode 100644 drivers/remoteproc/imx_rproc.c create mode 100644 drivers/remoteproc/remoteproc_core.c create mode 100644 drivers/remoteproc/remoteproc_elf_loader.c create mode 100644 drivers/remoteproc/remoteproc_internal.h create mode 100644 include/linux/remoteproc.h diff --git a/drivers/Kconfig b/drivers/Kconfig index f75da2698..09595433a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -31,6 +31,7 @@ source "drivers/pinctrl/Kconfig" source "drivers/nvmem/Kconfig" source "drivers/bus/Kconfig" source "drivers/regulator/Kconfig" +source "drivers/remoteproc/Kconfig" source "drivers/reset/Kconfig" source "drivers/pci/Kconfig" source "drivers/rtc/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index fb7fcd3fc..5a52225ee 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_W1) += w1/ obj-y += pinctrl/ obj-y += bus/ obj-$(CONFIG_REGULATOR) += regulator/ +obj-$(CONFIG_REMOTEPROC) += remoteproc/ obj-$(CONFIG_RESET_CONTROLLER) += reset/ obj-$(CONFIG_PCI) += pci/ obj-y += rtc/ diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig new file mode 100644 index 000000000..8139b6442 --- /dev/null +++ b/drivers/remoteproc/Kconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "Remoteproc drivers" + +config REMOTEPROC + tristate "Support for Remote Processor subsystem" + select CRC32 + select FIRMWARE + help + Support for remote processors (such as DSP coprocessors). These + are mainly used on embedded systems. + +if REMOTEPROC + +config IMX_REMOTEPROC + tristate "IMX6/7 remoteproc support" + depends on ARCH_IMX + select MFD_SYSCON + help + Say y here to support iMX's remote processors (Cortex M4 + on iMX7D) via the remote processor framework. + + It's safe to say N here. + +endif # REMOTEPROC + +endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile new file mode 100644 index 000000000..107296922 --- /dev/null +++ b/drivers/remoteproc/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Generic framework for controlling remote processors +# + +obj-$(CONFIG_REMOTEPROC) += remoteproc_core.o remoteproc_elf_loader.o +obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c new file mode 100644 index 000000000..c5cba3711 --- /dev/null +++ b/drivers/remoteproc/imx_rproc.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include <clock.h> +#include <common.h> +#include <driver.h> +#include <init.h> +#include <io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/remoteproc.h> +#include <mfd/syscon.h> +#include <module.h> +#include <memory.h> +#include <of_address.h> +#include <of_device.h> +#include <regmap.h> + +#define IMX7D_SRC_SCR 0x0C +#define IMX7D_ENABLE_M4 BIT(3) +#define IMX7D_SW_M4P_RST BIT(2) +#define IMX7D_SW_M4C_RST BIT(1) +#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0) + +#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ + | IMX7D_SW_M4C_RST \ + | IMX7D_SW_M4C_NON_SCLR_RST) + +#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ + | IMX7D_SW_M4C_RST) +#define IMX7D_M4_STOP IMX7D_SW_M4C_NON_SCLR_RST + +/* Address: 0x020D8000 */ +#define IMX6SX_SRC_SCR 0x00 +#define IMX6SX_ENABLE_M4 BIT(22) +#define IMX6SX_SW_M4P_RST BIT(12) +#define IMX6SX_SW_M4C_NON_SCLR_RST BIT(4) +#define IMX6SX_SW_M4C_RST BIT(3) + +#define IMX6SX_M4_START (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ + | IMX6SX_SW_M4C_RST) +#define IMX6SX_M4_STOP IMX6SX_SW_M4C_NON_SCLR_RST +#define IMX6SX_M4_RST_MASK (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ + | IMX6SX_SW_M4C_NON_SCLR_RST \ + | IMX6SX_SW_M4C_RST) + +#define IMX7D_RPROC_MEM_MAX 8 + +/** + * struct imx_rproc_mem - slim internal memory structure + * @cpu_addr: MPU virtual address of the memory region + * @sys_addr: Bus address used to access the memory region + * @size: Size of the memory region + */ +struct imx_rproc_mem { + void __iomem *cpu_addr; + phys_addr_t sys_addr; + size_t size; +}; + +/* att flags */ +/* M4 own area. Can be mapped at probe */ +#define ATT_OWN BIT(1) + +/* address translation table */ +struct imx_rproc_att { + u32 da; /* device address (From Cortex M4 view)*/ + u32 sa; /* system bus address */ + u32 size; /* size of reg range */ + int flags; +}; + +struct imx_rproc_dcfg { + u32 src_reg; + u32 src_mask; + u32 src_start; + u32 src_stop; + const struct imx_rproc_att *att; + size_t att_size; +}; + +struct imx_rproc { + struct device_d *dev; + struct regmap *regmap; + struct rproc *rproc; + const struct imx_rproc_dcfg *dcfg; + struct imx_rproc_mem mem[IMX7D_RPROC_MEM_MAX]; + struct clk *clk; +}; + +static const struct imx_rproc_att imx_rproc_att_imx7d[] = { + /* dev addr , sys addr , size , flags */ + /* OCRAM_S (M4 Boot code) - alias */ + { 0x00000000, 0x00180000, 0x00008000, 0 }, + /* OCRAM_S (Code) */ + { 0x00180000, 0x00180000, 0x00008000, ATT_OWN }, + /* OCRAM (Code) - alias */ + { 0x00900000, 0x00900000, 0x00020000, 0 }, + /* OCRAM_EPDC (Code) - alias */ + { 0x00920000, 0x00920000, 0x00020000, 0 }, + /* OCRAM_PXP (Code) - alias */ + { 0x00940000, 0x00940000, 0x00008000, 0 }, + /* TCML (Code) */ + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, + /* DDR (Code) - alias, first part of DDR (Data) */ + { 0x10000000, 0x80000000, 0x0FFF0000, 0 }, + + /* TCMU (Data) */ + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, + /* OCRAM (Data) */ + { 0x20200000, 0x00900000, 0x00020000, 0 }, + /* OCRAM_EPDC (Data) */ + { 0x20220000, 0x00920000, 0x00020000, 0 }, + /* OCRAM_PXP (Data) */ + { 0x20240000, 0x00940000, 0x00008000, 0 }, + /* DDR (Data) */ + { 0x80000000, 0x80000000, 0x60000000, 0 }, +}; + +static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { + /* dev addr , sys addr , size , flags */ + /* TCML (M4 Boot Code) - alias */ + { 0x00000000, 0x007F8000, 0x00008000, 0 }, + /* OCRAM_S (Code) */ + { 0x00180000, 0x008F8000, 0x00004000, 0 }, + /* OCRAM_S (Code) - alias */ + { 0x00180000, 0x008FC000, 0x00004000, 0 }, + /* TCML (Code) */ + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, + /* DDR (Code) - alias, first part of DDR (Data) */ + { 0x10000000, 0x80000000, 0x0FFF8000, 0 }, + + /* TCMU (Data) */ + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, + /* OCRAM_S (Data) - alias? */ + { 0x208F8000, 0x008F8000, 0x00004000, 0 }, + /* DDR (Data) */ + { 0x80000000, 0x80000000, 0x60000000, 0 }, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx7d, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { + .src_reg = IMX6SX_SRC_SCR, + .src_mask = IMX6SX_M4_RST_MASK, + .src_start = IMX6SX_M4_START, + .src_stop = IMX6SX_M4_STOP, + .att = imx_rproc_att_imx6sx, + .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), +}; + +static int imx_rproc_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device_d *dev = priv->dev; + int ret; + + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, + dcfg->src_mask, dcfg->src_start); + if (ret) + dev_err(dev, "Filed to enable M4!\n"); + + return ret; +} + +static int imx_rproc_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device_d *dev = priv->dev; + int ret; + + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, + dcfg->src_mask, dcfg->src_stop); + if (ret) + dev_err(dev, "Filed to stop M4!\n"); + + return ret; +} + +static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, + int len, u64 *sys) +{ + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int i; + + /* parse address translation table */ + for (i = 0; i < dcfg->att_size; i++) { + const struct imx_rproc_att *att = &dcfg->att[i]; + + if (da >= att->da && da + len < att->da + att->size) { + unsigned int offset = da - att->da; + + *sys = att->sa + offset; + return 0; + } + } + + dev_warn(priv->dev, "Translation filed: da = 0x%llx len = 0x%x\n", + da, len); + return -ENOENT; +} + +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len) +{ + struct imx_rproc *priv = rproc->priv; + void *va = NULL; + u64 sys; + int i; + + if (len <= 0) + return NULL; + + /* + * On device side we have many aliases, so we need to convert device + * address (M4) to system bus address first. + */ + if (imx_rproc_da_to_sys(priv, da, len, &sys)) + return NULL; + + for (i = 0; i < IMX7D_RPROC_MEM_MAX; i++) { + if (sys >= priv->mem[i].sys_addr && sys + len < + priv->mem[i].sys_addr + priv->mem[i].size) { + unsigned int offset = sys - priv->mem[i].sys_addr; + /* __force to make sparse happy with type conversion */ + va = (__force void *)(priv->mem[i].cpu_addr + offset); + break; + } + } + + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va); + + return va; +} + +static const struct rproc_ops imx_rproc_ops = { + .start = imx_rproc_start, + .stop = imx_rproc_stop, + .da_to_va = imx_rproc_da_to_va, +}; + +static int imx_rproc_addr_init(struct imx_rproc *priv, + struct device_d *dev) +{ + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device_node *np = dev->device_node; + int a, b = 0, err, nph; + + /* remap required addresses */ + for (a = 0; a < dcfg->att_size; a++) { + const struct imx_rproc_att *att = &dcfg->att[a]; + struct resource *res_cpu; + + if (!(att->flags & ATT_OWN)) + continue; + + if (b >= IMX7D_RPROC_MEM_MAX) + break; + + res_cpu = request_iomem_region(dev_name(dev), + att->sa, + att->sa + att->size - 1); + if (!res_cpu) { + dev_err(dev, "remap required addresses failed\n"); + return PTR_ERR(priv->mem[b].cpu_addr); + } + priv->mem[b].cpu_addr = (void *)res_cpu->start; + priv->mem[b].sys_addr = att->sa; + priv->mem[b].size = att->size; + b++; + } + + /* memory-region is optional property */ + nph = of_count_phandle_with_args(np, "memory-region", NULL); + if (nph <= 0) + return 0; + + /* remap optional addresses */ + for (a = 0; a < nph; a++) { + struct device_node *node; + struct resource res, *res_cpu; + + node = of_parse_phandle(np, "memory-region", a); + err = of_address_to_resource(node, 0, &res); + if (err) { + dev_err(dev, "unable to resolve memory region\n"); + return err; + } + + if (b >= IMX7D_RPROC_MEM_MAX) + break; + + res_cpu = request_sdram_region(dev_name(dev), res.start, + res.end - res.start); + if (!res_cpu) { + dev_err(dev, "remap optional addresses failed\n"); + return -ENOMEM; + } + priv->mem[b].cpu_addr = (void *)res_cpu->start; + priv->mem[b].sys_addr = res.start; + priv->mem[b].size = resource_size(&res); + b++; + } + + return 0; +} + +static int imx_rproc_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct imx_rproc *priv; + struct rproc *rproc; + const struct imx_rproc_dcfg *dcfg; + struct regmap *regmap; + int ret; + + regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to find syscon\n"); + return PTR_ERR(regmap); + } + + /* set some other name then imx */ + rproc = rproc_alloc(dev, dev_name(dev), &imx_rproc_ops, sizeof(*priv)); + if (!rproc) + return -ENOMEM; + + dcfg = of_device_get_match_data(dev); + if (!dcfg) { + ret = -EINVAL; + goto err_put_rproc; + } + + priv = rproc->priv; + priv->rproc = rproc; + priv->regmap = regmap; + priv->dcfg = dcfg; + priv->dev = dev; + + ret = imx_rproc_addr_init(priv, dev); + if (ret) { + dev_err(dev, "filed on imx_rproc_addr_init\n"); + goto err_put_rproc; + } + + priv->clk = clk_get(dev, 0); + if (IS_ERR(priv->clk)) { + dev_err(dev, "Failed to get clock\n"); + ret = PTR_ERR(priv->clk); + goto err_put_rproc; + } + + /* + * clk for M4 block including memory. Should be + * enabled before .start for FW transfer. + */ + ret = clk_enable(priv->clk); + if (ret) { + dev_err(&rproc->dev, "Failed to enable clock\n"); + goto err_put_rproc; + } + + ret = rproc_add(rproc); + if (ret) { + dev_err(dev, "rproc_add failed\n"); + goto err_put_clk; + } + + return 0; + +err_put_clk: + clk_disable(priv->clk); +err_put_rproc: + return ret; +} + +static const struct of_device_id imx_rproc_of_match[] = { + { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, + { .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx }, + {}, +}; + +static struct driver_d imx_rproc_driver = { + .name = "imx-rproc", + .probe = imx_rproc_probe, + .of_compatible = DRV_OF_COMPAT(imx_rproc_of_match), +}; +device_platform_driver(imx_rproc_driver); diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c new file mode 100644 index 000000000..7cac47e06 --- /dev/null +++ b/drivers/remoteproc/remoteproc_core.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Remote Processor Framework + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * Mark Grosen <mgrosen@ti.com> + * Fernando Guzman Lugo <fernando.lugo@ti.com> + * Suman Anna <s-anna@ti.com> + * Robert Tivy <rtivy@ti.com> + * Armando Uribe De Leon <x0095078@ti.com> + */ + +#include <common.h> +#include <firmware.h> +#include <linux/remoteproc.h> + +#include "remoteproc_internal.h" + +void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) +{ + void *ptr; + + if (rproc->ops->da_to_va) { + ptr = rproc->ops->da_to_va(rproc, da, len); + if (ptr) + return ptr; + } + + return NULL; +} + +static int rproc_start(struct rproc *rproc, const struct firmware *fw) +{ + struct device_d *dev = &rproc->dev; + int ret; + + /* load the ELF segments to memory */ + ret = rproc_load_segments(rproc, fw); + if (ret) { + dev_err(dev, "Failed to load program segments: %d\n", ret); + return ret; + } + + /* power up the remote processor */ + ret = rproc->ops->start(rproc); + if (ret) { + dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret); + return ret; + } + + dev_info(dev, "remote processor %s is now up\n", rproc->name); + + return 0; +} + +static int rproc_firmware_start(struct firmware_handler *fh) +{ + struct rproc *rproc = container_of(fh, struct rproc, fh); + + rproc->fw_buf = kzalloc((4096 * 1024), GFP_KERNEL); + rproc->fw_buf_ofs = 0; + return 0; +} + +static int rproc_firmware_write_buf(struct firmware_handler *fh, const void *buf, + size_t size) +{ + struct rproc *rproc = container_of(fh, struct rproc, fh); + + if (rproc->fw_buf_ofs + size > (4096 * 1024)) { + return -ENOMEM; + } + + memcpy(rproc->fw_buf + rproc->fw_buf_ofs, buf, size); + rproc->fw_buf_ofs += size; + + return 0; +} + +static int rproc_firmware_finish(struct firmware_handler *fh) +{ + struct rproc *rproc = container_of(fh, struct rproc, fh); + struct firmware fw; + struct device_d *dev; + int ret; + + if (!rproc) { + pr_err("invalid rproc handle\n"); + return -EINVAL; + } + + dev = &rproc->dev; + + dev_info(dev, "powering up %s\n", rproc->name); + + fw.data = rproc->fw_buf; + fw.size = rproc->fw_buf_ofs; + + ret = rproc_start(rproc, &fw); + + kfree(rproc->fw_buf); + + return ret; +} + +int rproc_add(struct rproc *rproc) +{ + struct device_d *dev = &rproc->dev; + struct firmware_handler *fh; + int ret; + + fh = &rproc->fh; + fh->id = xstrdup(rproc->name); + fh->open = rproc_firmware_start; + fh->write = rproc_firmware_write_buf; + fh->close = rproc_firmware_finish; + + ret = firmwaremgr_register(fh); + if (ret) + dev_err(dev, "filed to register firmware handler %s\n", rproc->name); + else + dev_info(dev, "%s is available\n", rproc->name); + + return ret; +} + +struct rproc *rproc_alloc(struct device_d *dev, const char *name, + const struct rproc_ops *ops, int len) +{ + struct rproc *rproc; + + if (!dev || !name || !ops) + return NULL; + + rproc = xzalloc(sizeof(struct rproc) + len); + if (!rproc) { + return NULL; + } + + rproc->ops = kmemdup(ops, sizeof(*ops), GFP_KERNEL); + if (!rproc->ops) { + kfree(rproc); + return NULL; + } + + rproc->name = name; + rproc->priv = &rproc[1]; + + rproc->dev.parent = dev; + rproc->dev.priv = rproc; + + /* Assign a unique device index and name */ + rproc->index = 1; + + dev_set_name(&rproc->dev, "remoteproc%d", rproc->index); + + /* Default to ELF loader if no load function is specified */ + if (!rproc->ops->load) + rproc->ops->load = rproc_elf_load_segments; + + return rproc; +} diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c new file mode 100644 index 000000000..45d52db5c --- /dev/null +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Remote Processor Framework Elf loader + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * Mark Grosen <mgrosen@ti.com> + * Fernando Guzman Lugo <fernando.lugo@ti.com> + * Suman Anna <s-anna@ti.com> + * Robert Tivy <rtivy@ti.com> + * Armando Uribe De Leon <x0095078@ti.com> + * Sjur Brændeland <sjur.brandeland@stericsson.com> + */ + +#include <common.h> +#include <elf.h> +#include <linux/remoteproc.h> + +#include "remoteproc_internal.h" + +int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) +{ + struct device_d *dev = &rproc->dev; + struct elf32_hdr *ehdr; + struct elf32_phdr *phdr; + int i, ret = 0; + const u8 *elf_data = fw->data; + + ehdr = (struct elf32_hdr *)elf_data; + phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); + + /* go through the available ELF segments */ + for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + u32 da = phdr->p_paddr; + u32 memsz = phdr->p_memsz; + u32 filesz = phdr->p_filesz; + u32 offset = phdr->p_offset; + void *ptr; + + if (phdr->p_type != PT_LOAD) + continue; + + dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", + phdr->p_type, da, memsz, filesz); + + if (filesz > memsz) { + dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", + filesz, memsz); + ret = -EINVAL; + break; + } + + if (offset + filesz > fw->size) { + dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", + offset + filesz, fw->size); + ret = -EINVAL; + break; + } + + /* grab the kernel address for this device address */ + ptr = rproc_da_to_va(rproc, da, memsz); + if (!ptr) { + dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); + ret = -EINVAL; + break; + } + + /* put the segment where the remote processor expects it */ + if (phdr->p_filesz) + memcpy(ptr, elf_data + phdr->p_offset, filesz); + + /* + * Zero out remaining memory for this segment. + * + * This isn't strictly required since dma_alloc_coherent already + * did this for us. albeit harmless, we may consider removing + * this. + */ + if (memsz > filesz) + memset(ptr + filesz, 0, memsz - filesz); + } + + return ret; +} +EXPORT_SYMBOL(rproc_elf_load_segments); diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h new file mode 100644 index 000000000..8893d1a40 --- /dev/null +++ b/drivers/remoteproc/remoteproc_internal.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Remote processor framework + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + */ + +#ifndef REMOTEPROC_INTERNAL_H +#define REMOTEPROC_INTERNAL_H + +struct rproc; + +void *rproc_da_to_va(struct rproc *rproc, u64 da, int len); + +int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw); + +static inline +int rproc_load_segments(struct rproc *rproc, const struct firmware *fw) +{ + if (rproc->ops->load) + return rproc->ops->load(rproc, fw); + + return -EINVAL; +} + +#endif /* REMOTEPROC_INTERNAL_H */ diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h new file mode 100644 index 000000000..feee9ee4e --- /dev/null +++ b/include/linux/remoteproc.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Remote Processor Framework + * + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, Inc. + */ + +#ifndef REMOTEPROC_H +#define REMOTEPROC_H + +#include <firmware.h> + +struct resource_table { + u32 ver; + u32 num; + u32 reserved[2]; + u32 offset[0]; +} __packed; + +struct firmware { + size_t size; + const u8 *data; +}; + +struct rproc; + +struct rproc_ops { + int (*start)(struct rproc *rproc); + int (*stop)(struct rproc *rproc); + void * (*da_to_va)(struct rproc *rproc, u64 da, int len); + int (*load)(struct rproc *rproc, const struct firmware *fw); +}; + +struct rproc { + struct firmware_handler fh; + const char *name; + void *priv; + struct rproc_ops *ops; + struct device_d dev; + int index; + + void *fw_buf; + size_t fw_buf_ofs; +}; + +struct rproc *rproc_alloc(struct device_d *dev, const char *name, + const struct rproc_ops *ops, int len); +int rproc_add(struct rproc *rproc); + +#endif /* REMOTEPROC_H */ -- 2.20.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1 4/4] port reduced version of remoteproc framework from linux 2019-06-05 16:52 ` [PATCH v1 4/4] port reduced version of remoteproc framework from linux Oleksij Rempel @ 2019-06-07 6:57 ` Sascha Hauer 2019-06-07 7:14 ` Oleksij Rempel 0 siblings, 1 reply; 6+ messages in thread From: Sascha Hauer @ 2019-06-07 6:57 UTC (permalink / raw) To: Oleksij Rempel; +Cc: barebox On Wed, Jun 05, 2019 at 06:52:42PM +0200, Oleksij Rempel wrote: > With this port it is possible to start same ELF firmware images as > for linux remoteproc. > Some more prosa would be nice here. Is it useful already? What does work and what doesn't? > Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> > --- > drivers/Kconfig | 1 + > drivers/Makefile | 1 + > drivers/remoteproc/Kconfig | 26 ++ > drivers/remoteproc/Makefile | 7 + > drivers/remoteproc/imx_rproc.c | 402 +++++++++++++++++++++ > drivers/remoteproc/remoteproc_core.c | 166 +++++++++ > drivers/remoteproc/remoteproc_elf_loader.c | 88 +++++ > drivers/remoteproc/remoteproc_internal.h | 30 ++ > include/linux/remoteproc.h | 51 +++ > 9 files changed, 772 insertions(+) > create mode 100644 drivers/remoteproc/Kconfig > create mode 100644 drivers/remoteproc/Makefile > create mode 100644 drivers/remoteproc/imx_rproc.c > create mode 100644 drivers/remoteproc/remoteproc_core.c > create mode 100644 drivers/remoteproc/remoteproc_elf_loader.c > create mode 100644 drivers/remoteproc/remoteproc_internal.h > create mode 100644 include/linux/remoteproc.h > > diff --git a/drivers/Kconfig b/drivers/Kconfig > index f75da2698..09595433a 100644 > --- a/drivers/Kconfig > +++ b/drivers/Kconfig > @@ -31,6 +31,7 @@ source "drivers/pinctrl/Kconfig" > source "drivers/nvmem/Kconfig" > source "drivers/bus/Kconfig" > source "drivers/regulator/Kconfig" > +source "drivers/remoteproc/Kconfig" > source "drivers/reset/Kconfig" > source "drivers/pci/Kconfig" > source "drivers/rtc/Kconfig" > diff --git a/drivers/Makefile b/drivers/Makefile > index fb7fcd3fc..5a52225ee 100644 > --- a/drivers/Makefile > +++ b/drivers/Makefile > @@ -29,6 +29,7 @@ obj-$(CONFIG_W1) += w1/ > obj-y += pinctrl/ > obj-y += bus/ > obj-$(CONFIG_REGULATOR) += regulator/ > +obj-$(CONFIG_REMOTEPROC) += remoteproc/ > obj-$(CONFIG_RESET_CONTROLLER) += reset/ > obj-$(CONFIG_PCI) += pci/ > obj-y += rtc/ > diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig > new file mode 100644 > index 000000000..8139b6442 > --- /dev/null > +++ b/drivers/remoteproc/Kconfig > @@ -0,0 +1,26 @@ > +# SPDX-License-Identifier: GPL-2.0-only > +menu "Remoteproc drivers" > + > +config REMOTEPROC > + tristate "Support for Remote Processor subsystem" > + select CRC32 > + select FIRMWARE > + help > + Support for remote processors (such as DSP coprocessors). These > + are mainly used on embedded systems. > + > +if REMOTEPROC > + > +config IMX_REMOTEPROC > + tristate "IMX6/7 remoteproc support" > + depends on ARCH_IMX > + select MFD_SYSCON > + help > + Say y here to support iMX's remote processors (Cortex M4 > + on iMX7D) via the remote processor framework. > + > + It's safe to say N here. > + > +endif # REMOTEPROC > + > +endmenu > diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile > new file mode 100644 > index 000000000..107296922 > --- /dev/null > +++ b/drivers/remoteproc/Makefile > @@ -0,0 +1,7 @@ > +# SPDX-License-Identifier: GPL-2.0 > +# > +# Generic framework for controlling remote processors > +# > + > +obj-$(CONFIG_REMOTEPROC) += remoteproc_core.o remoteproc_elf_loader.o > +obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o > diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c > new file mode 100644 > index 000000000..c5cba3711 > --- /dev/null > +++ b/drivers/remoteproc/imx_rproc.c > @@ -0,0 +1,402 @@ > +/* > + * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation. > + */ > + > +#include <clock.h> > +#include <common.h> > +#include <driver.h> > +#include <init.h> > +#include <io.h> > +#include <linux/clk.h> > +#include <linux/err.h> > +#include <linux/kernel.h> > +#include <linux/remoteproc.h> > +#include <mfd/syscon.h> > +#include <module.h> > +#include <memory.h> > +#include <of_address.h> > +#include <of_device.h> > +#include <regmap.h> > + > +#define IMX7D_SRC_SCR 0x0C > +#define IMX7D_ENABLE_M4 BIT(3) > +#define IMX7D_SW_M4P_RST BIT(2) > +#define IMX7D_SW_M4C_RST BIT(1) > +#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0) > + > +#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ > + | IMX7D_SW_M4C_RST \ > + | IMX7D_SW_M4C_NON_SCLR_RST) > + > +#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ > + | IMX7D_SW_M4C_RST) > +#define IMX7D_M4_STOP IMX7D_SW_M4C_NON_SCLR_RST > + > +/* Address: 0x020D8000 */ > +#define IMX6SX_SRC_SCR 0x00 > +#define IMX6SX_ENABLE_M4 BIT(22) > +#define IMX6SX_SW_M4P_RST BIT(12) > +#define IMX6SX_SW_M4C_NON_SCLR_RST BIT(4) > +#define IMX6SX_SW_M4C_RST BIT(3) > + > +#define IMX6SX_M4_START (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ > + | IMX6SX_SW_M4C_RST) > +#define IMX6SX_M4_STOP IMX6SX_SW_M4C_NON_SCLR_RST > +#define IMX6SX_M4_RST_MASK (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ > + | IMX6SX_SW_M4C_NON_SCLR_RST \ > + | IMX6SX_SW_M4C_RST) > + > +#define IMX7D_RPROC_MEM_MAX 8 > + > +/** > + * struct imx_rproc_mem - slim internal memory structure > + * @cpu_addr: MPU virtual address of the memory region > + * @sys_addr: Bus address used to access the memory region > + * @size: Size of the memory region > + */ > +struct imx_rproc_mem { > + void __iomem *cpu_addr; > + phys_addr_t sys_addr; > + size_t size; > +}; > + > +/* att flags */ > +/* M4 own area. Can be mapped at probe */ > +#define ATT_OWN BIT(1) > + > +/* address translation table */ > +struct imx_rproc_att { > + u32 da; /* device address (From Cortex M4 view)*/ > + u32 sa; /* system bus address */ > + u32 size; /* size of reg range */ > + int flags; > +}; > + > +struct imx_rproc_dcfg { > + u32 src_reg; > + u32 src_mask; > + u32 src_start; > + u32 src_stop; > + const struct imx_rproc_att *att; > + size_t att_size; > +}; > + > +struct imx_rproc { > + struct device_d *dev; > + struct regmap *regmap; > + struct rproc *rproc; > + const struct imx_rproc_dcfg *dcfg; > + struct imx_rproc_mem mem[IMX7D_RPROC_MEM_MAX]; > + struct clk *clk; > +}; > + > +static const struct imx_rproc_att imx_rproc_att_imx7d[] = { > + /* dev addr , sys addr , size , flags */ > + /* OCRAM_S (M4 Boot code) - alias */ > + { 0x00000000, 0x00180000, 0x00008000, 0 }, > + /* OCRAM_S (Code) */ > + { 0x00180000, 0x00180000, 0x00008000, ATT_OWN }, > + /* OCRAM (Code) - alias */ > + { 0x00900000, 0x00900000, 0x00020000, 0 }, > + /* OCRAM_EPDC (Code) - alias */ > + { 0x00920000, 0x00920000, 0x00020000, 0 }, > + /* OCRAM_PXP (Code) - alias */ > + { 0x00940000, 0x00940000, 0x00008000, 0 }, > + /* TCML (Code) */ > + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, > + /* DDR (Code) - alias, first part of DDR (Data) */ > + { 0x10000000, 0x80000000, 0x0FFF0000, 0 }, > + > + /* TCMU (Data) */ > + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, > + /* OCRAM (Data) */ > + { 0x20200000, 0x00900000, 0x00020000, 0 }, > + /* OCRAM_EPDC (Data) */ > + { 0x20220000, 0x00920000, 0x00020000, 0 }, > + /* OCRAM_PXP (Data) */ > + { 0x20240000, 0x00940000, 0x00008000, 0 }, > + /* DDR (Data) */ > + { 0x80000000, 0x80000000, 0x60000000, 0 }, > +}; > + > +static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { > + /* dev addr , sys addr , size , flags */ > + /* TCML (M4 Boot Code) - alias */ > + { 0x00000000, 0x007F8000, 0x00008000, 0 }, > + /* OCRAM_S (Code) */ > + { 0x00180000, 0x008F8000, 0x00004000, 0 }, > + /* OCRAM_S (Code) - alias */ > + { 0x00180000, 0x008FC000, 0x00004000, 0 }, > + /* TCML (Code) */ > + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, > + /* DDR (Code) - alias, first part of DDR (Data) */ > + { 0x10000000, 0x80000000, 0x0FFF8000, 0 }, > + > + /* TCMU (Data) */ > + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, > + /* OCRAM_S (Data) - alias? */ > + { 0x208F8000, 0x008F8000, 0x00004000, 0 }, > + /* DDR (Data) */ > + { 0x80000000, 0x80000000, 0x60000000, 0 }, > +}; > + > +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { > + .src_reg = IMX7D_SRC_SCR, > + .src_mask = IMX7D_M4_RST_MASK, > + .src_start = IMX7D_M4_START, > + .src_stop = IMX7D_M4_STOP, > + .att = imx_rproc_att_imx7d, > + .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), > +}; > + > +static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { > + .src_reg = IMX6SX_SRC_SCR, > + .src_mask = IMX6SX_M4_RST_MASK, > + .src_start = IMX6SX_M4_START, > + .src_stop = IMX6SX_M4_STOP, > + .att = imx_rproc_att_imx6sx, > + .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), > +}; > + > +static int imx_rproc_start(struct rproc *rproc) > +{ > + struct imx_rproc *priv = rproc->priv; > + const struct imx_rproc_dcfg *dcfg = priv->dcfg; > + struct device_d *dev = priv->dev; > + int ret; > + > + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, > + dcfg->src_mask, dcfg->src_start); > + if (ret) > + dev_err(dev, "Filed to enable M4!\n"); s/Filed/Failed/ > + > + return ret; > +} > + > +static int imx_rproc_stop(struct rproc *rproc) > +{ > + struct imx_rproc *priv = rproc->priv; > + const struct imx_rproc_dcfg *dcfg = priv->dcfg; > + struct device_d *dev = priv->dev; > + int ret; > + > + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, > + dcfg->src_mask, dcfg->src_stop); > + if (ret) > + dev_err(dev, "Filed to stop M4!\n"); ditto > + > + return ret; > +} > + > +static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, > + int len, u64 *sys) > +{ > + const struct imx_rproc_dcfg *dcfg = priv->dcfg; > + int i; > + > + /* parse address translation table */ > + for (i = 0; i < dcfg->att_size; i++) { > + const struct imx_rproc_att *att = &dcfg->att[i]; > + > + if (da >= att->da && da + len < att->da + att->size) { > + unsigned int offset = da - att->da; > + > + *sys = att->sa + offset; > + return 0; > + } > + } > + > + dev_warn(priv->dev, "Translation filed: da = 0x%llx len = 0x%x\n", ditto > + da, len); > + return -ENOENT; > +} > + > +static int rproc_firmware_finish(struct firmware_handler *fh) > +{ > + struct rproc *rproc = container_of(fh, struct rproc, fh); > + struct firmware fw; > + struct device_d *dev; > + int ret; > + > + if (!rproc) { > + pr_err("invalid rproc handle\n"); > + return -EINVAL; > + } You probably want to test 'fh' for NULL, not the pointer you got from container_of. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1 4/4] port reduced version of remoteproc framework from linux 2019-06-07 6:57 ` Sascha Hauer @ 2019-06-07 7:14 ` Oleksij Rempel 0 siblings, 0 replies; 6+ messages in thread From: Oleksij Rempel @ 2019-06-07 7:14 UTC (permalink / raw) To: Sascha Hauer; +Cc: barebox Am 07.06.19 um 08:57 schrieb Sascha Hauer: > On Wed, Jun 05, 2019 at 06:52:42PM +0200, Oleksij Rempel wrote: >> With this port it is possible to start same ELF firmware images as >> for linux remoteproc. >> > > Some more prosa would be nice here. ok. > Is it useful already? ack. > What does work and what doesn't? I tested it on phytec imx7 board with remoteproc ELF image previously used on linux. Linux would load this image, create appropriate resource (if defined in image) and boot it. The barebox version is only loading image and boot it. Currently barebox version do not extract resources defined by rproc ELF image. On this early stage it is hard to say, if it is needed. Previously there was an attempt to port bootaux command from u-boot. Porting of remoteproc framework is my attempt to lead this topic in to the (IMO) right direction. >> Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> >> --- >> drivers/Kconfig | 1 + >> drivers/Makefile | 1 + >> drivers/remoteproc/Kconfig | 26 ++ >> drivers/remoteproc/Makefile | 7 + >> drivers/remoteproc/imx_rproc.c | 402 +++++++++++++++++++++ >> drivers/remoteproc/remoteproc_core.c | 166 +++++++++ >> drivers/remoteproc/remoteproc_elf_loader.c | 88 +++++ >> drivers/remoteproc/remoteproc_internal.h | 30 ++ >> include/linux/remoteproc.h | 51 +++ >> 9 files changed, 772 insertions(+) >> create mode 100644 drivers/remoteproc/Kconfig >> create mode 100644 drivers/remoteproc/Makefile >> create mode 100644 drivers/remoteproc/imx_rproc.c >> create mode 100644 drivers/remoteproc/remoteproc_core.c >> create mode 100644 drivers/remoteproc/remoteproc_elf_loader.c >> create mode 100644 drivers/remoteproc/remoteproc_internal.h >> create mode 100644 include/linux/remoteproc.h >> >> diff --git a/drivers/Kconfig b/drivers/Kconfig >> index f75da2698..09595433a 100644 >> --- a/drivers/Kconfig >> +++ b/drivers/Kconfig >> @@ -31,6 +31,7 @@ source "drivers/pinctrl/Kconfig" >> source "drivers/nvmem/Kconfig" >> source "drivers/bus/Kconfig" >> source "drivers/regulator/Kconfig" >> +source "drivers/remoteproc/Kconfig" >> source "drivers/reset/Kconfig" >> source "drivers/pci/Kconfig" >> source "drivers/rtc/Kconfig" >> diff --git a/drivers/Makefile b/drivers/Makefile >> index fb7fcd3fc..5a52225ee 100644 >> --- a/drivers/Makefile >> +++ b/drivers/Makefile >> @@ -29,6 +29,7 @@ obj-$(CONFIG_W1) += w1/ >> obj-y += pinctrl/ >> obj-y += bus/ >> obj-$(CONFIG_REGULATOR) += regulator/ >> +obj-$(CONFIG_REMOTEPROC) += remoteproc/ >> obj-$(CONFIG_RESET_CONTROLLER) += reset/ >> obj-$(CONFIG_PCI) += pci/ >> obj-y += rtc/ >> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig >> new file mode 100644 >> index 000000000..8139b6442 >> --- /dev/null >> +++ b/drivers/remoteproc/Kconfig >> @@ -0,0 +1,26 @@ >> +# SPDX-License-Identifier: GPL-2.0-only >> +menu "Remoteproc drivers" >> + >> +config REMOTEPROC >> + tristate "Support for Remote Processor subsystem" >> + select CRC32 >> + select FIRMWARE >> + help >> + Support for remote processors (such as DSP coprocessors). These >> + are mainly used on embedded systems. >> + >> +if REMOTEPROC >> + >> +config IMX_REMOTEPROC >> + tristate "IMX6/7 remoteproc support" >> + depends on ARCH_IMX >> + select MFD_SYSCON >> + help >> + Say y here to support iMX's remote processors (Cortex M4 >> + on iMX7D) via the remote processor framework. >> + >> + It's safe to say N here. >> + >> +endif # REMOTEPROC >> + >> +endmenu >> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile >> new file mode 100644 >> index 000000000..107296922 >> --- /dev/null >> +++ b/drivers/remoteproc/Makefile >> @@ -0,0 +1,7 @@ >> +# SPDX-License-Identifier: GPL-2.0 >> +# >> +# Generic framework for controlling remote processors >> +# >> + >> +obj-$(CONFIG_REMOTEPROC) += remoteproc_core.o remoteproc_elf_loader.o >> +obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o >> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c >> new file mode 100644 >> index 000000000..c5cba3711 >> --- /dev/null >> +++ b/drivers/remoteproc/imx_rproc.c >> @@ -0,0 +1,402 @@ >> +/* >> + * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 >> + * as published by the Free Software Foundation. >> + */ >> + >> +#include <clock.h> >> +#include <common.h> >> +#include <driver.h> >> +#include <init.h> >> +#include <io.h> >> +#include <linux/clk.h> >> +#include <linux/err.h> >> +#include <linux/kernel.h> >> +#include <linux/remoteproc.h> >> +#include <mfd/syscon.h> >> +#include <module.h> >> +#include <memory.h> >> +#include <of_address.h> >> +#include <of_device.h> >> +#include <regmap.h> >> + >> +#define IMX7D_SRC_SCR 0x0C >> +#define IMX7D_ENABLE_M4 BIT(3) >> +#define IMX7D_SW_M4P_RST BIT(2) >> +#define IMX7D_SW_M4C_RST BIT(1) >> +#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0) >> + >> +#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ >> + | IMX7D_SW_M4C_RST \ >> + | IMX7D_SW_M4C_NON_SCLR_RST) >> + >> +#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ >> + | IMX7D_SW_M4C_RST) >> +#define IMX7D_M4_STOP IMX7D_SW_M4C_NON_SCLR_RST >> + >> +/* Address: 0x020D8000 */ >> +#define IMX6SX_SRC_SCR 0x00 >> +#define IMX6SX_ENABLE_M4 BIT(22) >> +#define IMX6SX_SW_M4P_RST BIT(12) >> +#define IMX6SX_SW_M4C_NON_SCLR_RST BIT(4) >> +#define IMX6SX_SW_M4C_RST BIT(3) >> + >> +#define IMX6SX_M4_START (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ >> + | IMX6SX_SW_M4C_RST) >> +#define IMX6SX_M4_STOP IMX6SX_SW_M4C_NON_SCLR_RST >> +#define IMX6SX_M4_RST_MASK (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ >> + | IMX6SX_SW_M4C_NON_SCLR_RST \ >> + | IMX6SX_SW_M4C_RST) >> + >> +#define IMX7D_RPROC_MEM_MAX 8 >> + >> +/** >> + * struct imx_rproc_mem - slim internal memory structure >> + * @cpu_addr: MPU virtual address of the memory region >> + * @sys_addr: Bus address used to access the memory region >> + * @size: Size of the memory region >> + */ >> +struct imx_rproc_mem { >> + void __iomem *cpu_addr; >> + phys_addr_t sys_addr; >> + size_t size; >> +}; >> + >> +/* att flags */ >> +/* M4 own area. Can be mapped at probe */ >> +#define ATT_OWN BIT(1) >> + >> +/* address translation table */ >> +struct imx_rproc_att { >> + u32 da; /* device address (From Cortex M4 view)*/ >> + u32 sa; /* system bus address */ >> + u32 size; /* size of reg range */ >> + int flags; >> +}; >> + >> +struct imx_rproc_dcfg { >> + u32 src_reg; >> + u32 src_mask; >> + u32 src_start; >> + u32 src_stop; >> + const struct imx_rproc_att *att; >> + size_t att_size; >> +}; >> + >> +struct imx_rproc { >> + struct device_d *dev; >> + struct regmap *regmap; >> + struct rproc *rproc; >> + const struct imx_rproc_dcfg *dcfg; >> + struct imx_rproc_mem mem[IMX7D_RPROC_MEM_MAX]; >> + struct clk *clk; >> +}; >> + >> +static const struct imx_rproc_att imx_rproc_att_imx7d[] = { >> + /* dev addr , sys addr , size , flags */ >> + /* OCRAM_S (M4 Boot code) - alias */ >> + { 0x00000000, 0x00180000, 0x00008000, 0 }, >> + /* OCRAM_S (Code) */ >> + { 0x00180000, 0x00180000, 0x00008000, ATT_OWN }, >> + /* OCRAM (Code) - alias */ >> + { 0x00900000, 0x00900000, 0x00020000, 0 }, >> + /* OCRAM_EPDC (Code) - alias */ >> + { 0x00920000, 0x00920000, 0x00020000, 0 }, >> + /* OCRAM_PXP (Code) - alias */ >> + { 0x00940000, 0x00940000, 0x00008000, 0 }, >> + /* TCML (Code) */ >> + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, >> + /* DDR (Code) - alias, first part of DDR (Data) */ >> + { 0x10000000, 0x80000000, 0x0FFF0000, 0 }, >> + >> + /* TCMU (Data) */ >> + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, >> + /* OCRAM (Data) */ >> + { 0x20200000, 0x00900000, 0x00020000, 0 }, >> + /* OCRAM_EPDC (Data) */ >> + { 0x20220000, 0x00920000, 0x00020000, 0 }, >> + /* OCRAM_PXP (Data) */ >> + { 0x20240000, 0x00940000, 0x00008000, 0 }, >> + /* DDR (Data) */ >> + { 0x80000000, 0x80000000, 0x60000000, 0 }, >> +}; >> + >> +static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { >> + /* dev addr , sys addr , size , flags */ >> + /* TCML (M4 Boot Code) - alias */ >> + { 0x00000000, 0x007F8000, 0x00008000, 0 }, >> + /* OCRAM_S (Code) */ >> + { 0x00180000, 0x008F8000, 0x00004000, 0 }, >> + /* OCRAM_S (Code) - alias */ >> + { 0x00180000, 0x008FC000, 0x00004000, 0 }, >> + /* TCML (Code) */ >> + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, >> + /* DDR (Code) - alias, first part of DDR (Data) */ >> + { 0x10000000, 0x80000000, 0x0FFF8000, 0 }, >> + >> + /* TCMU (Data) */ >> + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, >> + /* OCRAM_S (Data) - alias? */ >> + { 0x208F8000, 0x008F8000, 0x00004000, 0 }, >> + /* DDR (Data) */ >> + { 0x80000000, 0x80000000, 0x60000000, 0 }, >> +}; >> + >> +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { >> + .src_reg = IMX7D_SRC_SCR, >> + .src_mask = IMX7D_M4_RST_MASK, >> + .src_start = IMX7D_M4_START, >> + .src_stop = IMX7D_M4_STOP, >> + .att = imx_rproc_att_imx7d, >> + .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), >> +}; >> + >> +static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { >> + .src_reg = IMX6SX_SRC_SCR, >> + .src_mask = IMX6SX_M4_RST_MASK, >> + .src_start = IMX6SX_M4_START, >> + .src_stop = IMX6SX_M4_STOP, >> + .att = imx_rproc_att_imx6sx, >> + .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), >> +}; >> + >> +static int imx_rproc_start(struct rproc *rproc) >> +{ >> + struct imx_rproc *priv = rproc->priv; >> + const struct imx_rproc_dcfg *dcfg = priv->dcfg; >> + struct device_d *dev = priv->dev; >> + int ret; >> + >> + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, >> + dcfg->src_mask, dcfg->src_start); >> + if (ret) >> + dev_err(dev, "Filed to enable M4!\n"); > > s/Filed/Failed/ > >> + >> + return ret; >> +} >> + >> +static int imx_rproc_stop(struct rproc *rproc) >> +{ >> + struct imx_rproc *priv = rproc->priv; >> + const struct imx_rproc_dcfg *dcfg = priv->dcfg; >> + struct device_d *dev = priv->dev; >> + int ret; >> + >> + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, >> + dcfg->src_mask, dcfg->src_stop); >> + if (ret) >> + dev_err(dev, "Filed to stop M4!\n"); > > ditto > >> + >> + return ret; >> +} >> + >> +static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, >> + int len, u64 *sys) >> +{ >> + const struct imx_rproc_dcfg *dcfg = priv->dcfg; >> + int i; >> + >> + /* parse address translation table */ >> + for (i = 0; i < dcfg->att_size; i++) { >> + const struct imx_rproc_att *att = &dcfg->att[i]; >> + >> + if (da >= att->da && da + len < att->da + att->size) { >> + unsigned int offset = da - att->da; >> + >> + *sys = att->sa + offset; >> + return 0; >> + } >> + } >> + >> + dev_warn(priv->dev, "Translation filed: da = 0x%llx len = 0x%x\n", > > ditto > >> + da, len); >> + return -ENOENT; >> +} >> + >> +static int rproc_firmware_finish(struct firmware_handler *fh) >> +{ >> + struct rproc *rproc = container_of(fh, struct rproc, fh); >> + struct firmware fw; >> + struct device_d *dev; >> + int ret; >> + >> + if (!rproc) { >> + pr_err("invalid rproc handle\n"); >> + return -EINVAL; >> + } > > You probably want to test 'fh' for NULL, not the pointer you got from > container_of. > > Sascha > > -- Regards, Oleksij _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2019-06-07 7:14 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-06-05 16:52 [PATCH v1 1/4] add syscon_regmap_lookup_by_phandle() support Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 2/4] elf: add missing elf32_shdr Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 3/4] of: base: don't try to read cells_name property if no cells_name set Oleksij Rempel 2019-06-05 16:52 ` [PATCH v1 4/4] port reduced version of remoteproc framework from linux Oleksij Rempel 2019-06-07 6:57 ` Sascha Hauer 2019-06-07 7:14 ` Oleksij Rempel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox