#include <linux/bitops.h>
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/math.h>
 #include <linux/property.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #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 */
 
+/* Receive / Transmit Address Register bits */
+#define DW_UART_ADDR_MASK              GENMASK(7, 0)
+
+/* Line Status Register bits */
+#define DW_UART_LSR_ADDR_RCVD          BIT(8)
+
 /* Transceiver Control Register bits */
 #define DW_UART_TCR_RS485_EN           BIT(0)
 #define DW_UART_TCR_RE_POL             BIT(1)
 #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)
 
+/* 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)
                p->status |= UPSTAT_AUTOCTS;
 
        serial8250_do_set_termios(p, termios, old);
+
+       /* Filter addresses which have 9th bit set */
+       p->ignore_status_mask |= DW_UART_LSR_ADDR_RCVD;
+       p->read_status_mask |= DW_UART_LSR_ADDR_RCVD;
 }
 EXPORT_SYMBOL_GPL(dw8250_do_set_termios);
 
+/*
+ * Wait until re is de-asserted for sure. An ongoing receive will keep
+ * re asserted until end of frame. Without BUSY indication available,
+ * only available course of action is to wait for the time it takes to
+ * receive one frame (there might nothing to receive but w/o BUSY the
+ * driver cannot know).
+ */
+static void dw8250_wait_re_deassert(struct uart_port *p)
+{
+       ndelay(p->frame_time);
+}
+
+static void dw8250_update_rar(struct uart_port *p, u32 addr)
+{
+       u32 re_en = 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_rs485_set_addr(struct uart_port *p, struct serial_rs485 *rs485,
+                                 struct ktermios *termios)
+{
+       u32 lcr = dw8250_readl_ext(p, DW_UART_LCR_EXT);
+
+       if (rs485->flags & SER_RS485_ADDRB) {
+               lcr |= DW_UART_LCR_EXT_DLS_E;
+               if (termios)
+                       termios->c_cflag |= ADDRB;
+
+               if (rs485->flags & SER_RS485_ADDR_RECV) {
+                       u32 delta = p->rs485.flags ^ rs485->flags;
+
+                       /*
+                        * rs485 (param) is equal to uart_port's rs485 only during init
+                        * (during init, delta is not yet applicable).
+                        */
+                       if (unlikely(&p->rs485 == rs485))
+                               delta = rs485->flags;
+
+                       if ((delta & SER_RS485_ADDR_RECV) ||
+                           (p->rs485.addr_recv != rs485->addr_recv))
+                               dw8250_update_rar(p, rs485->addr_recv);
+                       lcr |= DW_UART_LCR_EXT_ADDR_MATCH;
+               } else {
+                       lcr &= ~DW_UART_LCR_EXT_ADDR_MATCH;
+               }
+               if (rs485->flags & SER_RS485_ADDR_DEST) {
+                       /*
+                        * Don't skip writes here as another endpoint could
+                        * have changed communication line's destination
+                        * address in between.
+                        */
+                       dw8250_writel_ext(p, DW_UART_TAR, rs485->addr_dest);
+                       lcr |= DW_UART_LCR_EXT_SEND_ADDR;
+               }
+       } else {
+               lcr = 0;
+       }
+       dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr);
+}
+
 static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios,
                               struct serial_rs485 *rs485)
 {
                dw8250_writel_ext(p, DW_UART_DE_EN, 1);
                dw8250_writel_ext(p, DW_UART_RE_EN, 1);
        } else {
+               if (termios)
+                       termios->c_cflag &= ~ADDRB;
+
                tcr &= ~DW_UART_TCR_RS485_EN;
        }
 
 
        dw8250_writel_ext(p, DW_UART_TCR, tcr);
 
+       /* Addressing mode can only be set up after TCR */
+       if (rs485->flags & SER_RS485_ENABLED)
+               dw8250_rs485_set_addr(p, rs485, termios);
+
        return 0;
 }
 
 
 static const struct serial_rs485 dw8250_rs485_supported = {
        .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND |
-                SER_RS485_RTS_AFTER_SEND,
+                SER_RS485_RTS_AFTER_SEND | SER_RS485_ADDRB | SER_RS485_ADDR_RECV |
+                SER_RS485_ADDR_DEST,
 };
 
 void dw8250_setup_port(struct uart_port *p)
        pd->hw_rs485_support = dw8250_detect_rs485_hw(p);
        if (pd->hw_rs485_support) {
                p->rs485_config = dw8250_rs485_config;
+               up->lsr_save_mask = LSR_SAVE_FLAGS | DW_UART_LSR_ADDR_RCVD;
                p->rs485_supported = &dw8250_rs485_supported;
        } else {
                p->rs485_config = serial8250_em485_config;