mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 20:53:03 +02:00
remoteproc updates for v7.3
Add a remoteproc driver and binding for AMD MicroBlaze/V soft cores executing from dual-port BRAM, with clock and reset control and support for firmware without a resource table. Introduce a generic Qualcomm PAS service with SCM and OP-TEE backends, and migrate the PAS, MSS, and WCNSS remoteproc drivers to it. Add Nord ADSP and CDSP support, Eliza CDSP support, Maili ADSP/CDSP bindings, and late-attach SoCCP support for Kaanapali, Hawi, Maili, and Glymur. Enable BAM-DMUX child devices for PAS modems and fix PAS memory protection, handover, shutdown, and resource lifetime handling. Harden remoteproc lifecycle handling by attaching asynchronously, stopping crashed processors, synchronizing crash work with removal, and forcing shutdown before device resources are released. Reallocate resources during attach recovery and fix several reference and error-path leaks. Add Xilinx R5 crash detection and move RPU start and stop sequencing into the platform firmware driver. Consolidate write-combining carveout mapping callbacks, use correct I/O-memory accessors, and share optional ELF resource-table handling across drivers. Convert the TI Wakeup M3 binding to DT schema, correct Qualcomm and generic remoteproc bindings, and harden resource-table iteration against signed-offset out-of-bounds accesses. -----BEGIN PGP SIGNATURE----- iQJCBAABCgAsFiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmqN/FgOHGJqb3JuQGty eW8uc2UACgkQCx85Pw2ZrcUvXRAAkCk6ogZOdjGY9WBugieN3WEfkAzrWAS9ntWK CGR+VcL633ymLtS/6E2fdv4d7Uh1An/ipcCJUSXU4CzumB7O1FJi1CfQok2j+4xz dIBc9m6SAMYBFVLAXD2NujdOf+nwEDLbJQib7lVBTBCNjQamvjFhUu9g/bnJt4gT F1ieAgNP15OFfHnoSWhoFHXI8ao4Vs0PwfoBLEwIP5VuFXy3DzVGaqEZgEgD7+G5 Qy0ii/TO+EFC8GdK8xxlCtKYT6J3qG/pQBaCtS9QwSXNPTbI31MlDimInUl7lxHS yWeDOJPVgNL279W7DnHiELQT6uGFac+1ILNBIGl9lI1+4Hcwgg6eTwwP6wcIOhYL YFXNfCeb5XW6moOKxhkcbOwZ46/FUS4sywoUyaAevFOc8kisDwMy81C1d2cYVg12 gq69ah4sWkSPSkAgOeUf8Aa8v3eXj9IaxcIAW9+fQdNaduuG7oRvVzowKbli9SiD qAAaIV2wyt+Il7VJl5Nw1R0nJONMTK44Xft+3k/TFzmr5N1ivfSBvGxIg0zdB9xZ 7akukQjCJgWOcyICa3ShyA6foClsJF26xVhQrfY7UPKI7DQHY5GQAKgpA2zWrqH5 cKt5xRcImKn+788pfkNdVj8IxROjGEI5JXf6etIvpPnUzkFG3nZfY6kLryOxvv0H zyxm4OM= =wi8c -----END PGP SIGNATURE----- Merge tag 'rproc-v7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux Pull remoteproc updates from Bjorn Andersson: "Add a remoteproc driver and binding for AMD MicroBlaze/V soft cores executing from dual-port BRAM, with clock and reset control and support for firmware without a resource table. Introduce a generic Qualcomm PAS service with SCM and OP-TEE backends, and migrate the PAS, MSS, and WCNSS remoteproc drivers to it. Add Nord ADSP and CDSP support, Eliza CDSP support, Maili ADSP/CDSP bindings, and late-attach SoCCP support for Kaanapali, Hawi, Maili, and Glymur. Enable BAM-DMUX child devices for PAS modems and fix PAS memory protection, handover, shutdown, and resource lifetime handling. Harden remoteproc lifecycle handling by attaching asynchronously, stopping crashed processors, synchronizing crash work with removal, and forcing shutdown before device resources are released. Reallocate resources during attach recovery and fix several reference and error-path leaks. Add Xilinx R5 crash detection and move RPU start and stop sequencing into the platform firmware driver. Consolidate write-combining carveout mapping callbacks, use correct I/O-memory accessors, and share optional ELF resource-table handling across drivers. Convert the TI Wakeup M3 binding to DT schema, correct Qualcomm and generic remoteproc bindings, and harden resource-table iteration against signed-offset out-of-bounds accesses" * tag 'rproc-v7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: (60 commits) remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry() remoteproc: replace BSD blurb with SPDX identifier in rsc_table.h remoteproc: replace BSD blurb with SPDX identifier in remoteproc.h remoteproc: fix coding style issues in remoteproc.h MAINTAINERS: add rsc_table.h to remoteproc entry remoteproc: qcom: pas: Add Nord ADSP and CDSP support dt-bindings: remoteproc: qcom,nord-pas: Document Nord PAS remoteproc: qcom: pas: Drop unused dtb_mem_region field remoteproc: qcom: pas: Map/unmap subsystem region before auth_and_reset remoteproc: qcom: pas: Fix the PAS context creation placement remoteproc: qcom: pas: Guard dtb metadata release with dtb_pas_id check remoteproc: qcom: annotate mem_region fields with __iomem arm64: dts: qcom: eliza: Add fallback compatible for ADSP remoteproc dt-bindings: remoteproc: qcom,milos-pas: Move Eliza ADSP to SM8550 schema remoteproc: qcom: pas: Add Eliza CDSP support dt-bindings: remoteproc: qcom,sm8550-pas: Add Eliza CDSP compatible remoteproc: qcom: q6v5: Request shutdown if crash is triggered host-side remoteproc: Force shutdown during device removal remoteproc: Prevent crash handling to race with rproc_del() remoteproc: Allow shutdown of crashed processors ...
This commit is contained in:
commit
fc710de0dd
105
Documentation/devicetree/bindings/remoteproc/amd,bram-rproc.yaml
Normal file
105
Documentation/devicetree/bindings/remoteproc/amd,bram-rproc.yaml
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/remoteproc/amd,bram-rproc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: AMD MicroBlaze/V BRAM-based Remote Processor
|
||||
|
||||
maintainers:
|
||||
- Ben Levinsky <ben.levinsky@amd.com>
|
||||
|
||||
description: |
|
||||
Soft-core processor subsystem instantiated in AMD programmable logic and
|
||||
using dual-port BRAM for firmware storage and execution.
|
||||
|
||||
Hardware Architecture:
|
||||
|
||||
Host (PS) Programmable Logic (PL)
|
||||
========= ======================
|
||||
|
||||
AXI Interface -----------------> AXI BRAM Controller (Host Port)
|
||||
|
|
||||
| Port A
|
||||
v
|
||||
+-----------------+
|
||||
| Dual-Port BRAM |
|
||||
| (shared memory) |
|
||||
+-----------------+
|
||||
^
|
||||
| Port B
|
||||
|
|
||||
AXI BRAM Controller (Soft-core Port)
|
||||
^
|
||||
| LMB
|
||||
|
|
||||
Soft-core CPU (MicroBlaze/V)
|
||||
|
||||
GPIO --------------------------> Proc Sys Reset ----> CPU Reset Signal
|
||||
|
||||
Clock -------------------------> Clock Distribution -> CPU Clock
|
||||
|
||||
Memory Architecture:
|
||||
|
||||
The dual-port BRAM allows simultaneous access from both processors:
|
||||
- Port A: Connected to the host AXI BRAM controller for firmware loading
|
||||
- Port B: Connected to the soft-core local memory bus for execution
|
||||
|
||||
The reg property describes the executable BRAM window in the processor-local
|
||||
address space. The parent bus node translates that window to the system
|
||||
physical address space by using standard devicetree address translation
|
||||
through ranges. A clock input and a reset GPIO control the subsystem.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: xlnx,zynqmp-bram-rproc
|
||||
- items:
|
||||
- enum:
|
||||
- amd,versal2-bram-rproc
|
||||
- xlnx,versal-bram-rproc
|
||||
- xlnx,versal-net-bram-rproc
|
||||
- const: xlnx,zynqmp-bram-rproc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description:
|
||||
Processor-local address and size of the BRAM firmware memory window,
|
||||
as seen by the soft-core processor (typically 0x0 for reset vector).
|
||||
The parent bus ranges property must translate this window to the
|
||||
corresponding system physical address.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Clock input for the soft-core processor subsystem.
|
||||
|
||||
firmware-name:
|
||||
maxItems: 1
|
||||
description:
|
||||
Name of the firmware ELF file to load.
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
GPIO specifier controlling the soft-core reset input.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- reset-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
remoteproc@0 {
|
||||
compatible = "xlnx,zynqmp-bram-rproc";
|
||||
reg = <0x0 0x40000>;
|
||||
clocks = <&pl_clk>;
|
||||
firmware-name = "firmware.elf";
|
||||
reset-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
...
|
||||
|
|
@ -25,7 +25,7 @@ properties:
|
|||
- const: amlogic,meson-mx-ao-arc
|
||||
|
||||
firmware-name:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
maxItems: 1
|
||||
description:
|
||||
The name of the firmware which should be loaded for this remote
|
||||
processor.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,14 @@ properties:
|
|||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XO clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
|
||||
cx-supply: true
|
||||
|
||||
px-supply:
|
||||
|
|
@ -49,6 +57,30 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
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
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- memory-region
|
||||
|
|
@ -57,56 +89,6 @@ unevaluatedProperties: false
|
|||
|
||||
allOf:
|
||||
- $ref: /schemas/remoteproc/qcom,pas-common.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,msm8226-adsp-pil
|
||||
- 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,sdm660-adsp-pas
|
||||
- qcom,sdm660-cdsp-pas
|
||||
- qcom,sdm845-adsp-pas
|
||||
- qcom,sdm845-cdsp-pas
|
||||
- qcom,sdm845-slpi-pas
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: XO clock
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,msm8226-adsp-pil
|
||||
- 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,sdm660-adsp-pas
|
||||
- qcom,sdm660-cdsp-pas
|
||||
- qcom,sdm845-adsp-pas
|
||||
- qcom,sdm845-cdsp-pas
|
||||
- qcom,sdm845-slpi-pas
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 5
|
||||
interrupt-names:
|
||||
maxItems: 5
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,156 @@
|
|||
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/remoteproc/qcom,kaanapali-soccp-pas.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Kaanapali SoCCP Peripheral Authentication Service
|
||||
|
||||
maintainers:
|
||||
- Jingyi Wang <jingyi.wang@oss.qualcomm.com>
|
||||
|
||||
description:
|
||||
The SoC Control Processor (SoCCP) is a small RISC-V MCU that controls USB
|
||||
Type-C, battery charging and various other functions on Qualcomm SoCs, somewhat
|
||||
analogous to traditional PC Embedded Controllers. This document describes
|
||||
the Peripheral Authentication Service that loads and boots firmware for SoCCP.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,hawi-soccp-pas
|
||||
- qcom,maili-soccp-pas
|
||||
- const: qcom,kaanapali-soccp-pas
|
||||
- enum:
|
||||
- qcom,glymur-soccp-pas
|
||||
- qcom,kaanapali-soccp-pas
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XO clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
|
||||
power-domains:
|
||||
items:
|
||||
- description: CX power domain
|
||||
- description: MX power domain
|
||||
|
||||
power-domain-names:
|
||||
items:
|
||||
- const: cx
|
||||
- const: mx
|
||||
|
||||
firmware-name:
|
||||
items:
|
||||
- description: Firmware name of the SoC Control Processor
|
||||
- description: Firmware name of the SoCCP Devicetree
|
||||
|
||||
memory-region:
|
||||
items:
|
||||
- description: Memory region for main Firmware authentication
|
||||
- description: Memory region for Devicetree Firmware authentication
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Pong interrupt
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: pong
|
||||
|
||||
qcom,smem-states:
|
||||
minItems: 2
|
||||
description: States used by the AP to signal the SoC Control Processor
|
||||
|
||||
qcom,smem-state-names:
|
||||
minItems: 2
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- memory-region
|
||||
- power-domains
|
||||
- power-domain-names
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/remoteproc/qcom,pas-common.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/mailbox/qcom-ipcc.h>
|
||||
#include <dt-bindings/power/qcom-rpmpd.h>
|
||||
#define IPCC_MPROC_SOCCP
|
||||
|
||||
remoteproc@d00000 {
|
||||
compatible = "qcom,kaanapali-soccp-pas";
|
||||
reg = <0x00d00000 0x200000>;
|
||||
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>;
|
||||
clock-names = "xo";
|
||||
|
||||
interrupts-extended = <&intc GIC_SPI 167 IRQ_TYPE_EDGE_RISING>,
|
||||
<&soccp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
|
||||
<&soccp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
|
||||
<&soccp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
|
||||
<&soccp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>,
|
||||
<&soccp_smp2p_in 9 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "wdog",
|
||||
"fatal",
|
||||
"ready",
|
||||
"handover",
|
||||
"stop-ack",
|
||||
"pong";
|
||||
|
||||
memory-region = <&soccp_mem>,
|
||||
<&soccp_dtb_mem_mem>;
|
||||
|
||||
firmware-name = "qcom/kaanapali/soccp.mbn",
|
||||
"qcom/kaanapali/soccp_dtb.mbn";
|
||||
|
||||
power-domains = <&rpmhpd RPMHPD_CX>,
|
||||
<&rpmhpd RPMHPD_MX>;
|
||||
power-domain-names = "cx",
|
||||
"mx";
|
||||
|
||||
qcom,smem-states = <&soccp_smp2p_out 0>,
|
||||
<&soccp_smp2p_out 8>;
|
||||
qcom,smem-state-names = "stop",
|
||||
"ping";
|
||||
|
||||
glink-edge {
|
||||
interrupts-extended = <&ipcc IPCC_MPROC_SOCCP
|
||||
IPCC_MPROC_SIGNAL_GLINK_QMP
|
||||
IRQ_TYPE_EDGE_RISING>;
|
||||
mboxes = <&ipcc IPCC_MPROC_SOCCP
|
||||
IPCC_MPROC_SIGNAL_GLINK_QMP>;
|
||||
|
||||
label = "soccp";
|
||||
qcom,remote-pid = <19>;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
};
|
||||
|
|
@ -16,7 +16,6 @@ description:
|
|||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,eliza-adsp-pas
|
||||
- qcom,milos-adsp-pas
|
||||
- qcom,milos-cdsp-pas
|
||||
- qcom,milos-mpss-pas
|
||||
|
|
@ -34,12 +33,22 @@ properties:
|
|||
- const: xo
|
||||
|
||||
interrupts:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,qmp:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
|
@ -59,6 +68,14 @@ properties:
|
|||
- description: Memory region for core Firmware authentication
|
||||
- description: Memory region for Devicetree Firmware authentication
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
@ -70,7 +87,6 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,eliza-adsp-pas
|
||||
- qcom,milos-adsp-pas
|
||||
- qcom,milos-cdsp-pas
|
||||
then:
|
||||
|
|
@ -91,7 +107,6 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,eliza-adsp-pas
|
||||
- qcom,milos-adsp-pas
|
||||
then:
|
||||
properties:
|
||||
|
|
|
|||
173
Documentation/devicetree/bindings/remoteproc/qcom,nord-pas.yaml
Normal file
173
Documentation/devicetree/bindings/remoteproc/qcom,nord-pas.yaml
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/remoteproc/qcom,nord-pas.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Nord SoC Peripheral Authentication Service
|
||||
|
||||
maintainers:
|
||||
- Shawn Guo <shengchao.guo@oss.qualcomm.com>
|
||||
|
||||
description:
|
||||
Qualcomm Nord SoC Peripheral Authentication Service loads and boots firmware
|
||||
on the Qualcomm DSP Hexagon cores.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,nord-adsp-pas
|
||||
- qcom,nord-cdsp0-pas
|
||||
- qcom,nord-cdsp1-pas
|
||||
- qcom,nord-cdsp2-pas
|
||||
- qcom,nord-cdsp3-pas
|
||||
|
||||
power-domains:
|
||||
minItems: 2
|
||||
items:
|
||||
- description: CX power domain
|
||||
- description: MX power domain
|
||||
- description: NSP power domain
|
||||
|
||||
power-domain-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: cx
|
||||
- const: mx
|
||||
- const: nsp
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XO clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
|
||||
qcom,qmp:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Reference to the AOSS side-channel message RAM.
|
||||
|
||||
smd-edge: false
|
||||
|
||||
firmware-name:
|
||||
items:
|
||||
- description: Firmware name of the Hexagon core
|
||||
- description: Firmware name of the Hexagon Devicetree
|
||||
|
||||
memory-region:
|
||||
items:
|
||||
- description: Memory region for main Firmware authentication
|
||||
- description: Memory region for Devicetree Firmware authentication
|
||||
|
||||
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
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- memory-region
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/remoteproc/qcom,pas-common.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,nord-adsp-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
maxItems: 2
|
||||
power-domain-names:
|
||||
maxItems: 2
|
||||
else:
|
||||
properties:
|
||||
power-domains:
|
||||
minItems: 3
|
||||
power-domain-names:
|
||||
minItems: 3
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/mailbox/qcom-ipcc.h>
|
||||
#include <dt-bindings/power/qcom,rpmhpd.h>
|
||||
#define IPCC_MPROC_ADSP0
|
||||
|
||||
remoteproc@4c00000 {
|
||||
compatible = "qcom,nord-adsp-pas";
|
||||
reg = <0x04c00000 0x10000>;
|
||||
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>;
|
||||
clock-names = "xo";
|
||||
|
||||
interrupts-extended = <&intc GIC_SPI 159 IRQ_TYPE_EDGE_RISING>,
|
||||
<&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>,
|
||||
<&smp2p_adsp_in 7 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "wdog",
|
||||
"fatal",
|
||||
"ready",
|
||||
"handover",
|
||||
"stop-ack",
|
||||
"shutdown-ack";
|
||||
|
||||
memory-region = <&hpass_dsp0_mem>, <&hpass_dsp0_dtb_mem>;
|
||||
|
||||
firmware-name = "qcom/nord/adsp.mbn",
|
||||
"qcom/nord/adsp_dtb.mbn";
|
||||
|
||||
power-domains = <&rpmhpd RPMHPD_CX>,
|
||||
<&rpmhpd RPMHPD_MX>;
|
||||
power-domain-names = "cx",
|
||||
"mx";
|
||||
|
||||
qcom,qmp = <&aoss_qmp>;
|
||||
qcom,smem-states = <&smp2p_adsp_out 0>;
|
||||
qcom,smem-state-names = "stop";
|
||||
|
||||
glink-edge {
|
||||
interrupts-extended = <&ipcc IPCC_MPROC_ADSP0
|
||||
IPCC_MPROC_SIGNAL_GLINK_QMP
|
||||
IRQ_TYPE_EDGE_RISING>;
|
||||
mboxes = <&ipcc IPCC_MPROC_ADSP0 IPCC_MPROC_SIGNAL_GLINK_QMP>;
|
||||
|
||||
label = "adsp";
|
||||
qcom,remote-pid = <2>;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
};
|
||||
|
|
@ -26,23 +26,11 @@ properties:
|
|||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
maxItems: 6
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
maxItems: 6
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
|
@ -58,8 +46,16 @@ properties:
|
|||
qcom,smem-states:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
minItems: 1
|
||||
items:
|
||||
- description: Stop the modem
|
||||
- description: Stop the remoteproc
|
||||
items:
|
||||
- description: Phandle to the Shared Memory Point 2 Point device
|
||||
handling the communication with a remote processor
|
||||
- description: Single bit index to toggle in the value sent to
|
||||
the remote processor
|
||||
maximum: 32
|
||||
- description: Ping the remoteproc
|
||||
items:
|
||||
- description: Phandle to the Shared Memory Point 2 Point device
|
||||
handling the communication with a remote processor
|
||||
|
|
@ -69,8 +65,10 @@ properties:
|
|||
|
||||
qcom,smem-state-names:
|
||||
description: The names of the state bits used for SMP2P output
|
||||
minItems: 1
|
||||
items:
|
||||
- const: stop
|
||||
- const: ping
|
||||
|
||||
smd-edge:
|
||||
$ref: /schemas/remoteproc/qcom,smd-edge.yaml#
|
||||
|
|
|
|||
|
|
@ -32,10 +32,20 @@ properties:
|
|||
- const: xo
|
||||
|
||||
interrupts:
|
||||
maxItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
maxItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
|
||||
power-domains: false
|
||||
power-domain-names: false
|
||||
|
|
@ -49,6 +59,14 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -59,10 +59,28 @@ properties:
|
|||
- description: Memory region for main Firmware authentication
|
||||
|
||||
interrupts:
|
||||
maxItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
maxItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
|
|||
|
|
@ -48,6 +48,34 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -45,6 +45,34 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -30,10 +30,22 @@ properties:
|
|||
- const: xo
|
||||
|
||||
interrupts:
|
||||
minItems: 6
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 6
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
power-domains:
|
||||
items:
|
||||
|
|
@ -59,6 +71,14 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -51,6 +51,26 @@ properties:
|
|||
and devices related to the remoteproc core.
|
||||
unevaluatedProperties: false
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
|
|
|||
|
|
@ -51,6 +51,34 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -45,6 +45,34 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -39,8 +39,36 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
smd-edge: false
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -61,6 +61,34 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -55,6 +55,34 @@ properties:
|
|||
maxItems: 1
|
||||
description: Firmware name for the Hexagon core
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ properties:
|
|||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- qcom,eliza-cdsp-pas
|
||||
- qcom,sdx75-mpss-pas
|
||||
- qcom,sm8550-adsp-pas
|
||||
- qcom,sm8550-cdsp-pas
|
||||
|
|
@ -29,9 +30,11 @@ properties:
|
|||
- qcom,x1e80100-cdsp-pas
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,eliza-adsp-pas
|
||||
- qcom,glymur-adsp-pas
|
||||
- qcom,hawi-adsp-pas
|
||||
- qcom,kaanapali-adsp-pas
|
||||
- qcom,maili-adsp-pas
|
||||
- qcom,sm8750-adsp-pas
|
||||
- const: qcom,sm8550-adsp-pas
|
||||
- items:
|
||||
|
|
@ -39,6 +42,7 @@ properties:
|
|||
- qcom,glymur-cdsp-pas
|
||||
- qcom,hawi-cdsp-pas
|
||||
- qcom,kaanapali-cdsp-pas
|
||||
- qcom,maili-cdsp-pas
|
||||
- const: qcom,sm8550-cdsp-pas
|
||||
- items:
|
||||
- const: qcom,sm8750-cdsp-pas
|
||||
|
|
@ -75,6 +79,34 @@ properties:
|
|||
- description: DSM Memory region 2
|
||||
- description: Memory region for Qlink Logging
|
||||
|
||||
interrupts:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Watchdog interrupt
|
||||
- description: Fatal interrupt
|
||||
- description: Ready interrupt
|
||||
- description: Handover interrupt
|
||||
- description: Stop acknowledge interrupt
|
||||
- description: Shutdown acknowledge interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: wdog
|
||||
- const: fatal
|
||||
- const: ready
|
||||
- const: handover
|
||||
- const: stop-ack
|
||||
- const: shutdown-ack
|
||||
|
||||
qcom,smem-states:
|
||||
maxItems: 1
|
||||
description: States used by the AP to signal the Hexagon core
|
||||
|
||||
qcom,smem-state-names:
|
||||
maxItems: 1
|
||||
description: The names of the state bits used for SMP2P output
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
@ -104,12 +136,15 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,eliza-adsp-pas
|
||||
- qcom,glymur-adsp-pas
|
||||
- qcom,glymur-cdsp-pas
|
||||
- qcom,hawi-adsp-pas
|
||||
- qcom,hawi-cdsp-pas
|
||||
- qcom,kaanapali-adsp-pas
|
||||
- qcom,kaanapali-cdsp-pas
|
||||
- qcom,maili-adsp-pas
|
||||
- qcom,maili-cdsp-pas
|
||||
- qcom,sm8750-adsp-pas
|
||||
then:
|
||||
properties:
|
||||
|
|
@ -139,6 +174,7 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,eliza-cdsp-pas
|
||||
- qcom,sm8750-cdsp-pas
|
||||
then:
|
||||
properties:
|
||||
|
|
@ -253,6 +289,25 @@ allOf:
|
|||
- const: mxc
|
||||
- const: nsp
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,eliza-cdsp-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
items:
|
||||
- description: CX power domain
|
||||
- description: MX power domain
|
||||
- description: NSP power domain
|
||||
power-domain-names:
|
||||
items:
|
||||
- const: cx
|
||||
- const: mx
|
||||
- const: nsp
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/remoteproc/ti,am3352-wkup-m3.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TI AM33xx/AM43xx Wakeup M3 Remote Processor
|
||||
|
||||
maintainers:
|
||||
- Suman Anna <s-anna@ti.com>
|
||||
- Bhargav Joshi <j.bhargav.u@gmail.com>
|
||||
|
||||
description:
|
||||
The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor
|
||||
(commonly referred to as Wakeup M3 or CM3) to help with various low power
|
||||
tasks that cannot be controlled from the MPU. This CM3 processor requires a
|
||||
firmware binary to accomplish this. A wkup_m3 device node is used to
|
||||
represent the Wakeup M3 processor instance within the SoC. It is added as a
|
||||
child node of the parent interconnect bus (l4_wkup) through which it is
|
||||
accessible to the MPU.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,am3352-wkup-m3
|
||||
- ti,am4372-wkup-m3
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Address range for UMEM
|
||||
- description: Address range for DMEM
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: umem
|
||||
- const: dmem
|
||||
|
||||
ti,pm-firmware:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
Name of firmware file to be used for loading and booting the wkup_m3
|
||||
remote processor.
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: rstctrl
|
||||
|
||||
ti,hwmods:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
description:
|
||||
Name of the hwmod associated with the wkupm3 device.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- ti,pm-firmware
|
||||
|
||||
dependencies:
|
||||
resets: [reset-names]
|
||||
reset-names: [resets]
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
target-module@0 {
|
||||
compatible = "ti,sysc-omap4", "ti,sysc";
|
||||
reg = <0x0 0x4>;
|
||||
reg-names = "rev";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x00000000 0x00000000 0x4000>,
|
||||
<0x00080000 0x00080000 0x2000>;
|
||||
|
||||
cpu@0 {
|
||||
compatible = "ti,am3352-wkup-m3";
|
||||
reg = <0x00000000 0x4000>,
|
||||
<0x00080000 0x2000>;
|
||||
reg-names = "umem", "dmem";
|
||||
resets = <&prm_wkup 3>;
|
||||
reset-names = "rstctrl";
|
||||
ti,pm-firmware = "am335x-pm-firmware.elf";
|
||||
};
|
||||
};
|
||||
|
|
@ -30,7 +30,6 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
firmware-name:
|
||||
$ref: /schemas/types.yaml#/definitions/string-array
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
description: |
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
TI Wakeup M3 Remoteproc Driver
|
||||
==============================
|
||||
|
||||
The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor
|
||||
(commonly referred to as Wakeup M3 or CM3) to help with various low power tasks
|
||||
that cannot be controlled from the MPU. This CM3 processor requires a firmware
|
||||
binary to accomplish this. The wkup_m3 remoteproc driver handles the loading of
|
||||
the firmware and booting of the CM3.
|
||||
|
||||
Wkup M3 Device Node:
|
||||
====================
|
||||
A wkup_m3 device node is used to represent the Wakeup M3 processor instance
|
||||
within the SoC. It is added as a child node of the parent interconnect bus
|
||||
(l4_wkup) through which it is accessible to the MPU.
|
||||
|
||||
Required properties:
|
||||
--------------------
|
||||
- compatible: Should be one of,
|
||||
"ti,am3352-wkup-m3" for AM33xx SoCs
|
||||
"ti,am4372-wkup-m3" for AM43xx SoCs
|
||||
- reg: Should contain the address ranges for the two internal
|
||||
memory regions, UMEM and DMEM. The parent node should
|
||||
provide an appropriate ranges property for properly
|
||||
translating these into bus addresses.
|
||||
- reg-names: Contains the corresponding names for the two memory
|
||||
regions. These should be named "umem" & "dmem".
|
||||
- ti,hwmods: Name of the hwmod associated with the wkupm3 device.
|
||||
- ti,pm-firmware: Name of firmware file to be used for loading and
|
||||
booting the wkup_m3 remote processor.
|
||||
|
||||
Example:
|
||||
--------
|
||||
/* AM33xx */
|
||||
ocp {
|
||||
l4_wkup: l4_wkup@44c00000 {
|
||||
compatible = "am335-l4-wkup", "simple-bus";
|
||||
ranges = <0 0x44c00000 0x400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
wkup_m3: wkup_m3@100000 {
|
||||
compatible = "ti,am3352-wkup-m3";
|
||||
reg = <0x100000 0x4000>,
|
||||
<0x180000 0x2000>;
|
||||
reg-names = "umem", "dmem";
|
||||
ti,hwmods = "wkup_m3";
|
||||
ti,pm-firmware = "am335x-pm-firmware.elf";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
};
|
||||
|
|
@ -23054,6 +23054,7 @@ F: Documentation/devicetree/bindings/remoteproc/
|
|||
F: Documentation/staging/remoteproc.rst
|
||||
F: drivers/remoteproc/
|
||||
F: include/linux/remoteproc.h
|
||||
F: include/linux/rsc_table.h
|
||||
F: include/linux/remoteproc/
|
||||
|
||||
REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
|
||||
|
|
|
|||
|
|
@ -1977,7 +1977,7 @@ tcsr: clock-controller@1fbf000 {
|
|||
};
|
||||
|
||||
remoteproc_adsp: remoteproc@3000000 {
|
||||
compatible = "qcom,eliza-adsp-pas";
|
||||
compatible = "qcom,eliza-adsp-pas", "qcom,sm8550-adsp-pas";
|
||||
reg = <0x0 0x03000000 0x0 0x10000>;
|
||||
|
||||
interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>,
|
||||
|
|
|
|||
|
|
@ -1517,6 +1517,99 @@ int zynqmp_pm_request_wake(const u32 node,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_request_wake);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_start_rpu - Boot Real-time Processing Unit (Cortex-R) on SoC
|
||||
*
|
||||
* @node: power-domains id of the core
|
||||
* @bootaddr: Boot address of elf
|
||||
*
|
||||
* Return: status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_start_rpu(const u32 node, const u64 bootaddr)
|
||||
{
|
||||
enum rpu_boot_mem bootmem;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The exception vector pointers (EVP) refer to the base-address of
|
||||
* exception vectors (for reset, IRQ, FIQ, etc). The reset-vector
|
||||
* starts at the base-address and subsequent vectors are on 4-byte
|
||||
* boundaries.
|
||||
*
|
||||
* Exception vectors can start either from 0x0000_0000 (LOVEC) or
|
||||
* from 0xFFFF_0000 (HIVEC) which is mapped in the OCM (On-Chip Memory)
|
||||
*
|
||||
* Usually firmware will put Exception vectors at LOVEC.
|
||||
*
|
||||
* It is not recommend that you change the exception vector.
|
||||
* Changing the EVP to HIVEC will result in increased interrupt latency
|
||||
* and jitter. Also, if the OCM is secured and the Cortex-R5F processor
|
||||
* is non-secured, then the Cortex-R5F processor cannot access the
|
||||
* HIVEC exception vectors in the OCM.
|
||||
*/
|
||||
bootmem = (bootaddr >= 0xFFFC0000) ?
|
||||
PM_RPU_BOOTMEM_HIVEC : PM_RPU_BOOTMEM_LOVEC;
|
||||
|
||||
pr_debug("RPU boot addr 0x%llx from %s.", bootaddr,
|
||||
bootmem == PM_RPU_BOOTMEM_HIVEC ? "OCM" : "TCM");
|
||||
|
||||
/* Request node before starting RPU core if new version of API is supported */
|
||||
if (zynqmp_pm_feature(PM_REQUEST_NODE) > PM_API_VERSION_1) {
|
||||
ret = zynqmp_pm_request_node(node,
|
||||
ZYNQMP_PM_CAPABILITY_ACCESS, 0,
|
||||
ZYNQMP_PM_REQUEST_ACK_BLOCKING);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to request 0x%x", node);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = zynqmp_pm_request_wake(node, true,
|
||||
bootmem, ZYNQMP_PM_REQUEST_ACK_NO);
|
||||
if (ret)
|
||||
pr_err("failed to start RPU = 0x%x\n", node);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_start_rpu);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_stop_rpu - Stop Real-time Processing Unit (Cortex-R) on SoC
|
||||
*
|
||||
* @node: power-domains id of the core
|
||||
*
|
||||
* Return: status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_stop_rpu(const u32 node)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Use release node API to stop core if new version of API is supported */
|
||||
if (zynqmp_pm_feature(PM_RELEASE_NODE) > PM_API_VERSION_1) {
|
||||
ret = zynqmp_pm_release_node(node);
|
||||
if (ret)
|
||||
pr_err("failed to stop remoteproc RPU %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check expected version of EEMI call before calling it. This avoids
|
||||
* any error or warning prints from firmware as it is expected that fw
|
||||
* doesn't support it.
|
||||
*/
|
||||
if (zynqmp_pm_feature(PM_FORCE_POWERDOWN) != PM_API_VERSION_1) {
|
||||
pr_debug("EEMI interface %d ver 1 not supported\n",
|
||||
PM_FORCE_POWERDOWN);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* maintain force pwr down for backward compatibility */
|
||||
ret = zynqmp_pm_force_pwrdwn(node, ZYNQMP_PM_REQUEST_ACK_BLOCKING);
|
||||
if (ret)
|
||||
pr_err("core force power down failed\n");
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_stop_rpu);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_set_requirement() - PM call to set requirement for PM slaves
|
||||
* @node: Node ID of the slave
|
||||
|
|
|
|||
|
|
@ -23,6 +23,15 @@ config REMOTEPROC_CDEV
|
|||
|
||||
It's safe to say N if you don't want to use this interface.
|
||||
|
||||
config AMD_MBV_BRAM_REMOTEPROC
|
||||
tristate "AMD MicroBlaze/V BRAM-based remoteproc support"
|
||||
depends on OF && COMMON_CLK && (GPIOLIB || COMPILE_TEST)
|
||||
help
|
||||
Say y or m here to support a MicroBlaze/V BRAM-based remote
|
||||
processor managed through the remoteproc framework.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config IMX_REMOTEPROC
|
||||
tristate "i.MX remoteproc support"
|
||||
depends on ARCH_MXC
|
||||
|
|
@ -210,6 +219,7 @@ config QCOM_Q6V5_MSS
|
|||
select QCOM_Q6V5_COMMON
|
||||
select QCOM_RPROC_COMMON
|
||||
select QCOM_SCM
|
||||
select QCOM_PAS
|
||||
help
|
||||
Say y here to support the Qualcomm self-authenticating modem
|
||||
subsystem based on Hexagon V5. The TrustZone based system is
|
||||
|
|
@ -230,6 +240,7 @@ config QCOM_Q6V5_PAS
|
|||
select QCOM_Q6V5_COMMON
|
||||
select QCOM_RPROC_COMMON
|
||||
select QCOM_SCM
|
||||
select QCOM_PAS
|
||||
help
|
||||
Say y here to support the TrustZone based Peripheral Image Loader for
|
||||
the Qualcomm remote processors. This is commonly used to control
|
||||
|
|
@ -282,7 +293,7 @@ config QCOM_WCNSS_PIL
|
|||
select QCOM_MDT_LOADER
|
||||
select QCOM_PIL_INFO
|
||||
select QCOM_RPROC_COMMON
|
||||
select QCOM_SCM
|
||||
select QCOM_PAS
|
||||
help
|
||||
Say y here to support the Peripheral Image Loader for loading WCNSS
|
||||
firmware and boot the core on e.g. MSM8974, MSM8916. The firmware is
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ remoteproc-y += remoteproc_sysfs.o
|
|||
remoteproc-y += remoteproc_virtio.o
|
||||
remoteproc-y += remoteproc_elf_loader.o
|
||||
obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o
|
||||
obj-$(CONFIG_AMD_MBV_BRAM_REMOTEPROC) += amd_mbv_bram_rproc.o
|
||||
obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
|
||||
obj-$(CONFIG_IMX_DSP_REMOTEPROC) += imx_dsp_rproc.o
|
||||
obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o
|
||||
|
|
|
|||
213
drivers/remoteproc/amd_mbv_bram_rproc.c
Normal file
213
drivers/remoteproc/amd_mbv_bram_rproc.c
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* AMD MicroBlaze/V BRAM-based Remote Processor driver
|
||||
*
|
||||
* Copyright (C) 2026 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This driver supports soft-core processors (MicroBlaze, MicroBlaze-V, or
|
||||
* similar) instantiated in AMD programmable logic, using dual-port BRAM
|
||||
* for firmware storage and execution.
|
||||
*
|
||||
* The firmware memory (BRAM) is described in the processor-local address
|
||||
* space and translated to the Linux-visible system physical address with
|
||||
* standard devicetree address translation.
|
||||
*
|
||||
* Reset is controlled via GPIO connected to Processor System Reset IP.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/remoteproc.h>
|
||||
|
||||
#include "remoteproc_internal.h"
|
||||
|
||||
/**
|
||||
* struct amd_bram_rproc - AMD MicroBlaze/V BRAM-based remoteproc private data
|
||||
* @dev: device pointer
|
||||
* @reset: GPIO descriptor for reset control (active-low)
|
||||
* @clk: processor clock
|
||||
*/
|
||||
struct amd_bram_rproc {
|
||||
struct device *dev;
|
||||
struct gpio_desc *reset;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static int amd_bram_rproc_prepare(struct rproc *rproc)
|
||||
{
|
||||
struct amd_bram_rproc *priv = rproc->priv;
|
||||
struct rproc_mem_entry *mem;
|
||||
struct resource res;
|
||||
u64 da, size;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_reg(priv->dev->of_node, 0, &da, &size);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to parse executable memory reg\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!size || size > U32_MAX) {
|
||||
dev_err(priv->dev, "invalid executable memory size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (da > U32_MAX) {
|
||||
dev_err(priv->dev, "invalid executable memory address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(priv->dev->of_node, 0, &res);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to translate executable memory reg\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)res.start,
|
||||
resource_size(&res), da,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
dev_name(priv->dev));
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
|
||||
rproc_add_carveout(rproc, mem);
|
||||
rproc_coredump_add_segment(rproc, da, resource_size(&res));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_bram_rproc_start(struct rproc *rproc)
|
||||
{
|
||||
struct amd_bram_rproc *priv = rproc->priv;
|
||||
int ret;
|
||||
|
||||
/* Enable clock before releasing reset */
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Deassert reset and let the processor run. */
|
||||
ret = gpiod_set_value_cansleep(priv->reset, 0);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to deassert reset: %d\n", ret);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_bram_rproc_stop(struct rproc *rproc)
|
||||
{
|
||||
struct amd_bram_rproc *priv = rproc->priv;
|
||||
int ret;
|
||||
|
||||
/* Assert reset before disabling the processor clock. */
|
||||
ret = gpiod_set_value_cansleep(priv->reset, 1);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to assert reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disable clock after asserting reset */
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_bram_rproc_parse_fw(struct rproc *rproc,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
rproc_elf_load_rsc_table_optional(rproc, fw, dev_dbg,
|
||||
"no resource table found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rproc_ops amd_bram_rproc_ops = {
|
||||
.prepare = amd_bram_rproc_prepare,
|
||||
.start = amd_bram_rproc_start,
|
||||
.stop = amd_bram_rproc_stop,
|
||||
.load = rproc_elf_load_segments,
|
||||
.sanity_check = rproc_elf_sanity_check,
|
||||
.get_boot_addr = rproc_elf_get_boot_addr,
|
||||
.parse_fw = amd_bram_rproc_parse_fw,
|
||||
};
|
||||
|
||||
static int amd_bram_rproc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct amd_bram_rproc *priv;
|
||||
const char *fw_name = NULL;
|
||||
struct rproc *rproc;
|
||||
int ret;
|
||||
|
||||
ret = rproc_of_parse_firmware(dev, 0, &fw_name);
|
||||
if (ret < 0 && ret != -EINVAL)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to parse firmware-name property\n");
|
||||
|
||||
rproc = devm_rproc_alloc(dev, dev_name(dev), &amd_bram_rproc_ops,
|
||||
fw_name, sizeof(*priv));
|
||||
if (!rproc)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = rproc->priv;
|
||||
priv->dev = dev;
|
||||
|
||||
/* Get the processor clock */
|
||||
priv->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->clk),
|
||||
"failed to get clock\n");
|
||||
|
||||
/*
|
||||
* Keep the processor in reset until remoteproc has finished loading
|
||||
* firmware into the executable memory window described by reg and
|
||||
* translated through the parent bus ranges property.
|
||||
*/
|
||||
priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->reset))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->reset),
|
||||
"failed to get reset gpio\n");
|
||||
|
||||
rproc->auto_boot = false;
|
||||
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to set DMA mask\n");
|
||||
|
||||
platform_set_drvdata(pdev, rproc);
|
||||
|
||||
ret = devm_rproc_add(dev, rproc);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to register rproc\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id amd_bram_rproc_of_match[] = {
|
||||
{ .compatible = "xlnx,zynqmp-bram-rproc" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, amd_bram_rproc_of_match);
|
||||
|
||||
static struct platform_driver amd_bram_rproc_driver = {
|
||||
.probe = amd_bram_rproc_probe,
|
||||
.driver = {
|
||||
.name = "amd-bram-rproc",
|
||||
.of_match_table = amd_bram_rproc_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(amd_bram_rproc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("AMD MicroBlaze/V BRAM-based Remote Processor driver");
|
||||
MODULE_AUTHOR("Ben Levinsky <ben.levinsky@amd.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -298,7 +298,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
|
|||
handle_event, 0, "da8xx-remoteproc",
|
||||
rproc);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "devm_request_threaded_irq error\n");
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* rproc_add() can end up enabling the DSP's clk with the DSP
|
||||
|
|
|
|||
|
|
@ -644,32 +644,6 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv)
|
|||
mbox_free_channel(priv->rxdb_ch);
|
||||
}
|
||||
|
||||
static int imx_dsp_rproc_mem_alloc(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
struct device *dev = rproc->dev.parent;
|
||||
void *va;
|
||||
|
||||
va = ioremap_wc(mem->dma, mem->len);
|
||||
if (!va) {
|
||||
dev_err(dev, "Unable to map memory region: %pa+%zx\n",
|
||||
&mem->dma, mem->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mem->va = va;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_dsp_rproc_mem_release(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
iounmap(mem->va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* imx_dsp_rproc_add_carveout() - request mailbox channels
|
||||
* @priv: private data pointer
|
||||
|
|
@ -700,8 +674,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
|
|||
|
||||
/* Register memory region */
|
||||
mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa,
|
||||
att->size, da, imx_dsp_rproc_mem_alloc,
|
||||
imx_dsp_rproc_mem_release, "dsp_mem");
|
||||
att->size, da,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
"dsp_mem");
|
||||
|
||||
if (mem)
|
||||
rproc_coredump_add_segment(rproc, da, att->size);
|
||||
|
|
@ -732,8 +708,8 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
|
|||
/* Register memory region */
|
||||
mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)res.start,
|
||||
resource_size(&res), da,
|
||||
imx_dsp_rproc_mem_alloc,
|
||||
imx_dsp_rproc_mem_release,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
"%.*s", strchrnul(res.name, '@') - res.name, res.name);
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
|
|
@ -980,9 +956,8 @@ static int imx_dsp_rproc_elf_load_segments(struct rproc *rproc, const struct fir
|
|||
|
||||
static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
if (rproc_elf_load_rsc_table(rproc, fw))
|
||||
dev_warn(&rproc->dev, "no resource table found for this firmware\n");
|
||||
|
||||
rproc_elf_load_rsc_table_optional(rproc, fw, dev_warn,
|
||||
"no resource table found for this firmware\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -600,35 +600,6 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *i
|
|||
return va;
|
||||
}
|
||||
|
||||
static int imx_rproc_mem_alloc(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
struct device *dev = rproc->dev.parent;
|
||||
void *va;
|
||||
|
||||
dev_dbg(dev, "map memory: %p+%zx\n", &mem->dma, mem->len);
|
||||
va = ioremap_wc(mem->dma, mem->len);
|
||||
if (IS_ERR_OR_NULL(va)) {
|
||||
dev_err(dev, "Unable to map memory region: %p+%zx\n",
|
||||
&mem->dma, mem->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Update memory entry va */
|
||||
mem->va = va;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_mem_release(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
|
||||
iounmap(mem->va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_sm_lmm_prepare(struct rproc *rproc)
|
||||
{
|
||||
struct imx_rproc *priv = rproc->priv;
|
||||
|
|
@ -692,7 +663,8 @@ static int imx_rproc_prepare(struct rproc *rproc)
|
|||
/* Register memory region */
|
||||
mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)res.start,
|
||||
resource_size(&res), da,
|
||||
imx_rproc_mem_alloc, imx_rproc_mem_release,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
"%.*s", strchrnul(res.name, '@') - res.name,
|
||||
res.name);
|
||||
if (!mem)
|
||||
|
|
@ -710,12 +682,8 @@ static int imx_rproc_prepare(struct rproc *rproc)
|
|||
|
||||
static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rproc_elf_load_rsc_table(rproc, fw);
|
||||
if (ret)
|
||||
dev_info(&rproc->dev, "No resource table in elf\n");
|
||||
|
||||
rproc_elf_load_rsc_table_optional(rproc, fw, dev_info,
|
||||
"No resource table in elf\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -219,10 +219,8 @@ static int ingenic_rproc_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_request_irq(dev, vpu->irq, vpu_interrupt, IRQF_NO_AUTOEN,
|
||||
"VPU", rproc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to request IRQ\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_rproc_add(dev, rproc);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ static int keystone_rproc_of_get_dev_syscon(struct platform_device *pdev,
|
|||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
if (!of_property_read_bool(np, "ti,syscon-dev")) {
|
||||
if (!of_property_present(np, "ti,syscon-dev")) {
|
||||
dev_err(dev, "ti,syscon-dev property is absent\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ static int keystone_rproc_probe(struct platform_device *pdev)
|
|||
ret = devm_request_irq(dev, ksproc->irq_ring, keystone_rproc_vring_interrupt,
|
||||
IRQF_NO_AUTOEN, dev_name(dev), ksproc);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to request vring interrupt\n");
|
||||
return ret;
|
||||
|
||||
ksproc->irq_fault = platform_get_irq_byname(pdev, "exception");
|
||||
if (ksproc->irq_fault < 0)
|
||||
|
|
@ -419,7 +419,7 @@ static int keystone_rproc_probe(struct platform_device *pdev)
|
|||
ret = devm_request_irq(dev, ksproc->irq_fault, keystone_rproc_exception_interrupt,
|
||||
IRQF_NO_AUTOEN, dev_name(dev), ksproc);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to enable exception interrupt\n");
|
||||
return ret;
|
||||
|
||||
ksproc->kick_gpio = devm_gpiod_get(dev, "kick", GPIOD_ASIS);
|
||||
ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ struct mtk_scp *scp_get(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct device_node *scp_node;
|
||||
struct platform_device *scp_pdev;
|
||||
struct mtk_scp *scp;
|
||||
|
||||
scp_node = of_parse_phandle(dev->of_node, "mediatek,scp", 0);
|
||||
if (!scp_node) {
|
||||
|
|
@ -51,7 +52,13 @@ struct mtk_scp *scp_get(struct platform_device *pdev)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return platform_get_drvdata(scp_pdev);
|
||||
scp = platform_get_drvdata(scp_pdev);
|
||||
if (!scp) {
|
||||
put_device(&scp_pdev->dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return scp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scp_get);
|
||||
|
||||
|
|
@ -1239,10 +1246,8 @@ static struct mtk_scp *scp_rproc_init(struct platform_device *pdev,
|
|||
scp_irq_handler, IRQF_ONESHOT,
|
||||
pdev->name, scp);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request irq\n");
|
||||
if (ret)
|
||||
goto remove_subdev;
|
||||
}
|
||||
|
||||
return scp;
|
||||
|
||||
|
|
|
|||
|
|
@ -1140,7 +1140,7 @@ static int omap_rproc_get_boot_data(struct platform_device *pdev,
|
|||
if (!data)
|
||||
return -ENODEV;
|
||||
|
||||
if (!of_property_read_bool(np, "ti,bootreg"))
|
||||
if (!of_property_present(np, "ti,bootreg"))
|
||||
return 0;
|
||||
|
||||
oproc->boot_data = devm_kzalloc(&pdev->dev, sizeof(*oproc->boot_data),
|
||||
|
|
|
|||
|
|
@ -253,8 +253,10 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink,
|
|||
return;
|
||||
|
||||
glink->ssr_name = kstrdup_const(ssr_name, GFP_KERNEL);
|
||||
if (!glink->ssr_name)
|
||||
if (!glink->ssr_name) {
|
||||
of_node_put(glink->node);
|
||||
return;
|
||||
}
|
||||
|
||||
glink->dev = dev;
|
||||
glink->subdev.start = glink_subdev_start;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
|
|||
int ssctl_instance);
|
||||
void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon);
|
||||
bool qcom_sysmon_shutdown_acked(struct qcom_sysmon *sysmon);
|
||||
bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon);
|
||||
#else
|
||||
static inline struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
|
||||
const char *name,
|
||||
|
|
@ -84,6 +85,11 @@ static inline bool qcom_sysmon_shutdown_acked(struct qcom_sysmon *sysmon)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,6 +36,40 @@ static int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void q6v5_handover_irq_enable(struct qcom_q6v5 *q6v5)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool enable = false;
|
||||
|
||||
spin_lock_irqsave(&q6v5->handover_lock, flags);
|
||||
if (!q6v5->handover_irq_enabled) {
|
||||
q6v5->handover_irq_enabled = true;
|
||||
enable = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&q6v5->handover_lock, flags);
|
||||
|
||||
if (enable)
|
||||
enable_irq(q6v5->handover_irq);
|
||||
}
|
||||
|
||||
static void q6v5_handover_irq_disable(struct qcom_q6v5 *q6v5, bool sync)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool disable = false;
|
||||
|
||||
spin_lock_irqsave(&q6v5->handover_lock, flags);
|
||||
if (q6v5->handover_irq_enabled) {
|
||||
q6v5->handover_irq_enabled = false;
|
||||
disable = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&q6v5->handover_lock, flags);
|
||||
|
||||
if (disable)
|
||||
disable_irq_nosync(q6v5->handover_irq);
|
||||
if (sync)
|
||||
synchronize_irq(q6v5->handover_irq);
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
|
||||
* @q6v5: reference to qcom_q6v5 context to be reinitialized
|
||||
|
|
@ -64,7 +98,7 @@ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
|
|||
q6v5->running = true;
|
||||
q6v5->handover_issued = false;
|
||||
|
||||
enable_irq(q6v5->handover_irq);
|
||||
q6v5_handover_irq_enable(q6v5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -78,7 +112,8 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
|
|||
*/
|
||||
int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
|
||||
{
|
||||
disable_irq(q6v5->handover_irq);
|
||||
q6v5_handover_irq_disable(q6v5, true);
|
||||
|
||||
q6v5_load_state_toggle(q6v5, false);
|
||||
|
||||
/* Disable interconnect vote, in case handover never happened */
|
||||
|
|
@ -164,18 +199,15 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
|
|||
{
|
||||
struct qcom_q6v5 *q6v5 = data;
|
||||
|
||||
if (q6v5->handover_issued) {
|
||||
dev_err(q6v5->dev, "Handover signaled, but it already happened\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
q6v5->handover_issued = true;
|
||||
|
||||
q6v5_handover_irq_disable(q6v5, false);
|
||||
|
||||
if (q6v5->handover)
|
||||
q6v5->handover(q6v5);
|
||||
|
||||
icc_set_bw(q6v5->path, 0, 0);
|
||||
|
||||
q6v5->handover_issued = true;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -197,12 +229,13 @@ static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
|
|||
*/
|
||||
int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon)
|
||||
{
|
||||
bool was_running = q6v5->running;
|
||||
int ret;
|
||||
|
||||
q6v5->running = false;
|
||||
|
||||
/* Don't perform SMP2P dance if remote isn't running */
|
||||
if (q6v5->rproc->state != RPROC_RUNNING || qcom_sysmon_shutdown_acked(sysmon))
|
||||
/* A watchdog/fatal IRQ clears running; logical crashes still need a stop. */
|
||||
if (!was_running || qcom_sysmon_shutdown_acked(sysmon))
|
||||
return 0;
|
||||
|
||||
qcom_smem_state_update_bits(q6v5->state,
|
||||
|
|
@ -256,6 +289,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
|
|||
q6v5->crash_reason = crash_reason;
|
||||
q6v5->handover = handover;
|
||||
|
||||
spin_lock_init(&q6v5->handover_lock);
|
||||
|
||||
init_completion(&q6v5->start_done);
|
||||
init_completion(&q6v5->stop_done);
|
||||
|
||||
|
|
@ -267,10 +302,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
|
|||
NULL, q6v5_wdog_interrupt,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"q6v5 wdog", q6v5);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
|
||||
if (q6v5->fatal_irq < 0)
|
||||
|
|
@ -280,10 +313,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
|
|||
NULL, q6v5_fatal_interrupt,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"q6v5 fatal", q6v5);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
|
||||
if (q6v5->ready_irq < 0)
|
||||
|
|
@ -293,10 +324,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
|
|||
NULL, q6v5_ready_interrupt,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"q6v5 ready", q6v5);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
|
||||
if (q6v5->handover_irq < 0)
|
||||
|
|
@ -304,13 +333,11 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
|
|||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
|
||||
NULL, q6v5_handover_interrupt,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT |
|
||||
IRQF_NO_AUTOEN,
|
||||
"q6v5 handover", q6v5);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
disable_irq(q6v5->handover_irq);
|
||||
|
||||
q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
|
||||
if (q6v5->stop_irq < 0)
|
||||
|
|
@ -320,10 +347,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
|
|||
NULL, q6v5_stop_interrupt,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"q6v5 stop", q6v5);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
|
||||
if (IS_ERR(q6v5->state)) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/soc/qcom/qcom_aoss.h>
|
||||
|
||||
struct icc_path;
|
||||
|
|
@ -29,6 +30,9 @@ struct qcom_q6v5 {
|
|||
int handover_irq;
|
||||
int stop_irq;
|
||||
|
||||
/* Protects handover_irq_enabled against stop/handover races. */
|
||||
spinlock_t handover_lock;
|
||||
bool handover_irq_enabled;
|
||||
bool handover_issued;
|
||||
|
||||
struct completion start_done;
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ struct qcom_adsp {
|
|||
|
||||
phys_addr_t mem_phys;
|
||||
phys_addr_t mem_reloc;
|
||||
void *mem_region;
|
||||
void __iomem *mem_region;
|
||||
size_t mem_size;
|
||||
bool has_iommu;
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
|
|||
int ret;
|
||||
|
||||
ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware,
|
||||
adsp->mem_region, adsp->mem_phys,
|
||||
(__force void *)adsp->mem_region, adsp->mem_phys,
|
||||
adsp->mem_size, &adsp->mem_reloc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -355,6 +355,7 @@ static int adsp_map_carveout(struct rproc *rproc)
|
|||
return ret;
|
||||
|
||||
sid = args.args[0] & SID_MASK_DEFAULT;
|
||||
of_node_put(args.np);
|
||||
|
||||
/* Add SID configuration for ADSP Firmware to SMMU */
|
||||
iova = adsp->mem_phys | (sid << 32);
|
||||
|
|
@ -491,7 +492,7 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iom
|
|||
if (offset < 0 || offset + len > adsp->mem_size)
|
||||
return NULL;
|
||||
|
||||
return adsp->mem_region + offset;
|
||||
return (__force void *)adsp->mem_region + offset;
|
||||
}
|
||||
|
||||
static int adsp_parse_firmware(struct rproc *rproc, const struct firmware *fw)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "qcom_pil_info.h"
|
||||
#include "qcom_q6v5.h"
|
||||
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
|
||||
#define MPSS_CRASH_REASON_SMEM 421
|
||||
|
|
@ -162,6 +163,7 @@ struct rproc_hexagon_res {
|
|||
char **active_clk_names;
|
||||
char **proxy_pd_names;
|
||||
int version;
|
||||
int ssctl_id;
|
||||
bool need_mem_protection;
|
||||
bool need_pas_mem_setup;
|
||||
bool has_alt_reset;
|
||||
|
|
@ -1480,7 +1482,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
|
|||
}
|
||||
|
||||
if (qproc->need_pas_mem_setup) {
|
||||
ret = qcom_scm_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
|
||||
ret = qcom_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
|
||||
if (ret) {
|
||||
dev_err(qproc->dev,
|
||||
"setting up mpss memory failed: %d\n", ret);
|
||||
|
|
@ -2077,7 +2079,7 @@ static int q6v5_probe(struct platform_device *pdev)
|
|||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->need_mem_protection && !qcom_scm_is_available())
|
||||
if (desc->need_mem_protection && !qcom_pas_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
mba_image = desc->hexagon_mba_image;
|
||||
|
|
@ -2191,7 +2193,7 @@ static int q6v5_probe(struct platform_device *pdev)
|
|||
qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
|
||||
qcom_add_pdm_subdev(rproc, &qproc->pdm_subdev);
|
||||
qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
|
||||
qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
|
||||
qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", desc->ssctl_id);
|
||||
if (IS_ERR(qproc->sysmon)) {
|
||||
ret = PTR_ERR(qproc->sysmon);
|
||||
goto remove_subdevs;
|
||||
|
|
@ -2271,6 +2273,7 @@ static const struct rproc_hexagon_res sc7180_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_SC7180,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res sc7280_mss = {
|
||||
|
|
@ -2301,6 +2304,7 @@ static const struct rproc_hexagon_res sc7280_mss = {
|
|||
.has_ext_cntl_regs = true,
|
||||
.has_vq6 = true,
|
||||
.version = MSS_SC7280,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res sdm660_mss = {
|
||||
|
|
@ -2334,6 +2338,7 @@ static const struct rproc_hexagon_res sdm660_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_SDM660,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res sdm845_mss = {
|
||||
|
|
@ -2371,6 +2376,7 @@ static const struct rproc_hexagon_res sdm845_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_SDM845,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8998_mss = {
|
||||
|
|
@ -2404,6 +2410,7 @@ static const struct rproc_hexagon_res msm8998_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8998,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8996_mss = {
|
||||
|
|
@ -2444,6 +2451,7 @@ static const struct rproc_hexagon_res msm8996_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8996,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res mdm9607_mss = {
|
||||
|
|
@ -2479,6 +2487,7 @@ static const struct rproc_hexagon_res mdm9607_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MDM9607,
|
||||
.ssctl_id = 0x22,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8909_mss = {
|
||||
|
|
@ -2515,6 +2524,7 @@ static const struct rproc_hexagon_res msm8909_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8909,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8916_mss = {
|
||||
|
|
@ -2562,6 +2572,7 @@ static const struct rproc_hexagon_res msm8916_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8916,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8917_mss = {
|
||||
|
|
@ -2606,6 +2617,7 @@ static const struct rproc_hexagon_res msm8917_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8917,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8937_mss = {
|
||||
|
|
@ -2650,6 +2662,7 @@ static const struct rproc_hexagon_res msm8937_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8937,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8940_mss = {
|
||||
|
|
@ -2694,6 +2707,7 @@ static const struct rproc_hexagon_res msm8940_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8940,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8953_mss = {
|
||||
|
|
@ -2731,6 +2745,7 @@ static const struct rproc_hexagon_res msm8953_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8953,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8974_mss = {
|
||||
|
|
@ -2785,6 +2800,7 @@ static const struct rproc_hexagon_res msm8974_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8974,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8226_mss = {
|
||||
|
|
@ -2824,6 +2840,7 @@ static const struct rproc_hexagon_res msm8226_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8226,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res msm8926_mss = {
|
||||
|
|
@ -2871,6 +2888,7 @@ static const struct rproc_hexagon_res msm8926_mss = {
|
|||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8926,
|
||||
.ssctl_id = 0x12,
|
||||
};
|
||||
|
||||
static const struct of_device_id q6v5_of_match[] = {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/remoteproc.h>
|
||||
|
|
@ -60,6 +62,8 @@ struct qcom_pas_data {
|
|||
int region_assign_count;
|
||||
bool region_assign_shared;
|
||||
int region_assign_vmid;
|
||||
bool early_boot;
|
||||
bool needs_tzmem;
|
||||
};
|
||||
|
||||
struct qcom_pas {
|
||||
|
|
@ -97,8 +101,9 @@ struct qcom_pas {
|
|||
phys_addr_t mem_reloc;
|
||||
phys_addr_t dtb_mem_reloc;
|
||||
phys_addr_t region_assign_phys[MAX_ASSIGN_COUNT];
|
||||
void *mem_region;
|
||||
void *dtb_mem_region;
|
||||
|
||||
void __iomem *mem_region;
|
||||
|
||||
size_t mem_size;
|
||||
size_t dtb_mem_size;
|
||||
size_t region_assign_size[MAX_ASSIGN_COUNT];
|
||||
|
|
@ -114,9 +119,10 @@ struct qcom_pas {
|
|||
struct qcom_rproc_pdm pdm_subdev;
|
||||
struct qcom_rproc_ssr ssr_subdev;
|
||||
struct qcom_sysmon *sysmon;
|
||||
struct platform_device *bam_dmux;
|
||||
|
||||
struct qcom_scm_pas_context *pas_ctx;
|
||||
struct qcom_scm_pas_context *dtb_pas_ctx;
|
||||
struct qcom_pas_context *pas_ctx;
|
||||
struct qcom_pas_context *dtb_pas_ctx;
|
||||
};
|
||||
|
||||
static void qcom_pas_segment_dump(struct rproc *rproc,
|
||||
|
|
@ -145,7 +151,13 @@ static void qcom_pas_minidump(struct rproc *rproc)
|
|||
if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
|
||||
return;
|
||||
|
||||
pas->mem_region = qcom_pas_ctx_map(pas->pas_ctx);
|
||||
if (!pas->mem_region)
|
||||
return;
|
||||
|
||||
qcom_minidump(rproc, pas->minidump_id, qcom_pas_segment_dump);
|
||||
iounmap(pas->mem_region);
|
||||
pas->mem_region = NULL;
|
||||
}
|
||||
|
||||
static int qcom_pas_pds_enable(struct qcom_pas *pas, struct device **pds,
|
||||
|
|
@ -193,7 +205,7 @@ static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas)
|
|||
|
||||
do {
|
||||
msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS);
|
||||
ret = qcom_scm_pas_shutdown(pas->pas_id);
|
||||
ret = qcom_pas_shutdown(pas->pas_id);
|
||||
} while (ret == -EINVAL && --retry_num);
|
||||
|
||||
return ret;
|
||||
|
|
@ -209,9 +221,9 @@ static int qcom_pas_unprepare(struct rproc *rproc)
|
|||
* auth_and_reset() was successful, but in other cases clean it up
|
||||
* here.
|
||||
*/
|
||||
qcom_scm_pas_metadata_release(pas->pas_ctx);
|
||||
qcom_pas_metadata_release(pas->pas_ctx);
|
||||
if (pas->dtb_pas_id)
|
||||
qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
qcom_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -225,9 +237,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
|
|||
pas->firmware = fw;
|
||||
|
||||
if (pas->lite_pas_id)
|
||||
qcom_scm_pas_shutdown(pas->lite_pas_id);
|
||||
qcom_pas_shutdown(pas->lite_pas_id);
|
||||
if (pas->lite_dtb_pas_id)
|
||||
qcom_scm_pas_shutdown(pas->lite_dtb_pas_id);
|
||||
qcom_pas_shutdown(pas->lite_dtb_pas_id);
|
||||
|
||||
if (pas->dtb_pas_id) {
|
||||
ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev);
|
||||
|
|
@ -238,19 +250,15 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
|
|||
}
|
||||
|
||||
ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware,
|
||||
pas->dtb_firmware_name, pas->dtb_mem_region,
|
||||
&pas->dtb_mem_reloc);
|
||||
if (ret)
|
||||
goto release_dtb_metadata;
|
||||
pas->dtb_firmware_name, &pas->dtb_mem_reloc);
|
||||
if (ret) {
|
||||
qcom_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
release_firmware(pas->dtb_firmware);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
release_dtb_metadata:
|
||||
qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
release_firmware(pas->dtb_firmware);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_pas_unmap_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size)
|
||||
|
|
@ -307,7 +315,7 @@ static int qcom_pas_start(struct rproc *rproc)
|
|||
if (ret)
|
||||
goto disable_px_supply;
|
||||
|
||||
ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
|
||||
ret = qcom_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
|
||||
if (ret) {
|
||||
dev_err(pas->dev,
|
||||
"failed to authenticate dtb image and release reset\n");
|
||||
|
|
@ -316,7 +324,7 @@ static int qcom_pas_start(struct rproc *rproc)
|
|||
}
|
||||
|
||||
ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware,
|
||||
pas->mem_region, &pas->mem_reloc);
|
||||
&pas->mem_reloc);
|
||||
if (ret)
|
||||
goto release_pas_metadata;
|
||||
|
||||
|
|
@ -326,7 +334,7 @@ static int qcom_pas_start(struct rproc *rproc)
|
|||
if (ret)
|
||||
goto release_pas_metadata;
|
||||
|
||||
ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx);
|
||||
ret = qcom_pas_prepare_and_auth_reset(pas->pas_ctx);
|
||||
if (ret) {
|
||||
dev_err(pas->dev,
|
||||
"failed to authenticate image and release reset\n");
|
||||
|
|
@ -336,13 +344,13 @@ static int qcom_pas_start(struct rproc *rproc)
|
|||
ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000));
|
||||
if (ret == -ETIMEDOUT) {
|
||||
dev_err(pas->dev, "start timed out\n");
|
||||
qcom_scm_pas_shutdown(pas->pas_id);
|
||||
qcom_pas_shutdown(pas->pas_id);
|
||||
goto unmap_carveout;
|
||||
}
|
||||
|
||||
qcom_scm_pas_metadata_release(pas->pas_ctx);
|
||||
qcom_pas_metadata_release(pas->pas_ctx);
|
||||
if (pas->dtb_pas_id)
|
||||
qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
qcom_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
|
||||
/* firmware is used to pass reference from qcom_pas_start(), drop it now */
|
||||
pas->firmware = NULL;
|
||||
|
|
@ -352,9 +360,9 @@ static int qcom_pas_start(struct rproc *rproc)
|
|||
unmap_carveout:
|
||||
qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size);
|
||||
release_pas_metadata:
|
||||
qcom_scm_pas_metadata_release(pas->pas_ctx);
|
||||
qcom_pas_metadata_release(pas->pas_ctx);
|
||||
if (pas->dtb_pas_id)
|
||||
qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
qcom_pas_metadata_release(pas->dtb_pas_ctx);
|
||||
|
||||
unmap_dtb_carveout:
|
||||
if (pas->dtb_pas_id)
|
||||
|
|
@ -403,7 +411,7 @@ static int qcom_pas_stop(struct rproc *rproc)
|
|||
if (ret == -ETIMEDOUT)
|
||||
dev_err(pas->dev, "timed out on wait\n");
|
||||
|
||||
ret = qcom_scm_pas_shutdown(pas->pas_id);
|
||||
ret = qcom_pas_shutdown(pas->pas_id);
|
||||
if (ret && pas->decrypt_shutdown)
|
||||
ret = qcom_pas_shutdown_poll_decrypt(pas);
|
||||
|
||||
|
|
@ -411,7 +419,7 @@ static int qcom_pas_stop(struct rproc *rproc)
|
|||
dev_err(pas->dev, "failed to shutdown: %d\n", ret);
|
||||
|
||||
if (pas->dtb_pas_id) {
|
||||
ret = qcom_scm_pas_shutdown(pas->dtb_pas_id);
|
||||
ret = qcom_pas_shutdown(pas->dtb_pas_id);
|
||||
if (ret)
|
||||
dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
|
||||
|
||||
|
|
@ -442,7 +450,7 @@ static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is
|
|||
if (is_iomem)
|
||||
*is_iomem = true;
|
||||
|
||||
return pas->mem_region + offset;
|
||||
return (__force void *)pas->mem_region + offset;
|
||||
}
|
||||
|
||||
static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *fw)
|
||||
|
|
@ -481,11 +489,11 @@ static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *f
|
|||
*
|
||||
* Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources
|
||||
* or not and if it is not having then we pass NULL and zero as input resource
|
||||
* table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table()
|
||||
* table pointer and size respectively to the argument of qcom_pas_get_rsc_table()
|
||||
* and this is even true for Qualcomm remote processor who does follow remoteproc
|
||||
* framework.
|
||||
*/
|
||||
output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
|
||||
output_rt = qcom_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
|
||||
ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0;
|
||||
if (ret) {
|
||||
dev_err(pas->dev, "Error in getting resource table: %d\n", ret);
|
||||
|
|
@ -507,6 +515,80 @@ static unsigned long qcom_pas_panic(struct rproc *rproc)
|
|||
return qcom_q6v5_panic(&pas->q6v5);
|
||||
}
|
||||
|
||||
static int qcom_pas_attach(struct rproc *rproc)
|
||||
{
|
||||
struct qcom_pas *pas = rproc->priv;
|
||||
bool ready_state;
|
||||
bool crash_state;
|
||||
bool stop_state;
|
||||
int ret;
|
||||
|
||||
pas->q6v5.handover_issued = true;
|
||||
enable_irq(pas->q6v5.handover_irq);
|
||||
|
||||
pas->q6v5.running = true;
|
||||
ret = irq_get_irqchip_state(pas->q6v5.fatal_irq,
|
||||
IRQCHIP_STATE_LINE_LEVEL, &crash_state);
|
||||
if (ret)
|
||||
goto disable_running;
|
||||
|
||||
if (crash_state) {
|
||||
dev_err(pas->dev, "Subsystem has crashed before driver probe\n");
|
||||
rproc_report_crash(rproc, RPROC_FATAL_ERROR);
|
||||
ret = -EINVAL;
|
||||
goto disable_running;
|
||||
}
|
||||
|
||||
ret = irq_get_irqchip_state(pas->q6v5.stop_irq,
|
||||
IRQCHIP_STATE_LINE_LEVEL, &stop_state);
|
||||
if (ret)
|
||||
goto disable_running;
|
||||
|
||||
if (stop_state || qcom_sysmon_shutdown_irq_state(pas->sysmon)) {
|
||||
dev_info(pas->dev, "Subsystem found stop state set. Falling back to start.\n");
|
||||
goto unroll_attach;
|
||||
}
|
||||
|
||||
ret = irq_get_irqchip_state(pas->q6v5.ready_irq,
|
||||
IRQCHIP_STATE_LINE_LEVEL, &ready_state);
|
||||
if (ret)
|
||||
goto disable_running;
|
||||
|
||||
if (unlikely(!ready_state)) {
|
||||
/*
|
||||
* The bootloader may not support early boot, mark the state as
|
||||
* RPROC_OFFLINE so that the PAS driver can load the firmware and
|
||||
* start the remoteproc.
|
||||
*/
|
||||
dev_err(pas->dev, "Failed to get subsystem ready interrupt\n");
|
||||
goto unroll_attach;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unroll_attach:
|
||||
pas->rproc->state = RPROC_OFFLINE;
|
||||
ret = -EINVAL;
|
||||
disable_running:
|
||||
disable_irq(pas->q6v5.handover_irq);
|
||||
pas->q6v5.running = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_pas_coredump(struct rproc *rproc)
|
||||
{
|
||||
struct qcom_pas *pas = rproc->priv;
|
||||
|
||||
pas->mem_region = qcom_pas_ctx_map(pas->pas_ctx);
|
||||
if (!pas->mem_region)
|
||||
return;
|
||||
|
||||
rproc_coredump(rproc);
|
||||
iounmap(pas->mem_region);
|
||||
pas->mem_region = NULL;
|
||||
}
|
||||
|
||||
static const struct rproc_ops qcom_pas_ops = {
|
||||
.unprepare = qcom_pas_unprepare,
|
||||
.start = qcom_pas_start,
|
||||
|
|
@ -515,6 +597,8 @@ static const struct rproc_ops qcom_pas_ops = {
|
|||
.parse_fw = qcom_pas_parse_firmware,
|
||||
.load = qcom_pas_load,
|
||||
.panic = qcom_pas_panic,
|
||||
.attach = qcom_pas_attach,
|
||||
.coredump = qcom_pas_coredump,
|
||||
};
|
||||
|
||||
static const struct rproc_ops qcom_pas_minidump_ops = {
|
||||
|
|
@ -526,6 +610,7 @@ static const struct rproc_ops qcom_pas_minidump_ops = {
|
|||
.load = qcom_pas_load,
|
||||
.panic = qcom_pas_panic,
|
||||
.coredump = qcom_pas_minidump,
|
||||
.attach = qcom_pas_attach,
|
||||
};
|
||||
|
||||
static int qcom_pas_init_clock(struct qcom_pas *pas)
|
||||
|
|
@ -631,11 +716,11 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas *pas)
|
|||
|
||||
pas->mem_phys = pas->mem_reloc = res.start;
|
||||
pas->mem_size = resource_size(&res);
|
||||
pas->mem_region = devm_ioremap_resource_wc(pas->dev, &res);
|
||||
if (IS_ERR(pas->mem_region)) {
|
||||
dev_err(pas->dev, "unable to map memory region: %pR\n", &res);
|
||||
return PTR_ERR(pas->mem_region);
|
||||
}
|
||||
|
||||
pas->pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->pas_id,
|
||||
pas->mem_phys, pas->mem_size);
|
||||
if (IS_ERR(pas->pas_ctx))
|
||||
return PTR_ERR(pas->pas_ctx);
|
||||
|
||||
if (!pas->dtb_pas_id)
|
||||
return 0;
|
||||
|
|
@ -648,11 +733,12 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas *pas)
|
|||
|
||||
pas->dtb_mem_phys = pas->dtb_mem_reloc = res.start;
|
||||
pas->dtb_mem_size = resource_size(&res);
|
||||
pas->dtb_mem_region = devm_ioremap_resource_wc(pas->dev, &res);
|
||||
if (IS_ERR(pas->dtb_mem_region)) {
|
||||
dev_err(pas->dev, "unable to map dtb memory region: %pR\n", &res);
|
||||
return PTR_ERR(pas->dtb_mem_region);
|
||||
}
|
||||
|
||||
pas->dtb_pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->dtb_pas_id,
|
||||
pas->dtb_mem_phys,
|
||||
pas->dtb_mem_size);
|
||||
if (IS_ERR(pas->dtb_pas_ctx))
|
||||
return PTR_ERR(pas->dtb_pas_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -735,6 +821,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
|
|||
const struct qcom_pas_data *desc;
|
||||
struct qcom_pas *pas;
|
||||
struct rproc *rproc;
|
||||
struct device_node *node;
|
||||
const char *fw_name, *dtb_fw_name = NULL;
|
||||
const struct rproc_ops *ops = &qcom_pas_ops;
|
||||
int ret;
|
||||
|
|
@ -743,7 +830,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
|
|||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
if (!qcom_scm_is_available())
|
||||
if (!qcom_pas_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
fw_name = desc->firmware_name;
|
||||
|
|
@ -835,27 +922,21 @@ static int qcom_pas_probe(struct platform_device *pdev)
|
|||
|
||||
qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name);
|
||||
|
||||
pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id,
|
||||
pas->mem_phys, pas->mem_size);
|
||||
if (IS_ERR(pas->pas_ctx)) {
|
||||
ret = PTR_ERR(pas->pas_ctx);
|
||||
goto remove_ssr_sysmon;
|
||||
}
|
||||
pas->pas_ctx->use_tzmem = desc->needs_tzmem || rproc->has_iommu;
|
||||
if (pas->dtb_pas_id)
|
||||
pas->dtb_pas_ctx->use_tzmem = desc->needs_tzmem || rproc->has_iommu;
|
||||
|
||||
pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id,
|
||||
pas->dtb_mem_phys,
|
||||
pas->dtb_mem_size);
|
||||
if (IS_ERR(pas->dtb_pas_ctx)) {
|
||||
ret = PTR_ERR(pas->dtb_pas_ctx);
|
||||
goto remove_ssr_sysmon;
|
||||
}
|
||||
if (desc->early_boot)
|
||||
pas->rproc->state = RPROC_DETACHED;
|
||||
|
||||
pas->pas_ctx->use_tzmem = rproc->has_iommu;
|
||||
pas->dtb_pas_ctx->use_tzmem = rproc->has_iommu;
|
||||
ret = rproc_add(rproc);
|
||||
if (ret)
|
||||
goto remove_ssr_sysmon;
|
||||
|
||||
node = of_get_compatible_child(pdev->dev.of_node, "qcom,bam-dmux");
|
||||
pas->bam_dmux = of_platform_device_create(node, NULL, &pdev->dev);
|
||||
of_node_put(node);
|
||||
|
||||
return 0;
|
||||
|
||||
remove_ssr_sysmon:
|
||||
|
|
@ -880,6 +961,9 @@ static void qcom_pas_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct qcom_pas *pas = platform_get_drvdata(pdev);
|
||||
|
||||
if (pas->bam_dmux)
|
||||
of_platform_device_destroy(&pas->bam_dmux->dev, NULL);
|
||||
|
||||
rproc_del(pas->rproc);
|
||||
|
||||
qcom_q6v5_deinit(&pas->q6v5);
|
||||
|
|
@ -1354,6 +1438,111 @@ static const struct qcom_pas_data milos_cdsp_resource = {
|
|||
.smem_host_id = 5,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data nord_adsp_resource = {
|
||||
.crash_reason_smem = 423,
|
||||
.firmware_name = "adsp.mbn",
|
||||
.dtb_firmware_name = "adsp_dtb.mbn",
|
||||
.pas_id = 1,
|
||||
.dtb_pas_id = 36,
|
||||
.minidump_id = 5,
|
||||
.auto_boot = true,
|
||||
.early_boot = true,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
NULL
|
||||
},
|
||||
.load_state = "adsp",
|
||||
.ssr_name = "lpass",
|
||||
.sysmon_name = "adsp",
|
||||
.ssctl_id = 0x14,
|
||||
.smem_host_id = 2,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data nord_cdsp0_resource = {
|
||||
.crash_reason_smem = 601,
|
||||
.firmware_name = "cdsp.mbn",
|
||||
.dtb_firmware_name = "cdsp_dtb.mbn",
|
||||
.pas_id = 18,
|
||||
.dtb_pas_id = 37,
|
||||
.minidump_id = 7,
|
||||
.auto_boot = true,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
"nsp",
|
||||
NULL
|
||||
},
|
||||
.load_state = "cdsp",
|
||||
.ssr_name = "cdsp0",
|
||||
.sysmon_name = "cdsp0",
|
||||
.ssctl_id = 0x17,
|
||||
.smem_host_id = 5,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data nord_cdsp1_resource = {
|
||||
.crash_reason_smem = 633,
|
||||
.firmware_name = "cdsp1.mbn",
|
||||
.dtb_firmware_name = "cdsp1_dtb.mbn",
|
||||
.pas_id = 30,
|
||||
.dtb_pas_id = 59,
|
||||
.minidump_id = 20,
|
||||
.auto_boot = true,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
"nsp",
|
||||
NULL
|
||||
},
|
||||
.load_state = "cdsp1",
|
||||
.ssr_name = "cdsp1",
|
||||
.sysmon_name = "cdsp1",
|
||||
.ssctl_id = 0x20,
|
||||
.smem_host_id = 69,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data nord_cdsp2_resource = {
|
||||
.crash_reason_smem = 665,
|
||||
.firmware_name = "cdsp2.mbn",
|
||||
.dtb_firmware_name = "cdsp2_dtb.mbn",
|
||||
.pas_id = 57,
|
||||
.dtb_pas_id = 60,
|
||||
.minidump_id = 29,
|
||||
.auto_boot = true,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
"nsp",
|
||||
NULL
|
||||
},
|
||||
.load_state = "cdsp2",
|
||||
.ssr_name = "cdsp2",
|
||||
.sysmon_name = "cdsp2",
|
||||
.ssctl_id = 0x1f,
|
||||
.smem_host_id = 133,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data nord_cdsp3_resource = {
|
||||
.crash_reason_smem = 666,
|
||||
.firmware_name = "cdsp3.mbn",
|
||||
.dtb_firmware_name = "cdsp3_dtb.mbn",
|
||||
.pas_id = 58,
|
||||
.dtb_pas_id = 61,
|
||||
.minidump_id = 30,
|
||||
.auto_boot = true,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
"nsp",
|
||||
NULL
|
||||
},
|
||||
.load_state = "cdsp3",
|
||||
.ssr_name = "cdsp3",
|
||||
.sysmon_name = "cdsp3",
|
||||
.ssctl_id = 0x1a,
|
||||
.smem_host_id = 197,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data sm8450_mpss_resource = {
|
||||
.crash_reason_smem = 421,
|
||||
.firmware_name = "modem.mdt",
|
||||
|
|
@ -1572,8 +1761,71 @@ static const struct qcom_pas_data sm8750_mpss_resource = {
|
|||
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data kaanapali_soccp_resource = {
|
||||
.crash_reason_smem = 656,
|
||||
.firmware_name = "soccp.mbn",
|
||||
.dtb_firmware_name = "soccp_dtb.mbn",
|
||||
.pas_id = 51,
|
||||
.dtb_pas_id = 0x41,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
NULL
|
||||
},
|
||||
.ssr_name = "soccp",
|
||||
.sysmon_name = "soccp",
|
||||
.auto_boot = true,
|
||||
.early_boot = true,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data glymur_soccp_resource = {
|
||||
.crash_reason_smem = 656,
|
||||
.firmware_name = "soccp.mbn",
|
||||
.dtb_firmware_name = "soccp_dtb.mbn",
|
||||
.pas_id = 51,
|
||||
.dtb_pas_id = 0x41,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
NULL
|
||||
},
|
||||
.ssr_name = "soccp",
|
||||
.sysmon_name = "soccp",
|
||||
.auto_boot = true,
|
||||
.early_boot = true,
|
||||
.needs_tzmem = true,
|
||||
};
|
||||
|
||||
static const struct qcom_pas_data eliza_cdsp_resource = {
|
||||
.crash_reason_smem = 601,
|
||||
.firmware_name = "cdsp.mbn",
|
||||
.dtb_firmware_name = "cdsp_dtb.mbn",
|
||||
.pas_id = 18,
|
||||
.dtb_pas_id = 0x25,
|
||||
.minidump_id = 7,
|
||||
.auto_boot = true,
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mx",
|
||||
"nsp",
|
||||
NULL
|
||||
},
|
||||
.load_state = "cdsp",
|
||||
.ssr_name = "cdsp",
|
||||
.sysmon_name = "cdsp",
|
||||
.ssctl_id = 0x17,
|
||||
.smem_host_id = 5,
|
||||
.region_assign_idx = 2,
|
||||
.region_assign_count = 1,
|
||||
.region_assign_shared = true,
|
||||
.region_assign_vmid = QCOM_SCM_VMID_CDSP,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_pas_of_match[] = {
|
||||
{ .compatible = "qcom,eliza-adsp-pas", .data = &sm8550_adsp_resource },
|
||||
{ .compatible = "qcom,eliza-cdsp-pas", .data = &eliza_cdsp_resource },
|
||||
{ .compatible = "qcom,glymur-soccp-pas", .data = &glymur_soccp_resource },
|
||||
{ .compatible = "qcom,kaanapali-soccp-pas", .data = &kaanapali_soccp_resource },
|
||||
{ .compatible = "qcom,milos-adsp-pas", .data = &sm8550_adsp_resource },
|
||||
{ .compatible = "qcom,milos-cdsp-pas", .data = &milos_cdsp_resource },
|
||||
{ .compatible = "qcom,milos-mpss-pas", .data = &sm8450_mpss_resource },
|
||||
|
|
@ -1585,6 +1837,11 @@ static const struct of_device_id qcom_pas_of_match[] = {
|
|||
{ .compatible = "qcom,msm8996-slpi-pil", .data = &msm8996_slpi_resource_init },
|
||||
{ .compatible = "qcom,msm8998-adsp-pas", .data = &msm8996_adsp_resource },
|
||||
{ .compatible = "qcom,msm8998-slpi-pas", .data = &msm8996_slpi_resource_init },
|
||||
{ .compatible = "qcom,nord-adsp-pas", .data = &nord_adsp_resource },
|
||||
{ .compatible = "qcom,nord-cdsp0-pas", .data = &nord_cdsp0_resource },
|
||||
{ .compatible = "qcom,nord-cdsp1-pas", .data = &nord_cdsp1_resource },
|
||||
{ .compatible = "qcom,nord-cdsp2-pas", .data = &nord_cdsp2_resource },
|
||||
{ .compatible = "qcom,nord-cdsp3-pas", .data = &nord_cdsp3_resource },
|
||||
{ .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init },
|
||||
{ .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
|
||||
{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
|
||||
|
|
|
|||
|
|
@ -662,8 +662,6 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
|
|||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"q6v5 shutdown-ack", sysmon);
|
||||
if (ret) {
|
||||
dev_err(sysmon->dev,
|
||||
"failed to acquire shutdown-ack IRQ\n");
|
||||
kfree(sysmon);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
@ -736,6 +734,25 @@ bool qcom_sysmon_shutdown_acked(struct qcom_sysmon *sysmon)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_sysmon_shutdown_acked);
|
||||
|
||||
bool qcom_sysmon_shutdown_irq_state(struct qcom_sysmon *sysmon)
|
||||
{
|
||||
bool shutdown_state;
|
||||
int ret;
|
||||
|
||||
if (!sysmon)
|
||||
return false;
|
||||
|
||||
ret = irq_get_irqchip_state(sysmon->shutdown_irq,
|
||||
IRQCHIP_STATE_LINE_LEVEL, &shutdown_state);
|
||||
if (ret) {
|
||||
dev_warn(sysmon->dev, "failed to get shutdown_state: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
return shutdown_state;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_sysmon_shutdown_irq_state);
|
||||
|
||||
/**
|
||||
* sysmon_probe() - probe sys_mon channel
|
||||
* @rpdev: rpmsg device handle
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/soc/qcom/mdt_loader.h>
|
||||
|
|
@ -94,7 +94,7 @@ struct qcom_wcnss {
|
|||
|
||||
phys_addr_t mem_phys;
|
||||
phys_addr_t mem_reloc;
|
||||
void *mem_region;
|
||||
void __iomem *mem_region;
|
||||
size_t mem_size;
|
||||
|
||||
struct qcom_rproc_subdev smd_subdev;
|
||||
|
|
@ -158,7 +158,7 @@ static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
|
|||
int ret;
|
||||
|
||||
ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
|
||||
wcnss->mem_region, wcnss->mem_phys,
|
||||
(__force void *)wcnss->mem_region, wcnss->mem_phys,
|
||||
wcnss->mem_size, &wcnss->mem_reloc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -257,7 +257,7 @@ static int wcnss_start(struct rproc *rproc)
|
|||
wcnss_indicate_nv_download(wcnss);
|
||||
wcnss_configure_iris(wcnss);
|
||||
|
||||
ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
|
||||
ret = qcom_pas_auth_and_reset(WCNSS_PAS_ID);
|
||||
if (ret) {
|
||||
dev_err(wcnss->dev,
|
||||
"failed to authenticate image and release reset\n");
|
||||
|
|
@ -269,7 +269,7 @@ static int wcnss_start(struct rproc *rproc)
|
|||
if (wcnss->ready_irq > 0 && ret == 0) {
|
||||
/* We have a ready_irq, but it didn't fire in time. */
|
||||
dev_err(wcnss->dev, "start timed out\n");
|
||||
qcom_scm_pas_shutdown(WCNSS_PAS_ID);
|
||||
qcom_pas_shutdown(WCNSS_PAS_ID);
|
||||
ret = -ETIMEDOUT;
|
||||
goto disable_iris;
|
||||
}
|
||||
|
|
@ -311,7 +311,7 @@ static int wcnss_stop(struct rproc *rproc)
|
|||
0);
|
||||
}
|
||||
|
||||
ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
|
||||
ret = qcom_pas_shutdown(WCNSS_PAS_ID);
|
||||
if (ret)
|
||||
dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
|
||||
|
||||
|
|
@ -327,7 +327,7 @@ static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_io
|
|||
if (offset < 0 || offset + len > wcnss->mem_size)
|
||||
return NULL;
|
||||
|
||||
return wcnss->mem_region + offset;
|
||||
return (__force void *)wcnss->mem_region + offset;
|
||||
}
|
||||
|
||||
static const struct rproc_ops wcnss_ops = {
|
||||
|
|
@ -441,25 +441,31 @@ static void wcnss_release_pds(struct qcom_wcnss *wcnss)
|
|||
}
|
||||
|
||||
static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
|
||||
const struct wcnss_vreg_info *info,
|
||||
int num_vregs, int num_pd_vregs)
|
||||
const struct wcnss_data *data)
|
||||
{
|
||||
const struct wcnss_vreg_info *info = data->vregs;
|
||||
struct regulator_bulk_data *bulk;
|
||||
size_t i, possible_pds = 0, num_vregs = data->num_vregs;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WCNSS_MAX_PDS; i++)
|
||||
if (data->pd_names[i])
|
||||
possible_pds++;
|
||||
|
||||
/*
|
||||
* If attaching the power domains suceeded we can skip requesting
|
||||
* the regulators for the power domains. For old device trees we need to
|
||||
* reserve extra space to manage them through the regulator interface.
|
||||
*/
|
||||
if (wcnss->num_pds) {
|
||||
if (possible_pds >= num_vregs) {
|
||||
/* Do nothing if vregs do not include PD regulators (pronto-v3) */
|
||||
} else if (wcnss->num_pds) {
|
||||
info += wcnss->num_pds;
|
||||
/* Handle single power domain case */
|
||||
if (wcnss->num_pds < num_pd_vregs)
|
||||
num_vregs += num_pd_vregs - wcnss->num_pds;
|
||||
if (wcnss->num_pds < data->num_pd_vregs)
|
||||
num_vregs += data->num_pd_vregs - wcnss->num_pds;
|
||||
} else {
|
||||
num_vregs += num_pd_vregs;
|
||||
num_vregs += data->num_pd_vregs;
|
||||
}
|
||||
|
||||
bulk = devm_kcalloc(wcnss->dev,
|
||||
|
|
@ -515,10 +521,8 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss,
|
|||
NULL, thread_fn,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"wcnss", wcnss);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request %s IRQ failed\n", name);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return the IRQ number if the IRQ was successfully acquired */
|
||||
return irq_number;
|
||||
|
|
@ -557,10 +561,10 @@ static int wcnss_probe(struct platform_device *pdev)
|
|||
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
if (!qcom_scm_is_available())
|
||||
if (!qcom_pas_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
|
||||
if (!qcom_pas_supported(WCNSS_PAS_ID)) {
|
||||
dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
|
@ -607,8 +611,7 @@ static int wcnss_probe(struct platform_device *pdev)
|
|||
if (ret && (ret != -ENODATA || !data->num_pd_vregs))
|
||||
return ret;
|
||||
|
||||
ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs,
|
||||
data->num_pd_vregs);
|
||||
ret = wcnss_init_regulators(wcnss, data);
|
||||
if (ret)
|
||||
goto detach_pds;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,35 +19,6 @@ struct rcar_rproc {
|
|||
struct reset_control *rst;
|
||||
};
|
||||
|
||||
static int rcar_rproc_mem_alloc(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
struct device *dev = &rproc->dev;
|
||||
void *va;
|
||||
|
||||
dev_dbg(dev, "map memory: %pa+%zx\n", &mem->dma, mem->len);
|
||||
va = ioremap_wc(mem->dma, mem->len);
|
||||
if (!va) {
|
||||
dev_err(dev, "Unable to map memory region: %pa+%zx\n",
|
||||
&mem->dma, mem->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Update memory entry va */
|
||||
mem->va = va;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_rproc_mem_release(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
dev_dbg(&rproc->dev, "unmap memory: %pa\n", &mem->dma);
|
||||
iounmap(mem->va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_rproc_prepare(struct rproc *rproc)
|
||||
{
|
||||
struct device *dev = rproc->dev.parent;
|
||||
|
|
@ -73,8 +44,8 @@ static int rcar_rproc_prepare(struct rproc *rproc)
|
|||
mem = rproc_mem_entry_init(dev, NULL,
|
||||
res.start,
|
||||
resource_size(&res), da,
|
||||
rcar_rproc_mem_alloc,
|
||||
rcar_rproc_mem_release,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
res.name);
|
||||
|
||||
if (!mem)
|
||||
|
|
@ -86,12 +57,8 @@ static int rcar_rproc_prepare(struct rproc *rproc)
|
|||
|
||||
static int rcar_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rproc_elf_load_rsc_table(rproc, fw);
|
||||
if (ret)
|
||||
dev_info(&rproc->dev, "No resource table in elf\n");
|
||||
|
||||
rproc_elf_load_rsc_table_optional(rproc, fw, dev_info,
|
||||
"No resource table in elf\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1099,6 +1099,8 @@ static int rproc_start_subdevices(struct rproc *rproc)
|
|||
}
|
||||
}
|
||||
|
||||
rproc->subdevs_started = true;
|
||||
|
||||
return 0;
|
||||
|
||||
unroll_registration:
|
||||
|
|
@ -1114,10 +1116,15 @@ static void rproc_stop_subdevices(struct rproc *rproc, bool crashed)
|
|||
{
|
||||
struct rproc_subdev *subdev;
|
||||
|
||||
if (!rproc->subdevs_started)
|
||||
return;
|
||||
|
||||
list_for_each_entry_reverse(subdev, &rproc->subdevs, node) {
|
||||
if (subdev->stop)
|
||||
subdev->stop(subdev, crashed);
|
||||
}
|
||||
|
||||
rproc->subdevs_started = false;
|
||||
}
|
||||
|
||||
static void rproc_unprepare_subdevices(struct rproc *rproc)
|
||||
|
|
@ -1668,18 +1675,21 @@ static void rproc_auto_boot_callback(const struct firmware *fw, void *context)
|
|||
release_firmware(fw);
|
||||
}
|
||||
|
||||
static void rproc_attach_work(struct work_struct *work)
|
||||
{
|
||||
struct rproc *rproc = container_of(work, struct rproc, attach_work);
|
||||
|
||||
rproc_boot(rproc);
|
||||
}
|
||||
|
||||
static int rproc_trigger_auto_boot(struct rproc *rproc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Since the remote processor is in a detached state, it has already
|
||||
* been booted by another entity. As such there is no point in waiting
|
||||
* for a firmware image to be loaded, we can simply initiate the process
|
||||
* of attaching to it immediately.
|
||||
*/
|
||||
if (rproc->state == RPROC_DETACHED)
|
||||
return rproc_boot(rproc);
|
||||
if (rproc->state == RPROC_DETACHED) {
|
||||
schedule_work(&rproc->attach_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're initiating an asynchronous firmware loading, so we can
|
||||
|
|
@ -1776,7 +1786,20 @@ static int rproc_attach_recovery(struct rproc *rproc)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __rproc_attach(rproc);
|
||||
/* clean up all acquired resources */
|
||||
rproc_resource_cleanup(rproc);
|
||||
|
||||
/* release HW resources if needed */
|
||||
rproc_unprepare_device(rproc);
|
||||
|
||||
rproc_disable_iommu(rproc);
|
||||
|
||||
/* Free the copy of the resource table */
|
||||
kfree(rproc->cached_table);
|
||||
rproc->cached_table = NULL;
|
||||
rproc->table_ptr = NULL;
|
||||
|
||||
return rproc_attach(rproc);
|
||||
}
|
||||
|
||||
static int rproc_boot_recovery(struct rproc *rproc)
|
||||
|
|
@ -1828,6 +1851,11 @@ int rproc_trigger_recovery(struct rproc *rproc)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (READ_ONCE(rproc->deleting)) {
|
||||
ret = -ENODEV;
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
/* State could have changed before we got the mutex */
|
||||
if (rproc->state != RPROC_CRASHED)
|
||||
goto unlock_mutex;
|
||||
|
|
@ -1860,6 +1888,11 @@ static void rproc_crash_handler_work(struct work_struct *work)
|
|||
|
||||
mutex_lock(&rproc->lock);
|
||||
|
||||
if (READ_ONCE(rproc->deleting)) {
|
||||
mutex_unlock(&rproc->lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rproc->state == RPROC_CRASHED) {
|
||||
/* handle only the first crash detected */
|
||||
mutex_unlock(&rproc->lock);
|
||||
|
|
@ -1915,9 +1948,9 @@ int rproc_boot(struct rproc *rproc)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (rproc->state == RPROC_DELETED) {
|
||||
if (READ_ONCE(rproc->deleting)) {
|
||||
ret = -ENODEV;
|
||||
dev_err(dev, "can't boot deleted rproc %s\n", rproc->name);
|
||||
dev_err(dev, "can't boot deleting rproc %s\n", rproc->name);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
|
|
@ -1955,6 +1988,54 @@ int rproc_boot(struct rproc *rproc)
|
|||
}
|
||||
EXPORT_SYMBOL(rproc_boot);
|
||||
|
||||
static int __rproc_shutdown(struct rproc *rproc, bool force)
|
||||
{
|
||||
struct device *dev = &rproc->dev;
|
||||
bool crashed;
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&rproc->lock);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rproc->state != RPROC_RUNNING &&
|
||||
rproc->state != RPROC_ATTACHED &&
|
||||
rproc->state != RPROC_CRASHED) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
crashed = rproc->state == RPROC_CRASHED;
|
||||
|
||||
if (!atomic_dec_and_test(&rproc->power) && !force) {
|
||||
/* The remote processor is still needed by another user. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rproc_stop(rproc, crashed);
|
||||
if (ret) {
|
||||
atomic_inc(&rproc->power);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* clean up all acquired resources */
|
||||
rproc_resource_cleanup(rproc);
|
||||
|
||||
/* release HW resources if needed */
|
||||
rproc_unprepare_device(rproc);
|
||||
|
||||
rproc_disable_iommu(rproc);
|
||||
|
||||
/* Free the copy of the resource table */
|
||||
kfree(rproc->cached_table);
|
||||
rproc->cached_table = NULL;
|
||||
rproc->table_ptr = NULL;
|
||||
out:
|
||||
mutex_unlock(&rproc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* rproc_shutdown() - power off the remote processor
|
||||
* @rproc: the remote processor
|
||||
|
|
@ -1978,46 +2059,7 @@ EXPORT_SYMBOL(rproc_boot);
|
|||
*/
|
||||
int rproc_shutdown(struct rproc *rproc)
|
||||
{
|
||||
struct device *dev = &rproc->dev;
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&rproc->lock);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rproc->state != RPROC_RUNNING &&
|
||||
rproc->state != RPROC_ATTACHED) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if the remote proc is still needed, bail out */
|
||||
if (!atomic_dec_and_test(&rproc->power))
|
||||
goto out;
|
||||
|
||||
ret = rproc_stop(rproc, false);
|
||||
if (ret) {
|
||||
atomic_inc(&rproc->power);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* clean up all acquired resources */
|
||||
rproc_resource_cleanup(rproc);
|
||||
|
||||
/* release HW resources if needed */
|
||||
rproc_unprepare_device(rproc);
|
||||
|
||||
rproc_disable_iommu(rproc);
|
||||
|
||||
/* Free the copy of the resource table */
|
||||
kfree(rproc->cached_table);
|
||||
rproc->cached_table = NULL;
|
||||
rproc->table_ptr = NULL;
|
||||
out:
|
||||
mutex_unlock(&rproc->lock);
|
||||
return ret;
|
||||
return __rproc_shutdown(rproc, false);
|
||||
}
|
||||
EXPORT_SYMBOL(rproc_shutdown);
|
||||
|
||||
|
|
@ -2317,6 +2359,7 @@ int rproc_add(struct rproc *rproc)
|
|||
return 0;
|
||||
|
||||
rproc_remove_dev:
|
||||
cancel_work_sync(&rproc->crash_handler);
|
||||
rproc_delete_debug_dir(rproc);
|
||||
device_del(dev);
|
||||
rproc_remove_cdev:
|
||||
|
|
@ -2506,7 +2549,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
|
|||
INIT_LIST_HEAD(&rproc->subdevs);
|
||||
INIT_LIST_HEAD(&rproc->dump_segments);
|
||||
|
||||
INIT_WORK(&rproc->attach_work, rproc_attach_work);
|
||||
INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
|
||||
spin_lock_init(&rproc->crash_handler_lock);
|
||||
|
||||
rproc->state = RPROC_OFFLINE;
|
||||
|
||||
|
|
@ -2570,15 +2615,19 @@ EXPORT_SYMBOL(rproc_put);
|
|||
*/
|
||||
int rproc_del(struct rproc *rproc)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!rproc)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: make sure this works with rproc->power > 1 */
|
||||
rproc_shutdown(rproc);
|
||||
spin_lock_irqsave(&rproc->crash_handler_lock, flags);
|
||||
WRITE_ONCE(rproc->deleting, true);
|
||||
spin_unlock_irqrestore(&rproc->crash_handler_lock, flags);
|
||||
|
||||
mutex_lock(&rproc->lock);
|
||||
rproc->state = RPROC_DELETED;
|
||||
mutex_unlock(&rproc->lock);
|
||||
if (cancel_work_sync(&rproc->crash_handler))
|
||||
pm_relax(rproc->dev.parent);
|
||||
|
||||
__rproc_shutdown(rproc, true);
|
||||
|
||||
rproc_delete_debug_dir(rproc);
|
||||
|
||||
|
|
@ -2691,18 +2740,26 @@ EXPORT_SYMBOL(rproc_get_by_child);
|
|||
*/
|
||||
void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!rproc) {
|
||||
pr_err("NULL rproc pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rproc->crash_handler_lock, flags);
|
||||
if (READ_ONCE(rproc->deleting)) {
|
||||
spin_unlock_irqrestore(&rproc->crash_handler_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prevent suspend while the remoteproc is being recovered */
|
||||
pm_stay_awake(rproc->dev.parent);
|
||||
queue_work(rproc_recovery_wq, &rproc->crash_handler);
|
||||
spin_unlock_irqrestore(&rproc->crash_handler_lock, flags);
|
||||
|
||||
dev_err(&rproc->dev, "crash detected in %s: type %s\n",
|
||||
rproc->name, rproc_crash_to_string(type));
|
||||
|
||||
queue_work(rproc_recovery_wq, &rproc->crash_handler);
|
||||
}
|
||||
EXPORT_SYMBOL(rproc_report_crash);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/firmware.h>
|
||||
#ifdef CONFIG_HAS_IOMEM
|
||||
#include <linux/io.h>
|
||||
#endif
|
||||
|
||||
struct rproc;
|
||||
|
||||
|
|
@ -122,6 +125,57 @@ rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...);
|
|||
void rproc_add_rvdev(struct rproc *rproc, struct rproc_vdev *rvdev);
|
||||
void rproc_remove_rvdev(struct rproc_vdev *rvdev);
|
||||
|
||||
#ifdef CONFIG_HAS_IOMEM
|
||||
static inline int rproc_mem_entry_ioremap_wc(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
void __iomem *va;
|
||||
|
||||
va = ioremap_wc(mem->dma, mem->len);
|
||||
if (!va) {
|
||||
dev_err(&rproc->dev, "Unable to map memory region: %pa+%zx\n",
|
||||
&mem->dma, mem->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mem->va = (__force void *)va;
|
||||
mem->is_iomem = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rproc_mem_entry_iounmap(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
iounmap((__force __iomem void *)mem->va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int rproc_mem_entry_ioremap_wc(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rproc_mem_entry_iounmap(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define rproc_elf_load_rsc_table_optional(rproc, fw, dev_func, fmt, ...) \
|
||||
({ \
|
||||
int ret = rproc_elf_load_rsc_table(rproc, fw); \
|
||||
if (ret == -EINVAL) { \
|
||||
dev_func(&rproc->dev, fmt, ##__VA_ARGS__); \
|
||||
return 0; \
|
||||
} else { \
|
||||
return ret; \
|
||||
} \
|
||||
})
|
||||
|
||||
static inline int rproc_prepare_device(struct rproc *rproc)
|
||||
{
|
||||
if (rproc->ops->prepare)
|
||||
|
|
|
|||
|
|
@ -168,7 +168,6 @@ static const char * const rproc_state_string[] = {
|
|||
[RPROC_SUSPENDED] = "suspended",
|
||||
[RPROC_RUNNING] = "running",
|
||||
[RPROC_CRASHED] = "crashed",
|
||||
[RPROC_DELETED] = "deleted",
|
||||
[RPROC_ATTACHED] = "attached",
|
||||
[RPROC_DETACHED] = "detached",
|
||||
[RPROC_LAST] = "invalid",
|
||||
|
|
|
|||
|
|
@ -88,33 +88,6 @@ static void st_rproc_kick(struct rproc *rproc, int vqid)
|
|||
dev_err(dev, "failed to send message via mbox: %d\n", ret);
|
||||
}
|
||||
|
||||
static int st_rproc_mem_alloc(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
struct device *dev = rproc->dev.parent;
|
||||
void *va;
|
||||
|
||||
va = ioremap_wc(mem->dma, mem->len);
|
||||
if (!va) {
|
||||
dev_err(dev, "Unable to map memory region: %pa+%zx\n",
|
||||
&mem->dma, mem->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Update memory entry va */
|
||||
mem->va = va;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_rproc_mem_release(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
iounmap(mem->va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
struct device *dev = rproc->dev.parent;
|
||||
|
|
@ -138,8 +111,8 @@ static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
|||
mem = rproc_mem_entry_init(dev, NULL,
|
||||
(dma_addr_t)res.start,
|
||||
resource_size(&res), res.start,
|
||||
st_rproc_mem_alloc,
|
||||
st_rproc_mem_release,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
"%.*s",
|
||||
strchrnul(res.name, '@') - res.name,
|
||||
res.name);
|
||||
|
|
|
|||
|
|
@ -113,35 +113,6 @@ static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stm32_rproc_mem_alloc(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
struct device *dev = rproc->dev.parent;
|
||||
void *va;
|
||||
|
||||
dev_dbg(dev, "map memory: %pad+%zx\n", &mem->dma, mem->len);
|
||||
va = (__force void *)ioremap_wc(mem->dma, mem->len);
|
||||
if (IS_ERR_OR_NULL(va)) {
|
||||
dev_err(dev, "Unable to map memory region: %pad+0x%zx\n",
|
||||
&mem->dma, mem->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Update memory entry va */
|
||||
mem->va = va;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rproc_mem_release(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
|
||||
iounmap((__force __iomem void *)mem->va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rproc_of_memory_translations(struct platform_device *pdev,
|
||||
struct stm32_rproc *ddata)
|
||||
{
|
||||
|
|
@ -237,8 +208,8 @@ static int stm32_rproc_prepare(struct rproc *rproc)
|
|||
mem = rproc_mem_entry_init(dev, NULL,
|
||||
(dma_addr_t)res.start,
|
||||
resource_size(&res), da,
|
||||
stm32_rproc_mem_alloc,
|
||||
stm32_rproc_mem_release,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
"%.*s", strchrnul(res.name, '@') - res.name,
|
||||
res.name);
|
||||
if (mem)
|
||||
|
|
@ -263,9 +234,8 @@ static int stm32_rproc_prepare(struct rproc *rproc)
|
|||
|
||||
static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
if (rproc_elf_load_rsc_table(rproc, fw))
|
||||
dev_warn(&rproc->dev, "no resource table found for this firmware\n");
|
||||
|
||||
rproc_elf_load_rsc_table_optional(rproc, fw, dev_warn,
|
||||
"no resource table found for this firmware\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -712,8 +682,7 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
|
|||
err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
|
||||
dev_name(dev), pdev);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err,
|
||||
"failed to request wdg irq\n");
|
||||
return err;
|
||||
|
||||
ddata->wdg_irq = irq;
|
||||
|
||||
|
|
@ -957,4 +926,3 @@ MODULE_DESCRIPTION("STM32 Remote Processor Control Driver");
|
|||
MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
|
||||
MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
|
|
|
|||
|
|
@ -1074,11 +1074,9 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
kproc->reset = devm_reset_control_get_exclusive(cdev, NULL);
|
||||
if (IS_ERR_OR_NULL(kproc->reset)) {
|
||||
ret = PTR_ERR_OR_ZERO(kproc->reset);
|
||||
if (!ret)
|
||||
ret = -ENODEV;
|
||||
dev_err_probe(cdev, ret, "failed to get reset handle\n");
|
||||
if (IS_ERR(kproc->reset)) {
|
||||
ret = dev_err_probe(cdev, PTR_ERR(kproc->reset),
|
||||
"failed to get reset handle\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ struct rsc_tbl_data {
|
|||
const uintptr_t rsc_tbl;
|
||||
} __packed;
|
||||
|
||||
enum xlnx_rproc_fw_rsc {
|
||||
XLNX_RPROC_FW_CRASH_REPORT = RSC_VENDOR_START,
|
||||
};
|
||||
|
||||
/*
|
||||
* Hardcoded TCM bank values. This will stay in driver to maintain backward
|
||||
* compatibility with device-tree that does not have TCM information.
|
||||
|
|
@ -131,9 +135,27 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = {
|
|||
{0xffe30000UL, 0x30000, 0x10000UL, PD_R5_1_BTCM, "btcm1"},
|
||||
};
|
||||
|
||||
#define CRASH_REASON_STR_LEN 16
|
||||
|
||||
/**
|
||||
* struct xlnx_rproc_crash_report - resource to know crash status and reason
|
||||
*
|
||||
* @version: version of this resource
|
||||
* @crashed: if true, the rproc is notifying crash, time to recover
|
||||
* @crash_reason: number to describe reason of crash
|
||||
* @crash_reason_str: short string description of crash reason
|
||||
*/
|
||||
struct xlnx_rproc_crash_report {
|
||||
u8 version;
|
||||
u8 crashed;
|
||||
u8 crash_reason;
|
||||
char crash_reason_str[CRASH_REASON_STR_LEN];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct zynqmp_r5_core - remoteproc core's internal data
|
||||
*
|
||||
* @crash_report: rproc crash state and reason
|
||||
* @rsc_tbl_va: resource table virtual address
|
||||
* @sram: Array of sram memories assigned to this core
|
||||
* @num_sram: number of sram for this core
|
||||
|
|
@ -147,6 +169,7 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = {
|
|||
* @ipi: pointer to mailbox information
|
||||
*/
|
||||
struct zynqmp_r5_core {
|
||||
struct xlnx_rproc_crash_report *crash_report;
|
||||
void __iomem *rsc_tbl_va;
|
||||
struct zynqmp_sram_bank *sram;
|
||||
int num_sram;
|
||||
|
|
@ -204,11 +227,27 @@ static int event_notified_idr_cb(int id, void *ptr, void *data)
|
|||
*/
|
||||
static void handle_event_notified(struct work_struct *work)
|
||||
{
|
||||
struct xlnx_rproc_crash_report *report;
|
||||
struct zynqmp_r5_core *r5_core;
|
||||
struct mbox_info *ipi;
|
||||
struct rproc *rproc;
|
||||
|
||||
ipi = container_of(work, struct mbox_info, mbox_work);
|
||||
rproc = ipi->r5_core->rproc;
|
||||
r5_core = ipi->r5_core;
|
||||
report = r5_core->crash_report;
|
||||
|
||||
/* report crash only if expected */
|
||||
if (report && report->crashed) {
|
||||
if (rproc->state == RPROC_ATTACHED || rproc->state == RPROC_RUNNING) {
|
||||
report->crash_reason_str[CRASH_REASON_STR_LEN - 1] = '\0';
|
||||
dev_warn(&rproc->dev, "crash reason id: %d %s\n",
|
||||
report->crash_reason, report->crash_reason_str);
|
||||
rproc_report_crash(rproc, RPROC_FATAL_ERROR);
|
||||
report->crashed = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We only use IPI for interrupt. The RPU firmware side may or may
|
||||
|
|
@ -364,49 +403,12 @@ static void zynqmp_r5_rproc_kick(struct rproc *rproc, int vqid)
|
|||
static int zynqmp_r5_rproc_start(struct rproc *rproc)
|
||||
{
|
||||
struct zynqmp_r5_core *r5_core = rproc->priv;
|
||||
enum rpu_boot_mem bootmem;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The exception vector pointers (EVP) refer to the base-address of
|
||||
* exception vectors (for reset, IRQ, FIQ, etc). The reset-vector
|
||||
* starts at the base-address and subsequent vectors are on 4-byte
|
||||
* boundaries.
|
||||
*
|
||||
* Exception vectors can start either from 0x0000_0000 (LOVEC) or
|
||||
* from 0xFFFF_0000 (HIVEC) which is mapped in the OCM (On-Chip Memory)
|
||||
*
|
||||
* Usually firmware will put Exception vectors at LOVEC.
|
||||
*
|
||||
* It is not recommend that you change the exception vector.
|
||||
* Changing the EVP to HIVEC will result in increased interrupt latency
|
||||
* and jitter. Also, if the OCM is secured and the Cortex-R5F processor
|
||||
* is non-secured, then the Cortex-R5F processor cannot access the
|
||||
* HIVEC exception vectors in the OCM.
|
||||
*/
|
||||
bootmem = (rproc->bootaddr >= 0xFFFC0000) ?
|
||||
PM_RPU_BOOTMEM_HIVEC : PM_RPU_BOOTMEM_LOVEC;
|
||||
|
||||
dev_dbg(r5_core->dev, "RPU boot addr 0x%llx from %s.", rproc->bootaddr,
|
||||
bootmem == PM_RPU_BOOTMEM_HIVEC ? "OCM" : "TCM");
|
||||
|
||||
/* Request node before starting RPU core if new version of API is supported */
|
||||
if (zynqmp_pm_feature(PM_REQUEST_NODE) > 1) {
|
||||
ret = zynqmp_pm_request_node(r5_core->pm_domain_id,
|
||||
ZYNQMP_PM_CAPABILITY_ACCESS, 0,
|
||||
ZYNQMP_PM_REQUEST_ACK_BLOCKING);
|
||||
if (ret < 0) {
|
||||
dev_err(r5_core->dev, "failed to request 0x%x",
|
||||
r5_core->pm_domain_id);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = zynqmp_pm_request_wake(r5_core->pm_domain_id, 1,
|
||||
bootmem, ZYNQMP_PM_REQUEST_ACK_NO);
|
||||
ret = zynqmp_pm_start_rpu(r5_core->pm_domain_id, rproc->bootaddr);
|
||||
if (ret)
|
||||
dev_err(r5_core->dev,
|
||||
"failed to start RPU = 0x%x\n", r5_core->pm_domain_id);
|
||||
dev_err(&rproc->dev, "failed to start RPU\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -423,73 +425,20 @@ static int zynqmp_r5_rproc_stop(struct rproc *rproc)
|
|||
struct zynqmp_r5_core *r5_core = rproc->priv;
|
||||
int ret;
|
||||
|
||||
/* Use release node API to stop core if new version of API is supported */
|
||||
if (zynqmp_pm_feature(PM_RELEASE_NODE) > 1) {
|
||||
ret = zynqmp_pm_release_node(r5_core->pm_domain_id);
|
||||
if (ret)
|
||||
dev_err(r5_core->dev, "failed to stop remoteproc RPU %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = zynqmp_pm_stop_rpu(r5_core->pm_domain_id);
|
||||
if (ret)
|
||||
dev_err(&rproc->dev, "failed to stop RPU\n");
|
||||
|
||||
/*
|
||||
* Check expected version of EEMI call before calling it. This avoids
|
||||
* any error or warning prints from firmware as it is expected that fw
|
||||
* doesn't support it.
|
||||
* Clear attach on recovery flag during stop operation. The next state
|
||||
* of the remote processor is expected to be in "Running" state. In this
|
||||
* state, boot recovery method must take place over attach on recovery.
|
||||
*/
|
||||
if (zynqmp_pm_feature(PM_FORCE_POWERDOWN) != 1) {
|
||||
dev_dbg(r5_core->dev, "EEMI interface %d ver 1 not supported\n",
|
||||
PM_FORCE_POWERDOWN);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* maintain force pwr down for backward compatibility */
|
||||
ret = zynqmp_pm_force_pwrdwn(r5_core->pm_domain_id,
|
||||
ZYNQMP_PM_REQUEST_ACK_BLOCKING);
|
||||
if (ret)
|
||||
dev_err(r5_core->dev, "core force power down failed\n");
|
||||
test_and_clear_bit(RPROC_FEAT_ATTACH_ON_RECOVERY, rproc->features);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* zynqmp_r5_mem_region_map()
|
||||
* @rproc: single R5 core's corresponding rproc instance
|
||||
* @mem: mem descriptor to map reserved memory-regions
|
||||
*
|
||||
* Callback to map va for memory-region's carveout.
|
||||
*
|
||||
* return 0 on success, otherwise non-zero value on failure
|
||||
*/
|
||||
static int zynqmp_r5_mem_region_map(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
void __iomem *va;
|
||||
|
||||
va = ioremap_wc(mem->dma, mem->len);
|
||||
if (IS_ERR_OR_NULL(va))
|
||||
return -ENOMEM;
|
||||
|
||||
mem->va = (void *)va;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* zynqmp_r5_rproc_mem_unmap
|
||||
* @rproc: single R5 core's corresponding rproc instance
|
||||
* @mem: mem entry to unmap
|
||||
*
|
||||
* Unmap memory-region carveout
|
||||
*
|
||||
* return: always returns 0
|
||||
*/
|
||||
static int zynqmp_r5_mem_region_unmap(struct rproc *rproc,
|
||||
struct rproc_mem_entry *mem)
|
||||
{
|
||||
iounmap((void __iomem *)mem->va);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* add_mem_regions_carveout()
|
||||
* @rproc: single R5 core's corresponding rproc instance
|
||||
|
|
@ -526,8 +475,8 @@ static int add_mem_regions_carveout(struct rproc *rproc)
|
|||
rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL,
|
||||
(dma_addr_t)res.start,
|
||||
resource_size(&res), res.start,
|
||||
zynqmp_r5_mem_region_map,
|
||||
zynqmp_r5_mem_region_unmap,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
"%.*s",
|
||||
strchrnul(res.name, '@') - res.name,
|
||||
res.name);
|
||||
|
|
@ -564,8 +513,8 @@ static int add_sram_carveouts(struct rproc *rproc)
|
|||
rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL,
|
||||
dma_addr,
|
||||
len, da,
|
||||
zynqmp_r5_mem_region_map,
|
||||
zynqmp_r5_mem_region_unmap,
|
||||
rproc_mem_entry_ioremap_wc,
|
||||
rproc_mem_entry_iounmap,
|
||||
sram->sram_res.name);
|
||||
if (!rproc_mem) {
|
||||
dev_err(&rproc->dev, "failed to add sram %s da=0x%x, size=0x%lx",
|
||||
|
|
@ -718,20 +667,15 @@ static int add_tcm_banks(struct rproc *rproc)
|
|||
*/
|
||||
static int zynqmp_r5_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rproc_elf_load_rsc_table(rproc, fw);
|
||||
if (ret == -EINVAL) {
|
||||
/*
|
||||
* resource table only required for IPC.
|
||||
* if not present, this is not necessarily an error;
|
||||
* for example, loading r5 hello world application
|
||||
* so simply inform user and keep going.
|
||||
*/
|
||||
dev_info(&rproc->dev, "no resource table found.\n");
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
/*
|
||||
* resource table only required for IPC.
|
||||
* if not present, this is not necessarily an error;
|
||||
* for example, loading r5 hello world application
|
||||
* so simply inform user and keep going.
|
||||
*/
|
||||
rproc_elf_load_rsc_table_optional(rproc, fw, dev_info,
|
||||
"no resource table found.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -886,6 +830,24 @@ static int zynqmp_r5_detach(struct rproc *rproc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int zynqmp_r5_handle_rsc(struct rproc *rproc, u32 rsc_type, void *rsc,
|
||||
int offset, int avail)
|
||||
{
|
||||
struct zynqmp_r5_core *r5_core = rproc->priv;
|
||||
void *rsc_offset = (r5_core->rsc_tbl_va + offset);
|
||||
|
||||
if (rsc_type != XLNX_RPROC_FW_CRASH_REPORT)
|
||||
return RSC_IGNORED;
|
||||
|
||||
r5_core->crash_report = rsc_offset;
|
||||
/* reset all values */
|
||||
r5_core->crash_report->crashed = false;
|
||||
r5_core->crash_report->crash_reason = 0;
|
||||
r5_core->crash_report->crash_reason_str[0] = '\0';
|
||||
|
||||
return RSC_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rproc_ops zynqmp_r5_rproc_ops = {
|
||||
.prepare = zynqmp_r5_rproc_prepare,
|
||||
.unprepare = zynqmp_r5_rproc_unprepare,
|
||||
|
|
@ -900,6 +862,7 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = {
|
|||
.get_loaded_rsc_table = zynqmp_r5_get_loaded_rsc_table,
|
||||
.attach = zynqmp_r5_attach,
|
||||
.detach = zynqmp_r5_detach,
|
||||
.handle_rsc = zynqmp_r5_handle_rsc,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -939,7 +902,7 @@ static struct zynqmp_r5_core *zynqmp_r5_alloc_rproc_core(struct device *cdev)
|
|||
|
||||
rproc_coredump_set_elf_info(r5_rproc, ELFCLASS32, EM_ARM);
|
||||
|
||||
r5_rproc->recovery_disabled = true;
|
||||
r5_rproc->recovery_disabled = false;
|
||||
r5_rproc->has_iommu = false;
|
||||
r5_rproc->auto_boot = false;
|
||||
|
||||
|
|
@ -1288,6 +1251,9 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster,
|
|||
if (zynqmp_r5_get_rsc_table_va(r5_core))
|
||||
dev_dbg(r5_core->dev, "rsc tbl not found\n");
|
||||
r5_core->rproc->state = RPROC_DETACHED;
|
||||
/* Enable attach on recovery method. Clear it during rproc stop. */
|
||||
rproc_set_feature(r5_core->rproc,
|
||||
RPROC_FEAT_ATTACH_ON_RECOVERY);
|
||||
r5_core->rproc->auto_boot = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,10 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/mdt_loader.h>
|
||||
|
|
@ -229,7 +230,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
|
|||
|
||||
static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
|
||||
const char *fw_name, int pas_id, phys_addr_t mem_phys,
|
||||
struct qcom_scm_pas_context *ctx)
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
const struct elf32_phdr *phdrs;
|
||||
const struct elf32_phdr *phdr;
|
||||
|
|
@ -271,7 +272,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx);
|
||||
ret = qcom_pas_init_image(pas_id, metadata, metadata_len, ctx);
|
||||
kfree(metadata);
|
||||
if (ret) {
|
||||
/* Invalid firmware metadata */
|
||||
|
|
@ -280,7 +281,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
|
|||
}
|
||||
|
||||
if (relocate) {
|
||||
ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
|
||||
ret = qcom_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
|
||||
if (ret) {
|
||||
/* Unable to set up relocation */
|
||||
dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
|
||||
|
|
@ -472,28 +473,34 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
|
|||
* firmware segments (e.g., .bXX files). Authentication of the segments done
|
||||
* by a separate call.
|
||||
*
|
||||
* The PAS context must be initialized using qcom_scm_pas_context_init()
|
||||
* The PAS context must be initialized using devm_qcom_pas_context_alloc()
|
||||
* prior to invoking this function.
|
||||
*
|
||||
* @ctx: Pointer to the PAS (Peripheral Authentication Service) context
|
||||
* @fw: Firmware object representing the .mdt file
|
||||
* @firmware: Name of the firmware used to construct segment file names
|
||||
* @mem_region: Memory region allocated for loading the firmware
|
||||
* @reloc_base: Physical address adjusted after relocation
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
|
||||
const char *firmware, void *mem_region, phys_addr_t *reloc_base)
|
||||
int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
|
||||
const char *firmware, phys_addr_t *reloc_base)
|
||||
{
|
||||
void __iomem *mem_region;
|
||||
int ret;
|
||||
|
||||
ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, ctx->mem_phys,
|
||||
ctx->mem_size, reloc_base);
|
||||
mem_region = qcom_pas_ctx_map(ctx);
|
||||
if (!mem_region)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = qcom_mdt_load_no_init(ctx->dev, fw, firmware, (__force void *)mem_region,
|
||||
ctx->mem_phys, ctx->mem_size, reloc_base);
|
||||
iounmap(mem_region);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_mdt_pas_load);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
#ifndef __QCOM_PAS_H
|
||||
#define __QCOM_PAS_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct qcom_pas_context {
|
||||
|
|
@ -22,6 +24,16 @@ struct qcom_pas_context {
|
|||
bool use_tzmem;
|
||||
};
|
||||
|
||||
static inline void __iomem *qcom_pas_ctx_map(struct qcom_pas_context *ctx)
|
||||
{
|
||||
void __iomem *ptr = ioremap_wc(ctx->mem_phys, ctx->mem_size);
|
||||
|
||||
if (!ptr)
|
||||
dev_err(ctx->dev, "unable to map memory region: %pa+%zx\n",
|
||||
&ctx->mem_phys, ctx->mem_size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool qcom_pas_is_available(void);
|
||||
struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
|
||||
u32 pas_id,
|
||||
|
|
|
|||
|
|
@ -652,6 +652,8 @@ int zynqmp_pm_get_node_status(const u32 node, u32 *const status,
|
|||
u32 *const requirements, u32 *const usage);
|
||||
int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status,
|
||||
u32 *const requirements, u32 *const usage);
|
||||
int zynqmp_pm_start_rpu(const u32 node, const u64 bootaddr);
|
||||
int zynqmp_pm_stop_rpu(const u32 node);
|
||||
int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value);
|
||||
int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config,
|
||||
u32 value);
|
||||
|
|
@ -968,6 +970,16 @@ static inline int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const statu
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int zynqmp_pm_start_rpu(const u32 node, const u64 bootaddr)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int zynqmp_pm_stop_rpu(const u32 node)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int zynqmp_pm_set_sd_config(u32 node,
|
||||
enum pm_sd_config_type config,
|
||||
u32 value)
|
||||
|
|
|
|||
|
|
@ -1,35 +1,8 @@
|
|||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
/*
|
||||
* Remote Processor Framework
|
||||
*
|
||||
* Copyright(c) 2011 Texas Instruments, Inc.
|
||||
* Copyright(c) 2011 Google, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Texas Instruments nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef REMOTEPROC_H
|
||||
|
|
@ -37,6 +10,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/completion.h>
|
||||
|
|
@ -127,10 +101,10 @@ struct rproc_ops {
|
|||
int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
|
||||
int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
|
||||
int offset, int avail);
|
||||
struct resource_table *(*find_loaded_rsc_table)(
|
||||
struct rproc *rproc, const struct firmware *fw);
|
||||
struct resource_table *(*get_loaded_rsc_table)(
|
||||
struct rproc *rproc, size_t *size);
|
||||
struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc,
|
||||
const struct firmware *fw);
|
||||
struct resource_table *(*get_loaded_rsc_table)(struct rproc *rproc,
|
||||
size_t *size);
|
||||
int (*load)(struct rproc *rproc, const struct firmware *fw);
|
||||
int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
|
||||
u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
|
||||
|
|
@ -145,7 +119,6 @@ struct rproc_ops {
|
|||
* a message.
|
||||
* @RPROC_RUNNING: device is up and running
|
||||
* @RPROC_CRASHED: device has crashed; need to start recovery
|
||||
* @RPROC_DELETED: device is deleted
|
||||
* @RPROC_ATTACHED: device has been booted by another entity and the core
|
||||
* has attached to it
|
||||
* @RPROC_DETACHED: device has been booted by another entity and waiting
|
||||
|
|
@ -163,10 +136,9 @@ enum rproc_state {
|
|||
RPROC_SUSPENDED = 1,
|
||||
RPROC_RUNNING = 2,
|
||||
RPROC_CRASHED = 3,
|
||||
RPROC_DELETED = 4,
|
||||
RPROC_ATTACHED = 5,
|
||||
RPROC_DETACHED = 6,
|
||||
RPROC_LAST = 7,
|
||||
RPROC_ATTACHED = 4,
|
||||
RPROC_DETACHED = 5,
|
||||
RPROC_LAST = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -259,7 +231,10 @@ enum rproc_features {
|
|||
* @subdevs: list of subdevices, to following the running state
|
||||
* @notifyids: idr for dynamically assigning rproc-wide unique notify ids
|
||||
* @index: index of this rproc device
|
||||
* @attach_work: workqueue for attaching rproc
|
||||
* @crash_handler: workqueue for handling a crash
|
||||
* @crash_handler_lock: serializes crash handler queueing and deletion
|
||||
* @deleting: remoteproc deletion has begun
|
||||
* @crash_cnt: crash counter
|
||||
* @recovery_disabled: flag that state if recovery was disabled
|
||||
* @max_notifyid: largest allocated notify id.
|
||||
|
|
@ -271,6 +246,7 @@ enum rproc_features {
|
|||
* @has_iommu: flag to indicate if remote processor is behind an MMU
|
||||
* @auto_boot: flag to indicate if remote processor should be auto-started
|
||||
* @sysfs_read_only: flag to make remoteproc sysfs files read only
|
||||
* @subdevs_started: flag to indicate if subdevs have started
|
||||
* @dump_segments: list of segments in the firmware
|
||||
* @nb_vdev: number of vdev currently handled by rproc
|
||||
* @elf_class: firmware ELF class
|
||||
|
|
@ -301,7 +277,10 @@ struct rproc {
|
|||
struct list_head subdevs;
|
||||
struct idr notifyids;
|
||||
int index;
|
||||
struct work_struct attach_work;
|
||||
struct work_struct crash_handler;
|
||||
spinlock_t crash_handler_lock;
|
||||
bool deleting;
|
||||
unsigned int crash_cnt;
|
||||
bool recovery_disabled;
|
||||
int max_notifyid;
|
||||
|
|
@ -312,6 +291,7 @@ struct rproc {
|
|||
bool has_iommu;
|
||||
bool auto_boot;
|
||||
bool sysfs_read_only;
|
||||
bool subdevs_started;
|
||||
struct list_head dump_segments;
|
||||
int nb_vdev;
|
||||
u8 elf_class;
|
||||
|
|
@ -375,7 +355,6 @@ struct rproc_vring {
|
|||
* @index: vdev position versus other vdev declared in resource table
|
||||
*/
|
||||
struct rproc_vdev {
|
||||
|
||||
struct rproc_subdev subdev;
|
||||
struct platform_device *pdev;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,8 @@
|
|||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
/*
|
||||
* Resource table and its types data structure
|
||||
*
|
||||
* Copyright(c) 2011 Texas Instruments, Inc.
|
||||
* Copyright(c) 2011 Google, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Texas Instruments nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RSC_TABLE_H
|
||||
|
|
@ -337,17 +310,22 @@ static inline int rsc_table_for_each_entry(struct resource_table *table,
|
|||
int i, ret;
|
||||
|
||||
for (i = 0; i < table->num; i++) {
|
||||
int offset = table->offset[i];
|
||||
struct fw_rsc_hdr *hdr = (void *)table + offset;
|
||||
int avail = table_sz - offset - sizeof(*hdr);
|
||||
int rsc_offset = offset + sizeof(*hdr);
|
||||
void *rsc = (void *)hdr + sizeof(*hdr);
|
||||
u32 offset = table->offset[i];
|
||||
struct fw_rsc_hdr *hdr;
|
||||
int avail, rsc_offset;
|
||||
void *rsc;
|
||||
|
||||
if (avail < 0) {
|
||||
if (offset < sizeof(*table) || offset >= table_sz ||
|
||||
table_sz - offset < sizeof(*hdr)) {
|
||||
dev_err(dev, "rsc table is truncated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdr = (void *)table + offset;
|
||||
avail = table_sz - offset - sizeof(*hdr);
|
||||
rsc_offset = offset + sizeof(*hdr);
|
||||
rsc = (void *)hdr + sizeof(*hdr);
|
||||
|
||||
ret = cb(hdr->type, rsc, rsc_offset, avail, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
struct device;
|
||||
struct firmware;
|
||||
struct qcom_scm_pas_context;
|
||||
struct qcom_pas_context;
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
|
||||
|
||||
|
|
@ -20,8 +20,8 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
phys_addr_t mem_phys, size_t mem_size,
|
||||
phys_addr_t *reloc_base);
|
||||
|
||||
int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
|
||||
const char *firmware, void *mem_region, phys_addr_t *reloc_base);
|
||||
int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
|
||||
const char *firmware, phys_addr_t *reloc_base);
|
||||
|
||||
int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
|
||||
const char *fw_name, void *mem_region,
|
||||
|
|
@ -45,9 +45,9 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx,
|
||||
static inline int qcom_mdt_pas_load(struct qcom_pas_context *ctx,
|
||||
const struct firmware *fw, const char *firmware,
|
||||
void *mem_region, phys_addr_t *reloc_base)
|
||||
phys_addr_t *reloc_base)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user