diff options
Diffstat (limited to 'drivers/remoteproc/st_remoteproc.c')
| -rw-r--r-- | drivers/remoteproc/st_remoteproc.c | 180 |
1 files changed, 113 insertions, 67 deletions
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index aacef0ea3b90..a07edf7217d2 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST's Remote Processor Control Driver * * Copyright (C) 2015 STMicroelectronics - All Rights Reserved * * Author: Ludovic Barre <ludovic.barre@st.com> - * - * 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 <linux/clk.h> @@ -19,9 +16,9 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/remoteproc.h> #include <linux/reset.h> @@ -91,6 +88,78 @@ static void st_rproc_kick(struct rproc *rproc, int vqid) dev_err(dev, "failed to send message via mbox: %d\n", ret); } +static int st_rproc_mem_alloc(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + struct device *dev = rproc->dev.parent; + void *va; + + va = ioremap_wc(mem->dma, mem->len); + if (!va) { + dev_err(dev, "Unable to map memory region: %pa+%zx\n", + &mem->dma, mem->len); + return -ENOMEM; + } + + /* Update memory entry va */ + mem->va = va; + + return 0; +} + +static int st_rproc_mem_release(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + iounmap(mem->va); + + return 0; +} + +static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) +{ + struct device *dev = rproc->dev.parent; + struct device_node *np = dev->of_node; + struct rproc_mem_entry *mem; + int entries; + + entries = of_reserved_mem_region_count(np); + + for (int index = 0; index < entries; index++) { + struct resource res; + int ret; + + ret = of_reserved_mem_region_to_resource(np, index, &res); + if (ret) + return ret; + + /* No need to map vdev buffer */ + if (!strstarts(res.name, "vdev0buffer")) { + /* Register memory region */ + mem = rproc_mem_entry_init(dev, NULL, + (dma_addr_t)res.start, + resource_size(&res), res.start, + st_rproc_mem_alloc, + st_rproc_mem_release, + "%.*s", + strchrnul(res.name, '@') - res.name, + res.name); + } else { + /* Register reserved memory for vdev buffer allocation */ + mem = rproc_of_resm_mem_entry_init(dev, index, + resource_size(&res), + res.start, + "vdev0buffer"); + } + + if (!mem) + return -ENOMEM; + + rproc_add_carveout(rproc, mem); + } + + return rproc_elf_load_rsc_table(rproc, fw); +} + static int st_rproc_start(struct rproc *rproc) { struct st_rproc *ddata = rproc->priv; @@ -121,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc) } } - dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr); + dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr); return 0; @@ -158,9 +227,14 @@ static int st_rproc_stop(struct rproc *rproc) } static const struct rproc_ops st_rproc_ops = { - .kick = st_rproc_kick, - .start = st_rproc_start, - .stop = st_rproc_stop, + .kick = st_rproc_kick, + .start = st_rproc_start, + .stop = st_rproc_stop, + .parse_fw = st_rproc_parse_fw, + .load = rproc_elf_load_segments, + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, + .sanity_check = rproc_elf_sanity_check, + .get_boot_addr = rproc_elf_get_boot_addr, }; /* @@ -214,26 +288,23 @@ static int st_rproc_parse_dt(struct platform_device *pdev) if (ddata->config->sw_reset) { ddata->sw_reset = devm_reset_control_get_exclusive(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 (IS_ERR(ddata->sw_reset)) + return dev_err_probe(dev, PTR_ERR(ddata->sw_reset), + "Failed to get S/W Reset\n"); } if (ddata->config->pwr_reset) { ddata->pwr_reset = devm_reset_control_get_exclusive(dev, "pwr_reset"); - if (IS_ERR(ddata->pwr_reset)) { - dev_err(dev, "Failed to get Power Reset\n"); - return PTR_ERR(ddata->pwr_reset); - } + if (IS_ERR(ddata->pwr_reset)) + return dev_err_probe(dev, PTR_ERR(ddata->pwr_reset), + "Failed to get Power Reset\n"); } 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); - } + if (IS_ERR(ddata->clk)) + return dev_err_probe(dev, PTR_ERR(ddata->clk), + "Failed to get clock\n"); err = of_property_read_u32(np, "clock-frequency", &ddata->clk_rate); if (err) { @@ -241,24 +312,11 @@ static int st_rproc_parse_dt(struct platform_device *pdev) return err; } - ddata->boot_base = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); - if (IS_ERR(ddata->boot_base)) { - dev_err(dev, "Boot base not found\n"); - return PTR_ERR(ddata->boot_base); - } - - 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; - } + ddata->boot_base = syscon_regmap_lookup_by_phandle_args(np, "st,syscfg", + 1, &ddata->boot_offset); + if (IS_ERR(ddata->boot_base)) + return dev_err_probe(dev, PTR_ERR(ddata->boot_base), + "Boot base not found\n"); err = clk_prepare(ddata->clk); if (err) @@ -270,7 +328,6 @@ static int st_rproc_parse_dt(struct platform_device *pdev) 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; @@ -278,25 +335,21 @@ static int st_rproc_probe(struct platform_device *pdev) int enabled; int ret, i; - 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)); + rproc = devm_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; + ddata->config = (struct st_rproc_config *)device_get_match_data(dev); + if (!ddata->config) + return -ENODEV; platform_set_drvdata(pdev, rproc); ret = st_rproc_parse_dt(pdev); if (ret) - goto free_rproc; + return ret; enabled = st_rproc_state(pdev); if (enabled < 0) { @@ -311,7 +364,7 @@ static int st_rproc_probe(struct platform_device *pdev) clk_set_rate(ddata->clk, ddata->clk_rate); } - if (of_get_property(np, "mbox-names", NULL)) { + if (of_property_present(np, "mbox-names")) { ddata->mbox_client_vq0.dev = dev; ddata->mbox_client_vq0.tx_done = NULL; ddata->mbox_client_vq0.tx_block = false; @@ -330,32 +383,32 @@ static int st_rproc_probe(struct platform_device *pdev) */ chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_rx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 0\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 0\n"); goto free_clk; } ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_RX] = chan; chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_tx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 0\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 0\n"); goto free_mbox; } ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_TX] = chan; chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_rx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 1\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 1\n"); goto free_mbox; } ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_RX] = chan; chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_tx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 1\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 1\n"); goto free_mbox; } ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_TX] = chan; @@ -372,12 +425,11 @@ free_mbox: mbox_free_channel(ddata->mbox_chan[i]); free_clk: clk_unprepare(ddata->clk); -free_rproc: - rproc_free(rproc); + return ret; } -static int st_rproc_remove(struct platform_device *pdev) +static void st_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); struct st_rproc *ddata = rproc->priv; @@ -387,14 +439,8 @@ static int st_rproc_remove(struct platform_device *pdev) clk_disable_unprepare(ddata->clk); - of_reserved_mem_device_release(&pdev->dev); - for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++) mbox_free_channel(ddata->mbox_chan[i]); - - rproc_free(rproc); - - return 0; } static struct platform_driver st_rproc_driver = { |
