From a66a5114b34bb23396568bf485e05a311b3ee22f Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 28 Aug 2015 18:08:19 -0700 Subject: remoteproc: report error if resource table doesn't exist Currently, if the resource table is completely missing in the firmware, powering up the remoteproc fails silently. Add a message indicating that the resource table is missing in the firmware. Signed-off-by: Stefan Agner Acked-by: Suman Anna Signed-off-by: Ohad Ben-Cohen diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9e03d15..3d7d58a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -823,8 +823,10 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) /* look for the resource table */ table = rproc_find_rsc_table(rproc, fw, &tablesz); - if (!table) + if (!table) { + dev_err(dev, "Failed to find resource table\n"); goto clean_up; + } /* Verify that resource table in loaded fw is unchanged */ if (rproc->table_csum != crc32(0, table, tablesz)) { -- cgit v0.10.2 From 99c429cb4e628e8b6b8131910952436ad10b21f5 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Wed, 16 Sep 2015 07:32:54 -0500 Subject: remoteproc/wkup_m3: Use MODULE_DEVICE_TABLE to export alias Use MODULE_DEVICE_TABLE with wkup_m3_rproc_of_match so the module alias is exported and the wkup_m3_rproc driver can automatically probe. Signed-off-by: Dave Gerlach Signed-off-by: Ohad Ben-Cohen diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index edf8181..02d271d 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -122,6 +122,7 @@ static const struct of_device_id wkup_m3_rproc_of_match[] = { { .compatible = "ti,am4372-wkup-m3", }, {}, }; +MODULE_DEVICE_TABLE(of, wkup_m3_rproc_of_match); static int wkup_m3_rproc_probe(struct platform_device *pdev) { -- cgit v0.10.2 From 47fff9fd8a7848c44c83b34ad7825d2185b9b319 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 Jan 2016 12:46:15 +0000 Subject: remoteproc: debugfs: Return error on invalid 'count' value If 'count' value is invalid, return -EINVAL. Signed-off-by: Lee Jones [bjorn: changed commit message] Signed-off-by: Bjorn Andersson diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 916af50..6fdfa68 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -157,7 +157,7 @@ rproc_recovery_write(struct file *filp, const char __user *user_buf, int ret; if (count < 1 || count > sizeof(buf)) - return count; + return -EINVAL; ret = copy_from_user(buf, user_buf, count); if (ret) -- cgit v0.10.2 From 6cb0e0f6a46a6c2f1d6f9d4a0539f2ed7d8487fb Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 Jan 2016 12:46:16 +0000 Subject: remoteproc: dt: Provide bindings for ST's Remote Processor Controller driver Signed-off-by: Ludovic Barre Signed-off-by: Lee Jones Acked-by: Rob Herring Signed-off-by: Bjorn Andersson diff --git a/Documentation/devicetree/bindings/remoteproc/st-rproc.txt b/Documentation/devicetree/bindings/remoteproc/st-rproc.txt new file mode 100644 index 0000000..1031bcd --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/st-rproc.txt @@ -0,0 +1,41 @@ +STMicroelectronics Co-Processor Bindings +---------------------------------------- + +This binding provides support for adjunct processors found on ST SoCs. + +Co-processors can be controlled from the bootloader or the primary OS. If +the bootloader starts a co-processor, the primary OS must detect its state +and act accordingly. + +Required properties: +- compatible Should be one of: + "st,st231-rproc" + "st,st40-rproc" +- memory-region Reserved memory (See: ../reserved-memory/reserved-memory.txt) +- resets Reset lines (See: ../reset/reset.txt) +- reset-names Must be "sw_reset" and "pwr_reset" +- clocks Clock for co-processor (See: ../clock/clock-bindings.txt) +- clock-frequency Clock frequency to set co-processor at if the bootloader + hasn't already done so +- st,syscfg System configuration register which holds the boot vector + for the co-processor + 1st cell: Phandle to syscon block + 2nd cell: Boot vector register offset + +Example: + + audio_reserved: rproc@42000000 { + compatible = "shared-dma-pool"; + reg = <0x42000000 0x01000000>; + no-map; + }; + + st231-audio { + compatible = "st,st231-rproc"; + memory-region = <&audio_reserved>; + resets = <&softreset STIH407_ST231_AUD_SOFTRESET>; + reset-names = "sw_reset"; + clocks = <&clk_s_c0_flexgen CLK_ST231_AUD_0>; + clock-frequency = <600000000>; + st,syscfg = <&syscfg_core 0x228>; + }; -- cgit v0.10.2 From 69e50479bd6b99a377223104be46f7b894ca4208 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 Jan 2016 12:46:17 +0000 Subject: remoteproc: debugfs: Add ability to boot remote processor using debugfs This functionality is especially useful during the testing phase. When used in conjunction with Mailbox's Test Framework we can trivially conduct end-to-end testing i.e. boot co-processor, send and receive messages to the co-processor, then shut it down again (repeat as required). Signed-off-by: Ludovic Barre Signed-off-by: Lee Jones Signed-off-by: Bjorn Andersson diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 6fdfa68..74a120b 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -88,8 +88,42 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf, return simple_read_from_buffer(userbuf, count, ppos, buf, i); } +static ssize_t rproc_state_write(struct file *filp, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + char buf[10]; + int ret; + + if (count > sizeof(buf) || count <= 0) + return -EINVAL; + + ret = copy_from_user(buf, userbuf, count); + if (ret) + return -EFAULT; + + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (!strncmp(buf, "start", count)) { + ret = rproc_boot(rproc); + if (ret) { + dev_err(&rproc->dev, "Boot failed: %d\n", ret); + return ret; + } + } else if (!strncmp(buf, "stop", count)) { + rproc_shutdown(rproc); + } else { + dev_err(&rproc->dev, "Unrecognised option: %s\n", buf); + return -EINVAL; + } + + return count; +} + static const struct file_operations rproc_state_ops = { .read = rproc_state_read, + .write = rproc_state_write, .open = simple_open, .llseek = generic_file_llseek, }; -- cgit v0.10.2 From 63edb0310a5ca736c81aaba661b365cd4887cd3b Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 Jan 2016 12:46:18 +0000 Subject: remoteproc: Supply controller driver for ST's Remote Processors Signed-off-by: Ludovic Barre Signed-off-by: Lee Jones Signed-off-by: Bjorn Andersson diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 28c711f..72e97d7 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -77,4 +77,13 @@ config DA8XX_REMOTEPROC It's safe to say n here if you're not interested in multimedia offloading. +config ST_REMOTEPROC + tristate "ST remoteproc support" + depends on ARCH_STI + select REMOTEPROC + help + Say y here to support ST's adjunct processors via the remote + processor framework. + This can be either built-in or a loadable module. + endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 81b04d1..279cb2e 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o +obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c new file mode 100644 index 0000000..6bb04d4 --- /dev/null +++ b/drivers/remoteproc/st_remoteproc.c @@ -0,0 +1,297 @@ +/* + * ST's Remote Processor Control Driver + * + * Copyright (C) 2015 STMicroelectronics - All Rights Reserved + * + * Author: Ludovic Barre + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct st_rproc_config { + bool sw_reset; + bool pwr_reset; + unsigned long bootaddr_mask; +}; + +struct st_rproc { + struct st_rproc_config *config; + struct reset_control *sw_reset; + struct reset_control *pwr_reset; + struct clk *clk; + u32 clk_rate; + struct regmap *boot_base; + u32 boot_offset; +}; + +static int st_rproc_start(struct rproc *rproc) +{ + struct st_rproc *ddata = rproc->priv; + int err; + + regmap_update_bits(ddata->boot_base, ddata->boot_offset, + ddata->config->bootaddr_mask, rproc->bootaddr); + + err = clk_enable(ddata->clk); + if (err) { + dev_err(&rproc->dev, "Failed to enable clock\n"); + return err; + } + + if (ddata->config->sw_reset) { + err = reset_control_deassert(ddata->sw_reset); + if (err) { + dev_err(&rproc->dev, "Failed to deassert S/W Reset\n"); + goto sw_reset_fail; + } + } + + if (ddata->config->pwr_reset) { + err = reset_control_deassert(ddata->pwr_reset); + if (err) { + dev_err(&rproc->dev, "Failed to deassert Power Reset\n"); + goto pwr_reset_fail; + } + } + + dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr); + + return 0; + + +pwr_reset_fail: + if (ddata->config->pwr_reset) + reset_control_assert(ddata->sw_reset); +sw_reset_fail: + clk_disable(ddata->clk); + + return err; +} + +static int st_rproc_stop(struct rproc *rproc) +{ + struct st_rproc *ddata = rproc->priv; + int sw_err = 0, pwr_err = 0; + + if (ddata->config->sw_reset) { + sw_err = reset_control_assert(ddata->sw_reset); + if (sw_err) + dev_err(&rproc->dev, "Failed to assert S/W Reset\n"); + } + + if (ddata->config->pwr_reset) { + pwr_err = reset_control_assert(ddata->pwr_reset); + if (pwr_err) + dev_err(&rproc->dev, "Failed to assert Power Reset\n"); + } + + clk_disable(ddata->clk); + + return sw_err ?: pwr_err; +} + +static struct rproc_ops st_rproc_ops = { + .start = st_rproc_start, + .stop = st_rproc_stop, +}; + +/* + * Fetch state of the processor: 0 is off, 1 is on. + */ +static int st_rproc_state(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + struct st_rproc *ddata = rproc->priv; + int reset_sw = 0, reset_pwr = 0; + + if (ddata->config->sw_reset) + reset_sw = reset_control_status(ddata->sw_reset); + + if (ddata->config->pwr_reset) + reset_pwr = reset_control_status(ddata->pwr_reset); + + if (reset_sw < 0 || reset_pwr < 0) + return -EINVAL; + + return !reset_sw && !reset_pwr; +} + +static const struct st_rproc_config st40_rproc_cfg = { + .sw_reset = true, + .pwr_reset = true, + .bootaddr_mask = GENMASK(28, 1), +}; + +static const struct st_rproc_config st231_rproc_cfg = { + .sw_reset = true, + .pwr_reset = false, + .bootaddr_mask = GENMASK(31, 6), +}; + +static const struct of_device_id st_rproc_match[] = { + { .compatible = "st,st40-rproc", .data = &st40_rproc_cfg }, + { .compatible = "st,st231-rproc", .data = &st231_rproc_cfg }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_rproc_match); + +static int st_rproc_parse_dt(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rproc *rproc = platform_get_drvdata(pdev); + struct st_rproc *ddata = rproc->priv; + struct device_node *np = dev->of_node; + int err; + + if (ddata->config->sw_reset) { + ddata->sw_reset = devm_reset_control_get(dev, "sw_reset"); + if (IS_ERR(ddata->sw_reset)) { + dev_err(dev, "Failed to get S/W Reset\n"); + return PTR_ERR(ddata->sw_reset); + } + } + + if (ddata->config->pwr_reset) { + ddata->pwr_reset = devm_reset_control_get(dev, "pwr_reset"); + if (IS_ERR(ddata->pwr_reset)) { + dev_err(dev, "Failed to get Power Reset\n"); + return PTR_ERR(ddata->pwr_reset); + } + } + + ddata->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ddata->clk)) { + dev_err(dev, "Failed to get clock\n"); + return PTR_ERR(ddata->clk); + } + + err = of_property_read_u32(np, "clock-frequency", &ddata->clk_rate); + if (err) { + dev_err(dev, "failed to get clock frequency\n"); + return err; + } + + ddata->boot_base = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (!ddata->boot_base) { + dev_err(dev, "Boot base not found\n"); + return -EINVAL; + } + + err = of_property_read_u32_index(np, "st,syscfg", 1, + &ddata->boot_offset); + if (err) { + dev_err(dev, "Boot offset not found\n"); + return -EINVAL; + } + + err = of_reserved_mem_device_init(dev); + if (err) { + dev_err(dev, "Failed to obtain shared memory\n"); + return err; + } + + err = clk_prepare(ddata->clk); + if (err) + dev_err(dev, "failed to get clock\n"); + + return err; +} + +static int st_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *match; + struct st_rproc *ddata; + struct device_node *np = dev->of_node; + struct rproc *rproc; + int enabled; + int ret; + + match = of_match_device(st_rproc_match, dev); + if (!match || !match->data) { + dev_err(dev, "No device match found\n"); + return -ENODEV; + } + + rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); + if (!rproc) + return -ENOMEM; + + rproc->has_iommu = false; + ddata = rproc->priv; + ddata->config = (struct st_rproc_config *)match->data; + + platform_set_drvdata(pdev, rproc); + + ret = st_rproc_parse_dt(pdev); + if (ret) + goto free_rproc; + + enabled = st_rproc_state(pdev); + if (enabled < 0) + goto free_rproc; + + if (enabled) { + atomic_inc(&rproc->power); + rproc->state = RPROC_RUNNING; + } else { + clk_set_rate(ddata->clk, ddata->clk_rate); + } + + ret = rproc_add(rproc); + if (ret) + goto free_rproc; + + return 0; + +free_rproc: + rproc_put(rproc); + return ret; +} + +static int st_rproc_remove(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + struct st_rproc *ddata = rproc->priv; + + rproc_del(rproc); + + clk_disable_unprepare(ddata->clk); + + of_reserved_mem_device_release(&pdev->dev); + + rproc_put(rproc); + + return 0; +} + +static struct platform_driver st_rproc_driver = { + .probe = st_rproc_probe, + .remove = st_rproc_remove, + .driver = { + .name = "st-rproc", + .of_match_table = of_match_ptr(st_rproc_match), + }, +}; +module_platform_driver(st_rproc_driver); + +MODULE_DESCRIPTION("ST Remote Processor Control Driver"); +MODULE_AUTHOR("Ludovic Barre "); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 69ae9895d3fed49ee830c491b3d51c72966a8a4c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 13 Feb 2016 17:35:19 -0800 Subject: MAINTAINERS: Add co-maintainer for remoteproc subsystems Add myself as co-maintainer for the remote processor related subsystems, as agreed with Ohad. Acked-by: Ohad Ben-Cohen Signed-off-by: Bjorn Andersson diff --git a/MAINTAINERS b/MAINTAINERS index 30aca4a..a4ca4b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4967,6 +4967,7 @@ F: include/linux/hw_random.h HARDWARE SPINLOCK CORE M: Ohad Ben-Cohen +M: Bjorn Andersson S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/hwspinlock.git F: Documentation/hwspinlock.txt @@ -9136,6 +9137,7 @@ F: include/linux/regmap.h REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM M: Ohad Ben-Cohen +M: Bjorn Andersson T: git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git S: Maintained F: drivers/remoteproc/ @@ -9144,6 +9146,7 @@ F: include/linux/remoteproc.h REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM M: Ohad Ben-Cohen +M: Bjorn Andersson T: git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/rpmsg.git S: Maintained F: drivers/rpmsg/ -- cgit v0.10.2