linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/14] Add support for TI PRU ICSS
@ 2019-02-04 14:22 Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Roger Quadros
                   ` (13 more replies)
  0 siblings, 14 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

Hi,

The Programmable Real-Time Unit and Industrial Communication Subsystem
(PRU-ICSS) is present on various TI SoCs such as AM335x, AM437x, AM57x,
Keystone 66AK2G, etc. A PRUSS consists of dual 32-bit RISC cores (Programmable
Real-Time Units, or PRUs), with instruction and data memories.

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,
  - Enhanced GPIO with async capture and serial support
  - 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)
  - a 16550-compatible UART to support PROFIBUS
  - Interrupt controller with 64 input events and 10 Host interrupts.

A typical usage scenario would be to load the application firmware into
one or more of the PRU cores, initialize one or more of the peripherals
and perform I/O through shared RAM (or MSMC RAM) from either a Kernel driver
or directly from userspace.

With this series we should be able to use the kernel RPMSG driver along with
firmware and user-space examples in the pru-software-support-package [1].

We will also be able to get Dual Ethernet functionality using a kernel driver
which will be posted later.

This series contains
1) soc: pruss: This is the parent driver for the entire ICSS. Its main
purpose is to populate the different modules and manage memories.
(i.e. DRAM0, DRAM1 and SharedRAM) It will also kernel APIs to
manage the common CFG module.

2) irqchip: pruss-intc: This driver supports the INTC module on the ICSS.

3) remoteproc: pru: This provides a remoteproc interface for the PRU cores.
With this we can load firmware, start/stop PRU from kernel or userspace.
It adds support for virtio RPMSG. It also provides some kernel APIs
(e.g. pru_rproc_set_ctable()) that are PRU specific and required for
in-kernel applications (e.g. ethernet)

4) rpmsg: pru: An RPMsg driver that exposes interfaces to user space, to
allow applications to communicate with the PRU processors.

Platform data and device tree files for AM33xx and other SoCs
will be sent as a separate series.

Testing:
All kernel patches along with AM335x (beaglebone) and AM57xx (IDK) platform
support are at [3]

To test the code with example firmware you can try the LAB5 tutorial
http://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs#LAB_5:_RPMsg_Communication_between_ARM_and_PRU
with the pru-software-support package at [2] and the sample rpmsg-client driver.
NOTE: you no longer need to build and run PRU_Halt example as shown in the tutorial.

[1] https://git.ti.com/pru-software-support-package
	NOTE: The repo needs update to the INTC resource data structures
	The updates that are required are listed in the below repo with one example fixed.
[2] https://github.com/rogerq/pru-software-support-package/commits/upstream/pruss

[3] https://github.com/rogerq/linux/commits/for-v5.1/pruss-2.0

Changelog:
v2:
- use IS_ERR() instead of IS_ERR_OR_NULL().
- sqashed related patches to reduce patch count.
- fixed build error at patch 11 "soc: ti: pruss: add pruss_get()/put() API".
- incorporated rproc_da_to_va patches from David Lechner.
- got rid of enum pruss_pru_id.
- got rid of pre & post loaders in device specific resource handler.
- get/set gpmux operation is now private to pru_rproc.c
- changed pruss_cfg_gpimode() to pru_rproc_set_gpimode(struct rproc *rproc, enum pruss_gpi_mode mode).
- moved pruss_intc.c to driver/irqchip/irq-pruss-intc.c. INTC APIs moved to include/irqchip/irq-pruss-intc.h.
  Decoupled struct pruss from INTC code. Any device who's interrupt-parent is pruss-intc can call the INTC APIs.
- removed device_name from pruss_private_data. use dt property for .has_no_sharedram.
- moved DRAM0, DRAM1 and SHARED_RAM memories into PRUSS node.

cheers,
-roger

Andrew F. Davis (2):
  dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts
  irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts

David Lechner (2):
  remoteproc: add map parameter to da_to_va
  remoteproc: add page lookup for TI PRU to ELF loader

Jason Reeder (1):
  rpmsg: pru: add a PRU RPMsg driver

Roger Quadros (1):
  remoteproc/pru: Add pru_rproc_set_ctable() and pru_rproc_set_gpimode()

Suman Anna (8):
  dt-bindings: remoteproc: Add TI PRUSS bindings
  soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs
  remoteproc: Add a rproc_set_firmware() API
  remoteproc: Add support to handle device specific resource types
  dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS
  remoteproc/pru: Add PRU remoteproc driver
  remoteproc/pru: Add support for virtio rpmsg stack
  rpmsg: virtio_rpmsg_bus: move back rpmsg_hdr into a public header

 .../interrupt-controller/ti,pruss-intc-irq.txt     |   51 +
 .../bindings/remoteproc/ti,pru-rproc.txt           |   56 +
 .../devicetree/bindings/soc/ti/ti,pruss.txt        |  212 ++++
 drivers/irqchip/Makefile                           |    1 +
 drivers/irqchip/irq-pruss-intc.c                   |  630 +++++++++++
 drivers/remoteproc/Kconfig                         |   16 +
 drivers/remoteproc/Makefile                        |    1 +
 drivers/remoteproc/imx_rproc.c                     |    2 +-
 drivers/remoteproc/keystone_remoteproc.c           |    3 +-
 drivers/remoteproc/pru_rproc.c                     | 1141 ++++++++++++++++++++
 drivers/remoteproc/pru_rproc.h                     |   54 +
 drivers/remoteproc/qcom_q6v5_mss.c                 |    2 +-
 drivers/remoteproc/qcom_wcnss.c                    |    2 +-
 drivers/remoteproc/remoteproc_core.c               |  108 +-
 drivers/remoteproc/remoteproc_debugfs.c            |    3 +
 drivers/remoteproc/remoteproc_elf_loader.c         |  117 +-
 drivers/remoteproc/remoteproc_internal.h           |    2 +-
 drivers/remoteproc/remoteproc_sysfs.c              |   33 +-
 drivers/remoteproc/st_slim_rproc.c                 |    2 +-
 drivers/remoteproc/wkup_m3_rproc.c                 |    3 +-
 drivers/rpmsg/Kconfig                              |   14 +
 drivers/rpmsg/Makefile                             |    1 +
 drivers/rpmsg/rpmsg_pru.c                          |  360 ++++++
 drivers/rpmsg/virtio_rpmsg_bus.c                   |   21 +-
 drivers/soc/ti/Kconfig                             |   12 +
 drivers/soc/ti/Makefile                            |    1 +
 drivers/soc/ti/pruss.c                             |  347 ++++++
 include/linux/irqchip/irq-pruss-intc.h             |   94 ++
 include/linux/pruss.h                              |  211 ++++
 include/linux/remoteproc.h                         |   20 +-
 include/linux/remoteproc/pru_rproc.h               |   57 +
 include/linux/rpmsg/virtio_rpmsg.h                 |   26 +
 include/uapi/linux/elf-em.h                        |    1 +
 33 files changed, 3533 insertions(+), 71 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
 create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt
 create mode 100644 Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
 create mode 100644 drivers/irqchip/irq-pruss-intc.c
 create mode 100644 drivers/remoteproc/pru_rproc.c
 create mode 100644 drivers/remoteproc/pru_rproc.h
 create mode 100644 drivers/rpmsg/rpmsg_pru.c
 create mode 100644 drivers/soc/ti/pruss.c
 create mode 100644 include/linux/irqchip/irq-pruss-intc.h
 create mode 100644 include/linux/pruss.h
 create mode 100644 include/linux/remoteproc/pru_rproc.h
 create mode 100644 include/linux/rpmsg/virtio_rpmsg.h

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply	[flat|nested] 61+ messages in thread

* [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 16:33   ` Tony Lindgren
                     ` (2 more replies)
  2019-02-04 14:22 ` [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs Roger Quadros
                   ` (12 subsequent siblings)
  13 siblings, 3 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: Suman Anna <s-anna@ti.com>

This patch adds the bindings for the Programmable Real-Time Unit
and Industrial Communication Subsystem (PRU-ICSS) present on various
SoCs such as AM33xx, AM437x, AM57xx, Keystone 66AK2G SoC, etc. It is
present on the Davinci based OMAPL138 SoCs and K3 architecture
based AM65x SoCs as well (not covered for now).

Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../devicetree/bindings/soc/ti/ti,pruss.txt        | 212 +++++++++++++++++++++
 1 file changed, 212 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/ti/ti,pruss.txt

diff --git a/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
new file mode 100644
index 0000000..5ac76fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
@@ -0,0 +1,212 @@
+PRU-ICSS on TI SoCs
+===================
+
+The Programmable Real-Time Unit and Industrial Communication Subsystem
+(PRU-ICSS) is present on various TI SoCs such as AM335x, AM437x, Keystone
+66AK2G, etc. A PRUSS consists of dual 32-bit RISC cores (Programmable
+Real-Time Units, or PRUs) with program memory and data memory.
+
+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,
+
+  - Enhanced GPIO with async capture and serial support
+  - 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)
+  - a 16550-compatible UART to support PROFIBUS
+  - Interrupt controller with 64 input events and 10 Host interrupts.
+
+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.
+
+Various sub-modules within a PRU-ICSS subsystem are represented as individual
+nodes.
+
+PRUSS Node
+=============
+
+This node represents the entire ICSS instance and the various modules are
+contained as children. The PRUSS driver is responsible for managing the
+common resources i.e. DRAM0, DRAM1, SHARED_RAM and CFG space.
+
+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
+- 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. Some PRU-ICSS
+		   instances on certain SoCs might not have Shared DRAM.
+                       "dram0" for Data RAM0,
+                       "dram1" for Data RAM1,
+                       "shrdram2" for Shared Data RAM,
+- #address-cells : should be 1
+- #size-cells    : should be 1
+- ranges         : no specific range translations required, child nodes have the
+                   same address view as the parent, so should be mentioned without
+                   any value for the property
+
+Optional Properties:
+--------------------
+- no-shared-ram	: Should be present if the instance doesn't have Shared RAM.
+		  e.g. AM4376 ICSS0 instance doesn't have Shared RAM.
+
+The PRUSS node will have one or more of the folowing child nodes.
+
+PRU CORES
+=========
+ICSS typically has 2 PRU cores. These should be represented as remoteproc devices.
+
+INTC node
+=========
+ICSS has one INTC interrupt controller module. This should be represented as
+a standard interrupt-controller node.
+
+CFG, IEP, MII_RT
+================
+The individual sub-modules CFG, IEP and MII_RT are represented as a syscon
+node each with specific node names as below:
+                  "cfg" for CFG sub-module,
+                  "iep" for IEP sub-module,
+                  "mii_rt" for MII-RT sub-module,
+
+See Documentation/devicetree/bindings/mfd/syscon.txt for details.
+
+MDIO
+====
+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.
+
+Application/User Nodes
+=======================
+A PRU application/user node typically uses one or more PRU device nodes to
+implement a PRU application/functionality. Each application/client node would
+need a reference to at least a PRU node, and optionally pass some configuration
+parameters.
+
+Required Properties:
+--------------------
+- prus                 : phandles to the PRU nodes used
+
+Optional Properties:
+--------------------
+- firmware-name        : firmwares for the PRU cores, the default firmware
+                         for the core from the PRU node will be used if not
+                         provided. The firmware names should correspond to
+                         the PRU cores listed in the 'prus' property
+- ti,pruss-gp-mux-sel  : array of values for the GP_MUX_SEL under PRUSS_GPCFG
+                         register for a PRU. This selects the internal muxing
+                         scheme for the PRU instance. If not provided, the
+                         default out-of-reset value (0) for the PRU core is
+                         used. Values should correspond to the PRU cores listed
+                         in the 'prus' property
+- ti,pru-interrupt-map : PRU interrupt mappings, containing an array of entries
+                         with each entry consisting of 4 cell-values. First one
+                         is an index towards the "prus" property to identify the
+                         PRU core for the interrupt map, second is the PRU
+                         System Event id, third is the PRU interrupt channel id
+                         and fourth is the PRU host interrupt id. If provided,
+                         this map will supercede any other configuration
+                         provided through firmware
+
+Example:
+========
+1.	/* AM33xx PRU-ICSS */
+
+	pruss: pruss@0 {
+		compatible = "ti,am3356-pruss";
+		reg = <0x0 0x2000>,
+		      <0x2000 0x2000>,
+		      <0x10000 0x3000>;
+		reg-names = "dram0", "dram1",
+			    "shrdram2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		pruss_cfg: cfg@26000 {
+			compatible = "syscon";
+			reg = <0x26000 0x2000>;
+		};
+
+		pruss_iep: iep@2e000 {
+			compatible = "syscon";
+			reg = <0x2e000 0x31c>;
+		};
+
+		pruss_mii_rt: mii_rt@32000 {
+			compatible = "syscon";
+			reg = <0x32000 0x58>;
+		};
+
+		pruss_intc: intc@20000 {
+			compatible = "ti,am3356-pruss-intc";
+			reg = <0x20000 0x2000>;
+			reg-names = "intc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupts = <20 21 22 23 24 25 26 27>;
+			interrupt-names = "host2", "host3", "host4",
+					  "host5", "host6", "host7",
+					  "host8", "host9";
+		};
+
+		pru0: pru@34000 {
+			compatible = "ti,am3356-pru";
+			reg = <0x34000 0x2000>,
+			      <0x22000 0x400>,
+			      <0x22400 0x100>;
+			reg-names = "iram", "control", "debug";
+			gpcfg = <&pruss_cfg 0x8>;
+			firmware-name = "am335x-pru0-fw";
+			interrupt-parent = <&pruss_intc>;
+			interrupts = <16>, <17>;
+			interrupt-names = "vring", "kick";
+		};
+
+		pru1: pru@38000 {
+			compatible = "ti,am3356-pru";
+			reg = <0x38000 0x2000>,
+			      <0x24000 0x400>,
+			      <0x24400 0x100>;
+			reg-names = "iram", "control", "debug";
+			gpcfg = <&pruss_cfg 0xc>;
+			firmware-name = "am335x-pru1-fw";
+			interrupt-parent = <&pruss_intc>;
+			interrupts = <18>, <19>;
+			interrupt-names = "vring", "kick";
+		};
+
+		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>;
+			status = "disabled";
+		};
+	};
+
+2:	/* PRU application node example */
+	app_node: app_node {
+		prus = <&pru0>, <&pru1>;
+		firmware-name = "pruss-app-fw", "pruss-app-fw-2";
+		ti,pruss-gp-mux-sel = <2>, <1>;
+		/* setup interrupts for prus:
+		   prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
+		   prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
+		ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
+	}
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 14:52   ` Andrew F. Davis
  2019-02-04 14:22 ` [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts Roger Quadros
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq, Keerthy, Andrew F . Davis

From: Suman Anna <s-anna@ti.com>

The Programmable Real-Time Unit - Industrial Communication
Subsystem (PRU-ICSS) is present on various TI SoCs such as
AM335x or AM437x or the Keystone 66AK2G. Each SoC can have
one or more PRUSS instances that may or may not be identical.
For example, AM335x SoCs have a single PRUSS, while AM437x has
two PRUSS instances PRUSS1 and PRUSS0, with the PRUSS0 being
a cut-down version of the PRUSS1.

The PRUSS consists of dual 32-bit RISC cores called the
Programmable Real-Time Units (PRUs), with data and
instruction memories. It also contains various sub-modules
like MDIO, MII_RT, UART, etc. Each sub-module will be driven
by it's own driver.

This PRUSS platform driver deals with the overall PRUSS and is
used for managing the subsystem level resources like various
memories and common CFG module. It is responsible for the
creation and deletion of the platform devices for the child PRU
devices and the various sub-modules.

This design provides flexibility in representing the different
modules of PRUSS accordingly, and at the same time allowing the
PRUSS driver to add some instance specific configuration within
an SoC.

pruss_get() and pruss_put() APIs allow client drivers to request
the 'struct pruss) device handle from the 'struct rproc' handle
for the respective PRU. This handle will be used by client drivers
to request various operations of the PRUSS platform driver through
below APIs.

pruss_request_mem_region() & pruss_release_mem_region() allow
client drivers to acquire and release the common memory resources
present within a PRU-ICSS subsystem. This allows the client drivers
to directly manipulate the respective memories,
as per their design contract with the associated firmware.

pruss_cfg_read() and pruss_cfg_update() allow other drivers to read
and update the registers in the CFG submodule within the PRUSS.
This interface provides a simple way for client drivers
without having them to include and parse these syscon nodes within
their respective device nodes.

pruss_cfg_miirt_enable() and pruss_cfg_xfr_enable() allow the
client drivers to set MII_RT event enable/disable and
XFR (XIN XOUT) enable/disable respectively.

Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/soc/ti/Kconfig  |  12 ++
 drivers/soc/ti/Makefile |   1 +
 drivers/soc/ti/pruss.c  | 347 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pruss.h   | 211 +++++++++++++++++++++++++++++
 4 files changed, 571 insertions(+)
 create mode 100644 drivers/soc/ti/pruss.c
 create mode 100644 include/linux/pruss.h

diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index be4570b..789f2a8 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -73,4 +73,16 @@ config TI_SCI_PM_DOMAINS
 	  called ti_sci_pm_domains. Note this is needed early in boot before
 	  rootfs may be available.
 
+config TI_PRUSS
+	tristate "TI PRU-ICSS Subsystem Platform drivers"
+	depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX
+	select MFD_SYSCON
+	default n
+	help
+	  TI PRU-ICSS Subsystem platform specific support.
+
+	  Say Y or M here to support the Programmable Realtime Unit (PRU)
+	  processors on various TI SoCs. It's safe to say N here if you're
+	  not interested in the PRU or if you are unsure.
+
 endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index a22edc0..55b4b04 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA)	+= knav_dma.o
 obj-$(CONFIG_AMX3_PM)			+= pm33xx.o
 obj-$(CONFIG_WKUP_M3_IPC)		+= wkup_m3_ipc.o
 obj-$(CONFIG_TI_SCI_PM_DOMAINS)		+= ti_sci_pm_domains.o
+obj-$(CONFIG_TI_PRUSS)			+= pruss.o
diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
new file mode 100644
index 0000000..c9493983
--- /dev/null
+++ b/drivers/soc/ti/pruss.c
@@ -0,0 +1,347 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PRU-ICSS platform driver for various TI SoCs
+ *
+ * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
+ *	Suman Anna <s-anna@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pruss.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+
+/**
+ * struct pruss - PRUSS parent structure
+ * @dev: pruss device pointer
+ * @cfg: regmap for config region
+ * @mem_regions: data for each of the PRUSS memory regions
+ * @mem_in_use: to indicate if memory resource is in use
+ * @no_shared_ram: indicate that shared RAM is absent
+ * @lock: mutex to serialize access to resources
+ */
+struct pruss {
+	struct device *dev;
+	struct regmap *cfg;
+	struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
+	struct pruss_mem_region *mem_in_use[PRUSS_MEM_MAX];
+	bool no_shared_ram;
+	struct mutex lock; /* PRU resource lock */
+};
+
+/**
+ * pruss_get() - get the pruss for a given PRU remoteproc
+ * @rproc: remoteproc handle of a PRU instance
+ *
+ * Finds the parent pruss device for a PRU given the @rproc handle of the
+ * PRU remote processor. This function increments the pruss device's refcount,
+ * so always use pruss_put() to decrement it back once pruss isn't needed
+ * anymore.
+ *
+ * Returns the pruss handle on success, and an ERR_PTR on failure using one
+ * of the following error values
+ *    -EINVAL if invalid parameter
+ *    -ENODEV if PRU device or PRUSS device is not found
+ */
+struct pruss *pruss_get(struct rproc *rproc)
+{
+	struct pruss *pruss;
+	struct device *dev;
+	struct platform_device *ppdev;
+
+	if (IS_ERR(rproc))
+		return ERR_PTR(-EINVAL);
+
+	dev = &rproc->dev;
+	if (!dev->parent)
+		return ERR_PTR(-ENODEV);
+
+	/* rudimentary check to make sure rproc handle is for a PRU */
+	if (!strstr(dev_name(dev->parent), "pru"))
+		return ERR_PTR(-ENODEV);
+
+	ppdev = to_platform_device(dev->parent->parent);
+	pruss = platform_get_drvdata(ppdev);
+	if (pruss)
+		get_device(pruss->dev);
+
+	return pruss ? pruss : ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(pruss_get);
+
+/**
+ * pruss_put() - decrement pruss device's usecount
+ * @pruss: pruss handle
+ *
+ * Complimentary function for pruss_get(). Needs to be called
+ * after the PRUSS is used, and only if the pruss_get() succeeds.
+ */
+void pruss_put(struct pruss *pruss)
+{
+	if (IS_ERR(pruss))
+		return;
+
+	put_device(pruss->dev);
+}
+EXPORT_SYMBOL_GPL(pruss_put);
+
+/**
+ * pruss_request_mem_region() - request a memory resource
+ * @pruss: the pruss instance
+ * @mem_id: the memory resource id
+ * @region: pointer to memory region structure to be filled in
+ *
+ * This function allows a client driver to request a memory resource,
+ * and if successful, will let the client driver own the particular
+ * memory region until released using the pruss_release_mem_region()
+ * API.
+ *
+ * Returns the memory region if requested resource is available, an
+ * error otherwise
+ */
+int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id,
+			     struct pruss_mem_region *region)
+{
+	if (IS_ERR(pruss) || !region)
+		return -EINVAL;
+
+	if (mem_id >= PRUSS_MEM_MAX)
+		return -EINVAL;
+
+	mutex_lock(&pruss->lock);
+
+	if (pruss->mem_in_use[mem_id]) {
+		mutex_unlock(&pruss->lock);
+		return -EBUSY;
+	}
+
+	*region = pruss->mem_regions[mem_id];
+	pruss->mem_in_use[mem_id] = region;
+
+	mutex_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_request_mem_region);
+
+/**
+ * pruss_release_mem_region() - release a memory resource
+ * @pruss: the pruss instance
+ * @region: the memory region to release
+ *
+ * This function is the complimentary function to
+ * pruss_request_mem_region(), and allows the client drivers to
+ * release back a memory resource.
+ *
+ * Returns 0 on success, an error code otherwise
+ */
+int pruss_release_mem_region(struct pruss *pruss,
+			     struct pruss_mem_region *region)
+{
+	int id;
+
+	if (IS_ERR(pruss) || !region)
+		return -EINVAL;
+
+	mutex_lock(&pruss->lock);
+
+	/* find out the memory region being released */
+	for (id = 0; id < PRUSS_MEM_MAX; id++) {
+		if (pruss->mem_in_use[id] == region)
+			break;
+	}
+
+	if (id == PRUSS_MEM_MAX) {
+		mutex_unlock(&pruss->lock);
+		return -EINVAL;
+	}
+
+	pruss->mem_in_use[id] = NULL;
+
+	mutex_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_release_mem_region);
+
+/**
+ * pruss_cfg_read() - read a PRUSS CFG register
+ * @pruss: the pruss instance handle
+ * @reg: register offset within the CFG sub-module
+ * @val: pointer to return the value in
+ *
+ * Reads a given register within CFG module of PRUSS
+ * and returns it through the passed-in @val pointer
+ *
+ * Returns 0 on success, or an error code otherwise
+ */
+int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val)
+{
+	if (IS_ERR(pruss))
+		return -EINVAL;
+
+	return regmap_read(pruss->cfg, reg, val);
+}
+EXPORT_SYMBOL_GPL(pruss_cfg_read);
+
+/**
+ * pruss_cfg_update() - update a PRUSS CFG register
+ * @pruss: the pruss instance handle
+ * @reg: register offset within the CFG sub-module
+ * @mask: bit mask to use for programming the @val
+ * @val: value to write
+ *
+ * Updates a given register within CFG sub-module of PRUSS
+ *
+ * Returns 0 on success, or an error code otherwise
+ */
+int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
+		     unsigned int mask, unsigned int val)
+{
+	if (IS_ERR(pruss))
+		return -EINVAL;
+
+	return regmap_update_bits(pruss->cfg, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(pruss_cfg_update);
+
+/**
+ * struct pruss_match_private_data - private data to handle multiple instances
+ * @device_name: device name of the PRUSS instance
+ * @priv_data: PRUSS driver private data for this PRUSS instance
+ */
+struct pruss_match_private_data {
+	const char *device_name;
+	const struct pruss_private_data *priv_data;
+};
+
+static const
+struct pruss_private_data *pruss_get_private_data(struct platform_device *pdev)
+{
+	const struct pruss_match_private_data *data;
+
+	if (!of_device_is_compatible(pdev->dev.of_node, "ti,am4376-pruss"))
+		return NULL;
+
+	data = of_device_get_match_data(&pdev->dev);
+	for (; data && data->device_name; data++) {
+		if (!strcmp(dev_name(&pdev->dev), data->device_name))
+			return data->priv_data;
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+static int pruss_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct device_node *np;
+	struct pruss *pruss;
+	struct resource *res;
+	int ret, i;
+	const struct pruss_private_data *data;
+	const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
+
+	if (!node) {
+		dev_err(dev, "Non-DT platform device not supported\n");
+		return -ENODEV;
+	}
+
+	data = pruss_get_private_data(pdev);
+	if (IS_ERR(data)) {
+		dev_err(dev, "missing private data\n");
+		return -ENODEV;
+	}
+
+	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(dev, "dma_set_coherent_mask: %d\n", ret);
+		return ret;
+	}
+
+	pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
+	if (!pruss)
+		return -ENOMEM;
+
+	pruss->dev = dev;
+	mutex_init(&pruss->lock);
+
+	pruss->no_shared_ram = of_property_read_bool(node, "no-shared-ram");
+
+	np = of_get_child_by_name(node, "cfg");
+	if (!np)
+		return -ENODEV;
+
+	pruss->cfg = syscon_node_to_regmap(np);
+	of_node_put(np);
+	if (IS_ERR(pruss->cfg))
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
+		if (pruss->no_shared_ram && !strcmp(mem_names[i], "shrdram2"))
+			continue;
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						   mem_names[i]);
+		pruss->mem_regions[i].va = devm_ioremap_resource(dev, res);
+		if (!pruss->mem_regions[i].va) {
+			dev_err(dev, "failed to get resource: %s\n",
+				mem_names[i]);
+			return -ENODEV;
+		}
+		pruss->mem_regions[i].pa = res->start;
+		pruss->mem_regions[i].size = resource_size(res);
+
+		dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %p\n",
+			mem_names[i], &pruss->mem_regions[i].pa,
+			pruss->mem_regions[i].size, pruss->mem_regions[i].va);
+	}
+
+	platform_set_drvdata(pdev, pruss);
+
+	dev_info(&pdev->dev, "creating PRU cores and other child platform devices\n");
+	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	if (ret)
+		dev_err(dev, "of_platform_populate failed\n");
+
+	return ret;
+}
+
+static int pruss_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	dev_info(dev, "remove PRU cores and other child platform devices\n");
+	of_platform_depopulate(dev);
+
+	return 0;
+}
+
+static const struct of_device_id pruss_of_match[] = {
+	{ .compatible = "ti,am3356-pruss", },
+	{ .compatible = "ti,am4376-pruss", },
+	{ .compatible = "ti,am5728-pruss", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, pruss_of_match);
+
+static struct platform_driver pruss_driver = {
+	.driver = {
+		.name = "pruss",
+		.of_match_table = pruss_of_match,
+	},
+	.probe  = pruss_probe,
+	.remove = pruss_remove,
+};
+module_platform_driver(pruss_driver);
+
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/pruss.h b/include/linux/pruss.h
new file mode 100644
index 0000000..b236b30
--- /dev/null
+++ b/include/linux/pruss.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * PRU-ICSS Subsystem user interfaces
+ *
+ * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com
+ *	Suman Anna <s-anna@ti.com>
+ *	Tero Kristo <t-kristo@ti.com>
+ */
+
+#ifndef __LINUX_PRUSS_H
+#define __LINUX_PRUSS_H
+
+/*
+ * PRU_ICSS_CFG registers
+ * SYSCFG, ISRP, ISP, IESP, IECP, SCRP applicable on AMxxxx devices only
+ */
+#define PRUSS_CFG_REVID		0x00
+#define PRUSS_CFG_SYSCFG	0x04
+#define PRUSS_CFG_GPCFG(x)	(0x08 + (x) * 4)
+#define PRUSS_CFG_CGR		0x10
+#define PRUSS_CFG_ISRP		0x14
+#define PRUSS_CFG_ISP		0x18
+#define PRUSS_CFG_IESP		0x1C
+#define PRUSS_CFG_IECP		0x20
+#define PRUSS_CFG_SCRP		0x24
+#define PRUSS_CFG_PMAO		0x28
+#define PRUSS_CFG_MII_RT	0x2C
+#define PRUSS_CFG_IEPCLK	0x30
+#define PRUSS_CFG_SPP		0x34
+#define PRUSS_CFG_PIN_MX	0x40
+
+/* PRUSS_GPCFG register bits */
+#define PRUSS_GPCFG_PRU_GPO_SH_SEL		BIT(25)
+
+#define PRUSS_GPCFG_PRU_DIV1_SHIFT		20
+#define PRUSS_GPCFG_PRU_DIV1_MASK		GENMASK(24, 20)
+
+#define PRUSS_GPCFG_PRU_DIV0_SHIFT		15
+#define PRUSS_GPCFG_PRU_DIV0_MASK		GENMASK(15, 19)
+
+#define PRUSS_GPCFG_PRU_GPO_MODE		BIT(14)
+#define PRUSS_GPCFG_PRU_GPO_MODE_DIRECT		0
+#define PRUSS_GPCFG_PRU_GPO_MODE_SERIAL		BIT(14)
+
+#define PRUSS_GPCFG_PRU_GPI_SB			BIT(13)
+
+#define PRUSS_GPCFG_PRU_GPI_DIV1_SHIFT		8
+#define PRUSS_GPCFG_PRU_GPI_DIV1_MASK		GENMASK(12, 8)
+
+#define PRUSS_GPCFG_PRU_GPI_DIV0_SHIFT		3
+#define PRUSS_GPCFG_PRU_GPI_DIV0_MASK		GENMASK(7, 3)
+
+#define PRUSS_GPCFG_PRU_GPI_CLK_MODE_POSITIVE	0
+#define PRUSS_GPCFG_PRU_GPI_CLK_MODE_NEGATIVE	BIT(2)
+#define PRUSS_GPCFG_PRU_GPI_CLK_MODE		BIT(2)
+
+#define PRUSS_GPCFG_PRU_GPI_MODE_MASK		GENMASK(1, 0)
+#define PRUSS_GPCFG_PRU_GPI_MODE_SHIFT		0
+
+#define PRUSS_GPCFG_PRU_MUX_SEL_SHIFT		26
+#define PRUSS_GPCFG_PRU_MUX_SEL_MASK		GENMASK(29, 26)
+
+/* PRUSS_MII_RT register bits */
+#define PRUSS_MII_RT_EVENT_EN			BIT(0)
+
+/* PRUSS_SPP register bits */
+#define PRUSS_SPP_XFER_SHIFT_EN			BIT(1)
+#define PRUSS_SPP_PRU1_PAD_HP_EN		BIT(0)
+
+/**
+ * enum pruss_gp_mux_sel - PRUSS GPI/O Mux modes for the
+ * PRUSS_GPCFG0/1 registers
+ *
+ * NOTE: The below defines are the most common values, but there
+ * are some exceptions like on 66AK2G, where the RESERVED and MII2
+ * values are interchanged. Also, this bit-field does not exist on
+ * AM335x SoCs
+ */
+enum pruss_gp_mux_sel {
+	PRUSS_GP_MUX_SEL_GP = 0,
+	PRUSS_GP_MUX_SEL_ENDAT,
+	PRUSS_GP_MUX_SEL_RESERVED,
+	PRUSS_GP_MUX_SEL_SD,
+	PRUSS_GP_MUX_SEL_MII2,
+	PRUSS_GP_MUX_SEL_MAX,
+};
+
+/**
+ * enum pruss_gpi_mode - PRUSS GPI configuration modes, used
+ *			 to program the PRUSS_GPCFG0/1 registers
+ */
+enum pruss_gpi_mode {
+	PRUSS_GPI_MODE_DIRECT = 0,
+	PRUSS_GPI_MODE_PARALLEL,
+	PRUSS_GPI_MODE_28BIT_SHIFT,
+	PRUSS_GPI_MODE_MII,
+};
+
+/**
+ * enum pruss_mem - PRUSS memory range identifiers
+ */
+enum pruss_mem {
+	PRUSS_MEM_DRAM0 = 0,
+	PRUSS_MEM_DRAM1,
+	PRUSS_MEM_SHRD_RAM2,
+	PRUSS_MEM_MAX,
+};
+
+/**
+ * struct pruss_mem_region - PRUSS memory region structure
+ * @va: kernel virtual address of the PRUSS memory region
+ * @pa: physical (bus) address of the PRUSS memory region
+ * @size: size of the PRUSS memory region
+ */
+struct pruss_mem_region {
+	void __iomem *va;
+	phys_addr_t pa;
+	size_t size;
+};
+
+struct pruss;
+struct rproc;
+
+#if IS_ENABLED(CONFIG_TI_PRUSS)
+
+struct pruss *pruss_get(struct rproc *rproc);
+void pruss_put(struct pruss *pruss);
+
+int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id,
+			     struct pruss_mem_region *region);
+int pruss_release_mem_region(struct pruss *pruss,
+			     struct pruss_mem_region *region);
+
+int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val);
+int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
+		     unsigned int mask, unsigned int val);
+
+/**
+ * pruss_cfg_miirt_enable() - Enable/disable MII RT Events
+ * @pruss: the pruss instance
+ * @enable: enable/disable
+ *
+ * Enable/disable the MII RT Events for the PRUSS.
+ */
+static inline int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable)
+{
+	u32 set = enable ? PRUSS_MII_RT_EVENT_EN : 0;
+
+	return pruss_cfg_update(pruss, PRUSS_CFG_MII_RT,
+				PRUSS_MII_RT_EVENT_EN, set);
+}
+
+/**
+ * pruss_cfg_xfr_enable() - Enable/disable XIN XOUT shift functionality
+ * @pruss: the pruss instance
+ * @enable: enable/disable
+ */
+static inline int pruss_cfg_xfr_enable(struct pruss *pruss, bool enable)
+{
+	u32 set = enable ? PRUSS_SPP_XFER_SHIFT_EN : 0;
+
+	return pruss_cfg_update(pruss, PRUSS_CFG_SPP,
+				PRUSS_SPP_XFER_SHIFT_EN, set);
+}
+#else
+
+static inline struct pruss *pruss_get(struct rproc *rproc)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+
+static inline void pruss_put(struct pruss *pruss) { }
+
+static inline int pruss_request_mem_region(struct pruss *pruss,
+					   enum pruss_mem mem_id,
+					   struct pruss_mem_region *region)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pruss_release_mem_region(struct pruss *pruss,
+					   struct pruss_mem_region *region)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pruss_cfg_read(struct pruss *pruss, unsigned int reg,
+				 unsigned int *val)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
+				   unsigned int mask, unsigned int val)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pruss_cfg_xfr_enable(struct pruss *pruss, bool enable)
+{
+	return -ENOTSUPP;
+}
+
+#endif /* CONFIG_TI_PRUSS */
+
+#endif /* __LINUX_PRUSS_H */
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 16:36   ` Tony Lindgren
                     ` (2 more replies)
  2019-02-04 14:22 ` [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip " Roger Quadros
                   ` (10 subsequent siblings)
  13 siblings, 3 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq, Andrew F. Davis,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Rob Herring

From: "Andrew F. Davis" <afd@ti.com>

The Programmable Real-Time Unit Subsystem (PRUSS) contains an
interrupt controller (INTC) that can handle various system input
events and post interrupts back to the device-level initiators.
The INTC can support upto 64 input events with individual control
configuration and hardware prioritization. These events are mapped
onto 10 interrupt signals through two levels of many-to-one mapping
support. Different interrupt signals are routed to the individual
PRU cores or to the host CPU.

The PRUSS INTC platform driver manages this PRUSS interrupt
controller and implements an irqchip driver to provide a Linux
standard way for the PRU client users to enable/disable/ack/
re-trigger a PRUSS system event. The system events to interrupt
channels and host interrupts relies on the mapping configuration
provided through a firmware resource table for now. This will be
revisited and enhanced in the future for a better interface. The
mappings will currently be programmed during the boot/shutdown
of the PRU.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Rob Herring <robh+dt@kernel.org>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../interrupt-controller/ti,pruss-intc-irq.txt     | 51 ++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
new file mode 100644
index 0000000..c70221c
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
@@ -0,0 +1,51 @@
+PRU ICSS INTC on TI SoCs
+========================
+
+Each PRUSS has a single interrupt controller instance that is common to both
+the PRU cores. Each interrupt controller can detect 64 input events which are
+then mapped to 10 possible output interrupts through two levels of mapping. The
+input events can be triggered by either the PRUs and/or various other PRUSS
+internal and external peripherals. The first 2 output interrupts are fed
+exclusively to the internal PRU cores, with the remaining 8 connected to
+external interrupt controllers including the MPU.
+
+Required Properties:
+--------------------
+- compatible           : should be one of,
+                             "ti,am3356-pruss-intc" for AM335x family of SoCs
+                             "ti,am4376-pruss-intc" for AM437x family of SoCs
+                             "ti,am5728-pruss-intc" for AM57xx family of SoCs
+                             "ti,k2g-pruss-intc" for 66AK2G family of SoCs
+- reg                  : base address and size for the PRUSS INTC sub-module
+- reg-names            : should contain the string "intc"
+- interrupts     : all the interrupts generated towards the main host
+                   processor in the SoC. The format depends on the
+                   interrupt specifier for the particular SoC's MPU
+                   parent interrupt controller
+- interrupt-names: should use one of the following names for each interrupt,
+                   the name should match the corresponding host interrupt
+                   number,
+                       "host2", "host3", "host4", "host5", "host6",
+                       "host7", "host8" or "host9"
+                   NOTE: AM437x and 66AK2G SoCs do not have "host7" interrupt
+                         connected to MPU
+- interrupt-controller : mark this node as an interrupt controller
+- #interrupt-cells     : should be 1. Client users shall use the PRU System
+                         event number (the interrupt source that the client
+                         is interested in) as the value of the interrupts
+                         property in their node
+
+Example:
+--------
+		pruss_intc: intc@20000 {
+			compatible = "ti,am3356-pruss-intc";
+			reg = <0x20000 0x2000>;
+			reg-names = "intc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupts = <20 21 22 23 24 25 26 27>;
+			interrupt-names = "host2", "host3", "host4",
+					  "host5", "host6", "host7",
+					  "host8", "host9";
+		};
+
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (2 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 15:11   ` Andrew F. Davis
  2019-02-04 18:15   ` Tony Lindgren
  2019-02-04 14:22 ` [PATCH v2 05/14] remoteproc: add map parameter to da_to_va Roger Quadros
                   ` (9 subsequent siblings)
  13 siblings, 2 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq, Andrew F. Davis,
	Thomas Gleixner, Jason Cooper, Marc Zyngier

From: "Andrew F. Davis" <afd@ti.com>

The Programmable Real-Time Unit Subsystem (PRUSS) contains an
interrupt controller (INTC) that can handle various system input
events and post interrupts back to the device-level initiators.
The INTC can support upto 64 input events with individual control
configuration and hardware prioritization. These events are mapped
onto 10 interrupt signals through two levels of many-to-one mapping
support. Different interrupt signals are routed to the individual
PRU cores or to the host CPU.

The PRUSS INTC platform driver manages this PRUSS interrupt
controller and implements an irqchip driver to provide a Linux
standard way for the PRU client users to enable/disable/ack/
re-trigger a PRUSS system event. The system events to interrupt
channels and host interrupts relies on the mapping configuration
provided through a firmware resource table for now. This will be
revisited and enhanced in the future for a better interface. The
mappings will currently be programmed during the boot/shutdown
of the PRU.

The PRUSS INTC module is reference counted during the interrupt
setup phase through the irqchip's irq_request_resources() and
irq_release_resources() ops. This restricts the module from being
removed as long as there are active interrupt users.

The PRUSS INTC can generate an interrupt to various processor
subsystems on the SoC through a set of 64 possible PRU system
events. These system events can be used by PRU client drivers
or applications for event notifications/signalling between PRUs
and MPU or other processors. An API, pruss_intc_trigger() is
provided to MPU-side PRU client drivers/applications to be able
to trigger an event/interrupt using IRQ numbers provided by the
PRUSS-INTC irqdomain chip.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/irqchip/Makefile               |   1 +
 drivers/irqchip/irq-pruss-intc.c       | 630 +++++++++++++++++++++++++++++++++
 include/linux/irqchip/irq-pruss-intc.h |  94 +++++
 3 files changed, 725 insertions(+)
 create mode 100644 drivers/irqchip/irq-pruss-intc.c
 create mode 100644 include/linux/irqchip/irq-pruss-intc.h

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index c93713d..e309101 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -94,3 +94,4 @@ obj-$(CONFIG_CSKY_APB_INTC)		+= irq-csky-apb-intc.o
 obj-$(CONFIG_SIFIVE_PLIC)		+= irq-sifive-plic.o
 obj-$(CONFIG_IMX_IRQSTEER)		+= irq-imx-irqsteer.o
 obj-$(CONFIG_MADERA_IRQ)		+= irq-madera.o
+obj-$(CONFIG_TI_PRUSS)			+= irq-pruss-intc.o
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
new file mode 100644
index 0000000..0288535
--- /dev/null
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PRU-ICSS INTC IRQChip driver for various TI SoCs
+ *
+ * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/
+ *	Andrew F. Davis <afd@ti.com>
+ *	Suman Anna <s-anna@ti.com>
+ */
+
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqchip/irq-pruss-intc.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+/*
+ * Number of host interrupts reaching the main MPU sub-system. Note that this
+ * is not the same as the total number of host interrupts supported by the PRUSS
+ * INTC instance
+ */
+#define MAX_HOST_NUM_IRQS	8
+
+/* minimum starting host interrupt number for MPU */
+#define MIN_PRU_HOST_INT	2
+
+/* maximum number of host interrupts */
+#define MAX_PRU_HOST_INT	10
+
+/* PRU_ICSS_INTC registers */
+#define PRU_INTC_REVID		0x0000
+#define PRU_INTC_CR		0x0004
+#define PRU_INTC_GER		0x0010
+#define PRU_INTC_GNLR		0x001C
+#define PRU_INTC_SISR		0x0020
+#define PRU_INTC_SICR		0x0024
+#define PRU_INTC_EISR		0x0028
+#define PRU_INTC_EICR		0x002C
+#define PRU_INTC_HIEISR		0x0034
+#define PRU_INTC_HIDISR		0x0038
+#define PRU_INTC_GPIR		0x0080
+#define PRU_INTC_SRSR0		0x0200
+#define PRU_INTC_SRSR1		0x0204
+#define PRU_INTC_SECR0		0x0280
+#define PRU_INTC_SECR1		0x0284
+#define PRU_INTC_ESR0		0x0300
+#define PRU_INTC_ESR1		0x0304
+#define PRU_INTC_ECR0		0x0380
+#define PRU_INTC_ECR1		0x0384
+#define PRU_INTC_CMR(x)		(0x0400 + (x) * 4)
+#define PRU_INTC_HMR(x)		(0x0800 + (x) * 4)
+#define PRU_INTC_HIPIR(x)	(0x0900 + (x) * 4)
+#define PRU_INTC_SIPR0		0x0D00
+#define PRU_INTC_SIPR1		0x0D04
+#define PRU_INTC_SITR0		0x0D80
+#define PRU_INTC_SITR1		0x0D84
+#define PRU_INTC_HINLR(x)	(0x1100 + (x) * 4)
+#define PRU_INTC_HIER		0x1500
+
+/* HIPIR register bit-fields */
+#define INTC_HIPIR_NONE_HINT	0x80000000
+
+static const char * const irq_names[] = {
+	"host2", "host3", "host4", "host5", "host6", "host7", "host8", "host9",
+};
+
+/**
+ * struct pruss_intc_match_data - match data to handle SoC variations
+ * @no_host7_intr: flag denoting the absence of host7 interrupt into MPU
+ */
+struct pruss_intc_match_data {
+	bool no_host7_intr;
+};
+
+/**
+ * struct pruss_intc - PRUSS interrupt controller structure
+ * @irqs: kernel irq numbers corresponding to PRUSS host interrupts
+ * @mem: base virtual address of INTC register space
+ * @irqchip: irq chip for this interrupt controller
+ * @domain: irq domain for this interrupt controller
+ * @config_map: stored INTC configuration mapping data
+ * @lock: mutex to serialize access to INTCa
+ * @host_mask: indicate which HOST IRQs are enabled
+ */
+struct pruss_intc {
+	unsigned int irqs[MAX_HOST_NUM_IRQS];
+	void __iomem *base;
+	struct irq_chip *irqchip;
+	struct irq_domain *domain;
+	struct pruss_intc_config config_map;
+	struct mutex lock; /* PRUSS INTC lock */
+	u32 host_mask;
+};
+
+static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg)
+{
+	return readl_relaxed(intc->base + reg);
+}
+
+static inline void pruss_intc_write_reg(struct pruss_intc *intc,
+					unsigned int reg, u32 val)
+{
+	writel_relaxed(val, intc->base + reg);
+}
+
+static int pruss_intc_check_write(struct pruss_intc *intc, unsigned int reg,
+				  unsigned int sysevent)
+{
+	if (!intc)
+		return -EINVAL;
+
+	if (sysevent >= MAX_PRU_SYS_EVENTS)
+		return -EINVAL;
+
+	pruss_intc_write_reg(intc, reg, sysevent);
+
+	return 0;
+}
+
+static struct pruss_intc *dev_to_intc(struct device *user_dev)
+{
+	struct device_node *np;
+	struct platform_device *pdev;
+	struct pruss_intc *intc;
+
+	np = of_irq_find_parent(user_dev->of_node);
+	if (!np)
+		return ERR_PTR(-ENODEV);
+
+	pdev = of_find_device_by_node(np);
+	if (!pdev)
+		return ERR_PTR(-EPROBE_DEFER); /* Not probed yet? */
+
+	intc = platform_get_drvdata(pdev);
+	if (!intc)
+		return ERR_PTR(-EINVAL);
+
+	return intc;
+}
+
+/**
+ * pruss_intc_configure() - configure the PRUSS INTC
+ * @dev: device
+ * @intc_config: PRU core-specific INTC configuration
+ *
+ * Configures the PRUSS INTC with the provided configuration from
+ * a PRU core. Any existing event to channel mappings or channel to
+ * host interrupt mappings are checked to make sure there are no
+ * conflicting configuration between both the PRU cores. The function
+ * is intended to be used only by the PRU remoteproc driver.
+ *
+ * Returns 0 on success, or a suitable error code otherwise
+ */
+int pruss_intc_configure(struct device *dev,
+			 struct pruss_intc_config *intc_config)
+{
+	struct pruss_intc *intc;
+	int i, idx, ret;
+	s8 ch, host;
+	u64 sysevt_mask = 0;
+	u32 ch_mask = 0;
+	u32 host_mask = 0;
+	u32 val;
+
+	intc = dev_to_intc(dev);
+	if (IS_ERR(intc))
+		return PTR_ERR(intc);
+
+	mutex_lock(&intc->lock);
+
+	/*
+	 * configure channel map registers - each register holds map info
+	 * for 4 events, with each event occupying the lower nibble in
+	 * a register byte address in little-endian fashion
+	 */
+	for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
+		ch = intc_config->sysev_to_ch[i];
+		if (ch < 0)
+			continue;
+
+		/* check if sysevent already assigned */
+		if (intc->config_map.sysev_to_ch[i] != -1) {
+			dev_err(dev, "event %d (req. channel %d) already assigned to channel %d\n",
+				i, ch, intc->config_map.sysev_to_ch[i]);
+			ret = -EEXIST;
+			goto unlock;
+		}
+
+		intc->config_map.sysev_to_ch[i] = ch;
+
+		idx = i / 4;
+		val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx));
+		val |= ch << ((i & 3) * 8);
+		pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val);
+		sysevt_mask |= BIT_ULL(i);
+		ch_mask |= BIT(ch);
+
+		dev_dbg(dev, "SYSEV%d -> CH%d (CMR%d 0x%08x)\n", i, ch, idx,
+			pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)));
+	}
+
+	/*
+	 * set host map registers - each register holds map info for
+	 * 4 channels, with each channel occupying the lower nibble in
+	 * a register byte address in little-endian fashion
+	 */
+	for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
+		host = intc_config->ch_to_host[i];
+		if (host < 0)
+			continue;
+
+		/* check if channel already assigned */
+		if (intc->config_map.ch_to_host[i] != -1) {
+			dev_err(dev, "channel %d (req. intr_no %d) already assigned to intr_no %d\n",
+				i, host, intc->config_map.ch_to_host[i]);
+			ret = -EEXIST;
+			goto unlock;
+		}
+
+		/* check if host intr is already in use by other PRU */
+		if (intc->host_mask & (1U << host)) {
+			dev_err(dev, "%s: host intr %d already in use\n",
+				__func__, host);
+			ret = -EEXIST;
+			goto unlock;
+		}
+
+		intc->config_map.ch_to_host[i] = host;
+
+		idx = i / 4;
+
+		val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx));
+		val |= host << ((i & 3) * 8);
+		pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val);
+
+		ch_mask |= BIT(i);
+		host_mask |= BIT(host);
+
+		dev_dbg(dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", i, host, idx,
+			pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
+	}
+
+	dev_info(dev, "intc: config: system_events = 0x%016llx intr_channels = 0x%08x host_intr = 0x%08x\n",
+		 sysevt_mask, ch_mask, host_mask);
+
+	/* enable system events, writing 0 has no-effect */
+	pruss_intc_write_reg(intc, PRU_INTC_ESR0, lower_32_bits(sysevt_mask));
+	pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
+	pruss_intc_write_reg(intc, PRU_INTC_ESR1, upper_32_bits(sysevt_mask));
+	pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
+
+	/* enable host interrupts */
+	for (i = 0; i < MAX_PRU_HOST_INT; i++) {
+		if (host_mask & BIT(i))
+			pruss_intc_write_reg(intc, PRU_INTC_HIEISR, i);
+	}
+
+	/* global interrupt enable */
+	pruss_intc_write_reg(intc, PRU_INTC_GER, 1);
+
+	intc->host_mask |= host_mask;
+
+	mutex_unlock(&intc->lock);
+	return 0;
+
+unlock:
+	mutex_unlock(&intc->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pruss_intc_configure);
+
+/**
+ * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
+ * @dev: device
+ * @intc_config: PRU core specific INTC configuration
+ *
+ * Undo whatever was done in pruss_intc_configure() for a PRU core.
+ * It should be sufficient to just mark the resources free in the
+ * global map and disable the host interrupts and sysevents.
+ */
+int pruss_intc_unconfigure(struct device *dev,
+			   struct pruss_intc_config *intc_config)
+{
+	struct pruss_intc *intc;
+	int i;
+	s8 ch, host;
+	u64 sysevt_mask = 0;
+	u32 host_mask = 0;
+
+	intc = dev_to_intc(dev);
+	if (IS_ERR(intc))
+		return PTR_ERR(intc);
+
+	mutex_lock(&intc->lock);
+
+	for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
+		ch = intc_config->sysev_to_ch[i];
+		if (ch < 0)
+			continue;
+
+		/* mark sysevent free in global map */
+		intc->config_map.sysev_to_ch[i] = -1;
+		sysevt_mask |= BIT_ULL(i);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
+		host = intc_config->ch_to_host[i];
+		if (host < 0)
+			continue;
+
+		/* mark channel free in global map */
+		intc->config_map.ch_to_host[i] = -1;
+		host_mask |= BIT(host);
+	}
+
+	dev_info(dev, "intc: unconfig: system_events = 0x%016llx host_intr = 0x%08x\n",
+		 sysevt_mask, host_mask);
+
+	/* disable system events, writing 0 has no-effect */
+	pruss_intc_write_reg(intc, PRU_INTC_ECR0, lower_32_bits(sysevt_mask));
+	pruss_intc_write_reg(intc, PRU_INTC_ECR1, upper_32_bits(sysevt_mask));
+	/* clear any pending status */
+	pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
+	pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
+
+	/* disable host interrupts */
+	for (i = 0; i < MAX_PRU_HOST_INT; i++) {
+		if (host_mask & BIT(i))
+			pruss_intc_write_reg(intc, PRU_INTC_HIDISR, i);
+	}
+
+	intc->host_mask &= ~host_mask;
+	mutex_unlock(&intc->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_intc_unconfigure);
+
+static void pruss_intc_init(struct pruss_intc *intc)
+{
+	int i;
+
+	/* configure polarity to active high for all system interrupts */
+	pruss_intc_write_reg(intc, PRU_INTC_SIPR0, 0xffffffff);
+	pruss_intc_write_reg(intc, PRU_INTC_SIPR1, 0xffffffff);
+
+	/* configure type to pulse interrupt for all system interrupts */
+	pruss_intc_write_reg(intc, PRU_INTC_SITR0, 0);
+	pruss_intc_write_reg(intc, PRU_INTC_SITR1, 0);
+
+	/* clear all 16 interrupt channel map registers */
+	for (i = 0; i < 16; i++)
+		pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0);
+
+	/* clear all 3 host interrupt map registers */
+	for (i = 0; i < 3; i++)
+		pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0);
+}
+
+static void pruss_intc_irq_ack(struct irq_data *data)
+{
+	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+	unsigned int hwirq = data->hwirq;
+
+	pruss_intc_check_write(intc, PRU_INTC_SICR, hwirq);
+}
+
+static void pruss_intc_irq_mask(struct irq_data *data)
+{
+	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+	unsigned int hwirq = data->hwirq;
+
+	pruss_intc_check_write(intc, PRU_INTC_EICR, hwirq);
+}
+
+static void pruss_intc_irq_unmask(struct irq_data *data)
+{
+	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+	unsigned int hwirq = data->hwirq;
+
+	pruss_intc_check_write(intc, PRU_INTC_EISR, hwirq);
+}
+
+static int pruss_intc_irq_retrigger(struct irq_data *data)
+{
+	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+	unsigned int hwirq = data->hwirq;
+
+	return pruss_intc_check_write(intc, PRU_INTC_SISR, hwirq);
+}
+
+static int pruss_intc_irq_reqres(struct irq_data *data)
+{
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
+
+	return 0;
+}
+
+static void pruss_intc_irq_relres(struct irq_data *data)
+{
+	module_put(THIS_MODULE);
+}
+
+/**
+ * pruss_intc_trigger() - trigger a PRU system event
+ * @irq: linux IRQ number associated with a PRU system event
+ *
+ * Trigger an interrupt by signalling a specific PRU system event.
+ * This can be used by PRUSS client users to raise/send an event to
+ * a PRU or any other core that is listening on the host interrupt
+ * mapped to that specific PRU system event. The @irq variable is the
+ * Linux IRQ number associated with a specific PRU system event that
+ * a client user/application uses. The interrupt mappings for this is
+ * provided by the PRUSS INTC irqchip instance.
+ *
+ * Returns 0 on success, or an error value upon failure.
+ */
+int pruss_intc_trigger(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	if (irq <= 0)
+		return -EINVAL;
+
+	desc = irq_to_desc(irq);
+	if (!desc)
+		return -EINVAL;
+
+	pruss_intc_irq_retrigger(&desc->irq_data);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_intc_trigger);
+
+static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
+				     irq_hw_number_t hw)
+{
+	struct pruss_intc *intc = d->host_data;
+
+	irq_set_chip_data(virq, intc);
+	irq_set_chip_and_handler(virq, intc->irqchip, handle_level_irq);
+
+	return 0;
+}
+
+static void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
+{
+	irq_set_chip_and_handler(virq, NULL, NULL);
+	irq_set_chip_data(virq, NULL);
+}
+
+static const struct irq_domain_ops pruss_intc_irq_domain_ops = {
+	.xlate	= irq_domain_xlate_onecell,
+	.map	= pruss_intc_irq_domain_map,
+	.unmap	= pruss_intc_irq_domain_unmap,
+};
+
+static void pruss_intc_irq_handler(struct irq_desc *desc)
+{
+	unsigned int irq = irq_desc_get_irq(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct pruss_intc *intc = irq_get_handler_data(irq);
+	u32 hipir;
+	unsigned int virq;
+	int i, hwirq;
+
+	chained_irq_enter(chip, desc);
+
+	/* find our host irq number */
+	for (i = 0; i < MAX_HOST_NUM_IRQS; i++)
+		if (intc->irqs[i] == irq)
+			break;
+	if (i == MAX_HOST_NUM_IRQS)
+		goto err;
+
+	i += MIN_PRU_HOST_INT;
+
+	/* get highest priority pending PRUSS system event */
+	hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(i));
+	while (!(hipir & BIT(31))) {
+		hwirq = hipir & GENMASK(9, 0);
+		virq = irq_linear_revmap(intc->domain, hwirq);
+
+		/*
+		 * XXX: manually ACK any system events that do not have a
+		 * handler mapped yet
+		 */
+		if (unlikely(!virq))
+			pruss_intc_check_write(intc, PRU_INTC_SICR, hwirq);
+		else
+			generic_handle_irq(virq);
+
+		/* get next system event */
+		hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(i));
+	}
+err:
+	chained_irq_exit(chip, desc);
+}
+
+static int pruss_intc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pruss_intc *intc;
+	struct resource *res;
+	struct irq_chip *irqchip;
+	int i, irq;
+	const struct pruss_intc_match_data *data;
+	bool skip_host7;
+
+	data = of_device_get_match_data(dev);
+	skip_host7 = data ? data->no_host7_intr : false;
+
+	intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
+	if (!intc)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, intc);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intc");
+	intc->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(intc->base)) {
+		dev_err(dev, "failed to parse and map intc memory resource\n");
+		return PTR_ERR(intc->base);
+	}
+
+	mutex_init(&intc->lock);
+
+	for (i = 0; i < ARRAY_SIZE(intc->config_map.sysev_to_ch); i++)
+		intc->config_map.sysev_to_ch[i] = -1;
+
+	for (i = 0; i < ARRAY_SIZE(intc->config_map.ch_to_host); i++)
+		intc->config_map.ch_to_host[i] = -1;
+
+	pruss_intc_init(intc);
+
+	irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL);
+	if (!irqchip)
+		return -ENOMEM;
+
+	irqchip->irq_ack = pruss_intc_irq_ack;
+	irqchip->irq_mask = pruss_intc_irq_mask;
+	irqchip->irq_unmask = pruss_intc_irq_unmask;
+	irqchip->irq_retrigger = pruss_intc_irq_retrigger;
+	irqchip->irq_request_resources = pruss_intc_irq_reqres;
+	irqchip->irq_release_resources = pruss_intc_irq_relres;
+	irqchip->name = dev_name(dev);
+	intc->irqchip = irqchip;
+
+	/* always 64 events */
+	intc->domain = irq_domain_add_linear(dev->of_node, MAX_PRU_SYS_EVENTS,
+					     &pruss_intc_irq_domain_ops, intc);
+	if (!intc->domain)
+		return -ENOMEM;
+
+	for (i = 0; i < MAX_HOST_NUM_IRQS; i++) {
+		irq = platform_get_irq_byname(pdev, irq_names[i]);
+		if (irq < 0) {
+			if (!strcmp(irq_names[i], "host7") && !!skip_host7)
+				continue;
+
+			dev_err(dev->parent, "platform_get_irq_byname failed for %s : %d\n",
+				irq_names[i], irq);
+			goto fail_irq;
+		}
+
+		intc->irqs[i] = irq;
+		irq_set_handler_data(irq, intc);
+		irq_set_chained_handler(irq, pruss_intc_irq_handler);
+	}
+
+	return 0;
+
+fail_irq:
+	irq_domain_remove(intc->domain);
+	return irq;
+}
+
+static int pruss_intc_remove(struct platform_device *pdev)
+{
+	struct pruss_intc *intc = platform_get_drvdata(pdev);
+	unsigned int hwirq;
+
+	if (intc->domain) {
+		for (hwirq = 0; hwirq < MAX_PRU_SYS_EVENTS; hwirq++)
+			irq_dispose_mapping(irq_find_mapping(intc->domain,
+							     hwirq));
+		irq_domain_remove(intc->domain);
+	}
+
+	return 0;
+}
+
+static const struct pruss_intc_match_data am437x_pruss_intc_data = {
+	.no_host7_intr = true,
+};
+
+static const struct of_device_id pruss_intc_of_match[] = {
+	{
+		.compatible = "ti,am3356-pruss-intc",
+		.data = NULL,
+	},
+	{
+		.compatible = "ti,am4376-pruss-intc",
+		.data = &am437x_pruss_intc_data,
+	},
+	{
+		.compatible = "ti,am5728-pruss-intc",
+		.data = NULL,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
+
+static struct platform_driver pruss_intc_driver = {
+	.driver = {
+		.name = "pruss-intc",
+		.of_match_table = pruss_intc_of_match,
+	},
+	.probe  = pruss_intc_probe,
+	.remove = pruss_intc_remove,
+};
+module_platform_driver(pruss_intc_driver);
+
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_DESCRIPTION("PRU-ICSS INTC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h
new file mode 100644
index 0000000..4538a0b
--- /dev/null
+++ b/include/linux/irqchip/irq-pruss-intc.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * irq-pruss-intc.h - PRU-ICSS INTC management
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ */
+
+#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
+#define __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
+
+/* maximum number of system events */
+#define MAX_PRU_SYS_EVENTS	64
+
+/* maximum number of interrupt channels */
+#define MAX_PRU_CHANNELS	10
+
+/**
+ * struct pruss_intc_config - INTC configuration info
+ * @sysev_to_ch: system events to channel mapping information
+ * @ch_to_host: interrupt channel to host interrupt information
+ */
+struct pruss_intc_config {
+	s8 sysev_to_ch[MAX_PRU_SYS_EVENTS];
+	s8 ch_to_host[MAX_PRU_CHANNELS];
+};
+
+#if IS_ENABLED(CONFIG_TI_PRUSS)
+
+/**
+ * pruss_intc_configure() - configure the PRUSS INTC
+ * @dev: device
+ * @intc_config: PRU core-specific INTC configuration
+ *
+ * Configures the PRUSS INTC with the provided configuration from
+ * a PRU core. Any existing event to channel mappings or channel to
+ * host interrupt mappings are checked to make sure there are no
+ * conflicting configuration between both the PRU cores. The function
+ * is intended to be used only by the PRU remoteproc driver.
+ *
+ * Returns 0 on success, or a suitable error code otherwise
+ */
+int pruss_intc_configure(struct device *dev,
+			 struct pruss_intc_config *intc_config);
+
+/**
+ * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
+ * @dev: device
+ * @intc_config: PRU core specific INTC configuration
+ *
+ * Undo whatever was done in pruss_intc_configure() for a PRU core.
+ * It should be sufficient to just mark the resources free in the
+ * global map and disable the host interrupts and sysevents.
+ */
+int pruss_intc_unconfigure(struct device *dev,
+			   struct pruss_intc_config *intc_config);
+/**
+ * pruss_intc_trigger() - trigger a PRU system event
+ * @irq: linux IRQ number associated with a PRU system event
+ *
+ * Trigger an interrupt by signalling a specific PRU system event.
+ * This can be used by PRUSS client users to raise/send an event to
+ * a PRU or any other core that is listening on the host interrupt
+ * mapped to that specific PRU system event. The @irq variable is the
+ * Linux IRQ number associated with a specific PRU system event that
+ * a client user/application uses. The interrupt mappings for this is
+ * provided by the PRUSS INTC irqchip instance.
+ *
+ * Returns 0 on success, or an error value upon failure.
+ */
+int pruss_intc_trigger(unsigned int irq);
+
+#else
+
+static inline int pruss_intc_configure(struct device *dev,
+				       struct pruss_intc_config *intc_config)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pruss_intc_unconfigure(struct device *dev,
+					 struct pruss_intc_config *intc_config)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pruss_intc_trigger(unsigned int irq)
+{
+	return -ENOTSUPP;
+}
+
+#endif	/* CONFIG_TI_PRUSS */
+
+#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H */
+
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 05/14] remoteproc: add map parameter to da_to_va
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (3 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip " Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader Roger Quadros
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: David Lechner <david@lechnology.com>

This adds a new map parameter to the da_to_va callback for remoteproc
devices. This parameter will be used by devices that have more than
one memory map, such as the PRU found in TI Sitara SoCs.

On these devices, the same physical memory address can refer to two
different locations, i.e. instruction memory or data memory both start
at 0x0. So, an extra bit of information is needed in the da_to_va
callback to tell these apart.

Devices that only have a single memory map will just pass 0 for this
parameter. For now we are using 0 everywhere, but later patches will
modify this value.

Signed-off-by: David Lechner <david@lechnology.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/remoteproc/imx_rproc.c             |  2 +-
 drivers/remoteproc/keystone_remoteproc.c   |  3 ++-
 drivers/remoteproc/qcom_q6v5_mss.c         |  2 +-
 drivers/remoteproc/qcom_wcnss.c            |  2 +-
 drivers/remoteproc/remoteproc_core.c       | 11 +++++++----
 drivers/remoteproc/remoteproc_elf_loader.c |  4 ++--
 drivers/remoteproc/remoteproc_internal.h   |  2 +-
 drivers/remoteproc/st_slim_rproc.c         |  2 +-
 drivers/remoteproc/wkup_m3_rproc.c         |  3 ++-
 include/linux/remoteproc.h                 |  2 +-
 10 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 54c07fd..78c3502 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -211,7 +211,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
 	return -ENOENT;
 }
 
-static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len, int map)
 {
 	struct imx_rproc *priv = rproc->priv;
 	void *va = NULL;
diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
index aaac311..0f87cf9 100644
--- a/drivers/remoteproc/keystone_remoteproc.c
+++ b/drivers/remoteproc/keystone_remoteproc.c
@@ -254,7 +254,8 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
  * can be used either by the remoteproc core for loading (when using kernel
  * remoteproc loader), or by any rpmsg bus drivers.
  */
-static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len,
+				     int map)
 {
 	struct keystone_rproc *ksproc = rproc->priv;
 	void __iomem *va = NULL;
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 01be731..d0cdc34 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -971,7 +971,7 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc,
 	int ret = 0;
 	struct q6v5 *qproc = rproc->priv;
 	unsigned long mask = BIT((unsigned long)segment->priv);
-	void *ptr = rproc_da_to_va(rproc, segment->da, segment->size);
+	void *ptr = rproc_da_to_va(rproc, segment->da, segment->size, 0);
 
 	/* Unlock mba before copying segments */
 	if (!qproc->dump_mba_loaded)
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index b0e07e9..92b05fb 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -295,7 +295,7 @@ static int wcnss_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len, int map)
 {
 	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 54ec38f..06ef4fa 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -166,6 +166,8 @@ static phys_addr_t rproc_va_to_pa(void *cpu_addr)
  * @rproc: handle of a remote processor
  * @da: remoteproc device address to translate
  * @len: length of the memory region @da is pointing to
+ * @map: indicates which memory map to use for devices with more than one
+ *       memory map or 0 for devices that only have a single memory map
  *
  * Some remote processors will ask us to allocate them physically contiguous
  * memory regions (which we call "carveouts"), and map them to specific
@@ -190,13 +192,13 @@ static phys_addr_t rproc_va_to_pa(void *cpu_addr)
  * here the output of the DMA API for the carveouts, which should be more
  * correct.
  */
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+void *rproc_da_to_va(struct rproc *rproc, u64 da, int len, int map)
 {
 	struct rproc_mem_entry *carveout;
 	void *ptr = NULL;
 
 	if (rproc->ops->da_to_va) {
-		ptr = rproc->ops->da_to_va(rproc, da, len);
+		ptr = rproc->ops->da_to_va(rproc, da, len, map);
 		if (ptr)
 			goto out;
 	}
@@ -575,7 +577,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
 	}
 
 	/* what's the kernel address of this resource ? */
-	ptr = rproc_da_to_va(rproc, rsc->da, rsc->len);
+	ptr = rproc_da_to_va(rproc, rsc->da, rsc->len, 0);
 	if (!ptr) {
 		dev_err(dev, "erroneous trace resource entry\n");
 		return -EINVAL;
@@ -1549,7 +1551,8 @@ static void rproc_coredump(struct rproc *rproc)
 		if (segment->dump) {
 			segment->dump(rproc, segment, data + offset);
 		} else {
-			ptr = rproc_da_to_va(rproc, segment->da, segment->size);
+			ptr = rproc_da_to_va(rproc, segment->da,
+					     segment->size, 0);
 			if (!ptr) {
 				dev_err(&rproc->dev,
 					"invalid coredump segment (%pad, %zu)\n",
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index b17d72e..8888d39 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -182,7 +182,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 		}
 
 		/* grab the kernel address for this device address */
-		ptr = rproc_da_to_va(rproc, da, memsz);
+		ptr = rproc_da_to_va(rproc, da, memsz, 0);
 		if (!ptr) {
 			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
 			ret = -EINVAL;
@@ -333,6 +333,6 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, 0);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index f6cad24..15e0833 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -51,7 +51,7 @@ void rproc_exit_sysfs(void);
 void rproc_free_vring(struct rproc_vring *rvring);
 int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
 
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
+void *rproc_da_to_va(struct rproc *rproc, u64 da, int len, int map);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
index d711d94..8b843c8 100644
--- a/drivers/remoteproc/st_slim_rproc.c
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -178,7 +178,7 @@ static int slim_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len, int map)
 {
 	struct st_slim_rproc *slim_rproc = rproc->priv;
 	void *va = NULL;
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index 1ada0e5..12cb26e 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -88,7 +88,8 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len,
+				    int map)
 {
 	struct wkup_m3_rproc *wkupm3 = rproc->priv;
 	void *va = NULL;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 507a2b5..e908b58 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -356,7 +356,7 @@ struct rproc_ops {
 	int (*start)(struct rproc *rproc);
 	int (*stop)(struct rproc *rproc);
 	void (*kick)(struct rproc *rproc, int vqid);
-	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
+	void * (*da_to_va)(struct rproc *rproc, u64 da, int len, int map);
 	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
 	struct resource_table *(*find_loaded_rsc_table)(
 				struct rproc *rproc, const struct firmware *fw);
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (4 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 05/14] remoteproc: add map parameter to da_to_va Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 15:19   ` Andrew F. Davis
  2019-02-04 14:22 ` [PATCH v2 07/14] remoteproc: Add a rproc_set_firmware() API Roger Quadros
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: David Lechner <david@lechnology.com>

This adds a special handler to the default remoteproc ELF firmware
loader that looks up the memory map on TI PRU firmware files.

These processors have multiple memory maps that share the same address
space, so we need to know the page in addition to the physical address
in order to translate the address to a local CPU address.

Signed-off-by: David Lechner <david@lechnology.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/remoteproc/remoteproc_elf_loader.c | 117 +++++++++++++++++++++++++++--
 include/uapi/linux/elf-em.h                |   1 +
 2 files changed, 112 insertions(+), 6 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 8888d39..79c9d39 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -32,6 +32,103 @@
 
 #include "remoteproc_internal.h"
 
+#define SHT_TI_PHATTRS 0x7F000004
+#define SHT_TI_SH_PAGE 0x7F000007
+
+struct elf32_ti_phattrs {
+	Elf32_Half pha_seg_id; /* Segment id */
+	Elf32_Half pha_tag_id; /* Attribute kind id */
+	union {
+		Elf32_Off pha_offset; /* byte offset within the section */
+		Elf32_Word pha_value; /* Constant tag value */
+	} pha_un;
+};
+
+/* this struct is reverse engineered, so not sure what most of the values are */
+struct ti_section_page {
+	u32 unk0;
+	u32 unk1;
+	u32 unk2;
+	u32 unk3;
+	u32 unk4;
+	u16 size;
+	u16 unk5;
+	u16 unk6;
+	u8 data[0]; /* array of size */
+};
+
+/**
+ * rproc_elf_segment_to_map() - Gets memory map for segment
+ * @id: segment id
+ * @elf_data: pointer to ELF file data
+ *
+ * Returns the memory map for the segment.
+ */
+static int rproc_elf_segment_to_map(u32 id, const u8 *elf_data)
+{
+	struct elf32_hdr *ehdr;
+	struct elf32_shdr *shdr;
+	struct elf32_ti_phattrs *ti_attrs = NULL;
+	int i;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
+
+	if (ehdr->e_machine != EM_TI_PRU)
+		return 0;
+
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		if (shdr->sh_type == SHT_TI_PHATTRS) {
+			ti_attrs = (struct elf32_ti_phattrs *)(elf_data + shdr->sh_offset);
+			break;
+		}
+	}
+
+	if (!ti_attrs)
+		return 0;
+
+	/* list is terminated by tag id == 0 (PHA_NULL) */
+	for (; ti_attrs->pha_tag_id; ti_attrs++) {
+		if (ti_attrs->pha_tag_id == 3 && ti_attrs->pha_seg_id == id)
+			return ti_attrs->pha_un.pha_value;
+	}
+
+	return 0;
+}
+
+/**
+ * rproc_elf_section_to_map() - Gets memory map for section
+ * @id: segment id
+ * @elf_data: pointer to ELF file data
+ *
+ * Returns the memory map for the section.
+ */
+static int rproc_elf_section_to_map(u32 id, const u8 *elf_data)
+{
+	struct elf32_hdr *ehdr;
+	struct elf32_shdr *shdr;
+	struct ti_section_page *map = NULL;
+	int i;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
+
+	if (ehdr->e_machine != EM_TI_PRU)
+		return 0;
+
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		if (shdr->sh_type == SHT_TI_SH_PAGE) {
+			map = (struct ti_section_page *)(elf_data + shdr->sh_offset);
+			break;
+		}
+	}
+
+	if (!map || id >= map->size)
+		return 0;
+
+	return map->data[id];
+}
+
 /**
  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
  * @rproc: the remote processor handle
@@ -147,7 +244,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 	struct device *dev = &rproc->dev;
 	struct elf32_hdr *ehdr;
 	struct elf32_phdr *phdr;
-	int i, ret = 0;
+	int i, map, ret = 0;
 	const u8 *elf_data = fw->data;
 
 	ehdr = (struct elf32_hdr *)elf_data;
@@ -181,8 +278,10 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 			break;
 		}
 
+		map = rproc_elf_segment_to_map(i, elf_data);
+
 		/* grab the kernel address for this device address */
-		ptr = rproc_da_to_va(rproc, da, memsz, 0);
+		ptr = rproc_da_to_va(rproc, da, memsz, map);
 		if (!ptr) {
 			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
 			ret = -EINVAL;
@@ -209,7 +308,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 EXPORT_SYMBOL(rproc_elf_load_segments);
 
 static struct elf32_shdr *
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
+find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size, int *id)
 {
 	struct elf32_shdr *shdr;
 	int i;
@@ -261,6 +360,9 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
 			return NULL;
 		}
 
+		if (id)
+			*id = i;
+
 		return shdr;
 	}
 
@@ -288,7 +390,7 @@ int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 
 	ehdr = (struct elf32_hdr *)elf_data;
 
-	shdr = find_table(dev, ehdr, fw->size);
+	shdr = find_table(dev, ehdr, fw->size, NULL);
 	if (!shdr)
 		return -EINVAL;
 
@@ -328,11 +430,14 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 {
 	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
 	struct elf32_shdr *shdr;
+	int id, map;
 
-	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	shdr = find_table(&rproc->dev, ehdr, fw->size, &id);
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, 0);
+	map = rproc_elf_section_to_map(id, fw->data);
+
+	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, map);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h
index 0c3000fa..70b487a 100644
--- a/include/uapi/linux/elf-em.h
+++ b/include/uapi/linux/elf-em.h
@@ -38,6 +38,7 @@
 #define EM_BLACKFIN     106     /* ADI Blackfin Processor */
 #define EM_ALTERA_NIOS2	113	/* Altera Nios II soft-core processor */
 #define EM_TI_C6000	140	/* TI C6X DSPs */
+#define EM_TI_PRU	144	/* TI Programmable Realtime Unit */
 #define EM_AARCH64	183	/* ARM 64 bit */
 #define EM_TILEPRO	188	/* Tilera TILEPro */
 #define EM_MICROBLAZE	189	/* Xilinx MicroBlaze */
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 07/14] remoteproc: Add a rproc_set_firmware() API
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (5 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 08/14] remoteproc: Add support to handle device specific resource types Roger Quadros
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: Suman Anna <s-anna@ti.com>

A new API, rproc_set_firmware() is added to allow the remoteproc platform
drivers and remoteproc client drivers to be able to configure a custom
firmware name that is different from the default name used during
remoteproc registration. This function is being introduced to provide
a kernel-level equivalent of the current sysfs interface to remoteproc
client drivers. This allows some remoteproc drivers to choose different
firmwares at runtime when the remote processor is not running based on
the functional feature it is providing using that remote processor.
The TI PRU Ethernet driver will be an example of such usage as it
requires to use different firmwares for different supported protocols.

Also, update the firmware_store() function used by the sysfs interface
to reuse this function to avoid code duplication.

Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/remoteproc/remoteproc_core.c  | 61 +++++++++++++++++++++++++++++++++++
 drivers/remoteproc/remoteproc_sysfs.c | 33 ++-----------------
 include/linux/remoteproc.h            |  1 +
 3 files changed, 64 insertions(+), 31 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 06ef4fa..2d9646f 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -2149,6 +2149,67 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
 }
 EXPORT_SYMBOL(rproc_report_crash);
 
+/**
+ * rproc_set_firmware() - assign a new firmware
+ * @rproc: rproc handle to which the new firmware is being assigned
+ * @fw_name: new firmware name to be assigned
+ *
+ * This function allows remoteproc drivers or clients to configure a custom
+ * firmware name that is different from the default name used during remoteproc
+ * registration. The function does not trigger a remote processor boot,
+ * only sets the firmware name used for a subsequent boot. This function
+ * should also be called only when the remote processor is offline.
+ *
+ * This allows either the userspace to configure a different name through
+ * sysfs or a kernel-level remoteproc or a remoteproc client driver to set
+ * a specific firmware when it is controlling the boot and shutdown of the
+ * remote processor.
+ *
+ * Returns 0 on success or a negative value upon failure
+ */
+int rproc_set_firmware(struct rproc *rproc, const char *fw_name)
+{
+	struct device *dev = rproc->dev.parent;
+	int ret, len;
+	char *p;
+
+	if (!rproc || !fw_name)
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&rproc->lock);
+	if (ret) {
+		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
+		return -EINVAL;
+	}
+
+	if (rproc->state != RPROC_OFFLINE) {
+		dev_err(dev, "can't change firmware while running\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	len = strcspn(fw_name, "\n");
+	if (!len) {
+		dev_err(dev, "empty firmware name string\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	p = kstrndup(fw_name, len, GFP_KERNEL);
+	if (!p) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	kfree(rproc->firmware);
+	rproc->firmware = p;
+
+out:
+	mutex_unlock(&rproc->lock);
+	return ret;
+}
+EXPORT_SYMBOL(rproc_set_firmware);
+
 static int __init remoteproc_init(void)
 {
 	rproc_init_sysfs();
diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c
index 3a4c3d7..6cf04a7 100644
--- a/drivers/remoteproc/remoteproc_sysfs.c
+++ b/drivers/remoteproc/remoteproc_sysfs.c
@@ -32,38 +32,9 @@ static ssize_t firmware_store(struct device *dev,
 			      const char *buf, size_t count)
 {
 	struct rproc *rproc = to_rproc(dev);
-	char *p;
-	int err, len = count;
+	int err;
 
-	err = mutex_lock_interruptible(&rproc->lock);
-	if (err) {
-		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err);
-		return -EINVAL;
-	}
-
-	if (rproc->state != RPROC_OFFLINE) {
-		dev_err(dev, "can't change firmware while running\n");
-		err = -EBUSY;
-		goto out;
-	}
-
-	len = strcspn(buf, "\n");
-	if (!len) {
-		dev_err(dev, "can't provide a NULL firmware\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-	p = kstrndup(buf, len, GFP_KERNEL);
-	if (!p) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	kfree(rproc->firmware);
-	rproc->firmware = p;
-out:
-	mutex_unlock(&rproc->lock);
+	err = rproc_set_firmware(rproc, buf);
 
 	return err ? err : count;
 }
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index e908b58..b5aa5fb 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -590,6 +590,7 @@ rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
 
 int rproc_boot(struct rproc *rproc);
 void rproc_shutdown(struct rproc *rproc);
+int rproc_set_firmware(struct rproc *rproc, const char *fw_name);
 void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
 int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size);
 int rproc_coredump_add_custom_segment(struct rproc *rproc,
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 08/14] remoteproc: Add support to handle device specific resource types
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (6 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 07/14] remoteproc: Add a rproc_set_firmware() API Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 09/14] dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS Roger Quadros
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: Suman Anna <s-anna@ti.com>

The remoteproc framework handles a fixed set of resource table entries
today. To make it scalable across multiple platforms, it makes sense
for the framework to provide a way for the device specific implementation
to define and handle vendor specific resource types. These resource types
would be very specific to an implementation instance that it does not
make sense for the framework to handle it.

For instance, a remoteproc implementation might want timers information
embedded in the resource table so that the driver could parse the binary
and enable accordingly. Another example would be hwspinlocks that it
is using, to properly share system wide resources. The PRU interrupt
controller's interrupt-map could be provided via a vendor specific
resource.

This patch adds a function pointer to the list of rproc_ops for the
driver implementation to handle such custom vendor resources.

[rogerq@ti.com] Get rid of pre/post loaders. Show in debugfs.
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/remoteproc/remoteproc_core.c    | 36 +++++++++++++++++++++++++++++++++
 drivers/remoteproc/remoteproc_debugfs.c |  3 +++
 include/linux/remoteproc.h              | 17 ++++++++++++++--
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 2d9646f..b43aa40 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -896,6 +896,41 @@ void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem)
 EXPORT_SYMBOL(rproc_add_carveout);
 
 /**
+ * rproc_handle_vendor_rsc() - provide implementation specific hook
+ *			       to handle vendor/custom resources
+ * @rproc: the remote processor
+ * @rsc: vendor resource to be handled by remoteproc drivers
+ * @offset: offset of the resource data in resource table
+ * @avail: size of available data
+ *
+ * Remoteproc implementations might want to add resource table entries
+ * that are not generic enough to be handled by the framework. This
+ * provides a hook to handle such custom resources.
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_vendor_rsc(struct rproc *rproc,
+				   struct fw_rsc_vendor *rsc,
+				   int offset, int avail)
+{
+	struct device *dev = &rproc->dev;
+
+	if (sizeof(*rsc) > avail) {
+		dev_err(dev, "vendor rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "vendor rsc:");
+
+	if (!rproc->ops->handle_vendor_rsc) {
+		dev_err(dev, "no vendor rsc handler! ignoring resource\n");
+		return 0;
+	}
+
+	return rproc->ops->handle_vendor_rsc(rproc, (void *)rsc);
+}
+
+/**
  * rproc_mem_entry_init() - allocate and initialize rproc_mem_entry struct
  * @dev: pointer on device struct
  * @va: virtual address
@@ -983,6 +1018,7 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
 	[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
 	[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
 	[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
+	[RSC_VENDOR] = (rproc_handle_resource_t)rproc_handle_vendor_rsc,
 	[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
 };
 
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index e90135c..ef66165 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -230,6 +230,9 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
 					   v->vring[j].pa);
 			}
 			break;
+		case RSC_VENDOR:
+			seq_printf(seq, "Entry %d is of type %s [Vendor specific]\n",
+				   i, types[hdr->type]);
 		default:
 			seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
 				   hdr->type, hdr);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index b5aa5fb..9f4c457 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -100,6 +100,7 @@ struct fw_rsc_hdr {
  *		    the remote processor will be writing logs.
  * @RSC_VDEV:       declare support for a virtio device, and serve as its
  *		    virtio header.
+ * @RSC_VENDOR:	    vendor specific resource type.
  * @RSC_LAST:       just keep this one at the end
  *
  * For more details regarding a specific resource type, please see its
@@ -115,7 +116,8 @@ enum fw_resource_type {
 	RSC_DEVMEM	= 1,
 	RSC_TRACE	= 2,
 	RSC_VDEV	= 3,
-	RSC_LAST	= 4,
+	RSC_VENDOR	= 4,
+	RSC_LAST,
 };
 
 #define FW_RSC_ADDR_ANY (-1)
@@ -308,6 +310,14 @@ struct fw_rsc_vdev {
 struct rproc;
 
 /**
+ * struct fw_rsc_vendor - vendor specific resource definition
+ * @data: resource data. vendor defined.
+ */
+struct fw_rsc_vendor {
+	u8 data[0];
+} __packed;
+
+/**
  * struct rproc_mem_entry - memory entry descriptor
  * @va:	virtual address
  * @dma: dma address
@@ -347,7 +357,8 @@ struct firmware;
  * @da_to_va:	optional platform hook to perform address translations
  * @load_rsc_table:	load resource table from firmware image
  * @find_loaded_rsc_table: find the loaded resouce table
- * @load:		load firmeware to memory, where the remote processor
+ * @handle_vendor_rsc:	hook to handle device specific resource table entries
+ * @load:		load firmware to memory, where the remote processor
  *			expects to find it
  * @sanity_check:	sanity check the fw image
  * @get_boot_addr:	get boot address to entry point specified in firmware
@@ -360,6 +371,8 @@ struct rproc_ops {
 	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
 	struct resource_table *(*find_loaded_rsc_table)(
 				struct rproc *rproc, const struct firmware *fw);
+	int (*handle_vendor_rsc)(struct rproc *rproc,
+				 struct fw_rsc_vendor *rsc);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
 	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 09/14] dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (7 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 08/14] remoteproc: Add support to handle device specific resource types Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-18 19:36   ` Rob Herring
  2019-02-04 14:22 ` [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver Roger Quadros
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq, Rob Herring

From: Suman Anna <s-anna@ti.com>

The Programmable Real-Time Unit Subsystem (PRUSS) consists of
dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs)
for program execution. This patch adds a remoteproc platform
driver for managing the individual PRU RISC cores life cycle.

Add DT binding documentation for that.

Cc: Rob Herring <robh+dt@kernel.org>
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../bindings/remoteproc/ti,pru-rproc.txt           | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt

diff --git a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt
new file mode 100644
index 0000000..02dfd0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt
@@ -0,0 +1,56 @@
+PRU Core on TI SoCs
+===================
+
+Each PRUSS has dual PRU cores, each represented by a PRU child node. Each node
+can optionally be rendered inactive by using the standard DT string property,
+"status".
+
+Required Properties:
+--------------------
+- compatible     : should be
+                       "ti,am3356-pru" for AM335x family of SoCs
+                       "ti,am4376-pru" for AM437x family of SoCs
+                       "ti,am5728-pru" for AM57xx family of SoCs
+                       "ti,k2g-pru" for 66AK2G family of SoCs
+- reg            : base address and size for each of the 3 sub-module address
+                   spaces as mentioned in reg-names, and in the same order as
+                   the reg-names
+- reg-names      : should contain each of the following 3 names, the binding is
+                   agnostic of the order of these reg-names
+                       "iram" for Instruction RAM,
+                       "control" for the CTRL sub-module registers,
+                       "debug" for the Debug sub-module registers,
+
+- firmware-name  : should contain the name of the firmware image file
+		   located on the firmware search path. This firmware will be
+		   used as default if the Application node or User (via sysfs)
+		   doesn't provide a firmware-name.
+
+- gpcfg		 : pHandle to CFG module's syscon regmap and offset to PRU's
+		   GPCFG register.
+
+Optional Properties:
+--------------------
+The virtio based communication between the MPU and a PRU core _requires_
+either the 'mboxes' property, or the set of 'interrupt-parent', 'interrupts'
+and 'interrupt-names' properties to be defined. The latter option is the
+preferred choice. The 'mboxes' property is not applicable for 66AK2G and
+DA850/OMAP-L138 SoCs.
+
+- mboxes           : OMAP Mailbox specifier denoting the sub-mailbox, if using
+                     a mailbox for IPC signalling between host and a PRU core.
+                     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 corresponding firmware image.
+- interrupt-parent : phandle to the PRUSS INTC node. Should be defined if
+                     interrupts property is to be used.
+- interrupts       : array of interrupt specifiers if using PRU system events
+                     for IPC signalling between host and a PRU core. This
+                     property should match with the PRU system event used in
+                     the corresponding firmware image.
+- interrupt-names  : should use one of the following names for each interrupt,
+                     the name should match the corresponding PRU system event
+                     number,
+                         "vring" - for PRU to HOST virtqueue signalling
+                         "kick"  - for HOST to PRU virtqueue signalling
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (8 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 09/14] dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-14  2:35   ` Suman Anna
  2019-02-04 14:22 ` [PATCH v2 11/14] remoteproc/pru: Add pru_rproc_set_ctable() and pru_rproc_set_gpimode() Roger Quadros
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq, Andrew F . Davis

From: Suman Anna <s-anna@ti.com>

The Programmable Real-Time Unit Subsystem (PRUSS) consists of
dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs)
for program execution. This patch adds a remoteproc platform
driver for managing the individual PRU RISC cores life cycle.

This remoteproc driver does not have support for error recovery
and system suspend/resume features. Different compatibles are
used to allow providing scalability for instance-specific device
data if needed. The driver uses a default firmware-name retrieved
from device-tree, and the firmwares are expected to be present
in the standard Linux firmware search paths. They can also be
adjusted by userspace if required through the sysfs interface
provided by the remoteproc core.

The PRU remoteproc driver uses a client-driven boot methodology
- it does _not_ support auto-boot so that the PRU load and boot
is dictated by the corresponding client drivers for achieving
various usecases. This allows flexibility for the client drivers
or applications to set a firmware name (if needed) based on their
desired functionality and boot the PRU. The sysfs bind and unbind
attributes have also been suppressed so that the PRU devices cannot
be unbound and thereby shutdown a PRU from underneath a PRU client
driver.

A new entry 'single_step' is added to the remoteproc debugfs dir.
The 'single_step' utilizes the single-step execution of the PRU
cores. Writing a non-zero value performs a single step, and a
zero value restores the PRU to execute in the same mode as the
mode before the first single step. (note: if the PRU is halted
because of a halt instruction, then no change occurs).

pru_rproc_get() and pru_rproc_put() functions allow client drivers
to acquire and release the remoteproc device associated with a PRU core.
The PRU cores are treated as resources with only one client owning
it at a time.

PRU interrupt mapping can be provided via devicetree using
ti,pru-interrupt-map property or via the resource table in the
firmware blob. If both are provided, the config in DT takes precedence.
For interrupt map via resource table, pru-software-support-package [1]
has been historically using version 0 for this. However, the current
data structure is not scaleable and is not self sufficient.
1) it hard codes number of channel to host mappings so is not
scaleable to newer SoCs than have more of these.
2) it does not contain the event to channel mappings within
itself but relies on a pointer to point to another section
in data memory. This causes a weird complication that the
respective data section must be loaded before we can really
use the INTC map.

With this patch we drop support for version 0 and support
version 1 which is a more robust and scalable data structure.
It should be able to support a sufficiently large number (255) of
sysevents, channels and host interrupts and is self contained
so it can be used without dependency on order of loading sections.

[1]  git://git.ti.com/pru-software-support-package/pru-software-support-package.git

Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/remoteproc/Kconfig           |  14 +
 drivers/remoteproc/Makefile          |   1 +
 drivers/remoteproc/pru_rproc.c       | 930 +++++++++++++++++++++++++++++++++++
 drivers/remoteproc/pru_rproc.h       |  54 ++
 include/linux/remoteproc/pru_rproc.h |  27 +
 5 files changed, 1026 insertions(+)
 create mode 100644 drivers/remoteproc/pru_rproc.c
 create mode 100644 drivers/remoteproc/pru_rproc.h
 create mode 100644 include/linux/remoteproc/pru_rproc.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f0abd26..333666e 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -197,6 +197,20 @@ config ST_REMOTEPROC
 config ST_SLIM_REMOTEPROC
 	tristate
 
+config PRUSS_REMOTEPROC
+	tristate "TI PRUSS remoteproc support"
+	depends on TI_PRUSS
+	default n
+	help
+	  Support for TI PRU-ICSS remote processors via the remote processor
+	  framework.
+
+	  Currently supported on AM33xx SoCs.
+
+	  Say Y or M here to support the Programmable Realtime Unit (PRU)
+	  processors on various TI SoCs. It's safe to say N here if you're
+	  not interested in the PRU or if you are unsure.
+
 endif # REMOTEPROC
 
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index ce5d061..88a86cc 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -26,3 +26,4 @@ qcom_wcnss_pil-y			+= qcom_wcnss.o
 qcom_wcnss_pil-y			+= qcom_wcnss_iris.o
 obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
 obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
+obj-$(CONFIG_PRUSS_REMOTEPROC)		+= pru_rproc.o
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
new file mode 100644
index 0000000..ddd4b64
--- /dev/null
+++ b/drivers/remoteproc/pru_rproc.c
@@ -0,0 +1,930 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PRU-ICSS remoteproc driver for various TI SoCs
+ *
+ * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
+ *	Suman Anna <s-anna@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip/irq-pruss-intc.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/pru_rproc.h>
+#include <linux/pruss.h>
+
+#include "remoteproc_internal.h"
+#include "pru_rproc.h"
+
+/* ELF PAGE ID */
+#define PRU_PAGE_IRAM	0
+#define PRU_PAGE_DRAM	1
+
+/* IRAM offsets */
+#define PRU0_IRAM_START		0x34000
+#define PRU1_IRAM_START		0x38000
+#define PRU_IRAM_MASK		0x3ffff
+
+/* PRU_ICSS_PRU_CTRL registers */
+#define PRU_CTRL_CTRL		0x0000
+#define PRU_CTRL_STS		0x0004
+#define PRU_CTRL_WAKEUP_EN	0x0008
+#define PRU_CTRL_CYCLE		0x000C
+#define PRU_CTRL_STALL		0x0010
+#define PRU_CTRL_CTBIR0		0x0020
+#define PRU_CTRL_CTBIR1		0x0024
+#define PRU_CTRL_CTPPR0		0x0028
+#define PRU_CTRL_CTPPR1		0x002C
+
+/* CTRL register bit-fields */
+#define CTRL_CTRL_SOFT_RST_N	BIT(0)
+#define CTRL_CTRL_EN		BIT(1)
+#define CTRL_CTRL_SLEEPING	BIT(2)
+#define CTRL_CTRL_CTR_EN	BIT(3)
+#define CTRL_CTRL_SINGLE_STEP	BIT(8)
+#define CTRL_CTRL_RUNSTATE	BIT(15)
+
+/* PRU_ICSS_PRU_DEBUG registers */
+#define PRU_DEBUG_GPREG(x)	(0x0000 + (x) * 4)
+#define PRU_DEBUG_CT_REG(x)	(0x0080 + (x) * 4)
+
+/**
+ * struct pru_rproc - PRU remoteproc structure
+ * @id: id of the PRU core within the PRUSS
+ * @pruss: back-reference to parent PRUSS structure
+ * @rproc: remoteproc pointer for this PRU core
+ * @iram_region: PRU IRAM IOMEM
+ * @ctrl_regmap: regmap to PRU CTRL IOMEM
+ * @debug_regmap: regmap to PRU DEBUG IOMEM
+ * @client_np: client device node
+ * @intc_config: PRU INTC configuration data
+ * @dram0: PRUSS DRAM0 region
+ * @dram1: PRUSS DRAM1 region
+ * @shrdram: PRUSS SHARED RAM region
+ * @iram_da: device address of Instruction RAM for this PRU
+ * @pdram_da: device address of primary Data RAM for this PRU
+ * @sdram_da: device address of secondary Data RAM for this PRU
+ * @shrdram_da: device address of shared Data RAM
+ * @cfg: regmap to CFG module
+ * @gpcfg_reg: offset to gpcfg register of this PRU
+ * @fw_name: name of firmware image used during loading
+ * @gpmux_save: saved value for gpmux config
+ * @dt_irqs: number of irqs configured from DT
+ * @fw_irqs: number of irqs configured from FW
+ * @lock: mutex to protect client usage
+ * @dbg_single_step: debug state variable to set PRU into single step mode
+ * @ctrl_saved_state: saved CTRL state to return to normal mode
+ */
+struct pru_rproc {
+	int id;
+	struct pruss *pruss;
+	struct rproc *rproc;
+	struct pruss_mem_region iram_region;
+	struct regmap *ctrl_regmap;
+	struct regmap *debug_regmap;
+	struct device_node *client_np;
+	struct pruss_intc_config intc_config;
+	struct pruss_mem_region dram0;
+	struct pruss_mem_region dram1;
+	struct pruss_mem_region shrdram;
+	u32 iram_da;
+	u32 pdram_da;
+	u32 sdram_da;
+	u32 shrdram_da;
+	struct regmap *cfg;
+	int gpcfg_reg;
+	const char *fw_name;
+	u8 gpmux_save;
+	int dt_irqs;
+	int fw_irqs;
+	struct mutex lock; /* client access lock */
+	bool dbg_single_step;
+	u32 ctrl_saved_state;
+};
+
+/**
+ * pru_rproc_set_firmware() - set firmware for a pru core
+ * @rproc: the rproc instance of the PRU
+ * @fw_name: the new firmware name, or NULL if default is desired
+ */
+static int pru_rproc_set_firmware(struct rproc *rproc, const char *fw_name)
+{
+	struct pru_rproc *pru = rproc->priv;
+
+	if (!fw_name)
+		fw_name = pru->fw_name;
+
+	return rproc_set_firmware(rproc, fw_name);
+}
+
+/*
+ * pru_get_gpmux() - get the current GPMUX value for a PRU device
+ * @pru: pru_rproc instance
+ * @mux: pointer to store the current mux value into
+ *
+ * returns 0 on success, negative error value otherwise.
+ */
+static int pru_get_gpmux(struct pru_rproc *pru, u8 *mux)
+{
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(pru->cfg, pru->gpcfg_reg, &val);
+	if (ret)
+		return ret;
+
+	*mux = (u8)((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK) >>
+		    PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
+
+	return 0;
+}
+
+/**
+ * pru_set_gpmux() - set the GPMUX value for a PRU device
+ * @pru: pru_rproc instance
+ * @mux: new mux value for PRU
+ *
+ * returns 0 on success, negative error value otherwise.
+ */
+static int pru_set_gpmux(struct pru_rproc *pru, u8 mux)
+{
+	if (mux >= PRUSS_GP_MUX_SEL_MAX)
+		return -EINVAL;
+
+	return regmap_update_bits(pru->cfg, pru->gpcfg_reg,
+				  PRUSS_GPCFG_PRU_MUX_SEL_MASK,
+				  (u32)mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
+}
+
+static int pru_get_intc_dt_config(struct pru_rproc *pru,
+				  const char *propname, int index,
+				  struct pruss_intc_config *intc_config)
+{
+	struct device *dev = &pru->rproc->dev;
+	struct device_node *np = pru->client_np;
+	struct property *prop;
+	int ret = 0, entries, i;
+	int dt_irqs = 0;
+	u32 *arr;
+	int max_system_events, max_pru_channels, max_pru_host_ints;
+
+	max_system_events = MAX_PRU_SYS_EVENTS;
+	max_pru_channels = MAX_PRU_CHANNELS;
+	max_pru_host_ints = MAX_PRU_CHANNELS;
+
+	prop = of_find_property(np, propname, NULL);
+	if (!prop)
+		return 0;
+
+	entries = of_property_count_u32_elems(np, propname);
+	if (entries <= 0 || entries % 4)
+		return -EINVAL;
+
+	arr = kmalloc_array(entries, sizeof(u32), GFP_KERNEL);
+	if (!arr)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, propname, arr, entries);
+	if (ret)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++)
+		intc_config->sysev_to_ch[i] = -1;
+
+	for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++)
+		intc_config->ch_to_host[i] = -1;
+
+	for (i = 0; i < entries; i += 4) {
+		if (arr[i] != index)
+			continue;
+
+		if (arr[i + 1] < 0 ||
+		    arr[i + 1] >= max_system_events) {
+			dev_err(dev, "bad sys event %d\n", arr[i + 1]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (arr[i + 2] < 0 ||
+		    arr[i + 2] >= max_pru_channels) {
+			dev_err(dev, "bad channel %d\n", arr[i + 2]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (arr[i + 3] < 0 ||
+		    arr[i + 3] >= max_pru_host_ints) {
+			dev_err(dev, "bad irq %d\n", arr[i + 3]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		intc_config->sysev_to_ch[arr[i + 1]] = arr[i + 2];
+		dev_dbg(dev, "sysevt-to-ch[%d] -> %d\n", arr[i + 1],
+			arr[i + 2]);
+
+		intc_config->ch_to_host[arr[i + 2]] = arr[i + 3];
+		dev_dbg(dev, "chnl-to-host[%d] -> %d\n", arr[i + 2],
+			arr[i + 3]);
+
+		dt_irqs++;
+	}
+
+	kfree(arr);
+	return dt_irqs;
+
+err:
+	kfree(arr);
+	return ret;
+}
+
+static struct rproc *__pru_rproc_get(struct device_node *np, int index)
+{
+	struct device_node *rproc_np = NULL;
+	struct platform_device *pdev;
+	struct rproc *rproc;
+
+	rproc_np = of_parse_phandle(np, "prus", index);
+	if (!rproc_np || !of_device_is_available(rproc_np))
+		return ERR_PTR(-ENODEV);
+
+	pdev = of_find_device_by_node(rproc_np);
+	of_node_put(rproc_np);
+
+	if (!pdev)
+		/* probably PRU not yet probed */
+		return ERR_PTR(-EPROBE_DEFER);
+
+	/* TODO: replace the crude string based check to make sure it is PRU */
+	if (!strstr(dev_name(&pdev->dev), "pru")) {
+		put_device(&pdev->dev);
+		return ERR_PTR(-ENODEV);
+	}
+
+	rproc = platform_get_drvdata(pdev);
+	put_device(&pdev->dev);
+	if (!rproc)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	get_device(&rproc->dev);
+
+	return rproc;
+}
+
+/**
+ * pru_rproc_get() - get the PRU rproc instance from a device node
+ * @np: the user/client device node
+ * @index: index to use for the prus property
+ *
+ * This function looks through a client device node's "prus" property at index
+ * @index and returns the rproc handle for a valid PRU remote processor if
+ * found. The function allows only one user to own the PRU rproc resource at
+ * a time. Caller must call pru_rproc_put() when done with using the rproc,
+ * not required if the function returns a failure.
+ *
+ * Returns the rproc handle on success, and an ERR_PTR on failure using one
+ * of the following error values
+ *    -ENODEV if device is not found
+ *    -EBUSY if PRU is already acquired by anyone
+ *    -EPROBE_DEFER is PRU device is not probed yet
+ */
+struct rproc *pru_rproc_get(struct device_node *np, int index)
+{
+	struct rproc *rproc;
+	struct pru_rproc *pru;
+	struct device *dev;
+	int ret;
+	u32 mux;
+	const char *fw_name;
+
+	rproc = __pru_rproc_get(np, index);
+	if (IS_ERR(rproc))
+		return rproc;
+
+	pru = rproc->priv;
+	dev = &rproc->dev;
+
+	mutex_lock(&pru->lock);
+
+	if (pru->client_np) {
+		mutex_unlock(&pru->lock);
+		put_device(&rproc->dev);
+		return ERR_PTR(-EBUSY);
+	}
+
+	pru->client_np = np;
+
+	mutex_unlock(&pru->lock);
+
+	ret = pru_get_gpmux(pru, &pru->gpmux_save);
+	if (ret) {
+		dev_err(dev, "failed to get cfg gpmux: %d\n", ret);
+		goto err;
+	}
+
+	ret = of_property_read_u32_index(np, "ti,pruss-gp-mux-sel", index,
+					 &mux);
+	if (!ret) {
+		ret = pru_set_gpmux(pru, mux);
+		if (ret) {
+			dev_err(dev, "failed to set cfg gpmux: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = of_property_read_string_index(np, "firmware-name", index,
+					    &fw_name);
+	if (!ret) {
+		ret = pru_rproc_set_firmware(rproc, fw_name);
+		if (ret) {
+			dev_err(dev, "failed to set firmware: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = pru_get_intc_dt_config(pru, "ti,pru-interrupt-map",
+				     index, &pru->intc_config);
+	if (ret < 0) {
+		dev_err(dev, "error getting DT interrupt map: %d\n", ret);
+		goto err;
+	}
+
+	pru->dt_irqs = ret;
+
+	return rproc;
+
+err:
+	pru_rproc_put(rproc);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(pru_rproc_get);
+
+/**
+ * pru_rproc_put() - release the PRU rproc resource
+ * @rproc: the rproc resource to release
+ *
+ * Releases the PRU rproc resource and makes it available to other
+ * users.
+ */
+void pru_rproc_put(struct rproc *rproc)
+{
+	struct pru_rproc *pru;
+
+	if (IS_ERR_OR_NULL(rproc))
+		return;
+
+	/* TODO: replace the crude string based check to make sure it is PRU */
+	if (!strstr(dev_name(rproc->dev.parent), "pru"))
+		return;
+
+	pru = rproc->priv;
+	if (!pru->client_np)
+		return;
+
+	pru_rproc_set_firmware(rproc, NULL);
+	pru_set_gpmux(pru, pru->gpmux_save);
+
+	mutex_lock(&pru->lock);
+	pru->client_np = NULL;
+	mutex_unlock(&pru->lock);
+
+	put_device(&rproc->dev);
+}
+EXPORT_SYMBOL_GPL(pru_rproc_put);
+
+/*
+ * Control PRU single-step mode
+ *
+ * This is a debug helper function used for controlling the single-step
+ * mode of the PRU. The PRU Debug registers are not accessible when the
+ * PRU is in RUNNING state.
+ *
+ * Writing a non-zero value sets the PRU into single-step mode irrespective
+ * of its previous state. The PRU mode is saved only on the first set into
+ * a single-step mode. Writing a zero value will restore the PRU into its
+ * original mode.
+ */
+static int pru_rproc_debug_ss_set(void *data, u64 val)
+{
+	struct rproc *rproc = data;
+	struct pru_rproc *pru = rproc->priv;
+	u32 reg_val;
+	bool debug_ss;
+
+	debug_ss = !!val;
+	if (!debug_ss && !pru->dbg_single_step)
+		return 0;
+
+	regmap_read(pru->ctrl_regmap, PRU_CTRL_CTRL, &reg_val);
+
+	if (debug_ss && !pru->dbg_single_step)
+		pru->ctrl_saved_state = reg_val;
+
+	if (debug_ss)
+		reg_val |= CTRL_CTRL_SINGLE_STEP | CTRL_CTRL_EN;
+	else
+		reg_val = pru->ctrl_saved_state;
+
+	pru->dbg_single_step = debug_ss;
+	regmap_write(pru->ctrl_regmap, PRU_CTRL_CTRL, reg_val);
+
+	return 0;
+}
+
+static int pru_rproc_debug_ss_get(void *data, u64 *val)
+{
+	struct rproc *rproc = data;
+	struct pru_rproc *pru = rproc->priv;
+
+	*val = pru->dbg_single_step;
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get,
+			pru_rproc_debug_ss_set, "%llu\n");
+
+/*
+ * Create PRU-specific debugfs entries
+ *
+ * The entries are created only if the parent remoteproc debugfs directory
+ * exists, and will be cleaned up by the remoteproc core.
+ */
+static void pru_rproc_create_debug_entries(struct rproc *rproc)
+{
+	if (!rproc->dbg_dir)
+		return;
+
+	debugfs_create_file("single_step", 0600, rproc->dbg_dir,
+			    rproc, &pru_rproc_debug_ss_fops);
+}
+
+static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len);
+
+/*
+ * parse the custom interrupt map resource and save the intc_config
+ * for use when booting the processor.
+ */
+static int pru_handle_vendor_intrmap(struct rproc *rproc,
+				     struct fw_rsc_pruss_intrmap *rsc)
+{
+	int fw_irqs = 0, i, ret = 0;
+	u8 *arr;
+	struct device *dev = &rproc->dev;
+	struct pru_rproc *pru = rproc->priv;
+
+	dev_dbg(dev, "vendor rsc intc: version %d\n", rsc->version);
+
+	/*
+	 * 0 was prototyping version. Not supported.
+	 * 1 is currently supported version.
+	 */
+	if (rsc->version == 0 || rsc->version > 1) {
+		dev_err(dev, "Unsupported version %d\n", rsc->version);
+		return -EINVAL;
+	}
+
+	/* DT provided INTC config takes precedence */
+	if (pru->dt_irqs) {
+		dev_info(dev, "INTC config in DT and FW. Using DT config.\n");
+		return 0;
+	}
+
+	arr = rsc->data;
+
+	for (i = 0; i < ARRAY_SIZE(pru->intc_config.sysev_to_ch); i++)
+		pru->intc_config.sysev_to_ch[i] = -1;
+
+	for (i = 0; i < ARRAY_SIZE(pru->intc_config.ch_to_host); i++)
+		pru->intc_config.ch_to_host[i] = -1;
+
+	for (i = 0; i < rsc->num_maps * 3; i += 3) {
+		if (arr[i] < 0 ||
+		    arr[i] >= MAX_PRU_SYS_EVENTS) {
+			dev_err(dev, "bad sys event %d\n", arr[i]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (arr[i + 1] < 0 ||
+		    arr[i + 1] >= MAX_PRU_CHANNELS) {
+			dev_err(dev, "bad channel %d\n", arr[i + 1]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (arr[i + 2] < 0 ||
+		    arr[i + 2] >= MAX_PRU_CHANNELS) {
+			dev_err(dev, "bad host irq %d\n", arr[i + 2]);
+				ret = -EINVAL;
+			goto err;
+		}
+
+		pru->intc_config.sysev_to_ch[arr[i]] = arr[i + 1];
+		dev_dbg(dev, "sysevt-to-ch[%d] -> %d\n", arr[i],
+			arr[i + 1]);
+
+		pru->intc_config.ch_to_host[arr[i + 1]] = arr[i + 2];
+		dev_dbg(dev, "chnl-to-host[%d] -> %d\n", arr[i + 1],
+			arr[i + 2]);
+
+		fw_irqs++;
+	}
+
+	pru->fw_irqs = fw_irqs;
+	return 0;
+
+err:
+	pru->fw_irqs = 0;
+	return ret;
+}
+
+/* PRU-specific vendor resource handler */
+static int pru_rproc_handle_vendor_rsc(struct rproc *rproc,
+				       struct fw_rsc_vendor *ven_rsc)
+{
+	struct device *dev = rproc->dev.parent;
+	int ret = -EINVAL;
+
+	struct fw_rsc_pruss_intrmap *rsc;
+
+	rsc = (struct fw_rsc_pruss_intrmap *)ven_rsc->data;
+
+	switch (rsc->type) {
+	case PRUSS_RSC_INTRS:
+		ret = pru_handle_vendor_intrmap(rproc, rsc);
+		break;
+	default:
+		dev_err(dev, "%s: cannot handle unknown type %d\n", __func__,
+			rsc->type);
+	}
+
+	return ret;
+}
+
+/* start a PRU core */
+static int pru_rproc_start(struct rproc *rproc)
+{
+	struct device *dev = &rproc->dev;
+	struct pru_rproc *pru = rproc->priv;
+	u32 val;
+	int ret;
+
+	dev_dbg(dev, "starting PRU%d: entry-point = 0x%x\n",
+		pru->id, (rproc->bootaddr >> 2));
+
+	if (pru->dt_irqs || pru->fw_irqs) {
+		ret = pruss_intc_configure(rproc->dev.parent,
+					   &pru->intc_config);
+		if (ret) {
+			dev_err(dev, "failed to configure intc %d\n", ret);
+			return ret;
+		}
+	}
+
+	val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16);
+	regmap_write(pru->ctrl_regmap, PRU_CTRL_CTRL, val);
+
+	return 0;
+}
+
+/* stop/disable a PRU core */
+static int pru_rproc_stop(struct rproc *rproc)
+{
+	struct device *dev = &rproc->dev;
+	struct pru_rproc *pru = rproc->priv;
+
+	dev_dbg(dev, "stopping PRU%d\n", pru->id);
+	regmap_update_bits(pru->ctrl_regmap, PRU_CTRL_CTRL, CTRL_CTRL_EN, 0);
+
+	/* undo INTC config */
+	if (pru->dt_irqs || pru->fw_irqs)
+		pruss_intc_unconfigure(rproc->dev.parent, &pru->intc_config);
+
+	return 0;
+}
+
+/*
+ * Convert PRU device address (data spaces only) to kernel virtual address
+ *
+ * Each PRU has access to all data memories within the PRUSS, accessible at
+ * different ranges. So, look through both its primary and secondary Data
+ * RAMs as well as any shared Data RAM to convert a PRU device address to
+ * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data
+ * RAM1 is primary Data RAM for PRU1.
+ */
+static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len)
+{
+	struct pruss_mem_region dram0, dram1, shrd_ram;
+	u32 offset;
+	void *va = NULL;
+
+	if (len <= 0)
+		return NULL;
+
+	dram0 = pru->dram0;
+	dram1 = pru->dram1;
+	/* PRU1 has its local RAM addresses reversed */
+	if (pru->id == 1)
+		swap(dram0, dram1);
+	shrd_ram = pru->shrdram;
+
+	if (da >= pru->pdram_da && da + len <= pru->pdram_da + dram0.size) {
+		offset = da - pru->pdram_da;
+		va = (__force void *)(dram0.va + offset);
+	} else if (da >= pru->sdram_da &&
+		   da + len <= pru->sdram_da + dram1.size) {
+		offset = da - pru->sdram_da;
+		va = (__force void *)(dram1.va + offset);
+	} else if (da >= pru->shrdram_da &&
+		   da + len <= pru->shrdram_da + shrd_ram.size) {
+		offset = da - pru->shrdram_da;
+		va = (__force void *)(shrd_ram.va + offset);
+	}
+
+	return va;
+}
+
+/*
+ * Convert PRU device address (instruction space) to kernel virtual address
+ *
+ * A PRU does not have an unified address space. Each PRU has its very own
+ * private Instruction RAM, and its device address is identical to that of
+ * its primary Data RAM device address.
+ */
+static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, int len)
+{
+	u32 offset;
+	void *va = NULL;
+
+	if (len <= 0)
+		return NULL;
+
+	if (da >= pru->iram_da &&
+	    da + len <= pru->iram_da + pru->iram_region.size) {
+		offset = da - pru->iram_da;
+		va = (__force void *)(pru->iram_region.va + offset);
+	}
+
+	return va;
+}
+
+/* PRU-specific address translator */
+static void *pru_da_to_va(struct rproc *rproc, u64 da, int len, int map)
+{
+	struct pru_rproc *pru = rproc->priv;
+	void *va;
+
+	switch (map) {
+	case PRU_PAGE_IRAM:
+		va = pru_i_da_to_va(pru, da, len);
+		break;
+	case PRU_PAGE_DRAM:
+		va = pru_d_da_to_va(pru, da, len);
+		break;
+	default:
+		dev_info(&rproc->dev, "%s: invalid page %d\n", __func__, map);
+		return 0;
+	};
+
+	return va;
+}
+
+static struct rproc_ops pru_rproc_ops = {
+	.start			= pru_rproc_start,
+	.stop			= pru_rproc_stop,
+	.da_to_va		= pru_da_to_va,
+	.handle_vendor_rsc	= pru_rproc_handle_vendor_rsc,
+};
+
+static int pru_rproc_set_id(struct pru_rproc *pru)
+{
+	int ret = 0;
+	u32 iram_start = pru->iram_region.pa & PRU_IRAM_MASK;
+
+	if (iram_start == PRU0_IRAM_START)
+		pru->id = 0;
+	else if (iram_start == PRU1_IRAM_START)
+		pru->id = 1;
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static struct regmap_config pru_ctrl_regmap_config = {
+	.name = "ctrl",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = PRU_CTRL_CTPPR1,
+};
+
+static struct regmap_config pru_debug_regmap_config = {
+	.name = "debug",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = PRU_DEBUG_CT_REG(31),
+};
+
+static int pru_rproc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct platform_device *ppdev = to_platform_device(dev->parent);
+	struct pru_rproc *pru;
+	const char *fw_name;
+	struct rproc *rproc = NULL;
+	struct resource *res;
+	int ret;
+	void __iomem *va;
+
+	if (!np) {
+		dev_err(dev, "Non-DT platform device not supported\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_string(np, "firmware-name", &fw_name);
+	if (ret) {
+		dev_err(dev, "unable to retrieve firmware-name %d\n", ret);
+		return ret;
+	}
+
+	rproc = rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name,
+			    sizeof(*pru));
+	if (!rproc) {
+		dev_err(dev, "rproc_alloc failed\n");
+		return -ENOMEM;
+	}
+
+	pru = rproc->priv;
+	pru->cfg = syscon_regmap_lookup_by_phandle(np, "gpcfg");
+	if (IS_ERR(pru->cfg)) {
+		if (PTR_ERR(pru->cfg) != -EPROBE_DEFER)
+			dev_err(dev, "can't get gpcfg syscon regmap\n");
+
+		return PTR_ERR(pru->cfg);
+	}
+
+	if (of_property_read_u32_index(np, "gpcfg", 1, &pru->gpcfg_reg)) {
+		dev_err(dev, "couldn't get gpcfg reg. offset\n");
+		return -EINVAL;
+	}
+
+	/* error recovery is not supported for PRUs */
+	rproc->recovery_disabled = true;
+
+	/*
+	 * rproc_add will auto-boot the processor normally, but this is
+	 * not desired with PRU client driven boot-flow methodology. A PRU
+	 * application/client driver will boot the corresponding PRU
+	 * remote-processor as part of its state machine either through
+	 * the remoteproc sysfs interface or through the equivalent kernel API
+	 */
+	rproc->auto_boot = false;
+
+	pru->pruss = platform_get_drvdata(ppdev);
+	pru->rproc = rproc;
+	pru->fw_name = fw_name;
+	mutex_init(&pru->lock);
+
+	ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_DRAM0,
+				       &pru->dram0);
+	if (ret) {
+		dev_err(dev, "couldn't get PRUSS DRAM0: %d\n", ret);
+		return ret;
+	}
+	pruss_release_mem_region(pru->pruss, &pru->dram0);
+
+	ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_DRAM1,
+				       &pru->dram1);
+	if (ret) {
+		dev_err(dev, "couldn't get PRUSS DRAM1: %d\n", ret);
+		return ret;
+	}
+	pruss_release_mem_region(pru->pruss, &pru->dram1);
+
+	ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_SHRD_RAM2,
+				       &pru->shrdram);
+	if (ret) {
+		dev_err(dev, "couldn't get PRUSS Shared RAM: %d\n", ret);
+		return ret;
+	}
+	pruss_release_mem_region(pru->pruss, &pru->shrdram);
+
+	/* XXX: get this from match data if different in the future */
+	pru->iram_da = 0;
+	pru->pdram_da = 0;
+	pru->sdram_da = 0x2000;
+	pru->shrdram_da = 0x10000;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iram");
+	pru->iram_region.va = devm_ioremap_resource(dev, res);
+	if (IS_ERR(pru->iram_region.va)) {
+		ret = PTR_ERR(pru->iram_region.va);
+		dev_err(dev, "failed to get iram resource: %d\n", ret);
+		goto free_rproc;
+	}
+
+	pru->iram_region.pa = res->start;
+	pru->iram_region.size = resource_size(res);
+
+	dev_dbg(dev, "iram: pa %pa size 0x%zx va %p\n",
+		&pru->iram_region.pa, pru->iram_region.size,
+		pru->iram_region.va);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
+	va = devm_ioremap_resource(dev, res);
+	if (IS_ERR(va)) {
+		ret = PTR_ERR(va);
+		dev_err(dev, "failed to get control resource: %d\n", ret);
+		goto free_rproc;
+	}
+
+	pru->ctrl_regmap = devm_regmap_init_mmio(dev, va,
+						 &pru_ctrl_regmap_config);
+	if (IS_ERR(pru->ctrl_regmap)) {
+		ret = PTR_ERR(pru->ctrl_regmap);
+		dev_err(dev, "CTRL regmap init failed: %d\n", ret);
+		goto free_rproc;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug");
+	va = devm_ioremap_resource(dev, res);
+	if (IS_ERR(va)) {
+		ret = PTR_ERR(va);
+		dev_err(dev, "failed to get debug resource: %d\n", ret);
+		goto free_rproc;
+	}
+	pru->debug_regmap = devm_regmap_init_mmio(dev, va,
+						  &pru_debug_regmap_config);
+	if (IS_ERR(pru->debug_regmap)) {
+		ret = PTR_ERR(pru->debug_regmap);
+		dev_err(dev, "DEBUG regmap init failed: %d\n", ret);
+		goto free_rproc;
+	}
+
+	ret = pru_rproc_set_id(pru);
+	if (ret < 0)
+		goto free_rproc;
+
+	platform_set_drvdata(pdev, rproc);
+
+	ret = rproc_add(pru->rproc);
+	if (ret) {
+		dev_err(dev, "rproc_add failed: %d\n", ret);
+		goto free_rproc;
+	}
+
+	pru_rproc_create_debug_entries(rproc);
+
+	dev_info(dev, "PRU rproc node %s probed successfully\n", np->full_name);
+
+	return 0;
+
+free_rproc:
+	rproc_free(rproc);
+	return ret;
+}
+
+static int pru_rproc_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rproc *rproc = platform_get_drvdata(pdev);
+
+	dev_info(dev, "%s: removing rproc %s\n", __func__, rproc->name);
+
+	rproc_del(rproc);
+	rproc_free(rproc);
+
+	return 0;
+}
+
+static const struct of_device_id pru_rproc_match[] = {
+	{ .compatible = "ti,am3356-pru", },
+	{ .compatible = "ti,am4376-pru", },
+	{ .compatible = "ti,am5728-pru", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pru_rproc_match);
+
+static struct platform_driver pru_rproc_driver = {
+	.driver = {
+		.name   = "pru-rproc",
+		.of_match_table = pru_rproc_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe  = pru_rproc_probe,
+	.remove = pru_rproc_remove,
+};
+module_platform_driver(pru_rproc_driver);
+
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/pru_rproc.h b/drivers/remoteproc/pru_rproc.h
new file mode 100644
index 0000000..bbcf392
--- /dev/null
+++ b/drivers/remoteproc/pru_rproc.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * PRUSS Remote Processor specific types
+ *
+ * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * All rights reserved.
+ */
+
+#ifndef _PRU_REMOTEPROC_H_
+#define _PRU_REMOTEPROC_H_
+
+/**
+ * enum pruss_rsc_types - PRU specific resource types
+ *
+ * @PRUSS_RSC_INTRS: Resource holding information on PRU PINTC configuration
+ * @PRUSS_RSC_MAX: Indicates end of known/defined PRU resource types.
+ *		   This should be the last definition.
+ *
+ * Introduce new custom resource types before PRUSS_RSC_MAX.
+ */
+enum pruss_rsc_types {
+	PRUSS_RSC_INTRS	= 1,
+	PRUSS_RSC_MAX	= 2,
+};
+
+/**
+ * struct fw_rsc_pruss_intrmap - vendor resource to define PRU interrupts
+ * @type: should be PRUSS_RSC_INTRS
+ * @version: should be 1 or greater. 0 was for prototyping and is not supported
+ * @num_maps: number of interrupt mappings that follow
+ * @data: Array of 'num_maps' mappings.
+ *		Each mapping is a triplet {s, c, h}
+ *		s - system event id
+ *		c - channel id
+ *		h - host interrupt id
+ *
+ * PRU system events are mapped to channels, and these channels are mapped
+ * to host interrupts. Events can be mapped to channels in a one-to-one or
+ * many-to-one ratio (multiple events per channel), and channels can be
+ * mapped to host interrupts in a one-to-one or many-to-one ratio (multiple
+ * channels per interrupt).
+ *
+ * This resource is variable length due to the nature of INTC map.
+ * The below data structure is scalable so it can support sufficiently
+ * large number of sysevents and hosts.
+ */
+struct fw_rsc_pruss_intrmap {
+	u16 type;
+	u16 version;
+	u8 num_maps;
+	u8 data[];
+} __packed;
+
+#endif	/* _PRU_REMOTEPROC_H_ */
diff --git a/include/linux/remoteproc/pru_rproc.h b/include/linux/remoteproc/pru_rproc.h
new file mode 100644
index 0000000..841da09
--- /dev/null
+++ b/include/linux/remoteproc/pru_rproc.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * PRU-ICSS Remote Subsystem user interfaces
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ */
+
+#ifndef __LINUX_REMOTEPROC_PRU_RPROC_H
+#define __LINUX_REMOTEPROC_PRU_RPROC_H
+
+#if IS_ENABLED(CONFIG_PRUSS_REMOTEPROC)
+
+struct rproc *pru_rproc_get(struct device_node *node, int index);
+void pru_rproc_put(struct rproc *rproc);
+
+#else
+
+static inline struct rproc *pru_rproc_get(struct device_node *node, int index)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+
+static inline void pru_rproc_put(struct rproc *rproc) { }
+
+#endif /* CONFIG_PRUSS_REMOTEPROC */
+
+#endif /* __LINUX_REMOTEPROC_PRU_RPROC_H */
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 11/14] remoteproc/pru: Add pru_rproc_set_ctable() and pru_rproc_set_gpimode()
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (9 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 12/14] remoteproc/pru: Add support for virtio rpmsg stack Roger Quadros
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq, Andrew F . Davis

Some firmwares expect the OS drivers to configure the CTABLE
entries publishing dynamically allocated memory regions. For
example, the PRU Ethernet firmwares use the C28 and C30 entries
for retrieving the Shared RAM and System SRAM (OCMC) areas
allocated by the PRU Ethernet client driver.

Provide a way for users to do that through a new API,
pru_rproc_set_ctable(). The API returns 0 on success and
a negative value on error.

NOTE:
The programmable CTABLE entries are typically re-programmed by
the PRU firmwares when dealing with a certain block of memory
during block processing. This API provides an interface to the
PRU client drivers to publish a dynamically allocated memory
block with the PRU firmware using a CTABLE entry instead of a
negotiated address in shared memory. Additional synchronization
may be needed between the PRU client drivers and firmwares if
different addresses needs to be published at run-time reusing
the same CTABLE entry.

Some client drivers need to set the GPI mode of the
PRU. The GPI mode select bits like in the GPCFG register
space. Add pru_rproc_set_gpimode() API to set the GPI
mode for the PRU.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
[s-anna@ti.com: add the NOTE: on patch description, minor cleanups]
Signed-off-by: Suman Anna <s-anna@ti.com>
---
 drivers/remoteproc/pru_rproc.c       | 48 ++++++++++++++++++++++++++++++++++++
 include/linux/remoteproc/pru_rproc.h | 30 ++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index ddd4b64..85463f7 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -398,6 +398,54 @@ void pru_rproc_put(struct rproc *rproc)
 }
 EXPORT_SYMBOL_GPL(pru_rproc_put);
 
+/**
+ * pru_rproc_set_ctable() - set the constant table index for the PRU
+ * @rproc: the rproc instance of the PRU
+ * @c: constant table index to set
+ * @addr: physical address to set it to
+ */
+int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr)
+{
+	struct pru_rproc *pru = rproc->priv;
+	unsigned int reg;
+	u32 mask, set;
+	u16 idx;
+	u16 idx_mask;
+
+	/* pointer is 16 bit and index is 8-bit so mask out the rest */
+	idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF;
+
+	/* ctable uses bit 8 and upwards only */
+	idx = (addr >> 8) & idx_mask;
+
+	/* configurable ctable (i.e. C24) starts at PRU_CTRL_CTBIR0 */
+	reg = PRU_CTRL_CTBIR0 + 4 * (c >> 1);
+	mask = idx_mask << (16 * (c & 1));
+	set = idx << (16 * (c & 1));
+
+	regmap_update_bits(pru->ctrl_regmap, reg, mask, set);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pru_rproc_set_ctable);
+
+/**
+ * pru_rproc_set_gpimode() - set the GPI mode for the PRU
+ * @rproc: the rproc instance of the PRU
+ * @mode: GPI mode to set
+ *
+ * Returns 0 on success, negative error value otherwise.
+ */
+int pru_rproc_set_gpimode(struct rproc *rproc, enum pruss_gpi_mode mode)
+{
+	struct pru_rproc *pru = rproc->priv;
+
+	return regmap_update_bits(pru->cfg, pru->gpcfg_reg,
+				  PRUSS_GPCFG_PRU_GPI_MODE_MASK,
+				  mode << PRUSS_GPCFG_PRU_GPI_MODE_SHIFT);
+}
+EXPORT_SYMBOL_GPL(pru_rproc_set_gpimode);
+
 /*
  * Control PRU single-step mode
  *
diff --git a/include/linux/remoteproc/pru_rproc.h b/include/linux/remoteproc/pru_rproc.h
index 841da09..887d996 100644
--- a/include/linux/remoteproc/pru_rproc.h
+++ b/include/linux/remoteproc/pru_rproc.h
@@ -8,10 +8,28 @@
 #ifndef __LINUX_REMOTEPROC_PRU_RPROC_H
 #define __LINUX_REMOTEPROC_PRU_RPROC_H
 
+/**
+ * enum pru_ctable_idx - Configurable Constant table index identifiers
+ */
+enum pru_ctable_idx {
+	PRU_C24 = 0,
+	PRU_C25,
+	PRU_C26,
+	PRU_C27,
+	PRU_C28,
+	PRU_C29,
+	PRU_C30,
+	PRU_C31,
+};
+
+enum pruss_gpi_mode;
+
 #if IS_ENABLED(CONFIG_PRUSS_REMOTEPROC)
 
 struct rproc *pru_rproc_get(struct device_node *node, int index);
 void pru_rproc_put(struct rproc *rproc);
+int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr);
+int pru_rproc_set_gpimode(struct rproc *rproc, enum pruss_gpi_mode mode);
 
 #else
 
@@ -22,6 +40,18 @@ static inline struct rproc *pru_rproc_get(struct device_node *node, int index)
 
 static inline void pru_rproc_put(struct rproc *rproc) { }
 
+static inline int pru_rproc_set_ctable(struct rproc *rproc,
+				       enum pru_ctable_idx c, u32 addr)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pru_rproc_set_gpimode(struct rproc *rproc,
+					enum pruss_gpi_mode mode)
+{
+	return -ENOTSUPP;
+}
+
 #endif /* CONFIG_PRUSS_REMOTEPROC */
 
 #endif /* __LINUX_REMOTEPROC_PRU_RPROC_H */
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 12/14] remoteproc/pru: Add support for virtio rpmsg stack
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (10 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 11/14] remoteproc/pru: Add pru_rproc_set_ctable() and pru_rproc_set_gpimode() Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 13/14] rpmsg: virtio_rpmsg_bus: move back rpmsg_hdr into a public header Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 14/14] rpmsg: pru: add a PRU RPMsg driver Roger Quadros
  13 siblings, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: Suman Anna <s-anna@ti.com>

The PRU remoteproc driver has been enhanced to support the optional
rpmsg stack using the virtio-ring based communication transport
between MPU and a PRU core. This provides support to any firmware
images supporting the virtio devices.

The virtio-ring signalling support is provided either through a OMAP
mailbox or through two PRU system events on OMAP-architecture based
SoCs - one event used in each direction for kicking from one processor
and receiving notification on the other processor. The virtio rpmsg
signalling is enabled only using using PRU system events for interrupts
on the Keystone-architecture based 66AK2G SoCs (it is possible to
implement using an alternate Keystone specific IPCGR registers as well).
The driver supports both signalling options, though the PRU events based
signalling is the recommended option as it avoids an external peripheral
access from the PRU side. It also provides a uniform solution across
both the OMAP, Keystone and Davinci architectures. The PRU events based
signalling takes precedence if both options are mentioned. Either of the
options would require the corresponding firmware support though. A build
dependency against MAILBOX is also added. Note that the OMAP Mailbox
IP is not present on 66AK2G and Davinci SoCs, so it is only selected
for OMAP-based SoCs.

Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/remoteproc/Kconfig     |   2 +
 drivers/remoteproc/pru_rproc.c | 165 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 166 insertions(+), 1 deletion(-)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 333666e..b89acb0 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -200,6 +200,8 @@ config ST_SLIM_REMOTEPROC
 config PRUSS_REMOTEPROC
 	tristate "TI PRUSS remoteproc support"
 	depends on TI_PRUSS
+	select MAILBOX
+	select OMAP2PLUS_MBOX if ARCH_OMAP2PLUS
 	default n
 	help
 	  Support for TI PRU-ICSS remote processors via the remote processor
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 85463f7..b47c4fd 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -11,6 +11,7 @@
 #include <linux/debugfs.h>
 #include <linux/interrupt.h>
 #include <linux/irqchip/irq-pruss-intc.h>
+#include <linux/mailbox_client.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
@@ -64,6 +65,10 @@
  * @debug_regmap: regmap to PRU DEBUG IOMEM
  * @client_np: client device node
  * @intc_config: PRU INTC configuration data
+ * @mbox: mailbox channel handle used for vring signalling with MPU
+ * @client: mailbox client to request the mailbox channel
+ * @irq_ring: IRQ number to use for processing vring buffers
+ * @irq_kick: IRQ number to use to perform virtio kick
  * @dram0: PRUSS DRAM0 region
  * @dram1: PRUSS DRAM1 region
  * @shrdram: PRUSS SHARED RAM region
@@ -90,6 +95,10 @@ struct pru_rproc {
 	struct regmap *debug_regmap;
 	struct device_node *client_np;
 	struct pruss_intc_config intc_config;
+	struct mbox_chan *mbox;
+	struct mbox_client client;
+	int irq_vring;
+	int irq_kick;
 	struct pruss_mem_region dram0;
 	struct pruss_mem_region dram1;
 	struct pruss_mem_region shrdram;
@@ -615,6 +624,82 @@ static int pru_rproc_handle_vendor_rsc(struct rproc *rproc,
 	return ret;
 }
 
+/**
+ * pru_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 omap's mailbox driver whenever a mailbox
+ * message is received. Usually, the mailbox payload simply contains
+ * the index of the virtqueue that is kicked by the PRU remote processor,
+ * and we let remoteproc core handle it.
+ *
+ * In addition to virtqueue indices, we might also have some out-of-band
+ * values that indicates different events. Those values are deliberately
+ * very big so they don't coincide with virtqueue indices.
+ */
+static void pru_rproc_mbox_callback(struct mbox_client *client, void *data)
+{
+	struct pru_rproc *pru = container_of(client, struct pru_rproc, client);
+	struct device *dev = &pru->rproc->dev;
+	u32 msg = (u32)data;
+
+	dev_dbg(dev, "mbox msg: 0x%x\n", msg);
+
+	/* msg contains the index of the triggered vring */
+	if (rproc_vq_interrupt(pru->rproc, msg) == IRQ_NONE)
+		dev_dbg(dev, "no message was found in vqid %d\n", msg);
+}
+
+/**
+ * pru_rproc_vring_interrupt() - interrupt handler for processing vrings
+ * @irq: irq number associated with the PRU event MPU is listening on
+ * @data: interrupt handler data, will be a PRU rproc structure
+ *
+ * This handler is used by the PRU remoteproc driver when using PRU system
+ * events for processing the virtqueues. Unlike the mailbox IP, there is
+ * no payload associated with an interrupt, so either a unique event is
+ * used for each virtqueue kick, or a both virtqueues are processed on
+ * a single event. The latter is chosen to conserve the usable PRU system
+ * events.
+ */
+static irqreturn_t pru_rproc_vring_interrupt(int irq, void *data)
+{
+	struct pru_rproc *pru = data;
+
+	dev_dbg(&pru->rproc->dev, "got vring irq\n");
+
+	/* process incoming buffers on both the Rx and Tx vrings */
+	rproc_vq_interrupt(pru->rproc, 0);
+	rproc_vq_interrupt(pru->rproc, 1);
+
+	return IRQ_HANDLED;
+}
+
+/* kick a virtqueue */
+static void pru_rproc_kick(struct rproc *rproc, int vq_id)
+{
+	struct device *dev = &rproc->dev;
+	struct pru_rproc *pru = rproc->priv;
+	int ret;
+
+	dev_dbg(dev, "kicking vqid %d on PRU%d\n", vq_id, pru->id);
+
+	if (pru->irq_kick > 0) {
+		ret = pruss_intc_trigger(pru->irq_kick);
+		if (ret < 0)
+			dev_err(dev, "pruss_intc_trigger failed: %d\n", ret);
+	} else if (pru->mbox) {
+		/*
+		 * send the index of the triggered virtqueue in the mailbox
+		 * payload
+		 */
+		ret = mbox_send_message(pru->mbox, (void *)vq_id);
+		if (ret < 0)
+			dev_err(dev, "mbox_send_message failed: %d\n", ret);
+	}
+}
+
 /* start a PRU core */
 static int pru_rproc_start(struct rproc *rproc)
 {
@@ -635,10 +720,36 @@ static int pru_rproc_start(struct rproc *rproc)
 		}
 	}
 
+	if (!list_empty(&pru->rproc->rvdevs)) {
+		if (!pru->mbox && (pru->irq_vring <= 0 || pru->irq_kick <= 0)) {
+			dev_err(dev, "virtio vring interrupt mechanisms are not provided\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+
+		if (!pru->mbox && pru->irq_vring > 0) {
+			ret = request_threaded_irq(pru->irq_vring, NULL,
+						   pru_rproc_vring_interrupt,
+						   IRQF_ONESHOT, dev_name(dev),
+						   pru);
+			if (ret) {
+				dev_err(dev, "failed to enable vring interrupt, ret = %d\n",
+					ret);
+				goto fail;
+			}
+		}
+	}
+
 	val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16);
 	regmap_write(pru->ctrl_regmap, PRU_CTRL_CTRL, val);
 
 	return 0;
+
+fail:
+	if (pru->dt_irqs || pru->fw_irqs)
+		pruss_intc_unconfigure(rproc->dev.parent, &pru->intc_config);
+
+	return ret;
 }
 
 /* stop/disable a PRU core */
@@ -650,6 +761,10 @@ static int pru_rproc_stop(struct rproc *rproc)
 	dev_dbg(dev, "stopping PRU%d\n", pru->id);
 	regmap_update_bits(pru->ctrl_regmap, PRU_CTRL_CTRL, CTRL_CTRL_EN, 0);
 
+	if (!list_empty(&pru->rproc->rvdevs) &&
+	    !pru->mbox && pru->irq_vring > 0)
+		free_irq(pru->irq_vring, pru);
+
 	/* undo INTC config */
 	if (pru->dt_irqs || pru->fw_irqs)
 		pruss_intc_unconfigure(rproc->dev.parent, &pru->intc_config);
@@ -746,6 +861,7 @@ static void *pru_da_to_va(struct rproc *rproc, u64 da, int len, int map)
 static struct rproc_ops pru_rproc_ops = {
 	.start			= pru_rproc_start,
 	.stop			= pru_rproc_stop,
+	.kick			= pru_rproc_kick,
 	.da_to_va		= pru_da_to_va,
 	.handle_vendor_rsc	= pru_rproc_handle_vendor_rsc,
 };
@@ -789,6 +905,7 @@ static int pru_rproc_probe(struct platform_device *pdev)
 	struct pru_rproc *pru;
 	const char *fw_name;
 	struct rproc *rproc = NULL;
+	struct mbox_client *client;
 	struct resource *res;
 	int ret;
 	void __iomem *va;
@@ -924,10 +1041,51 @@ static int pru_rproc_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, rproc);
 
+	/* get optional vring and kick interrupts for supporting virtio rpmsg */
+	pru->irq_vring = platform_get_irq_byname(pdev, "vring");
+	if (pru->irq_vring <= 0) {
+		ret = pru->irq_vring;
+		if (ret == -EPROBE_DEFER)
+			goto free_rproc;
+		dev_dbg(dev, "unable to get vring interrupt, status = %d\n",
+			ret);
+	}
+
+	pru->irq_kick = platform_get_irq_byname(pdev, "kick");
+	if (pru->irq_kick <= 0) {
+		ret = pru->irq_kick;
+		if (ret == -EPROBE_DEFER)
+			goto free_rproc;
+		dev_dbg(dev, "unable to get kick interrupt, status = %d\n",
+			ret);
+	}
+
+	/*
+	 * get optional mailbox for virtio rpmsg signalling if vring and kick
+	 * interrupts are not specified for OMAP architecture based SoCs
+	 */
+	if (pru->irq_vring <= 0 && pru->irq_kick <= 0 &&
+	    !of_device_is_compatible(np, "ti,k2g-pru") &&
+	    !of_device_is_compatible(np, "ti,da850-pru")) {
+		client = &pru->client;
+		client->dev = dev;
+		client->tx_done = NULL;
+		client->rx_callback = pru_rproc_mbox_callback;
+		client->tx_block = false;
+		client->knows_txdone = false;
+		pru->mbox = mbox_request_channel(client, 0);
+		if (IS_ERR(pru->mbox)) {
+			ret = PTR_ERR(pru->mbox);
+			pru->mbox = NULL;
+			dev_dbg(dev, "unable to get mailbox channel, status = %d\n",
+				ret);
+		}
+	}
+
 	ret = rproc_add(pru->rproc);
 	if (ret) {
 		dev_err(dev, "rproc_add failed: %d\n", ret);
-		goto free_rproc;
+		goto put_mbox;
 	}
 
 	pru_rproc_create_debug_entries(rproc);
@@ -936,6 +1094,8 @@ static int pru_rproc_probe(struct platform_device *pdev)
 
 	return 0;
 
+put_mbox:
+	mbox_free_channel(pru->mbox);
 free_rproc:
 	rproc_free(rproc);
 	return ret;
@@ -945,9 +1105,12 @@ static int pru_rproc_remove(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct rproc *rproc = platform_get_drvdata(pdev);
+	struct pru_rproc *pru = rproc->priv;
 
 	dev_info(dev, "%s: removing rproc %s\n", __func__, rproc->name);
 
+	mbox_free_channel(pru->mbox);
+
 	rproc_del(rproc);
 	rproc_free(rproc);
 
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 13/14] rpmsg: virtio_rpmsg_bus: move back rpmsg_hdr into a public header
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (11 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 12/14] remoteproc/pru: Add support for virtio rpmsg stack Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 14:22 ` [PATCH v2 14/14] rpmsg: pru: add a PRU RPMsg driver Roger Quadros
  13 siblings, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: Suman Anna <s-anna@ti.com>

Commit e88dae5da46d ("rpmsg: Move virtio specifics from public header")
has moved the struct rpmsg_hdr definition from the public rpmsg.h and
made it private to virtio_rpmsg_bus module. This structure is a common
header used in all virtio rpmsg messages, and used by various virtio
rpmsg bus drivers. So, move this back into the virtio_rpmsg specific
public header to make it visible to various rpmsg drivers.

Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/rpmsg/virtio_rpmsg_bus.c   | 21 +--------------------
 include/linux/rpmsg/virtio_rpmsg.h | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 20 deletions(-)
 create mode 100644 include/linux/rpmsg/virtio_rpmsg.h

diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 664f957..f654923 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -26,6 +26,7 @@
 #include <linux/rpmsg.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
+#include <linux/rpmsg/virtio_rpmsg.h>
 
 #include "rpmsg_internal.h"
 
@@ -73,26 +74,6 @@ struct virtproc_info {
 #define VIRTIO_RPMSG_F_NS	0 /* RP supports name service notifications */
 
 /**
- * struct rpmsg_hdr - common header for all rpmsg messages
- * @src: source address
- * @dst: destination address
- * @reserved: reserved for future use
- * @len: length of payload (in bytes)
- * @flags: message flags
- * @data: @len bytes of message payload data
- *
- * Every message sent(/received) on the rpmsg bus begins with this header.
- */
-struct rpmsg_hdr {
-	u32 src;
-	u32 dst;
-	u32 reserved;
-	u16 len;
-	u16 flags;
-	u8 data[0];
-} __packed;
-
-/**
  * struct rpmsg_ns_msg - dynamic name service announcement message
  * @name: name of remote service that is published
  * @addr: address of remote service that is published
diff --git a/include/linux/rpmsg/virtio_rpmsg.h b/include/linux/rpmsg/virtio_rpmsg.h
new file mode 100644
index 0000000..cf5f820
--- /dev/null
+++ b/include/linux/rpmsg/virtio_rpmsg.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_RPMSG_VIRTIO_RPMSG_H
+#define _LINUX_RPMSG_VIRTIO_RPMSG_H
+
+/**
+ * struct rpmsg_hdr - common header for all virtio rpmsg messages
+ * @src: source address
+ * @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ * @data: @len bytes of message payload data
+ *
+ * Every message sent(/received) on the rpmsg bus begins with this header.
+ */
+struct rpmsg_hdr {
+	u32 src;
+	u32 dst;
+	u32 reserved;
+	u16 len;
+	u16 flags;
+	u8 data[0];
+} __packed;
+
+#endif
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH v2 14/14] rpmsg: pru: add a PRU RPMsg driver
  2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
                   ` (12 preceding siblings ...)
  2019-02-04 14:22 ` [PATCH v2 13/14] rpmsg: virtio_rpmsg_bus: move back rpmsg_hdr into a public header Roger Quadros
@ 2019-02-04 14:22 ` Roger Quadros
  2019-02-04 15:26   ` Andrew F. Davis
  13 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 14:22 UTC (permalink / raw)
  To: tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, rogerq

From: Jason Reeder <jreeder@ti.com>

An RPMsg driver that exposes interfaces to user space, to
allow applications to communicate with the PRU processors
on available TI SoCs has been added. This is restricted to
SoCs that have the PRUSS remoteproc support.

Signed-off-by: Jason Reeder <jreeder@ti.com>
[s-anna@ti.com: various cleanups, rpmsg rebase fixes for 4.14]
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/rpmsg/Kconfig     |  14 ++
 drivers/rpmsg/Makefile    |   1 +
 drivers/rpmsg/rpmsg_pru.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 375 insertions(+)
 create mode 100644 drivers/rpmsg/rpmsg_pru.c

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index d0322b4..5beb5e4 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -55,4 +55,18 @@ config RPMSG_VIRTIO
 	select RPMSG
 	select VIRTIO
 
+config RPMSG_PRU
+	tristate "PRU RPMsg Communication driver"
+	default n
+	depends on RPMSG_VIRTIO
+	depends on REMOTEPROC
+	depends on PRUSS_REMOTEPROC
+	help
+	  An rpmsg driver that exposes interfaces to user space, to allow
+	  applications to communicate with the PRU processors on available
+	  TI SoCs. This is restricted to SoCs that have the PRUSS remoteproc
+	  support.
+
+	  If unsure, say N.
+
 endmenu
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 9aa8595..b66a5dd 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_RPMSG)		+= rpmsg_core.o
 obj-$(CONFIG_RPMSG_CHAR)	+= rpmsg_char.o
+obj-$(CONFIG_RPMSG_PRU)		+= rpmsg_pru.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o
diff --git a/drivers/rpmsg/rpmsg_pru.c b/drivers/rpmsg/rpmsg_pru.c
new file mode 100644
index 0000000..2e8d2b1
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_pru.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PRU Remote Processor Messaging Driver
+ *
+ * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com/
+ *	Jason Reeder <jreeder@ti.com>
+ *	Suman Anna <s-anna@ti.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/module.h>
+#include <linux/kfifo.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/rpmsg/virtio_rpmsg.h>
+
+#define PRU_MAX_DEVICES				(8)
+/* Matches the definition in virtio_rpmsg_bus.c */
+#define RPMSG_BUF_SIZE				(512)
+#define MAX_FIFO_MSG				(32)
+#define FIFO_MSG_SIZE				RPMSG_BUF_SIZE
+
+/**
+ * struct rpmsg_pru_dev - Structure that contains the per-device data
+ * @rpdev: rpmsg channel device that is associated with this rpmsg_pru device
+ * @dev: device
+ * @cdev: character device
+ * @locked: boolean used to determine whether or not the device file is in use
+ * @devt: dev_t structure for the rpmsg_pru device
+ * @msg_fifo: kernel fifo used to buffer the messages between userspace and PRU
+ * @msg_len: array storing the lengths of each message in the kernel fifo
+ * @msg_idx_rd: kernel fifo read index
+ * @msg_idx_wr: kernel fifo write index
+ * @wait_list: wait queue used to implement the poll operation of the character
+ *             device
+ *
+ * Each rpmsg_pru device provides an interface, using an rpmsg channel (rpdev),
+ * between a user space character device (cdev) and a PRU core. A kernel fifo
+ * (msg_fifo) is used to buffer the messages in the kernel that are
+ * being passed between the character device and the PRU.
+ */
+struct rpmsg_pru_dev {
+	struct rpmsg_device *rpdev;
+	struct device *dev;
+	struct cdev cdev;
+	bool locked;
+	dev_t devt;
+	struct kfifo msg_fifo;
+	u32 msg_len[MAX_FIFO_MSG];
+	int msg_idx_rd;
+	int msg_idx_wr;
+	wait_queue_head_t wait_list;
+};
+
+static struct class *rpmsg_pru_class;
+static dev_t rpmsg_pru_devt;
+static DEFINE_MUTEX(rpmsg_pru_lock);
+static DEFINE_IDR(rpmsg_pru_minors);
+
+static int rpmsg_pru_open(struct inode *inode, struct file *filp)
+{
+	struct rpmsg_pru_dev *prudev;
+	int ret = -EACCES;
+
+	prudev = container_of(inode->i_cdev, struct rpmsg_pru_dev, cdev);
+
+	mutex_lock(&rpmsg_pru_lock);
+	if (!prudev->locked) {
+		prudev->locked = true;
+		filp->private_data = prudev;
+		ret = 0;
+	}
+	mutex_unlock(&rpmsg_pru_lock);
+
+	if (ret)
+		dev_err(prudev->dev, "Device already open\n");
+
+	return ret;
+}
+
+static int rpmsg_pru_release(struct inode *inode, struct file *filp)
+{
+	struct rpmsg_pru_dev *prudev;
+
+	prudev = container_of(inode->i_cdev, struct rpmsg_pru_dev, cdev);
+	mutex_lock(&rpmsg_pru_lock);
+	prudev->locked = false;
+	mutex_unlock(&rpmsg_pru_lock);
+	return 0;
+}
+
+static ssize_t rpmsg_pru_read(struct file *filp, char __user *buf,
+			      size_t count, loff_t *f_pos)
+{
+	int ret;
+	u32 length;
+	struct rpmsg_pru_dev *prudev;
+
+	prudev = filp->private_data;
+
+	if (kfifo_is_empty(&prudev->msg_fifo) &&
+	    (filp->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	ret = wait_event_interruptible(prudev->wait_list,
+				       !kfifo_is_empty(&prudev->msg_fifo));
+	if (ret)
+		return -EINTR;
+
+	ret = kfifo_to_user(&prudev->msg_fifo, buf,
+			    prudev->msg_len[prudev->msg_idx_rd], &length);
+	prudev->msg_idx_rd = (prudev->msg_idx_rd + 1) % MAX_FIFO_MSG;
+
+	return ret ? ret : length;
+}
+
+static ssize_t rpmsg_pru_write(struct file *filp, const char __user *buf,
+			       size_t count, loff_t *f_pos)
+{
+	int ret;
+	struct rpmsg_pru_dev *prudev;
+	static char rpmsg_pru_buf[RPMSG_BUF_SIZE];
+
+	prudev = filp->private_data;
+
+	if (count > RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) {
+		dev_err(prudev->dev, "Data too large for RPMsg Buffer\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(rpmsg_pru_buf, buf, count)) {
+		dev_err(prudev->dev, "Error copying buffer from user space");
+		return -EFAULT;
+	}
+
+	ret = rpmsg_send(prudev->rpdev->ept, (void *)rpmsg_pru_buf, count);
+	if (ret)
+		dev_err(prudev->dev, "rpmsg_send failed: %d\n", ret);
+
+	return ret ? ret : count;
+}
+
+static unsigned int rpmsg_pru_poll(struct file *filp,
+				   struct poll_table_struct *wait)
+{
+	int mask;
+	struct rpmsg_pru_dev *prudev;
+
+	prudev = filp->private_data;
+
+	poll_wait(filp, &prudev->wait_list, wait);
+
+	mask = POLLOUT | POLLWRNORM;
+
+	if (!kfifo_is_empty(&prudev->msg_fifo))
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}
+
+static const struct file_operations rpmsg_pru_fops = {
+	.owner = THIS_MODULE,
+	.open = rpmsg_pru_open,
+	.release = rpmsg_pru_release,
+	.read = rpmsg_pru_read,
+	.write = rpmsg_pru_write,
+	.poll = rpmsg_pru_poll,
+};
+
+static int rpmsg_pru_cb(struct rpmsg_device *rpdev, void *data, int len,
+			void *priv, u32 src)
+{
+	u32 length;
+	struct rpmsg_pru_dev *prudev;
+
+	prudev = dev_get_drvdata(&rpdev->dev);
+
+	if (kfifo_avail(&prudev->msg_fifo) < len) {
+		dev_err(&rpdev->dev, "Not enough space on the FIFO\n");
+		return -ENOSPC;
+	}
+
+	if ((prudev->msg_idx_wr + 1) % MAX_FIFO_MSG ==
+		prudev->msg_idx_rd) {
+		dev_err(&rpdev->dev, "Message length table is full\n");
+		return -ENOSPC;
+	}
+
+	length = kfifo_in(&prudev->msg_fifo, data, len);
+	prudev->msg_len[prudev->msg_idx_wr] = length;
+	prudev->msg_idx_wr = (prudev->msg_idx_wr + 1) % MAX_FIFO_MSG;
+
+	wake_up_interruptible(&prudev->wait_list);
+
+	return 0;
+}
+
+static int rpmsg_pru_probe(struct rpmsg_device *rpdev)
+{
+	int ret;
+	struct rpmsg_pru_dev *prudev;
+	int minor_got;
+
+	prudev = devm_kzalloc(&rpdev->dev, sizeof(*prudev), GFP_KERNEL);
+	if (!prudev)
+		return -ENOMEM;
+
+	mutex_lock(&rpmsg_pru_lock);
+	minor_got = idr_alloc(&rpmsg_pru_minors, prudev, 0, PRU_MAX_DEVICES,
+			      GFP_KERNEL);
+	mutex_unlock(&rpmsg_pru_lock);
+	if (minor_got < 0) {
+		ret = minor_got;
+		dev_err(&rpdev->dev, "Failed to get a minor number for the rpmsg_pru device: %d\n",
+			ret);
+		goto fail_alloc_minor;
+	}
+
+	prudev->devt = MKDEV(MAJOR(rpmsg_pru_devt), minor_got);
+
+	cdev_init(&prudev->cdev, &rpmsg_pru_fops);
+	prudev->cdev.owner = THIS_MODULE;
+	ret = cdev_add(&prudev->cdev, prudev->devt, 1);
+	if (ret) {
+		dev_err(&rpdev->dev, "Unable to add cdev for the rpmsg_pru device\n");
+		goto fail_add_cdev;
+	}
+
+	prudev->dev = device_create(rpmsg_pru_class, &rpdev->dev, prudev->devt,
+				    NULL, "rpmsg_pru%d", rpdev->dst);
+	if (IS_ERR(prudev->dev)) {
+		dev_err(&rpdev->dev, "Unable to create the rpmsg_pru device\n");
+		ret = PTR_ERR(prudev->dev);
+		goto fail_create_device;
+	}
+
+	prudev->rpdev = rpdev;
+
+	ret = kfifo_alloc(&prudev->msg_fifo, MAX_FIFO_MSG * FIFO_MSG_SIZE,
+			  GFP_KERNEL);
+	if (ret) {
+		dev_err(&rpdev->dev, "Unable to allocate fifo for the rpmsg_pru device\n");
+		goto fail_alloc_fifo;
+	}
+
+	init_waitqueue_head(&prudev->wait_list);
+
+	dev_set_drvdata(&rpdev->dev, prudev);
+
+	dev_info(&rpdev->dev, "new rpmsg_pru device: /dev/rpmsg_pru%d",
+		 rpdev->dst);
+
+	return 0;
+
+fail_alloc_fifo:
+	device_destroy(rpmsg_pru_class, prudev->devt);
+fail_create_device:
+	cdev_del(&prudev->cdev);
+fail_add_cdev:
+	mutex_lock(&rpmsg_pru_lock);
+	idr_remove(&rpmsg_pru_minors, minor_got);
+	mutex_unlock(&rpmsg_pru_lock);
+fail_alloc_minor:
+	return ret;
+}
+
+static void rpmsg_pru_remove(struct rpmsg_device *rpdev)
+{
+	struct rpmsg_pru_dev *prudev;
+
+	prudev = dev_get_drvdata(&rpdev->dev);
+
+	kfifo_free(&prudev->msg_fifo);
+	device_destroy(rpmsg_pru_class, prudev->devt);
+	cdev_del(&prudev->cdev);
+	mutex_lock(&rpmsg_pru_lock);
+	idr_remove(&rpmsg_pru_minors, MINOR(prudev->devt));
+	mutex_unlock(&rpmsg_pru_lock);
+}
+
+/* .name matches on RPMsg Channels and causes a probe */
+static const struct rpmsg_device_id rpmsg_driver_pru_id_table[] = {
+	{ .name	= "rpmsg-pru" },
+	{ },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pru_id_table);
+
+static struct rpmsg_driver rpmsg_pru_driver = {
+	.drv.name	= KBUILD_MODNAME,
+	.id_table	= rpmsg_driver_pru_id_table,
+	.probe		= rpmsg_pru_probe,
+	.callback	= rpmsg_pru_cb,
+	.remove		= rpmsg_pru_remove,
+};
+
+static int __init rpmsg_pru_init(void)
+{
+	int ret;
+
+	rpmsg_pru_class = class_create(THIS_MODULE, "rpmsg_pru");
+	if (IS_ERR(rpmsg_pru_class)) {
+		pr_err("Unable to create class\n");
+		ret = PTR_ERR(rpmsg_pru_class);
+		goto fail_create_class;
+	}
+
+	ret = alloc_chrdev_region(&rpmsg_pru_devt, 0, PRU_MAX_DEVICES,
+				  "rpmsg_pru");
+	if (ret) {
+		pr_err("Unable to allocate chrdev region\n");
+		goto fail_alloc_region;
+	}
+
+	ret = register_rpmsg_driver(&rpmsg_pru_driver);
+	if (ret) {
+		pr_err("Unable to register rpmsg driver");
+		goto fail_register_rpmsg_driver;
+	}
+
+	return 0;
+
+fail_register_rpmsg_driver:
+	unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES);
+fail_alloc_region:
+	class_destroy(rpmsg_pru_class);
+fail_create_class:
+	return ret;
+}
+
+static void __exit rpmsg_pru_exit(void)
+{
+	unregister_rpmsg_driver(&rpmsg_pru_driver);
+	idr_destroy(&rpmsg_pru_minors);
+	mutex_destroy(&rpmsg_pru_lock);
+	class_destroy(rpmsg_pru_class);
+	unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES);
+}
+
+module_init(rpmsg_pru_init);
+module_exit(rpmsg_pru_exit);
+
+MODULE_AUTHOR("Jason Reeder <jreeder@ti.com>");
+MODULE_ALIAS("rpmsg:rpmsg-pru");
+MODULE_DESCRIPTION("PRU Remote Processor Messaging Driver");
+MODULE_LICENSE("GPL v2");
-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs
  2019-02-04 14:22 ` [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs Roger Quadros
@ 2019-02-04 14:52   ` Andrew F. Davis
  2019-02-04 15:32     ` Roger Quadros
  2019-02-04 16:35     ` Tony Lindgren
  0 siblings, 2 replies; 61+ messages in thread
From: Andrew F. Davis @ 2019-02-04 14:52 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, Keerthy

On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: Suman Anna <s-anna@ti.com>
> 
> The Programmable Real-Time Unit - Industrial Communication
> Subsystem (PRU-ICSS) is present on various TI SoCs such as
> AM335x or AM437x or the Keystone 66AK2G. Each SoC can have
> one or more PRUSS instances that may or may not be identical.
> For example, AM335x SoCs have a single PRUSS, while AM437x has
> two PRUSS instances PRUSS1 and PRUSS0, with the PRUSS0 being
> a cut-down version of the PRUSS1.
> 
> The PRUSS consists of dual 32-bit RISC cores called the
> Programmable Real-Time Units (PRUs), with data and
> instruction memories. It also contains various sub-modules
> like MDIO, MII_RT, UART, etc. Each sub-module will be driven
> by it's own driver.
> 
> This PRUSS platform driver deals with the overall PRUSS and is
> used for managing the subsystem level resources like various
> memories and common CFG module. It is responsible for the
> creation and deletion of the platform devices for the child PRU
> devices and the various sub-modules.
> 
> This design provides flexibility in representing the different
> modules of PRUSS accordingly, and at the same time allowing the
> PRUSS driver to add some instance specific configuration within
> an SoC.
> 
> pruss_get() and pruss_put() APIs allow client drivers to request
> the 'struct pruss) device handle from the 'struct rproc' handle

                   ) -> '

> for the respective PRU. This handle will be used by client drivers
> to request various operations of the PRUSS platform driver through
> below APIs.
> 
> pruss_request_mem_region() & pruss_release_mem_region() allow
> client drivers to acquire and release the common memory resources
> present within a PRU-ICSS subsystem. This allows the client drivers
> to directly manipulate the respective memories,
> as per their design contract with the associated firmware.
> 
> pruss_cfg_read() and pruss_cfg_update() allow other drivers to read
> and update the registers in the CFG submodule within the PRUSS.
> This interface provides a simple way for client drivers
> without having them to include and parse these syscon nodes within
> their respective device nodes.
> 
> pruss_cfg_miirt_enable() and pruss_cfg_xfr_enable() allow the
> client drivers to set MII_RT event enable/disable and
> XFR (XIN XOUT) enable/disable respectively.
> 
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Signed-off-by: Andrew F. Davis <afd@ti.com>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/soc/ti/Kconfig  |  12 ++
>  drivers/soc/ti/Makefile |   1 +
>  drivers/soc/ti/pruss.c  | 347 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pruss.h   | 211 +++++++++++++++++++++++++++++
>  4 files changed, 571 insertions(+)
>  create mode 100644 drivers/soc/ti/pruss.c
>  create mode 100644 include/linux/pruss.h
> 
> diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
> index be4570b..789f2a8 100644
> --- a/drivers/soc/ti/Kconfig
> +++ b/drivers/soc/ti/Kconfig
> @@ -73,4 +73,16 @@ config TI_SCI_PM_DOMAINS
>  	  called ti_sci_pm_domains. Note this is needed early in boot before
>  	  rootfs may be available.
>  
> +config TI_PRUSS
> +	tristate "TI PRU-ICSS Subsystem Platform drivers"
> +	depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX
> +	select MFD_SYSCON
> +	default n
> +	help
> +	  TI PRU-ICSS Subsystem platform specific support.
> +
> +	  Say Y or M here to support the Programmable Realtime Unit (PRU)
> +	  processors on various TI SoCs. It's safe to say N here if you're
> +	  not interested in the PRU or if you are unsure.
> +
>  endif # SOC_TI
> diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
> index a22edc0..55b4b04 100644
> --- a/drivers/soc/ti/Makefile
> +++ b/drivers/soc/ti/Makefile
> @@ -8,3 +8,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA)	+= knav_dma.o
>  obj-$(CONFIG_AMX3_PM)			+= pm33xx.o
>  obj-$(CONFIG_WKUP_M3_IPC)		+= wkup_m3_ipc.o
>  obj-$(CONFIG_TI_SCI_PM_DOMAINS)		+= ti_sci_pm_domains.o
> +obj-$(CONFIG_TI_PRUSS)			+= pruss.o
> diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
> new file mode 100644
> index 0000000..c9493983
> --- /dev/null
> +++ b/drivers/soc/ti/pruss.c
> @@ -0,0 +1,347 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * PRU-ICSS platform driver for various TI SoCs
> + *
> + * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
> + *	Suman Anna <s-anna@ti.com>
> + *	Andrew F. Davis <afd@ti.com>
> + */
> +
> +#include <linux/dma-mapping.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/pruss.h>
> +#include <linux/regmap.h>
> +#include <linux/remoteproc.h>
> +
> +/**
> + * struct pruss - PRUSS parent structure
> + * @dev: pruss device pointer
> + * @cfg: regmap for config region
> + * @mem_regions: data for each of the PRUSS memory regions
> + * @mem_in_use: to indicate if memory resource is in use
> + * @no_shared_ram: indicate that shared RAM is absent
> + * @lock: mutex to serialize access to resources
> + */
> +struct pruss {
> +	struct device *dev;
> +	struct regmap *cfg;
> +	struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
> +	struct pruss_mem_region *mem_in_use[PRUSS_MEM_MAX];
> +	bool no_shared_ram;
> +	struct mutex lock; /* PRU resource lock */
> +};
> +
> +/**
> + * pruss_get() - get the pruss for a given PRU remoteproc
> + * @rproc: remoteproc handle of a PRU instance
> + *
> + * Finds the parent pruss device for a PRU given the @rproc handle of the
> + * PRU remote processor. This function increments the pruss device's refcount,
> + * so always use pruss_put() to decrement it back once pruss isn't needed
> + * anymore.
> + *
> + * Returns the pruss handle on success, and an ERR_PTR on failure using one
> + * of the following error values
> + *    -EINVAL if invalid parameter
> + *    -ENODEV if PRU device or PRUSS device is not found
> + */
> +struct pruss *pruss_get(struct rproc *rproc)
> +{
> +	struct pruss *pruss;
> +	struct device *dev;
> +	struct platform_device *ppdev;
> +
> +	if (IS_ERR(rproc))
> +		return ERR_PTR(-EINVAL);
> +
> +	dev = &rproc->dev;
> +	if (!dev->parent)
> +		return ERR_PTR(-ENODEV);
> +
> +	/* rudimentary check to make sure rproc handle is for a PRU */
> +	if (!strstr(dev_name(dev->parent), "pru"))
> +		return ERR_PTR(-ENODEV);
> +
> +	ppdev = to_platform_device(dev->parent->parent);
> +	pruss = platform_get_drvdata(ppdev);
> +	if (pruss)
> +		get_device(pruss->dev);
> +
> +	return pruss ? pruss : ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL_GPL(pruss_get);
> +
> +/**
> + * pruss_put() - decrement pruss device's usecount
> + * @pruss: pruss handle
> + *
> + * Complimentary function for pruss_get(). Needs to be called
> + * after the PRUSS is used, and only if the pruss_get() succeeds.
> + */
> +void pruss_put(struct pruss *pruss)
> +{
> +	if (IS_ERR(pruss))
> +		return;
> +
> +	put_device(pruss->dev);
> +}
> +EXPORT_SYMBOL_GPL(pruss_put);
> +
> +/**
> + * pruss_request_mem_region() - request a memory resource
> + * @pruss: the pruss instance
> + * @mem_id: the memory resource id
> + * @region: pointer to memory region structure to be filled in
> + *
> + * This function allows a client driver to request a memory resource,
> + * and if successful, will let the client driver own the particular
> + * memory region until released using the pruss_release_mem_region()
> + * API.
> + *
> + * Returns the memory region if requested resource is available, an
> + * error otherwise
> + */
> +int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id,
> +			     struct pruss_mem_region *region)
> +{
> +	if (IS_ERR(pruss) || !region)
> +		return -EINVAL;
> +
> +	if (mem_id >= PRUSS_MEM_MAX)
> +		return -EINVAL;
> +
> +	mutex_lock(&pruss->lock);
> +
> +	if (pruss->mem_in_use[mem_id]) {
> +		mutex_unlock(&pruss->lock);
> +		return -EBUSY;
> +	}
> +
> +	*region = pruss->mem_regions[mem_id];
> +	pruss->mem_in_use[mem_id] = region;
> +
> +	mutex_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_request_mem_region);
> +
> +/**
> + * pruss_release_mem_region() - release a memory resource
> + * @pruss: the pruss instance
> + * @region: the memory region to release
> + *
> + * This function is the complimentary function to
> + * pruss_request_mem_region(), and allows the client drivers to
> + * release back a memory resource.
> + *
> + * Returns 0 on success, an error code otherwise
> + */
> +int pruss_release_mem_region(struct pruss *pruss,
> +			     struct pruss_mem_region *region)
> +{
> +	int id;
> +
> +	if (IS_ERR(pruss) || !region)
> +		return -EINVAL;
> +
> +	mutex_lock(&pruss->lock);
> +
> +	/* find out the memory region being released */
> +	for (id = 0; id < PRUSS_MEM_MAX; id++) {
> +		if (pruss->mem_in_use[id] == region)
> +			break;
> +	}
> +
> +	if (id == PRUSS_MEM_MAX) {
> +		mutex_unlock(&pruss->lock);
> +		return -EINVAL;
> +	}
> +
> +	pruss->mem_in_use[id] = NULL;
> +
> +	mutex_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_release_mem_region);
> +
> +/**
> + * pruss_cfg_read() - read a PRUSS CFG register
> + * @pruss: the pruss instance handle
> + * @reg: register offset within the CFG sub-module
> + * @val: pointer to return the value in
> + *
> + * Reads a given register within CFG module of PRUSS
> + * and returns it through the passed-in @val pointer
> + *
> + * Returns 0 on success, or an error code otherwise
> + */
> +int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val)
> +{
> +	if (IS_ERR(pruss))
> +		return -EINVAL;
> +
> +	return regmap_read(pruss->cfg, reg, val);
> +}
> +EXPORT_SYMBOL_GPL(pruss_cfg_read);
> +
> +/**
> + * pruss_cfg_update() - update a PRUSS CFG register
> + * @pruss: the pruss instance handle
> + * @reg: register offset within the CFG sub-module
> + * @mask: bit mask to use for programming the @val
> + * @val: value to write
> + *
> + * Updates a given register within CFG sub-module of PRUSS
> + *
> + * Returns 0 on success, or an error code otherwise
> + */
> +int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
> +		     unsigned int mask, unsigned int val)
> +{
> +	if (IS_ERR(pruss))
> +		return -EINVAL;
> +
> +	return regmap_update_bits(pruss->cfg, reg, mask, val);
> +}
> +EXPORT_SYMBOL_GPL(pruss_cfg_update);
> +
> +/**
> + * struct pruss_match_private_data - private data to handle multiple instances
> + * @device_name: device name of the PRUSS instance
> + * @priv_data: PRUSS driver private data for this PRUSS instance
> + */
> +struct pruss_match_private_data {
> +	const char *device_name;
> +	const struct pruss_private_data *priv_data;
> +};
> +
> +static const
> +struct pruss_private_data *pruss_get_private_data(struct platform_device *pdev)
> +{
> +	const struct pruss_match_private_data *data;
> +
> +	if (!of_device_is_compatible(pdev->dev.of_node, "ti,am4376-pruss"))
> +		return NULL;

Been a while since I worked with all this, so refresh my memory, this
was only so we could pull in the "shared RAM only on one PRUSS instance
on am4376" quirk, right? If so it looks like this is now done with a DT
flag. All this private_data stuff can now be dropped.

> +
> +	data = of_device_get_match_data(&pdev->dev);
> +	for (; data && data->device_name; data++) {
> +		if (!strcmp(dev_name(&pdev->dev), data->device_name))
> +			return data->priv_data;
> +	}
> +
> +	return ERR_PTR(-ENODEV);
> +}
> +
> +static int pruss_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *node = dev->of_node;
> +	struct device_node *np;
> +	struct pruss *pruss;
> +	struct resource *res;
> +	int ret, i;
> +	const struct pruss_private_data *data;
> +	const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
> +
> +	if (!node) {
> +		dev_err(dev, "Non-DT platform device not supported\n");
> +		return -ENODEV;
> +	}
> +
> +	data = pruss_get_private_data(pdev);
> +	if (IS_ERR(data)) {
> +		dev_err(dev, "missing private data\n");
> +		return -ENODEV;
> +	}

Above gets dropped.

> +
> +	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
> +	if (ret) {
> +		dev_err(dev, "dma_set_coherent_mask: %d\n", ret);
> +		return ret;
> +	}
> +
> +	pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
> +	if (!pruss)
> +		return -ENOMEM;
> +
> +	pruss->dev = dev;
> +	mutex_init(&pruss->lock);
> +
> +	pruss->no_shared_ram = of_property_read_bool(node, "no-shared-ram");
> +
> +	np = of_get_child_by_name(node, "cfg");
> +	if (!np)
> +		return -ENODEV;
> +
> +	pruss->cfg = syscon_node_to_regmap(np);
> +	of_node_put(np);
> +	if (IS_ERR(pruss->cfg))
> +		return -ENODEV;
> +
> +	for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
> +		if (pruss->no_shared_ram && !strcmp(mem_names[i], "shrdram2"))
> +			continue;
> +
> +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> +						   mem_names[i]);
> +		pruss->mem_regions[i].va = devm_ioremap_resource(dev, res);
> +		if (!pruss->mem_regions[i].va) {
> +			dev_err(dev, "failed to get resource: %s\n",
> +				mem_names[i]);
> +			return -ENODEV;
> +		}
> +		pruss->mem_regions[i].pa = res->start;
> +		pruss->mem_regions[i].size = resource_size(res);
> +
> +		dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %p\n",
> +			mem_names[i], &pruss->mem_regions[i].pa,
> +			pruss->mem_regions[i].size, pruss->mem_regions[i].va);
> +	}
> +
> +	platform_set_drvdata(pdev, pruss);
> +
> +	dev_info(&pdev->dev, "creating PRU cores and other child platform devices\n");
> +	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
> +	if (ret)
> +		dev_err(dev, "of_platform_populate failed\n");
> +
> +	return ret;
> +}
> +
> +static int pruss_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	dev_info(dev, "remove PRU cores and other child platform devices\n");
> +	of_platform_depopulate(dev);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id pruss_of_match[] = {
> +	{ .compatible = "ti,am3356-pruss", },
> +	{ .compatible = "ti,am4376-pruss", },
> +	{ .compatible = "ti,am5728-pruss", },

ti,k2g-pruss ?

Andrew

> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, pruss_of_match);
> +
> +static struct platform_driver pruss_driver = {
> +	.driver = {
> +		.name = "pruss",
> +		.of_match_table = pruss_of_match,
> +	},
> +	.probe  = pruss_probe,
> +	.remove = pruss_remove,
> +};
> +module_platform_driver(pruss_driver);
> +
> +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
> +MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/pruss.h b/include/linux/pruss.h
> new file mode 100644
> index 0000000..b236b30
> --- /dev/null
> +++ b/include/linux/pruss.h
> @@ -0,0 +1,211 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/**
> + * PRU-ICSS Subsystem user interfaces
> + *
> + * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com
> + *	Suman Anna <s-anna@ti.com>
> + *	Tero Kristo <t-kristo@ti.com>
> + */
> +
> +#ifndef __LINUX_PRUSS_H
> +#define __LINUX_PRUSS_H
> +
> +/*
> + * PRU_ICSS_CFG registers
> + * SYSCFG, ISRP, ISP, IESP, IECP, SCRP applicable on AMxxxx devices only
> + */
> +#define PRUSS_CFG_REVID		0x00
> +#define PRUSS_CFG_SYSCFG	0x04
> +#define PRUSS_CFG_GPCFG(x)	(0x08 + (x) * 4)
> +#define PRUSS_CFG_CGR		0x10
> +#define PRUSS_CFG_ISRP		0x14
> +#define PRUSS_CFG_ISP		0x18
> +#define PRUSS_CFG_IESP		0x1C
> +#define PRUSS_CFG_IECP		0x20
> +#define PRUSS_CFG_SCRP		0x24
> +#define PRUSS_CFG_PMAO		0x28
> +#define PRUSS_CFG_MII_RT	0x2C
> +#define PRUSS_CFG_IEPCLK	0x30
> +#define PRUSS_CFG_SPP		0x34
> +#define PRUSS_CFG_PIN_MX	0x40
> +
> +/* PRUSS_GPCFG register bits */
> +#define PRUSS_GPCFG_PRU_GPO_SH_SEL		BIT(25)
> +
> +#define PRUSS_GPCFG_PRU_DIV1_SHIFT		20
> +#define PRUSS_GPCFG_PRU_DIV1_MASK		GENMASK(24, 20)
> +
> +#define PRUSS_GPCFG_PRU_DIV0_SHIFT		15
> +#define PRUSS_GPCFG_PRU_DIV0_MASK		GENMASK(15, 19)
> +
> +#define PRUSS_GPCFG_PRU_GPO_MODE		BIT(14)
> +#define PRUSS_GPCFG_PRU_GPO_MODE_DIRECT		0
> +#define PRUSS_GPCFG_PRU_GPO_MODE_SERIAL		BIT(14)
> +
> +#define PRUSS_GPCFG_PRU_GPI_SB			BIT(13)
> +
> +#define PRUSS_GPCFG_PRU_GPI_DIV1_SHIFT		8
> +#define PRUSS_GPCFG_PRU_GPI_DIV1_MASK		GENMASK(12, 8)
> +
> +#define PRUSS_GPCFG_PRU_GPI_DIV0_SHIFT		3
> +#define PRUSS_GPCFG_PRU_GPI_DIV0_MASK		GENMASK(7, 3)
> +
> +#define PRUSS_GPCFG_PRU_GPI_CLK_MODE_POSITIVE	0
> +#define PRUSS_GPCFG_PRU_GPI_CLK_MODE_NEGATIVE	BIT(2)
> +#define PRUSS_GPCFG_PRU_GPI_CLK_MODE		BIT(2)
> +
> +#define PRUSS_GPCFG_PRU_GPI_MODE_MASK		GENMASK(1, 0)
> +#define PRUSS_GPCFG_PRU_GPI_MODE_SHIFT		0
> +
> +#define PRUSS_GPCFG_PRU_MUX_SEL_SHIFT		26
> +#define PRUSS_GPCFG_PRU_MUX_SEL_MASK		GENMASK(29, 26)
> +
> +/* PRUSS_MII_RT register bits */
> +#define PRUSS_MII_RT_EVENT_EN			BIT(0)
> +
> +/* PRUSS_SPP register bits */
> +#define PRUSS_SPP_XFER_SHIFT_EN			BIT(1)
> +#define PRUSS_SPP_PRU1_PAD_HP_EN		BIT(0)
> +
> +/**
> + * enum pruss_gp_mux_sel - PRUSS GPI/O Mux modes for the
> + * PRUSS_GPCFG0/1 registers
> + *
> + * NOTE: The below defines are the most common values, but there
> + * are some exceptions like on 66AK2G, where the RESERVED and MII2
> + * values are interchanged. Also, this bit-field does not exist on
> + * AM335x SoCs
> + */
> +enum pruss_gp_mux_sel {
> +	PRUSS_GP_MUX_SEL_GP = 0,
> +	PRUSS_GP_MUX_SEL_ENDAT,
> +	PRUSS_GP_MUX_SEL_RESERVED,
> +	PRUSS_GP_MUX_SEL_SD,
> +	PRUSS_GP_MUX_SEL_MII2,
> +	PRUSS_GP_MUX_SEL_MAX,
> +};
> +
> +/**
> + * enum pruss_gpi_mode - PRUSS GPI configuration modes, used
> + *			 to program the PRUSS_GPCFG0/1 registers
> + */
> +enum pruss_gpi_mode {
> +	PRUSS_GPI_MODE_DIRECT = 0,
> +	PRUSS_GPI_MODE_PARALLEL,
> +	PRUSS_GPI_MODE_28BIT_SHIFT,
> +	PRUSS_GPI_MODE_MII,
> +};
> +
> +/**
> + * enum pruss_mem - PRUSS memory range identifiers
> + */
> +enum pruss_mem {
> +	PRUSS_MEM_DRAM0 = 0,
> +	PRUSS_MEM_DRAM1,
> +	PRUSS_MEM_SHRD_RAM2,
> +	PRUSS_MEM_MAX,
> +};
> +
> +/**
> + * struct pruss_mem_region - PRUSS memory region structure
> + * @va: kernel virtual address of the PRUSS memory region
> + * @pa: physical (bus) address of the PRUSS memory region
> + * @size: size of the PRUSS memory region
> + */
> +struct pruss_mem_region {
> +	void __iomem *va;
> +	phys_addr_t pa;
> +	size_t size;
> +};
> +
> +struct pruss;
> +struct rproc;
> +
> +#if IS_ENABLED(CONFIG_TI_PRUSS)
> +
> +struct pruss *pruss_get(struct rproc *rproc);
> +void pruss_put(struct pruss *pruss);
> +
> +int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id,
> +			     struct pruss_mem_region *region);
> +int pruss_release_mem_region(struct pruss *pruss,
> +			     struct pruss_mem_region *region);
> +
> +int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val);
> +int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
> +		     unsigned int mask, unsigned int val);
> +
> +/**
> + * pruss_cfg_miirt_enable() - Enable/disable MII RT Events
> + * @pruss: the pruss instance
> + * @enable: enable/disable
> + *
> + * Enable/disable the MII RT Events for the PRUSS.
> + */
> +static inline int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable)
> +{
> +	u32 set = enable ? PRUSS_MII_RT_EVENT_EN : 0;
> +
> +	return pruss_cfg_update(pruss, PRUSS_CFG_MII_RT,
> +				PRUSS_MII_RT_EVENT_EN, set);
> +}
> +
> +/**
> + * pruss_cfg_xfr_enable() - Enable/disable XIN XOUT shift functionality
> + * @pruss: the pruss instance
> + * @enable: enable/disable
> + */
> +static inline int pruss_cfg_xfr_enable(struct pruss *pruss, bool enable)
> +{
> +	u32 set = enable ? PRUSS_SPP_XFER_SHIFT_EN : 0;
> +
> +	return pruss_cfg_update(pruss, PRUSS_CFG_SPP,
> +				PRUSS_SPP_XFER_SHIFT_EN, set);
> +}
> +#else
> +
> +static inline struct pruss *pruss_get(struct rproc *rproc)
> +{
> +	return ERR_PTR(-ENOTSUPP);
> +}
> +
> +static inline void pruss_put(struct pruss *pruss) { }
> +
> +static inline int pruss_request_mem_region(struct pruss *pruss,
> +					   enum pruss_mem mem_id,
> +					   struct pruss_mem_region *region)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int pruss_release_mem_region(struct pruss *pruss,
> +					   struct pruss_mem_region *region)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int pruss_cfg_read(struct pruss *pruss, unsigned int reg,
> +				 unsigned int *val)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
> +				   unsigned int mask, unsigned int val)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int pruss_cfg_xfr_enable(struct pruss *pruss, bool enable)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +#endif /* CONFIG_TI_PRUSS */
> +
> +#endif /* __LINUX_PRUSS_H */
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-04 14:22 ` [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip " Roger Quadros
@ 2019-02-04 15:11   ` Andrew F. Davis
  2019-02-04 15:33     ` Roger Quadros
  2019-02-04 18:15   ` Tony Lindgren
  1 sibling, 1 reply; 61+ messages in thread
From: Andrew F. Davis @ 2019-02-04 15:11 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, Thomas Gleixner, Jason Cooper,
	Marc Zyngier

On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: "Andrew F. Davis" <afd@ti.com>
> 

[...]

> +static const struct pruss_intc_match_data am437x_pruss_intc_data = {
> +	.no_host7_intr = true,

Like done for the PRUSS driver with 'has_no_sharedram' becoming a DT
flag the same could be done here, then all this match data stuff could
be dropped.

> +};
> +
> +static const struct of_device_id pruss_intc_of_match[] = {
> +	{
> +		.compatible = "ti,am3356-pruss-intc",
> +		.data = NULL,
> +	},
> +	{
> +		.compatible = "ti,am4376-pruss-intc",
> +		.data = &am437x_pruss_intc_data,
> +	},
> +	{
> +		.compatible = "ti,am5728-pruss-intc",
> +		.data = NULL,
> +	},
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
> +
> +static struct platform_driver pruss_intc_driver = {
> +	.driver = {
> +		.name = "pruss-intc",
> +		.of_match_table = pruss_intc_of_match,
> +	},
> +	.probe  = pruss_intc_probe,
> +	.remove = pruss_intc_remove,
> +};
> +module_platform_driver(pruss_intc_driver);
> +
> +MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
> +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
> +MODULE_DESCRIPTION("PRU-ICSS INTC Driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h
> new file mode 100644
> index 0000000..4538a0b
> --- /dev/null
> +++ b/include/linux/irqchip/irq-pruss-intc.h
> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/**
> + * irq-pruss-intc.h - PRU-ICSS INTC management

Filename not needed.

Andrew

> + *
> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
> + */
> +
> +#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
> +#define __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
> +
> +/* maximum number of system events */
> +#define MAX_PRU_SYS_EVENTS	64
> +
> +/* maximum number of interrupt channels */
> +#define MAX_PRU_CHANNELS	10
> +
> +/**
> + * struct pruss_intc_config - INTC configuration info
> + * @sysev_to_ch: system events to channel mapping information
> + * @ch_to_host: interrupt channel to host interrupt information
> + */
> +struct pruss_intc_config {
> +	s8 sysev_to_ch[MAX_PRU_SYS_EVENTS];
> +	s8 ch_to_host[MAX_PRU_CHANNELS];
> +};
> +
> +#if IS_ENABLED(CONFIG_TI_PRUSS)
> +
> +/**
> + * pruss_intc_configure() - configure the PRUSS INTC
> + * @dev: device
> + * @intc_config: PRU core-specific INTC configuration
> + *
> + * Configures the PRUSS INTC with the provided configuration from
> + * a PRU core. Any existing event to channel mappings or channel to
> + * host interrupt mappings are checked to make sure there are no
> + * conflicting configuration between both the PRU cores. The function
> + * is intended to be used only by the PRU remoteproc driver.
> + *
> + * Returns 0 on success, or a suitable error code otherwise
> + */
> +int pruss_intc_configure(struct device *dev,
> +			 struct pruss_intc_config *intc_config);
> +
> +/**
> + * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
> + * @dev: device
> + * @intc_config: PRU core specific INTC configuration
> + *
> + * Undo whatever was done in pruss_intc_configure() for a PRU core.
> + * It should be sufficient to just mark the resources free in the
> + * global map and disable the host interrupts and sysevents.
> + */
> +int pruss_intc_unconfigure(struct device *dev,
> +			   struct pruss_intc_config *intc_config);
> +/**
> + * pruss_intc_trigger() - trigger a PRU system event
> + * @irq: linux IRQ number associated with a PRU system event
> + *
> + * Trigger an interrupt by signalling a specific PRU system event.
> + * This can be used by PRUSS client users to raise/send an event to
> + * a PRU or any other core that is listening on the host interrupt
> + * mapped to that specific PRU system event. The @irq variable is the
> + * Linux IRQ number associated with a specific PRU system event that
> + * a client user/application uses. The interrupt mappings for this is
> + * provided by the PRUSS INTC irqchip instance.
> + *
> + * Returns 0 on success, or an error value upon failure.
> + */
> +int pruss_intc_trigger(unsigned int irq);
> +
> +#else
> +
> +static inline int pruss_intc_configure(struct device *dev,
> +				       struct pruss_intc_config *intc_config)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int pruss_intc_unconfigure(struct device *dev,
> +					 struct pruss_intc_config *intc_config)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int pruss_intc_trigger(unsigned int irq)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +#endif	/* CONFIG_TI_PRUSS */
> +
> +#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H */
> +
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader
  2019-02-04 14:22 ` [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader Roger Quadros
@ 2019-02-04 15:19   ` Andrew F. Davis
  2019-02-14  2:22     ` Suman Anna
  0 siblings, 1 reply; 61+ messages in thread
From: Andrew F. Davis @ 2019-02-04 15:19 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree

On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: David Lechner <david@lechnology.com>
> 
> This adds a special handler to the default remoteproc ELF firmware
> loader that looks up the memory map on TI PRU firmware files.
> 
> These processors have multiple memory maps that share the same address
> space, so we need to know the page in addition to the physical address
> in order to translate the address to a local CPU address.
> 
> Signed-off-by: David Lechner <david@lechnology.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/remoteproc/remoteproc_elf_loader.c | 117 +++++++++++++++++++++++++++--
>  include/uapi/linux/elf-em.h                |   1 +
>  2 files changed, 112 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 8888d39..79c9d39 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -32,6 +32,103 @@
>  
>  #include "remoteproc_internal.h"
>  
> +#define SHT_TI_PHATTRS 0x7F000004
> +#define SHT_TI_SH_PAGE 0x7F000007
> +
> +struct elf32_ti_phattrs {
> +	Elf32_Half pha_seg_id; /* Segment id */
> +	Elf32_Half pha_tag_id; /* Attribute kind id */
> +	union {
> +		Elf32_Off pha_offset; /* byte offset within the section */
> +		Elf32_Word pha_value; /* Constant tag value */
> +	} pha_un;
> +};
> +
> +/* this struct is reverse engineered, so not sure what most of the values are */

Do we really not know? Someone should go check this, if they are not
used then for now label them "unused", not "unknown".

Andrew

> +struct ti_section_page {
> +	u32 unk0;
> +	u32 unk1;
> +	u32 unk2;
> +	u32 unk3;
> +	u32 unk4;
> +	u16 size;
> +	u16 unk5;
> +	u16 unk6;
> +	u8 data[0]; /* array of size */
> +};
> +
> +/**
> + * rproc_elf_segment_to_map() - Gets memory map for segment
> + * @id: segment id
> + * @elf_data: pointer to ELF file data
> + *
> + * Returns the memory map for the segment.
> + */
> +static int rproc_elf_segment_to_map(u32 id, const u8 *elf_data)
> +{
> +	struct elf32_hdr *ehdr;
> +	struct elf32_shdr *shdr;
> +	struct elf32_ti_phattrs *ti_attrs = NULL;
> +	int i;
> +
> +	ehdr = (struct elf32_hdr *)elf_data;
> +	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> +
> +	if (ehdr->e_machine != EM_TI_PRU)
> +		return 0;
> +
> +	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> +		if (shdr->sh_type == SHT_TI_PHATTRS) {
> +			ti_attrs = (struct elf32_ti_phattrs *)(elf_data + shdr->sh_offset);
> +			break;
> +		}
> +	}
> +
> +	if (!ti_attrs)
> +		return 0;
> +
> +	/* list is terminated by tag id == 0 (PHA_NULL) */
> +	for (; ti_attrs->pha_tag_id; ti_attrs++) {
> +		if (ti_attrs->pha_tag_id == 3 && ti_attrs->pha_seg_id == id)
> +			return ti_attrs->pha_un.pha_value;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * rproc_elf_section_to_map() - Gets memory map for section
> + * @id: segment id
> + * @elf_data: pointer to ELF file data
> + *
> + * Returns the memory map for the section.
> + */
> +static int rproc_elf_section_to_map(u32 id, const u8 *elf_data)
> +{
> +	struct elf32_hdr *ehdr;
> +	struct elf32_shdr *shdr;
> +	struct ti_section_page *map = NULL;
> +	int i;
> +
> +	ehdr = (struct elf32_hdr *)elf_data;
> +	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> +
> +	if (ehdr->e_machine != EM_TI_PRU)
> +		return 0;
> +
> +	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> +		if (shdr->sh_type == SHT_TI_SH_PAGE) {
> +			map = (struct ti_section_page *)(elf_data + shdr->sh_offset);
> +			break;
> +		}
> +	}
> +
> +	if (!map || id >= map->size)
> +		return 0;
> +
> +	return map->data[id];
> +}
> +
>  /**
>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>   * @rproc: the remote processor handle
> @@ -147,7 +244,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  	struct device *dev = &rproc->dev;
>  	struct elf32_hdr *ehdr;
>  	struct elf32_phdr *phdr;
> -	int i, ret = 0;
> +	int i, map, ret = 0;
>  	const u8 *elf_data = fw->data;
>  
>  	ehdr = (struct elf32_hdr *)elf_data;
> @@ -181,8 +278,10 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  			break;
>  		}
>  
> +		map = rproc_elf_segment_to_map(i, elf_data);
> +
>  		/* grab the kernel address for this device address */
> -		ptr = rproc_da_to_va(rproc, da, memsz, 0);
> +		ptr = rproc_da_to_va(rproc, da, memsz, map);
>  		if (!ptr) {
>  			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>  			ret = -EINVAL;
> @@ -209,7 +308,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  EXPORT_SYMBOL(rproc_elf_load_segments);
>  
>  static struct elf32_shdr *
> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> +find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size, int *id)
>  {
>  	struct elf32_shdr *shdr;
>  	int i;
> @@ -261,6 +360,9 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>  			return NULL;
>  		}
>  
> +		if (id)
> +			*id = i;
> +
>  		return shdr;
>  	}
>  
> @@ -288,7 +390,7 @@ int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>  
>  	ehdr = (struct elf32_hdr *)elf_data;
>  
> -	shdr = find_table(dev, ehdr, fw->size);
> +	shdr = find_table(dev, ehdr, fw->size, NULL);
>  	if (!shdr)
>  		return -EINVAL;
>  
> @@ -328,11 +430,14 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>  {
>  	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>  	struct elf32_shdr *shdr;
> +	int id, map;
>  
> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> +	shdr = find_table(&rproc->dev, ehdr, fw->size, &id);
>  	if (!shdr)
>  		return NULL;
>  
> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, 0);
> +	map = rproc_elf_section_to_map(id, fw->data);
> +
> +	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, map);
>  }
>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h
> index 0c3000fa..70b487a 100644
> --- a/include/uapi/linux/elf-em.h
> +++ b/include/uapi/linux/elf-em.h
> @@ -38,6 +38,7 @@
>  #define EM_BLACKFIN     106     /* ADI Blackfin Processor */
>  #define EM_ALTERA_NIOS2	113	/* Altera Nios II soft-core processor */
>  #define EM_TI_C6000	140	/* TI C6X DSPs */
> +#define EM_TI_PRU	144	/* TI Programmable Realtime Unit */
>  #define EM_AARCH64	183	/* ARM 64 bit */
>  #define EM_TILEPRO	188	/* Tilera TILEPro */
>  #define EM_MICROBLAZE	189	/* Xilinx MicroBlaze */
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 14/14] rpmsg: pru: add a PRU RPMsg driver
  2019-02-04 14:22 ` [PATCH v2 14/14] rpmsg: pru: add a PRU RPMsg driver Roger Quadros
@ 2019-02-04 15:26   ` Andrew F. Davis
  0 siblings, 0 replies; 61+ messages in thread
From: Andrew F. Davis @ 2019-02-04 15:26 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree

On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: Jason Reeder <jreeder@ti.com>
> 

[...]

> +/* .name matches on RPMsg Channels and causes a probe */
> +static const struct rpmsg_device_id rpmsg_driver_pru_id_table[] = {
> +	{ .name	= "rpmsg-pru" },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pru_id_table);
> +
> +static struct rpmsg_driver rpmsg_pru_driver = {
> +	.drv.name	= KBUILD_MODNAME,
> +	.id_table	= rpmsg_driver_pru_id_table,
> +	.probe		= rpmsg_pru_probe,
> +	.callback	= rpmsg_pru_cb,
> +	.remove		= rpmsg_pru_remove,
> +};
> +
> +static int __init rpmsg_pru_init(void)
> +{
> +	int ret;
> +
> +	rpmsg_pru_class = class_create(THIS_MODULE, "rpmsg_pru");
> +	if (IS_ERR(rpmsg_pru_class)) {
> +		pr_err("Unable to create class\n");
> +		ret = PTR_ERR(rpmsg_pru_class);
> +		goto fail_create_class;
> +	}
> +
> +	ret = alloc_chrdev_region(&rpmsg_pru_devt, 0, PRU_MAX_DEVICES,
> +				  "rpmsg_pru");
> +	if (ret) {
> +		pr_err("Unable to allocate chrdev region\n");
> +		goto fail_alloc_region;
> +	}
> +
> +	ret = register_rpmsg_driver(&rpmsg_pru_driver);
> +	if (ret) {
> +		pr_err("Unable to register rpmsg driver");
> +		goto fail_register_rpmsg_driver;
> +	}
> +
> +	return 0;
> +
> +fail_register_rpmsg_driver:
> +	unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES);
> +fail_alloc_region:
> +	class_destroy(rpmsg_pru_class);
> +fail_create_class:
> +	return ret;
> +}
> +
> +static void __exit rpmsg_pru_exit(void)
> +{
> +	unregister_rpmsg_driver(&rpmsg_pru_driver);
> +	idr_destroy(&rpmsg_pru_minors);
> +	mutex_destroy(&rpmsg_pru_lock);
> +	class_destroy(rpmsg_pru_class);
> +	unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES);
> +}
> +
> +module_init(rpmsg_pru_init);
> +module_exit(rpmsg_pru_exit);
> +
> +MODULE_AUTHOR("Jason Reeder <jreeder@ti.com>");
> +MODULE_ALIAS("rpmsg:rpmsg-pru");

MODULE_ALIAS not needed, MODULE_DEVICE_TABLE will generate the alias.

Andrew

> +MODULE_DESCRIPTION("PRU Remote Processor Messaging Driver");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs
  2019-02-04 14:52   ` Andrew F. Davis
@ 2019-02-04 15:32     ` Roger Quadros
  2019-02-04 16:35     ` Tony Lindgren
  1 sibling, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 15:32 UTC (permalink / raw)
  To: Andrew F. Davis, tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, Keerthy

On 04/02/19 16:52, Andrew F. Davis wrote:
> On 2/4/19 8:22 AM, Roger Quadros wrote:
>> From: Suman Anna <s-anna@ti.com>
>>
>> The Programmable Real-Time Unit - Industrial Communication
>> Subsystem (PRU-ICSS) is present on various TI SoCs such as
>> AM335x or AM437x or the Keystone 66AK2G. Each SoC can have
>> one or more PRUSS instances that may or may not be identical.
>> For example, AM335x SoCs have a single PRUSS, while AM437x has
>> two PRUSS instances PRUSS1 and PRUSS0, with the PRUSS0 being
>> a cut-down version of the PRUSS1.
>>
>> The PRUSS consists of dual 32-bit RISC cores called the
>> Programmable Real-Time Units (PRUs), with data and
>> instruction memories. It also contains various sub-modules
>> like MDIO, MII_RT, UART, etc. Each sub-module will be driven
>> by it's own driver.
>>
>> This PRUSS platform driver deals with the overall PRUSS and is
>> used for managing the subsystem level resources like various
>> memories and common CFG module. It is responsible for the
>> creation and deletion of the platform devices for the child PRU
>> devices and the various sub-modules.
>>
>> This design provides flexibility in representing the different
>> modules of PRUSS accordingly, and at the same time allowing the
>> PRUSS driver to add some instance specific configuration within
>> an SoC.
>>
>> pruss_get() and pruss_put() APIs allow client drivers to request
>> the 'struct pruss) device handle from the 'struct rproc' handle
> 
>                    ) -> '
> 
>> for the respective PRU. This handle will be used by client drivers
>> to request various operations of the PRUSS platform driver through
>> below APIs.
>>
>> pruss_request_mem_region() & pruss_release_mem_region() allow
>> client drivers to acquire and release the common memory resources
>> present within a PRU-ICSS subsystem. This allows the client drivers
>> to directly manipulate the respective memories,
>> as per their design contract with the associated firmware.
>>
>> pruss_cfg_read() and pruss_cfg_update() allow other drivers to read
>> and update the registers in the CFG submodule within the PRUSS.
>> This interface provides a simple way for client drivers
>> without having them to include and parse these syscon nodes within
>> their respective device nodes.
>>
>> pruss_cfg_miirt_enable() and pruss_cfg_xfr_enable() allow the
>> client drivers to set MII_RT event enable/disable and
>> XFR (XIN XOUT) enable/disable respectively.
>>
>> Signed-off-by: Suman Anna <s-anna@ti.com>
>> Signed-off-by: Keerthy <j-keerthy@ti.com>
>> Signed-off-by: Andrew F. Davis <afd@ti.com>
>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  drivers/soc/ti/Kconfig  |  12 ++
>>  drivers/soc/ti/Makefile |   1 +
>>  drivers/soc/ti/pruss.c  | 347 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pruss.h   | 211 +++++++++++++++++++++++++++++
>>  4 files changed, 571 insertions(+)
>>  create mode 100644 drivers/soc/ti/pruss.c
>>  create mode 100644 include/linux/pruss.h
>>
>> diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
>> index be4570b..789f2a8 100644
>> --- a/drivers/soc/ti/Kconfig
>> +++ b/drivers/soc/ti/Kconfig
>> @@ -73,4 +73,16 @@ config TI_SCI_PM_DOMAINS
>>  	  called ti_sci_pm_domains. Note this is needed early in boot before
>>  	  rootfs may be available.
>>  
>> +config TI_PRUSS
>> +	tristate "TI PRU-ICSS Subsystem Platform drivers"
>> +	depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX
>> +	select MFD_SYSCON
>> +	default n
>> +	help
>> +	  TI PRU-ICSS Subsystem platform specific support.
>> +
>> +	  Say Y or M here to support the Programmable Realtime Unit (PRU)
>> +	  processors on various TI SoCs. It's safe to say N here if you're
>> +	  not interested in the PRU or if you are unsure.
>> +
>>  endif # SOC_TI
>> diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
>> index a22edc0..55b4b04 100644
>> --- a/drivers/soc/ti/Makefile
>> +++ b/drivers/soc/ti/Makefile
>> @@ -8,3 +8,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA)	+= knav_dma.o
>>  obj-$(CONFIG_AMX3_PM)			+= pm33xx.o
>>  obj-$(CONFIG_WKUP_M3_IPC)		+= wkup_m3_ipc.o
>>  obj-$(CONFIG_TI_SCI_PM_DOMAINS)		+= ti_sci_pm_domains.o
>> +obj-$(CONFIG_TI_PRUSS)			+= pruss.o
>> diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
>> new file mode 100644
>> index 0000000..c9493983
>> --- /dev/null
>> +++ b/drivers/soc/ti/pruss.c
>> @@ -0,0 +1,347 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * PRU-ICSS platform driver for various TI SoCs
>> + *
>> + * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
>> + *	Suman Anna <s-anna@ti.com>
>> + *	Andrew F. Davis <afd@ti.com>
>> + */
>> +
>> +#include <linux/dma-mapping.h>
>> +#include <linux/module.h>
>> +#include <linux/io.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/pruss.h>
>> +#include <linux/regmap.h>
>> +#include <linux/remoteproc.h>
>> +
>> +/**
>> + * struct pruss - PRUSS parent structure
>> + * @dev: pruss device pointer
>> + * @cfg: regmap for config region
>> + * @mem_regions: data for each of the PRUSS memory regions
>> + * @mem_in_use: to indicate if memory resource is in use
>> + * @no_shared_ram: indicate that shared RAM is absent
>> + * @lock: mutex to serialize access to resources
>> + */
>> +struct pruss {
>> +	struct device *dev;
>> +	struct regmap *cfg;
>> +	struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
>> +	struct pruss_mem_region *mem_in_use[PRUSS_MEM_MAX];
>> +	bool no_shared_ram;
>> +	struct mutex lock; /* PRU resource lock */
>> +};
>> +
>> +/**
>> + * pruss_get() - get the pruss for a given PRU remoteproc
>> + * @rproc: remoteproc handle of a PRU instance
>> + *
>> + * Finds the parent pruss device for a PRU given the @rproc handle of the
>> + * PRU remote processor. This function increments the pruss device's refcount,
>> + * so always use pruss_put() to decrement it back once pruss isn't needed
>> + * anymore.
>> + *
>> + * Returns the pruss handle on success, and an ERR_PTR on failure using one
>> + * of the following error values
>> + *    -EINVAL if invalid parameter
>> + *    -ENODEV if PRU device or PRUSS device is not found
>> + */
>> +struct pruss *pruss_get(struct rproc *rproc)
>> +{
>> +	struct pruss *pruss;
>> +	struct device *dev;
>> +	struct platform_device *ppdev;
>> +
>> +	if (IS_ERR(rproc))
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	dev = &rproc->dev;
>> +	if (!dev->parent)
>> +		return ERR_PTR(-ENODEV);
>> +
>> +	/* rudimentary check to make sure rproc handle is for a PRU */
>> +	if (!strstr(dev_name(dev->parent), "pru"))
>> +		return ERR_PTR(-ENODEV);
>> +
>> +	ppdev = to_platform_device(dev->parent->parent);
>> +	pruss = platform_get_drvdata(ppdev);
>> +	if (pruss)
>> +		get_device(pruss->dev);
>> +
>> +	return pruss ? pruss : ERR_PTR(-ENODEV);
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_get);
>> +
>> +/**
>> + * pruss_put() - decrement pruss device's usecount
>> + * @pruss: pruss handle
>> + *
>> + * Complimentary function for pruss_get(). Needs to be called
>> + * after the PRUSS is used, and only if the pruss_get() succeeds.
>> + */
>> +void pruss_put(struct pruss *pruss)
>> +{
>> +	if (IS_ERR(pruss))
>> +		return;
>> +
>> +	put_device(pruss->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_put);
>> +
>> +/**
>> + * pruss_request_mem_region() - request a memory resource
>> + * @pruss: the pruss instance
>> + * @mem_id: the memory resource id
>> + * @region: pointer to memory region structure to be filled in
>> + *
>> + * This function allows a client driver to request a memory resource,
>> + * and if successful, will let the client driver own the particular
>> + * memory region until released using the pruss_release_mem_region()
>> + * API.
>> + *
>> + * Returns the memory region if requested resource is available, an
>> + * error otherwise
>> + */
>> +int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id,
>> +			     struct pruss_mem_region *region)
>> +{
>> +	if (IS_ERR(pruss) || !region)
>> +		return -EINVAL;
>> +
>> +	if (mem_id >= PRUSS_MEM_MAX)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&pruss->lock);
>> +
>> +	if (pruss->mem_in_use[mem_id]) {
>> +		mutex_unlock(&pruss->lock);
>> +		return -EBUSY;
>> +	}
>> +
>> +	*region = pruss->mem_regions[mem_id];
>> +	pruss->mem_in_use[mem_id] = region;
>> +
>> +	mutex_unlock(&pruss->lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_request_mem_region);
>> +
>> +/**
>> + * pruss_release_mem_region() - release a memory resource
>> + * @pruss: the pruss instance
>> + * @region: the memory region to release
>> + *
>> + * This function is the complimentary function to
>> + * pruss_request_mem_region(), and allows the client drivers to
>> + * release back a memory resource.
>> + *
>> + * Returns 0 on success, an error code otherwise
>> + */
>> +int pruss_release_mem_region(struct pruss *pruss,
>> +			     struct pruss_mem_region *region)
>> +{
>> +	int id;
>> +
>> +	if (IS_ERR(pruss) || !region)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&pruss->lock);
>> +
>> +	/* find out the memory region being released */
>> +	for (id = 0; id < PRUSS_MEM_MAX; id++) {
>> +		if (pruss->mem_in_use[id] == region)
>> +			break;
>> +	}
>> +
>> +	if (id == PRUSS_MEM_MAX) {
>> +		mutex_unlock(&pruss->lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	pruss->mem_in_use[id] = NULL;
>> +
>> +	mutex_unlock(&pruss->lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_release_mem_region);
>> +
>> +/**
>> + * pruss_cfg_read() - read a PRUSS CFG register
>> + * @pruss: the pruss instance handle
>> + * @reg: register offset within the CFG sub-module
>> + * @val: pointer to return the value in
>> + *
>> + * Reads a given register within CFG module of PRUSS
>> + * and returns it through the passed-in @val pointer
>> + *
>> + * Returns 0 on success, or an error code otherwise
>> + */
>> +int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val)
>> +{
>> +	if (IS_ERR(pruss))
>> +		return -EINVAL;
>> +
>> +	return regmap_read(pruss->cfg, reg, val);
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_cfg_read);
>> +
>> +/**
>> + * pruss_cfg_update() - update a PRUSS CFG register
>> + * @pruss: the pruss instance handle
>> + * @reg: register offset within the CFG sub-module
>> + * @mask: bit mask to use for programming the @val
>> + * @val: value to write
>> + *
>> + * Updates a given register within CFG sub-module of PRUSS
>> + *
>> + * Returns 0 on success, or an error code otherwise
>> + */
>> +int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
>> +		     unsigned int mask, unsigned int val)
>> +{
>> +	if (IS_ERR(pruss))
>> +		return -EINVAL;
>> +
>> +	return regmap_update_bits(pruss->cfg, reg, mask, val);
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_cfg_update);
>> +
>> +/**
>> + * struct pruss_match_private_data - private data to handle multiple instances
>> + * @device_name: device name of the PRUSS instance
>> + * @priv_data: PRUSS driver private data for this PRUSS instance
>> + */
>> +struct pruss_match_private_data {
>> +	const char *device_name;
>> +	const struct pruss_private_data *priv_data;
>> +};
>> +
>> +static const
>> +struct pruss_private_data *pruss_get_private_data(struct platform_device *pdev)
>> +{
>> +	const struct pruss_match_private_data *data;
>> +
>> +	if (!of_device_is_compatible(pdev->dev.of_node, "ti,am4376-pruss"))
>> +		return NULL;
> 
> Been a while since I worked with all this, so refresh my memory, this
> was only so we could pull in the "shared RAM only on one PRUSS instance
> on am4376" quirk, right? If so it looks like this is now done with a DT
> flag. All this private_data stuff can now be dropped.

Good catch.
> 
>> +
>> +	data = of_device_get_match_data(&pdev->dev);
>> +	for (; data && data->device_name; data++) {
>> +		if (!strcmp(dev_name(&pdev->dev), data->device_name))
>> +			return data->priv_data;
>> +	}
>> +
>> +	return ERR_PTR(-ENODEV);
>> +}
>> +
>> +static int pruss_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *node = dev->of_node;
>> +	struct device_node *np;
>> +	struct pruss *pruss;
>> +	struct resource *res;
>> +	int ret, i;
>> +	const struct pruss_private_data *data;
>> +	const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
>> +
>> +	if (!node) {
>> +		dev_err(dev, "Non-DT platform device not supported\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	data = pruss_get_private_data(pdev);
>> +	if (IS_ERR(data)) {
>> +		dev_err(dev, "missing private data\n");
>> +		return -ENODEV;
>> +	}
> 
> Above gets dropped.

Yes.

> 
>> +
>> +	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
>> +	if (ret) {
>> +		dev_err(dev, "dma_set_coherent_mask: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
>> +	if (!pruss)
>> +		return -ENOMEM;
>> +
>> +	pruss->dev = dev;
>> +	mutex_init(&pruss->lock);
>> +
>> +	pruss->no_shared_ram = of_property_read_bool(node, "no-shared-ram");
>> +
>> +	np = of_get_child_by_name(node, "cfg");
>> +	if (!np)
>> +		return -ENODEV;
>> +
>> +	pruss->cfg = syscon_node_to_regmap(np);
>> +	of_node_put(np);
>> +	if (IS_ERR(pruss->cfg))
>> +		return -ENODEV;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
>> +		if (pruss->no_shared_ram && !strcmp(mem_names[i], "shrdram2"))
>> +			continue;
>> +
>> +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>> +						   mem_names[i]);
>> +		pruss->mem_regions[i].va = devm_ioremap_resource(dev, res);
>> +		if (!pruss->mem_regions[i].va) {
>> +			dev_err(dev, "failed to get resource: %s\n",
>> +				mem_names[i]);
>> +			return -ENODEV;
>> +		}
>> +		pruss->mem_regions[i].pa = res->start;
>> +		pruss->mem_regions[i].size = resource_size(res);
>> +
>> +		dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %p\n",
>> +			mem_names[i], &pruss->mem_regions[i].pa,
>> +			pruss->mem_regions[i].size, pruss->mem_regions[i].va);
>> +	}
>> +
>> +	platform_set_drvdata(pdev, pruss);
>> +
>> +	dev_info(&pdev->dev, "creating PRU cores and other child platform devices\n");
>> +	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
>> +	if (ret)
>> +		dev_err(dev, "of_platform_populate failed\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int pruss_remove(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +
>> +	dev_info(dev, "remove PRU cores and other child platform devices\n");
>> +	of_platform_depopulate(dev);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id pruss_of_match[] = {
>> +	{ .compatible = "ti,am3356-pruss", },
>> +	{ .compatible = "ti,am4376-pruss", },
>> +	{ .compatible = "ti,am5728-pruss", },
> 
> ti,k2g-pruss ?

Will add.


cheers,
-roger

> 
> Andrew
> 
>> +	{ /* sentinel */ },
>> +};
>> +MODULE_DEVICE_TABLE(of, pruss_of_match);
>> +
>> +static struct platform_driver pruss_driver = {
>> +	.driver = {
>> +		.name = "pruss",
>> +		.of_match_table = pruss_of_match,
>> +	},
>> +	.probe  = pruss_probe,
>> +	.remove = pruss_remove,
>> +};
>> +module_platform_driver(pruss_driver);
>> +
>> +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
>> +MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/pruss.h b/include/linux/pruss.h
>> new file mode 100644
>> index 0000000..b236b30
>> --- /dev/null
>> +++ b/include/linux/pruss.h
>> @@ -0,0 +1,211 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/**
>> + * PRU-ICSS Subsystem user interfaces
>> + *
>> + * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com
>> + *	Suman Anna <s-anna@ti.com>
>> + *	Tero Kristo <t-kristo@ti.com>
>> + */
>> +
>> +#ifndef __LINUX_PRUSS_H
>> +#define __LINUX_PRUSS_H
>> +
>> +/*
>> + * PRU_ICSS_CFG registers
>> + * SYSCFG, ISRP, ISP, IESP, IECP, SCRP applicable on AMxxxx devices only
>> + */
>> +#define PRUSS_CFG_REVID		0x00
>> +#define PRUSS_CFG_SYSCFG	0x04
>> +#define PRUSS_CFG_GPCFG(x)	(0x08 + (x) * 4)
>> +#define PRUSS_CFG_CGR		0x10
>> +#define PRUSS_CFG_ISRP		0x14
>> +#define PRUSS_CFG_ISP		0x18
>> +#define PRUSS_CFG_IESP		0x1C
>> +#define PRUSS_CFG_IECP		0x20
>> +#define PRUSS_CFG_SCRP		0x24
>> +#define PRUSS_CFG_PMAO		0x28
>> +#define PRUSS_CFG_MII_RT	0x2C
>> +#define PRUSS_CFG_IEPCLK	0x30
>> +#define PRUSS_CFG_SPP		0x34
>> +#define PRUSS_CFG_PIN_MX	0x40
>> +
>> +/* PRUSS_GPCFG register bits */
>> +#define PRUSS_GPCFG_PRU_GPO_SH_SEL		BIT(25)
>> +
>> +#define PRUSS_GPCFG_PRU_DIV1_SHIFT		20
>> +#define PRUSS_GPCFG_PRU_DIV1_MASK		GENMASK(24, 20)
>> +
>> +#define PRUSS_GPCFG_PRU_DIV0_SHIFT		15
>> +#define PRUSS_GPCFG_PRU_DIV0_MASK		GENMASK(15, 19)
>> +
>> +#define PRUSS_GPCFG_PRU_GPO_MODE		BIT(14)
>> +#define PRUSS_GPCFG_PRU_GPO_MODE_DIRECT		0
>> +#define PRUSS_GPCFG_PRU_GPO_MODE_SERIAL		BIT(14)
>> +
>> +#define PRUSS_GPCFG_PRU_GPI_SB			BIT(13)
>> +
>> +#define PRUSS_GPCFG_PRU_GPI_DIV1_SHIFT		8
>> +#define PRUSS_GPCFG_PRU_GPI_DIV1_MASK		GENMASK(12, 8)
>> +
>> +#define PRUSS_GPCFG_PRU_GPI_DIV0_SHIFT		3
>> +#define PRUSS_GPCFG_PRU_GPI_DIV0_MASK		GENMASK(7, 3)
>> +
>> +#define PRUSS_GPCFG_PRU_GPI_CLK_MODE_POSITIVE	0
>> +#define PRUSS_GPCFG_PRU_GPI_CLK_MODE_NEGATIVE	BIT(2)
>> +#define PRUSS_GPCFG_PRU_GPI_CLK_MODE		BIT(2)
>> +
>> +#define PRUSS_GPCFG_PRU_GPI_MODE_MASK		GENMASK(1, 0)
>> +#define PRUSS_GPCFG_PRU_GPI_MODE_SHIFT		0
>> +
>> +#define PRUSS_GPCFG_PRU_MUX_SEL_SHIFT		26
>> +#define PRUSS_GPCFG_PRU_MUX_SEL_MASK		GENMASK(29, 26)
>> +
>> +/* PRUSS_MII_RT register bits */
>> +#define PRUSS_MII_RT_EVENT_EN			BIT(0)
>> +
>> +/* PRUSS_SPP register bits */
>> +#define PRUSS_SPP_XFER_SHIFT_EN			BIT(1)
>> +#define PRUSS_SPP_PRU1_PAD_HP_EN		BIT(0)
>> +
>> +/**
>> + * enum pruss_gp_mux_sel - PRUSS GPI/O Mux modes for the
>> + * PRUSS_GPCFG0/1 registers
>> + *
>> + * NOTE: The below defines are the most common values, but there
>> + * are some exceptions like on 66AK2G, where the RESERVED and MII2
>> + * values are interchanged. Also, this bit-field does not exist on
>> + * AM335x SoCs
>> + */
>> +enum pruss_gp_mux_sel {
>> +	PRUSS_GP_MUX_SEL_GP = 0,
>> +	PRUSS_GP_MUX_SEL_ENDAT,
>> +	PRUSS_GP_MUX_SEL_RESERVED,
>> +	PRUSS_GP_MUX_SEL_SD,
>> +	PRUSS_GP_MUX_SEL_MII2,
>> +	PRUSS_GP_MUX_SEL_MAX,
>> +};
>> +
>> +/**
>> + * enum pruss_gpi_mode - PRUSS GPI configuration modes, used
>> + *			 to program the PRUSS_GPCFG0/1 registers
>> + */
>> +enum pruss_gpi_mode {
>> +	PRUSS_GPI_MODE_DIRECT = 0,
>> +	PRUSS_GPI_MODE_PARALLEL,
>> +	PRUSS_GPI_MODE_28BIT_SHIFT,
>> +	PRUSS_GPI_MODE_MII,
>> +};
>> +
>> +/**
>> + * enum pruss_mem - PRUSS memory range identifiers
>> + */
>> +enum pruss_mem {
>> +	PRUSS_MEM_DRAM0 = 0,
>> +	PRUSS_MEM_DRAM1,
>> +	PRUSS_MEM_SHRD_RAM2,
>> +	PRUSS_MEM_MAX,
>> +};
>> +
>> +/**
>> + * struct pruss_mem_region - PRUSS memory region structure
>> + * @va: kernel virtual address of the PRUSS memory region
>> + * @pa: physical (bus) address of the PRUSS memory region
>> + * @size: size of the PRUSS memory region
>> + */
>> +struct pruss_mem_region {
>> +	void __iomem *va;
>> +	phys_addr_t pa;
>> +	size_t size;
>> +};
>> +
>> +struct pruss;
>> +struct rproc;
>> +
>> +#if IS_ENABLED(CONFIG_TI_PRUSS)
>> +
>> +struct pruss *pruss_get(struct rproc *rproc);
>> +void pruss_put(struct pruss *pruss);
>> +
>> +int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id,
>> +			     struct pruss_mem_region *region);
>> +int pruss_release_mem_region(struct pruss *pruss,
>> +			     struct pruss_mem_region *region);
>> +
>> +int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val);
>> +int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
>> +		     unsigned int mask, unsigned int val);
>> +
>> +/**
>> + * pruss_cfg_miirt_enable() - Enable/disable MII RT Events
>> + * @pruss: the pruss instance
>> + * @enable: enable/disable
>> + *
>> + * Enable/disable the MII RT Events for the PRUSS.
>> + */
>> +static inline int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable)
>> +{
>> +	u32 set = enable ? PRUSS_MII_RT_EVENT_EN : 0;
>> +
>> +	return pruss_cfg_update(pruss, PRUSS_CFG_MII_RT,
>> +				PRUSS_MII_RT_EVENT_EN, set);
>> +}
>> +
>> +/**
>> + * pruss_cfg_xfr_enable() - Enable/disable XIN XOUT shift functionality
>> + * @pruss: the pruss instance
>> + * @enable: enable/disable
>> + */
>> +static inline int pruss_cfg_xfr_enable(struct pruss *pruss, bool enable)
>> +{
>> +	u32 set = enable ? PRUSS_SPP_XFER_SHIFT_EN : 0;
>> +
>> +	return pruss_cfg_update(pruss, PRUSS_CFG_SPP,
>> +				PRUSS_SPP_XFER_SHIFT_EN, set);
>> +}
>> +#else
>> +
>> +static inline struct pruss *pruss_get(struct rproc *rproc)
>> +{
>> +	return ERR_PTR(-ENOTSUPP);
>> +}
>> +
>> +static inline void pruss_put(struct pruss *pruss) { }
>> +
>> +static inline int pruss_request_mem_region(struct pruss *pruss,
>> +					   enum pruss_mem mem_id,
>> +					   struct pruss_mem_region *region)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int pruss_release_mem_region(struct pruss *pruss,
>> +					   struct pruss_mem_region *region)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int pruss_cfg_read(struct pruss *pruss, unsigned int reg,
>> +				 unsigned int *val)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
>> +				   unsigned int mask, unsigned int val)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int pruss_cfg_xfr_enable(struct pruss *pruss, bool enable)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +#endif /* CONFIG_TI_PRUSS */
>> +
>> +#endif /* __LINUX_PRUSS_H */
>>

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-04 15:11   ` Andrew F. Davis
@ 2019-02-04 15:33     ` Roger Quadros
  2019-02-05  8:51       ` Roger Quadros
  0 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-04 15:33 UTC (permalink / raw)
  To: Andrew F. Davis, tony, ohad, bjorn.andersson
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, Thomas Gleixner, Jason Cooper,
	Marc Zyngier

On 04/02/19 17:11, Andrew F. Davis wrote:
> On 2/4/19 8:22 AM, Roger Quadros wrote:
>> From: "Andrew F. Davis" <afd@ti.com>
>>
> 
> [...]
> 
>> +static const struct pruss_intc_match_data am437x_pruss_intc_data = {
>> +	.no_host7_intr = true,
> 
> Like done for the PRUSS driver with 'has_no_sharedram' becoming a DT
> flag the same could be done here, then all this match data stuff could
> be dropped.

Agreed.

> 
>> +};
>> +
>> +static const struct of_device_id pruss_intc_of_match[] = {
>> +	{
>> +		.compatible = "ti,am3356-pruss-intc",
>> +		.data = NULL,
>> +	},
>> +	{
>> +		.compatible = "ti,am4376-pruss-intc",
>> +		.data = &am437x_pruss_intc_data,
>> +	},
>> +	{
>> +		.compatible = "ti,am5728-pruss-intc",
>> +		.data = NULL,
>> +	},
>> +	{ /* sentinel */ },
>> +};
>> +MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
>> +
>> +static struct platform_driver pruss_intc_driver = {
>> +	.driver = {
>> +		.name = "pruss-intc",
>> +		.of_match_table = pruss_intc_of_match,
>> +	},
>> +	.probe  = pruss_intc_probe,
>> +	.remove = pruss_intc_remove,
>> +};
>> +module_platform_driver(pruss_intc_driver);
>> +
>> +MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
>> +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
>> +MODULE_DESCRIPTION("PRU-ICSS INTC Driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h
>> new file mode 100644
>> index 0000000..4538a0b
>> --- /dev/null
>> +++ b/include/linux/irqchip/irq-pruss-intc.h
>> @@ -0,0 +1,94 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/**
>> + * irq-pruss-intc.h - PRU-ICSS INTC management
> 
> Filename not needed.

OK.

cheers,
-roger

> 
> Andrew
> 
>> + *
>> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
>> + */
>> +
>> +#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
>> +#define __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
>> +
>> +/* maximum number of system events */
>> +#define MAX_PRU_SYS_EVENTS	64
>> +
>> +/* maximum number of interrupt channels */
>> +#define MAX_PRU_CHANNELS	10
>> +
>> +/**
>> + * struct pruss_intc_config - INTC configuration info
>> + * @sysev_to_ch: system events to channel mapping information
>> + * @ch_to_host: interrupt channel to host interrupt information
>> + */
>> +struct pruss_intc_config {
>> +	s8 sysev_to_ch[MAX_PRU_SYS_EVENTS];
>> +	s8 ch_to_host[MAX_PRU_CHANNELS];
>> +};
>> +
>> +#if IS_ENABLED(CONFIG_TI_PRUSS)
>> +
>> +/**
>> + * pruss_intc_configure() - configure the PRUSS INTC
>> + * @dev: device
>> + * @intc_config: PRU core-specific INTC configuration
>> + *
>> + * Configures the PRUSS INTC with the provided configuration from
>> + * a PRU core. Any existing event to channel mappings or channel to
>> + * host interrupt mappings are checked to make sure there are no
>> + * conflicting configuration between both the PRU cores. The function
>> + * is intended to be used only by the PRU remoteproc driver.
>> + *
>> + * Returns 0 on success, or a suitable error code otherwise
>> + */
>> +int pruss_intc_configure(struct device *dev,
>> +			 struct pruss_intc_config *intc_config);
>> +
>> +/**
>> + * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
>> + * @dev: device
>> + * @intc_config: PRU core specific INTC configuration
>> + *
>> + * Undo whatever was done in pruss_intc_configure() for a PRU core.
>> + * It should be sufficient to just mark the resources free in the
>> + * global map and disable the host interrupts and sysevents.
>> + */
>> +int pruss_intc_unconfigure(struct device *dev,
>> +			   struct pruss_intc_config *intc_config);
>> +/**
>> + * pruss_intc_trigger() - trigger a PRU system event
>> + * @irq: linux IRQ number associated with a PRU system event
>> + *
>> + * Trigger an interrupt by signalling a specific PRU system event.
>> + * This can be used by PRUSS client users to raise/send an event to
>> + * a PRU or any other core that is listening on the host interrupt
>> + * mapped to that specific PRU system event. The @irq variable is the
>> + * Linux IRQ number associated with a specific PRU system event that
>> + * a client user/application uses. The interrupt mappings for this is
>> + * provided by the PRUSS INTC irqchip instance.
>> + *
>> + * Returns 0 on success, or an error value upon failure.
>> + */
>> +int pruss_intc_trigger(unsigned int irq);
>> +
>> +#else
>> +
>> +static inline int pruss_intc_configure(struct device *dev,
>> +				       struct pruss_intc_config *intc_config)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int pruss_intc_unconfigure(struct device *dev,
>> +					 struct pruss_intc_config *intc_config)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int pruss_intc_trigger(unsigned int irq)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +#endif	/* CONFIG_TI_PRUSS */
>> +
>> +#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H */
>> +
>>

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-04 14:22 ` [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Roger Quadros
@ 2019-02-04 16:33   ` Tony Lindgren
  2019-02-05  9:39     ` Roger Quadros
  2019-02-08 13:51   ` Linus Walleij
  2019-02-14  2:52   ` Suman Anna
  2 siblings, 1 reply; 61+ messages in thread
From: Tony Lindgren @ 2019-02-04 16:33 UTC (permalink / raw)
  To: Roger Quadros
  Cc: ohad, bjorn.andersson, s-anna, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree

Hi,

* Roger Quadros <rogerq@ti.com> [190204 14:23]:
> From: Suman Anna <s-anna@ti.com>
...
> +Example:
> +========
> +1.	/* AM33xx PRU-ICSS */
> +
> +	pruss: pruss@0 {
> +		compatible = "ti,am3356-pruss";
> +		reg = <0x0 0x2000>,
> +		      <0x2000 0x2000>,
> +		      <0x10000 0x3000>;
> +		reg-names = "dram0", "dram1",
> +			    "shrdram2";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;

Thanks for fixing up the reg ranges for the top level node.

Ideally there would not even be a top level node here as
AFAIK the whole PRUSS is a collection of devices on a PRU
internal interconnect. So following that path a bit further..
How about just get rid of the top level node and just do:

pruss: pruss@0 {
	dram0: memory@0 {
	       device_type = "memory";
	       reg = <0x0 0x2000>;
	};

	dram1: memory@2000 {
	       device_type = "memory";
	       reg = <0x2000 0x2000>;
	};

	shrdram2: memory@10000 {
		device_type = "memory";
		reg = <0x10000 0x3000>;
	};

	pruss_cfg: cfg@26000 {
		...
	};
	...
};

If the device_type = "memory" cannot be used here for
being specific to the top level properties, then
there's probably some other generic property usable
here :)

> +		pruss_mii_rt: mii_rt@32000 {
> +			reg = <0x32000 0x58>;
> +		};

The node name should not have underscores so
pruss_mii_rt: mii-rt@32000. Please check the others
too, like app_node.

> +	app_node: app_node {
> +		prus = <&pru0>, <&pru1>;
> +		firmware-name = "pruss-app-fw", "pruss-app-fw-2";
> +		ti,pruss-gp-mux-sel = <2>, <1>;
> +		/* setup interrupts for prus:
> +		   prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
> +		   prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
> +		ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
> +	}

If the ti,pruss-gp-mux-sel and ti,pru-interrupt-map are
firmware configuration options, maybe leave them out of
the dts completely and make the app-node optional.

And have a proper compatible for this node such as
"ti,pruss-app-xyz". And this should be only set if the the
hardware is wired up in such way that things need to be
configured in the dts rather than by the firmware.

And then you can just hide mux-sel and interrupt-map
behind the compatible property for that hardware. And
leave them out from the dts and have the handling driver
would set mux-sel and interrupt-map based on the
match->data during probe.

Regards,

Tony

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs
  2019-02-04 14:52   ` Andrew F. Davis
  2019-02-04 15:32     ` Roger Quadros
@ 2019-02-04 16:35     ` Tony Lindgren
  1 sibling, 0 replies; 61+ messages in thread
From: Tony Lindgren @ 2019-02-04 16:35 UTC (permalink / raw)
  To: Andrew F. Davis
  Cc: Roger Quadros, ohad, bjorn.andersson, s-anna, david, nsekhar,
	t-kristo, nsaulnier, jreeder, m-karicheri2, woods.technical,
	linux-omap, linux-remoteproc, linux-kernel, devicetree, Keerthy

* Andrew F. Davis <afd@ti.com> [190204 14:52]:
> On 2/4/19 8:22 AM, Roger Quadros wrote:
> > From: Suman Anna <s-anna@ti.com>
> > +++ b/drivers/soc/ti/Kconfig
> > @@ -73,4 +73,16 @@ config TI_SCI_PM_DOMAINS
> >  	  called ti_sci_pm_domains. Note this is needed early in boot before
> >  	  rootfs may be available.
> >  
> > +config TI_PRUSS
> > +	tristate "TI PRU-ICSS Subsystem Platform drivers"
> > +	depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX
> > +	select MFD_SYSCON
> > +	default n

Just a nitpick comment, we have n as the default already,
so default n can be dropped.

Regards,

Tony

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts
  2019-02-04 14:22 ` [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts Roger Quadros
@ 2019-02-04 16:36   ` Tony Lindgren
  2019-02-14  2:40   ` Suman Anna
  2019-02-18 19:32   ` Rob Herring
  2 siblings, 0 replies; 61+ messages in thread
From: Tony Lindgren @ 2019-02-04 16:36 UTC (permalink / raw)
  To: Roger Quadros
  Cc: ohad, bjorn.andersson, s-anna, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Andrew F. Davis,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Rob Herring

* Roger Quadros <rogerq@ti.com> [190204 14:23]:
> From: "Andrew F. Davis" <afd@ti.com>
> 
> The Programmable Real-Time Unit Subsystem (PRUSS) contains an
> interrupt controller (INTC) that can handle various system input
> events and post interrupts back to the device-level initiators.
> The INTC can support upto 64 input events with individual control
> configuration and hardware prioritization. These events are mapped
> onto 10 interrupt signals through two levels of many-to-one mapping
> support. Different interrupt signals are routed to the individual
> PRU cores or to the host CPU.
> 
> The PRUSS INTC platform driver manages this PRUSS interrupt
> controller and implements an irqchip driver to provide a Linux
> standard way for the PRU client users to enable/disable/ack/
> re-trigger a PRUSS system event. The system events to interrupt
> channels and host interrupts relies on the mapping configuration
> provided through a firmware resource table for now. This will be
> revisited and enhanced in the future for a better interface. The
> mappings will currently be programmed during the boot/shutdown
> of the PRU.

Acked-by: Tony Lindgren <tony@atomide.com>

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-04 14:22 ` [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip " Roger Quadros
  2019-02-04 15:11   ` Andrew F. Davis
@ 2019-02-04 18:15   ` Tony Lindgren
  2019-02-05 10:35     ` Roger Quadros
  1 sibling, 1 reply; 61+ messages in thread
From: Tony Lindgren @ 2019-02-04 18:15 UTC (permalink / raw)
  To: Roger Quadros
  Cc: ohad, bjorn.andersson, s-anna, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Andrew F. Davis,
	Thomas Gleixner, Jason Cooper, Marc Zyngier

* Roger Quadros <rogerq@ti.com> [190204 14:23]:
> From: "Andrew F. Davis" <afd@ti.com>
> 
> The Programmable Real-Time Unit Subsystem (PRUSS) contains an
> interrupt controller (INTC) that can handle various system input
> events and post interrupts back to the device-level initiators.
> The INTC can support upto 64 input events with individual control
> configuration and hardware prioritization. These events are mapped
> onto 10 interrupt signals through two levels of many-to-one mapping
> support. Different interrupt signals are routed to the individual
> PRU cores or to the host CPU.
> 
> The PRUSS INTC platform driver manages this PRUSS interrupt
> controller and implements an irqchip driver to provide a Linux
> standard way for the PRU client users to enable/disable/ack/
> re-trigger a PRUSS system event. The system events to interrupt
> channels and host interrupts relies on the mapping configuration
> provided through a firmware resource table for now. This will be
> revisited and enhanced in the future for a better interface. The
> mappings will currently be programmed during the boot/shutdown
> of the PRU.
> 
> The PRUSS INTC module is reference counted during the interrupt
> setup phase through the irqchip's irq_request_resources() and
> irq_release_resources() ops. This restricts the module from being
> removed as long as there are active interrupt users.
> 
> The PRUSS INTC can generate an interrupt to various processor
> subsystems on the SoC through a set of 64 possible PRU system
> events. These system events can be used by PRU client drivers
> or applications for event notifications/signalling between PRUs
> and MPU or other processors. An API, pruss_intc_trigger() is
> provided to MPU-side PRU client drivers/applications to be able
> to trigger an event/interrupt using IRQ numbers provided by the
> PRUSS-INTC irqdomain chip.

I suggest you send the binding patch and the interrupt
controller driver separately to the irqchip guys. Maybe
put the trigger function in to a separate patch that can
be reviewed and applied separately.

Regards,

Tony

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-04 15:33     ` Roger Quadros
@ 2019-02-05  8:51       ` Roger Quadros
  2019-02-14  2:15         ` Suman Anna
  0 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-05  8:51 UTC (permalink / raw)
  To: Andrew F. Davis, tony, ohad, bjorn.andersson, Rob Herring
  Cc: s-anna, david, nsekhar, t-kristo, nsaulnier, jreeder,
	m-karicheri2, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree, Thomas Gleixner, Jason Cooper,
	Marc Zyngier

+Rob

Andrew,

On 04/02/19 17:33, Roger Quadros wrote:
> On 04/02/19 17:11, Andrew F. Davis wrote:
>> On 2/4/19 8:22 AM, Roger Quadros wrote:
>>> From: "Andrew F. Davis" <afd@ti.com>
>>>
>>
>> [...]
>>
>>> +static const struct pruss_intc_match_data am437x_pruss_intc_data = {
>>> +	.no_host7_intr = true,
>>
>> Like done for the PRUSS driver with 'has_no_sharedram' becoming a DT
>> flag the same could be done here, then all this match data stuff could
>> be dropped.
> 
> Agreed.
> 

Going back and looking at code here is a different perspective.

The has_no_sharedram case was a an odd duck because the 2 ICSSG instances
within the same SoC (AM437x) had differences. So we couldn't use
the compatible to differentiate there. The DT flag makes sense there.

In the no_host7_intr case, it SoC specific so we can use the compatible to
differentiate. And AM6 SoC has different number of system_events and host_interrupts
so that could come in macth_data as well. See below.

static const struct pruss_intc_match_data am335x_am57xx_pruss_intc_data = {
        .num_system_events = 64,
        .num_host_intrs = 10,
        .no_host7_intr = false,
};

static const struct pruss_intc_match_data am437x_k2g_pruss_intc_data = {
        .num_system_events = 64,
        .num_host_intrs = 10,
        .no_host7_intr = true,
};

static const struct pruss_intc_match_data am6x_icssg_intc_data = {
        .num_system_events = 160,
        .num_host_intrs = 20,
        .no_host7_intr = false,
};

Alternatively, we add a DT property each for all 3 of them and get rid
of match_data entirely.

Which is a better approach?

cheers,
-roger


>>
>>> +};
>>> +
>>> +static const struct of_device_id pruss_intc_of_match[] = {
>>> +	{
>>> +		.compatible = "ti,am3356-pruss-intc",
>>> +		.data = NULL,
>>> +	},
>>> +	{
>>> +		.compatible = "ti,am4376-pruss-intc",
>>> +		.data = &am437x_pruss_intc_data,
>>> +	},
>>> +	{
>>> +		.compatible = "ti,am5728-pruss-intc",
>>> +		.data = NULL,
>>> +	},
>>> +	{ /* sentinel */ },
>>> +};
>>> +MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
>>> +
>>> +static struct platform_driver pruss_intc_driver = {
>>> +	.driver = {
>>> +		.name = "pruss-intc",
>>> +		.of_match_table = pruss_intc_of_match,
>>> +	},
>>> +	.probe  = pruss_intc_probe,
>>> +	.remove = pruss_intc_remove,
>>> +};
>>> +module_platform_driver(pruss_intc_driver);
>>> +
>>> +MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
>>> +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
>>> +MODULE_DESCRIPTION("PRU-ICSS INTC Driver");
>>> +MODULE_LICENSE("GPL v2");
>>> diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h
>>> new file mode 100644
>>> index 0000000..4538a0b
>>> --- /dev/null
>>> +++ b/include/linux/irqchip/irq-pruss-intc.h
>>> @@ -0,0 +1,94 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/**
>>> + * irq-pruss-intc.h - PRU-ICSS INTC management
>>
>> Filename not needed.
> 
> OK.
> 
> cheers,
> -roger
> 
>>
>> Andrew
>>
>>> + *
>>> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
>>> + */
>>> +
>>> +#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
>>> +#define __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
>>> +
>>> +/* maximum number of system events */
>>> +#define MAX_PRU_SYS_EVENTS	64
>>> +
>>> +/* maximum number of interrupt channels */
>>> +#define MAX_PRU_CHANNELS	10
>>> +
>>> +/**
>>> + * struct pruss_intc_config - INTC configuration info
>>> + * @sysev_to_ch: system events to channel mapping information
>>> + * @ch_to_host: interrupt channel to host interrupt information
>>> + */
>>> +struct pruss_intc_config {
>>> +	s8 sysev_to_ch[MAX_PRU_SYS_EVENTS];
>>> +	s8 ch_to_host[MAX_PRU_CHANNELS];
>>> +};
>>> +
>>> +#if IS_ENABLED(CONFIG_TI_PRUSS)
>>> +
>>> +/**
>>> + * pruss_intc_configure() - configure the PRUSS INTC
>>> + * @dev: device
>>> + * @intc_config: PRU core-specific INTC configuration
>>> + *
>>> + * Configures the PRUSS INTC with the provided configuration from
>>> + * a PRU core. Any existing event to channel mappings or channel to
>>> + * host interrupt mappings are checked to make sure there are no
>>> + * conflicting configuration between both the PRU cores. The function
>>> + * is intended to be used only by the PRU remoteproc driver.
>>> + *
>>> + * Returns 0 on success, or a suitable error code otherwise
>>> + */
>>> +int pruss_intc_configure(struct device *dev,
>>> +			 struct pruss_intc_config *intc_config);
>>> +
>>> +/**
>>> + * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
>>> + * @dev: device
>>> + * @intc_config: PRU core specific INTC configuration
>>> + *
>>> + * Undo whatever was done in pruss_intc_configure() for a PRU core.
>>> + * It should be sufficient to just mark the resources free in the
>>> + * global map and disable the host interrupts and sysevents.
>>> + */
>>> +int pruss_intc_unconfigure(struct device *dev,
>>> +			   struct pruss_intc_config *intc_config);
>>> +/**
>>> + * pruss_intc_trigger() - trigger a PRU system event
>>> + * @irq: linux IRQ number associated with a PRU system event
>>> + *
>>> + * Trigger an interrupt by signalling a specific PRU system event.
>>> + * This can be used by PRUSS client users to raise/send an event to
>>> + * a PRU or any other core that is listening on the host interrupt
>>> + * mapped to that specific PRU system event. The @irq variable is the
>>> + * Linux IRQ number associated with a specific PRU system event that
>>> + * a client user/application uses. The interrupt mappings for this is
>>> + * provided by the PRUSS INTC irqchip instance.
>>> + *
>>> + * Returns 0 on success, or an error value upon failure.
>>> + */
>>> +int pruss_intc_trigger(unsigned int irq);
>>> +
>>> +#else
>>> +
>>> +static inline int pruss_intc_configure(struct device *dev,
>>> +				       struct pruss_intc_config *intc_config)
>>> +{
>>> +	return -ENOTSUPP;
>>> +}
>>> +
>>> +static inline int pruss_intc_unconfigure(struct device *dev,
>>> +					 struct pruss_intc_config *intc_config)
>>> +{
>>> +	return -ENOTSUPP;
>>> +}
>>> +
>>> +static inline int pruss_intc_trigger(unsigned int irq)
>>> +{
>>> +	return -ENOTSUPP;
>>> +}
>>> +
>>> +#endif	/* CONFIG_TI_PRUSS */
>>> +
>>> +#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H */
>>> +
>>>
> 

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-04 16:33   ` Tony Lindgren
@ 2019-02-05  9:39     ` Roger Quadros
  2019-02-05 15:08       ` Murali Karicheri
  2019-02-05 16:41       ` Tony Lindgren
  0 siblings, 2 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-05  9:39 UTC (permalink / raw)
  To: Tony Lindgren, s-anna
  Cc: ohad, bjorn.andersson, david, nsekhar, t-kristo, nsaulnier,
	jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree

Hi Tony & Suman,

On 04/02/19 18:33, Tony Lindgren wrote:
> Hi,
> 
> * Roger Quadros <rogerq@ti.com> [190204 14:23]:
>> From: Suman Anna <s-anna@ti.com>
> ...
>> +Example:
>> +========
>> +1.	/* AM33xx PRU-ICSS */
>> +
>> +	pruss: pruss@0 {
>> +		compatible = "ti,am3356-pruss";
>> +		reg = <0x0 0x2000>,
>> +		      <0x2000 0x2000>,
>> +		      <0x10000 0x3000>;
>> +		reg-names = "dram0", "dram1",
>> +			    "shrdram2";
>> +		#address-cells = <1>;
>> +		#size-cells = <1>;
>> +		ranges;
> 
> Thanks for fixing up the reg ranges for the top level node.
> 
> Ideally there would not even be a top level node here as
> AFAIK the whole PRUSS is a collection of devices on a PRU
> internal interconnect. So following that path a bit further..
> How about just get rid of the top level node and just do:
> 
> pruss: pruss@0 {
> 	dram0: memory@0 {
> 	       device_type = "memory";
> 	       reg = <0x0 0x2000>;
> 	};
> 
> 	dram1: memory@2000 {
> 	       device_type = "memory";
> 	       reg = <0x2000 0x2000>;
> 	};

Actually dram0 and dram1 are data memories for PRU0 and PRU1 respectively.
Isn't it better if they are moved to the pru node?
e.g.

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

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

I think it is better to place a restriction that firmware on PRU0 cannot use data
memory of PRU1 and vice versa.

Application drivers do sometimes need to read/write to data memory. The pru_rproc
driver could provide a API for the application drivers to get virtual address of
the respective PRU's data memory.

> 
> 	shrdram2: memory@10000 {
> 		device_type = "memory";
> 		reg = <0x10000 0x3000>;
> 	};

Shared RAM is not so straight forward. Both PRU firmwares and both application drivers
might need to read/write here. The area split is decided by firmware design and there
is no hardware protection to prevent from stomping on each others toes.

We need a carveout based memory allocator at least I think that can do a
allocate(base_offset, size); into shared RAM.

This could be used by pru_rproc driver at firmware load time and by application drivers
at initialization time.

Thoughts?

> 
> 	pruss_cfg: cfg@26000 {
> 		...
> 	};
> 	...
> };
> 
> If the device_type = "memory" cannot be used here for
> being specific to the top level properties, then
> there's probably some other generic property usable
> here :)
> 
>> +		pruss_mii_rt: mii_rt@32000 {
>> +			reg = <0x32000 0x58>;
>> +		};
> 
> The node name should not have underscores so
> pruss_mii_rt: mii-rt@32000. Please check the others
> too, like app_node.
> 

OK.

>> +	app_node: app_node {
>> +		prus = <&pru0>, <&pru1>;
>> +		firmware-name = "pruss-app-fw", "pruss-app-fw-2";
>> +		ti,pruss-gp-mux-sel = <2>, <1>;
>> +		/* setup interrupts for prus:
>> +		   prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
>> +		   prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
>> +		ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
>> +	}
> 
> If the ti,pruss-gp-mux-sel and ti,pru-interrupt-map are
> firmware configuration options, maybe leave them out of
> the dts completely and make the app-node optional.

Yes the app-node is optional. I will mention it.

No, ti,pruss-gp-mux-sel and ti,pru-interrupt-map are not firmware options.
But these settings are application/firmware specific.

ti,pru-interrupt-map specifies the configuration to be used for the INTC interrupt
controller.

ti,pruss-gp-mux-sel is used to configure this register.
"Table 30-20. PRUSS_GPCFG0" in http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf
"29:26 PR1_PRU0_GP_MUX_SEL"

It configures how the pins from the PRUSS module are routed internally
to the various modules.

see "30.2.1 PRU-ICSS I/O Interface"
and "Table 30-1. PRU-ICSS1 I/O Signals"

> 
> And have a proper compatible for this node such as
> "ti,pruss-app-xyz". And this should be only set if the the
> hardware is wired up in such way that things need to be
> configured in the dts rather than by the firmware.

Yes, compatible is a required property as we need to load
the appropriate application (kernel space) driver for it.
I will fix the example.

> 
> And then you can just hide mux-sel and interrupt-map
> behind the compatible property for that hardware. And
> leave them out from the dts and have the handling driver
> would set mux-sel and interrupt-map based on the
> match->data during probe.

To summarize:

I'll mark the app node as optional. Only required if a kernel
driver is required for the application.
Compatible is mandatory for app node.
ti,pruss-gp-mux-sel and ti,pru-interrupt-map are optional
for app node.

cheers,
-roger

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-04 18:15   ` Tony Lindgren
@ 2019-02-05 10:35     ` Roger Quadros
  2019-02-05 11:04       ` Marc Zyngier
  0 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-05 10:35 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: ohad, bjorn.andersson, s-anna, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Andrew F. Davis,
	Thomas Gleixner, Jason Cooper, Marc Zyngier

On 04/02/19 20:15, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [190204 14:23]:
>> From: "Andrew F. Davis" <afd@ti.com>
>>
>> The Programmable Real-Time Unit Subsystem (PRUSS) contains an
>> interrupt controller (INTC) that can handle various system input
>> events and post interrupts back to the device-level initiators.
>> The INTC can support upto 64 input events with individual control
>> configuration and hardware prioritization. These events are mapped
>> onto 10 interrupt signals through two levels of many-to-one mapping
>> support. Different interrupt signals are routed to the individual
>> PRU cores or to the host CPU.
>>
>> The PRUSS INTC platform driver manages this PRUSS interrupt
>> controller and implements an irqchip driver to provide a Linux
>> standard way for the PRU client users to enable/disable/ack/
>> re-trigger a PRUSS system event. The system events to interrupt
>> channels and host interrupts relies on the mapping configuration
>> provided through a firmware resource table for now. This will be
>> revisited and enhanced in the future for a better interface. The
>> mappings will currently be programmed during the boot/shutdown
>> of the PRU.
>>
>> The PRUSS INTC module is reference counted during the interrupt
>> setup phase through the irqchip's irq_request_resources() and
>> irq_release_resources() ops. This restricts the module from being
>> removed as long as there are active interrupt users.
>>
>> The PRUSS INTC can generate an interrupt to various processor
>> subsystems on the SoC through a set of 64 possible PRU system
>> events. These system events can be used by PRU client drivers
>> or applications for event notifications/signalling between PRUs
>> and MPU or other processors. An API, pruss_intc_trigger() is
>> provided to MPU-side PRU client drivers/applications to be able
>> to trigger an event/interrupt using IRQ numbers provided by the
>> PRUSS-INTC irqdomain chip.
> 
> I suggest you send the binding patch and the interrupt
> controller driver separately to the irqchip guys. Maybe
> put the trigger function in to a separate patch that can
> be reviewed and applied separately.

Good idea. I will send irqchip related patches separately.

cheers,
-roger
> 
> Regards,
> 
> Tony
> 

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-05 10:35     ` Roger Quadros
@ 2019-02-05 11:04       ` Marc Zyngier
  2019-02-14  2:16         ` Suman Anna
  0 siblings, 1 reply; 61+ messages in thread
From: Marc Zyngier @ 2019-02-05 11:04 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Tony Lindgren, ohad, bjorn.andersson, s-anna, david, nsekhar,
	t-kristo, nsaulnier, jreeder, m-karicheri2, woods.technical,
	linux-omap, linux-remoteproc, linux-kernel, devicetree,
	Andrew F. Davis, Thomas Gleixner, Jason Cooper

On Tue, 05 Feb 2019 10:35:44 +0000,
Roger Quadros <rogerq@ti.com> wrote:
> 
> On 04/02/19 20:15, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [190204 14:23]:
> >> From: "Andrew F. Davis" <afd@ti.com>
> >>
> >> The Programmable Real-Time Unit Subsystem (PRUSS) contains an
> >> interrupt controller (INTC) that can handle various system input
> >> events and post interrupts back to the device-level initiators.
> >> The INTC can support upto 64 input events with individual control
> >> configuration and hardware prioritization. These events are mapped
> >> onto 10 interrupt signals through two levels of many-to-one mapping
> >> support. Different interrupt signals are routed to the individual
> >> PRU cores or to the host CPU.
> >>
> >> The PRUSS INTC platform driver manages this PRUSS interrupt
> >> controller and implements an irqchip driver to provide a Linux
> >> standard way for the PRU client users to enable/disable/ack/
> >> re-trigger a PRUSS system event. The system events to interrupt
> >> channels and host interrupts relies on the mapping configuration
> >> provided through a firmware resource table for now. This will be
> >> revisited and enhanced in the future for a better interface. The
> >> mappings will currently be programmed during the boot/shutdown
> >> of the PRU.
> >>
> >> The PRUSS INTC module is reference counted during the interrupt
> >> setup phase through the irqchip's irq_request_resources() and
> >> irq_release_resources() ops. This restricts the module from being
> >> removed as long as there are active interrupt users.
> >>
> >> The PRUSS INTC can generate an interrupt to various processor
> >> subsystems on the SoC through a set of 64 possible PRU system
> >> events. These system events can be used by PRU client drivers
> >> or applications for event notifications/signalling between PRUs
> >> and MPU or other processors. An API, pruss_intc_trigger() is
> >> provided to MPU-side PRU client drivers/applications to be able
> >> to trigger an event/interrupt using IRQ numbers provided by the
> >> PRUSS-INTC irqdomain chip.
> > 
> > I suggest you send the binding patch and the interrupt
> > controller driver separately to the irqchip guys. Maybe
> > put the trigger function in to a separate patch that can
> > be reviewed and applied separately.
> 
> Good idea. I will send irqchip related patches separately.

Yes please. But also please document why you have so many non
irq-related entry points in this irqchip driver. It seems to replicate
the same "events vs irq" stuff we're trying to get rid of in the K3
patches...

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-05  9:39     ` Roger Quadros
@ 2019-02-05 15:08       ` Murali Karicheri
  2019-02-05 15:41         ` Roger Quadros
  2019-02-05 16:41       ` Tony Lindgren
  1 sibling, 1 reply; 61+ messages in thread
From: Murali Karicheri @ 2019-02-05 15:08 UTC (permalink / raw)
  To: Roger Quadros, Tony Lindgren, s-anna
  Cc: ohad, bjorn.andersson, david, nsekhar, t-kristo, nsaulnier,
	jreeder, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree

Hi Roger,

On 02/05/2019 04:39 AM, Roger Quadros wrote:
> Hi Tony & Suman,
> 
> On 04/02/19 18:33, Tony Lindgren wrote:
>> Hi,
>>
>> * Roger Quadros <rogerq@ti.com> [190204 14:23]:
>>> From: Suman Anna <s-anna@ti.com>
>> ...
>>> +Example:
>>> +========
>>> +1.	/* AM33xx PRU-ICSS */
>>> +
>>> +	pruss: pruss@0 {
>>> +		compatible = "ti,am3356-pruss";
>>> +		reg = <0x0 0x2000>,
>>> +		      <0x2000 0x2000>,
>>> +		      <0x10000 0x3000>;
>>> +		reg-names = "dram0", "dram1",
>>> +			    "shrdram2";
>>> +		#address-cells = <1>;
>>> +		#size-cells = <1>;
>>> +		ranges;
>>
>> Thanks for fixing up the reg ranges for the top level node.
>>
>> Ideally there would not even be a top level node here as
>> AFAIK the whole PRUSS is a collection of devices on a PRU
>> internal interconnect. So following that path a bit further..
>> How about just get rid of the top level node and just do:
>>
>> pruss: pruss@0 {
>> 	dram0: memory@0 {
>> 	       device_type = "memory";
>> 	       reg = <0x0 0x2000>;
>> 	};
>>
>> 	dram1: memory@2000 {
>> 	       device_type = "memory";
>> 	       reg = <0x2000 0x2000>;
>> 	};
> 
> Actually dram0 and dram1 are data memories for PRU0 and PRU1 respectively.
> Isn't it better if they are moved to the pru node?
> e.g.
> 
> 	pru0: pru@34000 {
> 		compatible = "ti,am3356-pru";
> 		reg = <0x34000 0x2000>,
> 		      <0x22000 0x400>,
> 		      <0x22400 0x100>,
> 		      <0x0     0x2000>;
> 		reg-names = "iram", "control", "debug", "dram";
> 		...
> 	};
> 
> 	pru1: pru@38000 {
> 		compatible = "ti,am3356-pru";
> 		reg = <0x38000 0x2000>,
> 		      <0x24000 0x400>,
> 		      <0x24400 0x100>,
> 		      <0x2000  0x2000>;
> 		reg-names = "iram", "control", "debug", "dram";
> 		...
> 	};
> 
> I think it is better to place a restriction that firmware on PRU0 cannot use data
> memory of PRU1 and vice versa.
> 
That will not work as there are switch firmware cases where PRU access
DRAM of other PRU and is a valid case to support in the future. So let
us not do that.

Murali
> Application drivers do sometimes need to read/write to data memory. The pru_rproc
> driver could provide a API for the application drivers to get virtual address of
> the respective PRU's data memory.
> 
>>
>> 	shrdram2: memory@10000 {
>> 		device_type = "memory";
>> 		reg = <0x10000 0x3000>;
>> 	};
> 
> Shared RAM is not so straight forward. Both PRU firmwares and both application drivers
> might need to read/write here. The area split is decided by firmware design and there
> is no hardware protection to prevent from stomping on each others toes.
> 
> We need a carveout based memory allocator at least I think that can do a
> allocate(base_offset, size); into shared RAM.
> 
> This could be used by pru_rproc driver at firmware load time and by application drivers
> at initialization time.
> 
> Thoughts?
> 
>>
>> 	pruss_cfg: cfg@26000 {
>> 		...
>> 	};
>> 	...
>> };
>>
>> If the device_type = "memory" cannot be used here for
>> being specific to the top level properties, then
>> there's probably some other generic property usable
>> here :)
>>
>>> +		pruss_mii_rt: mii_rt@32000 {
>>> +			reg = <0x32000 0x58>;
>>> +		};
>>
>> The node name should not have underscores so
>> pruss_mii_rt: mii-rt@32000. Please check the others
>> too, like app_node.
>>
> 
> OK.
> 
>>> +	app_node: app_node {
>>> +		prus = <&pru0>, <&pru1>;
>>> +		firmware-name = "pruss-app-fw", "pruss-app-fw-2";
>>> +		ti,pruss-gp-mux-sel = <2>, <1>;
>>> +		/* setup interrupts for prus:
>>> +		   prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
>>> +		   prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
>>> +		ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
>>> +	}
>>
>> If the ti,pruss-gp-mux-sel and ti,pru-interrupt-map are
>> firmware configuration options, maybe leave them out of
>> the dts completely and make the app-node optional.
> 
> Yes the app-node is optional. I will mention it.
> 
> No, ti,pruss-gp-mux-sel and ti,pru-interrupt-map are not firmware options.
> But these settings are application/firmware specific.
> 
> ti,pru-interrupt-map specifies the configuration to be used for the INTC interrupt
> controller.
> 
> ti,pruss-gp-mux-sel is used to configure this register.
> "Table 30-20. PRUSS_GPCFG0" in http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf
> "29:26 PR1_PRU0_GP_MUX_SEL"
> 
> It configures how the pins from the PRUSS module are routed internally
> to the various modules.
> 
> see "30.2.1 PRU-ICSS I/O Interface"
> and "Table 30-1. PRU-ICSS1 I/O Signals"
> 
>>
>> And have a proper compatible for this node such as
>> "ti,pruss-app-xyz". And this should be only set if the the
>> hardware is wired up in such way that things need to be
>> configured in the dts rather than by the firmware.
> 
> Yes, compatible is a required property as we need to load
> the appropriate application (kernel space) driver for it.
> I will fix the example.
> 
>>
>> And then you can just hide mux-sel and interrupt-map
>> behind the compatible property for that hardware. And
>> leave them out from the dts and have the handling driver
>> would set mux-sel and interrupt-map based on the
>> match->data during probe.
> 
> To summarize:
> 
> I'll mark the app node as optional. Only required if a kernel
> driver is required for the application.
> Compatible is mandatory for app node.
> ti,pruss-gp-mux-sel and ti,pru-interrupt-map are optional
> for app node.
> 
> cheers,
> -roger
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-05 15:08       ` Murali Karicheri
@ 2019-02-05 15:41         ` Roger Quadros
  2019-02-05 16:15           ` Murali Karicheri
  0 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-05 15:41 UTC (permalink / raw)
  To: Murali Karicheri, Tony Lindgren, s-anna
  Cc: ohad, bjorn.andersson, david, nsekhar, t-kristo, nsaulnier,
	jreeder, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree

Murali,

On 05/02/19 17:08, Murali Karicheri wrote:
> Hi Roger,
> 
> On 02/05/2019 04:39 AM, Roger Quadros wrote:
>> Hi Tony & Suman,
>>
>> On 04/02/19 18:33, Tony Lindgren wrote:
>>> Hi,
>>>
>>> * Roger Quadros <rogerq@ti.com> [190204 14:23]:
>>>> From: Suman Anna <s-anna@ti.com>
>>> ...
>>>> +Example:
>>>> +========
>>>> +1.    /* AM33xx PRU-ICSS */
>>>> +
>>>> +    pruss: pruss@0 {
>>>> +        compatible = "ti,am3356-pruss";
>>>> +        reg = <0x0 0x2000>,
>>>> +              <0x2000 0x2000>,
>>>> +              <0x10000 0x3000>;
>>>> +        reg-names = "dram0", "dram1",
>>>> +                "shrdram2";
>>>> +        #address-cells = <1>;
>>>> +        #size-cells = <1>;
>>>> +        ranges;
>>>
>>> Thanks for fixing up the reg ranges for the top level node.
>>>
>>> Ideally there would not even be a top level node here as
>>> AFAIK the whole PRUSS is a collection of devices on a PRU
>>> internal interconnect. So following that path a bit further..
>>> How about just get rid of the top level node and just do:
>>>
>>> pruss: pruss@0 {
>>>     dram0: memory@0 {
>>>            device_type = "memory";
>>>            reg = <0x0 0x2000>;
>>>     };
>>>
>>>     dram1: memory@2000 {
>>>            device_type = "memory";
>>>            reg = <0x2000 0x2000>;
>>>     };
>>
>> Actually dram0 and dram1 are data memories for PRU0 and PRU1 respectively.
>> Isn't it better if they are moved to the pru node?
>> e.g.
>>
>>     pru0: pru@34000 {
>>         compatible = "ti,am3356-pru";
>>         reg = <0x34000 0x2000>,
>>               <0x22000 0x400>,
>>               <0x22400 0x100>,
>>               <0x0     0x2000>;
>>         reg-names = "iram", "control", "debug", "dram";
>>         ...
>>     };
>>
>>     pru1: pru@38000 {
>>         compatible = "ti,am3356-pru";
>>         reg = <0x38000 0x2000>,
>>               <0x24000 0x400>,
>>               <0x24400 0x100>,
>>               <0x2000  0x2000>;
>>         reg-names = "iram", "control", "debug", "dram";
>>         ...
>>     };
>>
>> I think it is better to place a restriction that firmware on PRU0 cannot use data
>> memory of PRU1 and vice versa.
>>
> That will not work as there are switch firmware cases where PRU access
> DRAM of other PRU and is a valid case to support in the future. So let
> us not do that.

PRU firmware accessing DRAM of other PRU is a design contract and that use case
requires both PRUs to be loaded with matching firmware. That should continue to work.

What I'm suggesting here is that kernel remoteproc driver should have nothing to do
with the other PRU's data RAM.

The application driver if needs both PRUs then it can obviously access both DRAMs
as it has a phandle to both PRUs.

cheers,
-roger

> 
> Murali
>> Application drivers do sometimes need to read/write to data memory. The pru_rproc
>> driver could provide a API for the application drivers to get virtual address of
>> the respective PRU's data memory.
>>
>>>
>>>     shrdram2: memory@10000 {
>>>         device_type = "memory";
>>>         reg = <0x10000 0x3000>;
>>>     };
>>
>> Shared RAM is not so straight forward. Both PRU firmwares and both application drivers
>> might need to read/write here. The area split is decided by firmware design and there
>> is no hardware protection to prevent from stomping on each others toes.
>>
>> We need a carveout based memory allocator at least I think that can do a
>> allocate(base_offset, size); into shared RAM.
>>
>> This could be used by pru_rproc driver at firmware load time and by application drivers
>> at initialization time.
>>
>> Thoughts?
>>
>>>
>>>     pruss_cfg: cfg@26000 {
>>>         ...
>>>     };
>>>     ...
>>> };
>>>
>>> If the device_type = "memory" cannot be used here for
>>> being specific to the top level properties, then
>>> there's probably some other generic property usable
>>> here :)
>>>
>>>> +        pruss_mii_rt: mii_rt@32000 {
>>>> +            reg = <0x32000 0x58>;
>>>> +        };
>>>
>>> The node name should not have underscores so
>>> pruss_mii_rt: mii-rt@32000. Please check the others
>>> too, like app_node.
>>>
>>
>> OK.
>>
>>>> +    app_node: app_node {
>>>> +        prus = <&pru0>, <&pru1>;
>>>> +        firmware-name = "pruss-app-fw", "pruss-app-fw-2";
>>>> +        ti,pruss-gp-mux-sel = <2>, <1>;
>>>> +        /* setup interrupts for prus:
>>>> +           prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
>>>> +           prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
>>>> +        ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
>>>> +    }
>>>
>>> If the ti,pruss-gp-mux-sel and ti,pru-interrupt-map are
>>> firmware configuration options, maybe leave them out of
>>> the dts completely and make the app-node optional.
>>
>> Yes the app-node is optional. I will mention it.
>>
>> No, ti,pruss-gp-mux-sel and ti,pru-interrupt-map are not firmware options.
>> But these settings are application/firmware specific.
>>
>> ti,pru-interrupt-map specifies the configuration to be used for the INTC interrupt
>> controller.
>>
>> ti,pruss-gp-mux-sel is used to configure this register.
>> "Table 30-20. PRUSS_GPCFG0" in http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf
>> "29:26 PR1_PRU0_GP_MUX_SEL"
>>
>> It configures how the pins from the PRUSS module are routed internally
>> to the various modules.
>>
>> see "30.2.1 PRU-ICSS I/O Interface"
>> and "Table 30-1. PRU-ICSS1 I/O Signals"
>>
>>>
>>> And have a proper compatible for this node such as
>>> "ti,pruss-app-xyz". And this should be only set if the the
>>> hardware is wired up in such way that things need to be
>>> configured in the dts rather than by the firmware.
>>
>> Yes, compatible is a required property as we need to load
>> the appropriate application (kernel space) driver for it.
>> I will fix the example.
>>
>>>
>>> And then you can just hide mux-sel and interrupt-map
>>> behind the compatible property for that hardware. And
>>> leave them out from the dts and have the handling driver
>>> would set mux-sel and interrupt-map based on the
>>> match->data during probe.
>>
>> To summarize:
>>
>> I'll mark the app node as optional. Only required if a kernel
>> driver is required for the application.
>> Compatible is mandatory for app node.
>> ti,pruss-gp-mux-sel and ti,pru-interrupt-map are optional
>> for app node.
>>
>> cheers,
>> -roger
>>

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-05 15:41         ` Roger Quadros
@ 2019-02-05 16:15           ` Murali Karicheri
  2019-02-05 16:19             ` Tony Lindgren
  0 siblings, 1 reply; 61+ messages in thread
From: Murali Karicheri @ 2019-02-05 16:15 UTC (permalink / raw)
  To: Roger Quadros, Tony Lindgren, s-anna
  Cc: ohad, bjorn.andersson, david, nsekhar, t-kristo, nsaulnier,
	jreeder, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree

Roger,

On 02/05/2019 10:41 AM, Roger Quadros wrote:
> Murali,
> 
> On 05/02/19 17:08, Murali Karicheri wrote:
>> Hi Roger,
>>
>> On 02/05/2019 04:39 AM, Roger Quadros wrote:
>>> Hi Tony & Suman,
>>>
>>> On 04/02/19 18:33, Tony Lindgren wrote:
>>>> Hi,
>>>>
>>>> * Roger Quadros <rogerq@ti.com> [190204 14:23]:
>>>>> From: Suman Anna <s-anna@ti.com>
>>>> ...
>>>>> +Example:
>>>>> +========
>>>>> +1.    /* AM33xx PRU-ICSS */
>>>>> +
>>>>> +    pruss: pruss@0 {
>>>>> +        compatible = "ti,am3356-pruss";
>>>>> +        reg = <0x0 0x2000>,
>>>>> +              <0x2000 0x2000>,
>>>>> +              <0x10000 0x3000>;
>>>>> +        reg-names = "dram0", "dram1",
>>>>> +                "shrdram2";
>>>>> +        #address-cells = <1>;
>>>>> +        #size-cells = <1>;
>>>>> +        ranges;
>>>>
>>>> Thanks for fixing up the reg ranges for the top level node.
>>>>
>>>> Ideally there would not even be a top level node here as
>>>> AFAIK the whole PRUSS is a collection of devices on a PRU
>>>> internal interconnect. So following that path a bit further..
>>>> How about just get rid of the top level node and just do:
>>>>
>>>> pruss: pruss@0 {
>>>>      dram0: memory@0 {
>>>>             device_type = "memory";
>>>>             reg = <0x0 0x2000>;
>>>>      };
>>>>
>>>>      dram1: memory@2000 {
>>>>             device_type = "memory";
>>>>             reg = <0x2000 0x2000>;
>>>>      };
>>>
>>> Actually dram0 and dram1 are data memories for PRU0 and PRU1 respectively.
>>> Isn't it better if they are moved to the pru node?
>>> e.g.
>>>
>>>      pru0: pru@34000 {
>>>          compatible = "ti,am3356-pru";
>>>          reg = <0x34000 0x2000>,
>>>                <0x22000 0x400>,
>>>                <0x22400 0x100>,
>>>                <0x0     0x2000>;
>>>          reg-names = "iram", "control", "debug", "dram";
>>>          ...
>>>      };
>>>
>>>      pru1: pru@38000 {
>>>          compatible = "ti,am3356-pru";
>>>          reg = <0x38000 0x2000>,
>>>                <0x24000 0x400>,
>>>                <0x24400 0x100>,
>>>                <0x2000  0x2000>;
>>>          reg-names = "iram", "control", "debug", "dram";
>>>          ...
>>>      };
>>>
>>> I think it is better to place a restriction that firmware on PRU0 cannot use data
>>> memory of PRU1 and vice versa.
>>>
>> That will not work as there are switch firmware cases where PRU access
>> DRAM of other PRU and is a valid case to support in the future. So let
>> us not do that.
> 
> PRU firmware accessing DRAM of other PRU is a design contract and that use case
> requires both PRUs to be loaded with matching firmware. That should continue to work.
> 
> What I'm suggesting here is that kernel remoteproc driver should have nothing to do
> with the other PRU's data RAM.
> 
> The application driver if needs both PRUs then it can obviously access both DRAMs
> as it has a phandle to both PRUs.
> 
That should be fine.

Regards,
Murali

> cheers,
> -roger
> 
>>
>> Murali
>>> Application drivers do sometimes need to read/write to data memory. The pru_rproc
>>> driver could provide a API for the application drivers to get virtual address of
>>> the respective PRU's data memory.
>>>
>>>>
>>>>      shrdram2: memory@10000 {
>>>>          device_type = "memory";
>>>>          reg = <0x10000 0x3000>;
>>>>      };
>>>
>>> Shared RAM is not so straight forward. Both PRU firmwares and both application drivers
>>> might need to read/write here. The area split is decided by firmware design and there
>>> is no hardware protection to prevent from stomping on each others toes.
>>>
>>> We need a carveout based memory allocator at least I think that can do a
>>> allocate(base_offset, size); into shared RAM.
>>>
>>> This could be used by pru_rproc driver at firmware load time and by application drivers
>>> at initialization time.
>>>
>>> Thoughts?
>>>
>>>>
>>>>      pruss_cfg: cfg@26000 {
>>>>          ...
>>>>      };
>>>>      ...
>>>> };
>>>>
>>>> If the device_type = "memory" cannot be used here for
>>>> being specific to the top level properties, then
>>>> there's probably some other generic property usable
>>>> here :)
>>>>
>>>>> +        pruss_mii_rt: mii_rt@32000 {
>>>>> +            reg = <0x32000 0x58>;
>>>>> +        };
>>>>
>>>> The node name should not have underscores so
>>>> pruss_mii_rt: mii-rt@32000. Please check the others
>>>> too, like app_node.
>>>>
>>>
>>> OK.
>>>
>>>>> +    app_node: app_node {
>>>>> +        prus = <&pru0>, <&pru1>;
>>>>> +        firmware-name = "pruss-app-fw", "pruss-app-fw-2";
>>>>> +        ti,pruss-gp-mux-sel = <2>, <1>;
>>>>> +        /* setup interrupts for prus:
>>>>> +           prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
>>>>> +           prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
>>>>> +        ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
>>>>> +    }
>>>>
>>>> If the ti,pruss-gp-mux-sel and ti,pru-interrupt-map are
>>>> firmware configuration options, maybe leave them out of
>>>> the dts completely and make the app-node optional.
>>>
>>> Yes the app-node is optional. I will mention it.
>>>
>>> No, ti,pruss-gp-mux-sel and ti,pru-interrupt-map are not firmware options.
>>> But these settings are application/firmware specific.
>>>
>>> ti,pru-interrupt-map specifies the configuration to be used for the INTC interrupt
>>> controller.
>>>
>>> ti,pruss-gp-mux-sel is used to configure this register.
>>> "Table 30-20. PRUSS_GPCFG0" in http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf
>>> "29:26 PR1_PRU0_GP_MUX_SEL"
>>>
>>> It configures how the pins from the PRUSS module are routed internally
>>> to the various modules.
>>>
>>> see "30.2.1 PRU-ICSS I/O Interface"
>>> and "Table 30-1. PRU-ICSS1 I/O Signals"
>>>
>>>>
>>>> And have a proper compatible for this node such as
>>>> "ti,pruss-app-xyz". And this should be only set if the the
>>>> hardware is wired up in such way that things need to be
>>>> configured in the dts rather than by the firmware.
>>>
>>> Yes, compatible is a required property as we need to load
>>> the appropriate application (kernel space) driver for it.
>>> I will fix the example.
>>>
>>>>
>>>> And then you can just hide mux-sel and interrupt-map
>>>> behind the compatible property for that hardware. And
>>>> leave them out from the dts and have the handling driver
>>>> would set mux-sel and interrupt-map based on the
>>>> match->data during probe.
>>>
>>> To summarize:
>>>
>>> I'll mark the app node as optional. Only required if a kernel
>>> driver is required for the application.
>>> Compatible is mandatory for app node.
>>> ti,pruss-gp-mux-sel and ti,pru-interrupt-map are optional
>>> for app node.
>>>
>>> cheers,
>>> -roger
>>>
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-05 16:15           ` Murali Karicheri
@ 2019-02-05 16:19             ` Tony Lindgren
  2019-02-06 15:04               ` Roger Quadros
  0 siblings, 1 reply; 61+ messages in thread
From: Tony Lindgren @ 2019-02-05 16:19 UTC (permalink / raw)
  To: Murali Karicheri
  Cc: Roger Quadros, s-anna, ohad, bjorn.andersson, david, nsekhar,
	t-kristo, nsaulnier, jreeder, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree

* Murali Karicheri <m-karicheri2@ti.com> [190205 16:13]:
> On 02/05/2019 10:41 AM, Roger Quadros wrote:
> > What I'm suggesting here is that kernel remoteproc driver should have nothing to do
> > with the other PRU's data RAM.
> > 
> > The application driver if needs both PRUs then it can obviously access both DRAMs
> > as it has a phandle to both PRUs.
> > 
> That should be fine.

That sounds good to me too.

For dts, yeah please allocate the resources for the modules
where the resources belong to on the PRUSS internal interconnect :)
Devices can move around on the interconnect between SoCs and the
modules can get swapped or added.

Regards,

Tony

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-05  9:39     ` Roger Quadros
  2019-02-05 15:08       ` Murali Karicheri
@ 2019-02-05 16:41       ` Tony Lindgren
  2019-02-14  3:01         ` Suman Anna
  1 sibling, 1 reply; 61+ messages in thread
From: Tony Lindgren @ 2019-02-05 16:41 UTC (permalink / raw)
  To: Roger Quadros
  Cc: s-anna, ohad, bjorn.andersson, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Linus Walleij

* Roger Quadros <rogerq@ti.com> [190205 09:40]:
> On 04/02/19 18:33, Tony Lindgren wrote:
> > 
> > 	shrdram2: memory@10000 {
> > 		device_type = "memory";
> > 		reg = <0x10000 0x3000>;
> > 	};
> 
> Shared RAM is not so straight forward. Both PRU firmwares and both application drivers
> might need to read/write here. The area split is decided by firmware design and there
> is no hardware protection to prevent from stomping on each others toes.
> 
> We need a carveout based memory allocator at least I think that can do a
> allocate(base_offset, size); into shared RAM.
> 
> This could be used by pru_rproc driver at firmware load time and by application drivers
> at initialization time.
> 
> Thoughts?

That sounds sane to me :)

> > If the ti,pruss-gp-mux-sel and ti,pru-interrupt-map are
> > firmware configuration options, maybe leave them out of
> > the dts completely and make the app-node optional.
> 
> Yes the app-node is optional. I will mention it.
> 
> No, ti,pruss-gp-mux-sel and ti,pru-interrupt-map are not firmware options.
> But these settings are application/firmware specific.
> 
> ti,pru-interrupt-map specifies the configuration to be used for the INTC interrupt
> controller.

OK. So just to see if we have a standard solution available already..
It sounds a bit similar to what we're doing with omap-wakeupgen.c
and stacked interrupts? I wonder if something similar might help
here?

> ti,pruss-gp-mux-sel is used to configure this register.
> "Table 30-20. PRUSS_GPCFG0" in http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf
> "29:26 PR1_PRU0_GP_MUX_SEL"
> 
> It configures how the pins from the PRUSS module are routed internally
> to the various modules.
> 
> see "30.2.1 PRU-ICSS I/O Interface"
> and "Table 30-1. PRU-ICSS1 I/O Signals"

Well these are external signals for PRUSS processor (although not
necessarily external signals for the SoC). So why not handle them
with a standard pinctlr binding with #pinctrl-cells?

Sure it may not even be the Linux pinctrl framework running on the
main SoC handling these pins, but after all you're describing
hardware for a processor. Maybe Linus W has some comments on this?

Regards,

Tony

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-05 16:19             ` Tony Lindgren
@ 2019-02-06 15:04               ` Roger Quadros
  2019-02-14  2:47                 ` Suman Anna
  0 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-06 15:04 UTC (permalink / raw)
  To: Tony Lindgren, Murali Karicheri
  Cc: s-anna, ohad, bjorn.andersson, david, nsekhar, t-kristo,
	nsaulnier, jreeder, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree



On 05/02/19 18:19, Tony Lindgren wrote:
> * Murali Karicheri <m-karicheri2@ti.com> [190205 16:13]:
>> On 02/05/2019 10:41 AM, Roger Quadros wrote:
>>> What I'm suggesting here is that kernel remoteproc driver should have nothing to do
>>> with the other PRU's data RAM.
>>>
>>> The application driver if needs both PRUs then it can obviously access both DRAMs
>>> as it has a phandle to both PRUs.
>>>
>> That should be fine.
> 
> That sounds good to me too.
> 
> For dts, yeah please allocate the resources for the modules
> where the resources belong to on the PRUSS internal interconnect :)
> Devices can move around on the interconnect between SoCs and the
> modules can get swapped or added.

If you take a look at "Figure 30-1. PRU-ICSS Overview" in 
http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf

You can see that DRAM0 and DRAM1 are not part of PRU. That means
they shouldn't be in the PRU node then.

cheers,
-roger

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-04 14:22 ` [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Roger Quadros
  2019-02-04 16:33   ` Tony Lindgren
@ 2019-02-08 13:51   ` Linus Walleij
  2019-02-14  3:12     ` Suman Anna
  2019-02-14  2:52   ` Suman Anna
  2 siblings, 1 reply; 61+ messages in thread
From: Linus Walleij @ 2019-02-08 13:51 UTC (permalink / raw)
  To: Roger Quadros, Marc Zyngier
  Cc: ext Tony Lindgren, Ohad Ben-Cohen, Bjorn Andersson, Suman Anna,
	David Lechner, Nori, Sekhar, Tero Kristo, nsaulnier, jreeder,
	Murali Karicheri, woods.technical, Linux-OMAP, linux-remoteproc,
	linux-kernel,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On Mon, Feb 4, 2019 at 3:24 PM Roger Quadros <rogerq@ti.com> wrote:

> From: Suman Anna <s-anna@ti.com>
>
> This patch adds the bindings for the Programmable Real-Time Unit
> and Industrial Communication Subsystem (PRU-ICSS) present on various
> SoCs such as AM33xx, AM437x, AM57xx, Keystone 66AK2G SoC, etc. It is
> present on the Davinci based OMAPL138 SoCs and K3 architecture
> based AM65x SoCs as well (not covered for now).
>
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>

(...)
> +               pruss_intc: intc@20000 {
> +                       compatible = "ti,am3356-pruss-intc";
> +                       reg = <0x20000 0x2000>;
> +                       reg-names = "intc";
> +                       interrupt-controller;
> +                       #interrupt-cells = <1>;
> +                       interrupts = <20 21 22 23 24 25 26 27>;
> +                       interrupt-names = "host2", "host3", "host4",
> +                                         "host5", "host6", "host7",
> +                                         "host8", "host9";

If thsese interrupts are mapped 1-to-1 to a parent interrupt controller
then this is a hierarchical interrupt domain and then these should
be handled locally in the driver as offset from child to parent
statically encoded in the driver.

Several old drivers and old device tree bindings make this kind
of maps, but it is not how we do it anymore, if we can avoid it.

To be able to use hierarchical interrupt domain in the kernel, the top
interrupt controller must use the hierarchical (v2) irqdomain, so
if this is anything else than the ARM GIC it will be an interesting
undertaking to handle this.

The more I understand of hierarchical irqdomains, the more of
workarounds where we should be using it I see, we really need
to spread this knowledge. Using it requires a lot of upfront work
sometimes, sorry about that but the end result is so much better.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-05  8:51       ` Roger Quadros
@ 2019-02-14  2:15         ` Suman Anna
  0 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-14  2:15 UTC (permalink / raw)
  To: Roger Quadros, Andrew F. Davis, tony, ohad, bjorn.andersson, Rob Herring
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree, Thomas Gleixner, Jason Cooper, Marc Zyngier

On 2/5/19 2:51 AM, Roger Quadros wrote:
> +Rob
> 
> Andrew,
> 
> On 04/02/19 17:33, Roger Quadros wrote:
>> On 04/02/19 17:11, Andrew F. Davis wrote:
>>> On 2/4/19 8:22 AM, Roger Quadros wrote:
>>>> From: "Andrew F. Davis" <afd@ti.com>
>>>>
>>>
>>> [...]
>>>
>>>> +static const struct pruss_intc_match_data am437x_pruss_intc_data = {
>>>> +	.no_host7_intr = true,
>>>
>>> Like done for the PRUSS driver with 'has_no_sharedram' becoming a DT
>>> flag the same could be done here, then all this match data stuff could
>>> be dropped.
>>
>> Agreed.
>>
> 
> Going back and looking at code here is a different perspective.
> 
> The has_no_sharedram case was a an odd duck because the 2 ICSSG instances
> within the same SoC (AM437x) had differences. So we couldn't use
> the compatible to differentiate there. The DT flag makes sense there.
> 
> In the no_host7_intr case, it SoC specific so we can use the compatible to
> differentiate. And AM6 SoC has different number of system_events and host_interrupts
> so that could come in macth_data as well. See below.
> 
> static const struct pruss_intc_match_data am335x_am57xx_pruss_intc_data = {
>         .num_system_events = 64,
>         .num_host_intrs = 10,
>         .no_host7_intr = false,
> };
> 
> static const struct pruss_intc_match_data am437x_k2g_pruss_intc_data = {
>         .num_system_events = 64,
>         .num_host_intrs = 10,
>         .no_host7_intr = true,
> };
> 
> static const struct pruss_intc_match_data am6x_icssg_intc_data = {
>         .num_system_events = 160,
>         .num_host_intrs = 20,
>         .no_host7_intr = false,
> };
> 
> Alternatively, we add a DT property each for all 3 of them and get rid
> of match_data entirely.
> 
> Which is a better approach?

I prefer to retain the current reliance of using of_match_data, rather
than having to add additional DT properties and parse them and define
variables to store them. This has served well in terms of scaling up and
get the variable storage for free.

Rob, what is your recommendation here?

regards
Suman

> 
> cheers,
> -roger
> 
> 
>>>
>>>> +};
>>>> +
>>>> +static const struct of_device_id pruss_intc_of_match[] = {
>>>> +	{
>>>> +		.compatible = "ti,am3356-pruss-intc",
>>>> +		.data = NULL,
>>>> +	},
>>>> +	{
>>>> +		.compatible = "ti,am4376-pruss-intc",
>>>> +		.data = &am437x_pruss_intc_data,
>>>> +	},
>>>> +	{
>>>> +		.compatible = "ti,am5728-pruss-intc",
>>>> +		.data = NULL,
>>>> +	},
>>>> +	{ /* sentinel */ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
>>>> +
>>>> +static struct platform_driver pruss_intc_driver = {
>>>> +	.driver = {
>>>> +		.name = "pruss-intc",
>>>> +		.of_match_table = pruss_intc_of_match,
>>>> +	},
>>>> +	.probe  = pruss_intc_probe,
>>>> +	.remove = pruss_intc_remove,
>>>> +};
>>>> +module_platform_driver(pruss_intc_driver);
>>>> +
>>>> +MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
>>>> +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
>>>> +MODULE_DESCRIPTION("PRU-ICSS INTC Driver");
>>>> +MODULE_LICENSE("GPL v2");
>>>> diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h
>>>> new file mode 100644
>>>> index 0000000..4538a0b
>>>> --- /dev/null
>>>> +++ b/include/linux/irqchip/irq-pruss-intc.h
>>>> @@ -0,0 +1,94 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/**
>>>> + * irq-pruss-intc.h - PRU-ICSS INTC management
>>>
>>> Filename not needed.
>>
>> OK.
>>
>> cheers,
>> -roger
>>
>>>
>>> Andrew
>>>
>>>> + *
>>>> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
>>>> + */
>>>> +
>>>> +#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
>>>> +#define __INCLUDE_LINUX_IRQCHIP_IRQ_PRUSS_INTC_H
>>>> +
>>>> +/* maximum number of system events */
>>>> +#define MAX_PRU_SYS_EVENTS	64
>>>> +
>>>> +/* maximum number of interrupt channels */
>>>> +#define MAX_PRU_CHANNELS	10
>>>> +
>>>> +/**
>>>> + * struct pruss_intc_config - INTC configuration info
>>>> + * @sysev_to_ch: system events to channel mapping information
>>>> + * @ch_to_host: interrupt channel to host interrupt information
>>>> + */
>>>> +struct pruss_intc_config {
>>>> +	s8 sysev_to_ch[MAX_PRU_SYS_EVENTS];
>>>> +	s8 ch_to_host[MAX_PRU_CHANNELS];
>>>> +};
>>>> +
>>>> +#if IS_ENABLED(CONFIG_TI_PRUSS)
>>>> +
>>>> +/**
>>>> + * pruss_intc_configure() - configure the PRUSS INTC
>>>> + * @dev: device
>>>> + * @intc_config: PRU core-specific INTC configuration
>>>> + *
>>>> + * Configures the PRUSS INTC with the provided configuration from
>>>> + * a PRU core. Any existing event to channel mappings or channel to
>>>> + * host interrupt mappings are checked to make sure there are no
>>>> + * conflicting configuration between both the PRU cores. The function
>>>> + * is intended to be used only by the PRU remoteproc driver.
>>>> + *
>>>> + * Returns 0 on success, or a suitable error code otherwise
>>>> + */
>>>> +int pruss_intc_configure(struct device *dev,
>>>> +			 struct pruss_intc_config *intc_config);
>>>> +
>>>> +/**
>>>> + * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
>>>> + * @dev: device
>>>> + * @intc_config: PRU core specific INTC configuration
>>>> + *
>>>> + * Undo whatever was done in pruss_intc_configure() for a PRU core.
>>>> + * It should be sufficient to just mark the resources free in the
>>>> + * global map and disable the host interrupts and sysevents.
>>>> + */
>>>> +int pruss_intc_unconfigure(struct device *dev,
>>>> +			   struct pruss_intc_config *intc_config);
>>>> +/**
>>>> + * pruss_intc_trigger() - trigger a PRU system event
>>>> + * @irq: linux IRQ number associated with a PRU system event
>>>> + *
>>>> + * Trigger an interrupt by signalling a specific PRU system event.
>>>> + * This can be used by PRUSS client users to raise/send an event to
>>>> + * a PRU or any other core that is listening on the host interrupt
>>>> + * mapped to that specific PRU system event. The @irq variable is the
>>>> + * Linux IRQ number associated with a specific PRU system event that
>>>> + * a client user/application uses. The interrupt mappings for this is
>>>> + * provided by the PRUSS INTC irqchip instance.
>>>> + *
>>>> + * Returns 0 on success, or an error value upon failure.
>>>> + */
>>>> +int pruss_intc_trigger(unsigned int irq);
>>>> +
>>>> +#else
>>>> +
>>>> +static inline int pruss_intc_configure(struct device *dev,
>>>> +				       struct pruss_intc_config *intc_config)
>>>> +{
>>>> +	return -ENOTSUPP;
>>>> +}
>>>> +
>>>> +static inline int pruss_intc_unconfigure(struct device *dev,
>>>> +					 struct pruss_intc_config *intc_config)
>>>> +{
>>>> +	return -ENOTSUPP;
>>>> +}
>>>> +
>>>> +static inline int pruss_intc_trigger(unsigned int irq)
>>>> +{
>>>> +	return -ENOTSUPP;
>>>> +}
>>>> +
>>>> +#endif	/* CONFIG_TI_PRUSS */
>>>> +
>>>> +#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H */
>>>> +
>>>>
>>
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip driver for PRUSS interrupts
  2019-02-05 11:04       ` Marc Zyngier
@ 2019-02-14  2:16         ` Suman Anna
  0 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-14  2:16 UTC (permalink / raw)
  To: Marc Zyngier, Roger Quadros
  Cc: Tony Lindgren, ohad, bjorn.andersson, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Andrew F. Davis,
	Thomas Gleixner, Jason Cooper

On 2/5/19 5:04 AM, Marc Zyngier wrote:
> On Tue, 05 Feb 2019 10:35:44 +0000,
> Roger Quadros <rogerq@ti.com> wrote:
>>
>> On 04/02/19 20:15, Tony Lindgren wrote:
>>> * Roger Quadros <rogerq@ti.com> [190204 14:23]:
>>>> From: "Andrew F. Davis" <afd@ti.com>
>>>>
>>>> The Programmable Real-Time Unit Subsystem (PRUSS) contains an
>>>> interrupt controller (INTC) that can handle various system input
>>>> events and post interrupts back to the device-level initiators.
>>>> The INTC can support upto 64 input events with individual control
>>>> configuration and hardware prioritization. These events are mapped
>>>> onto 10 interrupt signals through two levels of many-to-one mapping
>>>> support. Different interrupt signals are routed to the individual
>>>> PRU cores or to the host CPU.
>>>>
>>>> The PRUSS INTC platform driver manages this PRUSS interrupt
>>>> controller and implements an irqchip driver to provide a Linux
>>>> standard way for the PRU client users to enable/disable/ack/
>>>> re-trigger a PRUSS system event. The system events to interrupt
>>>> channels and host interrupts relies on the mapping configuration
>>>> provided through a firmware resource table for now. This will be
>>>> revisited and enhanced in the future for a better interface. The
>>>> mappings will currently be programmed during the boot/shutdown
>>>> of the PRU.
>>>>
>>>> The PRUSS INTC module is reference counted during the interrupt
>>>> setup phase through the irqchip's irq_request_resources() and
>>>> irq_release_resources() ops. This restricts the module from being
>>>> removed as long as there are active interrupt users.
>>>>
>>>> The PRUSS INTC can generate an interrupt to various processor
>>>> subsystems on the SoC through a set of 64 possible PRU system
>>>> events. These system events can be used by PRU client drivers
>>>> or applications for event notifications/signalling between PRUs
>>>> and MPU or other processors. An API, pruss_intc_trigger() is
>>>> provided to MPU-side PRU client drivers/applications to be able
>>>> to trigger an event/interrupt using IRQ numbers provided by the
>>>> PRUSS-INTC irqdomain chip.
>>>
>>> I suggest you send the binding patch and the interrupt
>>> controller driver separately to the irqchip guys. Maybe
>>> put the trigger function in to a separate patch that can
>>> be reviewed and applied separately.
>>
>> Good idea. I will send irqchip related patches separately.
> 
> Yes please. But also please document why you have so many non
> irq-related entry points in this irqchip driver. It seems to replicate
> the same "events vs irq" stuff we're trying to get rid of in the K3
> patches...

This is not the same, the whole INTC is a sub-module within the
sub-system serving interrupts to both the PRUs and the main host
processor. In anycase, we can add more details when we send out the
series separately.

regards
Suman

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader
  2019-02-04 15:19   ` Andrew F. Davis
@ 2019-02-14  2:22     ` Suman Anna
  0 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-14  2:22 UTC (permalink / raw)
  To: Andrew F. Davis, Roger Quadros, tony, ohad, bjorn.andersson
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree

On 2/4/19 9:19 AM, Andrew F. Davis wrote:
> On 2/4/19 8:22 AM, Roger Quadros wrote:
>> From: David Lechner <david@lechnology.com>
>>
>> This adds a special handler to the default remoteproc ELF firmware
>> loader that looks up the memory map on TI PRU firmware files.
>>
>> These processors have multiple memory maps that share the same address
>> space, so we need to know the page in addition to the physical address
>> in order to translate the address to a local CPU address.
>>
>> Signed-off-by: David Lechner <david@lechnology.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  drivers/remoteproc/remoteproc_elf_loader.c | 117 +++++++++++++++++++++++++++--
>>  include/uapi/linux/elf-em.h                |   1 +
>>  2 files changed, 112 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
>> index 8888d39..79c9d39 100644
>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> @@ -32,6 +32,103 @@
>>  
>>  #include "remoteproc_internal.h"
>>  
>> +#define SHT_TI_PHATTRS 0x7F000004
>> +#define SHT_TI_SH_PAGE 0x7F000007
>> +
>> +struct elf32_ti_phattrs {
>> +	Elf32_Half pha_seg_id; /* Segment id */
>> +	Elf32_Half pha_tag_id; /* Attribute kind id */
>> +	union {
>> +		Elf32_Off pha_offset; /* byte offset within the section */
>> +		Elf32_Word pha_value; /* Constant tag value */
>> +	} pha_un;
>> +};
>> +
>> +/* this struct is reverse engineered, so not sure what most of the values are */
> 
> Do we really not know? Someone should go check this, if they are not
> used then for now label them "unused", not "unknown".

I am following up internally within TI to get more concrete definitions
around this.

In anycase, on AM65x SoC, I actually had to implement a custom ELF
loading function due to the differences in hardware behavior [1], so I
think we should consider moving this whole logic into the PRU remoteproc
driver itself, and see if it is possible to keep the generic ELF loader
code clean and without having to introduce the flag parameter to
rproc_da_to_va() function.

regards
Suman

[1]
http://git.ti.com/gitweb/?p=ti-linux-kernel/ti-linux-kernel.git;a=commitdiff;h=529c7767b4f3cff0568c8867cb18b39526d07785

> 
> Andrew
> 
>> +struct ti_section_page {
>> +	u32 unk0;
>> +	u32 unk1;
>> +	u32 unk2;
>> +	u32 unk3;
>> +	u32 unk4;
>> +	u16 size;
>> +	u16 unk5;
>> +	u16 unk6;
>> +	u8 data[0]; /* array of size */
>> +};
>> +
>> +/**
>> + * rproc_elf_segment_to_map() - Gets memory map for segment
>> + * @id: segment id
>> + * @elf_data: pointer to ELF file data
>> + *
>> + * Returns the memory map for the segment.
>> + */
>> +static int rproc_elf_segment_to_map(u32 id, const u8 *elf_data)
>> +{
>> +	struct elf32_hdr *ehdr;
>> +	struct elf32_shdr *shdr;
>> +	struct elf32_ti_phattrs *ti_attrs = NULL;
>> +	int i;
>> +
>> +	ehdr = (struct elf32_hdr *)elf_data;
>> +	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> +
>> +	if (ehdr->e_machine != EM_TI_PRU)
>> +		return 0;
>> +
>> +	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> +		if (shdr->sh_type == SHT_TI_PHATTRS) {
>> +			ti_attrs = (struct elf32_ti_phattrs *)(elf_data + shdr->sh_offset);
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!ti_attrs)
>> +		return 0;
>> +
>> +	/* list is terminated by tag id == 0 (PHA_NULL) */
>> +	for (; ti_attrs->pha_tag_id; ti_attrs++) {
>> +		if (ti_attrs->pha_tag_id == 3 && ti_attrs->pha_seg_id == id)
>> +			return ti_attrs->pha_un.pha_value;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * rproc_elf_section_to_map() - Gets memory map for section
>> + * @id: segment id
>> + * @elf_data: pointer to ELF file data
>> + *
>> + * Returns the memory map for the section.
>> + */
>> +static int rproc_elf_section_to_map(u32 id, const u8 *elf_data)
>> +{
>> +	struct elf32_hdr *ehdr;
>> +	struct elf32_shdr *shdr;
>> +	struct ti_section_page *map = NULL;
>> +	int i;
>> +
>> +	ehdr = (struct elf32_hdr *)elf_data;
>> +	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> +
>> +	if (ehdr->e_machine != EM_TI_PRU)
>> +		return 0;
>> +
>> +	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> +		if (shdr->sh_type == SHT_TI_SH_PAGE) {
>> +			map = (struct ti_section_page *)(elf_data + shdr->sh_offset);
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!map || id >= map->size)
>> +		return 0;
>> +
>> +	return map->data[id];
>> +}
>> +
>>  /**
>>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>>   * @rproc: the remote processor handle
>> @@ -147,7 +244,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>>  	struct device *dev = &rproc->dev;
>>  	struct elf32_hdr *ehdr;
>>  	struct elf32_phdr *phdr;
>> -	int i, ret = 0;
>> +	int i, map, ret = 0;
>>  	const u8 *elf_data = fw->data;
>>  
>>  	ehdr = (struct elf32_hdr *)elf_data;
>> @@ -181,8 +278,10 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>>  			break;
>>  		}
>>  
>> +		map = rproc_elf_segment_to_map(i, elf_data);
>> +
>>  		/* grab the kernel address for this device address */
>> -		ptr = rproc_da_to_va(rproc, da, memsz, 0);
>> +		ptr = rproc_da_to_va(rproc, da, memsz, map);
>>  		if (!ptr) {
>>  			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>>  			ret = -EINVAL;
>> @@ -209,7 +308,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>>  EXPORT_SYMBOL(rproc_elf_load_segments);
>>  
>>  static struct elf32_shdr *
>> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>> +find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size, int *id)
>>  {
>>  	struct elf32_shdr *shdr;
>>  	int i;
>> @@ -261,6 +360,9 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>>  			return NULL;
>>  		}
>>  
>> +		if (id)
>> +			*id = i;
>> +
>>  		return shdr;
>>  	}
>>  
>> @@ -288,7 +390,7 @@ int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>>  
>>  	ehdr = (struct elf32_hdr *)elf_data;
>>  
>> -	shdr = find_table(dev, ehdr, fw->size);
>> +	shdr = find_table(dev, ehdr, fw->size, NULL);
>>  	if (!shdr)
>>  		return -EINVAL;
>>  
>> @@ -328,11 +430,14 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>>  {
>>  	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>>  	struct elf32_shdr *shdr;
>> +	int id, map;
>>  
>> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
>> +	shdr = find_table(&rproc->dev, ehdr, fw->size, &id);
>>  	if (!shdr)
>>  		return NULL;
>>  
>> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, 0);
>> +	map = rproc_elf_section_to_map(id, fw->data);
>> +
>> +	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, map);
>>  }
>>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>> diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h
>> index 0c3000fa..70b487a 100644
>> --- a/include/uapi/linux/elf-em.h
>> +++ b/include/uapi/linux/elf-em.h
>> @@ -38,6 +38,7 @@
>>  #define EM_BLACKFIN     106     /* ADI Blackfin Processor */
>>  #define EM_ALTERA_NIOS2	113	/* Altera Nios II soft-core processor */
>>  #define EM_TI_C6000	140	/* TI C6X DSPs */
>> +#define EM_TI_PRU	144	/* TI Programmable Realtime Unit */
>>  #define EM_AARCH64	183	/* ARM 64 bit */
>>  #define EM_TILEPRO	188	/* Tilera TILEPro */
>>  #define EM_MICROBLAZE	189	/* Xilinx MicroBlaze */
>>


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver
  2019-02-04 14:22 ` [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver Roger Quadros
@ 2019-02-14  2:35   ` Suman Anna
  2019-02-14  3:44     ` Suman Anna
  0 siblings, 1 reply; 61+ messages in thread
From: Suman Anna @ 2019-02-14  2:35 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree, Andrew F . Davis

Hi Roger,

On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: Suman Anna <s-anna@ti.com>
> 
> The Programmable Real-Time Unit Subsystem (PRUSS) consists of
> dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs)
> for program execution. This patch adds a remoteproc platform
> driver for managing the individual PRU RISC cores life cycle.
> 
> This remoteproc driver does not have support for error recovery
> and system suspend/resume features. Different compatibles are
> used to allow providing scalability for instance-specific device
> data if needed. The driver uses a default firmware-name retrieved
> from device-tree, and the firmwares are expected to be present
> in the standard Linux firmware search paths. They can also be
> adjusted by userspace if required through the sysfs interface
> provided by the remoteproc core.
> 
> The PRU remoteproc driver uses a client-driven boot methodology
> - it does _not_ support auto-boot so that the PRU load and boot
> is dictated by the corresponding client drivers for achieving
> various usecases. This allows flexibility for the client drivers
> or applications to set a firmware name (if needed) based on their
> desired functionality and boot the PRU. The sysfs bind and unbind
> attributes have also been suppressed so that the PRU devices cannot
> be unbound and thereby shutdown a PRU from underneath a PRU client
> driver.
> 
> A new entry 'single_step' is added to the remoteproc debugfs dir.
> The 'single_step' utilizes the single-step execution of the PRU
> cores. Writing a non-zero value performs a single step, and a
> zero value restores the PRU to execute in the same mode as the
> mode before the first single step. (note: if the PRU is halted
> because of a halt instruction, then no change occurs).
> 
> pru_rproc_get() and pru_rproc_put() functions allow client drivers
> to acquire and release the remoteproc device associated with a PRU core.
> The PRU cores are treated as resources with only one client owning
> it at a time.
> 
> PRU interrupt mapping can be provided via devicetree using
> ti,pru-interrupt-map property or via the resource table in the
> firmware blob. If both are provided, the config in DT takes precedence.
> For interrupt map via resource table, pru-software-support-package [1]
> has been historically using version 0 for this. However, the current
> data structure is not scaleable and is not self sufficient.
> 1) it hard codes number of channel to host mappings so is not
> scaleable to newer SoCs than have more of these.
> 2) it does not contain the event to channel mappings within
> itself but relies on a pointer to point to another section
> in data memory. This causes a weird complication that the
> respective data section must be loaded before we can really
> use the INTC map.
> 
> With this patch we drop support for version 0 and support
> version 1 which is a more robust and scalable data structure.
> It should be able to support a sufficiently large number (255) of
> sysevents, channels and host interrupts and is self contained
> so it can be used without dependency on order of loading sections.

Hmm, looks like you squashed a whole bunch of patches into this. I would
prefer some of the logical ones to be separated out just like before,
makes it easier to review the interfaces.

Looks like you have also changed usage behavior on couple of things and
dropped some of my original changes. I was not able to test this series
either on AM335x or on AM57xx to comment more on the behavior (not even
seeing the pruss devices populated, not sure what pieces are missing still).

> 
> [1]  git://git.ti.com/pru-software-support-package/pru-software-support-package.git
> 
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Andrew F. Davis <afd@ti.com>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/remoteproc/Kconfig           |  14 +
>  drivers/remoteproc/Makefile          |   1 +
>  drivers/remoteproc/pru_rproc.c       | 930 +++++++++++++++++++++++++++++++++++
>  drivers/remoteproc/pru_rproc.h       |  54 ++
>  include/linux/remoteproc/pru_rproc.h |  27 +
>  5 files changed, 1026 insertions(+)
>  create mode 100644 drivers/remoteproc/pru_rproc.c
>  create mode 100644 drivers/remoteproc/pru_rproc.h
>  create mode 100644 include/linux/remoteproc/pru_rproc.h
> 
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index f0abd26..333666e 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -197,6 +197,20 @@ config ST_REMOTEPROC
>  config ST_SLIM_REMOTEPROC
>  	tristate
>  
> +config PRUSS_REMOTEPROC
> +	tristate "TI PRUSS remoteproc support"
> +	depends on TI_PRUSS
> +	default n
> +	help
> +	  Support for TI PRU-ICSS remote processors via the remote processor
> +	  framework.
> +
> +	  Currently supported on AM33xx SoCs.
> +
> +	  Say Y or M here to support the Programmable Realtime Unit (PRU)
> +	  processors on various TI SoCs. It's safe to say N here if you're
> +	  not interested in the PRU or if you are unsure.
> +
>  endif # REMOTEPROC
>  
>  endmenu
> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> index ce5d061..88a86cc 100644
> --- a/drivers/remoteproc/Makefile
> +++ b/drivers/remoteproc/Makefile
> @@ -26,3 +26,4 @@ qcom_wcnss_pil-y			+= qcom_wcnss.o
>  qcom_wcnss_pil-y			+= qcom_wcnss_iris.o
>  obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
>  obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
> +obj-$(CONFIG_PRUSS_REMOTEPROC)		+= pru_rproc.o
> diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
> new file mode 100644
> index 0000000..ddd4b64
> --- /dev/null
> +++ b/drivers/remoteproc/pru_rproc.c
> @@ -0,0 +1,930 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PRU-ICSS remoteproc driver for various TI SoCs
> + *
> + * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
> + *	Suman Anna <s-anna@ti.com>
> + *	Andrew F. Davis <afd@ti.com>
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/debugfs.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqchip/irq-pruss-intc.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/remoteproc.h>
> +#include <linux/remoteproc/pru_rproc.h>
> +#include <linux/pruss.h>
> +
> +#include "remoteproc_internal.h"
> +#include "pru_rproc.h"
> +
> +/* ELF PAGE ID */
> +#define PRU_PAGE_IRAM	0
> +#define PRU_PAGE_DRAM	1
> +
> +/* IRAM offsets */
> +#define PRU0_IRAM_START		0x34000
> +#define PRU1_IRAM_START		0x38000
> +#define PRU_IRAM_MASK		0x3ffff
> +
> +/* PRU_ICSS_PRU_CTRL registers */
> +#define PRU_CTRL_CTRL		0x0000
> +#define PRU_CTRL_STS		0x0004
> +#define PRU_CTRL_WAKEUP_EN	0x0008
> +#define PRU_CTRL_CYCLE		0x000C
> +#define PRU_CTRL_STALL		0x0010
> +#define PRU_CTRL_CTBIR0		0x0020
> +#define PRU_CTRL_CTBIR1		0x0024
> +#define PRU_CTRL_CTPPR0		0x0028
> +#define PRU_CTRL_CTPPR1		0x002C
> +
> +/* CTRL register bit-fields */
> +#define CTRL_CTRL_SOFT_RST_N	BIT(0)
> +#define CTRL_CTRL_EN		BIT(1)
> +#define CTRL_CTRL_SLEEPING	BIT(2)
> +#define CTRL_CTRL_CTR_EN	BIT(3)
> +#define CTRL_CTRL_SINGLE_STEP	BIT(8)
> +#define CTRL_CTRL_RUNSTATE	BIT(15)
> +
> +/* PRU_ICSS_PRU_DEBUG registers */
> +#define PRU_DEBUG_GPREG(x)	(0x0000 + (x) * 4)
> +#define PRU_DEBUG_CT_REG(x)	(0x0080 + (x) * 4)
> +
> +/**
> + * struct pru_rproc - PRU remoteproc structure
> + * @id: id of the PRU core within the PRUSS
> + * @pruss: back-reference to parent PRUSS structure
> + * @rproc: remoteproc pointer for this PRU core
> + * @iram_region: PRU IRAM IOMEM
> + * @ctrl_regmap: regmap to PRU CTRL IOMEM
> + * @debug_regmap: regmap to PRU DEBUG IOMEM
> + * @client_np: client device node
> + * @intc_config: PRU INTC configuration data
> + * @dram0: PRUSS DRAM0 region
> + * @dram1: PRUSS DRAM1 region
> + * @shrdram: PRUSS SHARED RAM region
> + * @iram_da: device address of Instruction RAM for this PRU
> + * @pdram_da: device address of primary Data RAM for this PRU
> + * @sdram_da: device address of secondary Data RAM for this PRU
> + * @shrdram_da: device address of shared Data RAM
> + * @cfg: regmap to CFG module
> + * @gpcfg_reg: offset to gpcfg register of this PRU
> + * @fw_name: name of firmware image used during loading
> + * @gpmux_save: saved value for gpmux config
> + * @dt_irqs: number of irqs configured from DT
> + * @fw_irqs: number of irqs configured from FW
> + * @lock: mutex to protect client usage
> + * @dbg_single_step: debug state variable to set PRU into single step mode
> + * @ctrl_saved_state: saved CTRL state to return to normal mode
> + */
> +struct pru_rproc {
> +	int id;
> +	struct pruss *pruss;
> +	struct rproc *rproc;
> +	struct pruss_mem_region iram_region;
> +	struct regmap *ctrl_regmap;
> +	struct regmap *debug_regmap;
> +	struct device_node *client_np;
> +	struct pruss_intc_config intc_config;
> +	struct pruss_mem_region dram0;
> +	struct pruss_mem_region dram1;
> +	struct pruss_mem_region shrdram;
> +	u32 iram_da;
> +	u32 pdram_da;
> +	u32 sdram_da;
> +	u32 shrdram_da;
> +	struct regmap *cfg;
> +	int gpcfg_reg;
> +	const char *fw_name;
> +	u8 gpmux_save;
> +	int dt_irqs;
> +	int fw_irqs;
> +	struct mutex lock; /* client access lock */
> +	bool dbg_single_step;
> +	u32 ctrl_saved_state;
> +};
> +
> +/**
> + * pru_rproc_set_firmware() - set firmware for a pru core
> + * @rproc: the rproc instance of the PRU
> + * @fw_name: the new firmware name, or NULL if default is desired
> + */
> +static int pru_rproc_set_firmware(struct rproc *rproc, const char *fw_name)
> +{
> +	struct pru_rproc *pru = rproc->priv;
> +
> +	if (!fw_name)
> +		fw_name = pru->fw_name;
> +
> +	return rproc_set_firmware(rproc, fw_name);
> +}
> +
> +/*
> + * pru_get_gpmux() - get the current GPMUX value for a PRU device
> + * @pru: pru_rproc instance
> + * @mux: pointer to store the current mux value into
> + *
> + * returns 0 on success, negative error value otherwise.
> + */
> +static int pru_get_gpmux(struct pru_rproc *pru, u8 *mux)
> +{
> +	int ret;
> +	unsigned int val;
> +
> +	ret = regmap_read(pru->cfg, pru->gpcfg_reg, &val);
> +	if (ret)
> +		return ret;
> +
> +	*mux = (u8)((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK) >>
> +		    PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
> +
> +	return 0;
> +}
> +
> +/**
> + * pru_set_gpmux() - set the GPMUX value for a PRU device
> + * @pru: pru_rproc instance
> + * @mux: new mux value for PRU
> + *
> + * returns 0 on success, negative error value otherwise.
> + */
> +static int pru_set_gpmux(struct pru_rproc *pru, u8 mux)
> +{
> +	if (mux >= PRUSS_GP_MUX_SEL_MAX)
> +		return -EINVAL;
> +
> +	return regmap_update_bits(pru->cfg, pru->gpcfg_reg,
> +				  PRUSS_GPCFG_PRU_MUX_SEL_MASK,
> +				  (u32)mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
> +}
> +
> +static int pru_get_intc_dt_config(struct pru_rproc *pru,
> +				  const char *propname, int index,
> +				  struct pruss_intc_config *intc_config)
> +{
> +	struct device *dev = &pru->rproc->dev;
> +	struct device_node *np = pru->client_np;
> +	struct property *prop;
> +	int ret = 0, entries, i;
> +	int dt_irqs = 0;
> +	u32 *arr;
> +	int max_system_events, max_pru_channels, max_pru_host_ints;
> +
> +	max_system_events = MAX_PRU_SYS_EVENTS;
> +	max_pru_channels = MAX_PRU_CHANNELS;
> +	max_pru_host_ints = MAX_PRU_CHANNELS;
> +
> +	prop = of_find_property(np, propname, NULL);
> +	if (!prop)
> +		return 0;
> +
> +	entries = of_property_count_u32_elems(np, propname);
> +	if (entries <= 0 || entries % 4)
> +		return -EINVAL;
> +
> +	arr = kmalloc_array(entries, sizeof(u32), GFP_KERNEL);
> +	if (!arr)
> +		return -ENOMEM;
> +
> +	ret = of_property_read_u32_array(np, propname, arr, entries);
> +	if (ret)
> +		return -EINVAL;
> +
> +	for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++)
> +		intc_config->sysev_to_ch[i] = -1;
> +
> +	for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++)
> +		intc_config->ch_to_host[i] = -1;
> +
> +	for (i = 0; i < entries; i += 4) {
> +		if (arr[i] != index)
> +			continue;
> +
> +		if (arr[i + 1] < 0 ||
> +		    arr[i + 1] >= max_system_events) {
> +			dev_err(dev, "bad sys event %d\n", arr[i + 1]);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		if (arr[i + 2] < 0 ||
> +		    arr[i + 2] >= max_pru_channels) {
> +			dev_err(dev, "bad channel %d\n", arr[i + 2]);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		if (arr[i + 3] < 0 ||
> +		    arr[i + 3] >= max_pru_host_ints) {
> +			dev_err(dev, "bad irq %d\n", arr[i + 3]);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		intc_config->sysev_to_ch[arr[i + 1]] = arr[i + 2];
> +		dev_dbg(dev, "sysevt-to-ch[%d] -> %d\n", arr[i + 1],
> +			arr[i + 2]);
> +
> +		intc_config->ch_to_host[arr[i + 2]] = arr[i + 3];
> +		dev_dbg(dev, "chnl-to-host[%d] -> %d\n", arr[i + 2],
> +			arr[i + 3]);
> +
> +		dt_irqs++;
> +	}
> +
> +	kfree(arr);
> +	return dt_irqs;
> +
> +err:
> +	kfree(arr);
> +	return ret;
> +}
> +
> +static struct rproc *__pru_rproc_get(struct device_node *np, int index)
> +{
> +	struct device_node *rproc_np = NULL;
> +	struct platform_device *pdev;
> +	struct rproc *rproc;
> +
> +	rproc_np = of_parse_phandle(np, "prus", index);
> +	if (!rproc_np || !of_device_is_available(rproc_np))
> +		return ERR_PTR(-ENODEV);
> +
> +	pdev = of_find_device_by_node(rproc_np);
> +	of_node_put(rproc_np);
> +
> +	if (!pdev)
> +		/* probably PRU not yet probed */
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	/* TODO: replace the crude string based check to make sure it is PRU */
> +	if (!strstr(dev_name(&pdev->dev), "pru")) {
> +		put_device(&pdev->dev);
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	rproc = platform_get_drvdata(pdev);
> +	put_device(&pdev->dev);
> +	if (!rproc)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	get_device(&rproc->dev);
> +
> +	return rproc;
> +}
> +
> +/**
> + * pru_rproc_get() - get the PRU rproc instance from a device node
> + * @np: the user/client device node
> + * @index: index to use for the prus property
> + *
> + * This function looks through a client device node's "prus" property at index
> + * @index and returns the rproc handle for a valid PRU remote processor if
> + * found. The function allows only one user to own the PRU rproc resource at
> + * a time. Caller must call pru_rproc_put() when done with using the rproc,
> + * not required if the function returns a failure.
> + *
> + * Returns the rproc handle on success, and an ERR_PTR on failure using one
> + * of the following error values
> + *    -ENODEV if device is not found
> + *    -EBUSY if PRU is already acquired by anyone
> + *    -EPROBE_DEFER is PRU device is not probed yet
> + */
> +struct rproc *pru_rproc_get(struct device_node *np, int index)
> +{
> +	struct rproc *rproc;
> +	struct pru_rproc *pru;
> +	struct device *dev;
> +	int ret;
> +	u32 mux;
> +	const char *fw_name;
> +
> +	rproc = __pru_rproc_get(np, index);
> +	if (IS_ERR(rproc))
> +		return rproc;
> +
> +	pru = rproc->priv;
> +	dev = &rproc->dev;
> +
> +	mutex_lock(&pru->lock);
> +
> +	if (pru->client_np) {
> +		mutex_unlock(&pru->lock);
> +		put_device(&rproc->dev);
> +		return ERR_PTR(-EBUSY);
> +	}
> +
> +	pru->client_np = np;
> +
> +	mutex_unlock(&pru->lock);
> +
> +	ret = pru_get_gpmux(pru, &pru->gpmux_save);
> +	if (ret) {
> +		dev_err(dev, "failed to get cfg gpmux: %d\n", ret);
> +		goto err;
> +	}
> +
> +	ret = of_property_read_u32_index(np, "ti,pruss-gp-mux-sel", index,
> +					 &mux);
> +	if (!ret) {
> +		ret = pru_set_gpmux(pru, mux);
> +		if (ret) {
> +			dev_err(dev, "failed to set cfg gpmux: %d\n", ret);
> +			goto err;
> +		}
> +	}
> +
> +	ret = of_property_read_string_index(np, "firmware-name", index,
> +					    &fw_name);
> +	if (!ret) {
> +		ret = pru_rproc_set_firmware(rproc, fw_name);
> +		if (ret) {
> +			dev_err(dev, "failed to set firmware: %d\n", ret);
> +			goto err;
> +		}
> +	}
> +
> +	ret = pru_get_intc_dt_config(pru, "ti,pru-interrupt-map",
> +				     index, &pru->intc_config);
> +	if (ret < 0) {
> +		dev_err(dev, "error getting DT interrupt map: %d\n", ret);
> +		goto err;
> +	}
> +
> +	pru->dt_irqs = ret;
> +
> +	return rproc;
> +
> +err:
> +	pru_rproc_put(rproc);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(pru_rproc_get);
> +
> +/**
> + * pru_rproc_put() - release the PRU rproc resource
> + * @rproc: the rproc resource to release
> + *
> + * Releases the PRU rproc resource and makes it available to other
> + * users.
> + */
> +void pru_rproc_put(struct rproc *rproc)
> +{
> +	struct pru_rproc *pru;
> +
> +	if (IS_ERR_OR_NULL(rproc))
> +		return;
> +
> +	/* TODO: replace the crude string based check to make sure it is PRU */
> +	if (!strstr(dev_name(rproc->dev.parent), "pru"))
> +		return;
> +
> +	pru = rproc->priv;
> +	if (!pru->client_np)
> +		return;
> +
> +	pru_rproc_set_firmware(rproc, NULL);
> +	pru_set_gpmux(pru, pru->gpmux_save);
> +
> +	mutex_lock(&pru->lock);
> +	pru->client_np = NULL;
> +	mutex_unlock(&pru->lock);
> +
> +	put_device(&rproc->dev);
> +}
> +EXPORT_SYMBOL_GPL(pru_rproc_put);
> +
> +/*
> + * Control PRU single-step mode
> + *
> + * This is a debug helper function used for controlling the single-step
> + * mode of the PRU. The PRU Debug registers are not accessible when the
> + * PRU is in RUNNING state.
> + *
> + * Writing a non-zero value sets the PRU into single-step mode irrespective
> + * of its previous state. The PRU mode is saved only on the first set into
> + * a single-step mode. Writing a zero value will restore the PRU into its
> + * original mode.
> + */
> +static int pru_rproc_debug_ss_set(void *data, u64 val)
> +{
> +	struct rproc *rproc = data;
> +	struct pru_rproc *pru = rproc->priv;
> +	u32 reg_val;
> +	bool debug_ss;
> +
> +	debug_ss = !!val;
> +	if (!debug_ss && !pru->dbg_single_step)
> +		return 0;
> +
> +	regmap_read(pru->ctrl_regmap, PRU_CTRL_CTRL, &reg_val);
> +
> +	if (debug_ss && !pru->dbg_single_step)
> +		pru->ctrl_saved_state = reg_val;
> +
> +	if (debug_ss)
> +		reg_val |= CTRL_CTRL_SINGLE_STEP | CTRL_CTRL_EN;
> +	else
> +		reg_val = pru->ctrl_saved_state;
> +
> +	pru->dbg_single_step = debug_ss;
> +	regmap_write(pru->ctrl_regmap, PRU_CTRL_CTRL, reg_val);
> +
> +	return 0;
> +}
> +
> +static int pru_rproc_debug_ss_get(void *data, u64 *val)
> +{
> +	struct rproc *rproc = data;
> +	struct pru_rproc *pru = rproc->priv;
> +
> +	*val = pru->dbg_single_step;
> +
> +	return 0;
> +}
> +DEFINE_SIMPLE_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get,
> +			pru_rproc_debug_ss_set, "%llu\n");
> +
> +/*
> + * Create PRU-specific debugfs entries
> + *
> + * The entries are created only if the parent remoteproc debugfs directory
> + * exists, and will be cleaned up by the remoteproc core.
> + */
> +static void pru_rproc_create_debug_entries(struct rproc *rproc)
> +{
> +	if (!rproc->dbg_dir)
> +		return;
> +
> +	debugfs_create_file("single_step", 0600, rproc->dbg_dir,
> +			    rproc, &pru_rproc_debug_ss_fops);
> +}
> +
> +static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len);
> +
> +/*
> + * parse the custom interrupt map resource and save the intc_config
> + * for use when booting the processor.
> + */
> +static int pru_handle_vendor_intrmap(struct rproc *rproc,
> +				     struct fw_rsc_pruss_intrmap *rsc)
> +{
> +	int fw_irqs = 0, i, ret = 0;
> +	u8 *arr;
> +	struct device *dev = &rproc->dev;
> +	struct pru_rproc *pru = rproc->priv;
> +
> +	dev_dbg(dev, "vendor rsc intc: version %d\n", rsc->version);
> +
> +	/*
> +	 * 0 was prototyping version. Not supported.
> +	 * 1 is currently supported version.
> +	 */
> +	if (rsc->version == 0 || rsc->version > 1) {
> +		dev_err(dev, "Unsupported version %d\n", rsc->version);
> +		return -EINVAL;
> +	}
> +
> +	/* DT provided INTC config takes precedence */
> +	if (pru->dt_irqs) {
> +		dev_info(dev, "INTC config in DT and FW. Using DT config.\n");
> +		return 0;
> +	}
> +
> +	arr = rsc->data;
> +
> +	for (i = 0; i < ARRAY_SIZE(pru->intc_config.sysev_to_ch); i++)
> +		pru->intc_config.sysev_to_ch[i] = -1;
> +
> +	for (i = 0; i < ARRAY_SIZE(pru->intc_config.ch_to_host); i++)
> +		pru->intc_config.ch_to_host[i] = -1;
> +
> +	for (i = 0; i < rsc->num_maps * 3; i += 3) {
> +		if (arr[i] < 0 ||
> +		    arr[i] >= MAX_PRU_SYS_EVENTS) {
> +			dev_err(dev, "bad sys event %d\n", arr[i]);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		if (arr[i + 1] < 0 ||
> +		    arr[i + 1] >= MAX_PRU_CHANNELS) {
> +			dev_err(dev, "bad channel %d\n", arr[i + 1]);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		if (arr[i + 2] < 0 ||
> +		    arr[i + 2] >= MAX_PRU_CHANNELS) {
> +			dev_err(dev, "bad host irq %d\n", arr[i + 2]);
> +				ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		pru->intc_config.sysev_to_ch[arr[i]] = arr[i + 1];
> +		dev_dbg(dev, "sysevt-to-ch[%d] -> %d\n", arr[i],
> +			arr[i + 1]);
> +
> +		pru->intc_config.ch_to_host[arr[i + 1]] = arr[i + 2];
> +		dev_dbg(dev, "chnl-to-host[%d] -> %d\n", arr[i + 1],
> +			arr[i + 2]);
> +
> +		fw_irqs++;
> +	}
> +
> +	pru->fw_irqs = fw_irqs;
> +	return 0;
> +
> +err:
> +	pru->fw_irqs = 0;
> +	return ret;
> +}
> +
> +/* PRU-specific vendor resource handler */
> +static int pru_rproc_handle_vendor_rsc(struct rproc *rproc,
> +				       struct fw_rsc_vendor *ven_rsc)
> +{
> +	struct device *dev = rproc->dev.parent;
> +	int ret = -EINVAL;
> +
> +	struct fw_rsc_pruss_intrmap *rsc;
> +
> +	rsc = (struct fw_rsc_pruss_intrmap *)ven_rsc->data;
> +
> +	switch (rsc->type) {
> +	case PRUSS_RSC_INTRS:
> +		ret = pru_handle_vendor_intrmap(rproc, rsc);
> +		break;
> +	default:
> +		dev_err(dev, "%s: cannot handle unknown type %d\n", __func__,
> +			rsc->type);
> +	}
> +
> +	return ret;
> +}
> +
> +/* start a PRU core */
> +static int pru_rproc_start(struct rproc *rproc)
> +{
> +	struct device *dev = &rproc->dev;
> +	struct pru_rproc *pru = rproc->priv;
> +	u32 val;
> +	int ret;
> +
> +	dev_dbg(dev, "starting PRU%d: entry-point = 0x%x\n",
> +		pru->id, (rproc->bootaddr >> 2));
> +
> +	if (pru->dt_irqs || pru->fw_irqs) {
> +		ret = pruss_intc_configure(rproc->dev.parent,
> +					   &pru->intc_config);
> +		if (ret) {
> +			dev_err(dev, "failed to configure intc %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16);
> +	regmap_write(pru->ctrl_regmap, PRU_CTRL_CTRL, val);
> +
> +	return 0;
> +}
> +
> +/* stop/disable a PRU core */
> +static int pru_rproc_stop(struct rproc *rproc)
> +{
> +	struct device *dev = &rproc->dev;
> +	struct pru_rproc *pru = rproc->priv;
> +
> +	dev_dbg(dev, "stopping PRU%d\n", pru->id);
> +	regmap_update_bits(pru->ctrl_regmap, PRU_CTRL_CTRL, CTRL_CTRL_EN, 0);
> +
> +	/* undo INTC config */
> +	if (pru->dt_irqs || pru->fw_irqs)
> +		pruss_intc_unconfigure(rproc->dev.parent, &pru->intc_config);
> +
> +	return 0;
> +}
> +
> +/*
> + * Convert PRU device address (data spaces only) to kernel virtual address
> + *
> + * Each PRU has access to all data memories within the PRUSS, accessible at
> + * different ranges. So, look through both its primary and secondary Data
> + * RAMs as well as any shared Data RAM to convert a PRU device address to
> + * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data
> + * RAM1 is primary Data RAM for PRU1.
> + */
> +static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len)
> +{
> +	struct pruss_mem_region dram0, dram1, shrd_ram;
> +	u32 offset;
> +	void *va = NULL;
> +
> +	if (len <= 0)
> +		return NULL;
> +
> +	dram0 = pru->dram0;
> +	dram1 = pru->dram1;
> +	/* PRU1 has its local RAM addresses reversed */
> +	if (pru->id == 1)
> +		swap(dram0, dram1);
> +	shrd_ram = pru->shrdram;
> +
> +	if (da >= pru->pdram_da && da + len <= pru->pdram_da + dram0.size) {
> +		offset = da - pru->pdram_da;
> +		va = (__force void *)(dram0.va + offset);
> +	} else if (da >= pru->sdram_da &&
> +		   da + len <= pru->sdram_da + dram1.size) {
> +		offset = da - pru->sdram_da;
> +		va = (__force void *)(dram1.va + offset);
> +	} else if (da >= pru->shrdram_da &&
> +		   da + len <= pru->shrdram_da + shrd_ram.size) {
> +		offset = da - pru->shrdram_da;
> +		va = (__force void *)(shrd_ram.va + offset);
> +	}
> +
> +	return va;
> +}
> +
> +/*
> + * Convert PRU device address (instruction space) to kernel virtual address
> + *
> + * A PRU does not have an unified address space. Each PRU has its very own
> + * private Instruction RAM, and its device address is identical to that of
> + * its primary Data RAM device address.
> + */
> +static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, int len)
> +{
> +	u32 offset;
> +	void *va = NULL;
> +
> +	if (len <= 0)
> +		return NULL;
> +
> +	if (da >= pru->iram_da &&
> +	    da + len <= pru->iram_da + pru->iram_region.size) {
> +		offset = da - pru->iram_da;
> +		va = (__force void *)(pru->iram_region.va + offset);
> +	}
> +
> +	return va;
> +}
> +
> +/* PRU-specific address translator */
> +static void *pru_da_to_va(struct rproc *rproc, u64 da, int len, int map)
> +{
> +	struct pru_rproc *pru = rproc->priv;
> +	void *va;
> +
> +	switch (map) {
> +	case PRU_PAGE_IRAM:
> +		va = pru_i_da_to_va(pru, da, len);
> +		break;
> +	case PRU_PAGE_DRAM:
> +		va = pru_d_da_to_va(pru, da, len);
> +		break;
> +	default:
> +		dev_info(&rproc->dev, "%s: invalid page %d\n", __func__, map);
> +		return 0;
> +	};
> +
> +	return va;
> +}
> +
> +static struct rproc_ops pru_rproc_ops = {
> +	.start			= pru_rproc_start,
> +	.stop			= pru_rproc_stop,
> +	.da_to_va		= pru_da_to_va,
> +	.handle_vendor_rsc	= pru_rproc_handle_vendor_rsc,
> +};
> +
> +static int pru_rproc_set_id(struct pru_rproc *pru)
> +{
> +	int ret = 0;
> +	u32 iram_start = pru->iram_region.pa & PRU_IRAM_MASK;
> +
> +	if (iram_start == PRU0_IRAM_START)
> +		pru->id = 0;
> +	else if (iram_start == PRU1_IRAM_START)
> +		pru->id = 1;
> +	else
> +		ret = -EINVAL;
> +
> +	return ret;
> +}
> +
> +static struct regmap_config pru_ctrl_regmap_config = {
> +	.name = "ctrl",
> +	.reg_bits = 32,
> +	.reg_stride = 4,
> +	.val_bits = 32,
> +	.max_register = PRU_CTRL_CTPPR1,
> +};
> +
> +static struct regmap_config pru_debug_regmap_config = {
> +	.name = "debug",
> +	.reg_bits = 32,
> +	.reg_stride = 4,
> +	.val_bits = 32,
> +	.max_register = PRU_DEBUG_CT_REG(31),
> +};
> +
> +static int pru_rproc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct platform_device *ppdev = to_platform_device(dev->parent);
> +	struct pru_rproc *pru;
> +	const char *fw_name;
> +	struct rproc *rproc = NULL;
> +	struct resource *res;
> +	int ret;
> +	void __iomem *va;
> +
> +	if (!np) {
> +		dev_err(dev, "Non-DT platform device not supported\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = of_property_read_string(np, "firmware-name", &fw_name);
> +	if (ret) {
> +		dev_err(dev, "unable to retrieve firmware-name %d\n", ret);
> +		return ret;
> +	}
> +
> +	rproc = rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name,
> +			    sizeof(*pru));
> +	if (!rproc) {
> +		dev_err(dev, "rproc_alloc failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	pru = rproc->priv;
> +	pru->cfg = syscon_regmap_lookup_by_phandle(np, "gpcfg");
> +	if (IS_ERR(pru->cfg)) {
> +		if (PTR_ERR(pru->cfg) != -EPROBE_DEFER)
> +			dev_err(dev, "can't get gpcfg syscon regmap\n");
> +
> +		return PTR_ERR(pru->cfg);
> +	}
> +
> +	if (of_property_read_u32_index(np, "gpcfg", 1, &pru->gpcfg_reg)) {
> +		dev_err(dev, "couldn't get gpcfg reg. offset\n");
> +		return -EINVAL;
> +	}
> +
> +	/* error recovery is not supported for PRUs */
> +	rproc->recovery_disabled = true;
> +
> +	/*
> +	 * rproc_add will auto-boot the processor normally, but this is
> +	 * not desired with PRU client driven boot-flow methodology. A PRU
> +	 * application/client driver will boot the corresponding PRU
> +	 * remote-processor as part of its state machine either through
> +	 * the remoteproc sysfs interface or through the equivalent kernel API
> +	 */
> +	rproc->auto_boot = false;
> +
> +	pru->pruss = platform_get_drvdata(ppdev);
> +	pru->rproc = rproc;
> +	pru->fw_name = fw_name;
> +	mutex_init(&pru->lock);
> +
> +	ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_DRAM0,
> +				       &pru->dram0);
> +	if (ret) {
> +		dev_err(dev, "couldn't get PRUSS DRAM0: %d\n", ret);
> +		return ret;
> +	}
> +	pruss_release_mem_region(pru->pruss, &pru->dram0);
> +
> +	ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_DRAM1,
> +				       &pru->dram1);
> +	if (ret) {
> +		dev_err(dev, "couldn't get PRUSS DRAM1: %d\n", ret);
> +		return ret;
> +	}
> +	pruss_release_mem_region(pru->pruss, &pru->dram1);
> +
> +	ret = pruss_request_mem_region(pru->pruss, PRUSS_MEM_SHRD_RAM2,
> +				       &pru->shrdram);
> +	if (ret) {
> +		dev_err(dev, "couldn't get PRUSS Shared RAM: %d\n", ret);
> +		return ret;
> +	}
> +	pruss_release_mem_region(pru->pruss, &pru->shrdram);

Are you doing this because now you don't have access to the pruss
structure?

> +
> +	/* XXX: get this from match data if different in the future */
> +	pru->iram_da = 0;
> +	pru->pdram_da = 0;
> +	pru->sdram_da = 0x2000;
> +	pru->shrdram_da = 0x10000;
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iram");
> +	pru->iram_region.va = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(pru->iram_region.va)) {
> +		ret = PTR_ERR(pru->iram_region.va);
> +		dev_err(dev, "failed to get iram resource: %d\n", ret);
> +		goto free_rproc;
> +	}
> +
> +	pru->iram_region.pa = res->start;
> +	pru->iram_region.size = resource_size(res);
> +
> +	dev_dbg(dev, "iram: pa %pa size 0x%zx va %p\n",
> +		&pru->iram_region.pa, pru->iram_region.size,
> +		pru->iram_region.va);
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
> +	va = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(va)) {
> +		ret = PTR_ERR(va);
> +		dev_err(dev, "failed to get control resource: %d\n", ret);
> +		goto free_rproc;
> +	}
> +
> +	pru->ctrl_regmap = devm_regmap_init_mmio(dev, va,
> +						 &pru_ctrl_regmap_config);
> +	if (IS_ERR(pru->ctrl_regmap)) {
> +		ret = PTR_ERR(pru->ctrl_regmap);
> +		dev_err(dev, "CTRL regmap init failed: %d\n", ret);
> +		goto free_rproc;
> +	}
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug");
> +	va = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(va)) {
> +		ret = PTR_ERR(va);
> +		dev_err(dev, "failed to get debug resource: %d\n", ret);
> +		goto free_rproc;
> +	}
> +	pru->debug_regmap = devm_regmap_init_mmio(dev, va,
> +						  &pru_debug_regmap_config);
> +	if (IS_ERR(pru->debug_regmap)) {
> +		ret = PTR_ERR(pru->debug_regmap);
> +		dev_err(dev, "DEBUG regmap init failed: %d\n", ret);
> +		goto free_rproc;
> +	}

I am not a big fan of this regmap conversion. Using it just for the sake
of leveraging regmap debugfs seems overkill, where does the debugfs
files show up for that? Also, I had logic around when the registers can
be accessed, so not sure if you have tested the behavior when the PRUs
are executing.

> +
> +	ret = pru_rproc_set_id(pru);
> +	if (ret < 0)
> +		goto free_rproc;
> +
> +	platform_set_drvdata(pdev, rproc);
> +
> +	ret = rproc_add(pru->rproc);
> +	if (ret) {
> +		dev_err(dev, "rproc_add failed: %d\n", ret);
> +		goto free_rproc;
> +	}
> +
> +	pru_rproc_create_debug_entries(rproc);
> +
> +	dev_info(dev, "PRU rproc node %s probed successfully\n", np->full_name);
> +
> +	return 0;
> +
> +free_rproc:
> +	rproc_free(rproc);
> +	return ret;
> +}
> +
> +static int pru_rproc_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct rproc *rproc = platform_get_drvdata(pdev);
> +
> +	dev_info(dev, "%s: removing rproc %s\n", __func__, rproc->name);
> +
> +	rproc_del(rproc);
> +	rproc_free(rproc);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id pru_rproc_match[] = {
> +	{ .compatible = "ti,am3356-pru", },
> +	{ .compatible = "ti,am4376-pru", },
> +	{ .compatible = "ti,am5728-pru", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, pru_rproc_match);
> +
> +static struct platform_driver pru_rproc_driver = {
> +	.driver = {
> +		.name   = "pru-rproc",
> +		.of_match_table = pru_rproc_match,
> +		.suppress_bind_attrs = true,
> +	},
> +	.probe  = pru_rproc_probe,
> +	.remove = pru_rproc_remove,
> +};
> +module_platform_driver(pru_rproc_driver);
> +
> +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
> +MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/remoteproc/pru_rproc.h b/drivers/remoteproc/pru_rproc.h
> new file mode 100644
> index 0000000..bbcf392
> --- /dev/null
> +++ b/drivers/remoteproc/pru_rproc.h
> @@ -0,0 +1,54 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
> +/*
> + * PRUSS Remote Processor specific types
> + *
> + * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
> + * All rights reserved.
> + */
> +
> +#ifndef _PRU_REMOTEPROC_H_
> +#define _PRU_REMOTEPROC_H_
> +
> +/**
> + * enum pruss_rsc_types - PRU specific resource types
> + *
> + * @PRUSS_RSC_INTRS: Resource holding information on PRU PINTC configuration
> + * @PRUSS_RSC_MAX: Indicates end of known/defined PRU resource types.
> + *		   This should be the last definition.
> + *
> + * Introduce new custom resource types before PRUSS_RSC_MAX.
> + */
> +enum pruss_rsc_types {
> +	PRUSS_RSC_INTRS	= 1,
> +	PRUSS_RSC_MAX	= 2,
> +};
> +
> +/**
> + * struct fw_rsc_pruss_intrmap - vendor resource to define PRU interrupts
> + * @type: should be PRUSS_RSC_INTRS
> + * @version: should be 1 or greater. 0 was for prototyping and is not supported
> + * @num_maps: number of interrupt mappings that follow
> + * @data: Array of 'num_maps' mappings.
> + *		Each mapping is a triplet {s, c, h}
> + *		s - system event id
> + *		c - channel id
> + *		h - host interrupt id
> + *
> + * PRU system events are mapped to channels, and these channels are mapped
> + * to host interrupts. Events can be mapped to channels in a one-to-one or
> + * many-to-one ratio (multiple events per channel), and channels can be
> + * mapped to host interrupts in a one-to-one or many-to-one ratio (multiple
> + * channels per interrupt).
> + *
> + * This resource is variable length due to the nature of INTC map.
> + * The below data structure is scalable so it can support sufficiently
> + * large number of sysevents and hosts.
> + */
> +struct fw_rsc_pruss_intrmap {
> +	u16 type;
> +	u16 version;
> +	u8 num_maps;
> +	u8 data[];

I can comment more on this once I get a testable version, but I explored
this idea initially before abandoning this. We would want to prefer
using as small an amount of memory as possible, as the resource table
has to be loaded into memory. The channel to host mapping need to be
defined only once for a channel, and not needed for every event.

Also, I am not sure if your current logic is handling the resource size
availability check with this open-ended structure definition.

regards
Suman

> +} __packed;
> +
> +#endif	/* _PRU_REMOTEPROC_H_ */
> diff --git a/include/linux/remoteproc/pru_rproc.h b/include/linux/remoteproc/pru_rproc.h
> new file mode 100644
> index 0000000..841da09
> --- /dev/null
> +++ b/include/linux/remoteproc/pru_rproc.h
> @@ -0,0 +1,27 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/**
> + * PRU-ICSS Remote Subsystem user interfaces
> + *
> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
> + */
> +
> +#ifndef __LINUX_REMOTEPROC_PRU_RPROC_H
> +#define __LINUX_REMOTEPROC_PRU_RPROC_H
> +
> +#if IS_ENABLED(CONFIG_PRUSS_REMOTEPROC)
> +
> +struct rproc *pru_rproc_get(struct device_node *node, int index);
> +void pru_rproc_put(struct rproc *rproc);
> +
> +#else
> +
> +static inline struct rproc *pru_rproc_get(struct device_node *node, int index)
> +{
> +	return ERR_PTR(-ENOTSUPP);
> +}
> +
> +static inline void pru_rproc_put(struct rproc *rproc) { }
> +
> +#endif /* CONFIG_PRUSS_REMOTEPROC */
> +
> +#endif /* __LINUX_REMOTEPROC_PRU_RPROC_H */
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts
  2019-02-04 14:22 ` [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts Roger Quadros
  2019-02-04 16:36   ` Tony Lindgren
@ 2019-02-14  2:40   ` Suman Anna
  2019-02-18 19:32   ` Rob Herring
  2 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-14  2:40 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree, Andrew F. Davis, Thomas Gleixner, Jason Cooper,
	Marc Zyngier, Rob Herring

On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: "Andrew F. Davis" <afd@ti.com>
> 
> The Programmable Real-Time Unit Subsystem (PRUSS) contains an
> interrupt controller (INTC) that can handle various system input
> events and post interrupts back to the device-level initiators.
> The INTC can support upto 64 input events with individual control
> configuration and hardware prioritization. These events are mapped
> onto 10 interrupt signals through two levels of many-to-one mapping
> support. Different interrupt signals are routed to the individual
> PRU cores or to the host CPU.
> 
> The PRUSS INTC platform driver manages this PRUSS interrupt
> controller and implements an irqchip driver to provide a Linux
> standard way for the PRU client users to enable/disable/ack/
> re-trigger a PRUSS system event. The system events to interrupt
> channels and host interrupts relies on the mapping configuration
> provided through a firmware resource table for now. This will be
> revisited and enhanced in the future for a better interface. The
> mappings will currently be programmed during the boot/shutdown
> of the PRU.
> 
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Jason Cooper <jason@lakedaemon.net>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Signed-off-by: Andrew F. Davis <afd@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  .../interrupt-controller/ti,pruss-intc-irq.txt     | 51 ++++++++++++++++++++++

Better to name the file just ti,pruss-intc.txt.

Also, one minor nit, %s/dt-binding/dt-bindings/ on the the patch title.

regards
Suman

>  1 file changed, 51 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
> new file mode 100644
> index 0000000..c70221c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
> @@ -0,0 +1,51 @@
> +PRU ICSS INTC on TI SoCs
> +========================
> +
> +Each PRUSS has a single interrupt controller instance that is common to both
> +the PRU cores. Each interrupt controller can detect 64 input events which are
> +then mapped to 10 possible output interrupts through two levels of mapping. The
> +input events can be triggered by either the PRUs and/or various other PRUSS
> +internal and external peripherals. The first 2 output interrupts are fed
> +exclusively to the internal PRU cores, with the remaining 8 connected to
> +external interrupt controllers including the MPU.
> +
> +Required Properties:
> +--------------------
> +- compatible           : should be one of,
> +                             "ti,am3356-pruss-intc" for AM335x family of SoCs
> +                             "ti,am4376-pruss-intc" for AM437x family of SoCs
> +                             "ti,am5728-pruss-intc" for AM57xx family of SoCs
> +                             "ti,k2g-pruss-intc" for 66AK2G family of SoCs
> +- reg                  : base address and size for the PRUSS INTC sub-module
> +- reg-names            : should contain the string "intc"
> +- interrupts     : all the interrupts generated towards the main host
> +                   processor in the SoC. The format depends on the
> +                   interrupt specifier for the particular SoC's MPU
> +                   parent interrupt controller
> +- interrupt-names: should use one of the following names for each interrupt,
> +                   the name should match the corresponding host interrupt
> +                   number,
> +                       "host2", "host3", "host4", "host5", "host6",
> +                       "host7", "host8" or "host9"
> +                   NOTE: AM437x and 66AK2G SoCs do not have "host7" interrupt
> +                         connected to MPU
> +- interrupt-controller : mark this node as an interrupt controller
> +- #interrupt-cells     : should be 1. Client users shall use the PRU System
> +                         event number (the interrupt source that the client
> +                         is interested in) as the value of the interrupts
> +                         property in their node
> +
> +Example:
> +--------
> +		pruss_intc: intc@20000 {
> +			compatible = "ti,am3356-pruss-intc";
> +			reg = <0x20000 0x2000>;
> +			reg-names = "intc";
> +			interrupt-controller;
> +			#interrupt-cells = <1>;
> +			interrupts = <20 21 22 23 24 25 26 27>;
> +			interrupt-names = "host2", "host3", "host4",
> +					  "host5", "host6", "host7",
> +					  "host8", "host9";
> +		};
> +
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-06 15:04               ` Roger Quadros
@ 2019-02-14  2:47                 ` Suman Anna
  0 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-14  2:47 UTC (permalink / raw)
  To: Roger Quadros, Tony Lindgren, Murali Karicheri
  Cc: ohad, bjorn.andersson, david, nsekhar, t-kristo, nsaulnier,
	jreeder, woods.technical, linux-omap, linux-remoteproc,
	linux-kernel, devicetree

On 2/6/19 9:04 AM, Roger Quadros wrote:
> 
> 
> On 05/02/19 18:19, Tony Lindgren wrote:
>> * Murali Karicheri <m-karicheri2@ti.com> [190205 16:13]:
>>> On 02/05/2019 10:41 AM, Roger Quadros wrote:
>>>> What I'm suggesting here is that kernel remoteproc driver should have nothing to do
>>>> with the other PRU's data RAM.
>>>>
>>>> The application driver if needs both PRUs then it can obviously access both DRAMs
>>>> as it has a phandle to both PRUs.
>>>>
>>> That should be fine.
>>
>> That sounds good to me too.
>>
>> For dts, yeah please allocate the resources for the modules
>> where the resources belong to on the PRUSS internal interconnect :)
>> Devices can move around on the interconnect between SoCs and the
>> modules can get swapped or added.
> 
> If you take a look at "Figure 30-1. PRU-ICSS Overview" in 
> http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf
> 
> You can see that DRAM0 and DRAM1 are not part of PRU. That means
> they shouldn't be in the PRU node then.

Yes, they do not belong to a PRU, and should not be defined underneath
one. Both are accessible from both PRU cores, so it is upto the
application on how they can partition the usage.

regards
Suman


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-04 14:22 ` [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Roger Quadros
  2019-02-04 16:33   ` Tony Lindgren
  2019-02-08 13:51   ` Linus Walleij
@ 2019-02-14  2:52   ` Suman Anna
  2019-02-14 11:08     ` Roger Quadros
  2 siblings, 1 reply; 61+ messages in thread
From: Suman Anna @ 2019-02-14  2:52 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree

Hi Roger,

On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: Suman Anna <s-anna@ti.com>
> 
> This patch adds the bindings for the Programmable Real-Time Unit
> and Industrial Communication Subsystem (PRU-ICSS) present on various
> SoCs such as AM33xx, AM437x, AM57xx, Keystone 66AK2G SoC, etc. It is
> present on the Davinci based OMAPL138 SoCs and K3 architecture
> based AM65x SoCs as well (not covered for now).
> 
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  .../devicetree/bindings/soc/ti/ti,pruss.txt        | 212 +++++++++++++++++++++
>  1 file changed, 212 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
> 
> diff --git a/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
> new file mode 100644
> index 0000000..5ac76fd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
> @@ -0,0 +1,212 @@
> +PRU-ICSS on TI SoCs
> +===================
> +
> +The Programmable Real-Time Unit and Industrial Communication Subsystem
> +(PRU-ICSS) is present on various TI SoCs such as AM335x, AM437x, Keystone
> +66AK2G, etc. A PRUSS consists of dual 32-bit RISC cores (Programmable
> +Real-Time Units, or PRUs) with program memory and data memory.
> +
> +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,
> +
> +  - Enhanced GPIO with async capture and serial support
> +  - 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)
> +  - a 16550-compatible UART to support PROFIBUS
> +  - Interrupt controller with 64 input events and 10 Host interrupts.
> +
> +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.
> +
> +Various sub-modules within a PRU-ICSS subsystem are represented as individual
> +nodes.
> +
> +PRUSS Node
> +=============
> +
> +This node represents the entire ICSS instance and the various modules are
> +contained as children. The PRUSS driver is responsible for managing the
> +common resources i.e. DRAM0, DRAM1, SHARED_RAM and CFG space.
> +
> +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
> +- 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

Hmm, not sure what prompted you to deviate from the design we had on TI
SDK kernels. Your revised bindings does not allow us to use this device
for the scalability with either UIO/VFIO.

Let's sort this out before you post the next series.

regards
Suman

> +- reg-names      : should contain a string(s) from among the following names,
> +                   each representing a specific Data RAM region. Some PRU-ICSS
> +		   instances on certain SoCs might not have Shared DRAM.
> +                       "dram0" for Data RAM0,
> +                       "dram1" for Data RAM1,
> +                       "shrdram2" for Shared Data RAM,
> +- #address-cells : should be 1
> +- #size-cells    : should be 1
> +- ranges         : no specific range translations required, child nodes have the
> +                   same address view as the parent, so should be mentioned without
> +                   any value for the property
> +
> +Optional Properties:
> +--------------------
> +- no-shared-ram	: Should be present if the instance doesn't have Shared RAM.
> +		  e.g. AM4376 ICSS0 instance doesn't have Shared RAM.
> +
> +The PRUSS node will have one or more of the folowing child nodes.
> +
> +PRU CORES
> +=========
> +ICSS typically has 2 PRU cores. These should be represented as remoteproc devices.
> +
> +INTC node
> +=========
> +ICSS has one INTC interrupt controller module. This should be represented as
> +a standard interrupt-controller node.
> +
> +CFG, IEP, MII_RT
> +================
> +The individual sub-modules CFG, IEP and MII_RT are represented as a syscon
> +node each with specific node names as below:
> +                  "cfg" for CFG sub-module,
> +                  "iep" for IEP sub-module,
> +                  "mii_rt" for MII-RT sub-module,
> +
> +See Documentation/devicetree/bindings/mfd/syscon.txt for details.
> +
> +MDIO
> +====
> +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.
> +
> +Application/User Nodes
> +=======================
> +A PRU application/user node typically uses one or more PRU device nodes to
> +implement a PRU application/functionality. Each application/client node would
> +need a reference to at least a PRU node, and optionally pass some configuration
> +parameters.
> +
> +Required Properties:
> +--------------------
> +- prus                 : phandles to the PRU nodes used
> +
> +Optional Properties:
> +--------------------
> +- firmware-name        : firmwares for the PRU cores, the default firmware
> +                         for the core from the PRU node will be used if not
> +                         provided. The firmware names should correspond to
> +                         the PRU cores listed in the 'prus' property
> +- ti,pruss-gp-mux-sel  : array of values for the GP_MUX_SEL under PRUSS_GPCFG
> +                         register for a PRU. This selects the internal muxing
> +                         scheme for the PRU instance. If not provided, the
> +                         default out-of-reset value (0) for the PRU core is
> +                         used. Values should correspond to the PRU cores listed
> +                         in the 'prus' property
> +- ti,pru-interrupt-map : PRU interrupt mappings, containing an array of entries
> +                         with each entry consisting of 4 cell-values. First one
> +                         is an index towards the "prus" property to identify the
> +                         PRU core for the interrupt map, second is the PRU
> +                         System Event id, third is the PRU interrupt channel id
> +                         and fourth is the PRU host interrupt id. If provided,
> +                         this map will supercede any other configuration
> +                         provided through firmware
> +
> +Example:
> +========
> +1.	/* AM33xx PRU-ICSS */
> +
> +	pruss: pruss@0 {
> +		compatible = "ti,am3356-pruss";
> +		reg = <0x0 0x2000>,
> +		      <0x2000 0x2000>,
> +		      <0x10000 0x3000>;
> +		reg-names = "dram0", "dram1",
> +			    "shrdram2";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		pruss_cfg: cfg@26000 {
> +			compatible = "syscon";
> +			reg = <0x26000 0x2000>;
> +		};
> +
> +		pruss_iep: iep@2e000 {
> +			compatible = "syscon";
> +			reg = <0x2e000 0x31c>;
> +		};
> +
> +		pruss_mii_rt: mii_rt@32000 {
> +			compatible = "syscon";
> +			reg = <0x32000 0x58>;
> +		};
> +
> +		pruss_intc: intc@20000 {
> +			compatible = "ti,am3356-pruss-intc";
> +			reg = <0x20000 0x2000>;
> +			reg-names = "intc";
> +			interrupt-controller;
> +			#interrupt-cells = <1>;
> +			interrupts = <20 21 22 23 24 25 26 27>;
> +			interrupt-names = "host2", "host3", "host4",
> +					  "host5", "host6", "host7",
> +					  "host8", "host9";
> +		};
> +
> +		pru0: pru@34000 {
> +			compatible = "ti,am3356-pru";
> +			reg = <0x34000 0x2000>,
> +			      <0x22000 0x400>,
> +			      <0x22400 0x100>;
> +			reg-names = "iram", "control", "debug";
> +			gpcfg = <&pruss_cfg 0x8>;
> +			firmware-name = "am335x-pru0-fw";
> +			interrupt-parent = <&pruss_intc>;
> +			interrupts = <16>, <17>;
> +			interrupt-names = "vring", "kick";
> +		};
> +
> +		pru1: pru@38000 {
> +			compatible = "ti,am3356-pru";
> +			reg = <0x38000 0x2000>,
> +			      <0x24000 0x400>,
> +			      <0x24400 0x100>;
> +			reg-names = "iram", "control", "debug";
> +			gpcfg = <&pruss_cfg 0xc>;
> +			firmware-name = "am335x-pru1-fw";
> +			interrupt-parent = <&pruss_intc>;
> +			interrupts = <18>, <19>;
> +			interrupt-names = "vring", "kick";
> +		};
> +
> +		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>;
> +			status = "disabled";
> +		};
> +	};
> +
> +2:	/* PRU application node example */
> +	app_node: app_node {
> +		prus = <&pru0>, <&pru1>;
> +		firmware-name = "pruss-app-fw", "pruss-app-fw-2";
> +		ti,pruss-gp-mux-sel = <2>, <1>;
> +		/* setup interrupts for prus:
> +		   prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
> +		   prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
> +		ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
> +	}
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-05 16:41       ` Tony Lindgren
@ 2019-02-14  3:01         ` Suman Anna
  0 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-14  3:01 UTC (permalink / raw)
  To: Tony Lindgren, Roger Quadros
  Cc: ohad, bjorn.andersson, david, nsekhar, t-kristo, nsaulnier,
	jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Linus Walleij

On 2/5/19 10:41 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [190205 09:40]:
>> On 04/02/19 18:33, Tony Lindgren wrote:
>>>
>>> 	shrdram2: memory@10000 {
>>> 		device_type = "memory";
>>> 		reg = <0x10000 0x3000>;
>>> 	};
>>
>> Shared RAM is not so straight forward. Both PRU firmwares and both application drivers
>> might need to read/write here. The area split is decided by firmware design and there
>> is no hardware protection to prevent from stomping on each others toes.
>>
>> We need a carveout based memory allocator at least I think that can do a
>> allocate(base_offset, size); into shared RAM.
>>
>> This could be used by pru_rproc driver at firmware load time and by application drivers
>> at initialization time.
>>
>> Thoughts?
> 
> That sounds sane to me :)
> 
>>> If the ti,pruss-gp-mux-sel and ti,pru-interrupt-map are
>>> firmware configuration options, maybe leave them out of
>>> the dts completely and make the app-node optional.
>>
>> Yes the app-node is optional. I will mention it.
>>
>> No, ti,pruss-gp-mux-sel and ti,pru-interrupt-map are not firmware options.
>> But these settings are application/firmware specific.
>>
>> ti,pru-interrupt-map specifies the configuration to be used for the INTC interrupt
>> controller.
> 
> OK. So just to see if we have a standard solution available already..
> It sounds a bit similar to what we're doing with omap-wakeupgen.c
> and stacked interrupts? I wonder if something similar might help
> here?
> 
>> ti,pruss-gp-mux-sel is used to configure this register.
>> "Table 30-20. PRUSS_GPCFG0" in http://www.tij.co.jp/jp/lit/ug/spruhz7h/spruhz7h.pdf
>> "29:26 PR1_PRU0_GP_MUX_SEL"
>>
>> It configures how the pins from the PRUSS module are routed internally
>> to the various modules.

Actually, that's not entirely accurate. This is an internal pinmux (not
controllable per pin, but rather dictates a different sets of groups of
pins at the PRUSS boundary, which are then again multiplexed at the SoC
level using the standard padconf/pinmux. It is a single register per
core into which you can set some values between 0 through 4 IIRC
(unfortunately the values are also not uniform across the various SoCs).

regards
Suman

>>
>> see "30.2.1 PRU-ICSS I/O Interface"
>> and "Table 30-1. PRU-ICSS1 I/O Signals"
> 
> Well these are external signals for PRUSS processor (although not
> necessarily external signals for the SoC). So why not handle them
> with a standard pinctlr binding with #pinctrl-cells?
> 
> Sure it may not even be the Linux pinctrl framework running on the
> main SoC handling these pins, but after all you're describing
> hardware for a processor. Maybe Linus W has some comments on this?
> 
> Regards,
> 
> Tony
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-08 13:51   ` Linus Walleij
@ 2019-02-14  3:12     ` Suman Anna
  2019-02-14  8:37       ` Linus Walleij
  0 siblings, 1 reply; 61+ messages in thread
From: Suman Anna @ 2019-02-14  3:12 UTC (permalink / raw)
  To: Linus Walleij, Roger Quadros, Marc Zyngier
  Cc: ext Tony Lindgren, Ohad Ben-Cohen, Bjorn Andersson,
	David Lechner, Nori, Sekhar, Tero Kristo, nsaulnier, jreeder,
	Murali Karicheri, woods.technical, Linux-OMAP, linux-remoteproc,
	linux-kernel,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On 2/8/19 7:51 AM, Linus Walleij wrote:
> On Mon, Feb 4, 2019 at 3:24 PM Roger Quadros <rogerq@ti.com> wrote:
> 
>> From: Suman Anna <s-anna@ti.com>
>>
>> This patch adds the bindings for the Programmable Real-Time Unit
>> and Industrial Communication Subsystem (PRU-ICSS) present on various
>> SoCs such as AM33xx, AM437x, AM57xx, Keystone 66AK2G SoC, etc. It is
>> present on the Davinci based OMAPL138 SoCs and K3 architecture
>> based AM65x SoCs as well (not covered for now).
>>
>> Signed-off-by: Suman Anna <s-anna@ti.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
> 
> (...)
>> +               pruss_intc: intc@20000 {
>> +                       compatible = "ti,am3356-pruss-intc";
>> +                       reg = <0x20000 0x2000>;
>> +                       reg-names = "intc";
>> +                       interrupt-controller;
>> +                       #interrupt-cells = <1>;
>> +                       interrupts = <20 21 22 23 24 25 26 27>;
>> +                       interrupt-names = "host2", "host3", "host4",
>> +                                         "host5", "host6", "host7",
>> +                                         "host8", "host9";
> 
> If thsese interrupts are mapped 1-to-1 to a parent interrupt controller
> then this is a hierarchical interrupt domain and then these should
> be handled locally in the driver as offset from child to parent
> statically encoded in the driver.
> 
> Several old drivers and old device tree bindings make this kind
> of maps, but it is not how we do it anymore, if we can avoid it.
> 
> To be able to use hierarchical interrupt domain in the kernel, the top
> interrupt controller must use the hierarchical (v2) irqdomain, so
> if this is anything else than the ARM GIC it will be an interesting
> undertaking to handle this.

These are interrupt lines coming towards the host processor running
Linux and are directly connected to the ARM GIC. This INTC module is
actually an PRUSS internal interrupt controller that can take in 64 (on
most SoCs) external events/interrupt sources and multiplexing them
through two layers of many-to-one events-to-intr channels &
intr-channels-to-host interrupts. Couple of the host interrupts go to
the PRU cores themselves while the remaining ones come out of the IP to
connect to other GICs in the SoC.

We have implemented this as an irqchip using chained interrupt handlers
with the consumers using the event numbers on the Linux-side. The PRUs
also access some of the associated registers for clearing an event source.

regards
Suman

> 
> The more I understand of hierarchical irqdomains, the more of
> workarounds where we should be using it I see, we really need
> to spread this knowledge. Using it requires a lot of upfront work
> sometimes, sorry about that but the end result is so much better.
> 
> Yours,
> Linus Walleij
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver
  2019-02-14  2:35   ` Suman Anna
@ 2019-02-14  3:44     ` Suman Anna
  0 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-14  3:44 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree, Andrew F . Davis

On 2/13/19 8:35 PM, Suman Anna wrote:
> Hi Roger,
> 
> On 2/4/19 8:22 AM, Roger Quadros wrote:
>> From: Suman Anna <s-anna@ti.com>
>>
>> The Programmable Real-Time Unit Subsystem (PRUSS) consists of
>> dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs)
>> for program execution. This patch adds a remoteproc platform
>> driver for managing the individual PRU RISC cores life cycle.
>>
>> This remoteproc driver does not have support for error recovery
>> and system suspend/resume features. Different compatibles are
>> used to allow providing scalability for instance-specific device
>> data if needed. The driver uses a default firmware-name retrieved
>> from device-tree, and the firmwares are expected to be present
>> in the standard Linux firmware search paths. They can also be
>> adjusted by userspace if required through the sysfs interface
>> provided by the remoteproc core.
>>
>> The PRU remoteproc driver uses a client-driven boot methodology
>> - it does _not_ support auto-boot so that the PRU load and boot
>> is dictated by the corresponding client drivers for achieving
>> various usecases. This allows flexibility for the client drivers
>> or applications to set a firmware name (if needed) based on their
>> desired functionality and boot the PRU. The sysfs bind and unbind
>> attributes have also been suppressed so that the PRU devices cannot
>> be unbound and thereby shutdown a PRU from underneath a PRU client
>> driver.
>>
>> A new entry 'single_step' is added to the remoteproc debugfs dir.
>> The 'single_step' utilizes the single-step execution of the PRU
>> cores. Writing a non-zero value performs a single step, and a
>> zero value restores the PRU to execute in the same mode as the
>> mode before the first single step. (note: if the PRU is halted
>> because of a halt instruction, then no change occurs).
>>
>> pru_rproc_get() and pru_rproc_put() functions allow client drivers
>> to acquire and release the remoteproc device associated with a PRU core.
>> The PRU cores are treated as resources with only one client owning
>> it at a time.
>>
>> PRU interrupt mapping can be provided via devicetree using
>> ti,pru-interrupt-map property or via the resource table in the
>> firmware blob. If both are provided, the config in DT takes precedence.
>> For interrupt map via resource table, pru-software-support-package [1]
>> has been historically using version 0 for this. However, the current
>> data structure is not scaleable and is not self sufficient.
>> 1) it hard codes number of channel to host mappings so is not
>> scaleable to newer SoCs than have more of these.
>> 2) it does not contain the event to channel mappings within
>> itself but relies on a pointer to point to another section
>> in data memory. This causes a weird complication that the
>> respective data section must be loaded before we can really
>> use the INTC map.
>>
>> With this patch we drop support for version 0 and support
>> version 1 which is a more robust and scalable data structure.
>> It should be able to support a sufficiently large number (255) of
>> sysevents, channels and host interrupts and is self contained
>> so it can be used without dependency on order of loading sections.
> 
> Hmm, looks like you squashed a whole bunch of patches into this. I would
> prefer some of the logical ones to be separated out just like before,
> makes it easier to review the interfaces.
> 
> Looks like you have also changed usage behavior on couple of things and
> dropped some of my original changes. I was not able to test this series
> either on AM335x or on AM57xx to comment more on the behavior (not even
> seeing the pruss devices populated, not sure what pieces are missing still).

Able to get the PRUSS devices show up on AM335x atleast after enabling
the Reset Controller related configs, but no such luck on AM57xx.

regards
Suman

> 
>>
>> [1]  git://git.ti.com/pru-software-support-package/pru-software-support-package.git
>>
>> Signed-off-by: Suman Anna <s-anna@ti.com>
>> Signed-off-by: Andrew F. Davis <afd@ti.com>
>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14  3:12     ` Suman Anna
@ 2019-02-14  8:37       ` Linus Walleij
  2019-02-14 10:55         ` Roger Quadros
  0 siblings, 1 reply; 61+ messages in thread
From: Linus Walleij @ 2019-02-14  8:37 UTC (permalink / raw)
  To: Suman Anna
  Cc: Roger Quadros, Marc Zyngier, ext Tony Lindgren, Ohad Ben-Cohen,
	Bjorn Andersson, David Lechner, Nori, Sekhar, Tero Kristo,
	nsaulnier, jreeder, Murali Karicheri, woods.technical,
	Linux-OMAP, linux-remoteproc, linux-kernel,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On Thu, Feb 14, 2019 at 4:13 AM Suman Anna <s-anna@ti.com> wrote:
> [Me]

> > To be able to use hierarchical interrupt domain in the kernel, the top
> > interrupt controller must use the hierarchical (v2) irqdomain, so
> > if this is anything else than the ARM GIC it will be an interesting
> > undertaking to handle this.
>
> These are interrupt lines coming towards the host processor running
> Linux and are directly connected to the ARM GIC. This INTC module is
> actually an PRUSS internal interrupt controller that can take in 64 (on
> most SoCs) external events/interrupt sources and multiplexing them
> through two layers of many-to-one events-to-intr channels &
> intr-channels-to-host interrupts. Couple of the host interrupts go to
> the PRU cores themselves while the remaining ones come out of the IP to
> connect to other GICs in the SoC.

If the muxing is static (like set up once at probe) so that while the system is
running, there is one and one only event mapped to the GIC from
the component below it, then it is hierarchical.

> We have implemented this as an irqchip using chained interrupt handlers
> with the consumers using the event numbers on the Linux-side. The PRUs
> also access some of the associated registers for clearing an event source.

Chaining with cascading is when two or more interrupts fire the
same upper level (say GIC) IRQ. If there is a 1:1 mapping,
it is not chained/cascaded but hierarchical.

I understand you used old irqdomain/chip frameworks in the past,
because everyone was working around the fact that they didn't have
an abstraction for hierarchical IRQs. Using chained interrupts
and custom 1:1 maps and assigning a long list of IRQs like this
patch does was the most common workaround. But we should
step out of that habit now.

Different levels of the IRQ handling having to do different stuff is
what hierarchical irqdomains do best, so it sounds like a good fit.

We handle some stuff at our level of the hierarchy and then fall
up to the next higher level using calls such as
irq_chip_ack_parent(), irq_chip_mask_parent() and friends.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14  8:37       ` Linus Walleij
@ 2019-02-14 10:55         ` Roger Quadros
       [not found]           ` <86ef8asfap.wl-marc.zyngier@arm.com>
  0 siblings, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-14 10:55 UTC (permalink / raw)
  To: Linus Walleij, Suman Anna, Lokesh Vutla
  Cc: Marc Zyngier, ext Tony Lindgren, Ohad Ben-Cohen, Bjorn Andersson,
	David Lechner, Nori, Sekhar, Tero Kristo, nsaulnier, jreeder,
	Murali Karicheri, woods.technical, Linux-OMAP, linux-remoteproc,
	linux-kernel,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS


On 14/02/19 10:37, Linus Walleij wrote:
> On Thu, Feb 14, 2019 at 4:13 AM Suman Anna <s-anna@ti.com> wrote:
>> [Me]
> 
>>> To be able to use hierarchical interrupt domain in the kernel, the top
>>> interrupt controller must use the hierarchical (v2) irqdomain, so
>>> if this is anything else than the ARM GIC it will be an interesting
>>> undertaking to handle this.
>>
>> These are interrupt lines coming towards the host processor running
>> Linux and are directly connected to the ARM GIC. This INTC module is
>> actually an PRUSS internal interrupt controller that can take in 64 (on
>> most SoCs) external events/interrupt sources and multiplexing them
>> through two layers of many-to-one events-to-intr channels &
>> intr-channels-to-host interrupts. Couple of the host interrupts go to
>> the PRU cores themselves while the remaining ones come out of the IP to
>> connect to other GICs in the SoC.
> 
> If the muxing is static (like set up once at probe) so that while the system is
> running, there is one and one only event mapped to the GIC from
> the component below it, then it is hierarchical.

This is how it looks.

[GIC]<---8---[INTC]<---64---[events from peripherals]

The 8 interrupt lines from INTC to the GIC are 1:1 mapped and fixed per SoC.
The muxing between 64 inputs to INTC and its 8 outputs are programmable
and might not necessarily be static per boot/probe as it depends on what firmware
is loaded on the PRU.

A typical PRUSS use case will usually use just one firmware per boot but if required it
can switch at runtime and the muxing might change.

> 
>> We have implemented this as an irqchip using chained interrupt handlers
>> with the consumers using the event numbers on the Linux-side. The PRUs
>> also access some of the associated registers for clearing an event source.
> 
> Chaining with cascading is when two or more interrupts fire the
> same upper level (say GIC) IRQ. If there is a 1:1 mapping,
> it is not chained/cascaded but hierarchical.
> 
> I understand you used old irqdomain/chip frameworks in the past,
> because everyone was working around the fact that they didn't have
> an abstraction for hierarchical IRQs. Using chained interrupts
> and custom 1:1 maps and assigning a long list of IRQs like this
> patch does was the most common workaround. But we should
> step out of that habit now.
> 
> Different levels of the IRQ handling having to do different stuff is
> what hierarchical irqdomains do best, so it sounds like a good fit.
> 
> We handle some stuff at our level of the hierarchy and then fall
> up to the next higher level using calls such as
> irq_chip_ack_parent(), irq_chip_mask_parent() and friends.
> 
> Yours,
> Linus Walleij
> 

--
cheers,
-roger
 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14  2:52   ` Suman Anna
@ 2019-02-14 11:08     ` Roger Quadros
  2019-02-14 15:56       ` Tony Lindgren
                         ` (2 more replies)
  0 siblings, 3 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-14 11:08 UTC (permalink / raw)
  To: Suman Anna, tony, ohad, bjorn.andersson
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree, Robert Nelson, dan, Matthijs van Duin

+Robert, Dan, Matthijs

Hi Suman,

On 14/02/19 04:52, Suman Anna wrote:
> Hi Roger,
> 
> On 2/4/19 8:22 AM, Roger Quadros wrote:
>> From: Suman Anna <s-anna@ti.com>
>>
>> This patch adds the bindings for the Programmable Real-Time Unit
>> and Industrial Communication Subsystem (PRU-ICSS) present on various
>> SoCs such as AM33xx, AM437x, AM57xx, Keystone 66AK2G SoC, etc. It is
>> present on the Davinci based OMAPL138 SoCs and K3 architecture
>> based AM65x SoCs as well (not covered for now).
>>
>> Signed-off-by: Suman Anna <s-anna@ti.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  .../devicetree/bindings/soc/ti/ti,pruss.txt        | 212 +++++++++++++++++++++
>>  1 file changed, 212 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
>>
>> diff --git a/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
>> new file mode 100644
>> index 0000000..5ac76fd
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
>> @@ -0,0 +1,212 @@
>> +PRU-ICSS on TI SoCs
>> +===================
>> +
>> +The Programmable Real-Time Unit and Industrial Communication Subsystem
>> +(PRU-ICSS) is present on various TI SoCs such as AM335x, AM437x, Keystone
>> +66AK2G, etc. A PRUSS consists of dual 32-bit RISC cores (Programmable
>> +Real-Time Units, or PRUs) with program memory and data memory.
>> +
>> +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,
>> +
>> +  - Enhanced GPIO with async capture and serial support
>> +  - 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)
>> +  - a 16550-compatible UART to support PROFIBUS
>> +  - Interrupt controller with 64 input events and 10 Host interrupts.
>> +
>> +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.
>> +
>> +Various sub-modules within a PRU-ICSS subsystem are represented as individual
>> +nodes.
>> +
>> +PRUSS Node
>> +=============
>> +
>> +This node represents the entire ICSS instance and the various modules are
>> +contained as children. The PRUSS driver is responsible for managing the
>> +common resources i.e. DRAM0, DRAM1, SHARED_RAM and CFG space.
>> +
>> +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
>> +- 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
> 
> Hmm, not sure what prompted you to deviate from the design we had on TI
> SDK kernels. Your revised bindings does not allow us to use this device
> for the scalability with either UIO/VFIO.

My understanding was that the device tree node will have to be modified
in any case to support the current uio_pruss.c driver so we don't
need to add things that we don't need right away.

> 
> Let's sort this out before you post the next series.

Let's discuss this here so I don't have to explain the whole thing again
in the next series.

Tony,

Suman is mainly concerned about the following changes in v2
1) pruss node does not contain reg property representing entire ICSS.
2) pruss node does not contain interrupts.

Both of these are required if drivers/uio/uio_pruss.c or in future if
VFIO is to be used.

The beagleboard community is a primary user of this driver and we need to
find a solution so that PRUSS is usable either via remoteproc or via UIO.

Ideal case should allow user to use either of the drivers by just doing
a unbind and bind.

I don't have a better idea than having a encapsulating node that has
the appropriate reg and interrupt properties.

cheers,
-roger

> 
> regards
> Suman
> 
>> +- reg-names      : should contain a string(s) from among the following names,
>> +                   each representing a specific Data RAM region. Some PRU-ICSS
>> +		   instances on certain SoCs might not have Shared DRAM.
>> +                       "dram0" for Data RAM0,
>> +                       "dram1" for Data RAM1,
>> +                       "shrdram2" for Shared Data RAM,
>> +- #address-cells : should be 1
>> +- #size-cells    : should be 1
>> +- ranges         : no specific range translations required, child nodes have the
>> +                   same address view as the parent, so should be mentioned without
>> +                   any value for the property
>> +
>> +Optional Properties:
>> +--------------------
>> +- no-shared-ram	: Should be present if the instance doesn't have Shared RAM.
>> +		  e.g. AM4376 ICSS0 instance doesn't have Shared RAM.
>> +
>> +The PRUSS node will have one or more of the folowing child nodes.
>> +
>> +PRU CORES
>> +=========
>> +ICSS typically has 2 PRU cores. These should be represented as remoteproc devices.
>> +
>> +INTC node
>> +=========
>> +ICSS has one INTC interrupt controller module. This should be represented as
>> +a standard interrupt-controller node.
>> +
>> +CFG, IEP, MII_RT
>> +================
>> +The individual sub-modules CFG, IEP and MII_RT are represented as a syscon
>> +node each with specific node names as below:
>> +                  "cfg" for CFG sub-module,
>> +                  "iep" for IEP sub-module,
>> +                  "mii_rt" for MII-RT sub-module,
>> +
>> +See Documentation/devicetree/bindings/mfd/syscon.txt for details.
>> +
>> +MDIO
>> +====
>> +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.
>> +
>> +Application/User Nodes
>> +=======================
>> +A PRU application/user node typically uses one or more PRU device nodes to
>> +implement a PRU application/functionality. Each application/client node would
>> +need a reference to at least a PRU node, and optionally pass some configuration
>> +parameters.
>> +
>> +Required Properties:
>> +--------------------
>> +- prus                 : phandles to the PRU nodes used
>> +
>> +Optional Properties:
>> +--------------------
>> +- firmware-name        : firmwares for the PRU cores, the default firmware
>> +                         for the core from the PRU node will be used if not
>> +                         provided. The firmware names should correspond to
>> +                         the PRU cores listed in the 'prus' property
>> +- ti,pruss-gp-mux-sel  : array of values for the GP_MUX_SEL under PRUSS_GPCFG
>> +                         register for a PRU. This selects the internal muxing
>> +                         scheme for the PRU instance. If not provided, the
>> +                         default out-of-reset value (0) for the PRU core is
>> +                         used. Values should correspond to the PRU cores listed
>> +                         in the 'prus' property
>> +- ti,pru-interrupt-map : PRU interrupt mappings, containing an array of entries
>> +                         with each entry consisting of 4 cell-values. First one
>> +                         is an index towards the "prus" property to identify the
>> +                         PRU core for the interrupt map, second is the PRU
>> +                         System Event id, third is the PRU interrupt channel id
>> +                         and fourth is the PRU host interrupt id. If provided,
>> +                         this map will supercede any other configuration
>> +                         provided through firmware
>> +
>> +Example:
>> +========
>> +1.	/* AM33xx PRU-ICSS */
>> +
>> +	pruss: pruss@0 {
>> +		compatible = "ti,am3356-pruss";
>> +		reg = <0x0 0x2000>,
>> +		      <0x2000 0x2000>,
>> +		      <0x10000 0x3000>;
>> +		reg-names = "dram0", "dram1",
>> +			    "shrdram2";
>> +		#address-cells = <1>;
>> +		#size-cells = <1>;
>> +		ranges;
>> +
>> +		pruss_cfg: cfg@26000 {
>> +			compatible = "syscon";
>> +			reg = <0x26000 0x2000>;
>> +		};
>> +
>> +		pruss_iep: iep@2e000 {
>> +			compatible = "syscon";
>> +			reg = <0x2e000 0x31c>;
>> +		};
>> +
>> +		pruss_mii_rt: mii_rt@32000 {
>> +			compatible = "syscon";
>> +			reg = <0x32000 0x58>;
>> +		};
>> +
>> +		pruss_intc: intc@20000 {
>> +			compatible = "ti,am3356-pruss-intc";
>> +			reg = <0x20000 0x2000>;
>> +			reg-names = "intc";
>> +			interrupt-controller;
>> +			#interrupt-cells = <1>;
>> +			interrupts = <20 21 22 23 24 25 26 27>;
>> +			interrupt-names = "host2", "host3", "host4",
>> +					  "host5", "host6", "host7",
>> +					  "host8", "host9";
>> +		};
>> +
>> +		pru0: pru@34000 {
>> +			compatible = "ti,am3356-pru";
>> +			reg = <0x34000 0x2000>,
>> +			      <0x22000 0x400>,
>> +			      <0x22400 0x100>;
>> +			reg-names = "iram", "control", "debug";
>> +			gpcfg = <&pruss_cfg 0x8>;
>> +			firmware-name = "am335x-pru0-fw";
>> +			interrupt-parent = <&pruss_intc>;
>> +			interrupts = <16>, <17>;
>> +			interrupt-names = "vring", "kick";
>> +		};
>> +
>> +		pru1: pru@38000 {
>> +			compatible = "ti,am3356-pru";
>> +			reg = <0x38000 0x2000>,
>> +			      <0x24000 0x400>,
>> +			      <0x24400 0x100>;
>> +			reg-names = "iram", "control", "debug";
>> +			gpcfg = <&pruss_cfg 0xc>;
>> +			firmware-name = "am335x-pru1-fw";
>> +			interrupt-parent = <&pruss_intc>;
>> +			interrupts = <18>, <19>;
>> +			interrupt-names = "vring", "kick";
>> +		};
>> +
>> +		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>;
>> +			status = "disabled";
>> +		};
>> +	};
>> +
>> +2:	/* PRU application node example */
>> +	app_node: app_node {
>> +		prus = <&pru0>, <&pru1>;
>> +		firmware-name = "pruss-app-fw", "pruss-app-fw-2";
>> +		ti,pruss-gp-mux-sel = <2>, <1>;
>> +		/* setup interrupts for prus:
>> +		   prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
>> +		   prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
>> +		ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
>> +	}
>>
> 

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
       [not found]           ` <86ef8asfap.wl-marc.zyngier@arm.com>
@ 2019-02-14 15:44             ` Roger Quadros
  2019-02-14 15:48               ` Roger Quadros
  2019-02-14 15:51               ` Marc Zyngier
  0 siblings, 2 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-14 15:44 UTC (permalink / raw)
  To: Marc Zyngier, Suman Anna, Davis, Andrew, Lokesh Vutla
  Cc: Linus Walleij, Lokesh Vutla, ext Tony Lindgren, Ohad Ben-Cohen,
	Bjorn Andersson, David Lechner, Nori, Sekhar, Tero Kristo,
	nsaulnier, jreeder, Murali Karicheri, woods.technical,
	Linux-OMAP, linux-remoteproc, linux-kernel,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On 14/02/19 14:52, Marc Zyngier wrote:
> On Thu, 14 Feb 2019 10:55:10 +0000,
> Roger Quadros <rogerq@ti.com> wrote:
>>
>>
>> On 14/02/19 10:37, Linus Walleij wrote:
>>> On Thu, Feb 14, 2019 at 4:13 AM Suman Anna <s-anna@ti.com> wrote:
>>>> [Me]
>>>
>>>>> To be able to use hierarchical interrupt domain in the kernel, the top
>>>>> interrupt controller must use the hierarchical (v2) irqdomain, so
>>>>> if this is anything else than the ARM GIC it will be an interesting
>>>>> undertaking to handle this.
>>>>
>>>> These are interrupt lines coming towards the host processor running
>>>> Linux and are directly connected to the ARM GIC. This INTC module is
>>>> actually an PRUSS internal interrupt controller that can take in 64 (on
>>>> most SoCs) external events/interrupt sources and multiplexing them
>>>> through two layers of many-to-one events-to-intr channels &
>>>> intr-channels-to-host interrupts. Couple of the host interrupts go to
>>>> the PRU cores themselves while the remaining ones come out of the IP to
>>>> connect to other GICs in the SoC.
>>>
>>> If the muxing is static (like set up once at probe) so that while
>>> the system is running, there is one and one only event mapped to
>>> the GIC from the component below it, then it is hierarchical.
>>
>> This is how it looks.
>>
>> [GIC]<---8---[INTC]<---64---[events from peripherals]
>>
>> The 8 interrupt lines from INTC to the GIC are 1:1 mapped and fixed
>> per SoC.  The muxing between 64 inputs to INTC and its 8 outputs are
>> programmable and might not necessarily be static per boot/probe as
>> it depends on what firmware is loaded on the PRU.
> 
> But the point is that at any given time, there are at most 8 out of 64
> inputs that are used, right? You *never* end-up with two (or more) of
> these "events" being multiplexed on a single output line.
> 

Since the INTC's internal logic allows assigning more than one event each outputs,
at most all 64 events can be assigned to one output or distributed among the 8 outputs.

> If these assertions do hold, then your design is typical of a
> hierarchy, for which we have countless examples in the tree (including
> for some TI HW).

OK.
Suman, Andrew, Lokesh, thoughts?

-- 
cheers,
-roger
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 15:44             ` Roger Quadros
@ 2019-02-14 15:48               ` Roger Quadros
  2019-02-15  0:59                 ` Suman Anna
  2019-02-14 15:51               ` Marc Zyngier
  1 sibling, 1 reply; 61+ messages in thread
From: Roger Quadros @ 2019-02-14 15:48 UTC (permalink / raw)
  To: Marc Zyngier, Suman Anna, Davis, Andrew, Lokesh Vutla
  Cc: Linus Walleij, ext Tony Lindgren, Ohad Ben-Cohen,
	Bjorn Andersson, David Lechner, Nori, Sekhar, Tero Kristo,
	nsaulnier, jreeder, Murali Karicheri, woods.technical,
	Linux-OMAP, linux-remoteproc, linux-kernel, DTML

fixed DTML id.

On 14/02/19 17:44, Roger Quadros wrote:
> On 14/02/19 14:52, Marc Zyngier wrote:
>> On Thu, 14 Feb 2019 10:55:10 +0000,
>> Roger Quadros <rogerq@ti.com> wrote:
>>>
>>>
>>> On 14/02/19 10:37, Linus Walleij wrote:
>>>> On Thu, Feb 14, 2019 at 4:13 AM Suman Anna <s-anna@ti.com> wrote:
>>>>> [Me]
>>>>
>>>>>> To be able to use hierarchical interrupt domain in the kernel, the top
>>>>>> interrupt controller must use the hierarchical (v2) irqdomain, so
>>>>>> if this is anything else than the ARM GIC it will be an interesting
>>>>>> undertaking to handle this.
>>>>>
>>>>> These are interrupt lines coming towards the host processor running
>>>>> Linux and are directly connected to the ARM GIC. This INTC module is
>>>>> actually an PRUSS internal interrupt controller that can take in 64 (on
>>>>> most SoCs) external events/interrupt sources and multiplexing them
>>>>> through two layers of many-to-one events-to-intr channels &
>>>>> intr-channels-to-host interrupts. Couple of the host interrupts go to
>>>>> the PRU cores themselves while the remaining ones come out of the IP to
>>>>> connect to other GICs in the SoC.
>>>>
>>>> If the muxing is static (like set up once at probe) so that while
>>>> the system is running, there is one and one only event mapped to
>>>> the GIC from the component below it, then it is hierarchical.
>>>
>>> This is how it looks.
>>>
>>> [GIC]<---8---[INTC]<---64---[events from peripherals]
>>>
>>> The 8 interrupt lines from INTC to the GIC are 1:1 mapped and fixed
>>> per SoC.  The muxing between 64 inputs to INTC and its 8 outputs are
>>> programmable and might not necessarily be static per boot/probe as
>>> it depends on what firmware is loaded on the PRU.
>>
>> But the point is that at any given time, there are at most 8 out of 64
>> inputs that are used, right? You *never* end-up with two (or more) of
>> these "events" being multiplexed on a single output line.
>>
> 
> Since the INTC's internal logic allows assigning more than one event each outputs,
> at most all 64 events can be assigned to one output or distributed among the 8 outputs.
> 
>> If these assertions do hold, then your design is typical of a
>> hierarchy, for which we have countless examples in the tree (including
>> for some TI HW).
> 
> OK.
> Suman, Andrew, Lokesh, thoughts?
> 

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 15:44             ` Roger Quadros
  2019-02-14 15:48               ` Roger Quadros
@ 2019-02-14 15:51               ` Marc Zyngier
  2019-02-14 16:50                 ` Roger Quadros
  1 sibling, 1 reply; 61+ messages in thread
From: Marc Zyngier @ 2019-02-14 15:51 UTC (permalink / raw)
  To: Roger Quadros, Suman Anna, Davis, Andrew, Lokesh Vutla
  Cc: Linus Walleij, ext Tony Lindgren, Ohad Ben-Cohen,
	Bjorn Andersson, David Lechner, Nori, Sekhar, Tero Kristo,
	nsaulnier, jreeder, Murali Karicheri, woods.technical,
	Linux-OMAP, linux-remoteproc, linux-kernel,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On 14/02/2019 15:44, Roger Quadros wrote:
> On 14/02/19 14:52, Marc Zyngier wrote:
>> On Thu, 14 Feb 2019 10:55:10 +0000,
>> Roger Quadros <rogerq@ti.com> wrote:
>>>
>>>
>>> On 14/02/19 10:37, Linus Walleij wrote:
>>>> On Thu, Feb 14, 2019 at 4:13 AM Suman Anna <s-anna@ti.com> wrote:
>>>>> [Me]
>>>>
>>>>>> To be able to use hierarchical interrupt domain in the kernel, the top
>>>>>> interrupt controller must use the hierarchical (v2) irqdomain, so
>>>>>> if this is anything else than the ARM GIC it will be an interesting
>>>>>> undertaking to handle this.
>>>>>
>>>>> These are interrupt lines coming towards the host processor running
>>>>> Linux and are directly connected to the ARM GIC. This INTC module is
>>>>> actually an PRUSS internal interrupt controller that can take in 64 (on
>>>>> most SoCs) external events/interrupt sources and multiplexing them
>>>>> through two layers of many-to-one events-to-intr channels &
>>>>> intr-channels-to-host interrupts. Couple of the host interrupts go to
>>>>> the PRU cores themselves while the remaining ones come out of the IP to
>>>>> connect to other GICs in the SoC.
>>>>
>>>> If the muxing is static (like set up once at probe) so that while
>>>> the system is running, there is one and one only event mapped to
>>>> the GIC from the component below it, then it is hierarchical.
>>>
>>> This is how it looks.
>>>
>>> [GIC]<---8---[INTC]<---64---[events from peripherals]
>>>
>>> The 8 interrupt lines from INTC to the GIC are 1:1 mapped and fixed
>>> per SoC.  The muxing between 64 inputs to INTC and its 8 outputs are
>>> programmable and might not necessarily be static per boot/probe as
>>> it depends on what firmware is loaded on the PRU.
>>
>> But the point is that at any given time, there are at most 8 out of 64
>> inputs that are used, right? You *never* end-up with two (or more) of
>> these "events" being multiplexed on a single output line.
>>
> 
> Since the INTC's internal logic allows assigning more than one event each outputs,
> at most all 64 events can be assigned to one output or distributed among the 8 outputs.

OK. Do you get individual masking and status bits for each input?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 11:08     ` Roger Quadros
@ 2019-02-14 15:56       ` Tony Lindgren
  2019-02-15  1:22         ` Suman Anna
  2019-02-15  1:08       ` Suman Anna
  2019-02-15 13:43       ` Matthijs van Duin
  2 siblings, 1 reply; 61+ messages in thread
From: Tony Lindgren @ 2019-02-14 15:56 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Suman Anna, ohad, bjorn.andersson, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Robert Nelson, dan,
	Matthijs van Duin, Rob Herring

* Roger Quadros <rogerq@ti.com> [190214 11:09]:
> Suman is mainly concerned about the following changes in v2
> 1) pruss node does not contain reg property representing entire ICSS.
> 2) pruss node does not contain interrupts.
> 
> Both of these are required if drivers/uio/uio_pruss.c or in future if
> VFIO is to be used.
> 
> The beagleboard community is a primary user of this driver and we need to
> find a solution so that PRUSS is usable either via remoteproc or via UIO.
> 
> Ideal case should allow user to use either of the drivers by just doing
> a unbind and bind.
> 
> I don't have a better idea than having a encapsulating node that has
> the appropriate reg and interrupt properties.

If there are existing use cases that need to be supported
you should list them as non-standard usage in the binding
and not recommended for future use. Rob may have some
comments on how to deal with this.

Then you can have device driver that needs to pass them
parse them from the PRUSS parent node. That does not mean
there needs to be a top level device driver for PRUSS,
the child control module can just parse the non-standard
bindings for compability from the parent node.

And naturally in addition to handling the non-standard
binding we need to have a proper standardized binding
too :)

Regards,

Tony

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 15:51               ` Marc Zyngier
@ 2019-02-14 16:50                 ` Roger Quadros
  0 siblings, 0 replies; 61+ messages in thread
From: Roger Quadros @ 2019-02-14 16:50 UTC (permalink / raw)
  To: Marc Zyngier, Suman Anna, Davis, Andrew, Lokesh Vutla
  Cc: Linus Walleij, ext Tony Lindgren, Ohad Ben-Cohen,
	Bjorn Andersson, David Lechner, Nori, Sekhar, Tero Kristo,
	nsaulnier, jreeder, Murali Karicheri, woods.technical,
	Linux-OMAP, linux-remoteproc, linux-kernel, DTML



On 14/02/19 17:51, Marc Zyngier wrote:
> On 14/02/2019 15:44, Roger Quadros wrote:
>> On 14/02/19 14:52, Marc Zyngier wrote:
>>> On Thu, 14 Feb 2019 10:55:10 +0000,
>>> Roger Quadros <rogerq@ti.com> wrote:
>>>>
>>>>
>>>> On 14/02/19 10:37, Linus Walleij wrote:
>>>>> On Thu, Feb 14, 2019 at 4:13 AM Suman Anna <s-anna@ti.com> wrote:
>>>>>> [Me]
>>>>>
>>>>>>> To be able to use hierarchical interrupt domain in the kernel, the top
>>>>>>> interrupt controller must use the hierarchical (v2) irqdomain, so
>>>>>>> if this is anything else than the ARM GIC it will be an interesting
>>>>>>> undertaking to handle this.
>>>>>>
>>>>>> These are interrupt lines coming towards the host processor running
>>>>>> Linux and are directly connected to the ARM GIC. This INTC module is
>>>>>> actually an PRUSS internal interrupt controller that can take in 64 (on
>>>>>> most SoCs) external events/interrupt sources and multiplexing them
>>>>>> through two layers of many-to-one events-to-intr channels &
>>>>>> intr-channels-to-host interrupts. Couple of the host interrupts go to
>>>>>> the PRU cores themselves while the remaining ones come out of the IP to
>>>>>> connect to other GICs in the SoC.
>>>>>
>>>>> If the muxing is static (like set up once at probe) so that while
>>>>> the system is running, there is one and one only event mapped to
>>>>> the GIC from the component below it, then it is hierarchical.
>>>>
>>>> This is how it looks.
>>>>
>>>> [GIC]<---8---[INTC]<---64---[events from peripherals]
>>>>
>>>> The 8 interrupt lines from INTC to the GIC are 1:1 mapped and fixed
>>>> per SoC.  The muxing between 64 inputs to INTC and its 8 outputs are
>>>> programmable and might not necessarily be static per boot/probe as
>>>> it depends on what firmware is loaded on the PRU.
>>>
>>> But the point is that at any given time, there are at most 8 out of 64
>>> inputs that are used, right? You *never* end-up with two (or more) of
>>> these "events" being multiplexed on a single output line.
>>>
>>
>> Since the INTC's internal logic allows assigning more than one event each outputs,
>> at most all 64 events can be assigned to one output or distributed among the 8 outputs.
> 
> OK. Do you get individual masking and status bits for each input?

Yes, we have individual enable/disable and status bits for each of the 64 events.

In addition to that it is possible to determine priority if multiple events come to the same
output by reading a register specific to that output.

--
cheers,
-roger
 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 15:48               ` Roger Quadros
@ 2019-02-15  0:59                 ` Suman Anna
  2019-02-20  9:51                   ` Linus Walleij
  0 siblings, 1 reply; 61+ messages in thread
From: Suman Anna @ 2019-02-15  0:59 UTC (permalink / raw)
  To: Roger Quadros, Marc Zyngier, Davis, Andrew, Lokesh Vutla
  Cc: Linus Walleij, ext Tony Lindgren, Ohad Ben-Cohen,
	Bjorn Andersson, David Lechner, Nori, Sekhar, Tero Kristo,
	nsaulnier, jreeder, Murali Karicheri, woods.technical,
	Linux-OMAP, linux-remoteproc, linux-kernel, DTML

On 2/14/19 9:48 AM, Roger Quadros wrote:
> fixed DTML id.
> 
> On 14/02/19 17:44, Roger Quadros wrote:
>> On 14/02/19 14:52, Marc Zyngier wrote:
>>> On Thu, 14 Feb 2019 10:55:10 +0000,
>>> Roger Quadros <rogerq@ti.com> wrote:
>>>>
>>>>
>>>> On 14/02/19 10:37, Linus Walleij wrote:
>>>>> On Thu, Feb 14, 2019 at 4:13 AM Suman Anna <s-anna@ti.com> wrote:
>>>>>> [Me]
>>>>>
>>>>>>> To be able to use hierarchical interrupt domain in the kernel, the top
>>>>>>> interrupt controller must use the hierarchical (v2) irqdomain, so
>>>>>>> if this is anything else than the ARM GIC it will be an interesting
>>>>>>> undertaking to handle this.
>>>>>>
>>>>>> These are interrupt lines coming towards the host processor running
>>>>>> Linux and are directly connected to the ARM GIC. This INTC module is
>>>>>> actually an PRUSS internal interrupt controller that can take in 64 (on
>>>>>> most SoCs) external events/interrupt sources and multiplexing them
>>>>>> through two layers of many-to-one events-to-intr channels &
>>>>>> intr-channels-to-host interrupts. Couple of the host interrupts go to
>>>>>> the PRU cores themselves while the remaining ones come out of the IP to
>>>>>> connect to other GICs in the SoC.
>>>>>
>>>>> If the muxing is static (like set up once at probe) so that while
>>>>> the system is running, there is one and one only event mapped to
>>>>> the GIC from the component below it, then it is hierarchical.
>>>>
>>>> This is how it looks.
>>>>
>>>> [GIC]<---8---[INTC]<---64---[events from peripherals]
>>>>
>>>> The 8 interrupt lines from INTC to the GIC are 1:1 mapped and fixed
>>>> per SoC.  The muxing between 64 inputs to INTC and its 8 outputs are
>>>> programmable and might not necessarily be static per boot/probe as
>>>> it depends on what firmware is loaded on the PRU.
>>>
>>> But the point is that at any given time, there are at most 8 out of 64
>>> inputs that are used, right? You *never* end-up with two (or more) of
>>> these "events" being multiplexed on a single output line.
>>>
>>
>> Since the INTC's internal logic allows assigning more than one event each outputs,
>> at most all 64 events can be assigned to one output or distributed among the 8 outputs.
>>
>>> If these assertions do hold, then your design is typical of a
>>> hierarchy, for which we have countless examples in the tree (including
>>> for some TI HW).
>>
>> OK.
>> Suman, Andrew, Lokesh, thoughts?
>>

Mark, Linus,

So, I hope it is clear from Roger's responses that above assertions do
not hold true to this INTC, and so want to confirm that we are good with
the current non-hierarchical design.

regards
Suman

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 11:08     ` Roger Quadros
  2019-02-14 15:56       ` Tony Lindgren
@ 2019-02-15  1:08       ` Suman Anna
  2019-02-15 13:43       ` Matthijs van Duin
  2 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-15  1:08 UTC (permalink / raw)
  To: Roger Quadros, tony, ohad, bjorn.andersson
  Cc: david, nsekhar, t-kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, linux-kernel,
	devicetree, Robert Nelson, dan, Matthijs van Duin

Hi Roger,

On 2/14/19 5:08 AM, Roger Quadros wrote:
> +Robert, Dan, Matthijs
> 
> Hi Suman,
> 
> On 14/02/19 04:52, Suman Anna wrote:
>> Hi Roger,
>>
>> On 2/4/19 8:22 AM, Roger Quadros wrote:
>>> From: Suman Anna <s-anna@ti.com>
>>>
>>> This patch adds the bindings for the Programmable Real-Time Unit
>>> and Industrial Communication Subsystem (PRU-ICSS) present on various
>>> SoCs such as AM33xx, AM437x, AM57xx, Keystone 66AK2G SoC, etc. It is
>>> present on the Davinci based OMAPL138 SoCs and K3 architecture
>>> based AM65x SoCs as well (not covered for now).
>>>
>>> Signed-off-by: Suman Anna <s-anna@ti.com>
>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>> ---
>>>  .../devicetree/bindings/soc/ti/ti,pruss.txt        | 212 +++++++++++++++++++++
>>>  1 file changed, 212 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
>>> new file mode 100644
>>> index 0000000..5ac76fd
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
>>> @@ -0,0 +1,212 @@
>>> +PRU-ICSS on TI SoCs
>>> +===================
>>> +
>>> +The Programmable Real-Time Unit and Industrial Communication Subsystem
>>> +(PRU-ICSS) is present on various TI SoCs such as AM335x, AM437x, Keystone
>>> +66AK2G, etc. A PRUSS consists of dual 32-bit RISC cores (Programmable
>>> +Real-Time Units, or PRUs) with program memory and data memory.
>>> +
>>> +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,
>>> +
>>> +  - Enhanced GPIO with async capture and serial support
>>> +  - 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)
>>> +  - a 16550-compatible UART to support PROFIBUS
>>> +  - Interrupt controller with 64 input events and 10 Host interrupts.
>>> +
>>> +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.
>>> +
>>> +Various sub-modules within a PRU-ICSS subsystem are represented as individual
>>> +nodes.
>>> +
>>> +PRUSS Node
>>> +=============
>>> +
>>> +This node represents the entire ICSS instance and the various modules are
>>> +contained as children. The PRUSS driver is responsible for managing the
>>> +common resources i.e. DRAM0, DRAM1, SHARED_RAM and CFG space.
>>> +
>>> +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
>>> +- 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
>>
>> Hmm, not sure what prompted you to deviate from the design we had on TI
>> SDK kernels. Your revised bindings does not allow us to use this device
>> for the scalability with either UIO/VFIO.
> 
> My understanding was that the device tree node will have to be modified
> in any case to support the current uio_pruss.c driver so we don't
> need to add things that we don't need right away.

Well, the previous design allows it to scale (as in add new properties
if needed to satisfy the UIO case) maintaining compatibility, but your
current binding does not even allow that. The modification you are
saying that can be done in the future cannot be done without breaking
the binding ABI with your current design.

> 
>>
>> Let's sort this out before you post the next series.
> 
> Let's discuss this here so I don't have to explain the whole thing again
> in the next series.

Yeah, thanks for the below summary.

regards
Suman

> 
> Tony,
> 
> Suman is mainly concerned about the following changes in v2
> 1) pruss node does not contain reg property representing entire ICSS.
> 2) pruss node does not contain interrupts.
> 
> Both of these are required if drivers/uio/uio_pruss.c or in future if
> VFIO is to be used.
> 
> The beagleboard community is a primary user of this driver and we need to
> find a solution so that PRUSS is usable either via remoteproc or via UIO.
> 
> Ideal case should allow user to use either of the drivers by just doing
> a unbind and bind.
> 
> I don't have a better idea than having a encapsulating node that has
> the appropriate reg and interrupt properties.
> 
> cheers,
> -roger
> 
>>
>> regards
>> Suman
>>
>>> +- reg-names      : should contain a string(s) from among the following names,
>>> +                   each representing a specific Data RAM region. Some PRU-ICSS
>>> +		   instances on certain SoCs might not have Shared DRAM.
>>> +                       "dram0" for Data RAM0,
>>> +                       "dram1" for Data RAM1,
>>> +                       "shrdram2" for Shared Data RAM,
>>> +- #address-cells : should be 1
>>> +- #size-cells    : should be 1
>>> +- ranges         : no specific range translations required, child nodes have the
>>> +                   same address view as the parent, so should be mentioned without
>>> +                   any value for the property
>>> +
>>> +Optional Properties:
>>> +--------------------
>>> +- no-shared-ram	: Should be present if the instance doesn't have Shared RAM.
>>> +		  e.g. AM4376 ICSS0 instance doesn't have Shared RAM.
>>> +
>>> +The PRUSS node will have one or more of the folowing child nodes.
>>> +
>>> +PRU CORES
>>> +=========
>>> +ICSS typically has 2 PRU cores. These should be represented as remoteproc devices.
>>> +
>>> +INTC node
>>> +=========
>>> +ICSS has one INTC interrupt controller module. This should be represented as
>>> +a standard interrupt-controller node.
>>> +
>>> +CFG, IEP, MII_RT
>>> +================
>>> +The individual sub-modules CFG, IEP and MII_RT are represented as a syscon
>>> +node each with specific node names as below:
>>> +                  "cfg" for CFG sub-module,
>>> +                  "iep" for IEP sub-module,
>>> +                  "mii_rt" for MII-RT sub-module,
>>> +
>>> +See Documentation/devicetree/bindings/mfd/syscon.txt for details.
>>> +
>>> +MDIO
>>> +====
>>> +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.
>>> +
>>> +Application/User Nodes
>>> +=======================
>>> +A PRU application/user node typically uses one or more PRU device nodes to
>>> +implement a PRU application/functionality. Each application/client node would
>>> +need a reference to at least a PRU node, and optionally pass some configuration
>>> +parameters.
>>> +
>>> +Required Properties:
>>> +--------------------
>>> +- prus                 : phandles to the PRU nodes used
>>> +
>>> +Optional Properties:
>>> +--------------------
>>> +- firmware-name        : firmwares for the PRU cores, the default firmware
>>> +                         for the core from the PRU node will be used if not
>>> +                         provided. The firmware names should correspond to
>>> +                         the PRU cores listed in the 'prus' property
>>> +- ti,pruss-gp-mux-sel  : array of values for the GP_MUX_SEL under PRUSS_GPCFG
>>> +                         register for a PRU. This selects the internal muxing
>>> +                         scheme for the PRU instance. If not provided, the
>>> +                         default out-of-reset value (0) for the PRU core is
>>> +                         used. Values should correspond to the PRU cores listed
>>> +                         in the 'prus' property
>>> +- ti,pru-interrupt-map : PRU interrupt mappings, containing an array of entries
>>> +                         with each entry consisting of 4 cell-values. First one
>>> +                         is an index towards the "prus" property to identify the
>>> +                         PRU core for the interrupt map, second is the PRU
>>> +                         System Event id, third is the PRU interrupt channel id
>>> +                         and fourth is the PRU host interrupt id. If provided,
>>> +                         this map will supercede any other configuration
>>> +                         provided through firmware
>>> +
>>> +Example:
>>> +========
>>> +1.	/* AM33xx PRU-ICSS */
>>> +
>>> +	pruss: pruss@0 {
>>> +		compatible = "ti,am3356-pruss";
>>> +		reg = <0x0 0x2000>,
>>> +		      <0x2000 0x2000>,
>>> +		      <0x10000 0x3000>;
>>> +		reg-names = "dram0", "dram1",
>>> +			    "shrdram2";
>>> +		#address-cells = <1>;
>>> +		#size-cells = <1>;
>>> +		ranges;
>>> +
>>> +		pruss_cfg: cfg@26000 {
>>> +			compatible = "syscon";
>>> +			reg = <0x26000 0x2000>;
>>> +		};
>>> +
>>> +		pruss_iep: iep@2e000 {
>>> +			compatible = "syscon";
>>> +			reg = <0x2e000 0x31c>;
>>> +		};
>>> +
>>> +		pruss_mii_rt: mii_rt@32000 {
>>> +			compatible = "syscon";
>>> +			reg = <0x32000 0x58>;
>>> +		};
>>> +
>>> +		pruss_intc: intc@20000 {
>>> +			compatible = "ti,am3356-pruss-intc";
>>> +			reg = <0x20000 0x2000>;
>>> +			reg-names = "intc";
>>> +			interrupt-controller;
>>> +			#interrupt-cells = <1>;
>>> +			interrupts = <20 21 22 23 24 25 26 27>;
>>> +			interrupt-names = "host2", "host3", "host4",
>>> +					  "host5", "host6", "host7",
>>> +					  "host8", "host9";
>>> +		};
>>> +
>>> +		pru0: pru@34000 {
>>> +			compatible = "ti,am3356-pru";
>>> +			reg = <0x34000 0x2000>,
>>> +			      <0x22000 0x400>,
>>> +			      <0x22400 0x100>;
>>> +			reg-names = "iram", "control", "debug";
>>> +			gpcfg = <&pruss_cfg 0x8>;
>>> +			firmware-name = "am335x-pru0-fw";
>>> +			interrupt-parent = <&pruss_intc>;
>>> +			interrupts = <16>, <17>;
>>> +			interrupt-names = "vring", "kick";
>>> +		};
>>> +
>>> +		pru1: pru@38000 {
>>> +			compatible = "ti,am3356-pru";
>>> +			reg = <0x38000 0x2000>,
>>> +			      <0x24000 0x400>,
>>> +			      <0x24400 0x100>;
>>> +			reg-names = "iram", "control", "debug";
>>> +			gpcfg = <&pruss_cfg 0xc>;
>>> +			firmware-name = "am335x-pru1-fw";
>>> +			interrupt-parent = <&pruss_intc>;
>>> +			interrupts = <18>, <19>;
>>> +			interrupt-names = "vring", "kick";
>>> +		};
>>> +
>>> +		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>;
>>> +			status = "disabled";
>>> +		};
>>> +	};
>>> +
>>> +2:	/* PRU application node example */
>>> +	app_node: app_node {
>>> +		prus = <&pru0>, <&pru1>;
>>> +		firmware-name = "pruss-app-fw", "pruss-app-fw-2";
>>> +		ti,pruss-gp-mux-sel = <2>, <1>;
>>> +		/* setup interrupts for prus:
>>> +		   prus[0] => pru1_0: ev=16, chnl=2, host-irq=7,
>>> +		   prus[1] => pru1_1: ev=19, chnl=1, host-irq=3 */
>>> +		ti,pru-interrupt-map = <0 16 2 7 >, <1 19 1 3>;
>>> +	}
>>>
>>
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 15:56       ` Tony Lindgren
@ 2019-02-15  1:22         ` Suman Anna
  0 siblings, 0 replies; 61+ messages in thread
From: Suman Anna @ 2019-02-15  1:22 UTC (permalink / raw)
  To: Tony Lindgren, Roger Quadros
  Cc: ohad, bjorn.andersson, david, nsekhar, t-kristo, nsaulnier,
	jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Robert Nelson, dan,
	Matthijs van Duin, Rob Herring

Hi Tony,

On 2/14/19 9:56 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [190214 11:09]:
>> Suman is mainly concerned about the following changes in v2
>> 1) pruss node does not contain reg property representing entire ICSS.
>> 2) pruss node does not contain interrupts.
>>
>> Both of these are required if drivers/uio/uio_pruss.c or in future if
>> VFIO is to be used.
>>
>> The beagleboard community is a primary user of this driver and we need to
>> find a solution so that PRUSS is usable either via remoteproc or via UIO.
>>
>> Ideal case should allow user to use either of the drivers by just doing
>> a unbind and bind.
>>
>> I don't have a better idea than having a encapsulating node that has
>> the appropriate reg and interrupt properties.
> 
> If there are existing use cases that need to be supported
> you should list them as non-standard usage in the binding
> and not recommended for future use. Rob may have some
> comments on how to deal with this.
> 
> Then you can have device driver that needs to pass them
> parse them from the PRUSS parent node. That does not mean
> there needs to be a top level device driver for PRUSS,
> the child control module can just parse the non-standard
> bindings for compability from the parent node.

The PRUSS SoC bus driver was handling all possible architectures (OMAP,
K2 and K3) which have different clocking and reset integration, and also
catering to the UIO vs remoteproc usecases, by taking care of clocks and
resets. I am ok to replace this layer with the ti-sysc layer on OMAP
SoCs since most of the functionality added to the driver is associated
with OCP, but we would still need a PRUSS driver.

Not all sub-modules are peripherals and managed by respective peripheral
drivers, and we still need a central entity managing the sub-system wide
resources. Layering wise - it is similar if we would have done a device
for the PRUSS local interconnect, but that driver wouldn't have much to
do with interconnect functionality. K2 and K3 families uses TI-SCI and
so you don't have a similar target-module concept that allows you to
query the PRUSS parent node for PRUSS specific ranges or properties.
In anycase, I don't think these drivers should depend on a parent
interconnect driver.

regards
Suman


> 
> And naturally in addition to handling the non-standard
> binding we need to have a proper standardized binding
> too :)
> 
> Regards,
> 
> Tony
> 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-14 11:08     ` Roger Quadros
  2019-02-14 15:56       ` Tony Lindgren
  2019-02-15  1:08       ` Suman Anna
@ 2019-02-15 13:43       ` Matthijs van Duin
  2 siblings, 0 replies; 61+ messages in thread
From: Matthijs van Duin @ 2019-02-15 13:43 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Suman Anna, Tony Lindgren, ohad, bjorn.andersson, David Lechner,
	nsekhar, Tero Kristo, nsaulnier, jreeder, m-karicheri2,
	woods.technical, linux-omap, linux-remoteproc, lkml, devicetree,
	Robert Nelson, dan

On Thu, 14 Feb 2019 at 12:08, Roger Quadros <rogerq@ti.com> wrote:
> The beagleboard community is a primary user of this driver and we need to
> find a solution so that PRUSS is usable either via remoteproc or via UIO.

While being able to switch drivers without changing the DT by forcibly
binding a different driver would definitely be a nice feature, and
would have been possible with the older remoteproc-pru bindings, I
think it's a stretch to say this "needs" a solution. Right now, in
practice, selection between uio-pruss and remoteproc-pru is done
simply by modifying the device tree appropriately (typically by having
u-boot apply an overlay to the DT), and I don't think anyone views
this as unduly burdensome?

Matthijs

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts
  2019-02-04 14:22 ` [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts Roger Quadros
  2019-02-04 16:36   ` Tony Lindgren
  2019-02-14  2:40   ` Suman Anna
@ 2019-02-18 19:32   ` Rob Herring
  2 siblings, 0 replies; 61+ messages in thread
From: Rob Herring @ 2019-02-18 19:32 UTC (permalink / raw)
  To: Roger Quadros
  Cc: tony, ohad, bjorn.andersson, s-anna, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, Andrew F. Davis,
	Thomas Gleixner, Jason Cooper, Marc Zyngier

On Mon, Feb 04, 2019 at 04:22:36PM +0200, Roger Quadros wrote:
> From: "Andrew F. Davis" <afd@ti.com>
> 
> The Programmable Real-Time Unit Subsystem (PRUSS) contains an
> interrupt controller (INTC) that can handle various system input
> events and post interrupts back to the device-level initiators.
> The INTC can support upto 64 input events with individual control
> configuration and hardware prioritization. These events are mapped
> onto 10 interrupt signals through two levels of many-to-one mapping
> support. Different interrupt signals are routed to the individual
> PRU cores or to the host CPU.
> 
> The PRUSS INTC platform driver manages this PRUSS interrupt
> controller and implements an irqchip driver to provide a Linux
> standard way for the PRU client users to enable/disable/ack/
> re-trigger a PRUSS system event. The system events to interrupt
> channels and host interrupts relies on the mapping configuration
> provided through a firmware resource table for now. This will be
> revisited and enhanced in the future for a better interface. The
> mappings will currently be programmed during the boot/shutdown
> of the PRU.
> 
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Jason Cooper <jason@lakedaemon.net>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Signed-off-by: Andrew F. Davis <afd@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  .../interrupt-controller/ti,pruss-intc-irq.txt     | 51 ++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
> new file mode 100644
> index 0000000..c70221c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc-irq.txt
> @@ -0,0 +1,51 @@
> +PRU ICSS INTC on TI SoCs
> +========================
> +
> +Each PRUSS has a single interrupt controller instance that is common to both
> +the PRU cores. Each interrupt controller can detect 64 input events which are
> +then mapped to 10 possible output interrupts through two levels of mapping. The
> +input events can be triggered by either the PRUs and/or various other PRUSS
> +internal and external peripherals. The first 2 output interrupts are fed
> +exclusively to the internal PRU cores, with the remaining 8 connected to
> +external interrupt controllers including the MPU.
> +
> +Required Properties:
> +--------------------
> +- compatible           : should be one of,
> +                             "ti,am3356-pruss-intc" for AM335x family of SoCs
> +                             "ti,am4376-pruss-intc" for AM437x family of SoCs
> +                             "ti,am5728-pruss-intc" for AM57xx family of SoCs
> +                             "ti,k2g-pruss-intc" for 66AK2G family of SoCs
> +- reg                  : base address and size for the PRUSS INTC sub-module
> +- reg-names            : should contain the string "intc"

Not really useful with only 1 entry.

> +- interrupts     : all the interrupts generated towards the main host
> +                   processor in the SoC. The format depends on the
> +                   interrupt specifier for the particular SoC's MPU
> +                   parent interrupt controller
> +- interrupt-names: should use one of the following names for each interrupt,
> +                   the name should match the corresponding host interrupt
> +                   number,
> +                       "host2", "host3", "host4", "host5", "host6",
> +                       "host7", "host8" or "host9"
> +                   NOTE: AM437x and 66AK2G SoCs do not have "host7" interrupt
> +                         connected to MPU
> +- interrupt-controller : mark this node as an interrupt controller
> +- #interrupt-cells     : should be 1. Client users shall use the PRU System
> +                         event number (the interrupt source that the client
> +                         is interested in) as the value of the interrupts
> +                         property in their node
> +
> +Example:
> +--------
> +		pruss_intc: intc@20000 {

interrupt-controller@20000

> +			compatible = "ti,am3356-pruss-intc";
> +			reg = <0x20000 0x2000>;
> +			reg-names = "intc";
> +			interrupt-controller;
> +			#interrupt-cells = <1>;
> +			interrupts = <20 21 22 23 24 25 26 27>;
> +			interrupt-names = "host2", "host3", "host4",
> +					  "host5", "host6", "host7",
> +					  "host8", "host9";
> +		};
> +
> -- 
> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 09/14] dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS
  2019-02-04 14:22 ` [PATCH v2 09/14] dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS Roger Quadros
@ 2019-02-18 19:36   ` Rob Herring
  0 siblings, 0 replies; 61+ messages in thread
From: Rob Herring @ 2019-02-18 19:36 UTC (permalink / raw)
  To: Roger Quadros
  Cc: tony, ohad, bjorn.andersson, s-anna, david, nsekhar, t-kristo,
	nsaulnier, jreeder, m-karicheri2, woods.technical, linux-omap,
	linux-remoteproc, linux-kernel, devicetree, rogerq

On Mon, 4 Feb 2019 16:22:42 +0200, Roger Quadros wrote:
> From: Suman Anna <s-anna@ti.com>
> 
> The Programmable Real-Time Unit Subsystem (PRUSS) consists of
> dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs)
> for program execution. This patch adds a remoteproc platform
> driver for managing the individual PRU RISC cores life cycle.
> 
> Add DT binding documentation for that.
> 
> Cc: Rob Herring <robh+dt@kernel.org>
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  .../bindings/remoteproc/ti,pru-rproc.txt           | 56 ++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.txt
> 

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings
  2019-02-15  0:59                 ` Suman Anna
@ 2019-02-20  9:51                   ` Linus Walleij
  0 siblings, 0 replies; 61+ messages in thread
From: Linus Walleij @ 2019-02-20  9:51 UTC (permalink / raw)
  To: Suman Anna
  Cc: Roger Quadros, Marc Zyngier, Davis, Andrew, Lokesh Vutla,
	ext Tony Lindgren, Ohad Ben-Cohen, Bjorn Andersson,
	David Lechner, Nori, Sekhar, Tero Kristo, nsaulnier, jreeder,
	Murali Karicheri, woods.technical, Linux-OMAP, linux-remoteproc,
	linux-kernel, DTML

On Fri, Feb 15, 2019 at 2:00 AM Suman Anna <s-anna@ti.com> wrote:

> Mark, Linus,
>
> So, I hope it is clear from Roger's responses that above assertions do
> not hold true to this INTC, and so want to confirm that we are good with
> the current non-hierarchical design.

IIUC the 64 lines are latched onto 8 lines, but all 64 lines have
individual masking and ACKing bits and can all be used at the same
time, so yes that is cascading and then you should indeed use
the chained (or nested) IRQ handler.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 61+ messages in thread

end of thread, other threads:[~2019-02-20  9:51 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-04 14:22 [PATCH v2 00/14] Add support for TI PRU ICSS Roger Quadros
2019-02-04 14:22 ` [PATCH v2 01/14] dt-bindings: remoteproc: Add TI PRUSS bindings Roger Quadros
2019-02-04 16:33   ` Tony Lindgren
2019-02-05  9:39     ` Roger Quadros
2019-02-05 15:08       ` Murali Karicheri
2019-02-05 15:41         ` Roger Quadros
2019-02-05 16:15           ` Murali Karicheri
2019-02-05 16:19             ` Tony Lindgren
2019-02-06 15:04               ` Roger Quadros
2019-02-14  2:47                 ` Suman Anna
2019-02-05 16:41       ` Tony Lindgren
2019-02-14  3:01         ` Suman Anna
2019-02-08 13:51   ` Linus Walleij
2019-02-14  3:12     ` Suman Anna
2019-02-14  8:37       ` Linus Walleij
2019-02-14 10:55         ` Roger Quadros
     [not found]           ` <86ef8asfap.wl-marc.zyngier@arm.com>
2019-02-14 15:44             ` Roger Quadros
2019-02-14 15:48               ` Roger Quadros
2019-02-15  0:59                 ` Suman Anna
2019-02-20  9:51                   ` Linus Walleij
2019-02-14 15:51               ` Marc Zyngier
2019-02-14 16:50                 ` Roger Quadros
2019-02-14  2:52   ` Suman Anna
2019-02-14 11:08     ` Roger Quadros
2019-02-14 15:56       ` Tony Lindgren
2019-02-15  1:22         ` Suman Anna
2019-02-15  1:08       ` Suman Anna
2019-02-15 13:43       ` Matthijs van Duin
2019-02-04 14:22 ` [PATCH v2 02/14] soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs Roger Quadros
2019-02-04 14:52   ` Andrew F. Davis
2019-02-04 15:32     ` Roger Quadros
2019-02-04 16:35     ` Tony Lindgren
2019-02-04 14:22 ` [PATCH v2 03/14] dt-binding: irqchip: Add pruss-intc-irq driver for PRUSS interrupts Roger Quadros
2019-02-04 16:36   ` Tony Lindgren
2019-02-14  2:40   ` Suman Anna
2019-02-18 19:32   ` Rob Herring
2019-02-04 14:22 ` [PATCH v2 04/14] irqchip: pruss: Add a PRUSS irqchip " Roger Quadros
2019-02-04 15:11   ` Andrew F. Davis
2019-02-04 15:33     ` Roger Quadros
2019-02-05  8:51       ` Roger Quadros
2019-02-14  2:15         ` Suman Anna
2019-02-04 18:15   ` Tony Lindgren
2019-02-05 10:35     ` Roger Quadros
2019-02-05 11:04       ` Marc Zyngier
2019-02-14  2:16         ` Suman Anna
2019-02-04 14:22 ` [PATCH v2 05/14] remoteproc: add map parameter to da_to_va Roger Quadros
2019-02-04 14:22 ` [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader Roger Quadros
2019-02-04 15:19   ` Andrew F. Davis
2019-02-14  2:22     ` Suman Anna
2019-02-04 14:22 ` [PATCH v2 07/14] remoteproc: Add a rproc_set_firmware() API Roger Quadros
2019-02-04 14:22 ` [PATCH v2 08/14] remoteproc: Add support to handle device specific resource types Roger Quadros
2019-02-04 14:22 ` [PATCH v2 09/14] dt-binding: remoteproc: Add binding doc for PRU Cores in the PRU-ICSS Roger Quadros
2019-02-18 19:36   ` Rob Herring
2019-02-04 14:22 ` [PATCH v2 10/14] remoteproc/pru: Add PRU remoteproc driver Roger Quadros
2019-02-14  2:35   ` Suman Anna
2019-02-14  3:44     ` Suman Anna
2019-02-04 14:22 ` [PATCH v2 11/14] remoteproc/pru: Add pru_rproc_set_ctable() and pru_rproc_set_gpimode() Roger Quadros
2019-02-04 14:22 ` [PATCH v2 12/14] remoteproc/pru: Add support for virtio rpmsg stack Roger Quadros
2019-02-04 14:22 ` [PATCH v2 13/14] rpmsg: virtio_rpmsg_bus: move back rpmsg_hdr into a public header Roger Quadros
2019-02-04 14:22 ` [PATCH v2 14/14] rpmsg: pru: add a PRU RPMsg driver Roger Quadros
2019-02-04 15:26   ` Andrew F. Davis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).