History

Merge tag 'rproc-v5.3' of git://github.com/andersson/remoteproc

Pull remoteproc updates from Bjorn Andersson: "This adds support for the STM32 remoteproc, additional i.MX platforms with Cortex M4 remoteprocs and Qualcomm's QCS404 Compute DSP. Also initial support for vendor specific resource table entries and support for unprocessed Qualcomm firmware files" * tag 'rproc-v5.3' of git://github.com/andersson/remoteproc: remoteproc: stm32: fix building without ARM SMCC remoteproc: qcom: q6v5-mss: Fix build error without QCOM_MDT_LOADER remoteproc: copy parent dma_pfn_offset for vdev remoteproc: qcom: q6v5-mss: Support loading non-split images soc: qcom: mdt_loader: Support loading non-split images remoteproc: stm32: add an ST stm32_rproc driver dt-bindings: remoteproc: add bindings for stm32 remote processor driver dt-bindings: stm32: add bindings for ML-AHB interconnect remoteproc: Use struct_size() helper remoteproc: add vendor resources handling remoteproc: imx: Fix typo in "failed" remoteproc: imx: Broaden the Kconfig selection logic remoteproc,rpmsg: add missing MAINTAINERS file entries remoteproc: qcom: qdsp6-adsp: Add support for QCS404 CDSP dt-bindings: remoteproc: Rename and amend Hexagon v56 binding

Linus Torvalds committed 7 years ago

Commit fdcec002 parents 7636b75 93f1d3e17 files · +1009 −57Browse files

Unified · Split

17 files
  1. Documentation/devicetree/bindings/arm/stm32/mlahb.txt +37 −0
  2. Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt +25 −10
  3. Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt +63 −0
  4. Documentation/remoteproc.txt +9 −5
  5. MAINTAINERS +5 −0
  6. drivers/remoteproc/Kconfig +17 −1
  7. drivers/remoteproc/Makefile +1 −0
  8. drivers/remoteproc/imx_rproc.c +4 −4
  9. drivers/remoteproc/qcom_q6v5_adsp.c +55 −18
  10. drivers/remoteproc/qcom_q6v5_mss.c +25 −8
  11. drivers/remoteproc/remoteproc_core.c +15 −0
  12. drivers/remoteproc/remoteproc_elf_loader.c +1 −2
  13. drivers/remoteproc/remoteproc_internal.h +11 −0
  14. drivers/remoteproc/stm32_rproc.c +628 −0
  15. drivers/soc/qcom/mdt_loader.c +85 −3
  16. include/linux/remoteproc.h +26 −6
  17. include/linux/soc/qcom/mdt_loader.h +2 −0
Documentation/devicetree/bindings/arm/stm32/mlahb.txt+37−0
@@ -0,0 +1,37 @@
1ML-AHB interconnect bindings
2
3These bindings describe the STM32 SoCs ML-AHB interconnect bus which connects
4a Cortex-M subsystem with dedicated memories.
5The MCU SRAM and RETRAM memory parts can be accessed through different addresses
6(see "RAM aliases" in [1]) using different buses (see [2]) : balancing the
7Cortex-M firmware accesses among those ports allows to tune the system
8performance.
9
10[1]: https://www.st.com/resource/en/reference_manual/dm00327659.pdf
11[2]: https://wiki.st.com/stm32mpu/wiki/STM32MP15_RAM_mapping
12
13Required properties:
14- compatible: should be "simple-bus"
15- dma-ranges: describes memory addresses translation between the local CPU and
16 the remote Cortex-M processor. Each memory region, is declared with
17 3 parameters:
18 - param 1: device base address (Cortex-M processor address)
19 - param 2: physical base address (local CPU address)
20 - param 3: size of the memory region.
21
22The Cortex-M remote processor accessed via the mlahb interconnect is described
23by a child node.
24
25Example:
26mlahb {
27 compatible = "simple-bus";
28 #address-cells = <1>;
29 #size-cells = <1>;
30 dma-ranges = <0x00000000 0x38000000 0x10000>,
31 <0x10000000 0x10000000 0x60000>,
32 <0x30000000 0x30000000 0x60000>;
33
34 m4_rproc: m4@10000000 {
35 ...
36 };
37};
Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txtrenamed from Documentation/devicetree/bindings/remoteproc/qcom,adsp-pil.txt+25−10
@@ -1,12 +1,13 @@
1Qualcomm Technology Inc. ADSP Peripheral Image Loader1Qualcomm Technology Inc. Hexagon v56 Peripheral Image Loader
2 2
3This document defines the binding for a component that loads and boots firmware3This document defines the binding for a component that loads and boots firmware
4on the Qualcomm Technology Inc. ADSP Hexagon core.4on the Qualcomm Technology Inc. Hexagon v56 core.
5 5
6- compatible:6- compatible:
7 Usage: required7 Usage: required
8 Value type: <string>8 Value type: <string>
9 Definition: must be one of:9 Definition: must be one of:
10 "qcom,qcs404-cdsp-pil",
10 "qcom,sdm845-adsp-pil"11 "qcom,sdm845-adsp-pil"
11 12
12- reg:13- reg:
@@ -28,10 +29,11 @@ on the Qualcomm Technology Inc. ADSP Hexagon core. · 15 unmodified lines
28- clocks:29- clocks:
29 Usage: required30 Usage: required
30 Value type: <prop-encoded-array>31 Value type: <prop-encoded-array>
31 Definition: List of 8 phandle and clock specifier pairs for the adsp.32 Definition: List of phandles and clock specifier pairs for the Hexagon,
33 per clock-names below.
32 34
33- clock-names:35- clock-names:
34 Usage: required36 Usage: required for SDM845 ADSP
35 Value type: <stringlist>37 Value type: <stringlist>
36 Definition: List of clock input name strings sorted in the same38 Definition: List of clock input name strings sorted in the same
37 order as the clocks property. Definition must have39 order as the clocks property. Definition must have
@@ -39,6 +41,14 @@ on the Qualcomm Technology Inc. ADSP Hexagon core. · 1 unmodified line
39 "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep"41 "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep"
40 and "qdsp6ss_core".42 and "qdsp6ss_core".
41 43
44- clock-names:
45 Usage: required for QCS404 CDSP
46 Value type: <stringlist>
47 Definition: List of clock input name strings sorted in the same
48 order as the clocks property. Definition must have
49 "xo", "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave",
50 "q6ss_master", "q6_axim".
51
42- power-domains:52- power-domains:
43 Usage: required53 Usage: required
44 Value type: <phandle>54 Value type: <phandle>
@@ -47,28 +57,33 @@ on the Qualcomm Technology Inc. ADSP Hexagon core. · 2 unmodified lines
47- resets:57- resets:
48 Usage: required58 Usage: required
49 Value type: <phandle>59 Value type: <phandle>
50 Definition: reference to the list of 2 reset-controller for the adsp.60 Definition: reference to the list of resets for the Hexagon.
51 61
52- reset-names:62- reset-names:
53 Usage: required63 Usage: required for SDM845 ADSP
54 Value type: <stringlist>64 Value type: <stringlist>
55 Definition: must be "pdc_sync" and "cc_lpass"65 Definition: must be "pdc_sync" and "cc_lpass"
56 66
67- reset-names:
68 Usage: required for QCS404 CDSP
69 Value type: <stringlist>
70 Definition: must be "restart"
71
57- qcom,halt-regs:72- qcom,halt-regs:
58 Usage: required73 Usage: required
59 Value type: <prop-encoded-array>74 Value type: <prop-encoded-array>
60 Definition: a phandle reference to a syscon representing TCSR followed75 Definition: a phandle reference to a syscon representing TCSR followed
61 by the offset within syscon for lpass halt register.76 by the offset within syscon for Hexagon halt register.
62 77
63- memory-region:78- memory-region:
64 Usage: required79 Usage: required
65 Value type: <phandle>80 Value type: <phandle>
66 Definition: reference to the reserved-memory for the ADSP81 Definition: reference to the reserved-memory for the firmware
67 82
68- qcom,smem-states:83- qcom,smem-states:
69 Usage: required84 Usage: required
70 Value type: <phandle>85 Value type: <phandle>
71 Definition: reference to the smem state for requesting the ADSP to86 Definition: reference to the smem state for requesting the Hexagon to
72 shut down87 shut down
73 88
74- qcom,smem-state-names:89- qcom,smem-state-names:
@@ -79,7 +94,7 @@ on the Qualcomm Technology Inc. ADSP Hexagon core. · 4 unmodified lines
79 94
80= SUBNODES95= SUBNODES
81The adsp node may have an subnode named "glink-edge" that describes the96The adsp node may have an subnode named "glink-edge" that describes the
82communication edge, channels and devices related to the ADSP.97communication edge, channels and devices related to the Hexagon.
83See ../soc/qcom/qcom,glink.txt for details on how to describe these.98See ../soc/qcom/qcom,glink.txt for details on how to describe these.
84 99
85= EXAMPLE100= EXAMPLE
Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt+63−0
@@ -0,0 +1,63 @@
1STMicroelectronics STM32 Remoteproc
2-----------------------------------
3This document defines the binding for the remoteproc component that loads and
4boots firmwares on the ST32MP family chipset.
5
6Required properties:
7- compatible: Must be "st,stm32mp1-m4"
8- reg: Address ranges of the RETRAM and MCU SRAM memories used by the
9 remote processor.
10- resets: Reference to a reset controller asserting the remote processor.
11- st,syscfg-holdboot: Reference to the system configuration which holds the
12 remote processor reset hold boot
13 1st cell: phandle of syscon block
14 2nd cell: register offset containing the hold boot setting
15 3rd cell: register bitmask for the hold boot field
16- st,syscfg-tz: Reference to the system configuration which holds the RCC trust
17 zone mode
18 1st cell: phandle to syscon block
19 2nd cell: register offset containing the RCC trust zone mode setting
20 3rd cell: register bitmask for the RCC trust zone mode bit
21
22Optional properties:
23- interrupts: Should contain the watchdog interrupt
24- mboxes: This property is required only if the rpmsg/virtio functionality
25 is used. List of phandle and mailbox channel specifiers:
26 - a channel (a) used to communicate through virtqueues with the
27 remote proc.
28 Bi-directional channel:
29 - from local to remote = send message
30 - from remote to local = send message ack
31 - a channel (b) working the opposite direction of channel (a)
32 - a channel (c) used by the local proc to notify the remote proc
33 that it is about to be shut down.
34 Unidirectional channel:
35 - from local to remote, where ACK from the remote means
36 that it is ready for shutdown
37- mbox-names: This property is required if the mboxes property is used.
38 - must be "vq0" for channel (a)
39 - must be "vq1" for channel (b)
40 - must be "shutdown" for channel (c)
41- memory-region: List of phandles to the reserved memory regions associated with
42 the remoteproc device. This is variable and describes the
43 memories shared with the remote processor (eg: remoteproc
44 firmware and carveouts, rpmsg vrings, ...).
45 (see ../reserved-memory/reserved-memory.txt)
46- st,syscfg-pdds: Reference to the system configuration which holds the remote
47 processor deep sleep setting
48 1st cell: phandle to syscon block
49 2nd cell: register offset containing the deep sleep setting
50 3rd cell: register bitmask for the deep sleep bit
51- st,auto-boot: If defined, when remoteproc is probed, it loads the default
52 firmware and starts the remote processor.
53
54Example:
55 m4_rproc: m4@10000000 {
56 compatible = "st,stm32mp1-m4";
57 reg = <0x10000000 0x40000>,
58 <0x30000000 0x40000>,
59 <0x38000000 0x10000>;
60 resets = <&rcc MCU_R>;
61 st,syscfg-holdboot = <&rcc 0x10C 0x1>;
62 st,syscfg-tz = <&rcc 0x000 0x1>;
63 };
Documentation/remoteproc.txt+9−5
@@ -314,6 +314,8 @@ Here are the various resource types that are currently supported:: · 313 unmodified lines
314 * @RSC_VDEV: declare support for a virtio device, and serve as its314 * @RSC_VDEV: declare support for a virtio device, and serve as its
315 * virtio header.315 * virtio header.
316 * @RSC_LAST: just keep this one at the end316 * @RSC_LAST: just keep this one at the end
317 * @RSC_VENDOR_START: start of the vendor specific resource types range
318 * @RSC_VENDOR_END: end of the vendor specific resource types range
317 *319 *
318 * Please note that these values are used as indices to the rproc_handle_rsc320 * Please note that these values are used as indices to the rproc_handle_rsc
319 * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to321 * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
@@ -321,11 +323,13 @@ Here are the various resource types that are currently supported:: · 1 unmodified line
321 * please update it as needed.323 * please update it as needed.
322 */324 */
323 enum fw_resource_type {325 enum fw_resource_type {
324 RSC_CARVEOUT = 0,326 RSC_CARVEOUT = 0,
325 RSC_DEVMEM = 1,327 RSC_DEVMEM = 1,
326 RSC_TRACE = 2,328 RSC_TRACE = 2,
327 RSC_VDEV = 3,329 RSC_VDEV = 3,
328 RSC_LAST = 4,330 RSC_LAST = 4,
331 RSC_VENDOR_START = 128,
332 RSC_VENDOR_END = 512,
329 };333 };
330 334
331For more details regarding a specific resource type, please see its335For more details regarding a specific resource type, please see its
MAINTAINERS+5−0
@@ -13590,9 +13590,11 @@ L: linux-remoteproc@vger.kernel.org · 13589 unmodified lines
13590T: git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git13590T: git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git
13591S: Maintained13591S: Maintained
13592F: Documentation/devicetree/bindings/remoteproc/13592F: Documentation/devicetree/bindings/remoteproc/
13593F: Documentation/ABI/testing/sysfs-class-remoteproc
13593F: Documentation/remoteproc.txt13594F: Documentation/remoteproc.txt
13594F: drivers/remoteproc/13595F: drivers/remoteproc/
13595F: include/linux/remoteproc.h13596F: include/linux/remoteproc.h
13597F: include/linux/remoteproc/
13596 13598
13597REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM13599REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
13598M: Ohad Ben-Cohen <ohad@wizery.com>13600M: Ohad Ben-Cohen <ohad@wizery.com>
@@ -13602,8 +13604,11 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/rpmsg.git · 3 unmodified lines
13602S: Maintained13604S: Maintained
13603F: drivers/rpmsg/13605F: drivers/rpmsg/
13604F: Documentation/rpmsg.txt13606F: Documentation/rpmsg.txt
13607F: Documentation/ABI/testing/sysfs-bus-rpmsg
13605F: include/linux/rpmsg.h13608F: include/linux/rpmsg.h
13606F: include/linux/rpmsg/13609F: include/linux/rpmsg/
13610F: include/uapi/linux/rpmsg.h
13611F: samples/rpmsg/
13607 13612
13608RENESAS CLOCK DRIVERS13613RENESAS CLOCK DRIVERS
13609M: Geert Uytterhoeven <geert+renesas@glider.be>13614M: Geert Uytterhoeven <geert+renesas@glider.be>
drivers/remoteproc/Kconfig+17−1
@@ -16,7 +16,7 @@ if REMOTEPROC · 15 unmodified lines
16 16
17config IMX_REMOTEPROC17config IMX_REMOTEPROC
18 tristate "IMX6/7 remoteproc support"18 tristate "IMX6/7 remoteproc support"
19 depends on SOC_IMX6SX || SOC_IMX7D19 depends on ARCH_MXC
20 help20 help
21 Say y here to support iMX's remote processors (Cortex M421 Say y here to support iMX's remote processors (Cortex M4
22 on iMX7D) via the remote processor framework.22 on iMX7D) via the remote processor framework.
@@ -116,6 +116,7 @@ config QCOM_Q6V5_MSS · 93 unmodified lines
116 depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n116 depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
117 depends on QCOM_SYSMON || QCOM_SYSMON=n117 depends on QCOM_SYSMON || QCOM_SYSMON=n
118 select MFD_SYSCON118 select MFD_SYSCON
119 select QCOM_MDT_LOADER
119 select QCOM_Q6V5_COMMON120 select QCOM_Q6V5_COMMON
120 select QCOM_RPROC_COMMON121 select QCOM_RPROC_COMMON
121 select QCOM_SCM122 select QCOM_SCM
@@ -198,6 +199,21 @@ config ST_REMOTEPROC · 76 unmodified lines
198config ST_SLIM_REMOTEPROC199config ST_SLIM_REMOTEPROC
199 tristate200 tristate
200 201
202config STM32_RPROC
203 tristate "STM32 remoteproc support"
204 depends on ARCH_STM32
205 depends on REMOTEPROC
206 select MAILBOX
207 help
208 Say y here to support STM32 MCU processors via the
209 remote processor framework.
210
211 You want to say y here in order to enable AMP
212 use-cases to run on your platform (dedicated firmware could be
213 offloaded to remote MCU processors using this framework).
214
215 This can be either built-in or a loadable module.
216
201endif # REMOTEPROC217endif # REMOTEPROC
202 218
203endmenu219endmenu
drivers/remoteproc/Makefile+1−0
@@ -26,3 +26,4 @@ qcom_wcnss_pil-y += qcom_wcnss.o · 25 unmodified lines
26qcom_wcnss_pil-y += qcom_wcnss_iris.o26qcom_wcnss_pil-y += qcom_wcnss_iris.o
27obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o27obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
28obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o28obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o
29obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o
drivers/remoteproc/imx_rproc.c+4−4
@@ -165,7 +165,7 @@ static int imx_rproc_start(struct rproc *rproc) · 164 unmodified lines
165 ret = regmap_update_bits(priv->regmap, dcfg->src_reg,165 ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
166 dcfg->src_mask, dcfg->src_start);166 dcfg->src_mask, dcfg->src_start);
167 if (ret)167 if (ret)
168 dev_err(dev, "Filed to enable M4!\n");168 dev_err(dev, "Failed to enable M4!\n");
169 169
170 return ret;170 return ret;
171}171}
@@ -180,7 +180,7 @@ static int imx_rproc_stop(struct rproc *rproc) · 8 unmodified lines
180 ret = regmap_update_bits(priv->regmap, dcfg->src_reg,180 ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
181 dcfg->src_mask, dcfg->src_stop);181 dcfg->src_mask, dcfg->src_stop);
182 if (ret)182 if (ret)
183 dev_err(dev, "Filed to stop M4!\n");183 dev_err(dev, "Failed to stop M4!\n");
184 184
185 return ret;185 return ret;
186}186}
@@ -203,7 +203,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, · 16 unmodified lines
203 }203 }
204 }204 }
205 205
206 dev_warn(priv->dev, "Translation filed: da = 0x%llx len = 0x%x\n",206 dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
207 da, len);207 da, len);
208 return -ENOENT;208 return -ENOENT;
209}209}
@@ -349,7 +349,7 @@ static int imx_rproc_probe(struct platform_device *pdev) · 139 unmodified lines
349 349
350 ret = imx_rproc_addr_init(priv, pdev);350 ret = imx_rproc_addr_init(priv, pdev);
351 if (ret) {351 if (ret) {
352 dev_err(dev, "filed on imx_rproc_addr_init\n");352 dev_err(dev, "failed on imx_rproc_addr_init\n");
353 goto err_put_rproc;353 goto err_put_rproc;
354 }354 }
355 355
drivers/remoteproc/qcom_q6v5_adsp.c+55−18
@@ -46,11 +46,9 @@ · 45 unmodified lines
46#define LPASS_PWR_ON_REG 0x1046#define LPASS_PWR_ON_REG 0x10
47#define LPASS_HALTREQ_REG 0x047#define LPASS_HALTREQ_REG 0x0
48 48
49/* list of clocks required by ADSP PIL */49#define QDSP6SS_XO_CBCR 0x38
50static const char * const adsp_clk_id[] = {50#define QDSP6SS_CORE_CBCR 0x20
51 "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",51#define QDSP6SS_SLEEP_CBCR 0x3c
52 "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core",
53};
54 52
55struct adsp_pil_data {53struct adsp_pil_data {
56 int crash_reason_smem;54 int crash_reason_smem;
@@ -59,6 +57,9 @@ struct adsp_pil_data { · 2 unmodified lines
59 const char *ssr_name;57 const char *ssr_name;
60 const char *sysmon_name;58 const char *sysmon_name;
61 int ssctl_id;59 int ssctl_id;
60
61 const char **clk_ids;
62 int num_clks;
62};63};
63 64
64struct qcom_adsp {65struct qcom_adsp {
@@ -75,7 +76,7 @@ struct qcom_adsp { · 10 unmodified lines
75 void __iomem *qdsp6ss_base;76 void __iomem *qdsp6ss_base;
76 77
77 struct reset_control *pdc_sync_reset;78 struct reset_control *pdc_sync_reset;
78 struct reset_control *cc_lpass_restart;79 struct reset_control *restart;
79 80
80 struct regmap *halt_map;81 struct regmap *halt_map;
81 unsigned int halt_lpass;82 unsigned int halt_lpass;
@@ -143,7 +144,7 @@ reset: · 61 unmodified lines
143 /* Assert the LPASS PDC Reset */144 /* Assert the LPASS PDC Reset */
144 reset_control_assert(adsp->pdc_sync_reset);145 reset_control_assert(adsp->pdc_sync_reset);
145 /* Place the LPASS processor into reset */146 /* Place the LPASS processor into reset */
146 reset_control_assert(adsp->cc_lpass_restart);147 reset_control_assert(adsp->restart);
147 /* wait after asserting subsystem restart from AOSS */148 /* wait after asserting subsystem restart from AOSS */
148 usleep_range(200, 300);149 usleep_range(200, 300);
149 150
@@ -153,7 +154,7 @@ reset: · 3 unmodified lines
153 /* De-assert the LPASS PDC Reset */154 /* De-assert the LPASS PDC Reset */
154 reset_control_deassert(adsp->pdc_sync_reset);155 reset_control_deassert(adsp->pdc_sync_reset);
155 /* Remove the LPASS reset */156 /* Remove the LPASS reset */
156 reset_control_deassert(adsp->cc_lpass_restart);157 reset_control_deassert(adsp->restart);
157 /* wait after de-asserting subsystem restart from AOSS */158 /* wait after de-asserting subsystem restart from AOSS */
158 usleep_range(200, 300);159 usleep_range(200, 300);
159 160
@@ -192,6 +193,15 @@ static int adsp_start(struct rproc *rproc) · 32 unmodified lines
192 goto disable_power_domain;193 goto disable_power_domain;
193 }194 }
194 195
196 /* Enable the XO clock */
197 writel(1, adsp->qdsp6ss_base + QDSP6SS_XO_CBCR);
198
199 /* Enable the QDSP6SS sleep clock */
200 writel(1, adsp->qdsp6ss_base + QDSP6SS_SLEEP_CBCR);
201
202 /* Enable the QDSP6 core clock */
203 writel(1, adsp->qdsp6ss_base + QDSP6SS_CORE_CBCR);
204
195 /* Program boot address */205 /* Program boot address */
196 writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);206 writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);
197 207
@@ -280,8 +290,9 @@ static const struct rproc_ops adsp_ops = { · 82 unmodified lines
280 .load = adsp_load,290 .load = adsp_load,
281};291};
282 292
283static int adsp_init_clock(struct qcom_adsp *adsp)293static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids)
284{294{
295 int num_clks = 0;
285 int i, ret;296 int i, ret;
286 297
287 adsp->xo = devm_clk_get(adsp->dev, "xo");298 adsp->xo = devm_clk_get(adsp->dev, "xo");
@@ -292,32 +303,39 @@ static int adsp_init_clock(struct qcom_adsp *adsp) · 4 unmodified lines
292 return ret;303 return ret;
293 }304 }
294 305
295 adsp->num_clks = ARRAY_SIZE(adsp_clk_id);306 for (i = 0; clk_ids[i]; i++)
307 num_clks++;
308
309 adsp->num_clks = num_clks;
296 adsp->clks = devm_kcalloc(adsp->dev, adsp->num_clks,310 adsp->clks = devm_kcalloc(adsp->dev, adsp->num_clks,
297 sizeof(*adsp->clks), GFP_KERNEL);311 sizeof(*adsp->clks), GFP_KERNEL);
298 if (!adsp->clks)312 if (!adsp->clks)
299 return -ENOMEM;313 return -ENOMEM;
300 314
301 for (i = 0; i < adsp->num_clks; i++)315 for (i = 0; i < adsp->num_clks; i++)
302 adsp->clks[i].id = adsp_clk_id[i];316 adsp->clks[i].id = clk_ids[i];
303 317
304 return devm_clk_bulk_get(adsp->dev, adsp->num_clks, adsp->clks);318 return devm_clk_bulk_get(adsp->dev, adsp->num_clks, adsp->clks);
305}319}
306 320
307static int adsp_init_reset(struct qcom_adsp *adsp)321static int adsp_init_reset(struct qcom_adsp *adsp)
308{322{
309 adsp->pdc_sync_reset = devm_reset_control_get_exclusive(adsp->dev,323 adsp->pdc_sync_reset = devm_reset_control_get_optional_exclusive(adsp->dev,
310 "pdc_sync");324 "pdc_sync");
311 if (IS_ERR(adsp->pdc_sync_reset)) {325 if (IS_ERR(adsp->pdc_sync_reset)) {
312 dev_err(adsp->dev, "failed to acquire pdc_sync reset\n");326 dev_err(adsp->dev, "failed to acquire pdc_sync reset\n");
313 return PTR_ERR(adsp->pdc_sync_reset);327 return PTR_ERR(adsp->pdc_sync_reset);
314 }328 }
315 329
316 adsp->cc_lpass_restart = devm_reset_control_get_exclusive(adsp->dev,330 adsp->restart = devm_reset_control_get_optional_exclusive(adsp->dev, "restart");
317 "cc_lpass");331
318 if (IS_ERR(adsp->cc_lpass_restart)) {332 /* Fall back to the old "cc_lpass" if "restart" is absent */
319 dev_err(adsp->dev, "failed to acquire cc_lpass restart\n");333 if (!adsp->restart)
320 return PTR_ERR(adsp->cc_lpass_restart);334 adsp->restart = devm_reset_control_get_exclusive(adsp->dev, "cc_lpass");
335
336 if (IS_ERR(adsp->restart)) {
337 dev_err(adsp->dev, "failed to acquire restart\n");
338 return PTR_ERR(adsp->restart);
321 }339 }
322 340
323 return 0;341 return 0;
@@ -415,7 +433,7 @@ static int adsp_probe(struct platform_device *pdev) · 91 unmodified lines
415 if (ret)433 if (ret)
416 goto free_rproc;434 goto free_rproc;
417 435
418 ret = adsp_init_clock(adsp);436 ret = adsp_init_clock(adsp, desc->clk_ids);
419 if (ret)437 if (ret)
420 goto free_rproc;438 goto free_rproc;
421 439
@@ -479,9 +497,28 @@ static const struct adsp_pil_data adsp_resource_init = { · 57 unmodified lines
479 .ssr_name = "lpass",497 .ssr_name = "lpass",
480 .sysmon_name = "adsp",498 .sysmon_name = "adsp",
481 .ssctl_id = 0x14,499 .ssctl_id = 0x14,
500 .clk_ids = (const char*[]) {
501 "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
502 "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
503 },
504 .num_clks = 7,
505};
506
507static const struct adsp_pil_data cdsp_resource_init = {
508 .crash_reason_smem = 601,
509 .firmware_name = "cdsp.mdt",
510 .ssr_name = "cdsp",
511 .sysmon_name = "cdsp",
512 .ssctl_id = 0x17,
513 .clk_ids = (const char*[]) {
514 "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master",
515 "q6_axim", NULL
516 },
517 .num_clks = 7,
482};518};
483 519
484static const struct of_device_id adsp_of_match[] = {520static const struct of_device_id adsp_of_match[] = {
521 { .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
485 { .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },522 { .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
486 { },523 { },
487};524};
drivers/remoteproc/qcom_q6v5_mss.c+25−8
@@ -659,23 +659,29 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) · 658 unmodified lines
659{659{
660 unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;660 unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
661 dma_addr_t phys;661 dma_addr_t phys;
662 void *metadata;
662 int mdata_perm;663 int mdata_perm;
663 int xferop_ret;664 int xferop_ret;
665 size_t size;
664 void *ptr;666 void *ptr;
665 int ret;667 int ret;
666 668
667 ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, dma_attrs);669 metadata = qcom_mdt_read_metadata(fw, &size);
670 if (IS_ERR(metadata))
671 return PTR_ERR(metadata);
672
673 ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
668 if (!ptr) {674 if (!ptr) {
675 kfree(metadata);
669 dev_err(qproc->dev, "failed to allocate mdt buffer\n");676 dev_err(qproc->dev, "failed to allocate mdt buffer\n");
670 return -ENOMEM;677 return -ENOMEM;
671 }678 }
672 679
673 memcpy(ptr, fw->data, fw->size);680 memcpy(ptr, metadata, size);
674 681
675 /* Hypervisor mapping to access metadata by modem */682 /* Hypervisor mapping to access metadata by modem */
676 mdata_perm = BIT(QCOM_SCM_VMID_HLOS);683 mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
677 ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,684 ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, true, phys, size);
678 true, phys, fw->size);
679 if (ret) {685 if (ret) {
680 dev_err(qproc->dev,686 dev_err(qproc->dev,
681 "assigning Q6 access to metadata failed: %d\n", ret);687 "assigning Q6 access to metadata failed: %d\n", ret);
@@ -693,14 +699,14 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) · 11 unmodified lines
693 dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);699 dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
694 700
695 /* Metadata authentication done, remove modem access */701 /* Metadata authentication done, remove modem access */
696 xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,702 xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, phys, size);
697 false, phys, fw->size);
698 if (xferop_ret)703 if (xferop_ret)
699 dev_warn(qproc->dev,704 dev_warn(qproc->dev,
700 "mdt buffer not reclaimed system may become unstable\n");705 "mdt buffer not reclaimed system may become unstable\n");
701 706
702free_dma_attrs:707free_dma_attrs:
703 dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs);708 dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
709 kfree(metadata);
704 710
705 return ret < 0 ? ret : 0;711 return ret < 0 ? ret : 0;
706}712}
@@ -981,7 +987,18 @@ static int q6v5_mpss_load(struct q6v5 *qproc) · 274 unmodified lines
981 987
982 ptr = qproc->mpss_region + offset;988 ptr = qproc->mpss_region + offset;
983 989
984 if (phdr->p_filesz) {990 if (phdr->p_filesz && phdr->p_offset < fw->size) {
991 /* Firmware is large enough to be non-split */
992 if (phdr->p_offset + phdr->p_filesz > fw->size) {
993 dev_err(qproc->dev,
994 "failed to load segment %d from truncated file %s\n",
995 i, fw_name);
996 ret = -EINVAL;
997 goto release_firmware;
998 }
999
1000 memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
1001 } else if (phdr->p_filesz) {
985 /* Replace "xxx.xxx" with "xxx.bxx" */1002 /* Replace "xxx.xxx" with "xxx.bxx" */
986 sprintf(fw_name + fw_name_len - 3, "b%02d", i);1003 sprintf(fw_name + fw_name_len - 3, "b%02d", i);
987 ret = request_firmware(&seg_fw, fw_name, qproc->dev);1004 ret = request_firmware(&seg_fw, fw_name, qproc->dev);
drivers/remoteproc/remoteproc_core.c+15−0
@@ -512,6 +512,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, · 511 unmodified lines
512 /* Initialise vdev subdevice */512 /* Initialise vdev subdevice */
513 snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index);513 snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index);
514 rvdev->dev.parent = rproc->dev.parent;514 rvdev->dev.parent = rproc->dev.parent;
515 rvdev->dev.dma_pfn_offset = rproc->dev.parent->dma_pfn_offset;
515 rvdev->dev.release = rproc_rvdev_release;516 rvdev->dev.release = rproc_rvdev_release;
516 dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name);517 dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name);
517 dev_set_drvdata(&rvdev->dev, rvdev);518 dev_set_drvdata(&rvdev->dev, rvdev);
@@ -1058,6 +1059,20 @@ static int rproc_handle_resources(struct rproc *rproc, · 540 unmodified lines
1058 1059
1059 dev_dbg(dev, "rsc: type %d\n", hdr->type);1060 dev_dbg(dev, "rsc: type %d\n", hdr->type);
1060 1061
1062 if (hdr->type >= RSC_VENDOR_START &&
1063 hdr->type <= RSC_VENDOR_END) {
1064 ret = rproc_handle_rsc(rproc, hdr->type, rsc,
1065 offset + sizeof(*hdr), avail);
1066 if (ret == RSC_HANDLED)
1067 continue;
1068 else if (ret < 0)
1069 break;
1070
1071 dev_warn(dev, "unsupported vendor resource %d\n",
1072 hdr->type);
1073 continue;
1074 }
1075
1061 if (hdr->type >= RSC_LAST) {1076 if (hdr->type >= RSC_LAST) {
1062 dev_warn(dev, "unsupported resource %d\n", hdr->type);1077 dev_warn(dev, "unsupported resource %d\n", hdr->type);
1063 continue;1078 continue;
drivers/remoteproc/remoteproc_elf_loader.c+1−2
@@ -247,8 +247,7 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size) · 246 unmodified lines
247 }247 }
248 248
249 /* make sure the offsets array isn't truncated */249 /* make sure the offsets array isn't truncated */
250 if (table->num * sizeof(table->offset[0]) +250 if (struct_size(table, offset, table->num) > size) {
251 sizeof(struct resource_table) > size) {
252 dev_err(dev, "resource table incomplete\n");251 dev_err(dev, "resource table incomplete\n");
253 return NULL;252 return NULL;
254 }253 }
drivers/remoteproc/remoteproc_internal.h+11−0
@@ -98,6 +98,17 @@ static inline int rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) · 97 unmodified lines
98 return 0;98 return 0;
99}99}
100 100
101static inline
102int rproc_handle_rsc(struct rproc *rproc, u32 rsc_type, void *rsc, int offset,
103 int avail)
104{
105 if (rproc->ops->handle_rsc)
106 return rproc->ops->handle_rsc(rproc, rsc_type, rsc, offset,
107 avail);
108
109 return RSC_IGNORED;
110}
111
101static inline112static inline
102struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,113struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
103 const struct firmware *fw)114 const struct firmware *fw)
drivers/remoteproc/stm32_rproc.c+628−0
@@ -0,0 +1,628 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
4 * Authors: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
5 * Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
6 */
7
8#include <linux/arm-smccc.h>
9#include <linux/dma-mapping.h>
10#include <linux/interrupt.h>
11#include <linux/io.h>
12#include <linux/mailbox_client.h>
13#include <linux/mfd/syscon.h>
14#include <linux/module.h>
15#include <linux/of_address.h>
16#include <linux/of_device.h>
17#include <linux/of_reserved_mem.h>
18#include <linux/regmap.h>
19#include <linux/remoteproc.h>
20#include <linux/reset.h>
21
22#include "remoteproc_internal.h"
23
24#define HOLD_BOOT 0
25#define RELEASE_BOOT 1
26
27#define MBOX_NB_VQ 2
28#define MBOX_NB_MBX 3
29
30#define STM32_SMC_RCC 0x82001000
31#define STM32_SMC_REG_WRITE 0x1
32
33#define STM32_MBX_VQ0 "vq0"
34#define STM32_MBX_VQ1 "vq1"
35#define STM32_MBX_SHUTDOWN "shutdown"
36
37struct stm32_syscon {
38 struct regmap *map;
39 u32 reg;
40 u32 mask;
41};
42
43struct stm32_rproc_mem {
44 char name[20];
45 void __iomem *cpu_addr;
46 phys_addr_t bus_addr;
47 u32 dev_addr;
48 size_t size;
49};
50
51struct stm32_rproc_mem_ranges {
52 u32 dev_addr;
53 u32 bus_addr;
54 u32 size;
55};
56
57struct stm32_mbox {
58 const unsigned char name[10];
59 struct mbox_chan *chan;
60 struct mbox_client client;
61 int vq_id;
62};
63
64struct stm32_rproc {
65 struct reset_control *rst;
66 struct stm32_syscon hold_boot;
67 struct stm32_syscon pdds;
68 u32 nb_rmems;
69 struct stm32_rproc_mem *rmems;
70 struct stm32_mbox mb[MBOX_NB_MBX];
71 bool secured_soc;
72};
73
74static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da)
75{
76 unsigned int i;
77 struct stm32_rproc *ddata = rproc->priv;
78 struct stm32_rproc_mem *p_mem;
79
80 for (i = 0; i < ddata->nb_rmems; i++) {
81 p_mem = &ddata->rmems[i];
82
83 if (pa < p_mem->bus_addr ||
84 pa >= p_mem->bus_addr + p_mem->size)
85 continue;
86 *da = pa - p_mem->bus_addr + p_mem->dev_addr;
87 dev_dbg(rproc->dev.parent, "pa %pa to da %llx\n", &pa, *da);
88 return 0;
89 }
90
91 return -EINVAL;
92}
93
94static int stm32_rproc_mem_alloc(struct rproc *rproc,
95 struct rproc_mem_entry *mem)
96{
97 struct device *dev = rproc->dev.parent;
98 void *va;
99
100 dev_dbg(dev, "map memory: %pa+%x\n", &mem->dma, mem->len);
101 va = ioremap_wc(mem->dma, mem->len);
102 if (IS_ERR_OR_NULL(va)) {
103 dev_err(dev, "Unable to map memory region: %pa+%x\n",
104 &mem->dma, mem->len);
105 return -ENOMEM;
106 }
107
108 /* Update memory entry va */
109 mem->va = va;
110
111 return 0;
112}
113
114static int stm32_rproc_mem_release(struct rproc *rproc,
115 struct rproc_mem_entry *mem)
116{
117 dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
118 iounmap(mem->va);
119
120 return 0;
121}
122
123static int stm32_rproc_of_memory_translations(struct rproc *rproc)
124{
125 struct device *parent, *dev = rproc->dev.parent;
126 struct stm32_rproc *ddata = rproc->priv;
127 struct device_node *np;
128 struct stm32_rproc_mem *p_mems;
129 struct stm32_rproc_mem_ranges *mem_range;
130 int cnt, array_size, i, ret = 0;
131
132 parent = dev->parent;
133 np = parent->of_node;
134
135 cnt = of_property_count_elems_of_size(np, "dma-ranges",
136 sizeof(*mem_range));
137 if (cnt <= 0) {
138 dev_err(dev, "%s: dma-ranges property not defined\n", __func__);
139 return -EINVAL;
140 }
141
142 p_mems = devm_kcalloc(dev, cnt, sizeof(*p_mems), GFP_KERNEL);
143 if (!p_mems)
144 return -ENOMEM;
145 mem_range = kcalloc(cnt, sizeof(*mem_range), GFP_KERNEL);
146 if (!mem_range)
147 return -ENOMEM;
148
149 array_size = cnt * sizeof(struct stm32_rproc_mem_ranges) / sizeof(u32);
150
151 ret = of_property_read_u32_array(np, "dma-ranges",
152 (u32 *)mem_range, array_size);
153 if (ret) {
154 dev_err(dev, "error while get dma-ranges property: %x\n", ret);
155 goto free_mem;
156 }
157
158 for (i = 0; i < cnt; i++) {
159 p_mems[i].bus_addr = mem_range[i].bus_addr;
160 p_mems[i].dev_addr = mem_range[i].dev_addr;
161 p_mems[i].size = mem_range[i].size;
162
163 dev_dbg(dev, "memory range[%i]: da %#x, pa %pa, size %#zx:\n",
164 i, p_mems[i].dev_addr, &p_mems[i].bus_addr,
165 p_mems[i].size);
166 }
167
168 ddata->rmems = p_mems;
169 ddata->nb_rmems = cnt;
170
171free_mem:
172 kfree(mem_range);
173 return ret;
174}
175
176static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)
177{
178 struct stm32_rproc *ddata = rproc->priv;
179 int i;
180
181 for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
182 if (!strncmp(ddata->mb[i].name, name, strlen(name)))
183 return i;
184 }
185 dev_err(&rproc->dev, "mailbox %s not found\n", name);
186
187 return -EINVAL;
188}
189
190static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc,
191 const struct firmware *fw)
192{
193 if (rproc_elf_load_rsc_table(rproc, fw))
194 dev_warn(&rproc->dev, "no resource table found for this firmware\n");
195
196 return 0;
197}
198
199static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
200{
201 struct device *dev = rproc->dev.parent;
202 struct device_node *np = dev->of_node;
203 struct of_phandle_iterator it;
204 struct rproc_mem_entry *mem;
205 struct reserved_mem *rmem;
206 u64 da;
207 int index = 0;
208
209 /* Register associated reserved memory regions */
210 of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
211 while (of_phandle_iterator_next(&it) == 0) {
212 rmem = of_reserved_mem_lookup(it.node);
213 if (!rmem) {
214 dev_err(dev, "unable to acquire memory-region\n");
215 return -EINVAL;
216 }
217
218 if (stm32_rproc_pa_to_da(rproc, rmem->base, &da) < 0) {
219 dev_err(dev, "memory region not valid %pa\n",
220 &rmem->base);
221 return -EINVAL;
222 }
223
224 /* No need to map vdev buffer */
225 if (strcmp(it.node->name, "vdev0buffer")) {
226 /* Register memory region */
227 mem = rproc_mem_entry_init(dev, NULL,
228 (dma_addr_t)rmem->base,
229 rmem->size, da,
230 stm32_rproc_mem_alloc,
231 stm32_rproc_mem_release,
232 it.node->name);
233
234 if (mem)
235 rproc_coredump_add_segment(rproc, da,
236 rmem->size);
237 } else {
238 /* Register reserved memory for vdev buffer alloc */
239 mem = rproc_of_resm_mem_entry_init(dev, index,
240 rmem->size,
241 rmem->base,
242 it.node->name);
243 }
244
245 if (!mem)
246 return -ENOMEM;
247
248 rproc_add_carveout(rproc, mem);
249 index++;
250 }
251
252 return stm32_rproc_elf_load_rsc_table(rproc, fw);
253}
254
255static irqreturn_t stm32_rproc_wdg(int irq, void *data)
256{
257 struct rproc *rproc = data;
258
259 rproc_report_crash(rproc, RPROC_WATCHDOG);
260
261 return IRQ_HANDLED;
262}
263
264static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data)
265{
266 struct rproc *rproc = dev_get_drvdata(cl->dev);
267 struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client);
268
269 if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
270 dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
271}
272
273static void stm32_rproc_free_mbox(struct rproc *rproc)
274{
275 struct stm32_rproc *ddata = rproc->priv;
276 unsigned int i;
277
278 for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
279 if (ddata->mb[i].chan)
280 mbox_free_channel(ddata->mb[i].chan);
281 ddata->mb[i].chan = NULL;
282 }
283}
284
285static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = {
286 {
287 .name = STM32_MBX_VQ0,
288 .vq_id = 0,
289 .client = {
290 .rx_callback = stm32_rproc_mb_callback,
291 .tx_block = false,
292 },
293 },
294 {
295 .name = STM32_MBX_VQ1,
296 .vq_id = 1,
297 .client = {
298 .rx_callback = stm32_rproc_mb_callback,
299 .tx_block = false,
300 },
301 },
302 {
303 .name = STM32_MBX_SHUTDOWN,
304 .vq_id = -1,
305 .client = {
306 .tx_block = true,
307 .tx_done = NULL,
308 .tx_tout = 500, /* 500 ms time out */
309 },
310 }
311};
312
313static void stm32_rproc_request_mbox(struct rproc *rproc)
314{
315 struct stm32_rproc *ddata = rproc->priv;
316 struct device *dev = &rproc->dev;
317 unsigned int i;
318 const unsigned char *name;
319 struct mbox_client *cl;
320
321 /* Initialise mailbox structure table */
322 memcpy(ddata->mb, stm32_rproc_mbox, sizeof(stm32_rproc_mbox));
323
324 for (i = 0; i < MBOX_NB_MBX; i++) {
325 name = ddata->mb[i].name;
326
327 cl = &ddata->mb[i].client;
328 cl->dev = dev->parent;
329
330 ddata->mb[i].chan = mbox_request_channel_byname(cl, name);
331 if (IS_ERR(ddata->mb[i].chan)) {
332 dev_warn(dev, "cannot get %s mbox\n", name);
333 ddata->mb[i].chan = NULL;
334 }
335 }
336}
337
338static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold)
339{
340 struct stm32_rproc *ddata = rproc->priv;
341 struct stm32_syscon hold_boot = ddata->hold_boot;
342 struct arm_smccc_res smc_res;
343 int val, err;
344
345 val = hold ? HOLD_BOOT : RELEASE_BOOT;
346
347 if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) && ddata->secured_soc) {
348 arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE,
349 hold_boot.reg, val, 0, 0, 0, 0, &smc_res);
350 err = smc_res.a0;
351 } else {
352 err = regmap_update_bits(hold_boot.map, hold_boot.reg,
353 hold_boot.mask, val);
354 }
355
356 if (err)
357 dev_err(&rproc->dev, "failed to set hold boot\n");
358
359 return err;
360}
361
362static void stm32_rproc_add_coredump_trace(struct rproc *rproc)
363{
364 struct rproc_debug_trace *trace;
365 struct rproc_dump_segment *segment;
366 bool already_added;
367
368 list_for_each_entry(trace, &rproc->traces, node) {
369 already_added = false;
370
371 list_for_each_entry(segment, &rproc->dump_segments, node) {
372 if (segment->da == trace->trace_mem.da) {
373 already_added = true;
374 break;
375 }
376 }
377
378 if (!already_added)
379 rproc_coredump_add_segment(rproc, trace->trace_mem.da,
380 trace->trace_mem.len);
381 }
382}
383
384static int stm32_rproc_start(struct rproc *rproc)
385{
386 int err;
387
388 stm32_rproc_add_coredump_trace(rproc);
389
390 err = stm32_rproc_set_hold_boot(rproc, false);
391 if (err)
392 return err;
393
394 return stm32_rproc_set_hold_boot(rproc, true);
395}
396
397static int stm32_rproc_stop(struct rproc *rproc)
398{
399 struct stm32_rproc *ddata = rproc->priv;
400 int err, dummy_data, idx;
401
402 /* request shutdown of the remote processor */
403 if (rproc->state != RPROC_OFFLINE) {
404 idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
405 if (idx >= 0 && ddata->mb[idx].chan) {
406 /* a dummy data is sent to allow to block on transmit */
407 err = mbox_send_message(ddata->mb[idx].chan,
408 &dummy_data);
409 if (err < 0)
410 dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
411 }
412 }
413
414 err = stm32_rproc_set_hold_boot(rproc, true);
415 if (err)
416 return err;
417
418 err = reset_control_assert(ddata->rst);
419 if (err) {
420 dev_err(&rproc->dev, "failed to assert the reset\n");
421 return err;
422 }
423
424 /* to allow platform Standby power mode, set remote proc Deep Sleep */
425 if (ddata->pdds.map) {
426 err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
427 ddata->pdds.mask, 1);
428 if (err) {
429 dev_err(&rproc->dev, "failed to set pdds\n");
430 return err;
431 }
432 }
433
434 return 0;
435}
436
437static void stm32_rproc_kick(struct rproc *rproc, int vqid)
438{
439 struct stm32_rproc *ddata = rproc->priv;
440 unsigned int i;
441 int err;
442
443 if (WARN_ON(vqid >= MBOX_NB_VQ))
444 return;
445
446 for (i = 0; i < MBOX_NB_MBX; i++) {
447 if (vqid != ddata->mb[i].vq_id)
448 continue;
449 if (!ddata->mb[i].chan)
450 return;
451 err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid);
452 if (err < 0)
453 dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
454 __func__, ddata->mb[i].name, err);
455 return;
456 }
457}
458
459static struct rproc_ops st_rproc_ops = {
460 .start = stm32_rproc_start,
461 .stop = stm32_rproc_stop,
462 .kick = stm32_rproc_kick,
463 .load = rproc_elf_load_segments,
464 .parse_fw = stm32_rproc_parse_fw,
465 .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
466 .sanity_check = rproc_elf_sanity_check,
467 .get_boot_addr = rproc_elf_get_boot_addr,
468};
469
470static const struct of_device_id stm32_rproc_match[] = {
471 { .compatible = "st,stm32mp1-m4" },
472 {},
473};
474MODULE_DEVICE_TABLE(of, stm32_rproc_match);
475
476static int stm32_rproc_get_syscon(struct device_node *np, const char *prop,
477 struct stm32_syscon *syscon)
478{
479 int err = 0;
480
481 syscon->map = syscon_regmap_lookup_by_phandle(np, prop);
482 if (IS_ERR(syscon->map)) {
483 err = PTR_ERR(syscon->map);
484 syscon->map = NULL;
485 goto out;
486 }
487
488 err = of_property_read_u32_index(np, prop, 1, &syscon->reg);
489 if (err)
490 goto out;
491
492 err = of_property_read_u32_index(np, prop, 2, &syscon->mask);
493
494out:
495 return err;
496}
497
498static int stm32_rproc_parse_dt(struct platform_device *pdev)
499{
500 struct device *dev = &pdev->dev;
501 struct device_node *np = dev->of_node;
502 struct rproc *rproc = platform_get_drvdata(pdev);
503 struct stm32_rproc *ddata = rproc->priv;
504 struct stm32_syscon tz;
505 unsigned int tzen;
506 int err, irq;
507
508 irq = platform_get_irq(pdev, 0);
509 if (irq > 0) {
510 err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
511 dev_name(dev), rproc);
512 if (err) {
513 dev_err(dev, "failed to request wdg irq\n");
514 return err;
515 }
516
517 dev_info(dev, "wdg irq registered\n");
518 }
519
520 ddata->rst = devm_reset_control_get_by_index(dev, 0);
521 if (IS_ERR(ddata->rst)) {
522 dev_err(dev, "failed to get mcu reset\n");
523 return PTR_ERR(ddata->rst);
524 }
525
526 /*
527 * if platform is secured the hold boot bit must be written by
528 * smc call and read normally.
529 * if not secure the hold boot bit could be read/write normally
530 */
531 err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
532 if (err) {
533 dev_err(dev, "failed to get tz syscfg\n");
534 return err;
535 }
536
537 err = regmap_read(tz.map, tz.reg, &tzen);
538 if (err) {
539 dev_err(&rproc->dev, "failed to read tzen\n");
540 return err;
541 }
542 ddata->secured_soc = tzen & tz.mask;
543
544 err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
545 &ddata->hold_boot);
546 if (err) {
547 dev_err(dev, "failed to get hold boot\n");
548 return err;
549 }
550
551 err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds);
552 if (err)
553 dev_warn(dev, "failed to get pdds\n");
554
555 rproc->auto_boot = of_property_read_bool(np, "st,auto-boot");
556
557 return stm32_rproc_of_memory_translations(rproc);
558}
559
560static int stm32_rproc_probe(struct platform_device *pdev)
561{
562 struct device *dev = &pdev->dev;
563 struct stm32_rproc *ddata;
564 struct device_node *np = dev->of_node;
565 struct rproc *rproc;
566 int ret;
567
568 ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
569 if (ret)
570 return ret;
571
572 rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
573 if (!rproc)
574 return -ENOMEM;
575
576 rproc->has_iommu = false;
577 ddata = rproc->priv;
578
579 platform_set_drvdata(pdev, rproc);
580
581 ret = stm32_rproc_parse_dt(pdev);
582 if (ret)
583 goto free_rproc;
584
585 stm32_rproc_request_mbox(rproc);
586
587 ret = rproc_add(rproc);
588 if (ret)
589 goto free_mb;
590
591 return 0;
592
593free_mb:
594 stm32_rproc_free_mbox(rproc);
595free_rproc:
596 rproc_free(rproc);
597 return ret;
598}
599
600static int stm32_rproc_remove(struct platform_device *pdev)
601{
602 struct rproc *rproc = platform_get_drvdata(pdev);
603
604 if (atomic_read(&rproc->power) > 0)
605 rproc_shutdown(rproc);
606
607 rproc_del(rproc);
608 stm32_rproc_free_mbox(rproc);
609 rproc_free(rproc);
610
611 return 0;
612}
613
614static struct platform_driver stm32_rproc_driver = {
615 .probe = stm32_rproc_probe,
616 .remove = stm32_rproc_remove,
617 .driver = {
618 .name = "stm32-rproc",
619 .of_match_table = of_match_ptr(stm32_rproc_match),
620 },
621};
622module_platform_driver(stm32_rproc_driver);
623
624MODULE_DESCRIPTION("STM32 Remote Processor Control Driver");
625MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
626MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
627MODULE_LICENSE("GPL v2");
628
drivers/soc/qcom/mdt_loader.c+85−3
@@ -66,6 +66,66 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw) · 65 unmodified lines
66}66}
67EXPORT_SYMBOL_GPL(qcom_mdt_get_size);67EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
68 68
69/**
70 * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
71 * @fw: firmware of mdt header or mbn
72 * @data_len: length of the read metadata blob
73 *
74 * The mechanism that performs the authentication of the loading firmware
75 * expects an ELF header directly followed by the segment of hashes, with no
76 * padding inbetween. This function allocates a chunk of memory for this pair
77 * and copy the two pieces into the buffer.
78 *
79 * In the case of split firmware the hash is found directly following the ELF
80 * header, rather than at p_offset described by the second program header.
81 *
82 * The caller is responsible to free (kfree()) the returned pointer.
83 *
84 * Return: pointer to data, or ERR_PTR()
85 */
86void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
87{
88 const struct elf32_phdr *phdrs;
89 const struct elf32_hdr *ehdr;
90 size_t hash_offset;
91 size_t hash_size;
92 size_t ehdr_size;
93 void *data;
94
95 ehdr = (struct elf32_hdr *)fw->data;
96 phdrs = (struct elf32_phdr *)(ehdr + 1);
97
98 if (ehdr->e_phnum < 2)
99 return ERR_PTR(-EINVAL);
100
101 if (phdrs[0].p_type == PT_LOAD || phdrs[1].p_type == PT_LOAD)
102 return ERR_PTR(-EINVAL);
103
104 if ((phdrs[1].p_flags & QCOM_MDT_TYPE_MASK) != QCOM_MDT_TYPE_HASH)
105 return ERR_PTR(-EINVAL);
106
107 ehdr_size = phdrs[0].p_filesz;
108 hash_size = phdrs[1].p_filesz;
109
110 data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
111 if (!data)
112 return ERR_PTR(-ENOMEM);
113
114 /* Is the header and hash already packed */
115 if (ehdr_size + hash_size == fw->size)
116 hash_offset = phdrs[0].p_filesz;
117 else
118 hash_offset = phdrs[1].p_offset;
119
120 memcpy(data, fw->data, ehdr_size);
121 memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
122
123 *data_len = ehdr_size + hash_size;
124
125 return data;
126}
127EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
128
69static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,129static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
70 const char *firmware, int pas_id, void *mem_region,130 const char *firmware, int pas_id, void *mem_region,
71 phys_addr_t mem_phys, size_t mem_size,131 phys_addr_t mem_phys, size_t mem_size,
@@ -78,12 +138,14 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, · 6 unmodified lines
78 phys_addr_t mem_reloc;138 phys_addr_t mem_reloc;
79 phys_addr_t min_addr = PHYS_ADDR_MAX;139 phys_addr_t min_addr = PHYS_ADDR_MAX;
80 phys_addr_t max_addr = 0;140 phys_addr_t max_addr = 0;
141 size_t metadata_len;
81 size_t fw_name_len;142 size_t fw_name_len;
82 ssize_t offset;143 ssize_t offset;
144 void *metadata;
83 char *fw_name;145 char *fw_name;
84 bool relocate = false;146 bool relocate = false;
85 void *ptr;147 void *ptr;
86 int ret;148 int ret = 0;
87 int i;149 int i;
88 150
89 if (!fw || !mem_region || !mem_phys || !mem_size)151 if (!fw || !mem_region || !mem_phys || !mem_size)
@@ -101,7 +163,15 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, · 11 unmodified lines
101 return -ENOMEM;163 return -ENOMEM;
102 164
103 if (pas_init) {165 if (pas_init) {
104 ret = qcom_scm_pas_init_image(pas_id, fw->data, fw->size);166 metadata = qcom_mdt_read_metadata(fw, &metadata_len);
167 if (IS_ERR(metadata)) {
168 ret = PTR_ERR(metadata);
169 goto out;
170 }
171
172 ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len);
173
174 kfree(metadata);
105 if (ret) {175 if (ret) {
106 dev_err(dev, "invalid firmware metadata\n");176 dev_err(dev, "invalid firmware metadata\n");
107 goto out;177 goto out;
@@ -162,7 +232,19 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, · 54 unmodified lines
162 232
163 ptr = mem_region + offset;233 ptr = mem_region + offset;
164 234
165 if (phdr->p_filesz) {235 if (phdr->p_filesz && phdr->p_offset < fw->size) {
236 /* Firmware is large enough to be non-split */
237 if (phdr->p_offset + phdr->p_filesz > fw->size) {
238 dev_err(dev,
239 "failed to load segment %d from truncated file %s\n",
240 i, firmware);
241 ret = -EINVAL;
242 break;
243 }
244
245 memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
246 } else if (phdr->p_filesz) {
247 /* Firmware not large enough, load split-out segments */
166 sprintf(fw_name + fw_name_len - 3, "b%02d", i);248 sprintf(fw_name + fw_name_len - 3, "b%02d", i);
167 ret = request_firmware_into_buf(&seg_fw, fw_name, dev,249 ret = request_firmware_into_buf(&seg_fw, fw_name, dev,
168 ptr, phdr->p_filesz);250 ptr, phdr->p_filesz);
include/linux/remoteproc.h+26−6
@@ -100,7 +100,9 @@ struct fw_rsc_hdr { · 99 unmodified lines
100 * the remote processor will be writing logs.100 * the remote processor will be writing logs.
101 * @RSC_VDEV: declare support for a virtio device, and serve as its101 * @RSC_VDEV: declare support for a virtio device, and serve as its
102 * virtio header.102 * virtio header.
103 * @RSC_LAST: just keep this one at the end103 * @RSC_LAST: just keep this one at the end of standard resources
104 * @RSC_VENDOR_START: start of the vendor specific resource types range
105 * @RSC_VENDOR_END: end of the vendor specific resource types range
104 *106 *
105 * For more details regarding a specific resource type, please see its107 * For more details regarding a specific resource type, please see its
106 * dedicated structure below.108 * dedicated structure below.
@@ -111,11 +113,13 @@ struct fw_rsc_hdr { · 4 unmodified lines
111 * please update it as needed.113 * please update it as needed.
112 */114 */
113enum fw_resource_type {115enum fw_resource_type {
114 RSC_CARVEOUT = 0,116 RSC_CARVEOUT = 0,
115 RSC_DEVMEM = 1,117 RSC_DEVMEM = 1,
116 RSC_TRACE = 2,118 RSC_TRACE = 2,
117 RSC_VDEV = 3,119 RSC_VDEV = 3,
118 RSC_LAST = 4,120 RSC_LAST = 4,
121 RSC_VENDOR_START = 128,
122 RSC_VENDOR_END = 512,
119};123};
120 124
121#define FW_RSC_ADDR_ANY (-1)125#define FW_RSC_ADDR_ANY (-1)
@@ -339,6 +343,16 @@ struct rproc_mem_entry { · 217 unmodified lines
339 343
340struct firmware;344struct firmware;
341 345
346/**
347 * enum rsc_handling_status - return status of rproc_ops handle_rsc hook
348 * @RSC_HANDLED: resource was handled
349 * @RSC_IGNORED: resource was ignored
350 */
351enum rsc_handling_status {
352 RSC_HANDLED = 0,
353 RSC_IGNORED = 1,
354};
355
342/**356/**
343 * struct rproc_ops - platform-specific device handlers357 * struct rproc_ops - platform-specific device handlers
344 * @start: power on the device and boot it358 * @start: power on the device and boot it
@@ -346,6 +360,10 @@ struct firmware; · 1 unmodified line
346 * @kick: kick a virtqueue (virtqueue id given as a parameter)360 * @kick: kick a virtqueue (virtqueue id given as a parameter)
347 * @da_to_va: optional platform hook to perform address translations361 * @da_to_va: optional platform hook to perform address translations
348 * @parse_fw: parse firmware to extract information (e.g. resource table)362 * @parse_fw: parse firmware to extract information (e.g. resource table)
363 * @handle_rsc: optional platform hook to handle vendor resources. Should return
364 * RSC_HANDLED if resource was handled, RSC_IGNORED if not handled and a
365 * negative value on error
366 * @load_rsc_table: load resource table from firmware image
349 * @find_loaded_rsc_table: find the loaded resouce table367 * @find_loaded_rsc_table: find the loaded resouce table
350 * @load: load firmware to memory, where the remote processor368 * @load: load firmware to memory, where the remote processor
351 * expects to find it369 * expects to find it
@@ -358,6 +376,8 @@ struct rproc_ops { · 6 unmodified lines
358 void (*kick)(struct rproc *rproc, int vqid);376 void (*kick)(struct rproc *rproc, int vqid);
359 void * (*da_to_va)(struct rproc *rproc, u64 da, int len);377 void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
360 int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);378 int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
379 int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
380 int offset, int avail);
361 struct resource_table *(*find_loaded_rsc_table)(381 struct resource_table *(*find_loaded_rsc_table)(
362 struct rproc *rproc, const struct firmware *fw);382 struct rproc *rproc, const struct firmware *fw);
363 int (*load)(struct rproc *rproc, const struct firmware *fw);383 int (*load)(struct rproc *rproc, const struct firmware *fw);
include/linux/soc/qcom/mdt_loader.h+2−0
@@ -21,4 +21,6 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, · 20 unmodified lines
21 const char *fw_name, int pas_id, void *mem_region,21 const char *fw_name, int pas_id, void *mem_region,
22 phys_addr_t mem_phys, size_t mem_size,22 phys_addr_t mem_phys, size_t mem_size,
23 phys_addr_t *reloc_base);23 phys_addr_t *reloc_base);
24void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len);
25
24#endif26#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t