mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
Merge tag 'rproc-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
Pull remoteproc updates from Bjorn Andersson: - Fix a memory remapping issue and make a few life-cycle improvements in the i.MX HiFi remoteproc driver - Add support the System Manager CPU and LMM APIs and use this to support i.MX95 - Rework the handling of the Mediatek SCP clock to avoid a potential circular deadlock in the clock providers - Refactor the Qualcomm secure-world helpers and add support in the Qualcomm PAS remoteproc driver for reading a resource-table from secure world. Use this to configure the IOMMU on newer targets where Linux runs in EL2 * tag 'rproc-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: remoteproc: imx_rproc: Fix invalid loaded resource table detection remoteproc: mediatek: Break lock dependency to `prepare_lock` remoteproc: imx_rproc: Add support for i.MX95 remoteproc: imx_rproc: Add support for System Manager CPU API remoteproc: imx_rproc: Add support for System Manager LMM API remoteproc: imx_rproc: Introduce prepare ops for imx_rproc_dcfg remoteproc: imx_rproc: Add runtime ops copy to support dynamic behavior dt-bindings: remoteproc: fsl,imx-rproc: Add support for i.MX95 dt-bindings: remoteproc: Add HSM M4F core on TI K3 SoCs remoteproc: xlnx_r5: Simplify with scoped for each OF child loop remoteproc: mtk_scp: Simplify with scoped for each OF child loop remoteproc: imx_dsp_rproc: Only reset carveout memory at RPROC_OFFLINE state dt-bindings: remoteproc: qcom,sm8550-pas: Drop SM8750 ADSP from if-branch dt-bindings: remoteproc: qcom,adsp: Allow cx-supply on qcom,sdm845-slpi-pas remoteproc: imx_dsp_rproc: Fix multiple start/stop operations remoteproc: imx_rproc: Use strstarts for "rsc-table" check remoteproc: imx_dsp_rproc: Wait for suspend ACK only if WAIT_FW_CONFIRMATION is set remoteproc: imx_dsp_rproc: Rename macro to reflect multiple contexts remoteproc: imx_dsp_rproc: Skip RP_MBOX_SUSPEND_SYSTEM when mailbox TX channel is uninitialized dt-bindings: remoteproc: Fix dead link to Keystone DSP GPIO binding
This commit is contained in:
@@ -28,6 +28,7 @@ properties:
|
||||
- fsl,imx8qxp-cm4
|
||||
- fsl,imx8ulp-cm33
|
||||
- fsl,imx93-cm33
|
||||
- fsl,imx95-cm7
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
@@ -32,6 +32,8 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
cx-supply: true
|
||||
|
||||
px-supply:
|
||||
description: Phandle to the PX regulator
|
||||
|
||||
@@ -159,6 +161,9 @@ allOf:
|
||||
items:
|
||||
- const: lcx
|
||||
- const: lmx
|
||||
else:
|
||||
properties:
|
||||
cx-supply: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
||||
@@ -187,7 +187,6 @@ allOf:
|
||||
enum:
|
||||
- qcom,sm8550-adsp-pas
|
||||
- qcom,sm8650-adsp-pas
|
||||
- qcom,sm8750-adsp-pas
|
||||
- qcom,x1e80100-adsp-pas
|
||||
then:
|
||||
properties:
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/remoteproc/ti,hsm-m4fss.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TI K3 HSM M4F processor subsystems
|
||||
|
||||
maintainers:
|
||||
- Beleswar Padhi <b-padhi@ti.com>
|
||||
|
||||
description: |
|
||||
Some K3 family SoCs have a HSM (High Security Module) M4F core in the
|
||||
Wakeup Voltage Domain which could be used to run secure services like
|
||||
Authentication. Some of those are J721S2, J784S4, J722S, AM62X.
|
||||
|
||||
$ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,hsm-m4fss
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: SRAM0_0 internal memory region
|
||||
- description: SRAM0_1 internal memory region
|
||||
- description: SRAM1 internal memory region
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: sram0_0
|
||||
- const: sram0_1
|
||||
- const: sram1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
firmware-name:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- resets
|
||||
- firmware-name
|
||||
- ti,sci
|
||||
- ti,sci-dev-id
|
||||
- ti,sci-proc-ids
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
remoteproc@43c00000 {
|
||||
compatible = "ti,hsm-m4fss";
|
||||
reg = <0x00 0x43c00000 0x00 0x20000>,
|
||||
<0x00 0x43c20000 0x00 0x10000>,
|
||||
<0x00 0x43c30000 0x00 0x10000>;
|
||||
reg-names = "sram0_0", "sram0_1", "sram1";
|
||||
resets = <&k3_reset 225 1>;
|
||||
firmware-name = "hsm.bin";
|
||||
ti,sci = <&sms>;
|
||||
ti,sci-dev-id = <225>;
|
||||
ti,sci-proc-ids = <0x80 0xff>;
|
||||
};
|
||||
};
|
||||
@@ -66,7 +66,7 @@ The following are the mandatory properties:
|
||||
- kick-gpios: Should specify the gpio device needed for the virtio IPC
|
||||
stack. This will be used to interrupt the remote processor.
|
||||
The gpio device to be used is as per the bindings in,
|
||||
Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt
|
||||
Documentation/devicetree/bindings/gpio/ti,keystone-dsp-gpio.yaml
|
||||
|
||||
SoC-specific Required properties:
|
||||
---------------------------------
|
||||
|
||||
@@ -27,6 +27,8 @@ config IMX_REMOTEPROC
|
||||
tristate "i.MX remoteproc support"
|
||||
depends on ARCH_MXC
|
||||
depends on HAVE_ARM_SMCCC
|
||||
depends on IMX_SCMI_CPU_DRV || !IMX_SCMI_CPU_DRV
|
||||
depends on IMX_SCMI_LMM_DRV || !IMX_SCMI_LMM_DRV
|
||||
select MAILBOX
|
||||
help
|
||||
Say y here to support iMX's remote processors via the remote
|
||||
|
||||
@@ -38,15 +38,15 @@ MODULE_PARM_DESC(no_mailboxes,
|
||||
|
||||
/* Flag indicating that the remote is up and running */
|
||||
#define REMOTE_IS_READY BIT(0)
|
||||
/* Flag indicating that the host should wait for a firmware-ready response */
|
||||
#define WAIT_FW_READY BIT(1)
|
||||
/* Flag indicating that the host should wait for a firmware-confirmation response */
|
||||
#define WAIT_FW_CONFIRMATION BIT(1)
|
||||
#define REMOTE_READY_WAIT_MAX_RETRIES 500
|
||||
|
||||
/*
|
||||
* This flag is set in the DSP resource table's features field to indicate
|
||||
* that the firmware requires the host NOT to wait for a FW_READY response.
|
||||
* that the firmware requires the host NOT to wait for a FW_CONFIRMATION response.
|
||||
*/
|
||||
#define FEATURE_DONT_WAIT_FW_READY BIT(0)
|
||||
#define FEATURE_SKIP_FW_CONFIRMATION BIT(0)
|
||||
|
||||
/* att flags */
|
||||
/* DSP own area */
|
||||
@@ -287,7 +287,7 @@ static int imx_dsp_rproc_ready(struct rproc *rproc)
|
||||
* @avail: available space in the resource table
|
||||
*
|
||||
* Parse the DSP-specific resource entry and update flags accordingly.
|
||||
* If the WAIT_FW_READY feature is set, the host must wait for the firmware
|
||||
* If the WAIT_FW_CONFIRMATION feature is set, the host must wait for the firmware
|
||||
* to signal readiness before proceeding with execution.
|
||||
*
|
||||
* Return: RSC_HANDLED if processed successfully, RSC_IGNORED otherwise.
|
||||
@@ -322,7 +322,7 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type,
|
||||
|
||||
/*
|
||||
* For now, in struct fw_rsc_imx_dsp, version 0,
|
||||
* only FEATURE_DONT_WAIT_FW_READY is valid.
|
||||
* only FEATURE_SKIP_FW_CONFIRMATION is valid.
|
||||
*
|
||||
* When adding new features, please upgrade version.
|
||||
*/
|
||||
@@ -332,8 +332,8 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type,
|
||||
return RSC_IGNORED;
|
||||
}
|
||||
|
||||
if (imx_dsp_rsc->features & FEATURE_DONT_WAIT_FW_READY)
|
||||
priv->flags &= ~WAIT_FW_READY;
|
||||
if (imx_dsp_rsc->features & FEATURE_SKIP_FW_CONFIRMATION)
|
||||
priv->flags &= ~WAIT_FW_CONFIRMATION;
|
||||
|
||||
return RSC_HANDLED;
|
||||
}
|
||||
@@ -385,7 +385,7 @@ static int imx_dsp_rproc_start(struct rproc *rproc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->flags & WAIT_FW_READY)
|
||||
if (priv->flags & WAIT_FW_CONFIRMATION)
|
||||
return imx_dsp_rproc_ready(rproc);
|
||||
|
||||
return 0;
|
||||
@@ -644,6 +644,32 @@ 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
|
||||
@@ -659,7 +685,6 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
|
||||
struct device *dev = rproc->dev.parent;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct rproc_mem_entry *mem;
|
||||
void __iomem *cpu_addr;
|
||||
int a, i = 0;
|
||||
u64 da;
|
||||
|
||||
@@ -673,15 +698,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
|
||||
if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da))
|
||||
return -EINVAL;
|
||||
|
||||
cpu_addr = devm_ioremap_wc(dev, att->sa, att->size);
|
||||
if (!cpu_addr) {
|
||||
dev_err(dev, "failed to map memory %p\n", &att->sa);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Register memory region */
|
||||
mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa,
|
||||
att->size, da, NULL, NULL, "dsp_mem");
|
||||
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");
|
||||
|
||||
if (mem)
|
||||
rproc_coredump_add_segment(rproc, da, att->size);
|
||||
@@ -709,15 +729,11 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
|
||||
if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da))
|
||||
return -EINVAL;
|
||||
|
||||
cpu_addr = devm_ioremap_resource_wc(dev, &res);
|
||||
if (IS_ERR(cpu_addr)) {
|
||||
dev_err(dev, "failed to map memory %pR\n", &res);
|
||||
return PTR_ERR(cpu_addr);
|
||||
}
|
||||
|
||||
/* Register memory region */
|
||||
mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)res.start,
|
||||
resource_size(&res), da, NULL, NULL,
|
||||
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,
|
||||
"%.*s", strchrnul(res.name, '@') - res.name, res.name);
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
@@ -984,9 +1000,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw)
|
||||
* Clear buffers after pm rumtime for internal ocram is not
|
||||
* accessible if power and clock are not enabled.
|
||||
*/
|
||||
list_for_each_entry(carveout, &rproc->carveouts, node) {
|
||||
if (carveout->va)
|
||||
memset(carveout->va, 0, carveout->len);
|
||||
if (rproc->state == RPROC_OFFLINE) {
|
||||
list_for_each_entry(carveout, &rproc->carveouts, node) {
|
||||
if (carveout->va)
|
||||
memset(carveout->va, 0, carveout->len);
|
||||
}
|
||||
}
|
||||
|
||||
ret = imx_dsp_rproc_elf_load_segments(rproc, fw);
|
||||
@@ -1131,8 +1149,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
|
||||
priv = rproc->priv;
|
||||
priv->rproc = rproc;
|
||||
priv->dsp_dcfg = dsp_dcfg;
|
||||
/* By default, host waits for fw_ready reply */
|
||||
priv->flags |= WAIT_FW_READY;
|
||||
/* By default, host waits for fw_confirmation reply */
|
||||
priv->flags |= WAIT_FW_CONFIRMATION;
|
||||
|
||||
if (no_mailboxes)
|
||||
imx_dsp_rproc_mbox_init = imx_dsp_rproc_mbox_no_alloc;
|
||||
@@ -1242,6 +1260,21 @@ static int imx_dsp_suspend(struct device *dev)
|
||||
if (rproc->state != RPROC_RUNNING)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* No channel available for sending messages;
|
||||
* indicates no mailboxes present, so trigger PM runtime suspend
|
||||
*/
|
||||
if (!priv->tx_ch) {
|
||||
dev_dbg(dev, "No initialized mbox tx channel, suspend directly.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* No fw confirmation expected, so trigger PM runtime suspend */
|
||||
if (!(priv->flags & WAIT_FW_CONFIRMATION)) {
|
||||
dev_dbg(dev, "No FW_CONFIRMATION needed, suspend directly.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
reinit_completion(&priv->pm_comp);
|
||||
|
||||
/* Tell DSP that suspend is happening */
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/firmware/imx/sci.h>
|
||||
#include <linux/firmware/imx/sm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/scmi_imx_protocol.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "imx_rproc.h"
|
||||
@@ -92,9 +94,16 @@ struct imx_rproc_mem {
|
||||
#define ATT_CORE_MASK 0xffff
|
||||
#define ATT_CORE(I) BIT((I))
|
||||
|
||||
/* Linux has permission to handle the Logical Machine of remote cores */
|
||||
#define IMX_RPROC_FLAGS_SM_LMM_CTRL BIT(0)
|
||||
|
||||
static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block);
|
||||
static void imx_rproc_free_mbox(void *data);
|
||||
|
||||
/* Forward declarations for platform operations */
|
||||
static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm;
|
||||
static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu;
|
||||
|
||||
struct imx_rproc {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
@@ -116,6 +125,24 @@ struct imx_rproc {
|
||||
u32 entry; /* cpu start address */
|
||||
u32 core_index;
|
||||
struct dev_pm_domain_list *pd_list;
|
||||
const struct imx_rproc_plat_ops *ops;
|
||||
/*
|
||||
* For i.MX System Manager based systems
|
||||
* BIT 0: IMX_RPROC_FLAGS_SM_LMM_CTRL(RPROC LM is under Linux control )
|
||||
*/
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = {
|
||||
/* 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, 0x50000000, 0 },
|
||||
};
|
||||
|
||||
static const struct imx_rproc_att imx_rproc_att_imx93[] = {
|
||||
@@ -312,10 +339,51 @@ 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 int imx_rproc_start(struct rproc *rproc)
|
||||
static int imx_rproc_sm_cpu_start(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
||||
int ret;
|
||||
|
||||
ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return scmi_imx_cpu_start(dcfg->cpuid, true);
|
||||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n",
|
||||
dcfg->lmid, dcfg->cpuid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_BOOT, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to boot lmm(%d): %d\n", dcfg->lmid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_start(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
struct device *dev = priv->dev;
|
||||
int ret;
|
||||
|
||||
@@ -323,10 +391,10 @@ static int imx_rproc_start(struct rproc *rproc)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!dcfg->ops || !dcfg->ops->start)
|
||||
if (!priv->ops || !priv->ops->start)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = dcfg->ops->start(rproc);
|
||||
ret = priv->ops->start(rproc);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to enable remote core!\n");
|
||||
|
||||
@@ -369,17 +437,35 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc)
|
||||
return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry);
|
||||
}
|
||||
|
||||
static int imx_rproc_stop(struct rproc *rproc)
|
||||
static int imx_rproc_sm_cpu_stop(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
||||
|
||||
return scmi_imx_cpu_start(dcfg->cpuid, false);
|
||||
}
|
||||
|
||||
static int imx_rproc_sm_lmm_stop(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
||||
|
||||
if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_CTRL))
|
||||
return -EACCES;
|
||||
|
||||
return scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
|
||||
}
|
||||
|
||||
static int imx_rproc_stop(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
struct device *dev = priv->dev;
|
||||
int ret;
|
||||
|
||||
if (!dcfg->ops || !dcfg->ops->stop)
|
||||
if (!priv->ops || !priv->ops->stop)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = dcfg->ops->stop(rproc);
|
||||
ret = priv->ops->stop(rproc);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to stop remote core\n");
|
||||
else
|
||||
@@ -486,6 +572,36 @@ static int imx_rproc_mem_release(struct rproc *rproc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_sm_lmm_prepare(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* IMX_RPROC_FLAGS_SM_LMM_CTRL not set indicates Linux is not able
|
||||
* to start/stop M7, then if rproc is not in detached state,
|
||||
* prepare should fail. If in detached state, this is in rproc_attach()
|
||||
* path.
|
||||
*/
|
||||
if (rproc->state == RPROC_DETACHED)
|
||||
return 0;
|
||||
|
||||
if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_CTRL))
|
||||
return -EACCES;
|
||||
|
||||
/* Power on the Logical Machine to make sure TCM is available. */
|
||||
ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Failed to power on lmm(%d): %d\n", dcfg->lmid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(priv->dev, "lmm(%d) powered on by Linux\n", dcfg->lmid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_prepare(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
@@ -528,6 +644,11 @@ static int imx_rproc_prepare(struct rproc *rproc)
|
||||
rproc_coredump_add_segment(rproc, da, resource_size(&res));
|
||||
rproc_add_carveout(rproc, mem);
|
||||
}
|
||||
|
||||
if (priv->ops && priv->ops->prepare)
|
||||
return priv->ops->prepare(rproc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
@@ -584,12 +705,11 @@ static int imx_rproc_scu_api_detach(struct rproc *rproc)
|
||||
static int imx_rproc_detach(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
||||
|
||||
if (!dcfg->ops || !dcfg->ops->detach)
|
||||
if (!priv->ops || !priv->ops->detach)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return dcfg->ops->detach(rproc);
|
||||
return priv->ops->detach(rproc);
|
||||
}
|
||||
|
||||
static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
|
||||
@@ -609,6 +729,10 @@ imx_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
|
||||
/* No resource table in the firmware */
|
||||
if (!rproc->table_ptr)
|
||||
return NULL;
|
||||
|
||||
if (priv->rsc_table)
|
||||
return (struct resource_table *)priv->rsc_table;
|
||||
|
||||
@@ -694,7 +818,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
|
||||
}
|
||||
priv->mem[b].sys_addr = res.start;
|
||||
priv->mem[b].size = resource_size(&res);
|
||||
if (!strcmp(res.name, "rsc-table"))
|
||||
if (strstarts(res.name, "rsc-table"))
|
||||
priv->rsc_table = priv->mem[b].cpu_addr;
|
||||
b++;
|
||||
}
|
||||
@@ -977,20 +1101,97 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_detect_mode(struct imx_rproc *priv)
|
||||
/* Check whether remoteproc core is responsible for M7 lifecycle */
|
||||
static int imx_rproc_sm_lmm_check(struct rproc *rproc, bool started)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
||||
struct device *dev = priv->dev;
|
||||
int ret;
|
||||
|
||||
ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
|
||||
if (ret) {
|
||||
if (ret == -EACCES) {
|
||||
/*
|
||||
* M7 is booted before Linux and not under Linux Control, so only
|
||||
* do IPC between RPROC and Linux, not return failure
|
||||
*/
|
||||
dev_info(dev, "lmm(%d) not under Linux Control\n", dcfg->lmid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(dev, "power on lmm(%d) failed: %d\n", dcfg->lmid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Shutdown remote processor if not started */
|
||||
if (!started) {
|
||||
ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "shutdown lmm(%d) failed: %d\n", dcfg->lmid, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
priv->flags |= IMX_RPROC_FLAGS_SM_LMM_CTRL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_sm_detect_mode(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
||||
struct device *dev = priv->dev;
|
||||
struct scmi_imx_lmm_info info;
|
||||
bool started = false;
|
||||
int ret;
|
||||
|
||||
ret = scmi_imx_cpu_started(dcfg->cpuid, &started);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to detect cpu(%d) status: %d\n", dcfg->cpuid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (started)
|
||||
priv->rproc->state = RPROC_DETACHED;
|
||||
|
||||
/* Get current Linux Logical Machine ID */
|
||||
ret = scmi_imx_lmm_info(LMM_ID_DISCOVER, &info);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get current LMM ID err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* To i.MX{7,8} ULP, Linux is under control of RTOS, no need
|
||||
* dcfg->ops or dcfg->ops->detect_mode, it is state RPROC_DETACHED.
|
||||
* Check whether M7 is in the same LM as host core(running Linux)
|
||||
* If yes, use CPU protocol API to manage M7.
|
||||
* If no, use Logical Machine API to manage M7.
|
||||
*/
|
||||
if (!dcfg->ops || !dcfg->ops->detect_mode) {
|
||||
if (dcfg->lmid == info.lmid) {
|
||||
priv->ops = &imx_rproc_ops_sm_cpu;
|
||||
dev_info(dev, "Using CPU Protocol OPS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv->ops = &imx_rproc_ops_sm_lmm;
|
||||
dev_info(dev, "Using LMM Protocol OPS\n");
|
||||
|
||||
return imx_rproc_sm_lmm_check(rproc, started);
|
||||
}
|
||||
|
||||
static int imx_rproc_detect_mode(struct imx_rproc *priv)
|
||||
{
|
||||
/*
|
||||
* To i.MX{7,8} ULP, Linux is under control of RTOS, no need
|
||||
* priv->ops or priv->ops->detect_mode, it is state RPROC_DETACHED.
|
||||
*/
|
||||
if (!priv->ops || !priv->ops->detect_mode) {
|
||||
priv->rproc->state = RPROC_DETACHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dcfg->ops->detect_mode(priv->rproc);
|
||||
return priv->ops->detect_mode(priv->rproc);
|
||||
}
|
||||
|
||||
static int imx_rproc_sys_off_handler(struct sys_off_data *data)
|
||||
@@ -1040,6 +1241,9 @@ static int imx_rproc_probe(struct platform_device *pdev)
|
||||
priv->dcfg = dcfg;
|
||||
priv->dev = dev;
|
||||
|
||||
if (dcfg->ops)
|
||||
priv->ops = dcfg->ops;
|
||||
|
||||
dev_set_drvdata(dev, rproc);
|
||||
priv->workqueue = create_workqueue(dev_name(dev));
|
||||
if (!priv->workqueue) {
|
||||
@@ -1151,6 +1355,19 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = {
|
||||
.detect_mode = imx_rproc_scu_api_detect_mode,
|
||||
};
|
||||
|
||||
static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm = {
|
||||
.detect_mode = imx_rproc_sm_detect_mode,
|
||||
.prepare = imx_rproc_sm_lmm_prepare,
|
||||
.start = imx_rproc_sm_lmm_start,
|
||||
.stop = imx_rproc_sm_lmm_stop,
|
||||
};
|
||||
|
||||
static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu = {
|
||||
.detect_mode = imx_rproc_sm_detect_mode,
|
||||
.start = imx_rproc_sm_cpu_start,
|
||||
.stop = imx_rproc_sm_cpu_stop,
|
||||
};
|
||||
|
||||
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = {
|
||||
.src_reg = IMX7D_SRC_SCR,
|
||||
.src_mask = IMX7D_M4_RST_MASK,
|
||||
@@ -1234,6 +1451,15 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
|
||||
.flags = IMX_RPROC_NEED_CLKS,
|
||||
};
|
||||
|
||||
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),
|
||||
.ops = &imx_rproc_ops_sm_lmm,
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
static const struct of_device_id imx_rproc_of_match[] = {
|
||||
{ .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp },
|
||||
{ .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d },
|
||||
@@ -1248,6 +1474,7 @@ 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,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
|
||||
|
||||
@@ -24,6 +24,7 @@ struct imx_rproc_plat_ops {
|
||||
int (*stop)(struct rproc *rproc);
|
||||
int (*detach)(struct rproc *rproc);
|
||||
int (*detect_mode)(struct rproc *rproc);
|
||||
int (*prepare)(struct rproc *rproc);
|
||||
};
|
||||
|
||||
struct imx_rproc_dcfg {
|
||||
@@ -37,6 +38,9 @@ struct imx_rproc_dcfg {
|
||||
size_t att_size;
|
||||
u32 flags;
|
||||
const struct imx_rproc_plat_ops *ops;
|
||||
/* For System Manager(SM) based SoCs */
|
||||
u32 cpuid; /* ID of the remote core */
|
||||
u32 lmid; /* ID of the Logcial Machine */
|
||||
};
|
||||
|
||||
#endif /* _IMX_RPROC_H */
|
||||
|
||||
@@ -283,7 +283,7 @@ static irqreturn_t scp_irq_handler(int irq, void *priv)
|
||||
struct mtk_scp *scp = priv;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(scp->clk);
|
||||
ret = clk_enable(scp->clk);
|
||||
if (ret) {
|
||||
dev_err(scp->dev, "failed to enable clocks\n");
|
||||
return IRQ_NONE;
|
||||
@@ -291,7 +291,7 @@ static irqreturn_t scp_irq_handler(int irq, void *priv)
|
||||
|
||||
scp->data->scp_irq_handler(scp);
|
||||
|
||||
clk_disable_unprepare(scp->clk);
|
||||
clk_disable(scp->clk);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -665,7 +665,7 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw)
|
||||
struct device *dev = scp->dev;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(scp->clk);
|
||||
ret = clk_enable(scp->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clocks\n");
|
||||
return ret;
|
||||
@@ -680,7 +680,7 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw)
|
||||
|
||||
ret = scp_elf_load_segments(rproc, fw);
|
||||
leave:
|
||||
clk_disable_unprepare(scp->clk);
|
||||
clk_disable(scp->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -691,14 +691,14 @@ static int scp_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
struct device *dev = scp->dev;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(scp->clk);
|
||||
ret = clk_enable(scp->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scp_ipi_init(scp, fw);
|
||||
clk_disable_unprepare(scp->clk);
|
||||
clk_disable(scp->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -709,7 +709,7 @@ static int scp_start(struct rproc *rproc)
|
||||
struct scp_run *run = &scp->run;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(scp->clk);
|
||||
ret = clk_enable(scp->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clocks\n");
|
||||
return ret;
|
||||
@@ -734,14 +734,14 @@ static int scp_start(struct rproc *rproc)
|
||||
goto stop;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(scp->clk);
|
||||
clk_disable(scp->clk);
|
||||
dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver);
|
||||
|
||||
return 0;
|
||||
|
||||
stop:
|
||||
scp->data->scp_reset_assert(scp);
|
||||
clk_disable_unprepare(scp->clk);
|
||||
clk_disable(scp->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -909,7 +909,7 @@ static int scp_stop(struct rproc *rproc)
|
||||
struct mtk_scp *scp = rproc->priv;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(scp->clk);
|
||||
ret = clk_enable(scp->clk);
|
||||
if (ret) {
|
||||
dev_err(scp->dev, "failed to enable clocks\n");
|
||||
return ret;
|
||||
@@ -917,12 +917,29 @@ static int scp_stop(struct rproc *rproc)
|
||||
|
||||
scp->data->scp_reset_assert(scp);
|
||||
scp->data->scp_stop(scp);
|
||||
clk_disable_unprepare(scp->clk);
|
||||
clk_disable(scp->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scp_prepare(struct rproc *rproc)
|
||||
{
|
||||
struct mtk_scp *scp = rproc->priv;
|
||||
|
||||
return clk_prepare(scp->clk);
|
||||
}
|
||||
|
||||
static int scp_unprepare(struct rproc *rproc)
|
||||
{
|
||||
struct mtk_scp *scp = rproc->priv;
|
||||
|
||||
clk_unprepare(scp->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rproc_ops scp_ops = {
|
||||
.prepare = scp_prepare,
|
||||
.unprepare = scp_unprepare,
|
||||
.start = scp_start,
|
||||
.stop = scp_stop,
|
||||
.load = scp_load,
|
||||
@@ -1287,7 +1304,6 @@ static int scp_add_multi_core(struct platform_device *pdev,
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev_of_node(dev);
|
||||
struct platform_device *cpdev;
|
||||
struct device_node *child;
|
||||
struct list_head *scp_list = &scp_cluster->mtk_scp_list;
|
||||
const struct mtk_scp_of_data **cluster_of_data;
|
||||
struct mtk_scp *scp, *temp;
|
||||
@@ -1296,11 +1312,10 @@ static int scp_add_multi_core(struct platform_device *pdev,
|
||||
|
||||
cluster_of_data = (const struct mtk_scp_of_data **)of_device_get_match_data(dev);
|
||||
|
||||
for_each_available_child_of_node(np, child) {
|
||||
for_each_available_child_of_node_scoped(np, child) {
|
||||
if (!cluster_of_data[core_id]) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "Not support core %d\n", core_id);
|
||||
of_node_put(child);
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
@@ -1308,7 +1323,6 @@ static int scp_add_multi_core(struct platform_device *pdev,
|
||||
if (!cpdev) {
|
||||
ret = -ENODEV;
|
||||
dev_err(dev, "Not found platform device for core %d\n", core_id);
|
||||
of_node_put(child);
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
@@ -1317,14 +1331,12 @@ static int scp_add_multi_core(struct platform_device *pdev,
|
||||
if (IS_ERR(scp)) {
|
||||
ret = PTR_ERR(scp);
|
||||
dev_err(dev, "Failed to initialize core %d rproc\n", core_id);
|
||||
of_node_put(child);
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
ret = rproc_add(scp->rproc);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add rproc of core %d\n", core_id);
|
||||
of_node_put(child);
|
||||
scp_free(scp);
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
|
||||
WARN_ON(len > scp_sizes->ipi_share_buffer_size) || WARN_ON(!buf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = clk_prepare_enable(scp->clk);
|
||||
ret = clk_enable(scp->clk);
|
||||
if (ret) {
|
||||
dev_err(scp->dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
@@ -211,7 +211,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
|
||||
|
||||
unlock_mutex:
|
||||
mutex_unlock(&scp->send_lock);
|
||||
clk_disable_unprepare(scp->clk);
|
||||
clk_disable(scp->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1271,7 +1271,6 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
|
||||
struct zynqmp_r5_core **r5_cores;
|
||||
enum rpu_oper_mode fw_reg_val;
|
||||
struct device **child_devs;
|
||||
struct device_node *child;
|
||||
enum rpu_tcm_comb tcm_mode;
|
||||
int core_count, ret, i;
|
||||
struct mbox_info *ipi;
|
||||
@@ -1350,10 +1349,9 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_available_child_of_node(dev_node, child) {
|
||||
for_each_available_child_of_node_scoped(dev_node, child) {
|
||||
child_pdev = of_find_device_by_node(child);
|
||||
if (!child_pdev) {
|
||||
of_node_put(child);
|
||||
ret = -ENODEV;
|
||||
goto release_r5_cores;
|
||||
}
|
||||
@@ -1363,7 +1361,6 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
|
||||
/* create and add remoteproc instance of type struct rproc */
|
||||
r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev);
|
||||
if (IS_ERR(r5_cores[i])) {
|
||||
of_node_put(child);
|
||||
ret = PTR_ERR(r5_cores[i]);
|
||||
r5_cores[i] = NULL;
|
||||
goto release_r5_cores;
|
||||
@@ -1383,10 +1380,8 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster)
|
||||
* If two child nodes are available in dts in lockstep mode,
|
||||
* then ignore second child node.
|
||||
*/
|
||||
if (cluster_mode == LOCKSTEP_MODE) {
|
||||
of_node_put(child);
|
||||
if (cluster_mode == LOCKSTEP_MODE)
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user