devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/12] serial: Add Tegra Combined UART driver
@ 2018-11-28  9:54 Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 01/12] mailbox: Support blocking transfers in atomic context Thierry Reding
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Thierry Reding <treding@nvidia.com>

Hi everyone,

this is a reworked version of Mikko's earlier proposal[0]. I've reworked
the TCU driver itself so that it relies less on global variables as well
as added a Kconfig option to allow the console support to be selected. I
also fixed a couple of issues that manifested themselves as I was moving
towards the IRQ driven mode (TCU was passing a pointer to a local
variable which was getting stored in the mailbox's ring buffer and the
data pointed at was becoming stale by the time the mailbox got around to
dequeue it).

The biggest bulk of the changes is in the mailbox driver. This series
addresses all of Jassi's comments from back at the time. One notable
additional change is that shared mailboxes are now interrupt driven,
which removes the need for polling mode.

Unfortunately there is still an issue because the TCU uses the mailbox
in atomic context for both TTY and console modes, so we get a sleeping-
while-atomic BUG when using mbox_client->tx_block = true in order to
rate-limit mbox_send_message(). In order to work around this, I added a
new mbox_flush() API that will allow flushing the mailbox in atomic
context by using the mailbox controller's implementation of ->flush().
For Tegra HSP shared mailboxes this is done by spinning on the shared
mailbox register until the receiver has marked the mailbox as empty. I
have been running this locally for a couple of days now and it works
perfectly.

Furthermore this series incorporates Mikko's work in progress on
splitting up the mailbox controllers and allowing multiple controllers
to match on the same device tree node during mbox_request_channel().

The new mbox_flush() API introduces a build-time dependency between the
TCU driver and the mailbox framework, so patches 1-9 would need to go
through one tree. Patch 9 was already acked by Greg, so I would suggest
that Jassi pick up the first 9 patches and I pick up patches 10-12 into
the Tegra tree.

Changes in v3:
- add a patch from Bartosz Golaszewski to use devm_kstrdup_const()
- add a patch to use device-managed registration to simplify code
- introduce explicit mailbox flush API

Changes in v2:
- address all of Pekka's comments regarding shared interrupts, registers
  that don't exist on Tegra186 and shared mailbox directionality
- add a patch to enable the TCU in the 64-bit ARM default configuration

Thanks,
Thierry

[0]: https://lore.kernel.org/patchwork/project/lkml/list/?series=357641

Bartosz Golaszewski (1):
  mailbox: tegra-hsp: use devm_kstrdup_const()

Mikko Perttunen (5):
  mailbox: Allow multiple controllers per device
  dt-bindings: tegra186-hsp: Add shared mailboxes
  dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
  arm64: tegra: Add nodes for TCU on Tegra194
  arm64: tegra: Mark TCU as primary serial port on Tegra194 P2888

Thierry Reding (6):
  mailbox: Support blocking transfers in atomic context
  mailbox: tegra-hsp: Add support for shared mailboxes
  mailbox: tegra-hsp: Add suspend/resume support
  mailbox: tegra-hsp: Use device-managed registration API
  serial: Add Tegra Combined UART driver
  arm64: defconfig: Enable Tegra TCU

 .../bindings/mailbox/nvidia,tegra186-hsp.txt  |  30 +-
 .../bindings/serial/nvidia,tegra194-tcu.txt   |  35 ++
 .../arm64/boot/dts/nvidia/tegra194-p2888.dtsi |   2 +-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi      |  38 +-
 arch/arm64/configs/defconfig                  |   1 +
 drivers/mailbox/mailbox.c                     |  31 +-
 drivers/mailbox/tegra-hsp.c                   | 517 +++++++++++++++---
 drivers/tty/serial/Kconfig                    |  22 +
 drivers/tty/serial/Makefile                   |   1 +
 drivers/tty/serial/tegra-tcu.c                | 298 ++++++++++
 include/dt-bindings/mailbox/tegra186-hsp.h    |  11 +
 include/linux/mailbox_client.h                |   1 +
 include/linux/mailbox_controller.h            |   4 +
 include/uapi/linux/serial_core.h              |   3 +
 14 files changed, 903 insertions(+), 91 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
 create mode 100644 drivers/tty/serial/tegra-tcu.c

-- 
2.19.1

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

* [PATCH v3 01/12] mailbox: Support blocking transfers in atomic context
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 02/12] mailbox: Allow multiple controllers per device Thierry Reding
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Thierry Reding <treding@nvidia.com>

The mailbox framework supports blocking transfers via completions for
clients that can sleep. In order to support blocking transfers in cases
where the transmission is not permitted to sleep, add a new ->flush()
callback that controller drivers can implement to busy loop until the
transmission has been completed. A new mbox_flush() function can be
called by mailbox consumers in atomic context to make sure a transfer
has completed.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v3:
- add explicit mailbox flush API
---
 drivers/mailbox/mailbox.c          | 28 ++++++++++++++++++++++++++++
 include/linux/mailbox_client.h     |  1 +
 include/linux/mailbox_controller.h |  4 ++++
 3 files changed, 33 insertions(+)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index eb781e2b19cb..044e24804767 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -283,6 +283,34 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
 }
 EXPORT_SYMBOL_GPL(mbox_send_message);
 
+/**
+ * mbox_flush - flush a mailbox channel
+ * @chan: mailbox channel to flush
+ * @timeout: time, in milliseconds, to allow the flush operation to succeed
+ *
+ * Mailbox controllers that need to work in atomic context can implement the
+ * ->flush() callback to busy loop until a transmission has been completed.
+ * The implementation must call mbox_chan_txdone() upon success. Clients can
+ * call the mbox_flush() function at any time after mbox_send_message() to
+ * flush the transmission. After the function returns success, the mailbox
+ * transmission is guaranteed to have completed.
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+int mbox_flush(struct mbox_chan *chan, unsigned long timeout)
+{
+	int ret;
+
+	if (!chan->mbox->ops->flush)
+		return -ENOTSUPP;
+
+	ret = chan->mbox->ops->flush(chan, timeout);
+	if (ret < 0)
+		tx_tick(chan, ret);
+
+	return ret;
+}
+
 /**
  * mbox_request_channel - Request a mailbox channel.
  * @cl: Identity of the client requesting the channel.
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
index 44348710953f..faa7da3c9c8b 100644
--- a/include/linux/mailbox_client.h
+++ b/include/linux/mailbox_client.h
@@ -44,6 +44,7 @@ struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
 					      const char *name);
 struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);
 int mbox_send_message(struct mbox_chan *chan, void *mssg);
+int mbox_flush(struct mbox_chan *chan, unsigned long timeout);
 void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */
 bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */
 void mbox_free_channel(struct mbox_chan *chan); /* may sleep */
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 9b0b21207345..4994a438444c 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -24,6 +24,9 @@ struct mbox_chan;
  *		transmission of data is reported by the controller via
  *		mbox_chan_txdone (if it has some TX ACK irq). It must not
  *		sleep.
+ * @flush:	Called when a client requests transmissions to be blocking but
+ *		the context doesn't allow sleeping. Typically the controller
+ *		will implement a busy loop waiting for the data to flush out.
  * @startup:	Called when a client requests the chan. The controller
  *		could ask clients for additional parameters of communication
  *		to be provided via client's chan_data. This call may
@@ -46,6 +49,7 @@ struct mbox_chan;
  */
 struct mbox_chan_ops {
 	int (*send_data)(struct mbox_chan *chan, void *data);
+	int (*flush)(struct mbox_chan *chan, unsigned long timeout);
 	int (*startup)(struct mbox_chan *chan);
 	void (*shutdown)(struct mbox_chan *chan);
 	bool (*last_tx_done)(struct mbox_chan *chan);
-- 
2.19.1

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

* [PATCH v3 02/12] mailbox: Allow multiple controllers per device
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 01/12] mailbox: Support blocking transfers in atomic context Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 03/12] dt-bindings: tegra186-hsp: Add shared mailboxes Thierry Reding
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Mikko Perttunen <mperttunen@nvidia.com>

Look through the whole controller list when mapping device tree
phandles to controllers instead of stopping at the first one.

Each controller is intended to only contain one kind of mailbox,
but some devices (like Tegra HSP) implement multiple kinds and use
the same device tree node for all of them. As such, we need to allow
multiple mbox_controllers per device tree node.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
---
 drivers/mailbox/mailbox.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 044e24804767..fbdcc82a61ae 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -355,7 +355,8 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
 	list_for_each_entry(mbox, &mbox_cons, node)
 		if (mbox->dev->of_node == spec.np) {
 			chan = mbox->of_xlate(mbox, &spec);
-			break;
+			if (!IS_ERR(chan))
+				break;
 		}
 
 	of_node_put(spec.np);
-- 
2.19.1

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

* [PATCH v3 03/12] dt-bindings: tegra186-hsp: Add shared mailboxes
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 01/12] mailbox: Support blocking transfers in atomic context Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 02/12] mailbox: Allow multiple controllers per device Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 04/12] mailbox: tegra-hsp: Add support for " Thierry Reding
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Mikko Perttunen <mperttunen@nvidia.com>

Shared mailboxes are a mechanism to transport data from one processor in
the system to another. They are bidirectional links with both a producer
and a consumer. Interrupts are used to let the consumer know when data
was written to the mailbox by the producer, and to let the producer know
when the consumer has read the data from the mailbox. These interrupts
are mapped to one or more "shared interrupts". Typically each processor
in the system owns one of these shared interrupts.

Add documentation to the device tree bindings about how clients can use
mailbox specifiers to request a specific shared mailbox and select which
direction they drive. Also document how to specify the shared interrupts
in addition to the existing doorbell interrupt.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- describe in more detail how the mailbox specifiers are constructed
- encode mailbox direction in the device tree mailbox specifier
---
 .../bindings/mailbox/nvidia,tegra186-hsp.txt  | 30 +++++++++++++++----
 include/dt-bindings/mailbox/tegra186-hsp.h    | 11 +++++++
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
index b99d25fc2f26..ff3eafc5a882 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
@@ -29,12 +32,29 @@ Required properties:
     in a matching order.
 - #mbox-cells : Should be 2.
 
-The mbox specifier of the "mboxes" property in the client node should
-contain two data. The first one should be the HSP type and the second
-one should be the ID that the client is going to use. Those information
-can be found in the following file.
+The mbox specifier of the "mboxes" property in the client node should contain
+two cells. The first cell determines the HSP type and the second cell is used
+to identify the mailbox that the client is going to use.
 
-- <dt-bindings/mailbox/tegra186-hsp.h>.
+For doorbells, the second cell specifies the index of the doorbell to use.
+
+For shared mailboxes, the second cell is composed of two fields:
+- bits 31..24:
+    A bit mask of flags that further specify how the shared mailbox will be
+    used. Valid flags are:
+    - bit 31:
+        Defines the direction of the mailbox. If set, the mailbox will be used
+        as a producer (i.e. used to send data). If cleared, the mailbox is the
+        consumer of data sent by a producer.
+
+- bits 23.. 0:
+    The index of the shared mailbox to use. The number of available mailboxes
+    may vary by instance of the HSP block and SoC generation.
+
+The following file contains definitions that can be used to construct mailbox
+specifiers:
+
+    <dt-bindings/mailbox/tegra186-hsp.h>
 
 Example:
 
diff --git a/include/dt-bindings/mailbox/tegra186-hsp.h b/include/dt-bindings/mailbox/tegra186-hsp.h
index bcab5b7ca785..3bdec7a84d35 100644
--- a/include/dt-bindings/mailbox/tegra186-hsp.h
+++ b/include/dt-bindings/mailbox/tegra186-hsp.h
@@ -22,4 +22,15 @@
 #define TEGRA_HSP_DB_MASTER_CCPLEX 17
 #define TEGRA_HSP_DB_MASTER_BPMP 19
 
+/*
+ * Shared mailboxes are unidirectional, so the direction needs to be specified
+ * in the device tree.
+ */
+#define TEGRA_HSP_SM_MASK 0x00ffffff
+#define TEGRA_HSP_SM_FLAG_RX (0 << 31)
+#define TEGRA_HSP_SM_FLAG_TX (1 << 31)
+
+#define TEGRA_HSP_SM_RX(x) (TEGRA_HSP_SM_FLAG_RX | ((x) & TEGRA_HSP_SM_MASK))
+#define TEGRA_HSP_SM_TX(x) (TEGRA_HSP_SM_FLAG_TX | ((x) & TEGRA_HSP_SM_MASK))
+
 #endif
-- 
2.19.1

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

* [PATCH v3 04/12] mailbox: tegra-hsp: Add support for shared mailboxes
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (2 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 03/12] dt-bindings: tegra186-hsp: Add shared mailboxes Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 05/12] mailbox: tegra-hsp: Add suspend/resume support Thierry Reding
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Thierry Reding <treding@nvidia.com>

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.

Based on work by Mikko Perttunen <mperttunen@nvidia.com>.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v3:
- update for explicit mailbox flushing

Changes in v2:
- do not write per-mailbox interrupt enable registers on Tegra186
- merge handlers for empty and full interrupts
- track direction of shared mailboxes
---
 drivers/mailbox/tegra-hsp.c | 504 +++++++++++++++++++++++++++++++-----
 1 file changed, 443 insertions(+), 61 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 0cde356c11ab..a4ec18d76cba 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,
@@ -11,6 +11,7 @@
  * more details.
  */
 
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mailbox_controller.h>
@@ -21,6 +22,17 @@
 
 #include <dt-bindings/mailbox/tegra186-hsp.h>
 
+#include "mailbox.h"
+
+#define HSP_INT_IE(x)		(0x100 + ((x) * 4))
+#define HSP_INT_IV		0x300
+#define HSP_INT_IR		0x304
+
+#define HSP_INT_EMPTY_SHIFT	0
+#define HSP_INT_EMPTY_MASK	0xff
+#define HSP_INT_FULL_SHIFT	8
+#define HSP_INT_FULL_MASK	0xff
+
 #define HSP_INT_DIMENSIONING	0x380
 #define HSP_nSM_SHIFT		0
 #define HSP_nSS_SHIFT		4
@@ -34,6 +46,11 @@
 #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_SM_SHRD_MBOX_FULL_INT_IE	0x04
+#define HSP_SM_SHRD_MBOX_EMPTY_INT_IE	0x08
+
 #define HSP_DB_CCPLEX		1
 #define HSP_DB_BPMP		3
 #define HSP_DB_MAX		7
@@ -55,6 +72,12 @@ struct tegra_hsp_doorbell {
 	unsigned int index;
 };
 
+struct tegra_hsp_mailbox {
+	struct tegra_hsp_channel channel;
+	unsigned int index;
+	bool producer;
+};
+
 struct tegra_hsp_db_map {
 	const char *name;
 	unsigned int master;
@@ -63,13 +86,18 @@ struct tegra_hsp_db_map {
 
 struct tegra_hsp_soc {
 	const struct tegra_hsp_db_map *map;
+	bool has_per_mb_ie;
 };
 
 struct tegra_hsp {
+	struct device *dev;
 	const struct tegra_hsp_soc *soc;
-	struct mbox_controller mbox;
+	struct mbox_controller mbox_db;
+	struct mbox_controller mbox_sm;
 	void __iomem *regs;
-	unsigned int irq;
+	unsigned int doorbell_irq;
+	unsigned int *shared_irqs;
+	unsigned int shared_irq;
 	unsigned int num_sm;
 	unsigned int num_as;
 	unsigned int num_ss;
@@ -78,13 +106,10 @@ struct tegra_hsp {
 	spinlock_t lock;
 
 	struct list_head doorbells;
-};
+	struct tegra_hsp_mailbox *mailboxes;
 
-static inline struct tegra_hsp *
-to_tegra_hsp(struct mbox_controller *mbox)
-{
-	return container_of(mbox, struct tegra_hsp, mbox);
-}
+	unsigned long mask;
+};
 
 static inline u32 tegra_hsp_readl(struct tegra_hsp *hsp, unsigned int offset)
 {
@@ -158,7 +183,7 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
 
 	spin_lock(&hsp->lock);
 
-	for_each_set_bit(master, &value, hsp->mbox.num_chans) {
+	for_each_set_bit(master, &value, hsp->mbox_db.num_chans) {
 		struct tegra_hsp_doorbell *db;
 
 		db = __tegra_hsp_doorbell_get(hsp, master);
@@ -182,6 +207,71 @@ 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 *hsp = data;
+	unsigned long bit, mask;
+	u32 status, value;
+	void *msg;
+
+	status = tegra_hsp_readl(hsp, HSP_INT_IR) & hsp->mask;
+
+	/* process EMPTY interrupts first */
+	mask = (status >> HSP_INT_EMPTY_SHIFT) & HSP_INT_EMPTY_MASK;
+
+	for_each_set_bit(bit, &mask, hsp->num_sm) {
+		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[bit];
+
+		if (mb->producer) {
+			/*
+			 * Disable EMPTY interrupts until data is sent with
+			 * the next message. These interrupts are level-
+			 * triggered, so if we kept them enabled they would
+			 * constantly trigger until we next write data into
+			 * the message.
+			 */
+			spin_lock(&hsp->lock);
+
+			hsp->mask &= ~BIT(HSP_INT_EMPTY_SHIFT + mb->index);
+			tegra_hsp_writel(hsp, hsp->mask,
+					 HSP_INT_IE(hsp->shared_irq));
+
+			spin_unlock(&hsp->lock);
+
+			mbox_chan_txdone(mb->channel.chan, 0);
+		}
+	}
+
+	/* process FULL interrupts */
+	mask = (status >> HSP_INT_FULL_SHIFT) & HSP_INT_FULL_MASK;
+
+	for_each_set_bit(bit, &mask, hsp->num_sm) {
+		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[bit];
+
+		if (!mb->producer) {
+			value = tegra_hsp_channel_readl(&mb->channel,
+							HSP_SM_SHRD_MBOX);
+			value &= ~HSP_SM_SHRD_MBOX_FULL;
+			msg = (void *)(unsigned long)value;
+			mbox_chan_received_data(mb->channel.chan, msg);
+
+			/*
+			 * Need to clear all bits here since some producers,
+			 * such as TCU, depend on fields in the register
+			 * getting cleared by the consumer.
+			 *
+			 * The mailbox API doesn't give the consumers a way
+			 * of doing that explicitly, so we have to make sure
+			 * we cover all possible cases.
+			 */
+			tegra_hsp_channel_writel(&mb->channel, 0x0,
+						 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)
@@ -194,7 +284,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;
@@ -235,8 +325,8 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
 	unsigned long flags;
 	u32 value;
 
-	if (db->master >= hsp->mbox.num_chans) {
-		dev_err(hsp->mbox.dev,
+	if (db->master >= chan->mbox->num_chans) {
+		dev_err(chan->mbox->dev,
 			"invalid master ID %u for HSP channel\n",
 			db->master);
 		return -EINVAL;
@@ -281,46 +371,167 @@ 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 = {
+static const struct mbox_chan_ops tegra_hsp_db_ops = {
 	.send_data = tegra_hsp_doorbell_send_data,
 	.startup = tegra_hsp_doorbell_startup,
 	.shutdown = tegra_hsp_doorbell_shutdown,
 };
 
-static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
+static int tegra_hsp_mailbox_send_data(struct mbox_chan *chan, void *data)
+{
+	struct tegra_hsp_mailbox *mb = chan->con_priv;
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	unsigned long flags;
+	u32 value;
+
+	if (WARN_ON(!mb->producer))
+		return -EPERM;
+
+	/* copy data and mark mailbox full */
+	value = (u32)(unsigned long)data;
+	value |= HSP_SM_SHRD_MBOX_FULL;
+
+	tegra_hsp_channel_writel(&mb->channel, value, HSP_SM_SHRD_MBOX);
+
+	/* enable EMPTY interrupt for the shared mailbox */
+	spin_lock_irqsave(&hsp->lock, flags);
+
+	hsp->mask |= BIT(HSP_INT_EMPTY_SHIFT + mb->index);
+	tegra_hsp_writel(hsp, hsp->mask, HSP_INT_IE(hsp->shared_irq));
+
+	spin_unlock_irqrestore(&hsp->lock, flags);
+
+	return 0;
+}
+
+static int tegra_hsp_mailbox_flush(struct mbox_chan *chan,
+				   unsigned long timeout)
+{
+	struct tegra_hsp_mailbox *mb = chan->con_priv;
+	struct tegra_hsp_channel *ch = &mb->channel;
+	u32 value;
+
+	timeout = jiffies + msecs_to_jiffies(timeout);
+
+	while (time_before(jiffies, timeout)) {
+		value = tegra_hsp_channel_readl(ch, HSP_SM_SHRD_MBOX);
+		if ((value & HSP_SM_SHRD_MBOX_FULL) == 0) {
+			mbox_chan_txdone(chan, 0);
+			return 0;
+		}
+
+		udelay(1);
+	}
+
+	return -ETIME;
+}
+
+static int tegra_hsp_mailbox_startup(struct mbox_chan *chan)
+{
+	struct tegra_hsp_mailbox *mb = chan->con_priv;
+	struct tegra_hsp_channel *ch = &mb->channel;
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	unsigned long flags;
+
+	chan->txdone_method = TXDONE_BY_IRQ;
+
+	/*
+	 * Shared mailboxes start out as consumers by default. FULL and EMPTY
+	 * interrupts are coalesced at the same shared interrupt.
+	 *
+	 * Keep EMPTY interrupts disabled at startup and only enable them when
+	 * the mailbox is actually full. This is required because the FULL and
+	 * EMPTY interrupts are level-triggered, so keeping EMPTY interrupts
+	 * enabled all the time would cause an interrupt storm while mailboxes
+	 * are idle.
+	 */
+
+	spin_lock_irqsave(&hsp->lock, flags);
+
+	if (mb->producer)
+		hsp->mask &= ~BIT(HSP_INT_EMPTY_SHIFT + mb->index);
+	else
+		hsp->mask |= BIT(HSP_INT_FULL_SHIFT + mb->index);
+
+	tegra_hsp_writel(hsp, hsp->mask, HSP_INT_IE(hsp->shared_irq));
+
+	spin_unlock_irqrestore(&hsp->lock, flags);
+
+	if (hsp->soc->has_per_mb_ie) {
+		if (mb->producer)
+			tegra_hsp_channel_writel(ch, 0x0,
+						 HSP_SM_SHRD_MBOX_EMPTY_INT_IE);
+		else
+			tegra_hsp_channel_writel(ch, 0x1,
+						 HSP_SM_SHRD_MBOX_FULL_INT_IE);
+	}
+
+	return 0;
+}
+
+static void tegra_hsp_mailbox_shutdown(struct mbox_chan *chan)
+{
+	struct tegra_hsp_mailbox *mb = chan->con_priv;
+	struct tegra_hsp_channel *ch = &mb->channel;
+	struct tegra_hsp *hsp = mb->channel.hsp;
+	unsigned long flags;
+
+	if (hsp->soc->has_per_mb_ie) {
+		if (mb->producer)
+			tegra_hsp_channel_writel(ch, 0x0,
+						 HSP_SM_SHRD_MBOX_EMPTY_INT_IE);
+		else
+			tegra_hsp_channel_writel(ch, 0x0,
+						 HSP_SM_SHRD_MBOX_FULL_INT_IE);
+	}
+
+	spin_lock_irqsave(&hsp->lock, flags);
+
+	if (mb->producer)
+		hsp->mask &= ~BIT(HSP_INT_EMPTY_SHIFT + mb->index);
+	else
+		hsp->mask &= ~BIT(HSP_INT_FULL_SHIFT + mb->index);
+
+	tegra_hsp_writel(hsp, hsp->mask, HSP_INT_IE(hsp->shared_irq));
+
+	spin_unlock_irqrestore(&hsp->lock, flags);
+}
+
+static const struct mbox_chan_ops tegra_hsp_sm_ops = {
+	.send_data = tegra_hsp_mailbox_send_data,
+	.flush = tegra_hsp_mailbox_flush,
+	.startup = tegra_hsp_mailbox_startup,
+	.shutdown = tegra_hsp_mailbox_shutdown,
+};
+
+static struct mbox_chan *tegra_hsp_db_xlate(struct mbox_controller *mbox,
 					    const struct of_phandle_args *args)
 {
+	struct tegra_hsp *hsp = container_of(mbox, struct tegra_hsp, mbox_db);
+	unsigned int type = args->args[0], master = args->args[1];
 	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;
+	if (type != TEGRA_HSP_MBOX_TYPE_DB || !hsp->doorbell_irq)
+		return ERR_PTR(-ENODEV);
 
-	default:
-		break;
-	}
+	db = tegra_hsp_doorbell_get(hsp, master);
+	if (db)
+		channel = &db->channel;
 
 	if (IS_ERR(channel))
 		return ERR_CAST(channel);
 
 	spin_lock_irqsave(&hsp->lock, flags);
 
-	for (i = 0; i < hsp->mbox.num_chans; i++) {
-		chan = &hsp->mbox.chans[i];
+	for (i = 0; i < mbox->num_chans; i++) {
+		chan = &mbox->chans[i];
 		if (!chan->con_priv) {
-			chan->con_priv = channel;
 			channel->chan = chan;
+			chan->con_priv = db;
 			break;
 		}
 
@@ -332,6 +543,29 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
 	return chan ?: ERR_PTR(-EBUSY);
 }
 
+static struct mbox_chan *tegra_hsp_sm_xlate(struct mbox_controller *mbox,
+					    const struct of_phandle_args *args)
+{
+	struct tegra_hsp *hsp = container_of(mbox, struct tegra_hsp, mbox_sm);
+	unsigned int type = args->args[0], index;
+	struct tegra_hsp_mailbox *mb;
+
+	index = args->args[1] & TEGRA_HSP_SM_MASK;
+
+	if (type != TEGRA_HSP_MBOX_TYPE_SM || !hsp->shared_irqs ||
+	    index >= hsp->num_sm)
+		return ERR_PTR(-ENODEV);
+
+	mb = &hsp->mailboxes[index];
+
+	if ((args->args[1] & TEGRA_HSP_SM_FLAG_TX) == 0)
+		mb->producer = false;
+	else
+		mb->producer = true;
+
+	return mb->channel.chan;
+}
+
 static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
 {
 	struct tegra_hsp_doorbell *db, *tmp;
@@ -364,10 +598,70 @@ 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->channel.hsp = hsp;
+		mb->channel.regs = hsp->regs + SZ_64K + i * SZ_32K;
+		mb->channel.chan = &hsp->mbox_sm.chans[i];
+		mb->channel.chan->con_priv = mb;
+	}
+
+	return 0;
+}
+
+static int tegra_hsp_request_shared_irq(struct tegra_hsp *hsp)
+{
+	unsigned int i, irq = 0;
+	int err;
+
+	for (i = 0; i < hsp->num_si; i++) {
+		irq = hsp->shared_irqs[i];
+		if (irq <= 0)
+			continue;
+
+		err = devm_request_irq(hsp->dev, irq, tegra_hsp_shared_irq, 0,
+				       dev_name(hsp->dev), hsp);
+		if (err < 0) {
+			dev_err(hsp->dev, "failed to request interrupt: %d\n",
+				err);
+			continue;
+		}
+
+		hsp->shared_irq = i;
+
+		/* disable all interrupts */
+		tegra_hsp_writel(hsp, 0, HSP_INT_IE(hsp->shared_irq));
+
+		dev_dbg(hsp->dev, "interrupt requested: %u\n", irq);
+
+		break;
+	}
+
+	if (i == hsp->num_si) {
+		dev_err(hsp->dev, "failed to find available interrupt\n");
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
 static int tegra_hsp_probe(struct platform_device *pdev)
 {
 	struct tegra_hsp *hsp;
 	struct resource *res;
+	unsigned int i;
 	u32 value;
 	int err;
 
@@ -375,6 +669,7 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	if (!hsp)
 		return -ENOMEM;
 
+	hsp->dev = &pdev->dev;
 	hsp->soc = of_device_get_match_data(&pdev->dev);
 	INIT_LIST_HEAD(&hsp->doorbells);
 	spin_lock_init(&hsp->lock);
@@ -392,58 +687,138 @@ 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;
+
+	if (hsp->num_si > 0) {
+		unsigned int count = 0;
+
+		hsp->shared_irqs = devm_kcalloc(&pdev->dev, hsp->num_si,
+						sizeof(*hsp->shared_irqs),
+						GFP_KERNEL);
+		if (!hsp->shared_irqs)
+			return -ENOMEM;
+
+		for (i = 0; i < hsp->num_si; i++) {
+			char *name;
+
+			name = kasprintf(GFP_KERNEL, "shared%u", i);
+			if (!name)
+				return -ENOMEM;
+
+			err = platform_get_irq_byname(pdev, name);
+			if (err >= 0) {
+				hsp->shared_irqs[i] = err;
+				count++;
+			}
+
+			kfree(name);
+		}
+
+		if (count == 0) {
+			devm_kfree(&pdev->dev, hsp->shared_irqs);
+			hsp->shared_irqs = NULL;
+		}
 	}
 
-	hsp->irq = err;
+	/* setup the doorbell controller */
+	hsp->mbox_db.of_xlate = tegra_hsp_db_xlate;
+	hsp->mbox_db.num_chans = 32;
+	hsp->mbox_db.dev = &pdev->dev;
+	hsp->mbox_db.ops = &tegra_hsp_db_ops;
 
-	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_db.chans = devm_kcalloc(&pdev->dev, hsp->mbox_db.num_chans,
+					  sizeof(*hsp->mbox_db.chans),
+					  GFP_KERNEL);
+	if (!hsp->mbox_db.chans)
+		return -ENOMEM;
 
-	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
-					sizeof(*hsp->mbox.chans),
-					GFP_KERNEL);
-	if (!hsp->mbox.chans)
+	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;
+		}
+	}
+
+	err = mbox_controller_register(&hsp->mbox_db);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to register doorbell mailbox: %d\n",
+			err);
+		goto remove_doorbells;
+	}
+
+	/* setup the shared mailbox controller */
+	hsp->mbox_sm.of_xlate = tegra_hsp_sm_xlate;
+	hsp->mbox_sm.num_chans = hsp->num_sm;
+	hsp->mbox_sm.dev = &pdev->dev;
+	hsp->mbox_sm.ops = &tegra_hsp_sm_ops;
+
+	hsp->mbox_sm.chans = devm_kcalloc(&pdev->dev, hsp->mbox_sm.num_chans,
+					  sizeof(*hsp->mbox_sm.chans),
+					  GFP_KERNEL);
+	if (!hsp->mbox_sm.chans)
 		return -ENOMEM;
 
-	err = tegra_hsp_add_doorbells(hsp);
+	if (hsp->shared_irqs) {
+		err = tegra_hsp_add_mailboxes(hsp, &pdev->dev);
+		if (err < 0) {
+			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
+			        err);
+			goto unregister_mbox_db;
+		}
+	}
+
+	err = mbox_controller_register(&hsp->mbox_sm);
 	if (err < 0) {
-		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
-		return err;
+		dev_err(&pdev->dev, "failed to register shared mailbox: %d\n",
+			err);
+		goto unregister_mbox_db;
 	}
 
 	platform_set_drvdata(pdev, hsp);
 
-	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;
+	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_sm;
+		}
 	}
 
-	err = devm_request_irq(&pdev->dev, hsp->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);
-		return err;
+	if (hsp->shared_irqs) {
+		err = tegra_hsp_request_shared_irq(hsp);
+		if (err < 0)
+			goto unregister_mbox_sm;
 	}
 
 	return 0;
+
+unregister_mbox_sm:
+	mbox_controller_unregister(&hsp->mbox_sm);
+unregister_mbox_db:
+	mbox_controller_unregister(&hsp->mbox_db);
+remove_doorbells:
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
+
+	return err;
 }
 
 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);
+	mbox_controller_unregister(&hsp->mbox_sm);
+	mbox_controller_unregister(&hsp->mbox_db);
+
+	if (hsp->doorbell_irq)
+		tegra_hsp_remove_doorbells(hsp);
 
 	return 0;
 }
@@ -456,10 +831,17 @@ static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = {
 
 static const struct tegra_hsp_soc tegra186_hsp_soc = {
 	.map = tegra186_hsp_db_map,
+	.has_per_mb_ie = false,
+};
+
+static const struct tegra_hsp_soc tegra194_hsp_soc = {
+	.map = tegra186_hsp_db_map,
+	.has_per_mb_ie = true,
 };
 
 static const struct of_device_id tegra_hsp_match[] = {
 	{ .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc },
+	{ .compatible = "nvidia,tegra194-hsp", .data = &tegra194_hsp_soc },
 	{ }
 };
 
-- 
2.19.1

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

* [PATCH v3 05/12] mailbox: tegra-hsp: Add suspend/resume support
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (3 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 04/12] mailbox: tegra-hsp: Add support for " Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 06/12] mailbox: tegra-hsp: use devm_kstrdup_const() Thierry Reding
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Thierry Reding <treding@nvidia.com>

Upon resuming from a system sleep state, the interrupts for all active
shared mailboxes need to be reenabled, otherwise they will not work.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/mailbox/tegra-hsp.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index a4ec18d76cba..07d1fbff3642 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 
 #include <dt-bindings/mailbox/tegra186-hsp.h>
@@ -823,6 +824,23 @@ static int tegra_hsp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int tegra_hsp_resume(struct device *dev)
+{
+	struct tegra_hsp *hsp = dev_get_drvdata(dev);
+	unsigned int i;
+
+	for (i = 0; i < hsp->num_sm; i++) {
+		struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
+
+		if (mb->channel.chan->cl)
+			tegra_hsp_mailbox_startup(mb->channel.chan);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(tegra_hsp_pm_ops, NULL, tegra_hsp_resume);
+
 static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = {
 	{ "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, },
 	{ "bpmp",   TEGRA_HSP_DB_MASTER_BPMP,   HSP_DB_BPMP,   },
@@ -849,6 +867,7 @@ static struct platform_driver tegra_hsp_driver = {
 	.driver = {
 		.name = "tegra-hsp",
 		.of_match_table = tegra_hsp_match,
+		.pm = &tegra_hsp_pm_ops,
 	},
 	.probe = tegra_hsp_probe,
 	.remove = tegra_hsp_remove,
-- 
2.19.1

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

* [PATCH v3 06/12] mailbox: tegra-hsp: use devm_kstrdup_const()
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (4 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 05/12] mailbox: tegra-hsp: Add suspend/resume support Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 07/12] mailbox: tegra-hsp: Use device-managed registration API Thierry Reding
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Bartosz Golaszewski <brgl@bgdev.pl>

Use devm_kstrdup_const() in the tegra-hsp driver. This mostly serves as
an example of how to use this new routine to shrink driver code.

Also use devm_kzalloc() instead of regular kzalloc() to shrink the
driver even more.

Doorbell objects are only removed in the driver's remove callback so
it's safe to convert all memory allocations to devres.

Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/mailbox/tegra-hsp.c | 36 ++++--------------------------------
 1 file changed, 4 insertions(+), 32 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 07d1fbff3642..9628e52e2371 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -281,7 +281,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 	unsigned int offset;
 	unsigned long flags;
 
-	db = kzalloc(sizeof(*db), GFP_KERNEL);
+	db = devm_kzalloc(hsp->dev, sizeof(*db), GFP_KERNEL);
 	if (!db)
 		return ERR_PTR(-ENOMEM);
 
@@ -291,7 +291,7 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 	db->channel.regs = hsp->regs + offset;
 	db->channel.hsp = hsp;
 
-	db->name = kstrdup_const(name, GFP_KERNEL);
+	db->name = devm_kstrdup_const(hsp->dev, name, GFP_KERNEL);
 	db->master = master;
 	db->index = index;
 
@@ -302,13 +302,6 @@ tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
 	return &db->channel;
 }
 
-static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
-{
-	list_del(&db->list);
-	kfree_const(db->name);
-	kfree(db);
-}
-
 static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
 {
 	struct tegra_hsp_doorbell *db = chan->con_priv;
@@ -567,19 +560,6 @@ static struct mbox_chan *tegra_hsp_sm_xlate(struct mbox_controller *mbox,
 	return mb->channel.chan;
 }
 
-static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
-{
-	struct tegra_hsp_doorbell *db, *tmp;
-	unsigned long flags;
-
-	spin_lock_irqsave(&hsp->lock, flags);
-
-	list_for_each_entry_safe(db, tmp, &hsp->doorbells, list)
-		__tegra_hsp_doorbell_destroy(db);
-
-	spin_unlock_irqrestore(&hsp->lock, flags);
-}
-
 static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
 {
 	const struct tegra_hsp_db_map *map = hsp->soc->map;
@@ -588,10 +568,8 @@ static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
 	while (map->name) {
 		channel = tegra_hsp_doorbell_create(hsp, map->name,
 						    map->master, map->index);
-		if (IS_ERR(channel)) {
-			tegra_hsp_remove_doorbells(hsp);
+		if (IS_ERR(channel))
 			return PTR_ERR(channel);
-		}
 
 		map++;
 	}
@@ -747,7 +725,7 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to register doorbell mailbox: %d\n",
 			err);
-		goto remove_doorbells;
+		return err;
 	}
 
 	/* setup the shared mailbox controller */
@@ -804,9 +782,6 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 	mbox_controller_unregister(&hsp->mbox_sm);
 unregister_mbox_db:
 	mbox_controller_unregister(&hsp->mbox_db);
-remove_doorbells:
-	if (hsp->doorbell_irq)
-		tegra_hsp_remove_doorbells(hsp);
 
 	return err;
 }
@@ -818,9 +793,6 @@ static int tegra_hsp_remove(struct platform_device *pdev)
 	mbox_controller_unregister(&hsp->mbox_sm);
 	mbox_controller_unregister(&hsp->mbox_db);
 
-	if (hsp->doorbell_irq)
-		tegra_hsp_remove_doorbells(hsp);
-
 	return 0;
 }
 
-- 
2.19.1

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

* [PATCH v3 07/12] mailbox: tegra-hsp: Use device-managed registration API
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (5 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 06/12] mailbox: tegra-hsp: use devm_kstrdup_const() Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 08/12] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu Thierry Reding
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Thierry Reding <treding@nvidia.com>

In order to get rid of a lot of cleanup boilerplate code, use the
device-managed registration API.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/mailbox/tegra-hsp.c | 30 ++++++------------------------
 1 file changed, 6 insertions(+), 24 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 9628e52e2371..e443f6a2ec4b 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -721,7 +721,7 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = mbox_controller_register(&hsp->mbox_db);
+	err = devm_mbox_controller_register(&pdev->dev, &hsp->mbox_db);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to register doorbell mailbox: %d\n",
 			err);
@@ -745,15 +745,15 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 		if (err < 0) {
 			dev_err(&pdev->dev, "failed to add mailboxes: %d\n",
 			        err);
-			goto unregister_mbox_db;
+			return err;
 		}
 	}
 
-	err = mbox_controller_register(&hsp->mbox_sm);
+	err = devm_mbox_controller_register(&pdev->dev, &hsp->mbox_sm);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to register shared mailbox: %d\n",
 			err);
-		goto unregister_mbox_db;
+		return err;
 	}
 
 	platform_set_drvdata(pdev, hsp);
@@ -766,33 +766,16 @@ static int tegra_hsp_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 			        "failed to request doorbell IRQ#%u: %d\n",
 				hsp->doorbell_irq, err);
-			goto unregister_mbox_sm;
+			return err;
 		}
 	}
 
 	if (hsp->shared_irqs) {
 		err = tegra_hsp_request_shared_irq(hsp);
 		if (err < 0)
-			goto unregister_mbox_sm;
+			return err;
 	}
 
-	return 0;
-
-unregister_mbox_sm:
-	mbox_controller_unregister(&hsp->mbox_sm);
-unregister_mbox_db:
-	mbox_controller_unregister(&hsp->mbox_db);
-
-	return err;
-}
-
-static int tegra_hsp_remove(struct platform_device *pdev)
-{
-	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
-
-	mbox_controller_unregister(&hsp->mbox_sm);
-	mbox_controller_unregister(&hsp->mbox_db);
-
 	return 0;
 }
 
@@ -842,7 +825,6 @@ static struct platform_driver tegra_hsp_driver = {
 		.pm = &tegra_hsp_pm_ops,
 	},
 	.probe = tegra_hsp_probe,
-	.remove = tegra_hsp_remove,
 };
 
 static int __init tegra_hsp_init(void)
-- 
2.19.1

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

* [PATCH v3 08/12] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (6 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 07/12] mailbox: tegra-hsp: Use device-managed registration API Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 09/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Mikko Perttunen <mperttunen@nvidia.com>

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>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 .../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..085a8591accd
--- /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.19.1

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

* [PATCH v3 09/12] serial: Add Tegra Combined UART driver
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (7 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 08/12] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 10/12] arm64: tegra: Add nodes for TCU on Tegra194 Thierry Reding
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Thierry Reding <treding@nvidia.com>

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.

Based on work by  Mikko Perttunen <mperttunen@nvidia.com>.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v3:
- explicitly flush mailbox to rate-limit console output
---
 drivers/tty/serial/Kconfig       |  22 +++
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/tegra-tcu.c   | 298 +++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 324 insertions(+)
 create mode 100644 drivers/tty/serial/tegra-tcu.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 32886c304641..785306388aa4 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -323,6 +323,28 @@ 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_TEGRA_TCU_CONSOLE
+	bool "Support for console on a Tegra TCU serial port"
+	depends on SERIAL_TEGRA_TCU=y
+	select SERIAL_CORE_CONSOLE
+	default y
+	---help---
+	  If you say Y here, it will be possible to use a the Tegra TCU as the
+	  system console (the system console is the device which receives all
+	  kernel messages and warnings and which allows logins in single user
+	  mode).
+
+	  If unsure, say Y.
+
 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..a349b3355d38
--- /dev/null
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -0,0 +1,298 @@
+// 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)
+
+struct tegra_tcu {
+	struct uart_driver driver;
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
+	struct console console;
+#endif
+	struct uart_port port;
+
+	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_one(struct tegra_tcu *tcu, u32 value,
+			       unsigned int count)
+{
+	void *msg;
+
+	value |= TCU_MBOX_NUM_BYTES(count);
+	msg = (void *)(unsigned long)value;
+	mbox_send_message(tcu->tx, msg);
+	mbox_flush(tcu->tx, 1000);
+}
+
+static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s,
+			    unsigned int count)
+{
+	unsigned int written = 0, i = 0;
+	bool insert_nl = false;
+	u32 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) {
+			tegra_tcu_write_one(tcu, value, 3);
+			value = written = 0;
+		}
+	}
+
+	if (written)
+		tegra_tcu_write_one(tcu, value, written);
+}
+
+static void tegra_tcu_uart_start_tx(struct uart_port *port)
+{
+	struct tegra_tcu *tcu = port->private_data;
+	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(tcu, &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,
+};
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
+static void tegra_tcu_console_write(struct console *cons, const char *s,
+				    unsigned int count)
+{
+	struct tegra_tcu *tcu = container_of(cons, struct tegra_tcu, console);
+
+	tegra_tcu_write(tcu, s, count);
+}
+
+static int tegra_tcu_console_setup(struct console *cons, char *options)
+{
+	return 0;
+}
+#endif
+
+static void tegra_tcu_receive(struct mbox_client *cl, void *msg)
+{
+	struct tegra_tcu *tcu = container_of(cl, struct tegra_tcu, rx_client);
+	struct tty_port *port = &tcu->port.state->port;
+	u32 value = (u32)(unsigned long)msg;
+	unsigned int num_bytes, i;
+
+	num_bytes = TCU_MBOX_NUM_BYTES_V(value);
+
+	for (i = 0; i < num_bytes; i++)
+		tty_insert_flip_char(port, TCU_MBOX_BYTE_V(value, i),
+				     TTY_NORMAL);
+
+	tty_flip_buffer_push(port);
+}
+
+static int tegra_tcu_probe(struct platform_device *pdev)
+{
+	struct uart_port *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;
+	}
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
+	/* setup the console */
+	strcpy(tcu->console.name, "ttyTCU");
+	tcu->console.device = uart_console_device;
+	tcu->console.flags = CON_PRINTBUFFER | CON_ANYTIME;
+	tcu->console.index = -1;
+	tcu->console.write = tegra_tcu_console_write;
+	tcu->console.setup = tegra_tcu_console_setup;
+	tcu->console.data = &tcu->driver;
+#endif
+
+	/* setup the driver */
+	tcu->driver.owner = THIS_MODULE;
+	tcu->driver.driver_name = "tegra-tcu";
+	tcu->driver.dev_name = "ttyTCU";
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
+	tcu->driver.cons = &tcu->console;
+#endif
+	tcu->driver.nr = 1;
+
+	err = uart_register_driver(&tcu->driver);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register UART driver: %d\n",
+			err);
+		goto free_rx;
+	}
+
+	/* setup the port */
+	port = &tcu->port;
+	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(&tcu->driver, port);
+	if (err) {
+		dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
+		goto unregister_uart;
+	}
+
+	platform_set_drvdata(pdev, tcu);
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
+	register_console(&tcu->console);
+#endif
+
+	return 0;
+
+unregister_uart:
+	uart_unregister_driver(&tcu->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)
+{
+	struct tegra_tcu *tcu = platform_get_drvdata(pdev);
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
+	unregister_console(&tcu->console);
+#endif
+	uart_remove_one_port(&tcu->driver, &tcu->port);
+	uart_unregister_driver(&tcu->driver);
+	mbox_free_channel(tcu->rx);
+	mbox_free_channel(tcu->tx);
+
+	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,
+};
+module_platform_driver(tegra_tcu_driver);
+
+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.19.1

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

* [PATCH v3 10/12] arm64: tegra: Add nodes for TCU on Tegra194
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (8 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 09/12] serial: Add Tegra Combined UART driver Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 11/12] arm64: tegra: Mark TCU as primary serial port on Tegra194 P2888 Thierry Reding
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Mikko Perttunen <mperttunen@nvidia.com>

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>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- encode direction of mailboxes in device tree mailbox specifier
---
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 38 ++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index d64fe306d2e4..1d8ed688fe59 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -688,10 +688,35 @@
 		};
 
 		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>;
+			/*
+			 * Shared interrupt 0 is routed only to AON/SPE, so
+			 * we only have 4 shared interrupts for the CCPLEX.
+			 */
+			interrupt-names = "shared1", "shared2", "shared3", "shared4";
 			#mbox-cells = <2>;
 		};
 
@@ -879,6 +904,13 @@
 		method = "smc";
 	};
 
+	tcu: tcu {
+		compatible = "nvidia,tegra194-tcu";
+		mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM TEGRA_HSP_SM_RX(0)>,
+		         <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM TEGRA_HSP_SM_TX(1)>;
+		mbox-names = "rx", "tx";
+	};
+
 	thermal-zones {
 		cpu {
 			thermal-sensors = <&{/bpmp/thermal}
-- 
2.19.1

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

* [PATCH v3 11/12] arm64: tegra: Mark TCU as primary serial port on Tegra194 P2888
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (9 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 10/12] arm64: tegra: Add nodes for TCU on Tegra194 Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-11-28  9:54 ` [PATCH v3 12/12] arm64: defconfig: Enable Tegra TCU Thierry Reding
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Mikko Perttunen <mperttunen@nvidia.com>

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>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 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 204a207ff4bd..23c3988a8f08 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.19.1

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

* [PATCH v3 12/12] arm64: defconfig: Enable Tegra TCU
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (10 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 11/12] arm64: tegra: Mark TCU as primary serial port on Tegra194 P2888 Thierry Reding
@ 2018-11-28  9:54 ` Thierry Reding
  2018-12-05 16:15 ` [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
  2018-12-22  5:13 ` Jassi Brar
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-11-28  9:54 UTC (permalink / raw)
  To: Thierry Reding, Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

From: Thierry Reding <treding@nvidia.com>

The Tegra Combined UART is used on some Tegra194 devices as a way of
multiplexing output from multiple producers onto a single physical UART.
Enable this by default so that it can be used as the default console to
write kernel messages to.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 1f1f4eab89df..db947853fc92 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -300,6 +300,7 @@ CONFIG_SERIAL_MESON_CONSOLE=y
 CONFIG_SERIAL_SAMSUNG=y
 CONFIG_SERIAL_SAMSUNG_CONSOLE=y
 CONFIG_SERIAL_TEGRA=y
+CONFIG_SERIAL_TEGRA_TCU=y
 CONFIG_SERIAL_SH_SCI=y
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
-- 
2.19.1

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

* Re: [PATCH v3 00/12] serial: Add Tegra Combined UART driver
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (11 preceding siblings ...)
  2018-11-28  9:54 ` [PATCH v3 12/12] arm64: defconfig: Enable Tegra TCU Thierry Reding
@ 2018-12-05 16:15 ` Thierry Reding
  2018-12-22  5:13 ` Jassi Brar
  13 siblings, 0 replies; 15+ messages in thread
From: Thierry Reding @ 2018-12-05 16:15 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 4548 bytes --]

On Wed, Nov 28, 2018 at 10:54:09AM +0100, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Hi everyone,
> 
> this is a reworked version of Mikko's earlier proposal[0]. I've reworked
> the TCU driver itself so that it relies less on global variables as well
> as added a Kconfig option to allow the console support to be selected. I
> also fixed a couple of issues that manifested themselves as I was moving
> towards the IRQ driven mode (TCU was passing a pointer to a local
> variable which was getting stored in the mailbox's ring buffer and the
> data pointed at was becoming stale by the time the mailbox got around to
> dequeue it).
> 
> The biggest bulk of the changes is in the mailbox driver. This series
> addresses all of Jassi's comments from back at the time. One notable
> additional change is that shared mailboxes are now interrupt driven,
> which removes the need for polling mode.
> 
> Unfortunately there is still an issue because the TCU uses the mailbox
> in atomic context for both TTY and console modes, so we get a sleeping-
> while-atomic BUG when using mbox_client->tx_block = true in order to
> rate-limit mbox_send_message(). In order to work around this, I added a
> new mbox_flush() API that will allow flushing the mailbox in atomic
> context by using the mailbox controller's implementation of ->flush().
> For Tegra HSP shared mailboxes this is done by spinning on the shared
> mailbox register until the receiver has marked the mailbox as empty. I
> have been running this locally for a couple of days now and it works
> perfectly.
> 
> Furthermore this series incorporates Mikko's work in progress on
> splitting up the mailbox controllers and allowing multiple controllers
> to match on the same device tree node during mbox_request_channel().
> 
> The new mbox_flush() API introduces a build-time dependency between the
> TCU driver and the mailbox framework, so patches 1-9 would need to go
> through one tree. Patch 9 was already acked by Greg, so I would suggest
> that Jassi pick up the first 9 patches and I pick up patches 10-12 into
> the Tegra tree.
> 
> Changes in v3:
> - add a patch from Bartosz Golaszewski to use devm_kstrdup_const()
> - add a patch to use device-managed registration to simplify code
> - introduce explicit mailbox flush API
> 
> Changes in v2:
> - address all of Pekka's comments regarding shared interrupts, registers
>   that don't exist on Tegra186 and shared mailbox directionality
> - add a patch to enable the TCU in the 64-bit ARM default configuration
> 
> Thanks,
> Thierry
> 
> [0]: https://lore.kernel.org/patchwork/project/lkml/list/?series=357641
> 
> Bartosz Golaszewski (1):
>   mailbox: tegra-hsp: use devm_kstrdup_const()
> 
> Mikko Perttunen (5):
>   mailbox: Allow multiple controllers per device
>   dt-bindings: tegra186-hsp: Add shared mailboxes
>   dt-bindings: serial: Add bindings for nvidia,tegra194-tcu
>   arm64: tegra: Add nodes for TCU on Tegra194
>   arm64: tegra: Mark TCU as primary serial port on Tegra194 P2888
> 
> Thierry Reding (6):
>   mailbox: Support blocking transfers in atomic context
>   mailbox: tegra-hsp: Add support for shared mailboxes
>   mailbox: tegra-hsp: Add suspend/resume support
>   mailbox: tegra-hsp: Use device-managed registration API
>   serial: Add Tegra Combined UART driver
>   arm64: defconfig: Enable Tegra TCU
> 
>  .../bindings/mailbox/nvidia,tegra186-hsp.txt  |  30 +-
>  .../bindings/serial/nvidia,tegra194-tcu.txt   |  35 ++
>  .../arm64/boot/dts/nvidia/tegra194-p2888.dtsi |   2 +-
>  arch/arm64/boot/dts/nvidia/tegra194.dtsi      |  38 +-
>  arch/arm64/configs/defconfig                  |   1 +
>  drivers/mailbox/mailbox.c                     |  31 +-
>  drivers/mailbox/tegra-hsp.c                   | 517 +++++++++++++++---
>  drivers/tty/serial/Kconfig                    |  22 +
>  drivers/tty/serial/Makefile                   |   1 +
>  drivers/tty/serial/tegra-tcu.c                | 298 ++++++++++
>  include/dt-bindings/mailbox/tegra186-hsp.h    |  11 +
>  include/linux/mailbox_client.h                |   1 +
>  include/linux/mailbox_controller.h            |   4 +
>  include/uapi/linux/serial_core.h              |   3 +
>  14 files changed, 903 insertions(+), 91 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt
>  create mode 100644 drivers/tty/serial/tegra-tcu.c

Hi Jassi,

do you have any comments on this?

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 00/12] serial: Add Tegra Combined UART driver
  2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
                   ` (12 preceding siblings ...)
  2018-12-05 16:15 ` [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
@ 2018-12-22  5:13 ` Jassi Brar
  13 siblings, 0 replies; 15+ messages in thread
From: Jassi Brar @ 2018-12-22  5:13 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Greg Kroah-Hartman, Jiri Slaby, Mikko Perttunen, Jon Hunter,
	Timo Alho, Pekka Pessi, Mika Liljeberg, linux-tegra, linux-serial,
	Devicetree List

On Wed, Nov 28, 2018 at 3:54 AM Thierry Reding <thierry.reding@gmail.com> wrote:
>
> From: Thierry Reding <treding@nvidia.com>
>
> Hi everyone,
>
> this is a reworked version of Mikko's earlier proposal[0]. I've reworked
> the TCU driver itself so that it relies less on global variables as well
> as added a Kconfig option to allow the console support to be selected. I
> also fixed a couple of issues that manifested themselves as I was moving
> towards the IRQ driven mode (TCU was passing a pointer to a local
> variable which was getting stored in the mailbox's ring buffer and the
> data pointed at was becoming stale by the time the mailbox got around to
> dequeue it).
>
> The biggest bulk of the changes is in the mailbox driver. This series
> addresses all of Jassi's comments from back at the time. One notable
> additional change is that shared mailboxes are now interrupt driven,
> which removes the need for polling mode.
>
> Unfortunately there is still an issue because the TCU uses the mailbox
> in atomic context for both TTY and console modes, so we get a sleeping-
> while-atomic BUG when using mbox_client->tx_block = true in order to
> rate-limit mbox_send_message(). In order to work around this, I added a
> new mbox_flush() API that will allow flushing the mailbox in atomic
> context by using the mailbox controller's implementation of ->flush().
> For Tegra HSP shared mailboxes this is done by spinning on the shared
> mailbox register until the receiver has marked the mailbox as empty. I
> have been running this locally for a couple of days now and it works
> perfectly.
>
> Furthermore this series incorporates Mikko's work in progress on
> splitting up the mailbox controllers and allowing multiple controllers
> to match on the same device tree node during mbox_request_channel().
>
> The new mbox_flush() API introduces a build-time dependency between the
> TCU driver and the mailbox framework, so patches 1-9 would need to go
> through one tree. Patch 9 was already acked by Greg, so I would suggest
> that Jassi pick up the first 9 patches and I pick up patches 10-12 into
> the Tegra tree.
>
Picked the first 8. The patch-9 is tcu serial driver and should go via tty.

-Jassi

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

end of thread, other threads:[~2018-12-22 18:26 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-11-28  9:54 [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
2018-11-28  9:54 ` [PATCH v3 01/12] mailbox: Support blocking transfers in atomic context Thierry Reding
2018-11-28  9:54 ` [PATCH v3 02/12] mailbox: Allow multiple controllers per device Thierry Reding
2018-11-28  9:54 ` [PATCH v3 03/12] dt-bindings: tegra186-hsp: Add shared mailboxes Thierry Reding
2018-11-28  9:54 ` [PATCH v3 04/12] mailbox: tegra-hsp: Add support for " Thierry Reding
2018-11-28  9:54 ` [PATCH v3 05/12] mailbox: tegra-hsp: Add suspend/resume support Thierry Reding
2018-11-28  9:54 ` [PATCH v3 06/12] mailbox: tegra-hsp: use devm_kstrdup_const() Thierry Reding
2018-11-28  9:54 ` [PATCH v3 07/12] mailbox: tegra-hsp: Use device-managed registration API Thierry Reding
2018-11-28  9:54 ` [PATCH v3 08/12] dt-bindings: serial: Add bindings for nvidia,tegra194-tcu Thierry Reding
2018-11-28  9:54 ` [PATCH v3 09/12] serial: Add Tegra Combined UART driver Thierry Reding
2018-11-28  9:54 ` [PATCH v3 10/12] arm64: tegra: Add nodes for TCU on Tegra194 Thierry Reding
2018-11-28  9:54 ` [PATCH v3 11/12] arm64: tegra: Mark TCU as primary serial port on Tegra194 P2888 Thierry Reding
2018-11-28  9:54 ` [PATCH v3 12/12] arm64: defconfig: Enable Tegra TCU Thierry Reding
2018-12-05 16:15 ` [PATCH v3 00/12] serial: Add Tegra Combined UART driver Thierry Reding
2018-12-22  5:13 ` Jassi Brar

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