Merge tag 'tty-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Oct 2016 03:11:49 +0000 (20:11 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Oct 2016 03:11:49 +0000 (20:11 -0700)
Pull tty and serial updates from Greg KH:
 "Here is the big tty and serial patch set for 4.9-rc1.

  It also includes some drivers/dma/ changes, as those were needed by
  some serial drivers, and they were all acked by the DMA maintainer.

  Also in here is the long-suffering ACPI SPCR patchset, which was
  passed around from maintainer to maintainer like a hot-potato. Seems I
  was the sucker^Wlucky one. All of those patches have been acked by the
  various subsystem maintainers as well.

  All of this has been in linux-next with no reported issues"

* tag 'tty-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (111 commits)
  Revert "serial: pl011: add console matching function"
  MAINTAINERS: update entry for atmel_serial driver
  serial: pl011: add console matching function
  ARM64: ACPI: enable ACPI_SPCR_TABLE
  ACPI: parse SPCR and enable matching console
  of/serial: move earlycon early_param handling to serial
  Revert "drivers/tty: Explicitly pass current to show_stack"
  tty: amba-pl011: Don't complain on -EPROBE_DEFER when no irq
  nios2: dts: 10m50: Add tx-threshold parameter
  serial: 8250: Set Altera 16550 TX FIFO Threshold
  serial: 8250: of: Load TX FIFO Threshold from DT
  Documentation: dt: serial: Add TX FIFO threshold parameter
  drivers/tty: Explicitly pass current to show_stack
  serial: imx: Fix DCD reading
  serial: stm32: mark symbols static where possible
  serial: xuartps: Add some register initialisation to cdns_early_console_setup()
  serial: xuartps: Removed unwanted checks while reading the error conditions
  serial: xuartps: Rewrite the interrupt handling logic
  serial: stm32: use mapbase instead of membase for DMA
  tty/serial: atmel: fix fractional baud rate computation
  ...

69 files changed:
Documentation/devicetree/bindings/serial/8250.txt
Documentation/devicetree/bindings/serial/st,stm32-usart.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
MAINTAINERS
arch/arm64/Kconfig
arch/arm64/kernel/acpi.c
arch/nios2/boot/dts/10m50_devboard.dts
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/spcr.c [new file with mode: 0644]
drivers/dma/dw/core.c
drivers/dma/dw/regs.h
drivers/dma/hsu/hsu.c
drivers/dma/hsu/pci.c
drivers/dma/imx-sdma.c
drivers/of/fdt.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250.h
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_lpss.c [new file with mode: 0644]
drivers/tty/serial/8250/8250_mid.c
drivers/tty/serial/8250/8250_mtk.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/8250/Makefile
drivers/tty/serial/altera_jtaguart.c
drivers/tty/serial/altera_uart.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/arc_uart.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/bcm63xx_uart.c
drivers/tty/serial/earlycon-arm-semihost.c
drivers/tty/serial/earlycon.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/imx.c
drivers/tty/serial/jsm/jsm_tty.c
drivers/tty/serial/max3100.c
drivers/tty/serial/max310x.c
drivers/tty/serial/men_z135_uart.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/samsung.c
drivers/tty/serial/samsung.h
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/st-asc.c
drivers/tty/serial/stm32-usart.c
drivers/tty/serial/stm32-usart.h [new file with mode: 0644]
drivers/tty/serial/timbuart.c
drivers/tty/serial/uartlite.c
drivers/tty/serial/vt8500_serial.c
drivers/tty/serial/xilinx_uartps.c
drivers/tty/vt/vt.c
fs/devpts/inode.c
include/linux/acpi.h
include/linux/amba/bus.h
include/linux/amba/serial.h
include/linux/atmel_serial.h
include/linux/dma/dw.h
include/linux/dma/hsu.h
include/linux/of_fdt.h
include/linux/platform_data/dma-dw.h
include/linux/serial_core.h
include/uapi/linux/serial_reg.h

index 936ab5b..f86bb06 100644 (file)
@@ -42,6 +42,8 @@ Optional properties:
 - auto-flow-control: one way to enable automatic flow control support. The
   driver is allowed to detect support for the capability even without this
   property.
+- tx-threshold: Specify the TX FIFO low water indication for parts with
+  programmable TX FIFO thresholds.
 
 Note:
 * fsl,ns16550:
diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
new file mode 100644 (file)
index 0000000..85ec5f2
--- /dev/null
@@ -0,0 +1,46 @@
+* STMicroelectronics STM32 USART
+
+Required properties:
+- compatible: Can be either "st,stm32-usart", "st,stm32-uart",
+"st,stm32f7-usart" or "st,stm32f7-uart" depending on whether
+the device supports synchronous mode and is compatible with
+stm32(f4) or stm32f7.
+- reg: The address and length of the peripheral registers space
+- interrupts: The interrupt line of the USART instance
+- clocks: The input clock of the USART instance
+
+Optional properties:
+- pinctrl: The reference on the pins configuration
+- st,hw-flow-ctrl: bool flag to enable hardware flow control.
+- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt
+- dma-names: "rx" and/or "tx"
+
+Examples:
+usart4: serial@40004c00 {
+       compatible = "st,stm32-uart";
+       reg = <0x40004c00 0x400>;
+       interrupts = <52>;
+       clocks = <&clk_pclk1>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usart4>;
+};
+
+usart2: serial@40004400 {
+       compatible = "st,stm32-usart", "st,stm32-uart";
+       reg = <0x40004400 0x400>;
+       interrupts = <38>;
+       clocks = <&clk_pclk1>;
+       st,hw-flow-ctrl;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>;
+};
+
+usart1: serial@40011000 {
+       compatible = "st,stm32-usart", "st,stm32-uart";
+       reg = <0x40011000 0x400>;
+       interrupts = <37>;
+       clocks = <&rcc 0 164>;
+       dmas = <&dma2 2 4 0x414 0x0>,
+              <&dma2 7 4 0x414 0x0>;
+       dma-names = "rx", "tx";
+};
index 25037de..0e28594 100644 (file)
@@ -1054,11 +1054,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        determined by the stdout-path property in device
                        tree's chosen node.
 
-               cdns,<addr>
-                       Start an early, polled-mode console on a cadence serial
-                       port at the specified address. The cadence serial port
-                       must already be setup and configured. Options are not
-                       yet supported.
+               cdns,<addr>[,options]
+                       Start an early, polled-mode console on a Cadence
+                       (xuartps) serial port at the specified address. Only
+                       supported option is baud rate. If baud rate is not
+                       specified, the serial port must already be setup and
+                       configured.
 
                uart[8250],io,<addr>[,options]
                uart[8250],mmio,<addr>[,options]
index d52eae7..434a43d 100644 (file)
@@ -2121,11 +2121,6 @@ M:       Ludovic Desroches <ludovic.desroches@atmel.com>
 S:     Maintained
 F:     drivers/mmc/host/atmel-mci.c
 
-ATMEL AT91 / AT32 SERIAL DRIVER
-M:     Nicolas Ferre <nicolas.ferre@atmel.com>
-S:     Supported
-F:     drivers/tty/serial/atmel_serial.c
-
 ATMEL AT91 SAMA5D2-Compatible Shutdown Controller
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
 S:     Supported
@@ -7774,6 +7769,12 @@ T:       git git://git.monstr.eu/linux-2.6-microblaze.git
 S:     Supported
 F:     arch/microblaze/
 
+MICROCHIP / ATMEL AT91 / AT32 SERIAL DRIVER
+M:     Richard Genoud <richard.genoud@gmail.com>
+S:     Maintained
+F:     drivers/tty/serial/atmel_serial.c
+F:     include/linux/atmel_serial.h
+
 MICROSOFT SURFACE PRO 3 BUTTON DRIVER
 M:     Chen Yu <yu.c.chen@intel.com>
 L:     platform-driver-x86@vger.kernel.org
index 17c14a1..7d6bcf6 100644 (file)
@@ -4,6 +4,7 @@ config ARM64
        select ACPI_GENERIC_GSI if ACPI
        select ACPI_REDUCED_HARDWARE_ONLY if ACPI
        select ACPI_MCFG if ACPI
+       select ACPI_SPCR_TABLE if ACPI
        select ARCH_CLOCKSOURCE_DATA
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
index 3e4f1a4..252a6d9 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/smp.h>
+#include <linux/serial_core.h>
 
 #include <asm/cputype.h>
 #include <asm/cpu_ops.h>
@@ -206,7 +207,7 @@ void __init acpi_boot_table_init(void)
        if (param_acpi_off ||
            (!param_acpi_on && !param_acpi_force &&
             of_scan_flat_dt(dt_scan_depth1_nodes, NULL)))
-               return;
+               goto done;
 
        /*
         * ACPI is disabled at this point. Enable it in order to parse
@@ -226,6 +227,14 @@ void __init acpi_boot_table_init(void)
                if (!param_acpi_force)
                        disable_acpi();
        }
+
+done:
+       if (acpi_disabled) {
+               if (earlycon_init_is_deferred)
+                       early_init_dt_scan_chosen_stdout();
+       } else {
+               parse_spcr(earlycon_init_is_deferred);
+       }
 }
 
 #ifdef CONFIG_ACPI_APEI
index 3e411c6..f362b22 100755 (executable)
@@ -83,6 +83,7 @@
                        fifo-size = <32>;
                        reg-io-width = <4>;
                        reg-shift = <2>;
+                       tx-threshold = <16>;
                };
 
                sysid: sysid@18001528 {
index 33201d4..535e782 100644 (file)
@@ -77,6 +77,9 @@ config ACPI_DEBUGGER_USER
 
 endif
 
+config ACPI_SPCR_TABLE
+       bool
+
 config ACPI_SLEEP
        bool
        depends on SUSPEND || HIBERNATION
index 313f970..9ed0878 100644 (file)
@@ -82,6 +82,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)                += bgrt.o
 obj-$(CONFIG_ACPI_CPPC_LIB)    += cppc_acpi.o
+obj-$(CONFIG_ACPI_SPCR_TABLE)  += spcr.o
 obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
 
 # processor has its own "processor." module_param namespace
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
new file mode 100644 (file)
index 0000000..e8d7bc7
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2012, Intel Corporation
+ * Copyright (c) 2015, Red Hat, Inc.
+ * Copyright (c) 2015, 2016 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "ACPI: SPCR: " fmt
+
+#include <linux/acpi.h>
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/serial_core.h>
+
+/**
+ * parse_spcr() - parse ACPI SPCR table and add preferred console
+ *
+ * @earlycon: set up earlycon for the console specified by the table
+ *
+ * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be
+ * defined to parse ACPI SPCR table.  As a result of the parsing preferred
+ * console is registered and if @earlycon is true, earlycon is set up.
+ *
+ * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called
+ * from arch inintialization code as soon as the DT/ACPI decision is made.
+ *
+ */
+int __init parse_spcr(bool earlycon)
+{
+       static char opts[64];
+       struct acpi_table_spcr *table;
+       acpi_size table_size;
+       acpi_status status;
+       char *uart;
+       char *iotype;
+       int baud_rate;
+       int err;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0,
+                                         (struct acpi_table_header **)&table,
+                                         &table_size);
+
+       if (ACPI_FAILURE(status))
+               return -ENOENT;
+
+       if (table->header.revision < 2) {
+               err = -ENOENT;
+               pr_err("wrong table version\n");
+               goto done;
+       }
+
+       iotype = table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ?
+                       "mmio" : "io";
+
+       switch (table->interface_type) {
+       case ACPI_DBG2_ARM_SBSA_32BIT:
+               iotype = "mmio32";
+               /* fall through */
+       case ACPI_DBG2_ARM_PL011:
+       case ACPI_DBG2_ARM_SBSA_GENERIC:
+       case ACPI_DBG2_BCM2835:
+               uart = "pl011";
+               break;
+       case ACPI_DBG2_16550_COMPATIBLE:
+       case ACPI_DBG2_16550_SUBSET:
+               uart = "uart";
+               break;
+       default:
+               err = -ENOENT;
+               goto done;
+       }
+
+       switch (table->baud_rate) {
+       case 3:
+               baud_rate = 9600;
+               break;
+       case 4:
+               baud_rate = 19200;
+               break;
+       case 6:
+               baud_rate = 57600;
+               break;
+       case 7:
+               baud_rate = 115200;
+               break;
+       default:
+               err = -ENOENT;
+               goto done;
+       }
+
+       snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype,
+                table->serial_port.address, baud_rate);
+
+       pr_info("console: %s\n", opts);
+
+       if (earlycon)
+               setup_earlycon(opts);
+
+       err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
+
+done:
+       early_acpi_os_unmap_memory((void __iomem *)table, table_size);
+       return err;
+}
index edf053f..da18b18 100644 (file)
@@ -46,9 +46,9 @@
                u8 _dmsize = _is_slave ? _sconfig->dst_maxburst :       \
                        DW_DMA_MSIZE_16;                        \
                u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ?         \
-                       _dwc->p_master : _dwc->m_master;                \
+                       _dwc->dws.p_master : _dwc->dws.m_master;        \
                u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ?         \
-                       _dwc->p_master : _dwc->m_master;                \
+                       _dwc->dws.p_master : _dwc->dws.m_master;        \
                                                                \
                (DWC_CTLL_DST_MSIZE(_dmsize)                    \
                 | DWC_CTLL_SRC_MSIZE(_smsize)                  \
@@ -143,12 +143,16 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
        struct dw_dma *dw = to_dw_dma(dwc->chan.device);
        u32 cfghi = DWC_CFGH_FIFO_MODE;
        u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
+       bool hs_polarity = dwc->dws.hs_polarity;
 
        if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
                return;
 
-       cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
-       cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
+       cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
+       cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
+
+       /* Set polarity of handshake interface */
+       cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
 
        channel_writel(dwc, CFG_LO, cfglo);
        channel_writel(dwc, CFG_HI, cfghi);
@@ -209,7 +213,7 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
 static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 {
        struct dw_dma   *dw = to_dw_dma(dwc->chan.device);
-       u8              lms = DWC_LLP_LMS(dwc->m_master);
+       u8              lms = DWC_LLP_LMS(dwc->dws.m_master);
        unsigned long   was_soft_llp;
 
        /* ASSERT:  channel is idle */
@@ -662,7 +666,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        struct dw_desc          *prev;
        size_t                  xfer_count;
        size_t                  offset;
-       u8                      m_master = dwc->m_master;
+       u8                      m_master = dwc->dws.m_master;
        unsigned int            src_width;
        unsigned int            dst_width;
        unsigned int            data_width = dw->pdata->data_width[m_master];
@@ -740,7 +744,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        struct dw_desc          *prev;
        struct dw_desc          *first;
        u32                     ctllo;
-       u8                      m_master = dwc->m_master;
+       u8                      m_master = dwc->dws.m_master;
        u8                      lms = DWC_LLP_LMS(m_master);
        dma_addr_t              reg;
        unsigned int            reg_width;
@@ -895,12 +899,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
                return false;
 
        /* We have to copy data since dws can be temporary storage */
-
-       dwc->src_id = dws->src_id;
-       dwc->dst_id = dws->dst_id;
-
-       dwc->m_master = dws->m_master;
-       dwc->p_master = dws->p_master;
+       memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave));
 
        return true;
 }
@@ -1167,11 +1166,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        spin_lock_irqsave(&dwc->lock, flags);
 
        /* Clear custom channel configuration */
-       dwc->src_id = 0;
-       dwc->dst_id = 0;
-
-       dwc->m_master = 0;
-       dwc->p_master = 0;
+       memset(&dwc->dws, 0, sizeof(struct dw_dma_slave));
 
        clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
 
@@ -1264,7 +1259,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
        struct dw_cyclic_desc           *retval = NULL;
        struct dw_desc                  *desc;
        struct dw_desc                  *last = NULL;
-       u8                              lms = DWC_LLP_LMS(dwc->m_master);
+       u8                              lms = DWC_LLP_LMS(dwc->dws.m_master);
        unsigned long                   was_cyclic;
        unsigned int                    reg_width;
        unsigned int                    periods;
@@ -1576,11 +1571,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
                                (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
                } else {
                        dwc->block_size = pdata->block_size;
-
-                       /* Check if channel supports multi block transfer */
-                       channel_writel(dwc, LLP, DWC_LLP_LOC(0xffffffff));
-                       dwc->nollp = DWC_LLP_LOC(channel_readl(dwc, LLP)) == 0;
-                       channel_writel(dwc, LLP, 0);
+                       dwc->nollp = pdata->is_nollp;
                }
        }
 
index 4b7bd78..f65dd10 100644 (file)
@@ -245,10 +245,7 @@ struct dw_dma_chan {
        bool                    nollp;
 
        /* custom slave configuration */
-       u8                      src_id;
-       u8                      dst_id;
-       u8                      m_master;
-       u8                      p_master;
+       struct dw_dma_slave     dws;
 
        /* configuration passed via .device_config */
        struct dma_slave_config dma_sconfig;
index c5f21ef..29d04ca 100644 (file)
@@ -200,10 +200,9 @@ EXPORT_SYMBOL_GPL(hsu_dma_get_status);
  *      is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0.
  *
  *      Return:
- *      IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise.
+ *      0 for invalid channel number, 1 otherwise.
  */
-irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
-                          u32 status)
+int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status)
 {
        struct hsu_dma_chan *hsuc;
        struct hsu_dma_desc *desc;
@@ -211,7 +210,7 @@ irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
 
        /* Sanity check */
        if (nr >= chip->hsu->nr_channels)
-               return IRQ_NONE;
+               return 0;
 
        hsuc = &chip->hsu->chan[nr];
 
@@ -230,7 +229,7 @@ irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
        }
        spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
 
-       return IRQ_HANDLED;
+       return 1;
 }
 EXPORT_SYMBOL_GPL(hsu_dma_do_irq);
 
index 9916058..b51639f 100644 (file)
@@ -29,7 +29,7 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
        u32 dmaisr;
        u32 status;
        unsigned short i;
-       irqreturn_t ret = IRQ_NONE;
+       int ret = 0;
        int err;
 
        dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
@@ -37,14 +37,14 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
                if (dmaisr & 0x1) {
                        err = hsu_dma_get_status(chip, i, &status);
                        if (err > 0)
-                               ret |= IRQ_HANDLED;
+                               ret |= 1;
                        else if (err == 0)
                                ret |= hsu_dma_do_irq(chip, i, status);
                }
                dmaisr >>= 1;
        }
 
-       return ret;
+       return IRQ_RETVAL(ret);
 }
 
 static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
index 03ec76f..3cb4738 100644 (file)
@@ -648,15 +648,11 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
        writel_relaxed(val, sdma->regs + chnenbl);
 }
 
-static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
-{
-       if (sdmac->desc.callback)
-               sdmac->desc.callback(sdmac->desc.callback_param);
-}
-
 static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 {
        struct sdma_buffer_descriptor *bd;
+       int error = 0;
+       enum dma_status old_status = sdmac->status;
 
        /*
         * loop mode. Iterate over descriptors, re-setup them and
@@ -668,17 +664,42 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
                if (bd->mode.status & BD_DONE)
                        break;
 
-               if (bd->mode.status & BD_RROR)
+               if (bd->mode.status & BD_RROR) {
+                       bd->mode.status &= ~BD_RROR;
                        sdmac->status = DMA_ERROR;
+                       error = -EIO;
+               }
+
+              /*
+               * We use bd->mode.count to calculate the residue, since contains
+               * the number of bytes present in the current buffer descriptor.
+               */
 
+               sdmac->chn_real_count = bd->mode.count;
                bd->mode.status |= BD_DONE;
+               bd->mode.count = sdmac->period_len;
+
+               /*
+                * The callback is called from the interrupt context in order
+                * to reduce latency and to avoid the risk of altering the
+                * SDMA transaction status by the time the client tasklet is
+                * executed.
+                */
+
+               if (sdmac->desc.callback)
+                       sdmac->desc.callback(sdmac->desc.callback_param);
+
                sdmac->buf_tail++;
                sdmac->buf_tail %= sdmac->num_bd;
+
+               if (error)
+                       sdmac->status = old_status;
        }
 }
 
-static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
+static void mxc_sdma_handle_channel_normal(unsigned long data)
 {
+       struct sdma_channel *sdmac = (struct sdma_channel *) data;
        struct sdma_buffer_descriptor *bd;
        int i, error = 0;
 
@@ -705,16 +726,6 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
                sdmac->desc.callback(sdmac->desc.callback_param);
 }
 
-static void sdma_tasklet(unsigned long data)
-{
-       struct sdma_channel *sdmac = (struct sdma_channel *) data;
-
-       if (sdmac->flags & IMX_DMA_SG_LOOP)
-               sdma_handle_channel_loop(sdmac);
-       else
-               mxc_sdma_handle_channel_normal(sdmac);
-}
-
 static irqreturn_t sdma_int_handler(int irq, void *dev_id)
 {
        struct sdma_engine *sdma = dev_id;
@@ -731,8 +742,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
 
                if (sdmac->flags & IMX_DMA_SG_LOOP)
                        sdma_update_channel_loop(sdmac);
-
-               tasklet_schedule(&sdmac->tasklet);
+               else
+                       tasklet_schedule(&sdmac->tasklet);
 
                __clear_bit(channel, &stat);
        }
@@ -1353,7 +1364,8 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
        u32 residue;
 
        if (sdmac->flags & IMX_DMA_SG_LOOP)
-               residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len;
+               residue = (sdmac->num_bd - sdmac->buf_tail) *
+                          sdmac->period_len - sdmac->chn_real_count;
        else
                residue = sdmac->chn_count - sdmac->chn_real_count;
 
@@ -1732,7 +1744,7 @@ static int sdma_probe(struct platform_device *pdev)
                dma_cookie_init(&sdmac->chan);
                sdmac->channel = i;
 
-               tasklet_init(&sdmac->tasklet, sdma_tasklet,
+               tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal,
                             (unsigned long) sdmac);
                /*
                 * Add the channel to the DMAC list. Do not add channel 0 though
index 085c638..c89d5d2 100644 (file)
@@ -924,7 +924,7 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
 
 #ifdef CONFIG_SERIAL_EARLYCON
 
-static int __init early_init_dt_scan_chosen_serial(void)
+int __init early_init_dt_scan_chosen_stdout(void)
 {
        int offset;
        const char *p, *q, *options = NULL;
@@ -968,15 +968,6 @@ static int __init early_init_dt_scan_chosen_serial(void)
        }
        return -ENODEV;
 }
-
-static int __init setup_of_earlycon(char *buf)
-{
-       if (buf)
-               return 0;
-
-       return early_init_dt_scan_chosen_serial();
-}
-early_param("earlycon", setup_of_earlycon);
 #endif
 
 /**
index 51e0d32..a23fa5e 100644 (file)
@@ -800,7 +800,7 @@ out_free_file:
        return retval;
 }
 
-static struct file_operations ptmx_fops;
+static struct file_operations ptmx_fops __ro_after_init;
 
 static void __init unix98_pty_init(void)
 {
index 1a16fea..a697a85 100644 (file)
@@ -31,6 +31,11 @@ struct uart_8250_dma {
        struct dma_chan         *rxchan;
        struct dma_chan         *txchan;
 
+       /* Device address base for DMA operations */
+       phys_addr_t             rx_dma_addr;
+       phys_addr_t             tx_dma_addr;
+
+       /* DMA address of the buffer in memory */
        dma_addr_t              rx_addr;
        dma_addr_t              tx_addr;
 
index dcf43f6..240a361 100644 (file)
@@ -639,7 +639,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
 {
        char match[] = "uart";  /* 8250-specific earlycon name */
        unsigned char iotype;
-       unsigned long addr;
+       resource_size_t addr;
        int i;
 
        if (strncmp(name, match, 4) != 0)
index 3590d01..fdbddbc 100644 (file)
@@ -142,7 +142,7 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p)
        if (dma->rx_running) {
                dmaengine_pause(dma->rxchan);
                __dma_rx_complete(p);
-               dmaengine_terminate_all(dma->rxchan);
+               dmaengine_terminate_async(dma->rxchan);
        }
 }
 EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
@@ -150,6 +150,10 @@ EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
 int serial8250_request_dma(struct uart_8250_port *p)
 {
        struct uart_8250_dma    *dma = p->dma;
+       phys_addr_t rx_dma_addr = dma->rx_dma_addr ?
+                                 dma->rx_dma_addr : p->port.mapbase;
+       phys_addr_t tx_dma_addr = dma->tx_dma_addr ?
+                                 dma->tx_dma_addr : p->port.mapbase;
        dma_cap_mask_t          mask;
        struct dma_slave_caps   caps;
        int                     ret;
@@ -157,11 +161,11 @@ int serial8250_request_dma(struct uart_8250_port *p)
        /* Default slave configuration parameters */
        dma->rxconf.direction           = DMA_DEV_TO_MEM;
        dma->rxconf.src_addr_width      = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       dma->rxconf.src_addr            = p->port.mapbase + UART_RX;
+       dma->rxconf.src_addr            = rx_dma_addr + UART_RX;
 
        dma->txconf.direction           = DMA_MEM_TO_DEV;
        dma->txconf.dst_addr_width      = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       dma->txconf.dst_addr            = p->port.mapbase + UART_TX;
+       dma->txconf.dst_addr            = tx_dma_addr + UART_TX;
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
@@ -247,14 +251,14 @@ void serial8250_release_dma(struct uart_8250_port *p)
                return;
 
        /* Release RX resources */
-       dmaengine_terminate_all(dma->rxchan);
+       dmaengine_terminate_sync(dma->rxchan);
        dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
                          dma->rx_addr);
        dma_release_channel(dma->rxchan);
        dma->rxchan = NULL;
 
        /* Release TX resources */
-       dmaengine_terminate_all(dma->txchan);
+       dmaengine_terminate_sync(dma->txchan);
        dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
                         UART_XMIT_SIZE, DMA_TO_DEVICE);
        dma_release_channel(dma->txchan);
index 5c0c123..459d726 100644 (file)
@@ -365,18 +365,19 @@ static int dw8250_probe(struct platform_device *pdev)
        struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int irq = platform_get_irq(pdev, 0);
        struct uart_port *p = &uart.port;
+       struct device *dev = &pdev->dev;
        struct dw8250_data *data;
        int err;
        u32 val;
 
        if (!regs) {
-               dev_err(&pdev->dev, "no registers defined\n");
+               dev_err(dev, "no registers defined\n");
                return -EINVAL;
        }
 
        if (irq < 0) {
                if (irq != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "cannot get irq\n");
+                       dev_err(dev, "cannot get irq\n");
                return irq;
        }
 
@@ -387,16 +388,16 @@ static int dw8250_probe(struct platform_device *pdev)
        p->pm           = dw8250_do_pm;
        p->type         = PORT_8250;
        p->flags        = UPF_SHARE_IRQ | UPF_FIXED_PORT;
-       p->dev          = &pdev->dev;
+       p->dev          = dev;
        p->iotype       = UPIO_MEM;
        p->serial_in    = dw8250_serial_in;
        p->serial_out   = dw8250_serial_out;
 
-       p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
+       p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
        if (!p->membase)
                return -ENOMEM;
 
-       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -404,57 +405,57 @@ static int dw8250_probe(struct platform_device *pdev)
        data->usr_reg = DW_UART_USR;
        p->private_data = data;
 
-       data->uart_16550_compatible = device_property_read_bool(p->dev,
+       data->uart_16550_compatible = device_property_read_bool(dev,
                                                "snps,uart-16550-compatible");
 
-       err = device_property_read_u32(p->dev, "reg-shift", &val);
+       err = device_property_read_u32(dev, "reg-shift", &val);
        if (!err)
                p->regshift = val;
 
-       err = device_property_read_u32(p->dev, "reg-io-width", &val);
+       err = device_property_read_u32(dev, "reg-io-width", &val);
        if (!err && val == 4) {
                p->iotype = UPIO_MEM32;
                p->serial_in = dw8250_serial_in32;
                p->serial_out = dw8250_serial_out32;
        }
 
-       if (device_property_read_bool(p->dev, "dcd-override")) {
+       if (device_property_read_bool(dev, "dcd-override")) {
                /* Always report DCD as active */
                data->msr_mask_on |= UART_MSR_DCD;
                data->msr_mask_off |= UART_MSR_DDCD;
        }
 
-       if (device_property_read_bool(p->dev, "dsr-override")) {
+       if (device_property_read_bool(dev, "dsr-override")) {
                /* Always report DSR as active */
                data->msr_mask_on |= UART_MSR_DSR;
                data->msr_mask_off |= UART_MSR_DDSR;
        }
 
-       if (device_property_read_bool(p->dev, "cts-override")) {
+       if (device_property_read_bool(dev, "cts-override")) {
                /* Always report CTS as active */
                data->msr_mask_on |= UART_MSR_CTS;
                data->msr_mask_off |= UART_MSR_DCTS;
        }
 
-       if (device_property_read_bool(p->dev, "ri-override")) {
+       if (device_property_read_bool(dev, "ri-override")) {
                /* Always report Ring indicator as inactive */
                data->msr_mask_off |= UART_MSR_RI;
                data->msr_mask_off |= UART_MSR_TERI;
        }
 
        /* Always ask for fixed clock rate from a property. */
-       device_property_read_u32(p->dev, "clock-frequency", &p->uartclk);
+       device_property_read_u32(dev, "clock-frequency", &p->uartclk);
 
        /* If there is separate baudclk, get the rate from it. */
-       data->clk = devm_clk_get(&pdev->dev, "baudclk");
+       data->clk = devm_clk_get(dev, "baudclk");
        if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
-               data->clk = devm_clk_get(&pdev->dev, NULL);
+               data->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
                return -EPROBE_DEFER;
        if (!IS_ERR_OR_NULL(data->clk)) {
                err = clk_prepare_enable(data->clk);
                if (err)
-                       dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
+                       dev_warn(dev, "could not enable optional baudclk: %d\n",
                                 err);
                else
                        p->uartclk = clk_get_rate(data->clk);
@@ -462,24 +463,24 @@ static int dw8250_probe(struct platform_device *pdev)
 
        /* If no clock rate is defined, fail. */
        if (!p->uartclk) {
-               dev_err(&pdev->dev, "clock rate not defined\n");
+               dev_err(dev, "clock rate not defined\n");
                return -EINVAL;
        }
 
-       data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
-       if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
+       data->pclk = devm_clk_get(dev, "apb_pclk");
+       if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) {
                err = -EPROBE_DEFER;
                goto err_clk;
        }
        if (!IS_ERR(data->pclk)) {
                err = clk_prepare_enable(data->pclk);
                if (err) {
-                       dev_err(&pdev->dev, "could not enable apb_pclk\n");
+                       dev_err(dev, "could not enable apb_pclk\n");
                        goto err_clk;
                }
        }
 
-       data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+       data->rst = devm_reset_control_get_optional(dev, NULL);
        if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
                err = -EPROBE_DEFER;
                goto err_pclk;
@@ -511,8 +512,8 @@ static int dw8250_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, data);
 
-       pm_runtime_set_active(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
 
        return 0;
 
@@ -624,6 +625,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
        { "APMC0D08", 0},
        { "AMD0020", 0 },
        { "AMDI0020", 0 },
+       { "HISI0031", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
new file mode 100644 (file)
index 0000000..886fcf3
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * 8250_lpss.c - Driver for UART on Intel Braswell and various other Intel SoCs
+ *
+ * Copyright (C) 2016 Intel Corporation
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/rational.h>
+
+#include <linux/dmaengine.h>
+#include <linux/dma/dw.h>
+
+#include "8250.h"
+
+#define PCI_DEVICE_ID_INTEL_QRK_UARTx  0x0936
+
+#define PCI_DEVICE_ID_INTEL_BYT_UART1  0x0f0a
+#define PCI_DEVICE_ID_INTEL_BYT_UART2  0x0f0c
+
+#define PCI_DEVICE_ID_INTEL_BSW_UART1  0x228a
+#define PCI_DEVICE_ID_INTEL_BSW_UART2  0x228c
+
+#define PCI_DEVICE_ID_INTEL_BDW_UART1  0x9ce3
+#define PCI_DEVICE_ID_INTEL_BDW_UART2  0x9ce4
+
+/* Intel LPSS specific registers */
+
+#define BYT_PRV_CLK                    0x800
+#define BYT_PRV_CLK_EN                 BIT(0)
+#define BYT_PRV_CLK_M_VAL_SHIFT                1
+#define BYT_PRV_CLK_N_VAL_SHIFT                16
+#define BYT_PRV_CLK_UPDATE             BIT(31)
+
+#define BYT_TX_OVF_INT                 0x820
+#define BYT_TX_OVF_INT_MASK            BIT(1)
+
+struct lpss8250;
+
+struct lpss8250_board {
+       unsigned long freq;
+       unsigned int base_baud;
+       int (*setup)(struct lpss8250 *, struct uart_port *p);
+       void (*exit)(struct lpss8250 *);
+};
+
+struct lpss8250 {
+       int line;
+       struct lpss8250_board *board;
+
+       /* DMA parameters */
+       struct uart_8250_dma dma;
+       struct dw_dma_chip dma_chip;
+       struct dw_dma_slave dma_param;
+       u8 dma_maxburst;
+};
+
+static void byt_set_termios(struct uart_port *p, struct ktermios *termios,
+                           struct ktermios *old)
+{
+       unsigned int baud = tty_termios_baud_rate(termios);
+       struct lpss8250 *lpss = p->private_data;
+       unsigned long fref = lpss->board->freq, fuart = baud * 16;
+       unsigned long w = BIT(15) - 1;
+       unsigned long m, n;
+       u32 reg;
+
+       /* Gracefully handle the B0 case: fall back to B9600 */
+       fuart = fuart ? fuart : 9600 * 16;
+
+       /* Get Fuart closer to Fref */
+       fuart *= rounddown_pow_of_two(fref / fuart);
+
+       /*
+        * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
+        * dividers must be adjusted.
+        *
+        * uartclk = (m / n) * 100 MHz, where m <= n
+        */
+       rational_best_approximation(fuart, fref, w, w, &m, &n);
+       p->uartclk = fuart;
+
+       /* Reset the clock */
+       reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
+       writel(reg, p->membase + BYT_PRV_CLK);
+       reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
+       writel(reg, p->membase + BYT_PRV_CLK);
+
+       p->status &= ~UPSTAT_AUTOCTS;
+       if (termios->c_cflag & CRTSCTS)
+               p->status |= UPSTAT_AUTOCTS;
+
+       serial8250_do_set_termios(p, termios, old);
+}
+
+static unsigned int byt_get_mctrl(struct uart_port *port)
+{
+       unsigned int ret = serial8250_do_get_mctrl(port);
+
+       /* Force DCD and DSR signals to permanently be reported as active */
+       ret |= TIOCM_CAR | TIOCM_DSR;
+
+       return ret;
+}
+
+static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
+{
+       struct dw_dma_slave *param = &lpss->dma_param;
+       struct uart_8250_port *up = up_to_u8250p(port);
+       struct pci_dev *pdev = to_pci_dev(port->dev);
+       unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
+       struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn);
+
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_INTEL_BYT_UART1:
+       case PCI_DEVICE_ID_INTEL_BSW_UART1:
+       case PCI_DEVICE_ID_INTEL_BDW_UART1:
+               param->src_id = 3;
+               param->dst_id = 2;
+               break;
+       case PCI_DEVICE_ID_INTEL_BYT_UART2:
+       case PCI_DEVICE_ID_INTEL_BSW_UART2:
+       case PCI_DEVICE_ID_INTEL_BDW_UART2:
+               param->src_id = 5;
+               param->dst_id = 4;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       param->dma_dev = &dma_dev->dev;
+       param->m_master = 0;
+       param->p_master = 1;
+
+       /* TODO: Detect FIFO size automaticaly for DesignWare 8250 */
+       port->fifosize = 64;
+       up->tx_loadsz = 64;
+
+       lpss->dma_maxburst = 16;
+
+       port->set_termios = byt_set_termios;
+       port->get_mctrl = byt_get_mctrl;
+
+       /* Disable TX counter interrupts */
+       writel(BYT_TX_OVF_INT_MASK, port->membase + BYT_TX_OVF_INT);
+
+       return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250_DMA
+static const struct dw_dma_platform_data qrk_serial_dma_pdata = {
+       .nr_channels = 2,
+       .is_private = true,
+       .is_nollp = true,
+       .chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
+       .chan_priority = CHAN_PRIORITY_ASCENDING,
+       .block_size = 4095,
+       .nr_masters = 1,
+       .data_width = {4},
+};
+
+static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port)
+{
+       struct uart_8250_dma *dma = &lpss->dma;
+       struct dw_dma_chip *chip = &lpss->dma_chip;
+       struct dw_dma_slave *param = &lpss->dma_param;
+       struct pci_dev *pdev = to_pci_dev(port->dev);
+       int ret;
+
+       chip->dev = &pdev->dev;
+       chip->irq = pdev->irq;
+       chip->regs = pci_ioremap_bar(pdev, 1);
+       chip->pdata = &qrk_serial_dma_pdata;
+
+       /* Falling back to PIO mode if DMA probing fails */
+       ret = dw_dma_probe(chip);
+       if (ret)
+               return;
+
+       /* Special DMA address for UART */
+       dma->rx_dma_addr = 0xfffff000;
+       dma->tx_dma_addr = 0xfffff000;
+
+       param->dma_dev = &pdev->dev;
+       param->src_id = 0;
+       param->dst_id = 1;
+       param->hs_polarity = true;
+
+       lpss->dma_maxburst = 8;
+}
+
+static void qrk_serial_exit_dma(struct lpss8250 *lpss)
+{
+       struct dw_dma_slave *param = &lpss->dma_param;
+
+       if (!param->dma_dev)
+               return;
+       dw_dma_remove(&lpss->dma_chip);
+}
+#else  /* CONFIG_SERIAL_8250_DMA */
+static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) {}
+static void qrk_serial_exit_dma(struct lpss8250 *lpss) {}
+#endif /* !CONFIG_SERIAL_8250_DMA */
+
+static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
+{
+       struct pci_dev *pdev = to_pci_dev(port->dev);
+       int ret;
+
+       ret = pci_alloc_irq_vectors(pdev, 1, 1, 0);
+       if (ret < 0)
+               return ret;
+
+       port->irq = pci_irq_vector(pdev, 0);
+
+       qrk_serial_setup_dma(lpss, port);
+       return 0;
+}
+
+static void qrk_serial_exit(struct lpss8250 *lpss)
+{
+       qrk_serial_exit_dma(lpss);
+}
+
+static bool lpss8250_dma_filter(struct dma_chan *chan, void *param)
+{
+       struct dw_dma_slave *dws = param;
+
+       if (dws->dma_dev != chan->device->dev)
+               return false;
+
+       chan->private = dws;
+       return true;
+}
+
+static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port)
+{
+       struct uart_8250_dma *dma = &lpss->dma;
+       struct dw_dma_slave *rx_param, *tx_param;
+       struct device *dev = port->port.dev;
+
+       if (!lpss->dma_param.dma_dev)
+               return 0;
+
+       rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
+       if (!rx_param)
+               return -ENOMEM;
+
+       tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
+       if (!tx_param)
+               return -ENOMEM;
+
+       *rx_param = lpss->dma_param;
+       dma->rxconf.src_maxburst = lpss->dma_maxburst;
+
+       *tx_param = lpss->dma_param;
+       dma->txconf.dst_maxburst = lpss->dma_maxburst;
+
+       dma->fn = lpss8250_dma_filter;
+       dma->rx_param = rx_param;
+       dma->tx_param = tx_param;
+
+       port->dma = dma;
+       return 0;
+}
+
+static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct uart_8250_port uart;
+       struct lpss8250 *lpss;
+       int ret;
+
+       ret = pcim_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       pci_set_master(pdev);
+
+       lpss = devm_kzalloc(&pdev->dev, sizeof(*lpss), GFP_KERNEL);
+       if (!lpss)
+               return -ENOMEM;
+
+       lpss->board = (struct lpss8250_board *)id->driver_data;
+
+       memset(&uart, 0, sizeof(struct uart_8250_port));
+
+       uart.port.dev = &pdev->dev;
+       uart.port.irq = pdev->irq;
+       uart.port.private_data = lpss;
+       uart.port.type = PORT_16550A;
+       uart.port.iotype = UPIO_MEM;
+       uart.port.regshift = 2;
+       uart.port.uartclk = lpss->board->base_baud * 16;
+       uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+       uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE;
+       uart.port.mapbase = pci_resource_start(pdev, 0);
+       uart.port.membase = pcim_iomap(pdev, 0, 0);
+       if (!uart.port.membase)
+               return -ENOMEM;
+
+       ret = lpss->board->setup(lpss, &uart.port);
+       if (ret)
+               return ret;
+
+       ret = lpss8250_dma_setup(lpss, &uart);
+       if (ret)
+               goto err_exit;
+
+       ret = serial8250_register_8250_port(&uart);
+       if (ret < 0)
+               goto err_exit;
+
+       lpss->line = ret;
+
+       pci_set_drvdata(pdev, lpss);
+       return 0;
+
+err_exit:
+       if (lpss->board->exit)
+               lpss->board->exit(lpss);
+       return ret;
+}
+
+static void lpss8250_remove(struct pci_dev *pdev)
+{
+       struct lpss8250 *lpss = pci_get_drvdata(pdev);
+
+       if (lpss->board->exit)
+               lpss->board->exit(lpss);
+
+       serial8250_unregister_port(lpss->line);
+}
+
+static const struct lpss8250_board byt_board = {
+       .freq = 100000000,
+       .base_baud = 2764800,
+       .setup = byt_serial_setup,
+};
+
+static const struct lpss8250_board qrk_board = {
+       .freq = 44236800,
+       .base_baud = 2764800,
+       .setup = qrk_serial_setup,
+       .exit = qrk_serial_exit,
+};
+
+#define LPSS_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
+
+static const struct pci_device_id pci_ids[] = {
+       LPSS_DEVICE(PCI_DEVICE_ID_INTEL_QRK_UARTx, qrk_board),
+       LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART1, byt_board),
+       LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART2, byt_board),
+       LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART1, byt_board),
+       LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART2, byt_board),
+       LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART1, byt_board),
+       LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART2, byt_board),
+       { },
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver lpss8250_pci_driver = {
+       .name           = "8250_lpss",
+       .id_table       = pci_ids,
+       .probe          = lpss8250_probe,
+       .remove         = lpss8250_remove,
+};
+
+module_pci_driver(lpss8250_pci_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel LPSS UART driver");
index 20c5db2..39c2324 100644 (file)
@@ -99,27 +99,27 @@ static int dnv_handle_irq(struct uart_port *p)
        struct uart_8250_port *up = up_to_u8250p(p);
        unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
        u32 status;
-       int ret = IRQ_NONE;
+       int ret = 0;
        int err;
 
        if (fisr & BIT(2)) {
                err = hsu_dma_get_status(&mid->dma_chip, 1, &status);
                if (err > 0) {
                        serial8250_rx_dma_flush(up);
-                       ret |= IRQ_HANDLED;
+                       ret |= 1;
                } else if (err == 0)
                        ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status);
        }
        if (fisr & BIT(1)) {
                err = hsu_dma_get_status(&mid->dma_chip, 0, &status);
                if (err > 0)
-                       ret |= IRQ_HANDLED;
+                       ret |= 1;
                else if (err == 0)
                        ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status);
        }
        if (fisr & BIT(0))
                ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
-       return ret;
+       return IRQ_RETVAL(ret);
 }
 
 #define DNV_DMA_CHAN_OFFSET 0x80
index 3611ec9..ce0cc47 100644 (file)
@@ -62,7 +62,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
         */
        baud = uart_get_baud_rate(port, termios, old,
                                  port->uartclk / 16 / 0xffff,
-                                 port->uartclk / 16);
+                                 port->uartclk);
 
        if (baud <= 115200) {
                serial_port_out(port, UART_MTK_HIGHS, 0x0);
@@ -76,10 +76,6 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
                quot = DIV_ROUND_UP(port->uartclk, 4 * baud);
        } else {
                serial_port_out(port, UART_MTK_HIGHS, 0x3);
-
-               /* Set to highest baudrate supported */
-               if (baud >= 1152000)
-                       baud = 921600;
                quot = DIV_ROUND_UP(port->uartclk, 256 * baud);
        }
 
index 38963d7..7a8b5fc 100644 (file)
@@ -195,6 +195,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
        switch (port_type) {
        case PORT_8250 ... PORT_MAX_8250:
        {
+               u32 tx_threshold;
                struct uart_8250_port port8250;
                memset(&port8250, 0, sizeof(port8250));
                port8250.port = port;
@@ -202,6 +203,12 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
                if (port.fifosize)
                        port8250.capabilities = UART_CAP_FIFO;
 
+               /* Check for TX FIFO threshold & set tx_loadsz */
+               if ((of_property_read_u32(ofdev->dev.of_node, "tx-threshold",
+                                         &tx_threshold) == 0) &&
+                   (tx_threshold < port.fifosize))
+                       port8250.tx_loadsz = port.fifosize - tx_threshold;
+
                if (of_property_read_bool(ofdev->dev.of_node,
                                          "auto-flow-control"))
                        port8250.capabilities |= UART_CAP_AFE;
index bc51b32..b98c157 100644 (file)
 #include <linux/serial_core.h>
 #include <linux/8250_pci.h>
 #include <linux/bitops.h>
-#include <linux/rational.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
 
-#include <linux/dmaengine.h>
-#include <linux/platform_data/dma-dw.h>
-
 #include "8250.h"
 
 /*
@@ -1349,160 +1345,6 @@ ce4100_serial_setup(struct serial_private *priv,
        return ret;
 }
 
-#define PCI_DEVICE_ID_INTEL_BYT_UART1  0x0f0a
-#define PCI_DEVICE_ID_INTEL_BYT_UART2  0x0f0c
-
-#define PCI_DEVICE_ID_INTEL_BSW_UART1  0x228a
-#define PCI_DEVICE_ID_INTEL_BSW_UART2  0x228c
-
-#define PCI_DEVICE_ID_INTEL_BDW_UART1  0x9ce3
-#define PCI_DEVICE_ID_INTEL_BDW_UART2  0x9ce4
-
-#define BYT_PRV_CLK                    0x800
-#define BYT_PRV_CLK_EN                 (1 << 0)
-#define BYT_PRV_CLK_M_VAL_SHIFT                1
-#define BYT_PRV_CLK_N_VAL_SHIFT                16
-#define BYT_PRV_CLK_UPDATE             (1 << 31)
-
-#define BYT_TX_OVF_INT                 0x820
-#define BYT_TX_OVF_INT_MASK            (1 << 1)
-
-static void
-byt_set_termios(struct uart_port *p, struct ktermios *termios,
-               struct ktermios *old)
-{
-       unsigned int baud = tty_termios_baud_rate(termios);
-       unsigned long fref = 100000000, fuart = baud * 16;
-       unsigned long w = BIT(15) - 1;
-       unsigned long m, n;
-       u32 reg;
-
-       /* Gracefully handle the B0 case: fall back to B9600 */
-       fuart = fuart ? fuart : 9600 * 16;
-
-       /* Get Fuart closer to Fref */
-       fuart *= rounddown_pow_of_two(fref / fuart);
-
-       /*
-        * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
-        * dividers must be adjusted.
-        *
-        * uartclk = (m / n) * 100 MHz, where m <= n
-        */
-       rational_best_approximation(fuart, fref, w, w, &m, &n);
-       p->uartclk = fuart;
-
-       /* Reset the clock */
-       reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
-       writel(reg, p->membase + BYT_PRV_CLK);
-       reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
-       writel(reg, p->membase + BYT_PRV_CLK);
-
-       p->status &= ~UPSTAT_AUTOCTS;
-       if (termios->c_cflag & CRTSCTS)
-               p->status |= UPSTAT_AUTOCTS;
-
-       serial8250_do_set_termios(p, termios, old);
-}
-
-static bool byt_dma_filter(struct dma_chan *chan, void *param)
-{
-       struct dw_dma_slave *dws = param;
-
-       if (dws->dma_dev != chan->device->dev)
-               return false;
-
-       chan->private = dws;
-       return true;
-}
-
-static unsigned int
-byt_get_mctrl(struct uart_port *port)
-{
-       unsigned int ret = serial8250_do_get_mctrl(port);
-
-       /* Force DCD and DSR signals to permanently be reported as active. */
-       ret |= TIOCM_CAR | TIOCM_DSR;
-
-       return ret;
-}
-
-static int
-byt_serial_setup(struct serial_private *priv,
-                const struct pciserial_board *board,
-                struct uart_8250_port *port, int idx)
-{
-       struct pci_dev *pdev = priv->dev;
-       struct device *dev = port->port.dev;
-       struct uart_8250_dma *dma;
-       struct dw_dma_slave *tx_param, *rx_param;
-       struct pci_dev *dma_dev;
-       int ret;
-
-       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
-       if (!dma)
-               return -ENOMEM;
-
-       tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
-       if (!tx_param)
-               return -ENOMEM;
-
-       rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
-       if (!rx_param)
-               return -ENOMEM;
-
-       switch (pdev->device) {
-       case PCI_DEVICE_ID_INTEL_BYT_UART1:
-       case PCI_DEVICE_ID_INTEL_BSW_UART1:
-       case PCI_DEVICE_ID_INTEL_BDW_UART1:
-               rx_param->src_id = 3;
-               tx_param->dst_id = 2;
-               break;
-       case PCI_DEVICE_ID_INTEL_BYT_UART2:
-       case PCI_DEVICE_ID_INTEL_BSW_UART2:
-       case PCI_DEVICE_ID_INTEL_BDW_UART2:
-               rx_param->src_id = 5;
-               tx_param->dst_id = 4;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       rx_param->m_master = 0;
-       rx_param->p_master = 1;
-
-       dma->rxconf.src_maxburst = 16;
-
-       tx_param->m_master = 0;
-       tx_param->p_master = 1;
-
-       dma->txconf.dst_maxburst = 16;
-
-       dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
-       rx_param->dma_dev = &dma_dev->dev;
-       tx_param->dma_dev = &dma_dev->dev;
-
-       dma->fn = byt_dma_filter;
-       dma->rx_param = rx_param;
-       dma->tx_param = tx_param;
-
-       ret = pci_default_setup(priv, board, port, idx);
-       port->port.iotype = UPIO_MEM;
-       port->port.type = PORT_16550A;
-       port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
-       port->port.set_termios = byt_set_termios;
-       port->port.get_mctrl = byt_get_mctrl;
-       port->port.fifosize = 64;
-       port->tx_loadsz = 64;
-       port->dma = dma;
-       port->capabilities = UART_CAP_FIFO | UART_CAP_AFE;
-
-       /* Disable Tx counter interrupts */
-       writel(BYT_TX_OVF_INT_MASK, port->port.membase + BYT_TX_OVF_INT);
-
-       return ret;
-}
-
 static int
 pci_omegapci_setup(struct serial_private *priv,
                      const struct pciserial_board *board,
@@ -1741,6 +1583,19 @@ static int pci_eg20t_init(struct pci_dev *dev)
 #define PCI_DEVICE_ID_EXAR_XR17V4358   0x4358
 #define PCI_DEVICE_ID_EXAR_XR17V8358   0x8358
 
+#define UART_EXAR_MPIOINT_7_0  0x8f    /* MPIOINT[7:0] */
+#define UART_EXAR_MPIOLVL_7_0  0x90    /* MPIOLVL[7:0] */
+#define UART_EXAR_MPIO3T_7_0   0x91    /* MPIO3T[7:0] */
+#define UART_EXAR_MPIOINV_7_0  0x92    /* MPIOINV[7:0] */
+#define UART_EXAR_MPIOSEL_7_0  0x93    /* MPIOSEL[7:0] */
+#define UART_EXAR_MPIOOD_7_0   0x94    /* MPIOOD[7:0] */
+#define UART_EXAR_MPIOINT_15_8 0x95    /* MPIOINT[15:8] */
+#define UART_EXAR_MPIOLVL_15_8 0x96    /* MPIOLVL[15:8] */
+#define UART_EXAR_MPIO3T_15_8  0x97    /* MPIO3T[15:8] */
+#define UART_EXAR_MPIOINV_15_8 0x98    /* MPIOINV[15:8] */
+#define UART_EXAR_MPIOSEL_15_8 0x99    /* MPIOSEL[15:8] */
+#define UART_EXAR_MPIOOD_15_8  0x9a    /* MPIOOD[15:8] */
+
 static int
 pci_xr17c154_setup(struct serial_private *priv,
                  const struct pciserial_board *board,
@@ -1783,18 +1638,18 @@ pci_xr17v35x_setup(struct serial_private *priv,
         * Setup Multipurpose Input/Output pins.
         */
        if (idx == 0) {
-               writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/
-               writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/
-               writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/
-               writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/
-               writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/
-               writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/
-               writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/
-               writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/
-               writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/
-               writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/
-               writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/
-               writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/
+               writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
+               writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
+               writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
+               writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
+               writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
+               writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
+               writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
+               writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
+               writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
+               writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
+               writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
+               writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
        }
        writeb(0x00, p + UART_EXAR_8XMODE);
        writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
@@ -1830,20 +1685,20 @@ pci_fastcom335_setup(struct serial_private *priv,
                switch (priv->dev->device) {
                case PCI_DEVICE_ID_COMMTECH_4222PCI335:
                case PCI_DEVICE_ID_COMMTECH_4224PCI335:
-                       writeb(0x78, p + 0x90); /* MPIOLVL[7:0] */
-                       writeb(0x00, p + 0x92); /* MPIOINV[7:0] */
-                       writeb(0x00, p + 0x93); /* MPIOSEL[7:0] */
+                       writeb(0x78, p + UART_EXAR_MPIOLVL_7_0);
+                       writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
+                       writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
                        break;
                case PCI_DEVICE_ID_COMMTECH_2324PCI335:
                case PCI_DEVICE_ID_COMMTECH_2328PCI335:
-                       writeb(0x00, p + 0x90); /* MPIOLVL[7:0] */
-                       writeb(0xc0, p + 0x92); /* MPIOINV[7:0] */
-                       writeb(0xc0, p + 0x93); /* MPIOSEL[7:0] */
+                       writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
+                       writeb(0xc0, p + UART_EXAR_MPIOINV_7_0);
+                       writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0);
                        break;
                }
-               writeb(0x00, p + 0x8f); /* MPIOINT[7:0] */
-               writeb(0x00, p + 0x91); /* MPIO3T[7:0] */
-               writeb(0x00, p + 0x94); /* MPIOOD[7:0] */
+               writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
+               writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
+               writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
        }
        writeb(0x00, p + UART_EXAR_8XMODE);
        writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
@@ -1934,7 +1789,6 @@ pci_wch_ch38x_setup(struct serial_private *priv,
 #define PCI_DEVICE_ID_COMMTECH_4222PCIE        0x0022
 #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
 #define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
-#define PCI_DEVICE_ID_INTEL_QRK_UART   0x0936
 
 #define PCI_VENDOR_ID_SUNIX            0x1fd4
 #define PCI_DEVICE_ID_SUNIX_1999       0x1999
@@ -2078,48 +1932,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = kt_serial_setup,
        },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_BYT_UART1,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = byt_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_BYT_UART2,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = byt_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_BSW_UART1,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = byt_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_BSW_UART2,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = byt_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_BDW_UART1,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = byt_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_BDW_UART2,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = byt_serial_setup,
-       },
        /*
         * ITE
         */
@@ -2992,8 +2804,6 @@ enum pci_board_num_t {
        pbn_ADDIDATA_PCIe_4_3906250,
        pbn_ADDIDATA_PCIe_8_3906250,
        pbn_ce4100_1_115200,
-       pbn_byt,
-       pbn_qrk,
        pbn_omegapci,
        pbn_NETMOS9900_2s_115200,
        pbn_brcm_trumanage,
@@ -3769,18 +3579,6 @@ static struct pciserial_board pci_boards[] = {
                .base_baud      = 921600,
                .reg_shift      = 2,
        },
-       [pbn_byt] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 2764800,
-               .reg_shift      = 2,
-       },
-       [pbn_qrk] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 2764800,
-               .reg_shift      = 2,
-       },
        [pbn_omegapci] = {
                .flags          = FL_BASE0,
                .num_ports      = 8,
@@ -3892,6 +3690,15 @@ static const struct pci_device_id blacklist[] = {
        { PCI_VDEVICE(INTEL, 0x081d), },
        { PCI_VDEVICE(INTEL, 0x1191), },
        { PCI_VDEVICE(INTEL, 0x19d8), },
+
+       /* Intel platforms with DesignWare UART */
+       { PCI_VDEVICE(INTEL, 0x0936), },
+       { PCI_VDEVICE(INTEL, 0x0f0a), },
+       { PCI_VDEVICE(INTEL, 0x0f0c), },
+       { PCI_VDEVICE(INTEL, 0x228a), },
+       { PCI_VDEVICE(INTEL, 0x228c), },
+       { PCI_VDEVICE(INTEL, 0x9ce3), },
+       { PCI_VDEVICE(INTEL, 0x9ce4), },
 };
 
 /*
@@ -5659,40 +5466,7 @@ static struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
                PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
                pbn_ce4100_1_115200 },
-       /* Intel BayTrail */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1,
-               PCI_ANY_ID,  PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
-               pbn_byt },
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2,
-               PCI_ANY_ID,  PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
-               pbn_byt },
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART1,
-               PCI_ANY_ID,  PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
-               pbn_byt },
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART2,
-               PCI_ANY_ID,  PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
-               pbn_byt },
-
-       /* Intel Broadwell */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART1,
-               PCI_ANY_ID,  PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
-               pbn_byt },
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART2,
-               PCI_ANY_ID,  PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
-               pbn_byt },
 
-       /*
-        * Intel Quark x1000
-        */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_qrk },
        /*
         * Cronyx Omega PCI
         */
index bdfa659..1bfb6fd 100644 (file)
@@ -178,7 +178,7 @@ static const struct serial8250_config uart_config[] = {
                .fifo_size      = 16,
                .tx_loadsz      = 16,
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
-               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+               .flags          = UART_CAP_FIFO /* | UART_CAP_AFE */,
        },
        [PORT_U6_16550A] = {
                .name           = "U6_16550A",
@@ -585,11 +585,11 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put);
  */
 int serial8250_em485_init(struct uart_8250_port *p)
 {
-       if (p->em485 != NULL)
+       if (p->em485)
                return 0;
 
        p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
-       if (p->em485 == NULL)
+       if (!p->em485)
                return -ENOMEM;
 
        setup_timer(&p->em485->stop_tx_timer,
@@ -619,7 +619,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_init);
  */
 void serial8250_em485_destroy(struct uart_8250_port *p)
 {
-       if (p->em485 == NULL)
+       if (!p->em485)
                return;
 
        del_timer(&p->em485->start_tx_timer);
@@ -1402,10 +1402,8 @@ static void serial8250_stop_rx(struct uart_port *port)
 
 static void __do_stop_tx_rs485(struct uart_8250_port *p)
 {
-       if (!p->em485)
-               return;
-
        serial8250_em485_rts_after_send(p);
+
        /*
         * Empty the RX FIFO, we are not interested in anything
         * received during the half-duplex transmission.
@@ -1414,12 +1412,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
        if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
                serial8250_clear_fifos(p);
 
-               serial8250_rpm_get(p);
-
                p->ier |= UART_IER_RLSI | UART_IER_RDI;
                serial_port_out(&p->port, UART_IER, p->ier);
-
-               serial8250_rpm_put(p);
        }
 }
 
@@ -1429,6 +1423,7 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg)
        struct uart_8250_em485 *em485 = p->em485;
        unsigned long flags;
 
+       serial8250_rpm_get(p);
        spin_lock_irqsave(&p->port.lock, flags);
        if (em485 &&
            em485->active_timer == &em485->stop_tx_timer) {
@@ -1436,15 +1431,13 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg)
                em485->active_timer = NULL;
        }
        spin_unlock_irqrestore(&p->port.lock, flags);
+       serial8250_rpm_put(p);
 }
 
 static void __stop_tx_rs485(struct uart_8250_port *p)
 {
        struct uart_8250_em485 *em485 = p->em485;
 
-       if (!em485)
-               return;
-
        /*
         * __do_stop_tx_rs485 is going to set RTS according to config
         * AND flush RX FIFO if required.
@@ -1475,7 +1468,7 @@ static inline void __stop_tx(struct uart_8250_port *p)
                unsigned char lsr = serial_in(p, UART_LSR);
                /*
                 * To provide required timeing and allow FIFO transfer,
-                * __stop_tx_rs485 must be called only when both FIFO and
+                * __stop_tx_rs485() must be called only when both FIFO and
                 * shift register are empty. It is for device driver to enable
                 * interrupt on TEMT.
                 */
@@ -1484,9 +1477,10 @@ static inline void __stop_tx(struct uart_8250_port *p)
 
                del_timer(&em485->start_tx_timer);
                em485->active_timer = NULL;
+
+               __stop_tx_rs485(p);
        }
        __do_stop_tx(p);
-       __stop_tx_rs485(p);
 }
 
 static void serial8250_stop_tx(struct uart_port *port)
@@ -1876,6 +1870,30 @@ static int exar_handle_irq(struct uart_port *port)
        return ret;
 }
 
+/*
+ * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP
+ * have a programmable TX threshold that triggers the THRE interrupt in
+ * the IIR register. In this case, the THRE interrupt indicates the FIFO
+ * has space available. Load it up with tx_loadsz bytes.
+ */
+static int serial8250_tx_threshold_handle_irq(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int iir = serial_port_in(port, UART_IIR);
+
+       /* TX Threshold IRQ triggered so load up FIFO */
+       if ((iir & UART_IIR_ID) == UART_IIR_THRI) {
+               struct uart_8250_port *up = up_to_u8250p(port);
+
+               spin_lock_irqsave(&port->lock, flags);
+               serial8250_tx_chars(up);
+               spin_unlock_irqrestore(&port->lock, flags);
+       }
+
+       iir = serial_port_in(port, UART_IIR);
+       return serial8250_handle_irq(port, iir);
+}
+
 static unsigned int serial8250_tx_empty(struct uart_port *port)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
@@ -1988,6 +2006,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
                if (--tmout == 0)
                        break;
                udelay(1);
+               touch_nmi_watchdog();
        }
 
        /* Wait up to 1s for flow control if necessary */
@@ -2164,6 +2183,25 @@ int serial8250_do_startup(struct uart_port *port)
                serial_port_out(port, UART_LCR, 0);
        }
 
+       /*
+        * For the Altera 16550 variants, set TX threshold trigger level.
+        */
+       if (((port->type == PORT_ALTR_16550_F32) ||
+            (port->type == PORT_ALTR_16550_F64) ||
+            (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) {
+               /* Bounds checking of TX threshold (valid 0 to fifosize-2) */
+               if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) {
+                       pr_err("ttyS%d TX FIFO Threshold errors, skipping\n",
+                              serial_index(port));
+               } else {
+                       serial_port_out(port, UART_ALTR_AFR,
+                                       UART_ALTR_EN_TXFIFO_LW);
+                       serial_port_out(port, UART_ALTR_TX_LOW,
+                                       port->fifosize - up->tx_loadsz);
+                       port->handle_irq = serial8250_tx_threshold_handle_irq;
+               }
+       }
+
        if (port->irq) {
                unsigned char iir1;
                /*
@@ -2499,8 +2537,6 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
                                             struct ktermios *termios,
                                             struct ktermios *old)
 {
-       unsigned int tolerance = port->uartclk / 100;
-
        /*
         * Ask the core to calculate the divisor for us.
         * Allow 1% tolerance at the upper limit so uart clks marginally
@@ -2509,7 +2545,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
         */
        return uart_get_baud_rate(port, termios, old,
                                  port->uartclk / 16 / 0xffff,
-                                 (port->uartclk + tolerance) / 16);
+                                 port->uartclk);
 }
 
 void
@@ -2546,12 +2582,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
        /*
         * MCR-based auto flow control.  When AFE is enabled, RTS will be
         * deasserted when the receive FIFO contains more characters than
-        * the trigger, or the MCR RTS bit is cleared.  In the case where
-        * the remote UART is not using CTS auto flow control, we must
-        * have sufficient FIFO entries for the latency of the remote
-        * UART to respond.  IOW, at least 32 bytes of FIFO.
+        * the trigger, or the MCR RTS bit is cleared.
         */
-       if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
+       if (up->capabilities & UART_CAP_AFE) {
                up->mcr &= ~UART_MCR_AFE;
                if (termios->c_cflag & CRTSCTS)
                        up->mcr |= UART_MCR_AFE;
index 7c6f7af..8998347 100644 (file)
@@ -120,7 +120,6 @@ config SERIAL_8250_PCI
        tristate "8250/16550 PCI device support" if EXPERT
        depends on SERIAL_8250 && PCI
        default SERIAL_8250
-       select RATIONAL
        help
          This builds standard PCI serial support. You may be able to
          disable this feature if you only need legacy serial support.
@@ -402,6 +401,21 @@ config SERIAL_8250_INGENIC
          If you have a system using an Ingenic SoC and wish to make use of
          its UARTs, say Y to this option. If unsure, say N.
 
+config SERIAL_8250_LPSS
+       tristate "Support for serial ports on Intel LPSS platforms" if EXPERT
+       default SERIAL_8250
+       depends on SERIAL_8250 && PCI
+       depends on X86 || COMPILE_TEST
+       select DW_DMAC_CORE if SERIAL_8250_DMA
+       select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS)
+       select RATIONAL
+       help
+         Selecting this option will enable handling of the extra features
+         present on the UART found on various Intel platforms such as:
+           - Intel Baytrail SoC
+           - Intel Braswell SoC
+           - Intel Quark X1000 SoC
+
 config SERIAL_8250_MID
        tristate "Support for serial ports on Intel MID platforms" if EXPERT
        default SERIAL_8250
index 367d403..276c6fb 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_LPC18XX)     += 8250_lpc18xx.o
 obj-$(CONFIG_SERIAL_8250_MT6577)       += 8250_mtk.o
 obj-$(CONFIG_SERIAL_8250_UNIPHIER)     += 8250_uniphier.o
 obj-$(CONFIG_SERIAL_8250_INGENIC)      += 8250_ingenic.o
+obj-$(CONFIG_SERIAL_8250_LPSS)         += 8250_lpss.o
 obj-$(CONFIG_SERIAL_8250_MID)          += 8250_mid.o
 obj-$(CONFIG_SERIAL_8250_MOXA)         += 8250_moxa.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM)       += 8250_of.o
index 32df2a0..e409d7d 100644 (file)
@@ -280,7 +280,7 @@ static int altera_jtaguart_verify_port(struct uart_port *port,
 /*
  *     Define the basic serial functions we support.
  */
-static struct uart_ops altera_jtaguart_ops = {
+static const struct uart_ops altera_jtaguart_ops = {
        .tx_empty       = altera_jtaguart_tx_empty,
        .get_mctrl      = altera_jtaguart_get_mctrl,
        .set_mctrl      = altera_jtaguart_set_mctrl,
index 61b607f..820a742 100644 (file)
@@ -404,7 +404,7 @@ static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
 /*
  *     Define the basic serial functions we support.
  */
-static struct uart_ops altera_uart_ops = {
+static const struct uart_ops altera_uart_ops = {
        .tx_empty       = altera_uart_tx_empty,
        .get_mctrl      = altera_uart_get_mctrl,
        .set_mctrl      = altera_uart_set_mctrl,
index 8a9e213..e2c33b9 100644 (file)
@@ -93,6 +93,10 @@ static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
 struct vendor_data {
        const u16               *reg_offset;
        unsigned int            ifls;
+       unsigned int            fr_busy;
+       unsigned int            fr_dsr;
+       unsigned int            fr_cts;
+       unsigned int            fr_ri;
        bool                    access_32b;
        bool                    oversampling;
        bool                    dma_threshold;
@@ -111,6 +115,10 @@ static unsigned int get_fifosize_arm(struct amba_device *dev)
 static struct vendor_data vendor_arm = {
        .reg_offset             = pl011_std_offsets,
        .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+       .fr_busy                = UART01x_FR_BUSY,
+       .fr_dsr                 = UART01x_FR_DSR,
+       .fr_cts                 = UART01x_FR_CTS,
+       .fr_ri                  = UART011_FR_RI,
        .oversampling           = false,
        .dma_threshold          = false,
        .cts_event_workaround   = false,
@@ -121,6 +129,10 @@ static struct vendor_data vendor_arm = {
 
 static struct vendor_data vendor_sbsa = {
        .reg_offset             = pl011_std_offsets,
+       .fr_busy                = UART01x_FR_BUSY,
+       .fr_dsr                 = UART01x_FR_DSR,
+       .fr_cts                 = UART01x_FR_CTS,
+       .fr_ri                  = UART011_FR_RI,
        .access_32b             = true,
        .oversampling           = false,
        .dma_threshold          = false,
@@ -164,6 +176,10 @@ static unsigned int get_fifosize_st(struct amba_device *dev)
 static struct vendor_data vendor_st = {
        .reg_offset             = pl011_st_offsets,
        .ifls                   = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
+       .fr_busy                = UART01x_FR_BUSY,
+       .fr_dsr                 = UART01x_FR_DSR,
+       .fr_cts                 = UART01x_FR_CTS,
+       .fr_ri                  = UART011_FR_RI,
        .oversampling           = true,
        .dma_threshold          = true,
        .cts_event_workaround   = true,
@@ -188,11 +204,20 @@ static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = {
        [REG_DMACR] = ZX_UART011_DMACR,
 };
 
-static struct vendor_data vendor_zte __maybe_unused = {
+static unsigned int get_fifosize_zte(struct amba_device *dev)
+{
+       return 16;
+}
+
+static struct vendor_data vendor_zte = {
        .reg_offset             = pl011_zte_offsets,
        .access_32b             = true,
        .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
-       .get_fifosize           = get_fifosize_arm,
+       .fr_busy                = ZX_UART01x_FR_BUSY,
+       .fr_dsr                 = ZX_UART01x_FR_DSR,
+       .fr_cts                 = ZX_UART01x_FR_CTS,
+       .fr_ri                  = ZX_UART011_FR_RI,
+       .get_fifosize           = get_fifosize_zte,
 };
 
 /* Deals with DMA transactions */
@@ -1167,7 +1192,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
                return;
 
        /* Disable RX and TX DMA */
-       while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+       while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
                cpu_relax();
 
        spin_lock_irq(&uap->port.lock);
@@ -1416,11 +1441,12 @@ static void pl011_modem_status(struct uart_amba_port *uap)
        if (delta & UART01x_FR_DCD)
                uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
 
-       if (delta & UART01x_FR_DSR)
+       if (delta & uap->vendor->fr_dsr)
                uap->port.icount.dsr++;
 
-       if (delta & UART01x_FR_CTS)
-               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
+       if (delta & uap->vendor->fr_cts)
+               uart_handle_cts_change(&uap->port,
+                                      status & uap->vendor->fr_cts);
 
        wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
 }
@@ -1493,7 +1519,8 @@ static unsigned int pl011_tx_empty(struct uart_port *port)
        struct uart_amba_port *uap =
            container_of(port, struct uart_amba_port, port);
        unsigned int status = pl011_read(uap, REG_FR);
-       return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
+       return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
+                                                       0 : TIOCSER_TEMT;
 }
 
 static unsigned int pl011_get_mctrl(struct uart_port *port)
@@ -1508,9 +1535,9 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
                result |= tiocmbit
 
        TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
-       TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
-       TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
-       TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
+       TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR);
+       TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS);
+       TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG);
 #undef TIOCMBIT
        return result;
 }
@@ -2191,7 +2218,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
         *      Finally, wait for transmitter to become empty
         *      and restore the TCR
         */
-       while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+       while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
                cpu_relax();
        if (!uap->vendor->always_enabled)
                pl011_write(old_cr, uap, REG_CR);
@@ -2555,7 +2582,8 @@ static int sbsa_uart_probe(struct platform_device *pdev)
 
        ret = platform_get_irq(pdev, 0);
        if (ret < 0) {
-               dev_err(&pdev->dev, "cannot obtain irq\n");
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "cannot obtain irq\n");
                return ret;
        }
        uap->port.irq   = ret;
@@ -2622,6 +2650,11 @@ static struct amba_id pl011_ids[] = {
                .mask   = 0x00ffffff,
                .data   = &vendor_st,
        },
+       {
+               .id     = AMBA_LINUX_ID(0x00, 0x1, 0xffe),
+               .mask   = 0x00ffffff,
+               .data   = &vendor_zte,
+       },
        { 0, 0 },
 };
 
index 3a1de5c..5ac06fc 100644 (file)
@@ -464,7 +464,7 @@ static int arc_serial_poll_getchar(struct uart_port *port)
 }
 #endif
 
-static struct uart_ops arc_serial_pops = {
+static const struct uart_ops arc_serial_pops = {
        .tx_empty       = arc_serial_tx_empty,
        .set_mctrl      = arc_serial_set_mctrl,
        .get_mctrl      = arc_serial_get_mctrl,
index 2eaa18d..fd8aa1f 100644 (file)
@@ -166,6 +166,7 @@ struct atmel_uart_port {
        u32                     rts_low;
        bool                    ms_irq_enabled;
        u32                     rtor;   /* address of receiver timeout register if it exists */
+       bool                    has_frac_baudrate;
        bool                    has_hw_timer;
        struct timer_list       uart_timer;
 
@@ -1634,8 +1635,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
 
        if (np) {
                /* DMA/PDC usage specification */
-               if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
-                       if (of_get_property(np, "dmas", NULL)) {
+               if (of_property_read_bool(np, "atmel,use-dma-rx")) {
+                       if (of_property_read_bool(np, "dmas")) {
                                atmel_port->use_dma_rx  = true;
                                atmel_port->use_pdc_rx  = false;
                        } else {
@@ -1647,8 +1648,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
                        atmel_port->use_pdc_rx  = false;
                }
 
-               if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
-                       if (of_get_property(np, "dmas", NULL)) {
+               if (of_property_read_bool(np, "atmel,use-dma-tx")) {
+                       if (of_property_read_bool(np, "dmas")) {
                                atmel_port->use_dma_tx  = true;
                                atmel_port->use_pdc_tx  = false;
                        } else {
@@ -1745,6 +1746,11 @@ static void atmel_get_ip_name(struct uart_port *port)
        dbgu_uart = 0x44424755; /* DBGU */
        new_uart = 0x55415254;  /* UART */
 
+       /*
+        * Only USART devices from at91sam9260 SOC implement fractional
+        * baudrate.
+        */
+       atmel_port->has_frac_baudrate = false;
        atmel_port->has_hw_timer = false;
 
        if (name == new_uart) {
@@ -1753,6 +1759,7 @@ static void atmel_get_ip_name(struct uart_port *port)
                atmel_port->rtor = ATMEL_UA_RTOR;
        } else if (name == usart) {
                dev_dbg(port->dev, "Usart\n");
+               atmel_port->has_frac_baudrate = true;
                atmel_port->has_hw_timer = true;
                atmel_port->rtor = ATMEL_US_RTOR;
        } else if (name == dbgu_uart) {
@@ -1764,6 +1771,7 @@ static void atmel_get_ip_name(struct uart_port *port)
                case 0x302:
                case 0x10213:
                        dev_dbg(port->dev, "This version is usart\n");
+                       atmel_port->has_frac_baudrate = true;
                        atmel_port->has_hw_timer = true;
                        atmel_port->rtor = ATMEL_US_RTOR;
                        break;
@@ -1929,6 +1937,9 @@ static void atmel_shutdown(struct uart_port *port)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
+       /* Disable modem control lines interrupts */
+       atmel_disable_ms(port);
+
        /* Disable interrupts at device level */
        atmel_uart_writel(port, ATMEL_US_IDR, -1);
 
@@ -1979,8 +1990,6 @@ static void atmel_shutdown(struct uart_port *port)
         */
        free_irq(port->irq, port);
 
-       atmel_port->ms_irq_enabled = false;
-
        atmel_flush_buffer(port);
 }
 
@@ -2025,8 +2034,9 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
 static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
                              struct ktermios *old)
 {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
        unsigned long flags;
-       unsigned int old_mode, mode, imr, quot, baud;
+       unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0;
 
        /* save the current mode register */
        mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR);
@@ -2036,12 +2046,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
                  ATMEL_US_PAR | ATMEL_US_USMODE);
 
        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud);
-
-       if (quot > 65535) {     /* BRGR is 16-bit, so switch to slower clock */
-               quot /= 8;
-               mode |= ATMEL_US_USCLKS_MCK_DIV8;
-       }
 
        /* byte size */
        switch (termios->c_cflag & CSIZE) {
@@ -2160,7 +2164,31 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
                atmel_uart_writel(port, ATMEL_US_CR, rts_state);
        }
 
-       /* set the baud rate */
+       /*
+        * Set the baud rate:
+        * Fractional baudrate allows to setup output frequency more
+        * accurately. This feature is enabled only when using normal mode.
+        * baudrate = selected clock / (8 * (2 - OVER) * (CD + FP / 8))
+        * Currently, OVER is always set to 0 so we get
+        * baudrate = selected clock / (16 * (CD + FP / 8))
+        * then
+        * 8 CD + FP = selected clock / (2 * baudrate)
+        */
+       if (atmel_port->has_frac_baudrate &&
+           (mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_NORMAL) {
+               div = DIV_ROUND_CLOSEST(port->uartclk, baud * 2);
+               cd = div >> 3;
+               fp = div & ATMEL_US_FP_MASK;
+       } else {
+               cd = uart_get_divisor(port, baud);
+       }
+
+       if (cd > 65535) {       /* BRGR is 16-bit, so switch to slower clock */
+               cd /= 8;
+               mode |= ATMEL_US_USCLKS_MCK_DIV8;
+       }
+       quot = cd | fp << ATMEL_US_FP_OFFSET;
+
        atmel_uart_writel(port, ATMEL_US_BRGR, quot);
        atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
        atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
@@ -2292,7 +2320,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
 }
 #endif
 
-static struct uart_ops atmel_pops = {
+static const struct uart_ops atmel_pops = {
        .tx_empty       = atmel_tx_empty,
        .set_mctrl      = atmel_set_mctrl,
        .get_mctrl      = atmel_get_mctrl,
index 5108fab..583c9a0 100644 (file)
@@ -631,7 +631,7 @@ static int bcm_uart_verify_port(struct uart_port *port,
 }
 
 /* serial core callbacks */
-static struct uart_ops bcm_uart_ops = {
+static const struct uart_ops bcm_uart_ops = {
        .tx_empty       = bcm_uart_tx_empty,
        .get_mctrl      = bcm_uart_get_mctrl,
        .set_mctrl      = bcm_uart_set_mctrl,
index 383db10..6bbeb69 100644 (file)
@@ -53,7 +53,8 @@ static void smh_write(struct console *con, const char *s, unsigned n)
        uart_console_write(&dev->port, s, n, smh_putc);
 }
 
-int __init early_smh_setup(struct earlycon_device *device, const char *opt)
+static int
+__init early_smh_setup(struct earlycon_device *device, const char *opt)
 {
        device->con->write = smh_write;
        return 0;
index 067783f..c365154 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sizes.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
+#include <linux/acpi.h>
 
 #ifdef CONFIG_FIX_EARLYCON_MEM
 #include <asm/fixmap.h>
@@ -38,7 +39,7 @@ static struct earlycon_device early_console_dev = {
        .con = &early_con,
 };
 
-static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
+static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size)
 {
        void __iomem *base;
 #ifdef CONFIG_FIX_EARLYCON_MEM
@@ -49,8 +50,7 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
        base = ioremap(paddr, size);
 #endif
        if (!base)
-               pr_err("%s: Couldn't map 0x%llx\n", __func__,
-                      (unsigned long long)paddr);
+               pr_err("%s: Couldn't map %pa\n", __func__, &paddr);
 
        return base;
 }
@@ -92,7 +92,7 @@ static int __init parse_options(struct earlycon_device *device, char *options)
 {
        struct uart_port *port = &device->port;
        int length;
-       unsigned long addr;
+       resource_size_t addr;
 
        if (uart_parse_earlycon(options, &port->iotype, &addr, &options))
                return -EINVAL;
@@ -199,6 +199,14 @@ int __init setup_earlycon(char *buf)
        return -ENOENT;
 }
 
+/*
+ * When CONFIG_ACPI_SPCR_TABLE is defined, "earlycon" without parameters in
+ * command line does not start DT earlycon immediately, instead it defers
+ * starting it until DT/ACPI decision is made.  At that time if ACPI is enabled
+ * call parse_spcr(), else call early_init_dt_scan_chosen_stdout()
+ */
+bool earlycon_init_is_deferred __initdata;
+
 /* early_param wrapper for setup_earlycon() */
 static int __init param_setup_earlycon(char *buf)
 {
@@ -208,8 +216,14 @@ static int __init param_setup_earlycon(char *buf)
         * Just 'earlycon' is a valid param for devicetree earlycons;
         * don't generate a warning from parse_early_params() in that case
         */
-       if (!buf || !buf[0])
-               return 0;
+       if (!buf || !buf[0]) {
+               if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
+                       earlycon_init_is_deferred = true;
+                       return 0;
+               } else {
+                       return early_init_dt_scan_chosen_stdout();
+               }
+       }
 
        err = setup_earlycon(buf);
        if (err == -ENOENT || err == -EALREADY)
index 7f95f78..de9d510 100644 (file)
 #define UARTWATER_TXWATER_OFF  0
 #define UARTWATER_RXWATER_OFF  16
 
-#define FSL_UART_RX_DMA_BUFFER_SIZE    64
+/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
+#define DMA_RX_TIMEOUT         (10)
 
 #define DRIVER_NAME    "fsl-lpuart"
 #define DEV_NAME       "ttyLP"
@@ -243,18 +244,18 @@ struct lpuart_port {
        struct dma_chan         *dma_rx_chan;
        struct dma_async_tx_descriptor  *dma_tx_desc;
        struct dma_async_tx_descriptor  *dma_rx_desc;
-       dma_addr_t              dma_tx_buf_bus;
-       dma_addr_t              dma_rx_buf_bus;
        dma_cookie_t            dma_tx_cookie;
        dma_cookie_t            dma_rx_cookie;
-       unsigned char           *dma_tx_buf_virt;
-       unsigned char           *dma_rx_buf_virt;
        unsigned int            dma_tx_bytes;
        unsigned int            dma_rx_bytes;
-       int                     dma_tx_in_progress;
-       int                     dma_rx_in_progress;
+       bool                    dma_tx_in_progress;
        unsigned int            dma_rx_timeout;
        struct timer_list       lpuart_timer;
+       struct scatterlist      rx_sgl, tx_sgl[2];
+       struct circ_buf         rx_ring;
+       int                     rx_dma_rng_buf_len;
+       unsigned int            dma_tx_nents;
+       wait_queue_head_t       dma_wait;
 };
 
 static const struct of_device_id lpuart_dt_ids[] = {
@@ -270,7 +271,6 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
 
 /* Forward declare this for the dma callbacks*/
 static void lpuart_dma_tx_complete(void *arg);
-static void lpuart_dma_rx_complete(void *arg);
 
 static u32 lpuart32_read(void __iomem *addr)
 {
@@ -316,141 +316,103 @@ static void lpuart32_stop_rx(struct uart_port *port)
        lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL);
 }
 
-static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
-               struct tty_port *tty, int count)
+static void lpuart_dma_tx(struct lpuart_port *sport)
 {
-       int copied;
-
-       sport->port.icount.rx += count;
+       struct circ_buf *xmit = &sport->port.state->xmit;
+       struct scatterlist *sgl = sport->tx_sgl;
+       struct device *dev = sport->port.dev;
+       int ret;
 
-       if (!tty) {
-               dev_err(sport->port.dev, "No tty port\n");
+       if (sport->dma_tx_in_progress)
                return;
-       }
 
-       dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus,
-                       FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
-       copied = tty_insert_flip_string(tty,
-                       ((unsigned char *)(sport->dma_rx_buf_virt)), count);
+       sport->dma_tx_bytes = uart_circ_chars_pending(xmit);
 
-       if (copied != count) {
-               WARN_ON(1);
-               dev_err(sport->port.dev, "RxData copy to tty layer failed\n");
+       if (xmit->tail < xmit->head) {
+               sport->dma_tx_nents = 1;
+               sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes);
+       } else {
+               sport->dma_tx_nents = 2;
+               sg_init_table(sgl, 2);
+               sg_set_buf(sgl, xmit->buf + xmit->tail,
+                               UART_XMIT_SIZE - xmit->tail);
+               sg_set_buf(sgl + 1, xmit->buf, xmit->head);
        }
 
-       dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
-                       FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
-}
-
-static void lpuart_pio_tx(struct lpuart_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       while (!uart_circ_empty(xmit) &&
-               readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
-               writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
+       ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+       if (!ret) {
+               dev_err(dev, "DMA mapping error for TX.\n");
+               return;
        }
 
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-       if (uart_circ_empty(xmit))
-               writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
-                       sport->port.membase + UARTCR5);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-       dma_addr_t tx_bus_addr;
-
-       dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus,
-                               UART_XMIT_SIZE, DMA_TO_DEVICE);
-       sport->dma_tx_bytes = count & ~(sport->txfifo_size - 1);
-       tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail;
-       sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan,
-                                       tx_bus_addr, sport->dma_tx_bytes,
+       sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl,
+                                       sport->dma_tx_nents,
                                        DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
-
        if (!sport->dma_tx_desc) {
-               dev_err(sport->port.dev, "Not able to get desc for tx\n");
-               return -EIO;
+               dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+               dev_err(dev, "Cannot prepare TX slave DMA!\n");
+               return;
        }
 
        sport->dma_tx_desc->callback = lpuart_dma_tx_complete;
        sport->dma_tx_desc->callback_param = sport;
-       sport->dma_tx_in_progress = 1;
+       sport->dma_tx_in_progress = true;
        sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
        dma_async_issue_pending(sport->dma_tx_chan);
 
-       return 0;
-}
-
-static void lpuart_prepare_tx(struct lpuart_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-       unsigned long count =  CIRC_CNT_TO_END(xmit->head,
-                                       xmit->tail, UART_XMIT_SIZE);
-
-       if (!count)
-               return;
-
-       if (count < sport->txfifo_size)
-               writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS,
-                               sport->port.membase + UARTCR5);
-       else {
-               writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
-                               sport->port.membase + UARTCR5);
-               lpuart_dma_tx(sport, count);
-       }
 }
 
 static void lpuart_dma_tx_complete(void *arg)
 {
        struct lpuart_port *sport = arg;
+       struct scatterlist *sgl = &sport->tx_sgl[0];
        struct circ_buf *xmit = &sport->port.state->xmit;
        unsigned long flags;
 
-       async_tx_ack(sport->dma_tx_desc);
-
        spin_lock_irqsave(&sport->port.lock, flags);
 
+       dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+
        xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
-       sport->dma_tx_in_progress = 0;
+
+       sport->port.icount.tx += sport->dma_tx_bytes;
+       sport->dma_tx_in_progress = false;
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(&sport->port);
 
-       lpuart_prepare_tx(sport);
+       if (waitqueue_active(&sport->dma_wait)) {
+               wake_up(&sport->dma_wait);
+               return;
+       }
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
+               lpuart_dma_tx(sport);
 
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-static int lpuart_dma_rx(struct lpuart_port *sport)
+static int lpuart_dma_tx_request(struct uart_port *port)
 {
-       dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
-                       FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
-       sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan,
-                       sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE,
-                       DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+       struct lpuart_port *sport = container_of(port,
+                                       struct lpuart_port, port);
+       struct dma_slave_config dma_tx_sconfig = {};
+       int ret;
 
-       if (!sport->dma_rx_desc) {
-               dev_err(sport->port.dev, "Not able to get desc for rx\n");
-               return -EIO;
-       }
+       dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
+       dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma_tx_sconfig.dst_maxburst = 1;
+       dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
+       ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
 
-       sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
-       sport->dma_rx_desc->callback_param = sport;
-       sport->dma_rx_in_progress = 1;
-       sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
-       dma_async_issue_pending(sport->dma_rx_chan);
+       if (ret) {
+               dev_err(sport->port.dev,
+                               "DMA slave config failed, err = %d\n", ret);
+               return ret;
+       }
 
        return 0;
 }
@@ -458,75 +420,17 @@ static int lpuart_dma_rx(struct lpuart_port *sport)
 static void lpuart_flush_buffer(struct uart_port *port)
 {
        struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+
        if (sport->lpuart_dma_tx_use) {
+               if (sport->dma_tx_in_progress) {
+                       dma_unmap_sg(sport->port.dev, &sport->tx_sgl[0],
+                               sport->dma_tx_nents, DMA_TO_DEVICE);
+                       sport->dma_tx_in_progress = false;
+               }
                dmaengine_terminate_all(sport->dma_tx_chan);
-               sport->dma_tx_in_progress = 0;
        }
 }
 
-static void lpuart_dma_rx_complete(void *arg)
-{
-       struct lpuart_port *sport = arg;
-       struct tty_port *port = &sport->port.state->port;
-       unsigned long flags;
-
-       async_tx_ack(sport->dma_rx_desc);
-       mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->dma_rx_in_progress = 0;
-       lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
-       tty_flip_buffer_push(port);
-       lpuart_dma_rx(sport);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static void lpuart_timer_func(unsigned long data)
-{
-       struct lpuart_port *sport = (struct lpuart_port *)data;
-       struct tty_port *port = &sport->port.state->port;
-       struct dma_tx_state state;
-       unsigned long flags;
-       unsigned char temp;
-       int count;
-
-       del_timer(&sport->lpuart_timer);
-       dmaengine_pause(sport->dma_rx_chan);
-       dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
-       dmaengine_terminate_all(sport->dma_rx_chan);
-       count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
-       async_tx_ack(sport->dma_rx_desc);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->dma_rx_in_progress = 0;
-       lpuart_copy_rx_to_tty(sport, port, count);
-       tty_flip_buffer_push(port);
-       temp = readb(sport->port.membase + UARTCR5);
-       writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static inline void lpuart_prepare_rx(struct lpuart_port *sport)
-{
-       unsigned long flags;
-       unsigned char temp;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
-       add_timer(&sport->lpuart_timer);
-
-       lpuart_dma_rx(sport);
-       temp = readb(sport->port.membase + UARTCR5);
-       writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
 static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
 {
        struct circ_buf *xmit = &sport->port.state->xmit;
@@ -580,8 +484,8 @@ static void lpuart_start_tx(struct uart_port *port)
        writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
 
        if (sport->lpuart_dma_tx_use) {
-               if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
-                       lpuart_prepare_tx(sport);
+               if (!uart_circ_empty(xmit) && !uart_tx_stopped(port))
+                       lpuart_dma_tx(sport);
        } else {
                if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
                        lpuart_transmit_buffer(sport);
@@ -600,6 +504,29 @@ static void lpuart32_start_tx(struct uart_port *port)
                lpuart32_transmit_buffer(sport);
 }
 
+/* return TIOCSER_TEMT when transmitter is not busy */
+static unsigned int lpuart_tx_empty(struct uart_port *port)
+{
+       struct lpuart_port *sport = container_of(port,
+                       struct lpuart_port, port);
+       unsigned char sr1 = readb(port->membase + UARTSR1);
+       unsigned char sfifo = readb(port->membase + UARTSFIFO);
+
+       if (sport->dma_tx_in_progress)
+               return 0;
+
+       if (sr1 & UARTSR1_TC && sfifo & UARTSFIFO_TXEMPT)
+               return TIOCSER_TEMT;
+
+       return 0;
+}
+
+static unsigned int lpuart32_tx_empty(struct uart_port *port)
+{
+       return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ?
+               TIOCSER_TEMT : 0;
+}
+
 static irqreturn_t lpuart_txint(int irq, void *dev_id)
 {
        struct lpuart_port *sport = dev_id;
@@ -766,23 +693,15 @@ out:
 static irqreturn_t lpuart_int(int irq, void *dev_id)
 {
        struct lpuart_port *sport = dev_id;
-       unsigned char sts, crdma;
+       unsigned char sts;
 
        sts = readb(sport->port.membase + UARTSR1);
-       crdma = readb(sport->port.membase + UARTCR5);
 
-       if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
-               if (sport->lpuart_dma_rx_use)
-                       lpuart_prepare_rx(sport);
-               else
-                       lpuart_rxint(irq, dev_id);
-       }
-       if (sts & UARTSR1_TDRE && !(crdma & UARTCR5_TDMAS)) {
-               if (sport->lpuart_dma_tx_use)
-                       lpuart_pio_tx(sport);
-               else
-                       lpuart_txint(irq, dev_id);
-       }
+       if (sts & UARTSR1_RDRF)
+               lpuart_rxint(irq, dev_id);
+
+       if (sts & UARTSR1_TDRE)
+               lpuart_txint(irq, dev_id);
 
        return IRQ_HANDLED;
 }
@@ -807,17 +726,241 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* return TIOCSER_TEMT when transmitter is not busy */
-static unsigned int lpuart_tx_empty(struct uart_port *port)
+static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
 {
-       return (readb(port->membase + UARTSR1) & UARTSR1_TC) ?
-               TIOCSER_TEMT : 0;
+       struct tty_port *port = &sport->port.state->port;
+       struct dma_tx_state state;
+       enum dma_status dmastat;
+       struct circ_buf *ring = &sport->rx_ring;
+       unsigned long flags;
+       int count = 0;
+       unsigned char sr;
+
+       sr = readb(sport->port.membase + UARTSR1);
+
+       if (sr & (UARTSR1_PE | UARTSR1_FE)) {
+               /* Read DR to clear the error flags */
+               readb(sport->port.membase + UARTDR);
+
+               if (sr & UARTSR1_PE)
+                   sport->port.icount.parity++;
+               else if (sr & UARTSR1_FE)
+                   sport->port.icount.frame++;
+       }
+
+       async_tx_ack(sport->dma_rx_desc);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       dmastat = dmaengine_tx_status(sport->dma_rx_chan,
+                               sport->dma_rx_cookie,
+                               &state);
+
+       if (dmastat == DMA_ERROR) {
+               dev_err(sport->port.dev, "Rx DMA transfer failed!\n");
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+               return;
+       }
+
+       /* CPU claims ownership of RX DMA buffer */
+       dma_sync_sg_for_cpu(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+
+       /*
+        * ring->head points to the end of data already written by the DMA.
+        * ring->tail points to the beginning of data to be read by the
+        * framework.
+        * The current transfer size should not be larger than the dma buffer
+        * length.
+        */
+       ring->head = sport->rx_sgl.length - state.residue;
+       BUG_ON(ring->head > sport->rx_sgl.length);
+       /*
+        * At this point ring->head may point to the first byte right after the
+        * last byte of the dma buffer:
+        * 0 <= ring->head <= sport->rx_sgl.length
+        *
+        * However ring->tail must always points inside the dma buffer:
+        * 0 <= ring->tail <= sport->rx_sgl.length - 1
+        *
+        * Since we use a ring buffer, we have to handle the case
+        * where head is lower than tail. In such a case, we first read from
+        * tail to the end of the buffer then reset tail.
+        */
+       if (ring->head < ring->tail) {
+               count = sport->rx_sgl.length - ring->tail;
+
+               tty_insert_flip_string(port, ring->buf + ring->tail, count);
+               ring->tail = 0;
+               sport->port.icount.rx += count;
+       }
+
+       /* Finally we read data from tail to head */
+       if (ring->tail < ring->head) {
+               count = ring->head - ring->tail;
+               tty_insert_flip_string(port, ring->buf + ring->tail, count);
+               /* Wrap ring->head if needed */
+               if (ring->head >= sport->rx_sgl.length)
+                       ring->head = 0;
+               ring->tail = ring->head;
+               sport->port.icount.rx += count;
+       }
+
+       dma_sync_sg_for_device(sport->port.dev, &sport->rx_sgl, 1,
+                              DMA_FROM_DEVICE);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+
+       tty_flip_buffer_push(port);
+       mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
 }
 
-static unsigned int lpuart32_tx_empty(struct uart_port *port)
+static void lpuart_dma_rx_complete(void *arg)
 {
-       return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ?
-               TIOCSER_TEMT : 0;
+       struct lpuart_port *sport = arg;
+
+       lpuart_copy_rx_to_tty(sport);
+}
+
+static void lpuart_timer_func(unsigned long data)
+{
+       struct lpuart_port *sport = (struct lpuart_port *)data;
+
+       lpuart_copy_rx_to_tty(sport);
+}
+
+static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
+{
+       struct dma_slave_config dma_rx_sconfig = {};
+       struct circ_buf *ring = &sport->rx_ring;
+       int ret, nent;
+       int bits, baud;
+       struct tty_struct *tty = tty_port_tty_get(&sport->port.state->port);
+       struct ktermios *termios = &tty->termios;
+
+       baud = tty_get_baud_rate(tty);
+
+       bits = (termios->c_cflag & CSIZE) == CS7 ? 9 : 10;
+       if (termios->c_cflag & PARENB)
+               bits++;
+
+       /*
+        * Calculate length of one DMA buffer size to keep latency below
+        * 10ms at any baud rate.
+        */
+       sport->rx_dma_rng_buf_len = (DMA_RX_TIMEOUT * baud /  bits / 1000) * 2;
+       sport->rx_dma_rng_buf_len = (1 << (fls(sport->rx_dma_rng_buf_len) - 1));
+       if (sport->rx_dma_rng_buf_len < 16)
+               sport->rx_dma_rng_buf_len = 16;
+
+       ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC);
+       if (!ring->buf) {
+               dev_err(sport->port.dev, "Ring buf alloc failed\n");
+               return -ENOMEM;
+       }
+
+       sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
+       sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
+       nent = dma_map_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+
+       if (!nent) {
+               dev_err(sport->port.dev, "DMA Rx mapping error\n");
+               return -EINVAL;
+       }
+
+       dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
+       dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma_rx_sconfig.src_maxburst = 1;
+       dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+       ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
+
+       if (ret < 0) {
+               dev_err(sport->port.dev,
+                               "DMA Rx slave config failed, err = %d\n", ret);
+               return ret;
+       }
+
+       sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan,
+                                sg_dma_address(&sport->rx_sgl),
+                                sport->rx_sgl.length,
+                                sport->rx_sgl.length / 2,
+                                DMA_DEV_TO_MEM,
+                                DMA_PREP_INTERRUPT);
+       if (!sport->dma_rx_desc) {
+               dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n");
+               return -EFAULT;
+       }
+
+       sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
+       sport->dma_rx_desc->callback_param = sport;
+       sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
+       dma_async_issue_pending(sport->dma_rx_chan);
+
+       writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS,
+                               sport->port.membase + UARTCR5);
+
+       return 0;
+}
+
+static void lpuart_dma_rx_free(struct uart_port *port)
+{
+       struct lpuart_port *sport = container_of(port,
+                                       struct lpuart_port, port);
+
+       if (sport->dma_rx_chan)
+               dmaengine_terminate_all(sport->dma_rx_chan);
+
+       dma_unmap_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+       kfree(sport->rx_ring.buf);
+       sport->rx_ring.tail = 0;
+       sport->rx_ring.head = 0;
+       sport->dma_rx_desc = NULL;
+       sport->dma_rx_cookie = -EINVAL;
+}
+
+static int lpuart_config_rs485(struct uart_port *port,
+                       struct serial_rs485 *rs485)
+{
+       struct lpuart_port *sport = container_of(port,
+                       struct lpuart_port, port);
+
+       u8 modem = readb(sport->port.membase + UARTMODEM) &
+               ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
+       writeb(modem, sport->port.membase + UARTMODEM);
+
+       if (rs485->flags & SER_RS485_ENABLED) {
+               /* Enable auto RS-485 RTS mode */
+               modem |= UARTMODEM_TXRTSE;
+
+               /*
+                * RTS needs to be logic HIGH either during transer _or_ after
+                * transfer, other variants are not supported by the hardware.
+                */
+
+               if (!(rs485->flags & (SER_RS485_RTS_ON_SEND |
+                               SER_RS485_RTS_AFTER_SEND)))
+                       rs485->flags |= SER_RS485_RTS_ON_SEND;
+
+               if (rs485->flags & SER_RS485_RTS_ON_SEND &&
+                               rs485->flags & SER_RS485_RTS_AFTER_SEND)
+                       rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+
+               /*
+                * The hardware defaults to RTS logic HIGH while transfer.
+                * Switch polarity in case RTS shall be logic HIGH
+                * after transfer.
+                * Note: UART is assumed to be active high.
+                */
+               if (rs485->flags & SER_RS485_RTS_ON_SEND)
+                       modem &= ~UARTMODEM_TXRTSPOL;
+               else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
+                       modem |= UARTMODEM_TXRTSPOL;
+       }
+
+       /* Store the new configuration */
+       sport->port.rs485 = *rs485;
+
+       writeb(modem, sport->port.membase + UARTMODEM);
+       return 0;
 }
 
 static unsigned int lpuart_get_mctrl(struct uart_port *port)
@@ -853,17 +996,22 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
 static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
        unsigned char temp;
+       struct lpuart_port *sport = container_of(port,
+                               struct lpuart_port, port);
 
-       temp = readb(port->membase + UARTMODEM) &
+       /* Make sure RXRTSE bit is not set when RS485 is enabled */
+       if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) {
+               temp = readb(sport->port.membase + UARTMODEM) &
                        ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
 
-       if (mctrl & TIOCM_RTS)
-               temp |= UARTMODEM_RXRTSE;
+               if (mctrl & TIOCM_RTS)
+                       temp |= UARTMODEM_RXRTSE;
 
-       if (mctrl & TIOCM_CTS)
-               temp |= UARTMODEM_TXCTSE;
+               if (mctrl & TIOCM_CTS)
+                       temp |= UARTMODEM_TXCTSE;
 
-       writeb(temp, port->membase + UARTMODEM);
+               writeb(temp, port->membase + UARTMODEM);
+       }
 }
 
 static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
@@ -921,13 +1069,16 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
        writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
                        sport->port.membase + UARTPFIFO);
 
-       /* explicitly clear RDRF */
-       readb(sport->port.membase + UARTSR1);
-
        /* flush Tx and Rx FIFO */
        writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
                        sport->port.membase + UARTCFIFO);
 
+       /* explicitly clear RDRF */
+       if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) {
+               readb(sport->port.membase + UARTDR);
+               writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
+       }
+
        writeb(0, sport->port.membase + UARTTWFIFO);
        writeb(1, sport->port.membase + UARTRWFIFO);
 
@@ -960,110 +1111,12 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
        lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL);
 }
 
-static int lpuart_dma_tx_request(struct uart_port *port)
-{
-       struct lpuart_port *sport = container_of(port,
-                                       struct lpuart_port, port);
-       struct dma_slave_config dma_tx_sconfig;
-       dma_addr_t dma_bus;
-       unsigned char *dma_buf;
-       int ret;
-
-       dma_bus = dma_map_single(sport->dma_tx_chan->device->dev,
-                               sport->port.state->xmit.buf,
-                               UART_XMIT_SIZE, DMA_TO_DEVICE);
-
-       if (dma_mapping_error(sport->dma_tx_chan->device->dev, dma_bus)) {
-               dev_err(sport->port.dev, "dma_map_single tx failed\n");
-               return -ENOMEM;
-       }
-
-       dma_buf = sport->port.state->xmit.buf;
-       dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
-       dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       dma_tx_sconfig.dst_maxburst = sport->txfifo_size;
-       dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
-       ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
-
-       if (ret < 0) {
-               dev_err(sport->port.dev,
-                               "Dma slave config failed, err = %d\n", ret);
-               return ret;
-       }
-
-       sport->dma_tx_buf_virt = dma_buf;
-       sport->dma_tx_buf_bus = dma_bus;
-       sport->dma_tx_in_progress = 0;
-
-       return 0;
-}
-
-static int lpuart_dma_rx_request(struct uart_port *port)
+static void rx_dma_timer_init(struct lpuart_port *sport)
 {
-       struct lpuart_port *sport = container_of(port,
-                                       struct lpuart_port, port);
-       struct dma_slave_config dma_rx_sconfig;
-       dma_addr_t dma_bus;
-       unsigned char *dma_buf;
-       int ret;
-
-       dma_buf = devm_kzalloc(sport->port.dev,
-                               FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
-
-       if (!dma_buf) {
-               dev_err(sport->port.dev, "Dma rx alloc failed\n");
-               return -ENOMEM;
-       }
-
-       dma_bus = dma_map_single(sport->dma_rx_chan->device->dev, dma_buf,
-                               FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
-
-       if (dma_mapping_error(sport->dma_rx_chan->device->dev, dma_bus)) {
-               dev_err(sport->port.dev, "dma_map_single rx failed\n");
-               return -ENOMEM;
-       }
-
-       dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
-       dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       dma_rx_sconfig.src_maxburst = 1;
-       dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
-       ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
-
-       if (ret < 0) {
-               dev_err(sport->port.dev,
-                               "Dma slave config failed, err = %d\n", ret);
-               return ret;
-       }
-
-       sport->dma_rx_buf_virt = dma_buf;
-       sport->dma_rx_buf_bus = dma_bus;
-       sport->dma_rx_in_progress = 0;
-
-       return 0;
-}
-
-static void lpuart_dma_tx_free(struct uart_port *port)
-{
-       struct lpuart_port *sport = container_of(port,
-                                       struct lpuart_port, port);
-
-       dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
-                       UART_XMIT_SIZE, DMA_TO_DEVICE);
-
-       sport->dma_tx_buf_bus = 0;
-       sport->dma_tx_buf_virt = NULL;
-}
-
-static void lpuart_dma_rx_free(struct uart_port *port)
-{
-       struct lpuart_port *sport = container_of(port,
-                                       struct lpuart_port, port);
-
-       dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
-                       FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
-
-       sport->dma_rx_buf_bus = 0;
-       sport->dma_rx_buf_virt = NULL;
+               setup_timer(&sport->lpuart_timer, lpuart_timer_func,
+                               (unsigned long)sport);
+               sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+               add_timer(&sport->lpuart_timer);
 }
 
 static int lpuart_startup(struct uart_port *port)
@@ -1084,22 +1137,6 @@ static int lpuart_startup(struct uart_port *port)
        sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
                UARTPFIFO_FIFOSIZE_MASK) + 1);
 
-       if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
-               sport->lpuart_dma_rx_use = true;
-               setup_timer(&sport->lpuart_timer, lpuart_timer_func,
-                           (unsigned long)sport);
-       } else
-               sport->lpuart_dma_rx_use = false;
-
-
-       if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) {
-               sport->lpuart_dma_tx_use = true;
-               temp = readb(port->membase + UARTCR5);
-               temp &= ~UARTCR5_RDMAS;
-               writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
-       } else
-               sport->lpuart_dma_tx_use = false;
-
        ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
                                DRIVER_NAME, sport);
        if (ret)
@@ -1113,7 +1150,29 @@ static int lpuart_startup(struct uart_port *port)
        temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
        writeb(temp, sport->port.membase + UARTCR2);
 
+       if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
+               /* set Rx DMA timeout */
+               sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT);
+               if (!sport->dma_rx_timeout)
+                    sport->dma_rx_timeout = 1;
+
+               sport->lpuart_dma_rx_use = true;
+               rx_dma_timer_init(sport);
+       } else {
+               sport->lpuart_dma_rx_use = false;
+       }
+
+       if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) {
+               init_waitqueue_head(&sport->dma_wait);
+               sport->lpuart_dma_tx_use = true;
+               temp = readb(port->membase + UARTCR5);
+               writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
+       } else {
+               sport->lpuart_dma_tx_use = false;
+       }
+
        spin_unlock_irqrestore(&sport->port.lock, flags);
+
        return 0;
 }
 
@@ -1170,12 +1229,19 @@ static void lpuart_shutdown(struct uart_port *port)
        devm_free_irq(port->dev, port->irq, sport);
 
        if (sport->lpuart_dma_rx_use) {
-               lpuart_dma_rx_free(&sport->port);
                del_timer_sync(&sport->lpuart_timer);
+               lpuart_dma_rx_free(&sport->port);
        }
 
-       if (sport->lpuart_dma_tx_use)
-               lpuart_dma_tx_free(&sport->port);
+       if (sport->lpuart_dma_tx_use) {
+               if (wait_event_interruptible(sport->dma_wait,
+                       !sport->dma_tx_in_progress) != false) {
+                       sport->dma_tx_in_progress = false;
+                       dmaengine_terminate_all(sport->dma_tx_chan);
+               }
+
+               lpuart_stop_tx(port);
+       }
 }
 
 static void lpuart32_shutdown(struct uart_port *port)
@@ -1203,13 +1269,14 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
 {
        struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
        unsigned long flags;
-       unsigned char cr1, old_cr1, old_cr2, cr4, bdh, modem;
+       unsigned char cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem;
        unsigned int  baud;
        unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
        unsigned int sbr, brfa;
 
        cr1 = old_cr1 = readb(sport->port.membase + UARTCR1);
        old_cr2 = readb(sport->port.membase + UARTCR2);
+       cr3 = readb(sport->port.membase + UARTCR3);
        cr4 = readb(sport->port.membase + UARTCR4);
        bdh = readb(sport->port.membase + UARTBDH);
        modem = readb(sport->port.membase + UARTMODEM);
@@ -1240,6 +1307,13 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
                cr1 |= UARTCR1_M;
        }
 
+       /*
+        * When auto RS-485 RTS mode is enabled,
+        * hardware flow control need to be disabled.
+        */
+       if (sport->port.rs485.flags & SER_RS485_ENABLED)
+               termios->c_cflag &= ~CRTSCTS;
+
        if (termios->c_cflag & CRTSCTS) {
                modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
        } else {
@@ -1257,7 +1331,10 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
        if ((termios->c_cflag & PARENB)) {
                if (termios->c_cflag & CMSPAR) {
                        cr1 &= ~UARTCR1_PE;
-                       cr1 |= UARTCR1_M;
+                       if (termios->c_cflag & PARODD)
+                               cr3 |= UARTCR3_T8;
+                       else
+                               cr3 &= ~UARTCR3_T8;
                } else {
                        cr1 |= UARTCR1_PE;
                        if ((termios->c_cflag & CSIZE) == CS8)
@@ -1297,17 +1374,6 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
        /* update the per-port timeout */
        uart_update_timeout(port, termios->c_cflag, baud);
 
-       if (sport->lpuart_dma_rx_use) {
-               /* Calculate delay for 1.5 DMA buffers */
-               sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
-                                       FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
-                                       sport->rxfifo_size / 2;
-               dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
-                       sport->dma_rx_timeout * 1000 / HZ, sport->port.timeout);
-               if (sport->dma_rx_timeout < msecs_to_jiffies(20))
-                       sport->dma_rx_timeout = msecs_to_jiffies(20);
-       }
-
        /* wait transmit engin complete */
        while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC))
                barrier();
@@ -1325,12 +1391,31 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
        writeb(cr4 | brfa, sport->port.membase + UARTCR4);
        writeb(bdh, sport->port.membase + UARTBDH);
        writeb(sbr & 0xFF, sport->port.membase + UARTBDL);
+       writeb(cr3, sport->port.membase + UARTCR3);
        writeb(cr1, sport->port.membase + UARTCR1);
        writeb(modem, sport->port.membase + UARTMODEM);
 
        /* restore control register */
        writeb(old_cr2, sport->port.membase + UARTCR2);
 
+       /*
+        * If new baud rate is set, we will also need to update the Ring buffer
+        * length according to the selected baud rate and restart Rx DMA path.
+        */
+       if (old) {
+               if (sport->lpuart_dma_rx_use) {
+                       del_timer_sync(&sport->lpuart_timer);
+                       lpuart_dma_rx_free(&sport->port);
+               }
+
+               if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
+                       sport->lpuart_dma_rx_use = true;
+                       rx_dma_timer_init(sport);
+               } else {
+                       sport->lpuart_dma_rx_use = false;
+               }
+       }
+
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
@@ -1494,7 +1579,7 @@ static int lpuart_verify_port(struct uart_port *port, struct serial_struct *ser)
        return ret;
 }
 
-static struct uart_ops lpuart_pops = {
+static const struct uart_ops lpuart_pops = {
        .tx_empty       = lpuart_tx_empty,
        .set_mctrl      = lpuart_set_mctrl,
        .get_mctrl      = lpuart_get_mctrl,
@@ -1513,7 +1598,7 @@ static struct uart_ops lpuart_pops = {
        .flush_buffer   = lpuart_flush_buffer,
 };
 
-static struct uart_ops lpuart32_pops = {
+static const struct uart_ops lpuart32_pops = {
        .tx_empty       = lpuart32_tx_empty,
        .set_mctrl      = lpuart32_set_mctrl,
        .get_mctrl      = lpuart32_get_mctrl,
@@ -1843,6 +1928,8 @@ static int lpuart_probe(struct platform_device *pdev)
                sport->port.ops = &lpuart_pops;
        sport->port.flags = UPF_BOOT_AUTOCONF;
 
+       sport->port.rs485_config = lpuart_config_rs485;
+
        sport->clk = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(sport->clk)) {
                ret = PTR_ERR(sport->clk);
@@ -1883,6 +1970,12 @@ static int lpuart_probe(struct platform_device *pdev)
                dev_info(sport->port.dev, "DMA rx channel request failed, "
                                "operating without rx DMA\n");
 
+       if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) {
+               sport->port.rs485.flags |= SER_RS485_ENABLED;
+               sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND;
+               writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM);
+       }
+
        return 0;
 }
 
@@ -1923,6 +2016,32 @@ static int lpuart_suspend(struct device *dev)
 
        uart_suspend_port(&lpuart_reg, &sport->port);
 
+       if (sport->lpuart_dma_rx_use) {
+               /*
+                * EDMA driver during suspend will forcefully release any
+                * non-idle DMA channels. If port wakeup is enabled or if port
+                * is console port or 'no_console_suspend' is set the Rx DMA
+                * cannot resume as as expected, hence gracefully release the
+                * Rx DMA path before suspend and start Rx DMA path on resume.
+                */
+               if (sport->port.irq_wake) {
+                       del_timer_sync(&sport->lpuart_timer);
+                       lpuart_dma_rx_free(&sport->port);
+               }
+
+               /* Disable Rx DMA to use UART port as wakeup source */
+               writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_RDMAS,
+                                       sport->port.membase + UARTCR5);
+       }
+
+       if (sport->lpuart_dma_tx_use) {
+               sport->dma_tx_in_progress = false;
+               dmaengine_terminate_all(sport->dma_tx_chan);
+       }
+
+       if (sport->port.suspended && !sport->port.irq_wake)
+               clk_disable_unprepare(sport->clk);
+
        return 0;
 }
 
@@ -1931,6 +2050,9 @@ static int lpuart_resume(struct device *dev)
        struct lpuart_port *sport = dev_get_drvdata(dev);
        unsigned long temp;
 
+       if (sport->port.suspended && !sport->port.irq_wake)
+               clk_prepare_enable(sport->clk);
+
        if (sport->lpuart32) {
                lpuart32_setup_watermark(sport);
                temp = lpuart32_read(sport->port.membase + UARTCTRL);
@@ -1944,6 +2066,26 @@ static int lpuart_resume(struct device *dev)
                writeb(temp, sport->port.membase + UARTCR2);
        }
 
+       if (sport->lpuart_dma_rx_use) {
+               if (sport->port.irq_wake) {
+                       if (!lpuart_start_rx_dma(sport)) {
+                               sport->lpuart_dma_rx_use = true;
+                               rx_dma_timer_init(sport);
+                       } else {
+                               sport->lpuart_dma_rx_use = false;
+                       }
+               }
+       }
+
+       if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) {
+                       init_waitqueue_head(&sport->dma_wait);
+                       sport->lpuart_dma_tx_use = true;
+                       writeb(readb(sport->port.membase + UARTCR5) |
+                               UARTCR5_TDMAS, sport->port.membase + UARTCR5);
+       } else {
+               sport->lpuart_dma_tx_use = false;
+       }
+
        uart_resume_port(&lpuart_reg, &sport->port);
 
        return 0;
index 0df2b1c..a70356d 100644 (file)
 enum imx_uart_type {
        IMX1_UART,
        IMX21_UART,
+       IMX53_UART,
        IMX6Q_UART,
 };
 
@@ -222,6 +223,9 @@ struct imx_port {
        struct dma_chan         *dma_chan_rx, *dma_chan_tx;
        struct scatterlist      rx_sgl, tx_sgl[2];
        void                    *rx_buf;
+       struct circ_buf         rx_ring;
+       unsigned int            rx_periods;
+       dma_cookie_t            rx_cookie;
        unsigned int            tx_bytes;
        unsigned int            dma_tx_nents;
        wait_queue_head_t       dma_wait;
@@ -244,6 +248,10 @@ static struct imx_uart_data imx_uart_devdata[] = {
                .uts_reg = IMX21_UTS,
                .devtype = IMX21_UART,
        },
+       [IMX53_UART] = {
+               .uts_reg = IMX21_UTS,
+               .devtype = IMX53_UART,
+       },
        [IMX6Q_UART] = {
                .uts_reg = IMX21_UTS,
                .devtype = IMX6Q_UART,
@@ -257,6 +265,9 @@ static const struct platform_device_id imx_uart_devtype[] = {
        }, {
                .name = "imx21-uart",
                .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
+       }, {
+               .name = "imx53-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX53_UART],
        }, {
                .name = "imx6q-uart",
                .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART],
@@ -268,6 +279,7 @@ MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
 
 static const struct of_device_id imx_uart_dt_ids[] = {
        { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },
+       { .compatible = "fsl,imx53-uart", .data = &imx_uart_devdata[IMX53_UART], },
        { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
        { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
        { /* sentinel */ }
@@ -289,6 +301,11 @@ static inline int is_imx21_uart(struct imx_port *sport)
        return sport->devdata->devtype == IMX21_UART;
 }
 
+static inline int is_imx53_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX53_UART;
+}
+
 static inline int is_imx6q_uart(struct imx_port *sport)
 {
        return sport->devdata->devtype == IMX6Q_UART;
@@ -701,6 +718,7 @@ out:
        return IRQ_HANDLED;
 }
 
+static void clear_rx_errors(struct imx_port *sport);
 static int start_rx_dma(struct imx_port *sport);
 /*
  * If the RXFIFO is filled with some data, and then we
@@ -726,6 +744,11 @@ static void imx_dma_rxint(struct imx_port *sport)
                temp &= ~(UCR2_ATEN);
                writel(temp, sport->port.membase + UCR2);
 
+               /* disable the rx errors interrupts */
+               temp = readl(sport->port.membase + UCR4);
+               temp &= ~UCR4_OREN;
+               writel(temp, sport->port.membase + UCR4);
+
                /* tell the DMA to receive the data. */
                start_rx_dma(sport);
        }
@@ -740,12 +763,13 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport)
 {
        unsigned int tmp = TIOCM_DSR;
        unsigned usr1 = readl(sport->port.membase + USR1);
+       unsigned usr2 = readl(sport->port.membase + USR2);
 
        if (usr1 & USR1_RTSS)
                tmp |= TIOCM_CTS;
 
        /* in DCE mode DCDIN is always 0 */
-       if (!(usr1 & USR2_DCDIN))
+       if (!(usr2 & USR2_DCDIN))
                tmp |= TIOCM_CAR;
 
        if (sport->dte_mode)
@@ -932,30 +956,6 @@ static void imx_timeout(unsigned long data)
 }
 
 #define RX_BUF_SIZE    (PAGE_SIZE)
-static void imx_rx_dma_done(struct imx_port *sport)
-{
-       unsigned long temp;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       /* re-enable interrupts to get notified when new symbols are incoming */
-       temp = readl(sport->port.membase + UCR1);
-       temp |= UCR1_RRDYEN;
-       writel(temp, sport->port.membase + UCR1);
-
-       temp = readl(sport->port.membase + UCR2);
-       temp |= UCR2_ATEN;
-       writel(temp, sport->port.membase + UCR2);
-
-       sport->dma_is_rxing = 0;
-
-       /* Is the shutdown waiting for us? */
-       if (waitqueue_active(&sport->dma_wait))
-               wake_up(&sport->dma_wait);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
 
 /*
  * There are two kinds of RX DMA interrupts(such as in the MX6Q):
@@ -972,43 +972,76 @@ static void dma_rx_callback(void *data)
        struct scatterlist *sgl = &sport->rx_sgl;
        struct tty_port *port = &sport->port.state->port;
        struct dma_tx_state state;
+       struct circ_buf *rx_ring = &sport->rx_ring;
        enum dma_status status;
-       unsigned int count;
-
-       /* unmap it first */
-       dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
+       unsigned int w_bytes = 0;
+       unsigned int r_bytes;
+       unsigned int bd_size;
 
        status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
-       count = RX_BUF_SIZE - state.residue;
 
-       dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
+       if (status == DMA_ERROR) {
+               dev_err(sport->port.dev, "DMA transaction error.\n");
+               clear_rx_errors(sport);
+               return;
+       }
+
+       if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
+
+               /*
+                * The state-residue variable represents the empty space
+                * relative to the entire buffer. Taking this in consideration
+                * the head is always calculated base on the buffer total
+                * length - DMA transaction residue. The UART script from the
+                * SDMA firmware will jump to the next buffer descriptor,
+                * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
+                * Taking this in consideration the tail is always at the
+                * beginning of the buffer descriptor that contains the head.
+                */
+
+               /* Calculate the head */
+               rx_ring->head = sg_dma_len(sgl) - state.residue;
+
+               /* Calculate the tail. */
+               bd_size = sg_dma_len(sgl) / sport->rx_periods;
+               rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
+
+               if (rx_ring->head <= sg_dma_len(sgl) &&
+                   rx_ring->head > rx_ring->tail) {
+
+                       /* Move data from tail to head */
+                       r_bytes = rx_ring->head - rx_ring->tail;
 
-       if (count) {
-               if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
-                       int bytes = tty_insert_flip_string(port, sport->rx_buf,
-                                       count);
+                       /* CPU claims ownership of RX DMA buffer */
+                       dma_sync_sg_for_cpu(sport->port.dev, sgl, 1,
+                               DMA_FROM_DEVICE);
 
-                       if (bytes != count)
+                       w_bytes = tty_insert_flip_string(port,
+                               sport->rx_buf + rx_ring->tail, r_bytes);
+
+                       /* UART retrieves ownership of RX DMA buffer */
+                       dma_sync_sg_for_device(sport->port.dev, sgl, 1,
+                               DMA_FROM_DEVICE);
+
+                       if (w_bytes != r_bytes)
                                sport->port.icount.buf_overrun++;
+
+                       sport->port.icount.rx += w_bytes;
+               } else  {
+                       WARN_ON(rx_ring->head > sg_dma_len(sgl));
+                       WARN_ON(rx_ring->head <= rx_ring->tail);
                }
-               tty_flip_buffer_push(port);
-               sport->port.icount.rx += count;
        }
 
-       /*
-        * Restart RX DMA directly if more data is available in order to skip
-        * the roundtrip through the IRQ handler. If there is some data already
-        * in the FIFO, DMA needs to be restarted soon anyways.
-        *
-        * Otherwise stop the DMA and reactivate FIFO IRQs to restart DMA once
-        * data starts to arrive again.
-        */
-       if (readl(sport->port.membase + USR2) & USR2_RDR)
-               start_rx_dma(sport);
-       else
-               imx_rx_dma_done(sport);
+       if (w_bytes) {
+               tty_flip_buffer_push(port);
+               dev_dbg(sport->port.dev, "We get %d bytes.\n", w_bytes);
+       }
 }
 
+/* RX DMA buffer periods */
+#define RX_DMA_PERIODS 4
+
 static int start_rx_dma(struct imx_port *sport)
 {
        struct scatterlist *sgl = &sport->rx_sgl;
@@ -1017,14 +1050,21 @@ static int start_rx_dma(struct imx_port *sport)
        struct dma_async_tx_descriptor *desc;
        int ret;
 
+       sport->rx_ring.head = 0;
+       sport->rx_ring.tail = 0;
+       sport->rx_periods = RX_DMA_PERIODS;
+
        sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
        ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
        if (ret == 0) {
                dev_err(dev, "DMA mapping error for RX.\n");
                return -EINVAL;
        }
-       desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
-                                       DMA_PREP_INTERRUPT);
+
+       desc = dmaengine_prep_dma_cyclic(chan, sg_dma_address(sgl),
+               sg_dma_len(sgl), sg_dma_len(sgl) / sport->rx_periods,
+               DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+
        if (!desc) {
                dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE);
                dev_err(dev, "We cannot prepare for the RX slave dma!\n");
@@ -1034,11 +1074,36 @@ static int start_rx_dma(struct imx_port *sport)
        desc->callback_param = sport;
 
        dev_dbg(dev, "RX: prepare for the DMA.\n");
-       dmaengine_submit(desc);
+       sport->rx_cookie = dmaengine_submit(desc);
        dma_async_issue_pending(chan);
        return 0;
 }
 
+static void clear_rx_errors(struct imx_port *sport)
+{
+       unsigned int status_usr1, status_usr2;
+
+       status_usr1 = readl(sport->port.membase + USR1);
+       status_usr2 = readl(sport->port.membase + USR2);
+
+       if (status_usr2 & USR2_BRCD) {
+               sport->port.icount.brk++;
+               writel(USR2_BRCD, sport->port.membase + USR2);
+       } else if (status_usr1 & USR1_FRAMERR) {
+               sport->port.icount.frame++;
+               writel(USR1_FRAMERR, sport->port.membase + USR1);
+       } else if (status_usr1 & USR1_PARITYERR) {
+               sport->port.icount.parity++;
+               writel(USR1_PARITYERR, sport->port.membase + USR1);
+       }
+
+       if (status_usr2 & USR2_ORE) {
+               sport->port.icount.overrun++;
+               writel(USR2_ORE, sport->port.membase + USR2);
+       }
+
+}
+
 #define TXTL_DEFAULT 2 /* reset default */
 #define RXTL_DEFAULT 1 /* reset default */
 #define TXTL_DMA 8 /* DMA burst setting */
@@ -1058,14 +1123,16 @@ static void imx_setup_ufcr(struct imx_port *sport,
 static void imx_uart_dma_exit(struct imx_port *sport)
 {
        if (sport->dma_chan_rx) {
+               dmaengine_terminate_sync(sport->dma_chan_rx);
                dma_release_channel(sport->dma_chan_rx);
                sport->dma_chan_rx = NULL;
-
+               sport->rx_cookie = -EINVAL;
                kfree(sport->rx_buf);
                sport->rx_buf = NULL;
        }
 
        if (sport->dma_chan_tx) {
+               dmaengine_terminate_sync(sport->dma_chan_tx);
                dma_release_channel(sport->dma_chan_tx);
                sport->dma_chan_tx = NULL;
        }
@@ -1103,6 +1170,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
                ret = -ENOMEM;
                goto err;
        }
+       sport->rx_ring.buf = sport->rx_buf;
 
        /* Prepare for TX : */
        sport->dma_chan_tx = dma_request_slave_channel(dev, "tx");
@@ -1201,8 +1269,7 @@ static int imx_startup(struct uart_port *port)
        writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
        /* Can we enable the DMA support? */
-       if (is_imx6q_uart(sport) && !uart_console(port) &&
-           !sport->dma_is_inited)
+       if (!uart_console(port) && !sport->dma_is_inited)
                imx_uart_dma_init(sport);
 
        spin_lock_irqsave(&sport->port.lock, flags);
@@ -1283,17 +1350,11 @@ static void imx_shutdown(struct uart_port *port)
        unsigned long flags;
 
        if (sport->dma_is_enabled) {
-               int ret;
+               sport->dma_is_rxing = 0;
+               sport->dma_is_txing = 0;
+               dmaengine_terminate_sync(sport->dma_chan_tx);
+               dmaengine_terminate_sync(sport->dma_chan_rx);
 
-               /* We have to wait for the DMA to finish. */
-               ret = wait_event_interruptible(sport->dma_wait,
-                       !sport->dma_is_rxing && !sport->dma_is_txing);
-               if (ret != 0) {
-                       sport->dma_is_rxing = 0;
-                       sport->dma_is_txing = 0;
-                       dmaengine_terminate_all(sport->dma_chan_tx);
-                       dmaengine_terminate_all(sport->dma_chan_rx);
-               }
                spin_lock_irqsave(&sport->port.lock, flags);
                imx_stop_tx(port);
                imx_stop_rx(port);
@@ -1690,7 +1751,7 @@ static int imx_rs485_config(struct uart_port *port,
        return 0;
 }
 
-static struct uart_ops imx_pops = {
+static const struct uart_ops imx_pops = {
        .tx_empty       = imx_tx_empty,
        .set_mctrl      = imx_set_mctrl,
        .get_mctrl      = imx_get_mctrl,
@@ -2077,8 +2138,10 @@ static int serial_imx_probe(struct platform_device *pdev)
 
        /* For register access, we only need to enable the ipg clock. */
        ret = clk_prepare_enable(sport->clk_ipg);
-       if (ret)
+       if (ret) {
+               dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret);
                return ret;
+       }
 
        /* Disable interrupts before requesting them */
        reg = readl_relaxed(sport->port.membase + UCR1);
@@ -2095,18 +2158,26 @@ static int serial_imx_probe(struct platform_device *pdev)
        if (txirq > 0) {
                ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,
                                       dev_name(&pdev->dev), sport);
-               if (ret)
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request rx irq: %d\n",
+                               ret);
                        return ret;
+               }
 
                ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,
                                       dev_name(&pdev->dev), sport);
-               if (ret)
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request tx irq: %d\n",
+                               ret);
                        return ret;
+               }
        } else {
                ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,
                                       dev_name(&pdev->dev), sport);
-               if (ret)
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
                        return ret;
+               }
        }
 
        imx_ports[sport->port.line] = sport;
index c5ddfe5..ec7d838 100644 (file)
@@ -346,7 +346,7 @@ static void jsm_config_port(struct uart_port *port, int flags)
        port->type = PORT_JSM;
 }
 
-static struct uart_ops jsm_ops = {
+static const struct uart_ops jsm_ops = {
        .tx_empty       = jsm_tty_tx_empty,
        .set_mctrl      = jsm_tty_set_mctrl,
        .get_mctrl      = jsm_tty_get_mctrl,
index 5c4c280..ace8264 100644 (file)
@@ -712,7 +712,7 @@ static void max3100_break_ctl(struct uart_port *port, int break_state)
        dev_dbg(&s->spi->dev, "%s\n", __func__);
 }
 
-static struct uart_ops max3100_ops = {
+static const struct uart_ops max3100_ops = {
        .tx_empty       = max3100_tx_empty,
        .set_mctrl      = max3100_set_mctrl,
        .get_mctrl      = max3100_get_mctrl,
index 9360801..8a3e926 100644 (file)
@@ -1329,9 +1329,9 @@ static int max310x_spi_probe(struct spi_device *spi)
                const struct spi_device_id *id_entry = spi_get_device_id(spi);
 
                devtype = (struct max310x_devtype *)id_entry->driver_data;
-               flags = IRQF_TRIGGER_FALLING;
        }
 
+       flags = IRQF_TRIGGER_FALLING;
        regcfg.max_register = devtype->nr * 0x20 - 1;
        regmap = devm_regmap_init_spi(spi, &regcfg);
 
index a44290e..e72ea61 100644 (file)
@@ -775,7 +775,7 @@ static int men_z135_verify_port(struct uart_port *port,
        return -EINVAL;
 }
 
-static struct uart_ops men_z135_ops = {
+static const struct uart_ops men_z135_ops = {
        .tx_empty = men_z135_tx_empty,
        .set_mctrl = men_z135_set_mctrl,
        .get_mctrl = men_z135_get_mctrl,
index eb54e5c..770454e 100644 (file)
@@ -1317,7 +1317,7 @@ static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
                mxs_clr(AUART_LINECTRL_BRK, s, REG_LINECTRL);
 }
 
-static struct uart_ops mxs_auart_ops = {
+static const struct uart_ops mxs_auart_ops = {
        .tx_empty       = mxs_auart_tx_empty,
        .start_tx       = mxs_auart_start_tx,
        .stop_tx        = mxs_auart_stop_tx,
@@ -1510,10 +1510,7 @@ static int mxs_get_clks(struct mxs_auart_port *s,
 
        if (!is_asm9260_auart(s)) {
                s->clk = devm_clk_get(&pdev->dev, NULL);
-               if (IS_ERR(s->clk))
-                       return PTR_ERR(s->clk);
-
-               return 0;
+               return PTR_ERR_OR_ZERO(s->clk);
        }
 
        s->clk = devm_clk_get(s->dev, "mod");
@@ -1537,16 +1534,20 @@ static int mxs_get_clks(struct mxs_auart_port *s,
        err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
        if (err) {
                dev_err(s->dev, "Failed to set rate!\n");
-               return err;
+               goto disable_clk_ahb;
        }
 
        err = clk_prepare_enable(s->clk);
        if (err) {
                dev_err(s->dev, "Failed to enable clk!\n");
-               return err;
+               goto disable_clk_ahb;
        }
 
        return 0;
+
+disable_clk_ahb:
+       clk_disable_unprepare(s->clk_ahb);
+       return err;
 }
 
 /*
index 23672f8..d391650 100644 (file)
@@ -1604,7 +1604,7 @@ static void pch_uart_put_poll_char(struct uart_port *port,
 }
 #endif /* CONFIG_CONSOLE_POLL */
 
-static struct uart_ops pch_uart_ops = {
+static const struct uart_ops pch_uart_ops = {
        .tx_empty = pch_uart_tx_empty,
        .set_mctrl = pch_uart_set_mctrl,
        .get_mctrl = pch_uart_get_mctrl,
index ae2095a..f44615f 100644 (file)
@@ -1577,7 +1577,7 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
 }
 
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
 
 static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
                                             unsigned long val, void *data)
index 2ae4fce..a04acef 100644 (file)
@@ -102,7 +102,7 @@ struct s3c24xx_uart_port {
 
        struct s3c24xx_uart_dma         *dma;
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
        struct notifier_block           freq_transition;
 #endif
 };
index f36e6df..a9d94f7 100644 (file)
@@ -1205,6 +1205,10 @@ static int sc16is7xx_probe(struct device *dev,
        }
 #endif
 
+       /* reset device, purging any pending irq / data */
+       regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
+                       SC16IS7XX_IOCONTROL_SRESET_BIT);
+
        for (i = 0; i < devtype->nr_uart; ++i) {
                s->p[i].line            = i;
                /* Initialize port data */
@@ -1234,6 +1238,22 @@ static int sc16is7xx_probe(struct device *dev,
                init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
                /* Register port */
                uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
+
+               /* Enable EFR */
+               sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
+                                    SC16IS7XX_LCR_CONF_MODE_B);
+
+               regcache_cache_bypass(s->regmap, true);
+
+               /* Enable write access to enhanced features */
+               sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG,
+                                    SC16IS7XX_EFR_ENABLE_BIT);
+
+               regcache_cache_bypass(s->regmap, false);
+
+               /* Restore access to general registers */
+               sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00);
+
                /* Go to suspend mode */
                sc16is7xx_power(&s->p[i].port, 0);
        }
index 9fc1533..6e4f636 100644 (file)
@@ -235,18 +235,9 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
        if (tty_port_initialized(port))
                return 0;
 
-       /*
-        * Set the TTY IO error marker - we will only clear this
-        * once we have successfully opened the port.
-        */
-       set_bit(TTY_IO_ERROR, &tty->flags);
-
        retval = uart_port_startup(tty, state, init_hw);
-       if (!retval) {
-               tty_port_set_initialized(port, 1);
-               clear_bit(TTY_IO_ERROR, &tty->flags);
-       } else if (retval > 0)
-               retval = 0;
+       if (retval)
+               set_bit(TTY_IO_ERROR, &tty->flags);
 
        return retval;
 }
@@ -972,8 +963,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
                        }
                        uart_change_speed(tty, state, NULL);
                }
-       } else
+       } else {
                retval = uart_startup(tty, state, 1);
+               if (retval > 0)
+                       retval = 0;
+       }
  exit:
        return retval;
 }
@@ -1139,6 +1133,8 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
                uport->ops->config_port(uport, flags);
 
                ret = uart_startup(tty, state, 1);
+               if (ret > 0)
+                       ret = 0;
        }
 out:
        mutex_unlock(&port->mutex);
@@ -1465,7 +1461,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 {
        struct uart_state *state = tty->driver_data;
        struct tty_port *port;
-       struct uart_port *uport;
 
        if (!state) {
                struct uart_driver *drv = tty->driver->driver_state;
@@ -1481,56 +1476,36 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        port = &state->port;
        pr_debug("uart_close(%d) called\n", tty->index);
 
-       if (tty_port_close_start(port, tty, filp) == 0)
-               return;
+       tty_port_close(tty->port, tty, filp);
+}
 
-       mutex_lock(&port->mutex);
-       uport = uart_port_check(state);
+static void uart_tty_port_shutdown(struct tty_port *port)
+{
+       struct uart_state *state = container_of(port, struct uart_state, port);
+       struct uart_port *uport = uart_port_check(state);
 
        /*
         * At this point, we stop accepting input.  To do this, we
         * disable the receive line status interrupts.
         */
-       if (tty_port_initialized(port) &&
-           !WARN(!uport, "detached port still initialized!\n")) {
-               spin_lock_irq(&uport->lock);
-               uport->ops->stop_rx(uport);
-               spin_unlock_irq(&uport->lock);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               uart_wait_until_sent(tty, uport->timeout);
-       }
-
-       uart_shutdown(tty, state);
-       tty_port_tty_set(port, NULL);
+       if (WARN(!uport, "detached port still initialized!\n"))
+               return;
 
-       spin_lock_irq(&port->lock);
+       spin_lock_irq(&uport->lock);
+       uport->ops->stop_rx(uport);
+       spin_unlock_irq(&uport->lock);
 
-       if (port->blocked_open) {
-               spin_unlock_irq(&port->lock);
-               if (port->close_delay)
-                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
-               spin_lock_irq(&port->lock);
-       } else if (uport && !uart_console(uport)) {
-               spin_unlock_irq(&port->lock);
-               uart_change_pm(state, UART_PM_STATE_OFF);
-               spin_lock_irq(&port->lock);
-       }
-       spin_unlock_irq(&port->lock);
-       tty_port_set_active(port, 0);
+       uart_port_shutdown(port);
 
        /*
-        * Wake up anyone trying to open this port.
+        * It's possible for shutdown to be called after suspend if we get
+        * a DCD drop (hangup) at just the right time.  Clear suspended bit so
+        * we don't try to resume a port that has been shutdown.
         */
-       wake_up_interruptible(&port->open_wait);
+       tty_port_set_suspended(port, 0);
 
-       mutex_unlock(&port->mutex);
+       uart_change_pm(state, UART_PM_STATE_OFF);
 
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
 }
 
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
@@ -1711,52 +1686,31 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        struct uart_driver *drv = tty->driver->driver_state;
        int retval, line = tty->index;
        struct uart_state *state = drv->state + line;
-       struct tty_port *port = &state->port;
-       struct uart_port *uport;
 
-       pr_debug("uart_open(%d) called\n", line);
+       tty->driver_data = state;
 
-       spin_lock_irq(&port->lock);
-       ++port->count;
-       spin_unlock_irq(&port->lock);
+       retval = tty_port_open(&state->port, tty, filp);
+       if (retval > 0)
+               retval = 0;
 
-       /*
-        * We take the semaphore here to guarantee that we won't be re-entered
-        * while allocating the state structure, or while we request any IRQs
-        * that the driver may need.  This also has the nice side-effect that
-        * it delays the action of uart_hangup, so we can guarantee that
-        * state->port.tty will always contain something reasonable.
-        */
-       if (mutex_lock_interruptible(&port->mutex)) {
-               retval = -ERESTARTSYS;
-               goto end;
-       }
+       return retval;
+}
+
+static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       struct uart_state *state = container_of(port, struct uart_state, port);
+       struct uart_port *uport;
 
        uport = uart_port_check(state);
-       if (!uport || uport->flags & UPF_DEAD) {
-               retval = -ENXIO;
-               goto err_unlock;
-       }
+       if (!uport || uport->flags & UPF_DEAD)
+               return -ENXIO;
 
-       tty->driver_data = state;
-       uport->state = state;
        port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
-       tty_port_tty_set(port, tty);
 
        /*
         * Start up the serial port.
         */
-       retval = uart_startup(tty, state, 0);
-
-       /*
-        * If we succeeded, wait until the port is ready.
-        */
-err_unlock:
-       mutex_unlock(&port->mutex);
-       if (retval == 0)
-               retval = tty_port_block_til_ready(port, tty, filp);
-end:
-       return retval;
+       return uart_startup(tty, state, 0);
 }
 
 static const char *uart_type(struct uart_port *port)
@@ -1940,7 +1894,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
  *
  *     Returns 0 on success or -EINVAL on failure
  */
-int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
+int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
                        char **options)
 {
        if (strncmp(p, "mmio,", 5) == 0) {
@@ -1968,7 +1922,11 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
                return -EINVAL;
        }
 
-       *addr = simple_strtoul(p, NULL, 0);
+       /*
+        * Before you replace it with kstrtoull(), think about options separator
+        * (',') it will not tolerate
+        */
+       *addr = simple_strtoull(p, NULL, 0);
        p = strchr(p, ',');
        if (p)
                p++;
@@ -2470,6 +2428,8 @@ static const struct tty_operations uart_ops = {
 static const struct tty_port_operations uart_port_ops = {
        .carrier_raised = uart_carrier_raised,
        .dtr_rts        = uart_dtr_rts,
+       .activate       = uart_port_activate,
+       .shutdown       = uart_tty_port_shutdown,
 };
 
 /**
@@ -2786,6 +2746,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
        uport->cons = drv->cons;
        uport->minor = drv->tty_driver->minor_start + uport->line;
 
+       port->console = uart_console(uport);
+
        /*
         * If this port is a console, then the spinlock is already
         * initialised.
index d86eee3..4b26252 100644 (file)
@@ -2533,7 +2533,7 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
        return 0;
 }
 
-static struct uart_ops sci_uart_ops = {
+static const struct uart_ops sci_uart_ops = {
        .tx_empty       = sci_tx_empty,
        .set_mctrl      = sci_set_mctrl,
        .get_mctrl      = sci_get_mctrl,
index 2d78cb3..379e5bd 100644 (file)
@@ -639,7 +639,7 @@ static void asc_put_poll_char(struct uart_port *port, unsigned char c)
 
 /*---------------------------------------------------------------------*/
 
-static struct uart_ops asc_uart_ops = {
+static const struct uart_ops asc_uart_ops = {
        .tx_empty       = asc_tx_empty,
        .set_mctrl      = asc_set_mctrl,
        .get_mctrl      = asc_get_mctrl,
index f89d1f7..0338562 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) Maxime Coquelin 2015
- * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * Authors:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *          Gerald Baeza <gerald.baeza@st.com>
  * License terms:  GNU General Public License (GPL), version 2
  *
  * Inspired by st-asc.c from STMicroelectronics (c)
 #define SUPPORT_SYSRQ
 #endif
 
-#include <linux/module.h>
-#include <linux/serial.h>
+#include <linux/clk.h>
 #include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-direction.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/irq.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/pm_runtime.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/serial_core.h>
-#include <linux/clk.h>
-
-#define DRIVER_NAME "stm32-usart"
-
-/* Register offsets */
-#define USART_SR               0x00
-#define USART_DR               0x04
-#define USART_BRR              0x08
-#define USART_CR1              0x0c
-#define USART_CR2              0x10
-#define USART_CR3              0x14
-#define USART_GTPR             0x18
-
-/* USART_SR */
-#define USART_SR_PE            BIT(0)
-#define USART_SR_FE            BIT(1)
-#define USART_SR_NF            BIT(2)
-#define USART_SR_ORE           BIT(3)
-#define USART_SR_IDLE          BIT(4)
-#define USART_SR_RXNE          BIT(5)
-#define USART_SR_TC            BIT(6)
-#define USART_SR_TXE           BIT(7)
-#define USART_SR_LBD           BIT(8)
-#define USART_SR_CTS           BIT(9)
-#define USART_SR_ERR_MASK      (USART_SR_LBD | USART_SR_ORE | \
-                                USART_SR_FE | USART_SR_PE)
-/* Dummy bits */
-#define USART_SR_DUMMY_RX      BIT(16)
-
-/* USART_DR */
-#define USART_DR_MASK          GENMASK(8, 0)
-
-/* USART_BRR */
-#define USART_BRR_DIV_F_MASK   GENMASK(3, 0)
-#define USART_BRR_DIV_M_MASK   GENMASK(15, 4)
-#define USART_BRR_DIV_M_SHIFT  4
-
-/* USART_CR1 */
-#define USART_CR1_SBK          BIT(0)
-#define USART_CR1_RWU          BIT(1)
-#define USART_CR1_RE           BIT(2)
-#define USART_CR1_TE           BIT(3)
-#define USART_CR1_IDLEIE       BIT(4)
-#define USART_CR1_RXNEIE       BIT(5)
-#define USART_CR1_TCIE         BIT(6)
-#define USART_CR1_TXEIE                BIT(7)
-#define USART_CR1_PEIE         BIT(8)
-#define USART_CR1_PS           BIT(9)
-#define USART_CR1_PCE          BIT(10)
-#define USART_CR1_WAKE         BIT(11)
-#define USART_CR1_M            BIT(12)
-#define USART_CR1_UE           BIT(13)
-#define USART_CR1_OVER8                BIT(15)
-#define USART_CR1_IE_MASK      GENMASK(8, 4)
-
-/* USART_CR2 */
-#define USART_CR2_ADD_MASK     GENMASK(3, 0)
-#define USART_CR2_LBDL         BIT(5)
-#define USART_CR2_LBDIE                BIT(6)
-#define USART_CR2_LBCL         BIT(8)
-#define USART_CR2_CPHA         BIT(9)
-#define USART_CR2_CPOL         BIT(10)
-#define USART_CR2_CLKEN                BIT(11)
-#define USART_CR2_STOP_2B      BIT(13)
-#define USART_CR2_STOP_MASK    GENMASK(13, 12)
-#define USART_CR2_LINEN                BIT(14)
-
-/* USART_CR3 */
-#define USART_CR3_EIE          BIT(0)
-#define USART_CR3_IREN         BIT(1)
-#define USART_CR3_IRLP         BIT(2)
-#define USART_CR3_HDSEL                BIT(3)
-#define USART_CR3_NACK         BIT(4)
-#define USART_CR3_SCEN         BIT(5)
-#define USART_CR3_DMAR         BIT(6)
-#define USART_CR3_DMAT         BIT(7)
-#define USART_CR3_RTSE         BIT(8)
-#define USART_CR3_CTSE         BIT(9)
-#define USART_CR3_CTSIE                BIT(10)
-#define USART_CR3_ONEBIT       BIT(11)
-
-/* USART_GTPR */
-#define USART_GTPR_PSC_MASK    GENMASK(7, 0)
-#define USART_GTPR_GT_MASK     GENMASK(15, 8)
-
-#define DRIVER_NAME "stm32-usart"
-#define STM32_SERIAL_NAME "ttyS"
-#define STM32_MAX_PORTS 6
-
-struct stm32_port {
-       struct uart_port port;
-       struct clk *clk;
-       bool hw_flow_control;
-};
+#include <linux/serial.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
 
-static struct stm32_port stm32_ports[STM32_MAX_PORTS];
-static struct uart_driver stm32_usart_driver;
+#include "stm32-usart.h"
 
 static void stm32_stop_tx(struct uart_port *port);
+static void stm32_transmit_chars(struct uart_port *port);
 
 static inline struct stm32_port *to_stm32_port(struct uart_port *port)
 {
@@ -148,19 +60,64 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
        writel_relaxed(val, port->membase + reg);
 }
 
-static void stm32_receive_chars(struct uart_port *port)
+static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
+                           bool threaded)
+{
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+       enum dma_status status;
+       struct dma_tx_state state;
+
+       *sr = readl_relaxed(port->membase + ofs->isr);
+
+       if (threaded && stm32_port->rx_ch) {
+               status = dmaengine_tx_status(stm32_port->rx_ch,
+                                            stm32_port->rx_ch->cookie,
+                                            &state);
+               if ((status == DMA_IN_PROGRESS) &&
+                   (*last_res != state.residue))
+                       return 1;
+               else
+                       return 0;
+       } else if (*sr & USART_SR_RXNE) {
+               return 1;
+       }
+       return 0;
+}
+
+static unsigned long
+stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
+{
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+       unsigned long c;
+
+       if (stm32_port->rx_ch) {
+               c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--];
+               if ((*last_res) == 0)
+                       *last_res = RX_BUF_L;
+               return c;
+       } else {
+               return readl_relaxed(port->membase + ofs->rdr);
+       }
+}
+
+static void stm32_receive_chars(struct uart_port *port, bool threaded)
 {
        struct tty_port *tport = &port->state->port;
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        unsigned long c;
        u32 sr;
        char flag;
+       static int last_res = RX_BUF_L;
 
        if (port->irq_wake)
                pm_wakeup_event(tport->tty->dev, 0);
 
-       while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+       while (stm32_pending_rx(port, &sr, &last_res, threaded)) {
                sr |= USART_SR_DUMMY_RX;
-               c = readl_relaxed(port->membase + USART_DR);
+               c = stm32_get_char(port, &sr, &last_res);
                flag = TTY_NORMAL;
                port->icount.rx++;
 
@@ -170,6 +127,10 @@ static void stm32_receive_chars(struct uart_port *port)
                                if (uart_handle_break(port))
                                        continue;
                        } else if (sr & USART_SR_ORE) {
+                               if (ofs->icr != UNDEF_REG)
+                                       writel_relaxed(USART_ICR_ORECF,
+                                                      port->membase +
+                                                      ofs->icr);
                                port->icount.overrun++;
                        } else if (sr & USART_SR_PE) {
                                port->icount.parity++;
@@ -197,14 +158,138 @@ static void stm32_receive_chars(struct uart_port *port)
        spin_lock(&port->lock);
 }
 
+static void stm32_tx_dma_complete(void *arg)
+{
+       struct uart_port *port = arg;
+       struct stm32_port *stm32port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
+       unsigned int isr;
+       int ret;
+
+       ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
+                                               isr,
+                                               (isr & USART_SR_TC),
+                                               10, 100000);
+
+       if (ret)
+               dev_err(port->dev, "terminal count not set\n");
+
+       if (ofs->icr == UNDEF_REG)
+               stm32_clr_bits(port, ofs->isr, USART_SR_TC);
+       else
+               stm32_set_bits(port, ofs->icr, USART_CR_TC);
+
+       stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+       stm32port->tx_dma_busy = false;
+
+       /* Let's see if we have pending data to send */
+       stm32_transmit_chars(port);
+}
+
+static void stm32_transmit_chars_pio(struct uart_port *port)
+{
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int isr;
+       int ret;
+
+       if (stm32_port->tx_dma_busy) {
+               stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+               stm32_port->tx_dma_busy = false;
+       }
+
+       ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
+                                               isr,
+                                               (isr & USART_SR_TXE),
+                                               10, 100);
+
+       if (ret)
+               dev_err(port->dev, "tx empty not set\n");
+
+       stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+
+       writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       port->icount.tx++;
+}
+
+static void stm32_transmit_chars_dma(struct uart_port *port)
+{
+       struct stm32_port *stm32port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct dma_async_tx_descriptor *desc = NULL;
+       dma_cookie_t cookie;
+       unsigned int count, i;
+
+       if (stm32port->tx_dma_busy)
+               return;
+
+       stm32port->tx_dma_busy = true;
+
+       count = uart_circ_chars_pending(xmit);
+
+       if (count > TX_BUF_L)
+               count = TX_BUF_L;
+
+       if (xmit->tail < xmit->head) {
+               memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], count);
+       } else {
+               size_t one = UART_XMIT_SIZE - xmit->tail;
+               size_t two;
+
+               if (one > count)
+                       one = count;
+               two = count - one;
+
+               memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], one);
+               if (two)
+                       memcpy(&stm32port->tx_buf[one], &xmit->buf[0], two);
+       }
+
+       desc = dmaengine_prep_slave_single(stm32port->tx_ch,
+                                          stm32port->tx_dma_buf,
+                                          count,
+                                          DMA_MEM_TO_DEV,
+                                          DMA_PREP_INTERRUPT);
+
+       if (!desc) {
+               for (i = count; i > 0; i--)
+                       stm32_transmit_chars_pio(port);
+               return;
+       }
+
+       desc->callback = stm32_tx_dma_complete;
+       desc->callback_param = port;
+
+       /* Push current DMA TX transaction in the pending queue */
+       cookie = dmaengine_submit(desc);
+
+       /* Issue pending DMA TX requests */
+       dma_async_issue_pending(stm32port->tx_ch);
+
+       stm32_clr_bits(port, ofs->isr, USART_SR_TC);
+       stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT);
+
+       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+       port->icount.tx += count;
+}
+
 static void stm32_transmit_chars(struct uart_port *port)
 {
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        struct circ_buf *xmit = &port->state->xmit;
 
        if (port->x_char) {
-               writel_relaxed(port->x_char, port->membase + USART_DR);
+               if (stm32_port->tx_dma_busy)
+                       stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+               writel_relaxed(port->x_char, port->membase + ofs->tdr);
                port->x_char = 0;
                port->icount.tx++;
+               if (stm32_port->tx_dma_busy)
+                       stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT);
                return;
        }
 
@@ -218,9 +303,10 @@ static void stm32_transmit_chars(struct uart_port *port)
                return;
        }
 
-       writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       port->icount.tx++;
+       if (stm32_port->tx_ch)
+               stm32_transmit_chars_dma(port);
+       else
+               stm32_transmit_chars_pio(port);
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
@@ -232,34 +318,60 @@ static void stm32_transmit_chars(struct uart_port *port)
 static irqreturn_t stm32_interrupt(int irq, void *ptr)
 {
        struct uart_port *port = ptr;
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        u32 sr;
 
        spin_lock(&port->lock);
 
-       sr = readl_relaxed(port->membase + USART_SR);
+       sr = readl_relaxed(port->membase + ofs->isr);
 
-       if (sr & USART_SR_RXNE)
-               stm32_receive_chars(port);
+       if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
+               stm32_receive_chars(port, false);
 
-       if (sr & USART_SR_TXE)
+       if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch))
                stm32_transmit_chars(port);
 
        spin_unlock(&port->lock);
 
+       if (stm32_port->rx_ch)
+               return IRQ_WAKE_THREAD;
+       else
+               return IRQ_HANDLED;
+}
+
+static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+       struct stm32_port *stm32_port = to_stm32_port(port);
+
+       spin_lock(&port->lock);
+
+       if (stm32_port->rx_ch)
+               stm32_receive_chars(port, true);
+
+       spin_unlock(&port->lock);
+
        return IRQ_HANDLED;
 }
 
 static unsigned int stm32_tx_empty(struct uart_port *port)
 {
-       return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+       return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE;
 }
 
 static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
        if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
-               stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
+               stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE);
        else
-               stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE);
+               stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE);
 }
 
 static unsigned int stm32_get_mctrl(struct uart_port *port)
@@ -271,7 +383,10 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
 /* Transmit stop */
 static void stm32_stop_tx(struct uart_port *port)
 {
-       stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+       stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
 }
 
 /* There are probably characters waiting to be transmitted. */
@@ -282,33 +397,40 @@ static void stm32_start_tx(struct uart_port *port)
        if (uart_circ_empty(xmit))
                return;
 
-       stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+       stm32_transmit_chars(port);
 }
 
 /* Throttle the remote when input buffer is about to overflow. */
 static void stm32_throttle(struct uart_port *port)
 {
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
-       stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+       stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
 /* Unthrottle the remote, the input buffer can now accept data. */
 static void stm32_unthrottle(struct uart_port *port)
 {
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
-       stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE);
+       stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE);
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
 /* Receive stop */
 static void stm32_stop_rx(struct uart_port *port)
 {
-       stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+       stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
 }
 
 /* Handle breaks - ignored by us */
@@ -318,26 +440,34 @@ static void stm32_break_ctl(struct uart_port *port, int break_state)
 
 static int stm32_startup(struct uart_port *port)
 {
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        const char *name = to_platform_device(port->dev)->name;
        u32 val;
        int ret;
 
-       ret = request_irq(port->irq, stm32_interrupt, 0, name, port);
+       ret = request_threaded_irq(port->irq, stm32_interrupt,
+                                  stm32_threaded_interrupt,
+                                  IRQF_NO_SUSPEND, name, port);
        if (ret)
                return ret;
 
        val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
-       stm32_set_bits(port, USART_CR1, val);
+       stm32_set_bits(port, ofs->cr1, val);
 
        return 0;
 }
 
 static void stm32_shutdown(struct uart_port *port)
 {
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+       struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        u32 val;
 
        val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
-       stm32_set_bits(port, USART_CR1, val);
+       val |= BIT(cfg->uart_enable_bit);
+       stm32_clr_bits(port, ofs->cr1, val);
 
        free_irq(port->irq, port);
 }
@@ -346,6 +476,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
        struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+       struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        unsigned int baud;
        u32 usartdiv, mantissa, fraction, oversampling;
        tcflag_t cflag = termios->c_cflag;
@@ -360,9 +492,10 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
        spin_lock_irqsave(&port->lock, flags);
 
        /* Stop serial port and reset value */
-       writel_relaxed(0, port->membase + USART_CR1);
+       writel_relaxed(0, port->membase + ofs->cr1);
 
-       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
+       cr1 |= BIT(cfg->uart_enable_bit);
        cr2 = 0;
        cr3 = 0;
 
@@ -371,8 +504,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
 
        if (cflag & PARENB) {
                cr1 |= USART_CR1_PCE;
-               if ((cflag & CSIZE) == CS8)
-                       cr1 |= USART_CR1_M;
+               if ((cflag & CSIZE) == CS8) {
+                       if (cfg->has_7bits_data)
+                               cr1 |= USART_CR1_M0;
+                       else
+                               cr1 |= USART_CR1_M;
+               }
        }
 
        if (cflag & PARODD)
@@ -394,15 +531,15 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
         */
        if (usartdiv < 16) {
                oversampling = 8;
-               stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
+               stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8);
        } else {
                oversampling = 16;
-               stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
+               stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
        }
 
        mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
        fraction = usartdiv % oversampling;
-       writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+       writel_relaxed(mantissa | fraction, port->membase + ofs->brr);
 
        uart_update_timeout(port, cflag, baud);
 
@@ -430,9 +567,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
        if ((termios->c_cflag & CREAD) == 0)
                port->ignore_status_mask |= USART_SR_DUMMY_RX;
 
-       writel_relaxed(cr3, port->membase + USART_CR3);
-       writel_relaxed(cr2, port->membase + USART_CR2);
-       writel_relaxed(cr1, port->membase + USART_CR1);
+       if (stm32_port->rx_ch)
+               cr3 |= USART_CR3_DMAR;
+
+       writel_relaxed(cr3, port->membase + ofs->cr3);
+       writel_relaxed(cr2, port->membase + ofs->cr2);
+       writel_relaxed(cr1, port->membase + ofs->cr1);
 
        spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -469,6 +609,8 @@ static void stm32_pm(struct uart_port *port, unsigned int state,
 {
        struct stm32_port *stm32port = container_of(port,
                        struct stm32_port, port);
+       struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
+       struct stm32_usart_config *cfg = &stm32port->info->cfg;
        unsigned long flags = 0;
 
        switch (state) {
@@ -477,7 +619,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state,
                break;
        case UART_PM_STATE_OFF:
                spin_lock_irqsave(&port->lock, flags);
-               stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+               stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
                spin_unlock_irqrestore(&port->lock, flags);
                clk_disable_unprepare(stm32port->clk);
                break;
@@ -539,8 +681,6 @@ static int stm32_init_port(struct stm32_port *stm32port,
        if (!stm32port->port.uartclk)
                ret = -EINVAL;
 
-       clk_disable_unprepare(stm32port->clk);
-
        return ret;
 }
 
@@ -560,30 +700,162 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
                return NULL;
 
        stm32_ports[id].hw_flow_control = of_property_read_bool(np,
-                                                       "auto-flow-control");
+                                                       "st,hw-flow-ctrl");
        stm32_ports[id].port.line = id;
        return &stm32_ports[id];
 }
 
 #ifdef CONFIG_OF
 static const struct of_device_id stm32_match[] = {
-       { .compatible = "st,stm32-usart", },
-       { .compatible = "st,stm32-uart", },
+       { .compatible = "st,stm32-usart", .data = &stm32f4_info},
+       { .compatible = "st,stm32-uart", .data = &stm32f4_info},
+       { .compatible = "st,stm32f7-usart", .data = &stm32f7_info},
+       { .compatible = "st,stm32f7-uart", .data = &stm32f7_info},
        {},
 };
 
 MODULE_DEVICE_TABLE(of, stm32_match);
 #endif
 
-static int stm32_serial_probe(struct platform_device *pdev)
+static int stm32_of_dma_rx_probe(struct stm32_port *stm32port,
+                                struct platform_device *pdev)
 {
+       struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
+       struct uart_port *port = &stm32port->port;
+       struct device *dev = &pdev->dev;
+       struct dma_slave_config config;
+       struct dma_async_tx_descriptor *desc = NULL;
+       dma_cookie_t cookie;
        int ret;
+
+       /* Request DMA RX channel */
+       stm32port->rx_ch = dma_request_slave_channel(dev, "rx");
+       if (!stm32port->rx_ch) {
+               dev_info(dev, "rx dma alloc failed\n");
+               return -ENODEV;
+       }
+       stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L,
+                                                &stm32port->rx_dma_buf,
+                                                GFP_KERNEL);
+       if (!stm32port->rx_buf) {
+               ret = -ENOMEM;
+               goto alloc_err;
+       }
+
+       /* Configure DMA channel */
+       memset(&config, 0, sizeof(config));
+       config.src_addr = port->mapbase + ofs->rdr;
+       config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+
+       ret = dmaengine_slave_config(stm32port->rx_ch, &config);
+       if (ret < 0) {
+               dev_err(dev, "rx dma channel config failed\n");
+               ret = -ENODEV;
+               goto config_err;
+       }
+
+       /* Prepare a DMA cyclic transaction */
+       desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch,
+                                        stm32port->rx_dma_buf,
+                                        RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM,
+                                        DMA_PREP_INTERRUPT);
+       if (!desc) {
+               dev_err(dev, "rx dma prep cyclic failed\n");
+               ret = -ENODEV;
+               goto config_err;
+       }
+
+       /* No callback as dma buffer is drained on usart interrupt */
+       desc->callback = NULL;
+       desc->callback_param = NULL;
+
+       /* Push current DMA transaction in the pending queue */
+       cookie = dmaengine_submit(desc);
+
+       /* Issue pending DMA requests */
+       dma_async_issue_pending(stm32port->rx_ch);
+
+       return 0;
+
+config_err:
+       dma_free_coherent(&pdev->dev,
+                         RX_BUF_L, stm32port->rx_buf,
+                         stm32port->rx_dma_buf);
+
+alloc_err:
+       dma_release_channel(stm32port->rx_ch);
+       stm32port->rx_ch = NULL;
+
+       return ret;
+}
+
+static int stm32_of_dma_tx_probe(struct stm32_port *stm32port,
+                                struct platform_device *pdev)
+{
+       struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
+       struct uart_port *port = &stm32port->port;
+       struct device *dev = &pdev->dev;
+       struct dma_slave_config config;
+       int ret;
+
+       stm32port->tx_dma_busy = false;
+
+       /* Request DMA TX channel */
+       stm32port->tx_ch = dma_request_slave_channel(dev, "tx");
+       if (!stm32port->tx_ch) {
+               dev_info(dev, "tx dma alloc failed\n");
+               return -ENODEV;
+       }
+       stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L,
+                                                &stm32port->tx_dma_buf,
+                                                GFP_KERNEL);
+       if (!stm32port->tx_buf) {
+               ret = -ENOMEM;
+               goto alloc_err;
+       }
+
+       /* Configure DMA channel */
+       memset(&config, 0, sizeof(config));
+       config.dst_addr = port->mapbase + ofs->tdr;
+       config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+
+       ret = dmaengine_slave_config(stm32port->tx_ch, &config);
+       if (ret < 0) {
+               dev_err(dev, "tx dma channel config failed\n");
+               ret = -ENODEV;
+               goto config_err;
+       }
+
+       return 0;
+
+config_err:
+       dma_free_coherent(&pdev->dev,
+                         TX_BUF_L, stm32port->tx_buf,
+                         stm32port->tx_dma_buf);
+
+alloc_err:
+       dma_release_channel(stm32port->tx_ch);
+       stm32port->tx_ch = NULL;
+
+       return ret;
+}
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
        struct stm32_port *stm32port;
+       int ret;
 
        stm32port = stm32_of_get_stm32_port(pdev);
        if (!stm32port)
                return -ENODEV;
 
+       match = of_match_device(stm32_match, &pdev->dev);
+       if (match && match->data)
+               stm32port->info = (struct stm32_usart_info *)match->data;
+       else
+               return -EINVAL;
+
        ret = stm32_init_port(stm32port, pdev);
        if (ret)
                return ret;
@@ -592,6 +864,14 @@ static int stm32_serial_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       ret = stm32_of_dma_rx_probe(stm32port, pdev);
+       if (ret)
+               dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n");
+
+       ret = stm32_of_dma_tx_probe(stm32port, pdev);
+       if (ret)
+               dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n");
+
        platform_set_drvdata(pdev, &stm32port->port);
 
        return 0;
@@ -600,6 +880,30 @@ static int stm32_serial_probe(struct platform_device *pdev)
 static int stm32_serial_remove(struct platform_device *pdev)
 {
        struct uart_port *port = platform_get_drvdata(pdev);
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+       stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
+
+       if (stm32_port->rx_ch)
+               dma_release_channel(stm32_port->rx_ch);
+
+       if (stm32_port->rx_dma_buf)
+               dma_free_coherent(&pdev->dev,
+                                 RX_BUF_L, stm32_port->rx_buf,
+                                 stm32_port->rx_dma_buf);
+
+       stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+
+       if (stm32_port->tx_ch)
+               dma_release_channel(stm32_port->tx_ch);
+
+       if (stm32_port->tx_dma_buf)
+               dma_free_coherent(&pdev->dev,
+                                 TX_BUF_L, stm32_port->tx_buf,
+                                 stm32_port->tx_dma_buf);
+
+       clk_disable_unprepare(stm32_port->clk);
 
        return uart_remove_one_port(&stm32_usart_driver, port);
 }
@@ -608,15 +912,21 @@ static int stm32_serial_remove(struct platform_device *pdev)
 #ifdef CONFIG_SERIAL_STM32_CONSOLE
 static void stm32_console_putchar(struct uart_port *port, int ch)
 {
-       while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+       while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
                cpu_relax();
 
-       writel_relaxed(ch, port->membase + USART_DR);
+       writel_relaxed(ch, port->membase + ofs->tdr);
 }
 
 static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
 {
        struct uart_port *port = &stm32_ports[co->index].port;
+       struct stm32_port *stm32_port = to_stm32_port(port);
+       struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+       struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        unsigned long flags;
        u32 old_cr1, new_cr1;
        int locked = 1;
@@ -629,15 +939,16 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
        else
                spin_lock(&port->lock);
 
-       /* Save and disable interrupts */
-       old_cr1 = readl_relaxed(port->membase + USART_CR1);
+       /* Save and disable interrupts, enable the transmitter */
+       old_cr1 = readl_relaxed(port->membase + ofs->cr1);
        new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
-       writel_relaxed(new_cr1, port->membase + USART_CR1);
+       new_cr1 |=  USART_CR1_TE | BIT(cfg->uart_enable_bit);
+       writel_relaxed(new_cr1, port->membase + ofs->cr1);
 
        uart_console_write(port, s, cnt, stm32_console_putchar);
 
        /* Restore interrupt state */
-       writel_relaxed(old_cr1, port->membase + USART_CR1);
+       writel_relaxed(old_cr1, port->membase + ofs->cr1);
 
        if (locked)
                spin_unlock(&port->lock);
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
new file mode 100644 (file)
index 0000000..41d9749
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Authors:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *          Gerald Baeza <gerald_baeza@yahoo.fr>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#define DRIVER_NAME "stm32-usart"
+
+struct stm32_usart_offsets {
+       u8 cr1;
+       u8 cr2;
+       u8 cr3;
+       u8 brr;
+       u8 gtpr;
+       u8 rtor;
+       u8 rqr;
+       u8 isr;
+       u8 icr;
+       u8 rdr;
+       u8 tdr;
+};
+
+struct stm32_usart_config {
+       u8 uart_enable_bit; /* USART_CR1_UE */
+       bool has_7bits_data;
+};
+
+struct stm32_usart_info {
+       struct stm32_usart_offsets ofs;
+       struct stm32_usart_config cfg;
+};
+
+#define UNDEF_REG ~0
+
+/* Register offsets */
+struct stm32_usart_info stm32f4_info = {
+       .ofs = {
+               .isr    = 0x00,
+               .rdr    = 0x04,
+               .tdr    = 0x04,
+               .brr    = 0x08,
+               .cr1    = 0x0c,
+               .cr2    = 0x10,
+               .cr3    = 0x14,
+               .gtpr   = 0x18,
+               .rtor   = UNDEF_REG,
+               .rqr    = UNDEF_REG,
+               .icr    = UNDEF_REG,
+       },
+       .cfg = {
+               .uart_enable_bit = 13,
+               .has_7bits_data = false,
+       }
+};
+
+struct stm32_usart_info stm32f7_info = {
+       .ofs = {
+               .cr1    = 0x00,
+               .cr2    = 0x04,
+               .cr3    = 0x08,
+               .brr    = 0x0c,
+               .gtpr   = 0x10,
+               .rtor   = 0x14,
+               .rqr    = 0x18,
+               .isr    = 0x1c,
+               .icr    = 0x20,
+               .rdr    = 0x24,
+               .tdr    = 0x28,
+       },
+       .cfg = {
+               .uart_enable_bit = 0,
+               .has_7bits_data = true,
+       }
+};
+
+/* USART_SR (F4) / USART_ISR (F7) */
+#define USART_SR_PE            BIT(0)
+#define USART_SR_FE            BIT(1)
+#define USART_SR_NF            BIT(2)
+#define USART_SR_ORE           BIT(3)
+#define USART_SR_IDLE          BIT(4)
+#define USART_SR_RXNE          BIT(5)
+#define USART_SR_TC            BIT(6)
+#define USART_SR_TXE           BIT(7)
+#define USART_SR_LBD           BIT(8)
+#define USART_SR_CTSIF         BIT(9)
+#define USART_SR_CTS           BIT(10)         /* F7 */
+#define USART_SR_RTOF          BIT(11)         /* F7 */
+#define USART_SR_EOBF          BIT(12)         /* F7 */
+#define USART_SR_ABRE          BIT(14)         /* F7 */
+#define USART_SR_ABRF          BIT(15)         /* F7 */
+#define USART_SR_BUSY          BIT(16)         /* F7 */
+#define USART_SR_CMF           BIT(17)         /* F7 */
+#define USART_SR_SBKF          BIT(18)         /* F7 */
+#define USART_SR_TEACK         BIT(21)         /* F7 */
+#define USART_SR_ERR_MASK      (USART_SR_LBD | USART_SR_ORE | \
+                                USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX      BIT(16)
+
+/* USART_ICR (F7) */
+#define USART_CR_TC            BIT(6)
+
+/* USART_DR */
+#define USART_DR_MASK          GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK   GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK   GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT  4
+
+/* USART_CR1 */
+#define USART_CR1_SBK          BIT(0)
+#define USART_CR1_RWU          BIT(1)          /* F4 */
+#define USART_CR1_RE           BIT(2)
+#define USART_CR1_TE           BIT(3)
+#define USART_CR1_IDLEIE       BIT(4)
+#define USART_CR1_RXNEIE       BIT(5)
+#define USART_CR1_TCIE         BIT(6)
+#define USART_CR1_TXEIE                BIT(7)
+#define USART_CR1_PEIE         BIT(8)
+#define USART_CR1_PS           BIT(9)
+#define USART_CR1_PCE          BIT(10)
+#define USART_CR1_WAKE         BIT(11)
+#define USART_CR1_M            BIT(12)
+#define USART_CR1_M0           BIT(12)         /* F7 */
+#define USART_CR1_MME          BIT(13)         /* F7 */
+#define USART_CR1_CMIE         BIT(14)         /* F7 */
+#define USART_CR1_OVER8                BIT(15)
+#define USART_CR1_DEDT_MASK    GENMASK(20, 16) /* F7 */
+#define USART_CR1_DEAT_MASK    GENMASK(25, 21) /* F7 */
+#define USART_CR1_RTOIE                BIT(26)         /* F7 */
+#define USART_CR1_EOBIE                BIT(27)         /* F7 */
+#define USART_CR1_M1           BIT(28)         /* F7 */
+#define USART_CR1_IE_MASK      (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27))
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK     GENMASK(3, 0)   /* F4 */
+#define USART_CR2_ADDM7                BIT(4)          /* F7 */
+#define USART_CR2_LBDL         BIT(5)
+#define USART_CR2_LBDIE                BIT(6)
+#define USART_CR2_LBCL         BIT(8)
+#define USART_CR2_CPHA         BIT(9)
+#define USART_CR2_CPOL         BIT(10)
+#define USART_CR2_CLKEN                BIT(11)
+#define USART_CR2_STOP_2B      BIT(13)
+#define USART_CR2_STOP_MASK    GENMASK(13, 12)
+#define USART_CR2_LINEN                BIT(14)
+#define USART_CR2_SWAP         BIT(15)         /* F7 */
+#define USART_CR2_RXINV                BIT(16)         /* F7 */
+#define USART_CR2_TXINV                BIT(17)         /* F7 */
+#define USART_CR2_DATAINV      BIT(18)         /* F7 */
+#define USART_CR2_MSBFIRST     BIT(19)         /* F7 */
+#define USART_CR2_ABREN                BIT(20)         /* F7 */
+#define USART_CR2_ABRMOD_MASK  GENMASK(22, 21) /* F7 */
+#define USART_CR2_RTOEN                BIT(23)         /* F7 */
+#define USART_CR2_ADD_F7_MASK  GENMASK(31, 24) /* F7 */
+
+/* USART_CR3 */
+#define USART_CR3_EIE          BIT(0)
+#define USART_CR3_IREN         BIT(1)
+#define USART_CR3_IRLP         BIT(2)
+#define USART_CR3_HDSEL                BIT(3)
+#define USART_CR3_NACK         BIT(4)
+#define USART_CR3_SCEN         BIT(5)
+#define USART_CR3_DMAR         BIT(6)
+#define USART_CR3_DMAT         BIT(7)
+#define USART_CR3_RTSE         BIT(8)
+#define USART_CR3_CTSE         BIT(9)
+#define USART_CR3_CTSIE                BIT(10)
+#define USART_CR3_ONEBIT       BIT(11)
+#define USART_CR3_OVRDIS       BIT(12)         /* F7 */
+#define USART_CR3_DDRE         BIT(13)         /* F7 */
+#define USART_CR3_DEM          BIT(14)         /* F7 */
+#define USART_CR3_DEP          BIT(15)         /* F7 */
+#define USART_CR3_SCARCNT_MASK GENMASK(19, 17) /* F7 */
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK    GENMASK(7, 0)
+#define USART_GTPR_GT_MASK     GENMASK(15, 8)
+
+/* USART_RTOR */
+#define USART_RTOR_RTO_MASK    GENMASK(23, 0)  /* F7 */
+#define USART_RTOR_BLEN_MASK   GENMASK(31, 24) /* F7 */
+
+/* USART_RQR */
+#define USART_RQR_ABRRQ                BIT(0)          /* F7 */
+#define USART_RQR_SBKRQ                BIT(1)          /* F7 */
+#define USART_RQR_MMRQ         BIT(2)          /* F7 */
+#define USART_RQR_RXFRQ                BIT(3)          /* F7 */
+#define USART_RQR_TXFRQ                BIT(4)          /* F7 */
+
+/* USART_ICR */
+#define USART_ICR_PECF         BIT(0)          /* F7 */
+#define USART_ICR_FFECF                BIT(1)          /* F7 */
+#define USART_ICR_NCF          BIT(2)          /* F7 */
+#define USART_ICR_ORECF                BIT(3)          /* F7 */
+#define USART_ICR_IDLECF       BIT(4)          /* F7 */
+#define USART_ICR_TCCF         BIT(6)          /* F7 */
+#define USART_ICR_LBDCF                BIT(8)          /* F7 */
+#define USART_ICR_CTSCF                BIT(9)          /* F7 */
+#define USART_ICR_RTOCF                BIT(11)         /* F7 */
+#define USART_ICR_EOBCF                BIT(12)         /* F7 */
+#define USART_ICR_CMCF         BIT(17)         /* F7 */
+
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+#define RX_BUF_L 200            /* dma rx buffer length     */
+#define RX_BUF_P RX_BUF_L       /* dma rx buffer period     */
+#define TX_BUF_L 200            /* dma tx buffer length     */
+
+struct stm32_port {
+       struct uart_port port;
+       struct clk *clk;
+       struct stm32_usart_info *info;
+       struct dma_chan *rx_ch;  /* dma rx channel            */
+       dma_addr_t rx_dma_buf;   /* dma rx buffer bus address */
+       unsigned char *rx_buf;   /* dma rx buffer cpu address */
+       struct dma_chan *tx_ch;  /* dma tx channel            */
+       dma_addr_t tx_dma_buf;   /* dma tx buffer bus address */
+       unsigned char *tx_buf;   /* dma tx buffer cpu address */
+       bool tx_dma_busy;        /* dma tx busy               */
+       bool hw_flow_control;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
index 512c162..5da7fe4 100644 (file)
@@ -394,7 +394,7 @@ static int timbuart_verify_port(struct uart_port *port,
        return -EINVAL;
 }
 
-static struct uart_ops timbuart_ops = {
+static const struct uart_ops timbuart_ops = {
        .tx_empty = timbuart_tx_empty,
        .set_mctrl = timbuart_set_mctrl,
        .get_mctrl = timbuart_get_mctrl,
index 05089b6..817bb0d 100644 (file)
@@ -387,7 +387,7 @@ static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
 }
 #endif
 
-static struct uart_ops ulite_ops = {
+static const struct uart_ops ulite_ops = {
        .tx_empty       = ulite_tx_empty,
        .set_mctrl      = ulite_set_mctrl,
        .get_mctrl      = ulite_get_mctrl,
index 23cfc5e..6b85adc 100644 (file)
@@ -118,7 +118,7 @@ struct vt8500_port {
  * have been allocated as we can't use pdev->id in
  * devicetree
  */
-static unsigned long vt8500_ports_in_use;
+static DECLARE_BITMAP(vt8500_ports_in_use, VT8500_MAX_PORTS);
 
 static inline void vt8500_write(struct uart_port *port, unsigned int val,
                             unsigned int off)
@@ -663,15 +663,15 @@ static int vt8500_serial_probe(struct platform_device *pdev)
 
        if (port < 0) {
                /* calculate the port id */
-               port = find_first_zero_bit(&vt8500_ports_in_use,
-                                       sizeof(vt8500_ports_in_use));
+               port = find_first_zero_bit(vt8500_ports_in_use,
+                                          VT8500_MAX_PORTS);
        }
 
        if (port >= VT8500_MAX_PORTS)
                return -ENODEV;
 
        /* reserve the port id */
-       if (test_and_set_bit(port, &vt8500_ports_in_use)) {
+       if (test_and_set_bit(port, vt8500_ports_in_use)) {
                /* port already in use - shouldn't really happen */
                return -EBUSY;
        }
index 9ca1a4d..f37edaa 100644 (file)
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
 #define CDNS_UART_IMR          0x10  /* Interrupt Mask */
 #define CDNS_UART_ISR          0x14  /* Interrupt Status */
 #define CDNS_UART_BAUDGEN      0x18  /* Baud Rate Generator */
-#define CDNS_UART_RXTOUT               0x1C  /* RX Timeout */
+#define CDNS_UART_RXTOUT       0x1C  /* RX Timeout */
 #define CDNS_UART_RXWM         0x20  /* RX FIFO Trigger Level */
 #define CDNS_UART_MODEMCR      0x24  /* Modem Control */
 #define CDNS_UART_MODEMSR      0x28  /* Modem Status */
@@ -68,6 +68,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
 #define CDNS_UART_IRRX_PWIDTH  0x3C  /* IR Min Received Pulse Width */
 #define CDNS_UART_IRTX_PWIDTH  0x40  /* IR Transmitted pulse Width */
 #define CDNS_UART_TXWM         0x44  /* TX FIFO Trigger Level */
+#define CDNS_UART_RXBS         0x48  /* RX FIFO byte status register */
 
 /* Control Register Bit Definitions */
 #define CDNS_UART_CR_STOPBRK   0x00000100  /* Stop TX break */
@@ -79,6 +80,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
 #define CDNS_UART_CR_TXRST     0x00000002  /* TX logic reset */
 #define CDNS_UART_CR_RXRST     0x00000001  /* RX logic reset */
 #define CDNS_UART_CR_RST_TO    0x00000040  /* Restart Timeout Counter */
+#define CDNS_UART_RXBS_PARITY    0x00000001 /* Parity error status */
+#define CDNS_UART_RXBS_FRAMING   0x00000002 /* Framing error status */
+#define CDNS_UART_RXBS_BRK       0x00000004 /* Overrun error status */
 
 /*
  * Mode Register:
@@ -126,13 +130,27 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
 #define CDNS_UART_IXR_RXEMPTY  0x00000002 /* RX FIFO empty interrupt. */
 #define CDNS_UART_IXR_MASK     0x00001FFF /* Valid bit mask */
 
-#define CDNS_UART_RX_IRQS      (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \
-                                CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \
+       /*
+        * Do not enable parity error interrupt for the following
+        * reason: When parity error interrupt is enabled, each Rx
+        * parity error always results in 2 events. The first one
+        * being parity error interrupt and the second one with a
+        * proper Rx interrupt with the incoming data.  Disabling
+        * parity error interrupt ensures better handling of parity
+        * error events. With this change, for a parity error case, we
+        * get a Rx interrupt with parity error set in ISR register
+        * and we still handle parity errors in the desired way.
+        */
+
+#define CDNS_UART_RX_IRQS      (CDNS_UART_IXR_FRAMING | \
+                                CDNS_UART_IXR_OVERRUN | \
+                                CDNS_UART_IXR_RXTRIG |  \
                                 CDNS_UART_IXR_TOUT)
 
 /* Goes in read_status_mask for break detection as the HW doesn't do it*/
-#define CDNS_UART_IXR_BRK      0x80000000
+#define CDNS_UART_IXR_BRK      0x00002000
 
+#define CDNS_UART_RXBS_SUPPORT BIT(1)
 /*
  * Modem Control register:
  * The read/write Modem Control register controls the interface with the modem
@@ -172,46 +190,66 @@ struct cdns_uart {
        struct clk              *pclk;
        unsigned int            baud;
        struct notifier_block   clk_rate_change_nb;
+       u32                     quirks;
+};
+struct cdns_platform_data {
+       u32 quirks;
 };
 #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
                clk_rate_change_nb);
 
-static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
+/**
+ * cdns_uart_handle_rx - Handle the received bytes along with Rx errors.
+ * @dev_id: Id of the UART port
+ * @isrstatus: The interrupt status register value as read
+ * Return: None
+ */
+static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
 {
-       /*
-        * There is no hardware break detection, so we interpret framing
-        * error with all-zeros data as a break sequence. Most of the time,
-        * there's another non-zero byte at the end of the sequence.
-        */
-       if (isrstatus & CDNS_UART_IXR_FRAMING) {
-               while (!(readl(port->membase + CDNS_UART_SR) &
-                                       CDNS_UART_SR_RXEMPTY)) {
-                       if (!readl(port->membase + CDNS_UART_FIFO)) {
+       struct uart_port *port = (struct uart_port *)dev_id;
+       struct cdns_uart *cdns_uart = port->private_data;
+       unsigned int data;
+       unsigned int rxbs_status = 0;
+       unsigned int status_mask;
+       unsigned int framerrprocessed = 0;
+       char status = TTY_NORMAL;
+       bool is_rxbs_support;
+
+       is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
+
+       while ((readl(port->membase + CDNS_UART_SR) &
+               CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
+               if (is_rxbs_support)
+                       rxbs_status = readl(port->membase + CDNS_UART_RXBS);
+               data = readl(port->membase + CDNS_UART_FIFO);
+               port->icount.rx++;
+               /*
+                * There is no hardware break detection in Zynq, so we interpret
+                * framing error with all-zeros data as a break sequence.
+                * Most of the time, there's another non-zero byte at the
+                * end of the sequence.
+                */
+               if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) {
+                       if (!data) {
                                port->read_status_mask |= CDNS_UART_IXR_BRK;
-                               isrstatus &= ~CDNS_UART_IXR_FRAMING;
+                               framerrprocessed = 1;
+                               continue;
                        }
                }
-               writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR);
-       }
-
-       /* drop byte with parity error if IGNPAR specified */
-       if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY)
-               isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT);
-
-       isrstatus &= port->read_status_mask;
-       isrstatus &= ~port->ignore_status_mask;
-
-       if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
-               return;
-
-       while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) {
-               u32 data;
-               char status = TTY_NORMAL;
+               if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) {
+                       port->icount.brk++;
+                       status = TTY_BREAK;
+                       if (uart_handle_break(port))
+                               continue;
+               }
 
-               data = readl(port->membase + CDNS_UART_FIFO);
+               isrstatus &= port->read_status_mask;
+               isrstatus &= ~port->ignore_status_mask;
+               status_mask = port->read_status_mask;
+               status_mask &= ~port->ignore_status_mask;
 
-               /* Non-NULL byte after BREAK is garbage (99%) */
-               if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) {
+               if (data &&
+                   (port->read_status_mask & CDNS_UART_IXR_BRK)) {
                        port->read_status_mask &= ~CDNS_UART_IXR_BRK;
                        port->icount.brk++;
                        if (uart_handle_break(port))
@@ -221,57 +259,83 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
                if (uart_handle_sysrq_char(port, data))
                        continue;
 
-               port->icount.rx++;
-
-               if (isrstatus & CDNS_UART_IXR_PARITY) {
-                       port->icount.parity++;
-                       status = TTY_PARITY;
-               } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
-                       port->icount.frame++;
-                       status = TTY_FRAME;
-               } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
+               if (is_rxbs_support) {
+                       if ((rxbs_status & CDNS_UART_RXBS_PARITY)
+                           && (status_mask & CDNS_UART_IXR_PARITY)) {
+                               port->icount.parity++;
+                               status = TTY_PARITY;
+                       }
+                       if ((rxbs_status & CDNS_UART_RXBS_FRAMING)
+                           && (status_mask & CDNS_UART_IXR_PARITY)) {
+                               port->icount.frame++;
+                               status = TTY_FRAME;
+                       }
+               } else {
+                       if (isrstatus & CDNS_UART_IXR_PARITY) {
+                               port->icount.parity++;
+                               status = TTY_PARITY;
+                       }
+                       if ((isrstatus & CDNS_UART_IXR_FRAMING) &&
+                           !framerrprocessed) {
+                               port->icount.frame++;
+                               status = TTY_FRAME;
+                       }
+               }
+               if (isrstatus & CDNS_UART_IXR_OVERRUN) {
                        port->icount.overrun++;
+                       tty_insert_flip_char(&port->state->port, 0,
+                                            TTY_OVERRUN);
                }
-
-               uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
-                                data, status);
+               tty_insert_flip_char(&port->state->port, data, status);
+               isrstatus = 0;
        }
+       spin_unlock(&port->lock);
        tty_flip_buffer_push(&port->state->port);
+       spin_lock(&port->lock);
 }
 
-static void cdns_uart_handle_tx(struct uart_port *port)
+/**
+ * cdns_uart_handle_tx - Handle the bytes to be Txed.
+ * @dev_id: Id of the UART port
+ * Return: None
+ */
+static void cdns_uart_handle_tx(void *dev_id)
 {
+       struct uart_port *port = (struct uart_port *)dev_id;
        unsigned int numbytes;
 
        if (uart_circ_empty(&port->state->xmit)) {
                writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
-               return;
-       }
-
-       numbytes = port->fifosize;
-       while (numbytes && !uart_circ_empty(&port->state->xmit) &&
-              !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
-               /*
-                * Get the data from the UART circular buffer
-                * and write it to the cdns_uart's TX_FIFO
-                * register.
-                */
-               writel(port->state->xmit.buf[port->state->xmit.tail],
-                       port->membase + CDNS_UART_FIFO);
-               port->icount.tx++;
-
-               /*
-                * Adjust the tail of the UART buffer and wrap
-                * the buffer if it reaches limit.
-                */
-               port->state->xmit.tail =
-                       (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
+       } else {
+               numbytes = port->fifosize;
+               while (numbytes && !uart_circ_empty(&port->state->xmit) &&
+                      !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
+                       /*
+                        * Get the data from the UART circular buffer
+                        * and write it to the cdns_uart's TX_FIFO
+                        * register.
+                        */
+                       writel(
+                               port->state->xmit.buf[port->state->xmit.
+                               tail], port->membase + CDNS_UART_FIFO);
+
+                       port->icount.tx++;
+
+                       /*
+                        * Adjust the tail of the UART buffer and wrap
+                        * the buffer if it reaches limit.
+                        */
+                       port->state->xmit.tail =
+                               (port->state->xmit.tail + 1) &
+                                       (UART_XMIT_SIZE - 1);
+
+                       numbytes--;
+               }
 
-               numbytes--;
+               if (uart_circ_chars_pending(
+                               &port->state->xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(port);
        }
-
-       if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
 }
 
 /**
@@ -284,27 +348,24 @@ static void cdns_uart_handle_tx(struct uart_port *port)
 static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
 {
        struct uart_port *port = (struct uart_port *)dev_id;
-       unsigned long flags;
        unsigned int isrstatus;
 
-       spin_lock_irqsave(&port->lock, flags);
+       spin_lock(&port->lock);
 
        /* Read the interrupt status register to determine which
-        * interrupt(s) is/are active.
+        * interrupt(s) is/are active and clear them.
         */
        isrstatus = readl(port->membase + CDNS_UART_ISR);
-
-       if (isrstatus & CDNS_UART_RX_IRQS)
-               cdns_uart_handle_rx(port, isrstatus);
-
-       if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY)
-               cdns_uart_handle_tx(port);
-
        writel(isrstatus, port->membase + CDNS_UART_ISR);
 
-       /* be sure to release the lock and tty before leaving */
-       spin_unlock_irqrestore(&port->lock, flags);
+       if (isrstatus & CDNS_UART_IXR_TXEMPTY) {
+               cdns_uart_handle_tx(dev_id);
+               isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
+       }
+       if (isrstatus & CDNS_UART_IXR_MASK)
+               cdns_uart_handle_rx(dev_id, isrstatus);
 
+       spin_unlock(&port->lock);
        return IRQ_HANDLED;
 }
 
@@ -653,6 +714,10 @@ static void cdns_uart_set_termios(struct uart_port *port,
        ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
        writel(ctrl_reg, port->membase + CDNS_UART_CR);
 
+       while (readl(port->membase + CDNS_UART_CR) &
+               (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
+               cpu_relax();
+
        /*
         * Clear the RX disable and TX disable bits and then set the TX enable
         * bit and RX enable bit to enable the transmitter and receiver.
@@ -736,10 +801,14 @@ static void cdns_uart_set_termios(struct uart_port *port,
  */
 static int cdns_uart_startup(struct uart_port *port)
 {
+       struct cdns_uart *cdns_uart = port->private_data;
+       bool is_brk_support;
        int ret;
        unsigned long flags;
        unsigned int status = 0;
 
+       is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
+
        spin_lock_irqsave(&port->lock, flags);
 
        /* Disable the TX and RX */
@@ -752,6 +821,10 @@ static int cdns_uart_startup(struct uart_port *port)
        writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
                        port->membase + CDNS_UART_CR);
 
+       while (readl(port->membase + CDNS_UART_CR) &
+               (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
+               cpu_relax();
+
        /*
         * Clear the RX disable bit and then set the RX enable bit to enable
         * the receiver.
@@ -794,7 +867,11 @@ static int cdns_uart_startup(struct uart_port *port)
        }
 
        /* Set the Interrupt Registers with desired interrupts */
-       writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
+       if (is_brk_support)
+               writel(CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK,
+                                       port->membase + CDNS_UART_IER);
+       else
+               writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
 
        return 0;
 }
@@ -993,7 +1070,7 @@ static void cdns_uart_pm(struct uart_port *port, unsigned int state,
        }
 }
 
-static struct uart_ops cdns_uart_ops = {
+static const struct uart_ops cdns_uart_ops = {
        .set_mctrl      = cdns_uart_set_mctrl,
        .get_mctrl      = cdns_uart_get_mctrl,
        .start_tx       = cdns_uart_start_tx,
@@ -1088,9 +1165,34 @@ static void __init cdns_early_write(struct console *con, const char *s,
 static int __init cdns_early_console_setup(struct earlycon_device *device,
                                           const char *opt)
 {
-       if (!device->port.membase)
+       struct uart_port *port = &device->port;
+
+       if (!port->membase)
                return -ENODEV;
 
+       /* initialise control register */
+       writel(CDNS_UART_CR_TX_EN|CDNS_UART_CR_TXRST|CDNS_UART_CR_RXRST,
+              port->membase + CDNS_UART_CR);
+
+       /* only set baud if specified on command line - otherwise
+        * assume it has been initialized by a boot loader.
+        */
+       if (device->baud) {
+               u32 cd = 0, bdiv = 0;
+               u32 mr;
+               int div8;
+
+               cdns_uart_calc_baud_divs(port->uartclk, device->baud,
+                                        &bdiv, &cd, &div8);
+               mr = CDNS_UART_MR_PARITY_NONE;
+               if (div8)
+                       mr |= CDNS_UART_MR_CLKSEL;
+
+               writel(mr,   port->membase + CDNS_UART_MR);
+               writel(cd,   port->membase + CDNS_UART_BAUDGEN);
+               writel(bdiv, port->membase + CDNS_UART_BAUDDIV);
+       }
+
        device->con->write = cdns_early_write;
 
        return 0;
@@ -1328,6 +1430,18 @@ static int cdns_uart_resume(struct device *device)
 static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
                cdns_uart_resume);
 
+static const struct cdns_platform_data zynqmp_uart_def = {
+                               .quirks = CDNS_UART_RXBS_SUPPORT, };
+
+/* Match table for of_platform binding */
+static const struct of_device_id cdns_uart_of_match[] = {
+       { .compatible = "xlnx,xuartps", },
+       { .compatible = "cdns,uart-r1p8", },
+       { .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def },
+       {}
+};
+MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
+
 /**
  * cdns_uart_probe - Platform driver probe
  * @pdev: Pointer to the platform device structure
@@ -1340,12 +1454,20 @@ static int cdns_uart_probe(struct platform_device *pdev)
        struct uart_port *port;
        struct resource *res;
        struct cdns_uart *cdns_uart_data;
+       const struct of_device_id *match;
 
        cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
                        GFP_KERNEL);
        if (!cdns_uart_data)
                return -ENOMEM;
 
+       match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
+       if (match && match->data) {
+               const struct cdns_platform_data *data = match->data;
+
+               cdns_uart_data->quirks = data->quirks;
+       }
+
        cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
        if (IS_ERR(cdns_uart_data->pclk)) {
                cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
@@ -1471,14 +1593,6 @@ static int cdns_uart_remove(struct platform_device *pdev)
        return rc;
 }
 
-/* Match table for of_platform binding */
-static const struct of_device_id cdns_uart_of_match[] = {
-       { .compatible = "xlnx,xuartps", },
-       { .compatible = "cdns,uart-r1p8", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
-
 static struct platform_driver cdns_uart_platform_driver = {
        .probe   = cdns_uart_probe,
        .remove  = cdns_uart_remove,
index 2705ca9..e841a4e 100644 (file)
@@ -1312,12 +1312,12 @@ static int vc_t416_color(struct vc_data *vc, int i,
        if (i > vc->vc_npar)
                return i;
 
-       if (vc->vc_par[i] == 5 && i < vc->vc_npar) {
-               /* 256 colours -- ubiquitous */
+       if (vc->vc_par[i] == 5 && i + 1 <= vc->vc_npar) {
+               /* 256 colours */
                i++;
                rgb_from_256(vc->vc_par[i], &c);
-       } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) {
-               /* 24 bit -- extremely rare */
+       } else if (vc->vc_par[i] == 2 && i + 3 <= vc->vc_npar) {
+               /* 24 bit */
                c.r = vc->vc_par[i + 1];
                c.g = vc->vc_par[i + 2];
                c.b = vc->vc_par[i + 3];
@@ -1415,6 +1415,11 @@ static void csi_m(struct vc_data *vc)
                                (vc->vc_color & 0x0f);
                        break;
                default:
+                       if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) {
+                               if (vc->vc_par[i] < 100)
+                                       vc->vc_intensity = 2;
+                               vc->vc_par[i] -= 60;
+                       }
                        if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
                                vc->vc_color = color_table[vc->vc_par[i] - 30]
                                        | (vc->vc_color & 0xf0);
index 79a5941..442d1a7 100644 (file)
@@ -272,13 +272,8 @@ static int mknod_ptmx(struct super_block *sb)
        struct dentry *root = sb->s_root;
        struct pts_fs_info *fsi = DEVPTS_SB(sb);
        struct pts_mount_opts *opts = &fsi->mount_opts;
-       kuid_t root_uid;
-       kgid_t root_gid;
-
-       root_uid = make_kuid(current_user_ns(), 0);
-       root_gid = make_kgid(current_user_ns(), 0);
-       if (!uid_valid(root_uid) || !gid_valid(root_gid))
-               return -EINVAL;
+       kuid_t ptmx_uid = current_fsuid();
+       kgid_t ptmx_gid = current_fsgid();
 
        inode_lock(d_inode(root));
 
@@ -309,8 +304,8 @@ static int mknod_ptmx(struct super_block *sb)
 
        mode = S_IFCHR|opts->ptmxmode;
        init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
-       inode->i_uid = root_uid;
-       inode->i_gid = root_gid;
+       inode->i_uid = ptmx_uid;
+       inode->i_gid = ptmx_gid;
 
        d_add(dentry, inode);
 
@@ -336,7 +331,6 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
        struct pts_fs_info *fsi = DEVPTS_SB(sb);
        struct pts_mount_opts *opts = &fsi->mount_opts;
 
-       sync_filesystem(sb);
        err = parse_mount_options(data, PARSE_REMOUNT, opts);
 
        /*
@@ -395,6 +389,7 @@ static int
 devpts_fill_super(struct super_block *s, void *data, int silent)
 {
        struct inode *inode;
+       int error;
 
        s->s_iflags &= ~SB_I_NODEV;
        s->s_blocksize = 1024;
@@ -403,10 +398,16 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
        s->s_op = &devpts_sops;
        s->s_time_gran = 1;
 
+       error = -ENOMEM;
        s->s_fs_info = new_pts_fs_info(s);
        if (!s->s_fs_info)
                goto fail;
 
+       error = parse_mount_options(data, PARSE_MOUNT, &DEVPTS_SB(s)->mount_opts);
+       if (error)
+               goto fail;
+
+       error = -ENOMEM;
        inode = new_inode(s);
        if (!inode)
                goto fail;
@@ -418,13 +419,21 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
        set_nlink(inode, 2);
 
        s->s_root = d_make_root(inode);
-       if (s->s_root)
-               return 0;
+       if (!s->s_root) {
+               pr_err("get root dentry failed\n");
+               goto fail;
+       }
 
-       pr_err("get root dentry failed\n");
+       error = mknod_ptmx(s);
+       if (error)
+               goto fail_dput;
 
+       return 0;
+fail_dput:
+       dput(s->s_root);
+       s->s_root = NULL;
 fail:
-       return -ENOMEM;
+       return error;
 }
 
 /*
@@ -436,43 +445,15 @@ fail:
 static struct dentry *devpts_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
-       int error;
-       struct pts_mount_opts opts;
-       struct super_block *s;
-
-       error = parse_mount_options(data, PARSE_MOUNT, &opts);
-       if (error)
-               return ERR_PTR(error);
-
-       s = sget(fs_type, NULL, set_anon_super, flags, NULL);
-       if (IS_ERR(s))
-               return ERR_CAST(s);
-
-       if (!s->s_root) {
-               error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
-               if (error)
-                       goto out_undo_sget;
-               s->s_flags |= MS_ACTIVE;
-       }
-
-       memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts));
-
-       error = mknod_ptmx(s);
-       if (error)
-               goto out_undo_sget;
-
-       return dget(s->s_root);
-
-out_undo_sget:
-       deactivate_locked_super(s);
-       return ERR_PTR(error);
+       return mount_nodev(fs_type, flags, data, devpts_fill_super);
 }
 
 static void devpts_kill_sb(struct super_block *sb)
 {
        struct pts_fs_info *fsi = DEVPTS_SB(sb);
 
-       ida_destroy(&fsi->allocated_ptys);
+       if (fsi)
+               ida_destroy(&fsi->allocated_ptys);
        kfree(fsi);
        kill_litter_super(sb);
 }
index 19e650c..94afcb2 100644 (file)
@@ -1099,4 +1099,10 @@ extern bool acpi_has_watchdog(void);
 static inline bool acpi_has_watchdog(void) { return false; }
 #endif
 
+#ifdef CONFIG_ACPI_SPCR_TABLE
+int parse_spcr(bool earlycon);
+#else
+static inline int parse_spcr(bool earlycon) { return 0; }
+#endif
+
 #endif /*_LINUX_ACPI_H*/
index 3d8dcdd..d143c13 100644 (file)
@@ -53,8 +53,14 @@ enum amba_vendor {
        AMBA_VENDOR_ST = 0x80,
        AMBA_VENDOR_QCOM = 0x51,
        AMBA_VENDOR_LSI = 0xb6,
+       AMBA_VENDOR_LINUX = 0xfe,       /* This value is not official */
 };
 
+/* This is used to generate pseudo-ID for AMBA device */
+#define AMBA_LINUX_ID(conf, rev, part) \
+       (((conf) & 0xff) << 24 | ((rev) & 0xf) << 20 | \
+       AMBA_VENDOR_LINUX << 12 | ((part) & 0xfff))
+
 extern struct bus_type amba_bustype;
 
 #define to_amba_device(d)      container_of(d, struct amba_device, dev)
index d76a19b..ad0965e 100644 (file)
 #define UART01x_FR_CTS                 0x001
 #define UART01x_FR_TMSK                (UART01x_FR_TXFF + UART01x_FR_BUSY)
 
+/*
+ * Some bits of Flag Register on ZTE device have different position from
+ * standard ones.
+ */
+#define ZX_UART01x_FR_BUSY     0x100
+#define ZX_UART01x_FR_DSR      0x008
+#define ZX_UART01x_FR_CTS      0x002
+#define ZX_UART011_FR_RI       0x001
+
 #define UART011_CR_CTSEN       0x8000  /* CTS hardware flow control */
 #define UART011_CR_RTSEN       0x4000  /* RTS hardware flow control */
 #define UART011_CR_OUT2                0x2000  /* OUT2 */
index 5a4d664..bd25605 100644 (file)
 
 #define ATMEL_US_BRGR          0x20    /* Baud Rate Generator Register */
 #define        ATMEL_US_CD             GENMASK(15, 0)  /* Clock Divider */
+#define ATMEL_US_FP_OFFSET     16      /* Fractional Part */
+#define ATMEL_US_FP_MASK       0x7
 
 #define ATMEL_US_RTOR          0x24    /* Receiver Time-out Register for USART */
 #define ATMEL_UA_RTOR          0x28    /* Receiver Time-out Register for UART */
index f2e538a..ccfd0c3 100644 (file)
@@ -40,8 +40,13 @@ struct dw_dma_chip {
 };
 
 /* Export to the platform drivers */
+#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
 int dw_dma_probe(struct dw_dma_chip *chip);
 int dw_dma_remove(struct dw_dma_chip *chip);
+#else
+static inline int dw_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
+static inline int dw_dma_remove(struct dw_dma_chip *chip) { return 0; }
+#endif /* CONFIG_DW_DMAC_CORE */
 
 /* DMA API extensions */
 struct dw_desc;
index aaff68e..197eec6 100644 (file)
@@ -41,8 +41,7 @@ struct hsu_dma_chip {
 /* Export to the internal users */
 int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr,
                       u32 *status);
-irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
-                          u32 status);
+int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status);
 
 /* Export to the platform drivers */
 int hsu_dma_probe(struct hsu_dma_chip *chip);
@@ -53,10 +52,10 @@ static inline int hsu_dma_get_status(struct hsu_dma_chip *chip,
 {
        return 0;
 }
-static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip,
-                                        unsigned short nr, u32 status)
+static inline int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
+                                u32 status)
 {
-       return IRQ_NONE;
+       return 0;
 }
 static inline int hsu_dma_probe(struct hsu_dma_chip *chip) { return -ENODEV; }
 static inline int hsu_dma_remove(struct hsu_dma_chip *chip) { return 0; }
index 26c3302..4341f32 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/errno.h>
 
 /* Definitions used by the flattened device tree */
 #define OF_DT_HEADER           0xd00dfeed      /* marker */
@@ -66,6 +67,7 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
                                     int depth, void *data);
 extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
                                     int depth, void *data);
+extern int early_init_dt_scan_chosen_stdout(void);
 extern void early_init_fdt_scan_reserved_mem(void);
 extern void early_init_fdt_reserve_self(void);
 extern void early_init_dt_add_memory_arch(u64 base, u64 size);
@@ -94,6 +96,7 @@ extern void early_get_first_memblock_info(void *, phys_addr_t *);
 extern u64 of_flat_dt_translate_address(unsigned long node);
 extern void of_fdt_limit_memory(int limit);
 #else /* CONFIG_OF_FLATTREE */
+static inline int early_init_dt_scan_chosen_stdout(void) { return -ENODEV; }
 static inline void early_init_fdt_scan_reserved_mem(void) {}
 static inline void early_init_fdt_reserve_self(void) {}
 static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
index d15d8ba..5f0e11e 100644 (file)
@@ -23,6 +23,7 @@
  * @dst_id:    dst request line
  * @m_master:  memory master for transfers on allocated channel
  * @p_master:  peripheral master for transfers on allocated channel
+ * @hs_polarity:set active low polarity of handshake interface
  */
 struct dw_dma_slave {
        struct device           *dma_dev;
@@ -30,6 +31,7 @@ struct dw_dma_slave {
        u8                      dst_id;
        u8                      m_master;
        u8                      p_master;
+       bool                    hs_polarity;
 };
 
 /**
@@ -38,6 +40,7 @@ struct dw_dma_slave {
  * @is_private: The device channels should be marked as private and not for
  *     by the general purpose DMA channel allocator.
  * @is_memcpy: The device channels do support memory-to-memory transfers.
+ * @is_nollp: The device channels does not support multi block transfers.
  * @chan_allocation_order: Allocate channels starting from 0 or 7
  * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
  * @block_size: Maximum block size supported by the controller
@@ -49,6 +52,7 @@ struct dw_dma_platform_data {
        unsigned int    nr_channels;
        bool            is_private;
        bool            is_memcpy;
+       bool            is_nollp;
 #define CHAN_ALLOCATION_ASCENDING      0       /* zero to seven */
 #define CHAN_ALLOCATION_DESCENDING     1       /* seven to zero */
        unsigned char   chan_allocation_order;
index 2f44e20..3442014 100644 (file)
@@ -367,14 +367,21 @@ extern const struct earlycon_id __earlycon_table_end[];
 
 #define EARLYCON_DECLARE(_name, fn)    OF_EARLYCON_DECLARE(_name, "", fn)
 
-extern int setup_earlycon(char *buf);
 extern int of_setup_earlycon(const struct earlycon_id *match,
                             unsigned long node,
                             const char *options);
 
+#ifdef CONFIG_SERIAL_EARLYCON
+extern bool earlycon_init_is_deferred __initdata;
+int setup_earlycon(char *buf);
+#else
+static const bool earlycon_init_is_deferred;
+static inline int setup_earlycon(char *buf) { return 0; }
+#endif
+
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,
                                   struct console *c);
-int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
+int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
                        char **options);
 void uart_parse_options(char *options, int *baud, int *parity, int *bits,
                        int *flow);
@@ -412,7 +419,7 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
 static inline int uart_tx_stopped(struct uart_port *port)
 {
        struct tty_struct *tty = port->state->port.tty;
-       if (tty->stopped || port->hw_stopped)
+       if ((tty && tty->stopped) || port->hw_stopped)
                return 1;
        return 0;
 }
index 1e5ac4e..b4c0484 100644 (file)
 #define UART_EXAR_TXTRG                0x0a    /* Tx FIFO trigger level write-only */
 #define UART_EXAR_RXTRG                0x0b    /* Rx FIFO trigger level write-only */
 
+/*
+ * These are definitions for the Altera ALTR_16550_F32/F64/F128
+ * Normalized from 0x100 to 0x40 because of shift by 2 (32 bit regs).
+ */
+#define UART_ALTR_AFR          0x40    /* Additional Features Register */
+#define UART_ALTR_EN_TXFIFO_LW 0x01    /* Enable the TX FIFO Low Watermark */
+#define UART_ALTR_TX_LOW       0x41    /* Tx FIFO Low Watermark */
+
 #endif /* _LINUX_SERIAL_REG_H */