diff options
Diffstat (limited to 'drivers/remoteproc/da8xx_remoteproc.c')
| -rw-r--r-- | drivers/remoteproc/da8xx_remoteproc.c | 237 |
1 files changed, 134 insertions, 103 deletions
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 9b2e60afa1a6..e418a2bf5d2e 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -1,33 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Remote processor machine-specific module for DA8XX * * Copyright (C) 2013 Texas Instruments, Inc. - * - * 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/bitops.h> #include <linux/clk.h> +#include <linux/reset.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/remoteproc.h> -#include <mach/clock.h> /* for davinci_clk_reset_assert/deassert() */ - #include "remoteproc_internal.h" static char *da8xx_fw_name; -module_param(da8xx_fw_name, charp, S_IRUGO); +module_param(da8xx_fw_name, charp, 0444); MODULE_PARM_DESC(da8xx_fw_name, - "\n\t\tName of DSP firmware file in /lib/firmware" - " (if not specified defaults to 'rproc-dsp-fw')"); + "Name of DSP firmware file in /lib/firmware (if not specified defaults to 'rproc-dsp-fw')"); /* * OMAP-L138 Technical References: @@ -39,9 +35,27 @@ MODULE_PARM_DESC(da8xx_fw_name, #define SYSCFG_CHIPSIG3 BIT(3) #define SYSCFG_CHIPSIG4 BIT(4) +#define DA8XX_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1) + +/** + * struct da8xx_rproc_mem - internal memory structure + * @cpu_addr: MPU virtual address of the memory region + * @bus_addr: Bus address used to access the memory region + * @dev_addr: Device address of the memory region from DSP view + * @size: Size of the memory region + */ +struct da8xx_rproc_mem { + void __iomem *cpu_addr; + phys_addr_t bus_addr; + u32 dev_addr; + size_t size; +}; + /** * struct da8xx_rproc - da8xx remote processor instance state * @rproc: rproc handle + * @mem: internal memory regions data + * @num_mems: number of internal memory regions * @dsp_clk: placeholder for platform's DSP clk * @ack_fxn: chip-specific ack function for ack'ing irq * @irq_data: ack_fxn function parameter @@ -51,7 +65,10 @@ MODULE_PARM_DESC(da8xx_fw_name, */ struct da8xx_rproc { struct rproc *rproc; + struct da8xx_rproc_mem *mem; + int num_mems; struct clk *dsp_clk; + struct reset_control *dsp_reset; void (*ack_fxn)(struct irq_data *data); struct irq_data *irq_data; void __iomem *chipsig; @@ -67,7 +84,7 @@ struct da8xx_rproc { */ static irqreturn_t handle_event(int irq, void *p) { - struct rproc *rproc = (struct rproc *)p; + struct rproc *rproc = p; /* Process incoming buffers on all our vrings */ rproc_vq_interrupt(rproc, 0); @@ -87,8 +104,8 @@ static irqreturn_t handle_event(int irq, void *p) */ static irqreturn_t da8xx_rproc_callback(int irq, void *p) { - struct rproc *rproc = (struct rproc *)p; - struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; + struct rproc *rproc = p; + struct da8xx_rproc *drproc = rproc->priv; u32 chipsig; chipsig = readl(drproc->chipsig); @@ -116,8 +133,10 @@ static irqreturn_t da8xx_rproc_callback(int irq, void *p) static int da8xx_rproc_start(struct rproc *rproc) { struct device *dev = rproc->dev.parent; - struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; + struct da8xx_rproc *drproc = rproc->priv; struct clk *dsp_clk = drproc->dsp_clk; + struct reset_control *dsp_reset = drproc->dsp_reset; + int ret; /* hw requires the start (boot) address be on 1KB boundary */ if (rproc->bootaddr & 0x3ff) { @@ -128,8 +147,18 @@ static int da8xx_rproc_start(struct rproc *rproc) writel(rproc->bootaddr, drproc->bootreg); - clk_enable(dsp_clk); - davinci_clk_reset_deassert(dsp_clk); + ret = clk_prepare_enable(dsp_clk); + if (ret) { + dev_err(dev, "clk_prepare_enable() failed: %d\n", ret); + return ret; + } + + ret = reset_control_deassert(dsp_reset); + if (ret) { + dev_err(dev, "reset_control_deassert() failed: %d\n", ret); + clk_disable_unprepare(dsp_clk); + return ret; + } return 0; } @@ -137,8 +166,16 @@ static int da8xx_rproc_start(struct rproc *rproc) static int da8xx_rproc_stop(struct rproc *rproc) { struct da8xx_rproc *drproc = rproc->priv; + struct device *dev = rproc->dev.parent; + int ret; - clk_disable(drproc->dsp_clk); + ret = reset_control_assert(drproc->dsp_reset); + if (ret) { + dev_err(dev, "reset_control_assert() failed: %d\n", ret); + return ret; + } + + clk_disable_unprepare(drproc->dsp_clk); return 0; } @@ -146,98 +183,124 @@ static int da8xx_rproc_stop(struct rproc *rproc) /* kick a virtqueue */ static void da8xx_rproc_kick(struct rproc *rproc, int vqid) { - struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; + struct da8xx_rproc *drproc = rproc->priv; - /* Interupt remote proc */ + /* Interrupt remote proc */ writel(SYSCFG_CHIPSIG2, drproc->chipsig); } -static struct rproc_ops da8xx_rproc_ops = { +static const struct rproc_ops da8xx_rproc_ops = { .start = da8xx_rproc_start, .stop = da8xx_rproc_stop, .kick = da8xx_rproc_kick, }; -static int reset_assert(struct device *dev) +static int da8xx_rproc_get_internal_memories(struct platform_device *pdev, + struct da8xx_rproc *drproc) { - struct clk *dsp_clk; + static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"}; + int num_mems = ARRAY_SIZE(mem_names); + struct device *dev = &pdev->dev; + struct resource *res; + int i; - dsp_clk = clk_get(dev, NULL); - if (IS_ERR(dsp_clk)) { - dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); - return PTR_RET(dsp_clk); - } + drproc->mem = devm_kcalloc(dev, num_mems, sizeof(*drproc->mem), + GFP_KERNEL); + if (!drproc->mem) + return -ENOMEM; - davinci_clk_reset_assert(dsp_clk); - clk_put(dsp_clk); + for (i = 0; i < num_mems; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + mem_names[i]); + drproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(drproc->mem[i].cpu_addr)) { + dev_err(dev, "failed to parse and map %s memory\n", + mem_names[i]); + return PTR_ERR(drproc->mem[i].cpu_addr); + } + drproc->mem[i].bus_addr = res->start; + drproc->mem[i].dev_addr = + res->start & DA8XX_RPROC_LOCAL_ADDRESS_MASK; + drproc->mem[i].size = resource_size(res); + + dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %p da 0x%x\n", + mem_names[i], &drproc->mem[i].bus_addr, + drproc->mem[i].size, drproc->mem[i].cpu_addr, + drproc->mem[i].dev_addr); + } + drproc->num_mems = num_mems; return 0; } +static void da8xx_rproc_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + static int da8xx_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct da8xx_rproc *drproc; struct rproc *rproc; struct irq_data *irq_data; - struct resource *bootreg_res; - struct resource *chipsig_res; struct clk *dsp_clk; + struct reset_control *dsp_reset; void __iomem *chipsig; void __iomem *bootreg; int irq; int ret; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "platform_get_irq(pdev, 0) error: %d\n", irq); + if (irq < 0) return irq; - } irq_data = irq_get_irq_data(irq); - if (!irq_data) { - dev_err(dev, "irq_get_irq_data(%d): NULL\n", irq); - return -EINVAL; - } - - bootreg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!bootreg_res) { - dev_err(dev, - "platform_get_resource(IORESOURCE_MEM, 0): NULL\n"); - return -EADDRNOTAVAIL; - } - - chipsig_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!chipsig_res) { - dev_err(dev, - "platform_get_resource(IORESOURCE_MEM, 1): NULL\n"); - return -EADDRNOTAVAIL; - } + if (!irq_data) + return dev_err_probe(dev, -EINVAL, "irq_get_irq_data(%d): NULL\n", irq); - bootreg = devm_ioremap_resource(dev, bootreg_res); + bootreg = devm_platform_ioremap_resource_byname(pdev, "host1cfg"); if (IS_ERR(bootreg)) return PTR_ERR(bootreg); - chipsig = devm_ioremap_resource(dev, chipsig_res); + chipsig = devm_platform_ioremap_resource_byname(pdev, "chipsig"); if (IS_ERR(chipsig)) return PTR_ERR(chipsig); dsp_clk = devm_clk_get(dev, NULL); - if (IS_ERR(dsp_clk)) { - dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); - - return PTR_ERR(dsp_clk); + if (IS_ERR(dsp_clk)) + return dev_err_probe(dev, PTR_ERR(dsp_clk), "clk_get error\n"); + + dsp_reset = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(dsp_reset)) + return dev_err_probe(dev, PTR_ERR(dsp_reset), "unable to get reset control\n"); + + if (dev->of_node) { + ret = of_reserved_mem_device_init(dev); + if (ret) + return dev_err_probe(dev, ret, "device does not have specific CMA pool\n"); + devm_add_action_or_reset(&pdev->dev, da8xx_rproc_mem_release, &pdev->dev); } - rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, - sizeof(*drproc)); + rproc = devm_rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, + sizeof(*drproc)); if (!rproc) return -ENOMEM; + /* error recovery is not supported at present */ + rproc->recovery_disabled = true; + drproc = rproc->priv; drproc->rproc = rproc; + drproc->dsp_clk = dsp_clk; + drproc->dsp_reset = dsp_reset; + rproc->has_iommu = false; - platform_set_drvdata(pdev, rproc); + ret = da8xx_rproc_get_internal_memories(pdev, drproc); + if (ret) + return ret; /* everything the ISR needs is now setup, so hook it up */ ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback, @@ -245,7 +308,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) rproc); if (ret) { dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); - goto free_rproc; + return ret; } /* @@ -253,68 +316,36 @@ static int da8xx_rproc_probe(struct platform_device *pdev) * *not* in reset, but da8xx_rproc_start() needs the DSP to be * held in reset at the time it is called. */ - ret = reset_assert(dev); + ret = reset_control_assert(dsp_reset); if (ret) - goto free_rproc; + return ret; drproc->chipsig = chipsig; drproc->bootreg = bootreg; drproc->ack_fxn = irq_data->chip->irq_ack; drproc->irq_data = irq_data; drproc->irq = irq; - drproc->dsp_clk = dsp_clk; - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); - goto free_rproc; + return ret; } return 0; - -free_rproc: - rproc_put(rproc); - - return ret; } -static int da8xx_rproc_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct rproc *rproc = platform_get_drvdata(pdev); - struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; - - /* - * It's important to place the DSP in reset before going away, - * since a subsequent insmod of this module may enable the DSP's - * clock before its program/boot-address has been loaded and - * before this module's probe has had a chance to reset the DSP. - * Without the reset, the DSP can lockup permanently when it - * begins executing garbage. - */ - reset_assert(dev); - - /* - * The devm subsystem might end up releasing things before - * freeing the irq, thus allowing an interrupt to sneak in while - * the device is being removed. This should prevent that. - */ - disable_irq(drproc->irq); - - devm_clk_put(dev, drproc->dsp_clk); - - rproc_del(rproc); - rproc_put(rproc); - - return 0; -} +static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { + { .compatible = "ti,da850-dsp", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, davinci_rproc_of_match); static struct platform_driver da8xx_rproc_driver = { .probe = da8xx_rproc_probe, - .remove = da8xx_rproc_remove, .driver = { .name = "davinci-rproc", - .owner = THIS_MODULE, + .of_match_table = of_match_ptr(davinci_rproc_of_match), }, }; |
