PRU-ICSS on TI SoCs
===================

Binding status: Unstable - Subject to changes for undocumented sub-modules

The Programmable Real-Time Unit and Industrial Communication Subsystem
(PRU-ICSS) is present on various TI SoCs such as AM335x, AM437x, Keystone
66AK2G, OMAP-L138/DA850 etc. A PRUSS consists of dual 32-bit RISC cores
(Programmable Real-Time Units, or PRUs), shared RAM, data and instruction
RAMs, some internal peripheral modules to facilitate industrial communication,
and an interrupt controller.

The programmable nature of the PRUs provide flexibility to implement custom
peripheral interfaces, fast real-time responses, or specialized data handling.
The common peripheral modules include the following,
  - an Ethernet MII_RT module with two MII ports
  - an MDIO port to control external Ethernet PHYs
  - an Industrial Ethernet Peripheral (IEP) to manage/generate Industrial
    Ethernet functions
  - an Enhanced Capture Module (eCAP)
  - an Industrial Ethernet Timer with 7/9 capture and 16 compare events
  - a 16550-compatible UART to support PROFIBUS
  - Enhanced GPIO with async capture and serial support

A PRU-ICSS subsystem can have up to three shared data memories. A PRU core
acts on a primary Data RAM (there are usually 2 Data RAMs) at its address
0x0, but also has access to a secondary Data RAM (primary to the other PRU
core) at its address 0x2000. A shared Data RAM, if present, can be accessed
by both the PRU cores. The Interrupt Controller (INTC) and a CFG module are
common to both the PRU cores. Each PRU core also has a private instruction RAM,
and specific register spaces for Control and Debug functionalities.

Various sub-modules within a PRU-ICSS subsystem are represented as individual
nodes and are defined using a parent-child hierarchy depending on their
integration within the IP and the SoC. These nodes are described in the
following sections.


PRU-ICSS Node
==============
Each PRU-ICSS subsystem instance is represented as a node by itself with the
individual PRU processor cores, the memories node, an INTC node, IEP nodes
and an MDIO node represented as child nodes within this PRUSS node. This
node shall be a child of the corresponding interconnect bus nodes or
target-module nodes.

Required Properties:
--------------------
- compatible     : should be one of,
                       "ti,am3356-pruss" for AM335x family of SoCs
                       "ti,am4376-pruss" for AM437x family of SoCs
                       "ti,am5728-pruss" for AM57xx family of SoCs
                       "ti,k2g-pruss" for 66AK2G family of SoCs
                       "ti,am654-icssg" for K3 AM65x family of SoCs
                       "ti,j721e-icssg" for K3 J721E family of SoCs
- reg            : base address and size of the entire PRU-ICSS space
- #address-cells : should be 1
- #size-cells    : should be 1
- ranges         : standard ranges definition using addresses from 0 for child
                   nodes

SoC-specific Required properties:
---------------------------------
The following properties are _required_ only for Keystone 2 66AK2G SoCs,
K3 AM65x SoCs and K3 J721E SoCs only:
- power-domains  : Should contain a phandle to a PM domain provider node and an
                   args specifier containing the PRUSS SCI device id value. This
                   property is as per the binding,
                       Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt

PRU-ICSS Memories Node
=======================
The various Data RAMs within a PRU-ICSS are represented as a single
node with the name 'memories'.

Required Properties:
--------------------
- reg            : base address and size for each of the Data RAMs as
                   mentioned in reg-names, and in the same order as the
                   reg-names
- reg-names      : should contain a string(s) from among the following names,
                   each representing a specific Data RAM region. A PRU-ICSS may
                   not have all of the Data RAMs. The binding is agnostic
                   of the order of these reg-names
                       "dram0" for Data RAM0,
                       "dram1" for Data RAM1,
                       "shrdram2" for Shared Data RAM,


PRU-ICSS CFG, MII_RT Nodes
==========================
The individual sub-modules CFG and MII_RT are represented as a syscon
node each for now with specific node names as below:
                  "cfg" for CFG sub-module,
                  "mii-rt" for MII-RT sub-module,

The following sub-modules are new and present only on ICSSG IP instances and
are applicable only for K3 SoCs. They are represented as follows:
	MII_G_RT sub-module: represent as a syscon node with name "mii-g-rt"

See Documentation/devicetree/bindings/mfd/syscon.txt for generic syscon
binding details.


IEPCLK MUX Clock node
=====================
The IEP module can get its clock from 2 sources i.e. IEP_CLK input to
the PRU-ICSS module or the Bus clock (ICLK). This node models this clock
mux and should have the name "iepclk-mux".

Required Properties:
--------------------
-#clock-cells   : should be 0
-clocks         : phandles to the 2 input clocks to the IEPCLK MUX.

CORECLK MUX Clock node
======================
This is applicable only for ICSSG (K3 SoCs). The ICSSG modules core clock
can be set to one of the 2 sources i.e. CORE_CLK input to the ICSSG module
or VBUS clock. This node models this clock mux and should have the name
"coreclk-mux".

Required Properties:
--------------------
-#clock-cells   : should be 0
-clocks         : phandles to the 2 input clocks to the CORECLK MUX.


PRUSS INTC Node
================
Each PRUSS has a single interrupt controller instance that is common to all
the PRU cores. This should be represented as an interrupt-controller node. The
bindings for this shall be defined in the file,
    Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.txt


PRU Node
=========
Each PRUSS has dual PRU cores, each represented as a remoteproc device through
a PRU child node each. Each node can optionally be rendered inactive by using
the standard DT string property, "status". The ICSSG IP present on K3 SoCs have
additional auxiliary PRU cores with slightly different IP integration. The
bindings for this shall be defined in the file,
    Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt

IEP Node
=========
Each PRUSS has either 1 IEP (on AM335x, AM437x, AM57xx & 66AK2G SoCs) or 2
IEPs (on K3 AM65x & J721E SoCs ). IEP is used for creating PTP clocks and
generating PPS signals. Please refer to the corresponding binding document,
Documentation/devicetree/bindings/net/ti,icss-iep.yaml

MDIO Node
==========
Each PRUSS has an MDIO module that can be used to control external PHYs. The
MDIO module used within the PRU-ICSS is an instance of the MDIO Controller
used in TI Davinci SoCs. Please refer to the corresponding binding document,
Documentation/devicetree/bindings/net/davinci-mdio.txt for details.

eCAP Node
=========
Each PRUSS includes an Enhanced Capture (eCAP) module that can provide some
time-stamp features using its capture input. The eCAP module used within the
PRU-ICSS is similar to other instances used within the PWM subsystems. This
is typically used for providing interrupt pacing for host traffic on various
PRU Ethernet usecases such as Dual-EMAC, HSR or PRP. Please refer to the
corresponding binding document,
Documentation/devicetree/bindings/net/ti,pruss-ecap.yaml

Example:
========
1.	/* AM33xx PRU-ICSS */
	pruss_tm: target-module@300000 {        /* 0x4a300000, ap 9 04.0 */
		compatible = "ti,pruss-sysc", "ti,sysc";
		reg = <0x326000 0x4>,
		      <0x326004 0x4>;
		reg-names = "rev", "sysc";
		ti,sysc-mask = <(SYSC_PRUSS_STANDBY_INIT |
				 SYSC_PRUSS_SUB_MWAIT)>;
		ti,sysc-midle = <SYSC_IDLE_FORCE>,
				<SYSC_IDLE_NO>,
				<SYSC_IDLE_SMART>;
		ti,sysc-sidle = <SYSC_IDLE_FORCE>,
				<SYSC_IDLE_NO>,
				<SYSC_IDLE_SMART>;
		clocks = <&pruss_ocp_clkctrl AM3_PRUSS_OCP_PRUSS_CLKCTRL 0>;
		clock-names = "fck";
		resets = <&prm_per 1>;
		reset-names = "rstctrl";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <0x0 0x300000 0x80000>;

		pruss: pruss@0 {
			compatible = "ti,am3356-pruss";
			reg = <0x0 0x80000>;
			#address-cells = <1>;
			#size-cells = <1>;
			ranges;

			pruss_mem: memories@0 {
				reg = <0x0 0x2000>,
				      <0x2000 0x2000>,
				      <0x10000 0x3000>;
				reg-names = "dram0", "dram1", "shrdram2";
			};

			pruss_cfg: cfg@26000 {
				compatible = "syscon";
				reg = <0x26000 0x2000>;
			};

			pruss_iepclk_mux: iepclk-mux {
				#clock-cells = <0>;
				clocks = <&l3_gclk>,        /* icss_iep_gclk */
					 <&pruss_ocp_gclk>; /* icss_ocp_gclk */
			};

			pruss_iep: iep@2e000 {
				compatible = "ti,am3356-icss-iep";
				reg = <0x2e000 0x31c>;
				clocks = <&pruss_iepclk_mux>;
			};

			pruss_ecap: ecap@30000 {
				compatible = "ti,pruss-ecap";
				reg = <0x30000 0x60>;
			};

			pruss_mii_rt: mii-rt@32000 {
				compatible = "syscon";
				reg = <0x32000 0x58>;
			};

			pruss_intc: interrupt-controller@20000 {
				compatible = "ti,pruss-intc";
				reg = <0x20000 0x2000>;
				interrupts = <20 21 22 23 24 25 26 27>;
				interrupt-names = "host_intr0", "host_intr1",
						  "host_intr2", "host_intr3",
						  "host_intr4", "host_intr5",
						  "host_intr6", "host_intr7",
				interrupt-controller;
				#interrupt-cells = <1>;
				ti,irqs-shared = /bits/ 8 <0 6 7>;
			};

			pru0: pru@34000 {
				compatible = "ti,am3356-pru";
				reg = <0x34000 0x2000>,
				      <0x22000 0x400>,
				      <0x22400 0x100>;
				reg-names = "iram", "control", "debug";
				firmware-name = "am335x-pru0-fw";
			};

			pru1: pru@38000 {
				compatible = "ti,am3356-pru";
				reg = <0x38000 0x2000>,
				      <0x24000 0x400>,
				      <0x24400 0x100>;
				reg-names = "iram", "control", "debug";
				firmware-name = "am335x-pru1-fw";
			};

			pruss_mdio: mdio@32400 {
				compatible = "ti,davinci_mdio";
				reg = <0x32400 0x90>;
				clocks = <&dpll_core_m4_ck>;
				clock-names = "fck";
				bus_freq = <1000000>;
				#address-cells = <1>;
				#size-cells = <0>;
			};
		};
	};

2.	/* AM43xx PRU-ICSS with PRUSS1 node (PRUSS0 not shown completely) */
	pruss_tm: target-module@54400000 {
		compatible = "ti,sysc-pruss", "ti,sysc";
		reg = <0x54426000 0x4>,
		      <0x54426004 0x4>;
		reg-names = "rev", "sysc";
		ti,sysc-mask = <(SYSC_PRUSS_STANDBY_INIT |
				 SYSC_PRUSS_SUB_MWAIT)>;
		ti,sysc-midle = <SYSC_IDLE_FORCE>,
				<SYSC_IDLE_NO>,
				<SYSC_IDLE_SMART>;
		ti,sysc-sidle = <SYSC_IDLE_FORCE>,
				<SYSC_IDLE_NO>,
				<SYSC_IDLE_SMART>;
		clocks = <&pruss_ocp_clkctrl AM4_PRUSS_OCP_PRUSS_CLKCTRL 0>;
		clock-names = "fck";
		resets = <&prm_per 1>;
		reset-names = "rstctrl";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <0x0 0x54400000 0x80000>;

		pruss1: pruss@0 {
			compatible = "ti,am4376-pruss";
			reg = <0x0 0x40000>;
			#address-cells = <1>;
			#size-cells = <1>;
			ranges;

			pruss1_mem: memories@0 {
				reg = <0x0 0x2000>,
				      <0x2000 0x2000>,
				      <0x10000 0x8000>;
				reg-names = "dram0", "dram1", "shrdram2";
			};

			pruss1_cfg: cfg@26000 {
				compatible = "syscon";
				reg = <0x26000 0x2000>;
			};

			pruss1_iepclk_mux: iepclk-mux {
				#clock-cells = <0>;
				clocks = <&sysclk_div>,     /* icss_iep_gclk */
					 <&pruss_ocp_gclk>; /* icss_ocp_gclk */
			};

			pruss1_iep: iep@2e000 {
				compatible = "ti,am3356-icss-iep";
				reg = <0x2e000 0x31c>;
				clocks = <&pruss1_iepclk_mux>;
			};

			pruss1_ecap: ecap@30000 {
				compatible = "ti,pruss-ecap";
				reg = <0x30000 0x60>;
			};

			pruss1_mii_rt: mii-rt@32000 {
				compatible = "syscon";
				reg = <0x32000 0x58>;
			};

			pruss1_intc: interrupt-controller@20000 {
				compatible = "ti,pruss-intc";
				reg = <0x20000 0x2000>;
				interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH
					      GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH
					      GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH
					      GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH
					      GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH
					      GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH
					      GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
				interrupt-names = "host_intr0", "host_intr1",
						  "host_intr2", "host_intr3",
						  "host_intr4",
						  "host_intr6", "host_intr7",
				interrupt-controller;
				#interrupt-cells = <1>;
				ti,irqs-reserved = /bits/ 8 <5>;
			};

			pru1_0: pru@34000 {
				compatible = "ti,am4376-pru";
				reg = <0x34000 0x3000>,
				      <0x22000 0x400>,
				      <0x22400 0x100>;
				reg-names = "iram", "control", "debug";
				firmware-name = "am437x-pru1_0-fw";
			};

			pru1_1: pru@38000 {
				compatible = "ti,am4376-pru";
				reg = <0x38000 0x3000>,
				      <0x24000 0x400>,
				      <0x24400 0x100>;
				reg-names = "iram", "control", "debug";
				firmware-name = "am437x-pru1_1-fw";
			};

			pruss1_mdio: mdio@32400 {
				compatible = "ti,davinci_mdio";
				reg = <0x32400 0x90>;
				clocks = <&dpll_core_m4_ck>;
				clock-names = "fck";
				bus_freq = <1000000>;
				#address-cells = <1>;
				#size-cells = <0>;
				status = "disabled";
			};
		};

		pruss0: pruss@40000 {
			compatible = "ti,am4376-pruss";
			reg = <0x40000 0x40000>;
			...
		};
	};
