提交 d0fe3f47 编写于 作者: L Linus Torvalds

Merge tag 'rproc-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc

Pull remoteproc updates from Bjorn Andersson:
 "This adds support for controlling the PRU and R5F clusters on the TI
  AM64x, the remote processor in i.MX7ULP, i.MX8MN/P and i.MX8ULP NXP
  and the audio, compute and modem remoteprocs in the Qualcomm SC8180x
  platform.

  It fixes improper ordering of cdev and device creation of the
  remoteproc control interface and it fixes resource leaks in the error
  handling path of rproc_add() and the Qualcomm modem and wifi
  remoteproc drivers.

  Lastly it fixes a few build warnings and replace the dummy parameter
  passed in the mailbox api of the stm32 driver to something not living
  on the stack"

* tag 'rproc-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc: (32 commits)
  remoteproc: qcom: pas: Add SC8180X adsp, cdsp and mpss
  dt-bindings: remoteproc: qcom: pas: Add SC8180X adsp, cdsp and mpss
  remoteproc: imx_rproc: support i.MX8ULP
  dt-bindings: remoteproc: imx_rproc: support i.MX8ULP
  remoteproc: stm32: fix mbox_send_message call
  remoteproc: core: Cleanup device in case of failure
  remoteproc: core: Fix cdev remove and rproc del
  remoteproc: core: Move validate before device add
  remoteproc: core: Move cdev add before device add
  remoteproc: pru: Add support for various PRU cores on K3 AM64x SoCs
  dt-bindings: remoteproc: pru: Update bindings for K3 AM64x SoCs
  remoteproc: qcom_wcnss: Use devm_qcom_smem_state_get()
  remoteproc: qcom_q6v5: Use devm_qcom_smem_state_get() to fix missing put()
  soc: qcom: smem_state: Add devm_qcom_smem_state_get()
  dt-bindings: remoteproc: qcom: pas: Fix indentation warnings
  remoteproc: imx-rproc: Fix IMX_REMOTEPROC configuration
  remoteproc: imx_rproc: support i.MX8MN/P
  remoteproc: imx_rproc: support i.MX7ULP
  remoteproc: imx_rproc: make clk optional
  remoteproc: imx_rproc: initial support for mutilple start/stop method
  ...
......@@ -17,7 +17,11 @@ properties:
enum:
- fsl,imx8mq-cm4
- fsl,imx8mm-cm4
- fsl,imx8mn-cm7
- fsl,imx8mp-cm7
- fsl,imx8ulp-cm33
- fsl,imx7d-cm4
- fsl,imx7ulp-cm4
- fsl,imx6sx-cm4
clocks:
......@@ -49,10 +53,14 @@ properties:
minItems: 1
maxItems: 32
fsl,auto-boot:
$ref: /schemas/types.yaml#/definitions/flag
description:
Indicate whether need to load the default firmware and start the remote
processor automatically.
required:
- compatible
- clocks
- syscon
additionalProperties: false
......
Qualcomm ADSP Peripheral Image Loader
This document defines the binding for a component that loads and boots firmware
on the Qualcomm ADSP Hexagon core.
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,msm8974-adsp-pil"
"qcom,msm8996-adsp-pil"
"qcom,msm8996-slpi-pil"
"qcom,msm8998-adsp-pas"
"qcom,msm8998-slpi-pas"
"qcom,qcs404-adsp-pas"
"qcom,qcs404-cdsp-pas"
"qcom,qcs404-wcss-pas"
"qcom,sc7180-mpss-pas"
"qcom,sdm845-adsp-pas"
"qcom,sdm845-cdsp-pas"
"qcom,sdx55-mpss-pas"
"qcom,sm8150-adsp-pas"
"qcom,sm8150-cdsp-pas"
"qcom,sm8150-mpss-pas"
"qcom,sm8150-slpi-pas"
"qcom,sm8250-adsp-pas"
"qcom,sm8250-cdsp-pas"
"qcom,sm8250-slpi-pas"
"qcom,sm8350-adsp-pas"
"qcom,sm8350-cdsp-pas"
"qcom,sm8350-slpi-pas"
"qcom,sm8350-mpss-pas"
- interrupts-extended:
Usage: required
Value type: <prop-encoded-array>
Definition: reference to the interrupts that match interrupt-names
- interrupt-names:
Usage: required
Value type: <stringlist>
Definition: The interrupts needed depends on the compatible
string:
qcom,msm8974-adsp-pil:
qcom,msm8996-adsp-pil:
qcom,msm8996-slpi-pil:
qcom,msm8998-adsp-pas:
qcom,msm8998-slpi-pas:
qcom,qcs404-adsp-pas:
qcom,qcs404-cdsp-pas:
qcom,sdm845-adsp-pas:
qcom,sdm845-cdsp-pas:
qcom,sm8150-adsp-pas:
qcom,sm8150-cdsp-pas:
qcom,sm8150-slpi-pas:
qcom,sm8250-adsp-pas:
qcom,sm8250-cdsp-pas:
qcom,sm8250-slpi-pas:
qcom,sm8350-adsp-pas:
qcom,sm8350-cdsp-pas:
qcom,sm8350-slpi-pas:
must be "wdog", "fatal", "ready", "handover", "stop-ack"
qcom,qcs404-wcss-pas:
qcom,sc7180-mpss-pas:
qcom,sdx55-mpss-pas:
qcom,sm8150-mpss-pas:
qcom,sm8350-mpss-pas:
must be "wdog", "fatal", "ready", "handover", "stop-ack",
"shutdown-ack"
- firmware-name:
Usage: optional
Value type: <string>
Definition: must list the relative firmware image path for the
Hexagon Core.
- clocks:
Usage: required
Value type: <prop-encoded-array>
Definition: reference to the xo clock and optionally aggre2 clock to be
held on behalf of the booting Hexagon core
- clock-names:
Usage: required
Value type: <stringlist>
Definition: must be "xo" and optionally include "aggre2"
- cx-supply:
Usage: required
Value type: <phandle>
Definition: reference to the regulator to be held on behalf of the
booting Hexagon core
- px-supply:
Usage: required
Value type: <phandle>
Definition: reference to the px regulator to be held on behalf of the
booting Hexagon core
- power-domains:
Usage: required
Value type: <phandle>
Definition: reference to power-domains that match the power-domain-names
- power-domain-names:
Usage: required
Value type: <stringlist>
Definition: The power-domains needed depend on the compatible string:
qcom,msm8974-adsp-pil:
qcom,msm8996-adsp-pil:
qcom,msm8998-adsp-pas:
must be "cx"
qcom,msm8996-slpi-pil:
must be "ss_cx"
qcom,msm8998-slpi-pas:
must be "ssc_cx"
qcom,qcs404-adsp-pas:
must be "lpi_cx"
qcom,qcs404-cdsp-pas:
qcom,qcs404-wcss-pas:
must be "mx"
qcom,sdm845-adsp-pas:
qcom,sdm845-cdsp-pas:
qcom,sm8150-adsp-pas:
qcom,sm8150-cdsp-pas:
qcom,sm8250-cdsp-pas:
qcom,sm8350-cdsp-pas:
must be "cx", "load_state"
qcom,sc7180-mpss-pas:
qcom,sm8150-mpss-pas:
qcom,sm8350-mpss-pas:
must be "cx", "load_state", "mss"
qcom,sdx55-mpss-pas:
must be "cx", "mss"
qcom,sm8250-adsp-pas:
qcom,sm8350-adsp-pas:
qcom,sm8150-slpi-pas:
qcom,sm8250-slpi-pas:
qcom,sm8350-slpi-pas:
must be "lcx", "lmx", "load_state"
- memory-region:
Usage: required
Value type: <phandle>
Definition: reference to the reserved-memory for the ADSP
- qcom,smem-states:
Usage: required
Value type: <phandle>
Definition: reference to the smem state for requesting the ADSP to
shut down
- qcom,smem-state-names:
Usage: required
Value type: <stringlist>
Definition: must be "stop"
= SUBNODES
The adsp node may have an subnode named either "smd-edge" or "glink-edge" that
describes the communication edge, channels and devices related to the ADSP.
See ../soc/qcom/qcom,smd.txt and ../soc/qcom/qcom,glink.txt for details on how
to describe these.
= EXAMPLE
The following example describes the resources needed to boot control the
ADSP, as it is found on MSM8974 boards.
adsp {
compatible = "qcom,msm8974-adsp-pil";
interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "wdog",
"fatal",
"ready",
"handover",
"stop-ack";
clocks = <&rpmcc RPM_CXO_CLK>;
clock-names = "xo";
cx-supply = <&pm8841_s2>;
memory-region = <&adsp_region>;
qcom,smem-states = <&adsp_smp2p_out 0>;
qcom,smem-state-names = "stop";
smd-edge {
interrupts = <0 156 IRQ_TYPE_EDGE_RISING>;
qcom,ipc = <&apcs 8 8>;
qcom,smd-edge = <1>;
};
};
The following example describes the resources needed to boot control the
SLPI, as it is found on MSM8996 boards.
slpi {
compatible = "qcom,msm8996-slpi-pil";
interrupts-extended = <&intc 0 390 IRQ_TYPE_EDGE_RISING>,
<&slpi_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
<&slpi_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
<&slpi_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
<&slpi_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "wdog",
"fatal",
"ready",
"handover",
"stop-ack";
clocks = <&rpmcc MSM8996_RPM_SMD_XO_CLK_SRC>,
<&rpmcc MSM8996_RPM_SMD_AGGR2_NOC_CLK>;
clock-names = "xo", "aggre2";
cx-supply = <&pm8994_l26>;
px-supply = <&pm8994_lvs2>;
memory-region = <&slpi_region>;
qcom,smem-states = <&slpi_smp2p_out 0>;
qcom,smem-state-names = "stop";
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/remoteproc/qcom,adsp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm ADSP Peripheral Image Loader binding
maintainers:
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
This document defines the binding for a component that loads and boots
firmware on the Qualcomm ADSP Hexagon core.
properties:
compatible:
enum:
- qcom,msm8974-adsp-pil
- qcom,msm8996-adsp-pil
- qcom,msm8996-slpi-pil
- qcom,msm8998-adsp-pas
- qcom,msm8998-slpi-pas
- qcom,qcs404-adsp-pas
- qcom,qcs404-cdsp-pas
- qcom,qcs404-wcss-pas
- qcom,sc7180-mpss-pas
- qcom,sc8180x-adsp-pas
- qcom,sc8180x-cdsp-pas
- qcom,sc8180x-mpss-pas
- qcom,sdm845-adsp-pas
- qcom,sdm845-cdsp-pas
- qcom,sdx55-mpss-pas
- qcom,sm8150-adsp-pas
- qcom,sm8150-cdsp-pas
- qcom,sm8150-mpss-pas
- qcom,sm8150-slpi-pas
- qcom,sm8250-adsp-pas
- qcom,sm8250-cdsp-pas
- qcom,sm8250-slpi-pas
- qcom,sm8350-adsp-pas
- qcom,sm8350-cdsp-pas
- qcom,sm8350-slpi-pas
- qcom,sm8350-mpss-pas
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 8
clock-names:
minItems: 1
maxItems: 8
interrupts:
minItems: 5
maxItems: 6
interrupt-names:
minItems: 5
maxItems: 6
resets:
minItems: 1
maxItems: 3
reset-names:
minItems: 1
maxItems: 3
cx-supply:
description: Phandle to the CX regulator
px-supply:
description: Phandle to the PX regulator
power-domains:
minItems: 1
maxItems: 3
power-domain-names:
minItems: 1
maxItems: 3
firmware-name:
$ref: /schemas/types.yaml#/definitions/string
description: Firmware name for the Hexagon core
memory-region:
maxItems: 1
description: Reference to the reserved-memory for the Hexagon core
qcom,smem-states:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: States used by the AP to signal the Hexagon core
items:
- description: Stop the modem
qcom,smem-state-names:
$ref: /schemas/types.yaml#/definitions/string-array
description: The names of the state bits used for SMP2P output
items:
- const: stop
qcom,halt-regs:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
Phandle reference to a syscon representing TCSR followed by the
three offsets within syscon for q6, modem and nc halt registers.
smd-edge:
type: object
description:
Qualcomm Shared Memory subnode which represents communication edge,
channels and devices related to the ADSP.
glink-edge:
type: object
description:
Qualcomm G-Link subnode which represents communication edge, channels
and devices related to the ADSP.
required:
- compatible
- clocks
- clock-names
- interrupts
- interrupt-names
- memory-region
- qcom,smem-states
- qcom,smem-state-names
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8974-adsp-pil
- qcom,msm8996-adsp-pil
- qcom,msm8996-slpi-pil
- qcom,msm8998-adsp-pas
- qcom,qcs404-adsp-pas
- qcom,qcs404-wcss-pas
- qcom,sc8180x-adsp-pas
- qcom,sc8180x-cdsp-pas
- qcom,sc8180x-mpss-pas
- qcom,sdm845-adsp-pas
- qcom,sdm845-cdsp-pas
- qcom,sm8150-adsp-pas
- qcom,sm8150-cdsp-pas
- qcom,sm8150-mpss-pas
- qcom,sm8150-slpi-pas
- qcom,sm8250-adsp-pas
- qcom,sm8250-cdsp-pas
- qcom,sm8250-slpi-pas
- qcom,sm8350-adsp-pas
- qcom,sm8350-cdsp-pas
- qcom,sm8350-slpi-pas
- qcom,sm8350-mpss-pas
then:
properties:
clocks:
items:
- description: XO clock
clock-names:
items:
- const: xo
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8998-slpi-pas
then:
properties:
clocks:
items:
- description: XO clock
- description: AGGRE2 clock
clock-names:
items:
- const: xo
- const: aggre2
- if:
properties:
compatible:
contains:
enum:
- qcom,qcs404-cdsp-pas
then:
properties:
clocks:
items:
- description: XO clock
- description: SWAY clock
- description: TBU clock
- description: BIMC clock
- description: AHB AON clock
- description: Q6SS SLAVE clock
- description: Q6SS MASTER clock
- description: Q6 AXIM clock
clock-names:
items:
- const: xo
- const: sway
- const: tbu
- const: bimc
- const: ahb_aon
- const: q6ss_slave
- const: q6ss_master
- const: q6_axim
- if:
properties:
compatible:
contains:
enum:
- qcom,sc7180-mpss-pas
then:
properties:
clocks:
items:
- description: XO clock
- description: IFACE clock
- description: BUS clock
- description: NAC clock
- description: SNOC AXI clock
- description: MNOC AXI clock
clock-names:
items:
- const: xo
- const: iface
- const: bus
- const: nav
- const: snoc_axi
- const: mnoc_axi
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8974-adsp-pil
- qcom,msm8996-adsp-pil
- qcom,msm8996-slpi-pil
- qcom,msm8998-adsp-pas
- qcom,msm8998-slpi-pas
- qcom,qcs404-adsp-pas
- qcom,qcs404-cdsp-pas
- qcom,qcs404-wcss-pas
- qcom,sc8180x-adsp-pas
- qcom,sc8180x-cdsp-pas
- qcom,sdm845-adsp-pas
- qcom,sdm845-cdsp-pas
- qcom,sm8150-adsp-pas
- qcom,sm8150-cdsp-pas
- qcom,sm8150-slpi-pas
- qcom,sm8250-adsp-pas
- qcom,sm8250-cdsp-pas
- qcom,sm8250-slpi-pas
- qcom,sm8350-adsp-pas
- qcom,sm8350-cdsp-pas
- qcom,sm8350-slpi-pas
then:
properties:
interrupts:
items:
- description: Watchdog interrupt
- description: Fatal interrupt
- description: Ready interrupt
- description: Handover interrupt
- description: Stop acknowledge interrupt
interrupt-names:
items:
- const: wdog
- const: fatal
- const: ready
- const: handover
- const: stop-ack
- if:
properties:
compatible:
contains:
enum:
- qcom,sc7180-mpss-pas
- qcom,sc8180x-mpss-pas
- qcom,sdx55-mpss-pas
- qcom,sm8150-mpss-pas
- qcom,sm8350-mpss-pas
then:
properties:
interrupts:
items:
- description: Watchdog interrupt
- description: Fatal interrupt
- description: Ready interrupt
- description: Handover interrupt
- description: Stop acknowledge interrupt
- description: Shutdown acknowledge interrupt
interrupt-names:
items:
- const: wdog
- const: fatal
- const: ready
- const: handover
- const: stop-ack
- const: shutdown-ack
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8974-adsp-pil
then:
required:
- cx-supply
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8996-adsp-pil
- qcom,msm8998-adsp-pas
then:
properties:
power-domains:
items:
- description: CX power domain
power-domain-names:
items:
- const: cx
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8996-slpi-pil
- qcom,msm8998-slpi-pas
then:
properties:
power-domains:
items:
- description: SSC-CX power domain
power-domain-names:
items:
- const: ssc_cx
required:
- px-supply
- if:
properties:
compatible:
contains:
enum:
- qcom,sc7180-mpss-pas
then:
properties:
power-domains:
items:
- description: Load State power domain
- description: CX power domain
- description: MX power domain
- description: MSS power domain
power-domain-names:
items:
- const: load_state
- const: cx
- const: mx
- const: mss
- if:
properties:
compatible:
contains:
enum:
- qcom,sm8150-adsp-pas
- qcom,sm8150-cdsp-pas
then:
properties:
power-domains:
items:
- description: Load State power domain
- description: CX power domain
power-domain-names:
items:
- const: load_state
- const: cx
- if:
properties:
compatible:
contains:
enum:
- qcom,sm8150-mpss-pas
- qcom,sm8350-mpss-pas
then:
properties:
power-domains:
items:
- description: Load State power domain
- description: CX power domain
- description: MSS power domain
power-domain-names:
items:
- const: load_state
- const: cx
- const: mss
- if:
properties:
compatible:
contains:
enum:
- qcom,sdx55-mpss-pas
then:
properties:
power-domains:
items:
- description: CX power domain
- description: MSS power domain
power-domain-names:
items:
- const: cx
- const: mss
- if:
properties:
compatible:
contains:
enum:
- qcom,sc8180x-adsp-pas
- qcom,sc8180x-cdsp-pas
- qcom,sm8150-slpi-pas
- qcom,sm8250-adsp-pas
- qcom,sm8250-slpi-pas
- qcom,sm8350-adsp-pas
- qcom,sm8350-slpi-pas
then:
properties:
power-domains:
items:
- description: Load State power domain
- description: LCX power domain
- description: LMX power domain
power-domain-names:
items:
- const: load_state
- const: lcx
- const: lmx
- if:
properties:
compatible:
contains:
enum:
- qcom,sm8350-cdsp-pas
then:
properties:
power-domains:
items:
- description: Load State power domain
- description: CX power domain
- description: MXC power domain
power-domain-names:
items:
- const: load_state
- const: cx
- const: mxc
- if:
properties:
compatible:
contains:
enum:
- qcom,qcs404-cdsp-pas
then:
properties:
resets:
items:
- description: CDSP restart
reset-names:
items:
- const: restart
- if:
properties:
compatible:
contains:
enum:
- qcom,sc7180-mpss-pas
then:
properties:
resets:
items:
- description: MSS restart
- description: PDC reset
reset-names:
items:
- const: mss_restart
- const: pdc_reset
examples:
- |
#include <dt-bindings/clock/qcom,rpmcc.h>
#include <dt-bindings/interrupt-controller/irq.h>
adsp {
compatible = "qcom,msm8974-adsp-pil";
interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "wdog",
"fatal",
"ready",
"handover",
"stop-ack";
clocks = <&rpmcc RPM_CXO_CLK>;
clock-names = "xo";
cx-supply = <&pm8841_s2>;
memory-region = <&adsp_region>;
qcom,smem-states = <&adsp_smp2p_out 0>;
qcom,smem-state-names = "stop";
smd-edge {
interrupts = <0 156 IRQ_TYPE_EDGE_RISING>;
qcom,ipc = <&apcs 8 8>;
qcom,smd-edge = <1>;
};
};
......@@ -14,8 +14,12 @@ description: |
processor subsystems/clusters (R5FSS). The dual core cluster can be used
either in a LockStep mode providing safety/fault tolerance features or in a
Split mode providing two individual compute cores for doubling the compute
capacity. These are used together with other processors present on the SoC
to achieve various system level goals.
capacity on most SoCs. These are used together with other processors present
on the SoC to achieve various system level goals.
AM64x SoCs do not support LockStep mode, but rather a new non-safety mode
called "Single-CPU" mode, where only Core0 is used, but with ability to use
Core1's TCMs as well.
Each Dual-Core R5F sub-system is represented as a single DTS node
representing the cluster, with a pair of child DT nodes representing
......@@ -33,6 +37,7 @@ properties:
- ti,am654-r5fss
- ti,j721e-r5fss
- ti,j7200-r5fss
- ti,am64-r5fss
power-domains:
description: |
......@@ -56,11 +61,12 @@ properties:
ti,cluster-mode:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
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),
default is LockStep mode if omitted.
Should be either a value of 1 (LockStep mode) or 0 (Split mode) on
most SoCs (AM65x, J721E, J7200), 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.
# R5F Processor Child Nodes:
# ==========================
......@@ -97,6 +103,7 @@ patternProperties:
- ti,am654-r5f
- ti,j721e-r5f
- ti,j7200-r5f
- ti,am64-r5f
reg:
items:
......@@ -198,6 +205,20 @@ 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]
required:
- compatible
- power-domains
......
......@@ -36,6 +36,9 @@ properties:
enum:
- ti,am3356-pru # for AM335x SoC family (AM3356+ SoCs only)
- ti,am4376-pru # for AM437x SoC family (AM4376+ SoCs only)
- ti,am642-pru # for PRUs in K3 AM64x SoC family
- ti,am642-rtu # for RTUs in K3 AM64x SoC family
- ti,am642-tx-pru # for Tx_PRUs in K3 AM64x SoC family
- ti,am5728-pru # for AM57xx SoC family
- ti,k2g-pru # for 66AK2G SoC family
- ti,am654-pru # for PRUs in K3 AM65x SoC family
......@@ -68,6 +71,7 @@ if:
enum:
- ti,am654-rtu
- ti,j721e-rtu
- ti,am642-rtu
then:
properties:
$nodename:
......@@ -79,6 +83,7 @@ else:
enum:
- ti,am654-tx-pru
- ti,j721e-tx-pru
- ti,am642-tx-pru
then:
properties:
$nodename:
......
......@@ -26,6 +26,7 @@ config REMOTEPROC_CDEV
config IMX_REMOTEPROC
tristate "i.MX remoteproc support"
depends on ARCH_MXC
depends on HAVE_ARM_SMCCC
select MAILBOX
help
Say y here to support iMX's remote processors via the remote
......
......@@ -3,6 +3,7 @@
* Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
*/
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/interrupt.h>
......@@ -50,6 +51,11 @@
#define IMX_RPROC_MEM_MAX 32
#define IMX_SIP_RPROC 0xC2000005
#define IMX_SIP_RPROC_START 0x00
#define IMX_SIP_RPROC_STARTED 0x01
#define IMX_SIP_RPROC_STOP 0x02
/**
* struct imx_rproc_mem - slim internal memory structure
* @cpu_addr: MPU virtual address of the memory region
......@@ -74,6 +80,15 @@ struct imx_rproc_att {
int flags;
};
/* Remote core start/stop method */
enum imx_rproc_method {
IMX_RPROC_NONE,
/* Through syscon regmap */
IMX_RPROC_MMIO,
/* Through ARM SMCCC */
IMX_RPROC_SMC,
};
struct imx_rproc_dcfg {
u32 src_reg;
u32 src_mask;
......@@ -81,6 +96,7 @@ struct imx_rproc_dcfg {
u32 src_stop;
const struct imx_rproc_att *att;
size_t att_size;
enum imx_rproc_method method;
};
struct imx_rproc {
......@@ -98,6 +114,36 @@ struct imx_rproc {
void __iomem *rsc_table;
};
static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
/* dev addr , sys addr , size , flags */
/* ITCM */
{ 0x00000000, 0x007E0000, 0x00020000, ATT_OWN },
/* OCRAM_S */
{ 0x00180000, 0x00180000, 0x00009000, 0 },
/* OCRAM */
{ 0x00900000, 0x00900000, 0x00020000, 0 },
/* OCRAM */
{ 0x00920000, 0x00920000, 0x00020000, 0 },
/* OCRAM */
{ 0x00940000, 0x00940000, 0x00050000, 0 },
/* QSPI Code - alias */
{ 0x08000000, 0x08000000, 0x08000000, 0 },
/* DDR (Code) - alias */
{ 0x10000000, 0x40000000, 0x0FFE0000, 0 },
/* DTCM */
{ 0x20000000, 0x00800000, 0x00020000, ATT_OWN },
/* OCRAM_S - alias */
{ 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
/* OCRAM */
{ 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
/* OCRAM */
{ 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
/* OCRAM */
{ 0x20240000, 0x00940000, 0x00040000, ATT_OWN },
/* DDR (Data) */
{ 0x40000000, 0x40000000, 0x80000000, 0 },
};
static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
/* dev addr , sys addr , size , flags */
/* TCML - alias */
......@@ -126,6 +172,20 @@ static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
{ 0x40000000, 0x40000000, 0x80000000, 0 },
};
static const struct imx_rproc_att imx_rproc_att_imx8ulp[] = {
{0x1FFC0000, 0x1FFC0000, 0xC0000, ATT_OWN},
{0x21000000, 0x21000000, 0x10000, ATT_OWN},
{0x80000000, 0x80000000, 0x60000000, 0}
};
static const struct imx_rproc_att imx_rproc_att_imx7ulp[] = {
{0x1FFD0000, 0x1FFD0000, 0x30000, ATT_OWN},
{0x20000000, 0x20000000, 0x10000, ATT_OWN},
{0x2F000000, 0x2F000000, 0x20000, ATT_OWN},
{0x2F020000, 0x2F020000, 0x20000, ATT_OWN},
{0x60000000, 0x60000000, 0x40000000, 0}
};
static const struct imx_rproc_att imx_rproc_att_imx7d[] = {
/* dev addr , sys addr , size , flags */
/* OCRAM_S (M4 Boot code) - alias */
......@@ -176,6 +236,12 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = {
{ 0x80000000, 0x80000000, 0x60000000, 0 },
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = {
.att = imx_rproc_att_imx8mn,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8mn),
.method = IMX_RPROC_SMC,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
.src_reg = IMX7D_SRC_SCR,
.src_mask = IMX7D_M4_RST_MASK,
......@@ -183,6 +249,19 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
.src_stop = IMX7D_M4_STOP,
.att = imx_rproc_att_imx8mq,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8mq),
.method = IMX_RPROC_MMIO,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = {
.att = imx_rproc_att_imx8ulp,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp),
.method = IMX_RPROC_NONE,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
.att = imx_rproc_att_imx7ulp,
.att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp),
.method = IMX_RPROC_NONE,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
......@@ -192,6 +271,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
.src_stop = IMX7D_M4_STOP,
.att = imx_rproc_att_imx7d,
.att_size = ARRAY_SIZE(imx_rproc_att_imx7d),
.method = IMX_RPROC_MMIO,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = {
......@@ -201,6 +281,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = {
.src_stop = IMX6SX_M4_STOP,
.att = imx_rproc_att_imx6sx,
.att_size = ARRAY_SIZE(imx_rproc_att_imx6sx),
.method = IMX_RPROC_MMIO,
};
static int imx_rproc_start(struct rproc *rproc)
......@@ -208,12 +289,24 @@ static int imx_rproc_start(struct rproc *rproc)
struct imx_rproc *priv = rproc->priv;
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
struct arm_smccc_res res;
int ret;
ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
dcfg->src_mask, dcfg->src_start);
switch (dcfg->method) {
case IMX_RPROC_MMIO:
ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask,
dcfg->src_start);
break;
case IMX_RPROC_SMC:
arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res);
ret = res.a0;
break;
default:
return -EOPNOTSUPP;
}
if (ret)
dev_err(dev, "Failed to enable M4!\n");
dev_err(dev, "Failed to enable remote core!\n");
return ret;
}
......@@ -223,12 +316,26 @@ static int imx_rproc_stop(struct rproc *rproc)
struct imx_rproc *priv = rproc->priv;
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
struct arm_smccc_res res;
int ret;
ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
dcfg->src_mask, dcfg->src_stop);
switch (dcfg->method) {
case IMX_RPROC_MMIO:
ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask,
dcfg->src_stop);
break;
case IMX_RPROC_SMC:
arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res);
ret = res.a0;
if (res.a1)
dev_info(dev, "Not in wfi, force stopped\n");
break;
default:
return -EOPNOTSUPP;
}
if (ret)
dev_err(dev, "Failed to stop M4!\n");
dev_err(dev, "Failed to stop remote core\n");
return ret;
}
......@@ -560,12 +667,37 @@ static void imx_rproc_free_mbox(struct rproc *rproc)
static int imx_rproc_detect_mode(struct imx_rproc *priv)
{
struct regmap_config config = { .name = "imx-rproc" };
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
struct regmap *regmap;
struct arm_smccc_res res;
int ret;
u32 val;
ret = regmap_read(priv->regmap, dcfg->src_reg, &val);
switch (dcfg->method) {
case IMX_RPROC_NONE:
priv->rproc->state = RPROC_DETACHED;
return 0;
case IMX_RPROC_SMC:
arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res);
if (res.a0)
priv->rproc->state = RPROC_DETACHED;
return 0;
default:
break;
}
regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
if (IS_ERR(regmap)) {
dev_err(dev, "failed to find syscon\n");
return PTR_ERR(regmap);
}
priv->regmap = regmap;
regmap_attach_dev(dev, regmap, &config);
ret = regmap_read(regmap, dcfg->src_reg, &val);
if (ret) {
dev_err(dev, "Failed to read src\n");
return ret;
......@@ -577,24 +709,44 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
return 0;
}
static int imx_rproc_clk_enable(struct imx_rproc *priv)
{
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
int ret;
/* Remote core is not under control of Linux */
if (dcfg->method == IMX_RPROC_NONE)
return 0;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "Failed to get clock\n");
return PTR_ERR(priv->clk);
}
/*
* clk for M4 block including memory. Should be
* enabled before .start for FW transfer.
*/
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(dev, "Failed to enable clock\n");
return ret;
}
return 0;
}
static int imx_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx_rproc *priv;
struct rproc *rproc;
struct regmap_config config = { .name = "imx-rproc" };
const struct imx_rproc_dcfg *dcfg;
struct regmap *regmap;
int ret;
regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(regmap)) {
dev_err(dev, "failed to find syscon\n");
return PTR_ERR(regmap);
}
regmap_attach_dev(dev, regmap, &config);
/* set some other name then imx */
rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
NULL, sizeof(*priv));
......@@ -609,7 +761,6 @@ static int imx_rproc_probe(struct platform_device *pdev)
priv = rproc->priv;
priv->rproc = rproc;
priv->regmap = regmap;
priv->dcfg = dcfg;
priv->dev = dev;
......@@ -635,25 +786,15 @@ static int imx_rproc_probe(struct platform_device *pdev)
if (ret)
goto err_put_mbox;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "Failed to get clock\n");
ret = PTR_ERR(priv->clk);
goto err_put_mbox;
}
/*
* clk for M4 block including memory. Should be
* enabled before .start for FW transfer.
*/
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(&rproc->dev, "Failed to enable clock\n");
ret = imx_rproc_clk_enable(priv);
if (ret)
goto err_put_mbox;
}
INIT_WORK(&priv->rproc_work, imx_rproc_vq_work);
if (rproc->state != RPROC_DETACHED)
rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot");
ret = rproc_add(rproc);
if (ret) {
dev_err(dev, "rproc_add failed\n");
......@@ -688,10 +829,14 @@ static int imx_rproc_remove(struct platform_device *pdev)
}
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 },
{ .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx },
{ .compatible = "fsl,imx8mq-cm4", .data = &imx_rproc_cfg_imx8mq },
{ .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq },
{ .compatible = "fsl,imx8mn-cm7", .data = &imx_rproc_cfg_imx8mn },
{ .compatible = "fsl,imx8mp-cm7", .data = &imx_rproc_cfg_imx8mn },
{ .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp },
{},
};
MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
......
......@@ -887,6 +887,9 @@ static const struct of_device_id pru_rproc_match[] = {
{ .compatible = "ti,am3356-pru", .data = &pru_data },
{ .compatible = "ti,am4376-pru", .data = &pru_data },
{ .compatible = "ti,am5728-pru", .data = &pru_data },
{ .compatible = "ti,am642-pru", .data = &k3_pru_data },
{ .compatible = "ti,am642-rtu", .data = &k3_rtu_data },
{ .compatible = "ti,am642-tx-pru", .data = &k3_tx_pru_data },
{ .compatible = "ti,k2g-pru", .data = &pru_data },
{ .compatible = "ti,am654-pru", .data = &k3_pru_data },
{ .compatible = "ti,am654-rtu", .data = &k3_rtu_data },
......
......@@ -280,7 +280,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
return ret;
}
q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
if (IS_ERR(q6v5->state)) {
dev_err(&pdev->dev, "failed to acquire stop state\n");
return PTR_ERR(q6v5->state);
......
......@@ -689,6 +689,25 @@ static const struct adsp_data mpss_resource_init = {
.ssctl_id = 0x12,
};
static const struct adsp_data sc8180x_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
.has_aggre2_clk = false,
.auto_boot = false,
.active_pd_names = (char*[]){
"load_state",
NULL
},
.proxy_pd_names = (char*[]){
"cx",
NULL
},
.ssr_name = "mpss",
.sysmon_name = "modem",
.ssctl_id = 0x12,
};
static const struct adsp_data slpi_resource_init = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
......@@ -811,6 +830,9 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
{ .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
{ .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
{ .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource},
{ .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource},
{ .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init},
{ .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init},
{ .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource},
......
......@@ -624,8 +624,8 @@ static int wcnss_probe(struct platform_device *pdev)
wcnss->stop_ack_irq = ret;
if (wcnss->stop_ack_irq) {
wcnss->state = qcom_smem_state_get(&pdev->dev, "stop",
&wcnss->stop_bit);
wcnss->state = devm_qcom_smem_state_get(&pdev->dev, "stop",
&wcnss->stop_bit);
if (IS_ERR(wcnss->state)) {
ret = PTR_ERR(wcnss->state);
goto detach_pds;
......@@ -659,7 +659,6 @@ static int wcnss_remove(struct platform_device *pdev)
of_platform_depopulate(&pdev->dev);
qcom_smem_state_put(wcnss->state);
rproc_del(wcnss->rproc);
qcom_remove_sysmon_subdev(wcnss->sysmon);
......
......@@ -124,7 +124,7 @@ int rproc_char_device_add(struct rproc *rproc)
void rproc_char_device_remove(struct rproc *rproc)
{
__unregister_chrdev(MAJOR(rproc->dev.devt), rproc->index, 1, "remoteproc");
cdev_del(&rproc->cdev);
}
void __init rproc_init_cdev(void)
......
......@@ -166,6 +166,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
* @rproc: handle of a remote processor
* @da: remoteproc device address to translate
* @len: length of the memory region @da is pointing to
* @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
*
* Some remote processors will ask us to allocate them physically contiguous
* memory regions (which we call "carveouts"), and map them to specific
......@@ -183,12 +184,12 @@ EXPORT_SYMBOL(rproc_va_to_pa);
* translations on the internal remoteproc memory regions through a platform
* implementation specific da_to_va ops, if present.
*
* The function returns a valid kernel address on success or NULL on failure.
*
* Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too,
* but only on kernel direct mapped RAM memory. Instead, we're just using
* here the output of the DMA API for the carveouts, which should be more
* correct.
*
* Return: a valid kernel address on success or NULL on failure
*/
void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{
......@@ -509,7 +510,7 @@ static int copy_dma_range_map(struct device *to, struct device *from)
* use RSC_DEVMEM resource entries to map their required @da to the physical
* address of their base CMA region (ouch, hacky!).
*
* Returns 0 on success, or an appropriate error code otherwise
* Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
int offset, int avail)
......@@ -644,7 +645,7 @@ void rproc_vdev_release(struct kref *ref)
* support dynamically allocating this address using the generic
* DMA API (but currently there isn't a use case for that).
*
* Returns 0 on success, or an appropriate error code otherwise
* Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_trace(struct rproc *rproc, void *ptr,
int offset, int avail)
......@@ -721,6 +722,8 @@ static int rproc_handle_trace(struct rproc *rproc, void *ptr,
* tell us ranges of physical addresses the firmware is allowed to request,
* and not allow firmwares to request access to physical addresses that
* are outside those ranges.
*
* Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_devmem(struct rproc *rproc, void *ptr,
int offset, int avail)
......@@ -783,6 +786,8 @@ static int rproc_handle_devmem(struct rproc *rproc, void *ptr,
*
* This function allocate specified memory entry @mem using
* dma_alloc_coherent() as default allocator
*
* Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_alloc_carveout(struct rproc *rproc,
struct rproc_mem_entry *mem)
......@@ -889,6 +894,8 @@ static int rproc_alloc_carveout(struct rproc *rproc,
*
* This function releases specified memory entry @mem allocated via
* rproc_alloc_carveout() function by @rproc.
*
* Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_release_carveout(struct rproc *rproc,
struct rproc_mem_entry *mem)
......@@ -918,6 +925,8 @@ static int rproc_release_carveout(struct rproc *rproc,
* (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
* needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
* pressure is important; it may have a substantial impact on performance.
*
* Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_carveout(struct rproc *rproc,
void *ptr, int offset, int avail)
......@@ -1006,6 +1015,8 @@ EXPORT_SYMBOL(rproc_add_carveout);
*
* This function allocates a rproc_mem_entry struct and fill it with parameters
* provided by client.
*
* Return: a valid pointer on success, or NULL on failure
*/
__printf(8, 9)
struct rproc_mem_entry *
......@@ -1050,6 +1061,8 @@ EXPORT_SYMBOL(rproc_mem_entry_init);
*
* This function allocates a rproc_mem_entry struct and fill it with parameters
* provided by client.
*
* Return: a valid pointer on success, or NULL on failure
*/
__printf(5, 6)
struct rproc_mem_entry *
......@@ -1881,6 +1894,8 @@ static int __rproc_detach(struct rproc *rproc)
* remoteproc functional again.
*
* This function can sleep, so it cannot be called from atomic context.
*
* Return: 0 on success or a negative value upon failure
*/
int rproc_trigger_recovery(struct rproc *rproc)
{
......@@ -1965,7 +1980,7 @@ static void rproc_crash_handler_work(struct work_struct *work)
* If the remote processor is already powered on, this function immediately
* returns (successfully).
*
* Returns 0 on success, and an appropriate error value otherwise.
* Return: 0 on success, and an appropriate error value otherwise
*/
int rproc_boot(struct rproc *rproc)
{
......@@ -2100,6 +2115,8 @@ EXPORT_SYMBOL(rproc_shutdown);
* no longer available. From there it should be possible to remove the
* platform driver and even power cycle the application processor (if the HW
* supports it) without needing to switch off the remote processor.
*
* Return: 0 on success, and an appropriate error value otherwise
*/
int rproc_detach(struct rproc *rproc)
{
......@@ -2152,7 +2169,7 @@ EXPORT_SYMBOL(rproc_detach);
* This function increments the remote processor's refcount, so always
* use rproc_put() to decrement it back once rproc isn't needed anymore.
*
* Returns the rproc handle on success, and NULL on failure.
* Return: rproc handle on success, and NULL on failure
*/
#ifdef CONFIG_OF
struct rproc *rproc_get_by_phandle(phandle phandle)
......@@ -2302,8 +2319,6 @@ static int rproc_validate(struct rproc *rproc)
* This is called by the platform-specific rproc implementation, whenever
* a new remote processor device is probed.
*
* Returns 0 on success and an appropriate error code otherwise.
*
* Note: this function initiates an asynchronous firmware loading
* context, which will look for virtio devices supported by the rproc's
* firmware.
......@@ -2311,35 +2326,39 @@ static int rproc_validate(struct rproc *rproc)
* If found, those virtio devices will be created and added, so as a result
* of registering this remote processor, additional virtio drivers might be
* probed.
*
* Return: 0 on success and an appropriate error code otherwise
*/
int rproc_add(struct rproc *rproc)
{
struct device *dev = &rproc->dev;
int ret;
ret = device_add(dev);
ret = rproc_validate(rproc);
if (ret < 0)
return ret;
ret = rproc_validate(rproc);
/* add char device for this remoteproc */
ret = rproc_char_device_add(rproc);
if (ret < 0)
return ret;
ret = device_add(dev);
if (ret < 0) {
put_device(dev);
goto rproc_remove_cdev;
}
dev_info(dev, "%s is available\n", rproc->name);
/* create debugfs entries */
rproc_create_debug_dir(rproc);
/* add char device for this remoteproc */
ret = rproc_char_device_add(rproc);
if (ret < 0)
return ret;
/* if rproc is marked always-on, request it to boot */
if (rproc->auto_boot) {
ret = rproc_trigger_auto_boot(rproc);
if (ret < 0)
return ret;
goto rproc_remove_dev;
}
/* expose to rproc_get_by_phandle users */
......@@ -2348,6 +2367,13 @@ int rproc_add(struct rproc *rproc)
mutex_unlock(&rproc_list_mutex);
return 0;
rproc_remove_dev:
rproc_delete_debug_dir(rproc);
device_del(dev);
rproc_remove_cdev:
rproc_char_device_remove(rproc);
return ret;
}
EXPORT_SYMBOL(rproc_add);
......@@ -2364,7 +2390,7 @@ static void devm_rproc_remove(void *rproc)
* This function performs like rproc_add() but the registered rproc device will
* automatically be removed on driver detach.
*
* Returns: 0 on success, negative errno on failure
* Return: 0 on success, negative errno on failure
*/
int devm_rproc_add(struct device *dev, struct rproc *rproc)
{
......@@ -2472,10 +2498,10 @@ static int rproc_alloc_ops(struct rproc *rproc, const struct rproc_ops *ops)
* implementations should then call rproc_add() to complete
* the registration of the remote processor.
*
* On success the new rproc is returned, and on failure, NULL.
*
* Note: _never_ directly deallocate @rproc, even if it was not registered
* yet. Instead, when you need to unroll rproc_alloc(), use rproc_free().
*
* Return: new rproc pointer on success, and NULL on failure
*/
struct rproc *rproc_alloc(struct device *dev, const char *name,
const struct rproc_ops *ops,
......@@ -2588,7 +2614,7 @@ EXPORT_SYMBOL(rproc_put);
* of the outstanding reference created by rproc_alloc. To decrement that
* one last refcount, one still needs to call rproc_free().
*
* Returns 0 on success and -EINVAL if @rproc isn't valid.
* Return: 0 on success and -EINVAL if @rproc isn't valid
*/
int rproc_del(struct rproc *rproc)
{
......@@ -2603,7 +2629,6 @@ int rproc_del(struct rproc *rproc)
mutex_unlock(&rproc->lock);
rproc_delete_debug_dir(rproc);
rproc_char_device_remove(rproc);
/* the rproc is downref'ed as soon as it's removed from the klist */
mutex_lock(&rproc_list_mutex);
......@@ -2614,6 +2639,7 @@ int rproc_del(struct rproc *rproc)
synchronize_rcu();
device_del(&rproc->dev);
rproc_char_device_remove(rproc);
return 0;
}
......@@ -2635,7 +2661,7 @@ static void devm_rproc_free(struct device *dev, void *res)
* This function performs like rproc_alloc() but the acquired rproc device will
* automatically be released on driver detach.
*
* Returns: new rproc instance, or NULL on failure
* Return: new rproc instance, or NULL on failure
*/
struct rproc *devm_rproc_alloc(struct device *dev, const char *name,
const struct rproc_ops *ops,
......@@ -2687,7 +2713,7 @@ EXPORT_SYMBOL(rproc_remove_subdev);
* rproc_get_by_child() - acquire rproc handle of @dev's ancestor
* @dev: child device to find ancestor of
*
* Returns the ancestor rproc instance, or NULL if not found.
* Return: the ancestor rproc instance, or NULL if not found
*/
struct rproc *rproc_get_by_child(struct device *dev)
{
......
......@@ -31,6 +31,8 @@
* @fw: the ELF firmware image
*
* Make sure this fw image is sane (ie a correct ELF32/ELF64 file).
*
* Return: 0 on success and -EINVAL upon any failure
*/
int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
{
......@@ -117,11 +119,11 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
* @rproc: the remote processor handle
* @fw: the ELF firmware image
*
* This function returns the entry point address of the ELF
* image.
*
* Note that the boot address is not a configurable property of all remote
* processors. Some will always boot at a specific hard-coded address.
*
* Return: entry point address of the ELF image
*
*/
u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
{
......@@ -152,6 +154,8 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
* might be different: they might not have iommus, and would prefer to
* directly allocate memory for every segment/resource. This is not yet
* supported, though.
*
* Return: 0 on success and an appropriate error code otherwise
*/
int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
{
......@@ -362,7 +366,7 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
* This function finds the location of the loaded resource table. Don't
* call this function if the table wasn't loaded yet - it's a bug if you do.
*
* Returns the pointer to the resource table if it is found or NULL otherwise.
* Return: pointer to the resource table if it is found or NULL otherwise.
* If the table wasn't loaded yet the result is unspecified.
*/
struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
......
......@@ -45,7 +45,7 @@ static bool rproc_virtio_notify(struct virtqueue *vq)
* when the remote processor signals that a specific virtqueue has pending
* messages available.
*
* Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
* Return: IRQ_NONE if no message was found in the @notifyid virtqueue,
* and otherwise returns IRQ_HANDLED.
*/
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
......@@ -325,7 +325,7 @@ static void rproc_virtio_dev_release(struct device *dev)
* This function registers a virtio device. This vdev's partent is
* the rproc device.
*
* Returns 0 on success or an appropriate error value otherwise.
* Return: 0 on success or an appropriate error value otherwise
*/
int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
{
......@@ -432,6 +432,8 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
* @data: must be null
*
* This function unregisters an existing virtio device.
*
* Return: 0
*/
int rproc_remove_virtio_dev(struct device *dev, void *data)
{
......
......@@ -474,14 +474,12 @@ static int stm32_rproc_attach(struct rproc *rproc)
static int stm32_rproc_detach(struct rproc *rproc)
{
struct stm32_rproc *ddata = rproc->priv;
int err, dummy_data, idx;
int err, idx;
/* Inform the remote processor of the detach */
idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_DETACH);
if (idx >= 0 && ddata->mb[idx].chan) {
/* A dummy data is sent to allow to block on transmit */
err = mbox_send_message(ddata->mb[idx].chan,
&dummy_data);
err = mbox_send_message(ddata->mb[idx].chan, "stop");
if (err < 0)
dev_warn(&rproc->dev, "warning: remote FW detach without ack\n");
}
......@@ -493,15 +491,13 @@ static int stm32_rproc_detach(struct rproc *rproc)
static int stm32_rproc_stop(struct rproc *rproc)
{
struct stm32_rproc *ddata = rproc->priv;
int err, dummy_data, idx;
int err, idx;
/* request shutdown of the remote processor */
if (rproc->state != RPROC_OFFLINE) {
idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
if (idx >= 0 && ddata->mb[idx].chan) {
/* a dummy data is sent to allow to block on transmit */
err = mbox_send_message(ddata->mb[idx].chan,
&dummy_data);
err = mbox_send_message(ddata->mb[idx].chan, "detach");
if (err < 0)
dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
}
......@@ -556,7 +552,7 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid)
continue;
if (!ddata->mb[i].chan)
return;
err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid);
err = mbox_send_message(ddata->mb[i].chan, "kick");
if (err < 0)
dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
__func__, ddata->mb[i].name, err);
......@@ -580,7 +576,7 @@ static int stm32_rproc_da_to_pa(struct rproc *rproc,
continue;
*pa = da - p_mem->dev_addr + p_mem->bus_addr;
dev_dbg(dev, "da %llx to pa %#x\n", da, *pa);
dev_dbg(dev, "da %llx to pa %pap\n", da, pa);
return 0;
}
......
......@@ -40,6 +40,8 @@
#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000
/* Available from J7200 SoCs onwards */
#define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000
/* Applicable to only AM64x SoCs */
#define PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE 0x00008000
/* R5 TI-SCI Processor Control Flags */
#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
......@@ -49,6 +51,8 @@
#define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002
#define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004
#define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100
/* Applicable to only AM64x SoCs */
#define PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY 0x00000200
/**
* struct k3_r5_mem - internal memory structure
......@@ -64,19 +68,29 @@ struct k3_r5_mem {
size_t size;
};
/*
* 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
*/
enum cluster_mode {
CLUSTER_MODE_SPLIT = 0,
CLUSTER_MODE_LOCKSTEP,
CLUSTER_MODE_SINGLECPU,
};
/**
* struct k3_r5_soc_data - match data to handle SoC variations
* @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
*/
struct k3_r5_soc_data {
bool tcm_is_double;
bool tcm_ecc_autoinit;
bool single_cpu_mode;
};
/**
......@@ -369,6 +383,13 @@ static inline int k3_r5_core_run(struct k3_r5_core *core)
* applicable cores to allow loading into the TCMs. The .prepare() ops is
* invoked by remoteproc core before any firmware loading, and is followed
* by the .start() ops after loading to actually let the R5 cores run.
*
* The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to
* execute code, but combines the TCMs from both cores. The resets for both
* cores need to be released to make this possible, as the TCMs are in general
* private to each core. Only Core0 needs to be unhalted for running the
* cluster in this mode. The function uses the same reset logic as LockStep
* mode for this (though the behavior is agnostic of the reset release order).
*/
static int k3_r5_rproc_prepare(struct rproc *rproc)
{
......@@ -386,7 +407,9 @@ static int k3_r5_rproc_prepare(struct rproc *rproc)
return ret;
mem_init_dis = !!(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS);
ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ?
/* Re-use LockStep-mode reset logic for Single-CPU mode */
ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU) ?
k3_r5_lockstep_release(cluster) : k3_r5_split_release(core);
if (ret) {
dev_err(dev, "unable to enable cores for TCM loading, ret = %d\n",
......@@ -427,6 +450,12 @@ static int k3_r5_rproc_prepare(struct rproc *rproc)
* cores. The cores themselves are only halted in the .stop() ops, and the
* .unprepare() ops is invoked by the remoteproc core after the remoteproc is
* stopped.
*
* The Single-CPU mode on applicable SoCs (eg: AM64x) combines the TCMs from
* both cores. The access is made possible only with releasing the resets for
* both cores, but with only Core0 unhalted. This function re-uses the same
* reset assert logic as LockStep mode for this mode (though the behavior is
* agnostic of the reset assert order).
*/
static int k3_r5_rproc_unprepare(struct rproc *rproc)
{
......@@ -436,7 +465,9 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc)
struct device *dev = kproc->dev;
int ret;
ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ?
/* Re-use LockStep-mode reset logic for Single-CPU mode */
ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU) ?
k3_r5_lockstep_reset(cluster) : k3_r5_split_reset(core);
if (ret)
dev_err(dev, "unable to disable cores, ret = %d\n", ret);
......@@ -455,6 +486,10 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc)
* first followed by Core0. The Split-mode requires that Core0 to be maintained
* always in a higher power state that Core1 (implying Core1 needs to be started
* always only after Core0 is started).
*
* The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute
* code, so only Core0 needs to be unhalted. The function uses the same logic
* flow as Split-mode for this.
*/
static int k3_r5_rproc_start(struct rproc *rproc)
{
......@@ -539,6 +574,10 @@ static int k3_r5_rproc_start(struct rproc *rproc)
* Core0 to be maintained always in a higher power state that Core1 (implying
* Core1 needs to be stopped first before Core0).
*
* The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute
* code, so only Core0 needs to be halted. The function uses the same logic
* flow as Split-mode for this.
*
* Note that the R5F halt operation in general is not effective when the R5F
* core is running, but is needed to make sure the core won't run after
* deasserting the reset the subsequent time. The asserting of reset can
......@@ -665,7 +704,9 @@ static const struct rproc_ops k3_r5_rproc_ops = {
*
* Each R5FSS has a cluster-level setting for configuring the processor
* subsystem either in a safety/fault-tolerant LockStep mode or a performance
* oriented Split mode. Each R5F core has a number of settings to either
* oriented Split mode on most SoCs. A fewer SoCs support a non-safety mode
* as an alternate for LockStep mode that exercises only a single R5F core
* called Single-CPU mode. Each R5F core has a number of settings to either
* enable/disable each of the TCMs, control which TCM appears at the R5F core's
* address 0x0. These settings need to be configured before the resets for the
* corresponding core are released. These settings are all protected and managed
......@@ -677,11 +718,13 @@ static const struct rproc_ops k3_r5_rproc_ops = {
* the cores are halted before the .prepare() step.
*
* The function is called from k3_r5_cluster_rproc_init() and is invoked either
* once (in LockStep mode) or twice (in Split mode). Support for LockStep-mode
* is dictated by an eFUSE register bit, and the config settings retrieved from
* DT are adjusted accordingly as per the permitted cluster mode. All cluster
* level settings like Cluster mode and TEINIT (exception handling state
* dictating ARM or Thumb mode) can only be set and retrieved using Core0.
* once (in LockStep mode or Single-CPU modes) or twice (in Split mode). Support
* for LockStep-mode is dictated by an eFUSE register bit, and the config
* settings retrieved from DT are adjusted accordingly as per the permitted
* cluster mode. Another eFUSE register bit dictates if the R5F cluster only
* supports a Single-CPU mode. All cluster level settings like Cluster mode and
* TEINIT (exception handling state dictating ARM or Thumb mode) can only be set
* and retrieved using Core0.
*
* The function behavior is different based on the cluster mode. The R5F cores
* are configured independently as per their individual settings in Split mode.
......@@ -700,10 +743,16 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc)
u32 set_cfg = 0, clr_cfg = 0;
u64 boot_vec = 0;
bool lockstep_en;
bool single_cpu;
int ret;
core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem);
core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? core0 : kproc->core;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU) {
core = core0;
} else {
core = kproc->core;
}
ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl,
&stat);
......@@ -713,23 +762,48 @@ 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;
}
/* check conventional LockStep vs Split mode configuration */
lockstep_en = !!(stat & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED);
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;
/*
* LockStep configuration bit is Read-only on Split-mode _only_
* devices and system firmware will NACK any requests with the
* bit configured, so program it only on permitted devices
*/
if (lockstep_en)
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
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;
} else {
/*
* LockStep configuration bit is Read-only on Split-mode
* _only_ devices and system firmware will NACK any
* requests with the bit configured, so program it only
* on permitted devices
*/
if (lockstep_en)
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
}
}
if (core->atcm_enable)
......@@ -894,12 +968,12 @@ static void k3_r5_reserved_mem_exit(struct k3_r5_rproc *kproc)
* cores are usable in Split-mode, but only the Core0 TCMs can be used in
* LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by
* leveraging the Core1 TCMs as well in certain modes where they would have
* otherwise been unusable (Eg: LockStep-mode on J7200 SoCs). This is done by
* making a Core1 TCM visible immediately after the corresponding Core0 TCM.
* The SoC memory map uses the larger 64 KB sizes for the Core0 TCMs, and the
* dts representation reflects this increased size on supported SoCs. The Core0
* TCM sizes therefore have to be adjusted to only half the original size in
* Split mode.
* otherwise been unusable (Eg: LockStep-mode on J7200 SoCs, Single-CPU mode on
* AM64x SoCs). This is done by making a Core1 TCM visible immediately after the
* corresponding Core0 TCM. The SoC memory map uses the larger 64 KB sizes for
* the Core0 TCMs, and the dts representation reflects this increased size on
* supported SoCs. The Core0 TCM sizes therefore have to be adjusted to only
* half the original size in Split mode.
*/
static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc)
{
......@@ -909,6 +983,7 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc)
struct k3_r5_core *core0;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU ||
!cluster->soc_data->tcm_is_double)
return;
......@@ -987,8 +1062,9 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
goto err_add;
}
/* create only one rproc in lockstep mode */
if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
/* create only one rproc in lockstep mode or single-cpu mode */
if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU)
break;
}
......@@ -1020,11 +1096,12 @@ static void k3_r5_cluster_rproc_exit(void *data)
struct rproc *rproc;
/*
* lockstep mode has only one rproc associated with first core, whereas
* split-mode has two rprocs associated with each core, and requires
* that core1 be powered down first
* lockstep mode and single-cpu modes have only one rproc associated
* with first core, whereas split-mode has two rprocs associated with
* each core, and requires that core1 be powered down first
*/
core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ?
core = (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
cluster->mode == CLUSTER_MODE_SINGLECPU) ?
list_first_entry(&cluster->cores, struct k3_r5_core, elem) :
list_last_entry(&cluster->cores, struct k3_r5_core, elem);
......@@ -1272,9 +1349,9 @@ static int k3_r5_core_of_init(struct platform_device *pdev)
core->tsp = k3_r5_core_of_get_tsp(dev, core->ti_sci);
if (IS_ERR(core->tsp)) {
ret = PTR_ERR(core->tsp);
dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n",
ret);
ret = PTR_ERR(core->tsp);
goto err;
}
......@@ -1396,7 +1473,12 @@ static int k3_r5_probe(struct platform_device *pdev)
return -ENOMEM;
cluster->dev = dev;
cluster->mode = CLUSTER_MODE_LOCKSTEP;
/*
* 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);
......@@ -1450,17 +1532,26 @@ static int k3_r5_probe(struct platform_device *pdev)
static const struct k3_r5_soc_data am65_j721e_soc_data = {
.tcm_is_double = false,
.tcm_ecc_autoinit = false,
.single_cpu_mode = false,
};
static const struct k3_r5_soc_data j7200_soc_data = {
.tcm_is_double = true,
.tcm_ecc_autoinit = true,
.single_cpu_mode = false,
};
static const struct k3_r5_soc_data am64_soc_data = {
.tcm_is_double = true,
.tcm_ecc_autoinit = true,
.single_cpu_mode = true,
};
static const struct of_device_id k3_r5_of_match[] = {
{ .compatible = "ti,am654-r5fss", .data = &am65_j721e_soc_data, },
{ .compatible = "ti,j721e-r5fss", .data = &am65_j721e_soc_data, },
{ .compatible = "ti,j7200-r5fss", .data = &j7200_soc_data, },
{ .compatible = "ti,am64-r5fss", .data = &am64_soc_data, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, k3_r5_of_match);
......
......@@ -151,6 +151,42 @@ void qcom_smem_state_put(struct qcom_smem_state *state)
}
EXPORT_SYMBOL_GPL(qcom_smem_state_put);
static void devm_qcom_smem_state_release(struct device *dev, void *res)
{
qcom_smem_state_put(*(struct qcom_smem_state **)res);
}
/**
* devm_qcom_smem_state_get() - acquire handle to a devres managed state
* @dev: client device pointer
* @con_id: name of the state to lookup
* @bit: flags from the state reference, indicating which bit's affected
*
* Returns handle to the state, or ERR_PTR(). qcom_smem_state_put() is called
* automatically when @dev is removed.
*/
struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev,
const char *con_id,
unsigned *bit)
{
struct qcom_smem_state **ptr, *state;
ptr = devres_alloc(devm_qcom_smem_state_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
state = qcom_smem_state_get(dev, con_id, bit);
if (!IS_ERR(state)) {
*ptr = state;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return state;
}
EXPORT_SYMBOL_GPL(devm_qcom_smem_state_get);
/**
* qcom_smem_state_register() - register a new state
* @of_node: of_node used for matching client lookups
......
......@@ -243,7 +243,7 @@ struct fw_rsc_trace {
* @da: device address
* @align: the alignment between the consumer and producer parts of the vring
* @num: num of buffers supported by this vring (must be power of two)
* @notifyid is a unique rproc-wide notify index for this vring. This notify
* @notifyid: a unique rproc-wide notify index for this vring. This notify
* index is used when kicking a remote processor, to let it know that this
* vring is triggered.
* @pa: physical address
......@@ -266,18 +266,18 @@ struct fw_rsc_vdev_vring {
/**
* struct fw_rsc_vdev - virtio device header
* @id: virtio device id (as in virtio_ids.h)
* @notifyid is a unique rproc-wide notify index for this vdev. This notify
* @notifyid: a unique rproc-wide notify index for this vdev. This notify
* index is used when kicking a remote processor, to let it know that the
* status/features of this vdev have changes.
* @dfeatures specifies the virtio device features supported by the firmware
* @gfeatures is a place holder used by the host to write back the
* @dfeatures: specifies the virtio device features supported by the firmware
* @gfeatures: a place holder used by the host to write back the
* negotiated features that are supported by both sides.
* @config_len is the size of the virtio config space of this vdev. The config
* @config_len: the size of the virtio config space of this vdev. The config
* space lies in the resource table immediate after this vdev header.
* @status is a place holder where the host will indicate its virtio progress.
* @num_of_vrings indicates how many vrings are described in this vdev header
* @status: a place holder where the host will indicate its virtio progress.
* @num_of_vrings: indicates how many vrings are described in this vdev header
* @reserved: reserved (must be zero)
* @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'.
* @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'.
*
* This resource is a virtio device header: it provides information about
* the vdev, and is then used by the host and its peer remote processors
......@@ -287,16 +287,17 @@ struct fw_rsc_vdev_vring {
* to statically allocate a vdev upon registration of the rproc (dynamic vdev
* allocation is not yet supported).
*
* Note: unlike virtualization systems, the term 'host' here means
* the Linux side which is running remoteproc to control the remote
* processors. We use the name 'gfeatures' to comply with virtio's terms,
* though there isn't really any virtualized guest OS here: it's the host
* which is responsible for negotiating the final features.
* Yeah, it's a bit confusing.
*
* Note: immediately following this structure is the virtio config space for
* this vdev (which is specific to the vdev; for more info, read the virtio
* spec). the size of the config space is specified by @config_len.
* Note:
* 1. unlike virtualization systems, the term 'host' here means
* the Linux side which is running remoteproc to control the remote
* processors. We use the name 'gfeatures' to comply with virtio's terms,
* though there isn't really any virtualized guest OS here: it's the host
* which is responsible for negotiating the final features.
* Yeah, it's a bit confusing.
*
* 2. immediately following this structure is the virtio config space for
* this vdev (which is specific to the vdev; for more info, read the virtio
* spec). The size of the config space is specified by @config_len.
*/
struct fw_rsc_vdev {
u32 id;
......@@ -440,7 +441,7 @@ enum rproc_state {
* enum rproc_crash_type - remote processor crash types
* @RPROC_MMUFAULT: iommu fault
* @RPROC_WATCHDOG: watchdog bite
* @RPROC_FATAL_ERROR fatal error
* @RPROC_FATAL_ERROR: fatal error
*
* Each element of the enum is used as an array index. So that, the value of
* the elements should be always something sane.
......@@ -457,9 +458,9 @@ enum rproc_crash_type {
* enum rproc_dump_mechanism - Coredump options for core
* @RPROC_COREDUMP_DISABLED: Don't perform any dump
* @RPROC_COREDUMP_ENABLED: Copy dump to separate buffer and carry on with
recovery
* recovery
* @RPROC_COREDUMP_INLINE: Read segments directly from device memory. Stall
recovery until all segments are read
* recovery until all segments are read
*/
enum rproc_dump_mechanism {
RPROC_COREDUMP_DISABLED,
......@@ -475,6 +476,7 @@ enum rproc_dump_mechanism {
* @priv: private data associated with the dump_segment
* @dump: custom dump function to fill device memory segment associated
* with coredump
* @offset: offset of the segment
*/
struct rproc_dump_segment {
struct list_head node;
......@@ -524,7 +526,9 @@ struct rproc_dump_segment {
* @auto_boot: flag to indicate if remote processor should be auto-started
* @dump_segments: list of segments in the firmware
* @nb_vdev: number of vdev currently handled by rproc
* @char_dev: character device of the rproc
* @elf_class: firmware ELF class
* @elf_machine: firmware ELF machine
* @cdev: character device of the rproc
* @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release
*/
struct rproc {
......@@ -613,10 +617,10 @@ struct rproc_vring {
* struct rproc_vdev - remoteproc state for a supported virtio device
* @refcount: reference counter for the vdev and vring allocations
* @subdev: handle for registering the vdev as a rproc subdevice
* @dev: device struct used for reference count semantics
* @id: virtio device id (as in virtio_ids.h)
* @node: list node
* @rproc: the rproc handle
* @vdev: the virio device
* @vring: the vrings for this vdev
* @rsc_offset: offset of the vdev's resource entry
* @index: vdev position versus other vdev declared in resource table
......
......@@ -14,6 +14,7 @@ struct qcom_smem_state_ops {
#ifdef CONFIG_QCOM_SMEM_STATE
struct qcom_smem_state *qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit);
struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit);
void qcom_smem_state_put(struct qcom_smem_state *);
int qcom_smem_state_update_bits(struct qcom_smem_state *state, u32 mask, u32 value);
......@@ -29,6 +30,13 @@ static inline struct qcom_smem_state *qcom_smem_state_get(struct device *dev,
return ERR_PTR(-EINVAL);
}
static inline struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev,
const char *con_id,
unsigned *bit)
{
return ERR_PTR(-EINVAL);
}
static inline void qcom_smem_state_put(struct qcom_smem_state *state)
{
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册