From nobody Tue Jun 23 16:13:06 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 09A7BC433F5 for ; Wed, 2 Mar 2022 09:57:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240747AbiCBJ5o (ORCPT ); Wed, 2 Mar 2022 04:57:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231358AbiCBJ5m (ORCPT ); Wed, 2 Mar 2022 04:57:42 -0500 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7200797B96; Wed, 2 Mar 2022 01:56:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646215019; x=1677751019; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=44LOYszFrJLEvO3q4+AUjDDBcsIz3GOTQUi+oFDrXX8=; b=i8iunL9Dhg9PWEMJoUtGX+SRT1mRe4LxGYnz05HQ97oEc+PsRvi2EneG GP9x8pYMdqdaq+sMCNRGMMed+ac6tuVkicAGbadofGfIHkdLj4I7xS+cF zYi0cx8T+qWmfsH1s+g7FUsUsQ5SqQehMYMC1sJXQlmJJIpiwmfy5yc61 DsPBX+7EseMFbd2XNAg66FA8dW8rluNAyNhLi3M9dAx3VYAx1AWWGqXOw DU2DelbZVImCdwwJLI4/s2uIUupVNWyerwXiGy04XVm6AvGV2Lgo7GeRT yLqiXB33Oc/hYSaqSEGsGuz0ocZCZHTkFUFoJlBgjlDyK83WlmehBYk9c w==; X-IronPort-AV: E=McAfee;i="6200,9189,10273"; a="233980114" X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="233980114" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:56:57 -0800 X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="551182055" Received: from abotoi-mobl2.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.251.218.48]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:56:54 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-serial@vger.kernel.org, Jiri Slaby , Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, Lukas Wunner , Johan Hovold , Andy Shevchenko , Heikki Krogerus , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Raymond Tan Subject: [PATCH 1/7] serial: 8250_dwlib: RS485 HW half duplex support Date: Wed, 2 Mar 2022 11:56:00 +0200 Message-Id: <20220302095606.14818-2-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> References: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The Synopsys DesignWare UART has a build-in support for the RS485 protocol from IP version 4.0 onward. This commit enables basic hardware-controlled half duplex mode support for it. HW will take care of managing DE and RE, the driver just gives it permission to use either by setting both to 1. Co-developed-by: Heikki Krogerus Signed-off-by: Heikki Krogerus Co-developed-by: Raymond Tan Signed-off-by: Raymond Tan Co-developed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Signed-off-by: Ilpo J=C3=A4rvinen --- drivers/tty/serial/8250/8250_dwlib.c | 67 +++++++++++++++++++++++++++- drivers/tty/serial/8250/8250_dwlib.h | 3 ++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250= /8250_dwlib.c index 622d3b0d89e7..a4f09a95049b 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -2,19 +2,33 @@ /* Synopsys DesignWare 8250 library. */ =20 #include +#include #include #include #include +#include #include #include =20 #include "8250_dwlib.h" =20 /* Offsets for the DesignWare specific registers */ +#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */ +#define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */ +#define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */ #define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ #define DW_UART_CPR 0xf4 /* Component Parameter Register */ #define DW_UART_UCV 0xf8 /* UART Component Version */ =20 +/* Transceiver Control Register bits */ +#define DW_UART_TCR_RS485_EN BIT(0) +#define DW_UART_TCR_RE_POL BIT(1) +#define DW_UART_TCR_DE_POL BIT(2) +#define DW_UART_TCR_XFER_MODE GENMASK(4, 3) +#define DW_UART_TCR_XFER_MODE_DE_DURING_RE FIELD_PREP(DW_UART_TCR_XFER_MOD= E, 0) +#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE= , 1) +#define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, = 2) + /* Component Parameter Register bits */ #define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) #define DW_UART_CPR_AFCE_MODE (1 << 4) @@ -87,11 +101,62 @@ void dw8250_do_set_termios(struct uart_port *p, struct= ktermios *termios, struct } EXPORT_SYMBOL_GPL(dw8250_do_set_termios); =20 +static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *r= s485) +{ + u32 tcr; + + tcr =3D dw8250_readl_ext(p, DW_UART_TCR); + tcr &=3D ~DW_UART_TCR_XFER_MODE; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Clearing unsupported flags. */ + rs485->flags &=3D SER_RS485_ENABLED; + + tcr |=3D DW_UART_TCR_RS485_EN | DW_UART_TCR_XFER_MODE_DE_OR_RE; + dw8250_writel_ext(p, DW_UART_DE_EN, 1); + dw8250_writel_ext(p, DW_UART_RE_EN, 1); + } else { + rs485->flags =3D 0; + + tcr &=3D ~DW_UART_TCR_RS485_EN; + dw8250_writel_ext(p, DW_UART_DE_EN, 0); + dw8250_writel_ext(p, DW_UART_RE_EN, 0); + } + + /* Resetting the default DE_POL & RE_POL */ + tcr &=3D ~(DW_UART_TCR_DE_POL | DW_UART_TCR_RE_POL); + + if (device_property_read_bool(p->dev, "snps,de-active-high")) + tcr |=3D DW_UART_TCR_DE_POL; + if (device_property_read_bool(p->dev, "snps,re-active-high")) + tcr |=3D DW_UART_TCR_RE_POL; + + dw8250_writel_ext(p, DW_UART_TCR, tcr); + + /* + * XXX: Though we could interpret the "RTS" timings as Driver Enable + * (DE) assertion/de-assertion timings, initially not supporting that. + * Ideally we should have timing values for the Driver instead of the + * RTS signal. + */ + rs485->delay_rts_before_send =3D 0; + rs485->delay_rts_after_send =3D 0; + + p->rs485 =3D *rs485; + + return 0; +} + void dw8250_setup_port(struct uart_port *p) { + struct dw8250_port_data *d =3D p->private_data; struct uart_8250_port *up =3D up_to_u8250p(p); u32 reg; =20 + d->hw_rs485_support =3D device_property_read_bool(p->dev, "snps,rs485-int= erface-en"); + if (d->hw_rs485_support) + p->rs485_config =3D dw8250_rs485_config; + /* * If the Component Version Register returns zero, we know that * ADDITIONAL_FEATURES are not enabled. No need to go any further. @@ -108,8 +173,6 @@ void dw8250_setup_port(struct uart_port *p) dw8250_writel_ext(p, DW_UART_DLF, 0); =20 if (reg) { - struct dw8250_port_data *d =3D p->private_data; - d->dlf_size =3D fls(reg); p->get_divisor =3D dw8250_get_divisor; p->set_divisor =3D dw8250_set_divisor; diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250= /8250_dwlib.h index 83d528e5cc21..a8fa020ca544 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -14,6 +14,9 @@ struct dw8250_port_data { =20 /* Hardware configuration */ u8 dlf_size; + + /* RS485 variables */ + bool hw_rs485_support; }; =20 void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, = struct ktermios *old); --=20 2.30.2 From nobody Tue Jun 23 16:13:06 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A70BC433EF for ; Wed, 2 Mar 2022 09:57:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240793AbiCBJ54 (ORCPT ); Wed, 2 Mar 2022 04:57:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46830 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240748AbiCBJ5o (ORCPT ); Wed, 2 Mar 2022 04:57:44 -0500 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CE12E97B96; Wed, 2 Mar 2022 01:57:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646215021; x=1677751021; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mG40HTqpEgp/9V7rBkq1TB4ShO4U7Y47+Ht/i8vsZY8=; b=U21VTUMscXCB+irCii/TWrWjAHl/6s//6TalBV8KojC8h4ZYJn6PzcWA dnnLtMuSIKcQRVuLJesrB1JNxwpG6ogMclD2Dpq/8WHigxs02QJbUmkuJ N3DxWyKZOU8nRydhN1mwnpA5K+quhfNh5//8ZHLzUDVFhalP2f8MuDLzs Bi/5Y/HMyO6i2VFiXQJHZecWr3TxsjQOdJIS5WAw1USxvyvWbZfqZ/mbr PljetaVwX+FHLMafbzH9DNDoiSqIH06790FnjYDoh2Cm/mSnBZPysxeQq dL3rVjH2Wjj7sto/PjPlC8xUg6QCC7kEhtTVI0MZtcURMZ9eek69MCZ52 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10273"; a="233980139" X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="233980139" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:01 -0800 X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="551182079" Received: from abotoi-mobl2.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.251.218.48]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:56:58 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-serial@vger.kernel.org, Jiri Slaby , Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, Lukas Wunner , Johan Hovold , Andy Shevchenko , Heikki Krogerus , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Raymond Tan Subject: [PATCH 2/7] serial: 8250_dwlib: RS485 HW full duplex support Date: Wed, 2 Mar 2022 11:56:01 +0200 Message-Id: <20220302095606.14818-3-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> References: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The Synopsys DesignWare UART has a build-in support for the RS485 protocol from IP version 4.0 onward. This patch enables the support of HW Full Duplex mode support for it. To ask for full duplex mode, userspace sets SER_RS485_RX_DURING_TX flag and HW will take care of the rest. Co-developed-by: Raymond Tan Signed-off-by: Raymond Tan Signed-off-by: Ilpo J=C3=A4rvinen --- drivers/tty/serial/8250/8250_dwlib.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250= /8250_dwlib.c index a4f09a95049b..d26792999984 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -110,9 +110,14 @@ static int dw8250_rs485_config(struct uart_port *p, st= ruct serial_rs485 *rs485) =20 if (rs485->flags & SER_RS485_ENABLED) { /* Clearing unsupported flags. */ - rs485->flags &=3D SER_RS485_ENABLED; - - tcr |=3D DW_UART_TCR_RS485_EN | DW_UART_TCR_XFER_MODE_DE_OR_RE; + rs485->flags &=3D SER_RS485_ENABLED | SER_RS485_RX_DURING_TX; + tcr |=3D DW_UART_TCR_RS485_EN; + + if (rs485->flags & SER_RS485_RX_DURING_TX) { + tcr |=3D DW_UART_TCR_XFER_MODE_DE_DURING_RE; + } else { + tcr |=3D DW_UART_TCR_XFER_MODE_DE_OR_RE; + } dw8250_writel_ext(p, DW_UART_DE_EN, 1); dw8250_writel_ext(p, DW_UART_RE_EN, 1); } else { --=20 2.30.2 From nobody Tue Jun 23 16:13:06 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1E4F2C433FE for ; Wed, 2 Mar 2022 09:57:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240771AbiCBJ6Y (ORCPT ); Wed, 2 Mar 2022 04:58:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48012 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240797AbiCBJ6U (ORCPT ); Wed, 2 Mar 2022 04:58:20 -0500 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 42071BDE4D; Wed, 2 Mar 2022 01:57:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646215046; x=1677751046; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TdTwchJPNHkxf+9FPgkIGkROH/nCVAeMcrI7kyCJGrw=; b=BUCcIhCqDuoiclVu9EoTcn9rgjoKas97andM2PGusHDTsOuDgnWlwcLk t1F9JEnkmIhc7vigVhsTmdRnHuHo4tr2hactpoxjHhtXYxGR5wlkEmFLn yz2Qq4wIBZr/fOGg3y0dk93wtkLIi8TZGflUNjA3eG83X47Bmq/iZPW1X DkZGwgeptdC5XGcaTG4SE+mD99YgcHg4H2EIFnKcVnxMFf6VxUIeUidx2 YPv88h9t454GvyH1vyLwlxHxO5cwFBmT7RD9SBthfWw5Ot8TjRWEov0Dw V7idkIAhrp39FMHw1Kr9yeR78lqh6ooSY/aO6UmSm7mrzbx8g2zowRMp8 A==; X-IronPort-AV: E=McAfee;i="6200,9189,10273"; a="233980161" X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="233980161" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:06 -0800 X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="551182087" Received: from abotoi-mobl2.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.251.218.48]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:03 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-serial@vger.kernel.org, Jiri Slaby , Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, Lukas Wunner , Johan Hovold , Andy Shevchenko , Heikki Krogerus , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Eric Tremblay , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Subject: [RFC PATCH 3/7] serial: 8250_dwlib: Implement SW half duplex support Date: Wed, 2 Mar 2022 11:56:02 +0200 Message-Id: <20220302095606.14818-4-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> References: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch enables support for SW half-duplex mode. Synopsys DesignWare UART has a build-in support for the RS485 protocol from IP version 4.0 onward with dedicated RE/DE_EN registers. This patch enables RS485 either using dedicated registers or em485 as fallback. In order to select preference for SW half-duplex mode (em485 + RE/DE_EN) over HW managed one, as both are supported under some configurations, SER_RS485_SW_RX_OR_TX flag is added to serial_rs485. This patch depends on UART_CAP_NOTEMT which is not provided by this series but another one: https://lore.kernel.org/all/20210204161158.643-1-etremblay@distech-contro= ls.com/ Cc: Eric Tremblay Cc: Uwe Kleine-K=C3=B6nig Signed-off-by: Ilpo J=C3=A4rvinen --- drivers/tty/serial/8250/8250_dwlib.c | 60 +++++++++++++++++++++++++--- include/uapi/linux/serial.h | 2 + 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250= /8250_dwlib.c index d26792999984..51b0f55ee9d0 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -101,8 +101,26 @@ void dw8250_do_set_termios(struct uart_port *p, struct= ktermios *termios, struct } EXPORT_SYMBOL_GPL(dw8250_do_set_termios); =20 +static void dw8250_rs485_start_tx(struct uart_8250_port *up) +{ + struct uart_port *p =3D &(up->port); + + dw8250_writel_ext(p, DW_UART_RE_EN, 0); + dw8250_writel_ext(p, DW_UART_DE_EN, 1); +} + +static void dw8250_rs485_stop_tx(struct uart_8250_port *up) +{ + struct uart_port *p =3D &(up->port); + + dw8250_writel_ext(p, DW_UART_DE_EN, 0); + dw8250_writel_ext(p, DW_UART_RE_EN, 1); +} + static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *r= s485) { + struct uart_8250_port *up =3D up_to_u8250p(p); + u32 re_en, de_en; u32 tcr; =20 tcr =3D dw8250_readl_ext(p, DW_UART_TCR); @@ -110,16 +128,29 @@ static int dw8250_rs485_config(struct uart_port *p, s= truct serial_rs485 *rs485) =20 if (rs485->flags & SER_RS485_ENABLED) { /* Clearing unsupported flags. */ - rs485->flags &=3D SER_RS485_ENABLED | SER_RS485_RX_DURING_TX; + rs485->flags &=3D SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485= _SW_RX_OR_TX; tcr |=3D DW_UART_TCR_RS485_EN; =20 if (rs485->flags & SER_RS485_RX_DURING_TX) { tcr |=3D DW_UART_TCR_XFER_MODE_DE_DURING_RE; + re_en =3D 1; + de_en =3D 1; + rs485->flags &=3D ~SER_RS485_SW_RX_OR_TX; + } else if (rs485->flags & SER_RS485_SW_RX_OR_TX) { + tcr |=3D DW_UART_TCR_XFER_MODE_SW_DE_OR_RE; + re_en =3D 1; + de_en =3D 0; + if (up->em485 && !up->em485->tx_stopped) { + re_en =3D 0; + de_en =3D 1; + } } else { tcr |=3D DW_UART_TCR_XFER_MODE_DE_OR_RE; + re_en =3D 1; + de_en =3D 1; } - dw8250_writel_ext(p, DW_UART_DE_EN, 1); - dw8250_writel_ext(p, DW_UART_RE_EN, 1); + dw8250_writel_ext(p, DW_UART_DE_EN, de_en); + dw8250_writel_ext(p, DW_UART_RE_EN, re_en); } else { rs485->flags =3D 0; =20 @@ -147,7 +178,16 @@ static int dw8250_rs485_config(struct uart_port *p, st= ruct serial_rs485 *rs485) rs485->delay_rts_before_send =3D 0; rs485->delay_rts_after_send =3D 0; =20 - p->rs485 =3D *rs485; + if (rs485->flags & SER_RS485_SW_RX_OR_TX) { + int ret; + + ret =3D serial8250_em485_config(p, rs485); + if (ret) + return ret; + } else { + serial8250_em485_destroy(up_to_u8250p(p)); + p->rs485 =3D *rs485; + } =20 return 0; } @@ -159,8 +199,16 @@ void dw8250_setup_port(struct uart_port *p) u32 reg; =20 d->hw_rs485_support =3D device_property_read_bool(p->dev, "snps,rs485-int= erface-en"); - if (d->hw_rs485_support) + if (d->hw_rs485_support) { p->rs485_config =3D dw8250_rs485_config; + up->rs485_start_tx =3D dw8250_rs485_start_tx; + up->rs485_stop_tx =3D dw8250_rs485_stop_tx; + } else { + p->rs485_config =3D serial8250_em485_config; + up->rs485_start_tx =3D serial8250_em485_start_tx; + up->rs485_stop_tx =3D serial8250_em485_stop_tx; + } + up->capabilities |=3D UART_CAP_NOTEMT; =20 /* * If the Component Version Register returns zero, we know that @@ -192,7 +240,7 @@ void dw8250_setup_port(struct uart_port *p) p->type =3D PORT_16550A; p->flags |=3D UPF_FIXED_TYPE; p->fifosize =3D DW_UART_CPR_FIFO_SIZE(reg); - up->capabilities =3D UART_CAP_FIFO; + up->capabilities =3D UART_CAP_FIFO | UART_CAP_NOTEMT; } =20 if (reg & DW_UART_CPR_AFCE_MODE) diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index fa6b16e5fdd8..f868685b35a0 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -126,6 +126,8 @@ struct serial_rs485 { #define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus termination (if supported) */ +#define SER_RS485_SW_RX_OR_TX (1 << 6) /* Prefer SW half-duplex + mode over HW one */ __u32 delay_rts_before_send; /* Delay before send (milliseconds) */ __u32 delay_rts_after_send; /* Delay after send (milliseconds) */ __u32 padding[5]; /* Memory is cheap, new structs --=20 2.30.2 From nobody Tue Jun 23 16:13:06 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0ACBCC433F5 for ; Wed, 2 Mar 2022 09:57:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240814AbiCBJ57 (ORCPT ); Wed, 2 Mar 2022 04:57:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47050 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231764AbiCBJ5z (ORCPT ); Wed, 2 Mar 2022 04:57:55 -0500 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CA768BA756; Wed, 2 Mar 2022 01:57:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646215031; x=1677751031; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9pJEOrD73oAQCPOOwxMD+qRqXz+/orCAtrsg7UcYRhU=; b=LLq/+P4qaELxm6qe/F5bdE6a8c8gaijIng74eWbre6G2gSu04d3a8+q6 Vp2IHtQuq4T9gz+g65AJ6IY+HjLTBal7AXr7Yr6nAmRecWFcHGeDQdj2o Rpb7cqgnRg2a4nazs70CYVwnku/yBHpEMXiBud5GphU60gi5Pzfyqd6Jj GQhFSEgNN02jjWiX5akFQGbApO/xdiR8Zeic8snD1rIz428mZm6ymIx7J 4Zm+WPSfg56N/bBsiNpap9mu2C7Xy6HvF770KBZOwiBimxT4PgDK/XNnR oUEAxK40JuT2OUPl0eNQ9U5lPYYkSd9T7spBtCj7WYEMneea8K5vBM/Xf g==; X-IronPort-AV: E=McAfee;i="6200,9189,10273"; a="339794569" X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="339794569" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:11 -0800 X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="551182126" Received: from abotoi-mobl2.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.251.218.48]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:07 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-serial@vger.kernel.org, Jiri Slaby , Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, Lukas Wunner , Johan Hovold , Andy Shevchenko , Heikki Krogerus , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Rob Herring , devicetree@vger.kernel.org Subject: [PATCH 4/7] dt_bindings: snps-dw-apb-uart: Add RS485 Date: Wed, 2 Mar 2022 11:56:03 +0200 Message-Id: <20220302095606.14818-5-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> References: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add RS485 enable & line polarity properties. Cc: Rob Herring Cc: devicetree@vger.kernel.org Signed-off-by: Ilpo J=C3=A4rvinen --- .../bindings/serial/snps-dw-apb-uart.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml= b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 12137fe80acf..8d440afabb1f 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -103,6 +103,23 @@ properties: register. Define this if your serial port does not use this pin. type: boolean =20 + snps,rs485-interface-en: + description: Use true RS-485 DE and RE signals (in contrast to RS-485 + emulation using RTS). Requires IP version 4 or above. + type: boolean + + snps,de-active-high: + description: Defines the polarity of driver enable (DE_EN) signal. + Meaningful only with snps,rs485-interface-en. True indicates active + high. + type: boolean + + snps,re-active-high: + description: Defines the polarity of receiver enable (RE_EN) signal. + Meaningful only with snps,rs485-interface-en. True indicates active + high. + type: boolean + required: - compatible - reg --=20 2.30.2 From nobody Tue Jun 23 16:13:06 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 32404C433F5 for ; Wed, 2 Mar 2022 09:58:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238733AbiCBJ6x (ORCPT ); Wed, 2 Mar 2022 04:58:53 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240798AbiCBJ6L (ORCPT ); Wed, 2 Mar 2022 04:58:11 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B64D0BDE41; Wed, 2 Mar 2022 01:57:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646215039; x=1677751039; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VVGdFbQA5dpTmH1Oi8imwujW6M34G1DuUPJxrfXUWac=; b=dUJKeVCEss+KIYUuBxj/U2E91CJk4EQBdgVwdxdCiUH7IxQfuWD7ciBE 7CTSyFgpqzbdVXtLW0mcWNq7J8kRPZ18sBOU0ZUXVEmY2ky0rSw9aMlH6 S+dPvdcG7dZgST+UeOaYlEf1g296G0Vox4JkeCC4li8fuF3CgPIOBtxRO tcjGWlRvmtCknvVFzT5EmYFYRxjoKHyKE6Z6TPvG/mUAx5FK1VGd47s2w CAO8N0OKnJMehp6YSj03+QefFnWqLPSLcHb84M/Kz2WIHu6zeZlrts2Tr +bOCE5qMaBYaM5ifYiinoASp/vYfJoEIOQ6pKOsJRY6pMTMTC0FWz2kNF A==; X-IronPort-AV: E=McAfee;i="6200,9189,10273"; a="240777082" X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="240777082" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:19 -0800 X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="551182160" Received: from abotoi-mobl2.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.251.218.48]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:12 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-serial@vger.kernel.org, Jiri Slaby , Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, Lukas Wunner , Johan Hovold , Andy Shevchenko , Heikki Krogerus , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , linux-api@vger.kernel.org, Richard Henderson , Ivan Kokshaysky , Matt Turner , linux-alpha@vger.kernel.org, Thomas Bogendoerfer , linux-mips@vger.kernel.org, "James E.J. Bottomley" , Helge Deller , linux-parisc@vger.kernel.org, Michael Ellerman , Benjamin Herrenschmidt , Paul Mackerras , linuxppc-dev@lists.ozlabs.org, "David S. Miller" , sparclinux@vger.kernel.org, Arnd Bergmann , linux-arch@vger.kernel.org, linux-usb@vger.kernel.org Subject: [RFC PATCH 5/7] serial: termbits: ADDRB to indicate 9th bit addressing mode Date: Wed, 2 Mar 2022 11:56:04 +0200 Message-Id: <20220302095606.14818-6-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> References: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add ADDRB to termbits to indicate 9th bit addressing mode. This change is necessary for supporting devices with RS485 multipoint addressing [*]. A later patch in the patch series adds support for Synopsys Designware UART capable for 9th bit addressing mode. In this mode, 9th bit is used to indicate an address (byte) within the communication line. The 9th bit addressing mode is selected using ADDRB introduced by an earlier patch. [*] Technically, RS485 is just an electronic spec and does not itself specify the 9th bit addressing mode but 9th bit seems at least "semi-standard" way to do addressing with RS485. Cc: linux-api@vger.kernel.org Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Cc: linux-alpha@vger.kernel.org Cc: Thomas Bogendoerfer Cc: linux-mips@vger.kernel.org Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-parisc@vger.kernel.org Cc: Michael Ellerman Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Cc: Arnd Bergmann Cc: linux-arch@vger.kernel.org Cc: linux-usb@vger.kernel.org Signed-off-by: Ilpo J=C3=A4rvinen --- arch/alpha/include/uapi/asm/termbits.h | 1 + arch/mips/include/uapi/asm/termbits.h | 1 + arch/parisc/include/uapi/asm/termbits.h | 1 + arch/powerpc/include/uapi/asm/termbits.h | 1 + arch/sparc/include/uapi/asm/termbits.h | 1 + drivers/tty/amiserial.c | 6 +++++- drivers/tty/moxa.c | 1 + drivers/tty/mxser.c | 1 + drivers/tty/serial/serial_core.c | 2 ++ drivers/tty/tty_ioctl.c | 2 ++ drivers/usb/serial/usb-serial.c | 5 +++-- include/uapi/asm-generic/termbits.h | 1 + 12 files changed, 20 insertions(+), 3 deletions(-) diff --git a/arch/alpha/include/uapi/asm/termbits.h b/arch/alpha/include/ua= pi/asm/termbits.h index 4575ba34a0ea..285169c794ec 100644 --- a/arch/alpha/include/uapi/asm/termbits.h +++ b/arch/alpha/include/uapi/asm/termbits.h @@ -180,6 +180,7 @@ struct ktermios { #define HUPCL 00040000 =20 #define CLOCAL 00100000 +#define ADDRB 010000000 /* address bit */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ =20 diff --git a/arch/mips/include/uapi/asm/termbits.h b/arch/mips/include/uapi= /asm/termbits.h index dfeffba729b7..e7ea31cfec78 100644 --- a/arch/mips/include/uapi/asm/termbits.h +++ b/arch/mips/include/uapi/asm/termbits.h @@ -181,6 +181,7 @@ struct ktermios { #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 +#define ADDRB 0020000 /* address bit */ #define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ diff --git a/arch/parisc/include/uapi/asm/termbits.h b/arch/parisc/include/= uapi/asm/termbits.h index 40e920f8d683..629be061f5d5 100644 --- a/arch/parisc/include/uapi/asm/termbits.h +++ b/arch/parisc/include/uapi/asm/termbits.h @@ -158,6 +158,7 @@ struct ktermios { #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 +#define ADDRB 0020000 /* address bit */ #define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ diff --git a/arch/powerpc/include/uapi/asm/termbits.h b/arch/powerpc/includ= e/uapi/asm/termbits.h index ed18bc61f63d..1b778ac562a4 100644 --- a/arch/powerpc/include/uapi/asm/termbits.h +++ b/arch/powerpc/include/uapi/asm/termbits.h @@ -171,6 +171,7 @@ struct ktermios { #define HUPCL 00040000 =20 #define CLOCAL 00100000 +#define ADDRB 00200000 /* address bit */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ =20 diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/ua= pi/asm/termbits.h index ce5ad5d0f105..4ad60c4acf65 100644 --- a/arch/sparc/include/uapi/asm/termbits.h +++ b/arch/sparc/include/uapi/asm/termbits.h @@ -200,6 +200,7 @@ struct ktermios { #define B3000000 0x00001011 #define B3500000 0x00001012 #define B4000000 0x00001013 */ +#define ADDRB 0x00002000 /* address bit */ #define CIBAUD 0x100f0000 /* input baud rate (not used) */ #define CMSPAR 0x40000000 /* mark or space (stick) parity */ #define CRTSCTS 0x80000000 /* flow control */ diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 533d02b38e02..3ca97007bd6e 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1175,7 +1175,11 @@ static void rs_set_termios(struct tty_struct *tty, s= truct ktermios *old_termios) { struct serial_state *info =3D tty->driver_data; unsigned long flags; - unsigned int cflag =3D tty->termios.c_cflag; + unsigned int cflag; + + tty->termios.c_cflag &=3D ~ADDRB; + + cflag =3D tty->termios.c_cflag; =20 change_speed(tty, info, old_termios); =20 diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index f3c72ab1476c..07cd88152d58 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -2050,6 +2050,7 @@ static int MoxaPortSetTermio(struct moxa_port *port, = struct ktermios *termio, =20 ofsAddr =3D port->tableAddr; =20 + termio->c_cflag &=3D ~ADDRB; mode =3D termio->c_cflag & CSIZE; if (mode =3D=3D CS5) mode =3D MX_CS5; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 836c9eca2946..220676363a07 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -577,6 +577,7 @@ static void mxser_change_speed(struct tty_struct *tty, = struct ktermios *old_term struct mxser_port *info =3D tty->driver_data; unsigned cflag, cval; =20 + tty->termios.c_cflag &=3D ~ADDRB; cflag =3D tty->termios.c_cflag; =20 if (mxser_set_baud(tty, tty_get_baud_rate(tty))) { diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_c= ore.c index 846192a7b4bf..8ab88293c917 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1489,6 +1489,8 @@ static void uart_set_termios(struct tty_struct *tty, goto out; } =20 + tty->termios.c_cflag &=3D ~ADDRB; + uart_change_speed(tty, state, old_termios); /* reload cflag from termios; port driver may have overridden flags */ cflag =3D tty->termios.c_cflag; diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 63181925ec1a..934037d78868 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -319,6 +319,8 @@ unsigned char tty_get_frame_size(unsigned int cflag) bits++; if (cflag & PARENB) bits++; + if (cflag & ADDRB) + bits++; =20 return bits; } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-seria= l.c index 24101bd7fcad..44b73aea80bb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -525,9 +525,10 @@ static void serial_set_termios(struct tty_struct *tty,= struct ktermios *old) =20 dev_dbg(&port->dev, "%s\n", __func__); =20 - if (port->serial->type->set_termios) + if (port->serial->type->set_termios) { + tty->termios.c_cflag &=3D ~ADDRB; port->serial->type->set_termios(tty, port, old); - else + } else tty_termios_copy_hw(&tty->termios, old); } =20 diff --git a/include/uapi/asm-generic/termbits.h b/include/uapi/asm-generic= /termbits.h index 2fbaf9ae89dd..5f5228329d45 100644 --- a/include/uapi/asm-generic/termbits.h +++ b/include/uapi/asm-generic/termbits.h @@ -157,6 +157,7 @@ struct ktermios { #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 +#define ADDRB 0020000 /* address bit */ #define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ --=20 2.30.2 From nobody Tue Jun 23 16:13:06 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 99EABC433F5 for ; Wed, 2 Mar 2022 09:57:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240786AbiCBJ6h (ORCPT ); Wed, 2 Mar 2022 04:58:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240835AbiCBJ6V (ORCPT ); Wed, 2 Mar 2022 04:58:21 -0500 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DEDD513D4A; Wed, 2 Mar 2022 01:57:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646215056; x=1677751056; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Cvy61TtTqRadNEYqsnnn/6324FPZ4RKg0XhIh6rkW/U=; b=UmOUUkWkJPVMli6ArEB4oVslR4jG71PWGLIPtIfo8U6kg5g8/OhU4+oR gxjR/HOp2drmpbAEReVRYHMGG2bz4xgi9nq1n4ROZ7TMMl93Ow6H2ZNk5 LMGwFOo8dTeMhBIrb0nM6tsmH1iEW7MOY07yTJdXv6qAAER0CBR6DW/gk j3zD15USuHBIrHjFS2V0WUPtO9J99XlTkESAKV9r7U9HnjA1uOFzqayoX bnE2kfizRglx6qo90xXCKBeNPlHgxF5uhg3o1y8ZekmS9JcQFin6V+4Eo 5eDTftHq24EwJSg8o1x5fY1e+ZG31TGofwpN5wNRjY5SlQicEik82HV3D g==; X-IronPort-AV: E=McAfee;i="6200,9189,10273"; a="339794633" X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="339794633" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:29 -0800 X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="551182218" Received: from abotoi-mobl2.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.251.218.48]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:20 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-serial@vger.kernel.org, Jiri Slaby , Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, Lukas Wunner , Johan Hovold , Andy Shevchenko , Heikki Krogerus , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , linux-api@vger.kernel.org, Richard Henderson , Ivan Kokshaysky , Matt Turner , linux-alpha@vger.kernel.org, Thomas Bogendoerfer , linux-mips@vger.kernel.org, "James E.J. Bottomley" , Helge Deller , linux-parisc@vger.kernel.org, Michael Ellerman , Benjamin Herrenschmidt , Paul Mackerras , linuxppc-dev@lists.ozlabs.org, Yoshinori Sato , Rich Felker , linux-sh@vger.kernel.org, "David S. Miller" , sparclinux@vger.kernel.org, Chris Zankel , Max Filippov , linux-xtensa@linux-xtensa.org, Arnd Bergmann , linux-arch@vger.kernel.org, linux-doc@vger.kernel.org Subject: [RFC PATCH 6/7] serial: General support for multipoint addresses Date: Wed, 2 Mar 2022 11:56:05 +0200 Message-Id: <20220302095606.14818-7-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> References: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds generic support for serial multipoint addressing. Two new ioctls are added. TIOCSADDR is used to indicate the destination/receive address. TIOCGADDR returns the current address in use. The driver should implement set_addr and get_addr to support addressing mode. Adjust ADDRB clearing to happen only if driver does not provide set_addr (=3Dthe driver doesn't support address mode). This change is necessary for supporting devices with RS485 multipoint addressing [*]. A following patch in the patch series adds support for Synopsys Designware UART capable for 9th bit addressing mode. In this mode, 9th bit is used to indicate an address (byte) within the communication line. The 9th bit addressing mode is selected using ADDRB introduced by the previous patch. Transmit addresses / receiver filter are specified by setting the flags SER_ADDR_DEST and/or SER_ADDR_RECV. When the user supplies the transmit address, in the 9bit addressing mode it is sent out immediately with the 9th bit set to 1. After that, the subsequent normal data bytes are sent with 9th bit as 0 and they are intended to the device with the given address. It is up to receiver to enforce the filter using SER_ADDR_RECV. When userspace has supplied the receive address, the driver is expected to handle the matching of the address and only data with that address is forwarded to the user. Both SER_ADDR_DEST and SER_ADDR_RECV can be given at the same time in a single call if the addresses are the same. The user can clear the receive filter with SER_ADDR_RECV_CLEAR. [*] Technically, RS485 is just an electronic spec and does not itself specify the 9th bit addressing mode but 9th bit seems at least "semi-standard" way to do addressing with RS485. Cc: linux-api@vger.kernel.org Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Cc: linux-alpha@vger.kernel.org Cc: Thomas Bogendoerfer Cc: linux-mips@vger.kernel.org Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-parisc@vger.kernel.org Cc: Michael Ellerman Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Cc: Yoshinori Sato Cc: Rich Felker Cc: linux-sh@vger.kernel.org Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Cc: Arnd Bergmann Cc: linux-arch@vger.kernel.org Cc: linux-doc@vger.kernel.org Signed-off-by: Ilpo J=C3=A4rvinen --- .../driver-api/serial/serial-rs485.rst | 23 ++++++- arch/alpha/include/uapi/asm/ioctls.h | 3 + arch/mips/include/uapi/asm/ioctls.h | 3 + arch/parisc/include/uapi/asm/ioctls.h | 3 + arch/powerpc/include/uapi/asm/ioctls.h | 3 + arch/sh/include/uapi/asm/ioctls.h | 3 + arch/sparc/include/uapi/asm/ioctls.h | 3 + arch/xtensa/include/uapi/asm/ioctls.h | 3 + drivers/tty/serial/8250/8250_core.c | 2 + drivers/tty/serial/serial_core.c | 62 ++++++++++++++++++- include/linux/serial_core.h | 6 ++ include/uapi/asm-generic/ioctls.h | 3 + include/uapi/linux/serial.h | 8 +++ 13 files changed, 123 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/serial/serial-rs485.rst b/Documentati= on/driver-api/serial/serial-rs485.rst index 6bc824f948f9..2f45f007fa5b 100644 --- a/Documentation/driver-api/serial/serial-rs485.rst +++ b/Documentation/driver-api/serial/serial-rs485.rst @@ -95,7 +95,28 @@ RS485 Serial Communications /* Error handling. See errno. */ } =20 -5. References +5. Multipoint Addressing +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + The Linux kernel provides serial_addr structure to handle addressing wi= thin + multipoint serial communications line such as RS485. 9th bit addression= g mode + is enabled by adding ADDRB flag in termios c_cflag. + + Serial core calls device specific set/get_addr in response to TIOCSADDR= and + TIOCGADDR ioctls with a pointer to serial_addr. Destination and receive + address can be specified using serial_addr flags field. Receive address= may + also be cleared using flags. Once an address is set, the communication + can occur only with the particular device and other peers are filtered = out. + It is left up to the receiver side to enforce the filtering. + + Address flags: + - SER_ADDR_RECV: Receive (filter) address. + - SER_ADDR_RECV_CLEAR: Clear receive filter (only for TIOCSADDR). + - SER_ADDR_DEST: Destination address. + + Note: not all devices supporting RS485 support multipoint addressing. + +6. References =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 [1] include/uapi/linux/serial.h diff --git a/arch/alpha/include/uapi/asm/ioctls.h b/arch/alpha/include/uapi= /asm/ioctls.h index 971311605288..500cab3e1d6b 100644 --- a/arch/alpha/include/uapi/asm/ioctls.h +++ b/arch/alpha/include/uapi/asm/ioctls.h @@ -125,4 +125,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + #endif /* _ASM_ALPHA_IOCTLS_H */ diff --git a/arch/mips/include/uapi/asm/ioctls.h b/arch/mips/include/uapi/a= sm/ioctls.h index 16aa8a766aec..3859dc46857e 100644 --- a/arch/mips/include/uapi/asm/ioctls.h +++ b/arch/mips/include/uapi/asm/ioctls.h @@ -96,6 +96,9 @@ #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + /* I hope the range from 0x5480 on is free ... */ #define TIOCSCTTY 0x5480 /* become controlling tty */ #define TIOCGSOFTCAR 0x5481 diff --git a/arch/parisc/include/uapi/asm/ioctls.h b/arch/parisc/include/ua= pi/asm/ioctls.h index 82d1148c6379..62337743db64 100644 --- a/arch/parisc/include/uapi/asm/ioctls.h +++ b/arch/parisc/include/uapi/asm/ioctls.h @@ -86,6 +86,9 @@ #define TIOCSTOP 0x5462 #define TIOCSLTC 0x5462 =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + /* Used for packet mode */ #define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 diff --git a/arch/powerpc/include/uapi/asm/ioctls.h b/arch/powerpc/include/= uapi/asm/ioctls.h index 2c145da3b774..84fd69ac366a 100644 --- a/arch/powerpc/include/uapi/asm/ioctls.h +++ b/arch/powerpc/include/uapi/asm/ioctls.h @@ -120,4 +120,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + #endif /* _ASM_POWERPC_IOCTLS_H */ diff --git a/arch/sh/include/uapi/asm/ioctls.h b/arch/sh/include/uapi/asm/i= octls.h index 11866d4f60e1..f82966b7dba2 100644 --- a/arch/sh/include/uapi/asm/ioctls.h +++ b/arch/sh/include/uapi/asm/ioctls.h @@ -113,4 +113,7 @@ #define TIOCMIWAIT _IO('T', 92) /* 0x545C */ /* wait for a change on seria= l input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + #endif /* __ASM_SH_IOCTLS_H */ diff --git a/arch/sparc/include/uapi/asm/ioctls.h b/arch/sparc/include/uapi= /asm/ioctls.h index 7fd2f5873c9e..e44624c67c79 100644 --- a/arch/sparc/include/uapi/asm/ioctls.h +++ b/arch/sparc/include/uapi/asm/ioctls.h @@ -125,6 +125,9 @@ #define TIOCMIWAIT 0x545C /* Wait for change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */ =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + /* Kernel definitions */ =20 /* Used for packet mode */ diff --git a/arch/xtensa/include/uapi/asm/ioctls.h b/arch/xtensa/include/ua= pi/asm/ioctls.h index 6d4a87296c95..759ca9377f2a 100644 --- a/arch/xtensa/include/uapi/asm/ioctls.h +++ b/arch/xtensa/include/uapi/asm/ioctls.h @@ -127,4 +127,7 @@ #define TIOCMIWAIT _IO('T', 92) /* wait for a change on serial input line(= s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + #endif /* _XTENSA_IOCTLS_H */ diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/= 8250_core.c index 01d30f6ed8fb..f67bc3b76f65 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1008,6 +1008,8 @@ int serial8250_register_8250_port(const struct uart_8= 250_port *up) uart->port.rs485 =3D up->port.rs485; uart->rs485_start_tx =3D up->rs485_start_tx; uart->rs485_stop_tx =3D up->rs485_stop_tx; + uart->port.set_addr =3D up->port.set_addr; + uart->port.get_addr =3D up->port.get_addr; uart->dma =3D up->dma; =20 /* Take tx_loadsz from fifosize if it wasn't set separately */ diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_c= ore.c index 8ab88293c917..8235f696d073 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1346,6 +1346,56 @@ static int uart_set_iso7816_config(struct uart_port = *port, return 0; } =20 +static int uart_set_addr(struct uart_port *port, + struct serial_addr __user *serial_addr_user) +{ + struct serial_addr addr; + unsigned long flags; + int ret; + + if (copy_from_user(&addr, serial_addr_user, sizeof(*serial_addr_user))) + return -EFAULT; + + spin_lock_irqsave(&port->lock, flags); + if (port->set_addr) + ret =3D port->set_addr(port, &addr); + else + ret =3D -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + if (ret) + return ret; + + if (copy_to_user(serial_addr_user, &addr, sizeof(addr))) + return -EFAULT; + + return 0; +} + +static int uart_get_addr(struct uart_port *port, + struct serial_addr __user *serial_addr_user) +{ + struct serial_addr addr; + unsigned long flags; + int ret; + + if (copy_from_user(&addr, serial_addr_user, sizeof(*serial_addr_user))) + return -EFAULT; + + spin_lock_irqsave(&port->lock, flags); + if (port->get_addr) + ret =3D port->get_addr(port, &addr); + else + ret =3D -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + if (ret) + return ret; + + if (copy_to_user(serial_addr_user, &addr, sizeof(addr))) + return -EFAULT; + + return 0; +} + /* * Called via sys_ioctl. We can use spin_lock_irq() here. */ @@ -1423,6 +1473,15 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,= unsigned long arg) case TIOCGISO7816: ret =3D uart_get_iso7816_config(state->uart_port, uarg); break; + + case TIOCSADDR: + ret =3D uart_set_addr(uport, uarg); + break; + + case TIOCGADDR: + ret =3D uart_get_addr(uport, uarg); + break; + default: if (uport->ops->ioctl) ret =3D uport->ops->ioctl(uport, cmd, arg); @@ -1489,7 +1548,8 @@ static void uart_set_termios(struct tty_struct *tty, goto out; } =20 - tty->termios.c_cflag &=3D ~ADDRB; + if (!uport->set_addr) + tty->termios.c_cflag &=3D ~ADDRB; =20 uart_change_speed(tty, state, old_termios); /* reload cflag from termios; port driver may have overridden flags */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 31f7fe527395..ebe1d0ec11d8 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -135,6 +135,12 @@ struct uart_port { struct serial_rs485 *rs485); int (*iso7816_config)(struct uart_port *, struct serial_iso7816 *iso7816); + + int (*set_addr)(struct uart_port *p, + struct serial_addr *addr); + int (*get_addr)(struct uart_port *p, + struct serial_addr *addr); + unsigned int irq; /* irq number */ unsigned long irqflags; /* irq flags */ unsigned int uartclk; /* base uart clock */ diff --git a/include/uapi/asm-generic/ioctls.h b/include/uapi/asm-generic/i= octls.h index cdc9f4ca8c27..689743366091 100644 --- a/include/uapi/asm-generic/ioctls.h +++ b/include/uapi/asm-generic/ioctls.h @@ -106,6 +106,9 @@ # define FIOQSIZE 0x5460 #endif =20 +#define TIOCSADDR _IOWR('T', 0x63, struct serial_addr) +#define TIOCGADDR _IOWR('T', 0x64, struct serial_addr) + /* Used for packet mode */ #define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index f868685b35a0..7b198fd5d390 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -151,4 +151,12 @@ struct serial_iso7816 { __u32 reserved[5]; }; =20 +struct serial_addr { + __u32 flags; +#define SER_ADDR_RECV (1 << 0) +#define SER_ADDR_RECV_CLEAR (1 << 1) +#define SER_ADDR_DEST (1 << 2) + __u32 addr; +}; + #endif /* _UAPI_LINUX_SERIAL_H */ --=20 2.30.2 From nobody Tue Jun 23 16:13:06 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D619C433F5 for ; Wed, 2 Mar 2022 09:58:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240763AbiCBJ6m (ORCPT ); Wed, 2 Mar 2022 04:58:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47892 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240837AbiCBJ6V (ORCPT ); Wed, 2 Mar 2022 04:58:21 -0500 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFEC21CB07; Wed, 2 Mar 2022 01:57:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646215056; x=1677751056; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6eiVEbbk45CnAZ8/EHrebW67L0OGGnBAhyrehZsBcas=; b=GpB7Q8rqyqjoDT2YGvpx3qIjB7vMCdpT12M4UAwMwRnnk3Hm+FqAejWt LNHrzLU93sbXNe7LILSK6q4W3kJ5YEHJ8x1S2XwddE8ckktlZTbitTPod 78zz9UXViM1w+9/GQIDF77k80FoZ/FcRfLQslF+Qec6oDaFbySQEK0aKP cALKwhHPSC1NNpiYo6did9gjOvXG6qMGSPNWurSQPInxc5CSb41CwxXzq KuuwwnLuAaethjfEYGTCP+xMzfygdvqmI6DnQln1Y1LzHVOXfH474ZUcs 592/VGsAVB6mydzT7J+kEBf7/2lSxK8fX0i3NHJqd2IrvaL01xRfdzbWj Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10273"; a="339794650" X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="339794650" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:34 -0800 X-IronPort-AV: E=Sophos;i="5.90,148,1643702400"; d="scan'208";a="551182269" Received: from abotoi-mobl2.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.251.218.48]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2022 01:57:30 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-serial@vger.kernel.org, Jiri Slaby , Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, Lukas Wunner , Johan Hovold , Andy Shevchenko , Heikki Krogerus , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Raymond Tan , Lakshmi Sowjanya Subject: [RFC PATCH 7/7] serial: 8250_dwlib: Support for 9th bit multipoint addressing Date: Wed, 2 Mar 2022 11:56:06 +0200 Message-Id: <20220302095606.14818-8-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> References: <20220302095606.14818-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This change adds 9th bit multipoint addressing mode for DW UART using the new ioctls introduced in the previous change. 9th bit addressing can be used only when HW RS485 is available. Updating RAR (receive address register) is bit tricky because busy indication is not be available when DW UART is strictly 16550 compatible, which is the case with the hardware I was testing with. RAR should not be updated while receive is in progress which is now achieved by deasserting RE and waiting for one frame (in case rx would be in progress, the driver seems to have no way of knowing it w/o busy indication). Co-developed-by: Heikki Krogerus Signed-off-by: Heikki Krogerus Co-developed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Co-developed-by: Raymond Tan Signed-off-by: Raymond Tan Co-developed-by: Lakshmi Sowjanya Signed-off-by: Lakshmi Sowjanya Signed-off-by: Ilpo J=C3=A4rvinen --- drivers/tty/serial/8250/8250_dwlib.c | 124 +++++++++++++++++++++++++++ drivers/tty/serial/8250/8250_dwlib.h | 3 + 2 files changed, 127 insertions(+) diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250= /8250_dwlib.c index 51b0f55ee9d0..57bf6ca0309b 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -3,9 +3,11 @@ =20 #include #include +#include #include #include #include +#include #include #include #include @@ -17,6 +19,9 @@ #define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */ #define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */ #define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ +#define DW_UART_RAR 0xc4 /* Receive Address Register */ +#define DW_UART_TAR 0xc8 /* Transmit Address Register */ +#define DW_UART_LCR_EXT 0xcc /* Line Extended Control Register */ #define DW_UART_CPR 0xf4 /* Component Parameter Register */ #define DW_UART_UCV 0xf8 /* UART Component Version */ =20 @@ -29,6 +34,12 @@ #define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE= , 1) #define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, = 2) =20 +/* Line Extended Control Register bits */ +#define DW_UART_LCR_EXT_DLS_E BIT(0) +#define DW_UART_LCR_EXT_ADDR_MATCH BIT(1) +#define DW_UART_LCR_EXT_SEND_ADDR BIT(2) +#define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3) + /* Component Parameter Register bits */ #define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) #define DW_UART_CPR_AFCE_MODE (1 << 4) @@ -91,16 +102,126 @@ static void dw8250_set_divisor(struct uart_port *p, u= nsigned int baud, serial8250_do_set_divisor(p, baud, quot, quot_frac); } =20 +/* Wait until re is de-asserted for sure. Without BUSY indication availabl= e, + * only available course of action is to wait until current frame is recei= ved. + */ +static void dw8250_wait_re_deassert(struct uart_port *p) +{ + struct dw8250_port_data *d =3D p->private_data; + + if (d->rar_timeout_us) + udelay(d->rar_timeout_us); +} + +static void dw8250_update_rar(struct uart_port *p, u32 addr) +{ + u32 re_en =3D dw8250_readl_ext(p, DW_UART_RE_EN); + + /* RAR shouldn't be changed while receiving. Thus, de-assert RE_EN + * if asserted and wait. + */ + if (re_en) + dw8250_writel_ext(p, DW_UART_RE_EN, 0); + dw8250_wait_re_deassert(p); + dw8250_writel_ext(p, DW_UART_RAR, addr); + if (re_en) + dw8250_writel_ext(p, DW_UART_RE_EN, re_en); +} + +static void dw8250_addrmode_setup(struct uart_port *p, bool enable_addrmod= e) +{ + struct dw8250_port_data *d =3D p->private_data; + + if (enable_addrmode) { + /* Clear RAR & TAR of any previous values */ + dw8250_writel_ext(p, DW_UART_RAR, 0); + dw8250_writel_ext(p, DW_UART_TAR, 0); + dw8250_writel_ext(p, DW_UART_LCR_EXT, DW_UART_LCR_EXT_DLS_E); + } else { + dw8250_writel_ext(p, DW_UART_LCR_EXT, 0); + } + + d->addrmode =3D enable_addrmode; +} + void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, = struct ktermios *old) { + struct dw8250_port_data *d =3D p->private_data; + p->status &=3D ~UPSTAT_AUTOCTS; if (termios->c_cflag & CRTSCTS) p->status |=3D UPSTAT_AUTOCTS; =20 + if (!(p->rs485.flags & SER_RS485_ENABLED) || !d->hw_rs485_support) + termios->c_cflag &=3D ~ADDRB; + + if (!old || (termios->c_cflag ^ old->c_cflag) & ADDRB) + dw8250_addrmode_setup(p, termios->c_cflag & ADDRB); + serial8250_do_set_termios(p, termios, old); + + d->rar_timeout_us =3D termios->c_ispeed ? + DIV_ROUND_UP(tty_get_frame_size(termios->c_cflag) * USEC_PER_SEC, + termios->c_ispeed) : 0; } EXPORT_SYMBOL_GPL(dw8250_do_set_termios); =20 +static int dw8250_rs485_set_addr(struct uart_port *p, struct serial_addr *= addr) +{ + struct dw8250_port_data *d =3D p->private_data; + u32 lcr; + + if (!(p->rs485.flags & SER_RS485_ENABLED) || !d->addrmode) + return -EINVAL; + + addr->flags &=3D SER_ADDR_RECV | SER_ADDR_RECV_CLEAR | SER_ADDR_DEST; + if (!addr->flags) + return -EINVAL; + + lcr =3D dw8250_readl_ext(p, DW_UART_LCR_EXT); + if (addr->flags & SER_ADDR_RECV) { + dw8250_update_rar(p, addr->addr & 0xff); + lcr |=3D DW_UART_LCR_EXT_ADDR_MATCH; + addr->flags &=3D ~SER_ADDR_RECV_CLEAR; + } else if (addr->flags & SER_ADDR_RECV_CLEAR) { + lcr &=3D DW_UART_LCR_EXT_ADDR_MATCH; + } + if (addr->flags & SER_ADDR_DEST) { + dw8250_writel_ext(p, DW_UART_TAR, addr->addr & 0xff); + lcr |=3D DW_UART_LCR_EXT_SEND_ADDR; + } + dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr); + + return 0; +} + +static int dw8250_rs485_get_addr(struct uart_port *p, struct serial_addr *= addr) +{ + struct dw8250_port_data *d =3D p->private_data; + + if (!(p->rs485.flags & SER_RS485_ENABLED) || !d->addrmode) + return -EINVAL; + + if (addr->flags =3D=3D SER_ADDR_DEST) { + addr->addr =3D dw8250_readl_ext(p, DW_UART_TAR) & 0xff; + return 0; + } + if (addr->flags =3D=3D SER_ADDR_RECV) { + u32 lcr =3D dw8250_readl_ext(p, DW_UART_LCR_EXT); + + if (!(lcr & DW_UART_LCR_EXT_ADDR_MATCH)) { + addr->flags =3D SER_ADDR_RECV_CLEAR; + addr->addr =3D 0; + } else { + addr->addr =3D dw8250_readl_ext(p, DW_UART_RAR) & 0xff; + } + + return 0; + } + + return -EINVAL; +} + static void dw8250_rs485_start_tx(struct uart_8250_port *up) { struct uart_port *p =3D &(up->port); @@ -157,6 +278,7 @@ static int dw8250_rs485_config(struct uart_port *p, str= uct serial_rs485 *rs485) tcr &=3D ~DW_UART_TCR_RS485_EN; dw8250_writel_ext(p, DW_UART_DE_EN, 0); dw8250_writel_ext(p, DW_UART_RE_EN, 0); + dw8250_addrmode_setup(p, false); } =20 /* Resetting the default DE_POL & RE_POL */ @@ -203,6 +325,8 @@ void dw8250_setup_port(struct uart_port *p) p->rs485_config =3D dw8250_rs485_config; up->rs485_start_tx =3D dw8250_rs485_start_tx; up->rs485_stop_tx =3D dw8250_rs485_stop_tx; + p->set_addr =3D dw8250_rs485_set_addr; + p->get_addr =3D dw8250_rs485_get_addr; } else { p->rs485_config =3D serial8250_em485_config; up->rs485_start_tx =3D serial8250_em485_start_tx; diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250= /8250_dwlib.h index a8fa020ca544..bfb1d8af7f0c 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -17,6 +17,9 @@ struct dw8250_port_data { =20 /* RS485 variables */ bool hw_rs485_support; + /* 9-bit framing (9th bit is address indicator) */ + bool addrmode; + unsigned int rar_timeout_us; }; =20 void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, = struct ktermios *old); --=20 2.30.2