]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge 4.3-rc5 into tty-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 12 Oct 2015 17:54:35 +0000 (10:54 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 12 Oct 2015 17:54:35 +0000 (10:54 -0700)
We want the tty fixes and reverts in here as well so that people can
properly test and use it.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
49 files changed:
Documentation/devicetree/bindings/serial/ingenic,uart.txt
Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt
Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
Documentation/serial/driver
Documentation/serial/tty.txt
arch/arm64/include/asm/dcc.h [new file with mode: 0644]
drivers/tty/hvc/Kconfig
drivers/tty/hvc/hvc_console.c
drivers/tty/hvc/hvc_dcc.c
drivers/tty/mips_ejtag_fdc.c
drivers/tty/pty.c
drivers/tty/serial/68328serial.c
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_early.c
drivers/tty/serial/8250/8250_ingenic.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/Kconfig
drivers/tty/serial/altera_uart.c
drivers/tty/serial/apbuart.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/clps711x.c
drivers/tty/serial/cpm_uart/cpm_uart_core.c
drivers/tty/serial/imx.c
drivers/tty/serial/lpc32xx_hs.c
drivers/tty/serial/mpc52xx_uart.c
drivers/tty/serial/mpsc.c
drivers/tty/serial/msm_serial.c
drivers/tty/serial/msm_serial.h
drivers/tty/serial/mux.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/serial_mctrl_gpio.c
drivers/tty/serial/serial_mctrl_gpio.h
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h
drivers/tty/serial/sprd_serial.c
drivers/tty/serial/st-asc.c
drivers/tty/serial/stm32-usart.c
drivers/tty/sysrq.c
include/linux/platform_data/atmel.h

index c2d3b3abe7d9ab17db07c9a60dc9f6318d651e61..02cb7fe59cb776281ec2cdf150ff661fcab9b4ce 100644 (file)
@@ -1,7 +1,8 @@
 * Ingenic SoC UART
 
 Required properties:
-- compatible : "ingenic,jz4740-uart" or "ingenic,jz4780-uart"
+- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart",
+       "ingenic,jz4775-uart" or "ingenic,jz4780-uart"
 - reg : offset and length of the register set for the device.
 - interrupts : should contain uart interrupt.
 - clocks : phandles to the module & baud clocks.
index a2114c217376a5dbf17a6fecd448da307516fee2..182777fac9a24dfa9f52e7b5c8774d0ed4715f51 100644 (file)
@@ -26,6 +26,12 @@ Required properties:
 Optional properties:
 - dmas: Should contain dma specifiers for transmit and receive channels
 - dma-names: Should contain "tx" for transmit and "rx" for receive channels
+- qcom,tx-crci: Identificator <u32> for Client Rate Control Interface to be
+           used with TX DMA channel. Required when using DMA for transmission
+           with UARTDM v1.3 and bellow.
+- qcom,rx-crci: Identificator <u32> for Client Rate Control Interface to be
+           used with RX DMA channel. Required when using DMA for reception
+           with UARTDM v1.3 and bellow.
 
 Note: Aliases may be defined to ensure the correct ordering of the UARTs.
 The alias serialN will result in the UART being assigned port N.  If any
index e84b13a8eda34a151edcd9107aaa7b1510a20d8c..73f825e5e64488151b8a7b49c0f99f06f0edb73c 100644 (file)
@@ -23,6 +23,8 @@ Required properties:
     - "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART.
     - "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART.
     - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART.
+    - "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART.
+    - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
     - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
     - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
     - "renesas,scif" for generic SCIF compatible UART.
index 289c40ed747042a70b13f9912dc0b5c443f7827e..12bbe9f22560c59d29ac8bd45bdbe5ad9be8bf2a 100644 (file)
@@ -15,6 +15,9 @@ The supplying peripheral clock can also be handled, needing a second property
        Required elements: "baudclk", "apb_pclk"
 
 Optional properties:
+- snps,uart-16550-compatible : reflects the value of UART_16550_COMPATIBLE
+  configuration parameter. Define this if your UART does not implement the busy
+  functionality.
 - resets : phandle to the parent reset controller.
 - reg-shift : quantity to shift the register offsets by.  If this property is
   not present then the register offsets are not shifted.
index c415b0ef449378db4698ca9552c54bdfb387a9d0..379468e12680dbfb1d4a3dd222fb617681ae1df7 100644 (file)
@@ -439,11 +439,13 @@ Modem control lines via GPIO
 
 Some helpers are provided in order to set/get modem control lines via GPIO.
 
-mctrl_gpio_init(dev, idx):
+mctrl_gpio_init(port, idx):
        This will get the {cts,rts,...}-gpios from device tree if they are
        present and request them, set direction etc, and return an
        allocated structure. devm_* functions are used, so there's no need
        to call mctrl_gpio_free().
+       As this sets up the irq handling make sure to not handle changes to the
+       gpio input lines in your driver, too.
 
 mctrl_gpio_free(dev, gpios):
        This will free the requested gpios in mctrl_gpio_init().
@@ -458,3 +460,9 @@ mctrl_gpio_set(gpios, mctrl):
 
 mctrl_gpio_get(gpios, mctrl):
        This will update mctrl with the gpios values.
+
+mctrl_gpio_enable_ms(gpios):
+       Enables irqs and handling of changes to the ms lines.
+
+mctrl_gpio_disable_ms(gpios):
+       Disables irqs and handling of changes to the ms lines.
index 973c8ad3f959fba7f722aafa6c89c5b29c40aaa9..bc3842dc323a629fae6ec4cf5de0f6d1d6d6f37d 100644 (file)
@@ -39,8 +39,13 @@ TTY side interfaces:
 open()         -       Called when the line discipline is attached to
                        the terminal. No other call into the line
                        discipline for this tty will occur until it
-                       completes successfully. Returning an error will
-                       prevent the ldisc from being attached. Can sleep.
+                       completes successfully. Should initialize any
+                       state needed by the ldisc, and set receive_room
+                       in the tty_struct to the maximum amount of data
+                       the line discipline is willing to accept from the
+                       driver with a single call to receive_buf().
+                       Returning an error will prevent the ldisc from
+                       being attached. Can sleep.
 
 close()                -       This is called on a terminal when the line
                        discipline is being unplugged. At the point of
@@ -52,9 +57,16 @@ hangup()     -       Called when the tty line is hung up.
                        No further calls into the ldisc code will occur.
                        The return value is ignored. Can sleep.
 
-write()                -       A process is writing data through the line
-                       discipline.  Multiple write calls are serialized
-                       by the tty layer for the ldisc.  May sleep. 
+read()         -       (optional) A process requests reading data from
+                       the line. Multiple read calls may occur in parallel
+                       and the ldisc must deal with serialization issues.
+                       If not defined, the process will receive an EIO
+                       error. May sleep.
+
+write()                -       (optional) A process requests writing data to the
+                       line. Multiple write calls are serialized by the
+                       tty layer for the ldisc. If not defined, the
+                       process will receive an EIO error. May sleep.
 
 flush_buffer() -       (optional) May be called at any point between
                        open and close, and instructs the line discipline
@@ -69,27 +81,33 @@ set_termios()       -       (optional) Called on termios structure changes.
                        termios semaphore so allowed to sleep. Serialized
                        against itself only.
 
-read()         -       Move data from the line discipline to the user.
-                       Multiple read calls may occur in parallel and the
-                       ldisc must deal with serialization issues. May 
-                       sleep.
-
-poll()         -       Check the status for the poll/select calls. Multiple
-                       poll calls may occur in parallel. May sleep.
+poll()         -       (optional) Check the status for the poll/select
+                       calls. Multiple poll calls may occur in parallel.
+                       May sleep.
 
-ioctl()                -       Called when an ioctl is handed to the tty layer
-                       that might be for the ldisc. Multiple ioctl calls
-                       may occur in parallel. May sleep. 
+ioctl()                -       (optional) Called when an ioctl is handed to the
+                       tty layer that might be for the ldisc. Multiple
+                       ioctl calls may occur in parallel. May sleep.
 
-compat_ioctl() -       Called when a 32 bit ioctl is handed to the tty layer
-                       that might be for the ldisc. Multiple ioctl calls
-                       may occur in parallel. May sleep.
+compat_ioctl() -       (optional) Called when a 32 bit ioctl is handed
+                       to the tty layer that might be for the ldisc.
+                       Multiple ioctl calls may occur in parallel.
+                       May sleep.
 
 Driver Side Interfaces:
 
-receive_buf()  -       Hand buffers of bytes from the driver to the ldisc
-                       for processing. Semantics currently rather
-                       mysterious 8(
+receive_buf()  -       (optional) Called by the low-level driver to hand
+                       a buffer of received bytes to the ldisc for
+                       processing. The number of bytes is guaranteed not
+                       to exceed the current value of tty->receive_room.
+                       All bytes must be processed.
+
+receive_buf2() -       (optional) Called by the low-level driver to hand
+                       a buffer of received bytes to the ldisc for
+                       processing. Returns the number of bytes processed.
+
+                       If both receive_buf() and receive_buf2() are
+                       defined, receive_buf2() should be preferred.
 
 write_wakeup() -       May be called at any point between open and close.
                        The TTY_DO_WRITE_WAKEUP flag indicates if a call
diff --git a/arch/arm64/include/asm/dcc.h b/arch/arm64/include/asm/dcc.h
new file mode 100644 (file)
index 0000000..65e0190
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * A call to __dcc_getchar() or __dcc_putchar() is typically followed by
+ * a call to __dcc_getstatus().  We want to make sure that the CPU does
+ * not speculative read the DCC status before executing the read or write
+ * instruction.  That's what the ISBs are for.
+ *
+ * The 'volatile' ensures that the compiler does not cache the status bits,
+ * and instead reads the DCC register every time.
+ */
+#ifndef __ASM_DCC_H
+#define __ASM_DCC_H
+
+#include <asm/barrier.h>
+
+static inline u32 __dcc_getstatus(void)
+{
+       u32 ret;
+
+       asm volatile("mrs %0, mdccsr_el0" : "=r" (ret));
+
+       return ret;
+}
+
+static inline char __dcc_getchar(void)
+{
+       char c;
+
+       asm volatile("mrs %0, dbgdtrrx_el0" : "=r" (c));
+       isb();
+
+       return c;
+}
+
+static inline void __dcc_putchar(char c)
+{
+       /*
+        * The typecast is to make absolutely certain that 'c' is
+        * zero-extended.
+        */
+       asm volatile("msr dbgdtrtx_el0, %0"
+                       : : "r" ((unsigned long)(unsigned char)c));
+       isb();
+}
+
+#endif
index 2509d057b99c32bf96b5ad35058b714cff326788..574da15fe618ed57837ffa7f9ccfdeef03e89cc9 100644 (file)
@@ -81,7 +81,7 @@ config HVC_UDBG
 
 config HVC_DCC
        bool "ARM JTAG DCC console"
-       depends on ARM
+       depends on ARM || ARM64
        select HVC_DRIVER
        help
          This console uses the JTAG DCC on ARM to create a console under the HVC
index 4e9c4cc9e1b52a5b6a91f2881a0f4495743997d9..9c30f67c802a80df3a66e860e1bf53ba828e67ff 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/major.h>
 #include <linux/atomic.h>
 #include <linux/sysrq.h>
@@ -1005,19 +1005,3 @@ put_tty:
 out:
        return err;
 }
-
-/* This isn't particularly necessary due to this being a console driver
- * but it is nice to be thorough.
- */
-static void __exit hvc_exit(void)
-{
-       if (hvc_driver) {
-               kthread_stop(hvc_task);
-
-               tty_unregister_driver(hvc_driver);
-               /* return tty_struct instances allocated in hvc_init(). */
-               put_tty_driver(hvc_driver);
-               unregister_console(&hvc_console);
-       }
-}
-module_exit(hvc_exit);
index 809920d80a66da7c08f8cd653451fa2fdcec636e..82f240fb98f00e8493c68cd331fa95a2d9be57da 100644 (file)
@@ -70,20 +70,27 @@ static const struct hv_ops hvc_dcc_get_put_ops = {
 
 static int __init hvc_dcc_console_init(void)
 {
+       int ret;
+
        if (!hvc_dcc_check())
                return -ENODEV;
 
-       hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
-       return 0;
+       /* Returns -1 if error */
+       ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
+
+       return ret < 0 ? -ENODEV : 0;
 }
 console_initcall(hvc_dcc_console_init);
 
 static int __init hvc_dcc_init(void)
 {
+       struct hvc_struct *p;
+
        if (!hvc_dcc_check())
                return -ENODEV;
 
-       hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
-       return 0;
+       p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
+
+       return PTR_ERR_OR_ZERO(p);
 }
 device_initcall(hvc_dcc_init);
index a8c8cfd52a23b862561b1211fe5f4330da909723..5a6d0b5cd18b839d43f8b2887adf8a852cbedbfb 100644 (file)
@@ -977,7 +977,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
        /* Try requesting the IRQ */
        if (priv->irq >= 0) {
                /*
-                * IRQF_SHARED, IRQF_NO_SUSPEND: The FDC IRQ may be shared with
+                * IRQF_SHARED, IRQF_COND_SUSPEND: The FDC IRQ may be shared with
                 * other local interrupts such as the timer which sets
                 * IRQF_TIMER (including IRQF_NO_SUSPEND).
                 *
@@ -987,7 +987,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
                 */
                ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr,
                                       IRQF_PERCPU | IRQF_SHARED |
-                                      IRQF_NO_THREAD | IRQF_NO_SUSPEND,
+                                      IRQF_NO_THREAD | IRQF_COND_SUSPEND,
                                       priv->fdc_name, priv);
                if (ret)
                        priv->irq = -1;
index 4d5937c185c17bda6d506f00232b3f3598f28b95..a45660f62db54e37c47e0a04f5101d4adfb3463f 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/module.h>
-
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
@@ -501,6 +500,10 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
 }
 
 static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
 module_param(legacy_count, int, 0);
 
 /*
@@ -877,4 +880,4 @@ static int __init pty_init(void)
        unix98_pty_init();
        return 0;
 }
-module_init(pty_init);
+device_initcall(pty_init);
index 748c18f8c8cdcbf417899e59b7ba60a35443607b..9ba0c933307898813fab2fba2e413b9d943f9472 100644 (file)
@@ -560,8 +560,8 @@ static void rs_fair_output(void)
        struct m68k_serial *info = &m68k_soft[0];
        char c;
 
-       if (info == 0) return;
-       if (info->xmit_buf == 0) return;
+       if (info == NULL) return;
+       if (info->xmit_buf == NULL) return;
 
        local_irq_save(flags);
        left = info->xmit_cnt;
index 271d121376490042e87bda6eeb06d26833d6c0d6..39126460c1f59097ad164bfee65579e8ce54085a 100644 (file)
@@ -569,6 +569,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
        for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
+               if (up->port.type == PORT_8250_CIR)
+                       continue;
+
                if (up->port.dev)
                        continue;
 
@@ -1027,13 +1030,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
                if (up->dl_write)
                        uart->dl_write = up->dl_write;
 
-               if (serial8250_isa_config != NULL)
-                       serial8250_isa_config(0, &uart->port,
-                                       &uart->capabilities);
+               if (uart->port.type != PORT_8250_CIR) {
+                       if (serial8250_isa_config != NULL)
+                               serial8250_isa_config(0, &uart->port,
+                                               &uart->capabilities);
+
+                       ret = uart_add_one_port(&serial8250_reg,
+                                               &uart->port);
+                       if (ret == 0)
+                               ret = uart->port.line;
+               } else {
+                       dev_info(uart->port.dev,
+                               "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
+                               uart->port.iobase,
+                               (unsigned long long)uart->port.mapbase,
+                               uart->port.irq);
 
-               ret = uart_add_one_port(&serial8250_reg, &uart->port);
-               if (ret == 0)
-                       ret = uart->port.line;
+                       ret = 0;
+               }
        }
        mutex_unlock(&serial_mutex);
 
index 21d01a491405a2c52cd1ec02f3198fa4c6b8f10c..b50307129901c39436b3c7170aae1fe63cc3aac3 100644 (file)
@@ -54,9 +54,6 @@ static void __dma_rx_complete(void *param)
        struct dma_tx_state     state;
        int                     count;
 
-       dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
-
        dma->rx_running = 0;
        dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 
@@ -156,9 +153,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 
        dma->rx_cookie = dmaengine_submit(desc);
 
-       dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
-                                  dma->rx_size, DMA_FROM_DEVICE);
-
        dma_async_issue_pending(dma->rxchan);
 
        return 0;
index 06324f17a0cb1de308128573330373d073e78db3..a0cdbf35dcb19bd637632f55d514ad16d1588036 100644 (file)
@@ -63,6 +63,9 @@ struct dw8250_data {
        struct clk              *pclk;
        struct reset_control    *rst;
        struct uart_8250_dma    dma;
+
+       unsigned int            skip_autocfg:1;
+       unsigned int            uart_16550_compatible:1;
 };
 
 #define BYT_PRV_CLK                    0x800
@@ -244,24 +247,77 @@ out:
        serial8250_do_set_termios(p, termios, old);
 }
 
-static bool dw8250_dma_filter(struct dma_chan *chan, void *param)
+/*
+ * dw8250_fallback_dma_filter will prevent the UART from getting just any free
+ * channel on platforms that have DMA engines, but don't have any channels
+ * assigned to the UART.
+ *
+ * REVISIT: This is a work around for limitation in the DMA Engine API. Once the
+ * core problem is fixed, this function is no longer needed.
+ */
+static bool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param)
 {
        return false;
 }
 
-static void dw8250_setup_port(struct uart_8250_port *up)
+static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
+{
+       return param == chan->device->dev->parent;
+}
+
+static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
 {
-       struct uart_port        *p = &up->port;
-       u32                     reg = readl(p->membase + DW_UART_UCV);
+       if (p->dev->of_node) {
+               struct device_node *np = p->dev->of_node;
+               int id;
+
+               /* get index of serial line, if found in DT aliases */
+               id = of_alias_get_id(np, "serial");
+               if (id >= 0)
+                       p->line = id;
+#ifdef CONFIG_64BIT
+               if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
+                       p->serial_in = dw8250_serial_inq;
+                       p->serial_out = dw8250_serial_outq;
+                       p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+                       p->type = PORT_OCTEON;
+                       data->usr_reg = 0x27;
+                       data->skip_autocfg = true;
+               }
+#endif
+       } else if (has_acpi_companion(p->dev)) {
+               p->iotype = UPIO_MEM32;
+               p->regshift = 2;
+               p->serial_in = dw8250_serial_in32;
+               p->set_termios = dw8250_set_termios;
+               /* So far none of there implement the Busy Functionality */
+               data->uart_16550_compatible = true;
+       }
+
+       /* Platforms with iDMA */
+       if (platform_get_resource_byname(to_platform_device(p->dev),
+                                        IORESOURCE_MEM, "lpss_priv")) {
+               p->set_termios = dw8250_set_termios;
+               data->dma.rx_param = p->dev->parent;
+               data->dma.tx_param = p->dev->parent;
+               data->dma.fn = dw8250_idma_filter;
+       }
+}
+
+static void dw8250_setup_port(struct uart_port *p)
+{
+       struct uart_8250_port *up = up_to_u8250p(p);
+       u32 reg;
 
        /*
         * If the Component Version Register returns zero, we know that
         * ADDITIONAL_FEATURES are not enabled. No need to go any further.
         */
+       reg = readl(p->membase + DW_UART_UCV);
        if (!reg)
                return;
 
-       dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
+       dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
                (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
 
        reg = readl(p->membase + DW_UART_CPR);
@@ -273,7 +329,6 @@ static void dw8250_setup_port(struct uart_8250_port *up)
                p->type = PORT_16550A;
                p->flags |= UPF_FIXED_TYPE;
                p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
-               up->tx_loadsz = p->fifosize;
                up->capabilities = UART_CAP_FIFO;
        }
 
@@ -281,166 +336,91 @@ static void dw8250_setup_port(struct uart_8250_port *up)
                up->capabilities |= UART_CAP_AFE;
 }
 
-static int dw8250_probe_of(struct uart_port *p,
-                          struct dw8250_data *data)
+static int dw8250_probe(struct platform_device *pdev)
 {
-       struct device_node      *np = p->dev->of_node;
-       struct uart_8250_port *up = up_to_u8250p(p);
-       u32                     val;
-       bool has_ucv = true;
-       int id;
+       struct uart_8250_port uart = {};
+       struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       int irq = platform_get_irq(pdev, 0);
+       struct uart_port *p = &uart.port;
+       struct dw8250_data *data;
+       int err;
+       u32 val;
 
-#ifdef CONFIG_64BIT
-       if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
-               p->serial_in = dw8250_serial_inq;
-               p->serial_out = dw8250_serial_outq;
-               p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-               p->type = PORT_OCTEON;
-               data->usr_reg = 0x27;
-               has_ucv = false;
-       } else
-#endif
-       if (!of_property_read_u32(np, "reg-io-width", &val)) {
-               switch (val) {
-               case 1:
-                       break;
-               case 4:
-                       p->iotype = UPIO_MEM32;
-                       p->serial_in = dw8250_serial_in32;
-                       p->serial_out = dw8250_serial_out32;
-                       break;
-               default:
-                       dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
-                       return -EINVAL;
-               }
+       if (!regs) {
+               dev_err(&pdev->dev, "no registers defined\n");
+               return -EINVAL;
        }
-       if (has_ucv)
-               dw8250_setup_port(up);
 
-       /* if we have a valid fifosize, try hooking up DMA here */
-       if (p->fifosize) {
-               up->dma = &data->dma;
-
-               up->dma->rxconf.src_maxburst = p->fifosize / 4;
-               up->dma->txconf.dst_maxburst = p->fifosize / 4;
+       if (irq < 0) {
+               if (irq != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "cannot get irq\n");
+               return irq;
        }
 
-       if (!of_property_read_u32(np, "reg-shift", &val))
+       spin_lock_init(&p->lock);
+       p->mapbase      = regs->start;
+       p->irq          = irq;
+       p->handle_irq   = dw8250_handle_irq;
+       p->pm           = dw8250_do_pm;
+       p->type         = PORT_8250;
+       p->flags        = UPF_SHARE_IRQ | UPF_FIXED_PORT;
+       p->dev          = &pdev->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));
+       if (!p->membase)
+               return -ENOMEM;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->dma.fn = dw8250_fallback_dma_filter;
+       data->usr_reg = DW_UART_USR;
+       p->private_data = data;
+
+       data->uart_16550_compatible = device_property_read_bool(p->dev,
+                                               "snps,uart-16550-compatible");
+
+       err = device_property_read_u32(p->dev, "reg-shift", &val);
+       if (!err)
                p->regshift = val;
 
-       /* get index of serial line, if found in DT aliases */
-       id = of_alias_get_id(np, "serial");
-       if (id >= 0)
-               p->line = id;
+       err = device_property_read_u32(p->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 (of_property_read_bool(np, "dcd-override")) {
+       if (device_property_read_bool(p->dev, "dcd-override")) {
                /* Always report DCD as active */
                data->msr_mask_on |= UART_MSR_DCD;
                data->msr_mask_off |= UART_MSR_DDCD;
        }
 
-       if (of_property_read_bool(np, "dsr-override")) {
+       if (device_property_read_bool(p->dev, "dsr-override")) {
                /* Always report DSR as active */
                data->msr_mask_on |= UART_MSR_DSR;
                data->msr_mask_off |= UART_MSR_DDSR;
        }
 
-       if (of_property_read_bool(np, "cts-override")) {
+       if (device_property_read_bool(p->dev, "cts-override")) {
                /* Always report CTS as active */
                data->msr_mask_on |= UART_MSR_CTS;
                data->msr_mask_off |= UART_MSR_DCTS;
        }
 
-       if (of_property_read_bool(np, "ri-override")) {
+       if (device_property_read_bool(p->dev, "ri-override")) {
                /* Always report Ring indicator as inactive */
                data->msr_mask_off |= UART_MSR_RI;
                data->msr_mask_off |= UART_MSR_TERI;
        }
 
-       return 0;
-}
-
-static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
-{
-       struct device *dev = param;
-
-       if (dev != chan->device->dev->parent)
-               return false;
-
-       return true;
-}
-
-static int dw8250_probe_acpi(struct uart_8250_port *up,
-                            struct dw8250_data *data)
-{
-       struct uart_port *p = &up->port;
-
-       dw8250_setup_port(up);
-
-       p->iotype = UPIO_MEM32;
-       p->serial_in = dw8250_serial_in32;
-       p->serial_out = dw8250_serial_out32;
-       p->regshift = 2;
-
-       /* Platforms with iDMA */
-       if (platform_get_resource_byname(to_platform_device(up->port.dev),
-                                        IORESOURCE_MEM, "lpss_priv")) {
-               data->dma.rx_param = up->port.dev->parent;
-               data->dma.tx_param = up->port.dev->parent;
-               data->dma.fn = dw8250_idma_filter;
-       }
-
-       up->dma = &data->dma;
-       up->dma->rxconf.src_maxburst = p->fifosize / 4;
-       up->dma->txconf.dst_maxburst = p->fifosize / 4;
-
-       up->port.set_termios = dw8250_set_termios;
-
-       return 0;
-}
-
-static int dw8250_probe(struct platform_device *pdev)
-{
-       struct uart_8250_port uart = {};
-       struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       int irq = platform_get_irq(pdev, 0);
-       struct dw8250_data *data;
-       int err;
-
-       if (!regs) {
-               dev_err(&pdev->dev, "no registers defined\n");
-               return -EINVAL;
-       }
-
-       if (irq < 0) {
-               if (irq != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "cannot get irq\n");
-               return irq;
-       }
-
-       spin_lock_init(&uart.port.lock);
-       uart.port.mapbase = regs->start;
-       uart.port.irq = irq;
-       uart.port.handle_irq = dw8250_handle_irq;
-       uart.port.pm = dw8250_do_pm;
-       uart.port.type = PORT_8250;
-       uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
-       uart.port.dev = &pdev->dev;
-
-       uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
-                                        resource_size(regs));
-       if (!uart.port.membase)
-               return -ENOMEM;
-
-       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       data->usr_reg = DW_UART_USR;
-
        /* Always ask for fixed clock rate from a property. */
-       device_property_read_u32(&pdev->dev, "clock-frequency",
-                                &uart.port.uartclk);
+       device_property_read_u32(p->dev, "clock-frequency", &p->uartclk);
 
        /* If there is separate baudclk, get the rate from it. */
        data->clk = devm_clk_get(&pdev->dev, "baudclk");
@@ -454,11 +434,11 @@ static int dw8250_probe(struct platform_device *pdev)
                        dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
                                 err);
                else
-                       uart.port.uartclk = clk_get_rate(data->clk);
+                       p->uartclk = clk_get_rate(data->clk);
        }
 
        /* If no clock rate is defined, fail. */
-       if (!uart.port.uartclk) {
+       if (!p->uartclk) {
                dev_err(&pdev->dev, "clock rate not defined\n");
                return -EINVAL;
        }
@@ -484,26 +464,22 @@ static int dw8250_probe(struct platform_device *pdev)
        if (!IS_ERR(data->rst))
                reset_control_deassert(data->rst);
 
-       data->dma.rx_param = data;
-       data->dma.tx_param = data;
-       data->dma.fn = dw8250_dma_filter;
+       dw8250_quirks(p, data);
 
-       uart.port.iotype = UPIO_MEM;
-       uart.port.serial_in = dw8250_serial_in;
-       uart.port.serial_out = dw8250_serial_out;
-       uart.port.private_data = data;
+       /* If the Busy Functionality is not implemented, don't handle it */
+       if (data->uart_16550_compatible) {
+               p->serial_out = NULL;
+               p->handle_irq = NULL;
+       }
 
-       if (pdev->dev.of_node) {
-               err = dw8250_probe_of(&uart.port, data);
-               if (err)
-                       goto err_reset;
-       } else if (ACPI_HANDLE(&pdev->dev)) {
-               err = dw8250_probe_acpi(&uart, data);
-               if (err)
-                       goto err_reset;
-       } else {
-               err = -ENODEV;
-               goto err_reset;
+       if (!data->skip_autocfg)
+               dw8250_setup_port(p);
+
+       /* If we have a valid fifosize, try hooking up DMA */
+       if (p->fifosize) {
+               data->dma.rxconf.src_maxburst = p->fifosize / 4;
+               data->dma.txconf.dst_maxburst = p->fifosize / 4;
+               uart.dma = &data->dma;
        }
 
        data->line = serial8250_register_8250_port(&uart);
index faed05f25bc2e148837518ad34958924c06eb90e..ceb85792a5cf26e8865b317d82426ded50bf37b8 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/tty.h>
 #include <linux/init.h>
 #include <linux/console.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/serial_reg.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
@@ -152,3 +154,5 @@ int __init early_serial8250_setup(struct earlycon_device *device,
 }
 EARLYCON_DECLARE(uart8250, early_serial8250_setup);
 EARLYCON_DECLARE(uart, early_serial8250_setup);
+OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
+OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
index 7c1e4be48e7b3b96b975b29ba4d2053083bd9700..49394b4c5cfdc947dd2763dcb368bea49e6cf3e0 100644 (file)
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
 
+#include "8250.h"
+
+/** ingenic_uart_config: SOC specific config data. */
+struct ingenic_uart_config {
+       int tx_loadsz;
+       int fifosize;
+};
+
 struct ingenic_uart_data {
        struct clk      *clk_module;
        struct clk      *clk_baud;
        int             line;
 };
 
+static const struct of_device_id of_match[];
+
 #define UART_FCR_UME   BIT(4)
 
+#define UART_MCR_MDCE  BIT(7)
+#define UART_MCR_FCM   BIT(6)
+
 static struct earlycon_device *early_device;
 
 static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -129,6 +143,8 @@ OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
 
 static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
 {
+       int ier;
+
        switch (offset) {
        case UART_FCR:
                /* UART module enable */
@@ -136,9 +152,22 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
                break;
 
        case UART_IER:
+               /* Enable receive timeout interrupt with the
+                * receive line status interrupt */
                value |= (value & 0x4) << 2;
                break;
 
+       case UART_MCR:
+               /* If we have enabled modem status IRQs we should enable modem
+                * mode. */
+               ier = p->serial_in(p, UART_IER);
+
+               if (ier & UART_IER_MSI)
+                       value |= UART_MCR_MDCE | UART_MCR_FCM;
+               else
+                       value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
+               break;
+
        default:
                break;
        }
@@ -146,14 +175,45 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
        writeb(value, p->membase + (offset << p->regshift));
 }
 
+static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset)
+{
+       unsigned int value;
+
+       value = readb(p->membase + (offset << p->regshift));
+
+       /* Hide non-16550 compliant bits from higher levels */
+       switch (offset) {
+       case UART_FCR:
+               value &= ~UART_FCR_UME;
+               break;
+
+       case UART_MCR:
+               value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
+               break;
+
+       default:
+               break;
+       }
+       return value;
+}
+
 static int ingenic_uart_probe(struct platform_device *pdev)
 {
        struct uart_8250_port uart = {};
        struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        struct ingenic_uart_data *data;
+       const struct ingenic_uart_config *cdata;
+       const struct of_device_id *match;
        int err, line;
 
+       match = of_match_device(of_match, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "Error: No device match found\n");
+               return -ENODEV;
+       }
+       cdata = match->data;
+
        if (!regs || !irq) {
                dev_err(&pdev->dev, "no registers/irq defined\n");
                return -EINVAL;
@@ -164,14 +224,18 @@ static int ingenic_uart_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        spin_lock_init(&uart.port.lock);
-       uart.port.type = PORT_16550;
+       uart.port.type = PORT_16550A;
        uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
        uart.port.iotype = UPIO_MEM;
        uart.port.mapbase = regs->start;
        uart.port.regshift = 2;
        uart.port.serial_out = ingenic_uart_serial_out;
+       uart.port.serial_in = ingenic_uart_serial_in;
        uart.port.irq = irq->start;
        uart.port.dev = &pdev->dev;
+       uart.port.fifosize = cdata->fifosize;
+       uart.tx_loadsz = cdata->tx_loadsz;
+       uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;
 
        /* Check for a fixed line number */
        line = of_alias_get_id(pdev->dev.of_node, "serial");
@@ -241,10 +305,26 @@ static int ingenic_uart_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct ingenic_uart_config jz4740_uart_config = {
+       .tx_loadsz = 8,
+       .fifosize = 16,
+};
+
+static const struct ingenic_uart_config jz4760_uart_config = {
+       .tx_loadsz = 16,
+       .fifosize = 32,
+};
+
+static const struct ingenic_uart_config jz4780_uart_config = {
+       .tx_loadsz = 32,
+       .fifosize = 64,
+};
+
 static const struct of_device_id of_match[] = {
-       { .compatible = "ingenic,jz4740-uart" },
-       { .compatible = "ingenic,jz4775-uart" },
-       { .compatible = "ingenic,jz4780-uart" },
+       { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
+       { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
+       { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
+       { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_match);
index 826c5c4a2103be3ac9c5065eeb8274fd8ce8c75f..6efe4dd6e77ad73599396c6343b8efcc9efbfdce 100644 (file)
@@ -726,6 +726,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
        struct dma_tx_state     state;
        int                     count;
        unsigned long           flags;
+       int                     ret;
 
        dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
                                dma->rx_size, DMA_FROM_DEVICE);
@@ -741,8 +742,10 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
 
        count = dma->rx_size - state.residue;
 
-       tty_insert_flip_string(tty_port, dma->rx_buf, count);
-       p->port.icount.rx += count;
+       ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
+
+       p->port.icount.rx += ret;
+       p->port.icount.buf_overrun += count - ret;
 unlock:
        spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
 
index 0bbf34035d6a51edb267d2f53c66fc13d7b54260..52d82d2ac726be56d5838b872b9049b3c7729188 100644 (file)
@@ -284,7 +284,7 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value)
        serial_out(up, UART_DLM, value >> 8 & 0xff);
 }
 
-#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
+#ifdef CONFIG_SERIAL_8250_RT288X
 
 /* Au1x00/RT288x UART hardware has a weird register layout */
 static const s8 au_io_in_map[8] = {
@@ -435,7 +435,7 @@ static void set_io_from_upio(struct uart_port *p)
                p->serial_out = mem32be_serial_out;
                break;
 
-#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
+#ifdef CONFIG_SERIAL_8250_RT288X
        case UPIO_AU:
                p->serial_in = au_serial_in;
                p->serial_out = au_serial_out;
@@ -1246,6 +1246,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
                inb_p(ICP);
        }
 
+       if (uart_console(port))
+               console_lock();
+
        /* forget possible initially masked and pending IRQ */
        probe_irq_off(probe_irq_on());
        save_mcr = serial_in(up, UART_MCR);
@@ -1277,6 +1280,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
        if (port->flags & UPF_FOURPORT)
                outb_p(save_ICP, ICP);
 
+       if (uart_console(port))
+               console_unlock();
+
        port->irq = (irq > 0) ? irq : 0;
 }
 
@@ -1807,9 +1813,6 @@ int serial8250_do_startup(struct uart_port *port)
        unsigned char lsr, iir;
        int retval;
 
-       if (port->type == PORT_8250_CIR)
-               return -ENODEV;
-
        if (!port->fifosize)
                port->fifosize = uart_config[port->type].fifo_size;
        if (!up->tx_loadsz)
@@ -2230,6 +2233,23 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
                serial_port_out(port, 0x2, quot_frac);
 }
 
+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
+        * slower than nominal still match standard baud rates without
+        * causing transmission errors.
+        */
+       return uart_get_baud_rate(port, termios, old,
+                                 port->uartclk / 16 / 0xffff,
+                                 (port->uartclk + tolerance) / 16);
+}
+
 void
 serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
                          struct ktermios *old)
@@ -2241,12 +2261,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 
        cval = serial8250_compute_lcr(up, termios->c_cflag);
 
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old,
-                                 port->uartclk / 16 / 0xffff,
-                                 port->uartclk / 16);
+       baud = serial8250_get_baud_rate(port, termios, old);
        quot = serial8250_get_divisor(up, baud, &frac);
 
        /*
@@ -2513,14 +2528,8 @@ static void serial8250_release_port(struct uart_port *port)
 static int serial8250_request_port(struct uart_port *port)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
-       int ret;
-
-       if (port->type == PORT_8250_CIR)
-               return -ENODEV;
-
-       ret = serial8250_request_std_resource(up);
 
-       return ret;
+       return serial8250_request_std_resource(up);
 }
 
 static int fcr_get_rxtrig_bytes(struct uart_8250_port *up)
@@ -2668,9 +2677,6 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        struct uart_8250_port *up = up_to_u8250p(port);
        int ret;
 
-       if (port->type == PORT_8250_CIR)
-               return;
-
        /*
         * Find the region that we can probe for.  This in turn
         * tells us whether we can probe for the type of port.
@@ -2804,6 +2810,27 @@ static void serial8250_console_putchar(struct uart_port *port, int ch)
        serial_port_out(port, UART_TX, ch);
 }
 
+/*
+ *     Restore serial console when h/w power-off detected
+ */
+static void serial8250_console_restore(struct uart_8250_port *up)
+{
+       struct uart_port *port = &up->port;
+       struct ktermios termios;
+       unsigned int baud, quot, frac = 0;
+
+       termios.c_cflag = port->cons->cflag;
+       if (port->state->port.tty && termios.c_cflag == 0)
+               termios.c_cflag = port->state->port.tty->termios.c_cflag;
+
+       baud = serial8250_get_baud_rate(port, &termios, NULL);
+       quot = serial8250_get_divisor(up, baud, &frac);
+
+       serial8250_set_divisor(port, baud, quot, frac);
+       serial_port_out(port, UART_LCR, up->lcr);
+       serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+}
+
 /*
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
@@ -2841,22 +2868,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
 
        /* check scratch reg to see if port powered off during system sleep */
        if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
-               struct ktermios termios;
-               unsigned int baud, quot, frac = 0;
-
-               termios.c_cflag = port->cons->cflag;
-               if (port->state->port.tty && termios.c_cflag == 0)
-                       termios.c_cflag = port->state->port.tty->termios.c_cflag;
-
-               baud = uart_get_baud_rate(port, &termios, NULL,
-                                         port->uartclk / 16 / 0xffff,
-                                         port->uartclk / 16);
-               quot = serial8250_get_divisor(up, baud, &frac);
-
-               serial8250_set_divisor(port, baud, quot, frac);
-               serial_port_out(port, UART_LCR, up->lcr);
-               serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
-
+               serial8250_console_restore(up);
                up->canary = 0;
        }
 
index e1de1181b322d6c4d40f689e99501915f2e63b8e..656a1737d509b2a2533dd35536001442d4b8aad5 100644 (file)
@@ -294,11 +294,12 @@ config SERIAL_8250_EM
 
 config SERIAL_8250_RT288X
        bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
-       depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620)
+       depends on SERIAL_8250
+       default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
        help
-         If you have a Ralink RT288x/RT305x SoC based board and want to use the
-         serial port, say Y to this option. The driver can handle up to 2 serial
-         ports. If unsure, say N.
+         Selecting this option will add support for the alternate register
+         layout used by Ralink RT288x/RT305x, Alchemy Au1xxx, and some others.
+         If unsure, say N.
 
 config SERIAL_8250_OMAP
        tristate "Support for OMAP internal UART (8250 based driver)"
@@ -337,7 +338,7 @@ config SERIAL_8250_FINTEK
          through the PNP driver. If unsure, say N.
 
 config SERIAL_8250_LPC18XX
-       bool "NXP LPC18xx/43xx serial port support"
+       tristate "NXP LPC18xx/43xx serial port support"
        depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
        default ARCH_LPC18XX
        help
index 687b1ea294b79bbf999c4c86747ee2df7ba30df5..0667d1a512991932d5f00c3dc6af2f7023f32334 100644 (file)
@@ -115,9 +115,9 @@ config SERIAL_SB1250_DUART_CONSOLE
 
 config SERIAL_ATMEL
        bool "AT91 / AT32 on-chip serial port support"
-       depends on ARCH_AT91 || AVR32
+       depends on ARCH_AT91 || AVR32 || COMPILE_TEST
        select SERIAL_CORE
-       select SERIAL_MCTRL_GPIO
+       select SERIAL_MCTRL_GPIO if GPIOLIB
        help
          This enables the driver for the on-chip UARTs of the Atmel
          AT91 and AT32 processors.
@@ -571,7 +571,7 @@ config BFIN_UART3_CTSRTS
 
 config SERIAL_IMX
        tristate "IMX serial port support"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        select SERIAL_CORE
        select RATIONAL
        help
@@ -582,6 +582,7 @@ config SERIAL_IMX_CONSOLE
        bool "Console on IMX serial port"
        depends on SERIAL_IMX=y
        select SERIAL_CORE_CONSOLE
+       select SERIAL_EARLYCON if OF
        help
          If you have enabled the serial port on the Freescale IMX
          CPU you can make it the console by answering Y to this option.
@@ -743,7 +744,7 @@ config SERIAL_SH_SCI_CONSOLE
 
 config SERIAL_SH_SCI_DMA
        bool "DMA support"
-       depends on SERIAL_SH_SCI && SH_DMAE
+       depends on SERIAL_SH_SCI && DMA_ENGINE
 
 config SERIAL_PNX8XXX
        bool "Enable PNX8XXX SoCs' UART Support"
@@ -1408,7 +1409,7 @@ config SERIAL_PCH_UART_CONSOLE
          warnings and which allows logins in single user mode).
 
 config SERIAL_MXS_AUART
-       depends on ARCH_MXS
+       depends on ARCH_MXS || COMPILE_TEST
        tristate "MXS AUART support"
        select SERIAL_CORE
        select SERIAL_MCTRL_GPIO if GPIOLIB
index fd87a6f574e3b32e370ce27244960c37c5f36576..61b607f2488e36761069e0e58a9bd2cf74661100 100644 (file)
@@ -508,29 +508,6 @@ static struct uart_driver altera_uart_driver = {
        .cons           = ALTERA_UART_CONSOLE,
 };
 
-#ifdef CONFIG_OF
-static int altera_uart_get_of_uartclk(struct platform_device *pdev,
-                                     struct uart_port *port)
-{
-       int len;
-       const __be32 *clk;
-
-       clk = of_get_property(pdev->dev.of_node, "clock-frequency", &len);
-       if (!clk || len < sizeof(__be32))
-               return -ENODEV;
-
-       port->uartclk = be32_to_cpup(clk);
-
-       return 0;
-}
-#else
-static int altera_uart_get_of_uartclk(struct platform_device *pdev,
-                                     struct uart_port *port)
-{
-       return -ENODEV;
-}
-#endif /* CONFIG_OF */
-
 static int altera_uart_probe(struct platform_device *pdev)
 {
        struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev);
@@ -570,7 +547,8 @@ static int altera_uart_probe(struct platform_device *pdev)
        if (platp)
                port->uartclk = platp->uartclk;
        else {
-               ret = altera_uart_get_of_uartclk(pdev, port);
+               ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+                                          &port->uartclk);
                if (ret)
                        return ret;
        }
index f3af317131acb022616739800cca755c29ebf404..75eb083b3361c8fc47c910eecc316152e4e34e84 100644 (file)
@@ -581,6 +581,7 @@ static const struct of_device_id apbuart_match[] = {
         },
        {},
 };
+MODULE_DEVICE_TABLE(of, apbuart_match);
 
 static struct platform_driver grlib_apbuart_of_driver = {
        .probe = apbuart_probe,
index 538ea03bc101a2994324d2ce33b8f7b237c12c78..298cbe34af4586424126a5c6f9a3136193fdc2ba 100644 (file)
@@ -111,6 +111,12 @@ struct atmel_uart_char {
 
 #define ATMEL_SERIAL_RINGSIZE 1024
 
+/*
+ * at91: 6 USARTs and one DBGU port (SAM9260)
+ * avr32: 4
+ */
+#define ATMEL_MAX_UART         7
+
 /*
  * We wrap our port structure around the generic uart_port.
  */
@@ -921,7 +927,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
        sg_set_page(&atmel_port->sg_tx,
                        virt_to_page(port->state->xmit.buf),
                        UART_XMIT_SIZE,
-                       (int)port->state->xmit.buf & ~PAGE_MASK);
+                       (unsigned long)port->state->xmit.buf & ~PAGE_MASK);
        nent = dma_map_sg(port->dev,
                                &atmel_port->sg_tx,
                                1,
@@ -931,10 +937,10 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
                dev_dbg(port->dev, "need to release resource of dma\n");
                goto chan_err;
        } else {
-               dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+               dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
                        sg_dma_len(&atmel_port->sg_tx),
                        port->state->xmit.buf,
-                       sg_dma_address(&atmel_port->sg_tx));
+                       &sg_dma_address(&atmel_port->sg_tx));
        }
 
        /* Configure the slave DMA */
@@ -1103,7 +1109,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
        sg_set_page(&atmel_port->sg_rx,
                    virt_to_page(ring->buf),
                    sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
-                   (int)ring->buf & ~PAGE_MASK);
+                   (unsigned long)ring->buf & ~PAGE_MASK);
        nent = dma_map_sg(port->dev,
                          &atmel_port->sg_rx,
                          1,
@@ -1113,10 +1119,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
                dev_dbg(port->dev, "need to release resource of dma\n");
                goto chan_err;
        } else {
-               dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+               dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
                        sg_dma_len(&atmel_port->sg_rx),
                        ring->buf,
-                       sg_dma_address(&atmel_port->sg_rx));
+                       &sg_dma_address(&atmel_port->sg_rx));
        }
 
        /* Configure the slave DMA */
@@ -2686,7 +2692,7 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
        enum mctrl_gpio_idx i;
        struct gpio_desc *gpiod;
 
-       p->gpios = mctrl_gpio_init(dev, 0);
+       p->gpios = mctrl_gpio_init_noauto(dev, 0);
        if (IS_ERR(p->gpios))
                return PTR_ERR(p->gpios);
 
index d5d2dd7c79174820432363d4a7076566eafc2204..b3a4e0cdddaab29b0b86e42738a763e279411354 100644 (file)
@@ -500,7 +500,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, s);
 
-       s->gpios = mctrl_gpio_init(&pdev->dev, 0);
+       s->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0);
        if (IS_ERR(s->gpios))
            return PTR_ERR(s->gpios);
 
index 08431adeacd5dcd4f24e4ba395a228eab1060457..d3e3d42c0c129035c96ca9ee7578d1195fd7db56 100644 (file)
@@ -1450,6 +1450,7 @@ static const struct of_device_id cpm_uart_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, cpm_uart_match);
 
 static struct platform_driver cpm_uart_driver = {
        .driver = {
index d0388a071ba1d474025a74fec8cfb80f5a1ed4a0..016e4be05cec3e60141f0497dd643d9ad0c7ee98 100644 (file)
 #define USR1_ESCF      (1<<11) /* Escape seq interrupt flag */
 #define USR1_FRAMERR   (1<<10) /* Frame error interrupt flag */
 #define USR1_RRDY      (1<<9)   /* Receiver ready interrupt/dma flag */
+#define USR1_AGTIM     (1<<8)   /* Ageing timer interrupt flag */
 #define USR1_TIMEOUT   (1<<7)   /* Receive timeout interrupt status */
 #define USR1_RXDS       (1<<6)  /* Receiver idle interrupt flag */
 #define USR1_AIRINT     (1<<5)  /* Async IR wake interrupt flag */
@@ -728,11 +729,15 @@ static void imx_dma_rxint(struct imx_port *sport)
        if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
                sport->dma_is_rxing = 1;
 
-               /* disable the `Recerver Ready Interrrupt` */
+               /* disable the receiver ready and aging timer interrupts */
                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);
+
                /* tell the DMA to receive the data. */
                start_rx_dma(sport);
        }
@@ -749,7 +754,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
        sts = readl(sport->port.membase + USR1);
        sts2 = readl(sport->port.membase + USR2);
 
-       if (sts & USR1_RRDY) {
+       if (sts & (USR1_RRDY | USR1_AGTIM)) {
                if (sport->dma_is_enabled)
                        imx_dma_rxint(sport);
                else
@@ -852,19 +857,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-#define TXTL 2 /* reset default */
-#define RXTL 1 /* reset default */
-
-static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
-{
-       unsigned int val;
-
-       /* set receiver / transmitter trigger level */
-       val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
-       val |= TXTL << UFCR_TXTL_SHF | RXTL;
-       writel(val, sport->port.membase + UFCR);
-}
-
 #define RX_BUF_SIZE    (PAGE_SIZE)
 static void imx_rx_dma_done(struct imx_port *sport)
 {
@@ -873,11 +865,15 @@ static void imx_rx_dma_done(struct imx_port *sport)
 
        spin_lock_irqsave(&sport->port.lock, flags);
 
-       /* Enable this interrupt when the RXFIFO is empty. */
+       /* 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? */
@@ -888,14 +884,12 @@ static void imx_rx_dma_done(struct imx_port *sport)
 }
 
 /*
- * There are three kinds of RX DMA interrupts(such as in the MX6Q):
+ * There are two kinds of RX DMA interrupts(such as in the MX6Q):
  *   [1] the RX DMA buffer is full.
- *   [2] the Aging timer expires(wait for 8 bytes long)
- *   [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
+ *   [2] the aging timer expires
  *
- * The [2] is trigger when a character was been sitting in the FIFO
- * meanwhile [3] can wait for 32 bytes long when the RX line is
- * on IDLE state and RxFIFO is empty.
+ * Condition [2] is triggered when a character has been sitting in the FIFO
+ * for at least 8 byte durations.
  */
 static void dma_rx_callback(void *data)
 {
@@ -913,13 +907,6 @@ static void dma_rx_callback(void *data)
        status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
        count = RX_BUF_SIZE - state.residue;
 
-       if (readl(sport->port.membase + USR2) & USR2_IDLE) {
-               /* In condition [3] the SDMA counted up too early */
-               count--;
-
-               writel(USR2_IDLE, sport->port.membase + USR2);
-       }
-
        dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
 
        if (count) {
@@ -931,23 +918,21 @@ static void dma_rx_callback(void *data)
                                sport->port.icount.buf_overrun++;
                }
                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 if (readl(sport->port.membase + USR2) & USR2_RDR) {
-               /*
-                * start rx_dma directly once data in RXFIFO, more efficient
-                * than before:
-                *      1. call imx_rx_dma_done to stop dma if no data received
-                *      2. wait next  RDR interrupt to start dma transfer.
-                */
-               start_rx_dma(sport);
-       } else {
-               /*
-                * stop dma to prevent too many IDLE event trigged if no data
-                * in RXFIFO
-                */
+       else
                imx_rx_dma_done(sport);
-       }
 }
 
 static int start_rx_dma(struct imx_port *sport)
@@ -980,6 +965,22 @@ static int start_rx_dma(struct imx_port *sport)
        return 0;
 }
 
+#define TXTL_DEFAULT 2 /* reset default */
+#define RXTL_DEFAULT 1 /* reset default */
+#define TXTL_DMA 8 /* DMA burst setting */
+#define RXTL_DMA 9 /* DMA burst setting */
+
+static void imx_setup_ufcr(struct imx_port *sport,
+                         unsigned char txwl, unsigned char rxwl)
+{
+       unsigned int val;
+
+       /* set receiver / transmitter trigger level */
+       val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
+       val |= txwl << UFCR_TXTL_SHF | rxwl;
+       writel(val, sport->port.membase + UFCR);
+}
+
 static void imx_uart_dma_exit(struct imx_port *sport)
 {
        if (sport->dma_chan_rx) {
@@ -1015,7 +1016,8 @@ static int imx_uart_dma_init(struct imx_port *sport)
        slave_config.direction = DMA_DEV_TO_MEM;
        slave_config.src_addr = sport->port.mapbase + URXD0;
        slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       slave_config.src_maxburst = RXTL;
+       /* one byte less than the watermark level to enable the aging timer */
+       slave_config.src_maxburst = RXTL_DMA - 1;
        ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
        if (ret) {
                dev_err(dev, "error in RX dma configuration.\n");
@@ -1039,7 +1041,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
        slave_config.direction = DMA_MEM_TO_DEV;
        slave_config.dst_addr = sport->port.mapbase + URTX0;
        slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       slave_config.dst_maxburst = TXTL;
+       slave_config.dst_maxburst = TXTL_DMA;
        ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
        if (ret) {
                dev_err(dev, "error in TX dma configuration.");
@@ -1062,15 +1064,14 @@ static void imx_enable_dma(struct imx_port *sport)
 
        /* set UCR1 */
        temp = readl(sport->port.membase + UCR1);
-       temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
-               /* wait for 32 idle frames for IDDMA interrupt */
-               UCR1_ICD_REG(3);
+       temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
        writel(temp, sport->port.membase + UCR1);
 
-       /* set UCR4 */
-       temp = readl(sport->port.membase + UCR4);
-       temp |= UCR4_IDDMAEN;
-       writel(temp, sport->port.membase + UCR4);
+       temp = readl(sport->port.membase + UCR2);
+       temp |= UCR2_ATEN;
+       writel(temp, sport->port.membase + UCR2);
+
+       imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA);
 
        sport->dma_is_enabled = 1;
 }
@@ -1086,13 +1087,10 @@ static void imx_disable_dma(struct imx_port *sport)
 
        /* clear UCR2 */
        temp = readl(sport->port.membase + UCR2);
-       temp &= ~(UCR2_CTSC | UCR2_CTS);
+       temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
        writel(temp, sport->port.membase + UCR2);
 
-       /* clear UCR4 */
-       temp = readl(sport->port.membase + UCR4);
-       temp &= ~UCR4_IDDMAEN;
-       writel(temp, sport->port.membase + UCR4);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        sport->dma_is_enabled = 0;
 }
@@ -1115,7 +1113,7 @@ static int imx_startup(struct uart_port *port)
                return retval;
        }
 
-       imx_setup_ufcr(sport, 0);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        /* disable the DREN bit (Data Ready interrupt enable) before
         * requesting IRQs
@@ -1128,6 +1126,11 @@ 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)
+               imx_uart_dma_init(sport);
+
        spin_lock_irqsave(&sport->port.lock, flags);
        /* Reset fifo's and state machines */
        i = 100;
@@ -1145,6 +1148,9 @@ static int imx_startup(struct uart_port *port)
        writel(USR1_RTSD, sport->port.membase + USR1);
        writel(USR2_ORE, sport->port.membase + USR2);
 
+       if (sport->dma_is_inited && !sport->dma_is_enabled)
+               imx_enable_dma(sport);
+
        temp = readl(sport->port.membase + UCR1);
        temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
 
@@ -1278,7 +1284,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 {
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long flags;
-       unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
+       unsigned int ucr2, old_ucr1, old_ucr2, baud, quot;
        unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
        unsigned int div, ufcr;
        unsigned long num, denom;
@@ -1315,11 +1321,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        } else {
                                ucr2 |= UCR2_CTSC;
                        }
-
-                       /* Can we enable the DMA support? */
-                       if (is_imx6q_uart(sport) && !uart_console(port)
-                               && !sport->dma_is_inited)
-                               imx_uart_dma_init(sport);
                } else {
                        termios->c_cflag &= ~CRTSCTS;
                }
@@ -1387,10 +1388,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                barrier();
 
        /* then, disable everything */
-       old_txrxen = readl(sport->port.membase + UCR2);
-       writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN),
+       old_ucr2 = readl(sport->port.membase + UCR2);
+       writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN),
                        sport->port.membase + UCR2);
-       old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
+       old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
 
        /* custom-baudrate handling */
        div = sport->port.uartclk / (baud * 16);
@@ -1431,13 +1432,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        writel(old_ucr1, sport->port.membase + UCR1);
 
        /* set the parity, stop bits and data size */
-       writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
+       writel(ucr2 | old_ucr2, sport->port.membase + UCR2);
 
        if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
                imx_enable_ms(&sport->port);
 
-       if (sport->dma_is_inited && !sport->dma_is_enabled)
-               imx_enable_dma(sport);
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
@@ -1503,7 +1502,7 @@ static int imx_poll_init(struct uart_port *port)
        if (retval)
                clk_disable_unprepare(sport->clk_ipg);
 
-       imx_setup_ufcr(sport, 0);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -1773,7 +1772,7 @@ imx_console_setup(struct console *co, char *options)
        else
                imx_console_get_options(sport, &baud, &parity, &bits);
 
-       imx_setup_ufcr(sport, 0);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
 
@@ -1803,6 +1802,38 @@ static struct console imx_console = {
 };
 
 #define IMX_CONSOLE    &imx_console
+
+#ifdef CONFIG_OF
+static void imx_console_early_putchar(struct uart_port *port, int ch)
+{
+       while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL)
+               cpu_relax();
+
+       writel_relaxed(ch, port->membase + URTX0);
+}
+
+static void imx_console_early_write(struct console *con, const char *s,
+                                   unsigned count)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, count, imx_console_early_putchar);
+}
+
+static int __init
+imx_console_early_setup(struct earlycon_device *dev, const char *opt)
+{
+       if (!dev->port.membase)
+               return -ENODEV;
+
+       dev->con->write = imx_console_early_write;
+
+       return 0;
+}
+OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
+OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
+#endif
+
 #else
 #define IMX_CONSOLE    NULL
 #endif
index e92d7ebe9e77e545dae5de45db8857535de123a6..7eb04ae71cc876c2fcd3f4826feb29f6d01b11cc 100644 (file)
@@ -691,12 +691,13 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev)
        p->port.mapbase = res->start;
        p->port.membase = NULL;
 
-       p->port.irq = platform_get_irq(pdev, 0);
-       if (p->port.irq < 0) {
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
                dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
                        uarts_registered);
-               return p->port.irq;
+               return ret;
        }
+       p->port.irq = ret;
 
        p->port.iotype = UPIO_MEM32;
        p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
index 41de374d9784384ece372732e972a3de7c52e84f..8c3e5131447027104f4497f177faec3e4df68ade 100644 (file)
@@ -1135,6 +1135,13 @@ mpc52xx_uart_startup(struct uart_port *port)
        psc_ops->command(port, MPC52xx_PSC_RST_RX);
        psc_ops->command(port, MPC52xx_PSC_RST_TX);
 
+       /*
+        * According to Freescale's support the RST_TX command can produce a
+        * spike on the TX pin. So they recommend to delay "for one character".
+        * One millisecond should be enough for everyone.
+        */
+       msleep(1);
+
        psc_ops->set_sicr(port, 0);     /* UART mode DCD ignored */
 
        psc_ops->fifo_init(port);
index 82bb6d1fe23b416f05ac5bee9879ae299ed1b185..2f43a58cb3923affa749ce2b0bb7e947dbcdab36 100644 (file)
@@ -55,8 +55,6 @@
 #define SUPPORT_SYSRQ
 #endif
 
-#include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/ioport.h>
@@ -755,7 +753,7 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
                pi->port.line);
 
        if (!pi->dma_region) {
-               if (!dma_supported(pi->port.dev, 0xffffffff)) {
+               if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
                        printk(KERN_ERR "MPSC: Inadequate DMA support\n");
                        rc = -ENXIO;
                } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
@@ -2108,24 +2106,8 @@ static int mpsc_drv_probe(struct platform_device *dev)
        return rc;
 }
 
-static int mpsc_drv_remove(struct platform_device *dev)
-{
-       pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
-
-       if (dev->id < MPSC_NUM_CTLRS) {
-               uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
-               mpsc_release_port((struct uart_port *)
-                               &mpsc_ports[dev->id].port);
-               mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
-               return 0;
-       } else {
-               return -ENODEV;
-       }
-}
-
 static struct platform_driver mpsc_driver = {
        .probe  = mpsc_drv_probe,
-       .remove = mpsc_drv_remove,
        .driver = {
                .name   = MPSC_CTLR_NAME,
        },
@@ -2156,22 +2138,10 @@ static int __init mpsc_drv_init(void)
 
        return rc;
 }
+device_initcall(mpsc_drv_init);
 
-static void __exit mpsc_drv_exit(void)
-{
-       platform_driver_unregister(&mpsc_driver);
-       platform_driver_unregister(&mpsc_shared_driver);
-       uart_unregister_driver(&mpsc_reg);
-       memset(mpsc_ports, 0, sizeof(mpsc_ports));
-       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-}
-
-module_init(mpsc_drv_init);
-module_exit(mpsc_drv_exit);
-
+/*
 MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
 MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
-MODULE_VERSION(MPSC_VERSION);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
-MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
+*/
index b73889c8ed4b91242be90295d225aaa93b0adaa2..dcde955475dc9b11029c614d0d137d582d04e77c 100644 (file)
@@ -20,6 +20,8 @@
 #endif
 
 #include <linux/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 #include <linux/hrtimer.h>
 #include <linux/module.h>
 #include <linux/io.h>
@@ -31,6 +33,7 @@
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 
 #include "msm_serial.h"
 
+#define UARTDM_BURST_SIZE      16   /* in bytes */
+#define UARTDM_TX_AIGN(x)      ((x) & ~0x3) /* valid for > 1p3 */
+#define UARTDM_TX_MAX          256   /* in bytes, valid for <= 1p3 */
+#define UARTDM_RX_SIZE         (UART_XMIT_SIZE / 4)
+
 enum {
        UARTDM_1P1 = 1,
        UARTDM_1P2,
@@ -46,6 +54,17 @@ enum {
        UARTDM_1P4,
 };
 
+struct msm_dma {
+       struct dma_chan         *chan;
+       enum dma_data_direction dir;
+       dma_addr_t              phys;
+       unsigned char           *virt;
+       dma_cookie_t            cookie;
+       u32                     enable_bit;
+       unsigned int            count;
+       struct dma_async_tx_descriptor  *desc;
+};
+
 struct msm_port {
        struct uart_port        uart;
        char                    name[16];
@@ -55,9 +74,153 @@ struct msm_port {
        int                     is_uartdm;
        unsigned int            old_snap_state;
        bool                    break_detected;
+       struct msm_dma          tx_dma;
+       struct msm_dma          rx_dma;
 };
 
-static inline void wait_for_xmitr(struct uart_port *port)
+static void msm_handle_tx(struct uart_port *port);
+static void msm_start_rx_dma(struct msm_port *msm_port);
+
+void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
+{
+       struct device *dev = port->dev;
+       unsigned int mapped;
+       u32 val;
+
+       mapped = dma->count;
+       dma->count = 0;
+
+       dmaengine_terminate_all(dma->chan);
+
+       /*
+        * DMA Stall happens if enqueue and flush command happens concurrently.
+        * For example before changing the baud rate/protocol configuration and
+        * sending flush command to ADM, disable the channel of UARTDM.
+        * Note: should not reset the receiver here immediately as it is not
+        * suggested to do disable/reset or reset/disable at the same time.
+        */
+       val = msm_read(port, UARTDM_DMEN);
+       val &= ~dma->enable_bit;
+       msm_write(port, val, UARTDM_DMEN);
+
+       if (mapped)
+               dma_unmap_single(dev, dma->phys, mapped, dma->dir);
+}
+
+static void msm_release_dma(struct msm_port *msm_port)
+{
+       struct msm_dma *dma;
+
+       dma = &msm_port->tx_dma;
+       if (dma->chan) {
+               msm_stop_dma(&msm_port->uart, dma);
+               dma_release_channel(dma->chan);
+       }
+
+       memset(dma, 0, sizeof(*dma));
+
+       dma = &msm_port->rx_dma;
+       if (dma->chan) {
+               msm_stop_dma(&msm_port->uart, dma);
+               dma_release_channel(dma->chan);
+               kfree(dma->virt);
+       }
+
+       memset(dma, 0, sizeof(*dma));
+}
+
+static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base)
+{
+       struct device *dev = msm_port->uart.dev;
+       struct dma_slave_config conf;
+       struct msm_dma *dma;
+       u32 crci = 0;
+       int ret;
+
+       dma = &msm_port->tx_dma;
+
+       /* allocate DMA resources, if available */
+       dma->chan = dma_request_slave_channel_reason(dev, "tx");
+       if (IS_ERR(dma->chan))
+               goto no_tx;
+
+       of_property_read_u32(dev->of_node, "qcom,tx-crci", &crci);
+
+       memset(&conf, 0, sizeof(conf));
+       conf.direction = DMA_MEM_TO_DEV;
+       conf.device_fc = true;
+       conf.dst_addr = base + UARTDM_TF;
+       conf.dst_maxburst = UARTDM_BURST_SIZE;
+       conf.slave_id = crci;
+
+       ret = dmaengine_slave_config(dma->chan, &conf);
+       if (ret)
+               goto rel_tx;
+
+       dma->dir = DMA_TO_DEVICE;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               dma->enable_bit = UARTDM_DMEN_TX_DM_ENABLE;
+       else
+               dma->enable_bit = UARTDM_DMEN_TX_BAM_ENABLE;
+
+       return;
+
+rel_tx:
+       dma_release_channel(dma->chan);
+no_tx:
+       memset(dma, 0, sizeof(*dma));
+}
+
+static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
+{
+       struct device *dev = msm_port->uart.dev;
+       struct dma_slave_config conf;
+       struct msm_dma *dma;
+       u32 crci = 0;
+       int ret;
+
+       dma = &msm_port->rx_dma;
+
+       /* allocate DMA resources, if available */
+       dma->chan = dma_request_slave_channel_reason(dev, "rx");
+       if (IS_ERR(dma->chan))
+               goto no_rx;
+
+       of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
+
+       dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
+       if (!dma->virt)
+               goto rel_rx;
+
+       memset(&conf, 0, sizeof(conf));
+       conf.direction = DMA_DEV_TO_MEM;
+       conf.device_fc = true;
+       conf.src_addr = base + UARTDM_RF;
+       conf.src_maxburst = UARTDM_BURST_SIZE;
+       conf.slave_id = crci;
+
+       ret = dmaengine_slave_config(dma->chan, &conf);
+       if (ret)
+               goto err;
+
+       dma->dir = DMA_FROM_DEVICE;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               dma->enable_bit = UARTDM_DMEN_RX_DM_ENABLE;
+       else
+               dma->enable_bit = UARTDM_DMEN_RX_BAM_ENABLE;
+
+       return;
+err:
+       kfree(dma->virt);
+rel_rx:
+       dma_release_channel(dma->chan);
+no_rx:
+       memset(dma, 0, sizeof(*dma));
+}
+
+static inline void msm_wait_for_xmitr(struct uart_port *port)
 {
        while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
                if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
@@ -78,17 +241,277 @@ static void msm_stop_tx(struct uart_port *port)
 static void msm_start_tx(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->tx_dma;
+
+       /* Already started in DMA mode */
+       if (dma->count)
+               return;
+
+       msm_port->imr |= UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_reset_dm_count(struct uart_port *port, int count)
+{
+       msm_wait_for_xmitr(port);
+       msm_write(port, count, UARTDM_NCF_TX);
+       msm_read(port, UARTDM_NCF_TX);
+}
+
+static void msm_complete_tx_dma(void *args)
+{
+       struct msm_port *msm_port = args;
+       struct uart_port *port = &msm_port->uart;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct msm_dma *dma = &msm_port->tx_dma;
+       struct dma_tx_state state;
+       enum dma_status status;
+       unsigned long flags;
+       unsigned int count;
+       u32 val;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Already stopped */
+       if (!dma->count)
+               goto done;
+
+       status = dmaengine_tx_status(dma->chan, dma->cookie, &state);
+
+       dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir);
 
+       val = msm_read(port, UARTDM_DMEN);
+       val &= ~dma->enable_bit;
+       msm_write(port, val, UARTDM_DMEN);
+
+       if (msm_port->is_uartdm > UARTDM_1P3) {
+               msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+               msm_write(port, UART_CR_TX_ENABLE, UART_CR);
+       }
+
+       count = dma->count - state.residue;
+       port->icount.tx += count;
+       dma->count = 0;
+
+       xmit->tail += count;
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       /* Restore "Tx FIFO below watermark" interrupt */
        msm_port->imr |= UART_IMR_TXLEV;
        msm_write(port, msm_port->imr, UART_IMR);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       msm_handle_tx(port);
+done:
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
+{
+       struct circ_buf *xmit = &msm_port->uart.state->xmit;
+       struct uart_port *port = &msm_port->uart;
+       struct msm_dma *dma = &msm_port->tx_dma;
+       void *cpu_addr;
+       int ret;
+       u32 val;
+
+       cpu_addr = &xmit->buf[xmit->tail];
+
+       dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir);
+       ret = dma_mapping_error(port->dev, dma->phys);
+       if (ret)
+               return ret;
+
+       dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
+                                               count, DMA_MEM_TO_DEV,
+                                               DMA_PREP_INTERRUPT |
+                                               DMA_PREP_FENCE);
+       if (!dma->desc) {
+               ret = -EIO;
+               goto unmap;
+       }
+
+       dma->desc->callback = msm_complete_tx_dma;
+       dma->desc->callback_param = msm_port;
+
+       dma->cookie = dmaengine_submit(dma->desc);
+       ret = dma_submit_error(dma->cookie);
+       if (ret)
+               goto unmap;
+
+       /*
+        * Using DMA complete for Tx FIFO reload, no need for
+        * "Tx FIFO below watermark" one, disable it
+        */
+       msm_port->imr &= ~UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+
+       dma->count = count;
+
+       val = msm_read(port, UARTDM_DMEN);
+       val |= dma->enable_bit;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               msm_write(port, val, UARTDM_DMEN);
+
+       msm_reset_dm_count(port, count);
+
+       if (msm_port->is_uartdm > UARTDM_1P3)
+               msm_write(port, val, UARTDM_DMEN);
+
+       dma_async_issue_pending(dma->chan);
+       return 0;
+unmap:
+       dma_unmap_single(port->dev, dma->phys, count, dma->dir);
+       return ret;
+}
+
+static void msm_complete_rx_dma(void *args)
+{
+       struct msm_port *msm_port = args;
+       struct uart_port *port = &msm_port->uart;
+       struct tty_port *tport = &port->state->port;
+       struct msm_dma *dma = &msm_port->rx_dma;
+       int count = 0, i, sysrq;
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Already stopped */
+       if (!dma->count)
+               goto done;
+
+       val = msm_read(port, UARTDM_DMEN);
+       val &= ~dma->enable_bit;
+       msm_write(port, val, UARTDM_DMEN);
+
+       /* Restore interrupts */
+       msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE;
+       msm_write(port, msm_port->imr, UART_IMR);
+
+       if (msm_read(port, UART_SR) & UART_SR_OVERRUN) {
+               port->icount.overrun++;
+               tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+               msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+       }
+
+       count = msm_read(port, UARTDM_RX_TOTAL_SNAP);
+
+       port->icount.rx += count;
+
+       dma->count = 0;
+
+       dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
+
+       for (i = 0; i < count; i++) {
+               char flag = TTY_NORMAL;
+
+               if (msm_port->break_detected && dma->virt[i] == 0) {
+                       port->icount.brk++;
+                       flag = TTY_BREAK;
+                       msm_port->break_detected = false;
+                       if (uart_handle_break(port))
+                               continue;
+               }
+
+               if (!(port->read_status_mask & UART_SR_RX_BREAK))
+                       flag = TTY_NORMAL;
+
+               spin_unlock_irqrestore(&port->lock, flags);
+               sysrq = uart_handle_sysrq_char(port, dma->virt[i]);
+               spin_lock_irqsave(&port->lock, flags);
+               if (!sysrq)
+                       tty_insert_flip_char(tport, dma->virt[i], flag);
+       }
+
+       msm_start_rx_dma(msm_port);
+done:
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (count)
+               tty_flip_buffer_push(tport);
+}
+
+static void msm_start_rx_dma(struct msm_port *msm_port)
+{
+       struct msm_dma *dma = &msm_port->rx_dma;
+       struct uart_port *uart = &msm_port->uart;
+       u32 val;
+       int ret;
+
+       if (!dma->chan)
+               return;
+
+       dma->phys = dma_map_single(uart->dev, dma->virt,
+                                  UARTDM_RX_SIZE, dma->dir);
+       ret = dma_mapping_error(uart->dev, dma->phys);
+       if (ret)
+               return;
+
+       dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
+                                               UARTDM_RX_SIZE, DMA_DEV_TO_MEM,
+                                               DMA_PREP_INTERRUPT);
+       if (!dma->desc)
+               goto unmap;
+
+       dma->desc->callback = msm_complete_rx_dma;
+       dma->desc->callback_param = msm_port;
+
+       dma->cookie = dmaengine_submit(dma->desc);
+       ret = dma_submit_error(dma->cookie);
+       if (ret)
+               goto unmap;
+       /*
+        * Using DMA for FIFO off-load, no need for "Rx FIFO over
+        * watermark" or "stale" interrupts, disable them
+        */
+       msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
+
+       /*
+        * Well, when DMA is ADM3 engine(implied by <= UARTDM v1.3),
+        * we need RXSTALE to flush input DMA fifo to memory
+        */
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               msm_port->imr |= UART_IMR_RXSTALE;
+
+       msm_write(uart, msm_port->imr, UART_IMR);
+
+       dma->count = UARTDM_RX_SIZE;
+
+       dma_async_issue_pending(dma->chan);
+
+       msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+       msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+
+       val = msm_read(uart, UARTDM_DMEN);
+       val |= dma->enable_bit;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               msm_write(uart, val, UARTDM_DMEN);
+
+       msm_write(uart, UARTDM_RX_SIZE, UARTDM_DMRX);
+
+       if (msm_port->is_uartdm > UARTDM_1P3)
+               msm_write(uart, val, UARTDM_DMEN);
+
+       return;
+unmap:
+       dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
 }
 
 static void msm_stop_rx(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->rx_dma;
 
        msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
        msm_write(port, msm_port->imr, UART_IMR);
+
+       if (dma->chan)
+               msm_stop_dma(port, dma);
 }
 
 static void msm_enable_ms(struct uart_port *port)
@@ -99,7 +522,7 @@ static void msm_enable_ms(struct uart_port *port)
        msm_write(port, msm_port->imr, UART_IMR);
 }
 
-static void handle_rx_dm(struct uart_port *port, unsigned int misr)
+static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
 {
        struct tty_port *tport = &port->state->port;
        unsigned int sr;
@@ -169,9 +592,12 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
                msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
        msm_write(port, 0xFFFFFF, UARTDM_DMRX);
        msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+
+       /* Try to use DMA */
+       msm_start_rx_dma(msm_port);
 }
 
-static void handle_rx(struct uart_port *port)
+static void msm_handle_rx(struct uart_port *port)
 {
        struct tty_port *tport = &port->state->port;
        unsigned int sr;
@@ -224,18 +650,11 @@ static void handle_rx(struct uart_port *port)
        spin_lock(&port->lock);
 }
 
-static void reset_dm_count(struct uart_port *port, int count)
-{
-       wait_for_xmitr(port);
-       msm_write(port, count, UARTDM_NCF_TX);
-       msm_read(port, UARTDM_NCF_TX);
-}
-
-static void handle_tx(struct uart_port *port)
+static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
 {
        struct circ_buf *xmit = &port->state->xmit;
        struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int tx_count, num_chars;
+       unsigned int num_chars;
        unsigned int tf_pointer = 0;
        void __iomem *tf;
 
@@ -244,20 +663,8 @@ static void handle_tx(struct uart_port *port)
        else
                tf = port->membase + UART_TF;
 
-       tx_count = uart_circ_chars_pending(xmit);
-       tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail,
-                       port->fifosize);
-
-       if (port->x_char) {
-               if (msm_port->is_uartdm)
-                       reset_dm_count(port, tx_count + 1);
-
-               iowrite8_rep(tf, &port->x_char, 1);
-               port->icount.tx++;
-               port->x_char = 0;
-       } else if (tx_count && msm_port->is_uartdm) {
-               reset_dm_count(port, tx_count);
-       }
+       if (tx_count && msm_port->is_uartdm)
+               msm_reset_dm_count(port, tx_count);
 
        while (tf_pointer < tx_count) {
                int i;
@@ -290,20 +697,76 @@ static void handle_tx(struct uart_port *port)
                uart_write_wakeup(port);
 }
 
-static void handle_delta_cts(struct uart_port *port)
+static void msm_handle_tx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       struct circ_buf *xmit = &msm_port->uart.state->xmit;
+       struct msm_dma *dma = &msm_port->tx_dma;
+       unsigned int pio_count, dma_count, dma_min;
+       void __iomem *tf;
+       int err = 0;
+
+       if (port->x_char) {
+               if (msm_port->is_uartdm)
+                       tf = port->membase + UARTDM_TF;
+               else
+                       tf = port->membase + UART_TF;
+
+               if (msm_port->is_uartdm)
+                       msm_reset_dm_count(port, 1);
+
+               iowrite8_rep(tf, &port->x_char, 1);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               msm_stop_tx(port);
+               return;
+       }
+
+       pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+       dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+       dma_min = 1;    /* Always DMA */
+       if (msm_port->is_uartdm > UARTDM_1P3) {
+               dma_count = UARTDM_TX_AIGN(dma_count);
+               dma_min = UARTDM_BURST_SIZE;
+       } else {
+               if (dma_count > UARTDM_TX_MAX)
+                       dma_count = UARTDM_TX_MAX;
+       }
+
+       if (pio_count > port->fifosize)
+               pio_count = port->fifosize;
+
+       if (!dma->chan || dma_count < dma_min)
+               msm_handle_tx_pio(port, pio_count);
+       else
+               err = msm_handle_tx_dma(msm_port, dma_count);
+
+       if (err)        /* fall back to PIO mode */
+               msm_handle_tx_pio(port, pio_count);
+}
+
+static void msm_handle_delta_cts(struct uart_port *port)
 {
        msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
        port->icount.cts++;
        wake_up_interruptible(&port->state->port.delta_msr_wait);
 }
 
-static irqreturn_t msm_irq(int irq, void *dev_id)
+static irqreturn_t msm_uart_irq(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
        struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->rx_dma;
+       unsigned long flags;
        unsigned int misr;
+       u32 val;
 
-       spin_lock(&port->lock);
+       spin_lock_irqsave(&port->lock, flags);
        misr = msm_read(port, UART_MISR);
        msm_write(port, 0, UART_IMR); /* disable interrupt */
 
@@ -313,18 +776,29 @@ static irqreturn_t msm_irq(int irq, void *dev_id)
        }
 
        if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
-               if (msm_port->is_uartdm)
-                       handle_rx_dm(port, misr);
-               else
-                       handle_rx(port);
+               if (dma->count) {
+                       val = UART_CR_CMD_STALE_EVENT_DISABLE;
+                       msm_write(port, val, UART_CR);
+                       val = UART_CR_CMD_RESET_STALE_INT;
+                       msm_write(port, val, UART_CR);
+                       /*
+                        * Flush DMA input fifo to memory, this will also
+                        * trigger DMA RX completion
+                        */
+                       dmaengine_terminate_all(dma->chan);
+               } else if (msm_port->is_uartdm) {
+                       msm_handle_rx_dm(port, misr);
+               } else {
+                       msm_handle_rx(port);
+               }
        }
        if (misr & UART_IMR_TXLEV)
-               handle_tx(port);
+               msm_handle_tx(port);
        if (misr & UART_IMR_DELTA_CTS)
-               handle_delta_cts(port);
+               msm_handle_delta_cts(port);
 
        msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
-       spin_unlock(&port->lock);
+       spin_unlock_irqrestore(&port->lock, flags);
 
        return IRQ_HANDLED;
 }
@@ -408,6 +882,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud)
                {    3, 0xdd,  8 },
                {    2, 0xee, 16 },
                {    1, 0xff, 31 },
+               {    0, 0xff, 31 },
        };
 
        divisor = uart_get_divisor(port, baud);
@@ -419,21 +894,41 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud)
        return entry; /* Default to smallest divider */
 }
 
-static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
+                            unsigned long *saved_flags)
 {
-       unsigned int rxstale, watermark;
+       unsigned int rxstale, watermark, mask;
        struct msm_port *msm_port = UART_TO_MSM(port);
        const struct msm_baud_map *entry;
+       unsigned long flags;
 
        entry = msm_find_best_baud(port, baud);
 
        msm_write(port, entry->code, UART_CSR);
 
+       if (baud > 460800)
+               port->uartclk = baud * 16;
+
+       flags = *saved_flags;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       clk_set_rate(msm_port->clk, port->uartclk);
+
+       spin_lock_irqsave(&port->lock, flags);
+       *saved_flags = flags;
+
        /* RX stale watermark */
        rxstale = entry->rxstale;
        watermark = UART_IPR_STALE_LSB & rxstale;
-       watermark |= UART_IPR_RXSTALE_LAST;
-       watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
+       if (msm_port->is_uartdm) {
+               mask = UART_DM_IPR_STALE_TIMEOUT_MSB;
+       } else {
+               watermark |= UART_IPR_RXSTALE_LAST;
+               mask = UART_IPR_STALE_TIMEOUT_MSB;
+       }
+
+       watermark |= mask & (rxstale << 2);
+
        msm_write(port, watermark, UART_IPR);
 
        /* set RX watermark */
@@ -476,13 +971,13 @@ static void msm_init_clock(struct uart_port *port)
 static int msm_startup(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int data, rfr_level;
+       unsigned int data, rfr_level, mask;
        int ret;
 
        snprintf(msm_port->name, sizeof(msm_port->name),
                 "msm_serial%d", port->line);
 
-       ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
+       ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
                          msm_port->name, port);
        if (unlikely(ret))
                return ret;
@@ -496,11 +991,23 @@ static int msm_startup(struct uart_port *port)
 
        /* set automatic RFR level */
        data = msm_read(port, UART_MR1);
-       data &= ~UART_MR1_AUTO_RFR_LEVEL1;
+
+       if (msm_port->is_uartdm)
+               mask = UART_DM_MR1_AUTO_RFR_LEVEL1;
+       else
+               mask = UART_MR1_AUTO_RFR_LEVEL1;
+
+       data &= ~mask;
        data &= ~UART_MR1_AUTO_RFR_LEVEL0;
-       data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
+       data |= mask & (rfr_level << 2);
        data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
        msm_write(port, data, UART_MR1);
+
+       if (msm_port->is_uartdm) {
+               msm_request_tx_dma(msm_port, msm_port->uart.mapbase);
+               msm_request_rx_dma(msm_port, msm_port->uart.mapbase);
+       }
+
        return 0;
 }
 
@@ -511,6 +1018,9 @@ static void msm_shutdown(struct uart_port *port)
        msm_port->imr = 0;
        msm_write(port, 0, UART_IMR); /* disable interrupts */
 
+       if (msm_port->is_uartdm)
+               msm_release_dma(msm_port);
+
        clk_disable_unprepare(msm_port->clk);
 
        free_irq(port->irq, port);
@@ -519,14 +1029,19 @@ static void msm_shutdown(struct uart_port *port)
 static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->rx_dma;
        unsigned long flags;
        unsigned int baud, mr;
 
        spin_lock_irqsave(&port->lock, flags);
 
+       if (dma->chan) /* Terminate if any */
+               msm_stop_dma(port, dma);
+
        /* calculate and set baud rate */
-       baud = uart_get_baud_rate(port, termios, old, 300, 115200);
-       baud = msm_set_baud_rate(port, baud);
+       baud = uart_get_baud_rate(port, termios, old, 300, 4000000);
+       baud = msm_set_baud_rate(port, baud, &flags);
        if (tty_termios_baud_rate(termios))
                tty_termios_encode_baud_rate(termios, baud, baud);
 
@@ -588,6 +1103,9 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
 
        uart_update_timeout(port, termios->c_cflag, baud);
 
+       /* Try to use DMA */
+       msm_start_rx_dma(msm_port);
+
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
@@ -765,7 +1283,7 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c)
        msm_write(port, 0, UART_IMR);
 
        if (msm_port->is_uartdm)
-               reset_dm_count(port, 1);
+               msm_reset_dm_count(port, 1);
 
        /* Wait until FIFO is empty */
        while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
@@ -839,7 +1357,7 @@ static struct msm_port msm_uart_ports[] = {
 
 #define UART_NR        ARRAY_SIZE(msm_uart_ports)
 
-static inline struct uart_port *get_port_from_line(unsigned int line)
+static inline struct uart_port *msm_get_port_from_line(unsigned int line)
 {
        return &msm_uart_ports[line].uart;
 }
@@ -866,7 +1384,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
 
        spin_lock(&port->lock);
        if (is_uartdm)
-               reset_dm_count(port, count);
+               msm_reset_dm_count(port, count);
 
        i = 0;
        while (i < count) {
@@ -911,7 +1429,7 @@ static void msm_console_write(struct console *co, const char *s,
 
        BUG_ON(co->index < 0 || co->index >= UART_NR);
 
-       port = get_port_from_line(co->index);
+       port = msm_get_port_from_line(co->index);
        msm_port = UART_TO_MSM(port);
 
        __msm_console_write(port, s, count, msm_port->is_uartdm);
@@ -928,7 +1446,7 @@ static int __init msm_console_setup(struct console *co, char *options)
        if (unlikely(co->index >= UART_NR || co->index < 0))
                return -ENXIO;
 
-       port = get_port_from_line(co->index);
+       port = msm_get_port_from_line(co->index);
 
        if (unlikely(!port->membase))
                return -ENXIO;
@@ -1043,7 +1561,7 @@ static int msm_serial_probe(struct platform_device *pdev)
 
        dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line);
 
-       port = get_port_from_line(line);
+       port = msm_get_port_from_line(line);
        port->dev = &pdev->dev;
        msm_port = UART_TO_MSM(port);
 
index 737f69fe7113a93410652cd84030a08bc6697335..178645826f1696bb0537f525443b022ae35cff12 100644 (file)
 
 #define UART_MR1_AUTO_RFR_LEVEL0       0x3F
 #define UART_MR1_AUTO_RFR_LEVEL1       0x3FF00
-#define UART_MR1_RX_RDY_CTL                    (1 << 7)
-#define UART_MR1_CTS_CTL                       (1 << 6)
+#define UART_DM_MR1_AUTO_RFR_LEVEL1    0xFFFFFF00
+#define UART_MR1_RX_RDY_CTL            BIT(7)
+#define UART_MR1_CTS_CTL               BIT(6)
 
 #define UART_MR2                       0x0004
-#define UART_MR2_ERROR_MODE            (1 << 6)
+#define UART_MR2_ERROR_MODE            BIT(6)
 #define UART_MR2_BITS_PER_CHAR         0x30
 #define UART_MR2_BITS_PER_CHAR_5       (0x0 << 4)
 #define UART_MR2_BITS_PER_CHAR_6       (0x1 << 4)
 #define UART_CR_CMD_SET_RFR            (13 << 4)
 #define UART_CR_CMD_RESET_RFR          (14 << 4)
 #define UART_CR_CMD_PROTECTION_EN      (16 << 4)
+#define UART_CR_CMD_STALE_EVENT_DISABLE        (6 << 8)
 #define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
 #define UART_CR_CMD_FORCE_STALE                (4 << 8)
 #define UART_CR_CMD_RESET_TX_READY     (3 << 8)
-#define UART_CR_TX_DISABLE             (1 << 3)
-#define UART_CR_TX_ENABLE              (1 << 2)
-#define UART_CR_RX_DISABLE             (1 << 1)
-#define UART_CR_RX_ENABLE              (1 << 0)
+#define UART_CR_TX_DISABLE             BIT(3)
+#define UART_CR_TX_ENABLE              BIT(2)
+#define UART_CR_RX_DISABLE             BIT(1)
+#define UART_CR_RX_ENABLE              BIT(0)
 #define UART_CR_CMD_RESET_RXBREAK_START        ((1 << 11) | (2 << 4))
 
 #define UART_IMR               0x0014
-#define UART_IMR_TXLEV         (1 << 0)
-#define UART_IMR_RXSTALE       (1 << 3)
-#define UART_IMR_RXLEV         (1 << 4)
-#define UART_IMR_DELTA_CTS     (1 << 5)
-#define UART_IMR_CURRENT_CTS   (1 << 6)
-#define UART_IMR_RXBREAK_START (1 << 10)
+#define UART_IMR_TXLEV                 BIT(0)
+#define UART_IMR_RXSTALE               BIT(3)
+#define UART_IMR_RXLEV                 BIT(4)
+#define UART_IMR_DELTA_CTS             BIT(5)
+#define UART_IMR_CURRENT_CTS           BIT(6)
+#define UART_IMR_RXBREAK_START         BIT(10)
 
 #define UART_IPR_RXSTALE_LAST          0x20
 #define UART_IPR_STALE_LSB             0x1F
 #define UART_IPR_STALE_TIMEOUT_MSB     0x3FF80
+#define UART_DM_IPR_STALE_TIMEOUT_MSB  0xFFFFFF80
 
 #define UART_IPR       0x0018
 #define UART_TFWR      0x001C
 #define UART_TEST_CTRL         0x0050
 
 #define UART_SR                        0x0008
-#define UART_SR_HUNT_CHAR      (1 << 7)
-#define UART_SR_RX_BREAK       (1 << 6)
-#define UART_SR_PAR_FRAME_ERR  (1 << 5)
-#define UART_SR_OVERRUN                (1 << 4)
-#define UART_SR_TX_EMPTY       (1 << 3)
-#define UART_SR_TX_READY       (1 << 2)
-#define UART_SR_RX_FULL                (1 << 1)
-#define UART_SR_RX_READY       (1 << 0)
+#define UART_SR_HUNT_CHAR      BIT(7)
+#define UART_SR_RX_BREAK       BIT(6)
+#define UART_SR_PAR_FRAME_ERR  BIT(5)
+#define UART_SR_OVERRUN                BIT(4)
+#define UART_SR_TX_EMPTY       BIT(3)
+#define UART_SR_TX_READY       BIT(2)
+#define UART_SR_RX_FULL                BIT(1)
+#define UART_SR_RX_READY       BIT(0)
 
 #define UART_RF                        0x000C
 #define UARTDM_RF              0x0070
 #define UART_MISR              0x0010
 #define UART_ISR               0x0014
-#define UART_ISR_TX_READY      (1 << 7)
+#define UART_ISR_TX_READY      BIT(7)
 
 #define UARTDM_RXFS            0x50
 #define UARTDM_RXFS_BUF_SHIFT  0x7
 #define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
 #define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
 
+#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2)       /* UARTDM_1P4 */
+#define UARTDM_DMEN_TX_DM_ENABLE  BIT(0)       /* < UARTDM_1P4 */
+
+#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3)       /* UARTDM_1P4 */
+#define UARTDM_DMEN_RX_DM_ENABLE  BIT(1)       /* < UARTDM_1P4 */
+
 #define UARTDM_DMRX            0x34
 #define UARTDM_NCF_TX          0x40
 #define UARTDM_RX_TOTAL_SNAP   0x38
index dd26511ad8754fa171114c96c18fdd01e4e66d73..8a4be4b73723381a6bcba7b89cb1137ed3b5ac96 100644 (file)
@@ -412,19 +412,14 @@ static int mux_console_setup(struct console *co, char *options)
         return 0;
 }
 
-struct tty_driver *mux_console_device(struct console *co, int *index)
-{
-        *index = co->index;
-       return mux_driver.tty_driver;
-}
-
 static struct console mux_console = {
        .name =         "ttyB",
        .write =        mux_console_write,
-       .device =       mux_console_device,
+       .device =       uart_console_device,
        .setup =        mux_console_setup,
        .flags =        CON_ENABLED | CON_PRINTBUFFER,
        .index =        0,
+       .data =         &mux_driver,
 };
 
 #define MUX_CONSOLE    &mux_console
index 7c7f30809849d24d337f8f2eedf4a83ed23907f1..cd0414bbe094898ed3fdeca0a941549312472581 100644 (file)
@@ -1196,7 +1196,7 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
        enum mctrl_gpio_idx i;
        struct gpio_desc *gpiod;
 
-       s->gpios = mctrl_gpio_init(dev, 0);
+       s->gpios = mctrl_gpio_init_noauto(dev, 0);
        if (IS_ERR(s->gpios))
                return PTR_ERR(s->gpios);
 
index 6823df99bd7685db295b94599e6bd1b7f7a78057..e08df9775983a053b9c7f58eb17c6910a391d166 100644 (file)
 #include <linux/nwpserial.h>
 #include <linux/clk.h>
 
+#ifdef CONFIG_SERIAL_8250_MODULE
+#define CONFIG_SERIAL_8250 CONFIG_SERIAL_8250_MODULE
+#endif
+
 #include "8250/8250.h"
 
 struct of_serial_info {
@@ -350,6 +354,7 @@ static const struct of_device_id of_platform_serial_table[] = {
 #endif
        { /* end of list */ },
 };
+MODULE_DEVICE_TABLE(of, of_platform_serial_table);
 
 static struct platform_driver of_platform_serial_driver = {
        .driver = {
index 7a2172b5e93cd296674c9b78a5fd31594db0f492..9d4c84f7485f6412231fdad9703202cfae0a4393 100644 (file)
@@ -199,6 +199,7 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
        serial_out(up, UART_FCR, 0);
 }
 
+#ifdef CONFIG_PM
 static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
 {
        struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
@@ -219,6 +220,7 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
 
        pdata->enable_wakeup(up->dev, enable);
 }
+#endif /* CONFIG_PM */
 
 /*
  * Calculate the absolute difference between the desired and actual baud
index 856686d6dcdbc61adbadc5ae6c0d86dbdf2c18d9..d72cd736bdc6ec9d28277616ca6231885089dc56 100644 (file)
@@ -385,32 +385,6 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
        }
 }
 
-static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
-                                    unsigned long ufstat);
-
-static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       struct tty_port *tty = &port->state->port;
-       unsigned int ch, ufstat;
-       unsigned int count;
-
-       ufstat = rd_regl(port, S3C2410_UFSTAT);
-       count = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
-
-       if (!count)
-               return;
-
-       while (count-- > 0) {
-               ch = rd_regb(port, S3C2410_URXH);
-
-               ourport->port.icount.rx++;
-               tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       }
-
-       tty_flip_buffer_push(tty);
-}
-
 static void s3c24xx_serial_stop_rx(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -573,7 +547,9 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
        ourport->rx_mode = S3C24XX_RX_PIO;
 }
 
-static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
+
+static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
 {
        unsigned int utrstat, ufstat, received;
        struct s3c24xx_uart_port *ourport = dev_id;
@@ -606,7 +582,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
                enable_rx_pio(ourport);
        }
 
-       uart_rx_drain_fifo(ourport);
+       s3c24xx_serial_rx_drain_fifo(ourport);
 
        if (tty) {
                tty_flip_buffer_push(t);
@@ -621,16 +597,12 @@ finish:
        return IRQ_HANDLED;
 }
 
-static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
 {
-       struct s3c24xx_uart_port *ourport = dev_id;
        struct uart_port *port = &ourport->port;
        unsigned int ufcon, ch, flag, ufstat, uerstat;
-       unsigned long flags;
        int max_count = port->fifosize;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        while (max_count-- > 0) {
                ufcon = rd_regl(port, S3C2410_UFCON);
                ufstat = rd_regl(port, S3C2410_UFSTAT);
@@ -654,9 +626,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                                        ufcon |= S3C2410_UFCON_RESETRX;
                                        wr_regl(port, S3C2410_UFCON, ufcon);
                                        rx_enabled(port) = 1;
-                                       spin_unlock_irqrestore(&port->lock,
-                                                       flags);
-                                       goto out;
+                                       return;
                                }
                                continue;
                        }
@@ -676,7 +646,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                                dbg("break!\n");
                                port->icount.brk++;
                                if (uart_handle_break(port))
-                                       goto ignore_char;
+                                       continue; /* Ignore character */
                        }
 
                        if (uerstat & S3C2410_UERSTAT_FRAME)
@@ -696,19 +666,25 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                }
 
                if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
+                       continue; /* Ignore character */
 
                uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
                                 ch, flag);
-
-ignore_char:
-               continue;
        }
 
-       spin_unlock_irqrestore(&port->lock, flags);
        tty_flip_buffer_push(&port->state->port);
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       s3c24xx_serial_rx_drain_fifo(ourport);
+       spin_unlock_irqrestore(&port->lock, flags);
 
-out:
        return IRQ_HANDLED;
 }
 
@@ -718,8 +694,8 @@ static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
        struct s3c24xx_uart_port *ourport = dev_id;
 
        if (ourport->dma && ourport->dma->rx_chan)
-               return s3c24xx_serial_rx_chars_dma(irq, dev_id);
-       return s3c24xx_serial_rx_chars_pio(irq, dev_id);
+               return s3c24xx_serial_rx_chars_dma(dev_id);
+       return s3c24xx_serial_rx_chars_pio(dev_id);
 }
 
 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
index 72ffd0dcab78459106abd44dc8da667c180c01b1..1ae8aa698fcbd6dc80ebfae05a0a3ae0b1c6e5eb 100644 (file)
@@ -1321,6 +1321,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi)
                const struct of_device_id *of_id =
                        of_match_device(sc16is7xx_dt_ids, &spi->dev);
 
+               if (!of_id)
+                       return -ENODEV;
+
                devtype = (struct sc16is7xx_devtype *)of_id->data;
        } else {
                const struct spi_device_id *id_entry = spi_get_device_id(spi);
@@ -1380,6 +1383,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
                const struct of_device_id *of_id =
                                of_match_device(sc16is7xx_dt_ids, &i2c->dev);
 
+               if (!of_id)
+                       return -ENODEV;
+
                devtype = (struct sc16is7xx_devtype *)of_id->data;
        } else {
                devtype = (struct sc16is7xx_devtype *)id->driver_data;
@@ -1420,7 +1426,6 @@ static struct i2c_driver sc16is7xx_i2c_uart_driver = {
        .id_table       = sc16is7xx_i2c_id_table,
 };
 
-MODULE_ALIAS("i2c:sc16is7xx");
 #endif
 
 static int __init sc16is7xx_init(void)
index 603d2cc3f424f691c53f2ccb7c91efd4cf8ae9a5..df4271ae7414267223f293f168646b0003833920 100644 (file)
@@ -1819,8 +1819,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
  *     @options: ptr for <options> field; NULL if not present (out)
  *
  *     Decodes earlycon kernel command line parameters of the form
- *        earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
- *        console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
+ *        earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
+ *        console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
  *
  *     The optional form
  *        earlycon=<name>,0x<addr>,<options>
@@ -1841,6 +1841,10 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
        } else if (strncmp(p, "mmio32be,", 9) == 0) {
                *iotype = UPIO_MEM32BE;
                p += 9;
+       } else if (strncmp(p, "mmio32native,", 13) == 0) {
+               *iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
+                       UPIO_MEM32BE : UPIO_MEM32;
+               p += 13;
        } else if (strncmp(p, "io,", 3) == 0) {
                *iotype = UPIO_PORT;
                p += 3;
index 402f7fb541333a67a0383a4ac2fb3754ed2f395d..3eb57eb532f18a6af5fc169b044699a453e59975 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/irq.h>
 #include <linux/gpio/consumer.h>
 #include <linux/termios.h>
+#include <linux/serial_core.h>
 
 #include "serial_mctrl_gpio.h"
 
 struct mctrl_gpios {
+       struct uart_port *port;
        struct gpio_desc *gpio[UART_GPIO_MAX];
+       int irq[UART_GPIO_MAX];
+       unsigned int mctrl_prev;
+       bool mctrl_on;
 };
 
 static const struct {
@@ -82,7 +87,7 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_get);
 
-struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
 {
        struct mctrl_gpios *gpios;
        enum mctrl_gpio_idx i;
@@ -110,15 +115,135 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
 
        return gpios;
 }
-EXPORT_SYMBOL_GPL(mctrl_gpio_init);
+EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
+
+#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
+static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
+{
+       struct mctrl_gpios *gpios = context;
+       struct uart_port *port = gpios->port;
+       u32 mctrl = gpios->mctrl_prev;
+       u32 mctrl_diff;
+
+       mctrl_gpio_get(gpios, &mctrl);
+
+       mctrl_diff = mctrl ^ gpios->mctrl_prev;
+       gpios->mctrl_prev = mctrl;
+
+       if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
+               if ((mctrl_diff & mctrl) & TIOCM_RI)
+                       port->icount.rng++;
+
+               if ((mctrl_diff & mctrl) & TIOCM_DSR)
+                       port->icount.dsr++;
+
+               if (mctrl_diff & TIOCM_CD)
+                       uart_handle_dcd_change(port, mctrl & TIOCM_CD);
+
+               if (mctrl_diff & TIOCM_CTS)
+                       uart_handle_cts_change(port, mctrl & TIOCM_CTS);
+
+               wake_up_interruptible(&port->state->port.delta_msr_wait);
+       }
+
+       return IRQ_HANDLED;
+}
+
+struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
+{
+       struct mctrl_gpios *gpios;
+       enum mctrl_gpio_idx i;
+
+       gpios = mctrl_gpio_init_noauto(port->dev, idx);
+       if (IS_ERR(gpios))
+               return gpios;
+
+       gpios->port = port;
+
+       for (i = 0; i < UART_GPIO_MAX; ++i) {
+               int ret;
+
+               if (!gpios->gpio[i] || mctrl_gpios_desc[i].dir_out)
+                       continue;
+
+               ret = gpiod_to_irq(gpios->gpio[i]);
+               if (ret <= 0) {
+                       dev_err(port->dev,
+                               "failed to find corresponding irq for %s (idx=%d, err=%d)\n",
+                               mctrl_gpios_desc[i].name, idx, ret);
+                       return ERR_PTR(ret);
+               }
+               gpios->irq[i] = ret;
+
+               /* irqs should only be enabled in .enable_ms */
+               irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
+
+               ret = devm_request_irq(port->dev, gpios->irq[i],
+                                      mctrl_gpio_irq_handle,
+                                      IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
+                                      gpios);
+               if (ret) {
+                       /* alternatively implement polling */
+                       dev_err(port->dev,
+                               "failed to request irq for %s (idx=%d, err=%d)\n",
+                               mctrl_gpios_desc[i].name, idx, ret);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       return gpios;
+}
 
 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
 {
        enum mctrl_gpio_idx i;
 
-       for (i = 0; i < UART_GPIO_MAX; i++)
+       for (i = 0; i < UART_GPIO_MAX; i++) {
+               if (gpios->irq[i])
+                       devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
+
                if (gpios->gpio[i])
                        devm_gpiod_put(dev, gpios->gpio[i]);
+       }
        devm_kfree(dev, gpios);
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_free);
+
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+{
+       enum mctrl_gpio_idx i;
+
+       /* .enable_ms may be called multiple times */
+       if (gpios->mctrl_on)
+               return;
+
+       gpios->mctrl_on = true;
+
+       /* get initial status of modem lines GPIOs */
+       mctrl_gpio_get(gpios, &gpios->mctrl_prev);
+
+       for (i = 0; i < UART_GPIO_MAX; ++i) {
+               if (!gpios->irq[i])
+                       continue;
+
+               enable_irq(gpios->irq[i]);
+       }
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
+
+void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+{
+       enum mctrl_gpio_idx i;
+
+       if (!gpios->mctrl_on)
+               return;
+
+       gpios->mctrl_on = false;
+
+       for (i = 0; i < UART_GPIO_MAX; ++i) {
+               if (!gpios->irq[i])
+                       continue;
+
+               disable_irq(gpios->irq[i]);
+       }
+}
index 400ba0494a1798ed4304c5b07da2b68e03234a4a..3c4ac9ae41f92914d4cce0e398b06e94e9d02a93 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
 
+struct uart_port;
+
 enum mctrl_gpio_idx {
        UART_GPIO_CTS,
        UART_GPIO_DSR,
@@ -59,13 +61,23 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
                                      enum mctrl_gpio_idx gidx);
 
+/*
+ * Request and set direction of modem control lines GPIOs and sets up irq
+ * handling.
+ * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
+ * allocation error.
+ */
+struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx);
+
 /*
  * Request and set direction of modem control lines GPIOs.
  * devm_* functions are used, so there's no need to call mctrl_gpio_free().
  * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
  * allocation error.
  */
-struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
+struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
+                                          unsigned int idx);
 
 /*
  * Free the mctrl_gpios structure.
@@ -74,6 +86,16 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
  */
 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
 
+/*
+ * Enable gpio interrupts to report status line changes.
+ */
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
+
+/*
+ * Disable gpio interrupts to report status line changes.
+ */
+void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
+
 #else /* GPIOLIB */
 
 static inline
@@ -95,7 +117,13 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
 }
 
 static inline
-struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static inline
+struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
 {
        return ERR_PTR(-ENOSYS);
 }
@@ -105,6 +133,14 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
 {
 }
 
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+{
+}
+
+void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+{
+}
+
 #endif /* GPIOLIB */
 
 #endif
index 1b2f894bdc9e0e6ed15cf93feb405337b1d0d07b..960e50a97558cff52a1fb9eb8ed8879a5238991c 100644 (file)
@@ -84,6 +84,7 @@ struct sci_port {
        unsigned int            overrun_reg;
        unsigned int            overrun_mask;
        unsigned int            error_mask;
+       unsigned int            error_clear;
        unsigned int            sampling_rate;
        resource_size_t         reg_size;
 
@@ -103,19 +104,15 @@ struct sci_port {
        struct dma_chan                 *chan_rx;
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct dma_async_tx_descriptor  *desc_tx;
-       struct dma_async_tx_descriptor  *desc_rx[2];
        dma_cookie_t                    cookie_tx;
        dma_cookie_t                    cookie_rx[2];
        dma_cookie_t                    active_rx;
-       struct scatterlist              sg_tx;
-       unsigned int                    sg_len_tx;
+       dma_addr_t                      tx_dma_addr;
+       unsigned int                    tx_dma_len;
        struct scatterlist              sg_rx[2];
+       void                            *rx_buf[2];
        size_t                          buf_len_rx;
-       struct sh_dmae_slave            param_tx;
-       struct sh_dmae_slave            param_rx;
        struct work_struct              work_tx;
-       struct work_struct              work_rx;
        struct timer_list               rx_timer;
        unsigned int                    rx_timeout;
 #endif
@@ -123,11 +120,6 @@ struct sci_port {
        struct notifier_block           freq_transition;
 };
 
-/* Function prototypes */
-static void sci_start_tx(struct uart_port *port);
-static void sci_stop_tx(struct uart_port *port);
-static void sci_start_rx(struct uart_port *port);
-
 #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
 
 static struct sci_port sci_ports[SCI_NPORTS];
@@ -146,7 +138,7 @@ struct plat_sci_reg {
 /* Helper for invalidating specific entries of an inherited map. */
 #define sci_reg_invalid        { .offset = 0, .size = 0 }
 
-static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
+static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
        [SCIx_PROBE_REGTYPE] = {
                [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid,
        },
@@ -399,7 +391,7 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
  */
 static unsigned int sci_serial_in(struct uart_port *p, int offset)
 {
-       struct plat_sci_reg *reg = sci_getreg(p, offset);
+       const struct plat_sci_reg *reg = sci_getreg(p, offset);
 
        if (reg->size == 8)
                return ioread8(p->membase + (reg->offset << p->regshift));
@@ -413,7 +405,7 @@ static unsigned int sci_serial_in(struct uart_port *p, int offset)
 
 static void sci_serial_out(struct uart_port *p, int offset, int value)
 {
-       struct plat_sci_reg *reg = sci_getreg(p, offset);
+       const struct plat_sci_reg *reg = sci_getreg(p, offset);
 
        if (reg->size == 8)
                iowrite8(value, p->membase + (reg->offset << p->regshift));
@@ -489,6 +481,105 @@ static void sci_port_disable(struct sci_port *sci_port)
        pm_runtime_put_sync(sci_port->port.dev);
 }
 
+static inline unsigned long port_rx_irq_mask(struct uart_port *port)
+{
+       /*
+        * Not all ports (such as SCIFA) will support REIE. Rather than
+        * special-casing the port type, we check the port initialization
+        * IRQ enable mask to see whether the IRQ is desired at all. If
+        * it's unset, it's logically inferred that there's no point in
+        * testing for it.
+        */
+       return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE);
+}
+
+static void sci_start_tx(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+       unsigned short ctrl;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 new, scr = serial_port_in(port, SCSCR);
+               if (s->chan_tx)
+                       new = scr | SCSCR_TDRQE;
+               else
+                       new = scr & ~SCSCR_TDRQE;
+               if (new != scr)
+                       serial_port_out(port, SCSCR, new);
+       }
+
+       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+           dma_submit_error(s->cookie_tx)) {
+               s->cookie_tx = 0;
+               schedule_work(&s->work_tx);
+       }
+#endif
+
+       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+               ctrl = serial_port_in(port, SCSCR);
+               serial_port_out(port, SCSCR, ctrl | SCSCR_TIE);
+       }
+}
+
+static void sci_stop_tx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+       ctrl = serial_port_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~SCSCR_TDRQE;
+
+       ctrl &= ~SCSCR_TIE;
+
+       serial_port_out(port, SCSCR, ctrl);
+}
+
+static void sci_start_rx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~SCSCR_RDRQE;
+
+       serial_port_out(port, SCSCR, ctrl);
+}
+
+static void sci_stop_rx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       ctrl = serial_port_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~SCSCR_RDRQE;
+
+       ctrl &= ~port_rx_irq_mask(port);
+
+       serial_port_out(port, SCSCR, ctrl);
+}
+
+static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
+{
+       if (port->type == PORT_SCI) {
+               /* Just store the mask */
+               serial_port_out(port, SCxSR, mask);
+       } else if (to_sci_port(port)->overrun_mask == SCIFA_ORER) {
+               /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */
+               /* Only clear the status bits we want to clear */
+               serial_port_out(port, SCxSR,
+                               serial_port_in(port, SCxSR) & mask);
+       } else {
+               /* Store the mask, clear parity/framing errors */
+               serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
+       }
+}
+
 #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
 
 #ifdef CONFIG_CONSOLE_POLL
@@ -500,7 +591,7 @@ static int sci_poll_get_char(struct uart_port *port)
        do {
                status = serial_port_in(port, SCxSR);
                if (status & SCxSR_ERRORS(port)) {
-                       serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+                       sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
                        continue;
                }
                break;
@@ -513,7 +604,7 @@ static int sci_poll_get_char(struct uart_port *port)
 
        /* Dummy read */
        serial_port_in(port, SCxSR);
-       serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+       sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
 
        return c;
 }
@@ -528,14 +619,14 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
        } while (!(status & SCxSR_TDxE(port)));
 
        serial_port_out(port, SCxTDR, c);
-       serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+       sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
 }
 #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
 
 static void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+       const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
 
        /*
         * Use port-specific handler if provided.
@@ -565,7 +656,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
 
 static int sci_txfill(struct uart_port *port)
 {
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
 
        reg = sci_getreg(port, SCTFDR);
        if (reg->size)
@@ -585,7 +676,7 @@ static int sci_txroom(struct uart_port *port)
 
 static int sci_rxfill(struct uart_port *port)
 {
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
 
        reg = sci_getreg(port, SCRFDR);
        if (reg->size)
@@ -655,7 +746,7 @@ static void sci_transmit_chars(struct uart_port *port)
                port->icount.tx++;
        } while (--count > 0);
 
-       serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+       sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
@@ -666,7 +757,7 @@ static void sci_transmit_chars(struct uart_port *port)
 
                if (port->type != PORT_SCI) {
                        serial_port_in(port, SCxSR); /* Dummy read */
-                       serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+                       sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
                }
 
                ctrl |= SCSCR_TIE;
@@ -750,7 +841,7 @@ static void sci_receive_chars(struct uart_port *port)
                }
 
                serial_port_in(port, SCxSR); /* dummy read */
-               serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
 
                copied += count;
                port->icount.rx += count;
@@ -761,7 +852,7 @@ static void sci_receive_chars(struct uart_port *port)
                tty_flip_buffer_push(tport);
        } else {
                serial_port_in(port, SCxSR); /* dummy read */
-               serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
        }
 }
 
@@ -866,7 +957,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
 {
        struct tty_port *tport = &port->state->port;
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
        int copied = 0;
        u16 status;
 
@@ -924,686 +1015,783 @@ static int sci_handle_breaks(struct uart_port *port)
        return copied;
 }
 
-static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
-{
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
+static void sci_dma_tx_complete(void *arg)
+{
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long flags;
 
-       if (s->chan_rx) {
-               u16 scr = serial_port_in(port, SCSCR);
-               u16 ssr = serial_port_in(port, SCxSR);
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
-               /* Disable future Rx interrupts */
-               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-                       disable_irq_nosync(irq);
-                       scr |= SCSCR_RDRQE;
-               } else {
-                       scr &= ~SCSCR_RIE;
-               }
-               serial_port_out(port, SCSCR, scr);
-               /* Clear current interrupt */
-               serial_port_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
-               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
-                       jiffies, s->rx_timeout);
-               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+       spin_lock_irqsave(&port->lock, flags);
 
-               return IRQ_HANDLED;
-       }
-#endif
+       xmit->tail += s->tx_dma_len;
+       xmit->tail &= UART_XMIT_SIZE - 1;
 
-       /* I think sci_receive_chars has to be called irrespective
-        * of whether the I_IXOFF is set, otherwise, how is the interrupt
-        * to be disabled?
-        */
-       sci_receive_chars(ptr);
+       port->icount.tx += s->tx_dma_len;
 
-       return IRQ_HANDLED;
-}
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
 
-static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-       unsigned long flags;
+       if (!uart_circ_empty(xmit)) {
+               s->cookie_tx = 0;
+               schedule_work(&s->work_tx);
+       } else {
+               s->cookie_tx = -EINVAL;
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+                       u16 ctrl = serial_port_in(port, SCSCR);
+                       serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+               }
+       }
 
-       spin_lock_irqsave(&port->lock, flags);
-       sci_transmit_chars(port);
        spin_unlock_irqrestore(&port->lock, flags);
-
-       return IRQ_HANDLED;
 }
 
-static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+/* Locking: called with port lock held */
+static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count)
 {
-       struct uart_port *port = ptr;
+       struct uart_port *port = &s->port;
+       struct tty_port *tport = &port->state->port;
+       int copied;
 
-       /* Handle errors */
-       if (port->type == PORT_SCI) {
-               if (sci_handle_errors(port)) {
-                       /* discard character in rx buffer */
-                       serial_port_in(port, SCxSR);
-                       serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-               }
-       } else {
-               sci_handle_fifo_overrun(port);
-               sci_rx_interrupt(irq, ptr);
+       copied = tty_insert_flip_string(tport, buf, count);
+       if (copied < count) {
+               dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",
+                        count - copied);
+               port->icount.buf_overrun++;
        }
 
-       serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-
-       /* Kick the transmission */
-       sci_tx_interrupt(irq, ptr);
+       port->icount.rx += copied;
 
-       return IRQ_HANDLED;
+       return copied;
 }
 
-static irqreturn_t sci_br_interrupt(int irq, void *ptr)
+static int sci_dma_rx_find_active(struct sci_port *s)
 {
-       struct uart_port *port = ptr;
+       unsigned int i;
 
-       /* Handle BREAKs */
-       sci_handle_breaks(port);
-       serial_port_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+       for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++)
+               if (s->active_rx == s->cookie_rx[i])
+                       return i;
 
-       return IRQ_HANDLED;
+       dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__,
+               s->active_rx);
+       return -1;
 }
 
-static inline unsigned long port_rx_irq_mask(struct uart_port *port)
+static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
 {
-       /*
-        * Not all ports (such as SCIFA) will support REIE. Rather than
-        * special-casing the port type, we check the port initialization
-        * IRQ enable mask to see whether the IRQ is desired at all. If
-        * it's unset, it's logically inferred that there's no point in
-        * testing for it.
-        */
-       return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE);
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       s->chan_rx = NULL;
+       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       dmaengine_terminate_all(chan);
+       dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
+                         sg_dma_address(&s->sg_rx[0]));
+       dma_release_channel(chan);
+       if (enable_pio)
+               sci_start_rx(port);
 }
 
-static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
+static void sci_dma_rx_complete(void *arg)
 {
-       unsigned short ssr_status, scr_status, err_enabled, orer_status = 0;
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
-       irqreturn_t ret = IRQ_NONE;
+       struct sci_port *s = arg;
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+       struct dma_async_tx_descriptor *desc;
+       unsigned long flags;
+       int active, count = 0;
 
-       ssr_status = serial_port_in(port, SCxSR);
-       scr_status = serial_port_in(port, SCSCR);
-       if (s->overrun_reg == SCxSR)
-               orer_status = ssr_status;
-       else {
-               if (sci_getreg(port, s->overrun_reg)->size)
-                       orer_status = serial_port_in(port, s->overrun_reg);
-       }
+       dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
+               s->active_rx);
 
-       err_enabled = scr_status & port_rx_irq_mask(port);
+       spin_lock_irqsave(&port->lock, flags);
 
-       /* Tx Interrupt */
-       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
-           !s->chan_tx)
-               ret = sci_tx_interrupt(irq, ptr);
+       active = sci_dma_rx_find_active(s);
+       if (active >= 0)
+               count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx);
 
-       /*
-        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
-        * DR flags
-        */
-       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
-           (scr_status & SCSCR_RIE)) {
-               if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
-                       sci_handle_fifo_overrun(port);
-               ret = sci_rx_interrupt(irq, ptr);
-       }
+       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
 
-       /* Error Interrupt */
-       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
-               ret = sci_er_interrupt(irq, ptr);
+       if (count)
+               tty_flip_buffer_push(&port->state->port);
 
-       /* Break Interrupt */
-       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
-               ret = sci_br_interrupt(irq, ptr);
+       desc = dmaengine_prep_slave_sg(s->chan_rx, &s->sg_rx[active], 1,
+                                      DMA_DEV_TO_MEM,
+                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc)
+               goto fail;
 
-       /* Overrun Interrupt */
-       if (orer_status & s->overrun_mask)
-               sci_handle_fifo_overrun(port);
+       desc->callback = sci_dma_rx_complete;
+       desc->callback_param = s;
+       s->cookie_rx[active] = dmaengine_submit(desc);
+       if (dma_submit_error(s->cookie_rx[active]))
+               goto fail;
 
-       return ret;
+       s->active_rx = s->cookie_rx[!active];
+
+       dma_async_issue_pending(chan);
+
+       dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
+               __func__, s->cookie_rx[active], active, s->active_rx);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return;
+
+fail:
+       spin_unlock_irqrestore(&port->lock, flags);
+       dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
+       sci_rx_dma_release(s, true);
 }
 
-/*
- * Here we define a transition notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
-                       unsigned long phase, void *p)
+static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
 {
-       struct sci_port *sci_port;
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
        unsigned long flags;
 
-       sci_port = container_of(self, struct sci_port, freq_transition);
-
-       if (phase == CPUFREQ_POSTCHANGE) {
-               struct uart_port *port = &sci_port->port;
+       spin_lock_irqsave(&port->lock, flags);
+       s->chan_tx = NULL;
+       s->cookie_tx = -EINVAL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       dmaengine_terminate_all(chan);
+       dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
+                        DMA_TO_DEVICE);
+       dma_release_channel(chan);
+       if (enable_pio)
+               sci_start_tx(port);
+}
 
-               spin_lock_irqsave(&port->lock, flags);
-               port->uartclk = clk_get_rate(sci_port->iclk);
-               spin_unlock_irqrestore(&port->lock, flags);
+static void sci_submit_rx(struct sci_port *s)
+{
+       struct dma_chan *chan = s->chan_rx;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               struct scatterlist *sg = &s->sg_rx[i];
+               struct dma_async_tx_descriptor *desc;
+
+               desc = dmaengine_prep_slave_sg(chan,
+                       sg, 1, DMA_DEV_TO_MEM,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc)
+                       goto fail;
+
+               desc->callback = sci_dma_rx_complete;
+               desc->callback_param = s;
+               s->cookie_rx[i] = dmaengine_submit(desc);
+               if (dma_submit_error(s->cookie_rx[i]))
+                       goto fail;
+
+               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
+                       s->cookie_rx[i], i);
        }
 
-       return NOTIFY_OK;
+       s->active_rx = s->cookie_rx[0];
+
+       dma_async_issue_pending(chan);
+       return;
+
+fail:
+       if (i)
+               dmaengine_terminate_all(chan);
+       for (i = 0; i < 2; i++)
+               s->cookie_rx[i] = -EINVAL;
+       s->active_rx = -EINVAL;
+       dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n");
+       sci_rx_dma_release(s, true);
 }
 
-static struct sci_irq_desc {
-       const char      *desc;
-       irq_handler_t   handler;
-} sci_irq_desc[] = {
+static void work_fn_tx(struct work_struct *work)
+{
+       struct sci_port *s = container_of(work, struct sci_port, work_tx);
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       dma_addr_t buf;
+
        /*
-        * Split out handlers, the default case.
+        * DMA is idle now.
+        * Port xmit buffer is already mapped, and it is one page... Just adjust
+        * offsets and lengths. Since it is a circular buffer, we have to
+        * transmit till the end, and then the rest. Take the port lock to get a
+        * consistent xmit buffer state.
         */
-       [SCIx_ERI_IRQ] = {
-               .desc = "rx err",
-               .handler = sci_er_interrupt,
-       },
+       spin_lock_irq(&port->lock);
+       buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1));
+       s->tx_dma_len = min_t(unsigned int,
+               CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
+               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
+       spin_unlock_irq(&port->lock);
 
-       [SCIx_RXI_IRQ] = {
-               .desc = "rx full",
-               .handler = sci_rx_interrupt,
-       },
+       desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
+                                          DMA_MEM_TO_DEV,
+                                          DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
 
-       [SCIx_TXI_IRQ] = {
-               .desc = "tx empty",
-               .handler = sci_tx_interrupt,
-       },
+       dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
+                                  DMA_TO_DEVICE);
 
-       [SCIx_BRI_IRQ] = {
-               .desc = "break",
-               .handler = sci_br_interrupt,
-       },
+       spin_lock_irq(&port->lock);
+       desc->callback = sci_dma_tx_complete;
+       desc->callback_param = s;
+       spin_unlock_irq(&port->lock);
+       s->cookie_tx = dmaengine_submit(desc);
+       if (dma_submit_error(s->cookie_tx)) {
+               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
 
-       /*
-        * Special muxed handler.
-        */
-       [SCIx_MUX_IRQ] = {
-               .desc = "mux",
-               .handler = sci_mpxed_interrupt,
-       },
-};
+       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
+               __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
 
-static int sci_request_irq(struct sci_port *port)
+       dma_async_issue_pending(chan);
+}
+
+static void rx_timer_fn(unsigned long arg)
 {
-       struct uart_port *up = &port->port;
-       int i, j, ret = 0;
+       struct sci_port *s = (struct sci_port *)arg;
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+       struct dma_tx_state state;
+       enum dma_status status;
+       unsigned long flags;
+       unsigned int read;
+       int active, count;
+       u16 scr;
 
-       for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
-               struct sci_irq_desc *desc;
-               int irq;
+       spin_lock_irqsave(&port->lock, flags);
 
-               if (SCIx_IRQ_IS_MUXED(port)) {
-                       i = SCIx_MUX_IRQ;
-                       irq = up->irq;
-               } else {
-                       irq = port->irqs[i];
+       dev_dbg(port->dev, "DMA Rx timed out\n");
 
-                       /*
-                        * Certain port types won't support all of the
-                        * available interrupt sources.
-                        */
-                       if (unlikely(irq < 0))
-                               continue;
-               }
+       active = sci_dma_rx_find_active(s);
+       if (active < 0) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               return;
+       }
 
-               desc = sci_irq_desc + i;
-               port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
-                                           dev_name(up->dev), desc->desc);
-               if (!port->irqstr[j]) {
-                       dev_err(up->dev, "Failed to allocate %s IRQ string\n",
-                               desc->desc);
-                       goto out_nomem;
-               }
+       status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
+       if (status == DMA_COMPLETE) {
+               dev_dbg(port->dev, "Cookie %d #%d has already completed\n",
+                       s->active_rx, active);
+               spin_unlock_irqrestore(&port->lock, flags);
 
-               ret = request_irq(irq, desc->handler, up->irqflags,
-                                 port->irqstr[j], port);
-               if (unlikely(ret)) {
-                       dev_err(up->dev, "Can't allocate %s IRQ\n", desc->desc);
-                       goto out_noirq;
-               }
+               /* Let packet complete handler take care of the packet */
+               return;
        }
 
-       return 0;
+       dmaengine_pause(chan);
 
-out_noirq:
-       while (--i >= 0)
-               free_irq(port->irqs[i], port);
+       /*
+        * sometimes DMA transfer doesn't stop even if it is stopped and
+        * data keeps on coming until transaction is complete so check
+        * for DMA_COMPLETE again
+        * Let packet complete handler take care of the packet
+        */
+       status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
+       if (status == DMA_COMPLETE) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               dev_dbg(port->dev, "Transaction complete after DMA engine was stopped");
+               return;
+       }
 
-out_nomem:
-       while (--j >= 0)
-               kfree(port->irqstr[j]);
+       /* Handle incomplete DMA receive */
+       dmaengine_terminate_all(s->chan_rx);
+       read = sg_dma_len(&s->sg_rx[active]) - state.residue;
+       dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read,
+               s->active_rx);
 
-       return ret;
+       if (read) {
+               count = sci_dma_rx_push(s, s->rx_buf[active], read);
+               if (count)
+                       tty_flip_buffer_push(&port->state->port);
+       }
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               sci_submit_rx(s);
+
+       /* Direct new serial port interrupts back to CPU */
+       scr = serial_port_in(port, SCSCR);
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               scr &= ~SCSCR_RDRQE;
+               enable_irq(s->irqs[SCIx_RXI_IRQ]);
+       }
+       serial_port_out(port, SCSCR, scr | SCSCR_RIE);
+
+       spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void sci_free_irq(struct sci_port *port)
+static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
+                                            enum dma_transfer_direction dir,
+                                            unsigned int id)
 {
-       int i;
+       dma_cap_mask_t mask;
+       struct dma_chan *chan;
+       struct dma_slave_config cfg;
+       int ret;
 
-       /*
-        * Intentionally in reverse order so we iterate over the muxed
-        * IRQ first.
-        */
-       for (i = 0; i < SCIx_NR_IRQS; i++) {
-               int irq = port->irqs[i];
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
 
-               /*
-                * Certain port types won't support all of the available
-                * interrupt sources.
-                */
-               if (unlikely(irq < 0))
-                       continue;
+       chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+                                       (void *)(unsigned long)id, port->dev,
+                                       dir == DMA_MEM_TO_DEV ? "tx" : "rx");
+       if (!chan) {
+               dev_warn(port->dev,
+                        "dma_request_slave_channel_compat failed\n");
+               return NULL;
+       }
 
-               free_irq(port->irqs[i], port);
-               kfree(port->irqstr[i]);
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.direction = dir;
+       if (dir == DMA_MEM_TO_DEV) {
+               cfg.dst_addr = port->mapbase +
+                       (sci_getreg(port, SCxTDR)->offset << port->regshift);
+               cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       } else {
+               cfg.src_addr = port->mapbase +
+                       (sci_getreg(port, SCxRDR)->offset << port->regshift);
+               cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       }
 
-               if (SCIx_IRQ_IS_MUXED(port)) {
-                       /* If there's only one IRQ, we're done. */
-                       return;
-               }
+       ret = dmaengine_slave_config(chan, &cfg);
+       if (ret) {
+               dev_warn(port->dev, "dmaengine_slave_config failed %d\n", ret);
+               dma_release_channel(chan);
+               return NULL;
        }
+
+       return chan;
 }
 
-static unsigned int sci_tx_empty(struct uart_port *port)
+static void sci_request_dma(struct uart_port *port)
 {
-       unsigned short status = serial_port_in(port, SCxSR);
-       unsigned short in_tx_fifo = sci_txfill(port);
+       struct sci_port *s = to_sci_port(port);
+       struct dma_chan *chan;
 
-       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
-}
+       dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
 
-/*
- * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
- * CTS/RTS is supported in hardware by at least one port and controlled
- * via SCSPTR (SCxPCR for SCIFA/B parts), or external pins (presently
- * handled via the ->init_pins() op, which is a bit of a one-way street,
- * lacking any ability to defer pin control -- this will later be
- * converted over to the GPIO framework).
- *
- * Other modes (such as loopback) are supported generically on certain
- * port types, but not others. For these it's sufficient to test for the
- * existence of the support register and simply ignore the port type.
- */
-static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       if (mctrl & TIOCM_LOOP) {
-               struct plat_sci_reg *reg;
+       if (!port->dev->of_node &&
+           (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0))
+               return;
 
-               /*
-                * Standard loopback mode for SCFCR ports.
-                */
-               reg = sci_getreg(port, SCFCR);
-               if (reg->size)
-                       serial_port_out(port, SCFCR,
-                                       serial_port_in(port, SCFCR) |
-                                       SCFCR_LOOP);
-       }
-}
+       s->cookie_tx = -EINVAL;
+       chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV, s->cfg->dma_slave_tx);
+       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
+       if (chan) {
+               s->chan_tx = chan;
+               /* UART circular tx buffer is an aligned page. */
+               s->tx_dma_addr = dma_map_single(chan->device->dev,
+                                               port->state->xmit.buf,
+                                               UART_XMIT_SIZE,
+                                               DMA_TO_DEVICE);
+               if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
+                       dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n");
+                       dma_release_channel(chan);
+                       s->chan_tx = NULL;
+               } else {
+                       dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
+                               __func__, UART_XMIT_SIZE,
+                               port->state->xmit.buf, &s->tx_dma_addr);
+               }
 
-static unsigned int sci_get_mctrl(struct uart_port *port)
-{
-       /*
-        * CTS/RTS is handled in hardware when supported, while nothing
-        * else is wired up. Keep it simple and simply assert DSR/CAR.
-        */
-       return TIOCM_DSR | TIOCM_CAR;
-}
+               INIT_WORK(&s->work_tx, work_fn_tx);
+       }
 
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static void sci_dma_tx_complete(void *arg)
-{
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned long flags;
+       chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM, s->cfg->dma_slave_rx);
+       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
+       if (chan) {
+               unsigned int i;
+               dma_addr_t dma;
+               void *buf;
 
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+               s->chan_rx = chan;
 
-       spin_lock_irqsave(&port->lock, flags);
+               s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize);
+               buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2,
+                                        &dma, GFP_KERNEL);
+               if (!buf) {
+                       dev_warn(port->dev,
+                                "Failed to allocate Rx dma buffer, using PIO\n");
+                       dma_release_channel(chan);
+                       s->chan_rx = NULL;
+                       return;
+               }
 
-       xmit->tail += sg_dma_len(&s->sg_tx);
-       xmit->tail &= UART_XMIT_SIZE - 1;
+               for (i = 0; i < 2; i++) {
+                       struct scatterlist *sg = &s->sg_rx[i];
 
-       port->icount.tx += sg_dma_len(&s->sg_tx);
+                       sg_init_table(sg, 1);
+                       s->rx_buf[i] = buf;
+                       sg_dma_address(sg) = dma;
+                       sg->length = s->buf_len_rx;
 
-       async_tx_ack(s->desc_tx);
-       s->desc_tx = NULL;
+                       buf += s->buf_len_rx;
+                       dma += s->buf_len_rx;
+               }
 
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
+               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
 
-       if (!uart_circ_empty(xmit)) {
-               s->cookie_tx = 0;
-               schedule_work(&s->work_tx);
-       } else {
-               s->cookie_tx = -EINVAL;
-               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-                       u16 ctrl = serial_port_in(port, SCSCR);
-                       serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE);
-               }
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+                       sci_submit_rx(s);
        }
+}
 
-       spin_unlock_irqrestore(&port->lock, flags);
+static void sci_free_dma(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       if (s->chan_tx)
+               sci_tx_dma_release(s, false);
+       if (s->chan_rx)
+               sci_rx_dma_release(s, false);
+}
+#else
+static inline void sci_request_dma(struct uart_port *port)
+{
 }
 
-/* Locking: called with port lock held */
-static int sci_dma_rx_push(struct sci_port *s, size_t count)
+static inline void sci_free_dma(struct uart_port *port)
 {
-       struct uart_port *port = &s->port;
-       struct tty_port *tport = &port->state->port;
-       int i, active, room;
+}
+#endif
 
-       room = tty_buffer_request_room(tport, count);
+static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
+{
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
 
-       if (s->active_rx == s->cookie_rx[0]) {
-               active = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               active = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return 0;
-       }
+       if (s->chan_rx) {
+               u16 scr = serial_port_in(port, SCSCR);
+               u16 ssr = serial_port_in(port, SCxSR);
 
-       if (room < count)
-               dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",
-                        count - room);
-       if (!room)
-               return room;
+               /* Disable future Rx interrupts */
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+                       disable_irq_nosync(irq);
+                       scr |= SCSCR_RDRQE;
+               } else {
+                       scr &= ~SCSCR_RIE;
+                       sci_submit_rx(s);
+               }
+               serial_port_out(port, SCSCR, scr);
+               /* Clear current interrupt */
+               serial_port_out(port, SCxSR,
+                               ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
+               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+                       jiffies, s->rx_timeout);
+               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
 
-       for (i = 0; i < room; i++)
-               tty_insert_flip_char(tport, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
-                                    TTY_NORMAL);
+               return IRQ_HANDLED;
+       }
+#endif
 
-       port->icount.rx += room;
+       /* I think sci_receive_chars has to be called irrespective
+        * of whether the I_IXOFF is set, otherwise, how is the interrupt
+        * to be disabled?
+        */
+       sci_receive_chars(ptr);
 
-       return room;
+       return IRQ_HANDLED;
 }
 
-static void sci_dma_rx_complete(void *arg)
+static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
 {
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
+       struct uart_port *port = ptr;
        unsigned long flags;
-       int count;
-
-       dev_dbg(port->dev, "%s(%d) active #%d\n",
-               __func__, port->line, s->active_rx);
 
        spin_lock_irqsave(&port->lock, flags);
+       sci_transmit_chars(port);
+       spin_unlock_irqrestore(&port->lock, flags);
 
-       count = sci_dma_rx_push(s, s->buf_len_rx);
+       return IRQ_HANDLED;
+}
 
-       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
 
-       spin_unlock_irqrestore(&port->lock, flags);
+       /* Handle errors */
+       if (port->type == PORT_SCI) {
+               if (sci_handle_errors(port)) {
+                       /* discard character in rx buffer */
+                       serial_port_in(port, SCxSR);
+                       sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+               }
+       } else {
+               sci_handle_fifo_overrun(port);
+               if (!s->chan_rx)
+                       sci_receive_chars(ptr);
+       }
 
-       if (count)
-               tty_flip_buffer_push(&port->state->port);
+       sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+
+       /* Kick the transmission */
+       if (!s->chan_tx)
+               sci_tx_interrupt(irq, ptr);
 
-       schedule_work(&s->work_rx);
+       return IRQ_HANDLED;
 }
 
-static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
+static irqreturn_t sci_br_interrupt(int irq, void *ptr)
 {
-       struct dma_chan *chan = s->chan_rx;
-       struct uart_port *port = &s->port;
+       struct uart_port *port = ptr;
 
-       s->chan_rx = NULL;
-       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
-       dma_release_channel(chan);
-       if (sg_dma_address(&s->sg_rx[0]))
-               dma_free_coherent(port->dev, s->buf_len_rx * 2,
-                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
-       if (enable_pio)
-               sci_start_rx(port);
+       /* Handle BREAKs */
+       sci_handle_breaks(port);
+       sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
+
+       return IRQ_HANDLED;
 }
 
-static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
+static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
 {
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
+       unsigned short ssr_status, scr_status, err_enabled, orer_status = 0;
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+       irqreturn_t ret = IRQ_NONE;
 
-       s->chan_tx = NULL;
-       s->cookie_tx = -EINVAL;
-       dma_release_channel(chan);
-       if (enable_pio)
-               sci_start_tx(port);
-}
+       ssr_status = serial_port_in(port, SCxSR);
+       scr_status = serial_port_in(port, SCSCR);
+       if (s->overrun_reg == SCxSR)
+               orer_status = ssr_status;
+       else {
+               if (sci_getreg(port, s->overrun_reg)->size)
+                       orer_status = serial_port_in(port, s->overrun_reg);
+       }
 
-static void sci_submit_rx(struct sci_port *s)
-{
-       struct dma_chan *chan = s->chan_rx;
-       int i;
+       err_enabled = scr_status & port_rx_irq_mask(port);
 
-       for (i = 0; i < 2; i++) {
-               struct scatterlist *sg = &s->sg_rx[i];
-               struct dma_async_tx_descriptor *desc;
+       /* Tx Interrupt */
+       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
+           !s->chan_tx)
+               ret = sci_tx_interrupt(irq, ptr);
 
-               desc = dmaengine_prep_slave_sg(chan,
-                       sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+       /*
+        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
+        * DR flags
+        */
+       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
+           (scr_status & SCSCR_RIE))
+               ret = sci_rx_interrupt(irq, ptr);
 
-               if (desc) {
-                       s->desc_rx[i] = desc;
-                       desc->callback = sci_dma_rx_complete;
-                       desc->callback_param = s;
-                       s->cookie_rx[i] = desc->tx_submit(desc);
-               }
+       /* Error Interrupt */
+       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
+               ret = sci_er_interrupt(irq, ptr);
 
-               if (!desc || s->cookie_rx[i] < 0) {
-                       if (i) {
-                               async_tx_ack(s->desc_rx[0]);
-                               s->cookie_rx[0] = -EINVAL;
-                       }
-                       if (desc) {
-                               async_tx_ack(desc);
-                               s->cookie_rx[i] = -EINVAL;
-                       }
-                       dev_warn(s->port.dev,
-                                "failed to re-start DMA, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n",
-                       __func__, s->cookie_rx[i], i);
-       }
+       /* Break Interrupt */
+       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
+               ret = sci_br_interrupt(irq, ptr);
 
-       s->active_rx = s->cookie_rx[0];
+       /* Overrun Interrupt */
+       if (orer_status & s->overrun_mask) {
+               sci_handle_fifo_overrun(port);
+               ret = IRQ_HANDLED;
+       }
 
-       dma_async_issue_pending(chan);
+       return ret;
 }
 
-static void work_fn_rx(struct work_struct *work)
+/*
+ * Here we define a transition notifier so that we can update all of our
+ * ports' baud rate when the peripheral clock changes.
+ */
+static int sci_notifier(struct notifier_block *self,
+                       unsigned long phase, void *p)
 {
-       struct sci_port *s = container_of(work, struct sci_port, work_rx);
-       struct uart_port *port = &s->port;
-       struct dma_async_tx_descriptor *desc;
-       int new;
-
-       if (s->active_rx == s->cookie_rx[0]) {
-               new = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               new = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return;
-       }
-       desc = s->desc_rx[new];
+       struct sci_port *sci_port;
+       unsigned long flags;
 
-       if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
-           DMA_COMPLETE) {
-               /* Handle incomplete DMA receive */
-               struct dma_chan *chan = s->chan_rx;
-               struct shdma_desc *sh_desc = container_of(desc,
-                                       struct shdma_desc, async_tx);
-               unsigned long flags;
-               int count;
+       sci_port = container_of(self, struct sci_port, freq_transition);
 
-               dmaengine_terminate_all(chan);
-               dev_dbg(port->dev, "Read %zu bytes with cookie %d\n",
-                       sh_desc->partial, sh_desc->cookie);
+       if (phase == CPUFREQ_POSTCHANGE) {
+               struct uart_port *port = &sci_port->port;
 
                spin_lock_irqsave(&port->lock, flags);
-               count = sci_dma_rx_push(s, sh_desc->partial);
+               port->uartclk = clk_get_rate(sci_port->iclk);
                spin_unlock_irqrestore(&port->lock, flags);
-
-               if (count)
-                       tty_flip_buffer_push(&port->state->port);
-
-               sci_submit_rx(s);
-
-               return;
-       }
-
-       s->cookie_rx[new] = desc->tx_submit(desc);
-       if (s->cookie_rx[new] < 0) {
-               dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
-               sci_rx_dma_release(s, true);
-               return;
        }
 
-       s->active_rx = s->cookie_rx[!new];
-
-       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n",
-               __func__, s->cookie_rx[new], new, s->active_rx);
+       return NOTIFY_OK;
 }
 
-static void work_fn_tx(struct work_struct *work)
-{
-       struct sci_port *s = container_of(work, struct sci_port, work_tx);
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct scatterlist *sg = &s->sg_tx;
-
+static const struct sci_irq_desc {
+       const char      *desc;
+       irq_handler_t   handler;
+} sci_irq_desc[] = {
        /*
-        * DMA is idle now.
-        * Port xmit buffer is already mapped, and it is one page... Just adjust
-        * offsets and lengths. Since it is a circular buffer, we have to
-        * transmit till the end, and then the rest. Take the port lock to get a
-        * consistent xmit buffer state.
+        * Split out handlers, the default case.
         */
-       spin_lock_irq(&port->lock);
-       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
-       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
-               sg->offset;
-       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
-               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
-       spin_unlock_irq(&port->lock);
+       [SCIx_ERI_IRQ] = {
+               .desc = "rx err",
+               .handler = sci_er_interrupt,
+       },
 
-       BUG_ON(!sg_dma_len(sg));
+       [SCIx_RXI_IRQ] = {
+               .desc = "rx full",
+               .handler = sci_rx_interrupt,
+       },
 
-       desc = dmaengine_prep_slave_sg(chan,
-                       sg, s->sg_len_tx, DMA_MEM_TO_DEV,
-                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
+       [SCIx_TXI_IRQ] = {
+               .desc = "tx empty",
+               .handler = sci_tx_interrupt,
+       },
+
+       [SCIx_BRI_IRQ] = {
+               .desc = "break",
+               .handler = sci_br_interrupt,
+       },
+
+       /*
+        * Special muxed handler.
+        */
+       [SCIx_MUX_IRQ] = {
+               .desc = "mux",
+               .handler = sci_mpxed_interrupt,
+       },
+};
 
-       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+static int sci_request_irq(struct sci_port *port)
+{
+       struct uart_port *up = &port->port;
+       int i, j, ret = 0;
 
-       spin_lock_irq(&port->lock);
-       s->desc_tx = desc;
-       desc->callback = sci_dma_tx_complete;
-       desc->callback_param = s;
-       spin_unlock_irq(&port->lock);
-       s->cookie_tx = desc->tx_submit(desc);
-       if (s->cookie_tx < 0) {
-               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
+       for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
+               const struct sci_irq_desc *desc;
+               int irq;
 
-       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
-               __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       i = SCIx_MUX_IRQ;
+                       irq = up->irq;
+               } else {
+                       irq = port->irqs[i];
 
-       dma_async_issue_pending(chan);
-}
-#endif
+                       /*
+                        * Certain port types won't support all of the
+                        * available interrupt sources.
+                        */
+                       if (unlikely(irq < 0))
+                               continue;
+               }
 
-static void sci_start_tx(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       unsigned short ctrl;
+               desc = sci_irq_desc + i;
+               port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
+                                           dev_name(up->dev), desc->desc);
+               if (!port->irqstr[j])
+                       goto out_nomem;
 
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 new, scr = serial_port_in(port, SCSCR);
-               if (s->chan_tx)
-                       new = scr | SCSCR_TDRQE;
-               else
-                       new = scr & ~SCSCR_TDRQE;
-               if (new != scr)
-                       serial_port_out(port, SCSCR, new);
+               ret = request_irq(irq, desc->handler, up->irqflags,
+                                 port->irqstr[j], port);
+               if (unlikely(ret)) {
+                       dev_err(up->dev, "Can't allocate %s IRQ\n", desc->desc);
+                       goto out_noirq;
+               }
        }
 
-       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
-           s->cookie_tx < 0) {
-               s->cookie_tx = 0;
-               schedule_work(&s->work_tx);
-       }
-#endif
+       return 0;
 
-       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
-               ctrl = serial_port_in(port, SCSCR);
-               serial_port_out(port, SCSCR, ctrl | SCSCR_TIE);
-       }
+out_noirq:
+       while (--i >= 0)
+               free_irq(port->irqs[i], port);
+
+out_nomem:
+       while (--j >= 0)
+               kfree(port->irqstr[j]);
+
+       return ret;
 }
 
-static void sci_stop_tx(struct uart_port *port)
+static void sci_free_irq(struct sci_port *port)
 {
-       unsigned short ctrl;
+       int i;
 
-       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
-       ctrl = serial_port_in(port, SCSCR);
+       /*
+        * Intentionally in reverse order so we iterate over the muxed
+        * IRQ first.
+        */
+       for (i = 0; i < SCIx_NR_IRQS; i++) {
+               int irq = port->irqs[i];
 
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~SCSCR_TDRQE;
+               /*
+                * Certain port types won't support all of the available
+                * interrupt sources.
+                */
+               if (unlikely(irq < 0))
+                       continue;
 
-       ctrl &= ~SCSCR_TIE;
+               free_irq(port->irqs[i], port);
+               kfree(port->irqstr[i]);
 
-       serial_port_out(port, SCSCR, ctrl);
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       /* If there's only one IRQ, we're done. */
+                       return;
+               }
+       }
 }
 
-static void sci_start_rx(struct uart_port *port)
+static unsigned int sci_tx_empty(struct uart_port *port)
 {
-       unsigned short ctrl;
-
-       ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~SCSCR_RDRQE;
+       unsigned short status = serial_port_in(port, SCxSR);
+       unsigned short in_tx_fifo = sci_txfill(port);
 
-       serial_port_out(port, SCSCR, ctrl);
+       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
 }
 
-static void sci_stop_rx(struct uart_port *port)
+/*
+ * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
+ * CTS/RTS is supported in hardware by at least one port and controlled
+ * via SCSPTR (SCxPCR for SCIFA/B parts), or external pins (presently
+ * handled via the ->init_pins() op, which is a bit of a one-way street,
+ * lacking any ability to defer pin control -- this will later be
+ * converted over to the GPIO framework).
+ *
+ * Other modes (such as loopback) are supported generically on certain
+ * port types, but not others. For these it's sufficient to test for the
+ * existence of the support register and simply ignore the port type.
+ */
+static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       unsigned short ctrl;
-
-       ctrl = serial_port_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~SCSCR_RDRQE;
+       if (mctrl & TIOCM_LOOP) {
+               const struct plat_sci_reg *reg;
 
-       ctrl &= ~port_rx_irq_mask(port);
+               /*
+                * Standard loopback mode for SCFCR ports.
+                */
+               reg = sci_getreg(port, SCFCR);
+               if (reg->size)
+                       serial_port_out(port, SCFCR,
+                                       serial_port_in(port, SCFCR) |
+                                       SCFCR_LOOP);
+       }
+}
 
-       serial_port_out(port, SCSCR, ctrl);
+static unsigned int sci_get_mctrl(struct uart_port *port)
+{
+       /*
+        * CTS/RTS is handled in hardware when supported, while nothing
+        * else is wired up. Keep it simple and simply assert DSR/CAR.
+        */
+       return TIOCM_DSR | TIOCM_CAR;
 }
 
 static void sci_break_ctl(struct uart_port *port, int break_state)
 {
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+       const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
        unsigned short scscr, scsptr;
 
        /* check wheter the port has SCSPTR */
@@ -1630,142 +1818,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
        serial_port_out(port, SCSCR, scscr);
 }
 
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct sh_dmae_slave *param = slave;
-
-       dev_dbg(chan->device->dev, "%s: slave ID %d\n",
-               __func__, param->shdma_slave.slave_id);
-
-       chan->private = &param->shdma_slave;
-       return true;
-}
-
-static void rx_timer_fn(unsigned long arg)
-{
-       struct sci_port *s = (struct sci_port *)arg;
-       struct uart_port *port = &s->port;
-       u16 scr = serial_port_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               scr &= ~SCSCR_RDRQE;
-               enable_irq(s->irqs[SCIx_RXI_IRQ]);
-       }
-       serial_port_out(port, SCSCR, scr | SCSCR_RIE);
-       dev_dbg(port->dev, "DMA Rx timed out\n");
-       schedule_work(&s->work_rx);
-}
-
-static void sci_request_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       struct sh_dmae_slave *param;
-       struct dma_chan *chan;
-       dma_cap_mask_t mask;
-       int nent;
-
-       dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
-
-       if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)
-               return;
-
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       param = &s->param_tx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
-       param->shdma_slave.slave_id = s->cfg->dma_slave_tx;
-
-       s->cookie_tx = -EINVAL;
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
-       if (chan) {
-               s->chan_tx = chan;
-               sg_init_table(&s->sg_tx, 1);
-               /* UART circular tx buffer is an aligned page. */
-               BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK);
-               sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
-                           UART_XMIT_SIZE,
-                           (uintptr_t)port->state->xmit.buf & ~PAGE_MASK);
-               nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
-               if (!nent)
-                       sci_tx_dma_release(s, false);
-               else
-                       dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n",
-                               __func__,
-                               sg_dma_len(&s->sg_tx), port->state->xmit.buf,
-                               &sg_dma_address(&s->sg_tx));
-
-               s->sg_len_tx = nent;
-
-               INIT_WORK(&s->work_tx, work_fn_tx);
-       }
-
-       param = &s->param_rx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
-       param->shdma_slave.slave_id = s->cfg->dma_slave_rx;
-
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
-       if (chan) {
-               dma_addr_t dma[2];
-               void *buf[2];
-               int i;
-
-               s->chan_rx = chan;
-
-               s->buf_len_rx = 2 * max(16, (int)port->fifosize);
-               buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
-                                           &dma[0], GFP_KERNEL);
-
-               if (!buf[0]) {
-                       dev_warn(port->dev,
-                                "failed to allocate dma buffer, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-
-               buf[1] = buf[0] + s->buf_len_rx;
-               dma[1] = dma[0] + s->buf_len_rx;
-
-               for (i = 0; i < 2; i++) {
-                       struct scatterlist *sg = &s->sg_rx[i];
-
-                       sg_init_table(sg, 1);
-                       sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
-                                   (uintptr_t)buf[i] & ~PAGE_MASK);
-                       sg_dma_address(sg) = dma[i];
-               }
-
-               INIT_WORK(&s->work_rx, work_fn_rx);
-               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
-
-               sci_submit_rx(s);
-       }
-}
-
-static void sci_free_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       if (s->chan_tx)
-               sci_tx_dma_release(s, false);
-       if (s->chan_rx)
-               sci_rx_dma_release(s, false);
-}
-#else
-static inline void sci_request_dma(struct uart_port *port)
-{
-}
-
-static inline void sci_free_dma(struct uart_port *port)
-{
-}
-#endif
-
 static int sci_startup(struct uart_port *port)
 {
        struct sci_port *s = to_sci_port(port);
@@ -1800,6 +1852,14 @@ static void sci_shutdown(struct uart_port *port)
        sci_stop_tx(port);
        spin_unlock_irqrestore(&port->lock, flags);
 
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       if (s->chan_rx) {
+               dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__,
+                       port->line);
+               del_timer_sync(&s->rx_timer);
+       }
+#endif
+
        sci_free_dma(port);
        sci_free_irq(s);
 }
@@ -1892,7 +1952,7 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
 
 static void sci_reset(struct uart_port *port)
 {
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
        unsigned int status;
 
        do {
@@ -1910,7 +1970,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
        unsigned int baud, smr_val = 0, max_baud, cks = 0;
        int t = -1;
        unsigned int srr = 15;
@@ -1951,7 +2011,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 
        sci_reset(port);
 
-       smr_val |= serial_port_in(port, SCSMR) & 3;
+       smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
 
        uart_update_timeout(port, termios->c_cflag, baud);
 
@@ -1996,13 +2056,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
        /*
         * Calculate delay for 2 DMA buffers (4 FIFO).
-        * See drivers/serial/serial_core.c::uart_update_timeout(). With 10
-        * bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
-        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
-        * Then below we calculate 5 jiffies (20ms) for 2 DMA buffers (4 FIFO
-        * sizes), but when performing a faster transfer, value obtained by
-        * this formula is may not enough. Therefore, if value is smaller than
-        * 20msec, this sets 20msec as timeout of DMA.
+        * See serial_core.c::uart_update_timeout().
+        * With 10 bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above
+        * function calculates 1 jiffie for the data plus 5 jiffies for the
+        * "slop(e)." Then below we calculate 5 jiffies (20ms) for 2 DMA
+        * buffers (4 FIFO sizes), but when performing a faster transfer, the
+        * value obtained by this formula is too small. Therefore, if the value
+        * is smaller than 20ms, use 20ms as the timeout value for DMA.
         */
        if (s->chan_rx) {
                unsigned int bits;
@@ -2187,7 +2247,6 @@ static int sci_init_single(struct platform_device *dev,
 {
        struct uart_port *port = &sci_port->port;
        const struct resource *res;
-       unsigned int sampling_rate;
        unsigned int i;
        int ret;
 
@@ -2232,37 +2291,37 @@ static int sci_init_single(struct platform_device *dev,
                port->fifosize = 256;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCIFA_ORER;
-               sampling_rate = 16;
+               sci_port->sampling_rate = 16;
                break;
        case PORT_HSCIF:
                port->fifosize = 128;
-               sampling_rate = 0;
                sci_port->overrun_reg = SCLSR;
                sci_port->overrun_mask = SCLSR_ORER;
+               sci_port->sampling_rate = 0;
                break;
        case PORT_SCIFA:
                port->fifosize = 64;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCIFA_ORER;
-               sampling_rate = 16;
+               sci_port->sampling_rate = 16;
                break;
        case PORT_SCIF:
                port->fifosize = 16;
                if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
                        sci_port->overrun_reg = SCxSR;
                        sci_port->overrun_mask = SCIFA_ORER;
-                       sampling_rate = 16;
+                       sci_port->sampling_rate = 16;
                } else {
                        sci_port->overrun_reg = SCLSR;
                        sci_port->overrun_mask = SCLSR_ORER;
-                       sampling_rate = 32;
+                       sci_port->sampling_rate = 32;
                }
                break;
        default:
                port->fifosize = 1;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCI_ORER;
-               sampling_rate = 32;
+               sci_port->sampling_rate = 32;
                break;
        }
 
@@ -2270,8 +2329,8 @@ static int sci_init_single(struct platform_device *dev,
         * match the SoC datasheet, this should be investigated. Let platform
         * data override the sampling rate for now.
         */
-       sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate
-                               : sampling_rate;
+       if (p->sampling_rate)
+               sci_port->sampling_rate = p->sampling_rate;
 
        if (!early) {
                sci_port->iclk = clk_get(&dev->dev, "sci_ick");
@@ -2303,15 +2362,22 @@ static int sci_init_single(struct platform_device *dev,
        /*
         * Establish some sensible defaults for the error detection.
         */
-       sci_port->error_mask = (p->type == PORT_SCI) ?
-                       SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
+       if (p->type == PORT_SCI) {
+               sci_port->error_mask = SCI_DEFAULT_ERROR_MASK;
+               sci_port->error_clear = SCI_ERROR_CLEAR;
+       } else {
+               sci_port->error_mask = SCIF_DEFAULT_ERROR_MASK;
+               sci_port->error_clear = SCIF_ERROR_CLEAR;
+       }
 
        /*
         * Make the error mask inclusive of overrun detection, if
         * supported.
         */
-       if (sci_port->overrun_reg == SCxSR)
+       if (sci_port->overrun_reg == SCxSR) {
                sci_port->error_mask |= sci_port->overrun_mask;
+               sci_port->error_clear &= ~sci_port->overrun_mask;
+       }
 
        port->type              = p->type;
        port->flags             = UPF_FIXED_PORT | p->flags;
@@ -2564,10 +2630,8 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
        info = match->data;
 
        p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
-       if (!p) {
-               dev_err(&pdev->dev, "failed to allocate DT config data\n");
+       if (!p)
                return NULL;
-       }
 
        /* Get the line number for the aliases node. */
        id = of_alias_get_id(np, "serial");
index 3393f67b4e84357890747bd79cd8002fdf33843f..bf69bbdcc1f9aa3975a7847ec323d23fa50a73ce 100644 (file)
@@ -54,10 +54,10 @@ enum {
 
 #define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
 
-#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF)
-#define SCI_ERROR_CLEAR        ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
-#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE)
-#define SCI_BREAK_CLEAR        ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
+#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF))
+#define SCI_ERROR_CLEAR        (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
+#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
+#define SCI_BREAK_CLEAR        (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
 
 /* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
 #define SCIF_ER                BIT(7)  /* Receive Error */
@@ -76,10 +76,10 @@ enum {
 
 #define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
 
-#define SCIF_RDxF_CLEAR                ~(SCIF_DR | SCIF_RDF)
-#define SCIF_ERROR_CLEAR       ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER)
-#define SCIF_TDxE_CLEAR                ~(SCIF_TDFE)
-#define SCIF_BREAK_CLEAR       ~(SCIF_PER | SCIF_FER | SCIF_BRK)
+#define SCIF_RDxF_CLEAR                (u32)(~(SCIF_DR | SCIF_RDF))
+#define SCIF_ERROR_CLEAR       (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
+#define SCIF_TDxE_CLEAR                (u32)(~(SCIF_TDFE))
+#define SCIF_BREAK_CLEAR       (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
 
 /* SCFCR (FIFO Control Register) */
 #define SCFCR_MCE      BIT(3)  /* Modem Control Enable */
@@ -119,28 +119,11 @@ enum {
 
 #define SCxSR_ERRORS(port)     (to_sci_port(port)->error_mask)
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_R8A7740)
-
-# define SCxSR_RDxF_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR)
-# define SCxSR_ERROR_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR)
-# define SCxSR_TDxE_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR)
-# define SCxSR_BREAK_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR)
-#else
-# define SCxSR_RDxF_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff)
-# define SCxSR_ERROR_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff)
-# define SCxSR_TDxE_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff)
-# define SCxSR_BREAK_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff)
-#endif
-
+#define SCxSR_RDxF_CLEAR(port) \
+       (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
+#define SCxSR_ERROR_CLEAR(port) \
+       (to_sci_port(port)->error_clear)
+#define SCxSR_TDxE_CLEAR(port) \
+       (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
+#define SCxSR_BREAK_CLEAR(port) \
+       (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR)
index 3866516c2926a32c5f63600b7dbee05497af99bf..9dbae01d41cef75186932201674ef937168279e6 100644 (file)
@@ -782,6 +782,7 @@ static const struct of_device_id serial_ids[] = {
        {.compatible = "sprd,sc9836-uart",},
        {}
 };
+MODULE_DEVICE_TABLE(of, serial_ids);
 
 static struct platform_driver sprd_platform_driver = {
        .probe          = sprd_probe,
index d625664ce1b51eea836775d800eded58140fb5ee..2d78cb3627aef9da5e0593d0da38810fc09977c5 100644 (file)
@@ -430,7 +430,7 @@ static void asc_break_ctl(struct uart_port *port, int break_state)
  */
 static int asc_startup(struct uart_port *port)
 {
-       if (request_irq(port->irq, asc_interrupt, IRQF_NO_SUSPEND,
+       if (request_irq(port->irq, asc_interrupt, 0,
                        asc_port_name(port), port)) {
                dev_err(port->dev, "cannot allocate irq.\n");
                return -ENODEV;
index e3de9c6d22265746ea1b34ffa822b0a381898b19..f89d1f79be18fffd199f902d5cc8fa3936d0b815 100644 (file)
@@ -322,8 +322,7 @@ static int stm32_startup(struct uart_port *port)
        u32 val;
        int ret;
 
-       ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
-                         name, port);
+       ret = request_irq(port->irq, stm32_interrupt, 0, name, port);
        if (ret)
                return ret;
 
index 95b330a9ea983dcafae63956cefd03ddefe9379b..5381a728d23e773af0e1ebe2869e01bf98757244 100644 (file)
@@ -1003,6 +1003,10 @@ static const struct kernel_param_ops param_ops_sysrq_reset_seq = {
 #define param_check_sysrq_reset_seq(name, p)   \
        __param_check(name, p, unsigned short)
 
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
 module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
                         &sysrq_reset_seq_len, 0644);
 
@@ -1119,4 +1123,4 @@ static int __init sysrq_init(void)
 
        return 0;
 }
-module_init(sysrq_init);
+device_initcall(sysrq_init);
index 527a85c6192443a50ca8846f24fe40d7e726eca9..c4bc90bfebe0b7904c91f3ed27a4c2a8b56bd935 100644 (file)
 #include <linux/serial.h>
 #include <linux/platform_data/macb.h>
 
-/*
- * at91: 6 USARTs and one DBGU port (SAM9260)
- * avr32: 4
- */
-#define ATMEL_MAX_UART 7
-
  /* USB Device */
 struct at91_udc_data {
        int     vbus_pin;               /* high == host powering us */