Commit 3361e9a4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rproc-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux

Pull remoteproc updates from Bjorn Andersson:

 - Unnecessary type casts from the 'void *' rproc->priv pointer are
   dropped throughout the subsystem.

 - A kernel-doc error is corrected in the Mediatek SCPI IPI
   implementation

 - The firmware loading onto the IMX DSP remote processors is reworked
   to avoid non-32bit memory operations. A module parameter is
   introduced to assist development of firmware without communication
   abilities in place. Error paths in imx_dsp_rproc_mbox_alloc() is
   cleaned up

 - The cluster configuration handling in the TI K3 R5 driver is
   corrected and support for the single-R5 core found in the TI AM62x
   SoC family is introduced

 - The TI PRU driver device- to virtual-address translation is updated
   to avoid compiler warning about the unsigned device-address always
   being larger than 0

 - The ST remoteproc driver is transitioned to use of_property_present()

 - Issues with kicks arriving after the STM32 remote processor has been
   shut down are mitigated by checking the processor's state before
   handling them.

 - Support for mailbox channels for communication with the remote
   processors are added to the Xilinx R5 remoteproc driver. The naming
   of carveouts are corrected and their parsing is reworked. For this a
   couple of fixes targeting the mailbox subsystem are picked up here as
   well.

 - Reference counting of of_nodes are corrected in the ST, STM32, RCAR
   and IMX remoteproc drivers

* tag 'rproc-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: (24 commits)
  remoteproc: st: Use of_property_present() for testing DT property presence
  dt-bindings: remoteproc: Drop unneeded quotes
  remoteproc: imx_dsp_rproc: Fix kernel test robot sparse warning
  remoteproc: imx_dsp_rproc: Improve exception handling in imx_dsp_rproc_mbox_alloc()
  remoteproc: pru: Remove always true check positive unsigned value
  dt-bindings: remoteproc: stm32-rproc: Typo fix
  remoteproc: stm32_rproc: Add mutex protection for workqueue
  remoteproc: Remove unnecessary (void*) conversions
  remoteproc: imx_dsp_rproc: Call of_node_put() on iteration error
  remoteproc: imx_rproc: Call of_node_put() on iteration error
  remoteproc: rcar_rproc: Call of_node_put() on iteration error
  remoteproc: st: Call of_node_put() on iteration error
  remoteproc: stm32: Call of_node_put() on iteration error
  remoteproc: k3-r5: Use separate compatible string for TI AM62x SoC family
  dt-bindings: remoteproc: ti: Add new compatible for AM62 SoC family
  remoteproc: k3-r5: Simplify cluster mode setting usage
  remoteproc/mtk_scpi_ipi: Fix one kernel-doc comment
  remoteproc: xilinx: Add mailbox channels for rpmsg
  drivers: remoteproc: xilinx: Fix carveout names
  mailbox: zynqmp: Fix typo in IPI documentation
  ...
parents fe89e9b1 1f6fa392
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/remoteproc/amlogic,meson-mx-ao-arc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/remoteproc/amlogic,meson-mx-ao-arc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson AO ARC Remote Processor
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/remoteproc/fsl,imx-rproc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/remoteproc/fsl,imx-rproc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX Co-Processor
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/remoteproc/ingenic,vpu.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/remoteproc/ingenic,vpu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ingenic Video Processing Unit
......
......@@ -15,7 +15,7 @@ description:
properties:
$nodename:
const: "glink-edge"
const: glink-edge
apr:
$ref: /schemas/soc/qcom/qcom,apr.yaml#
......
......@@ -21,7 +21,7 @@ description:
properties:
$nodename:
const: "smd-edge"
const: smd-edge
apr:
$ref: /schemas/soc/qcom/qcom,apr.yaml#
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/remoteproc/renesas,rcar-rproc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/remoteproc/renesas,rcar-rproc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car remote processor controller
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/remoteproc/st,stm32-rproc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/remoteproc/st,stm32-rproc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STM32 remote processor controller
......@@ -29,7 +29,7 @@ properties:
st,syscfg-holdboot:
description: remote processor reset hold boot
$ref: "/schemas/types.yaml#/definitions/phandle-array"
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: Phandle of syscon block
......@@ -39,7 +39,7 @@ properties:
st,syscfg-tz:
description:
Reference to the system configuration which holds the RCC trust zone mode
$ref: "/schemas/types.yaml#/definitions/phandle-array"
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: Phandle of syscon block
......@@ -72,9 +72,9 @@ properties:
ready for shutdown
- description: |
A channel (d) used by the local proc to notify the remote proc that it
has to stop interprocessor communnication.
has to stop interprocessor communication.
Unidirectional channel:
- from local to remote, where ACK from the remote means that communnication
- from local to remote, where ACK from the remote means that communication
as been stopped on the remote side.
minItems: 1
......@@ -95,7 +95,7 @@ properties:
(see ../reserved-memory/reserved-memory.txt)
st,syscfg-pdds:
$ref: "/schemas/types.yaml#/definitions/phandle-array"
$ref: /schemas/types.yaml#/definitions/phandle-array
description: |
Reference to the system configuration which holds the remote
items:
......@@ -105,7 +105,7 @@ properties:
- description: The field mask of the PDDS selection
st,syscfg-m4-state:
$ref: "/schemas/types.yaml#/definitions/phandle-array"
$ref: /schemas/types.yaml#/definitions/phandle-array
description: |
Reference to the tamp register which exposes the Cortex-M4 state.
items:
......@@ -115,7 +115,7 @@ properties:
- description: The field mask of the Cortex-M4 state
st,syscfg-rsc-tbl:
$ref: "/schemas/types.yaml#/definitions/phandle-array"
$ref: /schemas/types.yaml#/definitions/phandle-array
description: |
Reference to the tamp register which references the Cortex-M4
resource table address.
......
......@@ -21,6 +21,9 @@ description: |
called "Single-CPU" mode, where only Core0 is used, but with ability to use
Core1's TCMs as well.
AM62 SoC family support a single R5F core only which runs Device Manager
firmware and can also be used as a remote processor with IPC communication.
Each Dual-Core R5F sub-system is represented as a single DTS node
representing the cluster, with a pair of child DT nodes representing
the individual R5F cores. Each node has a number of required or optional
......@@ -34,10 +37,11 @@ properties:
compatible:
enum:
- ti,am62-r5fss
- ti,am64-r5fss
- ti,am654-r5fss
- ti,j721e-r5fss
- ti,j7200-r5fss
- ti,am64-r5fss
- ti,j721e-r5fss
- ti,j721s2-r5fss
power-domains:
......@@ -64,10 +68,17 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Configuration Mode for the Dual R5F cores within the R5F cluster.
Should be either a value of 1 (LockStep mode) or 0 (Split mode) on
For most SoCs (AM65x, J721E, J7200, J721s2),
It should be either a value of 1 (LockStep mode) or 0 (Split mode) on
most SoCs (AM65x, J721E, J7200, J721s2), default is LockStep mode if
omitted; and should be either a value of 0 (Split mode) or 2
(Single-CPU mode) on AM64x SoCs, default is Split mode if omitted.
omitted.
For AM64x SoCs,
It should be either a value of 0 (Split mode) or 2 (Single-CPU mode) and
default is Split mode if omitted.
For AM62x SoCs,
It should be set as 3 (Single-Core mode) which is also the default if
omitted.
# R5F Processor Child Nodes:
# ==========================
......@@ -80,7 +91,9 @@ patternProperties:
node representing a TI instantiation of the Arm Cortex R5F core. There
are some specific integration differences for the IP like the usage of
a Region Address Translator (RAT) for translating the larger SoC bus
addresses into a 32-bit address space for the processor.
addresses into a 32-bit address space for the processor. For AM62x,
the R5F Sub-System device node should only define one R5F child node
as it has only one core available.
Each R5F core has an associated 64 KB of Tightly-Coupled Memory (TCM)
internal memories split between two banks - TCMA and TCMB (further
......@@ -100,10 +113,11 @@ patternProperties:
properties:
compatible:
enum:
- ti,am62-r5f
- ti,am64-r5f
- ti,am654-r5f
- ti,j721e-r5f
- ti,j7200-r5f
- ti,am64-r5f
- ti,j721e-r5f
- ti,j721s2-r5f
reg:
......@@ -208,19 +222,39 @@ patternProperties:
unevaluatedProperties: false
if:
properties:
compatible:
enum:
- ti,am64-r5fss
then:
properties:
ti,cluster-mode:
enum: [0, 2]
else:
properties:
ti,cluster-mode:
enum: [0, 1]
allOf:
- if:
properties:
compatible:
enum:
- ti,am64-r5fss
then:
properties:
ti,cluster-mode:
enum: [0, 2]
- if:
properties:
compatible:
enum:
- ti,am654-r5fss
- ti,j7200-r5fss
- ti,j721e-r5fss
- ti,j721s2-r5fss
then:
properties:
ti,cluster-mode:
enum: [0, 1]
- if:
properties:
compatible:
enum:
- ti,am62-r5fss
then:
properties:
ti,cluster-mode:
enum: [3]
required:
- compatible
......
......@@ -152,7 +152,7 @@ static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data)
struct zynqmp_ipi_message *msg;
u64 arg0, arg3;
struct arm_smccc_res res;
int ret, i;
int ret, i, status = IRQ_NONE;
(void)irq;
arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY;
......@@ -170,11 +170,11 @@ static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data)
memcpy_fromio(msg->data, mchan->req_buf,
msg->len);
mbox_chan_received_data(chan, (void *)msg);
return IRQ_HANDLED;
status = IRQ_HANDLED;
}
}
}
return IRQ_NONE;
return status;
}
/**
......@@ -634,7 +634,12 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
struct zynqmp_ipi_mbox *mbox;
int num_mboxes, ret = -EINVAL;
num_mboxes = of_get_child_count(np);
num_mboxes = of_get_available_child_count(np);
if (num_mboxes == 0) {
dev_err(dev, "mailbox nodes not available\n");
return -EINVAL;
}
pdata = devm_kzalloc(dev, struct_size(pdata, ipi_mboxes, num_mboxes),
GFP_KERNEL);
if (!pdata)
......
......@@ -84,7 +84,7 @@ struct da8xx_rproc {
*/
static irqreturn_t handle_event(int irq, void *p)
{
struct rproc *rproc = (struct rproc *)p;
struct rproc *rproc = p;
/* Process incoming buffers on all our vrings */
rproc_vq_interrupt(rproc, 0);
......@@ -104,8 +104,8 @@ static irqreturn_t handle_event(int irq, void *p)
*/
static irqreturn_t da8xx_rproc_callback(int irq, void *p)
{
struct rproc *rproc = (struct rproc *)p;
struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
struct rproc *rproc = p;
struct da8xx_rproc *drproc = rproc->priv;
u32 chipsig;
chipsig = readl(drproc->chipsig);
......@@ -133,7 +133,7 @@ static irqreturn_t da8xx_rproc_callback(int irq, void *p)
static int da8xx_rproc_start(struct rproc *rproc)
{
struct device *dev = rproc->dev.parent;
struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
struct da8xx_rproc *drproc = rproc->priv;
struct clk *dsp_clk = drproc->dsp_clk;
struct reset_control *dsp_reset = drproc->dsp_reset;
int ret;
......@@ -183,7 +183,7 @@ static int da8xx_rproc_stop(struct rproc *rproc)
/* kick a virtqueue */
static void da8xx_rproc_kick(struct rproc *rproc, int vqid)
{
struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
struct da8xx_rproc *drproc = rproc->priv;
/* Interrupt remote proc */
writel(SYSCFG_CHIPSIG2, drproc->chipsig);
......@@ -360,7 +360,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
static int da8xx_rproc_remove(struct platform_device *pdev)
{
struct rproc *rproc = platform_get_drvdata(pdev);
struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
struct da8xx_rproc *drproc = rproc->priv;
struct device *dev = &pdev->dev;
/*
......
......@@ -28,6 +28,14 @@
#define DSP_RPROC_CLK_MAX 5
/*
* Module parameters
*/
static unsigned int no_mailboxes;
module_param_named(no_mailboxes, no_mailboxes, int, 0644);
MODULE_PARM_DESC(no_mailboxes,
"There is no mailbox between cores, so ignore remote proc reply after start, default is 0 (off).");
#define REMOTE_IS_READY BIT(0)
#define REMOTE_READY_WAIT_MAX_RETRIES 500
......@@ -172,6 +180,9 @@ static const struct imx_rproc_att imx_dsp_rproc_att_imx8ulp[] = {
{ 0x30000000, 0x90000000, 0x10000000, 0},
};
/* Initialize the mailboxes between cores, if exists */
static int (*imx_dsp_rproc_mbox_init)(struct imx_dsp_rproc *priv);
/* Reset function for DSP on i.MX8MP */
static int imx8mp_dsp_reset(struct imx_dsp_rproc *priv)
{
......@@ -492,12 +503,12 @@ static void imx_dsp_rproc_rxdb_callback(struct mbox_client *cl, void *data)
}
/**
* imx_dsp_rproc_mbox_init() - request mailbox channels
* imx_dsp_rproc_mbox_alloc() - request mailbox channels
* @priv: private data pointer
*
* Request three mailbox channels (tx, rx, rxdb).
*/
static int imx_dsp_rproc_mbox_init(struct imx_dsp_rproc *priv)
static int imx_dsp_rproc_mbox_alloc(struct imx_dsp_rproc *priv)
{
struct device *dev = priv->rproc->dev.parent;
struct mbox_client *cl;
......@@ -519,7 +530,7 @@ static int imx_dsp_rproc_mbox_init(struct imx_dsp_rproc *priv)
ret = PTR_ERR(priv->tx_ch);
dev_dbg(cl->dev, "failed to request tx mailbox channel: %d\n",
ret);
goto err_out;
return ret;
}
/* Channel for receiving message */
......@@ -528,7 +539,7 @@ static int imx_dsp_rproc_mbox_init(struct imx_dsp_rproc *priv)
ret = PTR_ERR(priv->rx_ch);
dev_dbg(cl->dev, "failed to request rx mailbox channel: %d\n",
ret);
goto err_out;
goto free_channel_tx;
}
cl = &priv->cl_rxdb;
......@@ -544,22 +555,30 @@ static int imx_dsp_rproc_mbox_init(struct imx_dsp_rproc *priv)
ret = PTR_ERR(priv->rxdb_ch);
dev_dbg(cl->dev, "failed to request mbox chan rxdb, ret %d\n",
ret);
goto err_out;
goto free_channel_rx;
}
return 0;
err_out:
if (!IS_ERR(priv->tx_ch))
mbox_free_channel(priv->tx_ch);
if (!IS_ERR(priv->rx_ch))
mbox_free_channel(priv->rx_ch);
if (!IS_ERR(priv->rxdb_ch))
mbox_free_channel(priv->rxdb_ch);
free_channel_rx:
mbox_free_channel(priv->rx_ch);
free_channel_tx:
mbox_free_channel(priv->tx_ch);
return ret;
}
/*
* imx_dsp_rproc_mbox_no_alloc()
*
* Empty function for no mailbox between cores
*
* Always return 0
*/
static int imx_dsp_rproc_mbox_no_alloc(struct imx_dsp_rproc *priv)
{
return 0;
}
static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv)
{
mbox_free_channel(priv->tx_ch);
......@@ -627,15 +646,19 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
rmem = of_reserved_mem_lookup(it.node);
if (!rmem) {
of_node_put(it.node);
dev_err(dev, "unable to acquire memory-region\n");
return -EINVAL;
}
if (imx_dsp_rproc_sys_to_da(priv, rmem->base, rmem->size, &da))
if (imx_dsp_rproc_sys_to_da(priv, rmem->base, rmem->size, &da)) {
of_node_put(it.node);
return -EINVAL;
}
cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size);
if (!cpu_addr) {
of_node_put(it.node);
dev_err(dev, "failed to map memory %p\n", &rmem->base);
return -ENOMEM;
}
......@@ -644,10 +667,12 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)rmem->base,
rmem->size, da, NULL, NULL, it.node->name);
if (mem)
if (mem) {
rproc_coredump_add_segment(rproc, da, rmem->size);
else
} else {
of_node_put(it.node);
return -ENOMEM;
}
rproc_add_carveout(rproc, mem);
}
......@@ -715,6 +740,191 @@ static void imx_dsp_rproc_kick(struct rproc *rproc, int vqid)
dev_err(dev, "%s: failed (%d, err:%d)\n", __func__, vqid, err);
}
/*
* Custom memory copy implementation for i.MX DSP Cores
*
* The IRAM is part of the HiFi DSP.
* According to hw specs only 32-bits writes are allowed.
*/
static int imx_dsp_rproc_memcpy(void *dst, const void *src, size_t size)
{
void __iomem *dest = (void __iomem *)dst;
const u8 *src_byte = src;
const u32 *source = src;
u32 affected_mask;
int i, q, r;
u32 tmp;
/* destination must be 32bit aligned */
if (!IS_ALIGNED((uintptr_t)dest, 4))
return -EINVAL;
q = size / 4;
r = size % 4;
/* copy data in units of 32 bits at a time */
for (i = 0; i < q; i++)
writel(source[i], dest + i * 4);
if (r) {
affected_mask = GENMASK(8 * r, 0);
/*
* first read the 32bit data of dest, then change affected
* bytes, and write back to dest.
* For unaffected bytes, it should not be changed
*/
tmp = readl(dest + q * 4);
tmp &= ~affected_mask;
/* avoid reading after end of source */
for (i = 0; i < r; i++)
tmp |= (src_byte[q * 4 + i] << (8 * i));
writel(tmp, dest + q * 4);
}
return 0;
}
/*
* Custom memset implementation for i.MX DSP Cores
*
* The IRAM is part of the HiFi DSP.
* According to hw specs only 32-bits writes are allowed.
*/
static int imx_dsp_rproc_memset(void *addr, u8 value, size_t size)
{
void __iomem *tmp_dst = (void __iomem *)addr;
u32 tmp_val = value;
u32 affected_mask;
int q, r;
u32 tmp;
/* destination must be 32bit aligned */
if (!IS_ALIGNED((uintptr_t)addr, 4))
return -EINVAL;
tmp_val |= tmp_val << 8;
tmp_val |= tmp_val << 16;
q = size / 4;
r = size % 4;
while (q--)
writel(tmp_val, tmp_dst++);
if (r) {
affected_mask = GENMASK(8 * r, 0);
/*
* first read the 32bit data of addr, then change affected
* bytes, and write back to addr.
* For unaffected bytes, it should not be changed
*/
tmp = readl(tmp_dst);
tmp &= ~affected_mask;
tmp |= (tmp_val & affected_mask);
writel(tmp, tmp_dst);
}
return 0;
}
/*
* imx_dsp_rproc_elf_load_segments() - load firmware segments to memory
* @rproc: remote processor which will be booted using these fw segments
* @fw: the ELF firmware image
*
* This function loads the firmware segments to memory, where the remote
* processor expects them.
*
* Return: 0 on success and an appropriate error code otherwise
*/
static int imx_dsp_rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
{
struct device *dev = &rproc->dev;
const void *ehdr, *phdr;
int i, ret = 0;
u16 phnum;
const u8 *elf_data = fw->data;
u8 class = fw_elf_get_class(fw);
u32 elf_phdr_get_size = elf_size_of_phdr(class);
ehdr = elf_data;
phnum = elf_hdr_get_e_phnum(class, ehdr);
phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr);
/* go through the available ELF segments */
for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) {
u64 da = elf_phdr_get_p_paddr(class, phdr);
u64 memsz = elf_phdr_get_p_memsz(class, phdr);
u64 filesz = elf_phdr_get_p_filesz(class, phdr);
u64 offset = elf_phdr_get_p_offset(class, phdr);
u32 type = elf_phdr_get_p_type(class, phdr);
void *ptr;
if (type != PT_LOAD || !memsz)
continue;
dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
type, da, memsz, filesz);
if (filesz > memsz) {
dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
filesz, memsz);
ret = -EINVAL;
break;
}
if (offset + filesz > fw->size) {
dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
offset + filesz, fw->size);
ret = -EINVAL;
break;
}
if (!rproc_u64_fit_in_size_t(memsz)) {
dev_err(dev, "size (%llx) does not fit in size_t type\n",
memsz);
ret = -EOVERFLOW;
break;
}
/* grab the kernel address for this device address */
ptr = rproc_da_to_va(rproc, da, memsz, NULL);
if (!ptr) {
dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
memsz);
ret = -EINVAL;
break;
}
/* put the segment where the remote processor expects it */
if (filesz) {
ret = imx_dsp_rproc_memcpy(ptr, elf_data + offset, filesz);
if (ret) {
dev_err(dev, "memory copy failed for da 0x%llx memsz 0x%llx\n",
da, memsz);
break;
}
}
/* zero out remaining memory for this segment */
if (memsz > filesz) {
ret = imx_dsp_rproc_memset(ptr + filesz, 0, memsz - filesz);
if (ret) {
dev_err(dev, "memset failed for da 0x%llx memsz 0x%llx\n",
da, memsz);
break;
}
}
}
return ret;
}
static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
{
if (rproc_elf_load_rsc_table(rproc, fw))
......@@ -729,7 +939,7 @@ static const struct rproc_ops imx_dsp_rproc_ops = {
.start = imx_dsp_rproc_start,
.stop = imx_dsp_rproc_stop,
.kick = imx_dsp_rproc_kick,
.load = rproc_elf_load_segments,
.load = imx_dsp_rproc_elf_load_segments,
.parse_fw = imx_dsp_rproc_parse_fw,
.sanity_check = rproc_elf_sanity_check,
.get_boot_addr = rproc_elf_get_boot_addr,
......@@ -903,6 +1113,11 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
priv->rproc = rproc;
priv->dsp_dcfg = dsp_dcfg;
if (no_mailboxes)
imx_dsp_rproc_mbox_init = imx_dsp_rproc_mbox_no_alloc;
else
imx_dsp_rproc_mbox_init = imx_dsp_rproc_mbox_alloc;
dev_set_drvdata(dev, rproc);
INIT_WORK(&priv->rproc_work, imx_dsp_rproc_vq_work);
......
......@@ -541,6 +541,7 @@ static int imx_rproc_prepare(struct rproc *rproc)
rmem = of_reserved_mem_lookup(it.node);
if (!rmem) {
of_node_put(it.node);
dev_err(priv->dev, "unable to acquire memory-region\n");
return -EINVAL;
}
......@@ -553,10 +554,12 @@ static int imx_rproc_prepare(struct rproc *rproc)
imx_rproc_mem_alloc, imx_rproc_mem_release,
it.node->name);
if (mem)
if (mem) {
rproc_coredump_add_segment(rproc, da, rmem->size);
else
} else {
of_node_put(it.node);
return -ENOMEM;
}
rproc_add_carveout(rproc, mem);
}
......
......@@ -74,8 +74,8 @@ static void scp_wdt_handler(struct mtk_scp *scp, u32 scp_to_host)
static void scp_init_ipi_handler(void *data, unsigned int len, void *priv)
{
struct mtk_scp *scp = (struct mtk_scp *)priv;
struct scp_run *run = (struct scp_run *)data;
struct mtk_scp *scp = priv;
struct scp_run *run = data;
scp->run.signaled = run->signaled;
strscpy(scp->run.fw_ver, run->fw_ver, SCP_FW_VER_LEN);
......@@ -498,7 +498,7 @@ static int scp_parse_fw(struct rproc *rproc, const struct firmware *fw)
static int scp_start(struct rproc *rproc)
{
struct mtk_scp *scp = (struct mtk_scp *)rproc->priv;
struct mtk_scp *scp = rproc->priv;
struct device *dev = scp->dev;
struct scp_run *run = &scp->run;
int ret;
......@@ -587,7 +587,7 @@ static void *mt8192_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len)
static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{
struct mtk_scp *scp = (struct mtk_scp *)rproc->priv;
struct mtk_scp *scp = rproc->priv;
return scp->data->scp_da_to_va(scp, da, len);
}
......@@ -627,7 +627,7 @@ static void mt8195_scp_stop(struct mtk_scp *scp)
static int scp_stop(struct rproc *rproc)
{
struct mtk_scp *scp = (struct mtk_scp *)rproc->priv;
struct mtk_scp *scp = rproc->priv;
int ret;
ret = clk_prepare_enable(scp->clk);
......@@ -829,7 +829,7 @@ static int scp_probe(struct platform_device *pdev)
if (!rproc)
return dev_err_probe(dev, -ENOMEM, "unable to allocate remoteproc\n");
scp = (struct mtk_scp *)rproc->priv;
scp = rproc->priv;
scp->rproc = rproc;
scp->dev = dev;
scp->data = of_device_get_match_data(dev);
......
......@@ -125,7 +125,7 @@ void scp_ipi_lock(struct mtk_scp *scp, u32 id)
EXPORT_SYMBOL_GPL(scp_ipi_lock);
/**
* scp_ipi_lock() - Unlock after operations of an IPI ID
* scp_ipi_unlock() - Unlock after operations of an IPI ID
*
* @scp: mtk_scp structure
* @id: IPI ID
......
......@@ -657,7 +657,7 @@ static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, size_t len)
swap(dram0, dram1);
shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2];
if (da >= PRU_PDRAM_DA && da + len <= PRU_PDRAM_DA + dram0.size) {
if (da + len <= PRU_PDRAM_DA + dram0.size) {
offset = da - PRU_PDRAM_DA;
va = (__force void *)(dram0.va + offset);
} else if (da >= PRU_SDRAM_DA &&
......@@ -706,8 +706,7 @@ static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, size_t len)
*/
da &= 0xfffff;
if (da >= PRU_IRAM_DA &&
da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) {
if (da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) {
offset = da - PRU_IRAM_DA;
va = (__force void *)(pru->mem_regions[PRU_IOMEM_IRAM].va +
offset);
......
......@@ -321,7 +321,7 @@ static int qcom_adsp_shutdown(struct qcom_adsp *adsp)
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int ret;
ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
......@@ -379,7 +379,7 @@ static int adsp_map_carveout(struct rproc *rproc)
static int adsp_start(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int ret;
unsigned int val;
......@@ -469,7 +469,7 @@ static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5)
static int adsp_stop(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int handover;
int ret;
......@@ -492,7 +492,7 @@ static int adsp_stop(struct rproc *rproc)
static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int offset;
offset = da - adsp->mem_reloc;
......@@ -696,7 +696,7 @@ static int adsp_probe(struct platform_device *pdev)
rproc->has_iommu = desc->has_iommu;
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
adsp = (struct qcom_adsp *)rproc->priv;
adsp = rproc->priv;
adsp->dev = &pdev->dev;
adsp->rproc = rproc;
adsp->info_name = desc->sysmon_name;
......
......@@ -1562,7 +1562,7 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc,
static int q6v5_start(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
struct q6v5 *qproc = rproc->priv;
int xfermemop_ret;
int ret;
......@@ -1604,7 +1604,7 @@ static int q6v5_start(struct rproc *rproc)
static int q6v5_stop(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
struct q6v5 *qproc = rproc->priv;
int ret;
ret = qcom_q6v5_request_stop(&qproc->q6v5, qproc->sysmon);
......@@ -1662,7 +1662,7 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc,
static unsigned long q6v5_panic(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
struct q6v5 *qproc = rproc->priv;
return qcom_q6v5_panic(&qproc->q6v5);
}
......@@ -1977,7 +1977,7 @@ static int q6v5_probe(struct platform_device *pdev)
rproc->auto_boot = false;
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
qproc = (struct q6v5 *)rproc->priv;
qproc = rproc->priv;
qproc->dev = &pdev->dev;
qproc->rproc = rproc;
qproc->hexagon_mdt_image = "modem.mdt";
......
......@@ -186,7 +186,7 @@ static int adsp_shutdown_poll_decrypt(struct qcom_adsp *adsp)
static int adsp_unprepare(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
/*
* adsp_load() did pass pas_metadata to the SCM driver for storing
......@@ -203,7 +203,7 @@ static int adsp_unprepare(struct rproc *rproc)
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int ret;
/* Store firmware handle to be used in adsp_start() */
......@@ -244,7 +244,7 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
static int adsp_start(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int ret;
ret = qcom_q6v5_prepare(&adsp->q6v5);
......@@ -360,7 +360,7 @@ static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
static int adsp_stop(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int handover;
int ret;
......@@ -390,7 +390,7 @@ static int adsp_stop(struct rproc *rproc)
static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
int offset;
offset = da - adsp->mem_reloc;
......@@ -405,7 +405,7 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iom
static unsigned long adsp_panic(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
struct qcom_adsp *adsp = rproc->priv;
return qcom_q6v5_panic(&adsp->q6v5);
}
......@@ -683,7 +683,7 @@ static int adsp_probe(struct platform_device *pdev)
rproc->auto_boot = desc->auto_boot;
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
adsp = (struct qcom_adsp *)rproc->priv;
adsp = rproc->priv;
adsp->dev = &pdev->dev;
adsp->rproc = rproc;
adsp->minidump_id = desc->minidump_id;
......
......@@ -154,7 +154,7 @@ static const struct wcnss_data pronto_v3_data = {
static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
struct qcom_wcnss *wcnss = rproc->priv;
int ret;
ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
......@@ -227,7 +227,7 @@ static void wcnss_configure_iris(struct qcom_wcnss *wcnss)
static int wcnss_start(struct rproc *rproc)
{
struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
struct qcom_wcnss *wcnss = rproc->priv;
int ret, i;
mutex_lock(&wcnss->iris_lock);
......@@ -293,7 +293,7 @@ static int wcnss_start(struct rproc *rproc)
static int wcnss_stop(struct rproc *rproc)
{
struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
struct qcom_wcnss *wcnss = rproc->priv;
int ret;
if (wcnss->state) {
......@@ -320,7 +320,7 @@ static int wcnss_stop(struct rproc *rproc)
static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{
struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
struct qcom_wcnss *wcnss = rproc->priv;
int offset;
offset = da - wcnss->mem_reloc;
......@@ -566,7 +566,7 @@ static int wcnss_probe(struct platform_device *pdev)
}
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
wcnss = (struct qcom_wcnss *)rproc->priv;
wcnss = rproc->priv;
wcnss->dev = &pdev->dev;
wcnss->rproc = rproc;
platform_set_drvdata(pdev, wcnss);
......
......@@ -62,13 +62,16 @@ static int rcar_rproc_prepare(struct rproc *rproc)
rmem = of_reserved_mem_lookup(it.node);
if (!rmem) {
of_node_put(it.node);
dev_err(&rproc->dev,
"unable to acquire memory-region\n");
return -EINVAL;
}
if (rmem->base > U32_MAX)
if (rmem->base > U32_MAX) {
of_node_put(it.node);
return -EINVAL;
}
/* No need to translate pa to da, R-Car use same map */
da = rmem->base;
......@@ -79,8 +82,10 @@ static int rcar_rproc_prepare(struct rproc *rproc)
rcar_rproc_mem_release,
it.node->name);
if (!mem)
if (!mem) {
of_node_put(it.node);
return -ENOMEM;
}
rproc_add_carveout(rproc, mem);
}
......
......@@ -129,6 +129,7 @@ static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
while (of_phandle_iterator_next(&it) == 0) {
rmem = of_reserved_mem_lookup(it.node);
if (!rmem) {
of_node_put(it.node);
dev_err(dev, "unable to acquire memory-region\n");
return -EINVAL;
}
......@@ -150,8 +151,10 @@ static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
it.node->name);
}
if (!mem)
if (!mem) {
of_node_put(it.node);
return -ENOMEM;
}
rproc_add_carveout(rproc, mem);
index++;
......@@ -379,7 +382,7 @@ static int st_rproc_probe(struct platform_device *pdev)
clk_set_rate(ddata->clk, ddata->clk_rate);
}
if (of_get_property(np, "mbox-names", NULL)) {
if (of_property_present(np, "mbox-names")) {
ddata->mbox_client_vq0.dev = dev;
ddata->mbox_client_vq0.tx_done = NULL;
ddata->mbox_client_vq0.tx_block = false;
......
......@@ -223,11 +223,13 @@ static int stm32_rproc_prepare(struct rproc *rproc)
while (of_phandle_iterator_next(&it) == 0) {
rmem = of_reserved_mem_lookup(it.node);
if (!rmem) {
of_node_put(it.node);
dev_err(dev, "unable to acquire memory-region\n");
return -EINVAL;
}
if (stm32_rproc_pa_to_da(rproc, rmem->base, &da) < 0) {
of_node_put(it.node);
dev_err(dev, "memory region not valid %pa\n",
&rmem->base);
return -EINVAL;
......@@ -254,8 +256,10 @@ static int stm32_rproc_prepare(struct rproc *rproc)
it.node->name);
}
if (!mem)
if (!mem) {
of_node_put(it.node);
return -ENOMEM;
}
rproc_add_carveout(rproc, mem);
index++;
......@@ -287,8 +291,16 @@ static void stm32_rproc_mb_vq_work(struct work_struct *work)
struct stm32_mbox *mb = container_of(work, struct stm32_mbox, vq_work);
struct rproc *rproc = dev_get_drvdata(mb->client.dev);
mutex_lock(&rproc->lock);
if (rproc->state != RPROC_RUNNING)
goto unlock_mutex;
if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
unlock_mutex:
mutex_unlock(&rproc->lock);
}
static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data)
......
......@@ -71,14 +71,16 @@ struct k3_r5_mem {
/*
* All cluster mode values are not applicable on all SoCs. The following
* are the modes supported on various SoCs:
* Split mode : AM65x, J721E, J7200 and AM64x SoCs
* LockStep mode : AM65x, J721E and J7200 SoCs
* Single-CPU mode : AM64x SoCs only
* Split mode : AM65x, J721E, J7200 and AM64x SoCs
* LockStep mode : AM65x, J721E and J7200 SoCs
* Single-CPU mode : AM64x SoCs only
* Single-Core mode : AM62x, AM62A SoCs
*/
enum cluster_mode {
CLUSTER_MODE_SPLIT = 0,
CLUSTER_MODE_LOCKSTEP,
CLUSTER_MODE_SINGLECPU,
CLUSTER_MODE_SINGLECORE
};
/**
......@@ -86,11 +88,13 @@ enum cluster_mode {
* @tcm_is_double: flag to denote the larger unified TCMs in certain modes
* @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC
* @single_cpu_mode: flag to denote if SoC/IP supports Single-CPU mode
* @is_single_core: flag to denote if SoC/IP has only single core R5
*/
struct k3_r5_soc_data {
bool tcm_is_double;
bool tcm_ecc_autoinit;
bool single_cpu_mode;
bool is_single_core;
};
/**
......@@ -838,7 +842,8 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc)
core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem);
if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU) {
cluster->mode == CLUSTER_MODE_SINGLECPU ||
cluster->mode == CLUSTER_MODE_SINGLECORE) {
core = core0;
} else {
core = kproc->core;
......@@ -852,38 +857,34 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc)
dev_dbg(dev, "boot_vector = 0x%llx, cfg = 0x%x ctrl = 0x%x stat = 0x%x\n",
boot_vec, cfg, ctrl, stat);
/* check if only Single-CPU mode is supported on applicable SoCs */
if (cluster->soc_data->single_cpu_mode) {
single_cpu =
!!(stat & PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY);
if (single_cpu && cluster->mode == CLUSTER_MODE_SPLIT) {
dev_err(cluster->dev, "split-mode not permitted, force configuring for single-cpu mode\n");
cluster->mode = CLUSTER_MODE_SINGLECPU;
}
goto config;
single_cpu = !!(stat & PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY);
lockstep_en = !!(stat & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED);
/* Override to single CPU mode if set in status flag */
if (single_cpu && cluster->mode == CLUSTER_MODE_SPLIT) {
dev_err(cluster->dev, "split-mode not permitted, force configuring for single-cpu mode\n");
cluster->mode = CLUSTER_MODE_SINGLECPU;
}
/* check conventional LockStep vs Split mode configuration */
lockstep_en = !!(stat & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED);
/* Override to split mode if lockstep enable bit is not set in status flag */
if (!lockstep_en && cluster->mode == CLUSTER_MODE_LOCKSTEP) {
dev_err(cluster->dev, "lockstep mode not permitted, force configuring for split-mode\n");
cluster->mode = CLUSTER_MODE_SPLIT;
}
config:
/* always enable ARM mode and set boot vector to 0 */
boot_vec = 0x0;
if (core == core0) {
clr_cfg = PROC_BOOT_CFG_FLAG_R5_TEINIT;
if (cluster->soc_data->single_cpu_mode) {
/*
* Single-CPU configuration bit can only be configured
* on Core0 and system firmware will NACK any requests
* with the bit configured, so program it only on
* permitted cores
*/
if (cluster->mode == CLUSTER_MODE_SINGLECPU)
set_cfg = PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE;
/*
* Single-CPU configuration bit can only be configured
* on Core0 and system firmware will NACK any requests
* with the bit configured, so program it only on
* permitted cores
*/
if (cluster->mode == CLUSTER_MODE_SINGLECPU ||
cluster->mode == CLUSTER_MODE_SINGLECORE) {
set_cfg = PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE;
} else {
/*
* LockStep configuration bit is Read-only on Split-mode
......@@ -1074,6 +1075,7 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc)
if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU ||
cluster->mode == CLUSTER_MODE_SINGLECORE ||
!cluster->soc_data->tcm_is_double)
return;
......@@ -1108,12 +1110,12 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
struct k3_r5_cluster *cluster = kproc->cluster;
struct k3_r5_core *core = kproc->core;
struct device *cdev = core->dev;
bool r_state = false, c_state = false;
bool r_state = false, c_state = false, lockstep_en = false, single_cpu = false;
u32 ctrl = 0, cfg = 0, stat = 0, halted = 0;
u64 boot_vec = 0;
u32 atcm_enable, btcm_enable, loczrama;
struct k3_r5_core *core0;
enum cluster_mode mode;
enum cluster_mode mode = cluster->mode;
int ret;
core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem);
......@@ -1147,13 +1149,14 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
atcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_ATCM_EN ? 1 : 0;
btcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_BTCM_EN ? 1 : 0;
loczrama = cfg & PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE ? 1 : 0;
if (cluster->soc_data->single_cpu_mode) {
mode = cfg & PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE ?
CLUSTER_MODE_SINGLECPU : CLUSTER_MODE_SPLIT;
} else {
mode = cfg & PROC_BOOT_CFG_FLAG_R5_LOCKSTEP ?
CLUSTER_MODE_LOCKSTEP : CLUSTER_MODE_SPLIT;
}
single_cpu = cfg & PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE ? 1 : 0;
lockstep_en = cfg & PROC_BOOT_CFG_FLAG_R5_LOCKSTEP ? 1 : 0;
if (single_cpu && mode != CLUSTER_MODE_SINGLECORE)
mode = CLUSTER_MODE_SINGLECPU;
if (lockstep_en)
mode = CLUSTER_MODE_LOCKSTEP;
halted = ctrl & PROC_BOOT_CTRL_FLAG_R5_CORE_HALT;
/*
......@@ -1269,9 +1272,12 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
goto err_add;
}
/* create only one rproc in lockstep mode or single-cpu mode */
/* create only one rproc in lockstep, single-cpu or
* single core mode
*/
if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU)
cluster->mode == CLUSTER_MODE_SINGLECPU ||
cluster->mode == CLUSTER_MODE_SINGLECORE)
break;
}
......@@ -1700,12 +1706,6 @@ static int k3_r5_probe(struct platform_device *pdev)
return -ENOMEM;
cluster->dev = dev;
/*
* default to most common efuse configurations - Split-mode on AM64x
* and LockStep-mode on all others
*/
cluster->mode = data->single_cpu_mode ?
CLUSTER_MODE_SPLIT : CLUSTER_MODE_LOCKSTEP;
cluster->soc_data = data;
INIT_LIST_HEAD(&cluster->cores);
......@@ -1716,9 +1716,37 @@ static int k3_r5_probe(struct platform_device *pdev)
return ret;
}
if (ret == -EINVAL) {
/*
* default to most common efuse configurations - Split-mode on AM64x
* and LockStep-mode on all others
* default to most common efuse configurations -
* Split-mode on AM64x
* Single core on AM62x
* LockStep-mode on all others
*/
if (!data->is_single_core)
cluster->mode = data->single_cpu_mode ?
CLUSTER_MODE_SPLIT : CLUSTER_MODE_LOCKSTEP;
else
cluster->mode = CLUSTER_MODE_SINGLECORE;
}
if ((cluster->mode == CLUSTER_MODE_SINGLECPU && !data->single_cpu_mode) ||
(cluster->mode == CLUSTER_MODE_SINGLECORE && !data->is_single_core)) {
dev_err(dev, "Cluster mode = %d is not supported on this SoC\n", cluster->mode);
return -EINVAL;
}
num_cores = of_get_available_child_count(np);
if (num_cores != 2) {
dev_err(dev, "MCU cluster requires both R5F cores to be enabled, num_cores = %d\n",
if (num_cores != 2 && !data->is_single_core) {
dev_err(dev, "MCU cluster requires both R5F cores to be enabled but num_cores is set to = %d\n",
num_cores);
return -ENODEV;
}
if (num_cores != 1 && data->is_single_core) {
dev_err(dev, "SoC supports only single core R5 but num_cores is set to %d\n",
num_cores);
return -ENODEV;
}
......@@ -1760,18 +1788,28 @@ static const struct k3_r5_soc_data am65_j721e_soc_data = {
.tcm_is_double = false,
.tcm_ecc_autoinit = false,
.single_cpu_mode = false,
.is_single_core = false,
};
static const struct k3_r5_soc_data j7200_j721s2_soc_data = {
.tcm_is_double = true,
.tcm_ecc_autoinit = true,
.single_cpu_mode = false,
.is_single_core = false,
};
static const struct k3_r5_soc_data am64_soc_data = {
.tcm_is_double = true,
.tcm_ecc_autoinit = true,
.single_cpu_mode = true,
.is_single_core = false,
};
static const struct k3_r5_soc_data am62_soc_data = {
.tcm_is_double = false,
.tcm_ecc_autoinit = true,
.single_cpu_mode = false,
.is_single_core = true,
};
static const struct of_device_id k3_r5_of_match[] = {
......@@ -1779,6 +1817,7 @@ static const struct of_device_id k3_r5_of_match[] = {
{ .compatible = "ti,j721e-r5fss", .data = &am65_j721e_soc_data, },
{ .compatible = "ti,j7200-r5fss", .data = &j7200_j721s2_soc_data, },
{ .compatible = "ti,am64-r5fss", .data = &am64_soc_data, },
{ .compatible = "ti,am62-r5fss", .data = &am62_soc_data, },
{ .compatible = "ti,j721s2-r5fss", .data = &j7200_j721s2_soc_data, },
{ /* sentinel */ },
};
......
......@@ -8,16 +8,23 @@
#include <linux/dma-mapping.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox/zynqmp-ipi-message.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
#include <linux/slab.h>
#include "remoteproc_internal.h"
/* IPI buffer MAX length */
#define IPI_BUF_LEN_MAX 32U
/* RX mailbox client buffer max length */
#define MBOX_CLIENT_BUF_MAX (IPI_BUF_LEN_MAX + \
sizeof(struct zynqmp_ipi_message))
/*
* settings for RPU cluster mode which
* reflects possible values of xlnx,cluster-mode dt-property
......@@ -43,6 +50,27 @@ struct mem_bank_data {
char *bank_name;
};
/**
* struct mbox_info
*
* @rx_mc_buf: to copy data from mailbox rx channel
* @tx_mc_buf: to copy data to mailbox tx channel
* @r5_core: this mailbox's corresponding r5_core pointer
* @mbox_work: schedule work after receiving data from mailbox
* @mbox_cl: mailbox client
* @tx_chan: mailbox tx channel
* @rx_chan: mailbox rx channel
*/
struct mbox_info {
unsigned char rx_mc_buf[MBOX_CLIENT_BUF_MAX];
unsigned char tx_mc_buf[MBOX_CLIENT_BUF_MAX];
struct zynqmp_r5_core *r5_core;
struct work_struct mbox_work;
struct mbox_client mbox_cl;
struct mbox_chan *tx_chan;
struct mbox_chan *rx_chan;
};
/*
* Hardcoded TCM bank values. This will be removed once TCM bindings are
* accepted for system-dt specifications and upstreamed in linux kernel
......@@ -61,20 +89,18 @@ static const struct mem_bank_data zynqmp_tcm_banks[] = {
* @np: device node of RPU instance
* @tcm_bank_count: number TCM banks accessible to this RPU
* @tcm_banks: array of each TCM bank data
* @rmem_count: Number of reserved mem regions
* @rmem: reserved memory region nodes from device tree
* @rproc: rproc handle
* @pm_domain_id: RPU CPU power domain id
* @ipi: pointer to mailbox information
*/
struct zynqmp_r5_core {
struct device *dev;
struct device_node *np;
int tcm_bank_count;
struct mem_bank_data **tcm_banks;
int rmem_count;
struct reserved_mem **rmem;
struct rproc *rproc;
u32 pm_domain_id;
struct mbox_info *ipi;
};
/**
......@@ -92,6 +118,178 @@ struct zynqmp_r5_cluster {
struct zynqmp_r5_core **r5_cores;
};
/**
* event_notified_idr_cb() - callback for vq_interrupt per notifyid
* @id: rproc->notify id
* @ptr: pointer to idr private data
* @data: data passed to idr_for_each callback
*
* Pass notification to remoteproc virtio
*
* Return: 0. having return is to satisfy the idr_for_each() function
* pointer input argument requirement.
**/
static int event_notified_idr_cb(int id, void *ptr, void *data)
{
struct rproc *rproc = data;
if (rproc_vq_interrupt(rproc, id) == IRQ_NONE)
dev_dbg(&rproc->dev, "data not found for vqid=%d\n", id);
return 0;
}
/**
* handle_event_notified() - remoteproc notification work function
* @work: pointer to the work structure
*
* It checks each registered remoteproc notify IDs.
*/
static void handle_event_notified(struct work_struct *work)
{
struct mbox_info *ipi;
struct rproc *rproc;
ipi = container_of(work, struct mbox_info, mbox_work);
rproc = ipi->r5_core->rproc;
/*
* We only use IPI for interrupt. The RPU firmware side may or may
* not write the notifyid when it trigger IPI.
* And thus, we scan through all the registered notifyids and
* find which one is valid to get the message.
* Even if message from firmware is NULL, we attempt to get vqid
*/
idr_for_each(&rproc->notifyids, event_notified_idr_cb, rproc);
}
/**
* zynqmp_r5_mb_rx_cb() - receive channel mailbox callback
* @cl: mailbox client
* @msg: message pointer
*
* Receive data from ipi buffer, ack interrupt and then
* it will schedule the R5 notification work.
*/
static void zynqmp_r5_mb_rx_cb(struct mbox_client *cl, void *msg)
{
struct zynqmp_ipi_message *ipi_msg, *buf_msg;
struct mbox_info *ipi;
size_t len;
ipi = container_of(cl, struct mbox_info, mbox_cl);
/* copy data from ipi buffer to r5_core */
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;
}
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)
dev_err(cl->dev, "ack failed to mbox rx_chan\n");
schedule_work(&ipi->mbox_work);
}
/**
* zynqmp_r5_setup_mbox() - Setup mailboxes related properties
* this is used for each individual R5 core
*
* @cdev: child node device
*
* Function to setup mailboxes related properties
* return : NULL if failed else pointer to mbox_info
*/
static struct mbox_info *zynqmp_r5_setup_mbox(struct device *cdev)
{
struct mbox_client *mbox_cl;
struct mbox_info *ipi;
ipi = kzalloc(sizeof(*ipi), GFP_KERNEL);
if (!ipi)
return NULL;
mbox_cl = &ipi->mbox_cl;
mbox_cl->rx_callback = zynqmp_r5_mb_rx_cb;
mbox_cl->tx_block = false;
mbox_cl->knows_txdone = false;
mbox_cl->tx_done = NULL;
mbox_cl->dev = cdev;
/* Request TX and RX channels */
ipi->tx_chan = mbox_request_channel_byname(mbox_cl, "tx");
if (IS_ERR(ipi->tx_chan)) {
ipi->tx_chan = NULL;
kfree(ipi);
dev_warn(cdev, "mbox tx channel request failed\n");
return NULL;
}
ipi->rx_chan = mbox_request_channel_byname(mbox_cl, "rx");
if (IS_ERR(ipi->rx_chan)) {
mbox_free_channel(ipi->tx_chan);
ipi->rx_chan = NULL;
ipi->tx_chan = NULL;
kfree(ipi);
dev_warn(cdev, "mbox rx channel request failed\n");
return NULL;
}
INIT_WORK(&ipi->mbox_work, handle_event_notified);
return ipi;
}
static void zynqmp_r5_free_mbox(struct mbox_info *ipi)
{
if (!ipi)
return;
if (ipi->tx_chan) {
mbox_free_channel(ipi->tx_chan);
ipi->tx_chan = NULL;
}
if (ipi->rx_chan) {
mbox_free_channel(ipi->rx_chan);
ipi->rx_chan = NULL;
}
kfree(ipi);
}
/*
* zynqmp_r5_core_kick() - kick a firmware if mbox is provided
* @rproc: r5 core's corresponding rproc structure
* @vqid: virtqueue ID
*/
static void zynqmp_r5_rproc_kick(struct rproc *rproc, int vqid)
{
struct zynqmp_r5_core *r5_core = rproc->priv;
struct device *dev = r5_core->dev;
struct zynqmp_ipi_message *mb_msg;
struct mbox_info *ipi;
int ret;
ipi = r5_core->ipi;
if (!ipi)
return;
mb_msg = (struct zynqmp_ipi_message *)ipi->tx_mc_buf;
memcpy(mb_msg->data, &vqid, sizeof(vqid));
mb_msg->len = sizeof(vqid);
ret = mbox_send_message(ipi->tx_chan, mb_msg);
if (ret < 0)
dev_warn(dev, "failed to send message\n");
}
/*
* zynqmp_r5_set_mode()
*
......@@ -239,21 +437,29 @@ static int add_mem_regions_carveout(struct rproc *rproc)
{
struct rproc_mem_entry *rproc_mem;
struct zynqmp_r5_core *r5_core;
struct of_phandle_iterator it;
struct reserved_mem *rmem;
int i, num_mem_regions;
int i = 0;
r5_core = (struct zynqmp_r5_core *)rproc->priv;
num_mem_regions = r5_core->rmem_count;
r5_core = rproc->priv;
for (i = 0; i < num_mem_regions; i++) {
rmem = r5_core->rmem[i];
/* Register associated reserved memory regions */
of_phandle_iterator_init(&it, r5_core->np, "memory-region", NULL, 0);
if (!strncmp(rmem->name, "vdev0buffer", strlen("vdev0buffer"))) {
while (of_phandle_iterator_next(&it) == 0) {
rmem = of_reserved_mem_lookup(it.node);
if (!rmem) {
of_node_put(it.node);
dev_err(&rproc->dev, "unable to acquire memory-region\n");
return -EINVAL;
}
if (!strcmp(it.node->name, "vdev0buffer")) {
/* Init reserved memory for vdev buffer */
rproc_mem = rproc_of_resm_mem_entry_init(&rproc->dev, i,
rmem->size,
rmem->base,
rmem->name);
it.node->name);
} else {
/* Register associated reserved memory regions */
rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL,
......@@ -261,16 +467,19 @@ static int add_mem_regions_carveout(struct rproc *rproc)
rmem->size, rmem->base,
zynqmp_r5_mem_region_map,
zynqmp_r5_mem_region_unmap,
rmem->name);
it.node->name);
}
if (!rproc_mem)
if (!rproc_mem) {
of_node_put(it.node);
return -ENOMEM;
}
rproc_add_carveout(rproc, rproc_mem);
dev_dbg(&rproc->dev, "reserved mem carveout %s addr=%llx, size=0x%llx",
rmem->name, rmem->base, rmem->size);
it.node->name, rmem->base, rmem->size);
i++;
}
return 0;
......@@ -363,7 +572,7 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc)
size_t bank_size;
char *bank_name;
r5_core = (struct zynqmp_r5_core *)rproc->priv;
r5_core = rproc->priv;
dev = r5_core->dev;
num_banks = r5_core->tcm_bank_count;
......@@ -432,7 +641,7 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc)
u32 pm_domain_id;
char *bank_name;
r5_core = (struct zynqmp_r5_core *)rproc->priv;
r5_core = rproc->priv;
dev = r5_core->dev;
/* Go through zynqmp banks for r5 node */
......@@ -502,7 +711,7 @@ static int add_tcm_banks(struct rproc *rproc)
struct zynqmp_r5_core *r5_core;
struct device *dev;
r5_core = (struct zynqmp_r5_core *)rproc->priv;
r5_core = rproc->priv;
if (!r5_core)
return -EINVAL;
......@@ -595,7 +804,7 @@ static int zynqmp_r5_rproc_unprepare(struct rproc *rproc)
u32 pm_domain_id;
int i;
r5_core = (struct zynqmp_r5_core *)rproc->priv;
r5_core = rproc->priv;
for (i = 0; i < r5_core->tcm_bank_count; i++) {
pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id;
......@@ -617,6 +826,7 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = {
.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
.sanity_check = rproc_elf_sanity_check,
.get_boot_addr = rproc_elf_get_boot_addr,
.kick = zynqmp_r5_rproc_kick,
};
/**
......@@ -649,7 +859,7 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
}
r5_rproc->auto_boot = false;
r5_core = (struct zynqmp_r5_core *)r5_rproc->priv;
r5_core = r5_rproc->priv;
r5_core->dev = cdev;
r5_core->np = dev_of_node(cdev);
if (!r5_core->np) {
......@@ -726,59 +936,6 @@ static int zynqmp_r5_get_tcm_node(struct zynqmp_r5_cluster *cluster)
return 0;
}
/**
* zynqmp_r5_get_mem_region_node()
* parse memory-region property and get reserved mem regions
*
* @r5_core: pointer to zynqmp_r5_core type object
*
* Return: 0 for success and error code for failure.
*/
static int zynqmp_r5_get_mem_region_node(struct zynqmp_r5_core *r5_core)
{
struct device_node *np, *rmem_np;
struct reserved_mem **rmem;
int res_mem_count, i;
struct device *dev;
dev = r5_core->dev;
np = r5_core->np;
res_mem_count = of_property_count_elems_of_size(np, "memory-region",
sizeof(phandle));
if (res_mem_count <= 0) {
dev_warn(dev, "failed to get memory-region property %d\n",
res_mem_count);
return 0;
}
rmem = devm_kcalloc(dev, res_mem_count,
sizeof(struct reserved_mem *), GFP_KERNEL);
if (!rmem)
return -ENOMEM;
for (i = 0; i < res_mem_count; i++) {
rmem_np = of_parse_phandle(np, "memory-region", i);
if (!rmem_np)
goto release_rmem;
rmem[i] = of_reserved_mem_lookup(rmem_np);
if (!rmem[i]) {
of_node_put(rmem_np);
goto release_rmem;
}
of_node_put(rmem_np);
}
r5_core->rmem_count = res_mem_count;
r5_core->rmem = rmem;
return 0;
release_rmem:
return -EINVAL;
}
/*
* zynqmp_r5_core_init()
* Create and initialize zynqmp_r5_core type object
......@@ -806,10 +963,6 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster,
for (i = 0; i < cluster->core_count; i++) {
r5_core = cluster->r5_cores[i];
ret = zynqmp_r5_get_mem_region_node(r5_core);
if (ret)
dev_warn(dev, "memory-region prop failed %d\n", ret);
/* Initialize r5 cores with power-domains parsed from dts */
ret = of_property_read_u32_index(r5_core->np, "power-domains",
1, &r5_core->pm_domain_id);
......@@ -849,6 +1002,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
struct device_node *child;
enum rpu_tcm_comb tcm_mode;
int core_count, ret, i;
struct mbox_info *ipi;
ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode);
......@@ -928,6 +1082,16 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
goto release_r5_cores;
}
/*
* If mailbox nodes are disabled using "status" property then
* setting up mailbox channels will fail.
*/
ipi = zynqmp_r5_setup_mbox(&child_pdev->dev);
if (ipi) {
r5_cores[i]->ipi = ipi;
ipi->r5_core = r5_cores[i];
}
/*
* If two child nodes are available in dts in lockstep mode,
* then ignore second child node.
......@@ -965,6 +1129,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
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);
......@@ -978,17 +1143,18 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
static void zynqmp_r5_cluster_exit(void *data)
{
struct platform_device *pdev = (struct platform_device *)data;
struct platform_device *pdev = data;
struct zynqmp_r5_cluster *cluster;
struct zynqmp_r5_core *r5_core;
int i;
cluster = (struct zynqmp_r5_cluster *)platform_get_drvdata(pdev);
cluster = platform_get_drvdata(pdev);
if (!cluster)
return;
for (i = 0; i < cluster->core_count; i++) {
r5_core = cluster->r5_cores[i];
zynqmp_r5_free_mbox(r5_core->ipi);
of_reserved_mem_device_release(r5_core->dev);
put_device(r5_core->dev);
rproc_del(r5_core->rproc);
......
......@@ -9,7 +9,7 @@
* @data: message payload
*
* This is the structure for data used in mbox_send_message
* the maximum length of data buffer is fixed to 12 bytes.
* the maximum length of data buffer is fixed to 32 bytes.
* Client is supposed to be aware of this.
*/
struct zynqmp_ipi_message {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment