All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] rs485 support for Raspberry Pi aux uart
@ 2020-02-28 13:31 Lukas Wunner
  2020-02-28 13:31 ` [PATCH 1/8] serial: 8250: Don't touch RTS modem control while in rs485 mode Lukas Wunner
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

The objective of this series is to add rs485 support for the
Raspberry Pi auxiliary uart (patch [6/8] and [7/8]).

But I'm taking the opportunity to improve rs485 support for any
8250-compatible uart:

* rs485 devicetree properties support (patch [2/8]).
* rs485 serial console support (patch [8/8]).
* various fixes and cleanups.

Please review and test.  Thanks!


Lukas Wunner (8):
  serial: 8250: Don't touch RTS modem control while in rs485 mode
  serial: 8250: Support rs485 devicetree properties
  serial: 8250: Deduplicate ->rs485_config() callback
  serial: 8250: Sanitize rs485 config harder
  serial: 8250: Deduplicate rs485 active_timer assignment
  serial: 8250: Generalize rs485 software emulation
  serial: 8250_bcm2835aux: Support rs485 software emulation
  serial: 8250: Support console on software emulated rs485 ports

 drivers/tty/serial/8250/8250.h            |   4 +-
 drivers/tty/serial/8250/8250_bcm2835aux.c |  62 ++++++++-
 drivers/tty/serial/8250/8250_core.c       |   6 +-
 drivers/tty/serial/8250/8250_of.c         |  39 +-----
 drivers/tty/serial/8250/8250_omap.c       |  34 +----
 drivers/tty/serial/8250/8250_port.c       | 157 +++++++++++++++++-----
 include/linux/serial_8250.h               |   3 +
 7 files changed, 204 insertions(+), 101 deletions(-)

-- 
2.24.0


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

* [PATCH 1/8] serial: 8250: Don't touch RTS modem control while in rs485 mode
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  2020-02-28 13:31 ` [PATCH 2/8] serial: 8250: Support rs485 devicetree properties Lukas Wunner
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

serial8250_do_set_mctrl() currently allows modifying the RTS modem
control line even when RTS is used as an rs485 Transmit Enable signal.
It is thus possible for user space to interfere with rs485 communication
by invoking a TIOCMSET ioctl().

Ignore such change requests and retain the current RTS polarity when in
rs485 mode.  Note that serial8250_set_mctrl() is always called with
port->lock held, so there's no risk that RTS is changed concurrently.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
---
 drivers/tty/serial/8250/8250_port.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index f398f162a1fd..a8f4cedde4dc 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1924,6 +1924,13 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 	struct uart_8250_port *up = up_to_u8250p(port);
 	unsigned char mcr;
 
+	if (port->rs485.flags & SER_RS485_ENABLED) {
+		if (serial8250_in_MCR(up) & UART_MCR_RTS)
+			mctrl |= TIOCM_RTS;
+		else
+			mctrl &= ~TIOCM_RTS;
+	}
+
 	mcr = serial8250_TIOCM_to_MCR(mctrl);
 
 	mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
-- 
2.24.0


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

* [PATCH 2/8] serial: 8250: Support rs485 devicetree properties
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
  2020-02-28 13:31 ` [PATCH 1/8] serial: 8250: Don't touch RTS modem control while in rs485 mode Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  2020-02-28 13:31 ` [PATCH 3/8] serial: 8250: Deduplicate ->rs485_config() callback Lukas Wunner
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

Retrieve rs485 devicetree properties on registration of 8250 ports in
case they are attached to an rs485 transceiver.

If the property "linux,rs485-enabled-at-boot-time" is present, invoke
the ->rs485_config() callback to immediately deassert RTS, thereby
ceasing control of the bus.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Giulio Benetti <giulio.benetti@micronovasrl.com>
Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/tty/serial/8250/8250_core.c | 4 +++-
 drivers/tty/serial/8250/8250_port.c | 3 +++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index f2a33c9082a6..9a1d09fbb836 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1013,8 +1013,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 		if (uart->port.fifosize && !uart->tx_loadsz)
 			uart->tx_loadsz = uart->port.fifosize;
 
-		if (up->port.dev)
+		if (up->port.dev) {
 			uart->port.dev = up->port.dev;
+			uart_get_rs485_mode(uart->port.dev, &uart->port.rs485);
+		}
 
 		if (up->port.flags & UPF_FIXED_TYPE)
 			uart->port.type = up->port.type;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index a8f4cedde4dc..40efcea8c6e7 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2989,6 +2989,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
 	if (flags & UART_CONFIG_TYPE)
 		autoconfig(up);
 
+	if (port->rs485.flags & SER_RS485_ENABLED)
+		port->rs485_config(port, &port->rs485);
+
 	/* if access method is AU, it is a 16550 with a quirk */
 	if (port->type == PORT_16550A && port->iotype == UPIO_AU)
 		up->bugs |= UART_BUG_NOMSR;
-- 
2.24.0


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

* [PATCH 3/8] serial: 8250: Deduplicate ->rs485_config() callback
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
  2020-02-28 13:31 ` [PATCH 1/8] serial: 8250: Don't touch RTS modem control while in rs485 mode Lukas Wunner
  2020-02-28 13:31 ` [PATCH 2/8] serial: 8250: Support rs485 devicetree properties Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  2020-02-28 13:31 ` [PATCH 4/8] serial: 8250: Sanitize rs485 config harder Lukas Wunner
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

Commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250")
introduced support to use RTS as an rs485 Transmit Enable signal.
Drivers opt in to the feature by calling serial8250_em485_init() from
their ->rs485_config() callback.

So far there are two drivers doing that, 8250_omap.c and 8250_of.c.
Both use an identical callback.  We're about to add a third user of that
callback, therefore deduplicate it and move it to 8250_port.c.

Drivers now opt in to rs485 software emulation by assigning the generic
serial8250_rs485_config() callback introduced herein to their
.rs485_config struct member.  This change allows unexporting
serial8250_em485_init() and declaring it static.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
Cc: Heiko Schocher <hs@denx.de>
---
 drivers/tty/serial/8250/8250.h      |  2 +-
 drivers/tty/serial/8250/8250_of.c   | 32 +---------------------
 drivers/tty/serial/8250/8250_omap.c | 32 +---------------------
 drivers/tty/serial/8250/8250_port.c | 41 +++++++++++++++++++++++++++--
 4 files changed, 42 insertions(+), 65 deletions(-)

diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 33ad9d6de532..e83b66e0f593 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -156,7 +156,7 @@ void serial8250_rpm_put(struct uart_8250_port *p);
 void serial8250_rpm_get_tx(struct uart_8250_port *p);
 void serial8250_rpm_put_tx(struct uart_8250_port *p);
 
-int serial8250_em485_init(struct uart_8250_port *p);
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485);
 void serial8250_em485_destroy(struct uart_8250_port *p);
 
 /* MCR <-> TIOCM conversion */
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index ad92f451f3b9..4a68a8785caa 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -25,36 +25,6 @@ struct of_serial_info {
 	int line;
 };
 
-static int of_8250_rs485_config(struct uart_port *port,
-				  struct serial_rs485 *rs485)
-{
-	struct uart_8250_port *up = up_to_u8250p(port);
-
-	/* Clamp the delays to [0, 100ms] */
-	rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
-	rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
-
-	port->rs485 = *rs485;
-
-	/*
-	 * Both serial8250_em485_init and serial8250_em485_destroy
-	 * are idempotent
-	 */
-	if (rs485->flags & SER_RS485_ENABLED) {
-		int ret = serial8250_em485_init(up);
-
-		if (ret) {
-			rs485->flags &= ~SER_RS485_ENABLED;
-			port->rs485.flags &= ~SER_RS485_ENABLED;
-		}
-		return ret;
-	}
-
-	serial8250_em485_destroy(up);
-
-	return 0;
-}
-
 /*
  * Fill a struct uart_port for a given device node
  */
@@ -184,7 +154,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
 		port->flags |= UPF_SKIP_TEST;
 
 	port->dev = &ofdev->dev;
-	port->rs485_config = of_8250_rs485_config;
+	port->rs485_config = serial8250_em485_config;
 
 	switch (type) {
 	case PORT_RT2880:
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6f343ca08440..fff70cb25046 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -714,36 +714,6 @@ static void omap_8250_throttle(struct uart_port *port)
 	pm_runtime_put_autosuspend(port->dev);
 }
 
-static int omap_8250_rs485_config(struct uart_port *port,
-				  struct serial_rs485 *rs485)
-{
-	struct uart_8250_port *up = up_to_u8250p(port);
-
-	/* Clamp the delays to [0, 100ms] */
-	rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
-	rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
-
-	port->rs485 = *rs485;
-
-	/*
-	 * Both serial8250_em485_init and serial8250_em485_destroy
-	 * are idempotent
-	 */
-	if (rs485->flags & SER_RS485_ENABLED) {
-		int ret = serial8250_em485_init(up);
-
-		if (ret) {
-			rs485->flags &= ~SER_RS485_ENABLED;
-			port->rs485.flags &= ~SER_RS485_ENABLED;
-		}
-		return ret;
-	}
-
-	serial8250_em485_destroy(up);
-
-	return 0;
-}
-
 static void omap_8250_unthrottle(struct uart_port *port)
 {
 	struct omap8250_priv *priv = port->private_data;
@@ -1187,7 +1157,7 @@ static int omap8250_probe(struct platform_device *pdev)
 	up.port.shutdown = omap_8250_shutdown;
 	up.port.throttle = omap_8250_throttle;
 	up.port.unthrottle = omap_8250_unthrottle;
-	up.port.rs485_config = omap_8250_rs485_config;
+	up.port.rs485_config = serial8250_em485_config;
 	up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
 
 	ret = of_alias_get_id(np, "serial");
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 40efcea8c6e7..73244806d701 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -615,7 +615,7 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put);
  *
  *	Return 0 - success, -errno - otherwise
  */
-int serial8250_em485_init(struct uart_8250_port *p)
+static int serial8250_em485_init(struct uart_8250_port *p)
 {
 	if (p->em485)
 		return 0;
@@ -636,7 +636,6 @@ int serial8250_em485_init(struct uart_8250_port *p)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(serial8250_em485_init);
 
 /**
  *	serial8250_em485_destroy() - put uart_8250_port into normal state
@@ -664,6 +663,44 @@ void serial8250_em485_destroy(struct uart_8250_port *p)
 }
 EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
 
+/**
+ * serial8250_em485_config() - generic ->rs485_config() callback
+ * @port: uart port
+ * @rs485: rs485 settings
+ *
+ * Generic callback usable by 8250 uart drivers to activate rs485 settings
+ * if the uart is incapable of driving RTS as a Transmit Enable signal in
+ * hardware, relying on software emulation instead.
+ */
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+
+	/* clamp the delays to [0, 100ms] */
+	rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+	rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
+
+	port->rs485 = *rs485;
+
+	/*
+	 * Both serial8250_em485_init() and serial8250_em485_destroy()
+	 * are idempotent.
+	 */
+	if (rs485->flags & SER_RS485_ENABLED) {
+		int ret = serial8250_em485_init(up);
+
+		if (ret) {
+			rs485->flags &= ~SER_RS485_ENABLED;
+			port->rs485.flags &= ~SER_RS485_ENABLED;
+		}
+		return ret;
+	}
+
+	serial8250_em485_destroy(up);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_config);
+
 /*
  * These two wrappers ensure that enable_runtime_pm_tx() can be called more than
  * once and disable_runtime_pm_tx() will still disable RPM because the fifo is
-- 
2.24.0


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

* [PATCH 4/8] serial: 8250: Sanitize rs485 config harder
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
                   ` (2 preceding siblings ...)
  2020-02-28 13:31 ` [PATCH 3/8] serial: 8250: Deduplicate ->rs485_config() callback Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  2020-02-28 13:31 ` [PATCH 5/8] serial: 8250: Deduplicate rs485 active_timer assignment Lukas Wunner
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

Amend the generic ->rs485_config() callback to sanitize RTS polarity and
zero-fill the padding (in addition to the existing sanitization of the
RTS delays).

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
---
 drivers/tty/serial/8250/8250_port.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 73244806d701..d281aea061d6 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -676,10 +676,18 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
 {
 	struct uart_8250_port *up = up_to_u8250p(port);
 
+	/* pick sane settings if the user hasn't */
+	if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
+	    !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
+		rs485->flags |= SER_RS485_RTS_ON_SEND;
+		rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+	}
+
 	/* clamp the delays to [0, 100ms] */
 	rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
 	rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
 
+	memset(rs485->padding, 0, sizeof(rs485->padding));
 	port->rs485 = *rs485;
 
 	/*
-- 
2.24.0


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

* [PATCH 5/8] serial: 8250: Deduplicate rs485 active_timer assignment
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
                   ` (3 preceding siblings ...)
  2020-02-28 13:31 ` [PATCH 4/8] serial: 8250: Sanitize rs485 config harder Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  2020-02-28 13:31 ` [PATCH 6/8] serial: 8250: Generalize rs485 software emulation Lukas Wunner
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

When rs485 transmission over an 8250 port stops, __stop_tx() assigns
active_timer = NULL before calling __stop_tx_rs485().

That function in turn either assigns active_timer = stop_tx_timer and
rearms the timer (in case a delay_rts_after_send needs to be observed)
or directly calls __do_stop_tx_rs485().

Move the assignment active_timer = NULL to __stop_tx_rs485() into the
branch which directly calls __do_stop_tx_rs485(), thereby avoiding a
duplicate assignment and simplifying the code.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
---
 drivers/tty/serial/8250/8250_port.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index d281aea061d6..1a71625a0d43 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1498,6 +1498,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
 				   p->port.rs485.delay_rts_after_send);
 	} else {
 		__do_stop_tx_rs485(p);
+		em485->active_timer = NULL;
 	}
 }
 
@@ -1522,8 +1523,6 @@ static inline void __stop_tx(struct uart_8250_port *p)
 		if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
 			return;
 
-		em485->active_timer = NULL;
-
 		__stop_tx_rs485(p);
 	}
 	__do_stop_tx(p);
-- 
2.24.0


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

* [PATCH 6/8] serial: 8250: Generalize rs485 software emulation
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
                   ` (4 preceding siblings ...)
  2020-02-28 13:31 ` [PATCH 5/8] serial: 8250: Deduplicate rs485 active_timer assignment Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  2020-02-28 13:31 ` [PATCH 7/8] serial: 8250_bcm2835aux: Support " Lukas Wunner
  2020-02-28 13:31 ` [PATCH 8/8] serial: 8250: Support console on software emulated rs485 ports Lukas Wunner
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

Commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250")
introduced support to use RTS as an rs485 Transmit Enable signal.
So far the only drivers taking advantage of it are 8250_omap.c and
8250_of.c.

We're about to make use of the feature in 8250_bcm2835aux.c as well.
The bcm2835aux differs from omap chips by inverting the meaning of RTS
in the MCR register.  Moreover, omap achieves half-duplex mode by
disabling the RX interrupt and clearing the RX FIFO when TX stops.
The bcm2835aux requires disabling the receiver instead.

Support these behavioral differences by generalizing the rs485 emulation:
Introduce ->rs485_start_tx() and ->rs485_stop_tx() callbacks in struct
uart_8250_port, provide generic implementations containing the existing
code and use them as callbacks in 8250_omap.c and 8250_of.c.

start_tx_rs485() is idempotent in that it recognizes whether RTS is
already asserted.  Achieve the same by introducing a tx_stopped flag in
struct uart_8250_em485.  This may even perform a little better on arches
where memory access is faster than mmio access.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
---
 drivers/tty/serial/8250/8250.h      |  2 +
 drivers/tty/serial/8250/8250_core.c |  2 +
 drivers/tty/serial/8250/8250_of.c   |  7 ++-
 drivers/tty/serial/8250/8250_omap.c |  2 +
 drivers/tty/serial/8250/8250_port.c | 82 +++++++++++++++++++----------
 include/linux/serial_8250.h         |  3 ++
 6 files changed, 67 insertions(+), 31 deletions(-)

diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index e83b66e0f593..0df02c055107 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -157,6 +157,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p);
 void serial8250_rpm_put_tx(struct uart_8250_port *p);
 
 int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485);
+void serial8250_em485_start_tx(struct uart_8250_port *p);
+void serial8250_em485_stop_tx(struct uart_8250_port *p);
 void serial8250_em485_destroy(struct uart_8250_port *p);
 
 /* MCR <-> TIOCM conversion */
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 9a1d09fbb836..f6eb00406ddf 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1007,6 +1007,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 		uart->port.unthrottle	= up->port.unthrottle;
 		uart->port.rs485_config	= up->port.rs485_config;
 		uart->port.rs485	= up->port.rs485;
+		uart->rs485_start_tx	= up->rs485_start_tx;
+		uart->rs485_stop_tx	= up->rs485_stop_tx;
 		uart->dma		= up->dma;
 
 		/* Take tx_loadsz from fifosize if it wasn't set separately */
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 4a68a8785caa..65e9045dafe6 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -29,11 +29,12 @@ struct of_serial_info {
  * Fill a struct uart_port for a given device node
  */
 static int of_platform_serial_setup(struct platform_device *ofdev,
-			int type, struct uart_port *port,
+			int type, struct uart_8250_port *up,
 			struct of_serial_info *info)
 {
 	struct resource resource;
 	struct device_node *np = ofdev->dev.of_node;
+	struct uart_port *port = &up->port;
 	u32 clk, spd, prop;
 	int ret, irq;
 
@@ -155,6 +156,8 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
 
 	port->dev = &ofdev->dev;
 	port->rs485_config = serial8250_em485_config;
+	up->rs485_start_tx = serial8250_em485_start_tx;
+	up->rs485_stop_tx = serial8250_em485_stop_tx;
 
 	switch (type) {
 	case PORT_RT2880:
@@ -201,7 +204,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
 		return -ENOMEM;
 
 	memset(&port8250, 0, sizeof(port8250));
-	ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info);
+	ret = of_platform_serial_setup(ofdev, port_type, &port8250, info);
 	if (ret)
 		goto err_free;
 
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index fff70cb25046..dd69226ce918 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1158,6 +1158,8 @@ static int omap8250_probe(struct platform_device *pdev)
 	up.port.throttle = omap_8250_throttle;
 	up.port.unthrottle = omap_8250_unthrottle;
 	up.port.rs485_config = serial8250_em485_config;
+	up.rs485_start_tx = serial8250_em485_start_tx;
+	up.rs485_stop_tx = serial8250_em485_stop_tx;
 	up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
 
 	ret = of_alias_get_id(np, "serial");
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 1a71625a0d43..8e8cca690bf9 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -557,17 +557,6 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
 	}
 }
 
-static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
-{
-	unsigned char mcr = serial8250_in_MCR(p);
-
-	if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
-		mcr |= UART_MCR_RTS;
-	else
-		mcr &= ~UART_MCR_RTS;
-	serial8250_out_MCR(p, mcr);
-}
-
 static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
 static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
 
@@ -632,7 +621,9 @@ static int serial8250_em485_init(struct uart_8250_port *p)
 	p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
 	p->em485->port = p;
 	p->em485->active_timer = NULL;
-	serial8250_em485_rts_after_send(p);
+	p->em485->tx_stopped = true;
+
+	p->rs485_stop_tx(p);
 
 	return 0;
 }
@@ -1439,9 +1430,21 @@ static void serial8250_stop_rx(struct uart_port *port)
 	serial8250_rpm_put(up);
 }
 
-static void __do_stop_tx_rs485(struct uart_8250_port *p)
+/**
+ * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
+ * @up: uart 8250 port
+ *
+ * Generic callback usable by 8250 uart drivers to stop rs485 transmission.
+ */
+void serial8250_em485_stop_tx(struct uart_8250_port *p)
 {
-	serial8250_em485_rts_after_send(p);
+	unsigned char mcr = serial8250_in_MCR(p);
+
+	if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+		mcr |= UART_MCR_RTS;
+	else
+		mcr &= ~UART_MCR_RTS;
+	serial8250_out_MCR(p, mcr);
 
 	/*
 	 * Empty the RX FIFO, we are not interested in anything
@@ -1455,6 +1458,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
 		serial_port_out(&p->port, UART_IER, p->ier);
 	}
 }
+EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
+
 static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
 {
 	struct uart_8250_em485 *em485;
@@ -1467,8 +1472,9 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
 	serial8250_rpm_get(p);
 	spin_lock_irqsave(&p->port.lock, flags);
 	if (em485->active_timer == &em485->stop_tx_timer) {
-		__do_stop_tx_rs485(p);
+		p->rs485_stop_tx(p);
 		em485->active_timer = NULL;
+		em485->tx_stopped = true;
 	}
 	spin_unlock_irqrestore(&p->port.lock, flags);
 	serial8250_rpm_put(p);
@@ -1489,7 +1495,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
 	struct uart_8250_em485 *em485 = p->em485;
 
 	/*
-	 * __do_stop_tx_rs485 is going to set RTS according to config
+	 * rs485_stop_tx() is going to set RTS according to config
 	 * AND flush RX FIFO if required.
 	 */
 	if (p->port.rs485.delay_rts_after_send > 0) {
@@ -1497,8 +1503,9 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
 		start_hrtimer_ms(&em485->stop_tx_timer,
 				   p->port.rs485.delay_rts_after_send);
 	} else {
-		__do_stop_tx_rs485(p);
+		p->rs485_stop_tx(p);
 		em485->active_timer = NULL;
+		em485->tx_stopped = true;
 	}
 }
 
@@ -1572,25 +1579,42 @@ static inline void __start_tx(struct uart_port *port)
 	}
 }
 
-static inline void start_tx_rs485(struct uart_port *port)
+/**
+ * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback
+ * @up: uart 8250 port
+ *
+ * Generic callback usable by 8250 uart drivers to start rs485 transmission.
+ * Assumes that setting the RTS bit in the MCR register means RTS is high.
+ * (Some chips use inverse semantics.)  Further assumes that reception is
+ * stoppable by disabling the UART_IER_RDI interrupt.  (Some chips set the
+ * UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.)
+ */
+void serial8250_em485_start_tx(struct uart_8250_port *up)
 {
-	struct uart_8250_port *up = up_to_u8250p(port);
-	struct uart_8250_em485 *em485 = up->em485;
-	unsigned char mcr;
+	unsigned char mcr = serial8250_in_MCR(up);
 
 	if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
 		serial8250_stop_rx(&up->port);
 
+	if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+		mcr |= UART_MCR_RTS;
+	else
+		mcr &= ~UART_MCR_RTS;
+	serial8250_out_MCR(up, mcr);
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_start_tx);
+
+static inline void start_tx_rs485(struct uart_port *port)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+	struct uart_8250_em485 *em485 = up->em485;
+
 	em485->active_timer = NULL;
 
-	mcr = serial8250_in_MCR(up);
-	if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
-	    !!(mcr & UART_MCR_RTS)) {
-		if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
-			mcr |= UART_MCR_RTS;
-		else
-			mcr &= ~UART_MCR_RTS;
-		serial8250_out_MCR(up, mcr);
+	if (em485->tx_stopped) {
+		em485->tx_stopped = false;
+
+		up->rs485_start_tx(up);
 
 		if (up->port.rs485.delay_rts_before_send > 0) {
 			em485->active_timer = &em485->start_tx_timer;
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 6a8e8c48c882..0901c2aa366c 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -81,6 +81,7 @@ struct uart_8250_em485 {
 	struct hrtimer		stop_tx_timer;  /* "rs485 stop tx" timer */
 	struct hrtimer		*active_timer;  /* pointer to active timer */
 	struct uart_8250_port	*port;          /* for hrtimer callbacks */
+	unsigned int		tx_stopped:1;	/* tx is currently stopped */
 };
 
 /*
@@ -132,6 +133,8 @@ struct uart_8250_port {
 	void			(*dl_write)(struct uart_8250_port *, int);
 
 	struct uart_8250_em485 *em485;
+	void			(*rs485_start_tx)(struct uart_8250_port *);
+	void			(*rs485_stop_tx)(struct uart_8250_port *);
 
 	/* Serial port overrun backoff */
 	struct delayed_work overrun_backoff;
-- 
2.24.0


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

* [PATCH 7/8] serial: 8250_bcm2835aux: Support rs485 software emulation
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
                   ` (5 preceding siblings ...)
  2020-02-28 13:31 ` [PATCH 6/8] serial: 8250: Generalize rs485 software emulation Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  2020-02-28 13:31 ` [PATCH 8/8] serial: 8250: Support console on software emulated rs485 ports Lukas Wunner
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

Amend 8250_bcm2835aux.c to support rs485 as introduced for 8250_omap.c
by commit e490c9144cfa ("tty: Add software emulated RS485 support for
8250").

The bcm2835aux differs from omap chips by inverting the meaning of RTS
in the MCR register:  If the bit is clear, RTS is high.  With omap, it's
apparently the other way round.

Moreover, omap achieves half-duplex mode by disabling the UART_IER_RDI
interrupt and clearing the RX FIFO when TX stops.  This approach doesn't
work on bcm2835aux because the UART_LSR_DR bit is set even when
UART_IER_RDI is disabled.  Consequently, serial8250_handle_irq() invokes
serial8250_rx_chars() to empty the FIFO and characters are received even
though the user requested half-duplex.  Solve by disabling the receiver
using the non-standard CNTL register.

Cache that register in the driver's private data for performance.  Set
the private data pointer before calling serial8250_register_8250_port()
to prevent a null pointer deref in case one of the rs485 callbacks is
invoked immediately after port registration.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
---
 drivers/tty/serial/8250/8250_bcm2835aux.c | 62 ++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index 5cc03bf24f85..12d03e678295 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -6,6 +6,10 @@
  *
  * Based on 8250_lpc18xx.c:
  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
+ * take advantage of it yet.  When adding support, be sure not to enable it
+ * simultaneously to rs485.
  */
 
 #include <linux/clk.h>
@@ -16,16 +20,64 @@
 
 #include "8250.h"
 
+#define BCM2835_AUX_UART_CNTL		8
+#define BCM2835_AUX_UART_CNTL_RXEN	0x01 /* Receiver enable */
+#define BCM2835_AUX_UART_CNTL_TXEN	0x02 /* Transmitter enable */
+#define BCM2835_AUX_UART_CNTL_AUTORTS	0x04 /* RTS set by RX fill level */
+#define BCM2835_AUX_UART_CNTL_AUTOCTS	0x08 /* CTS stops transmitter */
+#define BCM2835_AUX_UART_CNTL_RTS3	0x00 /* RTS set until 3 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS2	0x10 /* RTS set until 2 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS1	0x20 /* RTS set until 1 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS4	0x30 /* RTS set until 4 chars left */
+#define BCM2835_AUX_UART_CNTL_RTSINV	0x40 /* Invert auto RTS polarity */
+#define BCM2835_AUX_UART_CNTL_CTSINV	0x80 /* Invert auto CTS polarity */
+
 /**
  * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
  * @clk: clock producer of the port's uartclk
  * @line: index of the port's serial8250_ports[] entry
+ * @cntl: cached copy of CNTL register
  */
 struct bcm2835aux_data {
 	struct clk *clk;
 	int line;
+	u32 cntl;
 };
 
+static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
+{
+	if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+		struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
+
+		data->cntl &= ~BCM2835_AUX_UART_CNTL_RXEN;
+		serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
+	}
+
+	/*
+	 * On the bcm2835aux, the MCR register contains no other
+	 * flags besides RTS.  So no need for a read-modify-write.
+	 */
+	if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+		serial8250_out_MCR(up, 0);
+	else
+		serial8250_out_MCR(up, UART_MCR_RTS);
+}
+
+static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
+{
+	if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+		serial8250_out_MCR(up, 0);
+	else
+		serial8250_out_MCR(up, UART_MCR_RTS);
+
+	if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+		struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
+
+		data->cntl |= BCM2835_AUX_UART_CNTL_RXEN;
+		serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
+	}
+}
+
 static int bcm2835aux_serial_probe(struct platform_device *pdev)
 {
 	struct uart_8250_port up = { };
@@ -47,6 +99,14 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
 	up.port.fifosize = 8;
 	up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
 			UPF_SKIP_TEST | UPF_IOREMAP;
+	up.port.rs485_config = serial8250_em485_config;
+	up.rs485_start_tx = bcm2835aux_rs485_start_tx;
+	up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
+
+	/* initialize cached copy with power-on reset value */
+	data->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN;
+
+	platform_set_drvdata(pdev, data);
 
 	/* get the clock - this also enables the HW */
 	data->clk = devm_clk_get(&pdev->dev, NULL);
@@ -102,8 +162,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
 	}
 	data->line = ret;
 
-	platform_set_drvdata(pdev, data);
-
 	return 0;
 
 dis_clk:
-- 
2.24.0


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

* [PATCH 8/8] serial: 8250: Support console on software emulated rs485 ports
  2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
                   ` (6 preceding siblings ...)
  2020-02-28 13:31 ` [PATCH 7/8] serial: 8250_bcm2835aux: Support " Lukas Wunner
@ 2020-02-28 13:31 ` Lukas Wunner
  7 siblings, 0 replies; 9+ messages in thread
From: Lukas Wunner @ 2020-02-28 13:31 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Saenz Julienne
  Cc: Matwey V. Kornilov, Heiko Schocher, Giulio Benetti,
	Uwe Kleine-Koenig, Stefan Wahren, Matthias Brugger, Martin Sperl,
	linux-serial, linux-rpi-kernel

Commit e490c9144cfa ("tty: Add software emulated RS485 support for 8250")
introduced support to use RTS as an rs485 Transmit Enable signal if data
is transmitted through the tty layer.

Console messages bypass the tty layer and instead are emitted via
serial8250_console_write().  Amend that function to drive RTS as well,
allowing for a console on rs485 ports.

Note that serial8250_console_write() may be called concurrently to the
tty layer accessing the port.  The two protect their accesses with the
port lock, but serial8250_console_write() may find RTS still being
asserted by the tty layer, in which case it shouldn't be deasserted
after the console message has been printed.  Recognize such situations
by checking the em485->tx_stopped flag.

If a delay_rts_before_send or delay_rts_after_send has been specified,
serial8250_console_write() busy-waits for its duration.  Optimizations
for those wait times are conceivable:  E.g. if RTS is already asserted,
we could check whether em485->start_tx_timer is active and wait only
for the remaining expire time.  But this would require calling into
the hrtimer infrastructure, which involves acquiring locks and
potentially reprogramming timer hardware.  Such operations seem too
risky in the context of console printout, which needs to work even when
the kernel has crashed and emits a BUG splat.  So I've gone with a
simplistic solution which just always waits for the full delay.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matwey V. Kornilov <matwey@sai.msu.ru>
---
 drivers/tty/serial/8250/8250_port.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 8e8cca690bf9..0879bb8855cf 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -3204,6 +3204,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
 void serial8250_console_write(struct uart_8250_port *up, const char *s,
 			      unsigned int count)
 {
+	struct uart_8250_em485 *em485 = up->em485;
 	struct uart_port *port = &up->port;
 	unsigned long flags;
 	unsigned int ier;
@@ -3234,6 +3235,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
 		up->canary = 0;
 	}
 
+	if (em485) {
+		if (em485->tx_stopped)
+			up->rs485_start_tx(up);
+		mdelay(port->rs485.delay_rts_before_send);
+	}
+
 	uart_console_write(port, s, count, serial8250_console_putchar);
 
 	/*
@@ -3243,6 +3250,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
 	wait_for_xmitr(up, BOTH_EMPTY);
 	serial_port_out(port, UART_IER, ier);
 
+	if (em485) {
+		mdelay(port->rs485.delay_rts_before_send);
+		if (em485->tx_stopped)
+			up->rs485_stop_tx(up);
+	}
+
 	/*
 	 *	The receive handling will happen properly because the
 	 *	receive ready bit will still be set; it is not cleared
-- 
2.24.0


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

end of thread, other threads:[~2020-02-28 13:46 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-28 13:31 [PATCH 0/8] rs485 support for Raspberry Pi aux uart Lukas Wunner
2020-02-28 13:31 ` [PATCH 1/8] serial: 8250: Don't touch RTS modem control while in rs485 mode Lukas Wunner
2020-02-28 13:31 ` [PATCH 2/8] serial: 8250: Support rs485 devicetree properties Lukas Wunner
2020-02-28 13:31 ` [PATCH 3/8] serial: 8250: Deduplicate ->rs485_config() callback Lukas Wunner
2020-02-28 13:31 ` [PATCH 4/8] serial: 8250: Sanitize rs485 config harder Lukas Wunner
2020-02-28 13:31 ` [PATCH 5/8] serial: 8250: Deduplicate rs485 active_timer assignment Lukas Wunner
2020-02-28 13:31 ` [PATCH 6/8] serial: 8250: Generalize rs485 software emulation Lukas Wunner
2020-02-28 13:31 ` [PATCH 7/8] serial: 8250_bcm2835aux: Support " Lukas Wunner
2020-02-28 13:31 ` [PATCH 8/8] serial: 8250: Support console on software emulated rs485 ports Lukas Wunner

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.