Browse Source

Merge branch 'rpmsg-ti-linux-4.19.y-intg' of git://git.ti.com/rpmsg/rpmsg into ti-linux-4.19.y

TI-Feature: rpmsg
TI-Tree: git://git.ti.com/rpmsg/rpmsg.git
TI-Branch: rpmsg-ti-linux-4.19.y-intg

* 'rpmsg-ti-linux-4.19.y-intg' of git://git.ti.com/rpmsg/rpmsg: (27 commits)
  remoteproc/k3-dsp: add support for IPC-only mode for all K3 DSPs
  ti_config_fragments: v8_rpmsg: Enable K3 DSP remoteproc support
  arm64: dts: ti: k3-j721e: Add an alias for C71x rproc node
  arm64: dts: ti: k3-j721e-som-p0: Add DDR carveout memory nodes for C71x DSP
  arm64: dts: ti: k3-j721e-main: Add C71x DSP node
  remoteproc/k3-dsp: add support for C71x DSPs
  remoteproc: add support for a new 64-bit trace version
  remoteproc: introduce version element into resource type field
  remoteproc: add 64-bit ELF loader support code
  dt-bindings: remoteproc: k3-dsp: Update bindings for C71x DSPs
  arm64: dts: ti: k3-j721e: Add aliases for C66x rproc nodes
  arm64: dts: ti: k3-j721e-som-p0: Add DDR carveout memory nodes for C66 DSPs
  arm64: dts: ti: k3-j721e-main: Add C66x DSP nodes
  remoteproc/k3-dsp: add a remoteproc driver of K3 C66x DSPs
  dt-bindings: remoteproc: Add bindings for DSP C66x clusters on TI K3 SoCs
  remoteproc/k3-r5: add support for IPC-only mode for all R5Fs on J721E SoCs
  ti_config_fragments: v8_rpmsg: Enable rpmsg client sample
  TEMP: samples/rpmsg: add compatible to support J7ES PDK firmware images
  arm64: dts: ti: k3-j721e-som-p0: Reserve memory for IPC between RTOS cores
  arm64: dts: ti: k3-j721e-som-p0: Add DDR carveout memory nodes for MAIN R5Fs
  ...

Signed-off-by: LCPD Auto Merger <lcpd_integration@list.ti.com>
LCPD Auto Merger 6 years ago
parent
commit
c58460c925

+ 179 - 0
Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.txt

@@ -0,0 +1,179 @@
+TI K3 DSP devices
+=================
+
+The TI K3 family of SoCs usually have one or more TI DSP Core sub-systems that
+are used to offload some of the processor-intensive tasks or algorithms, for
+achieving various system level goals.
+
+These processor sub-systems usually contain additional sub-modules like L1
+and/or L2 caches/SRAMs, an Interrupt Controller, an external memory controller,
+a dedicated local power/sleep controller etc. The DSP processor cores in the
+K3 SoCs is usually either a TMS320C66x CorePac processor or a TMS320C71x CorePac
+processor.
+
+DSP Device Node:
+================
+Each DSP Core sub-system is represented as a single DT node. Each node has a
+number of required or optional properties that enable the OS running on the
+host processor (Arm CorePac) to perform the device management of the remote
+processor and to communicate with the remote processor.
+
+Required properties:
+--------------------
+The following are the mandatory properties:
+
+- compatible:		Should be one of the following,
+			    "ti,j721e-c66-dsp" for C66x DSPs on K3 J721E SoCs
+			    "ti,j721e-c71-dsp" for C71x DSPs on K3 J721E SoCs
+
+- reg:			Should contain an entry for each value in 'reg-names'.
+			Each entry should have the memory region's start address
+			and the size of the region, the representation matching
+			the parent node's '#address-cells' and '#size-cells' values.
+
+- reg-names:		Should contain strings with the following names, each
+			representing a specific internal memory region (if
+			present), and should be defined in this order,
+			     "l2sram", "l1pram", "l1dram"
+			NOTE: C71x DSPs do not have a "l1pram" memory.
+
+- ti,sci:		Should be a phandle to the TI-SCI System Controller node
+
+- ti,sci-dev-id:	Should contain the TI-SCI device id corresponding to the
+			DSP Core. Please refer to the corresponding System
+			Controller documentation for valid values for the DSP
+			cores.
+
+- ti,sci-proc-ids:	Should contain 2 integer values. The first cell should
+			contain the TI-SCI processor id for the DSP core device
+			and the second cell should contain the TI-SCI host id to
+			which the processor control ownership should be
+			transferred to.
+
+- resets:		Should contain the phandle to the reset controller node
+			managing the resets for this device, and a reset
+			specifier. Please refer to the following reset bindings
+			for the reset argument specifier,
+			Documentation/devicetree/bindings/reset/ti,sci-reset.txt
+
+- power-domains:	Should contain a phandle to a PM domain provider node
+			and an args specifier containing the DSP device id
+			value. This property is as per the binding,
+			Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
+
+- mboxes:		OMAP Mailbox specifier denoting the sub-mailbox, to be
+			used for communication with the remote processor. The
+			specifier format is as per the bindings,
+			Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
+			This property should match with the sub-mailbox node
+			used in the firmware image.
+
+- memory-region:	phandle to the reserved memory nodes to be associated
+			with the remoteproc device. There should be atleast two
+			reserved memory nodes defined - the first one would be
+			used for dynamic DMA allocations like vrings and vring
+			buffers, and the remaining ones used for the firmware
+			image sections. The reserved memory nodes should be
+			carveout nodes, and should be defined as per the
+			bindings in
+			Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
+
+Optional properties:
+--------------------
+
+- sram:			pHandle to a reserved on-chip SRAM region. The region
+			should be defined as a child node of the respective
+			SRAM node, and should be defined as per the generic
+			bindings in,
+			Documentation/devicetree/bindings/misc/sram.txt
+
+
+Example:
+---------
+
+1. J721E SoC
+	/* J721E remoteproc alias */
+	aliases {
+		rproc0 = &mcu_r5fss0_core0;
+		rproc1 = &mcu_r5fss0_core1;
+		rproc2 = &main_r5fss0_core0;
+		rproc3 = &main_r5fss0_core1;
+		rproc4 = &main_r5fss1_core0;
+		rproc5 = &main_r5fss1_core1;
+		rproc6 = &c66_0;
+		rproc7 = &c66_1;
+		rproc8 = &c71_0;
+	};
+
+	/* DSP Carveout reserved memory nodes */
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		c66_0_dma_memory_region: c66-dma-memory@a6000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa6000000 0x00 0x100000>;
+			no-map;
+		};
+
+		c66_0_memory_region: c66-memory@a6100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa6100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		c71_0_dma_memory_region: c71-dma-memory@a8000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa8000000 0x00 0x100000>;
+			no-map;
+		};
+
+		c71_0_memory_region: c71-memory@a8100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa8100000 0x00 0xf00000>;
+			no-map;
+		};
+	};
+
+	cbass_main: interconnect@100000 {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges = <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71_0 */
+			 <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */
+			 <0x4d 0x81800000 0x4d 0x81800000 0x00 0x00800000>; /* C66_1 */
+
+		/* J721E C66_0 DSP node */
+		c66_0: dsp@4d80800000 {
+			compatible = "ti,j721e-c66-dsp";
+			reg = <0x4d 0x80800000 0x00 0x00048000>,
+			      <0x4d 0x80e00000 0x00 0x00008000>,
+			      <0x4d 0x80f00000 0x00 0x00008000>;
+			reg-names = "l2sram", "l1pram", "l1dram";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <142>;
+			ti,sci-proc-ids = <0x03 0xFF>;
+			resets = <&k3_reset 142 1>;
+			power-domains = <&k3_pds 142 TI_SCI_PD_EXCLUSIVE>;
+			memory-region = <&c66_0_dma_memory_region>,
+					<&c66_0_memory_region>;
+			mboxes = <&mailbox0_cluster3 &mbox_c66_0>;
+		};
+
+		/* J721E C71_0 DSP node */
+		c71_0: dsp@64800000 {
+			compatible = "ti,j721e-c71-dsp";
+			reg = <0x00 0x64800000 0x00 0x00080000>,
+			      <0x00 0x64e00000 0x00 0x0000c000>;
+			reg-names = "l2sram", "l1dram";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <15>;
+			ti,sci-proc-ids = <0x30 0xFF>;
+			resets = <&k3_reset 15 1>;
+			power-domains = <&k3_pds 15 TI_SCI_PD_EXCLUSIVE>;
+			memory-region = <&c71_0_dma_memory_region>,
+					<&c71_0_memory_region>;
+			mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
+		};
+	};

+ 4 - 1
Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.txt

@@ -23,6 +23,8 @@ The following are the mandatory properties:
 - compatible:		Should be one of the following,
 - compatible:		Should be one of the following,
 			    "ti,am654-r5fss" for R5F clusters/subsystems on
 			    "ti,am654-r5fss" for R5F clusters/subsystems on
 			                       K3 AM65x SoCs
 			                       K3 AM65x SoCs
+			    "ti,j721e-r5fss" for R5F clusters/subsystems on
+			                       K3 J721E SoCs
 - power-domains:	Should contain a phandle to a PM domain provider node
 - power-domains:	Should contain a phandle to a PM domain provider node
 			and an args specifier containing the R5FSS device id
 			and an args specifier containing the R5FSS device id
 			value. This property is as per the binding,
 			value. This property is as per the binding,
@@ -53,6 +55,7 @@ The following are the mandatory properties:
 
 
 - compatible:		Should be one of the following,
 - compatible:		Should be one of the following,
 			    "ti,am654-r5f" for the R5F cores in K3 AM65x SoCs
 			    "ti,am654-r5f" for the R5F cores in K3 AM65x SoCs
+			    "ti,j721e-r5f" for the R5F cores in K3 J721E SOCs
 - reg:			Should contain an entry for each value in 'reg-names'.
 - reg:			Should contain an entry for each value in 'reg-names'.
 			Each entry should have the memory region's start address
 			Each entry should have the memory region's start address
 			and the size of the region, the representation matching
 			and the size of the region, the representation matching
@@ -76,7 +79,7 @@ The following are the mandatory properties:
 			specifier. Please refer to the following reset bindings
 			specifier. Please refer to the following reset bindings
 			for the reset argument specifier,
 			for the reset argument specifier,
 			Documentation/devicetree/bindings/reset/ti,sci-reset.txt
 			Documentation/devicetree/bindings/reset/ti,sci-reset.txt
-			    for AM65x SoCs
+			    for AM65x and J721E SoCs
 
 
 The following properties are mandatory for R5F Core0 in both LockStep and Split
 The following properties are mandatory for R5F Core0 in both LockStep and Split
 modes, and are mandatory for R5F Core1 _only_ in Split mode. They are unused for
 modes, and are mandatory for R5F Core1 _only_ in Split mode. They are unused for

+ 121 - 0
arch/arm64/boot/dts/ti/k3-j721e-main.dtsi

@@ -1316,4 +1316,125 @@
 		dma-coherent;
 		dma-coherent;
 		no-1-8-v;
 		no-1-8-v;
 	};
 	};
+
+	main_r5fss0: r5fss@5c00000 {
+		compatible = "ti,j721e-r5fss";
+		lockstep-mode = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x5c00000 0x00 0x5c00000 0x20000>,
+			 <0x5d00000 0x00 0x5d00000 0x20000>;
+		power-domains = <&k3_pds 243 TI_SCI_PD_EXCLUSIVE>;
+
+		main_r5fss0_core0: r5f@5c00000 {
+			compatible = "ti,j721e-r5f";
+			reg = <0x5c00000 0x00008000>,
+			      <0x5c10000 0x00008000>;
+			reg-names = "atcm", "btcm";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <245>;
+			ti,sci-proc-ids = <0x06 0xFF>;
+			resets = <&k3_reset 245 1>;
+			atcm-enable = <1>;
+			btcm-enable = <1>;
+			loczrama = <1>;
+			mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
+		};
+
+		main_r5fss0_core1: r5f@5d00000 {
+			compatible = "ti,j721e-r5f";
+			reg = <0x5d00000 0x00008000>,
+			      <0x5d10000 0x00008000>;
+			reg-names = "atcm", "btcm";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <246>;
+			ti,sci-proc-ids = <0x07 0xFF>;
+			resets = <&k3_reset 246 1>;
+			atcm-enable = <1>;
+			btcm-enable = <1>;
+			loczrama = <1>;
+			mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
+		};
+	};
+
+	main_r5fss1: r5fss@5e00000 {
+		compatible = "ti,j721e-r5fss";
+		lockstep-mode = <1>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x5e00000 0x00 0x5e00000 0x20000>,
+			 <0x5f00000 0x00 0x5f00000 0x20000>;
+		power-domains = <&k3_pds 244 TI_SCI_PD_EXCLUSIVE>;
+
+		main_r5fss1_core0: r5f@5e00000 {
+			compatible = "ti,j721e-r5f";
+			reg = <0x5e00000 0x00008000>,
+			      <0x5e10000 0x00008000>;
+			reg-names = "atcm", "btcm";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <247>;
+			ti,sci-proc-ids = <0x08 0xFF>;
+			resets = <&k3_reset 247 1>;
+			atcm-enable = <1>;
+			btcm-enable = <1>;
+			loczrama = <1>;
+			mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
+		};
+
+		main_r5fss1_core1: r5f@5f00000 {
+			compatible = "ti,j721e-r5f";
+			reg = <0x5f00000 0x00008000>,
+			      <0x5f10000 0x00008000>;
+			reg-names = "atcm", "btcm";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <248>;
+			ti,sci-proc-ids = <0x09 0xFF>;
+			resets = <&k3_reset 248 1>;
+			atcm-enable = <1>;
+			btcm-enable = <1>;
+			loczrama = <1>;
+			mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
+		};
+	};
+
+	c66_0: dsp@4d80800000 {
+		compatible = "ti,j721e-c66-dsp";
+		reg = <0x4d 0x80800000 0x00 0x00048000>,
+		      <0x4d 0x80e00000 0x00 0x00008000>,
+		      <0x4d 0x80f00000 0x00 0x00008000>;
+		reg-names = "l2sram", "l1pram", "l1dram";
+		ti,sci = <&dmsc>;
+		ti,sci-dev-id = <142>;
+		ti,sci-proc-ids = <0x03 0xFF>;
+		resets = <&k3_reset 142 1>;
+		/*power-domains = <&k3_pds 142 TI_SCI_PD_EXCLUSIVE>;*/
+		mboxes = <&mailbox0_cluster3 &mbox_c66_0>;
+	};
+
+	c66_1: dsp@4d81800000 {
+		compatible = "ti,j721e-c66-dsp";
+		reg = <0x4d 0x81800000 0x00 0x00048000>,
+		      <0x4d 0x81e00000 0x00 0x00008000>,
+		      <0x4d 0x81f00000 0x00 0x00008000>;
+		reg-names = "l2sram", "l1pram", "l1dram";
+		ti,sci = <&dmsc>;
+		ti,sci-dev-id = <143>;
+		ti,sci-proc-ids = <0x04 0xFF>;
+		resets = <&k3_reset 143 1>;
+		/*power-domains = <&k3_pds 143 TI_SCI_PD_EXCLUSIVE>;*/
+		mboxes = <&mailbox0_cluster3 &mbox_c66_1>;
+	};
+
+	c71_0: dsp@64800000 {
+		compatible = "ti,j721e-c71-dsp";
+		reg = <0x00 0x64800000 0x00 0x00080000>,
+		      <0x00 0x64e00000 0x00 0x0000c000>;
+		reg-names = "l2sram", "l1dram";
+		ti,sci = <&dmsc>;
+		ti,sci-dev-id = <15>;
+		ti,sci-proc-ids = <0x30 0xFF>;
+		resets = <&k3_reset 15 1>;
+		/*power-domains = <&k3_pds 15 TI_SCI_PD_EXCLUSIVE>;*/
+		mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
+	};
 };
 };

+ 40 - 0
arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi

@@ -415,4 +415,44 @@
 			#size-cells = <0>;
 			#size-cells = <0>;
 		};
 		};
 	};
 	};
+
+	mcu_r5fss0: r5fss@41000000 {
+		compatible = "ti,j721e-r5fss";
+		lockstep-mode = <1>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x41000000 0x00 0x41000000 0x20000>,
+			 <0x41400000 0x00 0x41400000 0x20000>;
+		power-domains = <&k3_pds 249 TI_SCI_PD_EXCLUSIVE>;
+
+		mcu_r5fss0_core0: r5f@41000000 {
+			compatible = "ti,j721e-r5f";
+			reg = <0x41000000 0x00008000>,
+			      <0x41010000 0x00008000>;
+			reg-names = "atcm", "btcm";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <250>;
+			ti,sci-proc-ids = <0x01 0xFF>;
+			resets = <&k3_reset 250 1>;
+			atcm-enable = <1>;
+			btcm-enable = <1>;
+			loczrama = <1>;
+			mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
+		};
+
+		mcu_r5fss0_core1: r5f@41400000 {
+			compatible = "ti,j721e-r5f";
+			reg = <0x41400000 0x00008000>,
+			      <0x41410000 0x00008000>;
+			reg-names = "atcm", "btcm";
+			ti,sci = <&dmsc>;
+			ti,sci-dev-id = <251>;
+			ti,sci-proc-ids = <0x02 0xFF>;
+			resets = <&k3_reset 251 1>;
+			atcm-enable = <1>;
+			btcm-enable = <1>;
+			loczrama = <1>;
+			mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
+		};
+	};
 };
 };

+ 159 - 0
arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi

@@ -25,6 +25,120 @@
 			alignment = <0x1000>;
 			alignment = <0x1000>;
 			no-map;
 			no-map;
 		};
 		};
+
+		mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa0000000 0x00 0x100000>;
+			no-map;
+		};
+
+		mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa0100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa1000000 0x00 0x100000>;
+			no-map;
+		};
+
+		mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa1100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a2000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa2000000 0x00 0x100000>;
+			no-map;
+		};
+
+		main_r5fss0_core0_memory_region: r5f-memory@a2100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa2100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a3000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa3000000 0x00 0x100000>;
+			no-map;
+		};
+
+		main_r5fss0_core1_memory_region: r5f-memory@a3100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa3100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a4000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa4000000 0x00 0x100000>;
+			no-map;
+		};
+
+		main_r5fss1_core0_memory_region: r5f-memory@a4100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa4100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a5000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa5000000 0x00 0x100000>;
+			no-map;
+		};
+
+		main_r5fss1_core1_memory_region: r5f-memory@a5100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa5100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		c66_1_dma_memory_region: c66-dma-memory@a6000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa6000000 0x00 0x100000>;
+			no-map;
+		};
+
+		c66_0_memory_region: c66-memory@a6100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa6100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		c66_0_dma_memory_region: c66-dma-memory@a7000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa7000000 0x00 0x100000>;
+			no-map;
+		};
+
+		c66_1_memory_region: c66-memory@a7100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa7100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		c71_0_dma_memory_region: c71-dma-memory@a8000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa8000000 0x00 0x100000>;
+			no-map;
+		};
+
+		c71_0_memory_region: c71-memory@a8100000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0xa8100000 0x00 0xf00000>;
+			no-map;
+		};
+
+		rtos_ipc_memory_region: ipc-memories@aa000000 {
+			reg = <0x00 0xaa000000 0x00 0x01c00000>;
+			alignment = <0x1000>;
+			no-map;
+		};
 	};
 	};
 };
 };
 
 
@@ -111,3 +225,48 @@
 		#size-cells = <1>;
 		#size-cells = <1>;
 	};
 	};
 };
 };
+
+&mcu_r5fss0_core0 {
+	memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
+			<&mcu_r5fss0_core0_memory_region>;
+};
+
+&mcu_r5fss0_core1 {
+	memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
+			<&mcu_r5fss0_core1_memory_region>;
+};
+
+&main_r5fss0_core0 {
+	memory-region = <&main_r5fss0_core0_dma_memory_region>,
+			<&main_r5fss0_core0_memory_region>;
+};
+
+&main_r5fss0_core1 {
+	memory-region = <&main_r5fss0_core1_dma_memory_region>,
+			<&main_r5fss0_core1_memory_region>;
+};
+
+&main_r5fss1_core0 {
+	memory-region = <&main_r5fss1_core0_dma_memory_region>,
+			<&main_r5fss1_core0_memory_region>;
+};
+
+&main_r5fss1_core1 {
+	memory-region = <&main_r5fss1_core1_dma_memory_region>,
+			<&main_r5fss1_core1_memory_region>;
+};
+
+&c66_0 {
+	memory-region = <&c66_0_dma_memory_region>,
+			<&c66_0_memory_region>;
+};
+
+&c66_1 {
+	memory-region = <&c66_1_dma_memory_region>,
+			<&c66_1_memory_region>;
+};
+
+&c71_0 {
+	memory-region = <&c71_0_dma_memory_region>,
+			<&c71_0_memory_region>;
+};

+ 9 - 0
arch/arm64/boot/dts/ti/k3-j721e.dtsi

@@ -33,6 +33,15 @@
 		serial11 = &main_uart9;
 		serial11 = &main_uart9;
 		spi0 = &ospi0;
 		spi0 = &ospi0;
 		spi1 = &ospi1;
 		spi1 = &ospi1;
+		rproc0 = &mcu_r5fss0_core0;
+		rproc1 = &mcu_r5fss0_core1;
+		rproc2 = &main_r5fss0_core0;
+		rproc3 = &main_r5fss0_core1;
+		rproc4 = &main_r5fss1_core0;
+		rproc5 = &main_r5fss1_core1;
+		rproc6 = &c66_0;
+		rproc7 = &c66_1;
+		rproc8 = &c71_0;
 	};
 	};
 
 
 	chosen { };
 	chosen { };

+ 16 - 0
drivers/remoteproc/Kconfig

@@ -223,6 +223,22 @@ config TI_K3_R5_REMOTEPROC
 	  It's safe to say N here if you're not interested in utilizing
 	  It's safe to say N here if you're not interested in utilizing
 	  a slave processor
 	  a slave processor
 
 
+config TI_K3_DSP_REMOTEPROC
+	tristate "TI K3 DSP remoteproc support"
+	depends on ARCH_K3
+	select MAILBOX
+	select OMAP2PLUS_MBOX
+	help
+	  Say y here to support TI's C66x and C71x DSP remote processor
+	  subsystems on various TI K3 family of SoCs through the remote
+	  processor framework.
+
+	  You want to say m here in order to offload some processing
+	  tasks to these processors.
+
+	  It's safe to say N here if you're not interested in utilizing
+	  the DSP slave processors.
+
 endif # REMOTEPROC
 endif # REMOTEPROC
 
 
 endmenu
 endmenu

+ 2 - 0
drivers/remoteproc/Makefile

@@ -9,6 +9,7 @@ remoteproc-y				+= remoteproc_debugfs.o
 remoteproc-y				+= remoteproc_sysfs.o
 remoteproc-y				+= remoteproc_sysfs.o
 remoteproc-y				+= remoteproc_virtio.o
 remoteproc-y				+= remoteproc_virtio.o
 remoteproc-y				+= remoteproc_elf_loader.o
 remoteproc-y				+= remoteproc_elf_loader.o
+remoteproc-y				+= remoteproc_elf64_loader.o
 obj-$(CONFIG_IMX_REMOTEPROC)		+= imx_rproc.o
 obj-$(CONFIG_IMX_REMOTEPROC)		+= imx_rproc.o
 obj-$(CONFIG_OMAP_REMOTEPROC)		+= omap_remoteproc.o
 obj-$(CONFIG_OMAP_REMOTEPROC)		+= omap_remoteproc.o
 obj-$(CONFIG_WKUP_M3_RPROC)		+= wkup_m3_rproc.o
 obj-$(CONFIG_WKUP_M3_RPROC)		+= wkup_m3_rproc.o
@@ -27,3 +28,4 @@ qcom_wcnss_pil-y			+= qcom_wcnss_iris.o
 obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
 obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
 obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
 obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
 obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o
 obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o
+obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)	+= ti_k3_dsp_remoteproc.o

+ 47 - 18
drivers/remoteproc/remoteproc_core.c

@@ -54,7 +54,7 @@ static LIST_HEAD(rproc_list);
 typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
 typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
 				struct resource_table *table, int len);
 				struct resource_table *table, int len);
 typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
 typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
-				 void *, int offset, int avail);
+				 void *, int offset, int avail, u16 ver);
 
 
 /* Unique indices for remoteproc devices */
 /* Unique indices for remoteproc devices */
 static DEFINE_IDA(rproc_dev_index);
 static DEFINE_IDA(rproc_dev_index);
@@ -382,6 +382,7 @@ static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed)
  * @rproc: the remote processor
  * @rproc: the remote processor
  * @rsc: the vring resource descriptor
  * @rsc: the vring resource descriptor
  * @avail: size of available data (for sanity checking the image)
  * @avail: size of available data (for sanity checking the image)
+ * @ver: version number of the resource type
  *
  *
  * This resource entry requests the host to statically register a virtio
  * This resource entry requests the host to statically register a virtio
  * device (vdev), and setup everything needed to support it. It contains
  * device (vdev), and setup everything needed to support it. It contains
@@ -405,7 +406,7 @@ static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed)
  * Returns 0 on success, or an appropriate error code otherwise
  * Returns 0 on success, or an appropriate error code otherwise
  */
  */
 static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
 static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
-			     int offset, int avail)
+			     int offset, int avail, u16 ver)
 {
 {
 	struct device *dev = &rproc->dev;
 	struct device *dev = &rproc->dev;
 	struct rproc_vdev *rvdev;
 	struct rproc_vdev *rvdev;
@@ -598,6 +599,7 @@ copy_and_exit:
  * @rproc: the remote processor
  * @rproc: the remote processor
  * @rsc: the trace resource descriptor
  * @rsc: the trace resource descriptor
  * @avail: size of available data (for sanity checking the image)
  * @avail: size of available data (for sanity checking the image)
+ * @ver: version number of the resource type
  *
  *
  * In case the remote processor dumps trace logs into memory,
  * In case the remote processor dumps trace logs into memory,
  * export it via debugfs.
  * export it via debugfs.
@@ -609,27 +611,51 @@ copy_and_exit:
  *
  *
  * Returns 0 on success, or an appropriate error code otherwise
  * Returns 0 on success, or an appropriate error code otherwise
  */
  */
-static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
-			      int offset, int avail)
+static int rproc_handle_trace(struct rproc *rproc, void *rsc,
+			      int offset, int avail, u16 ver)
 {
 {
 	struct rproc_mem_entry *trace;
 	struct rproc_mem_entry *trace;
 	struct device *dev = &rproc->dev;
 	struct device *dev = &rproc->dev;
+	struct fw_rsc_trace *rsc1;
+	struct fw_rsc_trace2 *rsc2;
 	void *ptr;
 	void *ptr;
 	char name[15];
 	char name[15];
+	size_t rsc_size;
+	u32 reserved;
+	u64 da;
+	u32 len;
+
+	if (!ver) {
+		rsc1 = (struct fw_rsc_trace *)rsc;
+		rsc_size = sizeof(*rsc1);
+		reserved = rsc1->reserved;
+		da = rsc1->da;
+		len = rsc1->len;
+	} else if (ver == 1) {
+		rsc2 = (struct fw_rsc_trace2 *)rsc;
+		rsc_size = sizeof(*rsc2);
+		reserved = rsc2->reserved;
+		da = rsc2->da;
+		len = rsc2->len;
+	} else {
+		dev_err(dev, "unsupported trace rsc version %d\n", ver);
+		return -EINVAL;
+	}
 
 
-	if (sizeof(*rsc) > avail) {
+	if (rsc_size > avail) {
 		dev_err(dev, "trace rsc is truncated\n");
 		dev_err(dev, "trace rsc is truncated\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	/* make sure reserved bytes are zeroes */
 	/* make sure reserved bytes are zeroes */
-	if (rsc->reserved) {
-		dev_err(dev, "trace rsc has non zero reserved bytes\n");
+	if (reserved) {
+		dev_err(dev, "trace rsc has non zero reserved bytes, value = 0x%x\n",
+			reserved);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	/* what's the kernel address of this resource ? */
 	/* what's the kernel address of this resource ? */
-	ptr = rproc_da_to_va(rproc, rsc->da, rsc->len, RPROC_FLAGS_NONE);
+	ptr = rproc_da_to_va(rproc, da, len, RPROC_FLAGS_NONE);
 	if (!ptr) {
 	if (!ptr) {
 		dev_err(dev, "erroneous trace resource entry\n");
 		dev_err(dev, "erroneous trace resource entry\n");
 		return -EINVAL;
 		return -EINVAL;
@@ -640,7 +666,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	/* set the trace buffer dma properties */
 	/* set the trace buffer dma properties */
-	trace->len = rsc->len;
+	trace->len = len;
 	trace->va = ptr;
 	trace->va = ptr;
 
 
 	/* make sure snprintf always null terminates, even if truncating */
 	/* make sure snprintf always null terminates, even if truncating */
@@ -658,8 +684,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
 
 
 	rproc->num_traces++;
 	rproc->num_traces++;
 
 
-	dev_dbg(dev, "%s added: va %pK, da 0x%x, len 0x%x\n",
-		name, ptr, rsc->da, rsc->len);
+	dev_dbg(dev, "%s added: va %pK, da 0x%llx, len 0x%x\n",
+		name, ptr, da, len);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -669,6 +695,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
  * @rproc: remote processor handle
  * @rproc: remote processor handle
  * @rsc: the devmem resource entry
  * @rsc: the devmem resource entry
  * @avail: size of available data (for sanity checking the image)
  * @avail: size of available data (for sanity checking the image)
+ * @ver: version number of the resource type
  *
  *
  * Remote processors commonly need to access certain on-chip peripherals.
  * Remote processors commonly need to access certain on-chip peripherals.
  *
  *
@@ -690,7 +717,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
  * are outside those ranges.
  * are outside those ranges.
  */
  */
 static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
 static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
-			       int offset, int avail)
+			       int offset, int avail, u16 ver)
 {
 {
 	struct rproc_mem_entry *mapping;
 	struct rproc_mem_entry *mapping;
 	struct device *dev = &rproc->dev;
 	struct device *dev = &rproc->dev;
@@ -748,6 +775,7 @@ out:
  * @rproc: rproc handle
  * @rproc: rproc handle
  * @rsc: the resource entry
  * @rsc: the resource entry
  * @avail: size of available data (for image validation)
  * @avail: size of available data (for image validation)
+ * @ver: version number of the resource type
  *
  *
  * This function will handle firmware requests for allocation of physically
  * This function will handle firmware requests for allocation of physically
  * contiguous memory regions.
  * contiguous memory regions.
@@ -763,7 +791,7 @@ out:
  */
  */
 static int rproc_handle_carveout(struct rproc *rproc,
 static int rproc_handle_carveout(struct rproc *rproc,
 				 struct fw_rsc_carveout *rsc,
 				 struct fw_rsc_carveout *rsc,
-				 int offset, int avail)
+				 int offset, int avail, u16 ver)
 {
 {
 	struct rproc_mem_entry *carveout, *mapping;
 	struct rproc_mem_entry *carveout, *mapping;
 	struct device *dev = &rproc->dev;
 	struct device *dev = &rproc->dev;
@@ -960,18 +988,19 @@ static int rproc_handle_resources(struct rproc *rproc,
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
-		dev_dbg(dev, "rsc: type %d\n", hdr->type);
+		dev_dbg(dev, "rsc: type %d vers %d\n", hdr->st.t, hdr->st.v);
 
 
-		if (hdr->type >= RSC_LAST) {
-			dev_warn(dev, "unsupported resource %d\n", hdr->type);
+		if (hdr->st.t >= RSC_LAST) {
+			dev_warn(dev, "unsupported resource %d\n", hdr->st.t);
 			continue;
 			continue;
 		}
 		}
 
 
-		handler = handlers[hdr->type];
+		handler = handlers[hdr->st.t];
 		if (!handler)
 		if (!handler)
 			continue;
 			continue;
 
 
-		ret = handler(rproc, rsc, offset + sizeof(*hdr), avail);
+		ret = handler(rproc, rsc, offset + sizeof(*hdr), avail,
+			      hdr->st.v);
 		if (ret)
 		if (ret)
 			break;
 			break;
 	}
 	}

+ 37 - 13
drivers/remoteproc/remoteproc_debugfs.c

@@ -164,7 +164,8 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
 	struct resource_table *table = rproc->table_ptr;
 	struct resource_table *table = rproc->table_ptr;
 	struct fw_rsc_carveout *c;
 	struct fw_rsc_carveout *c;
 	struct fw_rsc_devmem *d;
 	struct fw_rsc_devmem *d;
-	struct fw_rsc_trace *t;
+	struct fw_rsc_trace *t1;
+	struct fw_rsc_trace2 *t2;
 	struct fw_rsc_vdev *v;
 	struct fw_rsc_vdev *v;
 	struct fw_rsc_vendor *vr;
 	struct fw_rsc_vendor *vr;
 	int i, j;
 	int i, j;
@@ -178,11 +179,13 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
 		int offset = table->offset[i];
 		int offset = table->offset[i];
 		struct fw_rsc_hdr *hdr = (void *)table + offset;
 		struct fw_rsc_hdr *hdr = (void *)table + offset;
 		void *rsc = (void *)hdr + sizeof(*hdr);
 		void *rsc = (void *)hdr + sizeof(*hdr);
+		u16 ver = hdr->st.v;
 
 
-		switch (hdr->type) {
+		switch (hdr->st.t) {
 		case RSC_CARVEOUT:
 		case RSC_CARVEOUT:
 			c = rsc;
 			c = rsc;
-			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
+			seq_printf(seq, "Entry %d is of type %s\n",
+				   i, types[hdr->st.t]);
 			seq_printf(seq, "  Device Address 0x%x\n", c->da);
 			seq_printf(seq, "  Device Address 0x%x\n", c->da);
 			seq_printf(seq, "  Physical Address 0x%x\n", c->pa);
 			seq_printf(seq, "  Physical Address 0x%x\n", c->pa);
 			seq_printf(seq, "  Length 0x%x Bytes\n", c->len);
 			seq_printf(seq, "  Length 0x%x Bytes\n", c->len);
@@ -192,7 +195,8 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
 			break;
 			break;
 		case RSC_DEVMEM:
 		case RSC_DEVMEM:
 			d = rsc;
 			d = rsc;
-			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
+			seq_printf(seq, "Entry %d is of type %s\n",
+				   i, types[hdr->st.t]);
 			seq_printf(seq, "  Device Address 0x%x\n", d->da);
 			seq_printf(seq, "  Device Address 0x%x\n", d->da);
 			seq_printf(seq, "  Physical Address 0x%x\n", d->pa);
 			seq_printf(seq, "  Physical Address 0x%x\n", d->pa);
 			seq_printf(seq, "  Length 0x%x Bytes\n", d->len);
 			seq_printf(seq, "  Length 0x%x Bytes\n", d->len);
@@ -201,17 +205,37 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
 			seq_printf(seq, "  Name %s\n\n", d->name);
 			seq_printf(seq, "  Name %s\n\n", d->name);
 			break;
 			break;
 		case RSC_TRACE:
 		case RSC_TRACE:
-			t = rsc;
-			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
-			seq_printf(seq, "  Device Address 0x%x\n", t->da);
-			seq_printf(seq, "  Length 0x%x Bytes\n", t->len);
-			seq_printf(seq, "  Reserved (should be zero) [%d]\n", t->reserved);
-			seq_printf(seq, "  Name %s\n\n", t->name);
+			if (ver == 0) {
+				t1 = rsc;
+				seq_printf(seq, "Entry %d is version %d of type %s\n",
+					   i, ver, types[hdr->st.t]);
+				seq_printf(seq, "  Device Address 0x%x\n",
+					   t1->da);
+				seq_printf(seq, "  Length 0x%x Bytes\n",
+					   t1->len);
+				seq_printf(seq, "  Reserved (should be zero) [%d]\n",
+					   t1->reserved);
+				seq_printf(seq, "  Name %s\n\n", t1->name);
+			} else if (ver == 1) {
+				t2 = rsc;
+				seq_printf(seq, "Entry %d is version %d of type %s\n",
+					   i, ver, types[hdr->st.t]);
+				seq_printf(seq, "  Device Address 0x%llx\n",
+					   t2->da);
+				seq_printf(seq, "  Length 0x%x Bytes\n",
+					   t2->len);
+				seq_printf(seq, "  Reserved (should be zero) [%d]\n",
+					   t2->reserved);
+				seq_printf(seq, "  Name %s\n\n", t2->name);
+			} else {
+				seq_printf(seq, "Entry %d is an unsupported version %d of type %s\n",
+					   i, ver, types[hdr->st.t]);
+			}
 			break;
 			break;
 		case RSC_VDEV:
 		case RSC_VDEV:
 			v = rsc;
 			v = rsc;
-			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
-
+			seq_printf(seq, "Entry %d is of type %s\n",
+				   i, types[hdr->st.t]);
 			seq_printf(seq, "  ID %d\n", v->id);
 			seq_printf(seq, "  ID %d\n", v->id);
 			seq_printf(seq, "  Notify ID %d\n", v->notifyid);
 			seq_printf(seq, "  Notify ID %d\n", v->notifyid);
 			seq_printf(seq, "  Device features 0x%x\n", v->dfeatures);
 			seq_printf(seq, "  Device features 0x%x\n", v->dfeatures);
@@ -244,7 +268,7 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
 			break;
 			break;
 		default:
 		default:
 			seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
 			seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
-				   hdr->type, hdr);
+				   hdr->st.t, hdr);
 			break;
 			break;
 		}
 		}
 	}
 	}

+ 335 - 0
drivers/remoteproc/remoteproc_elf64_loader.c

@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Remote Processor Framework 64-bit Elf loader
+ * Code based on current remoteproc_elf_loader.c
+ *
+ * Copyright (C) 2018-2019 Texas Instruments, Inc.
+ *
+ * Suman Anna <s-anna@ti.com>
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/remoteproc.h>
+
+#include "remoteproc_internal.h"
+
+/**
+ * rproc_elf64_sanity_check() - Sanity Check ELF firmware image
+ * @rproc: the remote processor handle
+ * @fw: the ELF firmware image
+ *
+ * Make sure this fw image is sane.
+ */
+int rproc_elf64_sanity_check(struct rproc *rproc, const struct firmware *fw)
+{
+	const char *name = rproc->firmware;
+	struct device *dev = &rproc->dev;
+	struct elf64_hdr *ehdr;
+	char class;
+
+	if (!fw) {
+		dev_err(dev, "failed to load %s\n", name);
+		return -EINVAL;
+	}
+
+	if (fw->size < sizeof(struct elf64_hdr)) {
+		dev_err(dev, "Image is too small\n");
+		return -EINVAL;
+	}
+
+	ehdr = (struct elf64_hdr *)fw->data;
+
+	/* We only support ELF64 at this point */
+	class = ehdr->e_ident[EI_CLASS];
+	if (class != ELFCLASS64) {
+		dev_err(dev, "Unsupported class: %d\n", class);
+		return -EINVAL;
+	}
+
+	/* We assume the firmware has the same endianness as the host */
+# ifdef __LITTLE_ENDIAN
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+		dev_err(dev, "Unsupported firmware endianness\n");
+		return -EINVAL;
+	}
+
+	if (fw->size < ehdr->e_shoff + sizeof(struct elf64_shdr)) {
+		dev_err(dev, "Image is too small\n");
+		return -EINVAL;
+	}
+
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		dev_err(dev, "No loadable segments\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phoff > fw->size) {
+		dev_err(dev, "Firmware size is too small\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rproc_elf64_sanity_check);
+
+/**
+ * rproc_elf64_get_boot_addr() - Get rproc's boot address.
+ * @rproc: the remote processor handle
+ * @fw: the ELF firmware image
+ *
+ * This function returns the entry point address of the ELF
+ * image.
+ *
+ * Note that the boot address is not a configurable property of all remote
+ * processors. Some will always boot at a specific hard-coded address.
+ *
+ * FIXME: The entry-point with 64-bit processors will be a 64-bit address,
+ * but return a 32-bit address for now to overload and reuse the current
+ * rproc_ops. This will scale as long as the higher 32-bit addresses are
+ * zero.
+ */
+u32 rproc_elf64_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+{
+	struct elf64_hdr *ehdr = (struct elf64_hdr *)fw->data;
+
+	WARN_ON(upper_32_bits(ehdr->e_entry) != 0);
+
+	return lower_32_bits(ehdr->e_entry);
+}
+EXPORT_SYMBOL(rproc_elf64_get_boot_addr);
+
+/**
+ * rproc_elf64_load_segments() - load firmware segments to memory
+ * @rproc: remote processor which will be booted using these fw segments
+ * @fw: the ELF firmware image
+ *
+ * This function loads the firmware segments to memory, where the remote
+ * processor expects them.
+ *
+ * Some remote processors will expect their code and data to be placed
+ * in specific device addresses, and can't have them dynamically assigned.
+ *
+ * We currently support only those kind of remote processors, and expect
+ * the program header's paddr member to contain those addresses. We then
+ * request the remoteproc core to perform a lookup either in its list of
+ * allocated (and mapped) physically contiguous "carveout" memory regions
+ * and/or registered pre-fixed physically contiguous reserved memory
+ * regions, and "translate" device address to kernel addresses, so we can
+ * copy the segments where they are expected.
+ */
+int rproc_elf64_load_segments(struct rproc *rproc, const struct firmware *fw)
+{
+	struct device *dev = &rproc->dev;
+	struct elf64_hdr *ehdr;
+	struct elf64_phdr *phdr;
+	int i, ret = 0;
+	const u8 *elf_data = fw->data;
+
+	ehdr = (struct elf64_hdr *)elf_data;
+	phdr = (struct elf64_phdr *)(elf_data + ehdr->e_phoff);
+
+	/* go through the available ELF segments */
+	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+		u32 da = phdr->p_paddr;
+		u32 memsz = phdr->p_memsz;
+		u32 filesz = phdr->p_filesz;
+		u32 offset = phdr->p_offset;
+		void *ptr;
+
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
+			phdr->p_type, da, memsz, filesz);
+
+		if (filesz > memsz) {
+			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+				filesz, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (offset + filesz > fw->size) {
+			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+				offset + filesz, fw->size);
+			ret = -EINVAL;
+			break;
+		}
+
+		/*
+		 * grab the kernel address for this device address. Use
+		 * RPROC_FLAGS_NONE as current rproc_da_to_va() does not
+		 * scale for 64-bit flags, and there are no existing use-cases
+		 * requiring this
+		 */
+		ptr = rproc_da_to_va(rproc, da, memsz, RPROC_FLAGS_NONE);
+		if (!ptr) {
+			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		/* put the segment where the remote processor expects it */
+		if (phdr->p_filesz)
+			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+
+		/*
+		 * Zero out remaining memory for this segment.
+		 *
+		 * This isn't strictly required since dma_alloc_coherent already
+		 * did this for us. albeit harmless, we may consider removing
+		 * this.
+		 */
+		if (memsz > filesz)
+			memset(ptr + filesz, 0, memsz - filesz);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(rproc_elf64_load_segments);
+
+static struct elf64_shdr *
+find_table(struct device *dev, struct elf64_hdr *ehdr, size_t fw_size)
+{
+	struct elf64_shdr *shdr;
+	int i;
+	const char *name_table;
+	struct resource_table *table = NULL;
+	const u8 *elf_data = (void *)ehdr;
+
+	/* look for the resource table and handle it */
+	shdr = (struct elf64_shdr *)(elf_data + ehdr->e_shoff);
+	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
+
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		u32 size = shdr->sh_size;
+		u32 offset = shdr->sh_offset;
+
+		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+			continue;
+
+		table = (struct resource_table *)(elf_data + offset);
+
+		/* make sure we have the entire table */
+		if (offset + size > fw_size || offset + size < size) {
+			dev_err(dev, "resource table truncated\n");
+			return NULL;
+		}
+
+		/* make sure table has at least the header */
+		if (sizeof(struct resource_table) > size) {
+			dev_err(dev, "header-less resource table\n");
+			return NULL;
+		}
+
+		/* we don't support any version beyond the first */
+		if (table->ver != 1) {
+			dev_err(dev, "unsupported fw ver: %d\n", table->ver);
+			return NULL;
+		}
+
+		/* make sure reserved bytes are zeroes */
+		if (table->reserved[0] || table->reserved[1]) {
+			dev_err(dev, "non zero reserved bytes\n");
+			return NULL;
+		}
+
+		/* make sure the offsets array isn't truncated */
+		if (table->num * sizeof(table->offset[0]) +
+				sizeof(struct resource_table) > size) {
+			dev_err(dev, "resource table incomplete\n");
+			return NULL;
+		}
+
+		return shdr;
+	}
+
+	return NULL;
+}
+
+/**
+ * rproc_elf64_load_rsc_table() - load the resource table
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware, load it into the @cached_table and update @table_ptr.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int rproc_elf64_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
+{
+	struct elf64_hdr *ehdr;
+	struct elf64_shdr *shdr;
+	struct device *dev = &rproc->dev;
+	struct resource_table *table = NULL;
+	const u8 *elf_data = fw->data;
+	size_t tablesz;
+
+	ehdr = (struct elf64_hdr *)elf_data;
+
+	shdr = find_table(dev, ehdr, fw->size);
+	if (!shdr)
+		return -EINVAL;
+
+	table = (struct resource_table *)(elf_data + shdr->sh_offset);
+	tablesz = shdr->sh_size;
+
+	/*
+	 * Create a copy of the resource table. When a virtio device starts
+	 * and calls vring_new_virtqueue() the address of the allocated vring
+	 * will be stored in the cached_table. Before the device is started,
+	 * cached_table will be copied into device memory.
+	 */
+	rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
+	if (!rproc->cached_table)
+		return -ENOMEM;
+
+	rproc->table_ptr = rproc->cached_table;
+	rproc->table_sz = tablesz;
+
+	return 0;
+}
+EXPORT_SYMBOL(rproc_elf64_load_rsc_table);
+
+/**
+ * rproc_elf64_find_loaded_rsc_table() - find the loaded resource table
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ *
+ * This function finds the location of the loaded resource table. Don't
+ * call this function if the table wasn't loaded yet - it's a bug if you do.
+ *
+ * Returns the pointer to the resource table if it is found or NULL otherwise.
+ * If the table wasn't loaded yet the result is unspecified.
+ */
+struct resource_table *
+rproc_elf64_find_loaded_rsc_table(struct rproc *rproc,
+				  const struct firmware *fw)
+{
+	struct elf64_hdr *ehdr = (struct elf64_hdr *)fw->data;
+	struct elf64_shdr *shdr;
+
+	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	if (!shdr)
+		return NULL;
+
+	/*
+	 * Use RPROC_FLAGS_NONE as current rproc_da_to_va() does not
+	 * scale for 64-bit flags, and no current use-cases require this
+	 */
+	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size,
+			      RPROC_FLAGS_NONE);
+}
+EXPORT_SYMBOL(rproc_elf64_find_loaded_rsc_table);

+ 8 - 0
drivers/remoteproc/remoteproc_internal.h

@@ -60,6 +60,14 @@ int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 						       const struct firmware *fw);
 						       const struct firmware *fw);
 
 
+int rproc_elf64_sanity_check(struct rproc *rproc, const struct firmware *fw);
+u32 rproc_elf64_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+int rproc_elf64_load_segments(struct rproc *rproc, const struct firmware *fw);
+int rproc_elf64_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
+struct resource_table *
+rproc_elf64_find_loaded_rsc_table(struct rproc *rproc,
+				  const struct firmware *fw);
+
 static inline
 static inline
 int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
 int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 {

+ 785 - 0
drivers/remoteproc/ti_k3_dsp_remoteproc.c

@@ -0,0 +1,785 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TI K3 DSP Remote Processor(s) driver
+ *
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ *	Suman Anna <s-anna@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/remoteproc.h>
+#include <linux/mailbox_client.h>
+#include <linux/omap-mailbox.h>
+#include <linux/reset.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+#include "omap_remoteproc.h"
+#include "remoteproc_internal.h"
+#include "ti_sci_proc.h"
+
+#define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK	(SZ_16M - 1)
+
+/**
+ * struct k3_dsp_rproc_mem - internal memory structure
+ * @cpu_addr: MPU virtual address of the memory region
+ * @bus_addr: Bus address used to access the memory region
+ * @dev_addr: Device address of the memory region from DSP view
+ * @size: Size of the memory region
+ */
+struct k3_dsp_rproc_mem {
+	void __iomem *cpu_addr;
+	phys_addr_t bus_addr;
+	u32 dev_addr;
+	size_t size;
+};
+
+/**
+ * struct k3_dsp_rproc - k3 DSP remote processor driver structure
+ * @dev: cached device pointer
+ * @rproc: remoteproc device handle
+ * @mem: internal memory regions data
+ * @num_mems: number of internal memory regions
+ * @rmem: reserved memory regions data
+ * @num_rmems: number of reserved memory regions
+ * @reset: reset control handle
+ * @tsp: TI-SCI processor control handle
+ * @ti_sci: TI-SCI handle
+ * @ti_sci_id: TI-SCI device identifier
+ * @mbox: mailbox channel handle
+ * @client: mailbox client to request the mailbox channel
+ * @ipc_only: flag to indicate IPC-only mode
+ */
+struct k3_dsp_rproc {
+	struct device *dev;
+	struct rproc *rproc;
+	struct k3_dsp_rproc_mem *mem;
+	int num_mems;
+	struct k3_dsp_rproc_mem *rmem;
+	int num_rmems;
+	struct reset_control *reset;
+	struct ti_sci_proc *tsp;
+	const struct ti_sci_handle *ti_sci;
+	u32 ti_sci_id;
+	struct mbox_chan *mbox;
+	struct mbox_client client;
+	unsigned int ipc_only : 1;
+};
+
+/**
+ * struct k3_dsp_rproc_dev_data - device data for the remote processor
+ * @device_name: device name of the remote processor
+ * @fw_name: firmware name to use
+ */
+struct k3_dsp_rproc_dev_data {
+	const char *device_name;
+	const char *fw_name;
+};
+
+/**
+ * k3_dsp_rproc_mbox_callback() - inbound mailbox message handler
+ * @client: mailbox client pointer used for requesting the mailbox channel
+ * @data: mailbox payload
+ *
+ * This handler is invoked by the OMAP mailbox driver whenever a mailbox
+ * message is received. Usually, the mailbox payload simply contains
+ * the index of the virtqueue that is kicked by the remote processor,
+ * and we let remoteproc core handle it.
+ *
+ * In addition to virtqueue indices, we also have some out-of-band values
+ * that indicate different events. Those values are deliberately very
+ * large so they don't coincide with virtqueue indices.
+ */
+static void k3_dsp_rproc_mbox_callback(struct mbox_client *client, void *data)
+{
+	struct k3_dsp_rproc *kproc = container_of(client, struct k3_dsp_rproc,
+						client);
+	struct device *dev = kproc->rproc->dev.parent;
+	const char *name = kproc->rproc->name;
+	u32 msg = to_omap_mbox_msg(data);
+
+	dev_dbg(dev, "mbox msg: 0x%x\n", msg);
+
+	switch (msg) {
+	case RP_MBOX_CRASH:
+		/*
+		 * remoteproc detected an exception, but error recovery is not
+		 * supported. So, just log this for now
+		 */
+		dev_err(dev, "K3 DSP rproc %s crashed\n", name);
+		break;
+	case RP_MBOX_ECHO_REPLY:
+		dev_info(dev, "received echo reply from %s\n", name);
+		break;
+	default:
+		/* silently handle all other valid messages */
+		if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG)
+			return;
+		if (msg > kproc->rproc->max_notifyid) {
+			dev_dbg(dev, "dropping unknown message 0x%x", msg);
+			return;
+		}
+		/* msg contains the index of the triggered vring */
+		if (rproc_vq_interrupt(kproc->rproc, msg) == IRQ_NONE)
+			dev_dbg(dev, "no message was found in vqid %d\n", msg);
+	}
+}
+
+/*
+ * Kick the remote processor to notify about pending unprocessed messages.
+ * The vqid usage is not used and is inconsequential, as the kick is performed
+ * through a simulated GPIO (a bit in an IPC interrupt-triggering register),
+ * the remote processor is expected to process both its Tx and Rx virtqueues.
+ */
+static void k3_dsp_rproc_kick(struct rproc *rproc, int vqid)
+{
+	struct k3_dsp_rproc *kproc = rproc->priv;
+	struct device *dev = rproc->dev.parent;
+	mbox_msg_t msg = (mbox_msg_t)vqid;
+	int ret;
+
+	/* send the index of the triggered virtqueue in the mailbox payload */
+	ret = mbox_send_message(kproc->mbox, (void *)msg);
+	if (ret < 0)
+		dev_err(dev, "failed to send mailbox message, status = %d\n",
+			ret);
+}
+
+/* Put the DSP processor into reset */
+static int k3_dsp_rproc_reset(struct k3_dsp_rproc *kproc)
+{
+	struct device *dev = kproc->dev;
+	int ret;
+
+#ifdef LOCAL_RESET
+	ret = reset_control_assert(kproc->reset);
+	if (ret) {
+		dev_err(dev, "local-reset assert failed, ret = %d\n", ret);
+		return ret;
+	}
+#endif
+
+	ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci,
+						    kproc->ti_sci_id);
+	if (ret) {
+		dev_err(dev, "module-reset assert failed, ret = %d\n", ret);
+#ifdef LOCAL_RESET
+		if (reset_control_deassert(kproc->reset))
+			dev_warn(dev, "local-reset deassert back failed\n");
+#endif
+	}
+
+	return ret;
+}
+
+/* Release the DSP processor from reset */
+static int k3_dsp_rproc_release(struct k3_dsp_rproc *kproc)
+{
+	struct device *dev = kproc->dev;
+	int ret;
+
+	ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci,
+						   kproc->ti_sci_id);
+	if (ret) {
+		dev_err(dev, "module-reset deassert failed, ret = %d\n", ret);
+		return ret;
+	}
+
+#ifdef LOCAL_RESET
+	ret = reset_control_deassert(kproc->reset);
+	if (ret) {
+		dev_err(dev, "local-reset deassert failed, ret = %d\n", ret);
+		if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci,
+							  kproc->ti_sci_id))
+			dev_warn(dev, "module-reset assert back failed\n");
+	}
+#endif
+
+	return ret;
+}
+
+/*
+ * Power up the DSP remote processor.
+ *
+ * This function will be invoked only after the firmware for this rproc
+ * was loaded, parsed successfully, and all of its resource requirements
+ * were met.
+ */
+static int k3_dsp_rproc_start(struct rproc *rproc)
+{
+	struct k3_dsp_rproc *kproc = rproc->priv;
+	struct mbox_client *client = &kproc->client;
+	struct device *dev = kproc->dev;
+	u32 boot_addr;
+	int ret;
+
+	client->dev = dev;
+	client->tx_done = NULL;
+	client->rx_callback = k3_dsp_rproc_mbox_callback;
+	client->tx_block = false;
+	client->knows_txdone = false;
+
+	kproc->mbox = mbox_request_channel(client, 0);
+	if (IS_ERR(kproc->mbox)) {
+		ret = -EBUSY;
+		dev_err(dev, "mbox_request_channel failed: %ld\n",
+			PTR_ERR(kproc->mbox));
+		return ret;
+	}
+
+	/*
+	 * Ping the remote processor, this is only for sanity-sake for now;
+	 * there is no functional effect whatsoever.
+	 *
+	 * Note that the reply will _not_ arrive immediately: this message
+	 * will wait in the mailbox fifo until the remote processor is booted.
+	 */
+	ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST);
+	if (ret < 0) {
+		dev_err(dev, "mbox_send_message failed: %d\n", ret);
+		goto put_mbox;
+	}
+
+	/*
+	 * no need to issue TI-SCI commands to configure and boot the DSP cores
+	 * in IPC-only mode.
+	 */
+	if (kproc->ipc_only) {
+		dev_err(dev, "DSP initialized in IPC-only mode\n");
+		return 0;
+	}
+
+	boot_addr = rproc->bootaddr;
+	if (boot_addr & (SZ_1K - 1)) {
+		dev_err(dev, "invalid boot address 0x%x, must be aligned on a 1KB boundary\n",
+			boot_addr);
+		ret = -EINVAL;
+		goto put_mbox;
+	}
+
+	dev_err(dev, "booting DSP core using boot addr = 0x%x\n", boot_addr);
+	ret = ti_sci_proc_set_config(kproc->tsp, boot_addr, 0, 0);
+	if (ret)
+		goto put_mbox;
+
+	ret = k3_dsp_rproc_release(kproc);
+	if (ret)
+		goto put_mbox;
+
+	return 0;
+
+put_mbox:
+	mbox_free_channel(kproc->mbox);
+	return ret;
+}
+
+/*
+ * Stop the DSP remote processor.
+ *
+ * This function puts the DSP processor into reset, and finishes processing
+ * of any pending messages.
+ */
+static int k3_dsp_rproc_stop(struct rproc *rproc)
+{
+	struct k3_dsp_rproc *kproc = rproc->priv;
+
+	mbox_free_channel(kproc->mbox);
+
+	/*
+	 * no need to issue TI-SCI commands to stop the DSP core
+	 * in IPC-only mode.
+	 */
+	if (kproc->ipc_only) {
+		dev_err(kproc->dev, "DSP deinitialized in IPC-only mode\n");
+		return 0;
+	}
+
+	k3_dsp_rproc_reset(kproc);
+
+	return 0;
+}
+
+/*
+ * Custom function to translate a DSP device address (internal RAMs only) to a
+ * kernel virtual address.  The DSPs can access their RAMs at either an internal
+ * address visible only from a DSP, or at the SoC-level bus address. Both these
+ * addresses need to be looked through for translation. The translated addresses
+ * can be used either by the remoteproc core for loading (when using kernel
+ * remoteproc loader), or by any rpmsg bus drivers.
+ */
+static void *k3_dsp_rproc_da_to_va(struct rproc *rproc, u64 da, int len,
+				   u32 flags)
+{
+	struct k3_dsp_rproc *kproc = rproc->priv;
+	void __iomem *va = NULL;
+	phys_addr_t bus_addr;
+	u32 dev_addr, offset;
+	size_t size;
+	int i;
+
+	if (len <= 0)
+		return NULL;
+
+	for (i = 0; i < kproc->num_mems; i++) {
+		bus_addr = kproc->mem[i].bus_addr;
+		dev_addr = kproc->mem[i].dev_addr;
+		size = kproc->mem[i].size;
+
+		if (da < KEYSTONE_RPROC_LOCAL_ADDRESS_MASK) {
+			/* handle DSP-view addresses */
+			if (da >= dev_addr &&
+			    ((da + len) <= (dev_addr + size))) {
+				offset = da - dev_addr;
+				va = kproc->mem[i].cpu_addr + offset;
+				return (__force void *)va;
+			}
+		} else {
+			/* handle SoC-view addresses */
+			if (da >= bus_addr &&
+			    (da + len) <= (bus_addr + size)) {
+				offset = da - bus_addr;
+				va = kproc->mem[i].cpu_addr + offset;
+				return (__force void *)va;
+			}
+		}
+	}
+
+	/* handle static DDR reserved memory regions */
+	for (i = 0; i < kproc->num_rmems; i++) {
+		dev_addr = kproc->rmem[i].dev_addr;
+		size = kproc->rmem[i].size;
+
+		if (da >= dev_addr && ((da + len) <= (dev_addr + size))) {
+			offset = da - dev_addr;
+			va = kproc->rmem[i].cpu_addr + offset;
+			return (__force void *)va;
+		}
+	}
+
+	return NULL;
+}
+
+static const struct rproc_ops k3_dsp_rproc_ops = {
+	.start		= k3_dsp_rproc_start,
+	.stop		= k3_dsp_rproc_stop,
+	.kick		= k3_dsp_rproc_kick,
+	.da_to_va	= k3_dsp_rproc_da_to_va,
+};
+
+static const char *k3_dsp_rproc_get_firmware(struct device *dev)
+{
+	const struct k3_dsp_rproc_dev_data *data =
+						of_device_get_match_data(dev);
+
+	if (!data) {
+		dev_err(dev, "data is NULL, %s\n", dev_name(dev));
+		return ERR_PTR(-ENODEV);
+	}
+
+	for (; data && data->device_name; data++) {
+		if (!strcmp(dev_name(dev), data->device_name))
+			return data->fw_name;
+	}
+
+	dev_err(dev, "No matching DSP device found, %s\n", dev_name(dev));
+	return ERR_PTR(-ENODEV);
+}
+
+static int k3_dsp_rproc_of_get_memories(struct platform_device *pdev,
+					struct k3_dsp_rproc *kproc)
+{
+	static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"};
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct resource *res;
+	int num_mems = 0;
+	int i;
+
+	num_mems = ARRAY_SIZE(mem_names);
+	kproc->mem = devm_kcalloc(kproc->dev, num_mems,
+				  sizeof(*kproc->mem), GFP_KERNEL);
+	if (!kproc->mem)
+		return -ENOMEM;
+
+	for (i = 0; i < num_mems; i++) {
+		/* C71x cores only have a L1P Cache, there are no L1P SRAMs */
+		if (of_device_is_compatible(np, "ti,j721e-c71-dsp") &&
+		    !strcmp(mem_names[i], "l1pram"))
+			continue;
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						   mem_names[i]);
+		kproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
+		if (IS_ERR(kproc->mem[i].cpu_addr)) {
+			dev_err(dev, "failed to parse and map %s memory\n",
+				mem_names[i]);
+			return PTR_ERR(kproc->mem[i].cpu_addr);
+		}
+		kproc->mem[i].bus_addr = res->start;
+		kproc->mem[i].dev_addr =
+				res->start & KEYSTONE_RPROC_LOCAL_ADDRESS_MASK;
+		kproc->mem[i].size = resource_size(res);
+
+		dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %pK da 0x%x\n",
+			mem_names[i], &kproc->mem[i].bus_addr,
+			kproc->mem[i].size, kproc->mem[i].cpu_addr,
+			kproc->mem[i].dev_addr);
+
+		/* zero out memories to start in a pristine state */
+		/*
+		 * FIXME: comment out until kernel crash is fixed, possible
+		 * issue with local resets.
+		 * memset((__force void *)kproc->mem[i].cpu_addr, 0,
+		 *      kproc->mem[i].size);
+		 */
+	}
+	kproc->num_mems = num_mems;
+
+	return 0;
+}
+
+static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc)
+{
+	struct device *dev = kproc->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *rmem_np;
+	struct reserved_mem *rmem;
+	int num_rmems;
+	int ret, i;
+
+	num_rmems = of_property_count_elems_of_size(np, "memory-region",
+						    sizeof(phandle));
+	if (num_rmems <= 0) {
+		dev_err(dev, "device does not reserved memory regions, ret = %d\n",
+			num_rmems);
+		return -EINVAL;
+	}
+	if (num_rmems < 2) {
+		dev_err(dev, "device needs atleast two memory regions to be defined, num = %d\n",
+			num_rmems);
+		return -EINVAL;
+	}
+
+	/* use reserved memory region 0 for vring DMA allocations */
+	ret = of_reserved_mem_device_init_by_idx(dev, np, 0);
+	if (ret) {
+		dev_err(dev, "device cannot initialize DMA pool, ret = %d\n",
+			ret);
+		return ret;
+	}
+
+	num_rmems--;
+	kproc->rmem = kcalloc(num_rmems, sizeof(*kproc->rmem), GFP_KERNEL);
+	if (!kproc->rmem) {
+		ret = -ENOMEM;
+		goto release_rmem;
+	}
+
+	/* use remaining reserved memory regions for static carveouts */
+	for (i = 0; i < num_rmems; i++) {
+		rmem_np = of_parse_phandle(np, "memory-region", i + 1);
+		if (!rmem_np) {
+			ret = -EINVAL;
+			goto unmap_rmem;
+		}
+
+		rmem = of_reserved_mem_lookup(rmem_np);
+		if (!rmem) {
+			of_node_put(rmem_np);
+			ret = -EINVAL;
+			goto unmap_rmem;
+		}
+		of_node_put(rmem_np);
+
+		kproc->rmem[i].bus_addr = rmem->base;
+		/* 64-bit address regions currently not supported */
+		kproc->rmem[i].dev_addr = (u32)rmem->base;
+		kproc->rmem[i].size = rmem->size;
+		kproc->rmem[i].cpu_addr = ioremap_wc(rmem->base, rmem->size);
+		if (!kproc->rmem[i].cpu_addr) {
+			dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n",
+				i + 1, &rmem->base, &rmem->size);
+			ret = -ENOMEM;
+			goto unmap_rmem;
+		}
+
+		dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n",
+			i + 1, &kproc->rmem[i].bus_addr,
+			kproc->rmem[i].size, kproc->rmem[i].cpu_addr,
+			kproc->rmem[i].dev_addr);
+	}
+	kproc->num_rmems = num_rmems;
+
+	return 0;
+
+unmap_rmem:
+	for (i--; i >= 0; i--) {
+		if (kproc->rmem[i].cpu_addr)
+			iounmap(kproc->rmem[i].cpu_addr);
+	}
+	kfree(kproc->rmem);
+release_rmem:
+	of_reserved_mem_device_release(kproc->dev);
+	return ret;
+}
+
+static void k3_dsp_reserved_mem_exit(struct k3_dsp_rproc *kproc)
+{
+	int i;
+
+	for (i = 0; i < kproc->num_rmems; i++)
+		iounmap(kproc->rmem[i].cpu_addr);
+	kfree(kproc->rmem);
+
+	of_reserved_mem_device_release(kproc->dev);
+}
+
+static
+struct ti_sci_proc *k3_dsp_rproc_of_get_tsp(struct device *dev,
+					    const struct ti_sci_handle *sci)
+{
+	struct ti_sci_proc *tsp;
+	u32 temp[2];
+	int ret;
+
+	ret = of_property_read_u32_array(dev->of_node, "ti,sci-proc-ids",
+					 temp, 2);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	tsp = kzalloc(sizeof(*tsp), GFP_KERNEL);
+	if (!tsp)
+		return ERR_PTR(-ENOMEM);
+
+	tsp->dev = dev;
+	tsp->sci = sci;
+	tsp->ops = &sci->ops.proc_ops;
+	tsp->proc_id = temp[0];
+	tsp->host_id = temp[1];
+
+	return tsp;
+}
+
+static int k3_dsp_rproc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct k3_dsp_rproc *kproc;
+	struct rproc *rproc;
+	const char *fw_name;
+	bool r_state = false;
+	bool p_state = false;
+	int ret = 0;
+	int ret1;
+
+	fw_name = k3_dsp_rproc_get_firmware(dev);
+	if (IS_ERR(fw_name))
+		return PTR_ERR(fw_name);
+
+	rproc = rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops, fw_name,
+			    sizeof(*kproc));
+	if (!rproc)
+		return -ENOMEM;
+
+	rproc->has_iommu = false;
+	rproc->recovery_disabled = true;
+	kproc = rproc->priv;
+	kproc->rproc = rproc;
+	kproc->dev = dev;
+
+	/* C71x is a 64-bit processor, so customize rproc elf loader ops */
+	if (of_device_is_compatible(np, "ti,j721e-c71-dsp")) {
+		rproc->ops->load = rproc_elf64_load_segments;
+		rproc->ops->sanity_check = rproc_elf64_sanity_check;
+		rproc->ops->parse_fw = rproc_elf64_load_rsc_table;
+		rproc->ops->find_loaded_rsc_table =
+				rproc_elf64_find_loaded_rsc_table;
+		rproc->ops->get_boot_addr = rproc_elf64_get_boot_addr;
+		rproc->ops->load = rproc_elf64_load_segments;
+	}
+
+	kproc->ti_sci = ti_sci_get_by_phandle(np, "ti,sci");
+	if (IS_ERR(kproc->ti_sci)) {
+		ret = PTR_ERR(kproc->ti_sci);
+		if (ret != -EPROBE_DEFER) {
+			dev_err(dev, "failed to get ti-sci handle, ret = %d\n",
+				ret);
+		}
+		kproc->ti_sci = NULL;
+		goto free_rproc;
+	}
+
+	ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id);
+	if (ret) {
+		dev_err(dev, "missing 'ti,sci-dev-id' property\n");
+		goto put_sci;
+	}
+
+	kproc->reset = devm_reset_control_get_exclusive(dev, NULL);
+	if (IS_ERR(kproc->reset)) {
+		ret = PTR_ERR(kproc->reset);
+		dev_err(dev, "failed to get reset, status = %d\n", ret);
+		goto put_sci;
+	}
+
+	kproc->tsp = k3_dsp_rproc_of_get_tsp(dev, kproc->ti_sci);
+	if (IS_ERR(kproc->tsp)) {
+		dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n",
+			ret);
+		ret = PTR_ERR(kproc->tsp);
+		goto put_sci;
+	}
+
+	ret = ti_sci_proc_request(kproc->tsp);
+	if (ret < 0) {
+		dev_err(dev, "ti_sci_proc_request failed, ret = %d\n", ret);
+		goto free_tsp;
+	}
+
+	/* enable clock for accessing DSP internal memories */
+	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable clock, status = %d\n", ret);
+		pm_runtime_put_noidle(dev);
+		goto disable_rpm;
+	}
+
+	ret = k3_dsp_rproc_of_get_memories(pdev, kproc);
+	if (ret)
+		goto disable_clk;
+
+	ret = k3_dsp_reserved_mem_init(kproc);
+	if (ret) {
+		dev_err(dev, "reserved memory init failed, ret = %d\n", ret);
+		goto disable_clk;
+	}
+
+	ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id,
+					       &r_state, &p_state);
+	if (ret) {
+		dev_err(dev, "failed to get initial state, mode cannot be determined, ret = %d\n",
+			ret);
+		goto release_mem;
+	}
+
+	/* configure J721E devices for either remoteproc or IPC-only mode */
+	if (p_state) {
+		dev_err(dev, "configured DSP for IPC-only mode\n");
+		rproc->skip_load = 1;
+		kproc->ipc_only = 1;
+	} else {
+		dev_err(dev, "configured DSP for remoteproc mode\n");
+	}
+
+	ret = rproc_add(rproc);
+	if (ret) {
+		dev_err(dev, "failed to add register device with remoteproc core, status = %d\n",
+			ret);
+		goto release_mem;
+	}
+
+	platform_set_drvdata(pdev, kproc);
+
+	return 0;
+
+release_mem:
+	k3_dsp_reserved_mem_exit(kproc);
+disable_clk:
+	pm_runtime_put_sync(dev);
+disable_rpm:
+	pm_runtime_disable(dev);
+	ret1 = ti_sci_proc_release(kproc->tsp);
+	if (ret1)
+		dev_err(dev, "failed to release proc, ret = %d\n", ret1);
+free_tsp:
+	kfree(kproc->tsp);
+put_sci:
+	ret1 = ti_sci_put_handle(kproc->ti_sci);
+	if (ret1)
+		dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret1);
+free_rproc:
+	rproc_free(rproc);
+	return ret;
+}
+
+static int k3_dsp_rproc_remove(struct platform_device *pdev)
+{
+	struct k3_dsp_rproc *kproc = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	rproc_del(kproc->rproc);
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	ret = ti_sci_proc_release(kproc->tsp);
+	if (ret)
+		dev_err(dev, "failed to release proc, ret = %d\n", ret);
+
+	kfree(kproc->tsp);
+
+	ret = ti_sci_put_handle(kproc->ti_sci);
+	if (ret)
+		dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret);
+
+	k3_dsp_reserved_mem_exit(kproc);
+	rproc_free(kproc->rproc);
+
+	return 0;
+}
+
+static const struct k3_dsp_rproc_dev_data j721e_c66_dsp_dev_data[] = {
+	{
+		.device_name	= "4d80800000.dsp",
+		.fw_name	= "j7-c66_0-fw",
+	},
+	{
+		.device_name	= "4d81800000.dsp",
+		.fw_name	= "j7-c66_1-fw",
+	},
+	{
+		/* sentinel */
+	},
+};
+
+static const struct k3_dsp_rproc_dev_data j721e_c71_dsp_dev_data[] = {
+	{
+		.device_name	= "64800000.dsp",
+		.fw_name	= "j7-c71_0-fw",
+	},
+	{
+		/* sentinel */
+	},
+};
+
+static const struct of_device_id k3_dsp_of_match[] = {
+	{
+		.compatible = "ti,j721e-c66-dsp",
+		.data = j721e_c66_dsp_dev_data,
+	},
+	{
+		.compatible = "ti,j721e-c71-dsp",
+		.data = j721e_c71_dsp_dev_data,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, k3_dsp_of_match);
+
+static struct platform_driver k3_dsp_rproc_driver = {
+	.probe	= k3_dsp_rproc_probe,
+	.remove	= k3_dsp_rproc_remove,
+	.driver	= {
+		.name = "k3-dsp-rproc",
+		.of_match_table = k3_dsp_of_match,
+	},
+};
+
+module_platform_driver(k3_dsp_rproc_driver);
+
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI K3 DSP Remoteproc driver");

+ 172 - 0
drivers/remoteproc/ti_k3_r5_remoteproc.c

@@ -122,6 +122,7 @@ struct k3_r5_core {
  * @core: cached pointer to r5 core structure being used
  * @core: cached pointer to r5 core structure being used
  * @rmem: reserved memory regions data
  * @rmem: reserved memory regions data
  * @num_rmems: number of reserved memory regions
  * @num_rmems: number of reserved memory regions
+ * @ipc_only: flag to indicate IPC-only mode
  */
  */
 struct k3_r5_rproc {
 struct k3_r5_rproc {
 	struct device *dev;
 	struct device *dev;
@@ -132,6 +133,7 @@ struct k3_r5_rproc {
 	struct k3_r5_core *core;
 	struct k3_r5_core *core;
 	struct k3_r5_mem *rmem;
 	struct k3_r5_mem *rmem;
 	int num_rmems;
 	int num_rmems;
+	unsigned int ipc_only : 1;
 };
 };
 
 
 /**
 /**
@@ -373,6 +375,10 @@ static int k3_r5_rproc_prepare(struct rproc *rproc)
 	struct device *dev = kproc->dev;
 	struct device *dev = kproc->dev;
 	int ret;
 	int ret;
 
 
+	/* IPC-only mode does not require the cores to be released from reset */
+	if (kproc->ipc_only)
+		return 0;
+
 	ret = cluster->mode ? k3_r5_lockstep_release(cluster) :
 	ret = cluster->mode ? k3_r5_lockstep_release(cluster) :
 			      k3_r5_split_release(core);
 			      k3_r5_split_release(core);
 	if (ret)
 	if (ret)
@@ -399,6 +405,10 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc)
 	struct device *dev = kproc->dev;
 	struct device *dev = kproc->dev;
 	int ret;
 	int ret;
 
 
+	/* do not put back the cores into reset in IPC-only mode */
+	if (kproc->ipc_only)
+		return 0;
+
 	ret = cluster->mode ? k3_r5_lockstep_reset(cluster) :
 	ret = cluster->mode ? k3_r5_lockstep_reset(cluster) :
 			      k3_r5_split_reset(core);
 			      k3_r5_split_reset(core);
 	if (ret)
 	if (ret)
@@ -456,6 +466,15 @@ static int k3_r5_rproc_start(struct rproc *rproc)
 		goto put_mbox;
 		goto put_mbox;
 	}
 	}
 
 
+	/*
+	 * no need to issue TI-SCI commands to configure and boot the R5F cores
+	 * in IPC-only mode.
+	 */
+	if (kproc->ipc_only) {
+		dev_err(dev, "R5F core initialized in IPC-only mode\n");
+		return 0;
+	}
+
 	boot_addr = rproc->bootaddr;
 	boot_addr = rproc->bootaddr;
 	/* TODO: add boot_addr sanity checking */
 	/* TODO: add boot_addr sanity checking */
 	dev_err(dev, "booting R5F core using boot addr = 0x%x\n", boot_addr);
 	dev_err(dev, "booting R5F core using boot addr = 0x%x\n", boot_addr);
@@ -517,6 +536,16 @@ static int k3_r5_rproc_stop(struct rproc *rproc)
 	struct k3_r5_core *core = kproc->core;
 	struct k3_r5_core *core = kproc->core;
 	int ret;
 	int ret;
 
 
+	/*
+	 * no need to issue TI-SCI commands to stop the R5F cores
+	 * in IPC-only mode.
+	 */
+	if (kproc->ipc_only) {
+		mbox_free_channel(kproc->mbox);
+		dev_err(kproc->dev, "R5F core deinitialized in IPC-only mode\n");
+		return 0;
+	}
+
 	/* halt all applicable cores */
 	/* halt all applicable cores */
 	if (cluster->mode) {
 	if (cluster->mode) {
 		list_for_each_entry(core, &cluster->cores, elem) {
 		list_for_each_entry(core, &cluster->cores, elem) {
@@ -826,6 +855,108 @@ static void k3_r5_reserved_mem_exit(struct k3_r5_rproc *kproc)
 	of_reserved_mem_device_release(kproc->dev);
 	of_reserved_mem_device_release(kproc->dev);
 }
 }
 
 
+/*
+ * This function checks and configures a R5F core for IPC-only or remoteproc
+ * mode. The driver is configured to be in IPC-only mode for a R5F core when
+ * the core has been loaded and started by a bootloader. The IPC-only mode is
+ * detected by querying the System Firmware for reset, power on and halt status
+ * and ensuring that the core is running. Any incomplete steps at bootloader
+ * are validated and errored out.
+ *
+ * In IPC-only mode, the driver state flags for ATCM, BTCM and LOCZRAMA settings
+ * and cluster mode parsed originally from kernel DT are updated to reflect the
+ * actual values configured by bootloader. The driver internal device memory
+ * addresses for TCMs are also updated.
+ *
+ * The R5F cores on AM65x SoCs are currently limited to remoteproc mode only
+ * until the early-boot support is added for the AM65x SoC family.
+ */
+static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
+{
+	struct k3_r5_cluster *cluster = kproc->cluster;
+	struct k3_r5_core *core = kproc->core;
+	struct device *cdev = core->dev;
+	bool r_state = false, c_state = false;
+	u32 ctrl = 0, cfg = 0, stat = 0, halted = 0;
+	u64 boot_vec = 0;
+	u32 atcm_enable, btcm_enable, loczrama;
+	struct k3_r5_core *core0;
+	enum cluster_mode mode;
+	int ret;
+
+	if (!of_device_is_compatible(cdev->of_node, "ti,j721e-r5f"))
+		return 0;
+
+	core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem);
+
+	ret = core->ti_sci->ops.dev_ops.is_on(core->ti_sci, core->ti_sci_id,
+					      &r_state, &c_state);
+	if (ret) {
+		dev_err(cdev, "failed to get initial state, mode cannot be determined, ret = %d\n",
+			ret);
+		return ret;
+	}
+	if (r_state != c_state) {
+		dev_warn(cdev, "R5F core may have been powered on by a different host, programmed state (%d) != actual state (%d)\n",
+			 r_state, c_state);
+	}
+
+	ret = reset_control_status(core->reset);
+	if (ret < 0) {
+		dev_err(cdev, "failed to get initial local reset status, ret = %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl,
+				     &stat);
+	if (ret < 0) {
+		dev_err(cdev, "failed to get initial processor status, ret = %d\n",
+			ret);
+		return ret;
+	}
+	atcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_ATCM_EN ?  1 : 0;
+	btcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_BTCM_EN ?  1 : 0;
+	loczrama = cfg & PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE ?  1 : 0;
+	mode = cfg & PROC_BOOT_CFG_FLAG_R5_LOCKSTEP ?  1 : 0;
+	halted = ctrl & PROC_BOOT_CTRL_FLAG_R5_CORE_HALT;
+
+	/*
+	 * IPC-only mode detection requires both local and module resets to
+	 * be deasserted and R5F core to be unhalted. Local reset status is
+	 * irrelevant if module reset is asserted (POR value has local reset
+	 * deasserted), and is deemed as remoteproc mode
+	 */
+	if (c_state && !ret && !halted) {
+		dev_err(cdev, "configured R5F for IPC-only mode\n");
+		kproc->rproc->skip_load = 1;
+		kproc->ipc_only = 1;
+		ret = 1;
+	} else if (!c_state) {
+		dev_err(cdev, "configured R5F for remoteproc mode\n");
+		ret = 0;
+	} else {
+		dev_err(cdev, "mismatched mode: local_reset = %s, module_reset = %s, core_state = %s\n",
+			!ret ? "deasserted" : "asserted",
+			c_state ? "deasserted" : "asserted",
+			halted ? "halted" : "unhalted");
+		ret = -EINVAL;
+	}
+
+	/* fixup TCMs, cluster & core flags to actual values in IPC-only mode */
+	if (ret > 0) {
+		if (core == core0)
+			cluster->mode = mode;
+		core->atcm_enable = atcm_enable;
+		core->btcm_enable = btcm_enable;
+		core->loczrama = loczrama;
+		core->mem[0].dev_addr = loczrama ? 0 : K3_R5_TCM_DEV_ADDR;
+		core->mem[1].dev_addr = loczrama ? K3_R5_TCM_DEV_ADDR : 0;
+	}
+
+	return ret;
+}
+
 static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
 static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
 {
 {
 	struct k3_r5_cluster *cluster = platform_get_drvdata(pdev);
 	struct k3_r5_cluster *cluster = platform_get_drvdata(pdev);
@@ -865,6 +996,12 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
 		kproc->rproc = rproc;
 		kproc->rproc = rproc;
 		core->rproc = rproc;
 		core->rproc = rproc;
 
 
+		ret = k3_r5_rproc_configure_mode(kproc);
+		if (ret < 0)
+			goto err_config;
+		if (ret)
+			goto init_rmem;
+
 		ret = k3_r5_rproc_configure(kproc);
 		ret = k3_r5_rproc_configure(kproc);
 		if (ret) {
 		if (ret) {
 			dev_err(dev, "initial configure failed, ret = %d\n",
 			dev_err(dev, "initial configure failed, ret = %d\n",
@@ -872,6 +1009,7 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
 			goto err_config;
 			goto err_config;
 		}
 		}
 
 
+init_rmem:
 		ret = k3_r5_reserved_mem_init(kproc);
 		ret = k3_r5_reserved_mem_init(kproc);
 		if (ret) {
 		if (ret) {
 			dev_err(dev, "reserved memory init failed, ret = %d\n",
 			dev_err(dev, "reserved memory init failed, ret = %d\n",
@@ -1423,11 +1561,45 @@ static const struct k3_r5_rproc_dev_data am65x_r5f_dev_data[] = {
 	},
 	},
 };
 };
 
 
+static const struct k3_r5_rproc_dev_data j721e_r5f_dev_data[] = {
+	{
+		.device_name	= "41000000.r5f",
+		.fw_name	= "j7-mcu-r5f0_0-fw",
+	},
+	{
+		.device_name	= "41400000.r5f",
+		.fw_name	= "j7-mcu-r5f0_1-fw",
+	},
+	{
+		.device_name	= "5c00000.r5f",
+		.fw_name	= "j7-main-r5f0_0-fw",
+	},
+	{
+		.device_name	= "5d00000.r5f",
+		.fw_name	= "j7-main-r5f0_1-fw",
+	},
+	{
+		.device_name	= "5e00000.r5f",
+		.fw_name	= "j7-main-r5f1_0-fw",
+	},
+	{
+		.device_name	= "5f00000.r5f",
+		.fw_name	= "j7-main-r5f1_1-fw",
+	},
+	{
+		/* sentinel */
+	},
+};
+
 static const struct of_device_id k3_r5_of_match[] = {
 static const struct of_device_id k3_r5_of_match[] = {
 	{
 	{
 		.compatible     = "ti,am654-r5fss",
 		.compatible     = "ti,am654-r5fss",
 		.data           = am65x_r5f_dev_data,
 		.data           = am65x_r5f_dev_data,
 	},
 	},
+	{
+		.compatible     = "ti,j721e-r5fss",
+		.data           = j721e_r5f_dev_data,
+	},
 	{ /* sentinel */ },
 	{ /* sentinel */ },
 };
 };
 MODULE_DEVICE_TABLE(of, k3_r5_of_match);
 MODULE_DEVICE_TABLE(of, k3_r5_of_match);

+ 33 - 1
include/linux/remoteproc.h

@@ -87,7 +87,13 @@ struct resource_table {
  * this header, and it should be parsed according to the resource type.
  * this header, and it should be parsed according to the resource type.
  */
  */
 struct fw_rsc_hdr {
 struct fw_rsc_hdr {
-	u32 type;
+	union {
+		u32 type;
+		struct {
+			u16 t;
+			u16 v;
+		} st;
+	};
 	u8 data[0];
 	u8 data[0];
 } __packed;
 } __packed;
 
 
@@ -240,6 +246,32 @@ struct fw_rsc_trace {
 	u8 name[32];
 	u8 name[32];
 } __packed;
 } __packed;
 
 
+/**
+ * struct fw_rsc_trace2 - trace buffer declaration supporting 64-bits
+ * @padding: initial padding after type field for aligned 64-bit access
+ * @da: device address (64-bit)
+ * @len: length (in bytes)
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the trace buffer
+ *
+ * This resource entry is an enhanced version of the fw_rsc_trace resourec entry
+ * and the provides equivalent functionality but designed for 64-bit remote
+ * processors.
+ *
+ * @da specifies the device address of the buffer, @len specifies
+ * its size, and @name may contain a human readable name of the trace buffer.
+ *
+ * After booting the remote processor, the trace buffers are exposed to the
+ * user via debugfs entries (called trace0, trace1, etc..).
+ */
+struct fw_rsc_trace2 {
+	u32 padding;
+	u64 da;
+	u32 len;
+	u32 reserved;
+	u8 name[32];
+} __packed;
+
 /**
 /**
  * struct fw_rsc_vdev_vring - vring descriptor entry
  * struct fw_rsc_vdev_vring - vring descriptor entry
  * @da: device address
  * @da: device address

+ 1 - 0
samples/rpmsg/rpmsg_client_sample.c

@@ -87,6 +87,7 @@ static void rpmsg_sample_remove(struct rpmsg_device *rpdev)
 
 
 static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
 static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
 	{ .name	= "rpmsg-client-sample" },
 	{ .name	= "rpmsg-client-sample" },
+	{ .name	= "ti.ipc4.ping-pong" },
 	{ },
 	{ },
 };
 };
 MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
 MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);

+ 5 - 0
ti_config_fragments/v8_ipc.cfg

@@ -16,8 +16,13 @@ CONFIG_TI_PRUSS=m
 CONFIG_REMOTEPROC=m
 CONFIG_REMOTEPROC=m
 CONFIG_PRU_REMOTEPROC=m
 CONFIG_PRU_REMOTEPROC=m
 CONFIG_TI_K3_R5_REMOTEPROC=m
 CONFIG_TI_K3_R5_REMOTEPROC=m
+CONFIG_TI_K3_DSP_REMOTEPROC=m
 
 
 # RPMsg
 # RPMsg
 CONFIG_RPMSG_VIRTIO=m
 CONFIG_RPMSG_VIRTIO=m
 CONFIG_RPMSG_PROTO=m
 CONFIG_RPMSG_PROTO=m
 CONFIG_RPMSG_PRU=m
 CONFIG_RPMSG_PRU=m
+
+# RPMsg Samples
+CONFIG_SAMPLES=y
+CONFIG_SAMPLE_RPMSG_CLIENT=m