summaryrefslogtreecommitdiff
path: root/drivers/remoteproc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r--drivers/remoteproc/Kconfig16
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/amd_mbv_bram_rproc.c213
-rw-r--r--drivers/remoteproc/da8xx_remoteproc.c95
-rw-r--r--drivers/remoteproc/imx_dsp_rproc.c41
-rw-r--r--drivers/remoteproc/imx_rproc.c143
-rw-r--r--drivers/remoteproc/imx_rproc.h2
-rw-r--r--drivers/remoteproc/ingenic_rproc.c4
-rw-r--r--drivers/remoteproc/keystone_remoteproc.c43
-rw-r--r--drivers/remoteproc/mtk_scp.c15
-rw-r--r--drivers/remoteproc/mtk_scp_ipi.c2
-rw-r--r--drivers/remoteproc/omap_remoteproc.c2
-rw-r--r--drivers/remoteproc/pru_rproc.c17
-rw-r--r--drivers/remoteproc/qcom_common.c35
-rw-r--r--drivers/remoteproc/qcom_common.h6
-rw-r--r--drivers/remoteproc/qcom_q6v5.c79
-rw-r--r--drivers/remoteproc/qcom_q6v5.h4
-rw-r--r--drivers/remoteproc/qcom_q6v5_adsp.c15
-rw-r--r--drivers/remoteproc/qcom_q6v5_mss.c294
-rw-r--r--drivers/remoteproc/qcom_q6v5_pas.c569
-rw-r--r--drivers/remoteproc/qcom_q6v5_wcss.c23
-rw-r--r--drivers/remoteproc/qcom_sysmon.c23
-rw-r--r--drivers/remoteproc/qcom_wcnss.c45
-rw-r--r--drivers/remoteproc/rcar_rproc.c41
-rw-r--r--drivers/remoteproc/remoteproc_core.c226
-rw-r--r--drivers/remoteproc/remoteproc_internal.h56
-rw-r--r--drivers/remoteproc/remoteproc_sysfs.c1
-rw-r--r--drivers/remoteproc/st_remoteproc.c31
-rw-r--r--drivers/remoteproc/stm32_rproc.c42
-rw-r--r--drivers/remoteproc/ti_k3_common.c2
-rw-r--r--drivers/remoteproc/ti_k3_r5_remoteproc.c8
-rw-r--r--drivers/remoteproc/xlnx_r5_remoteproc.c332
32 files changed, 1649 insertions, 777 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index ee54436fea5a..5b56b2dcc725 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -23,6 +23,15 @@ config REMOTEPROC_CDEV
It's safe to say N if you don't want to use this interface.
+config AMD_MBV_BRAM_REMOTEPROC
+ tristate "AMD MicroBlaze/V BRAM-based remoteproc support"
+ depends on OF && COMMON_CLK && (GPIOLIB || COMPILE_TEST)
+ help
+ Say y or m here to support a MicroBlaze/V BRAM-based remote
+ processor managed through the remoteproc framework.
+
+ If unsure, say N.
+
config IMX_REMOTEPROC
tristate "i.MX remoteproc support"
depends on ARCH_MXC
@@ -176,7 +185,7 @@ config QCOM_Q6V5_COMMON
depends on QCOM_SMEM
config QCOM_Q6V5_ADSP
- tristate "Qualcomm Technology Inc ADSP Peripheral Image Loader"
+ tristate "Qualcomm ADSP Peripheral Image Loader"
depends on OF && ARCH_QCOM
depends on QCOM_SMEM
depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n
@@ -210,6 +219,7 @@ config QCOM_Q6V5_MSS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the Qualcomm self-authenticating modem
subsystem based on Hexagon V5. The TrustZone based system is
@@ -230,6 +240,7 @@ config QCOM_Q6V5_PAS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the TrustZone based Peripheral Image Loader for
the Qualcomm remote processors. This is commonly used to control
@@ -282,7 +293,7 @@ config QCOM_WCNSS_PIL
select QCOM_MDT_LOADER
select QCOM_PIL_INFO
select QCOM_RPROC_COMMON
- select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the Peripheral Image Loader for loading WCNSS
firmware and boot the core on e.g. MSM8974, MSM8916. The firmware is
@@ -316,7 +327,6 @@ config ST_SLIM_REMOTEPROC
config STM32_RPROC
tristate "STM32 remoteproc support"
depends on ARCH_STM32 || COMPILE_TEST
- depends on REMOTEPROC
select MAILBOX
help
Say y here to support STM32 MCU processors via the
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 1c7598b8475d..689686de0d41 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -11,6 +11,7 @@ remoteproc-y += remoteproc_sysfs.o
remoteproc-y += remoteproc_virtio.o
remoteproc-y += remoteproc_elf_loader.o
obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o
+obj-$(CONFIG_AMD_MBV_BRAM_REMOTEPROC) += amd_mbv_bram_rproc.o
obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
obj-$(CONFIG_IMX_DSP_REMOTEPROC) += imx_dsp_rproc.o
obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o
diff --git a/drivers/remoteproc/amd_mbv_bram_rproc.c b/drivers/remoteproc/amd_mbv_bram_rproc.c
new file mode 100644
index 000000000000..e4a103cf8455
--- /dev/null
+++ b/drivers/remoteproc/amd_mbv_bram_rproc.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD MicroBlaze/V BRAM-based Remote Processor driver
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ *
+ * This driver supports soft-core processors (MicroBlaze, MicroBlaze-V, or
+ * similar) instantiated in AMD programmable logic, using dual-port BRAM
+ * for firmware storage and execution.
+ *
+ * The firmware memory (BRAM) is described in the processor-local address
+ * space and translated to the Linux-visible system physical address with
+ * standard devicetree address translation.
+ *
+ * Reset is controlled via GPIO connected to Processor System Reset IP.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+
+#include "remoteproc_internal.h"
+
+/**
+ * struct amd_bram_rproc - AMD MicroBlaze/V BRAM-based remoteproc private data
+ * @dev: device pointer
+ * @reset: GPIO descriptor for reset control (active-low)
+ * @clk: processor clock
+ */
+struct amd_bram_rproc {
+ struct device *dev;
+ struct gpio_desc *reset;
+ struct clk *clk;
+};
+
+static int amd_bram_rproc_prepare(struct rproc *rproc)
+{
+ struct amd_bram_rproc *priv = rproc->priv;
+ struct rproc_mem_entry *mem;
+ struct resource res;
+ u64 da, size;
+ int ret;
+
+ ret = of_property_read_reg(priv->dev->of_node, 0, &da, &size);
+ if (ret) {
+ dev_err(priv->dev, "failed to parse executable memory reg\n");
+ return ret;
+ }
+
+ if (!size || size > U32_MAX) {
+ dev_err(priv->dev, "invalid executable memory size\n");
+ return -EINVAL;
+ }
+
+ if (da > U32_MAX) {
+ dev_err(priv->dev, "invalid executable memory address\n");
+ return -EINVAL;
+ }
+
+ ret = of_address_to_resource(priv->dev->of_node, 0, &res);
+ if (ret) {
+ dev_err(priv->dev, "failed to translate executable memory reg\n");
+ return ret;
+ }
+
+ mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)res.start,
+ resource_size(&res), da,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
+ dev_name(priv->dev));
+ if (!mem)
+ return -ENOMEM;
+
+ rproc_add_carveout(rproc, mem);
+ rproc_coredump_add_segment(rproc, da, resource_size(&res));
+
+ return 0;
+}
+
+static int amd_bram_rproc_start(struct rproc *rproc)
+{
+ struct amd_bram_rproc *priv = rproc->priv;
+ int ret;
+
+ /* Enable clock before releasing reset */
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(priv->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ /* Deassert reset and let the processor run. */
+ ret = gpiod_set_value_cansleep(priv->reset, 0);
+ if (ret) {
+ dev_err(priv->dev, "failed to deassert reset: %d\n", ret);
+ clk_disable_unprepare(priv->clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int amd_bram_rproc_stop(struct rproc *rproc)
+{
+ struct amd_bram_rproc *priv = rproc->priv;
+ int ret;
+
+ /* Assert reset before disabling the processor clock. */
+ ret = gpiod_set_value_cansleep(priv->reset, 1);
+ if (ret) {
+ dev_err(priv->dev, "failed to assert reset: %d\n", ret);
+ return ret;
+ }
+
+ /* Disable clock after asserting reset */
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int amd_bram_rproc_parse_fw(struct rproc *rproc,
+ const struct firmware *fw)
+{
+ rproc_elf_load_rsc_table_optional(rproc, fw, dev_dbg,
+ "no resource table found\n");
+ return 0;
+}
+
+static const struct rproc_ops amd_bram_rproc_ops = {
+ .prepare = amd_bram_rproc_prepare,
+ .start = amd_bram_rproc_start,
+ .stop = amd_bram_rproc_stop,
+ .load = rproc_elf_load_segments,
+ .sanity_check = rproc_elf_sanity_check,
+ .get_boot_addr = rproc_elf_get_boot_addr,
+ .parse_fw = amd_bram_rproc_parse_fw,
+};
+
+static int amd_bram_rproc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct amd_bram_rproc *priv;
+ const char *fw_name = NULL;
+ struct rproc *rproc;
+ int ret;
+
+ ret = rproc_of_parse_firmware(dev, 0, &fw_name);
+ if (ret < 0 && ret != -EINVAL)
+ return dev_err_probe(dev, ret,
+ "failed to parse firmware-name property\n");
+
+ rproc = devm_rproc_alloc(dev, dev_name(dev), &amd_bram_rproc_ops,
+ fw_name, sizeof(*priv));
+ if (!rproc)
+ return -ENOMEM;
+
+ priv = rproc->priv;
+ priv->dev = dev;
+
+ /* Get the processor clock */
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get clock\n");
+
+ /*
+ * Keep the processor in reset until remoteproc has finished loading
+ * firmware into the executable memory window described by reg and
+ * translated through the parent bus ranges property.
+ */
+ priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset))
+ return dev_err_probe(dev, PTR_ERR(priv->reset),
+ "failed to get reset gpio\n");
+
+ rproc->auto_boot = false;
+
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set DMA mask\n");
+
+ platform_set_drvdata(pdev, rproc);
+
+ ret = devm_rproc_add(dev, rproc);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register rproc\n");
+
+ return 0;
+}
+
+static const struct of_device_id amd_bram_rproc_of_match[] = {
+ { .compatible = "xlnx,zynqmp-bram-rproc" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, amd_bram_rproc_of_match);
+
+static struct platform_driver amd_bram_rproc_driver = {
+ .probe = amd_bram_rproc_probe,
+ .driver = {
+ .name = "amd-bram-rproc",
+ .of_match_table = amd_bram_rproc_of_match,
+ },
+};
+module_platform_driver(amd_bram_rproc_driver);
+
+MODULE_DESCRIPTION("AMD MicroBlaze/V BRAM-based Remote Processor driver");
+MODULE_AUTHOR("Ben Levinsky <ben.levinsky@amd.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index e418a2bf5d2e..006fa7b56727 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -57,11 +57,10 @@ struct da8xx_rproc_mem {
* @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
+ * @dsp_reset: control for local reset
* @irq_data: ack_fxn function parameter
* @chipsig: virt ptr to DSP interrupt registers (CHIPSIG & CHIPSIG_CLR)
* @bootreg: virt ptr to DSP boot address register (HOST1CFG)
- * @irq: irq # used by this instance
*/
struct da8xx_rproc {
struct rproc *rproc;
@@ -69,11 +68,9 @@ struct da8xx_rproc {
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;
void __iomem *bootreg;
- int irq;
};
/**
@@ -122,7 +119,7 @@ static irqreturn_t da8xx_rproc_callback(int irq, void *p)
* we need to ack it after taking down the level else we'll
* be called again immediately after returning.
*/
- drproc->ack_fxn(drproc->irq_data);
+ drproc->irq_data->chip->irq_ack(drproc->irq_data);
return IRQ_WAKE_THREAD;
}
@@ -245,45 +242,9 @@ 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 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)
- return irq;
-
- irq_data = irq_get_irq_data(irq);
- if (!irq_data)
- return dev_err_probe(dev, -EINVAL, "irq_get_irq_data(%d): NULL\n", irq);
-
- bootreg = devm_platform_ioremap_resource_byname(pdev, "host1cfg");
- if (IS_ERR(bootreg))
- return PTR_ERR(bootreg);
-
- 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))
- 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 = devm_rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name,
sizeof(*drproc));
if (!rproc)
@@ -294,43 +255,63 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
drproc = rproc->priv;
drproc->rproc = rproc;
- drproc->dsp_clk = dsp_clk;
- drproc->dsp_reset = dsp_reset;
rproc->has_iommu = false;
+ drproc->dsp_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(drproc->dsp_clk))
+ return dev_err_probe(dev, PTR_ERR(drproc->dsp_clk), "clk_get error\n");
+
+ drproc->dsp_reset = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(drproc->dsp_reset))
+ return dev_err_probe(dev, PTR_ERR(drproc->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);
+ }
+
ret = da8xx_rproc_get_internal_memories(pdev, drproc);
if (ret)
return ret;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ drproc->irq_data = irq_get_irq_data(irq);
+ if (!drproc->irq_data)
+ return dev_err_probe(dev, -EINVAL, "irq_get_irq_data(%d): NULL\n", irq);
+
+ drproc->chipsig = devm_platform_ioremap_resource_byname(pdev, "chipsig");
+ if (IS_ERR(drproc->chipsig))
+ return PTR_ERR(drproc->chipsig);
+
+ drproc->bootreg = devm_platform_ioremap_resource_byname(pdev, "host1cfg");
+ if (IS_ERR(drproc->bootreg))
+ return PTR_ERR(drproc->bootreg);
+
/* everything the ISR needs is now setup, so hook it up */
ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback,
handle_event, 0, "da8xx-remoteproc",
rproc);
- if (ret) {
- dev_err(dev, "devm_request_threaded_irq error: %d\n", ret);
+ if (ret)
return ret;
- }
/*
* rproc_add() can end up enabling the DSP's clk with the DSP
* *not* in reset, but da8xx_rproc_start() needs the DSP to be
* held in reset at the time it is called.
*/
- ret = reset_control_assert(dsp_reset);
+ ret = reset_control_assert(drproc->dsp_reset);
if (ret)
return ret;
- drproc->chipsig = chipsig;
- drproc->bootreg = bootreg;
- drproc->ack_fxn = irq_data->chip->irq_ack;
- drproc->irq_data = irq_data;
- drproc->irq = irq;
-
ret = devm_rproc_add(dev, rproc);
- if (ret) {
- dev_err(dev, "rproc_add failed: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "rproc_add failed\n");
return 0;
}
diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 008741af9f11..fd60c67ba8a9 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -644,32 +644,6 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv)
mbox_free_channel(priv->rxdb_ch);
}
-static int imx_dsp_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;
- }
-
- mem->va = va;
-
- return 0;
-}
-
-static int imx_dsp_rproc_mem_release(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- iounmap(mem->va);
-
- return 0;
-}
-
/**
* imx_dsp_rproc_add_carveout() - request mailbox channels
* @priv: private data pointer
@@ -700,8 +674,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
/* Register memory region */
mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa,
- att->size, da, imx_dsp_rproc_mem_alloc,
- imx_dsp_rproc_mem_release, "dsp_mem");
+ att->size, da,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
+ "dsp_mem");
if (mem)
rproc_coredump_add_segment(rproc, da, att->size);
@@ -732,8 +708,8 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
/* Register memory region */
mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)res.start,
resource_size(&res), da,
- imx_dsp_rproc_mem_alloc,
- imx_dsp_rproc_mem_release,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
"%.*s", strchrnul(res.name, '@') - res.name, res.name);
if (!mem)
return -ENOMEM;
@@ -980,9 +956,8 @@ static int imx_dsp_rproc_elf_load_segments(struct rproc *rproc, const struct fir
static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
{
- if (rproc_elf_load_rsc_table(rproc, fw))
- dev_warn(&rproc->dev, "no resource table found for this firmware\n");
-
+ rproc_elf_load_rsc_table_optional(rproc, fw, dev_warn,
+ "no resource table found for this firmware\n");
return 0;
}
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 8c8ddbf995a4..745ce52cd822 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -145,6 +145,41 @@ static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = {
{ 0x80000000, 0x80000000, 0x50000000, 0 },
};
+static const struct imx_rproc_att imx_rproc_att_imx94_m70[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCM CODE NON-SECURE */
+ { 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+ /* TCM SYS NON-SECURE*/
+ { 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* DDR */
+ { 0x80000000, 0x80000000, 0x10000000, 0 },
+};
+
+static const struct imx_rproc_att imx_rproc_att_imx94_m71[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCM CODE NON-SECURE */
+ { 0x00000000, 0x202C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+ /* TCM SYS NON-SECURE*/
+ { 0x20000000, 0x20300000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* DDR */
+ { 0x80000000, 0x80000000, 0x10000000, 0 },
+};
+
+static const struct imx_rproc_att imx_rproc_att_imx94_m33s[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCM CODE NON-SECURE */
+ { 0x0FFC0000, 0x209C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+ /* TCM SYS NON-SECURE */
+ { 0x20000000, 0x20A00000, 0x00040000, ATT_OWN | ATT_IOMEM },
+ /* M33S OCRAM NON-SECURE */
+ { 0x20800000, 0x20800000, 0x180000, ATT_OWN | ATT_IOMEM },
+
+ /* DDR */
+ { 0x80000000, 0x80000000, 0x10000000, 0 },
+};
+
static const struct imx_rproc_att imx_rproc_att_imx93[] = {
/* dev addr , sys addr , size , flags */
/* TCM CODE NON-SECURE */
@@ -339,13 +374,32 @@ static int imx_rproc_scu_api_start(struct rproc *rproc)
return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry);
}
+static u64 imx_rproc_sm_get_reset_vector(struct rproc *rproc)
+{
+ struct imx_rproc *priv = rproc->priv;
+ u32 reset_vector_mask = priv->dcfg->reset_vector_mask ?: GENMASK(31, 0);
+
+ /*
+ * The hardware fetches the first two words from reset_vectors
+ * (hardware reset address) and populates SP and PC using the first
+ * two words. Execution proceeds from PC. The ELF entry point does
+ * not always match the hardware reset address.
+ * To derive the correct hardware reset address, the lower address
+ * bits must be masked off before programming the reset vector.
+ */
+ return rproc->bootaddr & reset_vector_mask;
+}
+
static int imx_rproc_sm_cpu_start(struct rproc *rproc)
{
struct imx_rproc *priv = rproc->priv;
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ u64 reset_vector;
int ret;
- ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false);
+ reset_vector = imx_rproc_sm_get_reset_vector(rproc);
+
+ ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, reset_vector, true, false, false);
if (ret) {
dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret);
return ret;
@@ -359,13 +413,16 @@ static int imx_rproc_sm_lmm_start(struct rproc *rproc)
struct imx_rproc *priv = rproc->priv;
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
+ u64 reset_vector;
int ret;
+ reset_vector = imx_rproc_sm_get_reset_vector(rproc);
+
/*
* If the remoteproc core can't start the M7, it will already be
* handled in imx_rproc_sm_lmm_prepare().
*/
- ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0);
+ ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, reset_vector);
if (ret) {
dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n",
dcfg->lmid, dcfg->cpuid, ret);
@@ -543,35 +600,6 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *i
return va;
}
-static int imx_rproc_mem_alloc(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- struct device *dev = rproc->dev.parent;
- void *va;
-
- dev_dbg(dev, "map memory: %p+%zx\n", &mem->dma, mem->len);
- va = ioremap_wc(mem->dma, mem->len);
- if (IS_ERR_OR_NULL(va)) {
- dev_err(dev, "Unable to map memory region: %p+%zx\n",
- &mem->dma, mem->len);
- return -ENOMEM;
- }
-
- /* Update memory entry va */
- mem->va = va;
-
- return 0;
-}
-
-static int imx_rproc_mem_release(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
- iounmap(mem->va);
-
- return 0;
-}
-
static int imx_rproc_sm_lmm_prepare(struct rproc *rproc)
{
struct imx_rproc *priv = rproc->priv;
@@ -635,7 +663,8 @@ static int imx_rproc_prepare(struct rproc *rproc)
/* Register memory region */
mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)res.start,
resource_size(&res), da,
- imx_rproc_mem_alloc, imx_rproc_mem_release,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
"%.*s", strchrnul(res.name, '@') - res.name,
res.name);
if (!mem)
@@ -653,12 +682,8 @@ static int imx_rproc_prepare(struct rproc *rproc)
static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
{
- int ret;
-
- ret = rproc_elf_load_rsc_table(rproc, fw);
- if (ret)
- dev_info(&rproc->dev, "No resource table in elf\n");
-
+ rproc_elf_load_rsc_table_optional(rproc, fw, dev_info,
+ "No resource table in elf\n");
return 0;
}
@@ -812,7 +837,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
/* Not use resource version, because we might share region */
priv->mem[b].cpu_addr = devm_ioremap_resource_wc(&pdev->dev, &res);
- if (!priv->mem[b].cpu_addr) {
+ if (IS_ERR(priv->mem[b].cpu_addr)) {
dev_err(dev, "failed to remap %pr\n", &res);
return -ENOMEM;
}
@@ -1007,7 +1032,11 @@ static int imx_rproc_mmio_detect_mode(struct rproc *rproc)
}
priv->regmap = regmap;
- regmap_attach_dev(dev, regmap, &config);
+ ret = regmap_attach_dev(dev, regmap, &config);
+ if (ret) {
+ dev_err(dev, "regmap attach failed\n");
+ return ret;
+ }
if (priv->gpr) {
ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val);
@@ -1226,8 +1255,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
const struct imx_rproc_dcfg *dcfg;
int ret;
- /* set some other name then imx */
- rproc = devm_rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
+ rproc = devm_rproc_alloc(dev, np->name, &imx_rproc_ops,
NULL, sizeof(*priv));
if (!rproc)
return -ENOMEM;
@@ -1451,6 +1479,33 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
.flags = IMX_RPROC_NEED_CLKS,
};
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m70 = {
+ .att = imx_rproc_att_imx94_m70,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m70),
+ .ops = &imx_rproc_ops_sm_lmm,
+ .cpuid = 1,
+ .lmid = 2,
+ .reset_vector_mask = GENMASK_U32(31, 16),
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m71 = {
+ .att = imx_rproc_att_imx94_m71,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m71),
+ .ops = &imx_rproc_ops_sm_lmm,
+ .cpuid = 7,
+ .lmid = 3,
+ .reset_vector_mask = GENMASK_U32(31, 16),
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m33s = {
+ .att = imx_rproc_att_imx94_m33s,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m33s),
+ .ops = &imx_rproc_ops_sm_lmm,
+ .cpuid = 8,
+ .lmid = 1,
+ .reset_vector_mask = GENMASK_U32(31, 16),
+};
+
static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = {
.att = imx_rproc_att_imx95_m7,
.att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7),
@@ -1458,6 +1513,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = {
/* Must align with System Manager Firmware */
.cpuid = 1, /* Use 1 as cpu id for M7 core */
.lmid = 1, /* Use 1 as Logical Machine ID where M7 resides */
+ .reset_vector_mask = GENMASK_U32(31, 16),
};
static const struct of_device_id imx_rproc_of_match[] = {
@@ -1474,6 +1530,9 @@ static const struct of_device_id imx_rproc_of_match[] = {
{ .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm },
{ .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp },
{ .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 },
+ { .compatible = "fsl,imx94-cm70", .data = &imx_rproc_cfg_imx94_m70 },
+ { .compatible = "fsl,imx94-cm71", .data = &imx_rproc_cfg_imx94_m71 },
+ { .compatible = "fsl,imx94-cm33s", .data = &imx_rproc_cfg_imx94_m33s },
{ .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 },
{},
};
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index d37e6f90548c..0d7d48352a10 100644
--- a/drivers/remoteproc/imx_rproc.h
+++ b/drivers/remoteproc/imx_rproc.h
@@ -41,6 +41,8 @@ struct imx_rproc_dcfg {
/* For System Manager(SM) based SoCs */
u32 cpuid; /* ID of the remote core */
u32 lmid; /* ID of the Logcial Machine */
+ /* reset_vector = elf_entry_addr & reset_vector_mask */
+ u32 reset_vector_mask;
};
#endif /* _IMX_RPROC_H */
diff --git a/drivers/remoteproc/ingenic_rproc.c b/drivers/remoteproc/ingenic_rproc.c
index 1b78d8ddeacf..252519f48964 100644
--- a/drivers/remoteproc/ingenic_rproc.c
+++ b/drivers/remoteproc/ingenic_rproc.c
@@ -219,10 +219,8 @@ static int ingenic_rproc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, vpu->irq, vpu_interrupt, IRQF_NO_AUTOEN,
"VPU", rproc);
- if (ret < 0) {
- dev_err(dev, "Failed to request IRQ\n");
+ if (ret < 0)
return ret;
- }
ret = devm_rproc_add(dev, rproc);
if (ret) {
diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
index 4d6550b48567..407d6034f748 100644
--- a/drivers/remoteproc/keystone_remoteproc.c
+++ b/drivers/remoteproc/keystone_remoteproc.c
@@ -173,35 +173,16 @@ static int keystone_rproc_start(struct rproc *rproc)
INIT_WORK(&ksproc->workqueue, handle_event);
- ret = request_irq(ksproc->irq_ring, keystone_rproc_vring_interrupt, 0,
- dev_name(ksproc->dev), ksproc);
- if (ret) {
- dev_err(ksproc->dev, "failed to enable vring interrupt, ret = %d\n",
- ret);
- goto out;
- }
+ enable_irq(ksproc->irq_ring);
+ enable_irq(ksproc->irq_fault);
- ret = request_irq(ksproc->irq_fault, keystone_rproc_exception_interrupt,
- 0, dev_name(ksproc->dev), ksproc);
+ ret = keystone_rproc_dsp_boot(ksproc, rproc->bootaddr);
if (ret) {
- dev_err(ksproc->dev, "failed to enable exception interrupt, ret = %d\n",
- ret);
- goto free_vring_irq;
+ flush_work(&ksproc->workqueue);
+ return ret;
}
- ret = keystone_rproc_dsp_boot(ksproc, rproc->bootaddr);
- if (ret)
- goto free_exc_irq;
-
return 0;
-
-free_exc_irq:
- free_irq(ksproc->irq_fault, ksproc);
-free_vring_irq:
- free_irq(ksproc->irq_ring, ksproc);
- flush_work(&ksproc->workqueue);
-out:
- return ret;
}
/*
@@ -215,8 +196,8 @@ static int keystone_rproc_stop(struct rproc *rproc)
struct keystone_rproc *ksproc = rproc->priv;
keystone_rproc_dsp_reset(ksproc);
- free_irq(ksproc->irq_fault, ksproc);
- free_irq(ksproc->irq_ring, ksproc);
+ disable_irq(ksproc->irq_fault);
+ disable_irq(ksproc->irq_ring);
flush_work(&ksproc->workqueue);
return 0;
@@ -336,7 +317,7 @@ static int keystone_rproc_of_get_dev_syscon(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
- if (!of_property_read_bool(np, "ti,syscon-dev")) {
+ if (!of_property_present(np, "ti,syscon-dev")) {
dev_err(dev, "ti,syscon-dev property is absent\n");
return -EINVAL;
}
@@ -427,10 +408,18 @@ static int keystone_rproc_probe(struct platform_device *pdev)
ksproc->irq_ring = platform_get_irq_byname(pdev, "vring");
if (ksproc->irq_ring < 0)
return ksproc->irq_ring;
+ ret = devm_request_irq(dev, ksproc->irq_ring, keystone_rproc_vring_interrupt,
+ IRQF_NO_AUTOEN, dev_name(dev), ksproc);
+ if (ret)
+ return ret;
ksproc->irq_fault = platform_get_irq_byname(pdev, "exception");
if (ksproc->irq_fault < 0)
return ksproc->irq_fault;
+ ret = devm_request_irq(dev, ksproc->irq_fault, keystone_rproc_exception_interrupt,
+ IRQF_NO_AUTOEN, dev_name(dev), ksproc);
+ if (ret)
+ return ret;
ksproc->kick_gpio = devm_gpiod_get(dev, "kick", GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio);
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index bb6f6a16d895..9751acc2bf83 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -36,6 +36,7 @@ struct mtk_scp *scp_get(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *scp_node;
struct platform_device *scp_pdev;
+ struct mtk_scp *scp;
scp_node = of_parse_phandle(dev->of_node, "mediatek,scp", 0);
if (!scp_node) {
@@ -51,7 +52,13 @@ struct mtk_scp *scp_get(struct platform_device *pdev)
return NULL;
}
- return platform_get_drvdata(scp_pdev);
+ scp = platform_get_drvdata(scp_pdev);
+ if (!scp) {
+ put_device(&scp_pdev->dev);
+ return NULL;
+ }
+
+ return scp;
}
EXPORT_SYMBOL_GPL(scp_get);
@@ -1078,7 +1085,7 @@ static void scp_unregister_ipi(struct platform_device *pdev, u32 id)
scp_ipi_unregister(scp, id);
}
-static int scp_send_ipi(struct platform_device *pdev, u32 id, void *buf,
+static int scp_send_ipi(struct platform_device *pdev, u32 id, const void *buf,
unsigned int len, unsigned int wait)
{
struct mtk_scp *scp = platform_get_drvdata(pdev);
@@ -1239,10 +1246,8 @@ static struct mtk_scp *scp_rproc_init(struct platform_device *pdev,
scp_irq_handler, IRQF_ONESHOT,
pdev->name, scp);
- if (ret) {
- dev_err(dev, "failed to request irq\n");
+ if (ret)
goto remove_subdev;
- }
return scp;
diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c
index 7a37e273b3af..ee2f1121411f 100644
--- a/drivers/remoteproc/mtk_scp_ipi.c
+++ b/drivers/remoteproc/mtk_scp_ipi.c
@@ -156,7 +156,7 @@ EXPORT_SYMBOL_GPL(scp_ipi_unlock);
*
* Return: 0 if sending data successfully, -error on error.
**/
-int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
+int scp_ipi_send(struct mtk_scp *scp, u32 id, const void *buf, unsigned int len,
unsigned int wait)
{
struct mtk_share_obj __iomem *send_obj = scp->send_buf;
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index cb01354248af..6ed0f28edac9 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -1140,7 +1140,7 @@ static int omap_rproc_get_boot_data(struct platform_device *pdev,
if (!data)
return -ENODEV;
- if (!of_property_read_bool(np, "ti,bootreg"))
+ if (!of_property_present(np, "ti,bootreg"))
return 0;
oproc->boot_data = devm_kzalloc(&pdev->dev, sizeof(*oproc->boot_data),
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 5e3eb7b86a0e..a4636c7bc6b7 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -1003,11 +1003,9 @@ static int pru_rproc_probe(struct platform_device *pdev)
if (!data)
return -ENODEV;
- ret = of_property_read_string(np, "firmware-name", &fw_name);
- if (ret) {
- dev_err(dev, "unable to retrieve firmware-name %d\n", ret);
- return ret;
- }
+ ret = rproc_of_parse_firmware(dev, 0, &fw_name);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to retrieve firmware-name\n");
rproc = devm_rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name,
sizeof(*pru));
@@ -1080,14 +1078,6 @@ static int pru_rproc_probe(struct platform_device *pdev)
return 0;
}
-static void pru_rproc_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct rproc *rproc = platform_get_drvdata(pdev);
-
- dev_dbg(dev, "%s: removing rproc %s\n", __func__, rproc->name);
-}
-
static const struct pru_private_data pru_data = {
.type = PRU_TYPE_PRU,
};
@@ -1133,7 +1123,6 @@ static struct platform_driver pru_rproc_driver = {
.suppress_bind_attrs = true,
},
.probe = pru_rproc_probe,
- .remove = pru_rproc_remove,
};
module_platform_driver(pru_rproc_driver);
diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c
index 6c31140268ac..5294e327f158 100644
--- a/drivers/remoteproc/qcom_common.c
+++ b/drivers/remoteproc/qcom_common.c
@@ -28,7 +28,6 @@
#define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev)
#define to_pdm_subdev(d) container_of(d, struct qcom_rproc_pdm, subdev)
-#define MAX_NUM_OF_SS 10
#define MAX_REGION_NAME_LENGTH 16
#define SBL_MINIDUMP_SMEM_ID 602
#define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0)
@@ -80,7 +79,7 @@ struct minidump_global_toc {
__le32 status;
__le32 md_revision;
__le32 enabled;
- struct minidump_subsystem subsystems[MAX_NUM_OF_SS];
+ struct minidump_subsystem subsystems[];
};
struct qcom_ssr_subsystem {
@@ -110,6 +109,7 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy
struct minidump_region __iomem *ptr;
struct minidump_region region;
int seg_cnt, i;
+ int ret = 0;
dma_addr_t da;
size_t size;
char *name;
@@ -130,17 +130,22 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy
if (le32_to_cpu(region.valid) == MINIDUMP_REGION_VALID) {
name = kstrndup(region.name, MAX_REGION_NAME_LENGTH - 1, GFP_KERNEL);
if (!name) {
- iounmap(ptr);
- return -ENOMEM;
+ ret = -ENOMEM;
+ break;
}
da = le64_to_cpu(region.address);
size = le64_to_cpu(region.size);
- rproc_coredump_add_custom_segment(rproc, da, size, rproc_dumpfn_t, name);
+ ret = rproc_coredump_add_custom_segment(rproc, da, size, rproc_dumpfn_t,
+ name);
+ if (ret) {
+ kfree(name);
+ break;
+ }
}
}
iounmap(ptr);
- return 0;
+ return ret;
}
void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
@@ -151,9 +156,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
int ret;
struct minidump_subsystem *subsystem;
struct minidump_global_toc *toc;
+ unsigned int num_ss;
+ size_t toc_size;
/* Get Global minidump ToC*/
- toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL);
+ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size);
/* check if global table pointer exists and init is set */
if (IS_ERR(toc) || !toc->status) {
@@ -161,6 +168,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
return;
}
+ /* Derive the number of subsystems from the actual SMEM item size */
+ num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) /
+ sizeof(struct minidump_subsystem);
+
+ if (minidump_id >= num_ss) {
+ dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n",
+ minidump_id, num_ss);
+ return;
+ }
+
/* Get subsystem table of contents using the minidump id */
subsystem = &toc->subsystems[minidump_id];
@@ -236,8 +253,10 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink,
return;
glink->ssr_name = kstrdup_const(ssr_name, GFP_KERNEL);
- if (!glink->ssr_name)
+ if (!glink->ssr_name) {
+ of_node_put(glink->node);
return;
+ }
glink->dev = dev;
glink->subdev.start = glink_subdev_start;
diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h
index b07fbaa091a0..b0e7e336d363 100644
--- a/drivers/remoteproc/qcom_common.h
+++ b/drivers/remoteproc/qcom_common.h
@@ -68,6 +68,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
int ssctl_instance);
void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon);
bool qcom_sysmon_shutdown_acked(struct qcom_sysmon *sysmon);
+bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon);
#else
static inline struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name,
@@ -84,6 +85,11 @@ static inline bool qcom_sysmon_shutdown_acked(struct qcom_sysmon *sysmon)
{
return false;
}
+
+static inline bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon)
+{
+ return false;
+}
#endif
#endif
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 58d5b85e58cd..fe148b4b3775 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -36,6 +36,40 @@ static int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable)
return ret;
}
+static void q6v5_handover_irq_enable(struct qcom_q6v5 *q6v5)
+{
+ unsigned long flags;
+ bool enable = false;
+
+ spin_lock_irqsave(&q6v5->handover_lock, flags);
+ if (!q6v5->handover_irq_enabled) {
+ q6v5->handover_irq_enabled = true;
+ enable = true;
+ }
+ spin_unlock_irqrestore(&q6v5->handover_lock, flags);
+
+ if (enable)
+ enable_irq(q6v5->handover_irq);
+}
+
+static void q6v5_handover_irq_disable(struct qcom_q6v5 *q6v5, bool sync)
+{
+ unsigned long flags;
+ bool disable = false;
+
+ spin_lock_irqsave(&q6v5->handover_lock, flags);
+ if (q6v5->handover_irq_enabled) {
+ q6v5->handover_irq_enabled = false;
+ disable = true;
+ }
+ spin_unlock_irqrestore(&q6v5->handover_lock, flags);
+
+ if (disable)
+ disable_irq_nosync(q6v5->handover_irq);
+ if (sync)
+ synchronize_irq(q6v5->handover_irq);
+}
+
/**
* qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
* @q6v5: reference to qcom_q6v5 context to be reinitialized
@@ -64,7 +98,7 @@ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
q6v5->running = true;
q6v5->handover_issued = false;
- enable_irq(q6v5->handover_irq);
+ q6v5_handover_irq_enable(q6v5);
return 0;
}
@@ -78,7 +112,8 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
*/
int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
{
- disable_irq(q6v5->handover_irq);
+ q6v5_handover_irq_disable(q6v5, true);
+
q6v5_load_state_toggle(q6v5, false);
/* Disable interconnect vote, in case handover never happened */
@@ -164,18 +199,15 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
- if (q6v5->handover_issued) {
- dev_err(q6v5->dev, "Handover signaled, but it already happened\n");
- return IRQ_HANDLED;
- }
+ q6v5->handover_issued = true;
+
+ q6v5_handover_irq_disable(q6v5, false);
if (q6v5->handover)
q6v5->handover(q6v5);
icc_set_bw(q6v5->path, 0, 0);
- q6v5->handover_issued = true;
-
return IRQ_HANDLED;
}
@@ -197,12 +229,13 @@ static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
*/
int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon)
{
+ bool was_running = q6v5->running;
int ret;
q6v5->running = false;
- /* Don't perform SMP2P dance if remote isn't running */
- if (q6v5->rproc->state != RPROC_RUNNING || qcom_sysmon_shutdown_acked(sysmon))
+ /* A watchdog/fatal IRQ clears running; logical crashes still need a stop. */
+ if (!was_running || qcom_sysmon_shutdown_acked(sysmon))
return 0;
qcom_smem_state_update_bits(q6v5->state,
@@ -256,6 +289,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
q6v5->crash_reason = crash_reason;
q6v5->handover = handover;
+ spin_lock_init(&q6v5->handover_lock);
+
init_completion(&q6v5->start_done);
init_completion(&q6v5->stop_done);
@@ -267,10 +302,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
NULL, q6v5_wdog_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 wdog", q6v5);
- if (ret) {
- dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
+ if (ret)
return ret;
- }
q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
if (q6v5->fatal_irq < 0)
@@ -280,10 +313,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
NULL, q6v5_fatal_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 fatal", q6v5);
- if (ret) {
- dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
+ if (ret)
return ret;
- }
q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
if (q6v5->ready_irq < 0)
@@ -293,10 +324,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
NULL, q6v5_ready_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 ready", q6v5);
- if (ret) {
- dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
+ if (ret)
return ret;
- }
q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
if (q6v5->handover_irq < 0)
@@ -304,13 +333,11 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
NULL, q6v5_handover_interrupt,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+ IRQF_NO_AUTOEN,
"q6v5 handover", q6v5);
- if (ret) {
- dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
+ if (ret)
return ret;
- }
- disable_irq(q6v5->handover_irq);
q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
if (q6v5->stop_irq < 0)
@@ -320,10 +347,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
NULL, q6v5_stop_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 stop", q6v5);
- if (ret) {
- dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
+ if (ret)
return ret;
- }
q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
if (IS_ERR(q6v5->state)) {
diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h
index 5a859c41896e..8991ff090579 100644
--- a/drivers/remoteproc/qcom_q6v5.h
+++ b/drivers/remoteproc/qcom_q6v5.h
@@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/completion.h>
+#include <linux/spinlock.h>
#include <linux/soc/qcom/qcom_aoss.h>
struct icc_path;
@@ -29,6 +30,9 @@ struct qcom_q6v5 {
int handover_irq;
int stop_irq;
+ /* Protects handover_irq_enabled against stop/handover races. */
+ spinlock_t handover_lock;
+ bool handover_irq_enabled;
bool handover_issued;
struct completion start_done;
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index b5c8d6d38c9c..2e5fb5954fa9 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -104,8 +104,9 @@ struct qcom_adsp {
struct completion stop_done;
phys_addr_t mem_phys;
+ unsigned long iova;
phys_addr_t mem_reloc;
- void *mem_region;
+ void __iomem *mem_region;
size_t mem_size;
bool has_iommu;
@@ -318,7 +319,7 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
int ret;
ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware,
- adsp->mem_region, adsp->mem_phys,
+ (__force void *)adsp->mem_region, adsp->mem_phys,
adsp->mem_size, &adsp->mem_reloc);
if (ret)
return ret;
@@ -333,7 +334,7 @@ static void adsp_unmap_carveout(struct rproc *rproc)
struct qcom_adsp *adsp = rproc->priv;
if (adsp->has_iommu)
- iommu_unmap(rproc->domain, adsp->mem_phys, adsp->mem_size);
+ iommu_unmap(rproc->domain, adsp->iova, adsp->mem_size);
}
static int adsp_map_carveout(struct rproc *rproc)
@@ -341,7 +342,6 @@ static int adsp_map_carveout(struct rproc *rproc)
struct qcom_adsp *adsp = rproc->priv;
struct of_phandle_args args;
long long sid;
- unsigned long iova;
int ret;
if (!adsp->has_iommu)
@@ -355,11 +355,12 @@ static int adsp_map_carveout(struct rproc *rproc)
return ret;
sid = args.args[0] & SID_MASK_DEFAULT;
+ of_node_put(args.np);
/* Add SID configuration for ADSP Firmware to SMMU */
- iova = adsp->mem_phys | (sid << 32);
+ adsp->iova = adsp->mem_phys | (sid << 32);
- ret = iommu_map(rproc->domain, iova, adsp->mem_phys,
+ ret = iommu_map(rproc->domain, adsp->iova, adsp->mem_phys,
adsp->mem_size, IOMMU_READ | IOMMU_WRITE,
GFP_KERNEL);
if (ret) {
@@ -491,7 +492,7 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iom
if (offset < 0 || offset + len > adsp->mem_size)
return NULL;
- return adsp->mem_region + offset;
+ return (__force void *)adsp->mem_region + offset;
}
static int adsp_parse_firmware(struct rproc *rproc, const struct firmware *fw)
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 91940977ca89..2f71ed2feff6 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -34,6 +34,7 @@
#include "qcom_pil_info.h"
#include "qcom_q6v5.h"
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#define MPSS_CRASH_REASON_SMEM 421
@@ -124,6 +125,7 @@
#define QDSP6v56_CLAMP_QMC_MEM BIT(22)
#define QDSP6SS_XO_CBCR 0x0038
#define QDSP6SS_ACC_OVERRIDE_VAL 0x20
+#define QDSP6SS_ACC_OVERRIDE_VAL_9607 0x80800000
#define QDSP6v55_BHS_EN_REST_ACK BIT(0)
/* QDSP6v65 parameters */
@@ -161,7 +163,9 @@ struct rproc_hexagon_res {
char **active_clk_names;
char **proxy_pd_names;
int version;
+ int ssctl_id;
bool need_mem_protection;
+ bool need_pas_mem_setup;
bool has_alt_reset;
bool has_mba_logs;
bool has_spare_reg;
@@ -240,6 +244,7 @@ struct q6v5 {
struct qcom_sysmon *sysmon;
struct platform_device *bam_dmux;
bool need_mem_protection;
+ bool need_pas_mem_setup;
bool has_alt_reset;
bool has_mba_logs;
bool has_spare_reg;
@@ -254,10 +259,14 @@ struct q6v5 {
};
enum {
+ MSS_MDM9607,
MSS_MSM8226,
MSS_MSM8909,
MSS_MSM8916,
+ MSS_MSM8917,
MSS_MSM8926,
+ MSS_MSM8937,
+ MSS_MSM8940,
MSS_MSM8953,
MSS_MSM8974,
MSS_MSM8996,
@@ -745,15 +754,25 @@ static int q6v5proc_reset(struct q6v5 *qproc)
return ret;
}
goto pbl_wait;
- } else if (qproc->version == MSS_MSM8909 ||
+ } else if (qproc->version == MSS_MDM9607 ||
+ qproc->version == MSS_MSM8909 ||
+ qproc->version == MSS_MSM8917 ||
+ qproc->version == MSS_MSM8937 ||
+ qproc->version == MSS_MSM8940 ||
qproc->version == MSS_MSM8953 ||
qproc->version == MSS_MSM8996 ||
qproc->version == MSS_MSM8998 ||
qproc->version == MSS_SDM660) {
- if (qproc->version != MSS_MSM8909 &&
- qproc->version != MSS_MSM8953)
- /* Override the ACC value if required */
+ /* Override the ACC value if required */
+ if (qproc->version == MSS_MDM9607 ||
+ qproc->version == MSS_MSM8917 ||
+ qproc->version == MSS_MSM8937 ||
+ qproc->version == MSS_MSM8940)
+ writel(QDSP6SS_ACC_OVERRIDE_VAL_9607,
+ qproc->reg_base + QDSP6SS_STRAP_ACC);
+ else if (qproc->version != MSS_MSM8909 &&
+ qproc->version != MSS_MSM8953)
writel(QDSP6SS_ACC_OVERRIDE_VAL,
qproc->reg_base + QDSP6SS_STRAP_ACC);
@@ -799,6 +818,7 @@ static int q6v5proc_reset(struct q6v5 *qproc)
if (qproc->version != MSS_MSM8909) {
int mem_pwr_ctl;
+ int reverse;
/* Deassert QDSP6 compiler memory clamp */
val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
@@ -810,17 +830,37 @@ static int q6v5proc_reset(struct q6v5 *qproc)
writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
/* Turn on L1, L2, ETB and JU memories 1 at a time */
- if (qproc->version == MSS_MSM8953 ||
+ if (qproc->version == MSS_MSM8940 ||
+ qproc->version == MSS_MSM8953 ||
qproc->version == MSS_MSM8996) {
mem_pwr_ctl = QDSP6SS_MEM_PWR_CTL;
i = 19;
+ reverse = 0;
+ } else if (qproc->version == MSS_MDM9607 ||
+ qproc->version == MSS_MSM8917 ||
+ qproc->version == MSS_MSM8937) {
+ mem_pwr_ctl = QDSP6SS_MEM_PWR_CTL;
+ i = 19;
+ /*
+ * Set first 5 bits in reverse to avoid
+ * "inrush current" issues.
+ */
+ reverse = 6;
} else {
/* MSS_MSM8998, MSS_SDM660 */
mem_pwr_ctl = QDSP6V6SS_MEM_PWR_CTL;
i = 28;
+ reverse = 0;
}
+
val = readl(qproc->reg_base + mem_pwr_ctl);
- for (; i >= 0; i--) {
+ for (; i >= reverse; i--) {
+ val |= BIT(i);
+ writel(val, qproc->reg_base + mem_pwr_ctl);
+ val = readl(qproc->reg_base + mem_pwr_ctl);
+ udelay(1);
+ }
+ for (i = 0; i < reverse; i++) {
val |= BIT(i);
writel(val, qproc->reg_base + mem_pwr_ctl);
/*
@@ -828,7 +868,7 @@ static int q6v5proc_reset(struct q6v5 *qproc)
* wait for 1us for both memory peripheral and data
* array to turn on.
*/
- val |= readl(qproc->reg_base + mem_pwr_ctl);
+ val = readl(qproc->reg_base + mem_pwr_ctl);
udelay(1);
}
} else {
@@ -1441,8 +1481,8 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
}
- if (qproc->version == MSS_MSM8953) {
- ret = qcom_scm_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
+ if (qproc->need_pas_mem_setup) {
+ ret = qcom_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
if (ret) {
dev_err(qproc->dev,
"setting up mpss memory failed: %d\n", ret);
@@ -2039,9 +2079,18 @@ static int q6v5_probe(struct platform_device *pdev)
if (!desc)
return -EINVAL;
+ /*
+ * Memory protection is done through qcom_scm_assign_mem(), which needs
+ * SCM but not PAS. Only the memory setup path issues PAS calls, so
+ * requiring PAS for every need_mem_protection platform prevents the
+ * modem from probing at all on TZ firmware that offers no PAS.
+ */
if (desc->need_mem_protection && !qcom_scm_is_available())
return -EPROBE_DEFER;
+ if (desc->need_pas_mem_setup && !qcom_pas_is_available())
+ return -EPROBE_DEFER;
+
mba_image = desc->hexagon_mba_image;
ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name",
0, &mba_image);
@@ -2153,7 +2202,7 @@ static int q6v5_probe(struct platform_device *pdev)
qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
qcom_add_pdm_subdev(rproc, &qproc->pdm_subdev);
qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
- qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
+ qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", desc->ssctl_id);
if (IS_ERR(qproc->sysmon)) {
ret = PTR_ERR(qproc->sysmon);
goto remove_subdevs;
@@ -2224,6 +2273,7 @@ static const struct rproc_hexagon_res sc7180_mss = {
NULL
},
.need_mem_protection = true,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = true,
.has_spare_reg = true,
@@ -2232,6 +2282,7 @@ static const struct rproc_hexagon_res sc7180_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_SC7180,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res sc7280_mss = {
@@ -2253,6 +2304,7 @@ static const struct rproc_hexagon_res sc7280_mss = {
NULL
},
.need_mem_protection = true,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = true,
.has_spare_reg = false,
@@ -2261,6 +2313,7 @@ static const struct rproc_hexagon_res sc7280_mss = {
.has_ext_cntl_regs = true,
.has_vq6 = true,
.version = MSS_SC7280,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res sdm660_mss = {
@@ -2285,6 +2338,7 @@ static const struct rproc_hexagon_res sdm660_mss = {
NULL
},
.need_mem_protection = true,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2293,6 +2347,7 @@ static const struct rproc_hexagon_res sdm660_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_SDM660,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res sdm845_mss = {
@@ -2321,6 +2376,7 @@ static const struct rproc_hexagon_res sdm845_mss = {
NULL
},
.need_mem_protection = true,
+ .need_pas_mem_setup = false,
.has_alt_reset = true,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2329,6 +2385,7 @@ static const struct rproc_hexagon_res sdm845_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_SDM845,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res msm8998_mss = {
@@ -2353,6 +2410,7 @@ static const struct rproc_hexagon_res msm8998_mss = {
NULL
},
.need_mem_protection = true,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2361,6 +2419,7 @@ static const struct rproc_hexagon_res msm8998_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8998,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res msm8996_mss = {
@@ -2392,6 +2451,7 @@ static const struct rproc_hexagon_res msm8996_mss = {
NULL
},
.need_mem_protection = true,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2400,6 +2460,43 @@ static const struct rproc_hexagon_res msm8996_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8996,
+ .ssctl_id = 0x12,
+};
+
+static const struct rproc_hexagon_res mdm9607_mss = {
+ .hexagon_mba_image = "mba.mbn",
+ .proxy_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "pll",
+ .uA = 100000,
+ },
+ {}
+ },
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
+ .proxy_pd_names = (char*[]){
+ "mx",
+ "cx",
+ NULL
+ },
+ .need_mem_protection = false,
+ .has_alt_reset = false,
+ .has_mba_logs = false,
+ .has_spare_reg = false,
+ .has_qaccept_regs = false,
+ .has_ext_bhs_reg = false,
+ .has_ext_cntl_regs = false,
+ .has_vq6 = false,
+ .version = MSS_MDM9607,
+ .ssctl_id = 0x22,
};
static const struct rproc_hexagon_res msm8909_mss = {
@@ -2427,6 +2524,7 @@ static const struct rproc_hexagon_res msm8909_mss = {
NULL
},
.need_mem_protection = false,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2435,6 +2533,7 @@ static const struct rproc_hexagon_res msm8909_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8909,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res msm8916_mss = {
@@ -2473,6 +2572,7 @@ static const struct rproc_hexagon_res msm8916_mss = {
NULL
},
.need_mem_protection = false,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2481,6 +2581,142 @@ static const struct rproc_hexagon_res msm8916_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8916,
+ .ssctl_id = 0x12,
+};
+
+static const struct rproc_hexagon_res msm8917_mss = {
+ .hexagon_mba_image = "mba.mbn",
+ .proxy_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "pll",
+ .uA = 100000,
+ },
+ {}
+ },
+ .active_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "mss",
+ .uV = 1050000,
+ .uA = 100000,
+ },
+ {}
+ },
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
+ .proxy_pd_names = (char*[]) {
+ "cx",
+ "mx",
+ NULL
+ },
+ .need_mem_protection = false,
+ .need_pas_mem_setup = false,
+ .has_alt_reset = false,
+ .has_mba_logs = false,
+ .has_spare_reg = false,
+ .has_qaccept_regs = false,
+ .has_ext_bhs_reg = false,
+ .has_ext_cntl_regs = false,
+ .has_vq6 = false,
+ .version = MSS_MSM8917,
+ .ssctl_id = 0x12,
+};
+
+static const struct rproc_hexagon_res msm8937_mss = {
+ .hexagon_mba_image = "mba.mbn",
+ .proxy_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "pll",
+ .uA = 100000,
+ },
+ {}
+ },
+ .active_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "mss",
+ .uV = 1050000,
+ .uA = 100000,
+ },
+ {}
+ },
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
+ .proxy_pd_names = (char*[]) {
+ "cx",
+ "mx",
+ NULL
+ },
+ .need_mem_protection = false,
+ .need_pas_mem_setup = true,
+ .has_alt_reset = false,
+ .has_mba_logs = false,
+ .has_spare_reg = false,
+ .has_qaccept_regs = false,
+ .has_ext_bhs_reg = false,
+ .has_ext_cntl_regs = false,
+ .has_vq6 = false,
+ .version = MSS_MSM8937,
+ .ssctl_id = 0x12,
+};
+
+static const struct rproc_hexagon_res msm8940_mss = {
+ .hexagon_mba_image = "mba.mbn",
+ .proxy_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "pll",
+ .uA = 100000,
+ },
+ {}
+ },
+ .active_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "mss",
+ .uV = 1050000,
+ .uA = 100000,
+ },
+ {}
+ },
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
+ .proxy_pd_names = (char*[]) {
+ "cx",
+ "mx",
+ NULL
+ },
+ .need_mem_protection = false,
+ .need_pas_mem_setup = true,
+ .has_alt_reset = false,
+ .has_mba_logs = false,
+ .has_spare_reg = false,
+ .has_qaccept_regs = false,
+ .has_ext_bhs_reg = false,
+ .has_ext_cntl_regs = false,
+ .has_vq6 = false,
+ .version = MSS_MSM8940,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res msm8953_mss = {
@@ -2509,6 +2745,7 @@ static const struct rproc_hexagon_res msm8953_mss = {
NULL
},
.need_mem_protection = false,
+ .need_pas_mem_setup = true,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2517,6 +2754,7 @@ static const struct rproc_hexagon_res msm8953_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8953,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res msm8974_mss = {
@@ -2562,6 +2800,7 @@ static const struct rproc_hexagon_res msm8974_mss = {
NULL
},
.need_mem_protection = false,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2570,6 +2809,7 @@ static const struct rproc_hexagon_res msm8974_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8974,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res msm8226_mss = {
@@ -2600,6 +2840,7 @@ static const struct rproc_hexagon_res msm8226_mss = {
NULL
},
.need_mem_protection = false,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2608,6 +2849,7 @@ static const struct rproc_hexagon_res msm8226_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8226,
+ .ssctl_id = 0x12,
};
static const struct rproc_hexagon_res msm8926_mss = {
@@ -2646,6 +2888,7 @@ static const struct rproc_hexagon_res msm8926_mss = {
NULL
},
.need_mem_protection = false,
+ .need_pas_mem_setup = false,
.has_alt_reset = false,
.has_mba_logs = false,
.has_spare_reg = false,
@@ -2654,22 +2897,27 @@ static const struct rproc_hexagon_res msm8926_mss = {
.has_ext_cntl_regs = false,
.has_vq6 = false,
.version = MSS_MSM8926,
+ .ssctl_id = 0x12,
};
static const struct of_device_id q6v5_of_match[] = {
- { .compatible = "qcom,q6v5-pil", .data = &msm8916_mss},
- { .compatible = "qcom,msm8226-mss-pil", .data = &msm8226_mss},
- { .compatible = "qcom,msm8909-mss-pil", .data = &msm8909_mss},
- { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss},
- { .compatible = "qcom,msm8926-mss-pil", .data = &msm8926_mss},
- { .compatible = "qcom,msm8953-mss-pil", .data = &msm8953_mss},
- { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss},
- { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss},
- { .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss},
- { .compatible = "qcom,sc7180-mss-pil", .data = &sc7180_mss},
- { .compatible = "qcom,sc7280-mss-pil", .data = &sc7280_mss},
- { .compatible = "qcom,sdm660-mss-pil", .data = &sdm660_mss},
- { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss},
+ { .compatible = "qcom,q6v5-pil", .data = &msm8916_mss },
+ { .compatible = "qcom,mdm9607-mss-pil", .data = &mdm9607_mss },
+ { .compatible = "qcom,msm8226-mss-pil", .data = &msm8226_mss },
+ { .compatible = "qcom,msm8909-mss-pil", .data = &msm8909_mss },
+ { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss },
+ { .compatible = "qcom,msm8917-mss-pil", .data = &msm8917_mss },
+ { .compatible = "qcom,msm8926-mss-pil", .data = &msm8926_mss },
+ { .compatible = "qcom,msm8937-mss-pil", .data = &msm8937_mss },
+ { .compatible = "qcom,msm8940-mss-pil", .data = &msm8940_mss },
+ { .compatible = "qcom,msm8953-mss-pil", .data = &msm8953_mss },
+ { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss },
+ { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss },
+ { .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss },
+ { .compatible = "qcom,sc7180-mss-pil", .data = &sc7180_mss },
+ { .compatible = "qcom,sc7280-mss-pil", .data = &sc7280_mss },
+ { .compatible = "qcom,sdm660-mss-pil", .data = &sdm660_mss },
+ { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss },
{ },
};
MODULE_DEVICE_TABLE(of, q6v5_of_match);
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 46204da046fa..a005546c265d 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -16,10 +16,12 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
@@ -60,6 +62,8 @@ struct qcom_pas_data {
int region_assign_count;
bool region_assign_shared;
int region_assign_vmid;
+ bool early_boot;
+ bool needs_tzmem;
};
struct qcom_pas {
@@ -92,16 +96,14 @@ struct qcom_pas {
const struct firmware *firmware;
const struct firmware *dtb_firmware;
- struct completion start_done;
- struct completion stop_done;
-
phys_addr_t mem_phys;
phys_addr_t dtb_mem_phys;
phys_addr_t mem_reloc;
phys_addr_t dtb_mem_reloc;
phys_addr_t region_assign_phys[MAX_ASSIGN_COUNT];
- void *mem_region;
- void *dtb_mem_region;
+
+ void __iomem *mem_region;
+
size_t mem_size;
size_t dtb_mem_size;
size_t region_assign_size[MAX_ASSIGN_COUNT];
@@ -117,9 +119,10 @@ struct qcom_pas {
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
+ struct platform_device *bam_dmux;
- struct qcom_scm_pas_context *pas_ctx;
- struct qcom_scm_pas_context *dtb_pas_ctx;
+ struct qcom_pas_context *pas_ctx;
+ struct qcom_pas_context *dtb_pas_ctx;
};
static void qcom_pas_segment_dump(struct rproc *rproc,
@@ -148,7 +151,13 @@ static void qcom_pas_minidump(struct rproc *rproc)
if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
return;
+ pas->mem_region = qcom_pas_ctx_map(pas->pas_ctx);
+ if (!pas->mem_region)
+ return;
+
qcom_minidump(rproc, pas->minidump_id, qcom_pas_segment_dump);
+ iounmap(pas->mem_region);
+ pas->mem_region = NULL;
}
static int qcom_pas_pds_enable(struct qcom_pas *pas, struct device **pds,
@@ -196,7 +205,7 @@ static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas)
do {
msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS);
- ret = qcom_scm_pas_shutdown(pas->pas_id);
+ ret = qcom_pas_shutdown(pas->pas_id);
} while (ret == -EINVAL && --retry_num);
return ret;
@@ -212,9 +221,9 @@ static int qcom_pas_unprepare(struct rproc *rproc)
* auth_and_reset() was successful, but in other cases clean it up
* here.
*/
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
return 0;
}
@@ -228,9 +237,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
pas->firmware = fw;
if (pas->lite_pas_id)
- qcom_scm_pas_shutdown(pas->lite_pas_id);
+ qcom_pas_shutdown(pas->lite_pas_id);
if (pas->lite_dtb_pas_id)
- qcom_scm_pas_shutdown(pas->lite_dtb_pas_id);
+ qcom_pas_shutdown(pas->lite_dtb_pas_id);
if (pas->dtb_pas_id) {
ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev);
@@ -241,19 +250,15 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
}
ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware,
- pas->dtb_firmware_name, pas->dtb_mem_region,
- &pas->dtb_mem_reloc);
- if (ret)
- goto release_dtb_metadata;
+ pas->dtb_firmware_name, &pas->dtb_mem_reloc);
+ if (ret) {
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
+ release_firmware(pas->dtb_firmware);
+ return ret;
+ }
}
return 0;
-
-release_dtb_metadata:
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
- release_firmware(pas->dtb_firmware);
-
- return ret;
}
static void qcom_pas_unmap_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size)
@@ -310,7 +315,7 @@ static int qcom_pas_start(struct rproc *rproc)
if (ret)
goto disable_px_supply;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
+ ret = qcom_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
if (ret) {
dev_err(pas->dev,
"failed to authenticate dtb image and release reset\n");
@@ -319,7 +324,7 @@ static int qcom_pas_start(struct rproc *rproc)
}
ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware,
- pas->mem_region, &pas->mem_reloc);
+ &pas->mem_reloc);
if (ret)
goto release_pas_metadata;
@@ -329,7 +334,7 @@ static int qcom_pas_start(struct rproc *rproc)
if (ret)
goto release_pas_metadata;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx);
+ ret = qcom_pas_prepare_and_auth_reset(pas->pas_ctx);
if (ret) {
dev_err(pas->dev,
"failed to authenticate image and release reset\n");
@@ -339,13 +344,13 @@ static int qcom_pas_start(struct rproc *rproc)
ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) {
dev_err(pas->dev, "start timed out\n");
- qcom_scm_pas_shutdown(pas->pas_id);
+ qcom_pas_shutdown(pas->pas_id);
goto unmap_carveout;
}
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
/* firmware is used to pass reference from qcom_pas_start(), drop it now */
pas->firmware = NULL;
@@ -355,9 +360,9 @@ static int qcom_pas_start(struct rproc *rproc)
unmap_carveout:
qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size);
release_pas_metadata:
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
unmap_dtb_carveout:
if (pas->dtb_pas_id)
@@ -400,13 +405,14 @@ static int qcom_pas_stop(struct rproc *rproc)
{
struct qcom_pas *pas = rproc->priv;
int handover;
+ int dtb_ret;
int ret;
ret = qcom_q6v5_request_stop(&pas->q6v5, pas->sysmon);
if (ret == -ETIMEDOUT)
dev_err(pas->dev, "timed out on wait\n");
- ret = qcom_scm_pas_shutdown(pas->pas_id);
+ ret = qcom_pas_shutdown(pas->pas_id);
if (ret && pas->decrypt_shutdown)
ret = qcom_pas_shutdown_poll_decrypt(pas);
@@ -414,9 +420,12 @@ static int qcom_pas_stop(struct rproc *rproc)
dev_err(pas->dev, "failed to shutdown: %d\n", ret);
if (pas->dtb_pas_id) {
- ret = qcom_scm_pas_shutdown(pas->dtb_pas_id);
- if (ret)
- dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
+ dtb_ret = qcom_pas_shutdown(pas->dtb_pas_id);
+ if (dtb_ret)
+ dev_err(pas->dev, "failed to shutdown dtb: %d\n", dtb_ret);
+
+ if (!ret && dtb_ret)
+ ret = dtb_ret;
qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size);
}
@@ -445,7 +454,7 @@ static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is
if (is_iomem)
*is_iomem = true;
- return pas->mem_region + offset;
+ return (__force void *)pas->mem_region + offset;
}
static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *fw)
@@ -484,11 +493,11 @@ static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *f
*
* Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources
* or not and if it is not having then we pass NULL and zero as input resource
- * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table()
+ * table pointer and size respectively to the argument of qcom_pas_get_rsc_table()
* and this is even true for Qualcomm remote processor who does follow remoteproc
* framework.
*/
- output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
+ output_rt = qcom_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0;
if (ret) {
dev_err(pas->dev, "Error in getting resource table: %d\n", ret);
@@ -510,6 +519,78 @@ static unsigned long qcom_pas_panic(struct rproc *rproc)
return qcom_q6v5_panic(&pas->q6v5);
}
+static int qcom_pas_attach(struct rproc *rproc)
+{
+ struct qcom_pas *pas = rproc->priv;
+ bool ready_state;
+ bool crash_state;
+ bool stop_state;
+ int ret;
+
+ pas->q6v5.handover_issued = true;
+
+ pas->q6v5.running = true;
+ ret = irq_get_irqchip_state(pas->q6v5.fatal_irq,
+ IRQCHIP_STATE_LINE_LEVEL, &crash_state);
+ if (ret)
+ goto disable_running;
+
+ if (crash_state) {
+ dev_err(pas->dev, "Subsystem has crashed before driver probe\n");
+ rproc_report_crash(rproc, RPROC_FATAL_ERROR);
+ ret = -EINVAL;
+ goto disable_running;
+ }
+
+ ret = irq_get_irqchip_state(pas->q6v5.stop_irq,
+ IRQCHIP_STATE_LINE_LEVEL, &stop_state);
+ if (ret)
+ goto disable_running;
+
+ if (stop_state || qcom_sysmon_shutdown_irq_state(pas->sysmon)) {
+ dev_info(pas->dev, "Subsystem found stop state set. Falling back to start.\n");
+ goto unroll_attach;
+ }
+
+ ret = irq_get_irqchip_state(pas->q6v5.ready_irq,
+ IRQCHIP_STATE_LINE_LEVEL, &ready_state);
+ if (ret)
+ goto disable_running;
+
+ if (unlikely(!ready_state)) {
+ /*
+ * The bootloader may not support early boot, mark the state as
+ * RPROC_OFFLINE so that the PAS driver can load the firmware and
+ * start the remoteproc.
+ */
+ dev_err(pas->dev, "Failed to get subsystem ready interrupt\n");
+ goto unroll_attach;
+ }
+
+ return 0;
+
+unroll_attach:
+ pas->rproc->state = RPROC_OFFLINE;
+ ret = -EINVAL;
+disable_running:
+ pas->q6v5.running = false;
+
+ return ret;
+}
+
+static void qcom_pas_coredump(struct rproc *rproc)
+{
+ struct qcom_pas *pas = rproc->priv;
+
+ pas->mem_region = qcom_pas_ctx_map(pas->pas_ctx);
+ if (!pas->mem_region)
+ return;
+
+ rproc_coredump(rproc);
+ iounmap(pas->mem_region);
+ pas->mem_region = NULL;
+}
+
static const struct rproc_ops qcom_pas_ops = {
.unprepare = qcom_pas_unprepare,
.start = qcom_pas_start,
@@ -518,6 +599,8 @@ static const struct rproc_ops qcom_pas_ops = {
.parse_fw = qcom_pas_parse_firmware,
.load = qcom_pas_load,
.panic = qcom_pas_panic,
+ .attach = qcom_pas_attach,
+ .coredump = qcom_pas_coredump,
};
static const struct rproc_ops qcom_pas_minidump_ops = {
@@ -529,6 +612,7 @@ static const struct rproc_ops qcom_pas_minidump_ops = {
.load = qcom_pas_load,
.panic = qcom_pas_panic,
.coredump = qcom_pas_minidump,
+ .attach = qcom_pas_attach,
};
static int qcom_pas_init_clock(struct qcom_pas *pas)
@@ -634,11 +718,11 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas *pas)
pas->mem_phys = pas->mem_reloc = res.start;
pas->mem_size = resource_size(&res);
- pas->mem_region = devm_ioremap_resource_wc(pas->dev, &res);
- if (IS_ERR(pas->mem_region)) {
- dev_err(pas->dev, "unable to map memory region: %pR\n", &res);
- return PTR_ERR(pas->mem_region);
- }
+
+ pas->pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->pas_id,
+ pas->mem_phys, pas->mem_size);
+ if (IS_ERR(pas->pas_ctx))
+ return PTR_ERR(pas->pas_ctx);
if (!pas->dtb_pas_id)
return 0;
@@ -651,11 +735,12 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas *pas)
pas->dtb_mem_phys = pas->dtb_mem_reloc = res.start;
pas->dtb_mem_size = resource_size(&res);
- pas->dtb_mem_region = devm_ioremap_resource_wc(pas->dev, &res);
- if (IS_ERR(pas->dtb_mem_region)) {
- dev_err(pas->dev, "unable to map dtb memory region: %pR\n", &res);
- return PTR_ERR(pas->dtb_mem_region);
- }
+
+ pas->dtb_pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->dtb_pas_id,
+ pas->dtb_mem_phys,
+ pas->dtb_mem_size);
+ if (IS_ERR(pas->dtb_pas_ctx))
+ return PTR_ERR(pas->dtb_pas_ctx);
return 0;
}
@@ -738,6 +823,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
const struct qcom_pas_data *desc;
struct qcom_pas *pas;
struct rproc *rproc;
+ struct device_node *node;
const char *fw_name, *dtb_fw_name = NULL;
const struct rproc_ops *ops = &qcom_pas_ops;
int ret;
@@ -746,7 +832,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
if (!desc)
return -EINVAL;
- if (!qcom_scm_is_available())
+ if (!qcom_pas_is_available())
return -EPROBE_DEFER;
fw_name = desc->firmware_name;
@@ -838,27 +924,21 @@ static int qcom_pas_probe(struct platform_device *pdev)
qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name);
- pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id,
- pas->mem_phys, pas->mem_size);
- if (IS_ERR(pas->pas_ctx)) {
- ret = PTR_ERR(pas->pas_ctx);
- goto remove_ssr_sysmon;
- }
+ pas->pas_ctx->use_tzmem = desc->needs_tzmem || rproc->has_iommu;
+ if (pas->dtb_pas_id)
+ pas->dtb_pas_ctx->use_tzmem = desc->needs_tzmem || rproc->has_iommu;
- pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id,
- pas->dtb_mem_phys,
- pas->dtb_mem_size);
- if (IS_ERR(pas->dtb_pas_ctx)) {
- ret = PTR_ERR(pas->dtb_pas_ctx);
- goto remove_ssr_sysmon;
- }
+ if (desc->early_boot)
+ pas->rproc->state = RPROC_DETACHED;
- pas->pas_ctx->use_tzmem = rproc->has_iommu;
- pas->dtb_pas_ctx->use_tzmem = rproc->has_iommu;
ret = rproc_add(rproc);
if (ret)
goto remove_ssr_sysmon;
+ node = of_get_compatible_child(pdev->dev.of_node, "qcom,bam-dmux");
+ pas->bam_dmux = of_platform_device_create(node, NULL, &pdev->dev);
+ of_node_put(node);
+
return 0;
remove_ssr_sysmon:
@@ -883,6 +963,9 @@ static void qcom_pas_remove(struct platform_device *pdev)
{
struct qcom_pas *pas = platform_get_drvdata(pdev);
+ if (pas->bam_dmux)
+ of_platform_device_destroy(&pas->bam_dmux->dev, NULL);
+
rproc_del(pas->rproc);
qcom_q6v5_deinit(&pas->q6v5);
@@ -1357,6 +1440,111 @@ static const struct qcom_pas_data milos_cdsp_resource = {
.smem_host_id = 5,
};
+static const struct qcom_pas_data nord_adsp_resource = {
+ .crash_reason_smem = 423,
+ .firmware_name = "adsp.mbn",
+ .dtb_firmware_name = "adsp_dtb.mbn",
+ .pas_id = 1,
+ .dtb_pas_id = 36,
+ .minidump_id = 5,
+ .auto_boot = true,
+ .early_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ NULL
+ },
+ .load_state = "adsp",
+ .ssr_name = "lpass",
+ .sysmon_name = "adsp",
+ .ssctl_id = 0x14,
+ .smem_host_id = 2,
+};
+
+static const struct qcom_pas_data nord_cdsp0_resource = {
+ .crash_reason_smem = 601,
+ .firmware_name = "cdsp.mbn",
+ .dtb_firmware_name = "cdsp_dtb.mbn",
+ .pas_id = 18,
+ .dtb_pas_id = 37,
+ .minidump_id = 7,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ "nsp",
+ NULL
+ },
+ .load_state = "cdsp",
+ .ssr_name = "cdsp0",
+ .sysmon_name = "cdsp0",
+ .ssctl_id = 0x17,
+ .smem_host_id = 5,
+};
+
+static const struct qcom_pas_data nord_cdsp1_resource = {
+ .crash_reason_smem = 633,
+ .firmware_name = "cdsp1.mbn",
+ .dtb_firmware_name = "cdsp1_dtb.mbn",
+ .pas_id = 30,
+ .dtb_pas_id = 59,
+ .minidump_id = 20,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ "nsp",
+ NULL
+ },
+ .load_state = "cdsp1",
+ .ssr_name = "cdsp1",
+ .sysmon_name = "cdsp1",
+ .ssctl_id = 0x20,
+ .smem_host_id = 69,
+};
+
+static const struct qcom_pas_data nord_cdsp2_resource = {
+ .crash_reason_smem = 665,
+ .firmware_name = "cdsp2.mbn",
+ .dtb_firmware_name = "cdsp2_dtb.mbn",
+ .pas_id = 57,
+ .dtb_pas_id = 60,
+ .minidump_id = 29,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ "nsp",
+ NULL
+ },
+ .load_state = "cdsp2",
+ .ssr_name = "cdsp2",
+ .sysmon_name = "cdsp2",
+ .ssctl_id = 0x1f,
+ .smem_host_id = 133,
+};
+
+static const struct qcom_pas_data nord_cdsp3_resource = {
+ .crash_reason_smem = 666,
+ .firmware_name = "cdsp3.mbn",
+ .dtb_firmware_name = "cdsp3_dtb.mbn",
+ .pas_id = 58,
+ .dtb_pas_id = 61,
+ .minidump_id = 30,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ "nsp",
+ NULL
+ },
+ .load_state = "cdsp3",
+ .ssr_name = "cdsp3",
+ .sysmon_name = "cdsp3",
+ .ssctl_id = 0x1a,
+ .smem_host_id = 197,
+};
+
static const struct qcom_pas_data sm8450_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
@@ -1457,6 +1645,51 @@ static const struct qcom_pas_data sc7280_wpss_resource = {
.ssctl_id = 0x19,
};
+static const struct qcom_pas_data shikra_cdsp_resource = {
+ .crash_reason_smem = 601,
+ .firmware_name = "cdsp.mbn",
+ .pas_id = 18,
+ .minidump_id = 7,
+ .auto_boot = true,
+ .proxy_pd_names = (char *[]){
+ "cx",
+ NULL
+ },
+ .load_state = "cdsp",
+ .ssr_name = "cdsp",
+ .sysmon_name = "cdsp",
+ .ssctl_id = 0x17,
+ .smem_host_id = 5,
+};
+
+static const struct qcom_pas_data shikra_lpaicp_resource = {
+ .crash_reason_smem = 682,
+ .firmware_name = "lpaicp.mbn",
+ .dtb_firmware_name = "lpaicp_dtb.mbn",
+ .pas_id = 0x56,
+ .dtb_pas_id = 0x57,
+ .minidump_id = 0,
+ .auto_boot = true,
+ .ssr_name = "lpaicp",
+ .sysmon_name = "lpaicp",
+};
+
+static const struct qcom_pas_data shikra_mpss_resource = {
+ .crash_reason_smem = 421,
+ .firmware_name = "qdsp6sw.mbn",
+ .pas_id = 4,
+ .minidump_id = 3,
+ .auto_boot = false,
+ .proxy_pd_names = (char *[]){
+ "cx",
+ NULL
+ },
+ .load_state = "modem",
+ .ssr_name = "mpss",
+ .sysmon_name = "modem",
+ .ssctl_id = 0x12,
+};
+
static const struct qcom_pas_data sm8650_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
@@ -1530,79 +1763,151 @@ static const struct qcom_pas_data sm8750_mpss_resource = {
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
};
+static const struct qcom_pas_data kaanapali_soccp_resource = {
+ .crash_reason_smem = 656,
+ .firmware_name = "soccp.mbn",
+ .dtb_firmware_name = "soccp_dtb.mbn",
+ .pas_id = 51,
+ .dtb_pas_id = 0x41,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ NULL
+ },
+ .ssr_name = "soccp",
+ .sysmon_name = "soccp",
+ .auto_boot = true,
+ .early_boot = true,
+};
+
+static const struct qcom_pas_data glymur_soccp_resource = {
+ .crash_reason_smem = 656,
+ .firmware_name = "soccp.mbn",
+ .dtb_firmware_name = "soccp_dtb.mbn",
+ .pas_id = 51,
+ .dtb_pas_id = 0x41,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ NULL
+ },
+ .ssr_name = "soccp",
+ .sysmon_name = "soccp",
+ .auto_boot = true,
+ .early_boot = true,
+ .needs_tzmem = true,
+};
+
+static const struct qcom_pas_data eliza_cdsp_resource = {
+ .crash_reason_smem = 601,
+ .firmware_name = "cdsp.mbn",
+ .dtb_firmware_name = "cdsp_dtb.mbn",
+ .pas_id = 18,
+ .dtb_pas_id = 0x25,
+ .minidump_id = 7,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ "nsp",
+ NULL
+ },
+ .load_state = "cdsp",
+ .ssr_name = "cdsp",
+ .sysmon_name = "cdsp",
+ .ssctl_id = 0x17,
+ .smem_host_id = 5,
+ .region_assign_idx = 2,
+ .region_assign_count = 1,
+ .region_assign_shared = true,
+ .region_assign_vmid = QCOM_SCM_VMID_CDSP,
+};
+
static const struct of_device_id qcom_pas_of_match[] = {
- { .compatible = "qcom,milos-adsp-pas", .data = &sm8550_adsp_resource},
- { .compatible = "qcom,milos-cdsp-pas", .data = &milos_cdsp_resource},
- { .compatible = "qcom,milos-mpss-pas", .data = &sm8450_mpss_resource},
- { .compatible = "qcom,milos-wpss-pas", .data = &sc7280_wpss_resource},
- { .compatible = "qcom,msm8226-adsp-pil", .data = &msm8996_adsp_resource},
- { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource},
- { .compatible = "qcom,msm8974-adsp-pil", .data = &msm8996_adsp_resource},
- { .compatible = "qcom,msm8996-adsp-pil", .data = &msm8996_adsp_resource},
- { .compatible = "qcom,msm8996-slpi-pil", .data = &msm8996_slpi_resource_init},
- { .compatible = "qcom,msm8998-adsp-pas", .data = &msm8996_adsp_resource},
- { .compatible = "qcom,msm8998-slpi-pas", .data = &msm8996_slpi_resource_init},
+ { .compatible = "qcom,eliza-adsp-pas", .data = &sm8550_adsp_resource },
+ { .compatible = "qcom,eliza-cdsp-pas", .data = &eliza_cdsp_resource },
+ { .compatible = "qcom,glymur-soccp-pas", .data = &glymur_soccp_resource },
+ { .compatible = "qcom,kaanapali-soccp-pas", .data = &kaanapali_soccp_resource },
+ { .compatible = "qcom,milos-adsp-pas", .data = &sm8550_adsp_resource },
+ { .compatible = "qcom,milos-cdsp-pas", .data = &milos_cdsp_resource },
+ { .compatible = "qcom,milos-mpss-pas", .data = &sm8450_mpss_resource },
+ { .compatible = "qcom,milos-wpss-pas", .data = &sc7280_wpss_resource },
+ { .compatible = "qcom,msm8226-adsp-pil", .data = &msm8996_adsp_resource },
+ { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource },
+ { .compatible = "qcom,msm8974-adsp-pil", .data = &msm8996_adsp_resource },
+ { .compatible = "qcom,msm8996-adsp-pil", .data = &msm8996_adsp_resource },
+ { .compatible = "qcom,msm8996-slpi-pil", .data = &msm8996_slpi_resource_init },
+ { .compatible = "qcom,msm8998-adsp-pas", .data = &msm8996_adsp_resource },
+ { .compatible = "qcom,msm8998-slpi-pas", .data = &msm8996_slpi_resource_init },
+ { .compatible = "qcom,nord-adsp-pas", .data = &nord_adsp_resource },
+ { .compatible = "qcom,nord-cdsp0-pas", .data = &nord_cdsp0_resource },
+ { .compatible = "qcom,nord-cdsp1-pas", .data = &nord_cdsp1_resource },
+ { .compatible = "qcom,nord-cdsp2-pas", .data = &nord_cdsp2_resource },
+ { .compatible = "qcom,nord-cdsp3-pas", .data = &nord_cdsp3_resource },
{ .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init },
{ .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
- { .compatible = "qcom,sa8775p-adsp-pas", .data = &sa8775p_adsp_resource},
- { .compatible = "qcom,sa8775p-cdsp0-pas", .data = &sa8775p_cdsp0_resource},
- { .compatible = "qcom,sa8775p-cdsp1-pas", .data = &sa8775p_cdsp1_resource},
- { .compatible = "qcom,sa8775p-gpdsp0-pas", .data = &sa8775p_gpdsp0_resource},
- { .compatible = "qcom,sa8775p-gpdsp1-pas", .data = &sa8775p_gpdsp1_resource},
- { .compatible = "qcom,sar2130p-adsp-pas", .data = &sm8350_adsp_resource},
- { .compatible = "qcom,sc7180-adsp-pas", .data = &sm8250_adsp_resource},
- { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
- { .compatible = "qcom,sc7280-adsp-pas", .data = &sm8350_adsp_resource},
- { .compatible = "qcom,sc7280-cdsp-pas", .data = &sm6350_cdsp_resource},
- { .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init},
- { .compatible = "qcom,sc7280-wpss-pas", .data = &sc7280_wpss_resource},
- { .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
- { .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource},
- { .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource},
- { .compatible = "qcom,sc8280xp-adsp-pas", .data = &sm8250_adsp_resource},
- { .compatible = "qcom,sc8280xp-nsp0-pas", .data = &sc8280xp_nsp0_resource},
- { .compatible = "qcom,sc8280xp-nsp1-pas", .data = &sc8280xp_nsp1_resource},
- { .compatible = "qcom,sdm660-adsp-pas", .data = &adsp_resource_init},
- { .compatible = "qcom,sdm660-cdsp-pas", .data = &cdsp_resource_init},
- { .compatible = "qcom,sdm845-adsp-pas", .data = &sdm845_adsp_resource_init},
- { .compatible = "qcom,sdm845-cdsp-pas", .data = &sdm845_cdsp_resource_init},
- { .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init},
- { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource},
- { .compatible = "qcom,sdx75-mpss-pas", .data = &sm8650_mpss_resource},
- { .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init},
- { .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init},
- { .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource},
- { .compatible = "qcom,sm6350-adsp-pas", .data = &sm6350_adsp_resource},
- { .compatible = "qcom,sm6350-cdsp-pas", .data = &sm6350_cdsp_resource},
- { .compatible = "qcom,sm6350-mpss-pas", .data = &mpss_resource_init},
- { .compatible = "qcom,sm6375-adsp-pas", .data = &sm6350_adsp_resource},
- { .compatible = "qcom,sm6375-cdsp-pas", .data = &sm8150_cdsp_resource},
- { .compatible = "qcom,sm6375-mpss-pas", .data = &sm6375_mpss_resource},
- { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource},
- { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource},
- { .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init},
- { .compatible = "qcom,sm8150-slpi-pas", .data = &sdm845_slpi_resource_init},
- { .compatible = "qcom,sm8250-adsp-pas", .data = &sm8250_adsp_resource},
- { .compatible = "qcom,sm8250-cdsp-pas", .data = &sm8250_cdsp_resource},
- { .compatible = "qcom,sm8250-slpi-pas", .data = &sdm845_slpi_resource_init},
- { .compatible = "qcom,sm8350-adsp-pas", .data = &sm8350_adsp_resource},
- { .compatible = "qcom,sm8350-cdsp-pas", .data = &sm8350_cdsp_resource},
- { .compatible = "qcom,sm8350-slpi-pas", .data = &sdm845_slpi_resource_init},
- { .compatible = "qcom,sm8350-mpss-pas", .data = &mpss_resource_init},
- { .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource},
- { .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
- { .compatible = "qcom,sm8450-slpi-pas", .data = &sdm845_slpi_resource_init},
- { .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource},
- { .compatible = "qcom,sm8550-adsp-pas", .data = &sm8550_adsp_resource},
- { .compatible = "qcom,sm8550-cdsp-pas", .data = &sm8550_cdsp_resource},
- { .compatible = "qcom,sm8550-mpss-pas", .data = &sm8550_mpss_resource},
- { .compatible = "qcom,sm8650-adsp-pas", .data = &sm8550_adsp_resource},
- { .compatible = "qcom,sm8650-cdsp-pas", .data = &sm8650_cdsp_resource},
- { .compatible = "qcom,sm8650-mpss-pas", .data = &sm8650_mpss_resource},
- { .compatible = "qcom,sm8750-mpss-pas", .data = &sm8750_mpss_resource},
- { .compatible = "qcom,x1e80100-adsp-pas", .data = &x1e80100_adsp_resource},
- { .compatible = "qcom,x1e80100-cdsp-pas", .data = &x1e80100_cdsp_resource},
+ { .compatible = "qcom,sa8775p-adsp-pas", .data = &sa8775p_adsp_resource },
+ { .compatible = "qcom,sa8775p-cdsp0-pas", .data = &sa8775p_cdsp0_resource },
+ { .compatible = "qcom,sa8775p-cdsp1-pas", .data = &sa8775p_cdsp1_resource },
+ { .compatible = "qcom,sa8775p-gpdsp0-pas", .data = &sa8775p_gpdsp0_resource },
+ { .compatible = "qcom,sa8775p-gpdsp1-pas", .data = &sa8775p_gpdsp1_resource },
+ { .compatible = "qcom,sar2130p-adsp-pas", .data = &sm8350_adsp_resource },
+ { .compatible = "qcom,sc7180-adsp-pas", .data = &sm8250_adsp_resource },
+ { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init },
+ { .compatible = "qcom,sc7280-adsp-pas", .data = &sm8350_adsp_resource },
+ { .compatible = "qcom,sc7280-cdsp-pas", .data = &sm6350_cdsp_resource },
+ { .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init },
+ { .compatible = "qcom,sc7280-wpss-pas", .data = &sc7280_wpss_resource },
+ { .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource },
+ { .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource },
+ { .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource },
+ { .compatible = "qcom,sc8280xp-adsp-pas", .data = &sm8250_adsp_resource },
+ { .compatible = "qcom,sc8280xp-nsp0-pas", .data = &sc8280xp_nsp0_resource },
+ { .compatible = "qcom,sc8280xp-nsp1-pas", .data = &sc8280xp_nsp1_resource },
+ { .compatible = "qcom,sdm660-adsp-pas", .data = &adsp_resource_init },
+ { .compatible = "qcom,sdm660-cdsp-pas", .data = &cdsp_resource_init },
+ { .compatible = "qcom,sdm845-adsp-pas", .data = &sdm845_adsp_resource_init },
+ { .compatible = "qcom,sdm845-cdsp-pas", .data = &sdm845_cdsp_resource_init },
+ { .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init },
+ { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource },
+ { .compatible = "qcom,sdx75-mpss-pas", .data = &sm8650_mpss_resource },
+ { .compatible = "qcom,shikra-cdsp-pas", .data = &shikra_cdsp_resource },
+ { .compatible = "qcom,shikra-lpaicp-pas", .data = &shikra_lpaicp_resource },
+ { .compatible = "qcom,shikra-mpss-pas", .data = &shikra_mpss_resource },
+ { .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init },
+ { .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init },
+ { .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource },
+ { .compatible = "qcom,sm6350-adsp-pas", .data = &sm6350_adsp_resource },
+ { .compatible = "qcom,sm6350-cdsp-pas", .data = &sm6350_cdsp_resource },
+ { .compatible = "qcom,sm6350-mpss-pas", .data = &mpss_resource_init },
+ { .compatible = "qcom,sm6375-adsp-pas", .data = &sm6350_adsp_resource },
+ { .compatible = "qcom,sm6375-cdsp-pas", .data = &sm8150_cdsp_resource },
+ { .compatible = "qcom,sm6375-mpss-pas", .data = &sm6375_mpss_resource },
+ { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource },
+ { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource },
+ { .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init },
+ { .compatible = "qcom,sm8150-slpi-pas", .data = &sdm845_slpi_resource_init },
+ { .compatible = "qcom,sm8250-adsp-pas", .data = &sm8250_adsp_resource },
+ { .compatible = "qcom,sm8250-cdsp-pas", .data = &sm8250_cdsp_resource },
+ { .compatible = "qcom,sm8250-slpi-pas", .data = &sdm845_slpi_resource_init },
+ { .compatible = "qcom,sm8350-adsp-pas", .data = &sm8350_adsp_resource },
+ { .compatible = "qcom,sm8350-cdsp-pas", .data = &sm8350_cdsp_resource },
+ { .compatible = "qcom,sm8350-slpi-pas", .data = &sdm845_slpi_resource_init },
+ { .compatible = "qcom,sm8350-mpss-pas", .data = &mpss_resource_init },
+ { .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource },
+ { .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource },
+ { .compatible = "qcom,sm8450-slpi-pas", .data = &sdm845_slpi_resource_init },
+ { .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource },
+ { .compatible = "qcom,sm8550-adsp-pas", .data = &sm8550_adsp_resource },
+ { .compatible = "qcom,sm8550-cdsp-pas", .data = &sm8550_cdsp_resource },
+ { .compatible = "qcom,sm8550-mpss-pas", .data = &sm8550_mpss_resource },
+ { .compatible = "qcom,sm8650-adsp-pas", .data = &sm8550_adsp_resource },
+ { .compatible = "qcom,sm8650-cdsp-pas", .data = &sm8650_cdsp_resource },
+ { .compatible = "qcom,sm8650-mpss-pas", .data = &sm8650_mpss_resource },
+ { .compatible = "qcom,sm8750-mpss-pas", .data = &sm8750_mpss_resource },
+ { .compatible = "qcom,x1e80100-adsp-pas", .data = &x1e80100_adsp_resource },
+ { .compatible = "qcom,x1e80100-cdsp-pas", .data = &x1e80100_cdsp_resource },
{ },
};
MODULE_DEVICE_TABLE(of, qcom_pas_of_match);
diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
index c27200159a88..b391724cfd08 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
@@ -96,7 +96,6 @@ struct wcss_data {
unsigned int crash_reason_smem;
u32 version;
bool aon_reset_required;
- bool wcss_q6_reset_required;
const char *ssr_name;
const char *sysmon_name;
int ssctl_id;
@@ -134,7 +133,6 @@ struct q6v5_wcss {
struct reset_control *wcss_aon_reset;
struct reset_control *wcss_reset;
struct reset_control *wcss_q6_reset;
- struct reset_control *wcss_q6_bcr_reset;
struct qcom_q6v5 q6v5;
@@ -309,7 +307,7 @@ static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss)
return ret;
/* Remove reset to the WCNSS QDSP6SS */
- reset_control_deassert(wcss->wcss_q6_bcr_reset);
+ reset_control_deassert(wcss->wcss_q6_reset);
/* Enable Q6SSTOP_AHBFABRIC_CBCR clock */
ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk);
@@ -803,19 +801,10 @@ static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss,
return PTR_ERR(wcss->wcss_reset);
}
- if (desc->wcss_q6_reset_required) {
- wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset");
- if (IS_ERR(wcss->wcss_q6_reset)) {
- dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
- return PTR_ERR(wcss->wcss_q6_reset);
- }
- }
-
- wcss->wcss_q6_bcr_reset = devm_reset_control_get_optional_exclusive(dev,
- "wcss_q6_bcr_reset");
- if (IS_ERR(wcss->wcss_q6_bcr_reset)) {
- dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n");
- return PTR_ERR(wcss->wcss_q6_bcr_reset);
+ wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset");
+ if (IS_ERR(wcss->wcss_q6_reset)) {
+ dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
+ return PTR_ERR(wcss->wcss_q6_reset);
}
return 0;
@@ -1062,7 +1051,6 @@ static const struct wcss_data wcss_ipq8074_res_init = {
.firmware_name = "IPQ8074/q6_fw.mdt",
.crash_reason_smem = WCSS_CRASH_REASON,
.aon_reset_required = true,
- .wcss_q6_reset_required = true,
.ops = &q6v5_wcss_ipq8074_ops,
.requires_force_stop = true,
};
@@ -1072,7 +1060,6 @@ static const struct wcss_data wcss_qcs404_res_init = {
.firmware_name = "wcnss.mdt",
.version = WCSS_QCS404,
.aon_reset_required = false,
- .wcss_q6_reset_required = false,
.ssr_name = "mpss",
.sysmon_name = "wcnss",
.ssctl_id = 0x12,
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index 3ceec1fd6d99..61e1038328e8 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -662,8 +662,6 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 shutdown-ack", sysmon);
if (ret) {
- dev_err(sysmon->dev,
- "failed to acquire shutdown-ack IRQ\n");
kfree(sysmon);
return ERR_PTR(ret);
}
@@ -677,7 +675,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
return ERR_PTR(ret);
}
- qmi_add_lookup(&sysmon->qmi, 43, 0, 0);
+ qmi_add_lookup(&sysmon->qmi, QMI_SERVICE_ID_SSCTL, 0, 0);
sysmon->subdev.prepare = sysmon_prepare;
sysmon->subdev.start = sysmon_start;
@@ -736,6 +734,25 @@ bool qcom_sysmon_shutdown_acked(struct qcom_sysmon *sysmon)
}
EXPORT_SYMBOL_GPL(qcom_sysmon_shutdown_acked);
+bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon)
+{
+ bool shutdown_state;
+ int ret;
+
+ if (!sysmon)
+ return false;
+
+ ret = irq_get_irqchip_state(sysmon->shutdown_irq,
+ IRQCHIP_STATE_LINE_LEVEL, &shutdown_state);
+ if (ret) {
+ dev_warn(sysmon->dev, "failed to get shutdown_state: %d\n", ret);
+ return false;
+ }
+
+ return shutdown_state;
+}
+EXPORT_SYMBOL_GPL(qcom_sysmon_shutdown_irq_state);
+
/**
* sysmon_probe() - probe sys_mon channel
* @rpdev: rpmsg device handle
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 4add9037dbd5..c856a92af43c 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -94,7 +94,7 @@ struct qcom_wcnss {
phys_addr_t mem_phys;
phys_addr_t mem_reloc;
- void *mem_region;
+ void __iomem *mem_region;
size_t mem_size;
struct qcom_rproc_subdev smd_subdev;
@@ -158,7 +158,7 @@ static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
int ret;
ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
- wcnss->mem_region, wcnss->mem_phys,
+ (__force void *)wcnss->mem_region, wcnss->mem_phys,
wcnss->mem_size, &wcnss->mem_reloc);
if (ret)
return ret;
@@ -257,7 +257,7 @@ static int wcnss_start(struct rproc *rproc)
wcnss_indicate_nv_download(wcnss);
wcnss_configure_iris(wcnss);
- ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
+ ret = qcom_pas_auth_and_reset(WCNSS_PAS_ID);
if (ret) {
dev_err(wcnss->dev,
"failed to authenticate image and release reset\n");
@@ -269,7 +269,7 @@ static int wcnss_start(struct rproc *rproc)
if (wcnss->ready_irq > 0 && ret == 0) {
/* We have a ready_irq, but it didn't fire in time. */
dev_err(wcnss->dev, "start timed out\n");
- qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ qcom_pas_shutdown(WCNSS_PAS_ID);
ret = -ETIMEDOUT;
goto disable_iris;
}
@@ -311,7 +311,7 @@ static int wcnss_stop(struct rproc *rproc)
0);
}
- ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ ret = qcom_pas_shutdown(WCNSS_PAS_ID);
if (ret)
dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
@@ -327,7 +327,7 @@ static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_io
if (offset < 0 || offset + len > wcnss->mem_size)
return NULL;
- return wcnss->mem_region + offset;
+ return (__force void *)wcnss->mem_region + offset;
}
static const struct rproc_ops wcnss_ops = {
@@ -441,25 +441,31 @@ static void wcnss_release_pds(struct qcom_wcnss *wcnss)
}
static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
- const struct wcnss_vreg_info *info,
- int num_vregs, int num_pd_vregs)
+ const struct wcnss_data *data)
{
+ const struct wcnss_vreg_info *info = data->vregs;
struct regulator_bulk_data *bulk;
+ size_t i, possible_pds = 0, num_vregs = data->num_vregs;
int ret;
- int i;
+
+ for (i = 0; i < WCNSS_MAX_PDS; i++)
+ if (data->pd_names[i])
+ possible_pds++;
/*
* If attaching the power domains suceeded we can skip requesting
* the regulators for the power domains. For old device trees we need to
* reserve extra space to manage them through the regulator interface.
*/
- if (wcnss->num_pds) {
+ if (possible_pds >= num_vregs) {
+ /* Do nothing if vregs do not include PD regulators (pronto-v3) */
+ } else if (wcnss->num_pds) {
info += wcnss->num_pds;
/* Handle single power domain case */
- if (wcnss->num_pds < num_pd_vregs)
- num_vregs += num_pd_vregs - wcnss->num_pds;
+ if (wcnss->num_pds < data->num_pd_vregs)
+ num_vregs += data->num_pd_vregs - wcnss->num_pds;
} else {
- num_vregs += num_pd_vregs;
+ num_vregs += data->num_pd_vregs;
}
bulk = devm_kcalloc(wcnss->dev,
@@ -515,10 +521,8 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss,
NULL, thread_fn,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"wcnss", wcnss);
- if (ret) {
- dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+ if (ret)
return ret;
- }
/* Return the IRQ number if the IRQ was successfully acquired */
return irq_number;
@@ -557,10 +561,10 @@ static int wcnss_probe(struct platform_device *pdev)
data = of_device_get_match_data(&pdev->dev);
- if (!qcom_scm_is_available())
+ if (!qcom_pas_is_available())
return -EPROBE_DEFER;
- if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
+ if (!qcom_pas_supported(WCNSS_PAS_ID)) {
dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
return -ENXIO;
}
@@ -607,8 +611,7 @@ static int wcnss_probe(struct platform_device *pdev)
if (ret && (ret != -ENODATA || !data->num_pd_vregs))
return ret;
- ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs,
- data->num_pd_vregs);
+ ret = wcnss_init_regulators(wcnss, data);
if (ret)
goto detach_pds;
diff --git a/drivers/remoteproc/rcar_rproc.c b/drivers/remoteproc/rcar_rproc.c
index 3c25625f966d..1fe6c01bde40 100644
--- a/drivers/remoteproc/rcar_rproc.c
+++ b/drivers/remoteproc/rcar_rproc.c
@@ -19,35 +19,6 @@ struct rcar_rproc {
struct reset_control *rst;
};
-static int rcar_rproc_mem_alloc(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- struct device *dev = &rproc->dev;
- void *va;
-
- dev_dbg(dev, "map memory: %pa+%zx\n", &mem->dma, mem->len);
- 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 rcar_rproc_mem_release(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- dev_dbg(&rproc->dev, "unmap memory: %pa\n", &mem->dma);
- iounmap(mem->va);
-
- return 0;
-}
-
static int rcar_rproc_prepare(struct rproc *rproc)
{
struct device *dev = rproc->dev.parent;
@@ -73,8 +44,8 @@ static int rcar_rproc_prepare(struct rproc *rproc)
mem = rproc_mem_entry_init(dev, NULL,
res.start,
resource_size(&res), da,
- rcar_rproc_mem_alloc,
- rcar_rproc_mem_release,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
res.name);
if (!mem)
@@ -86,12 +57,8 @@ static int rcar_rproc_prepare(struct rproc *rproc)
static int rcar_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
{
- int ret;
-
- ret = rproc_elf_load_rsc_table(rproc, fw);
- if (ret)
- dev_info(&rproc->dev, "No resource table in elf\n");
-
+ rproc_elf_load_rsc_table_optional(rproc, fw, dev_info,
+ "No resource table in elf\n");
return 0;
}
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index b087ed21858a..1ed406714849 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1011,60 +1011,55 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
[RSC_VDEV] = rproc_handle_vdev,
};
-/* handle firmware resource entries before booting the remote processor */
-static int rproc_handle_resources(struct rproc *rproc,
- rproc_handle_resource_t handlers[RSC_LAST])
+struct rproc_rsc_cb_data {
+ struct rproc *rproc;
+ rproc_handle_resource_t *handlers;
+};
+
+static int rproc_handle_rsc_entry(u32 type, void *rsc, int offset,
+ int avail, void *data)
{
+ struct rproc_rsc_cb_data *d = data;
+ struct rproc *rproc = d->rproc;
struct device *dev = &rproc->dev;
rproc_handle_resource_t handler;
- int ret = 0, i;
-
- if (!rproc->table_ptr)
- return 0;
-
- for (i = 0; i < rproc->table_ptr->num; i++) {
- int offset = rproc->table_ptr->offset[i];
- struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset;
- int avail = rproc->table_sz - offset - sizeof(*hdr);
- void *rsc = (void *)hdr + sizeof(*hdr);
+ int ret;
- /* make sure table isn't truncated */
- if (avail < 0) {
- dev_err(dev, "rsc table is truncated\n");
- return -EINVAL;
- }
+ dev_dbg(dev, "rsc: type %d\n", type);
- dev_dbg(dev, "rsc: type %d\n", hdr->type);
+ if (type >= RSC_VENDOR_START && type <= RSC_VENDOR_END) {
+ ret = rproc_handle_rsc(rproc, type, rsc, offset, avail);
+ if (ret == RSC_HANDLED)
+ return 0;
+ if (ret < 0)
+ return ret;
+ dev_warn(dev, "unsupported vendor resource %d\n", type);
+ return 0;
+ }
- if (hdr->type >= RSC_VENDOR_START &&
- hdr->type <= RSC_VENDOR_END) {
- ret = rproc_handle_rsc(rproc, hdr->type, rsc,
- offset + sizeof(*hdr), avail);
- if (ret == RSC_HANDLED)
- continue;
- else if (ret < 0)
- break;
+ if (type >= RSC_LAST) {
+ dev_warn(dev, "unsupported resource %d\n", type);
+ return 0;
+ }
- dev_warn(dev, "unsupported vendor resource %d\n",
- hdr->type);
- continue;
- }
+ handler = d->handlers[type];
+ if (!handler)
+ return 0;
- if (hdr->type >= RSC_LAST) {
- dev_warn(dev, "unsupported resource %d\n", hdr->type);
- continue;
- }
+ return handler(rproc, rsc, offset, avail);
+}
- handler = handlers[hdr->type];
- if (!handler)
- continue;
+/* handle firmware resource entries before booting the remote processor */
+static int rproc_handle_resources(struct rproc *rproc,
+ rproc_handle_resource_t handlers[RSC_LAST])
+{
+ struct rproc_rsc_cb_data d = { .rproc = rproc, .handlers = handlers };
- ret = handler(rproc, rsc, offset + sizeof(*hdr), avail);
- if (ret)
- break;
- }
+ if (!rproc->table_ptr)
+ return 0;
- return ret;
+ return rsc_table_for_each_entry(rproc->table_ptr, rproc->table_sz,
+ &rproc->dev, rproc_handle_rsc_entry, &d);
}
static int rproc_prepare_subdevices(struct rproc *rproc)
@@ -1104,6 +1099,8 @@ static int rproc_start_subdevices(struct rproc *rproc)
}
}
+ rproc->subdevs_started = true;
+
return 0;
unroll_registration:
@@ -1119,10 +1116,15 @@ static void rproc_stop_subdevices(struct rproc *rproc, bool crashed)
{
struct rproc_subdev *subdev;
+ if (!rproc->subdevs_started)
+ return;
+
list_for_each_entry_reverse(subdev, &rproc->subdevs, node) {
if (subdev->stop)
subdev->stop(subdev, crashed);
}
+
+ rproc->subdevs_started = false;
}
static void rproc_unprepare_subdevices(struct rproc *rproc)
@@ -1673,18 +1675,21 @@ static void rproc_auto_boot_callback(const struct firmware *fw, void *context)
release_firmware(fw);
}
+static void rproc_attach_work(struct work_struct *work)
+{
+ struct rproc *rproc = container_of(work, struct rproc, attach_work);
+
+ rproc_boot(rproc);
+}
+
static int rproc_trigger_auto_boot(struct rproc *rproc)
{
int ret;
- /*
- * Since the remote processor is in a detached state, it has already
- * been booted by another entity. As such there is no point in waiting
- * for a firmware image to be loaded, we can simply initiate the process
- * of attaching to it immediately.
- */
- if (rproc->state == RPROC_DETACHED)
- return rproc_boot(rproc);
+ if (rproc->state == RPROC_DETACHED) {
+ schedule_work(&rproc->attach_work);
+ return 0;
+ }
/*
* We're initiating an asynchronous firmware loading, so we can
@@ -1781,7 +1786,20 @@ static int rproc_attach_recovery(struct rproc *rproc)
if (ret)
return ret;
- return __rproc_attach(rproc);
+ /* clean up all acquired resources */
+ rproc_resource_cleanup(rproc);
+
+ /* release HW resources if needed */
+ rproc_unprepare_device(rproc);
+
+ rproc_disable_iommu(rproc);
+
+ /* Free the copy of the resource table */
+ kfree(rproc->cached_table);
+ rproc->cached_table = NULL;
+ rproc->table_ptr = NULL;
+
+ return rproc_attach(rproc);
}
static int rproc_boot_recovery(struct rproc *rproc)
@@ -1833,6 +1851,11 @@ int rproc_trigger_recovery(struct rproc *rproc)
if (ret)
return ret;
+ if (READ_ONCE(rproc->deleting)) {
+ ret = -ENODEV;
+ goto unlock_mutex;
+ }
+
/* State could have changed before we got the mutex */
if (rproc->state != RPROC_CRASHED)
goto unlock_mutex;
@@ -1865,6 +1888,11 @@ static void rproc_crash_handler_work(struct work_struct *work)
mutex_lock(&rproc->lock);
+ if (READ_ONCE(rproc->deleting)) {
+ mutex_unlock(&rproc->lock);
+ goto out;
+ }
+
if (rproc->state == RPROC_CRASHED) {
/* handle only the first crash detected */
mutex_unlock(&rproc->lock);
@@ -1920,9 +1948,9 @@ int rproc_boot(struct rproc *rproc)
return ret;
}
- if (rproc->state == RPROC_DELETED) {
+ if (READ_ONCE(rproc->deleting)) {
ret = -ENODEV;
- dev_err(dev, "can't boot deleted rproc %s\n", rproc->name);
+ dev_err(dev, "can't boot deleting rproc %s\n", rproc->name);
goto unlock_mutex;
}
@@ -1960,30 +1988,10 @@ unlock_mutex:
}
EXPORT_SYMBOL(rproc_boot);
-/**
- * rproc_shutdown() - power off the remote processor
- * @rproc: the remote processor
- *
- * Power off a remote processor (previously booted with rproc_boot()).
- *
- * In case @rproc is still being used by an additional user(s), then
- * this function will just decrement the power refcount and exit,
- * without really powering off the device.
- *
- * Every call to rproc_boot() must (eventually) be accompanied by a call
- * to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
- *
- * Notes:
- * - we're not decrementing the rproc's refcount, only the power refcount.
- * which means that the @rproc handle stays valid even after rproc_shutdown()
- * returns, and users can still use it with a subsequent rproc_boot(), if
- * needed.
- *
- * Return: 0 on success, and an appropriate error value otherwise
- */
-int rproc_shutdown(struct rproc *rproc)
+static int __rproc_shutdown(struct rproc *rproc, bool force)
{
struct device *dev = &rproc->dev;
+ bool crashed;
int ret;
ret = mutex_lock_interruptible(&rproc->lock);
@@ -1993,16 +2001,19 @@ int rproc_shutdown(struct rproc *rproc)
}
if (rproc->state != RPROC_RUNNING &&
- rproc->state != RPROC_ATTACHED) {
+ rproc->state != RPROC_ATTACHED &&
+ rproc->state != RPROC_CRASHED) {
ret = -EINVAL;
goto out;
}
+ crashed = rproc->state == RPROC_CRASHED;
- /* if the remote proc is still needed, bail out */
- if (!atomic_dec_and_test(&rproc->power))
+ if (!atomic_dec_and_test(&rproc->power) && !force) {
+ /* The remote processor is still needed by another user. */
goto out;
+ }
- ret = rproc_stop(rproc, false);
+ ret = rproc_stop(rproc, crashed);
if (ret) {
atomic_inc(&rproc->power);
goto out;
@@ -2024,6 +2035,32 @@ out:
mutex_unlock(&rproc->lock);
return ret;
}
+
+/**
+ * rproc_shutdown() - power off the remote processor
+ * @rproc: the remote processor
+ *
+ * Power off a remote processor (previously booted with rproc_boot()).
+ *
+ * In case @rproc is still being used by an additional user(s), then
+ * this function will just decrement the power refcount and exit,
+ * without really powering off the device.
+ *
+ * Every call to rproc_boot() must (eventually) be accompanied by a call
+ * to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+ *
+ * Notes:
+ * - we're not decrementing the rproc's refcount, only the power refcount.
+ * which means that the @rproc handle stays valid even after rproc_shutdown()
+ * returns, and users can still use it with a subsequent rproc_boot(), if
+ * needed.
+ *
+ * Return: 0 on success, and an appropriate error value otherwise
+ */
+int rproc_shutdown(struct rproc *rproc)
+{
+ return __rproc_shutdown(rproc, false);
+}
EXPORT_SYMBOL(rproc_shutdown);
/**
@@ -2322,6 +2359,7 @@ int rproc_add(struct rproc *rproc)
return 0;
rproc_remove_dev:
+ cancel_work_sync(&rproc->crash_handler);
rproc_delete_debug_dir(rproc);
device_del(dev);
rproc_remove_cdev:
@@ -2511,7 +2549,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
INIT_LIST_HEAD(&rproc->subdevs);
INIT_LIST_HEAD(&rproc->dump_segments);
+ INIT_WORK(&rproc->attach_work, rproc_attach_work);
INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
+ spin_lock_init(&rproc->crash_handler_lock);
rproc->state = RPROC_OFFLINE;
@@ -2575,15 +2615,19 @@ EXPORT_SYMBOL(rproc_put);
*/
int rproc_del(struct rproc *rproc)
{
+ unsigned long flags;
+
if (!rproc)
return -EINVAL;
- /* TODO: make sure this works with rproc->power > 1 */
- rproc_shutdown(rproc);
+ spin_lock_irqsave(&rproc->crash_handler_lock, flags);
+ WRITE_ONCE(rproc->deleting, true);
+ spin_unlock_irqrestore(&rproc->crash_handler_lock, flags);
- mutex_lock(&rproc->lock);
- rproc->state = RPROC_DELETED;
- mutex_unlock(&rproc->lock);
+ if (cancel_work_sync(&rproc->crash_handler))
+ pm_relax(rproc->dev.parent);
+
+ __rproc_shutdown(rproc, true);
rproc_delete_debug_dir(rproc);
@@ -2696,18 +2740,26 @@ EXPORT_SYMBOL(rproc_get_by_child);
*/
void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
{
+ unsigned long flags;
+
if (!rproc) {
pr_err("NULL rproc pointer\n");
return;
}
+ spin_lock_irqsave(&rproc->crash_handler_lock, flags);
+ if (READ_ONCE(rproc->deleting)) {
+ spin_unlock_irqrestore(&rproc->crash_handler_lock, flags);
+ return;
+ }
+
/* Prevent suspend while the remoteproc is being recovered */
pm_stay_awake(rproc->dev.parent);
+ queue_work(rproc_recovery_wq, &rproc->crash_handler);
+ spin_unlock_irqrestore(&rproc->crash_handler_lock, flags);
dev_err(&rproc->dev, "crash detected in %s: type %s\n",
rproc->name, rproc_crash_to_string(type));
-
- queue_work(rproc_recovery_wq, &rproc->crash_handler);
}
EXPORT_SYMBOL(rproc_report_crash);
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 0cd09e67ac14..3a742ef6ef60 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -14,6 +14,9 @@
#include <linux/irqreturn.h>
#include <linux/firmware.h>
+#ifdef CONFIG_HAS_IOMEM
+#include <linux/io.h>
+#endif
struct rproc;
@@ -122,6 +125,57 @@ rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...);
void rproc_add_rvdev(struct rproc *rproc, struct rproc_vdev *rvdev);
void rproc_remove_rvdev(struct rproc_vdev *rvdev);
+#ifdef CONFIG_HAS_IOMEM
+static inline int rproc_mem_entry_ioremap_wc(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ void __iomem *va;
+
+ va = ioremap_wc(mem->dma, mem->len);
+ if (!va) {
+ dev_err(&rproc->dev, "Unable to map memory region: %pa+%zx\n",
+ &mem->dma, mem->len);
+ return -ENOMEM;
+ }
+
+ mem->va = (__force void *)va;
+ mem->is_iomem = true;
+
+ return 0;
+}
+
+static inline int rproc_mem_entry_iounmap(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ iounmap((__force __iomem void *)mem->va);
+
+ return 0;
+}
+#else
+static inline int rproc_mem_entry_ioremap_wc(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int rproc_mem_entry_iounmap(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ return 0;
+}
+#endif
+
+#define rproc_elf_load_rsc_table_optional(rproc, fw, dev_func, fmt, ...) \
+ ({ \
+ int ret = rproc_elf_load_rsc_table(rproc, fw); \
+ if (ret == -EINVAL) { \
+ dev_func(&rproc->dev, fmt, ##__VA_ARGS__); \
+ return 0; \
+ } else { \
+ return ret; \
+ } \
+ })
+
static inline int rproc_prepare_device(struct rproc *rproc)
{
if (rproc->ops->prepare)
@@ -218,7 +272,7 @@ bool rproc_u64_fit_in_size_t(u64 val)
if (sizeof(size_t) == sizeof(u64))
return true;
- return (val <= (size_t) -1);
+ return val <= SIZE_MAX;
}
#endif /* REMOTEPROC_INTERNAL_H */
diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c
index 138e752c5e4e..925b0cdbe577 100644
--- a/drivers/remoteproc/remoteproc_sysfs.c
+++ b/drivers/remoteproc/remoteproc_sysfs.c
@@ -168,7 +168,6 @@ static const char * const rproc_state_string[] = {
[RPROC_SUSPENDED] = "suspended",
[RPROC_RUNNING] = "running",
[RPROC_CRASHED] = "crashed",
- [RPROC_DELETED] = "deleted",
[RPROC_ATTACHED] = "attached",
[RPROC_DETACHED] = "detached",
[RPROC_LAST] = "invalid",
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index a07edf7217d2..486180cdccb4 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -88,33 +88,6 @@ 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;
@@ -138,8 +111,8 @@ static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
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,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
"%.*s",
strchrnul(res.name, '@') - res.name,
res.name);
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 632614013dc6..1fe4cdc0a13a 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -113,35 +113,6 @@ static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da)
return -EINVAL;
}
-static int stm32_rproc_mem_alloc(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- struct device *dev = rproc->dev.parent;
- void *va;
-
- dev_dbg(dev, "map memory: %pad+%zx\n", &mem->dma, mem->len);
- va = (__force void *)ioremap_wc(mem->dma, mem->len);
- if (IS_ERR_OR_NULL(va)) {
- dev_err(dev, "Unable to map memory region: %pad+0x%zx\n",
- &mem->dma, mem->len);
- return -ENOMEM;
- }
-
- /* Update memory entry va */
- mem->va = va;
-
- return 0;
-}
-
-static int stm32_rproc_mem_release(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
- iounmap((__force __iomem void *)mem->va);
-
- return 0;
-}
-
static int stm32_rproc_of_memory_translations(struct platform_device *pdev,
struct stm32_rproc *ddata)
{
@@ -237,8 +208,8 @@ static int stm32_rproc_prepare(struct rproc *rproc)
mem = rproc_mem_entry_init(dev, NULL,
(dma_addr_t)res.start,
resource_size(&res), da,
- stm32_rproc_mem_alloc,
- stm32_rproc_mem_release,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
"%.*s", strchrnul(res.name, '@') - res.name,
res.name);
if (mem)
@@ -263,9 +234,8 @@ static int stm32_rproc_prepare(struct rproc *rproc)
static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
{
- if (rproc_elf_load_rsc_table(rproc, fw))
- dev_warn(&rproc->dev, "no resource table found for this firmware\n");
-
+ rproc_elf_load_rsc_table_optional(rproc, fw, dev_warn,
+ "no resource table found for this firmware\n");
return 0;
}
@@ -712,8 +682,7 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
dev_name(dev), pdev);
if (err)
- return dev_err_probe(dev, err,
- "failed to request wdg irq\n");
+ return err;
ddata->wdg_irq = irq;
@@ -957,4 +926,3 @@ MODULE_DESCRIPTION("STM32 Remote Processor Control Driver");
MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/remoteproc/ti_k3_common.c b/drivers/remoteproc/ti_k3_common.c
index 32aa954dc5be..3cb8ae5d72f6 100644
--- a/drivers/remoteproc/ti_k3_common.c
+++ b/drivers/remoteproc/ti_k3_common.c
@@ -513,7 +513,7 @@ int k3_reserved_mem_init(struct k3_rproc *kproc)
kproc->rmem[i].dev_addr = (u32)res.start;
kproc->rmem[i].size = resource_size(&res);
kproc->rmem[i].cpu_addr = devm_ioremap_resource_wc(dev, &res);
- if (!kproc->rmem[i].cpu_addr) {
+ if (IS_ERR(kproc->rmem[i].cpu_addr)) {
dev_err(dev, "failed to map reserved memory#%d at %pR\n",
i + 1, &res);
return -ENOMEM;
diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c
index 04f23295ffc1..b1d04d082e44 100644
--- a/drivers/remoteproc/ti_k3_r5_remoteproc.c
+++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c
@@ -1074,11 +1074,9 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
}
kproc->reset = devm_reset_control_get_exclusive(cdev, NULL);
- if (IS_ERR_OR_NULL(kproc->reset)) {
- ret = PTR_ERR_OR_ZERO(kproc->reset);
- if (!ret)
- ret = -ENODEV;
- dev_err_probe(cdev, ret, "failed to get reset handle\n");
+ if (IS_ERR(kproc->reset)) {
+ ret = dev_err_probe(cdev, PTR_ERR(kproc->reset),
+ "failed to get reset handle\n");
goto out;
}
diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c
index b71ce69afe9f..c685bb5fa62c 100644
--- a/drivers/remoteproc/xlnx_r5_remoteproc.c
+++ b/drivers/remoteproc/xlnx_r5_remoteproc.c
@@ -4,7 +4,6 @@
*
*/
-#include <dt-bindings/power/xlnx-zynqmp-power.h>
#include <linux/dma-mapping.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/kernel.h>
@@ -19,6 +18,11 @@
#include "remoteproc_internal.h"
+#define PD_R5_0_ATCM 15
+#define PD_R5_0_BTCM 16
+#define PD_R5_1_ATCM 17
+#define PD_R5_1_BTCM 18
+
/* IPI buffer MAX length */
#define IPI_BUF_LEN_MAX 32U
@@ -108,6 +112,10 @@ struct rsc_tbl_data {
const uintptr_t rsc_tbl;
} __packed;
+enum xlnx_rproc_fw_rsc {
+ XLNX_RPROC_FW_CRASH_REPORT = RSC_VENDOR_START,
+};
+
/*
* Hardcoded TCM bank values. This will stay in driver to maintain backward
* compatibility with device-tree that does not have TCM information.
@@ -127,9 +135,27 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = {
{0xffe30000UL, 0x30000, 0x10000UL, PD_R5_1_BTCM, "btcm1"},
};
+#define CRASH_REASON_STR_LEN 16
+
+/**
+ * struct xlnx_rproc_crash_report - resource to know crash status and reason
+ *
+ * @version: version of this resource
+ * @crashed: if true, the rproc is notifying crash, time to recover
+ * @crash_reason: number to describe reason of crash
+ * @crash_reason_str: short string description of crash reason
+ */
+struct xlnx_rproc_crash_report {
+ u8 version;
+ u8 crashed;
+ u8 crash_reason;
+ char crash_reason_str[CRASH_REASON_STR_LEN];
+} __packed;
+
/**
* struct zynqmp_r5_core - remoteproc core's internal data
*
+ * @crash_report: rproc crash state and reason
* @rsc_tbl_va: resource table virtual address
* @sram: Array of sram memories assigned to this core
* @num_sram: number of sram for this core
@@ -143,6 +169,7 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = {
* @ipi: pointer to mailbox information
*/
struct zynqmp_r5_core {
+ struct xlnx_rproc_crash_report *crash_report;
void __iomem *rsc_tbl_va;
struct zynqmp_sram_bank *sram;
int num_sram;
@@ -200,11 +227,27 @@ static int event_notified_idr_cb(int id, void *ptr, void *data)
*/
static void handle_event_notified(struct work_struct *work)
{
+ struct xlnx_rproc_crash_report *report;
+ struct zynqmp_r5_core *r5_core;
struct mbox_info *ipi;
struct rproc *rproc;
ipi = container_of(work, struct mbox_info, mbox_work);
rproc = ipi->r5_core->rproc;
+ r5_core = ipi->r5_core;
+ report = r5_core->crash_report;
+
+ /* report crash only if expected */
+ if (report && report->crashed) {
+ if (rproc->state == RPROC_ATTACHED || rproc->state == RPROC_RUNNING) {
+ report->crash_reason_str[CRASH_REASON_STR_LEN - 1] = '\0';
+ dev_warn(&rproc->dev, "crash reason id: %d %s\n",
+ report->crash_reason, report->crash_reason_str);
+ rproc_report_crash(rproc, RPROC_FATAL_ERROR);
+ report->crashed = false;
+ return;
+ }
+ }
/*
* We only use IPI for interrupt. The RPU firmware side may or may
@@ -232,17 +275,19 @@ static void zynqmp_r5_mb_rx_cb(struct mbox_client *cl, void *msg)
ipi = container_of(cl, struct mbox_info, mbox_cl);
- /* copy data from ipi buffer to r5_core */
+ /* copy data from ipi buffer to r5_core if IPI is buffered. */
ipi_msg = (struct zynqmp_ipi_message *)msg;
- buf_msg = (struct zynqmp_ipi_message *)ipi->rx_mc_buf;
- len = ipi_msg->len;
- if (len > IPI_BUF_LEN_MAX) {
- dev_warn(cl->dev, "msg size exceeded than %d\n",
- IPI_BUF_LEN_MAX);
- len = IPI_BUF_LEN_MAX;
+ if (ipi_msg) {
+ buf_msg = (struct zynqmp_ipi_message *)ipi->rx_mc_buf;
+ len = ipi_msg->len;
+ if (len > IPI_BUF_LEN_MAX) {
+ dev_warn(cl->dev, "msg size exceeded than %d\n",
+ IPI_BUF_LEN_MAX);
+ len = IPI_BUF_LEN_MAX;
+ }
+ buf_msg->len = len;
+ memcpy(buf_msg->data, ipi_msg->data, len);
}
- buf_msg->len = len;
- memcpy(buf_msg->data, ipi_msg->data, len);
/* received and processed interrupt ack */
if (mbox_send_message(ipi->rx_chan, NULL) < 0)
@@ -265,6 +310,10 @@ static struct mbox_info *zynqmp_r5_setup_mbox(struct device *cdev)
struct mbox_client *mbox_cl;
struct mbox_info *ipi;
+ if (!of_property_present(dev_of_node(cdev), "mboxes") ||
+ !of_property_present(dev_of_node(cdev), "mbox-names"))
+ return NULL;
+
ipi = kzalloc_obj(*ipi);
if (!ipi)
return NULL;
@@ -354,49 +403,12 @@ static void zynqmp_r5_rproc_kick(struct rproc *rproc, int vqid)
static int zynqmp_r5_rproc_start(struct rproc *rproc)
{
struct zynqmp_r5_core *r5_core = rproc->priv;
- enum rpu_boot_mem bootmem;
int ret;
- /*
- * The exception vector pointers (EVP) refer to the base-address of
- * exception vectors (for reset, IRQ, FIQ, etc). The reset-vector
- * starts at the base-address and subsequent vectors are on 4-byte
- * boundaries.
- *
- * Exception vectors can start either from 0x0000_0000 (LOVEC) or
- * from 0xFFFF_0000 (HIVEC) which is mapped in the OCM (On-Chip Memory)
- *
- * Usually firmware will put Exception vectors at LOVEC.
- *
- * It is not recommend that you change the exception vector.
- * Changing the EVP to HIVEC will result in increased interrupt latency
- * and jitter. Also, if the OCM is secured and the Cortex-R5F processor
- * is non-secured, then the Cortex-R5F processor cannot access the
- * HIVEC exception vectors in the OCM.
- */
- bootmem = (rproc->bootaddr >= 0xFFFC0000) ?
- PM_RPU_BOOTMEM_HIVEC : PM_RPU_BOOTMEM_LOVEC;
-
- dev_dbg(r5_core->dev, "RPU boot addr 0x%llx from %s.", rproc->bootaddr,
- bootmem == PM_RPU_BOOTMEM_HIVEC ? "OCM" : "TCM");
-
- /* Request node before starting RPU core if new version of API is supported */
- if (zynqmp_pm_feature(PM_REQUEST_NODE) > 1) {
- ret = zynqmp_pm_request_node(r5_core->pm_domain_id,
- ZYNQMP_PM_CAPABILITY_ACCESS, 0,
- ZYNQMP_PM_REQUEST_ACK_BLOCKING);
- if (ret < 0) {
- dev_err(r5_core->dev, "failed to request 0x%x",
- r5_core->pm_domain_id);
- return ret;
- }
- }
-
- ret = zynqmp_pm_request_wake(r5_core->pm_domain_id, 1,
- bootmem, ZYNQMP_PM_REQUEST_ACK_NO);
+ ret = zynqmp_pm_start_rpu(r5_core->pm_domain_id, rproc->bootaddr);
if (ret)
- dev_err(r5_core->dev,
- "failed to start RPU = 0x%x\n", r5_core->pm_domain_id);
+ dev_err(&rproc->dev, "failed to start RPU\n");
+
return ret;
}
@@ -413,74 +425,21 @@ static int zynqmp_r5_rproc_stop(struct rproc *rproc)
struct zynqmp_r5_core *r5_core = rproc->priv;
int ret;
- /* Use release node API to stop core if new version of API is supported */
- if (zynqmp_pm_feature(PM_RELEASE_NODE) > 1) {
- ret = zynqmp_pm_release_node(r5_core->pm_domain_id);
- if (ret)
- dev_err(r5_core->dev, "failed to stop remoteproc RPU %d\n", ret);
- return ret;
- }
+ ret = zynqmp_pm_stop_rpu(r5_core->pm_domain_id);
+ if (ret)
+ dev_err(&rproc->dev, "failed to stop RPU\n");
/*
- * Check expected version of EEMI call before calling it. This avoids
- * any error or warning prints from firmware as it is expected that fw
- * doesn't support it.
+ * Clear attach on recovery flag during stop operation. The next state
+ * of the remote processor is expected to be in "Running" state. In this
+ * state, boot recovery method must take place over attach on recovery.
*/
- if (zynqmp_pm_feature(PM_FORCE_POWERDOWN) != 1) {
- dev_dbg(r5_core->dev, "EEMI interface %d ver 1 not supported\n",
- PM_FORCE_POWERDOWN);
- return -EOPNOTSUPP;
- }
-
- /* maintain force pwr down for backward compatibility */
- ret = zynqmp_pm_force_pwrdwn(r5_core->pm_domain_id,
- ZYNQMP_PM_REQUEST_ACK_BLOCKING);
- if (ret)
- dev_err(r5_core->dev, "core force power down failed\n");
+ test_and_clear_bit(RPROC_FEAT_ATTACH_ON_RECOVERY, rproc->features);
return ret;
}
/*
- * zynqmp_r5_mem_region_map()
- * @rproc: single R5 core's corresponding rproc instance
- * @mem: mem descriptor to map reserved memory-regions
- *
- * Callback to map va for memory-region's carveout.
- *
- * return 0 on success, otherwise non-zero value on failure
- */
-static int zynqmp_r5_mem_region_map(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- void __iomem *va;
-
- va = ioremap_wc(mem->dma, mem->len);
- if (IS_ERR_OR_NULL(va))
- return -ENOMEM;
-
- mem->va = (void *)va;
-
- return 0;
-}
-
-/*
- * zynqmp_r5_rproc_mem_unmap
- * @rproc: single R5 core's corresponding rproc instance
- * @mem: mem entry to unmap
- *
- * Unmap memory-region carveout
- *
- * return: always returns 0
- */
-static int zynqmp_r5_mem_region_unmap(struct rproc *rproc,
- struct rproc_mem_entry *mem)
-{
- iounmap((void __iomem *)mem->va);
- return 0;
-}
-
-/*
* add_mem_regions_carveout()
* @rproc: single R5 core's corresponding rproc instance
*
@@ -516,8 +475,8 @@ static int add_mem_regions_carveout(struct rproc *rproc)
rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL,
(dma_addr_t)res.start,
resource_size(&res), res.start,
- zynqmp_r5_mem_region_map,
- zynqmp_r5_mem_region_unmap,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
"%.*s",
strchrnul(res.name, '@') - res.name,
res.name);
@@ -554,8 +513,8 @@ static int add_sram_carveouts(struct rproc *rproc)
rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL,
dma_addr,
len, da,
- zynqmp_r5_mem_region_map,
- zynqmp_r5_mem_region_unmap,
+ rproc_mem_entry_ioremap_wc,
+ rproc_mem_entry_iounmap,
sram->sram_res.name);
if (!rproc_mem) {
dev_err(&rproc->dev, "failed to add sram %s da=0x%x, size=0x%lx",
@@ -708,20 +667,15 @@ release_tcm:
*/
static int zynqmp_r5_parse_fw(struct rproc *rproc, const struct firmware *fw)
{
- int ret;
-
- ret = rproc_elf_load_rsc_table(rproc, fw);
- if (ret == -EINVAL) {
- /*
- * resource table only required for IPC.
- * if not present, this is not necessarily an error;
- * for example, loading r5 hello world application
- * so simply inform user and keep going.
- */
- dev_info(&rproc->dev, "no resource table found.\n");
- ret = 0;
- }
- return ret;
+ /*
+ * resource table only required for IPC.
+ * if not present, this is not necessarily an error;
+ * for example, loading r5 hello world application
+ * so simply inform user and keep going.
+ */
+ rproc_elf_load_rsc_table_optional(rproc, fw, dev_info,
+ "no resource table found.\n");
+ return 0;
}
/**
@@ -876,6 +830,24 @@ static int zynqmp_r5_detach(struct rproc *rproc)
return 0;
}
+static int zynqmp_r5_handle_rsc(struct rproc *rproc, u32 rsc_type, void *rsc,
+ int offset, int avail)
+{
+ struct zynqmp_r5_core *r5_core = rproc->priv;
+ void *rsc_offset = (r5_core->rsc_tbl_va + offset);
+
+ if (rsc_type != XLNX_RPROC_FW_CRASH_REPORT)
+ return RSC_IGNORED;
+
+ r5_core->crash_report = rsc_offset;
+ /* reset all values */
+ r5_core->crash_report->crashed = false;
+ r5_core->crash_report->crash_reason = 0;
+ r5_core->crash_report->crash_reason_str[0] = '\0';
+
+ return RSC_HANDLED;
+}
+
static const struct rproc_ops zynqmp_r5_rproc_ops = {
.prepare = zynqmp_r5_rproc_prepare,
.unprepare = zynqmp_r5_rproc_unprepare,
@@ -890,20 +862,22 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = {
.get_loaded_rsc_table = zynqmp_r5_get_loaded_rsc_table,
.attach = zynqmp_r5_attach,
.detach = zynqmp_r5_detach,
+ .handle_rsc = zynqmp_r5_handle_rsc,
};
/**
- * zynqmp_r5_add_rproc_core() - Add core data to framework.
- * Allocate and add struct rproc object for each r5f core
+ * zynqmp_r5_alloc_rproc_core() - alloc rproc core data structure
+ * Allocate struct rproc object for each r5f core
* This is called for each individual r5f core
*
* @cdev: Device node of each r5 core
*
* Return: zynqmp_r5_core object for success else error code pointer
*/
-static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
+static struct zynqmp_r5_core *zynqmp_r5_alloc_rproc_core(struct device *cdev)
{
struct zynqmp_r5_core *r5_core;
+ const char *fw_name = NULL;
struct rproc *r5_rproc;
int ret;
@@ -912,10 +886,15 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
if (ret)
return ERR_PTR(ret);
+ ret = rproc_of_parse_firmware(cdev, 0, &fw_name);
+ if (ret < 0 && ret != -EINVAL)
+ return ERR_PTR(dev_err_probe(cdev, ret,
+ "failed to parse firmware-name\n"));
+
/* Allocate remoteproc instance */
r5_rproc = rproc_alloc(cdev, dev_name(cdev),
&zynqmp_r5_rproc_ops,
- NULL, sizeof(struct zynqmp_r5_core));
+ fw_name, sizeof(struct zynqmp_r5_core));
if (!r5_rproc) {
dev_err(cdev, "failed to allocate memory for rproc instance\n");
return ERR_PTR(-ENOMEM);
@@ -923,9 +902,14 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
rproc_coredump_set_elf_info(r5_rproc, ELFCLASS32, EM_ARM);
- r5_rproc->recovery_disabled = true;
+ r5_rproc->recovery_disabled = false;
r5_rproc->has_iommu = false;
r5_rproc->auto_boot = false;
+
+ /* attempt to boot automatically if the firmware-name is provided */
+ if (fw_name)
+ r5_rproc->auto_boot = true;
+
r5_core = r5_rproc->priv;
r5_core->dev = cdev;
r5_core->np = dev_of_node(cdev);
@@ -935,23 +919,6 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
goto free_rproc;
}
- /* Add R5 remoteproc core */
- ret = rproc_add(r5_rproc);
- if (ret) {
- dev_err(cdev, "failed to add r5 remoteproc\n");
- goto free_rproc;
- }
-
- /*
- * If firmware is already available in the memory then move rproc state
- * to DETACHED. Firmware can be preloaded via debugger or by any other
- * agent (processors) in the system.
- * If firmware isn't available in the memory and resource table isn't
- * found, then rproc state remains OFFLINE.
- */
- if (!zynqmp_r5_get_rsc_table_va(r5_core))
- r5_rproc->state = RPROC_DETACHED;
-
r5_core->rproc = r5_rproc;
return r5_core;
@@ -1005,7 +972,7 @@ static int zynqmp_r5_get_sram_banks(struct zynqmp_r5_core *r5_core)
}
/* Get SRAM device address */
- ret = of_property_read_reg(sram_np, i, &abs_addr, &size);
+ ret = of_property_read_reg(sram_np, 0, &abs_addr, &size);
if (ret) {
dev_err(dev, "failed to get reg property\n");
goto fail_sram_get;
@@ -1204,6 +1171,7 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster,
{
struct device *dev = cluster->dev;
struct zynqmp_r5_core *r5_core;
+ u32 req, usage, status;
int ret = -EINVAL, i;
r5_core = cluster->r5_cores[0];
@@ -1249,6 +1217,45 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster,
ret = zynqmp_r5_get_sram_banks(r5_core);
if (ret)
return ret;
+
+ /*
+ * It is possible that firmware is loaded into the memory, but
+ * RPU (remote) is not running. In such case, RPU state will be
+ * moved to RPROC_DETACHED wrongfully. To avoid it first make
+ * sure RPU is power-on and out of reset before parsing for the
+ * resource table.
+ */
+ ret = zynqmp_pm_get_rpu_node_status(r5_core->pm_domain_id,
+ &status, &req, &usage);
+ if (ret) {
+ dev_warn(r5_core->dev,
+ "failed to get rpu node status, err %d\n", ret);
+ continue;
+ }
+
+ /*
+ * If RPU state is power on and out of reset i.e. running, then
+ * assign RPROC_DETACHED state. If the RPU is not out of reset
+ * then do not attempt to attach to the remote processor.
+ */
+ if (status == PM_NODE_RUNNING) {
+ /*
+ * Not all the firmware that is running on the remote
+ * core is expected to have the resource table. The
+ * firmware might not use RPMsg at all, and in that case
+ * resource table becomes irrelevant. However, we still
+ * need to make sure that running core is not reported
+ * as offline. so do not decide remote core state based
+ * on the resource table availability
+ */
+ if (zynqmp_r5_get_rsc_table_va(r5_core))
+ dev_dbg(r5_core->dev, "rsc tbl not found\n");
+ r5_core->rproc->state = RPROC_DETACHED;
+ /* Enable attach on recovery method. Clear it during rproc stop. */
+ rproc_set_feature(r5_core->rproc,
+ RPROC_FEAT_ATTACH_ON_RECOVERY);
+ r5_core->rproc->auto_boot = true;
+ }
}
return 0;
@@ -1272,7 +1279,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
enum rpu_oper_mode fw_reg_val;
struct device **child_devs;
enum rpu_tcm_comb tcm_mode;
- int core_count, ret, i;
+ int core_count, ret, i, j;
struct mbox_info *ipi;
ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode);
@@ -1358,7 +1365,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
child_devs[i] = &child_pdev->dev;
/* create and add remoteproc instance of type struct rproc */
- r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev);
+ r5_cores[i] = zynqmp_r5_alloc_rproc_core(&child_pdev->dev);
if (IS_ERR(r5_cores[i])) {
ret = PTR_ERR(r5_cores[i]);
r5_cores[i] = NULL;
@@ -1403,16 +1410,31 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
goto release_r5_cores;
}
+ for (j = 0; j < cluster->core_count; j++) {
+ /* Add R5 remoteproc core */
+ ret = rproc_add(r5_cores[j]->rproc);
+ if (ret) {
+ dev_err_probe(r5_cores[j]->dev, ret,
+ "failed to add remoteproc\n");
+ goto delete_r5_cores;
+ }
+ }
+
kfree(child_devs);
return 0;
+delete_r5_cores:
+ i = core_count - 1;
+ /* delete previous added rproc */
+ while (--j >= 0)
+ rproc_del(r5_cores[j]->rproc);
+
release_r5_cores:
while (i >= 0) {
put_device(child_devs[i]);
if (r5_cores[i]) {
zynqmp_r5_free_mbox(r5_cores[i]->ipi);
of_reserved_mem_device_release(r5_cores[i]->dev);
- rproc_del(r5_cores[i]->rproc);
rproc_free(r5_cores[i]->rproc);
}
i--;
@@ -1484,6 +1506,8 @@ static void zynqmp_r5_remoteproc_shutdown(struct platform_device *pdev)
dev_err(cluster->dev, "failed to %s rproc %d\n",
rproc_state_str, rproc->index);
}
+
+ zynqmp_r5_free_mbox(r5_core->ipi);
}
}