Commit b8dd631f authored by Linus Torvalds's avatar Linus Torvalds

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

Pull remoteproc updates from Bjorn Andersson:
 "Support for controlling the second core in Mediatek's SCP dual-core
  setup is introduced.

  Support for audio, compute and modem DSPs on Qualcomm SM6375, and the
  audio DSP in SC7180 are introduced. The peripheral NoC clock is
  dropped from MSM8996 modem DSP, as this is handled through the
  interconnect provider.

  In the zynqmp driver the setup for TCM memory, and device address
  translation thereof, when operating in lockstep mode is corrected.

  A few bug fixes and cleanups are introduces across the ST and STM32
  remoteproc drivers"

* tag 'rproc-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: (28 commits)
  remoteproc: st: Fix sometimes uninitialized ret in st_rproc_probe()
  remoteproc: st: Use device_get_match_data()
  remoteproc: zynqmp: Change tcm address translation method
  remoteproc: mediatek: Refactor single core check and fix retrocompatibility
  remoteproc: qcom: q6v5-mss: Remove PNoC clock from 8996 MSS
  dt-bindings: remoteproc: qcom,msm8996-mss-pil: Remove PNoC clock
  dt-bindings: remoteproc: qcom,adsp: Remove AGGRE2 clock
  remoteproc: qcom: pas: Add SM6375 MPSS
  remoteproc: qcom: pas: Add SM6375 ADSP & CDSP
  dt-bindings: remoteproc: qcom,sm6375-pas: Document remoteprocs
  dt-bindings: remoteproc: pru: Add Interrupt property
  remoteproc: qcom: pas: Add sc7180 adsp
  dt-bindings: remoteproc: qcom: sc7180-pas: Add ADSP compatible
  arm64: dts: mediatek: Update the node name of SCP rpmsg subnode
  remoteproc: zynqmp: fix TCM carveouts in lockstep mode
  remoteproc: mediatek: Refine ipi handler error message
  remoteproc: mediatek: Report watchdog crash to all cores
  remoteproc: mediatek: Handle MT8195 SCP core 1 watchdog timeout
  remoteproc: mediatek: Setup MT8195 SCP core 1 SRAM offset
  remoteproc: mediatek: Remove dependency of MT8195 SCP L2TCM power control on dual-core SCP
  ...
parents c87271ee 3d8a1869
......@@ -21,6 +21,7 @@ properties:
- mediatek,mt8188-scp
- mediatek,mt8192-scp
- mediatek,mt8195-scp
- mediatek,mt8195-scp-dual
reg:
description:
......@@ -31,10 +32,7 @@ properties:
reg-names:
minItems: 2
items:
- const: sram
- const: cfg
- const: l1tcm
maxItems: 3
clocks:
description:
......@@ -58,6 +56,93 @@ properties:
memory-region:
maxItems: 1
cros-ec-rpmsg:
$ref: /schemas/mfd/google,cros-ec.yaml
description:
This subnode represents the rpmsg device. The properties
of this node are defined by the individual bindings for
the rpmsg devices.
required:
- mediatek,rpmsg-name
unevaluatedProperties: false
'#address-cells':
const: 1
'#size-cells':
const: 1
ranges:
description:
Standard ranges definition providing address translations for
local SCP SRAM address spaces to bus addresses.
patternProperties:
"^scp@[a-f0-9]+$":
type: object
description:
The MediaTek SCP integrated to SoC might be a multi-core version.
The other cores are represented as child nodes of the boot core.
There are some integration differences for the IP like the usage of
address translator for translating SoC bus addresses into address space
for the processor.
Each SCP core has own cache memory. The SRAM and L1TCM are shared by
cores. The power of cache, SRAM and L1TCM power should be enabled
before booting SCP cores. The size of cache, SRAM, and L1TCM are varied
on differnt SoCs.
The SCP cores do not use an MMU, but has a set of registers to
control the translations between 32-bit CPU addresses into system bus
addresses. Cache and memory access settings are provided through a
Memory Protection Unit (MPU), programmable only from the SCP.
properties:
compatible:
enum:
- mediatek,scp-core
reg:
description: The base address and size of SRAM.
maxItems: 1
reg-names:
const: sram
interrupts:
maxItems: 1
firmware-name:
$ref: /schemas/types.yaml#/definitions/string
description:
If present, name (or relative path) of the file within the
firmware search path containing the firmware image used when
initializing sub cores of multi-core SCP.
memory-region:
maxItems: 1
cros-ec-rpmsg:
$ref: /schemas/mfd/google,cros-ec.yaml
description:
This subnode represents the rpmsg device. The properties
of this node are defined by the individual bindings for
the rpmsg devices.
required:
- mediatek,rpmsg-name
unevaluatedProperties: false
required:
- compatible
- reg
- reg-names
additionalProperties: false
required:
- compatible
- reg
......@@ -87,23 +172,39 @@ allOf:
reg:
maxItems: 2
reg-names:
items:
- const: sram
- const: cfg
- if:
properties:
compatible:
enum:
- mediatek,mt8192-scp
- mediatek,mt8195-scp
then:
properties:
reg:
maxItems: 3
reg-names:
items:
- const: sram
- const: cfg
- const: l1tcm
- if:
properties:
compatible:
enum:
- mediatek,mt8195-scp-dual
then:
properties:
reg:
maxItems: 2
reg-names:
items:
- const: cfg
- const: l1tcm
additionalProperties:
type: object
description:
Subnodes of the SCP represent rpmsg devices. The names of the devices
are not important. The properties of these nodes are defined by the
individual bindings for the rpmsg devices.
properties:
mediatek,rpmsg-name:
$ref: /schemas/types.yaml#/definitions/string-array
description:
Contains the name for the rpmsg device. Used to match
the subnode to rpmsg device announced by SCP.
required:
- mediatek,rpmsg-name
additionalProperties: false
examples:
- |
......@@ -118,7 +219,42 @@ examples:
clocks = <&infracfg CLK_INFRA_SCPSYS>;
clock-names = "main";
cros_ec {
cros-ec-rpmsg {
compatible = "google,cros-ec-rpmsg";
mediatek,rpmsg-name = "cros-ec-rpmsg";
};
};
- |
scp@10500000 {
compatible = "mediatek,mt8195-scp-dual";
reg = <0x10720000 0xe0000>,
<0x10700000 0x8000>;
reg-names = "cfg", "l1tcm";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x10500000 0x100000>;
scp@0 {
compatible = "mediatek,scp-core";
reg = <0x0 0xa0000>;
reg-names = "sram";
cros-ec-rpmsg {
compatible = "google,cros-ec-rpmsg";
mediatek,rpmsg-name = "cros-ec-rpmsg";
};
};
scp@a0000 {
compatible = "mediatek,scp-core";
reg = <0xa0000 0x20000>;
reg-names = "sram";
cros-ec-rpmsg {
compatible = "google,cros-ec-rpmsg";
mediatek,rpmsg-name = "cros-ec-rpmsg";
};
};
};
......@@ -66,7 +66,9 @@ allOf:
- qcom,msm8953-adsp-pil
- qcom,msm8974-adsp-pil
- qcom,msm8996-adsp-pil
- qcom,msm8996-slpi-pil
- qcom,msm8998-adsp-pas
- qcom,msm8998-slpi-pas
- qcom,sdm845-adsp-pas
- qcom,sdm845-cdsp-pas
- qcom,sdm845-slpi-pas
......@@ -79,24 +81,6 @@ allOf:
items:
- const: xo
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8996-slpi-pil
- qcom,msm8998-slpi-pas
then:
properties:
clocks:
items:
- description: XO clock
- description: AGGRE2 clock
clock-names:
items:
- const: xo
- const: aggre2
- if:
properties:
compatible:
......
......@@ -220,7 +220,6 @@ allOf:
- description: GCC MSS GPLL0 clock
- description: GCC MSS SNOC_AXI clock
- description: GCC MSS MNOC_AXI clock
- description: RPM PNOC clock
- description: RPM QDSS clock
clock-names:
items:
......@@ -231,7 +230,6 @@ allOf:
- const: gpll0_mss
- const: snoc_axi
- const: mnoc_axi
- const: pnoc
- const: qdss
glink-edge: false
required:
......
......@@ -16,6 +16,7 @@ description:
properties:
compatible:
enum:
- qcom,sc7180-adsp-pas
- qcom,sc7180-mpss-pas
- qcom,sc7280-mpss-pas
......@@ -30,26 +31,6 @@ properties:
items:
- const: xo
interrupts:
minItems: 6
interrupt-names:
minItems: 6
power-domains:
minItems: 2
items:
- description: CX power domain
- description: MX power domain
- description: MSS power domain
power-domain-names:
minItems: 2
items:
- const: cx
- const: mx
- const: mss
memory-region:
maxItems: 1
description: Reference to the reserved-memory for the Hexagon core
......@@ -71,6 +52,40 @@ required:
allOf:
- $ref: /schemas/remoteproc/qcom,pas-common.yaml#
- if:
properties:
compatible:
enum:
- qcom,sc7180-adsp-pas
then:
properties:
interrupts:
maxItems: 5
interrupt-names:
maxItems: 5
else:
properties:
interrupts:
minItems: 6
interrupt-names:
minItems: 6
- if:
properties:
compatible:
enum:
- qcom,sc7180-adsp-pas
then:
properties:
power-domains:
items:
- description: LCX power domain
- description: LMX power domain
power-domain-names:
items:
- const: lcx
- const: lmx
- if:
properties:
compatible:
......@@ -79,15 +94,31 @@ allOf:
then:
properties:
power-domains:
minItems: 3
items:
- description: CX power domain
- description: MX power domain
- description: MSS power domain
power-domain-names:
minItems: 3
else:
items:
- const: cx
- const: mx
- const: mss
- if:
properties:
compatible:
enum:
- qcom,sc7280-mpss-pas
then:
properties:
power-domains:
maxItems: 2
items:
- description: CX power domain
- description: MX power domain
power-domain-names:
maxItems: 2
items:
- const: cx
- const: mx
unevaluatedProperties: false
......
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/remoteproc/qcom,sm6375-pas.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SM6375 Peripheral Authentication Service
maintainers:
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SM6375 SoC Peripheral Authentication Service loads and boots
firmware on the Qualcomm DSP Hexagon cores.
properties:
compatible:
enum:
- qcom,sm6375-adsp-pas
- qcom,sm6375-cdsp-pas
- qcom,sm6375-mpss-pas
reg:
maxItems: 1
clocks:
items:
- description: XO clock
clock-names:
items:
- const: xo
memory-region:
maxItems: 1
description: Reference to the reserved-memory for the Hexagon core
firmware-name:
$ref: /schemas/types.yaml#/definitions/string
description: Firmware name for the Hexagon core
smd-edge: false
required:
- compatible
- reg
allOf:
- $ref: /schemas/remoteproc/qcom,pas-common.yaml#
- if:
properties:
compatible:
enum:
- qcom,sm6375-adsp-pas
- qcom,sm6375-cdsp-pas
then:
properties:
interrupts:
maxItems: 5
interrupt-names:
maxItems: 5
else:
properties:
interrupts:
minItems: 6
interrupt-names:
minItems: 6
- if:
properties:
compatible:
enum:
- qcom,sm6375-adsp-pas
then:
properties:
power-domains:
items:
- description: LCX power domain
- description: LMX power domain
power-domain-names:
items:
- const: lcx
- const: lmx
- if:
properties:
compatible:
enum:
- qcom,sm6375-cdsp-pas
- qcom,sm6375-mpss-pas
then:
properties:
power-domains:
items:
- description: CX power domain
power-domain-names:
items:
- const: cx
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmcc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mailbox/qcom-ipcc.h>
#include <dt-bindings/power/qcom-rpmpd.h>
remoteproc_adsp: remoteproc@a400000 {
compatible = "qcom,sm6375-adsp-pas";
reg = <0x0a400000 0x100>;
interrupts-extended = <&intc GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
<&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
<&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>,
<&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>,
<&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "wdog", "fatal", "ready",
"handover", "stop-ack";
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>;
clock-names = "xo";
power-domains = <&rpmpd SM6375_VDD_LPI_CX>,
<&rpmpd SM6375_VDD_LPI_MX>;
power-domain-names = "lcx", "lmx";
memory-region = <&pil_adsp_mem>;
qcom,smem-states = <&smp2p_adsp_out 0>;
qcom,smem-state-names = "stop";
glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
mboxes = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP>;
label = "lpass";
qcom,remote-pid = <2>;
/* ... */
};
};
......@@ -66,6 +66,17 @@ properties:
Should contain the name of the default firmware image
file located on the firmware search path.
interrupts:
maxItems: 1
description:
Interrupt specifiers enable the virtio/rpmsg communication between MPU
and the PRU/RTU cores. For the values of the interrupt cells please refer
to interrupt-controller/ti,pruss-intc.yaml schema.
interrupt-names:
items:
- const: vring
if:
properties:
compatible:
......@@ -171,6 +182,9 @@ examples:
<0x22400 0x100>;
reg-names = "iram", "control", "debug";
firmware-name = "am65x-pru0_0-fw";
interrupt-parent = <&icssg0_intc>;
interrupts = <16 2 2>;
interrupt-names = "vring";
};
rtu0_0: rtu@4000 {
......@@ -180,6 +194,9 @@ examples:
<0x23400 0x100>;
reg-names = "iram", "control", "debug";
firmware-name = "am65x-rtu0_0-fw";
interrupt-parent = <&icssg0_intc>;
interrupts = <20 4 4>;
interrupt-names = "vring";
};
tx_pru0_0: txpru@a000 {
......@@ -198,6 +215,9 @@ examples:
<0x24400 0x100>;
reg-names = "iram", "control", "debug";
firmware-name = "am65x-pru0_1-fw";
interrupt-parent = <&icssg0_intc>;
interrupts = <18 3 3>;
interrupt-names = "vring";
};
rtu0_1: rtu@6000 {
......@@ -207,6 +227,9 @@ examples:
<0x23c00 0x100>;
reg-names = "iram", "control", "debug";
firmware-name = "am65x-rtu0_1-fw";
interrupt-parent = <&icssg0_intc>;
interrupts = <22 5 5>;
interrupt-names = "vring";
};
tx_pru0_1: txpru@c000 {
......
......@@ -859,7 +859,7 @@ &scp {
pinctrl-names = "default";
pinctrl-0 = <&scp_pins>;
cros_ec {
cros-ec-rpmsg {
compatible = "google,cros-ec-rpmsg";
mediatek,rpmsg-name = "cros-ec-rpmsg";
};
......
......@@ -1312,7 +1312,7 @@ &scp {
pinctrl-names = "default";
pinctrl-0 = <&scp_pins>;
cros-ec {
cros-ec-rpmsg {
compatible = "google,cros-ec-rpmsg";
mediatek,rpmsg-name = "cros-ec-rpmsg";
};
......
......@@ -47,6 +47,7 @@
#define MT8192_SCP2SPM_IPC_CLR 0x4094
#define MT8192_GIPC_IN_SET 0x4098
#define MT8192_HOST_IPC_INT_BIT BIT(0)
#define MT8195_CORE1_HOST_IPC_INT_BIT BIT(4)
#define MT8192_CORE0_SW_RSTN_CLR 0x10000
#define MT8192_CORE0_SW_RSTN_SET 0x10004
......@@ -54,8 +55,28 @@
#define MT8192_CORE0_WDT_IRQ 0x10030
#define MT8192_CORE0_WDT_CFG 0x10034
#define MT8195_SYS_STATUS 0x4004
#define MT8195_CORE0_WDT BIT(16)
#define MT8195_CORE1_WDT BIT(17)
#define MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS GENMASK(7, 4)
#define MT8195_CPU1_SRAM_PD 0x1084
#define MT8195_SSHUB2APMCU_IPC_SET 0x4088
#define MT8195_SSHUB2APMCU_IPC_CLR 0x408C
#define MT8195_CORE1_SW_RSTN_CLR 0x20000
#define MT8195_CORE1_SW_RSTN_SET 0x20004
#define MT8195_CORE1_MEM_ATT_PREDEF 0x20008
#define MT8195_CORE1_WDT_IRQ 0x20030
#define MT8195_CORE1_WDT_CFG 0x20034
#define MT8195_SEC_CTRL 0x85000
#define MT8195_CORE_OFFSET_ENABLE_D BIT(13)
#define MT8195_CORE_OFFSET_ENABLE_I BIT(12)
#define MT8195_L2TCM_OFFSET_RANGE_0_LOW 0x850b0
#define MT8195_L2TCM_OFFSET_RANGE_0_HIGH 0x850b4
#define MT8195_L2TCM_OFFSET 0x850d0
#define SCP_FW_VER_LEN 32
#define SCP_SHARE_BUFFER_SIZE 288
......@@ -91,17 +112,24 @@ struct mtk_scp_of_data {
size_t ipi_buf_offset;
};
struct mtk_scp_of_cluster {
void __iomem *reg_base;
void __iomem *l1tcm_base;
size_t l1tcm_size;
phys_addr_t l1tcm_phys;
struct list_head mtk_scp_list;
/* Prevent concurrent operations of this structure and L2TCM power control. */
struct mutex cluster_lock;
u32 l2tcm_refcnt;
};
struct mtk_scp {
struct device *dev;
struct rproc *rproc;
struct clk *clk;
void __iomem *reg_base;
void __iomem *sram_base;
size_t sram_size;
phys_addr_t sram_phys;
void __iomem *l1tcm_base;
size_t l1tcm_size;
phys_addr_t l1tcm_phys;
const struct mtk_scp_of_data *data;
......@@ -119,6 +147,9 @@ struct mtk_scp {
size_t dram_size;
struct rproc_subdev *rpmsg_subdev;
struct list_head elem;
struct mtk_scp_of_cluster *cluster;
};
/**
......
......@@ -68,8 +68,14 @@ EXPORT_SYMBOL_GPL(scp_put);
static void scp_wdt_handler(struct mtk_scp *scp, u32 scp_to_host)
{
struct mtk_scp_of_cluster *scp_cluster = scp->cluster;
struct mtk_scp *scp_node;
dev_err(scp->dev, "SCP watchdog timeout! 0x%x", scp_to_host);
rproc_report_crash(scp->rproc, RPROC_WATCHDOG);
/* report watchdog timeout to all cores */
list_for_each_entry(scp_node, &scp_cluster->mtk_scp_list, elem)
rproc_report_crash(scp_node->rproc, RPROC_WATCHDOG);
}
static void scp_init_ipi_handler(void *data, unsigned int len, void *priv)
......@@ -106,7 +112,7 @@ static void scp_ipi_handler(struct mtk_scp *scp)
scp_ipi_lock(scp, id);
handler = ipi_desc[id].handler;
if (!handler) {
dev_err(scp->dev, "No such ipi id = %d\n", id);
dev_err(scp->dev, "No handler for ipi id = %d\n", id);
scp_ipi_unlock(scp, id);
return;
}
......@@ -152,35 +158,45 @@ static void mt8183_scp_reset_assert(struct mtk_scp *scp)
{
u32 val;
val = readl(scp->reg_base + MT8183_SW_RSTN);
val = readl(scp->cluster->reg_base + MT8183_SW_RSTN);
val &= ~MT8183_SW_RSTN_BIT;
writel(val, scp->reg_base + MT8183_SW_RSTN);
writel(val, scp->cluster->reg_base + MT8183_SW_RSTN);
}
static void mt8183_scp_reset_deassert(struct mtk_scp *scp)
{
u32 val;
val = readl(scp->reg_base + MT8183_SW_RSTN);
val = readl(scp->cluster->reg_base + MT8183_SW_RSTN);
val |= MT8183_SW_RSTN_BIT;
writel(val, scp->reg_base + MT8183_SW_RSTN);
writel(val, scp->cluster->reg_base + MT8183_SW_RSTN);
}
static void mt8192_scp_reset_assert(struct mtk_scp *scp)
{
writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET);
writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET);
}
static void mt8192_scp_reset_deassert(struct mtk_scp *scp)
{
writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_CLR);
writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_CLR);
}
static void mt8195_scp_c1_reset_assert(struct mtk_scp *scp)
{
writel(1, scp->cluster->reg_base + MT8195_CORE1_SW_RSTN_SET);
}
static void mt8195_scp_c1_reset_deassert(struct mtk_scp *scp)
{
writel(1, scp->cluster->reg_base + MT8195_CORE1_SW_RSTN_CLR);
}
static void mt8183_scp_irq_handler(struct mtk_scp *scp)
{
u32 scp_to_host;
scp_to_host = readl(scp->reg_base + MT8183_SCP_TO_HOST);
scp_to_host = readl(scp->cluster->reg_base + MT8183_SCP_TO_HOST);
if (scp_to_host & MT8183_SCP_IPC_INT_BIT)
scp_ipi_handler(scp);
else
......@@ -188,14 +204,14 @@ static void mt8183_scp_irq_handler(struct mtk_scp *scp)
/* SCP won't send another interrupt until we set SCP_TO_HOST to 0. */
writel(MT8183_SCP_IPC_INT_BIT | MT8183_SCP_WDT_INT_BIT,
scp->reg_base + MT8183_SCP_TO_HOST);
scp->cluster->reg_base + MT8183_SCP_TO_HOST);
}
static void mt8192_scp_irq_handler(struct mtk_scp *scp)
{
u32 scp_to_host;
scp_to_host = readl(scp->reg_base + MT8192_SCP2APMCU_IPC_SET);
scp_to_host = readl(scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_SET);
if (scp_to_host & MT8192_SCP_IPC_INT_BIT) {
scp_ipi_handler(scp);
......@@ -205,13 +221,48 @@ static void mt8192_scp_irq_handler(struct mtk_scp *scp)
* MT8192_SCP2APMCU_IPC.
*/
writel(MT8192_SCP_IPC_INT_BIT,
scp->reg_base + MT8192_SCP2APMCU_IPC_CLR);
scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_CLR);
} else {
scp_wdt_handler(scp, scp_to_host);
writel(1, scp->reg_base + MT8192_CORE0_WDT_IRQ);
writel(1, scp->cluster->reg_base + MT8192_CORE0_WDT_IRQ);
}
}
static void mt8195_scp_irq_handler(struct mtk_scp *scp)
{
u32 scp_to_host;
scp_to_host = readl(scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_SET);
if (scp_to_host & MT8192_SCP_IPC_INT_BIT) {
scp_ipi_handler(scp);
} else {
u32 reason = readl(scp->cluster->reg_base + MT8195_SYS_STATUS);
if (reason & MT8195_CORE0_WDT)
writel(1, scp->cluster->reg_base + MT8192_CORE0_WDT_IRQ);
if (reason & MT8195_CORE1_WDT)
writel(1, scp->cluster->reg_base + MT8195_CORE1_WDT_IRQ);
scp_wdt_handler(scp, reason);
}
writel(scp_to_host, scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_CLR);
}
static void mt8195_scp_c1_irq_handler(struct mtk_scp *scp)
{
u32 scp_to_host;
scp_to_host = readl(scp->cluster->reg_base + MT8195_SSHUB2APMCU_IPC_SET);
if (scp_to_host & MT8192_SCP_IPC_INT_BIT)
scp_ipi_handler(scp);
writel(scp_to_host, scp->cluster->reg_base + MT8195_SSHUB2APMCU_IPC_CLR);
}
static irqreturn_t scp_irq_handler(int irq, void *priv)
{
struct mtk_scp *scp = priv;
......@@ -341,26 +392,26 @@ static int mt8195_scp_clk_get(struct mtk_scp *scp)
static int mt8183_scp_before_load(struct mtk_scp *scp)
{
/* Clear SCP to host interrupt */
writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST);
writel(MT8183_SCP_IPC_INT_BIT, scp->cluster->reg_base + MT8183_SCP_TO_HOST);
/* Reset clocks before loading FW */
writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL);
writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_SW_SEL);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_DIV_SEL);
/* Initialize TCM before loading FW. */
writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD);
writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_L1_SRAM_PD);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD);
/* Turn on the power of SCP's SRAM before using it. */
writel(0x0, scp->reg_base + MT8183_SCP_SRAM_PDN);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_SRAM_PDN);
/*
* Set I-cache and D-cache size before loading SCP FW.
* SCP SRAM logical address may change when cache size setting differs.
*/
writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB,
scp->reg_base + MT8183_SCP_CACHE_CON);
writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON);
scp->cluster->reg_base + MT8183_SCP_CACHE_CON);
writel(MT8183_SCP_CACHESIZE_8KB, scp->cluster->reg_base + MT8183_SCP_DCACHE_CON);
return 0;
}
......@@ -386,28 +437,28 @@ static void scp_sram_power_off(void __iomem *addr, u32 reserved_mask)
static int mt8186_scp_before_load(struct mtk_scp *scp)
{
/* Clear SCP to host interrupt */
writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST);
writel(MT8183_SCP_IPC_INT_BIT, scp->cluster->reg_base + MT8183_SCP_TO_HOST);
/* Reset clocks before loading FW */
writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL);
writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_SW_SEL);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_DIV_SEL);
/* Turn on the power of SCP's SRAM before using it. Enable 1 block per time*/
scp_sram_power_on(scp->reg_base + MT8183_SCP_SRAM_PDN, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8183_SCP_SRAM_PDN, 0);
/* Initialize TCM before loading FW. */
writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD);
writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD);
writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_P1);
writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_p2);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_L1_SRAM_PD);
writel(0x0, scp->cluster->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD);
writel(0x0, scp->cluster->reg_base + MT8186_SCP_L1_SRAM_PD_P1);
writel(0x0, scp->cluster->reg_base + MT8186_SCP_L1_SRAM_PD_p2);
/*
* Set I-cache and D-cache size before loading SCP FW.
* SCP SRAM logical address may change when cache size setting differs.
*/
writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB,
scp->reg_base + MT8183_SCP_CACHE_CON);
writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON);
scp->cluster->reg_base + MT8183_SCP_CACHE_CON);
writel(MT8183_SCP_CACHESIZE_8KB, scp->cluster->reg_base + MT8183_SCP_DCACHE_CON);
return 0;
}
......@@ -415,40 +466,100 @@ static int mt8186_scp_before_load(struct mtk_scp *scp)
static int mt8192_scp_before_load(struct mtk_scp *scp)
{
/* clear SPM interrupt, SCP2SPM_IPC_CLR */
writel(0xff, scp->reg_base + MT8192_SCP2SPM_IPC_CLR);
writel(0xff, scp->cluster->reg_base + MT8192_SCP2SPM_IPC_CLR);
writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET);
writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET);
/* enable SRAM clock */
scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_on(scp->reg_base + MT8192_L1TCM_SRAM_PDN, 0);
scp_sram_power_on(scp->reg_base + MT8192_CPU0_SRAM_PD, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0);
/* enable MPU for all memory regions */
writel(0xff, scp->reg_base + MT8192_CORE0_MEM_ATT_PREDEF);
writel(0xff, scp->cluster->reg_base + MT8192_CORE0_MEM_ATT_PREDEF);
return 0;
}
static int mt8195_scp_l2tcm_on(struct mtk_scp *scp)
{
struct mtk_scp_of_cluster *scp_cluster = scp->cluster;
mutex_lock(&scp_cluster->cluster_lock);
if (scp_cluster->l2tcm_refcnt == 0) {
/* clear SPM interrupt, SCP2SPM_IPC_CLR */
writel(0xff, scp->cluster->reg_base + MT8192_SCP2SPM_IPC_CLR);
/* Power on L2TCM */
scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN,
MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS);
}
scp_cluster->l2tcm_refcnt += 1;
mutex_unlock(&scp_cluster->cluster_lock);
return 0;
}
static int mt8195_scp_before_load(struct mtk_scp *scp)
{
/* clear SPM interrupt, SCP2SPM_IPC_CLR */
writel(0xff, scp->reg_base + MT8192_SCP2SPM_IPC_CLR);
writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET);
writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET);
mt8195_scp_l2tcm_on(scp);
/* enable SRAM clock */
scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_on(scp->reg_base + MT8192_L1TCM_SRAM_PDN,
MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS);
scp_sram_power_on(scp->reg_base + MT8192_CPU0_SRAM_PD, 0);
scp_sram_power_on(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0);
/* enable MPU for all memory regions */
writel(0xff, scp->reg_base + MT8192_CORE0_MEM_ATT_PREDEF);
writel(0xff, scp->cluster->reg_base + MT8192_CORE0_MEM_ATT_PREDEF);
return 0;
}
static int mt8195_scp_c1_before_load(struct mtk_scp *scp)
{
u32 sec_ctrl;
struct mtk_scp *scp_c0;
struct mtk_scp_of_cluster *scp_cluster = scp->cluster;
scp->data->scp_reset_assert(scp);
mt8195_scp_l2tcm_on(scp);
scp_sram_power_on(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0);
/* enable MPU for all memory regions */
writel(0xff, scp->cluster->reg_base + MT8195_CORE1_MEM_ATT_PREDEF);
/*
* The L2TCM_OFFSET_RANGE and L2TCM_OFFSET shift the destination address
* on SRAM when SCP core 1 accesses SRAM.
*
* This configuration solves booting the SCP core 0 and core 1 from
* different SRAM address because core 0 and core 1 both boot from
* the head of SRAM by default. this must be configured before boot SCP core 1.
*
* The value of L2TCM_OFFSET_RANGE is from the viewpoint of SCP core 1.
* When SCP core 1 issues address within the range (L2TCM_OFFSET_RANGE),
* the address will be added with a fixed offset (L2TCM_OFFSET) on the bus.
* The shift action is tranparent to software.
*/
writel(0, scp->cluster->reg_base + MT8195_L2TCM_OFFSET_RANGE_0_LOW);
writel(scp->sram_size, scp->cluster->reg_base + MT8195_L2TCM_OFFSET_RANGE_0_HIGH);
scp_c0 = list_first_entry(&scp_cluster->mtk_scp_list, struct mtk_scp, elem);
writel(scp->sram_phys - scp_c0->sram_phys, scp->cluster->reg_base + MT8195_L2TCM_OFFSET);
/* enable SRAM offset when fetching instruction and data */
sec_ctrl = readl(scp->cluster->reg_base + MT8195_SEC_CTRL);
sec_ctrl |= MT8195_CORE_OFFSET_ENABLE_I | MT8195_CORE_OFFSET_ENABLE_D;
writel(sec_ctrl, scp->cluster->reg_base + MT8195_SEC_CTRL);
return 0;
}
......@@ -567,11 +678,11 @@ static void *mt8192_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len)
}
/* optional memory region */
if (scp->l1tcm_size &&
da >= scp->l1tcm_phys &&
(da + len) <= scp->l1tcm_phys + scp->l1tcm_size) {
offset = da - scp->l1tcm_phys;
return (void __force *)scp->l1tcm_base + offset;
if (scp->cluster->l1tcm_size &&
da >= scp->cluster->l1tcm_phys &&
(da + len) <= scp->cluster->l1tcm_phys + scp->cluster->l1tcm_size) {
offset = da - scp->cluster->l1tcm_phys;
return (void __force *)scp->cluster->l1tcm_base + offset;
}
/* optional memory region */
......@@ -595,34 +706,62 @@ static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iome
static void mt8183_scp_stop(struct mtk_scp *scp)
{
/* Disable SCP watchdog */
writel(0, scp->reg_base + MT8183_WDT_CFG);
writel(0, scp->cluster->reg_base + MT8183_WDT_CFG);
}
static void mt8192_scp_stop(struct mtk_scp *scp)
{
/* Disable SRAM clock */
scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_off(scp->reg_base + MT8192_L1TCM_SRAM_PDN, 0);
scp_sram_power_off(scp->reg_base + MT8192_CPU0_SRAM_PD, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0);
/* Disable SCP watchdog */
writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG);
writel(0, scp->cluster->reg_base + MT8192_CORE0_WDT_CFG);
}
static void mt8195_scp_l2tcm_off(struct mtk_scp *scp)
{
struct mtk_scp_of_cluster *scp_cluster = scp->cluster;
mutex_lock(&scp_cluster->cluster_lock);
if (scp_cluster->l2tcm_refcnt > 0)
scp_cluster->l2tcm_refcnt -= 1;
if (scp_cluster->l2tcm_refcnt == 0) {
/* Power off L2TCM */
scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_off(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN,
MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS);
}
mutex_unlock(&scp_cluster->cluster_lock);
}
static void mt8195_scp_stop(struct mtk_scp *scp)
{
/* Disable SRAM clock */
scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0);
scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0);
scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0);
scp_sram_power_off(scp->reg_base + MT8192_L1TCM_SRAM_PDN,
MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS);
scp_sram_power_off(scp->reg_base + MT8192_CPU0_SRAM_PD, 0);
mt8195_scp_l2tcm_off(scp);
scp_sram_power_off(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0);
/* Disable SCP watchdog */
writel(0, scp->cluster->reg_base + MT8192_CORE0_WDT_CFG);
}
static void mt8195_scp_c1_stop(struct mtk_scp *scp)
{
mt8195_scp_l2tcm_off(scp);
/* Power off CPU SRAM */
scp_sram_power_off(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0);
/* Disable SCP watchdog */
writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG);
writel(0, scp->cluster->reg_base + MT8195_CORE1_WDT_CFG);
}
static int scp_stop(struct rproc *rproc)
......@@ -811,7 +950,9 @@ static void scp_remove_rpmsg_subdev(struct mtk_scp *scp)
}
}
static int scp_probe(struct platform_device *pdev)
static struct mtk_scp *scp_rproc_init(struct platform_device *pdev,
struct mtk_scp_of_cluster *scp_cluster,
const struct mtk_scp_of_data *of_data)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
......@@ -823,52 +964,38 @@ static int scp_probe(struct platform_device *pdev)
ret = rproc_of_parse_firmware(dev, 0, &fw_name);
if (ret < 0 && ret != -EINVAL)
return ret;
return ERR_PTR(ret);
rproc = devm_rproc_alloc(dev, np->name, &scp_ops, fw_name, sizeof(*scp));
if (!rproc)
return dev_err_probe(dev, -ENOMEM, "unable to allocate remoteproc\n");
if (!rproc) {
dev_err(dev, "unable to allocate remoteproc\n");
return ERR_PTR(-ENOMEM);
}
scp = rproc->priv;
scp->rproc = rproc;
scp->dev = dev;
scp->data = of_device_get_match_data(dev);
scp->data = of_data;
scp->cluster = scp_cluster;
platform_set_drvdata(pdev, scp);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
scp->sram_base = devm_ioremap_resource(dev, res);
if (IS_ERR(scp->sram_base))
return dev_err_probe(dev, PTR_ERR(scp->sram_base),
"Failed to parse and map sram memory\n");
if (IS_ERR(scp->sram_base)) {
dev_err(dev, "Failed to parse and map sram memory\n");
return ERR_CAST(scp->sram_base);
}
scp->sram_size = resource_size(res);
scp->sram_phys = res->start;
/* l1tcm is an optional memory region */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm");
scp->l1tcm_base = devm_ioremap_resource(dev, res);
if (IS_ERR(scp->l1tcm_base)) {
ret = PTR_ERR(scp->l1tcm_base);
if (ret != -EINVAL) {
return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n");
}
} else {
scp->l1tcm_size = resource_size(res);
scp->l1tcm_phys = res->start;
}
scp->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
if (IS_ERR(scp->reg_base))
return dev_err_probe(dev, PTR_ERR(scp->reg_base),
"Failed to parse and map cfg memory\n");
ret = scp->data->scp_clk_get(scp);
if (ret)
return ret;
return ERR_PTR(ret);
ret = scp_map_memory_region(scp);
if (ret)
return ret;
return ERR_PTR(ret);
mutex_init(&scp->send_lock);
for (i = 0; i < SCP_IPI_MAX; i++)
......@@ -895,11 +1022,7 @@ static int scp_probe(struct platform_device *pdev)
goto remove_subdev;
}
ret = rproc_add(rproc);
if (ret)
goto remove_subdev;
return 0;
return scp;
remove_subdev:
scp_remove_rpmsg_subdev(scp);
......@@ -910,15 +1033,13 @@ static int scp_probe(struct platform_device *pdev)
mutex_destroy(&scp->ipi_desc[i].lock);
mutex_destroy(&scp->send_lock);
return ret;
return ERR_PTR(ret);
}
static void scp_remove(struct platform_device *pdev)
static void scp_free(struct mtk_scp *scp)
{
struct mtk_scp *scp = platform_get_drvdata(pdev);
int i;
rproc_del(scp->rproc);
scp_remove_rpmsg_subdev(scp);
scp_ipi_unregister(scp, SCP_IPI_INIT);
scp_unmap_memory_region(scp);
......@@ -927,6 +1048,186 @@ static void scp_remove(struct platform_device *pdev)
mutex_destroy(&scp->send_lock);
}
static int scp_add_single_core(struct platform_device *pdev,
struct mtk_scp_of_cluster *scp_cluster)
{
struct device *dev = &pdev->dev;
struct list_head *scp_list = &scp_cluster->mtk_scp_list;
struct mtk_scp *scp;
int ret;
scp = scp_rproc_init(pdev, scp_cluster, of_device_get_match_data(dev));
if (IS_ERR(scp))
return PTR_ERR(scp);
ret = rproc_add(scp->rproc);
if (ret) {
dev_err(dev, "Failed to add rproc\n");
scp_free(scp);
return ret;
}
list_add_tail(&scp->elem, scp_list);
return 0;
}
static int scp_add_multi_core(struct platform_device *pdev,
struct mtk_scp_of_cluster *scp_cluster)
{
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;
int core_id = 0;
int ret;
cluster_of_data = (const struct mtk_scp_of_data **)of_device_get_match_data(dev);
for_each_available_child_of_node(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;
}
cpdev = of_find_device_by_node(child);
if (!cpdev) {
ret = -ENODEV;
dev_err(dev, "Not found platform device for core %d\n", core_id);
of_node_put(child);
goto init_fail;
}
scp = scp_rproc_init(cpdev, scp_cluster, cluster_of_data[core_id]);
put_device(&cpdev->dev);
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;
}
list_add_tail(&scp->elem, scp_list);
core_id++;
}
/*
* Here we are setting the platform device for @pdev to the last @scp that was
* created, which is needed because (1) scp_rproc_init() is calling
* platform_set_drvdata() on the child platform devices and (2) we need a handle to
* the cluster list in scp_remove().
*/
platform_set_drvdata(pdev, scp);
return 0;
init_fail:
list_for_each_entry_safe_reverse(scp, temp, scp_list, elem) {
list_del(&scp->elem);
rproc_del(scp->rproc);
scp_free(scp);
}
return ret;
}
static bool scp_is_single_core(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev_of_node(dev);
struct device_node *child;
int num_cores = 0;
for_each_child_of_node(np, child)
if (of_device_is_compatible(child, "mediatek,scp-core"))
num_cores++;
return num_cores < 2;
}
static int scp_cluster_init(struct platform_device *pdev, struct mtk_scp_of_cluster *scp_cluster)
{
int ret;
if (scp_is_single_core(pdev))
ret = scp_add_single_core(pdev, scp_cluster);
else
ret = scp_add_multi_core(pdev, scp_cluster);
return ret;
}
static int scp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_scp_of_cluster *scp_cluster;
struct resource *res;
int ret;
scp_cluster = devm_kzalloc(dev, sizeof(*scp_cluster), GFP_KERNEL);
if (!scp_cluster)
return -ENOMEM;
scp_cluster->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
if (IS_ERR(scp_cluster->reg_base))
return dev_err_probe(dev, PTR_ERR(scp_cluster->reg_base),
"Failed to parse and map cfg memory\n");
/* l1tcm is an optional memory region */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm");
scp_cluster->l1tcm_base = devm_ioremap_resource(dev, res);
if (IS_ERR(scp_cluster->l1tcm_base)) {
ret = PTR_ERR(scp_cluster->l1tcm_base);
if (ret != -EINVAL)
return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n");
scp_cluster->l1tcm_base = NULL;
} else {
scp_cluster->l1tcm_size = resource_size(res);
scp_cluster->l1tcm_phys = res->start;
}
INIT_LIST_HEAD(&scp_cluster->mtk_scp_list);
mutex_init(&scp_cluster->cluster_lock);
ret = devm_of_platform_populate(dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to populate platform devices\n");
ret = scp_cluster_init(pdev, scp_cluster);
if (ret)
return ret;
return 0;
}
static void scp_remove(struct platform_device *pdev)
{
struct mtk_scp *scp = platform_get_drvdata(pdev);
struct mtk_scp_of_cluster *scp_cluster = scp->cluster;
struct mtk_scp *temp;
list_for_each_entry_safe_reverse(scp, temp, &scp_cluster->mtk_scp_list, elem) {
list_del(&scp->elem);
rproc_del(scp->rproc);
scp_free(scp);
}
mutex_destroy(&scp_cluster->cluster_lock);
}
static const struct mtk_scp_of_data mt8183_of_data = {
.scp_clk_get = mt8183_scp_clk_get,
.scp_before_load = mt8183_scp_before_load,
......@@ -980,7 +1281,7 @@ static const struct mtk_scp_of_data mt8192_of_data = {
static const struct mtk_scp_of_data mt8195_of_data = {
.scp_clk_get = mt8195_scp_clk_get,
.scp_before_load = mt8195_scp_before_load,
.scp_irq_handler = mt8192_scp_irq_handler,
.scp_irq_handler = mt8195_scp_irq_handler,
.scp_reset_assert = mt8192_scp_reset_assert,
.scp_reset_deassert = mt8192_scp_reset_deassert,
.scp_stop = mt8195_scp_stop,
......@@ -989,12 +1290,31 @@ static const struct mtk_scp_of_data mt8195_of_data = {
.host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT,
};
static const struct mtk_scp_of_data mt8195_of_data_c1 = {
.scp_clk_get = mt8195_scp_clk_get,
.scp_before_load = mt8195_scp_c1_before_load,
.scp_irq_handler = mt8195_scp_c1_irq_handler,
.scp_reset_assert = mt8195_scp_c1_reset_assert,
.scp_reset_deassert = mt8195_scp_c1_reset_deassert,
.scp_stop = mt8195_scp_c1_stop,
.scp_da_to_va = mt8192_scp_da_to_va,
.host_to_scp_reg = MT8192_GIPC_IN_SET,
.host_to_scp_int_bit = MT8195_CORE1_HOST_IPC_INT_BIT,
};
static const struct mtk_scp_of_data *mt8195_of_data_cores[] = {
&mt8195_of_data,
&mt8195_of_data_c1,
NULL
};
static const struct of_device_id mtk_scp_of_match[] = {
{ .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data },
{ .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data },
{ .compatible = "mediatek,mt8188-scp", .data = &mt8188_of_data },
{ .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data },
{ .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data },
{ .compatible = "mediatek,mt8195-scp-dual", .data = &mt8195_of_data_cores },
{},
};
MODULE_DEVICE_TABLE(of, mtk_scp_of_match);
......
......@@ -177,7 +177,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
mutex_lock(&scp->send_lock);
/* Wait until SCP receives the last command */
ret = readl_poll_timeout_atomic(scp->reg_base + scp->data->host_to_scp_reg,
ret = readl_poll_timeout_atomic(scp->cluster->reg_base + scp->data->host_to_scp_reg,
val, !val, 0, SCP_TIMEOUT_US);
if (ret) {
dev_err(scp->dev, "%s: IPI timeout!\n", __func__);
......@@ -192,7 +192,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
scp->ipi_id_ack[id] = false;
/* send the command to SCP */
writel(scp->data->host_to_scp_int_bit,
scp->reg_base + scp->data->host_to_scp_reg);
scp->cluster->reg_base + scp->data->host_to_scp_reg);
if (wait) {
/* wait for SCP's ACK */
......
......@@ -2322,7 +2322,6 @@ static const struct rproc_hexagon_res msm8996_mss = {
},
.proxy_clk_names = (char*[]){
"xo",
"pnoc",
"qdss",
NULL
},
......
......@@ -813,6 +813,21 @@ static const struct adsp_data sm6350_adsp_resource = {
.ssctl_id = 0x14,
};
static const struct adsp_data sm6375_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
.minidump_id = 3,
.auto_boot = false,
.proxy_pd_names = (char*[]){
"cx",
NULL
},
.ssr_name = "mpss",
.sysmon_name = "modem",
.ssctl_id = 0x12,
};
static const struct adsp_data sm8150_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
......@@ -1161,6 +1176,7 @@ static const struct of_device_id adsp_of_match[] = {
{ .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,sc7180-adsp-pas", .data = &sm8250_adsp_resource},
{ .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
{ .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init},
{ .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
......@@ -1180,6 +1196,9 @@ static const struct of_device_id adsp_of_match[] = {
{ .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},
......
......@@ -16,10 +16,9 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/remoteproc.h>
#include <linux/reset.h>
......@@ -341,7 +340,6 @@ static int st_rproc_parse_dt(struct platform_device *pdev)
static int st_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *match;
struct st_rproc *ddata;
struct device_node *np = dev->of_node;
struct rproc *rproc;
......@@ -349,19 +347,17 @@ static int st_rproc_probe(struct platform_device *pdev)
int enabled;
int ret, i;
match = of_match_device(st_rproc_match, dev);
if (!match || !match->data) {
dev_err(dev, "No device match found\n");
return -ENODEV;
}
rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
if (!rproc)
return -ENOMEM;
rproc->has_iommu = false;
ddata = rproc->priv;
ddata->config = (struct st_rproc_config *)match->data;
ddata->config = (struct st_rproc_config *)device_get_match_data(dev);
if (!ddata->config) {
ret = -ENODEV;
goto free_rproc;
}
platform_set_drvdata(pdev, rproc);
......
......@@ -712,9 +712,9 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
unsigned int tzen;
int err, irq;
irq = platform_get_irq(pdev, 0);
irq = platform_get_irq_optional(pdev, 0);
if (irq == -EPROBE_DEFER)
return dev_err_probe(dev, irq, "failed to get interrupt\n");
return irq;
if (irq > 0) {
err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
......
......@@ -39,12 +39,14 @@ enum zynqmp_r5_cluster_mode {
* struct mem_bank_data - Memory Bank description
*
* @addr: Start address of memory bank
* @da: device address
* @size: Size of Memory bank
* @pm_domain_id: Power-domains id of memory bank for firmware to turn on/off
* @bank_name: name of the bank for remoteproc framework
*/
struct mem_bank_data {
phys_addr_t addr;
u32 da;
size_t size;
u32 pm_domain_id;
char *bank_name;
......@@ -75,11 +77,19 @@ struct mbox_info {
* Hardcoded TCM bank values. This will be removed once TCM bindings are
* accepted for system-dt specifications and upstreamed in linux kernel
*/
static const struct mem_bank_data zynqmp_tcm_banks[] = {
{0xffe00000UL, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */
{0xffe20000UL, 0x10000UL, PD_R5_0_BTCM, "btcm0"},
{0xffe90000UL, 0x10000UL, PD_R5_1_ATCM, "atcm1"},
{0xffeb0000UL, 0x10000UL, PD_R5_1_BTCM, "btcm1"},
static const struct mem_bank_data zynqmp_tcm_banks_split[] = {
{0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */
{0xffe20000UL, 0x20000, 0x10000UL, PD_R5_0_BTCM, "btcm0"},
{0xffe90000UL, 0x0, 0x10000UL, PD_R5_1_ATCM, "atcm1"},
{0xffeb0000UL, 0x20000, 0x10000UL, PD_R5_1_BTCM, "btcm1"},
};
/* In lockstep mode cluster combines each 64KB TCM and makes 128KB TCM */
static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = {
{0xffe00000UL, 0x0, 0x20000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 128KB each */
{0xffe20000UL, 0x20000, 0x20000UL, PD_R5_0_BTCM, "btcm0"},
{0, 0, 0, PD_R5_1_ATCM, ""},
{0, 0, 0, PD_R5_1_BTCM, ""},
};
/**
......@@ -526,30 +536,6 @@ static int tcm_mem_map(struct rproc *rproc,
/* clear TCMs */
memset_io(va, 0, mem->len);
/*
* The R5s expect their TCM banks to be at address 0x0 and 0x2000,
* while on the Linux side they are at 0xffexxxxx.
*
* Zero out the high 12 bits of the address. This will give
* expected values for TCM Banks 0A and 0B (0x0 and 0x20000).
*/
mem->da &= 0x000fffff;
/*
* TCM Banks 1A and 1B still have to be translated.
*
* Below handle these two banks' absolute addresses (0xffe90000 and
* 0xffeb0000) and convert to the expected relative addresses
* (0x0 and 0x20000).
*/
if (mem->da == 0x90000 || mem->da == 0xB0000)
mem->da -= 0x90000;
/* if translated TCM bank address is not valid report error */
if (mem->da != 0x0 && mem->da != 0x20000) {
dev_err(&rproc->dev, "invalid TCM address: %x\n", mem->da);
return -EINVAL;
}
return 0;
}
......@@ -571,6 +557,7 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc)
u32 pm_domain_id;
size_t bank_size;
char *bank_name;
u32 da;
r5_core = rproc->priv;
dev = r5_core->dev;
......@@ -583,6 +570,7 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc)
*/
for (i = 0; i < num_banks; i++) {
bank_addr = r5_core->tcm_banks[i]->addr;
da = r5_core->tcm_banks[i]->da;
bank_name = r5_core->tcm_banks[i]->bank_name;
bank_size = r5_core->tcm_banks[i]->size;
pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id;
......@@ -595,11 +583,11 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc)
goto release_tcm_split;
}
dev_dbg(dev, "TCM carveout split mode %s addr=%llx, size=0x%lx",
bank_name, bank_addr, bank_size);
dev_dbg(dev, "TCM carveout split mode %s addr=%llx, da=0x%x, size=0x%lx",
bank_name, bank_addr, da, bank_size);
rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr,
bank_size, bank_addr,
bank_size, da,
tcm_mem_map, tcm_mem_unmap,
bank_name);
if (!rproc_mem) {
......@@ -640,6 +628,7 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc)
struct device *dev;
u32 pm_domain_id;
char *bank_name;
u32 da;
r5_core = rproc->priv;
dev = r5_core->dev;
......@@ -650,14 +639,11 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc)
/*
* In lockstep mode, TCM is contiguous memory block
* However, each TCM block still needs to be enabled individually.
* So, Enable each TCM block individually, but add their size
* to create contiguous memory region.
* So, Enable each TCM block individually.
* Although ATCM and BTCM is contiguous memory block, add two separate
* carveouts for both.
*/
bank_addr = r5_core->tcm_banks[0]->addr;
bank_name = r5_core->tcm_banks[0]->bank_name;
for (i = 0; i < num_banks; i++) {
bank_size += r5_core->tcm_banks[i]->size;
pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id;
/* Turn on each TCM bank individually */
......@@ -668,23 +654,32 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc)
dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id);
goto release_tcm_lockstep;
}
}
dev_dbg(dev, "TCM add carveout lockstep mode %s addr=0x%llx, size=0x%lx",
bank_name, bank_addr, bank_size);
/* Register TCM address range, TCM map and unmap functions */
rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr,
bank_size, bank_addr,
tcm_mem_map, tcm_mem_unmap,
bank_name);
if (!rproc_mem) {
ret = -ENOMEM;
goto release_tcm_lockstep;
}
bank_size = r5_core->tcm_banks[i]->size;
if (bank_size == 0)
continue;
/* If registration is success, add carveouts */
rproc_add_carveout(rproc, rproc_mem);
bank_addr = r5_core->tcm_banks[i]->addr;
da = r5_core->tcm_banks[i]->da;
bank_name = r5_core->tcm_banks[i]->bank_name;
/* Register TCM address range, TCM map and unmap functions */
rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr,
bank_size, da,
tcm_mem_map, tcm_mem_unmap,
bank_name);
if (!rproc_mem) {
ret = -ENOMEM;
zynqmp_pm_release_node(pm_domain_id);
goto release_tcm_lockstep;
}
/* If registration is success, add carveouts */
rproc_add_carveout(rproc, rproc_mem);
dev_dbg(dev, "TCM carveout lockstep mode %s addr=0x%llx, da=0x%x, size=0x%lx",
bank_name, bank_addr, da, bank_size);
}
return 0;
......@@ -895,12 +890,19 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
*/
static int zynqmp_r5_get_tcm_node(struct zynqmp_r5_cluster *cluster)
{
const struct mem_bank_data *zynqmp_tcm_banks;
struct device *dev = cluster->dev;
struct zynqmp_r5_core *r5_core;
int tcm_bank_count, tcm_node;
int i, j;
tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks);
if (cluster->mode == SPLIT_MODE) {
zynqmp_tcm_banks = zynqmp_tcm_banks_split;
tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks_split);
} else {
zynqmp_tcm_banks = zynqmp_tcm_banks_lockstep;
tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks_lockstep);
}
/* count per core tcm banks */
tcm_bank_count = tcm_bank_count / cluster->core_count;
......
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