All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] Tegra Combined UART driver
@ 2018-06-20 12:20 ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-kernel, Mikko Perttunen, linux-serial,
	linux-tegra, linux-arm-kernel

Hi again - see individual patches for v2 changes.

Thanks,
Mikko

Original message:

Hi all,

on Tegra194, the primary console UART is the "Tegra Combined UART",
or TCU. This is a "virtual UART", where each consumer communicates
with a central implementation over mailboxes. The central
implementation then multiplexes the streams and arbitrates use of
a hardware serial port. This driver implements the consumer portion
to allow using the primary console.

The series is split into the following parts:
* patches 1 and 2 add the device tree bindings for mailbox and tcu
  itself.
* patch 3 adds a blocking transmission option to the mailbox
  framework.
* patches 4 and 5 add support for the "shared mailbox" primitive
  to the Tegra HSP driver.
* patch 6 adds the TCU driver itself
* patches 7 and 8 do the necessary device tree changes.

The series has been tested on the Tegra194 P2972 board.

Mikko Perttunen (8):
  dt-bindings: tegra186-hsp: Add shared interrupts
  dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
  mailbox: Add transmit done by blocking option
  mailbox: tegra-hsp: Refactor in preparation of mailboxes
  mailbox: tegra-hsp: Add support for shared mailboxes
  serial: Add Tegra Combined UART driver
  arm64: tegra: Add nodes for tcu on Tegra194
  arm64: tegra: Mark tcu as primary serial port on Tegra194 P2888

 .../bindings/mailbox/nvidia,tegra186-hsp.txt       |   3 +
 .../bindings/serial/nvidia,tegra194-tcu.txt        |  35 +++
 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi     |   2 +-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |  34 ++-
 drivers/mailbox/mailbox.c                          |  30 +-
 drivers/mailbox/mailbox.h                          |   1 +
 drivers/mailbox/tegra-hsp.c                        | 319 +++++++++++++++++----
 drivers/tty/serial/Kconfig                         |   9 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/tegra-tcu.c                     | 289 +++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 11 files changed, 658 insertions(+), 68 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
 create mode 100644 drivers/tty/serial/tegra-tcu.c

-- 
2.16.1

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

* [PATCH v2 0/8] Tegra Combined UART driver
@ 2018-06-20 12:20 ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

Hi again - see individual patches for v2 changes.

Thanks,
Mikko

Original message:

Hi all,

on Tegra194, the primary console UART is the "Tegra Combined UART",
or TCU. This is a "virtual UART", where each consumer communicates
with a central implementation over mailboxes. The central
implementation then multiplexes the streams and arbitrates use of
a hardware serial port. This driver implements the consumer portion
to allow using the primary console.

The series is split into the following parts:
* patches 1 and 2 add the device tree bindings for mailbox and tcu
  itself.
* patch 3 adds a blocking transmission option to the mailbox
  framework.
* patches 4 and 5 add support for the "shared mailbox" primitive
  to the Tegra HSP driver.
* patch 6 adds the TCU driver itself
* patches 7 and 8 do the necessary device tree changes.

The series has been tested on the Tegra194 P2972 board.

Mikko Perttunen (8):
  dt-bindings: tegra186-hsp: Add shared interrupts
  dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
  mailbox: Add transmit done by blocking option
  mailbox: tegra-hsp: Refactor in preparation of mailboxes
  mailbox: tegra-hsp: Add support for shared mailboxes
  serial: Add Tegra Combined UART driver
  arm64: tegra: Add nodes for tcu on Tegra194
  arm64: tegra: Mark tcu as primary serial port on Tegra194 P2888

 .../bindings/mailbox/nvidia,tegra186-hsp.txt       |   3 +
 .../bindings/serial/nvidia,tegra194-tcu.txt        |  35 +++
 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi     |   2 +-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |  34 ++-
 drivers/mailbox/mailbox.c                          |  30 +-
 drivers/mailbox/mailbox.h                          |   1 +
 drivers/mailbox/tegra-hsp.c                        | 319 +++++++++++++++++----
 drivers/tty/serial/Kconfig                         |   9 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/tegra-tcu.c                     | 289 +++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 11 files changed, 658 insertions(+), 68 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
 create mode 100644 drivers/tty/serial/tegra-tcu.c

-- 
2.16.1


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

* [PATCH v2 0/8] Tegra Combined UART driver
@ 2018-06-20 12:20 ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi again - see individual patches for v2 changes.

Thanks,
Mikko

Original message:

Hi all,

on Tegra194, the primary console UART is the "Tegra Combined UART",
or TCU. This is a "virtual UART", where each consumer communicates
with a central implementation over mailboxes. The central
implementation then multiplexes the streams and arbitrates use of
a hardware serial port. This driver implements the consumer portion
to allow using the primary console.

The series is split into the following parts:
* patches 1 and 2 add the device tree bindings for mailbox and tcu
  itself.
* patch 3 adds a blocking transmission option to the mailbox
  framework.
* patches 4 and 5 add support for the "shared mailbox" primitive
  to the Tegra HSP driver.
* patch 6 adds the TCU driver itself
* patches 7 and 8 do the necessary device tree changes.

The series has been tested on the Tegra194 P2972 board.

Mikko Perttunen (8):
  dt-bindings: tegra186-hsp: Add shared interrupts
  dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
  mailbox: Add transmit done by blocking option
  mailbox: tegra-hsp: Refactor in preparation of mailboxes
  mailbox: tegra-hsp: Add support for shared mailboxes
  serial: Add Tegra Combined UART driver
  arm64: tegra: Add nodes for tcu on Tegra194
  arm64: tegra: Mark tcu as primary serial port on Tegra194 P2888

 .../bindings/mailbox/nvidia,tegra186-hsp.txt       |   3 +
 .../bindings/serial/nvidia,tegra194-tcu.txt        |  35 +++
 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi     |   2 +-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |  34 ++-
 drivers/mailbox/mailbox.c                          |  30 +-
 drivers/mailbox/mailbox.h                          |   1 +
 drivers/mailbox/tegra-hsp.c                        | 319 +++++++++++++++++----
 drivers/tty/serial/Kconfig                         |   9 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/tegra-tcu.c                     | 289 +++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 11 files changed, 658 insertions(+), 68 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
 create mode 100644 drivers/tty/serial/tegra-tcu.c

-- 
2.16.1

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

* [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

HSP interrupts can be routed through exposed "shared interrupts". These
interrupts can be mapped to various internal interrupt lines. Add
interrupt properties for shared interrupts to the tegra186-hsp device
tree bindings. At the same time, add the compatibility string for
tegra194-hsp, which is backwards compatible with tegra186.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Edited commit message to not say that doorbell interrupts cannot be
      routed to shared interrupts.
    - Added tegra194 compatibility string.

 Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
index b99d25fc2f26..620c249363ca 100644
--- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
+++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
@@ -15,12 +15,15 @@ Required properties:
     Array of strings.
     one of:
     - "nvidia,tegra186-hsp"
+    - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"
 - reg : Offset and length of the register set for the device.
 - interrupt-names
     Array of strings.
     Contains a list of names for the interrupts described by the interrupt
     property. May contain the following entries, in any order:
     - "doorbell"
+    - "sharedN", where 'N' is a number from zero up to the number of
+      external interrupts supported by the HSP instance minus one.
     Users of this binding MUST look up entries in the interrupt property
     by name, using this interrupt-names property to do so.
 - interrupts
-- 
2.16.1

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

* [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

HSP interrupts can be routed through exposed "shared interrupts". These
interrupts can be mapped to various internal interrupt lines. Add
interrupt properties for shared interrupts to the tegra186-hsp device
tree bindings. At the same time, add the compatibility string for
tegra194-hsp, which is backwards compatible with tegra186.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Edited commit message to not say that doorbell interrupts cannot be
      routed to shared interrupts.
    - Added tegra194 compatibility string.

 Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
index b99d25fc2f26..620c249363ca 100644
--- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
+++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
@@ -15,12 +15,15 @@ Required properties:
     Array of strings.
     one of:
     - "nvidia,tegra186-hsp"
+    - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"
 - reg : Offset and length of the register set for the device.
 - interrupt-names
     Array of strings.
     Contains a list of names for the interrupts described by the interrupt
     property. May contain the following entries, in any order:
     - "doorbell"
+    - "sharedN", where 'N' is a number from zero up to the number of
+      external interrupts supported by the HSP instance minus one.
     Users of this binding MUST look up entries in the interrupt property
     by name, using this interrupt-names property to do so.
 - interrupts
-- 
2.16.1


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

* [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

HSP interrupts can be routed through exposed "shared interrupts". These
interrupts can be mapped to various internal interrupt lines. Add
interrupt properties for shared interrupts to the tegra186-hsp device
tree bindings. At the same time, add the compatibility string for
tegra194-hsp, which is backwards compatible with tegra186.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Edited commit message to not say that doorbell interrupts cannot be
      routed to shared interrupts.
    - Added tegra194 compatibility string.

 Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
index b99d25fc2f26..620c249363ca 100644
--- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
+++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
@@ -15,12 +15,15 @@ Required properties:
     Array of strings.
     one of:
     - "nvidia,tegra186-hsp"
+    - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"
 - reg : Offset and length of the register set for the device.
 - interrupt-names
     Array of strings.
     Contains a list of names for the interrupts described by the interrupt
     property. May contain the following entries, in any order:
     - "doorbell"
+    - "sharedN", where 'N' is a number from zero up to the number of
+      external interrupts supported by the HSP instance minus one.
     Users of this binding MUST look up entries in the interrupt property
     by name, using this interrupt-names property to do so.
 - interrupts
-- 
2.16.1

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

* [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia, tegra194-tcu
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-kernel, Mikko Perttunen, linux-serial,
	linux-tegra, linux-arm-kernel

Add bindings for the Tegra Combined UART device used to talk to the
UART console on Tegra194 systems.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---

Notes:
    v2:
    - Added Rob's Reviewed-by.

 .../bindings/serial/nvidia,tegra194-tcu.txt        | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt

diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
new file mode 100644
index 000000000000..a8becf6efd2a
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
@@ -0,0 +1,35 @@
+NVIDIA Tegra Combined UART (TCU)
+
+The TCU is a system for sharing a hardware UART instance among multiple
+systems within the Tegra SoC. It is implemented through a mailbox-
+based protocol where each "virtual UART" has a pair of mailboxes, one
+for transmitting and one for receiving, that is used to communicate
+with the hardware implementing the TCU.
+
+Required properties:
+- name : Should be tcu
+- compatible
+    Array of strings
+    One of:
+    - "nvidia,tegra194-tcu"
+- mbox-names:
+    "rx" - Mailbox for receiving data from hardware UART
+    "tx" - Mailbox for transmitting data to hardware UART
+- mboxes: Mailboxes corresponding to the mbox-names. 
+
+This node is a mailbox consumer. See the following files for details of
+the mailbox subsystem, and the specifiers implemented by the relevant
+provider(s):
+
+- .../mailbox/mailbox.txt
+- .../mailbox/nvidia,tegra186-hsp.txt
+
+Example bindings:
+-----------------
+
+tcu: tcu {
+	compatible = "nvidia,tegra194-tcu";
+	mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
+	         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
+	mbox-names = "rx", "tx";
+};
-- 
2.16.1

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

* [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

Add bindings for the Tegra Combined UART device used to talk to the
UART console on Tegra194 systems.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---

Notes:
    v2:
    - Added Rob's Reviewed-by.

 .../bindings/serial/nvidia,tegra194-tcu.txt        | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt

diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
new file mode 100644
index 000000000000..a8becf6efd2a
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
@@ -0,0 +1,35 @@
+NVIDIA Tegra Combined UART (TCU)
+
+The TCU is a system for sharing a hardware UART instance among multiple
+systems within the Tegra SoC. It is implemented through a mailbox-
+based protocol where each "virtual UART" has a pair of mailboxes, one
+for transmitting and one for receiving, that is used to communicate
+with the hardware implementing the TCU.
+
+Required properties:
+- name : Should be tcu
+- compatible
+    Array of strings
+    One of:
+    - "nvidia,tegra194-tcu"
+- mbox-names:
+    "rx" - Mailbox for receiving data from hardware UART
+    "tx" - Mailbox for transmitting data to hardware UART
+- mboxes: Mailboxes corresponding to the mbox-names. 
+
+This node is a mailbox consumer. See the following files for details of
+the mailbox subsystem, and the specifiers implemented by the relevant
+provider(s):
+
+- .../mailbox/mailbox.txt
+- .../mailbox/nvidia,tegra186-hsp.txt
+
+Example bindings:
+-----------------
+
+tcu: tcu {
+	compatible = "nvidia,tegra194-tcu";
+	mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
+	         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
+	mbox-names = "rx", "tx";
+};
-- 
2.16.1


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

* [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia, tegra194-tcu
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

Add bindings for the Tegra Combined UART device used to talk to the
UART console on Tegra194 systems.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---

Notes:
    v2:
    - Added Rob's Reviewed-by.

 .../bindings/serial/nvidia,tegra194-tcu.txt        | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt

diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
new file mode 100644
index 000000000000..a8becf6efd2a
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
@@ -0,0 +1,35 @@
+NVIDIA Tegra Combined UART (TCU)
+
+The TCU is a system for sharing a hardware UART instance among multiple
+systems within the Tegra SoC. It is implemented through a mailbox-
+based protocol where each "virtual UART" has a pair of mailboxes, one
+for transmitting and one for receiving, that is used to communicate
+with the hardware implementing the TCU.
+
+Required properties:
+- name : Should be tcu
+- compatible
+    Array of strings
+    One of:
+    - "nvidia,tegra194-tcu"
+- mbox-names:
+    "rx" - Mailbox for receiving data from hardware UART
+    "tx" - Mailbox for transmitting data to hardware UART
+- mboxes: Mailboxes corresponding to the mbox-names. 
+
+This node is a mailbox consumer. See the following files for details of
+the mailbox subsystem, and the specifiers implemented by the relevant
+provider(s):
+
+- .../mailbox/mailbox.txt
+- .../mailbox/nvidia,tegra186-hsp.txt
+
+Example bindings:
+-----------------
+
+tcu: tcu {
+	compatible = "nvidia,tegra194-tcu";
+	mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
+	         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
+	mbox-names = "rx", "tx";
+};
-- 
2.16.1

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

* [PATCH v2 3/8] mailbox: Add transmit done by blocking option
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

Add a new TXDONE option, TXDONE_BY_BLOCK. With this option, the
send_data function of the mailbox driver is expected to block until
the message has been sent. The new option is used with the Tegra
Combined UART driver to minimize unnecessary overhead when transmitting
data.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
 drivers/mailbox/mailbox.c | 30 +++++++++++++++++++++---------
 drivers/mailbox/mailbox.h |  1 +
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 674b35f402f5..5c76b70e673c 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -53,6 +53,8 @@ static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
 	return idx;
 }
 
+static void tx_tick(struct mbox_chan *chan, int r, bool submit_next);
+
 static void msg_submit(struct mbox_chan *chan)
 {
 	unsigned count, idx;
@@ -60,10 +62,13 @@ static void msg_submit(struct mbox_chan *chan)
 	void *data;
 	int err = -EBUSY;
 
+next:
 	spin_lock_irqsave(&chan->lock, flags);
 
-	if (!chan->msg_count || chan->active_req)
-		goto exit;
+	if (!chan->msg_count || chan->active_req) {
+		spin_unlock_irqrestore(&chan->lock, flags);
+		return;
+	}
 
 	count = chan->msg_count;
 	idx = chan->msg_free;
@@ -82,15 +87,21 @@ static void msg_submit(struct mbox_chan *chan)
 		chan->active_req = data;
 		chan->msg_count--;
 	}
-exit:
+
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	if (!err && (chan->txdone_method & TXDONE_BY_POLL))
 		/* kick start the timer immediately to avoid delays */
 		hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
+
+	if (chan->txdone_method & TXDONE_BY_BLOCK) {
+		tx_tick(chan, err, false);
+		if (!err)
+			goto next;
+	}
 }
 
-static void tx_tick(struct mbox_chan *chan, int r)
+static void tx_tick(struct mbox_chan *chan, int r, bool submit_next)
 {
 	unsigned long flags;
 	void *mssg;
@@ -101,7 +112,8 @@ static void tx_tick(struct mbox_chan *chan, int r)
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	/* Submit next message */
-	msg_submit(chan);
+	if (submit_next)
+		msg_submit(chan);
 
 	if (!mssg)
 		return;
@@ -127,7 +139,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
 		if (chan->active_req && chan->cl) {
 			txdone = chan->mbox->ops->last_tx_done(chan);
 			if (txdone)
-				tx_tick(chan, 0);
+				tx_tick(chan, 0, true);
 			else
 				resched = true;
 		}
@@ -176,7 +188,7 @@ void mbox_chan_txdone(struct mbox_chan *chan, int r)
 		return;
 	}
 
-	tx_tick(chan, r);
+	tx_tick(chan, r, true);
 }
 EXPORT_SYMBOL_GPL(mbox_chan_txdone);
 
@@ -196,7 +208,7 @@ void mbox_client_txdone(struct mbox_chan *chan, int r)
 		return;
 	}
 
-	tx_tick(chan, r);
+	tx_tick(chan, r, true);
 }
 EXPORT_SYMBOL_GPL(mbox_client_txdone);
 
@@ -275,7 +287,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
 		ret = wait_for_completion_timeout(&chan->tx_complete, wait);
 		if (ret == 0) {
 			t = -ETIME;
-			tx_tick(chan, t);
+			tx_tick(chan, t, true);
 		}
 	}
 
diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h
index 456ba68513bb..ec68e2e28cd6 100644
--- a/drivers/mailbox/mailbox.h
+++ b/drivers/mailbox/mailbox.h
@@ -10,5 +10,6 @@
 #define TXDONE_BY_IRQ	BIT(0) /* controller has remote RTR irq */
 #define TXDONE_BY_POLL	BIT(1) /* controller can read status of last TX */
 #define TXDONE_BY_ACK	BIT(2) /* S/W ACK recevied by Client ticks the TX */
+#define TXDONE_BY_BLOCK	BIT(3) /* mailbox driver send_data blocks until done */
 
 #endif /* __MAILBOX_H */
-- 
2.16.1

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

* [PATCH v2 3/8] mailbox: Add transmit done by blocking option
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

Add a new TXDONE option, TXDONE_BY_BLOCK. With this option, the
send_data function of the mailbox driver is expected to block until
the message has been sent. The new option is used with the Tegra
Combined UART driver to minimize unnecessary overhead when transmitting
data.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
 drivers/mailbox/mailbox.c | 30 +++++++++++++++++++++---------
 drivers/mailbox/mailbox.h |  1 +
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 674b35f402f5..5c76b70e673c 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -53,6 +53,8 @@ static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
 	return idx;
 }
 
+static void tx_tick(struct mbox_chan *chan, int r, bool submit_next);
+
 static void msg_submit(struct mbox_chan *chan)
 {
 	unsigned count, idx;
@@ -60,10 +62,13 @@ static void msg_submit(struct mbox_chan *chan)
 	void *data;
 	int err = -EBUSY;
 
+next:
 	spin_lock_irqsave(&chan->lock, flags);
 
-	if (!chan->msg_count || chan->active_req)
-		goto exit;
+	if (!chan->msg_count || chan->active_req) {
+		spin_unlock_irqrestore(&chan->lock, flags);
+		return;
+	}
 
 	count = chan->msg_count;
 	idx = chan->msg_free;
@@ -82,15 +87,21 @@ static void msg_submit(struct mbox_chan *chan)
 		chan->active_req = data;
 		chan->msg_count--;
 	}
-exit:
+
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	if (!err && (chan->txdone_method & TXDONE_BY_POLL))
 		/* kick start the timer immediately to avoid delays */
 		hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
+
+	if (chan->txdone_method & TXDONE_BY_BLOCK) {
+		tx_tick(chan, err, false);
+		if (!err)
+			goto next;
+	}
 }
 
-static void tx_tick(struct mbox_chan *chan, int r)
+static void tx_tick(struct mbox_chan *chan, int r, bool submit_next)
 {
 	unsigned long flags;
 	void *mssg;
@@ -101,7 +112,8 @@ static void tx_tick(struct mbox_chan *chan, int r)
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	/* Submit next message */
-	msg_submit(chan);
+	if (submit_next)
+		msg_submit(chan);
 
 	if (!mssg)
 		return;
@@ -127,7 +139,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
 		if (chan->active_req && chan->cl) {
 			txdone = chan->mbox->ops->last_tx_done(chan);
 			if (txdone)
-				tx_tick(chan, 0);
+				tx_tick(chan, 0, true);
 			else
 				resched = true;
 		}
@@ -176,7 +188,7 @@ void mbox_chan_txdone(struct mbox_chan *chan, int r)
 		return;
 	}
 
-	tx_tick(chan, r);
+	tx_tick(chan, r, true);
 }
 EXPORT_SYMBOL_GPL(mbox_chan_txdone);
 
@@ -196,7 +208,7 @@ void mbox_client_txdone(struct mbox_chan *chan, int r)
 		return;
 	}
 
-	tx_tick(chan, r);
+	tx_tick(chan, r, true);
 }
 EXPORT_SYMBOL_GPL(mbox_client_txdone);
 
@@ -275,7 +287,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
 		ret = wait_for_completion_timeout(&chan->tx_complete, wait);
 		if (ret == 0) {
 			t = -ETIME;
-			tx_tick(chan, t);
+			tx_tick(chan, t, true);
 		}
 	}
 
diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h
index 456ba68513bb..ec68e2e28cd6 100644
--- a/drivers/mailbox/mailbox.h
+++ b/drivers/mailbox/mailbox.h
@@ -10,5 +10,6 @@
 #define TXDONE_BY_IRQ	BIT(0) /* controller has remote RTR irq */
 #define TXDONE_BY_POLL	BIT(1) /* controller can read status of last TX */
 #define TXDONE_BY_ACK	BIT(2) /* S/W ACK recevied by Client ticks the TX */
+#define TXDONE_BY_BLOCK	BIT(3) /* mailbox driver send_data blocks until done */
 
 #endif /* __MAILBOX_H */
-- 
2.16.1


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

* [PATCH v2 3/8] mailbox: Add transmit done by blocking option
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

Add a new TXDONE option, TXDONE_BY_BLOCK. With this option, the
send_data function of the mailbox driver is expected to block until
the message has been sent. The new option is used with the Tegra
Combined UART driver to minimize unnecessary overhead when transmitting
data.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
 drivers/mailbox/mailbox.c | 30 +++++++++++++++++++++---------
 drivers/mailbox/mailbox.h |  1 +
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 674b35f402f5..5c76b70e673c 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -53,6 +53,8 @@ static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
 	return idx;
 }
 
+static void tx_tick(struct mbox_chan *chan, int r, bool submit_next);
+
 static void msg_submit(struct mbox_chan *chan)
 {
 	unsigned count, idx;
@@ -60,10 +62,13 @@ static void msg_submit(struct mbox_chan *chan)
 	void *data;
 	int err = -EBUSY;
 
+next:
 	spin_lock_irqsave(&chan->lock, flags);
 
-	if (!chan->msg_count || chan->active_req)
-		goto exit;
+	if (!chan->msg_count || chan->active_req) {
+		spin_unlock_irqrestore(&chan->lock, flags);
+		return;
+	}
 
 	count = chan->msg_count;
 	idx = chan->msg_free;
@@ -82,15 +87,21 @@ static void msg_submit(struct mbox_chan *chan)
 		chan->active_req = data;
 		chan->msg_count--;
 	}
-exit:
+
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	if (!err && (chan->txdone_method & TXDONE_BY_POLL))
 		/* kick start the timer immediately to avoid delays */
 		hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
+
+	if (chan->txdone_method & TXDONE_BY_BLOCK) {
+		tx_tick(chan, err, false);
+		if (!err)
+			goto next;
+	}
 }
 
-static void tx_tick(struct mbox_chan *chan, int r)
+static void tx_tick(struct mbox_chan *chan, int r, bool submit_next)
 {
 	unsigned long flags;
 	void *mssg;
@@ -101,7 +112,8 @@ static void tx_tick(struct mbox_chan *chan, int r)
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	/* Submit next message */
-	msg_submit(chan);
+	if (submit_next)
+		msg_submit(chan);
 
 	if (!mssg)
 		return;
@@ -127,7 +139,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
 		if (chan->active_req && chan->cl) {
 			txdone = chan->mbox->ops->last_tx_done(chan);
 			if (txdone)
-				tx_tick(chan, 0);
+				tx_tick(chan, 0, true);
 			else
 				resched = true;
 		}
@@ -176,7 +188,7 @@ void mbox_chan_txdone(struct mbox_chan *chan, int r)
 		return;
 	}
 
-	tx_tick(chan, r);
+	tx_tick(chan, r, true);
 }
 EXPORT_SYMBOL_GPL(mbox_chan_txdone);
 
@@ -196,7 +208,7 @@ void mbox_client_txdone(struct mbox_chan *chan, int r)
 		return;
 	}
 
-	tx_tick(chan, r);
+	tx_tick(chan, r, true);
 }
 EXPORT_SYMBOL_GPL(mbox_client_txdone);
 
@@ -275,7 +287,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
 		ret = wait_for_completion_timeout(&chan->tx_complete, wait);
 		if (ret == 0) {
 			t = -ETIME;
-			tx_tick(chan, t);
+			tx_tick(chan, t, true);
 		}
 	}
 
diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h
index 456ba68513bb..ec68e2e28cd6 100644
--- a/drivers/mailbox/mailbox.h
+++ b/drivers/mailbox/mailbox.h
@@ -10,5 +10,6 @@
 #define TXDONE_BY_IRQ	BIT(0) /* controller has remote RTR irq */
 #define TXDONE_BY_POLL	BIT(1) /* controller can read status of last TX */
 #define TXDONE_BY_ACK	BIT(2) /* S/W ACK recevied by Client ticks the TX */
+#define TXDONE_BY_BLOCK	BIT(3) /* mailbox driver send_data blocks until done */
 
 #endif /* __MAILBOX_H */
-- 
2.16.1

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

* [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The HSP driver is currently in many places written with the assumption
of only supporting doorbells. Prepare for the addition of shared
mailbox support by removing these assumptions and cleaning up the code.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Moved fixes for some style and other issues from the next patch
      here, where they belong.

 drivers/mailbox/tegra-hsp.c | 123 +++++++++++++++++++++++++++++---------------
 1 file changed, 81 insertions(+), 42 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 0cde356c11ab..5dc21a6d01bb 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -42,6 +42,7 @@ struct tegra_hsp_channel;
 struct tegra_hsp;
 
 struct tegra_hsp_channel {
+	unsigned int type;
 	struct tegra_hsp *hsp;
 	struct mbox_chan *chan;
 	void __iomem *regs;
@@ -55,6 +56,12 @@ struct tegra_hsp_doorbell {
 	unsigned int index;
 };
 
+static inline struct tegra_hsp_doorbell *
+channel_to_doorbell(struct tegra_hsp_channel *channel)
+{
+	return container_of(channel, struct tegra_hsp_doorbell, channel);
+}
+
 struct tegra_hsp_db_map {
 	const char *name;
 	unsigned int master;
@@ -69,7 +76,7 @@ struct tegra_hsp {
 	const struct tegra_hsp_soc *soc;
 	struct mbox_controller mbox;
 	void __iomem *regs;
-	unsigned int irq;
+	unsigned int doorbell_irq;
 	unsigned int num_sm;
 	unsigned int num_as;
 	unsigned int num_ss;
@@ -194,7 +201,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 	if (!db)
 		return ERR_PTR(-ENOMEM);
 
-	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
+	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K;
 	offset += index * 0x100;
 
 	db->channel.regs = hsp->regs + offset;
@@ -218,18 +225,8 @@ static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
 	kfree(db);
 }
 
-static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
-{
-	struct tegra_hsp_doorbell *db = chan->con_priv;
-
-	tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
-
-	return 0;
-}
-
-static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
+static int tegra_hsp_doorbell_startup(struct tegra_hsp_doorbell *db)
 {
-	struct tegra_hsp_doorbell *db = chan->con_priv;
 	struct tegra_hsp *hsp = db->channel.hsp;
 	struct tegra_hsp_doorbell *ccplex;
 	unsigned long flags;
@@ -260,9 +257,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
 	return 0;
 }
 
-static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
+static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
 {
-	struct tegra_hsp_doorbell *db = chan->con_priv;
 	struct tegra_hsp *hsp = db->channel.hsp;
 	struct tegra_hsp_doorbell *ccplex;
 	unsigned long flags;
@@ -281,35 +277,60 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
 	spin_unlock_irqrestore(&hsp->lock, flags);
 }
 
-static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
-	.send_data = tegra_hsp_doorbell_send_data,
-	.startup = tegra_hsp_doorbell_startup,
-	.shutdown = tegra_hsp_doorbell_shutdown,
+static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int tegra_hsp_startup(struct mbox_chan *chan)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
+	}
+
+	return -EINVAL;
+}
+
+static void tegra_hsp_shutdown(struct mbox_chan *chan)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
+		break;
+	}
+}
+
+static const struct mbox_chan_ops tegra_hsp_ops = {
+	.send_data = tegra_hsp_send_data,
+	.startup = tegra_hsp_startup,
+	.shutdown = tegra_hsp_shutdown,
 };
 
-static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
-					    const struct of_phandle_args *args)
+static struct mbox_chan *tegra_hsp_doorbell_xlate(struct tegra_hsp *hsp,
+						  unsigned int master)
 {
 	struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
-	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
-	unsigned int type = args->args[0];
-	unsigned int master = args->args[1];
 	struct tegra_hsp_doorbell *db;
 	struct mbox_chan *chan;
 	unsigned long flags;
 	unsigned int i;
 
-	switch (type) {
-	case TEGRA_HSP_MBOX_TYPE_DB:
-		db = tegra_hsp_doorbell_get(hsp, master);
-		if (db)
-			channel = &db->channel;
-
-		break;
-
-	default:
-		break;
-	}
+	db = tegra_hsp_doorbell_get(hsp, master);
+	if (db)
+		channel = &db->channel;
 
 	if (IS_ERR(channel))
 		return ERR_CAST(channel);
@@ -321,6 +342,7 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 		if (!chan->con_priv) {
 			chan->con_priv = channel;
 			channel->chan = chan;
+			channel->type = TEGRA_HSP_MBOX_TYPE_DB;
 			break;
 		}
 
@@ -332,6 +354,22 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 	return chan ?: ERR_PTR(-EBUSY);
 }
 
+static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
+					    const struct of_phandle_args *args)
+{
+	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
+	unsigned int type = args->args[0];
+	unsigned int param = args->args[1];
+
+	switch (type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		return tegra_hsp_doorbell_xlate(hsp, param);
+
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
 static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
 {
 	struct tegra_hsp_doorbell *db, *tmp;
@@ -397,14 +435,14 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	hsp->irq = err;
+	hsp->doorbell_irq = err;
 
 	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
 	hsp->mbox.num_chans = 32;
 	hsp->mbox.dev = &pdev->dev;
 	hsp->mbox.txdone_irq = false;
 	hsp->mbox.txdone_poll = false;
-	hsp->mbox.ops = &tegra_hsp_doorbell_ops;
+	hsp->mbox.ops = &tegra_hsp_ops;
 
 	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
 					sizeof(*hsp->mbox.chans),
@@ -427,11 +465,12 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
-			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
+	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
+			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
+			       dev_name(&pdev->dev), hsp);
 	if (err < 0) {
-		dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
-			hsp->irq, err);
+		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
+			hsp->doorbell_irq, err);
 		return err;
 	}
 
-- 
2.16.1

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

* [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The HSP driver is currently in many places written with the assumption
of only supporting doorbells. Prepare for the addition of shared
mailbox support by removing these assumptions and cleaning up the code.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Moved fixes for some style and other issues from the next patch
      here, where they belong.

 drivers/mailbox/tegra-hsp.c | 123 +++++++++++++++++++++++++++++---------------
 1 file changed, 81 insertions(+), 42 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 0cde356c11ab..5dc21a6d01bb 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -42,6 +42,7 @@ struct tegra_hsp_channel;
 struct tegra_hsp;
 
 struct tegra_hsp_channel {
+	unsigned int type;
 	struct tegra_hsp *hsp;
 	struct mbox_chan *chan;
 	void __iomem *regs;
@@ -55,6 +56,12 @@ struct tegra_hsp_doorbell {
 	unsigned int index;
 };
 
+static inline struct tegra_hsp_doorbell *
+channel_to_doorbell(struct tegra_hsp_channel *channel)
+{
+	return container_of(channel, struct tegra_hsp_doorbell, channel);
+}
+
 struct tegra_hsp_db_map {
 	const char *name;
 	unsigned int master;
@@ -69,7 +76,7 @@ struct tegra_hsp {
 	const struct tegra_hsp_soc *soc;
 	struct mbox_controller mbox;
 	void __iomem *regs;
-	unsigned int irq;
+	unsigned int doorbell_irq;
 	unsigned int num_sm;
 	unsigned int num_as;
 	unsigned int num_ss;
@@ -194,7 +201,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 	if (!db)
 		return ERR_PTR(-ENOMEM);
 
-	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
+	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K;
 	offset += index * 0x100;
 
 	db->channel.regs = hsp->regs + offset;
@@ -218,18 +225,8 @@ static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
 	kfree(db);
 }
 
-static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
-{
-	struct tegra_hsp_doorbell *db = chan->con_priv;
-
-	tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
-
-	return 0;
-}
-
-static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
+static int tegra_hsp_doorbell_startup(struct tegra_hsp_doorbell *db)
 {
-	struct tegra_hsp_doorbell *db = chan->con_priv;
 	struct tegra_hsp *hsp = db->channel.hsp;
 	struct tegra_hsp_doorbell *ccplex;
 	unsigned long flags;
@@ -260,9 +257,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
 	return 0;
 }
 
-static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
+static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
 {
-	struct tegra_hsp_doorbell *db = chan->con_priv;
 	struct tegra_hsp *hsp = db->channel.hsp;
 	struct tegra_hsp_doorbell *ccplex;
 	unsigned long flags;
@@ -281,35 +277,60 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
 	spin_unlock_irqrestore(&hsp->lock, flags);
 }
 
-static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
-	.send_data = tegra_hsp_doorbell_send_data,
-	.startup = tegra_hsp_doorbell_startup,
-	.shutdown = tegra_hsp_doorbell_shutdown,
+static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int tegra_hsp_startup(struct mbox_chan *chan)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
+	}
+
+	return -EINVAL;
+}
+
+static void tegra_hsp_shutdown(struct mbox_chan *chan)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
+		break;
+	}
+}
+
+static const struct mbox_chan_ops tegra_hsp_ops = {
+	.send_data = tegra_hsp_send_data,
+	.startup = tegra_hsp_startup,
+	.shutdown = tegra_hsp_shutdown,
 };
 
-static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
-					    const struct of_phandle_args *args)
+static struct mbox_chan *tegra_hsp_doorbell_xlate(struct tegra_hsp *hsp,
+						  unsigned int master)
 {
 	struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
-	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
-	unsigned int type = args->args[0];
-	unsigned int master = args->args[1];
 	struct tegra_hsp_doorbell *db;
 	struct mbox_chan *chan;
 	unsigned long flags;
 	unsigned int i;
 
-	switch (type) {
-	case TEGRA_HSP_MBOX_TYPE_DB:
-		db = tegra_hsp_doorbell_get(hsp, master);
-		if (db)
-			channel = &db->channel;
-
-		break;
-
-	default:
-		break;
-	}
+	db = tegra_hsp_doorbell_get(hsp, master);
+	if (db)
+		channel = &db->channel;
 
 	if (IS_ERR(channel))
 		return ERR_CAST(channel);
@@ -321,6 +342,7 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 		if (!chan->con_priv) {
 			chan->con_priv = channel;
 			channel->chan = chan;
+			channel->type = TEGRA_HSP_MBOX_TYPE_DB;
 			break;
 		}
 
@@ -332,6 +354,22 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 	return chan ?: ERR_PTR(-EBUSY);
 }
 
+static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
+					    const struct of_phandle_args *args)
+{
+	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
+	unsigned int type = args->args[0];
+	unsigned int param = args->args[1];
+
+	switch (type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		return tegra_hsp_doorbell_xlate(hsp, param);
+
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
 static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
 {
 	struct tegra_hsp_doorbell *db, *tmp;
@@ -397,14 +435,14 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	hsp->irq = err;
+	hsp->doorbell_irq = err;
 
 	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
 	hsp->mbox.num_chans = 32;
 	hsp->mbox.dev = &pdev->dev;
 	hsp->mbox.txdone_irq = false;
 	hsp->mbox.txdone_poll = false;
-	hsp->mbox.ops = &tegra_hsp_doorbell_ops;
+	hsp->mbox.ops = &tegra_hsp_ops;
 
 	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
 					sizeof(*hsp->mbox.chans),
@@ -427,11 +465,12 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
-			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
+	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
+			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
+			       dev_name(&pdev->dev), hsp);
 	if (err < 0) {
-		dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
-			hsp->irq, err);
+		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
+			hsp->doorbell_irq, err);
 		return err;
 	}
 
-- 
2.16.1


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

* [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

The HSP driver is currently in many places written with the assumption
of only supporting doorbells. Prepare for the addition of shared
mailbox support by removing these assumptions and cleaning up the code.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Moved fixes for some style and other issues from the next patch
      here, where they belong.

 drivers/mailbox/tegra-hsp.c | 123 +++++++++++++++++++++++++++++---------------
 1 file changed, 81 insertions(+), 42 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 0cde356c11ab..5dc21a6d01bb 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -42,6 +42,7 @@ struct tegra_hsp_channel;
 struct tegra_hsp;
 
 struct tegra_hsp_channel {
+	unsigned int type;
 	struct tegra_hsp *hsp;
 	struct mbox_chan *chan;
 	void __iomem *regs;
@@ -55,6 +56,12 @@ struct tegra_hsp_doorbell {
 	unsigned int index;
 };
 
+static inline struct tegra_hsp_doorbell *
+channel_to_doorbell(struct tegra_hsp_channel *channel)
+{
+	return container_of(channel, struct tegra_hsp_doorbell, channel);
+}
+
 struct tegra_hsp_db_map {
 	const char *name;
 	unsigned int master;
@@ -69,7 +76,7 @@ struct tegra_hsp {
 	const struct tegra_hsp_soc *soc;
 	struct mbox_controller mbox;
 	void __iomem *regs;
-	unsigned int irq;
+	unsigned int doorbell_irq;
 	unsigned int num_sm;
 	unsigned int num_as;
 	unsigned int num_ss;
@@ -194,7 +201,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 	if (!db)
 		return ERR_PTR(-ENOMEM);
 
-	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
+	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K;
 	offset += index * 0x100;
 
 	db->channel.regs = hsp->regs + offset;
@@ -218,18 +225,8 @@ static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
 	kfree(db);
 }
 
-static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
-{
-	struct tegra_hsp_doorbell *db = chan->con_priv;
-
-	tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
-
-	return 0;
-}
-
-static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
+static int tegra_hsp_doorbell_startup(struct tegra_hsp_doorbell *db)
 {
-	struct tegra_hsp_doorbell *db = chan->con_priv;
 	struct tegra_hsp *hsp = db->channel.hsp;
 	struct tegra_hsp_doorbell *ccplex;
 	unsigned long flags;
@@ -260,9 +257,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
 	return 0;
 }
 
-static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
+static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
 {
-	struct tegra_hsp_doorbell *db = chan->con_priv;
 	struct tegra_hsp *hsp = db->channel.hsp;
 	struct tegra_hsp_doorbell *ccplex;
 	unsigned long flags;
@@ -281,35 +277,60 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
 	spin_unlock_irqrestore(&hsp->lock, flags);
 }
 
-static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
-	.send_data = tegra_hsp_doorbell_send_data,
-	.startup = tegra_hsp_doorbell_startup,
-	.shutdown = tegra_hsp_doorbell_shutdown,
+static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int tegra_hsp_startup(struct mbox_chan *chan)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
+	}
+
+	return -EINVAL;
+}
+
+static void tegra_hsp_shutdown(struct mbox_chan *chan)
+{
+	struct tegra_hsp_channel *channel = chan->con_priv;
+
+	switch (channel->type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
+		break;
+	}
+}
+
+static const struct mbox_chan_ops tegra_hsp_ops = {
+	.send_data = tegra_hsp_send_data,
+	.startup = tegra_hsp_startup,
+	.shutdown = tegra_hsp_shutdown,
 };
 
-static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
-					    const struct of_phandle_args *args)
+static struct mbox_chan *tegra_hsp_doorbell_xlate(struct tegra_hsp *hsp,
+						  unsigned int master)
 {
 	struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
-	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
-	unsigned int type = args->args[0];
-	unsigned int master = args->args[1];
 	struct tegra_hsp_doorbell *db;
 	struct mbox_chan *chan;
 	unsigned long flags;
 	unsigned int i;
 
-	switch (type) {
-	case TEGRA_HSP_MBOX_TYPE_DB:
-		db = tegra_hsp_doorbell_get(hsp, master);
-		if (db)
-			channel = &db->channel;
-
-		break;
-
-	default:
-		break;
-	}
+	db = tegra_hsp_doorbell_get(hsp, master);
+	if (db)
+		channel = &db->channel;
 
 	if (IS_ERR(channel))
 		return ERR_CAST(channel);
@@ -321,6 +342,7 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 		if (!chan->con_priv) {
 			chan->con_priv = channel;
 			channel->chan = chan;
+			channel->type = TEGRA_HSP_MBOX_TYPE_DB;
 			break;
 		}
 
@@ -332,6 +354,22 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 	return chan ?: ERR_PTR(-EBUSY);
 }
 
+static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
+					    const struct of_phandle_args *args)
+{
+	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
+	unsigned int type = args->args[0];
+	unsigned int param = args->args[1];
+
+	switch (type) {
+	case TEGRA_HSP_MBOX_TYPE_DB:
+		return tegra_hsp_doorbell_xlate(hsp, param);
+
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
 static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
 {
 	struct tegra_hsp_doorbell *db, *tmp;
@@ -397,14 +435,14 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	hsp->irq = err;
+	hsp->doorbell_irq = err;
 
 	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
 	hsp->mbox.num_chans = 32;
 	hsp->mbox.dev = &pdev->dev;
 	hsp->mbox.txdone_irq = false;
 	hsp->mbox.txdone_poll = false;
-	hsp->mbox.ops = &tegra_hsp_doorbell_ops;
+	hsp->mbox.ops = &tegra_hsp_ops;
 
 	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
 					sizeof(*hsp->mbox.chans),
@@ -427,11 +465,12 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
-			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
+	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
+			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
+			       dev_name(&pdev->dev), hsp);
 	if (err < 0) {
-		dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
-			hsp->irq, err);
+		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
+			hsp->doorbell_irq, err);
 		return err;
 	}
 
-- 
2.16.1

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

* [PATCH v2 5/8] mailbox: tegra-hsp: Add support for shared mailboxes
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
registers consisting of a FULL bit in MSB position and 31 bits of data.
The hardware can be configured to trigger interrupts when a mailbox
is empty or full. Add support for these shared mailboxes to the HSP
driver.

The initial use for the mailboxes is the Tegra Combined UART. For this
purpose, we use interrupts to receive data, and spinning to wait for
the transmit mailbox to be emptied to minimize unnecessary overhead.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Added defines for some register fields
    - Simplified bit looping logic in interrupt handler
    - Changed write done polling to use readl_poll_timeout
    - Removed unnecessary zero assignments
    - Fixed two error cases in probe to do proper cleanup

 drivers/mailbox/tegra-hsp.c | 210 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 190 insertions(+), 20 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 5dc21a6d01bb..6864446417c9 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -13,6 +13,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/mailbox_controller.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -21,6 +22,13 @@
 
 #include <dt-bindings/mailbox/tegra186-hsp.h>
 
+#include "mailbox.h"
+
+#define HSP_INT0_IE		0x100
+#define HSP_INT_IR		0x304
+#define HSP_INT_IR_FULL_SHIFT	8
+#define HSP_INT_IR_FULL_MASK	0xff
+
 #define HSP_INT_DIMENSIONING	0x380
 #define HSP_nSM_SHIFT		0
 #define HSP_nSS_SHIFT		4
@@ -34,6 +42,9 @@
 #define HSP_DB_RAW	0x8
 #define HSP_DB_PENDING	0xc
 
+#define HSP_SM_SHRD_MBOX	0x0
+#define HSP_SM_SHRD_MBOX_FULL	BIT(31)
+
 #define HSP_DB_CCPLEX		1
 #define HSP_DB_BPMP		3
 #define HSP_DB_MAX		7
@@ -68,6 +79,18 @@ struct tegra_hsp_db_map {
 	unsigned int index;
 };
 
+struct tegra_hsp_mailbox {
+	struct tegra_hsp_channel channel;
+	unsigned int index;
+	bool sending;
+};
+
+static inline struct tegra_hsp_mailbox *
+channel_to_mailbox(struct tegra_hsp_channel *channel)
+{
+	return container_of(channel, struct tegra_hsp_mailbox, channel);
+}
+
 struct tegra_hsp_soc {
 	const struct tegra_hsp_db_map *map;
 };
@@ -77,6 +100,7 @@ struct tegra_hsp {
 	struct mbox_controller mbox;
 	void __iomem *regs;
 	unsigned int doorbell_irq;
+	unsigned int shared_irq;
 	unsigned int num_sm;
 	unsigned int num_as;
 	unsigned int num_ss;
@@ -85,6 +109,7 @@ struct tegra_hsp {
 	spinlock_t lock;
 
 	struct list_head doorbells;
+	struct tegra_hsp_mailbox *mailboxes;
 };
 
 static inline struct tegra_hsp *
@@ -189,6 +214,33 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t tegra_hsp_shared_irq(int irq, void *data)
+{
+	struct tegra_hsp_mailbox *mb;
+	struct tegra_hsp *hsp = data;
+	unsigned long bit, mask;
+	u32 value;
+
+	mask = tegra_hsp_readl(hsp, HSP_INT_IR);
+	/* Only interested in FULL interrupts */
+	mask = (mask >> HSP_INT_IR_FULL_SHIFT) & HSP_INT_IR_FULL_MASK;
+
+	for_each_set_bit(bit, &mask, 8) {
+		mb = &hsp->mailboxes[bit];
+
+		if (!mb->sending) {
+			value = tegra_hsp_channel_readl(&mb->channel,
+							HSP_SM_SHRD_MBOX);
+			value &= ~HSP_SM_SHRD_MBOX_FULL;
+			mbox_chan_received_data(mb->channel.chan, &value);
+			tegra_hsp_channel_writel(&mb->channel, value,
+						 HSP_SM_SHRD_MBOX);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static struct tegra_hsp_channel *
 tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 			  unsigned int master, unsigned int index)
@@ -277,14 +329,57 @@ static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
 	spin_unlock_irqrestore(&hsp->lock, flags);
 }
 
+static int tegra_hsp_mailbox_startup(struct tegra_hsp_mailbox *mb)
+{
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	u32 value;
+
+	mb->channel.chan->txdone_method = TXDONE_BY_BLOCK;
+
+	/* Route FULL interrupt to external IRQ 0 */
+	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+	value |= BIT(mb->index + 8);
+	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+	return 0;
+}
+
+static int tegra_hsp_mailbox_shutdown(struct tegra_hsp_mailbox *mb)
+{
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	u32 value;
+
+	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+	value &= ~BIT(mb->index + 8);
+	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+	return 0;
+}
+
 static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
 {
 	struct tegra_hsp_channel *channel = chan->con_priv;
+	struct tegra_hsp_mailbox *mailbox;
+	uint32_t value;
 
 	switch (channel->type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
 		return 0;
+
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		mailbox = channel_to_mailbox(channel);
+		mailbox->sending = true;
+
+		value = *(uint32_t *)data;
+		/* Mark mailbox full */
+		value |= HSP_SM_SHRD_MBOX_FULL;
+
+		tegra_hsp_channel_writel(channel, value, HSP_SM_SHRD_MBOX);
+
+		return readl_poll_timeout(
+			channel->regs + HSP_SM_SHRD_MBOX, value,
+			!(value & HSP_SM_SHRD_MBOX_FULL), 0, 10000);
 	}
 
 	return -EINVAL;
@@ -297,6 +392,8 @@ static int tegra_hsp_startup(struct mbox_chan *chan)
 	switch (channel->type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		return tegra_hsp_mailbox_startup(channel_to_mailbox(channel));
 	}
 
 	return -EINVAL;
@@ -310,6 +407,9 @@ static void tegra_hsp_shutdown(struct mbox_chan *chan)
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
 		break;
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		tegra_hsp_mailbox_shutdown(channel_to_mailbox(channel));
+		break;
 	}
 }
 
@@ -363,7 +463,16 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 
 	switch (type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
-		return tegra_hsp_doorbell_xlate(hsp, param);
+		if (hsp->doorbell_irq)
+			return tegra_hsp_doorbell_xlate(hsp, param);
+		else
+			return ERR_PTR(-EINVAL);
+
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		if (hsp->shared_irq && param < hsp->num_sm)
+			return hsp->mailboxes[param].channel.chan;
+		else
+			return ERR_PTR(-EINVAL);
 
 	default:
 		return ERR_PTR(-EINVAL);
@@ -402,6 +511,31 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
 	return 0;
 }
 
+static int tegra_hsp_add_mailboxes(struct tegra_hsp *hsp, struct device *dev)
+{
+	int i;
+
+	hsp->mailboxes = devm_kcalloc(dev, hsp->num_sm, sizeof(*hsp->mailboxes),
+				      GFP_KERNEL);
+	if (!hsp->mailboxes)
+		return -ENOMEM;
+
+	for (i = 0; i < hsp->num_sm; i++) {
+		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
+
+		mb->index = i;
+		mb->sending = false;
+
+		mb->channel.hsp = hsp;
+		mb->channel.type = TEGRA_HSP_MBOX_TYPE_SM;
+		mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K;
+		mb->channel.chan = &hsp->mbox.chans[i];
+		mb->channel.chan->con_priv = &mb->channel;
+	}
+
+	return 0;
+}
+
 static int tegra_hsp_probe(struct platform_device *pdev)
 {
 	struct tegra_hsp *hsp;
@@ -430,14 +564,15 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
 
 	err = platform_get_irq_byname(pdev, "doorbell");
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
-		return err;
-	}
+	if (err >= 0)
+		hsp->doorbell_irq = err;
 
-	hsp->doorbell_irq = err;
+	err = platform_get_irq_byname(pdev, "shared0");
+	if (err >= 0)
+		hsp->shared_irq = err;
 
 	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
+	/* First nSM are reserved for mailboxes */
 	hsp->mbox.num_chans = 32;
 	hsp->mbox.dev = &pdev->dev;
 	hsp->mbox.txdone_irq = false;
@@ -450,10 +585,22 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	if (!hsp->mbox.chans)
 		return -ENOMEM;
 
-	err = tegra_hsp_add_doorbells(hsp);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
-		return err;
+	if (hsp->doorbell_irq) {
+		err = tegra_hsp_add_doorbells(hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to add doorbells: %d\n",
+			        err);
+			return err;
+		}
+	}
+
+	if (hsp->shared_irq) {
+		err = tegra_hsp_add_mailboxes(hsp, &pdev->dev);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
+			        err);
+			goto remove_doorbells;
+		}
 	}
 
 	platform_set_drvdata(pdev, hsp);
@@ -461,20 +608,42 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	err = mbox_controller_register(&hsp->mbox);
 	if (err) {
 		dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
-		tegra_hsp_remove_doorbells(hsp);
-		return err;
+		goto remove_doorbells;
 	}
 
-	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
-			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
-			       dev_name(&pdev->dev), hsp);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
-			hsp->doorbell_irq, err);
-		return err;
+	if (hsp->doorbell_irq) {
+		err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
+				       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
+				       dev_name(&pdev->dev), hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+			        "failed to request doorbell IRQ#%u: %d\n",
+				hsp->doorbell_irq, err);
+			goto unregister_mbox_controller;
+		}
+	}
+
+	if (hsp->shared_irq) {
+		err = devm_request_irq(&pdev->dev, hsp->shared_irq,
+				       tegra_hsp_shared_irq, 0,
+				       dev_name(&pdev->dev), hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"failed to request shared0 IRQ%u: %d\n",
+				hsp->shared_irq, err);
+			goto unregister_mbox_controller;
+		}
 	}
 
 	return 0;
+
+unregister_mbox_controller:
+	mbox_controller_unregister(&hsp->mbox);
+remove_doorbells:
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
+
+	return err;
 }
 
 static int tegra_hsp_remove(struct platform_device *pdev)
@@ -482,7 +651,8 @@ static int tegra_hsp_remove(struct platform_device *pdev)
 	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
 
 	mbox_controller_unregister(&hsp->mbox);
-	tegra_hsp_remove_doorbells(hsp);
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
 
 	return 0;
 }
-- 
2.16.1

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

* [PATCH v2 5/8] mailbox: tegra-hsp: Add support for shared mailboxes
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
registers consisting of a FULL bit in MSB position and 31 bits of data.
The hardware can be configured to trigger interrupts when a mailbox
is empty or full. Add support for these shared mailboxes to the HSP
driver.

The initial use for the mailboxes is the Tegra Combined UART. For this
purpose, we use interrupts to receive data, and spinning to wait for
the transmit mailbox to be emptied to minimize unnecessary overhead.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Added defines for some register fields
    - Simplified bit looping logic in interrupt handler
    - Changed write done polling to use readl_poll_timeout
    - Removed unnecessary zero assignments
    - Fixed two error cases in probe to do proper cleanup

 drivers/mailbox/tegra-hsp.c | 210 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 190 insertions(+), 20 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 5dc21a6d01bb..6864446417c9 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -13,6 +13,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/mailbox_controller.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -21,6 +22,13 @@
 
 #include <dt-bindings/mailbox/tegra186-hsp.h>
 
+#include "mailbox.h"
+
+#define HSP_INT0_IE		0x100
+#define HSP_INT_IR		0x304
+#define HSP_INT_IR_FULL_SHIFT	8
+#define HSP_INT_IR_FULL_MASK	0xff
+
 #define HSP_INT_DIMENSIONING	0x380
 #define HSP_nSM_SHIFT		0
 #define HSP_nSS_SHIFT		4
@@ -34,6 +42,9 @@
 #define HSP_DB_RAW	0x8
 #define HSP_DB_PENDING	0xc
 
+#define HSP_SM_SHRD_MBOX	0x0
+#define HSP_SM_SHRD_MBOX_FULL	BIT(31)
+
 #define HSP_DB_CCPLEX		1
 #define HSP_DB_BPMP		3
 #define HSP_DB_MAX		7
@@ -68,6 +79,18 @@ struct tegra_hsp_db_map {
 	unsigned int index;
 };
 
+struct tegra_hsp_mailbox {
+	struct tegra_hsp_channel channel;
+	unsigned int index;
+	bool sending;
+};
+
+static inline struct tegra_hsp_mailbox *
+channel_to_mailbox(struct tegra_hsp_channel *channel)
+{
+	return container_of(channel, struct tegra_hsp_mailbox, channel);
+}
+
 struct tegra_hsp_soc {
 	const struct tegra_hsp_db_map *map;
 };
@@ -77,6 +100,7 @@ struct tegra_hsp {
 	struct mbox_controller mbox;
 	void __iomem *regs;
 	unsigned int doorbell_irq;
+	unsigned int shared_irq;
 	unsigned int num_sm;
 	unsigned int num_as;
 	unsigned int num_ss;
@@ -85,6 +109,7 @@ struct tegra_hsp {
 	spinlock_t lock;
 
 	struct list_head doorbells;
+	struct tegra_hsp_mailbox *mailboxes;
 };
 
 static inline struct tegra_hsp *
@@ -189,6 +214,33 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t tegra_hsp_shared_irq(int irq, void *data)
+{
+	struct tegra_hsp_mailbox *mb;
+	struct tegra_hsp *hsp = data;
+	unsigned long bit, mask;
+	u32 value;
+
+	mask = tegra_hsp_readl(hsp, HSP_INT_IR);
+	/* Only interested in FULL interrupts */
+	mask = (mask >> HSP_INT_IR_FULL_SHIFT) & HSP_INT_IR_FULL_MASK;
+
+	for_each_set_bit(bit, &mask, 8) {
+		mb = &hsp->mailboxes[bit];
+
+		if (!mb->sending) {
+			value = tegra_hsp_channel_readl(&mb->channel,
+							HSP_SM_SHRD_MBOX);
+			value &= ~HSP_SM_SHRD_MBOX_FULL;
+			mbox_chan_received_data(mb->channel.chan, &value);
+			tegra_hsp_channel_writel(&mb->channel, value,
+						 HSP_SM_SHRD_MBOX);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static struct tegra_hsp_channel *
 tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 			  unsigned int master, unsigned int index)
@@ -277,14 +329,57 @@ static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
 	spin_unlock_irqrestore(&hsp->lock, flags);
 }
 
+static int tegra_hsp_mailbox_startup(struct tegra_hsp_mailbox *mb)
+{
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	u32 value;
+
+	mb->channel.chan->txdone_method = TXDONE_BY_BLOCK;
+
+	/* Route FULL interrupt to external IRQ 0 */
+	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+	value |= BIT(mb->index + 8);
+	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+	return 0;
+}
+
+static int tegra_hsp_mailbox_shutdown(struct tegra_hsp_mailbox *mb)
+{
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	u32 value;
+
+	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+	value &= ~BIT(mb->index + 8);
+	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+	return 0;
+}
+
 static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
 {
 	struct tegra_hsp_channel *channel = chan->con_priv;
+	struct tegra_hsp_mailbox *mailbox;
+	uint32_t value;
 
 	switch (channel->type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
 		return 0;
+
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		mailbox = channel_to_mailbox(channel);
+		mailbox->sending = true;
+
+		value = *(uint32_t *)data;
+		/* Mark mailbox full */
+		value |= HSP_SM_SHRD_MBOX_FULL;
+
+		tegra_hsp_channel_writel(channel, value, HSP_SM_SHRD_MBOX);
+
+		return readl_poll_timeout(
+			channel->regs + HSP_SM_SHRD_MBOX, value,
+			!(value & HSP_SM_SHRD_MBOX_FULL), 0, 10000);
 	}
 
 	return -EINVAL;
@@ -297,6 +392,8 @@ static int tegra_hsp_startup(struct mbox_chan *chan)
 	switch (channel->type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		return tegra_hsp_mailbox_startup(channel_to_mailbox(channel));
 	}
 
 	return -EINVAL;
@@ -310,6 +407,9 @@ static void tegra_hsp_shutdown(struct mbox_chan *chan)
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
 		break;
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		tegra_hsp_mailbox_shutdown(channel_to_mailbox(channel));
+		break;
 	}
 }
 
@@ -363,7 +463,16 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 
 	switch (type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
-		return tegra_hsp_doorbell_xlate(hsp, param);
+		if (hsp->doorbell_irq)
+			return tegra_hsp_doorbell_xlate(hsp, param);
+		else
+			return ERR_PTR(-EINVAL);
+
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		if (hsp->shared_irq && param < hsp->num_sm)
+			return hsp->mailboxes[param].channel.chan;
+		else
+			return ERR_PTR(-EINVAL);
 
 	default:
 		return ERR_PTR(-EINVAL);
@@ -402,6 +511,31 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
 	return 0;
 }
 
+static int tegra_hsp_add_mailboxes(struct tegra_hsp *hsp, struct device *dev)
+{
+	int i;
+
+	hsp->mailboxes = devm_kcalloc(dev, hsp->num_sm, sizeof(*hsp->mailboxes),
+				      GFP_KERNEL);
+	if (!hsp->mailboxes)
+		return -ENOMEM;
+
+	for (i = 0; i < hsp->num_sm; i++) {
+		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
+
+		mb->index = i;
+		mb->sending = false;
+
+		mb->channel.hsp = hsp;
+		mb->channel.type = TEGRA_HSP_MBOX_TYPE_SM;
+		mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K;
+		mb->channel.chan = &hsp->mbox.chans[i];
+		mb->channel.chan->con_priv = &mb->channel;
+	}
+
+	return 0;
+}
+
 static int tegra_hsp_probe(struct platform_device *pdev)
 {
 	struct tegra_hsp *hsp;
@@ -430,14 +564,15 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
 
 	err = platform_get_irq_byname(pdev, "doorbell");
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
-		return err;
-	}
+	if (err >= 0)
+		hsp->doorbell_irq = err;
 
-	hsp->doorbell_irq = err;
+	err = platform_get_irq_byname(pdev, "shared0");
+	if (err >= 0)
+		hsp->shared_irq = err;
 
 	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
+	/* First nSM are reserved for mailboxes */
 	hsp->mbox.num_chans = 32;
 	hsp->mbox.dev = &pdev->dev;
 	hsp->mbox.txdone_irq = false;
@@ -450,10 +585,22 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	if (!hsp->mbox.chans)
 		return -ENOMEM;
 
-	err = tegra_hsp_add_doorbells(hsp);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
-		return err;
+	if (hsp->doorbell_irq) {
+		err = tegra_hsp_add_doorbells(hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to add doorbells: %d\n",
+			        err);
+			return err;
+		}
+	}
+
+	if (hsp->shared_irq) {
+		err = tegra_hsp_add_mailboxes(hsp, &pdev->dev);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
+			        err);
+			goto remove_doorbells;
+		}
 	}
 
 	platform_set_drvdata(pdev, hsp);
@@ -461,20 +608,42 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	err = mbox_controller_register(&hsp->mbox);
 	if (err) {
 		dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
-		tegra_hsp_remove_doorbells(hsp);
-		return err;
+		goto remove_doorbells;
 	}
 
-	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
-			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
-			       dev_name(&pdev->dev), hsp);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
-			hsp->doorbell_irq, err);
-		return err;
+	if (hsp->doorbell_irq) {
+		err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
+				       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
+				       dev_name(&pdev->dev), hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+			        "failed to request doorbell IRQ#%u: %d\n",
+				hsp->doorbell_irq, err);
+			goto unregister_mbox_controller;
+		}
+	}
+
+	if (hsp->shared_irq) {
+		err = devm_request_irq(&pdev->dev, hsp->shared_irq,
+				       tegra_hsp_shared_irq, 0,
+				       dev_name(&pdev->dev), hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"failed to request shared0 IRQ%u: %d\n",
+				hsp->shared_irq, err);
+			goto unregister_mbox_controller;
+		}
 	}
 
 	return 0;
+
+unregister_mbox_controller:
+	mbox_controller_unregister(&hsp->mbox);
+remove_doorbells:
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
+
+	return err;
 }
 
 static int tegra_hsp_remove(struct platform_device *pdev)
@@ -482,7 +651,8 @@ static int tegra_hsp_remove(struct platform_device *pdev)
 	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
 
 	mbox_controller_unregister(&hsp->mbox);
-	tegra_hsp_remove_doorbells(hsp);
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
 
 	return 0;
 }
-- 
2.16.1


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

* [PATCH v2 5/8] mailbox: tegra-hsp: Add support for shared mailboxes
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
registers consisting of a FULL bit in MSB position and 31 bits of data.
The hardware can be configured to trigger interrupts when a mailbox
is empty or full. Add support for these shared mailboxes to the HSP
driver.

The initial use for the mailboxes is the Tegra Combined UART. For this
purpose, we use interrupts to receive data, and spinning to wait for
the transmit mailbox to be emptied to minimize unnecessary overhead.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Added defines for some register fields
    - Simplified bit looping logic in interrupt handler
    - Changed write done polling to use readl_poll_timeout
    - Removed unnecessary zero assignments
    - Fixed two error cases in probe to do proper cleanup

 drivers/mailbox/tegra-hsp.c | 210 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 190 insertions(+), 20 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 5dc21a6d01bb..6864446417c9 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -13,6 +13,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/mailbox_controller.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -21,6 +22,13 @@
 
 #include <dt-bindings/mailbox/tegra186-hsp.h>
 
+#include "mailbox.h"
+
+#define HSP_INT0_IE		0x100
+#define HSP_INT_IR		0x304
+#define HSP_INT_IR_FULL_SHIFT	8
+#define HSP_INT_IR_FULL_MASK	0xff
+
 #define HSP_INT_DIMENSIONING	0x380
 #define HSP_nSM_SHIFT		0
 #define HSP_nSS_SHIFT		4
@@ -34,6 +42,9 @@
 #define HSP_DB_RAW	0x8
 #define HSP_DB_PENDING	0xc
 
+#define HSP_SM_SHRD_MBOX	0x0
+#define HSP_SM_SHRD_MBOX_FULL	BIT(31)
+
 #define HSP_DB_CCPLEX		1
 #define HSP_DB_BPMP		3
 #define HSP_DB_MAX		7
@@ -68,6 +79,18 @@ struct tegra_hsp_db_map {
 	unsigned int index;
 };
 
+struct tegra_hsp_mailbox {
+	struct tegra_hsp_channel channel;
+	unsigned int index;
+	bool sending;
+};
+
+static inline struct tegra_hsp_mailbox *
+channel_to_mailbox(struct tegra_hsp_channel *channel)
+{
+	return container_of(channel, struct tegra_hsp_mailbox, channel);
+}
+
 struct tegra_hsp_soc {
 	const struct tegra_hsp_db_map *map;
 };
@@ -77,6 +100,7 @@ struct tegra_hsp {
 	struct mbox_controller mbox;
 	void __iomem *regs;
 	unsigned int doorbell_irq;
+	unsigned int shared_irq;
 	unsigned int num_sm;
 	unsigned int num_as;
 	unsigned int num_ss;
@@ -85,6 +109,7 @@ struct tegra_hsp {
 	spinlock_t lock;
 
 	struct list_head doorbells;
+	struct tegra_hsp_mailbox *mailboxes;
 };
 
 static inline struct tegra_hsp *
@@ -189,6 +214,33 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t tegra_hsp_shared_irq(int irq, void *data)
+{
+	struct tegra_hsp_mailbox *mb;
+	struct tegra_hsp *hsp = data;
+	unsigned long bit, mask;
+	u32 value;
+
+	mask = tegra_hsp_readl(hsp, HSP_INT_IR);
+	/* Only interested in FULL interrupts */
+	mask = (mask >> HSP_INT_IR_FULL_SHIFT) & HSP_INT_IR_FULL_MASK;
+
+	for_each_set_bit(bit, &mask, 8) {
+		mb = &hsp->mailboxes[bit];
+
+		if (!mb->sending) {
+			value = tegra_hsp_channel_readl(&mb->channel,
+							HSP_SM_SHRD_MBOX);
+			value &= ~HSP_SM_SHRD_MBOX_FULL;
+			mbox_chan_received_data(mb->channel.chan, &value);
+			tegra_hsp_channel_writel(&mb->channel, value,
+						 HSP_SM_SHRD_MBOX);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static struct tegra_hsp_channel *
 tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 			  unsigned int master, unsigned int index)
@@ -277,14 +329,57 @@ static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
 	spin_unlock_irqrestore(&hsp->lock, flags);
 }
 
+static int tegra_hsp_mailbox_startup(struct tegra_hsp_mailbox *mb)
+{
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	u32 value;
+
+	mb->channel.chan->txdone_method = TXDONE_BY_BLOCK;
+
+	/* Route FULL interrupt to external IRQ 0 */
+	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+	value |= BIT(mb->index + 8);
+	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+	return 0;
+}
+
+static int tegra_hsp_mailbox_shutdown(struct tegra_hsp_mailbox *mb)
+{
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	u32 value;
+
+	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+	value &= ~BIT(mb->index + 8);
+	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+	return 0;
+}
+
 static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
 {
 	struct tegra_hsp_channel *channel = chan->con_priv;
+	struct tegra_hsp_mailbox *mailbox;
+	uint32_t value;
 
 	switch (channel->type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
 		return 0;
+
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		mailbox = channel_to_mailbox(channel);
+		mailbox->sending = true;
+
+		value = *(uint32_t *)data;
+		/* Mark mailbox full */
+		value |= HSP_SM_SHRD_MBOX_FULL;
+
+		tegra_hsp_channel_writel(channel, value, HSP_SM_SHRD_MBOX);
+
+		return readl_poll_timeout(
+			channel->regs + HSP_SM_SHRD_MBOX, value,
+			!(value & HSP_SM_SHRD_MBOX_FULL), 0, 10000);
 	}
 
 	return -EINVAL;
@@ -297,6 +392,8 @@ static int tegra_hsp_startup(struct mbox_chan *chan)
 	switch (channel->type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		return tegra_hsp_mailbox_startup(channel_to_mailbox(channel));
 	}
 
 	return -EINVAL;
@@ -310,6 +407,9 @@ static void tegra_hsp_shutdown(struct mbox_chan *chan)
 	case TEGRA_HSP_MBOX_TYPE_DB:
 		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
 		break;
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		tegra_hsp_mailbox_shutdown(channel_to_mailbox(channel));
+		break;
 	}
 }
 
@@ -363,7 +463,16 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 
 	switch (type) {
 	case TEGRA_HSP_MBOX_TYPE_DB:
-		return tegra_hsp_doorbell_xlate(hsp, param);
+		if (hsp->doorbell_irq)
+			return tegra_hsp_doorbell_xlate(hsp, param);
+		else
+			return ERR_PTR(-EINVAL);
+
+	case TEGRA_HSP_MBOX_TYPE_SM:
+		if (hsp->shared_irq && param < hsp->num_sm)
+			return hsp->mailboxes[param].channel.chan;
+		else
+			return ERR_PTR(-EINVAL);
 
 	default:
 		return ERR_PTR(-EINVAL);
@@ -402,6 +511,31 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
 	return 0;
 }
 
+static int tegra_hsp_add_mailboxes(struct tegra_hsp *hsp, struct device *dev)
+{
+	int i;
+
+	hsp->mailboxes = devm_kcalloc(dev, hsp->num_sm, sizeof(*hsp->mailboxes),
+				      GFP_KERNEL);
+	if (!hsp->mailboxes)
+		return -ENOMEM;
+
+	for (i = 0; i < hsp->num_sm; i++) {
+		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
+
+		mb->index = i;
+		mb->sending = false;
+
+		mb->channel.hsp = hsp;
+		mb->channel.type = TEGRA_HSP_MBOX_TYPE_SM;
+		mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K;
+		mb->channel.chan = &hsp->mbox.chans[i];
+		mb->channel.chan->con_priv = &mb->channel;
+	}
+
+	return 0;
+}
+
 static int tegra_hsp_probe(struct platform_device *pdev)
 {
 	struct tegra_hsp *hsp;
@@ -430,14 +564,15 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
 
 	err = platform_get_irq_byname(pdev, "doorbell");
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
-		return err;
-	}
+	if (err >= 0)
+		hsp->doorbell_irq = err;
 
-	hsp->doorbell_irq = err;
+	err = platform_get_irq_byname(pdev, "shared0");
+	if (err >= 0)
+		hsp->shared_irq = err;
 
 	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
+	/* First nSM are reserved for mailboxes */
 	hsp->mbox.num_chans = 32;
 	hsp->mbox.dev = &pdev->dev;
 	hsp->mbox.txdone_irq = false;
@@ -450,10 +585,22 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	if (!hsp->mbox.chans)
 		return -ENOMEM;
 
-	err = tegra_hsp_add_doorbells(hsp);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
-		return err;
+	if (hsp->doorbell_irq) {
+		err = tegra_hsp_add_doorbells(hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to add doorbells: %d\n",
+			        err);
+			return err;
+		}
+	}
+
+	if (hsp->shared_irq) {
+		err = tegra_hsp_add_mailboxes(hsp, &pdev->dev);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
+			        err);
+			goto remove_doorbells;
+		}
 	}
 
 	platform_set_drvdata(pdev, hsp);
@@ -461,20 +608,42 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	err = mbox_controller_register(&hsp->mbox);
 	if (err) {
 		dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
-		tegra_hsp_remove_doorbells(hsp);
-		return err;
+		goto remove_doorbells;
 	}
 
-	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
-			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
-			       dev_name(&pdev->dev), hsp);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
-			hsp->doorbell_irq, err);
-		return err;
+	if (hsp->doorbell_irq) {
+		err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
+				       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
+				       dev_name(&pdev->dev), hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+			        "failed to request doorbell IRQ#%u: %d\n",
+				hsp->doorbell_irq, err);
+			goto unregister_mbox_controller;
+		}
+	}
+
+	if (hsp->shared_irq) {
+		err = devm_request_irq(&pdev->dev, hsp->shared_irq,
+				       tegra_hsp_shared_irq, 0,
+				       dev_name(&pdev->dev), hsp);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"failed to request shared0 IRQ%u: %d\n",
+				hsp->shared_irq, err);
+			goto unregister_mbox_controller;
+		}
 	}
 
 	return 0;
+
+unregister_mbox_controller:
+	mbox_controller_unregister(&hsp->mbox);
+remove_doorbells:
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
+
+	return err;
 }
 
 static int tegra_hsp_remove(struct platform_device *pdev)
@@ -482,7 +651,8 @@ static int tegra_hsp_remove(struct platform_device *pdev)
 	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
 
 	mbox_controller_unregister(&hsp->mbox);
-	tegra_hsp_remove_doorbells(hsp);
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
 
 	return 0;
 }
-- 
2.16.1

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

* [PATCH v2 6/8] serial: Add Tegra Combined UART driver
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The Tegra Combined UART (TCU) is a mailbox-based mechanism that allows
multiplexing multiple "virtual UARTs" into a single hardware serial
port. The TCU is the primary serial port on Tegra194 devices.

Add a TCU driver utilizing the mailbox framework, as the used mailboxes
are part of Tegra HSP blocks that are already controlled by the Tegra
HSP mailbox driver.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Removed (void) casts for unused variables.
    - Changed the uart_set_options() call to be on one line, even if its
      over 80 characters.
    - Added defines for magic numbers.
    - Style fixes.
    - Changed Kconfig entry to depend on the Tegra HSP driver instead of
      just the mailbox framework.

 drivers/tty/serial/Kconfig       |   9 ++
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/tegra-tcu.c   | 289 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/tty/serial/tegra-tcu.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index df8bd0c7b97d..5fdd336e8937 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -322,6 +322,15 @@ config SERIAL_TEGRA
 	  are enabled). This driver uses the APB DMA to achieve higher baudrate
 	  and better performance.
 
+config SERIAL_TEGRA_TCU
+	tristate "NVIDIA Tegra Combined UART"
+	depends on ARCH_TEGRA && TEGRA_HSP_MBOX
+	select SERIAL_CORE
+	help
+	  Support for the mailbox-based TCU (Tegra Combined UART) serial port.
+	  TCU is a virtual serial port that allows multiplexing multiple data
+	  streams into a single hardware serial port.
+
 config SERIAL_MAX3100
 	tristate "MAX3100 support"
 	depends on SPI
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index daac675612df..4ad82231ff8a 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_SERIAL_LANTIQ)	+= lantiq.o
 obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
 obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
 obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
+obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
 obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
 obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
new file mode 100644
index 000000000000..b54ebe2ad917
--- /dev/null
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#include <linux/console.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#define TCU_MBOX_BYTE(i, x)			((x) << (i*8))
+#define TCU_MBOX_BYTE_V(x, i)			(((x) >> (i*8)) & 0xff)
+#define TCU_MBOX_NUM_BYTES(x)			((x) << 24)
+#define TCU_MBOX_NUM_BYTES_V(x)			(((x) >> 24) & 0x3)
+#define TCU_MBOX_FLUSH				BIT(26)
+
+static struct uart_driver tegra_tcu_uart_driver;
+static struct uart_port tegra_tcu_uart_port;
+
+struct tegra_tcu {
+	struct mbox_client tx_client, rx_client;
+	struct mbox_chan *tx, *rx;
+};
+
+static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port)
+{
+	return TIOCSER_TEMT;
+}
+
+static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port)
+{
+	return 0;
+}
+
+static void tegra_tcu_uart_stop_tx(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_write(const char *s, unsigned int count)
+{
+	struct tegra_tcu *tcu = tegra_tcu_uart_port.private_data;
+	unsigned int written = 0, i = 0;
+	bool insert_nl = false;
+	uint32_t value = 0;
+
+	while (i < count) {
+		if (insert_nl) {
+			value |= TCU_MBOX_BYTE(written++, '\n');
+			insert_nl = false;
+			i++;
+		} else if (s[i] == '\n') {
+			value |= TCU_MBOX_BYTE(written++, '\r');
+			insert_nl = true;
+		} else {
+			value |= TCU_MBOX_BYTE(written++, s[i++]);
+		}
+
+		if (written == 3) {
+			value |= TCU_MBOX_NUM_BYTES(3) | TCU_MBOX_FLUSH;
+			mbox_send_message(tcu->tx, &value);
+			value = 0;
+			written = 0;
+		}
+	}
+
+	if (written) {
+		value |= TCU_MBOX_NUM_BYTES(written) | TCU_MBOX_FLUSH;
+		mbox_send_message(tcu->tx, &value);
+	}
+}
+
+static void tegra_tcu_uart_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long count;
+
+	for (;;) {
+		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+		if (!count)
+			break;
+
+		tegra_tcu_write(&xmit->buf[xmit->tail], count);
+		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+	}
+
+	uart_write_wakeup(port);
+}
+
+static void tegra_tcu_uart_stop_rx(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl)
+{
+}
+
+static int tegra_tcu_uart_startup(struct uart_port *port)
+{
+	return 0;
+}
+
+static void tegra_tcu_uart_shutdown(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_uart_set_termios(struct uart_port *port,
+				       struct ktermios *new,
+				       struct ktermios *old)
+{
+}
+
+static const struct uart_ops tegra_tcu_uart_ops = {
+	.tx_empty = tegra_tcu_uart_tx_empty,
+	.set_mctrl = tegra_tcu_uart_set_mctrl,
+	.get_mctrl = tegra_tcu_uart_get_mctrl,
+	.stop_tx = tegra_tcu_uart_stop_tx,
+	.start_tx = tegra_tcu_uart_start_tx,
+	.stop_rx = tegra_tcu_uart_stop_rx,
+	.break_ctl = tegra_tcu_uart_break_ctl,
+	.startup = tegra_tcu_uart_startup,
+	.shutdown = tegra_tcu_uart_shutdown,
+	.set_termios = tegra_tcu_uart_set_termios,
+};
+
+static void tegra_tcu_console_write(struct console *cons, const char *s,
+				    unsigned int count)
+{
+	tegra_tcu_write(s, count);
+}
+
+static int tegra_tcu_console_setup(struct console *cons, char *options)
+{
+	if (!tegra_tcu_uart_port.private_data)
+		return -ENODEV;
+
+	return uart_set_options(&tegra_tcu_uart_port, cons, 115200, 'n', 8, 'n');
+}
+
+static struct console tegra_tcu_console = {
+	.name = "ttyTCU",
+	.device = uart_console_device,
+	.flags = CON_PRINTBUFFER | CON_ANYTIME,
+	.index = -1,
+	.write = tegra_tcu_console_write,
+	.setup = tegra_tcu_console_setup,
+	.data = &tegra_tcu_uart_driver,
+};
+
+static struct uart_driver tegra_tcu_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "tegra-tcu",
+	.dev_name = "ttyTCU",
+	.cons = &tegra_tcu_console,
+	.nr = 1,
+};
+
+static void tegra_tcu_receive(struct mbox_client *client, void *msg_p)
+{
+	struct tty_port *port = &tegra_tcu_uart_port.state->port;
+	uint32_t msg = *(uint32_t *)msg_p;
+	unsigned int num_bytes;
+	int i;
+
+	num_bytes = TCU_MBOX_NUM_BYTES_V(msg);
+	for (i = 0; i < num_bytes; i++)
+		tty_insert_flip_char(port, TCU_MBOX_BYTE_V(msg, i), TTY_NORMAL);
+
+	tty_flip_buffer_push(port);
+}
+
+static int tegra_tcu_probe(struct platform_device *pdev)
+{
+	struct uart_port *port = &tegra_tcu_uart_port;
+	struct tegra_tcu *tcu;
+	int err;
+
+	tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
+	if (!tcu)
+		return -ENOMEM;
+
+	tcu->tx_client.dev = &pdev->dev;
+	tcu->rx_client.dev = &pdev->dev;
+	tcu->rx_client.rx_callback = tegra_tcu_receive;
+
+	tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
+	if (IS_ERR(tcu->tx)) {
+		err = PTR_ERR(tcu->tx);
+		dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
+		return err;
+	}
+
+	tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
+	if (IS_ERR(tcu->rx)) {
+		err = PTR_ERR(tcu->rx);
+		dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
+		goto free_tx;
+	}
+
+	err = uart_register_driver(&tegra_tcu_uart_driver);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register UART driver: %d\n",
+			err);
+		goto free_rx;
+	}
+
+	spin_lock_init(&port->lock);
+	port->dev = &pdev->dev;
+	port->type = PORT_TEGRA_TCU;
+	port->ops = &tegra_tcu_uart_ops;
+	port->fifosize = 1;
+	port->iotype = UPIO_MEM;
+	port->flags = UPF_BOOT_AUTOCONF;
+	port->private_data = tcu;
+
+	err = uart_add_one_port(&tegra_tcu_uart_driver, port);
+	if (err) {
+		dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
+		goto unregister_uart;
+	}
+
+	return 0;
+
+unregister_uart:
+	uart_unregister_driver(&tegra_tcu_uart_driver);
+free_rx:
+	mbox_free_channel(tcu->rx);
+free_tx:
+	mbox_free_channel(tcu->tx);
+
+	return err;
+}
+
+static int tegra_tcu_remove(struct platform_device *pdev)
+{
+	uart_remove_one_port(&tegra_tcu_uart_driver, &tegra_tcu_uart_port);
+	uart_unregister_driver(&tegra_tcu_uart_driver);
+
+	return 0;
+}
+
+static const struct of_device_id tegra_tcu_match[] = {
+	{ .compatible = "nvidia,tegra194-tcu" },
+	{ }
+};
+
+static struct platform_driver tegra_tcu_driver = {
+	.driver = {
+		.name = "tegra-tcu",
+		.of_match_table = tegra_tcu_match,
+	},
+	.probe = tegra_tcu_probe,
+	.remove = tegra_tcu_remove,
+};
+
+static int __init tegra_tcu_init(void)
+{
+	int err;
+
+	err = platform_driver_register(&tegra_tcu_driver);
+	if (err)
+		return err;
+
+	register_console(&tegra_tcu_console);
+
+	return 0;
+}
+module_init(tegra_tcu_init);
+
+static void __exit tegra_tcu_exit(void)
+{
+	unregister_console(&tegra_tcu_console);
+	platform_driver_unregister(&tegra_tcu_driver);
+}
+module_exit(tegra_tcu_exit);
+
+MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index dce5f9dae121..69883c32cb98 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -79,6 +79,9 @@
 /* Nuvoton UART */
 #define PORT_NPCM	40
 
+/* NVIDIA Tegra Combined UART */
+#define PORT_TEGRA_TCU	41
+
 /* Intel EG20 */
 #define PORT_PCH_8LINE	44
 #define PORT_PCH_2LINE	45
-- 
2.16.1

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

* [PATCH v2 6/8] serial: Add Tegra Combined UART driver
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The Tegra Combined UART (TCU) is a mailbox-based mechanism that allows
multiplexing multiple "virtual UARTs" into a single hardware serial
port. The TCU is the primary serial port on Tegra194 devices.

Add a TCU driver utilizing the mailbox framework, as the used mailboxes
are part of Tegra HSP blocks that are already controlled by the Tegra
HSP mailbox driver.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Removed (void) casts for unused variables.
    - Changed the uart_set_options() call to be on one line, even if its
      over 80 characters.
    - Added defines for magic numbers.
    - Style fixes.
    - Changed Kconfig entry to depend on the Tegra HSP driver instead of
      just the mailbox framework.

 drivers/tty/serial/Kconfig       |   9 ++
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/tegra-tcu.c   | 289 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/tty/serial/tegra-tcu.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index df8bd0c7b97d..5fdd336e8937 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -322,6 +322,15 @@ config SERIAL_TEGRA
 	  are enabled). This driver uses the APB DMA to achieve higher baudrate
 	  and better performance.
 
+config SERIAL_TEGRA_TCU
+	tristate "NVIDIA Tegra Combined UART"
+	depends on ARCH_TEGRA && TEGRA_HSP_MBOX
+	select SERIAL_CORE
+	help
+	  Support for the mailbox-based TCU (Tegra Combined UART) serial port.
+	  TCU is a virtual serial port that allows multiplexing multiple data
+	  streams into a single hardware serial port.
+
 config SERIAL_MAX3100
 	tristate "MAX3100 support"
 	depends on SPI
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index daac675612df..4ad82231ff8a 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_SERIAL_LANTIQ)	+= lantiq.o
 obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
 obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
 obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
+obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
 obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
 obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
new file mode 100644
index 000000000000..b54ebe2ad917
--- /dev/null
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#include <linux/console.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#define TCU_MBOX_BYTE(i, x)			((x) << (i*8))
+#define TCU_MBOX_BYTE_V(x, i)			(((x) >> (i*8)) & 0xff)
+#define TCU_MBOX_NUM_BYTES(x)			((x) << 24)
+#define TCU_MBOX_NUM_BYTES_V(x)			(((x) >> 24) & 0x3)
+#define TCU_MBOX_FLUSH				BIT(26)
+
+static struct uart_driver tegra_tcu_uart_driver;
+static struct uart_port tegra_tcu_uart_port;
+
+struct tegra_tcu {
+	struct mbox_client tx_client, rx_client;
+	struct mbox_chan *tx, *rx;
+};
+
+static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port)
+{
+	return TIOCSER_TEMT;
+}
+
+static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port)
+{
+	return 0;
+}
+
+static void tegra_tcu_uart_stop_tx(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_write(const char *s, unsigned int count)
+{
+	struct tegra_tcu *tcu = tegra_tcu_uart_port.private_data;
+	unsigned int written = 0, i = 0;
+	bool insert_nl = false;
+	uint32_t value = 0;
+
+	while (i < count) {
+		if (insert_nl) {
+			value |= TCU_MBOX_BYTE(written++, '\n');
+			insert_nl = false;
+			i++;
+		} else if (s[i] == '\n') {
+			value |= TCU_MBOX_BYTE(written++, '\r');
+			insert_nl = true;
+		} else {
+			value |= TCU_MBOX_BYTE(written++, s[i++]);
+		}
+
+		if (written == 3) {
+			value |= TCU_MBOX_NUM_BYTES(3) | TCU_MBOX_FLUSH;
+			mbox_send_message(tcu->tx, &value);
+			value = 0;
+			written = 0;
+		}
+	}
+
+	if (written) {
+		value |= TCU_MBOX_NUM_BYTES(written) | TCU_MBOX_FLUSH;
+		mbox_send_message(tcu->tx, &value);
+	}
+}
+
+static void tegra_tcu_uart_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long count;
+
+	for (;;) {
+		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+		if (!count)
+			break;
+
+		tegra_tcu_write(&xmit->buf[xmit->tail], count);
+		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+	}
+
+	uart_write_wakeup(port);
+}
+
+static void tegra_tcu_uart_stop_rx(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl)
+{
+}
+
+static int tegra_tcu_uart_startup(struct uart_port *port)
+{
+	return 0;
+}
+
+static void tegra_tcu_uart_shutdown(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_uart_set_termios(struct uart_port *port,
+				       struct ktermios *new,
+				       struct ktermios *old)
+{
+}
+
+static const struct uart_ops tegra_tcu_uart_ops = {
+	.tx_empty = tegra_tcu_uart_tx_empty,
+	.set_mctrl = tegra_tcu_uart_set_mctrl,
+	.get_mctrl = tegra_tcu_uart_get_mctrl,
+	.stop_tx = tegra_tcu_uart_stop_tx,
+	.start_tx = tegra_tcu_uart_start_tx,
+	.stop_rx = tegra_tcu_uart_stop_rx,
+	.break_ctl = tegra_tcu_uart_break_ctl,
+	.startup = tegra_tcu_uart_startup,
+	.shutdown = tegra_tcu_uart_shutdown,
+	.set_termios = tegra_tcu_uart_set_termios,
+};
+
+static void tegra_tcu_console_write(struct console *cons, const char *s,
+				    unsigned int count)
+{
+	tegra_tcu_write(s, count);
+}
+
+static int tegra_tcu_console_setup(struct console *cons, char *options)
+{
+	if (!tegra_tcu_uart_port.private_data)
+		return -ENODEV;
+
+	return uart_set_options(&tegra_tcu_uart_port, cons, 115200, 'n', 8, 'n');
+}
+
+static struct console tegra_tcu_console = {
+	.name = "ttyTCU",
+	.device = uart_console_device,
+	.flags = CON_PRINTBUFFER | CON_ANYTIME,
+	.index = -1,
+	.write = tegra_tcu_console_write,
+	.setup = tegra_tcu_console_setup,
+	.data = &tegra_tcu_uart_driver,
+};
+
+static struct uart_driver tegra_tcu_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "tegra-tcu",
+	.dev_name = "ttyTCU",
+	.cons = &tegra_tcu_console,
+	.nr = 1,
+};
+
+static void tegra_tcu_receive(struct mbox_client *client, void *msg_p)
+{
+	struct tty_port *port = &tegra_tcu_uart_port.state->port;
+	uint32_t msg = *(uint32_t *)msg_p;
+	unsigned int num_bytes;
+	int i;
+
+	num_bytes = TCU_MBOX_NUM_BYTES_V(msg);
+	for (i = 0; i < num_bytes; i++)
+		tty_insert_flip_char(port, TCU_MBOX_BYTE_V(msg, i), TTY_NORMAL);
+
+	tty_flip_buffer_push(port);
+}
+
+static int tegra_tcu_probe(struct platform_device *pdev)
+{
+	struct uart_port *port = &tegra_tcu_uart_port;
+	struct tegra_tcu *tcu;
+	int err;
+
+	tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
+	if (!tcu)
+		return -ENOMEM;
+
+	tcu->tx_client.dev = &pdev->dev;
+	tcu->rx_client.dev = &pdev->dev;
+	tcu->rx_client.rx_callback = tegra_tcu_receive;
+
+	tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
+	if (IS_ERR(tcu->tx)) {
+		err = PTR_ERR(tcu->tx);
+		dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
+		return err;
+	}
+
+	tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
+	if (IS_ERR(tcu->rx)) {
+		err = PTR_ERR(tcu->rx);
+		dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
+		goto free_tx;
+	}
+
+	err = uart_register_driver(&tegra_tcu_uart_driver);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register UART driver: %d\n",
+			err);
+		goto free_rx;
+	}
+
+	spin_lock_init(&port->lock);
+	port->dev = &pdev->dev;
+	port->type = PORT_TEGRA_TCU;
+	port->ops = &tegra_tcu_uart_ops;
+	port->fifosize = 1;
+	port->iotype = UPIO_MEM;
+	port->flags = UPF_BOOT_AUTOCONF;
+	port->private_data = tcu;
+
+	err = uart_add_one_port(&tegra_tcu_uart_driver, port);
+	if (err) {
+		dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
+		goto unregister_uart;
+	}
+
+	return 0;
+
+unregister_uart:
+	uart_unregister_driver(&tegra_tcu_uart_driver);
+free_rx:
+	mbox_free_channel(tcu->rx);
+free_tx:
+	mbox_free_channel(tcu->tx);
+
+	return err;
+}
+
+static int tegra_tcu_remove(struct platform_device *pdev)
+{
+	uart_remove_one_port(&tegra_tcu_uart_driver, &tegra_tcu_uart_port);
+	uart_unregister_driver(&tegra_tcu_uart_driver);
+
+	return 0;
+}
+
+static const struct of_device_id tegra_tcu_match[] = {
+	{ .compatible = "nvidia,tegra194-tcu" },
+	{ }
+};
+
+static struct platform_driver tegra_tcu_driver = {
+	.driver = {
+		.name = "tegra-tcu",
+		.of_match_table = tegra_tcu_match,
+	},
+	.probe = tegra_tcu_probe,
+	.remove = tegra_tcu_remove,
+};
+
+static int __init tegra_tcu_init(void)
+{
+	int err;
+
+	err = platform_driver_register(&tegra_tcu_driver);
+	if (err)
+		return err;
+
+	register_console(&tegra_tcu_console);
+
+	return 0;
+}
+module_init(tegra_tcu_init);
+
+static void __exit tegra_tcu_exit(void)
+{
+	unregister_console(&tegra_tcu_console);
+	platform_driver_unregister(&tegra_tcu_driver);
+}
+module_exit(tegra_tcu_exit);
+
+MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index dce5f9dae121..69883c32cb98 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -79,6 +79,9 @@
 /* Nuvoton UART */
 #define PORT_NPCM	40
 
+/* NVIDIA Tegra Combined UART */
+#define PORT_TEGRA_TCU	41
+
 /* Intel EG20 */
 #define PORT_PCH_8LINE	44
 #define PORT_PCH_2LINE	45
-- 
2.16.1


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

* [PATCH v2 6/8] serial: Add Tegra Combined UART driver
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

The Tegra Combined UART (TCU) is a mailbox-based mechanism that allows
multiplexing multiple "virtual UARTs" into a single hardware serial
port. The TCU is the primary serial port on Tegra194 devices.

Add a TCU driver utilizing the mailbox framework, as the used mailboxes
are part of Tegra HSP blocks that are already controlled by the Tegra
HSP mailbox driver.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---

Notes:
    v2:
    - Removed (void) casts for unused variables.
    - Changed the uart_set_options() call to be on one line, even if its
      over 80 characters.
    - Added defines for magic numbers.
    - Style fixes.
    - Changed Kconfig entry to depend on the Tegra HSP driver instead of
      just the mailbox framework.

 drivers/tty/serial/Kconfig       |   9 ++
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/tegra-tcu.c   | 289 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/tty/serial/tegra-tcu.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index df8bd0c7b97d..5fdd336e8937 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -322,6 +322,15 @@ config SERIAL_TEGRA
 	  are enabled). This driver uses the APB DMA to achieve higher baudrate
 	  and better performance.
 
+config SERIAL_TEGRA_TCU
+	tristate "NVIDIA Tegra Combined UART"
+	depends on ARCH_TEGRA && TEGRA_HSP_MBOX
+	select SERIAL_CORE
+	help
+	  Support for the mailbox-based TCU (Tegra Combined UART) serial port.
+	  TCU is a virtual serial port that allows multiplexing multiple data
+	  streams into a single hardware serial port.
+
 config SERIAL_MAX3100
 	tristate "MAX3100 support"
 	depends on SPI
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index daac675612df..4ad82231ff8a 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_SERIAL_LANTIQ)	+= lantiq.o
 obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
 obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
 obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
+obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
 obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
 obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
new file mode 100644
index 000000000000..b54ebe2ad917
--- /dev/null
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#include <linux/console.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#define TCU_MBOX_BYTE(i, x)			((x) << (i*8))
+#define TCU_MBOX_BYTE_V(x, i)			(((x) >> (i*8)) & 0xff)
+#define TCU_MBOX_NUM_BYTES(x)			((x) << 24)
+#define TCU_MBOX_NUM_BYTES_V(x)			(((x) >> 24) & 0x3)
+#define TCU_MBOX_FLUSH				BIT(26)
+
+static struct uart_driver tegra_tcu_uart_driver;
+static struct uart_port tegra_tcu_uart_port;
+
+struct tegra_tcu {
+	struct mbox_client tx_client, rx_client;
+	struct mbox_chan *tx, *rx;
+};
+
+static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port)
+{
+	return TIOCSER_TEMT;
+}
+
+static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port)
+{
+	return 0;
+}
+
+static void tegra_tcu_uart_stop_tx(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_write(const char *s, unsigned int count)
+{
+	struct tegra_tcu *tcu = tegra_tcu_uart_port.private_data;
+	unsigned int written = 0, i = 0;
+	bool insert_nl = false;
+	uint32_t value = 0;
+
+	while (i < count) {
+		if (insert_nl) {
+			value |= TCU_MBOX_BYTE(written++, '\n');
+			insert_nl = false;
+			i++;
+		} else if (s[i] == '\n') {
+			value |= TCU_MBOX_BYTE(written++, '\r');
+			insert_nl = true;
+		} else {
+			value |= TCU_MBOX_BYTE(written++, s[i++]);
+		}
+
+		if (written == 3) {
+			value |= TCU_MBOX_NUM_BYTES(3) | TCU_MBOX_FLUSH;
+			mbox_send_message(tcu->tx, &value);
+			value = 0;
+			written = 0;
+		}
+	}
+
+	if (written) {
+		value |= TCU_MBOX_NUM_BYTES(written) | TCU_MBOX_FLUSH;
+		mbox_send_message(tcu->tx, &value);
+	}
+}
+
+static void tegra_tcu_uart_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long count;
+
+	for (;;) {
+		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+		if (!count)
+			break;
+
+		tegra_tcu_write(&xmit->buf[xmit->tail], count);
+		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+	}
+
+	uart_write_wakeup(port);
+}
+
+static void tegra_tcu_uart_stop_rx(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl)
+{
+}
+
+static int tegra_tcu_uart_startup(struct uart_port *port)
+{
+	return 0;
+}
+
+static void tegra_tcu_uart_shutdown(struct uart_port *port)
+{
+}
+
+static void tegra_tcu_uart_set_termios(struct uart_port *port,
+				       struct ktermios *new,
+				       struct ktermios *old)
+{
+}
+
+static const struct uart_ops tegra_tcu_uart_ops = {
+	.tx_empty = tegra_tcu_uart_tx_empty,
+	.set_mctrl = tegra_tcu_uart_set_mctrl,
+	.get_mctrl = tegra_tcu_uart_get_mctrl,
+	.stop_tx = tegra_tcu_uart_stop_tx,
+	.start_tx = tegra_tcu_uart_start_tx,
+	.stop_rx = tegra_tcu_uart_stop_rx,
+	.break_ctl = tegra_tcu_uart_break_ctl,
+	.startup = tegra_tcu_uart_startup,
+	.shutdown = tegra_tcu_uart_shutdown,
+	.set_termios = tegra_tcu_uart_set_termios,
+};
+
+static void tegra_tcu_console_write(struct console *cons, const char *s,
+				    unsigned int count)
+{
+	tegra_tcu_write(s, count);
+}
+
+static int tegra_tcu_console_setup(struct console *cons, char *options)
+{
+	if (!tegra_tcu_uart_port.private_data)
+		return -ENODEV;
+
+	return uart_set_options(&tegra_tcu_uart_port, cons, 115200, 'n', 8, 'n');
+}
+
+static struct console tegra_tcu_console = {
+	.name = "ttyTCU",
+	.device = uart_console_device,
+	.flags = CON_PRINTBUFFER | CON_ANYTIME,
+	.index = -1,
+	.write = tegra_tcu_console_write,
+	.setup = tegra_tcu_console_setup,
+	.data = &tegra_tcu_uart_driver,
+};
+
+static struct uart_driver tegra_tcu_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "tegra-tcu",
+	.dev_name = "ttyTCU",
+	.cons = &tegra_tcu_console,
+	.nr = 1,
+};
+
+static void tegra_tcu_receive(struct mbox_client *client, void *msg_p)
+{
+	struct tty_port *port = &tegra_tcu_uart_port.state->port;
+	uint32_t msg = *(uint32_t *)msg_p;
+	unsigned int num_bytes;
+	int i;
+
+	num_bytes = TCU_MBOX_NUM_BYTES_V(msg);
+	for (i = 0; i < num_bytes; i++)
+		tty_insert_flip_char(port, TCU_MBOX_BYTE_V(msg, i), TTY_NORMAL);
+
+	tty_flip_buffer_push(port);
+}
+
+static int tegra_tcu_probe(struct platform_device *pdev)
+{
+	struct uart_port *port = &tegra_tcu_uart_port;
+	struct tegra_tcu *tcu;
+	int err;
+
+	tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
+	if (!tcu)
+		return -ENOMEM;
+
+	tcu->tx_client.dev = &pdev->dev;
+	tcu->rx_client.dev = &pdev->dev;
+	tcu->rx_client.rx_callback = tegra_tcu_receive;
+
+	tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
+	if (IS_ERR(tcu->tx)) {
+		err = PTR_ERR(tcu->tx);
+		dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
+		return err;
+	}
+
+	tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
+	if (IS_ERR(tcu->rx)) {
+		err = PTR_ERR(tcu->rx);
+		dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
+		goto free_tx;
+	}
+
+	err = uart_register_driver(&tegra_tcu_uart_driver);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register UART driver: %d\n",
+			err);
+		goto free_rx;
+	}
+
+	spin_lock_init(&port->lock);
+	port->dev = &pdev->dev;
+	port->type = PORT_TEGRA_TCU;
+	port->ops = &tegra_tcu_uart_ops;
+	port->fifosize = 1;
+	port->iotype = UPIO_MEM;
+	port->flags = UPF_BOOT_AUTOCONF;
+	port->private_data = tcu;
+
+	err = uart_add_one_port(&tegra_tcu_uart_driver, port);
+	if (err) {
+		dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
+		goto unregister_uart;
+	}
+
+	return 0;
+
+unregister_uart:
+	uart_unregister_driver(&tegra_tcu_uart_driver);
+free_rx:
+	mbox_free_channel(tcu->rx);
+free_tx:
+	mbox_free_channel(tcu->tx);
+
+	return err;
+}
+
+static int tegra_tcu_remove(struct platform_device *pdev)
+{
+	uart_remove_one_port(&tegra_tcu_uart_driver, &tegra_tcu_uart_port);
+	uart_unregister_driver(&tegra_tcu_uart_driver);
+
+	return 0;
+}
+
+static const struct of_device_id tegra_tcu_match[] = {
+	{ .compatible = "nvidia,tegra194-tcu" },
+	{ }
+};
+
+static struct platform_driver tegra_tcu_driver = {
+	.driver = {
+		.name = "tegra-tcu",
+		.of_match_table = tegra_tcu_match,
+	},
+	.probe = tegra_tcu_probe,
+	.remove = tegra_tcu_remove,
+};
+
+static int __init tegra_tcu_init(void)
+{
+	int err;
+
+	err = platform_driver_register(&tegra_tcu_driver);
+	if (err)
+		return err;
+
+	register_console(&tegra_tcu_console);
+
+	return 0;
+}
+module_init(tegra_tcu_init);
+
+static void __exit tegra_tcu_exit(void)
+{
+	unregister_console(&tegra_tcu_console);
+	platform_driver_unregister(&tegra_tcu_driver);
+}
+module_exit(tegra_tcu_exit);
+
+MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index dce5f9dae121..69883c32cb98 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -79,6 +79,9 @@
 /* Nuvoton UART */
 #define PORT_NPCM	40
 
+/* NVIDIA Tegra Combined UART */
+#define PORT_TEGRA_TCU	41
+
 /* Intel EG20 */
 #define PORT_PCH_8LINE	44
 #define PORT_PCH_2LINE	45
-- 
2.16.1

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

* [PATCH v2 7/8] arm64: tegra: Add nodes for tcu on Tegra194
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

Add nodes required for communication through the Tegra Combined UART.
This includes the AON HSP instance, addition of shared interrupts
for the TOP0 HSP instance, and finally the TCU node itself. Also
mark the HSP instances as compatible to tegra194-hsp, as the hardware
is not identical but is compatible to tegra186-hsp.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 34 +++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 6d699815a84f..d7f780b06fe2 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -217,10 +217,31 @@
 		};
 
 		hsp_top0: hsp@3c00000 {
-			compatible = "nvidia,tegra186-hsp";
+			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
 			reg = <0x03c00000 0xa0000>;
-			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "doorbell";
+			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "doorbell", "shared0", "shared1", "shared2",
+			                  "shared3", "shared4", "shared5", "shared6",
+			                  "shared7";
+			#mbox-cells = <2>;
+		};
+
+		hsp_aon: hsp@c150000 {
+			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
+			reg = <0x0c150000 0xa0000>;
+			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "shared0", "shared1", "shared2", "shared3";
 			#mbox-cells = <2>;
 		};
 
@@ -382,6 +403,13 @@
 		};
 	};
 
+	tcu: tcu {
+		compatible = "nvidia,tegra194-tcu";
+		mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
+		         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
+		mbox-names = "rx", "tx";
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 13
-- 
2.16.1

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

* [PATCH v2 7/8] arm64: tegra: Add nodes for tcu on Tegra194
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

Add nodes required for communication through the Tegra Combined UART.
This includes the AON HSP instance, addition of shared interrupts
for the TOP0 HSP instance, and finally the TCU node itself. Also
mark the HSP instances as compatible to tegra194-hsp, as the hardware
is not identical but is compatible to tegra186-hsp.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 34 +++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 6d699815a84f..d7f780b06fe2 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -217,10 +217,31 @@
 		};
 
 		hsp_top0: hsp@3c00000 {
-			compatible = "nvidia,tegra186-hsp";
+			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
 			reg = <0x03c00000 0xa0000>;
-			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "doorbell";
+			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "doorbell", "shared0", "shared1", "shared2",
+			                  "shared3", "shared4", "shared5", "shared6",
+			                  "shared7";
+			#mbox-cells = <2>;
+		};
+
+		hsp_aon: hsp@c150000 {
+			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
+			reg = <0x0c150000 0xa0000>;
+			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "shared0", "shared1", "shared2", "shared3";
 			#mbox-cells = <2>;
 		};
 
@@ -382,6 +403,13 @@
 		};
 	};
 
+	tcu: tcu {
+		compatible = "nvidia,tegra194-tcu";
+		mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
+		         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
+		mbox-names = "rx", "tx";
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 13
-- 
2.16.1


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

* [PATCH v2 7/8] arm64: tegra: Add nodes for tcu on Tegra194
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

Add nodes required for communication through the Tegra Combined UART.
This includes the AON HSP instance, addition of shared interrupts
for the TOP0 HSP instance, and finally the TCU node itself. Also
mark the HSP instances as compatible to tegra194-hsp, as the hardware
is not identical but is compatible to tegra186-hsp.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 34 +++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 6d699815a84f..d7f780b06fe2 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -217,10 +217,31 @@
 		};
 
 		hsp_top0: hsp at 3c00000 {
-			compatible = "nvidia,tegra186-hsp";
+			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
 			reg = <0x03c00000 0xa0000>;
-			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "doorbell";
+			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "doorbell", "shared0", "shared1", "shared2",
+			                  "shared3", "shared4", "shared5", "shared6",
+			                  "shared7";
+			#mbox-cells = <2>;
+		};
+
+		hsp_aon: hsp at c150000 {
+			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
+			reg = <0x0c150000 0xa0000>;
+			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+			             <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "shared0", "shared1", "shared2", "shared3";
 			#mbox-cells = <2>;
 		};
 
@@ -382,6 +403,13 @@
 		};
 	};
 
+	tcu: tcu {
+		compatible = "nvidia,tegra194-tcu";
+		mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
+		         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
+		mbox-names = "rx", "tx";
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 13
-- 
2.16.1

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

* [PATCH v2 8/8] arm64: tegra: Mark tcu as primary serial port on Tegra194 P2888
  2018-06-20 12:20 ` Mikko Perttunen
  (?)
@ 2018-06-20 12:20   ` Mikko Perttunen
  -1 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The Tegra Combined UART is the proper primary serial port on P2888,
so use it.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
---

Notes:
    v2:
    - Added Jon's Acked-by.

 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
index 859ab5af17c1..95e2433984f7 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
@@ -10,7 +10,7 @@
 	aliases {
 		sdhci0 = "/cbb/sdhci@3460000";
 		sdhci1 = "/cbb/sdhci@3400000";
-		serial0 = &uartb;
+		serial0 = &tcu;
 		i2c0 = "/bpmp/i2c";
 		i2c1 = "/cbb/i2c@3160000";
 		i2c2 = "/cbb/i2c@c240000";
-- 
2.16.1

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

* [PATCH v2 8/8] arm64: tegra: Mark tcu as primary serial port on Tegra194 P2888
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel, Mikko Perttunen

The Tegra Combined UART is the proper primary serial port on P2888,
so use it.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
---

Notes:
    v2:
    - Added Jon's Acked-by.

 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
index 859ab5af17c1..95e2433984f7 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
@@ -10,7 +10,7 @@
 	aliases {
 		sdhci0 = "/cbb/sdhci@3460000";
 		sdhci1 = "/cbb/sdhci@3400000";
-		serial0 = &uartb;
+		serial0 = &tcu;
 		i2c0 = "/bpmp/i2c";
 		i2c1 = "/cbb/i2c@3160000";
 		i2c2 = "/cbb/i2c@c240000";
-- 
2.16.1


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

* [PATCH v2 8/8] arm64: tegra: Mark tcu as primary serial port on Tegra194 P2888
@ 2018-06-20 12:20   ` Mikko Perttunen
  0 siblings, 0 replies; 47+ messages in thread
From: Mikko Perttunen @ 2018-06-20 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

The Tegra Combined UART is the proper primary serial port on P2888,
so use it.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
---

Notes:
    v2:
    - Added Jon's Acked-by.

 arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
index 859ab5af17c1..95e2433984f7 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
@@ -10,7 +10,7 @@
 	aliases {
 		sdhci0 = "/cbb/sdhci at 3460000";
 		sdhci1 = "/cbb/sdhci at 3400000";
-		serial0 = &uartb;
+		serial0 = &tcu;
 		i2c0 = "/bpmp/i2c";
 		i2c1 = "/cbb/i2c at 3160000";
 		i2c2 = "/cbb/i2c at c240000";
-- 
2.16.1

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

* Re: [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
  2018-06-20 12:20   ` Mikko Perttunen
  (?)
@ 2018-06-21  8:05     ` Jon Hunter
  -1 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:05 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: linux-tegra, devicetree, linux-arm-kernel, linux-serial, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> HSP interrupts can be routed through exposed "shared interrupts". These
> interrupts can be mapped to various internal interrupt lines. Add
> interrupt properties for shared interrupts to the tegra186-hsp device
> tree bindings. At the same time, add the compatibility string for
> tegra194-hsp, which is backwards compatible with tegra186.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Edited commit message to not say that doorbell interrupts cannot be
>       routed to shared interrupts.
>     - Added tegra194 compatibility string.
> 
>  Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> index b99d25fc2f26..620c249363ca 100644
> --- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> +++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> @@ -15,12 +15,15 @@ Required properties:
>      Array of strings.
>      one of:
>      - "nvidia,tegra186-hsp"
> +    - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"
>  - reg : Offset and length of the register set for the device.
>  - interrupt-names
>      Array of strings.
>      Contains a list of names for the interrupts described by the interrupt
>      property. May contain the following entries, in any order:
>      - "doorbell"
> +    - "sharedN", where 'N' is a number from zero up to the number of
> +      external interrupts supported by the HSP instance minus one.
>      Users of this binding MUST look up entries in the interrupt property
>      by name, using this interrupt-names property to do so.
>  - interrupts

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
@ 2018-06-21  8:05     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:05 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> HSP interrupts can be routed through exposed "shared interrupts". These
> interrupts can be mapped to various internal interrupt lines. Add
> interrupt properties for shared interrupts to the tegra186-hsp device
> tree bindings. At the same time, add the compatibility string for
> tegra194-hsp, which is backwards compatible with tegra186.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Edited commit message to not say that doorbell interrupts cannot be
>       routed to shared interrupts.
>     - Added tegra194 compatibility string.
> 
>  Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> index b99d25fc2f26..620c249363ca 100644
> --- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> +++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> @@ -15,12 +15,15 @@ Required properties:
>      Array of strings.
>      one of:
>      - "nvidia,tegra186-hsp"
> +    - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"
>  - reg : Offset and length of the register set for the device.
>  - interrupt-names
>      Array of strings.
>      Contains a list of names for the interrupts described by the interrupt
>      property. May contain the following entries, in any order:
>      - "doorbell"
> +    - "sharedN", where 'N' is a number from zero up to the number of
> +      external interrupts supported by the HSP instance minus one.
>      Users of this binding MUST look up entries in the interrupt property
>      by name, using this interrupt-names property to do so.
>  - interrupts

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
@ 2018-06-21  8:05     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:05 UTC (permalink / raw)
  To: linux-arm-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> HSP interrupts can be routed through exposed "shared interrupts". These
> interrupts can be mapped to various internal interrupt lines. Add
> interrupt properties for shared interrupts to the tegra186-hsp device
> tree bindings. At the same time, add the compatibility string for
> tegra194-hsp, which is backwards compatible with tegra186.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Edited commit message to not say that doorbell interrupts cannot be
>       routed to shared interrupts.
>     - Added tegra194 compatibility string.
> 
>  Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> index b99d25fc2f26..620c249363ca 100644
> --- a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> +++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
> @@ -15,12 +15,15 @@ Required properties:
>      Array of strings.
>      one of:
>      - "nvidia,tegra186-hsp"
> +    - "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"
>  - reg : Offset and length of the register set for the device.
>  - interrupt-names
>      Array of strings.
>      Contains a list of names for the interrupts described by the interrupt
>      property. May contain the following entries, in any order:
>      - "doorbell"
> +    - "sharedN", where 'N' is a number from zero up to the number of
> +      external interrupts supported by the HSP instance minus one.
>      Users of this binding MUST look up entries in the interrupt property
>      by name, using this interrupt-names property to do so.
>  - interrupts

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
  2018-06-20 12:20   ` [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu Mikko Perttunen
  (?)
@ 2018-06-21  8:05     ` Jon Hunter
  -1 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:05 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> Add bindings for the Tegra Combined UART device used to talk to the
> UART console on Tegra194 systems.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> 
> Notes:
>     v2:
>     - Added Rob's Reviewed-by.
> 
>  .../bindings/serial/nvidia,tegra194-tcu.txt        | 35 ++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> 
> diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> new file mode 100644
> index 000000000000..a8becf6efd2a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> @@ -0,0 +1,35 @@
> +NVIDIA Tegra Combined UART (TCU)
> +
> +The TCU is a system for sharing a hardware UART instance among multiple
> +systems within the Tegra SoC. It is implemented through a mailbox-
> +based protocol where each "virtual UART" has a pair of mailboxes, one
> +for transmitting and one for receiving, that is used to communicate
> +with the hardware implementing the TCU.
> +
> +Required properties:
> +- name : Should be tcu
> +- compatible
> +    Array of strings
> +    One of:
> +    - "nvidia,tegra194-tcu"
> +- mbox-names:
> +    "rx" - Mailbox for receiving data from hardware UART
> +    "tx" - Mailbox for transmitting data to hardware UART
> +- mboxes: Mailboxes corresponding to the mbox-names. 
> +
> +This node is a mailbox consumer. See the following files for details of
> +the mailbox subsystem, and the specifiers implemented by the relevant
> +provider(s):
> +
> +- .../mailbox/mailbox.txt
> +- .../mailbox/nvidia,tegra186-hsp.txt
> +
> +Example bindings:
> +-----------------
> +
> +tcu: tcu {
> +	compatible = "nvidia,tegra194-tcu";
> +	mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
> +	         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
> +	mbox-names = "rx", "tx";
> +};

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
@ 2018-06-21  8:05     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:05 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> Add bindings for the Tegra Combined UART device used to talk to the
> UART console on Tegra194 systems.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> 
> Notes:
>     v2:
>     - Added Rob's Reviewed-by.
> 
>  .../bindings/serial/nvidia,tegra194-tcu.txt        | 35 ++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> 
> diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> new file mode 100644
> index 000000000000..a8becf6efd2a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> @@ -0,0 +1,35 @@
> +NVIDIA Tegra Combined UART (TCU)
> +
> +The TCU is a system for sharing a hardware UART instance among multiple
> +systems within the Tegra SoC. It is implemented through a mailbox-
> +based protocol where each "virtual UART" has a pair of mailboxes, one
> +for transmitting and one for receiving, that is used to communicate
> +with the hardware implementing the TCU.
> +
> +Required properties:
> +- name : Should be tcu
> +- compatible
> +    Array of strings
> +    One of:
> +    - "nvidia,tegra194-tcu"
> +- mbox-names:
> +    "rx" - Mailbox for receiving data from hardware UART
> +    "tx" - Mailbox for transmitting data to hardware UART
> +- mboxes: Mailboxes corresponding to the mbox-names. 
> +
> +This node is a mailbox consumer. See the following files for details of
> +the mailbox subsystem, and the specifiers implemented by the relevant
> +provider(s):
> +
> +- .../mailbox/mailbox.txt
> +- .../mailbox/nvidia,tegra186-hsp.txt
> +
> +Example bindings:
> +-----------------
> +
> +tcu: tcu {
> +	compatible = "nvidia,tegra194-tcu";
> +	mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
> +	         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
> +	mbox-names = "rx", "tx";
> +};

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
@ 2018-06-21  8:05     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:05 UTC (permalink / raw)
  To: linux-arm-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> Add bindings for the Tegra Combined UART device used to talk to the
> UART console on Tegra194 systems.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> 
> Notes:
>     v2:
>     - Added Rob's Reviewed-by.
> 
>  .../bindings/serial/nvidia,tegra194-tcu.txt        | 35 ++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> 
> diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> new file mode 100644
> index 000000000000..a8becf6efd2a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
> @@ -0,0 +1,35 @@
> +NVIDIA Tegra Combined UART (TCU)
> +
> +The TCU is a system for sharing a hardware UART instance among multiple
> +systems within the Tegra SoC. It is implemented through a mailbox-
> +based protocol where each "virtual UART" has a pair of mailboxes, one
> +for transmitting and one for receiving, that is used to communicate
> +with the hardware implementing the TCU.
> +
> +Required properties:
> +- name : Should be tcu
> +- compatible
> +    Array of strings
> +    One of:
> +    - "nvidia,tegra194-tcu"
> +- mbox-names:
> +    "rx" - Mailbox for receiving data from hardware UART
> +    "tx" - Mailbox for transmitting data to hardware UART
> +- mboxes: Mailboxes corresponding to the mbox-names. 
> +
> +This node is a mailbox consumer. See the following files for details of
> +the mailbox subsystem, and the specifiers implemented by the relevant
> +provider(s):
> +
> +- .../mailbox/mailbox.txt
> +- .../mailbox/nvidia,tegra186-hsp.txt
> +
> +Example bindings:
> +-----------------
> +
> +tcu: tcu {
> +	compatible = "nvidia,tegra194-tcu";
> +	mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
> +	         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
> +	mbox-names = "rx", "tx";
> +};

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes
  2018-06-20 12:20   ` Mikko Perttunen
  (?)
@ 2018-06-21  8:13     ` Jon Hunter
  -1 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:13 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The HSP driver is currently in many places written with the assumption
> of only supporting doorbells. Prepare for the addition of shared
> mailbox support by removing these assumptions and cleaning up the code.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Moved fixes for some style and other issues from the next patch
>       here, where they belong.
> 
>  drivers/mailbox/tegra-hsp.c | 123 +++++++++++++++++++++++++++++---------------
>  1 file changed, 81 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 0cde356c11ab..5dc21a6d01bb 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
> @@ -42,6 +42,7 @@ struct tegra_hsp_channel;
>  struct tegra_hsp;
>  
>  struct tegra_hsp_channel {
> +	unsigned int type;
>  	struct tegra_hsp *hsp;
>  	struct mbox_chan *chan;
>  	void __iomem *regs;
> @@ -55,6 +56,12 @@ struct tegra_hsp_doorbell {
>  	unsigned int index;
>  };
>  
> +static inline struct tegra_hsp_doorbell *
> +channel_to_doorbell(struct tegra_hsp_channel *channel)
> +{
> +	return container_of(channel, struct tegra_hsp_doorbell, channel);
> +}
> +
>  struct tegra_hsp_db_map {
>  	const char *name;
>  	unsigned int master;
> @@ -69,7 +76,7 @@ struct tegra_hsp {
>  	const struct tegra_hsp_soc *soc;
>  	struct mbox_controller mbox;
>  	void __iomem *regs;
> -	unsigned int irq;
> +	unsigned int doorbell_irq;
>  	unsigned int num_sm;
>  	unsigned int num_as;
>  	unsigned int num_ss;
> @@ -194,7 +201,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
>  	if (!db)
>  		return ERR_PTR(-ENOMEM);
>  
> -	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
> +	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K;
>  	offset += index * 0x100;
>  
>  	db->channel.regs = hsp->regs + offset;
> @@ -218,18 +225,8 @@ static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
>  	kfree(db);
>  }
>  
> -static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
> -{
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
> -
> -	tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
> -
> -	return 0;
> -}
> -
> -static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
> +static int tegra_hsp_doorbell_startup(struct tegra_hsp_doorbell *db)
>  {
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
>  	struct tegra_hsp *hsp = db->channel.hsp;
>  	struct tegra_hsp_doorbell *ccplex;
>  	unsigned long flags;
> @@ -260,9 +257,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
>  	return 0;
>  }
>  
> -static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
> +static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
>  {
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
>  	struct tegra_hsp *hsp = db->channel.hsp;
>  	struct tegra_hsp_doorbell *ccplex;
>  	unsigned long flags;
> @@ -281,35 +277,60 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
>  	spin_unlock_irqrestore(&hsp->lock, flags);
>  }
>  
> -static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
> -	.send_data = tegra_hsp_doorbell_send_data,
> -	.startup = tegra_hsp_doorbell_startup,
> -	.shutdown = tegra_hsp_doorbell_shutdown,
> +static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int tegra_hsp_startup(struct mbox_chan *chan)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static void tegra_hsp_shutdown(struct mbox_chan *chan)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
> +		break;
> +	}
> +}
> +
> +static const struct mbox_chan_ops tegra_hsp_ops = {
> +	.send_data = tegra_hsp_send_data,
> +	.startup = tegra_hsp_startup,
> +	.shutdown = tegra_hsp_shutdown,
>  };
>  
> -static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> -					    const struct of_phandle_args *args)
> +static struct mbox_chan *tegra_hsp_doorbell_xlate(struct tegra_hsp *hsp,
> +						  unsigned int master)
>  {
>  	struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
> -	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> -	unsigned int type = args->args[0];
> -	unsigned int master = args->args[1];
>  	struct tegra_hsp_doorbell *db;
>  	struct mbox_chan *chan;
>  	unsigned long flags;
>  	unsigned int i;
>  
> -	switch (type) {
> -	case TEGRA_HSP_MBOX_TYPE_DB:
> -		db = tegra_hsp_doorbell_get(hsp, master);
> -		if (db)
> -			channel = &db->channel;
> -
> -		break;
> -
> -	default:
> -		break;
> -	}
> +	db = tegra_hsp_doorbell_get(hsp, master);
> +	if (db)
> +		channel = &db->channel;
>  
>  	if (IS_ERR(channel))
>  		return ERR_CAST(channel);
> @@ -321,6 +342,7 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  		if (!chan->con_priv) {
>  			chan->con_priv = channel;
>  			channel->chan = chan;
> +			channel->type = TEGRA_HSP_MBOX_TYPE_DB;
>  			break;
>  		}
>  
> @@ -332,6 +354,22 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  	return chan ?: ERR_PTR(-EBUSY);
>  }
>  
> +static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> +					    const struct of_phandle_args *args)
> +{
> +	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> +	unsigned int type = args->args[0];
> +	unsigned int param = args->args[1];
> +
> +	switch (type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		return tegra_hsp_doorbell_xlate(hsp, param);
> +
> +	default:
> +		return ERR_PTR(-EINVAL);
> +	}
> +}
> +
>  static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
>  {
>  	struct tegra_hsp_doorbell *db, *tmp;
> @@ -397,14 +435,14 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	hsp->irq = err;
> +	hsp->doorbell_irq = err;
>  
>  	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
>  	hsp->mbox.num_chans = 32;
>  	hsp->mbox.dev = &pdev->dev;
>  	hsp->mbox.txdone_irq = false;
>  	hsp->mbox.txdone_poll = false;
> -	hsp->mbox.ops = &tegra_hsp_doorbell_ops;
> +	hsp->mbox.ops = &tegra_hsp_ops;
>  
>  	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
>  					sizeof(*hsp->mbox.chans),
> @@ -427,11 +465,12 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
> -			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
> +	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> +			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> +			       dev_name(&pdev->dev), hsp);
>  	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
> -			hsp->irq, err);
> +		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
> +			hsp->doorbell_irq, err);
>  		return err;
>  	}

Reviewed-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes
@ 2018-06-21  8:13     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:13 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The HSP driver is currently in many places written with the assumption
> of only supporting doorbells. Prepare for the addition of shared
> mailbox support by removing these assumptions and cleaning up the code.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Moved fixes for some style and other issues from the next patch
>       here, where they belong.
> 
>  drivers/mailbox/tegra-hsp.c | 123 +++++++++++++++++++++++++++++---------------
>  1 file changed, 81 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 0cde356c11ab..5dc21a6d01bb 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
> @@ -42,6 +42,7 @@ struct tegra_hsp_channel;
>  struct tegra_hsp;
>  
>  struct tegra_hsp_channel {
> +	unsigned int type;
>  	struct tegra_hsp *hsp;
>  	struct mbox_chan *chan;
>  	void __iomem *regs;
> @@ -55,6 +56,12 @@ struct tegra_hsp_doorbell {
>  	unsigned int index;
>  };
>  
> +static inline struct tegra_hsp_doorbell *
> +channel_to_doorbell(struct tegra_hsp_channel *channel)
> +{
> +	return container_of(channel, struct tegra_hsp_doorbell, channel);
> +}
> +
>  struct tegra_hsp_db_map {
>  	const char *name;
>  	unsigned int master;
> @@ -69,7 +76,7 @@ struct tegra_hsp {
>  	const struct tegra_hsp_soc *soc;
>  	struct mbox_controller mbox;
>  	void __iomem *regs;
> -	unsigned int irq;
> +	unsigned int doorbell_irq;
>  	unsigned int num_sm;
>  	unsigned int num_as;
>  	unsigned int num_ss;
> @@ -194,7 +201,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
>  	if (!db)
>  		return ERR_PTR(-ENOMEM);
>  
> -	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
> +	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K;
>  	offset += index * 0x100;
>  
>  	db->channel.regs = hsp->regs + offset;
> @@ -218,18 +225,8 @@ static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
>  	kfree(db);
>  }
>  
> -static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
> -{
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
> -
> -	tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
> -
> -	return 0;
> -}
> -
> -static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
> +static int tegra_hsp_doorbell_startup(struct tegra_hsp_doorbell *db)
>  {
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
>  	struct tegra_hsp *hsp = db->channel.hsp;
>  	struct tegra_hsp_doorbell *ccplex;
>  	unsigned long flags;
> @@ -260,9 +257,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
>  	return 0;
>  }
>  
> -static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
> +static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
>  {
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
>  	struct tegra_hsp *hsp = db->channel.hsp;
>  	struct tegra_hsp_doorbell *ccplex;
>  	unsigned long flags;
> @@ -281,35 +277,60 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
>  	spin_unlock_irqrestore(&hsp->lock, flags);
>  }
>  
> -static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
> -	.send_data = tegra_hsp_doorbell_send_data,
> -	.startup = tegra_hsp_doorbell_startup,
> -	.shutdown = tegra_hsp_doorbell_shutdown,
> +static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int tegra_hsp_startup(struct mbox_chan *chan)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static void tegra_hsp_shutdown(struct mbox_chan *chan)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
> +		break;
> +	}
> +}
> +
> +static const struct mbox_chan_ops tegra_hsp_ops = {
> +	.send_data = tegra_hsp_send_data,
> +	.startup = tegra_hsp_startup,
> +	.shutdown = tegra_hsp_shutdown,
>  };
>  
> -static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> -					    const struct of_phandle_args *args)
> +static struct mbox_chan *tegra_hsp_doorbell_xlate(struct tegra_hsp *hsp,
> +						  unsigned int master)
>  {
>  	struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
> -	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> -	unsigned int type = args->args[0];
> -	unsigned int master = args->args[1];
>  	struct tegra_hsp_doorbell *db;
>  	struct mbox_chan *chan;
>  	unsigned long flags;
>  	unsigned int i;
>  
> -	switch (type) {
> -	case TEGRA_HSP_MBOX_TYPE_DB:
> -		db = tegra_hsp_doorbell_get(hsp, master);
> -		if (db)
> -			channel = &db->channel;
> -
> -		break;
> -
> -	default:
> -		break;
> -	}
> +	db = tegra_hsp_doorbell_get(hsp, master);
> +	if (db)
> +		channel = &db->channel;
>  
>  	if (IS_ERR(channel))
>  		return ERR_CAST(channel);
> @@ -321,6 +342,7 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  		if (!chan->con_priv) {
>  			chan->con_priv = channel;
>  			channel->chan = chan;
> +			channel->type = TEGRA_HSP_MBOX_TYPE_DB;
>  			break;
>  		}
>  
> @@ -332,6 +354,22 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  	return chan ?: ERR_PTR(-EBUSY);
>  }
>  
> +static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> +					    const struct of_phandle_args *args)
> +{
> +	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> +	unsigned int type = args->args[0];
> +	unsigned int param = args->args[1];
> +
> +	switch (type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		return tegra_hsp_doorbell_xlate(hsp, param);
> +
> +	default:
> +		return ERR_PTR(-EINVAL);
> +	}
> +}
> +
>  static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
>  {
>  	struct tegra_hsp_doorbell *db, *tmp;
> @@ -397,14 +435,14 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	hsp->irq = err;
> +	hsp->doorbell_irq = err;
>  
>  	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
>  	hsp->mbox.num_chans = 32;
>  	hsp->mbox.dev = &pdev->dev;
>  	hsp->mbox.txdone_irq = false;
>  	hsp->mbox.txdone_poll = false;
> -	hsp->mbox.ops = &tegra_hsp_doorbell_ops;
> +	hsp->mbox.ops = &tegra_hsp_ops;
>  
>  	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
>  					sizeof(*hsp->mbox.chans),
> @@ -427,11 +465,12 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
> -			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
> +	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> +			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> +			       dev_name(&pdev->dev), hsp);
>  	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
> -			hsp->irq, err);
> +		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
> +			hsp->doorbell_irq, err);
>  		return err;
>  	}

Reviewed-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes
@ 2018-06-21  8:13     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:13 UTC (permalink / raw)
  To: linux-arm-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The HSP driver is currently in many places written with the assumption
> of only supporting doorbells. Prepare for the addition of shared
> mailbox support by removing these assumptions and cleaning up the code.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Moved fixes for some style and other issues from the next patch
>       here, where they belong.
> 
>  drivers/mailbox/tegra-hsp.c | 123 +++++++++++++++++++++++++++++---------------
>  1 file changed, 81 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 0cde356c11ab..5dc21a6d01bb 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
> @@ -42,6 +42,7 @@ struct tegra_hsp_channel;
>  struct tegra_hsp;
>  
>  struct tegra_hsp_channel {
> +	unsigned int type;
>  	struct tegra_hsp *hsp;
>  	struct mbox_chan *chan;
>  	void __iomem *regs;
> @@ -55,6 +56,12 @@ struct tegra_hsp_doorbell {
>  	unsigned int index;
>  };
>  
> +static inline struct tegra_hsp_doorbell *
> +channel_to_doorbell(struct tegra_hsp_channel *channel)
> +{
> +	return container_of(channel, struct tegra_hsp_doorbell, channel);
> +}
> +
>  struct tegra_hsp_db_map {
>  	const char *name;
>  	unsigned int master;
> @@ -69,7 +76,7 @@ struct tegra_hsp {
>  	const struct tegra_hsp_soc *soc;
>  	struct mbox_controller mbox;
>  	void __iomem *regs;
> -	unsigned int irq;
> +	unsigned int doorbell_irq;
>  	unsigned int num_sm;
>  	unsigned int num_as;
>  	unsigned int num_ss;
> @@ -194,7 +201,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
>  	if (!db)
>  		return ERR_PTR(-ENOMEM);
>  
> -	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
> +	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) * SZ_64K;
>  	offset += index * 0x100;
>  
>  	db->channel.regs = hsp->regs + offset;
> @@ -218,18 +225,8 @@ static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
>  	kfree(db);
>  }
>  
> -static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
> -{
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
> -
> -	tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
> -
> -	return 0;
> -}
> -
> -static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
> +static int tegra_hsp_doorbell_startup(struct tegra_hsp_doorbell *db)
>  {
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
>  	struct tegra_hsp *hsp = db->channel.hsp;
>  	struct tegra_hsp_doorbell *ccplex;
>  	unsigned long flags;
> @@ -260,9 +257,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
>  	return 0;
>  }
>  
> -static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
> +static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
>  {
> -	struct tegra_hsp_doorbell *db = chan->con_priv;
>  	struct tegra_hsp *hsp = db->channel.hsp;
>  	struct tegra_hsp_doorbell *ccplex;
>  	unsigned long flags;
> @@ -281,35 +277,60 @@ static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
>  	spin_unlock_irqrestore(&hsp->lock, flags);
>  }
>  
> -static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
> -	.send_data = tegra_hsp_doorbell_send_data,
> -	.startup = tegra_hsp_doorbell_startup,
> -	.shutdown = tegra_hsp_doorbell_shutdown,
> +static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int tegra_hsp_startup(struct mbox_chan *chan)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static void tegra_hsp_shutdown(struct mbox_chan *chan)
> +{
> +	struct tegra_hsp_channel *channel = chan->con_priv;
> +
> +	switch (channel->type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
> +		break;
> +	}
> +}
> +
> +static const struct mbox_chan_ops tegra_hsp_ops = {
> +	.send_data = tegra_hsp_send_data,
> +	.startup = tegra_hsp_startup,
> +	.shutdown = tegra_hsp_shutdown,
>  };
>  
> -static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> -					    const struct of_phandle_args *args)
> +static struct mbox_chan *tegra_hsp_doorbell_xlate(struct tegra_hsp *hsp,
> +						  unsigned int master)
>  {
>  	struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
> -	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> -	unsigned int type = args->args[0];
> -	unsigned int master = args->args[1];
>  	struct tegra_hsp_doorbell *db;
>  	struct mbox_chan *chan;
>  	unsigned long flags;
>  	unsigned int i;
>  
> -	switch (type) {
> -	case TEGRA_HSP_MBOX_TYPE_DB:
> -		db = tegra_hsp_doorbell_get(hsp, master);
> -		if (db)
> -			channel = &db->channel;
> -
> -		break;
> -
> -	default:
> -		break;
> -	}
> +	db = tegra_hsp_doorbell_get(hsp, master);
> +	if (db)
> +		channel = &db->channel;
>  
>  	if (IS_ERR(channel))
>  		return ERR_CAST(channel);
> @@ -321,6 +342,7 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  		if (!chan->con_priv) {
>  			chan->con_priv = channel;
>  			channel->chan = chan;
> +			channel->type = TEGRA_HSP_MBOX_TYPE_DB;
>  			break;
>  		}
>  
> @@ -332,6 +354,22 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  	return chan ?: ERR_PTR(-EBUSY);
>  }
>  
> +static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
> +					    const struct of_phandle_args *args)
> +{
> +	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
> +	unsigned int type = args->args[0];
> +	unsigned int param = args->args[1];
> +
> +	switch (type) {
> +	case TEGRA_HSP_MBOX_TYPE_DB:
> +		return tegra_hsp_doorbell_xlate(hsp, param);
> +
> +	default:
> +		return ERR_PTR(-EINVAL);
> +	}
> +}
> +
>  static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
>  {
>  	struct tegra_hsp_doorbell *db, *tmp;
> @@ -397,14 +435,14 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	hsp->irq = err;
> +	hsp->doorbell_irq = err;
>  
>  	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
>  	hsp->mbox.num_chans = 32;
>  	hsp->mbox.dev = &pdev->dev;
>  	hsp->mbox.txdone_irq = false;
>  	hsp->mbox.txdone_poll = false;
> -	hsp->mbox.ops = &tegra_hsp_doorbell_ops;
> +	hsp->mbox.ops = &tegra_hsp_ops;
>  
>  	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
>  					sizeof(*hsp->mbox.chans),
> @@ -427,11 +465,12 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
> -			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
> +	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> +			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> +			       dev_name(&pdev->dev), hsp);
>  	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
> -			hsp->irq, err);
> +		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
> +			hsp->doorbell_irq, err);
>  		return err;
>  	}

Reviewed-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 5/8] mailbox: tegra-hsp: Add support for shared mailboxes
  2018-06-20 12:20   ` Mikko Perttunen
  (?)
@ 2018-06-21  8:29     ` Jon Hunter
  -1 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:29 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
> registers consisting of a FULL bit in MSB position and 31 bits of data.
> The hardware can be configured to trigger interrupts when a mailbox
> is empty or full. Add support for these shared mailboxes to the HSP
> driver.
> 
> The initial use for the mailboxes is the Tegra Combined UART. For this
> purpose, we use interrupts to receive data, and spinning to wait for
> the transmit mailbox to be emptied to minimize unnecessary overhead.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Added defines for some register fields
>     - Simplified bit looping logic in interrupt handler
>     - Changed write done polling to use readl_poll_timeout
>     - Removed unnecessary zero assignments
>     - Fixed two error cases in probe to do proper cleanup
> 
>  drivers/mailbox/tegra-hsp.c | 210 +++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 190 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 5dc21a6d01bb..6864446417c9 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -13,6 +13,7 @@
>  
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> +#include <linux/iopoll.h>
>  #include <linux/mailbox_controller.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> @@ -21,6 +22,13 @@
>  
>  #include <dt-bindings/mailbox/tegra186-hsp.h>
>  
> +#include "mailbox.h"
> +
> +#define HSP_INT0_IE		0x100
> +#define HSP_INT_IR		0x304
> +#define HSP_INT_IR_FULL_SHIFT	8
> +#define HSP_INT_IR_FULL_MASK	0xff
> +
>  #define HSP_INT_DIMENSIONING	0x380
>  #define HSP_nSM_SHIFT		0
>  #define HSP_nSS_SHIFT		4
> @@ -34,6 +42,9 @@
>  #define HSP_DB_RAW	0x8
>  #define HSP_DB_PENDING	0xc
>  
> +#define HSP_SM_SHRD_MBOX	0x0
> +#define HSP_SM_SHRD_MBOX_FULL	BIT(31)
> +
>  #define HSP_DB_CCPLEX		1
>  #define HSP_DB_BPMP		3
>  #define HSP_DB_MAX		7
> @@ -68,6 +79,18 @@ struct tegra_hsp_db_map {
>  	unsigned int index;
>  };
>  
> +struct tegra_hsp_mailbox {
> +	struct tegra_hsp_channel channel;
> +	unsigned int index;
> +	bool sending;
> +};
> +
> +static inline struct tegra_hsp_mailbox *
> +channel_to_mailbox(struct tegra_hsp_channel *channel)
> +{
> +	return container_of(channel, struct tegra_hsp_mailbox, channel);
> +}
> +
>  struct tegra_hsp_soc {
>  	const struct tegra_hsp_db_map *map;
>  };
> @@ -77,6 +100,7 @@ struct tegra_hsp {
>  	struct mbox_controller mbox;
>  	void __iomem *regs;
>  	unsigned int doorbell_irq;
> +	unsigned int shared_irq;
>  	unsigned int num_sm;
>  	unsigned int num_as;
>  	unsigned int num_ss;
> @@ -85,6 +109,7 @@ struct tegra_hsp {
>  	spinlock_t lock;
>  
>  	struct list_head doorbells;
> +	struct tegra_hsp_mailbox *mailboxes;
>  };
>  
>  static inline struct tegra_hsp *
> @@ -189,6 +214,33 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t tegra_hsp_shared_irq(int irq, void *data)
> +{
> +	struct tegra_hsp_mailbox *mb;
> +	struct tegra_hsp *hsp = data;
> +	unsigned long bit, mask;
> +	u32 value;
> +
> +	mask = tegra_hsp_readl(hsp, HSP_INT_IR);
> +	/* Only interested in FULL interrupts */
> +	mask = (mask >> HSP_INT_IR_FULL_SHIFT) & HSP_INT_IR_FULL_MASK;
> +
> +	for_each_set_bit(bit, &mask, 8) {
> +		mb = &hsp->mailboxes[bit];
> +
> +		if (!mb->sending) {
> +			value = tegra_hsp_channel_readl(&mb->channel,
> +							HSP_SM_SHRD_MBOX);
> +			value &= ~HSP_SM_SHRD_MBOX_FULL;
> +			mbox_chan_received_data(mb->channel.chan, &value);
> +			tegra_hsp_channel_writel(&mb->channel, value,
> +						 HSP_SM_SHRD_MBOX);
> +		}
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static struct tegra_hsp_channel *
>  tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
>  			  unsigned int master, unsigned int index)
> @@ -277,14 +329,57 @@ static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
>  	spin_unlock_irqrestore(&hsp->lock, flags);
>  }
>  
> +static int tegra_hsp_mailbox_startup(struct tegra_hsp_mailbox *mb)
> +{
> +	struct tegra_hsp *hsp = mb->channel.hsp;
> +	u32 value;
> +
> +	mb->channel.chan->txdone_method = TXDONE_BY_BLOCK;
> +
> +	/* Route FULL interrupt to external IRQ 0 */
> +	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
> +	value |= BIT(mb->index + 8);

Ideally this '8' should be defined as something like HSP_SM_FULL_IRQ_BASE.

> +	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
> +
> +	return 0;
> +}
> +
> +static int tegra_hsp_mailbox_shutdown(struct tegra_hsp_mailbox *mb)
> +{
> +	struct tegra_hsp *hsp = mb->channel.hsp;
> +	u32 value;
> +
> +	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
> +	value &= ~BIT(mb->index + 8);
> +	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
> +
> +	return 0;
> +}
> +
>  static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
>  {
>  	struct tegra_hsp_channel *channel = chan->con_priv;
> +	struct tegra_hsp_mailbox *mailbox;
> +	uint32_t value;
>  
>  	switch (channel->type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
>  		return 0;
> +
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		mailbox = channel_to_mailbox(channel);
> +		mailbox->sending = true;
> +
> +		value = *(uint32_t *)data;
> +		/* Mark mailbox full */
> +		value |= HSP_SM_SHRD_MBOX_FULL;
> +
> +		tegra_hsp_channel_writel(channel, value, HSP_SM_SHRD_MBOX);
> +
> +		return readl_poll_timeout(
> +			channel->regs + HSP_SM_SHRD_MBOX, value,
> +			!(value & HSP_SM_SHRD_MBOX_FULL), 0, 10000);
>  	}
>  
>  	return -EINVAL;
> @@ -297,6 +392,8 @@ static int tegra_hsp_startup(struct mbox_chan *chan)
>  	switch (channel->type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		return tegra_hsp_mailbox_startup(channel_to_mailbox(channel));
>  	}
>  
>  	return -EINVAL;
> @@ -310,6 +407,9 @@ static void tegra_hsp_shutdown(struct mbox_chan *chan)
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
>  		break;
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		tegra_hsp_mailbox_shutdown(channel_to_mailbox(channel));
> +		break;
>  	}
>  }
>  
> @@ -363,7 +463,16 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  
>  	switch (type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
> -		return tegra_hsp_doorbell_xlate(hsp, param);
> +		if (hsp->doorbell_irq)
> +			return tegra_hsp_doorbell_xlate(hsp, param);
> +		else
> +			return ERR_PTR(-EINVAL);
> +
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		if (hsp->shared_irq && param < hsp->num_sm)
> +			return hsp->mailboxes[param].channel.chan;
> +		else
> +			return ERR_PTR(-EINVAL);
>  
>  	default:
>  		return ERR_PTR(-EINVAL);
> @@ -402,6 +511,31 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
>  	return 0;
>  }
>  
> +static int tegra_hsp_add_mailboxes(struct tegra_hsp *hsp, struct device *dev)
> +{
> +	int i;
> +
> +	hsp->mailboxes = devm_kcalloc(dev, hsp->num_sm, sizeof(*hsp->mailboxes),
> +				      GFP_KERNEL);
> +	if (!hsp->mailboxes)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < hsp->num_sm; i++) {
> +		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
> +
> +		mb->index = i;
> +		mb->sending = false;
> +
> +		mb->channel.hsp = hsp;
> +		mb->channel.type = TEGRA_HSP_MBOX_TYPE_SM;
> +		mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K;
> +		mb->channel.chan = &hsp->mbox.chans[i];
> +		mb->channel.chan->con_priv = &mb->channel;
> +	}
> +
> +	return 0;
> +}
> +
>  static int tegra_hsp_probe(struct platform_device *pdev)
>  {
>  	struct tegra_hsp *hsp;
> @@ -430,14 +564,15 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
>  
>  	err = platform_get_irq_byname(pdev, "doorbell");
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
> -		return err;
> -	}
> +	if (err >= 0)
> +		hsp->doorbell_irq = err;
>  
> -	hsp->doorbell_irq = err;
> +	err = platform_get_irq_byname(pdev, "shared0");
> +	if (err >= 0)
> +		hsp->shared_irq = err;
>  
>  	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
> +	/* First nSM are reserved for mailboxes */
>  	hsp->mbox.num_chans = 32;
>  	hsp->mbox.dev = &pdev->dev;
>  	hsp->mbox.txdone_irq = false;
> @@ -450,10 +585,22 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	if (!hsp->mbox.chans)
>  		return -ENOMEM;
>  
> -	err = tegra_hsp_add_doorbells(hsp);
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
> -		return err;
> +	if (hsp->doorbell_irq) {
> +		err = tegra_hsp_add_doorbells(hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev, "failed to add doorbells: %d\n",
> +			        err);
> +			return err;
> +		}
> +	}
> +
> +	if (hsp->shared_irq) {
> +		err = tegra_hsp_add_mailboxes(hsp, &pdev->dev);
> +		if (err < 0) {
> +			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
> +			        err);
> +			goto remove_doorbells;
> +		}
>  	}
>  
>  	platform_set_drvdata(pdev, hsp);
> @@ -461,20 +608,42 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	err = mbox_controller_register(&hsp->mbox);
>  	if (err) {
>  		dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
> -		tegra_hsp_remove_doorbells(hsp);
> -		return err;
> +		goto remove_doorbells;
>  	}
>  
> -	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> -			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> -			       dev_name(&pdev->dev), hsp);
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
> -			hsp->doorbell_irq, err);
> -		return err;
> +	if (hsp->doorbell_irq) {
> +		err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> +				       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> +				       dev_name(&pdev->dev), hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev,
> +			        "failed to request doorbell IRQ#%u: %d\n",
> +				hsp->doorbell_irq, err);
> +			goto unregister_mbox_controller;
> +		}
> +	}
> +
> +	if (hsp->shared_irq) {
> +		err = devm_request_irq(&pdev->dev, hsp->shared_irq,
> +				       tegra_hsp_shared_irq, 0,
> +				       dev_name(&pdev->dev), hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev,
> +				"failed to request shared0 IRQ%u: %d\n",
> +				hsp->shared_irq, err);
> +			goto unregister_mbox_controller;
> +		}
>  	}
>  
>  	return 0;
> +
> +unregister_mbox_controller:
> +	mbox_controller_unregister(&hsp->mbox);
> +remove_doorbells:
> +	if (hsp->doorbell_irq)
> +		tegra_hsp_remove_doorbells(hsp);

This bit looks like it should have been a separate patch to fix the
clean-up if probe fails. However, unless there is a reason to re-spin
the series, probably OK.

> +
> +	return err;
>  }
>  
>  static int tegra_hsp_remove(struct platform_device *pdev)
> @@ -482,7 +651,8 @@ static int tegra_hsp_remove(struct platform_device *pdev)
>  	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
>  
>  	mbox_controller_unregister(&hsp->mbox);
> -	tegra_hsp_remove_doorbells(hsp);
> +	if (hsp->doorbell_irq)
> +		tegra_hsp_remove_doorbells(hsp);
>  
>  	return 0;
>  }
> 

Reviewed-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 5/8] mailbox: tegra-hsp: Add support for shared mailboxes
@ 2018-06-21  8:29     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:29 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
> registers consisting of a FULL bit in MSB position and 31 bits of data.
> The hardware can be configured to trigger interrupts when a mailbox
> is empty or full. Add support for these shared mailboxes to the HSP
> driver.
> 
> The initial use for the mailboxes is the Tegra Combined UART. For this
> purpose, we use interrupts to receive data, and spinning to wait for
> the transmit mailbox to be emptied to minimize unnecessary overhead.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Added defines for some register fields
>     - Simplified bit looping logic in interrupt handler
>     - Changed write done polling to use readl_poll_timeout
>     - Removed unnecessary zero assignments
>     - Fixed two error cases in probe to do proper cleanup
> 
>  drivers/mailbox/tegra-hsp.c | 210 +++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 190 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 5dc21a6d01bb..6864446417c9 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -13,6 +13,7 @@
>  
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> +#include <linux/iopoll.h>
>  #include <linux/mailbox_controller.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> @@ -21,6 +22,13 @@
>  
>  #include <dt-bindings/mailbox/tegra186-hsp.h>
>  
> +#include "mailbox.h"
> +
> +#define HSP_INT0_IE		0x100
> +#define HSP_INT_IR		0x304
> +#define HSP_INT_IR_FULL_SHIFT	8
> +#define HSP_INT_IR_FULL_MASK	0xff
> +
>  #define HSP_INT_DIMENSIONING	0x380
>  #define HSP_nSM_SHIFT		0
>  #define HSP_nSS_SHIFT		4
> @@ -34,6 +42,9 @@
>  #define HSP_DB_RAW	0x8
>  #define HSP_DB_PENDING	0xc
>  
> +#define HSP_SM_SHRD_MBOX	0x0
> +#define HSP_SM_SHRD_MBOX_FULL	BIT(31)
> +
>  #define HSP_DB_CCPLEX		1
>  #define HSP_DB_BPMP		3
>  #define HSP_DB_MAX		7
> @@ -68,6 +79,18 @@ struct tegra_hsp_db_map {
>  	unsigned int index;
>  };
>  
> +struct tegra_hsp_mailbox {
> +	struct tegra_hsp_channel channel;
> +	unsigned int index;
> +	bool sending;
> +};
> +
> +static inline struct tegra_hsp_mailbox *
> +channel_to_mailbox(struct tegra_hsp_channel *channel)
> +{
> +	return container_of(channel, struct tegra_hsp_mailbox, channel);
> +}
> +
>  struct tegra_hsp_soc {
>  	const struct tegra_hsp_db_map *map;
>  };
> @@ -77,6 +100,7 @@ struct tegra_hsp {
>  	struct mbox_controller mbox;
>  	void __iomem *regs;
>  	unsigned int doorbell_irq;
> +	unsigned int shared_irq;
>  	unsigned int num_sm;
>  	unsigned int num_as;
>  	unsigned int num_ss;
> @@ -85,6 +109,7 @@ struct tegra_hsp {
>  	spinlock_t lock;
>  
>  	struct list_head doorbells;
> +	struct tegra_hsp_mailbox *mailboxes;
>  };
>  
>  static inline struct tegra_hsp *
> @@ -189,6 +214,33 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t tegra_hsp_shared_irq(int irq, void *data)
> +{
> +	struct tegra_hsp_mailbox *mb;
> +	struct tegra_hsp *hsp = data;
> +	unsigned long bit, mask;
> +	u32 value;
> +
> +	mask = tegra_hsp_readl(hsp, HSP_INT_IR);
> +	/* Only interested in FULL interrupts */
> +	mask = (mask >> HSP_INT_IR_FULL_SHIFT) & HSP_INT_IR_FULL_MASK;
> +
> +	for_each_set_bit(bit, &mask, 8) {
> +		mb = &hsp->mailboxes[bit];
> +
> +		if (!mb->sending) {
> +			value = tegra_hsp_channel_readl(&mb->channel,
> +							HSP_SM_SHRD_MBOX);
> +			value &= ~HSP_SM_SHRD_MBOX_FULL;
> +			mbox_chan_received_data(mb->channel.chan, &value);
> +			tegra_hsp_channel_writel(&mb->channel, value,
> +						 HSP_SM_SHRD_MBOX);
> +		}
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static struct tegra_hsp_channel *
>  tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
>  			  unsigned int master, unsigned int index)
> @@ -277,14 +329,57 @@ static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
>  	spin_unlock_irqrestore(&hsp->lock, flags);
>  }
>  
> +static int tegra_hsp_mailbox_startup(struct tegra_hsp_mailbox *mb)
> +{
> +	struct tegra_hsp *hsp = mb->channel.hsp;
> +	u32 value;
> +
> +	mb->channel.chan->txdone_method = TXDONE_BY_BLOCK;
> +
> +	/* Route FULL interrupt to external IRQ 0 */
> +	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
> +	value |= BIT(mb->index + 8);

Ideally this '8' should be defined as something like HSP_SM_FULL_IRQ_BASE.

> +	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
> +
> +	return 0;
> +}
> +
> +static int tegra_hsp_mailbox_shutdown(struct tegra_hsp_mailbox *mb)
> +{
> +	struct tegra_hsp *hsp = mb->channel.hsp;
> +	u32 value;
> +
> +	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
> +	value &= ~BIT(mb->index + 8);
> +	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
> +
> +	return 0;
> +}
> +
>  static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
>  {
>  	struct tegra_hsp_channel *channel = chan->con_priv;
> +	struct tegra_hsp_mailbox *mailbox;
> +	uint32_t value;
>  
>  	switch (channel->type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
>  		return 0;
> +
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		mailbox = channel_to_mailbox(channel);
> +		mailbox->sending = true;
> +
> +		value = *(uint32_t *)data;
> +		/* Mark mailbox full */
> +		value |= HSP_SM_SHRD_MBOX_FULL;
> +
> +		tegra_hsp_channel_writel(channel, value, HSP_SM_SHRD_MBOX);
> +
> +		return readl_poll_timeout(
> +			channel->regs + HSP_SM_SHRD_MBOX, value,
> +			!(value & HSP_SM_SHRD_MBOX_FULL), 0, 10000);
>  	}
>  
>  	return -EINVAL;
> @@ -297,6 +392,8 @@ static int tegra_hsp_startup(struct mbox_chan *chan)
>  	switch (channel->type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		return tegra_hsp_mailbox_startup(channel_to_mailbox(channel));
>  	}
>  
>  	return -EINVAL;
> @@ -310,6 +407,9 @@ static void tegra_hsp_shutdown(struct mbox_chan *chan)
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
>  		break;
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		tegra_hsp_mailbox_shutdown(channel_to_mailbox(channel));
> +		break;
>  	}
>  }
>  
> @@ -363,7 +463,16 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  
>  	switch (type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
> -		return tegra_hsp_doorbell_xlate(hsp, param);
> +		if (hsp->doorbell_irq)
> +			return tegra_hsp_doorbell_xlate(hsp, param);
> +		else
> +			return ERR_PTR(-EINVAL);
> +
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		if (hsp->shared_irq && param < hsp->num_sm)
> +			return hsp->mailboxes[param].channel.chan;
> +		else
> +			return ERR_PTR(-EINVAL);
>  
>  	default:
>  		return ERR_PTR(-EINVAL);
> @@ -402,6 +511,31 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
>  	return 0;
>  }
>  
> +static int tegra_hsp_add_mailboxes(struct tegra_hsp *hsp, struct device *dev)
> +{
> +	int i;
> +
> +	hsp->mailboxes = devm_kcalloc(dev, hsp->num_sm, sizeof(*hsp->mailboxes),
> +				      GFP_KERNEL);
> +	if (!hsp->mailboxes)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < hsp->num_sm; i++) {
> +		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
> +
> +		mb->index = i;
> +		mb->sending = false;
> +
> +		mb->channel.hsp = hsp;
> +		mb->channel.type = TEGRA_HSP_MBOX_TYPE_SM;
> +		mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K;
> +		mb->channel.chan = &hsp->mbox.chans[i];
> +		mb->channel.chan->con_priv = &mb->channel;
> +	}
> +
> +	return 0;
> +}
> +
>  static int tegra_hsp_probe(struct platform_device *pdev)
>  {
>  	struct tegra_hsp *hsp;
> @@ -430,14 +564,15 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
>  
>  	err = platform_get_irq_byname(pdev, "doorbell");
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
> -		return err;
> -	}
> +	if (err >= 0)
> +		hsp->doorbell_irq = err;
>  
> -	hsp->doorbell_irq = err;
> +	err = platform_get_irq_byname(pdev, "shared0");
> +	if (err >= 0)
> +		hsp->shared_irq = err;
>  
>  	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
> +	/* First nSM are reserved for mailboxes */
>  	hsp->mbox.num_chans = 32;
>  	hsp->mbox.dev = &pdev->dev;
>  	hsp->mbox.txdone_irq = false;
> @@ -450,10 +585,22 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	if (!hsp->mbox.chans)
>  		return -ENOMEM;
>  
> -	err = tegra_hsp_add_doorbells(hsp);
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
> -		return err;
> +	if (hsp->doorbell_irq) {
> +		err = tegra_hsp_add_doorbells(hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev, "failed to add doorbells: %d\n",
> +			        err);
> +			return err;
> +		}
> +	}
> +
> +	if (hsp->shared_irq) {
> +		err = tegra_hsp_add_mailboxes(hsp, &pdev->dev);
> +		if (err < 0) {
> +			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
> +			        err);
> +			goto remove_doorbells;
> +		}
>  	}
>  
>  	platform_set_drvdata(pdev, hsp);
> @@ -461,20 +608,42 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	err = mbox_controller_register(&hsp->mbox);
>  	if (err) {
>  		dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
> -		tegra_hsp_remove_doorbells(hsp);
> -		return err;
> +		goto remove_doorbells;
>  	}
>  
> -	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> -			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> -			       dev_name(&pdev->dev), hsp);
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
> -			hsp->doorbell_irq, err);
> -		return err;
> +	if (hsp->doorbell_irq) {
> +		err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> +				       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> +				       dev_name(&pdev->dev), hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev,
> +			        "failed to request doorbell IRQ#%u: %d\n",
> +				hsp->doorbell_irq, err);
> +			goto unregister_mbox_controller;
> +		}
> +	}
> +
> +	if (hsp->shared_irq) {
> +		err = devm_request_irq(&pdev->dev, hsp->shared_irq,
> +				       tegra_hsp_shared_irq, 0,
> +				       dev_name(&pdev->dev), hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev,
> +				"failed to request shared0 IRQ%u: %d\n",
> +				hsp->shared_irq, err);
> +			goto unregister_mbox_controller;
> +		}
>  	}
>  
>  	return 0;
> +
> +unregister_mbox_controller:
> +	mbox_controller_unregister(&hsp->mbox);
> +remove_doorbells:
> +	if (hsp->doorbell_irq)
> +		tegra_hsp_remove_doorbells(hsp);

This bit looks like it should have been a separate patch to fix the
clean-up if probe fails. However, unless there is a reason to re-spin
the series, probably OK.

> +
> +	return err;
>  }
>  
>  static int tegra_hsp_remove(struct platform_device *pdev)
> @@ -482,7 +651,8 @@ static int tegra_hsp_remove(struct platform_device *pdev)
>  	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
>  
>  	mbox_controller_unregister(&hsp->mbox);
> -	tegra_hsp_remove_doorbells(hsp);
> +	if (hsp->doorbell_irq)
> +		tegra_hsp_remove_doorbells(hsp);
>  
>  	return 0;
>  }
> 

Reviewed-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* [PATCH v2 5/8] mailbox: tegra-hsp: Add support for shared mailboxes
@ 2018-06-21  8:29     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  8:29 UTC (permalink / raw)
  To: linux-arm-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
> registers consisting of a FULL bit in MSB position and 31 bits of data.
> The hardware can be configured to trigger interrupts when a mailbox
> is empty or full. Add support for these shared mailboxes to the HSP
> driver.
> 
> The initial use for the mailboxes is the Tegra Combined UART. For this
> purpose, we use interrupts to receive data, and spinning to wait for
> the transmit mailbox to be emptied to minimize unnecessary overhead.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Added defines for some register fields
>     - Simplified bit looping logic in interrupt handler
>     - Changed write done polling to use readl_poll_timeout
>     - Removed unnecessary zero assignments
>     - Fixed two error cases in probe to do proper cleanup
> 
>  drivers/mailbox/tegra-hsp.c | 210 +++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 190 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 5dc21a6d01bb..6864446417c9 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -13,6 +13,7 @@
>  
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> +#include <linux/iopoll.h>
>  #include <linux/mailbox_controller.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> @@ -21,6 +22,13 @@
>  
>  #include <dt-bindings/mailbox/tegra186-hsp.h>
>  
> +#include "mailbox.h"
> +
> +#define HSP_INT0_IE		0x100
> +#define HSP_INT_IR		0x304
> +#define HSP_INT_IR_FULL_SHIFT	8
> +#define HSP_INT_IR_FULL_MASK	0xff
> +
>  #define HSP_INT_DIMENSIONING	0x380
>  #define HSP_nSM_SHIFT		0
>  #define HSP_nSS_SHIFT		4
> @@ -34,6 +42,9 @@
>  #define HSP_DB_RAW	0x8
>  #define HSP_DB_PENDING	0xc
>  
> +#define HSP_SM_SHRD_MBOX	0x0
> +#define HSP_SM_SHRD_MBOX_FULL	BIT(31)
> +
>  #define HSP_DB_CCPLEX		1
>  #define HSP_DB_BPMP		3
>  #define HSP_DB_MAX		7
> @@ -68,6 +79,18 @@ struct tegra_hsp_db_map {
>  	unsigned int index;
>  };
>  
> +struct tegra_hsp_mailbox {
> +	struct tegra_hsp_channel channel;
> +	unsigned int index;
> +	bool sending;
> +};
> +
> +static inline struct tegra_hsp_mailbox *
> +channel_to_mailbox(struct tegra_hsp_channel *channel)
> +{
> +	return container_of(channel, struct tegra_hsp_mailbox, channel);
> +}
> +
>  struct tegra_hsp_soc {
>  	const struct tegra_hsp_db_map *map;
>  };
> @@ -77,6 +100,7 @@ struct tegra_hsp {
>  	struct mbox_controller mbox;
>  	void __iomem *regs;
>  	unsigned int doorbell_irq;
> +	unsigned int shared_irq;
>  	unsigned int num_sm;
>  	unsigned int num_as;
>  	unsigned int num_ss;
> @@ -85,6 +109,7 @@ struct tegra_hsp {
>  	spinlock_t lock;
>  
>  	struct list_head doorbells;
> +	struct tegra_hsp_mailbox *mailboxes;
>  };
>  
>  static inline struct tegra_hsp *
> @@ -189,6 +214,33 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t tegra_hsp_shared_irq(int irq, void *data)
> +{
> +	struct tegra_hsp_mailbox *mb;
> +	struct tegra_hsp *hsp = data;
> +	unsigned long bit, mask;
> +	u32 value;
> +
> +	mask = tegra_hsp_readl(hsp, HSP_INT_IR);
> +	/* Only interested in FULL interrupts */
> +	mask = (mask >> HSP_INT_IR_FULL_SHIFT) & HSP_INT_IR_FULL_MASK;
> +
> +	for_each_set_bit(bit, &mask, 8) {
> +		mb = &hsp->mailboxes[bit];
> +
> +		if (!mb->sending) {
> +			value = tegra_hsp_channel_readl(&mb->channel,
> +							HSP_SM_SHRD_MBOX);
> +			value &= ~HSP_SM_SHRD_MBOX_FULL;
> +			mbox_chan_received_data(mb->channel.chan, &value);
> +			tegra_hsp_channel_writel(&mb->channel, value,
> +						 HSP_SM_SHRD_MBOX);
> +		}
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static struct tegra_hsp_channel *
>  tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
>  			  unsigned int master, unsigned int index)
> @@ -277,14 +329,57 @@ static void tegra_hsp_doorbell_shutdown(struct tegra_hsp_doorbell *db)
>  	spin_unlock_irqrestore(&hsp->lock, flags);
>  }
>  
> +static int tegra_hsp_mailbox_startup(struct tegra_hsp_mailbox *mb)
> +{
> +	struct tegra_hsp *hsp = mb->channel.hsp;
> +	u32 value;
> +
> +	mb->channel.chan->txdone_method = TXDONE_BY_BLOCK;
> +
> +	/* Route FULL interrupt to external IRQ 0 */
> +	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
> +	value |= BIT(mb->index + 8);

Ideally this '8' should be defined as something like HSP_SM_FULL_IRQ_BASE.

> +	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
> +
> +	return 0;
> +}
> +
> +static int tegra_hsp_mailbox_shutdown(struct tegra_hsp_mailbox *mb)
> +{
> +	struct tegra_hsp *hsp = mb->channel.hsp;
> +	u32 value;
> +
> +	value = tegra_hsp_readl(hsp, HSP_INT0_IE);
> +	value &= ~BIT(mb->index + 8);
> +	tegra_hsp_writel(hsp, value, HSP_INT0_IE);
> +
> +	return 0;
> +}
> +
>  static int tegra_hsp_send_data(struct mbox_chan *chan, void *data)
>  {
>  	struct tegra_hsp_channel *channel = chan->con_priv;
> +	struct tegra_hsp_mailbox *mailbox;
> +	uint32_t value;
>  
>  	switch (channel->type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		tegra_hsp_channel_writel(channel, 1, HSP_DB_TRIGGER);
>  		return 0;
> +
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		mailbox = channel_to_mailbox(channel);
> +		mailbox->sending = true;
> +
> +		value = *(uint32_t *)data;
> +		/* Mark mailbox full */
> +		value |= HSP_SM_SHRD_MBOX_FULL;
> +
> +		tegra_hsp_channel_writel(channel, value, HSP_SM_SHRD_MBOX);
> +
> +		return readl_poll_timeout(
> +			channel->regs + HSP_SM_SHRD_MBOX, value,
> +			!(value & HSP_SM_SHRD_MBOX_FULL), 0, 10000);
>  	}
>  
>  	return -EINVAL;
> @@ -297,6 +392,8 @@ static int tegra_hsp_startup(struct mbox_chan *chan)
>  	switch (channel->type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		return tegra_hsp_doorbell_startup(channel_to_doorbell(channel));
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		return tegra_hsp_mailbox_startup(channel_to_mailbox(channel));
>  	}
>  
>  	return -EINVAL;
> @@ -310,6 +407,9 @@ static void tegra_hsp_shutdown(struct mbox_chan *chan)
>  	case TEGRA_HSP_MBOX_TYPE_DB:
>  		tegra_hsp_doorbell_shutdown(channel_to_doorbell(channel));
>  		break;
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		tegra_hsp_mailbox_shutdown(channel_to_mailbox(channel));
> +		break;
>  	}
>  }
>  
> @@ -363,7 +463,16 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
>  
>  	switch (type) {
>  	case TEGRA_HSP_MBOX_TYPE_DB:
> -		return tegra_hsp_doorbell_xlate(hsp, param);
> +		if (hsp->doorbell_irq)
> +			return tegra_hsp_doorbell_xlate(hsp, param);
> +		else
> +			return ERR_PTR(-EINVAL);
> +
> +	case TEGRA_HSP_MBOX_TYPE_SM:
> +		if (hsp->shared_irq && param < hsp->num_sm)
> +			return hsp->mailboxes[param].channel.chan;
> +		else
> +			return ERR_PTR(-EINVAL);
>  
>  	default:
>  		return ERR_PTR(-EINVAL);
> @@ -402,6 +511,31 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
>  	return 0;
>  }
>  
> +static int tegra_hsp_add_mailboxes(struct tegra_hsp *hsp, struct device *dev)
> +{
> +	int i;
> +
> +	hsp->mailboxes = devm_kcalloc(dev, hsp->num_sm, sizeof(*hsp->mailboxes),
> +				      GFP_KERNEL);
> +	if (!hsp->mailboxes)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < hsp->num_sm; i++) {
> +		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
> +
> +		mb->index = i;
> +		mb->sending = false;
> +
> +		mb->channel.hsp = hsp;
> +		mb->channel.type = TEGRA_HSP_MBOX_TYPE_SM;
> +		mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K;
> +		mb->channel.chan = &hsp->mbox.chans[i];
> +		mb->channel.chan->con_priv = &mb->channel;
> +	}
> +
> +	return 0;
> +}
> +
>  static int tegra_hsp_probe(struct platform_device *pdev)
>  {
>  	struct tegra_hsp *hsp;
> @@ -430,14 +564,15 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
>  
>  	err = platform_get_irq_byname(pdev, "doorbell");
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
> -		return err;
> -	}
> +	if (err >= 0)
> +		hsp->doorbell_irq = err;
>  
> -	hsp->doorbell_irq = err;
> +	err = platform_get_irq_byname(pdev, "shared0");
> +	if (err >= 0)
> +		hsp->shared_irq = err;
>  
>  	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
> +	/* First nSM are reserved for mailboxes */
>  	hsp->mbox.num_chans = 32;
>  	hsp->mbox.dev = &pdev->dev;
>  	hsp->mbox.txdone_irq = false;
> @@ -450,10 +585,22 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	if (!hsp->mbox.chans)
>  		return -ENOMEM;
>  
> -	err = tegra_hsp_add_doorbells(hsp);
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
> -		return err;
> +	if (hsp->doorbell_irq) {
> +		err = tegra_hsp_add_doorbells(hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev, "failed to add doorbells: %d\n",
> +			        err);
> +			return err;
> +		}
> +	}
> +
> +	if (hsp->shared_irq) {
> +		err = tegra_hsp_add_mailboxes(hsp, &pdev->dev);
> +		if (err < 0) {
> +			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
> +			        err);
> +			goto remove_doorbells;
> +		}
>  	}
>  
>  	platform_set_drvdata(pdev, hsp);
> @@ -461,20 +608,42 @@ static int tegra_hsp_probe(struct platform_device *pdev)
>  	err = mbox_controller_register(&hsp->mbox);
>  	if (err) {
>  		dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
> -		tegra_hsp_remove_doorbells(hsp);
> -		return err;
> +		goto remove_doorbells;
>  	}
>  
> -	err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> -			       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> -			       dev_name(&pdev->dev), hsp);
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to request doorbell IRQ#%u: %d\n",
> -			hsp->doorbell_irq, err);
> -		return err;
> +	if (hsp->doorbell_irq) {
> +		err = devm_request_irq(&pdev->dev, hsp->doorbell_irq,
> +				       tegra_hsp_doorbell_irq, IRQF_NO_SUSPEND,
> +				       dev_name(&pdev->dev), hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev,
> +			        "failed to request doorbell IRQ#%u: %d\n",
> +				hsp->doorbell_irq, err);
> +			goto unregister_mbox_controller;
> +		}
> +	}
> +
> +	if (hsp->shared_irq) {
> +		err = devm_request_irq(&pdev->dev, hsp->shared_irq,
> +				       tegra_hsp_shared_irq, 0,
> +				       dev_name(&pdev->dev), hsp);
> +		if (err < 0) {
> +			dev_err(&pdev->dev,
> +				"failed to request shared0 IRQ%u: %d\n",
> +				hsp->shared_irq, err);
> +			goto unregister_mbox_controller;
> +		}
>  	}
>  
>  	return 0;
> +
> +unregister_mbox_controller:
> +	mbox_controller_unregister(&hsp->mbox);
> +remove_doorbells:
> +	if (hsp->doorbell_irq)
> +		tegra_hsp_remove_doorbells(hsp);

This bit looks like it should have been a separate patch to fix the
clean-up if probe fails. However, unless there is a reason to re-spin
the series, probably OK.

> +
> +	return err;
>  }
>  
>  static int tegra_hsp_remove(struct platform_device *pdev)
> @@ -482,7 +651,8 @@ static int tegra_hsp_remove(struct platform_device *pdev)
>  	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
>  
>  	mbox_controller_unregister(&hsp->mbox);
> -	tegra_hsp_remove_doorbells(hsp);
> +	if (hsp->doorbell_irq)
> +		tegra_hsp_remove_doorbells(hsp);
>  
>  	return 0;
>  }
> 

Reviewed-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 6/8] serial: Add Tegra Combined UART driver
  2018-06-20 12:20   ` Mikko Perttunen
  (?)
@ 2018-06-21  9:20     ` Jon Hunter
  -1 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  9:20 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The Tegra Combined UART (TCU) is a mailbox-based mechanism that allows
> multiplexing multiple "virtual UARTs" into a single hardware serial
> port. The TCU is the primary serial port on Tegra194 devices.
> 
> Add a TCU driver utilizing the mailbox framework, as the used mailboxes
> are part of Tegra HSP blocks that are already controlled by the Tegra
> HSP mailbox driver.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Removed (void) casts for unused variables.
>     - Changed the uart_set_options() call to be on one line, even if its
>       over 80 characters.
>     - Added defines for magic numbers.
>     - Style fixes.
>     - Changed Kconfig entry to depend on the Tegra HSP driver instead of
>       just the mailbox framework.
> 
>  drivers/tty/serial/Kconfig       |   9 ++
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/tegra-tcu.c   | 289 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 302 insertions(+)
>  create mode 100644 drivers/tty/serial/tegra-tcu.c
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index df8bd0c7b97d..5fdd336e8937 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -322,6 +322,15 @@ config SERIAL_TEGRA
>  	  are enabled). This driver uses the APB DMA to achieve higher baudrate
>  	  and better performance.
>  
> +config SERIAL_TEGRA_TCU
> +	tristate "NVIDIA Tegra Combined UART"
> +	depends on ARCH_TEGRA && TEGRA_HSP_MBOX
> +	select SERIAL_CORE
> +	help
> +	  Support for the mailbox-based TCU (Tegra Combined UART) serial port.
> +	  TCU is a virtual serial port that allows multiplexing multiple data
> +	  streams into a single hardware serial port.
> +
>  config SERIAL_MAX3100
>  	tristate "MAX3100 support"
>  	depends on SPI
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index daac675612df..4ad82231ff8a 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_SERIAL_LANTIQ)	+= lantiq.o
>  obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
>  obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
>  obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
> +obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
>  obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
>  obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
>  obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
> diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
> new file mode 100644
> index 000000000000..b54ebe2ad917
> --- /dev/null
> +++ b/drivers/tty/serial/tegra-tcu.c
> @@ -0,0 +1,289 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
> + */
> +
> +#include <linux/console.h>
> +#include <linux/mailbox_client.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/serial.h>
> +#include <linux/serial_core.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +
> +#define TCU_MBOX_BYTE(i, x)			((x) << (i*8))
> +#define TCU_MBOX_BYTE_V(x, i)			(((x) >> (i*8)) & 0xff)
> +#define TCU_MBOX_NUM_BYTES(x)			((x) << 24)
> +#define TCU_MBOX_NUM_BYTES_V(x)			(((x) >> 24) & 0x3)
> +#define TCU_MBOX_FLUSH				BIT(26)
> +
> +static struct uart_driver tegra_tcu_uart_driver;
> +static struct uart_port tegra_tcu_uart_port;
> +
> +struct tegra_tcu {
> +	struct mbox_client tx_client, rx_client;
> +	struct mbox_chan *tx, *rx;
> +};
> +
> +static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port)
> +{
> +	return TIOCSER_TEMT;
> +}
> +
> +static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +}
> +
> +static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void tegra_tcu_uart_stop_tx(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_write(const char *s, unsigned int count)
> +{
> +	struct tegra_tcu *tcu = tegra_tcu_uart_port.private_data;
> +	unsigned int written = 0, i = 0;
> +	bool insert_nl = false;
> +	uint32_t value = 0;
> +
> +	while (i < count) {
> +		if (insert_nl) {
> +			value |= TCU_MBOX_BYTE(written++, '\n');
> +			insert_nl = false;
> +			i++;
> +		} else if (s[i] == '\n') {
> +			value |= TCU_MBOX_BYTE(written++, '\r');
> +			insert_nl = true;
> +		} else {
> +			value |= TCU_MBOX_BYTE(written++, s[i++]);
> +		}
> +
> +		if (written == 3) {
> +			value |= TCU_MBOX_NUM_BYTES(3) | TCU_MBOX_FLUSH;
> +			mbox_send_message(tcu->tx, &value);
> +			value = 0;
> +			written = 0;
> +		}
> +	}
> +
> +	if (written) {
> +		value |= TCU_MBOX_NUM_BYTES(written) | TCU_MBOX_FLUSH;
> +		mbox_send_message(tcu->tx, &value);
> +	}
> +}
> +
> +static void tegra_tcu_uart_start_tx(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +	unsigned long count;
> +
> +	for (;;) {
> +		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
> +		if (!count)
> +			break;
> +
> +		tegra_tcu_write(&xmit->buf[xmit->tail], count);
> +		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
> +	}
> +
> +	uart_write_wakeup(port);
> +}
> +
> +static void tegra_tcu_uart_stop_rx(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl)
> +{
> +}
> +
> +static int tegra_tcu_uart_startup(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void tegra_tcu_uart_shutdown(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_uart_set_termios(struct uart_port *port,
> +				       struct ktermios *new,
> +				       struct ktermios *old)
> +{
> +}
> +
> +static const struct uart_ops tegra_tcu_uart_ops = {
> +	.tx_empty = tegra_tcu_uart_tx_empty,
> +	.set_mctrl = tegra_tcu_uart_set_mctrl,
> +	.get_mctrl = tegra_tcu_uart_get_mctrl,
> +	.stop_tx = tegra_tcu_uart_stop_tx,
> +	.start_tx = tegra_tcu_uart_start_tx,
> +	.stop_rx = tegra_tcu_uart_stop_rx,
> +	.break_ctl = tegra_tcu_uart_break_ctl,
> +	.startup = tegra_tcu_uart_startup,
> +	.shutdown = tegra_tcu_uart_shutdown,
> +	.set_termios = tegra_tcu_uart_set_termios,
> +};
> +
> +static void tegra_tcu_console_write(struct console *cons, const char *s,
> +				    unsigned int count)
> +{
> +	tegra_tcu_write(s, count);
> +}
> +
> +static int tegra_tcu_console_setup(struct console *cons, char *options)
> +{
> +	if (!tegra_tcu_uart_port.private_data)
> +		return -ENODEV;
> +
> +	return uart_set_options(&tegra_tcu_uart_port, cons, 115200, 'n', 8, 'n');
> +}

I am curious if we actually need to call uart_set_options() here? Given that
set_termios does nothing, is this actually needed?

> +
> +static struct console tegra_tcu_console = {
> +	.name = "ttyTCU",
> +	.device = uart_console_device,
> +	.flags = CON_PRINTBUFFER | CON_ANYTIME,
> +	.index = -1,
> +	.write = tegra_tcu_console_write,
> +	.setup = tegra_tcu_console_setup,
> +	.data = &tegra_tcu_uart_driver,
> +};
> +
> +static struct uart_driver tegra_tcu_uart_driver = {
> +	.owner = THIS_MODULE,
> +	.driver_name = "tegra-tcu",
> +	.dev_name = "ttyTCU",
> +	.cons = &tegra_tcu_console,
> +	.nr = 1,
> +};
> +
> +static void tegra_tcu_receive(struct mbox_client *client, void *msg_p)
> +{
> +	struct tty_port *port = &tegra_tcu_uart_port.state->port;
> +	uint32_t msg = *(uint32_t *)msg_p;
> +	unsigned int num_bytes;
> +	int i;
> +
> +	num_bytes = TCU_MBOX_NUM_BYTES_V(msg);
> +	for (i = 0; i < num_bytes; i++)
> +		tty_insert_flip_char(port, TCU_MBOX_BYTE_V(msg, i), TTY_NORMAL);
> +
> +	tty_flip_buffer_push(port);
> +}
> +
> +static int tegra_tcu_probe(struct platform_device *pdev)
> +{
> +	struct uart_port *port = &tegra_tcu_uart_port;
> +	struct tegra_tcu *tcu;
> +	int err;
> +
> +	tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
> +	if (!tcu)
> +		return -ENOMEM;
> +
> +	tcu->tx_client.dev = &pdev->dev;
> +	tcu->rx_client.dev = &pdev->dev;
> +	tcu->rx_client.rx_callback = tegra_tcu_receive;
> +
> +	tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
> +	if (IS_ERR(tcu->tx)) {
> +		err = PTR_ERR(tcu->tx);
> +		dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
> +		return err;
> +	}
> +
> +	tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
> +	if (IS_ERR(tcu->rx)) {
> +		err = PTR_ERR(tcu->rx);
> +		dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
> +		goto free_tx;
> +	}
> +
> +	err = uart_register_driver(&tegra_tcu_uart_driver);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to register UART driver: %d\n",
> +			err);
> +		goto free_rx;
> +	}
> +
> +	spin_lock_init(&port->lock);
> +	port->dev = &pdev->dev;
> +	port->type = PORT_TEGRA_TCU;
> +	port->ops = &tegra_tcu_uart_ops;
> +	port->fifosize = 1;
> +	port->iotype = UPIO_MEM;
> +	port->flags = UPF_BOOT_AUTOCONF;
> +	port->private_data = tcu;
> +
> +	err = uart_add_one_port(&tegra_tcu_uart_driver, port);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
> +		goto unregister_uart;
> +	}
> +
> +	return 0;
> +
> +unregister_uart:
> +	uart_unregister_driver(&tegra_tcu_uart_driver);
> +free_rx:
> +	mbox_free_channel(tcu->rx);
> +free_tx:
> +	mbox_free_channel(tcu->tx);
> +
> +	return err;
> +}
> +
> +static int tegra_tcu_remove(struct platform_device *pdev)
> +{
> +	uart_remove_one_port(&tegra_tcu_uart_driver, &tegra_tcu_uart_port);
> +	uart_unregister_driver(&tegra_tcu_uart_driver);

mbox_free_channel()?

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id tegra_tcu_match[] = {
> +	{ .compatible = "nvidia,tegra194-tcu" },
> +	{ }
> +};
> +
> +static struct platform_driver tegra_tcu_driver = {
> +	.driver = {
> +		.name = "tegra-tcu",
> +		.of_match_table = tegra_tcu_match,
> +	},
> +	.probe = tegra_tcu_probe,
> +	.remove = tegra_tcu_remove,
> +};
> +
> +static int __init tegra_tcu_init(void)
> +{
> +	int err;
> +
> +	err = platform_driver_register(&tegra_tcu_driver);
> +	if (err)
> +		return err;
> +
> +	register_console(&tegra_tcu_console);
> +
> +	return 0;
> +}
> +module_init(tegra_tcu_init);
> +
> +static void __exit tegra_tcu_exit(void)
> +{
> +	unregister_console(&tegra_tcu_console);
> +	platform_driver_unregister(&tegra_tcu_driver);
> +}
> +module_exit(tegra_tcu_exit);
> +
> +MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index dce5f9dae121..69883c32cb98 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -79,6 +79,9 @@
>  /* Nuvoton UART */
>  #define PORT_NPCM	40
>  
> +/* NVIDIA Tegra Combined UART */
> +#define PORT_TEGRA_TCU	41
> +
>  /* Intel EG20 */
>  #define PORT_PCH_8LINE	44
>  #define PORT_PCH_2LINE	45
> 

Otherwise looks good to me.

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 6/8] serial: Add Tegra Combined UART driver
@ 2018-06-21  9:20     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  9:20 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The Tegra Combined UART (TCU) is a mailbox-based mechanism that allows
> multiplexing multiple "virtual UARTs" into a single hardware serial
> port. The TCU is the primary serial port on Tegra194 devices.
> 
> Add a TCU driver utilizing the mailbox framework, as the used mailboxes
> are part of Tegra HSP blocks that are already controlled by the Tegra
> HSP mailbox driver.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Removed (void) casts for unused variables.
>     - Changed the uart_set_options() call to be on one line, even if its
>       over 80 characters.
>     - Added defines for magic numbers.
>     - Style fixes.
>     - Changed Kconfig entry to depend on the Tegra HSP driver instead of
>       just the mailbox framework.
> 
>  drivers/tty/serial/Kconfig       |   9 ++
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/tegra-tcu.c   | 289 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 302 insertions(+)
>  create mode 100644 drivers/tty/serial/tegra-tcu.c
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index df8bd0c7b97d..5fdd336e8937 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -322,6 +322,15 @@ config SERIAL_TEGRA
>  	  are enabled). This driver uses the APB DMA to achieve higher baudrate
>  	  and better performance.
>  
> +config SERIAL_TEGRA_TCU
> +	tristate "NVIDIA Tegra Combined UART"
> +	depends on ARCH_TEGRA && TEGRA_HSP_MBOX
> +	select SERIAL_CORE
> +	help
> +	  Support for the mailbox-based TCU (Tegra Combined UART) serial port.
> +	  TCU is a virtual serial port that allows multiplexing multiple data
> +	  streams into a single hardware serial port.
> +
>  config SERIAL_MAX3100
>  	tristate "MAX3100 support"
>  	depends on SPI
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index daac675612df..4ad82231ff8a 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_SERIAL_LANTIQ)	+= lantiq.o
>  obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
>  obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
>  obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
> +obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
>  obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
>  obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
>  obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
> diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
> new file mode 100644
> index 000000000000..b54ebe2ad917
> --- /dev/null
> +++ b/drivers/tty/serial/tegra-tcu.c
> @@ -0,0 +1,289 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
> + */
> +
> +#include <linux/console.h>
> +#include <linux/mailbox_client.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/serial.h>
> +#include <linux/serial_core.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +
> +#define TCU_MBOX_BYTE(i, x)			((x) << (i*8))
> +#define TCU_MBOX_BYTE_V(x, i)			(((x) >> (i*8)) & 0xff)
> +#define TCU_MBOX_NUM_BYTES(x)			((x) << 24)
> +#define TCU_MBOX_NUM_BYTES_V(x)			(((x) >> 24) & 0x3)
> +#define TCU_MBOX_FLUSH				BIT(26)
> +
> +static struct uart_driver tegra_tcu_uart_driver;
> +static struct uart_port tegra_tcu_uart_port;
> +
> +struct tegra_tcu {
> +	struct mbox_client tx_client, rx_client;
> +	struct mbox_chan *tx, *rx;
> +};
> +
> +static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port)
> +{
> +	return TIOCSER_TEMT;
> +}
> +
> +static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +}
> +
> +static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void tegra_tcu_uart_stop_tx(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_write(const char *s, unsigned int count)
> +{
> +	struct tegra_tcu *tcu = tegra_tcu_uart_port.private_data;
> +	unsigned int written = 0, i = 0;
> +	bool insert_nl = false;
> +	uint32_t value = 0;
> +
> +	while (i < count) {
> +		if (insert_nl) {
> +			value |= TCU_MBOX_BYTE(written++, '\n');
> +			insert_nl = false;
> +			i++;
> +		} else if (s[i] == '\n') {
> +			value |= TCU_MBOX_BYTE(written++, '\r');
> +			insert_nl = true;
> +		} else {
> +			value |= TCU_MBOX_BYTE(written++, s[i++]);
> +		}
> +
> +		if (written == 3) {
> +			value |= TCU_MBOX_NUM_BYTES(3) | TCU_MBOX_FLUSH;
> +			mbox_send_message(tcu->tx, &value);
> +			value = 0;
> +			written = 0;
> +		}
> +	}
> +
> +	if (written) {
> +		value |= TCU_MBOX_NUM_BYTES(written) | TCU_MBOX_FLUSH;
> +		mbox_send_message(tcu->tx, &value);
> +	}
> +}
> +
> +static void tegra_tcu_uart_start_tx(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +	unsigned long count;
> +
> +	for (;;) {
> +		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
> +		if (!count)
> +			break;
> +
> +		tegra_tcu_write(&xmit->buf[xmit->tail], count);
> +		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
> +	}
> +
> +	uart_write_wakeup(port);
> +}
> +
> +static void tegra_tcu_uart_stop_rx(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl)
> +{
> +}
> +
> +static int tegra_tcu_uart_startup(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void tegra_tcu_uart_shutdown(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_uart_set_termios(struct uart_port *port,
> +				       struct ktermios *new,
> +				       struct ktermios *old)
> +{
> +}
> +
> +static const struct uart_ops tegra_tcu_uart_ops = {
> +	.tx_empty = tegra_tcu_uart_tx_empty,
> +	.set_mctrl = tegra_tcu_uart_set_mctrl,
> +	.get_mctrl = tegra_tcu_uart_get_mctrl,
> +	.stop_tx = tegra_tcu_uart_stop_tx,
> +	.start_tx = tegra_tcu_uart_start_tx,
> +	.stop_rx = tegra_tcu_uart_stop_rx,
> +	.break_ctl = tegra_tcu_uart_break_ctl,
> +	.startup = tegra_tcu_uart_startup,
> +	.shutdown = tegra_tcu_uart_shutdown,
> +	.set_termios = tegra_tcu_uart_set_termios,
> +};
> +
> +static void tegra_tcu_console_write(struct console *cons, const char *s,
> +				    unsigned int count)
> +{
> +	tegra_tcu_write(s, count);
> +}
> +
> +static int tegra_tcu_console_setup(struct console *cons, char *options)
> +{
> +	if (!tegra_tcu_uart_port.private_data)
> +		return -ENODEV;
> +
> +	return uart_set_options(&tegra_tcu_uart_port, cons, 115200, 'n', 8, 'n');
> +}

I am curious if we actually need to call uart_set_options() here? Given that
set_termios does nothing, is this actually needed?

> +
> +static struct console tegra_tcu_console = {
> +	.name = "ttyTCU",
> +	.device = uart_console_device,
> +	.flags = CON_PRINTBUFFER | CON_ANYTIME,
> +	.index = -1,
> +	.write = tegra_tcu_console_write,
> +	.setup = tegra_tcu_console_setup,
> +	.data = &tegra_tcu_uart_driver,
> +};
> +
> +static struct uart_driver tegra_tcu_uart_driver = {
> +	.owner = THIS_MODULE,
> +	.driver_name = "tegra-tcu",
> +	.dev_name = "ttyTCU",
> +	.cons = &tegra_tcu_console,
> +	.nr = 1,
> +};
> +
> +static void tegra_tcu_receive(struct mbox_client *client, void *msg_p)
> +{
> +	struct tty_port *port = &tegra_tcu_uart_port.state->port;
> +	uint32_t msg = *(uint32_t *)msg_p;
> +	unsigned int num_bytes;
> +	int i;
> +
> +	num_bytes = TCU_MBOX_NUM_BYTES_V(msg);
> +	for (i = 0; i < num_bytes; i++)
> +		tty_insert_flip_char(port, TCU_MBOX_BYTE_V(msg, i), TTY_NORMAL);
> +
> +	tty_flip_buffer_push(port);
> +}
> +
> +static int tegra_tcu_probe(struct platform_device *pdev)
> +{
> +	struct uart_port *port = &tegra_tcu_uart_port;
> +	struct tegra_tcu *tcu;
> +	int err;
> +
> +	tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
> +	if (!tcu)
> +		return -ENOMEM;
> +
> +	tcu->tx_client.dev = &pdev->dev;
> +	tcu->rx_client.dev = &pdev->dev;
> +	tcu->rx_client.rx_callback = tegra_tcu_receive;
> +
> +	tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
> +	if (IS_ERR(tcu->tx)) {
> +		err = PTR_ERR(tcu->tx);
> +		dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
> +		return err;
> +	}
> +
> +	tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
> +	if (IS_ERR(tcu->rx)) {
> +		err = PTR_ERR(tcu->rx);
> +		dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
> +		goto free_tx;
> +	}
> +
> +	err = uart_register_driver(&tegra_tcu_uart_driver);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to register UART driver: %d\n",
> +			err);
> +		goto free_rx;
> +	}
> +
> +	spin_lock_init(&port->lock);
> +	port->dev = &pdev->dev;
> +	port->type = PORT_TEGRA_TCU;
> +	port->ops = &tegra_tcu_uart_ops;
> +	port->fifosize = 1;
> +	port->iotype = UPIO_MEM;
> +	port->flags = UPF_BOOT_AUTOCONF;
> +	port->private_data = tcu;
> +
> +	err = uart_add_one_port(&tegra_tcu_uart_driver, port);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
> +		goto unregister_uart;
> +	}
> +
> +	return 0;
> +
> +unregister_uart:
> +	uart_unregister_driver(&tegra_tcu_uart_driver);
> +free_rx:
> +	mbox_free_channel(tcu->rx);
> +free_tx:
> +	mbox_free_channel(tcu->tx);
> +
> +	return err;
> +}
> +
> +static int tegra_tcu_remove(struct platform_device *pdev)
> +{
> +	uart_remove_one_port(&tegra_tcu_uart_driver, &tegra_tcu_uart_port);
> +	uart_unregister_driver(&tegra_tcu_uart_driver);

mbox_free_channel()?

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id tegra_tcu_match[] = {
> +	{ .compatible = "nvidia,tegra194-tcu" },
> +	{ }
> +};
> +
> +static struct platform_driver tegra_tcu_driver = {
> +	.driver = {
> +		.name = "tegra-tcu",
> +		.of_match_table = tegra_tcu_match,
> +	},
> +	.probe = tegra_tcu_probe,
> +	.remove = tegra_tcu_remove,
> +};
> +
> +static int __init tegra_tcu_init(void)
> +{
> +	int err;
> +
> +	err = platform_driver_register(&tegra_tcu_driver);
> +	if (err)
> +		return err;
> +
> +	register_console(&tegra_tcu_console);
> +
> +	return 0;
> +}
> +module_init(tegra_tcu_init);
> +
> +static void __exit tegra_tcu_exit(void)
> +{
> +	unregister_console(&tegra_tcu_console);
> +	platform_driver_unregister(&tegra_tcu_driver);
> +}
> +module_exit(tegra_tcu_exit);
> +
> +MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index dce5f9dae121..69883c32cb98 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -79,6 +79,9 @@
>  /* Nuvoton UART */
>  #define PORT_NPCM	40
>  
> +/* NVIDIA Tegra Combined UART */
> +#define PORT_TEGRA_TCU	41
> +
>  /* Intel EG20 */
>  #define PORT_PCH_8LINE	44
>  #define PORT_PCH_2LINE	45
> 

Otherwise looks good to me.

Cheers
Jon

-- 
nvpublic

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

* [PATCH v2 6/8] serial: Add Tegra Combined UART driver
@ 2018-06-21  9:20     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  9:20 UTC (permalink / raw)
  To: linux-arm-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> The Tegra Combined UART (TCU) is a mailbox-based mechanism that allows
> multiplexing multiple "virtual UARTs" into a single hardware serial
> port. The TCU is the primary serial port on Tegra194 devices.
> 
> Add a TCU driver utilizing the mailbox framework, as the used mailboxes
> are part of Tegra HSP blocks that are already controlled by the Tegra
> HSP mailbox driver.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Removed (void) casts for unused variables.
>     - Changed the uart_set_options() call to be on one line, even if its
>       over 80 characters.
>     - Added defines for magic numbers.
>     - Style fixes.
>     - Changed Kconfig entry to depend on the Tegra HSP driver instead of
>       just the mailbox framework.
> 
>  drivers/tty/serial/Kconfig       |   9 ++
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/tegra-tcu.c   | 289 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 302 insertions(+)
>  create mode 100644 drivers/tty/serial/tegra-tcu.c
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index df8bd0c7b97d..5fdd336e8937 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -322,6 +322,15 @@ config SERIAL_TEGRA
>  	  are enabled). This driver uses the APB DMA to achieve higher baudrate
>  	  and better performance.
>  
> +config SERIAL_TEGRA_TCU
> +	tristate "NVIDIA Tegra Combined UART"
> +	depends on ARCH_TEGRA && TEGRA_HSP_MBOX
> +	select SERIAL_CORE
> +	help
> +	  Support for the mailbox-based TCU (Tegra Combined UART) serial port.
> +	  TCU is a virtual serial port that allows multiplexing multiple data
> +	  streams into a single hardware serial port.
> +
>  config SERIAL_MAX3100
>  	tristate "MAX3100 support"
>  	depends on SPI
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index daac675612df..4ad82231ff8a 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_SERIAL_LANTIQ)	+= lantiq.o
>  obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
>  obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
>  obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
> +obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
>  obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
>  obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
>  obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
> diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
> new file mode 100644
> index 000000000000..b54ebe2ad917
> --- /dev/null
> +++ b/drivers/tty/serial/tegra-tcu.c
> @@ -0,0 +1,289 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
> + */
> +
> +#include <linux/console.h>
> +#include <linux/mailbox_client.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/serial.h>
> +#include <linux/serial_core.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +
> +#define TCU_MBOX_BYTE(i, x)			((x) << (i*8))
> +#define TCU_MBOX_BYTE_V(x, i)			(((x) >> (i*8)) & 0xff)
> +#define TCU_MBOX_NUM_BYTES(x)			((x) << 24)
> +#define TCU_MBOX_NUM_BYTES_V(x)			(((x) >> 24) & 0x3)
> +#define TCU_MBOX_FLUSH				BIT(26)
> +
> +static struct uart_driver tegra_tcu_uart_driver;
> +static struct uart_port tegra_tcu_uart_port;
> +
> +struct tegra_tcu {
> +	struct mbox_client tx_client, rx_client;
> +	struct mbox_chan *tx, *rx;
> +};
> +
> +static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port)
> +{
> +	return TIOCSER_TEMT;
> +}
> +
> +static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +}
> +
> +static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void tegra_tcu_uart_stop_tx(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_write(const char *s, unsigned int count)
> +{
> +	struct tegra_tcu *tcu = tegra_tcu_uart_port.private_data;
> +	unsigned int written = 0, i = 0;
> +	bool insert_nl = false;
> +	uint32_t value = 0;
> +
> +	while (i < count) {
> +		if (insert_nl) {
> +			value |= TCU_MBOX_BYTE(written++, '\n');
> +			insert_nl = false;
> +			i++;
> +		} else if (s[i] == '\n') {
> +			value |= TCU_MBOX_BYTE(written++, '\r');
> +			insert_nl = true;
> +		} else {
> +			value |= TCU_MBOX_BYTE(written++, s[i++]);
> +		}
> +
> +		if (written == 3) {
> +			value |= TCU_MBOX_NUM_BYTES(3) | TCU_MBOX_FLUSH;
> +			mbox_send_message(tcu->tx, &value);
> +			value = 0;
> +			written = 0;
> +		}
> +	}
> +
> +	if (written) {
> +		value |= TCU_MBOX_NUM_BYTES(written) | TCU_MBOX_FLUSH;
> +		mbox_send_message(tcu->tx, &value);
> +	}
> +}
> +
> +static void tegra_tcu_uart_start_tx(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +	unsigned long count;
> +
> +	for (;;) {
> +		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
> +		if (!count)
> +			break;
> +
> +		tegra_tcu_write(&xmit->buf[xmit->tail], count);
> +		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
> +	}
> +
> +	uart_write_wakeup(port);
> +}
> +
> +static void tegra_tcu_uart_stop_rx(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl)
> +{
> +}
> +
> +static int tegra_tcu_uart_startup(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void tegra_tcu_uart_shutdown(struct uart_port *port)
> +{
> +}
> +
> +static void tegra_tcu_uart_set_termios(struct uart_port *port,
> +				       struct ktermios *new,
> +				       struct ktermios *old)
> +{
> +}
> +
> +static const struct uart_ops tegra_tcu_uart_ops = {
> +	.tx_empty = tegra_tcu_uart_tx_empty,
> +	.set_mctrl = tegra_tcu_uart_set_mctrl,
> +	.get_mctrl = tegra_tcu_uart_get_mctrl,
> +	.stop_tx = tegra_tcu_uart_stop_tx,
> +	.start_tx = tegra_tcu_uart_start_tx,
> +	.stop_rx = tegra_tcu_uart_stop_rx,
> +	.break_ctl = tegra_tcu_uart_break_ctl,
> +	.startup = tegra_tcu_uart_startup,
> +	.shutdown = tegra_tcu_uart_shutdown,
> +	.set_termios = tegra_tcu_uart_set_termios,
> +};
> +
> +static void tegra_tcu_console_write(struct console *cons, const char *s,
> +				    unsigned int count)
> +{
> +	tegra_tcu_write(s, count);
> +}
> +
> +static int tegra_tcu_console_setup(struct console *cons, char *options)
> +{
> +	if (!tegra_tcu_uart_port.private_data)
> +		return -ENODEV;
> +
> +	return uart_set_options(&tegra_tcu_uart_port, cons, 115200, 'n', 8, 'n');
> +}

I am curious if we actually need to call uart_set_options() here? Given that
set_termios does nothing, is this actually needed?

> +
> +static struct console tegra_tcu_console = {
> +	.name = "ttyTCU",
> +	.device = uart_console_device,
> +	.flags = CON_PRINTBUFFER | CON_ANYTIME,
> +	.index = -1,
> +	.write = tegra_tcu_console_write,
> +	.setup = tegra_tcu_console_setup,
> +	.data = &tegra_tcu_uart_driver,
> +};
> +
> +static struct uart_driver tegra_tcu_uart_driver = {
> +	.owner = THIS_MODULE,
> +	.driver_name = "tegra-tcu",
> +	.dev_name = "ttyTCU",
> +	.cons = &tegra_tcu_console,
> +	.nr = 1,
> +};
> +
> +static void tegra_tcu_receive(struct mbox_client *client, void *msg_p)
> +{
> +	struct tty_port *port = &tegra_tcu_uart_port.state->port;
> +	uint32_t msg = *(uint32_t *)msg_p;
> +	unsigned int num_bytes;
> +	int i;
> +
> +	num_bytes = TCU_MBOX_NUM_BYTES_V(msg);
> +	for (i = 0; i < num_bytes; i++)
> +		tty_insert_flip_char(port, TCU_MBOX_BYTE_V(msg, i), TTY_NORMAL);
> +
> +	tty_flip_buffer_push(port);
> +}
> +
> +static int tegra_tcu_probe(struct platform_device *pdev)
> +{
> +	struct uart_port *port = &tegra_tcu_uart_port;
> +	struct tegra_tcu *tcu;
> +	int err;
> +
> +	tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
> +	if (!tcu)
> +		return -ENOMEM;
> +
> +	tcu->tx_client.dev = &pdev->dev;
> +	tcu->rx_client.dev = &pdev->dev;
> +	tcu->rx_client.rx_callback = tegra_tcu_receive;
> +
> +	tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
> +	if (IS_ERR(tcu->tx)) {
> +		err = PTR_ERR(tcu->tx);
> +		dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
> +		return err;
> +	}
> +
> +	tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
> +	if (IS_ERR(tcu->rx)) {
> +		err = PTR_ERR(tcu->rx);
> +		dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
> +		goto free_tx;
> +	}
> +
> +	err = uart_register_driver(&tegra_tcu_uart_driver);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to register UART driver: %d\n",
> +			err);
> +		goto free_rx;
> +	}
> +
> +	spin_lock_init(&port->lock);
> +	port->dev = &pdev->dev;
> +	port->type = PORT_TEGRA_TCU;
> +	port->ops = &tegra_tcu_uart_ops;
> +	port->fifosize = 1;
> +	port->iotype = UPIO_MEM;
> +	port->flags = UPF_BOOT_AUTOCONF;
> +	port->private_data = tcu;
> +
> +	err = uart_add_one_port(&tegra_tcu_uart_driver, port);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
> +		goto unregister_uart;
> +	}
> +
> +	return 0;
> +
> +unregister_uart:
> +	uart_unregister_driver(&tegra_tcu_uart_driver);
> +free_rx:
> +	mbox_free_channel(tcu->rx);
> +free_tx:
> +	mbox_free_channel(tcu->tx);
> +
> +	return err;
> +}
> +
> +static int tegra_tcu_remove(struct platform_device *pdev)
> +{
> +	uart_remove_one_port(&tegra_tcu_uart_driver, &tegra_tcu_uart_port);
> +	uart_unregister_driver(&tegra_tcu_uart_driver);

mbox_free_channel()?

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id tegra_tcu_match[] = {
> +	{ .compatible = "nvidia,tegra194-tcu" },
> +	{ }
> +};
> +
> +static struct platform_driver tegra_tcu_driver = {
> +	.driver = {
> +		.name = "tegra-tcu",
> +		.of_match_table = tegra_tcu_match,
> +	},
> +	.probe = tegra_tcu_probe,
> +	.remove = tegra_tcu_remove,
> +};
> +
> +static int __init tegra_tcu_init(void)
> +{
> +	int err;
> +
> +	err = platform_driver_register(&tegra_tcu_driver);
> +	if (err)
> +		return err;
> +
> +	register_console(&tegra_tcu_console);
> +
> +	return 0;
> +}
> +module_init(tegra_tcu_init);
> +
> +static void __exit tegra_tcu_exit(void)
> +{
> +	unregister_console(&tegra_tcu_console);
> +	platform_driver_unregister(&tegra_tcu_driver);
> +}
> +module_exit(tegra_tcu_exit);
> +
> +MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index dce5f9dae121..69883c32cb98 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -79,6 +79,9 @@
>  /* Nuvoton UART */
>  #define PORT_NPCM	40
>  
> +/* NVIDIA Tegra Combined UART */
> +#define PORT_TEGRA_TCU	41
> +
>  /* Intel EG20 */
>  #define PORT_PCH_8LINE	44
>  #define PORT_PCH_2LINE	45
> 

Otherwise looks good to me.

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 7/8] arm64: tegra: Add nodes for tcu on Tegra194
  2018-06-20 12:20   ` Mikko Perttunen
  (?)
@ 2018-06-21  9:48     ` Jon Hunter
  -1 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  9:48 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> Add nodes required for communication through the Tegra Combined UART.
> This includes the AON HSP instance, addition of shared interrupts
> for the TOP0 HSP instance, and finally the TCU node itself. Also
> mark the HSP instances as compatible to tegra194-hsp, as the hardware
> is not identical but is compatible to tegra186-hsp.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
>  arch/arm64/boot/dts/nvidia/tegra194.dtsi | 34 +++++++++++++++++++++++++++++---
>  1 file changed, 31 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> index 6d699815a84f..d7f780b06fe2 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> @@ -217,10 +217,31 @@
>  		};
>  
>  		hsp_top0: hsp@3c00000 {
> -			compatible = "nvidia,tegra186-hsp";
> +			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
>  			reg = <0x03c00000 0xa0000>;
> -			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
> -			interrupt-names = "doorbell";
> +			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "doorbell", "shared0", "shared1", "shared2",
> +			                  "shared3", "shared4", "shared5", "shared6",
> +			                  "shared7";
> +			#mbox-cells = <2>;
> +		};
> +
> +		hsp_aon: hsp@c150000 {
> +			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
> +			reg = <0x0c150000 0xa0000>;
> +			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "shared0", "shared1", "shared2", "shared3";
>  			#mbox-cells = <2>;
>  		};
>  
> @@ -382,6 +403,13 @@
>  		};
>  	};
>  
> +	tcu: tcu {
> +		compatible = "nvidia,tegra194-tcu";
> +		mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
> +		         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
> +		mbox-names = "rx", "tx";
> +	};
> +
>  	timer {
>  		compatible = "arm,armv8-timer";
>  		interrupts = <GIC_PPI 13
> 

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 7/8] arm64: tegra: Add nodes for tcu on Tegra194
@ 2018-06-21  9:48     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  9:48 UTC (permalink / raw)
  To: Mikko Perttunen, robh+dt, mark.rutland, jassisinghbrar, gregkh,
	thierry.reding
  Cc: devicetree, linux-serial, linux-tegra, linux-arm-kernel, linux-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> Add nodes required for communication through the Tegra Combined UART.
> This includes the AON HSP instance, addition of shared interrupts
> for the TOP0 HSP instance, and finally the TCU node itself. Also
> mark the HSP instances as compatible to tegra194-hsp, as the hardware
> is not identical but is compatible to tegra186-hsp.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
>  arch/arm64/boot/dts/nvidia/tegra194.dtsi | 34 +++++++++++++++++++++++++++++---
>  1 file changed, 31 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> index 6d699815a84f..d7f780b06fe2 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> @@ -217,10 +217,31 @@
>  		};
>  
>  		hsp_top0: hsp@3c00000 {
> -			compatible = "nvidia,tegra186-hsp";
> +			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
>  			reg = <0x03c00000 0xa0000>;
> -			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
> -			interrupt-names = "doorbell";
> +			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "doorbell", "shared0", "shared1", "shared2",
> +			                  "shared3", "shared4", "shared5", "shared6",
> +			                  "shared7";
> +			#mbox-cells = <2>;
> +		};
> +
> +		hsp_aon: hsp@c150000 {
> +			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
> +			reg = <0x0c150000 0xa0000>;
> +			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "shared0", "shared1", "shared2", "shared3";
>  			#mbox-cells = <2>;
>  		};
>  
> @@ -382,6 +403,13 @@
>  		};
>  	};
>  
> +	tcu: tcu {
> +		compatible = "nvidia,tegra194-tcu";
> +		mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
> +		         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
> +		mbox-names = "rx", "tx";
> +	};
> +
>  	timer {
>  		compatible = "arm,armv8-timer";
>  		interrupts = <GIC_PPI 13
> 

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* [PATCH v2 7/8] arm64: tegra: Add nodes for tcu on Tegra194
@ 2018-06-21  9:48     ` Jon Hunter
  0 siblings, 0 replies; 47+ messages in thread
From: Jon Hunter @ 2018-06-21  9:48 UTC (permalink / raw)
  To: linux-arm-kernel


On 20/06/18 13:20, Mikko Perttunen wrote:
> Add nodes required for communication through the Tegra Combined UART.
> This includes the AON HSP instance, addition of shared interrupts
> for the TOP0 HSP instance, and finally the TCU node itself. Also
> mark the HSP instances as compatible to tegra194-hsp, as the hardware
> is not identical but is compatible to tegra186-hsp.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
>  arch/arm64/boot/dts/nvidia/tegra194.dtsi | 34 +++++++++++++++++++++++++++++---
>  1 file changed, 31 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> index 6d699815a84f..d7f780b06fe2 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
> @@ -217,10 +217,31 @@
>  		};
>  
>  		hsp_top0: hsp at 3c00000 {
> -			compatible = "nvidia,tegra186-hsp";
> +			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
>  			reg = <0x03c00000 0xa0000>;
> -			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
> -			interrupt-names = "doorbell";
> +			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "doorbell", "shared0", "shared1", "shared2",
> +			                  "shared3", "shared4", "shared5", "shared6",
> +			                  "shared7";
> +			#mbox-cells = <2>;
> +		};
> +
> +		hsp_aon: hsp at c150000 {
> +			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
> +			reg = <0x0c150000 0xa0000>;
> +			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
> +			             <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "shared0", "shared1", "shared2", "shared3";
>  			#mbox-cells = <2>;
>  		};
>  
> @@ -382,6 +403,13 @@
>  		};
>  	};
>  
> +	tcu: tcu {
> +		compatible = "nvidia,tegra194-tcu";
> +		mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>,
> +		         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>;
> +		mbox-names = "rx", "tx";
> +	};
> +
>  	timer {
>  		compatible = "arm,armv8-timer";
>  		interrupts = <GIC_PPI 13
> 

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
  2018-06-20 12:20   ` Mikko Perttunen
@ 2018-06-25 19:07     ` Rob Herring
  -1 siblings, 0 replies; 47+ messages in thread
From: Rob Herring @ 2018-06-25 19:07 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: mark.rutland, jassisinghbrar, gregkh, thierry.reding, jonathanh,
	devicetree, linux-serial, linux-tegra, linux-arm-kernel,
	linux-kernel

On Wed, Jun 20, 2018 at 03:20:35PM +0300, Mikko Perttunen wrote:
> HSP interrupts can be routed through exposed "shared interrupts". These
> interrupts can be mapped to various internal interrupt lines. Add
> interrupt properties for shared interrupts to the tegra186-hsp device
> tree bindings. At the same time, add the compatibility string for
> tegra194-hsp, which is backwards compatible with tegra186.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Edited commit message to not say that doorbell interrupts cannot be
>       routed to shared interrupts.
>     - Added tegra194 compatibility string.
> 
>  Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
>  1 file changed, 3 insertions(+)

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

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

* [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts
@ 2018-06-25 19:07     ` Rob Herring
  0 siblings, 0 replies; 47+ messages in thread
From: Rob Herring @ 2018-06-25 19:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 20, 2018 at 03:20:35PM +0300, Mikko Perttunen wrote:
> HSP interrupts can be routed through exposed "shared interrupts". These
> interrupts can be mapped to various internal interrupt lines. Add
> interrupt properties for shared interrupts to the tegra186-hsp device
> tree bindings. At the same time, add the compatibility string for
> tegra194-hsp, which is backwards compatible with tegra186.
> 
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> 
> Notes:
>     v2:
>     - Edited commit message to not say that doorbell interrupts cannot be
>       routed to shared interrupts.
>     - Added tegra194 compatibility string.
> 
>  Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 3 +++
>  1 file changed, 3 insertions(+)

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

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

end of thread, other threads:[~2018-06-25 19:07 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-20 12:20 [PATCH v2 0/8] Tegra Combined UART driver Mikko Perttunen
2018-06-20 12:20 ` Mikko Perttunen
2018-06-20 12:20 ` Mikko Perttunen
2018-06-20 12:20 ` [PATCH v2 1/8] dt-bindings: tegra186-hsp: Add shared interrupts Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-21  8:05   ` Jon Hunter
2018-06-21  8:05     ` Jon Hunter
2018-06-21  8:05     ` Jon Hunter
2018-06-25 19:07   ` Rob Herring
2018-06-25 19:07     ` Rob Herring
2018-06-20 12:20 ` [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia, tegra194-tcu Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` [PATCH v2 2/8] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu Mikko Perttunen
2018-06-21  8:05   ` Jon Hunter
2018-06-21  8:05     ` Jon Hunter
2018-06-21  8:05     ` Jon Hunter
2018-06-20 12:20 ` [PATCH v2 3/8] mailbox: Add transmit done by blocking option Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20 ` [PATCH v2 4/8] mailbox: tegra-hsp: Refactor in preparation of mailboxes Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-21  8:13   ` Jon Hunter
2018-06-21  8:13     ` Jon Hunter
2018-06-21  8:13     ` Jon Hunter
2018-06-20 12:20 ` [PATCH v2 5/8] mailbox: tegra-hsp: Add support for shared mailboxes Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-21  8:29   ` Jon Hunter
2018-06-21  8:29     ` Jon Hunter
2018-06-21  8:29     ` Jon Hunter
2018-06-20 12:20 ` [PATCH v2 6/8] serial: Add Tegra Combined UART driver Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-21  9:20   ` Jon Hunter
2018-06-21  9:20     ` Jon Hunter
2018-06-21  9:20     ` Jon Hunter
2018-06-20 12:20 ` [PATCH v2 7/8] arm64: tegra: Add nodes for tcu on Tegra194 Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-21  9:48   ` Jon Hunter
2018-06-21  9:48     ` Jon Hunter
2018-06-21  9:48     ` Jon Hunter
2018-06-20 12:20 ` [PATCH v2 8/8] arm64: tegra: Mark tcu as primary serial port on Tegra194 P2888 Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen
2018-06-20 12:20   ` Mikko Perttunen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.