Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull remoteproc updates from Bjorn Andersson:
"rproc-virtio device names are now auto generated, to avoid conflicts
between remoteproc instances.

The imx_rproc driver is extended with support for communicating with
and attaching to a running M4 on i.MX8QXP, as well as support for
attaching to the M4 after self-recovering from a crash. Support is
added for i.MX8QM and mailbox channels are reconnected during the
recovery process, in order to avoid data corruption.

The Xilinx Zynqmp firmware interface is extended and support for the
Xilinx R5 RPU is introduced.

Various resources leaks, primarily in error paths, throughout the
Qualcomm drivers are corrected.

Lastly a fix to ensure that pm_relax is invoked even if the remoteproc
instance is stopped between a crash is being reported and the recovery
handler is scheduled"

* tag 'rproc-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: (25 commits)
remoteproc: core: Do pm_relax when in RPROC_OFFLINE state
remoteproc: qcom: q6v5: Fix missing clk_disable_unprepare() in q6v5_wcss_qcs404_power_on()
remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()
remoteproc: qcom_q6v5_pas: detach power domains on remove
remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove
remoteproc: qcom: q6v5: Fix potential null-ptr-deref in q6v5_wcss_init_mmio()
remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
remoteproc: sysmon: Make QMI message rules const
drivers: remoteproc: Add Xilinx r5 remoteproc driver
firmware: xilinx: Add RPU configuration APIs
firmware: xilinx: Add shutdown/wakeup APIs
firmware: xilinx: Add ZynqMP firmware ioctl enums for RPU configuration.
arm64: dts: xilinx: zynqmp: Add RPU subsystem device node
dt-bindings: remoteproc: Add Xilinx RPU subsystem bindings
remoteproc: core: Use device_match_of_node()
remoteproc: imx_rproc: Correct i.MX93 DRAM mapping
remoteproc: imx_rproc: Enable attach recovery for i.MX8QM/QXP
remoteproc: imx_rproc: Request mbox channel later
remoteproc: imx_rproc: Support i.MX8QM
remoteproc: imx_rproc: Support kicking Mcore from Linux for i.MX8QXP
...

+1760 -20
+16
Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
··· 22 22 - fsl,imx8mn-cm7 23 23 - fsl,imx8mp-cm7 24 24 - fsl,imx8mq-cm4 25 + - fsl,imx8qm-cm4 26 + - fsl,imx8qxp-cm4 25 27 - fsl,imx8ulp-cm33 26 28 - fsl,imx93-cm33 27 29 ··· 56 54 minItems: 1 57 55 maxItems: 32 58 56 57 + power-domains: 58 + maxItems: 8 59 + 59 60 fsl,auto-boot: 60 61 $ref: /schemas/types.yaml#/definitions/flag 61 62 description: 62 63 Indicate whether need to load the default firmware and start the remote 63 64 processor automatically. 65 + 66 + fsl,entry-address: 67 + $ref: /schemas/types.yaml#/definitions/uint32 68 + description: 69 + Specify CPU entry address for SCU enabled processor. 70 + 71 + fsl,resource-id: 72 + $ref: /schemas/types.yaml#/definitions/uint32 73 + description: 74 + This property is to specify the resource id of the remote processor in SoC 75 + which supports SCFW 64 76 65 77 required: 66 78 - compatible
+135
Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/remoteproc/xlnx,zynqmp-r5fss.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Xilinx R5F processor subsystem 8 + 9 + maintainers: 10 + - Ben Levinsky <ben.levinsky@amd.com> 11 + - Tanmay Shah <tanmay.shah@amd.com> 12 + 13 + description: | 14 + The Xilinx platforms include a pair of Cortex-R5F processors (RPU) for 15 + real-time processing based on the Cortex-R5F processor core from ARM. 16 + The Cortex-R5F processor implements the Arm v7-R architecture and includes a 17 + floating-point unit that implements the Arm VFPv3 instruction set. 18 + 19 + properties: 20 + compatible: 21 + const: xlnx,zynqmp-r5fss 22 + 23 + xlnx,cluster-mode: 24 + $ref: /schemas/types.yaml#/definitions/uint32 25 + enum: [0, 1, 2] 26 + description: | 27 + The RPU MPCore can operate in split mode (Dual-processor performance), Safety 28 + lock-step mode(Both RPU cores execute the same code in lock-step, 29 + clock-for-clock) or Single CPU mode (RPU core 0 is held in reset while 30 + core 1 runs normally). The processor does not support dynamic configuration. 31 + Switching between modes is only permitted immediately after a processor reset. 32 + If set to 1 then lockstep mode and if 0 then split mode. 33 + If set to 2 then single CPU mode. When not defined, default will be lockstep mode. 34 + In summary, 35 + 0: split mode 36 + 1: lockstep mode (default) 37 + 2: single cpu mode 38 + 39 + patternProperties: 40 + "^r5f-[a-f0-9]+$": 41 + type: object 42 + description: | 43 + The RPU is located in the Low Power Domain of the Processor Subsystem. 44 + Each processor includes separate L1 instruction and data caches and 45 + tightly coupled memories (TCM). System memory is cacheable, but the TCM 46 + memory space is non-cacheable. 47 + 48 + Each RPU contains one 64KB memory and two 32KB memories that 49 + are accessed via the TCM A and B port interfaces, for a total of 128KB 50 + per processor. In lock-step mode, the processor has access to 256KB of 51 + TCM memory. 52 + 53 + properties: 54 + compatible: 55 + const: xlnx,zynqmp-r5f 56 + 57 + power-domains: 58 + maxItems: 1 59 + 60 + mboxes: 61 + minItems: 1 62 + items: 63 + - description: mailbox channel to send data to RPU 64 + - description: mailbox channel to receive data from RPU 65 + 66 + mbox-names: 67 + minItems: 1 68 + items: 69 + - const: tx 70 + - const: rx 71 + 72 + sram: 73 + $ref: /schemas/types.yaml#/definitions/phandle-array 74 + minItems: 1 75 + maxItems: 8 76 + items: 77 + maxItems: 1 78 + description: | 79 + phandles to one or more reserved on-chip SRAM regions. Other than TCM, 80 + the RPU can execute instructions and access data from the OCM memory, 81 + the main DDR memory, and other system memories. 82 + 83 + The regions should be defined as child nodes of the respective SRAM 84 + node, and should be defined as per the generic bindings in 85 + Documentation/devicetree/bindings/sram/sram.yaml 86 + 87 + memory-region: 88 + description: | 89 + List of phandles to the reserved memory regions associated with the 90 + remoteproc device. This is variable and describes the memories shared with 91 + the remote processor (e.g. remoteproc firmware and carveouts, rpmsg 92 + vrings, ...). This reserved memory region will be allocated in DDR memory. 93 + minItems: 1 94 + maxItems: 8 95 + items: 96 + - description: region used for RPU firmware image section 97 + - description: vdev buffer 98 + - description: vring0 99 + - description: vring1 100 + additionalItems: true 101 + 102 + required: 103 + - compatible 104 + - power-domains 105 + 106 + unevaluatedProperties: false 107 + 108 + required: 109 + - compatible 110 + 111 + additionalProperties: false 112 + 113 + examples: 114 + - | 115 + remoteproc { 116 + compatible = "xlnx,zynqmp-r5fss"; 117 + xlnx,cluster-mode = <1>; 118 + 119 + r5f-0 { 120 + compatible = "xlnx,zynqmp-r5f"; 121 + power-domains = <&zynqmp_firmware 0x7>; 122 + memory-region = <&rproc_0_fw_image>, <&rpu0vdev0buffer>, <&rpu0vdev0vring0>, <&rpu0vdev0vring1>; 123 + mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>; 124 + mbox-names = "tx", "rx"; 125 + }; 126 + 127 + r5f-1 { 128 + compatible = "xlnx,zynqmp-r5f"; 129 + power-domains = <&zynqmp_firmware 0x8>; 130 + memory-region = <&rproc_1_fw_image>, <&rpu1vdev0buffer>, <&rpu1vdev0vring0>, <&rpu1vdev0vring1>; 131 + mboxes = <&ipi_mailbox_rpu1 0>, <&ipi_mailbox_rpu1 1>; 132 + mbox-names = "tx", "rx"; 133 + }; 134 + }; 135 + ...
+33
arch/arm64/boot/dts/xilinx/zynqmp.dtsi
··· 100 100 }; 101 101 }; 102 102 103 + reserved-memory { 104 + #address-cells = <2>; 105 + #size-cells = <2>; 106 + ranges; 107 + 108 + rproc_0_fw_image: memory@3ed00000 { 109 + no-map; 110 + reg = <0x0 0x3ed00000 0x0 0x40000>; 111 + }; 112 + 113 + rproc_1_fw_image: memory@3ef00000 { 114 + no-map; 115 + reg = <0x0 0x3ef00000 0x0 0x40000>; 116 + }; 117 + }; 118 + 103 119 zynqmp_ipi: zynqmp_ipi { 104 120 compatible = "xlnx,zynqmp-ipi-mailbox"; 105 121 interrupt-parent = <&gic>; ··· 217 201 #address-cells = <2>; 218 202 #size-cells = <2>; 219 203 ranges; 204 + }; 205 + 206 + remoteproc { 207 + compatible = "xlnx,zynqmp-r5fss"; 208 + xlnx,cluster-mode = <1>; 209 + 210 + r5f-0 { 211 + compatible = "xlnx,zynqmp-r5f"; 212 + power-domains = <&zynqmp_firmware PD_RPU_0>; 213 + memory-region = <&rproc_0_fw_image>; 214 + }; 215 + 216 + r5f-1 { 217 + compatible = "xlnx,zynqmp-r5f"; 218 + power-domains = <&zynqmp_firmware PD_RPU_1>; 219 + memory-region = <&rproc_1_fw_image>; 220 + }; 220 221 }; 221 222 222 223 amba: axi {
+97
drivers/firmware/xilinx/zynqmp.c
··· 1167 1167 EXPORT_SYMBOL_GPL(zynqmp_pm_release_node); 1168 1168 1169 1169 /** 1170 + * zynqmp_pm_get_rpu_mode() - Get RPU mode 1171 + * @node_id: Node ID of the device 1172 + * @rpu_mode: return by reference value 1173 + * either split or lockstep 1174 + * 1175 + * Return: return 0 on success or error+reason. 1176 + * if success, then rpu_mode will be set 1177 + * to current rpu mode. 1178 + */ 1179 + int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode) 1180 + { 1181 + u32 ret_payload[PAYLOAD_ARG_CNT]; 1182 + int ret; 1183 + 1184 + ret = zynqmp_pm_invoke_fn(PM_IOCTL, node_id, 1185 + IOCTL_GET_RPU_OPER_MODE, 0, 0, ret_payload); 1186 + 1187 + /* only set rpu_mode if no error */ 1188 + if (ret == XST_PM_SUCCESS) 1189 + *rpu_mode = ret_payload[0]; 1190 + 1191 + return ret; 1192 + } 1193 + EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_mode); 1194 + 1195 + /** 1196 + * zynqmp_pm_set_rpu_mode() - Set RPU mode 1197 + * @node_id: Node ID of the device 1198 + * @rpu_mode: Argument 1 to requested IOCTL call. either split or lockstep 1199 + * 1200 + * This function is used to set RPU mode to split or 1201 + * lockstep 1202 + * 1203 + * Return: Returns status, either success or error+reason 1204 + */ 1205 + int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode) 1206 + { 1207 + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, 1208 + IOCTL_SET_RPU_OPER_MODE, (u32)rpu_mode, 1209 + 0, NULL); 1210 + } 1211 + EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode); 1212 + 1213 + /** 1214 + * zynqmp_pm_set_tcm_config - configure TCM 1215 + * @node_id: Firmware specific TCM subsystem ID 1216 + * @tcm_mode: Argument 1 to requested IOCTL call 1217 + * either PM_RPU_TCM_COMB or PM_RPU_TCM_SPLIT 1218 + * 1219 + * This function is used to set RPU mode to split or combined 1220 + * 1221 + * Return: status: 0 for success, else failure 1222 + */ 1223 + int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode) 1224 + { 1225 + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, 1226 + IOCTL_TCM_COMB_CONFIG, (u32)tcm_mode, 0, 1227 + NULL); 1228 + } 1229 + EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config); 1230 + 1231 + /** 1232 + * zynqmp_pm_force_pwrdwn - PM call to request for another PU or subsystem to 1233 + * be powered down forcefully 1234 + * @node: Node ID of the targeted PU or subsystem 1235 + * @ack: Flag to specify whether acknowledge is requested 1236 + * 1237 + * Return: status, either success or error+reason 1238 + */ 1239 + int zynqmp_pm_force_pwrdwn(const u32 node, 1240 + const enum zynqmp_pm_request_ack ack) 1241 + { 1242 + return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, node, ack, 0, 0, NULL); 1243 + } 1244 + EXPORT_SYMBOL_GPL(zynqmp_pm_force_pwrdwn); 1245 + 1246 + /** 1247 + * zynqmp_pm_request_wake - PM call to wake up selected master or subsystem 1248 + * @node: Node ID of the master or subsystem 1249 + * @set_addr: Specifies whether the address argument is relevant 1250 + * @address: Address from which to resume when woken up 1251 + * @ack: Flag to specify whether acknowledge requested 1252 + * 1253 + * Return: status, either success or error+reason 1254 + */ 1255 + int zynqmp_pm_request_wake(const u32 node, 1256 + const bool set_addr, 1257 + const u64 address, 1258 + const enum zynqmp_pm_request_ack ack) 1259 + { 1260 + /* set_addr flag is encoded into 1st bit of address */ 1261 + return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, node, address | set_addr, 1262 + address >> 32, ack, NULL); 1263 + } 1264 + EXPORT_SYMBOL_GPL(zynqmp_pm_request_wake); 1265 + 1266 + /** 1170 1267 * zynqmp_pm_set_requirement() - PM call to set requirement for PM slaves 1171 1268 * @node: Node ID of the slave 1172 1269 * @capabilities: Requested capabilities of the slave
+13
drivers/remoteproc/Kconfig
··· 352 352 It's safe to say N here if you're not interested in utilizing 353 353 a slave processor. 354 354 355 + config XLNX_R5_REMOTEPROC 356 + tristate "Xilinx R5 remoteproc support" 357 + depends on PM && ARCH_ZYNQMP 358 + select ZYNQMP_FIRMWARE 359 + select RPMSG_VIRTIO 360 + select MAILBOX 361 + select ZYNQMP_IPI_MBOX 362 + help 363 + Say y or m here to support Xilinx R5 remote processors via the remote 364 + processor framework. 365 + 366 + It's safe to say N if not interested in using RPU r5f cores. 367 + 355 368 endif # REMOTEPROC 356 369 357 370 endmenu
+1
drivers/remoteproc/Makefile
··· 38 38 obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o 39 39 obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o 40 40 obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o 41 + obj-$(CONFIG_XLNX_R5_REMOTEPROC) += xlnx_r5_remoteproc.o
+9 -3
drivers/remoteproc/imx_dsp_rproc.c
··· 347 347 struct device *dev = rproc->dev.parent; 348 348 int ret = 0; 349 349 350 - /* Make sure work is finished */ 351 - flush_work(&priv->rproc_work); 352 - 353 350 if (rproc->state == RPROC_CRASHED) { 354 351 priv->flags &= ~REMOTE_IS_READY; 355 352 return 0; ··· 429 432 { 430 433 struct imx_dsp_rproc *priv = container_of(work, struct imx_dsp_rproc, 431 434 rproc_work); 435 + struct rproc *rproc = priv->rproc; 436 + 437 + mutex_lock(&rproc->lock); 438 + 439 + if (rproc->state != RPROC_RUNNING) 440 + goto unlock_mutex; 432 441 433 442 rproc_vq_interrupt(priv->rproc, 0); 434 443 rproc_vq_interrupt(priv->rproc, 1); 444 + 445 + unlock_mutex: 446 + mutex_unlock(&rproc->lock); 435 447 } 436 448 437 449 /**
+290 -8
drivers/remoteproc/imx_rproc.c
··· 3 3 * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> 4 4 */ 5 5 6 + #include <dt-bindings/firmware/imx/rsrc.h> 6 7 #include <linux/arm-smccc.h> 7 8 #include <linux/clk.h> 8 9 #include <linux/err.h> 10 + #include <linux/firmware/imx/sci.h> 9 11 #include <linux/interrupt.h> 10 12 #include <linux/kernel.h> 11 13 #include <linux/mailbox_client.h> ··· 17 15 #include <linux/of_reserved_mem.h> 18 16 #include <linux/of_device.h> 19 17 #include <linux/platform_device.h> 18 + #include <linux/pm_domain.h> 20 19 #include <linux/regmap.h> 21 20 #include <linux/remoteproc.h> 22 21 #include <linux/workqueue.h> ··· 62 59 #define IMX_SIP_RPROC_STARTED 0x01 63 60 #define IMX_SIP_RPROC_STOP 0x02 64 61 62 + #define IMX_SC_IRQ_GROUP_REBOOTED 5 63 + 65 64 /** 66 65 * struct imx_rproc_mem - slim internal memory structure 67 66 * @cpu_addr: MPU virtual address of the memory region ··· 76 71 size_t size; 77 72 }; 78 73 79 - /* att flags */ 74 + /* att flags: lower 16 bits specifying core, higher 16 bits for flags */ 80 75 /* M4 own area. Can be mapped at probe */ 81 - #define ATT_OWN BIT(1) 82 - #define ATT_IOMEM BIT(2) 76 + #define ATT_OWN BIT(31) 77 + #define ATT_IOMEM BIT(30) 78 + 79 + #define ATT_CORE_MASK 0xffff 80 + #define ATT_CORE(I) BIT((I)) 81 + 82 + static int imx_rproc_xtr_mbox_init(struct rproc *rproc); 83 + static void imx_rproc_free_mbox(struct rproc *rproc); 84 + static int imx_rproc_detach_pd(struct rproc *rproc); 83 85 84 86 struct imx_rproc { 85 87 struct device *dev; ··· 101 89 struct work_struct rproc_work; 102 90 struct workqueue_struct *workqueue; 103 91 void __iomem *rsc_table; 92 + struct imx_sc_ipc *ipc_handle; 93 + struct notifier_block rproc_nb; 94 + u32 rproc_pt; /* partition id */ 95 + u32 rsrc_id; /* resource id */ 96 + u32 entry; /* cpu start address */ 97 + int num_pd; 98 + u32 core_index; 99 + struct device **pd_dev; 100 + struct device_link **pd_dev_link; 104 101 }; 105 102 106 103 static const struct imx_rproc_att imx_rproc_att_imx93[] = { ··· 134 113 { 0x80000000, 0x80000000, 0x10000000, 0 }, 135 114 { 0x90000000, 0x80000000, 0x10000000, 0 }, 136 115 137 - { 0xC0000000, 0xa0000000, 0x10000000, 0 }, 138 - { 0xD0000000, 0xa0000000, 0x10000000, 0 }, 116 + { 0xC0000000, 0xC0000000, 0x10000000, 0 }, 117 + { 0xD0000000, 0xC0000000, 0x10000000, 0 }, 118 + }; 119 + 120 + static const struct imx_rproc_att imx_rproc_att_imx8qm[] = { 121 + /* dev addr , sys addr , size , flags */ 122 + { 0x08000000, 0x08000000, 0x10000000, 0}, 123 + /* TCML */ 124 + { 0x1FFE0000, 0x34FE0000, 0x00020000, ATT_OWN | ATT_IOMEM | ATT_CORE(0)}, 125 + { 0x1FFE0000, 0x38FE0000, 0x00020000, ATT_OWN | ATT_IOMEM | ATT_CORE(1)}, 126 + /* TCMU */ 127 + { 0x20000000, 0x35000000, 0x00020000, ATT_OWN | ATT_IOMEM | ATT_CORE(0)}, 128 + { 0x20000000, 0x39000000, 0x00020000, ATT_OWN | ATT_IOMEM | ATT_CORE(1)}, 129 + /* DDR (Data) */ 130 + { 0x80000000, 0x80000000, 0x60000000, 0 }, 131 + }; 132 + 133 + static const struct imx_rproc_att imx_rproc_att_imx8qxp[] = { 134 + { 0x08000000, 0x08000000, 0x10000000, 0 }, 135 + /* TCML/U */ 136 + { 0x1FFE0000, 0x34FE0000, 0x00040000, ATT_OWN | ATT_IOMEM }, 137 + /* OCRAM(Low 96KB) */ 138 + { 0x21000000, 0x00100000, 0x00018000, 0 }, 139 + /* OCRAM */ 140 + { 0x21100000, 0x00100000, 0x00040000, 0 }, 141 + /* DDR (Data) */ 142 + { 0x80000000, 0x80000000, 0x60000000, 0 }, 139 143 }; 140 144 141 145 static const struct imx_rproc_att imx_rproc_att_imx8mn[] = { ··· 301 255 .method = IMX_RPROC_MMIO, 302 256 }; 303 257 258 + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { 259 + .att = imx_rproc_att_imx8qm, 260 + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), 261 + .method = IMX_RPROC_SCU_API, 262 + }; 263 + 264 + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { 265 + .att = imx_rproc_att_imx8qxp, 266 + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), 267 + .method = IMX_RPROC_SCU_API, 268 + }; 269 + 304 270 static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { 305 271 .att = imx_rproc_att_imx8ulp, 306 272 .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), ··· 359 301 struct arm_smccc_res res; 360 302 int ret; 361 303 304 + ret = imx_rproc_xtr_mbox_init(rproc); 305 + if (ret) 306 + return ret; 307 + 362 308 switch (dcfg->method) { 363 309 case IMX_RPROC_MMIO: 364 310 ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, ··· 371 309 case IMX_RPROC_SMC: 372 310 arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); 373 311 ret = res.a0; 312 + break; 313 + case IMX_RPROC_SCU_API: 314 + ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); 374 315 break; 375 316 default: 376 317 return -EOPNOTSUPP; ··· 404 339 if (res.a1) 405 340 dev_info(dev, "Not in wfi, force stopped\n"); 406 341 break; 342 + case IMX_RPROC_SCU_API: 343 + ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); 344 + break; 407 345 default: 408 346 return -EOPNOTSUPP; 409 347 } 410 348 411 349 if (ret) 412 350 dev_err(dev, "Failed to stop remote core\n"); 351 + else 352 + imx_rproc_free_mbox(rproc); 413 353 414 354 return ret; 415 355 } ··· 428 358 /* parse address translation table */ 429 359 for (i = 0; i < dcfg->att_size; i++) { 430 360 const struct imx_rproc_att *att = &dcfg->att[i]; 361 + 362 + /* 363 + * Ignore entries not belong to current core: 364 + * i.MX8QM has dual general M4_[0,1] cores, M4_0's own entries 365 + * has "ATT_CORE(0) & BIT(0)" true, M4_1's own entries has 366 + * "ATT_CORE(1) & BIT(1)" true. 367 + */ 368 + if (att->flags & ATT_CORE_MASK) { 369 + if (!((BIT(priv->core_index)) & (att->flags & ATT_CORE_MASK))) 370 + continue; 371 + } 431 372 432 373 if (da >= att->da && da + len < att->da + att->size) { 433 374 unsigned int offset = da - att->da; ··· 600 519 601 520 static int imx_rproc_attach(struct rproc *rproc) 602 521 { 522 + return imx_rproc_xtr_mbox_init(rproc); 523 + } 524 + 525 + static int imx_rproc_detach(struct rproc *rproc) 526 + { 527 + struct imx_rproc *priv = rproc->priv; 528 + const struct imx_rproc_dcfg *dcfg = priv->dcfg; 529 + 530 + if (dcfg->method != IMX_RPROC_SCU_API) 531 + return -EOPNOTSUPP; 532 + 533 + if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) 534 + return -EOPNOTSUPP; 535 + 536 + imx_rproc_free_mbox(rproc); 537 + 603 538 return 0; 604 539 } 605 540 ··· 634 537 static const struct rproc_ops imx_rproc_ops = { 635 538 .prepare = imx_rproc_prepare, 636 539 .attach = imx_rproc_attach, 540 + .detach = imx_rproc_detach, 637 541 .start = imx_rproc_start, 638 542 .stop = imx_rproc_stop, 639 543 .kick = imx_rproc_kick, ··· 745 647 struct device *dev = priv->dev; 746 648 struct mbox_client *cl; 747 649 650 + /* 651 + * stop() and detach() will free the mbox channels, so need 652 + * to request mbox channels in start() and attach(). 653 + * 654 + * Because start() and attach() not able to handle mbox defer 655 + * probe, imx_rproc_xtr_mbox_init is also called in probe(). 656 + * The check is to avoid request mbox again when start() or 657 + * attach() after probe() returns success. 658 + */ 659 + if (priv->tx_ch && priv->rx_ch) 660 + return 0; 661 + 748 662 if (!of_get_property(dev->of_node, "mbox-names", NULL)) 749 663 return 0; 750 664 ··· 786 676 { 787 677 struct imx_rproc *priv = rproc->priv; 788 678 789 - mbox_free_channel(priv->tx_ch); 790 - mbox_free_channel(priv->rx_ch); 679 + if (priv->tx_ch) { 680 + mbox_free_channel(priv->tx_ch); 681 + priv->tx_ch = NULL; 682 + } 683 + 684 + if (priv->rx_ch) { 685 + mbox_free_channel(priv->rx_ch); 686 + priv->rx_ch = NULL; 687 + } 688 + } 689 + 690 + static void imx_rproc_put_scu(struct rproc *rproc) 691 + { 692 + struct imx_rproc *priv = rproc->priv; 693 + const struct imx_rproc_dcfg *dcfg = priv->dcfg; 694 + 695 + if (dcfg->method != IMX_RPROC_SCU_API) 696 + return; 697 + 698 + if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { 699 + imx_rproc_detach_pd(rproc); 700 + return; 701 + } 702 + 703 + imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), false); 704 + imx_scu_irq_unregister_notifier(&priv->rproc_nb); 705 + } 706 + 707 + static int imx_rproc_partition_notify(struct notifier_block *nb, 708 + unsigned long event, void *group) 709 + { 710 + struct imx_rproc *priv = container_of(nb, struct imx_rproc, rproc_nb); 711 + 712 + /* Ignore other irqs */ 713 + if (!((event & BIT(priv->rproc_pt)) && (*(u8 *)group == IMX_SC_IRQ_GROUP_REBOOTED))) 714 + return 0; 715 + 716 + rproc_report_crash(priv->rproc, RPROC_WATCHDOG); 717 + 718 + pr_info("Partition%d reset!\n", priv->rproc_pt); 719 + 720 + return 0; 721 + } 722 + 723 + static int imx_rproc_attach_pd(struct imx_rproc *priv) 724 + { 725 + struct device *dev = priv->dev; 726 + int ret, i; 727 + 728 + /* 729 + * If there is only one power-domain entry, the platform driver framework 730 + * will handle it, no need handle it in this driver. 731 + */ 732 + priv->num_pd = of_count_phandle_with_args(dev->of_node, "power-domains", 733 + "#power-domain-cells"); 734 + if (priv->num_pd <= 1) 735 + return 0; 736 + 737 + priv->pd_dev = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev), GFP_KERNEL); 738 + if (!priv->pd_dev) 739 + return -ENOMEM; 740 + 741 + priv->pd_dev_link = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev_link), 742 + GFP_KERNEL); 743 + 744 + if (!priv->pd_dev_link) 745 + return -ENOMEM; 746 + 747 + for (i = 0; i < priv->num_pd; i++) { 748 + priv->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); 749 + if (IS_ERR(priv->pd_dev[i])) { 750 + ret = PTR_ERR(priv->pd_dev[i]); 751 + goto detach_pd; 752 + } 753 + 754 + priv->pd_dev_link[i] = device_link_add(dev, priv->pd_dev[i], DL_FLAG_STATELESS | 755 + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); 756 + if (!priv->pd_dev_link[i]) { 757 + dev_pm_domain_detach(priv->pd_dev[i], false); 758 + ret = -EINVAL; 759 + goto detach_pd; 760 + } 761 + } 762 + 763 + return 0; 764 + 765 + detach_pd: 766 + while (--i >= 0) { 767 + device_link_del(priv->pd_dev_link[i]); 768 + dev_pm_domain_detach(priv->pd_dev[i], false); 769 + } 770 + 771 + return ret; 772 + } 773 + 774 + static int imx_rproc_detach_pd(struct rproc *rproc) 775 + { 776 + struct imx_rproc *priv = rproc->priv; 777 + int i; 778 + 779 + /* 780 + * If there is only one power-domain entry, the platform driver framework 781 + * will handle it, no need handle it in this driver. 782 + */ 783 + if (priv->num_pd <= 1) 784 + return 0; 785 + 786 + for (i = 0; i < priv->num_pd; i++) { 787 + device_link_del(priv->pd_dev_link[i]); 788 + dev_pm_domain_detach(priv->pd_dev[i], false); 789 + } 790 + 791 + return 0; 791 792 } 792 793 793 794 static int imx_rproc_detect_mode(struct imx_rproc *priv) ··· 910 689 struct arm_smccc_res res; 911 690 int ret; 912 691 u32 val; 692 + u8 pt; 913 693 914 694 switch (dcfg->method) { 915 695 case IMX_RPROC_NONE: ··· 920 698 arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); 921 699 if (res.a0) 922 700 priv->rproc->state = RPROC_DETACHED; 701 + return 0; 702 + case IMX_RPROC_SCU_API: 703 + ret = imx_scu_get_handle(&priv->ipc_handle); 704 + if (ret) 705 + return ret; 706 + ret = of_property_read_u32(dev->of_node, "fsl,resource-id", &priv->rsrc_id); 707 + if (ret) { 708 + dev_err(dev, "No fsl,resource-id property\n"); 709 + return ret; 710 + } 711 + 712 + if (priv->rsrc_id == IMX_SC_R_M4_1_PID0) 713 + priv->core_index = 1; 714 + else 715 + priv->core_index = 0; 716 + 717 + /* 718 + * If Mcore resource is not owned by Acore partition, It is kicked by ROM, 719 + * and Linux could only do IPC with Mcore and nothing else. 720 + */ 721 + if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { 722 + if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry)) 723 + return -EINVAL; 724 + 725 + return imx_rproc_attach_pd(priv); 726 + } 727 + 728 + priv->rproc->state = RPROC_DETACHED; 729 + priv->rproc->recovery_disabled = false; 730 + rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); 731 + 732 + /* Get partition id and enable irq in SCFW */ 733 + ret = imx_sc_rm_get_resource_owner(priv->ipc_handle, priv->rsrc_id, &pt); 734 + if (ret) { 735 + dev_err(dev, "not able to get resource owner\n"); 736 + return ret; 737 + } 738 + 739 + priv->rproc_pt = pt; 740 + priv->rproc_nb.notifier_call = imx_rproc_partition_notify; 741 + 742 + ret = imx_scu_irq_register_notifier(&priv->rproc_nb); 743 + if (ret) { 744 + dev_err(dev, "register scu notifier failed, %d\n", ret); 745 + return ret; 746 + } 747 + 748 + ret = imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), 749 + true); 750 + if (ret) { 751 + imx_scu_irq_unregister_notifier(&priv->rproc_nb); 752 + dev_err(dev, "Enable irq failed, %d\n", ret); 753 + return ret; 754 + } 755 + 923 756 return 0; 924 757 default: 925 758 break; ··· 1080 803 1081 804 ret = imx_rproc_clk_enable(priv); 1082 805 if (ret) 1083 - goto err_put_mbox; 806 + goto err_put_scu; 1084 807 1085 808 INIT_WORK(&priv->rproc_work, imx_rproc_vq_work); 1086 809 ··· 1097 820 1098 821 err_put_clk: 1099 822 clk_disable_unprepare(priv->clk); 823 + err_put_scu: 824 + imx_rproc_put_scu(rproc); 1100 825 err_put_mbox: 1101 826 imx_rproc_free_mbox(rproc); 1102 827 err_put_wkq: ··· 1116 837 1117 838 clk_disable_unprepare(priv->clk); 1118 839 rproc_del(rproc); 840 + imx_rproc_put_scu(rproc); 1119 841 imx_rproc_free_mbox(rproc); 1120 842 destroy_workqueue(priv->workqueue); 1121 843 rproc_free(rproc); ··· 1132 852 { .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq }, 1133 853 { .compatible = "fsl,imx8mn-cm7", .data = &imx_rproc_cfg_imx8mn }, 1134 854 { .compatible = "fsl,imx8mp-cm7", .data = &imx_rproc_cfg_imx8mn }, 855 + { .compatible = "fsl,imx8qxp-cm4", .data = &imx_rproc_cfg_imx8qxp }, 856 + { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm }, 1135 857 { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, 1136 858 { .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 }, 1137 859 {},
+4
drivers/remoteproc/qcom_q6v5_pas.c
··· 449 449 } 450 450 451 451 ret = of_address_to_resource(node, 0, &r); 452 + of_node_put(node); 452 453 if (ret) 453 454 return ret; 454 455 ··· 557 556 detach_proxy_pds: 558 557 adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); 559 558 free_rproc: 559 + device_init_wakeup(adsp->dev, false); 560 560 rproc_free(rproc); 561 561 562 562 return ret; ··· 574 572 qcom_remove_sysmon_subdev(adsp->sysmon); 575 573 qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev); 576 574 qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev); 575 + adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); 576 + device_init_wakeup(adsp->dev, false); 577 577 rproc_free(adsp->rproc); 578 578 579 579 return 0;
+5 -1
drivers/remoteproc/qcom_q6v5_wcss.c
··· 351 351 if (ret) { 352 352 dev_err(wcss->dev, 353 353 "xo cbcr enabling timed out (rc:%d)\n", ret); 354 - return ret; 354 + goto disable_xo_cbcr_clk; 355 355 } 356 356 357 357 writel(0, wcss->reg_base + Q6SS_CGC_OVERRIDE); ··· 417 417 val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR); 418 418 val &= ~Q6SS_CLK_ENABLE; 419 419 writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR); 420 + disable_xo_cbcr_clk: 420 421 val = readl(wcss->reg_base + Q6SS_XO_CBCR); 421 422 val &= ~Q6SS_CLK_ENABLE; 422 423 writel(val, wcss->reg_base + Q6SS_XO_CBCR); ··· 828 827 int ret; 829 828 830 829 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6"); 830 + if (!res) 831 + return -EINVAL; 832 + 831 833 wcss->reg_base = devm_ioremap(&pdev->dev, res->start, 832 834 resource_size(res)); 833 835 if (!wcss->reg_base)
+8 -5
drivers/remoteproc/qcom_sysmon.c
··· 190 190 struct qmi_response_type_v01 resp; 191 191 }; 192 192 193 - static struct qmi_elem_info ssctl_shutdown_resp_ei[] = { 193 + static const struct qmi_elem_info ssctl_shutdown_resp_ei[] = { 194 194 { 195 195 .data_type = QMI_STRUCT, 196 196 .elem_len = 1, ··· 211 211 u32 evt_driven; 212 212 }; 213 213 214 - static struct qmi_elem_info ssctl_subsys_event_req_ei[] = { 214 + static const struct qmi_elem_info ssctl_subsys_event_req_ei[] = { 215 215 { 216 216 .data_type = QMI_DATA_LEN, 217 217 .elem_len = 1, ··· 269 269 struct qmi_response_type_v01 resp; 270 270 }; 271 271 272 - static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = { 272 + static const struct qmi_elem_info ssctl_subsys_event_resp_ei[] = { 273 273 { 274 274 .data_type = QMI_STRUCT, 275 275 .elem_len = 1, ··· 283 283 {} 284 284 }; 285 285 286 - static struct qmi_elem_info ssctl_shutdown_ind_ei[] = { 286 + static const struct qmi_elem_info ssctl_shutdown_ind_ei[] = { 287 287 {} 288 288 }; 289 289 ··· 652 652 if (sysmon->shutdown_irq != -ENODATA) { 653 653 dev_err(sysmon->dev, 654 654 "failed to retrieve shutdown-ack IRQ\n"); 655 - return ERR_PTR(sysmon->shutdown_irq); 655 + ret = sysmon->shutdown_irq; 656 + kfree(sysmon); 657 + return ERR_PTR(ret); 656 658 } 657 659 } else { 658 660 ret = devm_request_threaded_irq(sysmon->dev, ··· 665 663 if (ret) { 666 664 dev_err(sysmon->dev, 667 665 "failed to acquire shutdown-ack IRQ\n"); 666 + kfree(sysmon); 668 667 return ERR_PTR(ret); 669 668 } 670 669 }
+16 -3
drivers/remoteproc/remoteproc_core.c
··· 509 509 rvdev_data.rsc_offset = offset; 510 510 rvdev_data.rsc = rsc; 511 511 512 - pdev = platform_device_register_data(dev, "rproc-virtio", rvdev_data.index, &rvdev_data, 512 + /* 513 + * When there is more than one remote processor, rproc->nb_vdev number is 514 + * same for each separate instances of "rproc". If rvdev_data.index is used 515 + * as device id, then we get duplication in sysfs, so need to use 516 + * PLATFORM_DEVID_AUTO to auto select device id. 517 + */ 518 + pdev = platform_device_register_data(dev, "rproc-virtio", PLATFORM_DEVID_AUTO, &rvdev_data, 513 519 sizeof(rvdev_data)); 514 520 if (IS_ERR(pdev)) { 515 521 dev_err(dev, "failed to create rproc-virtio device\n"); ··· 1868 1862 1869 1863 mutex_lock(&rproc->lock); 1870 1864 1871 - if (rproc->state == RPROC_CRASHED || rproc->state == RPROC_OFFLINE) { 1865 + if (rproc->state == RPROC_CRASHED) { 1872 1866 /* handle only the first crash detected */ 1873 1867 mutex_unlock(&rproc->lock); 1874 1868 return; 1869 + } 1870 + 1871 + if (rproc->state == RPROC_OFFLINE) { 1872 + /* Don't recover if the remote processor was stopped */ 1873 + mutex_unlock(&rproc->lock); 1874 + goto out; 1875 1875 } 1876 1876 1877 1877 rproc->state = RPROC_CRASHED; ··· 1889 1877 if (!rproc->recovery_disabled) 1890 1878 rproc_trigger_recovery(rproc); 1891 1879 1880 + out: 1892 1881 pm_relax(rproc->dev.parent); 1893 1882 } 1894 1883 ··· 2119 2106 2120 2107 rcu_read_lock(); 2121 2108 list_for_each_entry_rcu(r, &rproc_list, node) { 2122 - if (r->dev.parent && r->dev.parent->of_node == np) { 2109 + if (r->dev.parent && device_match_of_node(r->dev.parent, np)) { 2123 2110 /* prevent underlying implementation from being removed */ 2124 2111 if (!try_module_get(r->dev.parent->driver->owner)) { 2125 2112 dev_err(&r->dev, "can't get owner\n");
+1067
drivers/remoteproc/xlnx_r5_remoteproc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * ZynqMP R5 Remote Processor driver 4 + * 5 + */ 6 + 7 + #include <dt-bindings/power/xlnx-zynqmp-power.h> 8 + #include <linux/dma-mapping.h> 9 + #include <linux/firmware/xlnx-zynqmp.h> 10 + #include <linux/kernel.h> 11 + #include <linux/module.h> 12 + #include <linux/of_address.h> 13 + #include <linux/of_platform.h> 14 + #include <linux/of_reserved_mem.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/remoteproc.h> 17 + #include <linux/slab.h> 18 + 19 + #include "remoteproc_internal.h" 20 + 21 + /* 22 + * settings for RPU cluster mode which 23 + * reflects possible values of xlnx,cluster-mode dt-property 24 + */ 25 + enum zynqmp_r5_cluster_mode { 26 + SPLIT_MODE = 0, /* When cores run as separate processor */ 27 + LOCKSTEP_MODE = 1, /* cores execute same code in lockstep,clk-for-clk */ 28 + SINGLE_CPU_MODE = 2, /* core0 is held in reset and only core1 runs */ 29 + }; 30 + 31 + /** 32 + * struct mem_bank_data - Memory Bank description 33 + * 34 + * @addr: Start address of memory bank 35 + * @size: Size of Memory bank 36 + * @pm_domain_id: Power-domains id of memory bank for firmware to turn on/off 37 + * @bank_name: name of the bank for remoteproc framework 38 + */ 39 + struct mem_bank_data { 40 + phys_addr_t addr; 41 + size_t size; 42 + u32 pm_domain_id; 43 + char *bank_name; 44 + }; 45 + 46 + /* 47 + * Hardcoded TCM bank values. This will be removed once TCM bindings are 48 + * accepted for system-dt specifications and upstreamed in linux kernel 49 + */ 50 + static const struct mem_bank_data zynqmp_tcm_banks[] = { 51 + {0xffe00000UL, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ 52 + {0xffe20000UL, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, 53 + {0xffe90000UL, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, 54 + {0xffeb0000UL, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, 55 + }; 56 + 57 + /** 58 + * struct zynqmp_r5_core 59 + * 60 + * @dev: device of RPU instance 61 + * @np: device node of RPU instance 62 + * @tcm_bank_count: number TCM banks accessible to this RPU 63 + * @tcm_banks: array of each TCM bank data 64 + * @rmem_count: Number of reserved mem regions 65 + * @rmem: reserved memory region nodes from device tree 66 + * @rproc: rproc handle 67 + * @pm_domain_id: RPU CPU power domain id 68 + */ 69 + struct zynqmp_r5_core { 70 + struct device *dev; 71 + struct device_node *np; 72 + int tcm_bank_count; 73 + struct mem_bank_data **tcm_banks; 74 + int rmem_count; 75 + struct reserved_mem **rmem; 76 + struct rproc *rproc; 77 + u32 pm_domain_id; 78 + }; 79 + 80 + /** 81 + * struct zynqmp_r5_cluster 82 + * 83 + * @dev: r5f subsystem cluster device node 84 + * @mode: cluster mode of type zynqmp_r5_cluster_mode 85 + * @core_count: number of r5 cores used for this cluster mode 86 + * @r5_cores: Array of pointers pointing to r5 core 87 + */ 88 + struct zynqmp_r5_cluster { 89 + struct device *dev; 90 + enum zynqmp_r5_cluster_mode mode; 91 + int core_count; 92 + struct zynqmp_r5_core **r5_cores; 93 + }; 94 + 95 + /* 96 + * zynqmp_r5_set_mode() 97 + * 98 + * set RPU cluster and TCM operation mode 99 + * 100 + * @r5_core: pointer to zynqmp_r5_core type object 101 + * @fw_reg_val: value expected by firmware to configure RPU cluster mode 102 + * @tcm_mode: value expected by fw to configure TCM mode (lockstep or split) 103 + * 104 + * Return: 0 for success and < 0 for failure 105 + */ 106 + static int zynqmp_r5_set_mode(struct zynqmp_r5_core *r5_core, 107 + enum rpu_oper_mode fw_reg_val, 108 + enum rpu_tcm_comb tcm_mode) 109 + { 110 + int ret; 111 + 112 + ret = zynqmp_pm_set_rpu_mode(r5_core->pm_domain_id, fw_reg_val); 113 + if (ret < 0) { 114 + dev_err(r5_core->dev, "failed to set RPU mode\n"); 115 + return ret; 116 + } 117 + 118 + ret = zynqmp_pm_set_tcm_config(r5_core->pm_domain_id, tcm_mode); 119 + if (ret < 0) 120 + dev_err(r5_core->dev, "failed to configure TCM\n"); 121 + 122 + return ret; 123 + } 124 + 125 + /* 126 + * zynqmp_r5_rproc_start() 127 + * @rproc: single R5 core's corresponding rproc instance 128 + * 129 + * Start R5 Core from designated boot address. 130 + * 131 + * return 0 on success, otherwise non-zero value on failure 132 + */ 133 + static int zynqmp_r5_rproc_start(struct rproc *rproc) 134 + { 135 + struct zynqmp_r5_core *r5_core = rproc->priv; 136 + enum rpu_boot_mem bootmem; 137 + int ret; 138 + 139 + /* 140 + * The exception vector pointers (EVP) refer to the base-address of 141 + * exception vectors (for reset, IRQ, FIQ, etc). The reset-vector 142 + * starts at the base-address and subsequent vectors are on 4-byte 143 + * boundaries. 144 + * 145 + * Exception vectors can start either from 0x0000_0000 (LOVEC) or 146 + * from 0xFFFF_0000 (HIVEC) which is mapped in the OCM (On-Chip Memory) 147 + * 148 + * Usually firmware will put Exception vectors at LOVEC. 149 + * 150 + * It is not recommend that you change the exception vector. 151 + * Changing the EVP to HIVEC will result in increased interrupt latency 152 + * and jitter. Also, if the OCM is secured and the Cortex-R5F processor 153 + * is non-secured, then the Cortex-R5F processor cannot access the 154 + * HIVEC exception vectors in the OCM. 155 + */ 156 + bootmem = (rproc->bootaddr >= 0xFFFC0000) ? 157 + PM_RPU_BOOTMEM_HIVEC : PM_RPU_BOOTMEM_LOVEC; 158 + 159 + dev_dbg(r5_core->dev, "RPU boot addr 0x%llx from %s.", rproc->bootaddr, 160 + bootmem == PM_RPU_BOOTMEM_HIVEC ? "OCM" : "TCM"); 161 + 162 + ret = zynqmp_pm_request_wake(r5_core->pm_domain_id, 1, 163 + bootmem, ZYNQMP_PM_REQUEST_ACK_NO); 164 + if (ret) 165 + dev_err(r5_core->dev, 166 + "failed to start RPU = 0x%x\n", r5_core->pm_domain_id); 167 + return ret; 168 + } 169 + 170 + /* 171 + * zynqmp_r5_rproc_stop() 172 + * @rproc: single R5 core's corresponding rproc instance 173 + * 174 + * Power down R5 Core. 175 + * 176 + * return 0 on success, otherwise non-zero value on failure 177 + */ 178 + static int zynqmp_r5_rproc_stop(struct rproc *rproc) 179 + { 180 + struct zynqmp_r5_core *r5_core = rproc->priv; 181 + int ret; 182 + 183 + ret = zynqmp_pm_force_pwrdwn(r5_core->pm_domain_id, 184 + ZYNQMP_PM_REQUEST_ACK_BLOCKING); 185 + if (ret) 186 + dev_err(r5_core->dev, "failed to stop remoteproc RPU %d\n", ret); 187 + 188 + return ret; 189 + } 190 + 191 + /* 192 + * zynqmp_r5_mem_region_map() 193 + * @rproc: single R5 core's corresponding rproc instance 194 + * @mem: mem descriptor to map reserved memory-regions 195 + * 196 + * Callback to map va for memory-region's carveout. 197 + * 198 + * return 0 on success, otherwise non-zero value on failure 199 + */ 200 + static int zynqmp_r5_mem_region_map(struct rproc *rproc, 201 + struct rproc_mem_entry *mem) 202 + { 203 + void __iomem *va; 204 + 205 + va = ioremap_wc(mem->dma, mem->len); 206 + if (IS_ERR_OR_NULL(va)) 207 + return -ENOMEM; 208 + 209 + mem->va = (void *)va; 210 + 211 + return 0; 212 + } 213 + 214 + /* 215 + * zynqmp_r5_rproc_mem_unmap 216 + * @rproc: single R5 core's corresponding rproc instance 217 + * @mem: mem entry to unmap 218 + * 219 + * Unmap memory-region carveout 220 + * 221 + * return: always returns 0 222 + */ 223 + static int zynqmp_r5_mem_region_unmap(struct rproc *rproc, 224 + struct rproc_mem_entry *mem) 225 + { 226 + iounmap((void __iomem *)mem->va); 227 + return 0; 228 + } 229 + 230 + /* 231 + * add_mem_regions_carveout() 232 + * @rproc: single R5 core's corresponding rproc instance 233 + * 234 + * Construct rproc mem carveouts from memory-region property nodes 235 + * 236 + * return 0 on success, otherwise non-zero value on failure 237 + */ 238 + static int add_mem_regions_carveout(struct rproc *rproc) 239 + { 240 + struct rproc_mem_entry *rproc_mem; 241 + struct zynqmp_r5_core *r5_core; 242 + struct reserved_mem *rmem; 243 + int i, num_mem_regions; 244 + 245 + r5_core = (struct zynqmp_r5_core *)rproc->priv; 246 + num_mem_regions = r5_core->rmem_count; 247 + 248 + for (i = 0; i < num_mem_regions; i++) { 249 + rmem = r5_core->rmem[i]; 250 + 251 + if (!strncmp(rmem->name, "vdev0buffer", strlen("vdev0buffer"))) { 252 + /* Init reserved memory for vdev buffer */ 253 + rproc_mem = rproc_of_resm_mem_entry_init(&rproc->dev, i, 254 + rmem->size, 255 + rmem->base, 256 + rmem->name); 257 + } else { 258 + /* Register associated reserved memory regions */ 259 + rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL, 260 + (dma_addr_t)rmem->base, 261 + rmem->size, rmem->base, 262 + zynqmp_r5_mem_region_map, 263 + zynqmp_r5_mem_region_unmap, 264 + rmem->name); 265 + } 266 + 267 + if (!rproc_mem) 268 + return -ENOMEM; 269 + 270 + rproc_add_carveout(rproc, rproc_mem); 271 + 272 + dev_dbg(&rproc->dev, "reserved mem carveout %s addr=%llx, size=0x%llx", 273 + rmem->name, rmem->base, rmem->size); 274 + } 275 + 276 + return 0; 277 + } 278 + 279 + /* 280 + * tcm_mem_unmap() 281 + * @rproc: single R5 core's corresponding rproc instance 282 + * @mem: tcm mem entry to unmap 283 + * 284 + * Unmap TCM banks when powering down R5 core. 285 + * 286 + * return always 0 287 + */ 288 + static int tcm_mem_unmap(struct rproc *rproc, struct rproc_mem_entry *mem) 289 + { 290 + iounmap((void __iomem *)mem->va); 291 + 292 + return 0; 293 + } 294 + 295 + /* 296 + * tcm_mem_map() 297 + * @rproc: single R5 core's corresponding rproc instance 298 + * @mem: tcm memory entry descriptor 299 + * 300 + * Given TCM bank entry, this func setup virtual address for TCM bank 301 + * remoteproc carveout. It also takes care of va to da address translation 302 + * 303 + * return 0 on success, otherwise non-zero value on failure 304 + */ 305 + static int tcm_mem_map(struct rproc *rproc, 306 + struct rproc_mem_entry *mem) 307 + { 308 + void __iomem *va; 309 + 310 + va = ioremap_wc(mem->dma, mem->len); 311 + if (IS_ERR_OR_NULL(va)) 312 + return -ENOMEM; 313 + 314 + /* Update memory entry va */ 315 + mem->va = (void *)va; 316 + 317 + /* clear TCMs */ 318 + memset_io(va, 0, mem->len); 319 + 320 + /* 321 + * The R5s expect their TCM banks to be at address 0x0 and 0x2000, 322 + * while on the Linux side they are at 0xffexxxxx. 323 + * 324 + * Zero out the high 12 bits of the address. This will give 325 + * expected values for TCM Banks 0A and 0B (0x0 and 0x20000). 326 + */ 327 + mem->da &= 0x000fffff; 328 + 329 + /* 330 + * TCM Banks 1A and 1B still have to be translated. 331 + * 332 + * Below handle these two banks' absolute addresses (0xffe90000 and 333 + * 0xffeb0000) and convert to the expected relative addresses 334 + * (0x0 and 0x20000). 335 + */ 336 + if (mem->da == 0x90000 || mem->da == 0xB0000) 337 + mem->da -= 0x90000; 338 + 339 + /* if translated TCM bank address is not valid report error */ 340 + if (mem->da != 0x0 && mem->da != 0x20000) { 341 + dev_err(&rproc->dev, "invalid TCM address: %x\n", mem->da); 342 + return -EINVAL; 343 + } 344 + return 0; 345 + } 346 + 347 + /* 348 + * add_tcm_carveout_split_mode() 349 + * @rproc: single R5 core's corresponding rproc instance 350 + * 351 + * allocate and add remoteproc carveout for TCM memory in split mode 352 + * 353 + * return 0 on success, otherwise non-zero value on failure 354 + */ 355 + static int add_tcm_carveout_split_mode(struct rproc *rproc) 356 + { 357 + struct rproc_mem_entry *rproc_mem; 358 + struct zynqmp_r5_core *r5_core; 359 + int i, num_banks, ret; 360 + phys_addr_t bank_addr; 361 + struct device *dev; 362 + u32 pm_domain_id; 363 + size_t bank_size; 364 + char *bank_name; 365 + 366 + r5_core = (struct zynqmp_r5_core *)rproc->priv; 367 + dev = r5_core->dev; 368 + num_banks = r5_core->tcm_bank_count; 369 + 370 + /* 371 + * Power-on Each 64KB TCM, 372 + * register its address space, map and unmap functions 373 + * and add carveouts accordingly 374 + */ 375 + for (i = 0; i < num_banks; i++) { 376 + bank_addr = r5_core->tcm_banks[i]->addr; 377 + bank_name = r5_core->tcm_banks[i]->bank_name; 378 + bank_size = r5_core->tcm_banks[i]->size; 379 + pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 380 + 381 + ret = zynqmp_pm_request_node(pm_domain_id, 382 + ZYNQMP_PM_CAPABILITY_ACCESS, 0, 383 + ZYNQMP_PM_REQUEST_ACK_BLOCKING); 384 + if (ret < 0) { 385 + dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); 386 + goto release_tcm_split; 387 + } 388 + 389 + dev_dbg(dev, "TCM carveout split mode %s addr=%llx, size=0x%lx", 390 + bank_name, bank_addr, bank_size); 391 + 392 + rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, 393 + bank_size, bank_addr, 394 + tcm_mem_map, tcm_mem_unmap, 395 + bank_name); 396 + if (!rproc_mem) { 397 + ret = -ENOMEM; 398 + zynqmp_pm_release_node(pm_domain_id); 399 + goto release_tcm_split; 400 + } 401 + 402 + rproc_add_carveout(rproc, rproc_mem); 403 + } 404 + 405 + return 0; 406 + 407 + release_tcm_split: 408 + /* If failed, Turn off all TCM banks turned on before */ 409 + for (i--; i >= 0; i--) { 410 + pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 411 + zynqmp_pm_release_node(pm_domain_id); 412 + } 413 + return ret; 414 + } 415 + 416 + /* 417 + * add_tcm_carveout_lockstep_mode() 418 + * @rproc: single R5 core's corresponding rproc instance 419 + * 420 + * allocate and add remoteproc carveout for TCM memory in lockstep mode 421 + * 422 + * return 0 on success, otherwise non-zero value on failure 423 + */ 424 + static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) 425 + { 426 + struct rproc_mem_entry *rproc_mem; 427 + struct zynqmp_r5_core *r5_core; 428 + int i, num_banks, ret; 429 + phys_addr_t bank_addr; 430 + size_t bank_size = 0; 431 + struct device *dev; 432 + u32 pm_domain_id; 433 + char *bank_name; 434 + 435 + r5_core = (struct zynqmp_r5_core *)rproc->priv; 436 + dev = r5_core->dev; 437 + 438 + /* Go through zynqmp banks for r5 node */ 439 + num_banks = r5_core->tcm_bank_count; 440 + 441 + /* 442 + * In lockstep mode, TCM is contiguous memory block 443 + * However, each TCM block still needs to be enabled individually. 444 + * So, Enable each TCM block individually, but add their size 445 + * to create contiguous memory region. 446 + */ 447 + bank_addr = r5_core->tcm_banks[0]->addr; 448 + bank_name = r5_core->tcm_banks[0]->bank_name; 449 + 450 + for (i = 0; i < num_banks; i++) { 451 + bank_size += r5_core->tcm_banks[i]->size; 452 + pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 453 + 454 + /* Turn on each TCM bank individually */ 455 + ret = zynqmp_pm_request_node(pm_domain_id, 456 + ZYNQMP_PM_CAPABILITY_ACCESS, 0, 457 + ZYNQMP_PM_REQUEST_ACK_BLOCKING); 458 + if (ret < 0) { 459 + dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); 460 + goto release_tcm_lockstep; 461 + } 462 + } 463 + 464 + dev_dbg(dev, "TCM add carveout lockstep mode %s addr=0x%llx, size=0x%lx", 465 + bank_name, bank_addr, bank_size); 466 + 467 + /* Register TCM address range, TCM map and unmap functions */ 468 + rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, 469 + bank_size, bank_addr, 470 + tcm_mem_map, tcm_mem_unmap, 471 + bank_name); 472 + if (!rproc_mem) { 473 + ret = -ENOMEM; 474 + goto release_tcm_lockstep; 475 + } 476 + 477 + /* If registration is success, add carveouts */ 478 + rproc_add_carveout(rproc, rproc_mem); 479 + 480 + return 0; 481 + 482 + release_tcm_lockstep: 483 + /* If failed, Turn off all TCM banks turned on before */ 484 + for (i--; i >= 0; i--) { 485 + pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 486 + zynqmp_pm_release_node(pm_domain_id); 487 + } 488 + return ret; 489 + } 490 + 491 + /* 492 + * add_tcm_banks() 493 + * @rproc: single R5 core's corresponding rproc instance 494 + * 495 + * allocate and add remoteproc carveouts for TCM memory based on cluster mode 496 + * 497 + * return 0 on success, otherwise non-zero value on failure 498 + */ 499 + static int add_tcm_banks(struct rproc *rproc) 500 + { 501 + struct zynqmp_r5_cluster *cluster; 502 + struct zynqmp_r5_core *r5_core; 503 + struct device *dev; 504 + 505 + r5_core = (struct zynqmp_r5_core *)rproc->priv; 506 + if (!r5_core) 507 + return -EINVAL; 508 + 509 + dev = r5_core->dev; 510 + 511 + cluster = dev_get_drvdata(dev->parent); 512 + if (!cluster) { 513 + dev_err(dev->parent, "Invalid driver data\n"); 514 + return -EINVAL; 515 + } 516 + 517 + /* 518 + * In lockstep mode TCM banks are one contiguous memory region of 256Kb 519 + * In split mode, each TCM bank is 64Kb and not contiguous. 520 + * We add memory carveouts accordingly. 521 + */ 522 + if (cluster->mode == SPLIT_MODE) 523 + return add_tcm_carveout_split_mode(rproc); 524 + else if (cluster->mode == LOCKSTEP_MODE) 525 + return add_tcm_carveout_lockstep_mode(rproc); 526 + 527 + return -EINVAL; 528 + } 529 + 530 + /* 531 + * zynqmp_r5_parse_fw() 532 + * @rproc: single R5 core's corresponding rproc instance 533 + * @fw: ptr to firmware to be loaded onto r5 core 534 + * 535 + * get resource table if available 536 + * 537 + * return 0 on success, otherwise non-zero value on failure 538 + */ 539 + static int zynqmp_r5_parse_fw(struct rproc *rproc, const struct firmware *fw) 540 + { 541 + int ret; 542 + 543 + ret = rproc_elf_load_rsc_table(rproc, fw); 544 + if (ret == -EINVAL) { 545 + /* 546 + * resource table only required for IPC. 547 + * if not present, this is not necessarily an error; 548 + * for example, loading r5 hello world application 549 + * so simply inform user and keep going. 550 + */ 551 + dev_info(&rproc->dev, "no resource table found.\n"); 552 + ret = 0; 553 + } 554 + return ret; 555 + } 556 + 557 + /** 558 + * zynqmp_r5_rproc_prepare() 559 + * adds carveouts for TCM bank and reserved memory regions 560 + * 561 + * @rproc: Device node of each rproc 562 + * 563 + * Return: 0 for success else < 0 error code 564 + */ 565 + static int zynqmp_r5_rproc_prepare(struct rproc *rproc) 566 + { 567 + int ret; 568 + 569 + ret = add_tcm_banks(rproc); 570 + if (ret) { 571 + dev_err(&rproc->dev, "failed to get TCM banks, err %d\n", ret); 572 + return ret; 573 + } 574 + 575 + ret = add_mem_regions_carveout(rproc); 576 + if (ret) { 577 + dev_err(&rproc->dev, "failed to get reserve mem regions %d\n", ret); 578 + return ret; 579 + } 580 + 581 + return 0; 582 + } 583 + 584 + /** 585 + * zynqmp_r5_rproc_unprepare() 586 + * Turns off TCM banks using power-domain id 587 + * 588 + * @rproc: Device node of each rproc 589 + * 590 + * Return: always 0 591 + */ 592 + static int zynqmp_r5_rproc_unprepare(struct rproc *rproc) 593 + { 594 + struct zynqmp_r5_core *r5_core; 595 + u32 pm_domain_id; 596 + int i; 597 + 598 + r5_core = (struct zynqmp_r5_core *)rproc->priv; 599 + 600 + for (i = 0; i < r5_core->tcm_bank_count; i++) { 601 + pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 602 + if (zynqmp_pm_release_node(pm_domain_id)) 603 + dev_warn(r5_core->dev, 604 + "can't turn off TCM bank 0x%x", pm_domain_id); 605 + } 606 + 607 + return 0; 608 + } 609 + 610 + static const struct rproc_ops zynqmp_r5_rproc_ops = { 611 + .prepare = zynqmp_r5_rproc_prepare, 612 + .unprepare = zynqmp_r5_rproc_unprepare, 613 + .start = zynqmp_r5_rproc_start, 614 + .stop = zynqmp_r5_rproc_stop, 615 + .load = rproc_elf_load_segments, 616 + .parse_fw = zynqmp_r5_parse_fw, 617 + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, 618 + .sanity_check = rproc_elf_sanity_check, 619 + .get_boot_addr = rproc_elf_get_boot_addr, 620 + }; 621 + 622 + /** 623 + * zynqmp_r5_add_rproc_core() 624 + * Allocate and add struct rproc object for each r5f core 625 + * This is called for each individual r5f core 626 + * 627 + * @cdev: Device node of each r5 core 628 + * 629 + * Return: zynqmp_r5_core object for success else error code pointer 630 + */ 631 + static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) 632 + { 633 + struct zynqmp_r5_core *r5_core; 634 + struct rproc *r5_rproc; 635 + int ret; 636 + 637 + /* Set up DMA mask */ 638 + ret = dma_set_coherent_mask(cdev, DMA_BIT_MASK(32)); 639 + if (ret) 640 + return ERR_PTR(ret); 641 + 642 + /* Allocate remoteproc instance */ 643 + r5_rproc = rproc_alloc(cdev, dev_name(cdev), 644 + &zynqmp_r5_rproc_ops, 645 + NULL, sizeof(struct zynqmp_r5_core)); 646 + if (!r5_rproc) { 647 + dev_err(cdev, "failed to allocate memory for rproc instance\n"); 648 + return ERR_PTR(-ENOMEM); 649 + } 650 + 651 + r5_rproc->auto_boot = false; 652 + r5_core = (struct zynqmp_r5_core *)r5_rproc->priv; 653 + r5_core->dev = cdev; 654 + r5_core->np = dev_of_node(cdev); 655 + if (!r5_core->np) { 656 + dev_err(cdev, "can't get device node for r5 core\n"); 657 + ret = -EINVAL; 658 + goto free_rproc; 659 + } 660 + 661 + /* Add R5 remoteproc core */ 662 + ret = rproc_add(r5_rproc); 663 + if (ret) { 664 + dev_err(cdev, "failed to add r5 remoteproc\n"); 665 + goto free_rproc; 666 + } 667 + 668 + r5_core->rproc = r5_rproc; 669 + return r5_core; 670 + 671 + free_rproc: 672 + rproc_free(r5_rproc); 673 + return ERR_PTR(ret); 674 + } 675 + 676 + /** 677 + * zynqmp_r5_get_tcm_node() 678 + * Ideally this function should parse tcm node and store information 679 + * in r5_core instance. For now, Hardcoded TCM information is used. 680 + * This approach is used as TCM bindings for system-dt is being developed 681 + * 682 + * @cluster: pointer to zynqmp_r5_cluster type object 683 + * 684 + * Return: 0 for success and < 0 error code for failure. 685 + */ 686 + static int zynqmp_r5_get_tcm_node(struct zynqmp_r5_cluster *cluster) 687 + { 688 + struct device *dev = cluster->dev; 689 + struct zynqmp_r5_core *r5_core; 690 + int tcm_bank_count, tcm_node; 691 + int i, j; 692 + 693 + tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks); 694 + 695 + /* count per core tcm banks */ 696 + tcm_bank_count = tcm_bank_count / cluster->core_count; 697 + 698 + /* 699 + * r5 core 0 will use all of TCM banks in lockstep mode. 700 + * In split mode, r5 core0 will use 128k and r5 core1 will use another 701 + * 128k. Assign TCM banks to each core accordingly 702 + */ 703 + tcm_node = 0; 704 + for (i = 0; i < cluster->core_count; i++) { 705 + r5_core = cluster->r5_cores[i]; 706 + r5_core->tcm_banks = devm_kcalloc(dev, tcm_bank_count, 707 + sizeof(struct mem_bank_data *), 708 + GFP_KERNEL); 709 + if (!r5_core->tcm_banks) 710 + return -ENOMEM; 711 + 712 + for (j = 0; j < tcm_bank_count; j++) { 713 + /* 714 + * Use pre-defined TCM reg values. 715 + * Eventually this should be replaced by values 716 + * parsed from dts. 717 + */ 718 + r5_core->tcm_banks[j] = 719 + (struct mem_bank_data *)&zynqmp_tcm_banks[tcm_node]; 720 + tcm_node++; 721 + } 722 + 723 + r5_core->tcm_bank_count = tcm_bank_count; 724 + } 725 + 726 + return 0; 727 + } 728 + 729 + /** 730 + * zynqmp_r5_get_mem_region_node() 731 + * parse memory-region property and get reserved mem regions 732 + * 733 + * @r5_core: pointer to zynqmp_r5_core type object 734 + * 735 + * Return: 0 for success and error code for failure. 736 + */ 737 + static int zynqmp_r5_get_mem_region_node(struct zynqmp_r5_core *r5_core) 738 + { 739 + struct device_node *np, *rmem_np; 740 + struct reserved_mem **rmem; 741 + int res_mem_count, i; 742 + struct device *dev; 743 + 744 + dev = r5_core->dev; 745 + np = r5_core->np; 746 + 747 + res_mem_count = of_property_count_elems_of_size(np, "memory-region", 748 + sizeof(phandle)); 749 + if (res_mem_count <= 0) { 750 + dev_warn(dev, "failed to get memory-region property %d\n", 751 + res_mem_count); 752 + return 0; 753 + } 754 + 755 + rmem = devm_kcalloc(dev, res_mem_count, 756 + sizeof(struct reserved_mem *), GFP_KERNEL); 757 + if (!rmem) 758 + return -ENOMEM; 759 + 760 + for (i = 0; i < res_mem_count; i++) { 761 + rmem_np = of_parse_phandle(np, "memory-region", i); 762 + if (!rmem_np) 763 + goto release_rmem; 764 + 765 + rmem[i] = of_reserved_mem_lookup(rmem_np); 766 + if (!rmem[i]) { 767 + of_node_put(rmem_np); 768 + goto release_rmem; 769 + } 770 + 771 + of_node_put(rmem_np); 772 + } 773 + 774 + r5_core->rmem_count = res_mem_count; 775 + r5_core->rmem = rmem; 776 + return 0; 777 + 778 + release_rmem: 779 + return -EINVAL; 780 + } 781 + 782 + /* 783 + * zynqmp_r5_core_init() 784 + * Create and initialize zynqmp_r5_core type object 785 + * 786 + * @cluster: pointer to zynqmp_r5_cluster type object 787 + * @fw_reg_val: value expected by firmware to configure RPU cluster mode 788 + * @tcm_mode: value expected by fw to configure TCM mode (lockstep or split) 789 + * 790 + * Return: 0 for success and error code for failure. 791 + */ 792 + static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, 793 + enum rpu_oper_mode fw_reg_val, 794 + enum rpu_tcm_comb tcm_mode) 795 + { 796 + struct device *dev = cluster->dev; 797 + struct zynqmp_r5_core *r5_core; 798 + int ret, i; 799 + 800 + ret = zynqmp_r5_get_tcm_node(cluster); 801 + if (ret < 0) { 802 + dev_err(dev, "can't get tcm node, err %d\n", ret); 803 + return ret; 804 + } 805 + 806 + for (i = 0; i < cluster->core_count; i++) { 807 + r5_core = cluster->r5_cores[i]; 808 + 809 + ret = zynqmp_r5_get_mem_region_node(r5_core); 810 + if (ret) 811 + dev_warn(dev, "memory-region prop failed %d\n", ret); 812 + 813 + /* Initialize r5 cores with power-domains parsed from dts */ 814 + ret = of_property_read_u32_index(r5_core->np, "power-domains", 815 + 1, &r5_core->pm_domain_id); 816 + if (ret) { 817 + dev_err(dev, "failed to get power-domains property\n"); 818 + return ret; 819 + } 820 + 821 + ret = zynqmp_r5_set_mode(r5_core, fw_reg_val, tcm_mode); 822 + if (ret) { 823 + dev_err(dev, "failed to set r5 cluster mode %d, err %d\n", 824 + cluster->mode, ret); 825 + return ret; 826 + } 827 + } 828 + 829 + return 0; 830 + } 831 + 832 + /* 833 + * zynqmp_r5_cluster_init() 834 + * Create and initialize zynqmp_r5_cluster type object 835 + * 836 + * @cluster: pointer to zynqmp_r5_cluster type object 837 + * 838 + * Return: 0 for success and error code for failure. 839 + */ 840 + static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) 841 + { 842 + enum zynqmp_r5_cluster_mode cluster_mode = LOCKSTEP_MODE; 843 + struct device *dev = cluster->dev; 844 + struct device_node *dev_node = dev_of_node(dev); 845 + struct platform_device *child_pdev; 846 + struct zynqmp_r5_core **r5_cores; 847 + enum rpu_oper_mode fw_reg_val; 848 + struct device **child_devs; 849 + struct device_node *child; 850 + enum rpu_tcm_comb tcm_mode; 851 + int core_count, ret, i; 852 + 853 + ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode); 854 + 855 + /* 856 + * on success returns 0, if not defined then returns -EINVAL, 857 + * In that case, default is LOCKSTEP mode. Other than that 858 + * returns relative error code < 0. 859 + */ 860 + if (ret != -EINVAL && ret != 0) { 861 + dev_err(dev, "Invalid xlnx,cluster-mode property\n"); 862 + return ret; 863 + } 864 + 865 + /* 866 + * For now driver only supports split mode and lockstep mode. 867 + * fail driver probe if either of that is not set in dts. 868 + */ 869 + if (cluster_mode == LOCKSTEP_MODE) { 870 + tcm_mode = PM_RPU_TCM_COMB; 871 + fw_reg_val = PM_RPU_MODE_LOCKSTEP; 872 + } else if (cluster_mode == SPLIT_MODE) { 873 + tcm_mode = PM_RPU_TCM_SPLIT; 874 + fw_reg_val = PM_RPU_MODE_SPLIT; 875 + } else { 876 + dev_err(dev, "driver does not support cluster mode %d\n", cluster_mode); 877 + return -EINVAL; 878 + } 879 + 880 + /* 881 + * Number of cores is decided by number of child nodes of 882 + * r5f subsystem node in dts. If Split mode is used in dts 883 + * 2 child nodes are expected. 884 + * In lockstep mode if two child nodes are available, 885 + * only use first child node and consider it as core0 886 + * and ignore core1 dt node. 887 + */ 888 + core_count = of_get_available_child_count(dev_node); 889 + if (core_count == 0) { 890 + dev_err(dev, "Invalid number of r5 cores %d", core_count); 891 + return -EINVAL; 892 + } else if (cluster_mode == SPLIT_MODE && core_count != 2) { 893 + dev_err(dev, "Invalid number of r5 cores for split mode\n"); 894 + return -EINVAL; 895 + } else if (cluster_mode == LOCKSTEP_MODE && core_count == 2) { 896 + dev_warn(dev, "Only r5 core0 will be used\n"); 897 + core_count = 1; 898 + } 899 + 900 + child_devs = kcalloc(core_count, sizeof(struct device *), GFP_KERNEL); 901 + if (!child_devs) 902 + return -ENOMEM; 903 + 904 + r5_cores = kcalloc(core_count, 905 + sizeof(struct zynqmp_r5_core *), GFP_KERNEL); 906 + if (!r5_cores) { 907 + kfree(child_devs); 908 + return -ENOMEM; 909 + } 910 + 911 + i = 0; 912 + for_each_available_child_of_node(dev_node, child) { 913 + child_pdev = of_find_device_by_node(child); 914 + if (!child_pdev) { 915 + of_node_put(child); 916 + ret = -ENODEV; 917 + goto release_r5_cores; 918 + } 919 + 920 + child_devs[i] = &child_pdev->dev; 921 + 922 + /* create and add remoteproc instance of type struct rproc */ 923 + r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev); 924 + if (IS_ERR(r5_cores[i])) { 925 + of_node_put(child); 926 + ret = PTR_ERR(r5_cores[i]); 927 + r5_cores[i] = NULL; 928 + goto release_r5_cores; 929 + } 930 + 931 + /* 932 + * If two child nodes are available in dts in lockstep mode, 933 + * then ignore second child node. 934 + */ 935 + if (cluster_mode == LOCKSTEP_MODE) { 936 + of_node_put(child); 937 + break; 938 + } 939 + 940 + i++; 941 + } 942 + 943 + cluster->mode = cluster_mode; 944 + cluster->core_count = core_count; 945 + cluster->r5_cores = r5_cores; 946 + 947 + ret = zynqmp_r5_core_init(cluster, fw_reg_val, tcm_mode); 948 + if (ret < 0) { 949 + dev_err(dev, "failed to init r5 core err %d\n", ret); 950 + cluster->core_count = 0; 951 + cluster->r5_cores = NULL; 952 + 953 + /* 954 + * at this point rproc resources for each core are allocated. 955 + * adjust index to free resources in reverse order 956 + */ 957 + i = core_count - 1; 958 + goto release_r5_cores; 959 + } 960 + 961 + kfree(child_devs); 962 + return 0; 963 + 964 + release_r5_cores: 965 + while (i >= 0) { 966 + put_device(child_devs[i]); 967 + if (r5_cores[i]) { 968 + of_reserved_mem_device_release(r5_cores[i]->dev); 969 + rproc_del(r5_cores[i]->rproc); 970 + rproc_free(r5_cores[i]->rproc); 971 + } 972 + i--; 973 + } 974 + kfree(r5_cores); 975 + kfree(child_devs); 976 + return ret; 977 + } 978 + 979 + static void zynqmp_r5_cluster_exit(void *data) 980 + { 981 + struct platform_device *pdev = (struct platform_device *)data; 982 + struct zynqmp_r5_cluster *cluster; 983 + struct zynqmp_r5_core *r5_core; 984 + int i; 985 + 986 + cluster = (struct zynqmp_r5_cluster *)platform_get_drvdata(pdev); 987 + if (!cluster) 988 + return; 989 + 990 + for (i = 0; i < cluster->core_count; i++) { 991 + r5_core = cluster->r5_cores[i]; 992 + of_reserved_mem_device_release(r5_core->dev); 993 + put_device(r5_core->dev); 994 + rproc_del(r5_core->rproc); 995 + rproc_free(r5_core->rproc); 996 + } 997 + 998 + kfree(cluster->r5_cores); 999 + kfree(cluster); 1000 + platform_set_drvdata(pdev, NULL); 1001 + } 1002 + 1003 + /* 1004 + * zynqmp_r5_remoteproc_probe() 1005 + * parse device-tree, initialize hardware and allocate required resources 1006 + * and remoteproc ops 1007 + * 1008 + * @pdev: domain platform device for R5 cluster 1009 + * 1010 + * Return: 0 for success and < 0 for failure. 1011 + */ 1012 + static int zynqmp_r5_remoteproc_probe(struct platform_device *pdev) 1013 + { 1014 + struct zynqmp_r5_cluster *cluster; 1015 + struct device *dev = &pdev->dev; 1016 + int ret; 1017 + 1018 + cluster = kzalloc(sizeof(*cluster), GFP_KERNEL); 1019 + if (!cluster) 1020 + return -ENOMEM; 1021 + 1022 + cluster->dev = dev; 1023 + 1024 + ret = devm_of_platform_populate(dev); 1025 + if (ret) { 1026 + dev_err_probe(dev, ret, "failed to populate platform dev\n"); 1027 + kfree(cluster); 1028 + return ret; 1029 + } 1030 + 1031 + /* wire in so each core can be cleaned up at driver remove */ 1032 + platform_set_drvdata(pdev, cluster); 1033 + 1034 + ret = zynqmp_r5_cluster_init(cluster); 1035 + if (ret) { 1036 + kfree(cluster); 1037 + platform_set_drvdata(pdev, NULL); 1038 + dev_err_probe(dev, ret, "Invalid r5f subsystem device tree\n"); 1039 + return ret; 1040 + } 1041 + 1042 + ret = devm_add_action_or_reset(dev, zynqmp_r5_cluster_exit, pdev); 1043 + if (ret) 1044 + return ret; 1045 + 1046 + return 0; 1047 + } 1048 + 1049 + /* Match table for OF platform binding */ 1050 + static const struct of_device_id zynqmp_r5_remoteproc_match[] = { 1051 + { .compatible = "xlnx,zynqmp-r5fss", }, 1052 + { /* end of list */ }, 1053 + }; 1054 + MODULE_DEVICE_TABLE(of, zynqmp_r5_remoteproc_match); 1055 + 1056 + static struct platform_driver zynqmp_r5_remoteproc_driver = { 1057 + .probe = zynqmp_r5_remoteproc_probe, 1058 + .driver = { 1059 + .name = "zynqmp_r5_remoteproc", 1060 + .of_match_table = zynqmp_r5_remoteproc_match, 1061 + }, 1062 + }; 1063 + module_platform_driver(zynqmp_r5_remoteproc_driver); 1064 + 1065 + MODULE_DESCRIPTION("Xilinx R5F remote processor driver"); 1066 + MODULE_AUTHOR("Xilinx Inc."); 1067 + MODULE_LICENSE("GPL");
+6
include/dt-bindings/power/xlnx-zynqmp-power.h
··· 6 6 #ifndef _DT_BINDINGS_ZYNQMP_POWER_H 7 7 #define _DT_BINDINGS_ZYNQMP_POWER_H 8 8 9 + #define PD_RPU_0 7 10 + #define PD_RPU_1 8 11 + #define PD_R5_0_ATCM 15 12 + #define PD_R5_0_BTCM 16 13 + #define PD_R5_1_ATCM 17 14 + #define PD_R5_1_BTCM 18 9 15 #define PD_USB_0 22 10 16 #define PD_USB_1 23 11 17 #define PD_TTC_0 24
+60
include/linux/firmware/xlnx-zynqmp.h
··· 12 12 13 13 #ifndef __FIRMWARE_ZYNQMP_H__ 14 14 #define __FIRMWARE_ZYNQMP_H__ 15 + #include <linux/types.h> 15 16 16 17 #include <linux/err.h> 17 18 ··· 88 87 enum pm_api_id { 89 88 PM_GET_API_VERSION = 1, 90 89 PM_REGISTER_NOTIFIER = 5, 90 + PM_FORCE_POWERDOWN = 8, 91 + PM_REQUEST_WAKEUP = 10, 91 92 PM_SYSTEM_SHUTDOWN = 12, 92 93 PM_REQUEST_NODE = 13, 93 94 PM_RELEASE_NODE = 14, ··· 138 135 }; 139 136 140 137 enum pm_ioctl_id { 138 + IOCTL_GET_RPU_OPER_MODE = 0, 139 + IOCTL_SET_RPU_OPER_MODE = 1, 140 + IOCTL_RPU_BOOT_ADDR_CONFIG = 2, 141 + IOCTL_TCM_COMB_CONFIG = 3, 141 142 IOCTL_SET_TAPDELAY_BYPASS = 4, 142 143 IOCTL_SD_DLL_RESET = 6, 143 144 IOCTL_SET_SD_TAPDELAY = 7, ··· 181 174 PM_QID_PINCTRL_GET_PIN_GROUPS = 11, 182 175 PM_QID_CLOCK_GET_NUM_CLOCKS = 12, 183 176 PM_QID_CLOCK_GET_MAX_DIVISOR = 13, 177 + }; 178 + 179 + enum rpu_oper_mode { 180 + PM_RPU_MODE_LOCKSTEP = 0, 181 + PM_RPU_MODE_SPLIT = 1, 182 + }; 183 + 184 + enum rpu_boot_mem { 185 + PM_RPU_BOOTMEM_LOVEC = 0, 186 + PM_RPU_BOOTMEM_HIVEC = 1, 187 + }; 188 + 189 + enum rpu_tcm_comb { 190 + PM_RPU_TCM_SPLIT = 0, 191 + PM_RPU_TCM_COMB = 1, 184 192 }; 185 193 186 194 enum zynqmp_pm_reset_action { ··· 538 516 int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value); 539 517 int zynqmp_pm_get_feature_config(enum pm_feature_config_id id, u32 *payload); 540 518 int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset); 519 + int zynqmp_pm_force_pwrdwn(const u32 target, 520 + const enum zynqmp_pm_request_ack ack); 521 + int zynqmp_pm_request_wake(const u32 node, 522 + const bool set_addr, 523 + const u64 address, 524 + const enum zynqmp_pm_request_ack ack); 525 + int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode); 526 + int zynqmp_pm_set_rpu_mode(u32 node_id, u32 arg1); 527 + int zynqmp_pm_set_tcm_config(u32 node_id, u32 arg1); 541 528 int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); 542 529 int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, 543 530 u32 value); ··· 822 791 } 823 792 824 793 static inline int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset) 794 + { 795 + return -ENODEV; 796 + } 797 + 798 + static inline int zynqmp_pm_force_pwrdwn(const u32 target, 799 + const enum zynqmp_pm_request_ack ack) 800 + { 801 + return -ENODEV; 802 + } 803 + 804 + static inline int zynqmp_pm_request_wake(const u32 node, 805 + const bool set_addr, 806 + const u64 address, 807 + const enum zynqmp_pm_request_ack ack) 808 + { 809 + return -ENODEV; 810 + } 811 + 812 + static inline int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode) 813 + { 814 + return -ENODEV; 815 + } 816 + 817 + static inline int zynqmp_pm_set_rpu_mode(u32 node_id, u32 arg1) 818 + { 819 + return -ENODEV; 820 + } 821 + 822 + static inline int zynqmp_pm_set_tcm_config(u32 node_id, u32 arg1) 825 823 { 826 824 return -ENODEV; 827 825 }