TTY/Serial driver patches for 4.21-rc1
Here is the large TTY/Serial driver set of patches for 4.21-rc1. A number of small serial driver changes along with some good tty core fixes for long-reported issues with locking. There is also a new console font added to the tree, for high-res screens, so that should be helpful for many. The last patch in the series is a revert of an older one in the tree, it came late but it resolves a reported issue that linux-next was having for some people. Full details are in the shortlog, and all of these, with the exception of the revert, have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iGwEABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXCY+1w8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yl9PgCXckFuSe66uNMzdq2jsVgLKtMR+ACbBzrLQeMZ LU8UpaVqDJrrPxVURGY= =a/Xk -----END PGP SIGNATURE----- Merge tag 'tty-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver updates from Greg KH: "Here is the large TTY/Serial driver set of patches for 4.21-rc1. A number of small serial driver changes along with some good tty core fixes for long-reported issues with locking. There is also a new console font added to the tree, for high-res screens, so that should be helpful for many. The last patch in the series is a revert of an older one in the tree, it came late but it resolves a reported issue that linux-next was having for some people. Full details are in the shortlog, and all of these, with the exception of the revert, have been in linux-next for a while with no reported issues" * tag 'tty-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (85 commits) Revert "serial: 8250: Default SERIAL_OF_PLATFORM to SERIAL_8250" serial: sccnxp: Allow to use non-standard baud rates serial: sccnxp: Adds a delay between sequential read/write cycles tty: serial: qcom_geni_serial: Fix UART hang tty: serial: qcom_geni_serial: Fix wrap around of TX buffer serial: max310x: Fix tx_empty() callback dt-bindings: serial: sh-sci: Document r8a774c0 bindings dt-bindings: serial: sh-sci: Document r8a774a1 bindings Fonts: New Terminus large console font dt-bindings: serial: lpuart: add imx8qxp compatible string serial: uartps: Fix interrupt mask issue to handle the RX interrupts properly serial: uartps: Fix error path when alloc failed serial: uartps: Check if the device is a console serial: uartps: Add the device_init_wakeup tty: serial: samsung: Increase maximum baudrate tty: serial: samsung: Properly set flags in autoCTS mode tty: Use of_node_name_{eq,prefix} for node name comparisons tty/serial: do not free trasnmit buffer page under port lock serial: 8250: Rate limit serial port rx interrupts during input overruns dt-bindings: serial: 8250: Add rate limit for serial port input overruns ...
This commit is contained in:
commit
117eda8f71
|
@ -0,0 +1,33 @@
|
|||
* Mediatek UART APDMA Controller
|
||||
|
||||
Required properties:
|
||||
- compatible should contain:
|
||||
* "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
|
||||
* "mediatek,mt6577-uart-dma" for MT6577 and all of the above
|
||||
|
||||
- reg: The base address of the APDMA register bank.
|
||||
|
||||
- interrupts: A single interrupt specifier.
|
||||
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: The APDMA clock for register accesses
|
||||
|
||||
Examples:
|
||||
|
||||
apdma: dma-controller@11000380 {
|
||||
compatible = "mediatek,mt2712-uart-dma";
|
||||
reg = <0 0x11000380 0 0x400>;
|
||||
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 65 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 66 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 67 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 68 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 69 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pericfg CLK_PERI_AP_DMA>;
|
||||
clock-names = "apdma";
|
||||
#dma-cells = <1>;
|
||||
};
|
||||
|
|
@ -51,6 +51,7 @@ Optional properties:
|
|||
- tx-threshold: Specify the TX FIFO low water indication for parts with
|
||||
programmable TX FIFO thresholds.
|
||||
- resets : phandle + reset specifier pairs
|
||||
- overrun-throttle-ms : how long to pause uart rx when input overrun is encountered.
|
||||
|
||||
Note:
|
||||
* fsl,ns16550:
|
||||
|
|
|
@ -8,6 +8,8 @@ Required properties:
|
|||
on LS1021A SoC with 32-bit big-endian register organization
|
||||
- "fsl,imx7ulp-lpuart" for lpuart compatible with the one integrated
|
||||
on i.MX7ULP SoC with 32-bit little-endian register organization
|
||||
- "fsl,imx8qxp-lpuart" for lpuart compatible with the one integrated
|
||||
on i.MX8QXP SoC with 32-bit little-endian register organization
|
||||
- reg : Address and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- clocks : phandle + clock specifier pairs, one for each entry in clock-names
|
||||
|
|
|
@ -6,8 +6,23 @@ Required properties:
|
|||
- interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier
|
||||
depends on the interrupt-parent interrupt controller.
|
||||
|
||||
Optional properties:
|
||||
- clocks: Should contain frequency clock and gate clock
|
||||
- clock-names: Should be "freq" and "asc"
|
||||
|
||||
Example:
|
||||
|
||||
asc0: serial@16600000 {
|
||||
compatible = "lantiq,asc";
|
||||
reg = <0x16600000 0x100000>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SHARED 103 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 105 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 106 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cgu CLK_SSX4>, <&cgu GCLK_UART>;
|
||||
clock-names = "freq", "asc";
|
||||
};
|
||||
|
||||
asc1: serial@e100c00 {
|
||||
compatible = "lantiq,asc";
|
||||
reg = <0xE100C00 0x400>;
|
||||
|
|
|
@ -24,6 +24,10 @@ Required properties:
|
|||
- "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a77470" for R8A77470 (RZ/G1C) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a77470" for R8A77470 (RZ/G1C) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a774a1" for R8A774A1 (RZ/G2M) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a774a1" for R8A774A1 (RZ/G2M) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a774c0" for R8A774C0 (RZ/G2E) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a774c0" for R8A774C0 (RZ/G2E) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART.
|
||||
- "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
|
||||
- "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.
|
||||
|
@ -61,13 +65,13 @@ Required properties:
|
|||
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
|
||||
- "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART,
|
||||
- "renesas,rcar-gen2-scif" for R-Car Gen2 SCIF compatible UART,
|
||||
- "renesas,rcar-gen3-scif" for R-Car Gen3 SCIF compatible UART,
|
||||
- "renesas,rcar-gen2-scifa" for R-Car Gen2 SCIFA compatible UART,
|
||||
- "renesas,rcar-gen2-scifb" for R-Car Gen2 SCIFB compatible UART,
|
||||
- "renesas,rcar-gen2-scif" for R-Car Gen2 and RZ/G1 SCIF compatible UART,
|
||||
- "renesas,rcar-gen3-scif" for R-Car Gen3 and RZ/G2 SCIF compatible UART,
|
||||
- "renesas,rcar-gen2-scifa" for R-Car Gen2 and RZ/G1 SCIFA compatible UART,
|
||||
- "renesas,rcar-gen2-scifb" for R-Car Gen2 and RZ/G1 SCIFB compatible UART,
|
||||
- "renesas,rcar-gen1-hscif" for R-Car Gen1 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen2-hscif" for R-Car Gen2 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen3-hscif" for R-Car Gen3 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen2-hscif" for R-Car Gen2 and RZ/G1 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen3-hscif" for R-Car Gen3 and RZ/G2 HSCIF compatible UART,
|
||||
- "renesas,scif" for generic SCIF compatible UART.
|
||||
- "renesas,scifa" for generic SCIFA compatible UART.
|
||||
- "renesas,scifb" for generic SCIFB compatible UART.
|
||||
|
|
|
@ -66,6 +66,14 @@ config TTY_PRINTK
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config TTY_PRINTK_LEVEL
|
||||
depends on TTY_PRINTK
|
||||
int "ttyprintk log level (1-7)"
|
||||
range 1 7
|
||||
default "6"
|
||||
help
|
||||
Printk log level to use for ttyprintk messages.
|
||||
|
||||
config PRINTER
|
||||
tristate "Parallel printer support"
|
||||
depends on PARPORT
|
||||
|
|
|
@ -37,6 +37,8 @@ static struct ttyprintk_port tpk_port;
|
|||
*/
|
||||
#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
|
||||
#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
|
||||
#define TPK_PREFIX KERN_SOH __stringify(CONFIG_TTY_PRINTK_LEVEL)
|
||||
|
||||
static int tpk_curr;
|
||||
|
||||
static char tpk_buffer[TPK_STR_SIZE + 4];
|
||||
|
@ -45,7 +47,7 @@ static void tpk_flush(void)
|
|||
{
|
||||
if (tpk_curr > 0) {
|
||||
tpk_buffer[tpk_curr] = '\0';
|
||||
pr_info("[U] %s\n", tpk_buffer);
|
||||
printk(TPK_PREFIX "[U] %s\n", tpk_buffer);
|
||||
tpk_curr = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ static int gnss_serial_write_raw(struct gnss_device *gdev,
|
|||
|
||||
/* write is only buffered synchronously */
|
||||
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
if (ret < 0 || ret < count)
|
||||
return ret;
|
||||
|
||||
/* FIXME: determine if interrupted? */
|
||||
|
|
|
@ -85,7 +85,7 @@ static int sirf_write_raw(struct gnss_device *gdev, const unsigned char *buf,
|
|||
|
||||
/* write is only buffered synchronously */
|
||||
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
if (ret < 0 || ret < count)
|
||||
return ret;
|
||||
|
||||
/* FIXME: determine if interrupted? */
|
||||
|
|
|
@ -353,7 +353,7 @@ void __init hvc_opal_init_early(void)
|
|||
if (!opal)
|
||||
return;
|
||||
for_each_child_of_node(opal, np) {
|
||||
if (!strcmp(np->name, "serial")) {
|
||||
if (of_node_name_eq(np, "serial")) {
|
||||
stdout_node = np;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -371,20 +371,11 @@ device_initcall(hvc_vio_init); /* after drivers/tty/hvc/hvc_console.c */
|
|||
void __init hvc_vio_init_early(void)
|
||||
{
|
||||
const __be32 *termno;
|
||||
const char *name;
|
||||
const struct hv_ops *ops;
|
||||
|
||||
/* find the boot console from /chosen/stdout */
|
||||
if (!of_stdout)
|
||||
return;
|
||||
name = of_get_property(of_stdout, "name", NULL);
|
||||
if (!name) {
|
||||
printk(KERN_WARNING "stdout node missing 'name' property!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if it's a virtual terminal */
|
||||
if (strncmp(name, "vty", 3) != 0)
|
||||
if (!of_node_name_prefix(of_stdout, "vty"))
|
||||
return;
|
||||
termno = of_get_property(of_stdout, "reg", NULL);
|
||||
if (termno == NULL)
|
||||
|
|
|
@ -612,7 +612,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
|
|||
}
|
||||
|
||||
/* no data */
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
@ -679,7 +679,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
|
|||
if (tbuf)
|
||||
break;
|
||||
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
error = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1085,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
|||
pMsg = remove_msg(pInfo, pClient);
|
||||
if (pMsg == NULL) {
|
||||
/* no messages available. */
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
ret = -EAGAIN;
|
||||
goto unlock;
|
||||
}
|
||||
|
|
|
@ -1702,7 +1702,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
|||
|
||||
down_read(&tty->termios_rwsem);
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
/*
|
||||
* When PARMRK is set, each input char may take up to 3 chars
|
||||
* in the read buf; reduce the buffer space avail by 3x
|
||||
|
@ -1744,7 +1744,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
|||
fp += n;
|
||||
count -= n;
|
||||
rcvd += n;
|
||||
}
|
||||
} while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
|
||||
|
||||
tty->receive_room = room;
|
||||
|
||||
|
@ -2211,7 +2211,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
|||
break;
|
||||
if (!timeout)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
@ -2365,7 +2365,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
|
|||
}
|
||||
if (!nr)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -216,6 +217,21 @@ void serdev_device_write_wakeup(struct serdev_device *serdev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_device_write_wakeup);
|
||||
|
||||
/**
|
||||
* serdev_device_write_buf() - write data asynchronously
|
||||
* @serdev: serdev device
|
||||
* @buf: data to be written
|
||||
* @count: number of bytes to write
|
||||
*
|
||||
* Write data to the device asynchronously.
|
||||
*
|
||||
* Note that any accepted data has only been buffered by the controller; use
|
||||
* serdev_device_wait_until_sent() to make sure the controller write buffer
|
||||
* has actually been emptied.
|
||||
*
|
||||
* Return: The number of bytes written (less than count if not enough room in
|
||||
* the write buffer), or a negative errno on errors.
|
||||
*/
|
||||
int serdev_device_write_buf(struct serdev_device *serdev,
|
||||
const unsigned char *buf, size_t count)
|
||||
{
|
||||
|
@ -228,17 +244,42 @@ int serdev_device_write_buf(struct serdev_device *serdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_device_write_buf);
|
||||
|
||||
/**
|
||||
* serdev_device_write() - write data synchronously
|
||||
* @serdev: serdev device
|
||||
* @buf: data to be written
|
||||
* @count: number of bytes to write
|
||||
* @timeout: timeout in jiffies, or 0 to wait indefinitely
|
||||
*
|
||||
* Write data to the device synchronously by repeatedly calling
|
||||
* serdev_device_write() until the controller has accepted all data (unless
|
||||
* interrupted by a timeout or a signal).
|
||||
*
|
||||
* Note that any accepted data has only been buffered by the controller; use
|
||||
* serdev_device_wait_until_sent() to make sure the controller write buffer
|
||||
* has actually been emptied.
|
||||
*
|
||||
* Note that this function depends on serdev_device_write_wakeup() being
|
||||
* called in the serdev driver write_wakeup() callback.
|
||||
*
|
||||
* Return: The number of bytes written (less than count if interrupted),
|
||||
* -ETIMEDOUT or -ERESTARTSYS if interrupted before any bytes were written, or
|
||||
* a negative errno on errors.
|
||||
*/
|
||||
int serdev_device_write(struct serdev_device *serdev,
|
||||
const unsigned char *buf, size_t count,
|
||||
unsigned long timeout)
|
||||
long timeout)
|
||||
{
|
||||
struct serdev_controller *ctrl = serdev->ctrl;
|
||||
int written = 0;
|
||||
int ret;
|
||||
|
||||
if (!ctrl || !ctrl->ops->write_buf ||
|
||||
(timeout && !serdev->ops->write_wakeup))
|
||||
if (!ctrl || !ctrl->ops->write_buf || !serdev->ops->write_wakeup)
|
||||
return -EINVAL;
|
||||
|
||||
if (timeout == 0)
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
|
||||
mutex_lock(&serdev->write_lock);
|
||||
do {
|
||||
reinit_completion(&serdev->write_comp);
|
||||
|
@ -247,14 +288,29 @@ int serdev_device_write(struct serdev_device *serdev,
|
|||
if (ret < 0)
|
||||
break;
|
||||
|
||||
written += ret;
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
|
||||
} while (count &&
|
||||
(timeout = wait_for_completion_timeout(&serdev->write_comp,
|
||||
timeout)));
|
||||
if (count == 0)
|
||||
break;
|
||||
|
||||
timeout = wait_for_completion_interruptible_timeout(&serdev->write_comp,
|
||||
timeout);
|
||||
} while (timeout > 0);
|
||||
mutex_unlock(&serdev->write_lock);
|
||||
return ret < 0 ? ret : (count ? -ETIMEDOUT : 0);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (timeout <= 0 && written == 0) {
|
||||
if (timeout == -ERESTARTSYS)
|
||||
return -ERESTARTSYS;
|
||||
else
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_device_write);
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
* Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp.
|
||||
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
|
||||
*/
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -293,7 +297,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port)
|
|||
if (lsr & UART_LSR_THRE)
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
uart_unlock_and_check_sysrq(port, flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -942,6 +942,21 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void serial_8250_overrun_backoff_work(struct work_struct *work)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(to_delayed_work(work), struct uart_8250_port,
|
||||
overrun_backoff);
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
up->port.read_status_mask |= UART_LSR_DR;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* serial8250_register_8250_port - register a serial port
|
||||
* @up: serial port template
|
||||
|
@ -1056,6 +1071,16 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise interrupt backoff work if required */
|
||||
if (up->overrun_backoff_time_ms > 0) {
|
||||
uart->overrun_backoff_time_ms = up->overrun_backoff_time_ms;
|
||||
INIT_DELAYED_WORK(&uart->overrun_backoff,
|
||||
serial_8250_overrun_backoff_work);
|
||||
} else {
|
||||
uart->overrun_backoff_time_ms = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
|
@ -45,8 +49,29 @@ int fsl8250_handle_irq(struct uart_port *port)
|
|||
|
||||
lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
|
||||
|
||||
if (lsr & (UART_LSR_DR | UART_LSR_BI))
|
||||
/* Process incoming characters first */
|
||||
if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
|
||||
(up->ier & (UART_IER_RLSI | UART_IER_RDI))) {
|
||||
lsr = serial8250_rx_chars(up, lsr);
|
||||
}
|
||||
|
||||
/* Stop processing interrupts on input overrun */
|
||||
if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
|
||||
unsigned long delay;
|
||||
|
||||
up->ier = port->serial_in(port, UART_IER);
|
||||
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
|
||||
port->ops->stop_rx(port);
|
||||
} else {
|
||||
/* Keep restarting the timer until
|
||||
* the input overrun subsides.
|
||||
*/
|
||||
cancel_delayed_work(&up->overrun_backoff);
|
||||
}
|
||||
|
||||
delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
|
||||
schedule_delayed_work(&up->overrun_backoff, delay);
|
||||
}
|
||||
|
||||
serial8250_modem_status(up);
|
||||
|
||||
|
@ -54,7 +79,7 @@ int fsl8250_handle_irq(struct uart_port *port)
|
|||
serial8250_tx_chars(up);
|
||||
|
||||
up->lsr_saved_flags = orig_lsr;
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
uart_unlock_and_check_sysrq(&up->port, flags);
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
|
@ -22,12 +26,172 @@
|
|||
#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
|
||||
#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */
|
||||
|
||||
#define MTK_UART_DMA_EN 0x13 /* DMA Enable register */
|
||||
#define MTK_UART_DMA_EN_TX 0x2
|
||||
#define MTK_UART_DMA_EN_RX 0x5
|
||||
|
||||
#define MTK_UART_TX_SIZE UART_XMIT_SIZE
|
||||
#define MTK_UART_RX_SIZE 0x8000
|
||||
#define MTK_UART_TX_TRIGGER 1
|
||||
#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
enum dma_rx_status {
|
||||
DMA_RX_START = 0,
|
||||
DMA_RX_RUNNING = 1,
|
||||
DMA_RX_SHUTDOWN = 2,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mtk8250_data {
|
||||
int line;
|
||||
unsigned int rx_pos;
|
||||
struct clk *uart_clk;
|
||||
struct clk *bus_clk;
|
||||
struct uart_8250_dma *dma;
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
enum dma_rx_status rx_status;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static void mtk8250_rx_dma(struct uart_8250_port *up);
|
||||
|
||||
static void mtk8250_dma_rx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *up = param;
|
||||
struct uart_8250_dma *dma = up->dma;
|
||||
struct mtk8250_data *data = up->port.private_data;
|
||||
struct tty_port *tty_port = &up->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
unsigned char *ptr;
|
||||
int copied;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
|
||||
if (data->rx_status == DMA_RX_SHUTDOWN)
|
||||
return;
|
||||
|
||||
if ((data->rx_pos + state.residue) <= dma->rx_size) {
|
||||
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
|
||||
copied = tty_insert_flip_string(tty_port, ptr, state.residue);
|
||||
} else {
|
||||
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
|
||||
copied = tty_insert_flip_string(tty_port, ptr,
|
||||
dma->rx_size - data->rx_pos);
|
||||
ptr = (unsigned char *)(dma->rx_buf);
|
||||
copied += tty_insert_flip_string(tty_port, ptr,
|
||||
data->rx_pos + state.residue - dma->rx_size);
|
||||
}
|
||||
up->port.icount.rx += copied;
|
||||
|
||||
tty_flip_buffer_push(tty_port);
|
||||
|
||||
mtk8250_rx_dma(up);
|
||||
}
|
||||
|
||||
static void mtk8250_rx_dma(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_8250_dma *dma = up->dma;
|
||||
struct mtk8250_data *data = up->port.private_data;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct dma_tx_state state;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
pr_err("failed to prepare rx slave single\n");
|
||||
return;
|
||||
}
|
||||
|
||||
desc->callback = mtk8250_dma_rx_complete;
|
||||
desc->callback_param = up;
|
||||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
data->rx_pos = state.residue;
|
||||
|
||||
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
}
|
||||
|
||||
static void mtk8250_dma_enable(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_8250_dma *dma = up->dma;
|
||||
struct mtk8250_data *data = up->port.private_data;
|
||||
int lcr = serial_in(up, UART_LCR);
|
||||
|
||||
if (data->rx_status != DMA_RX_START)
|
||||
return;
|
||||
|
||||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||
dma->rxconf.src_addr_width = dma->rx_size / 1024;
|
||||
dma->rxconf.src_addr = dma->rx_addr;
|
||||
|
||||
dma->txconf.direction = DMA_MEM_TO_DEV;
|
||||
dma->txconf.dst_addr_width = MTK_UART_TX_SIZE / 1024;
|
||||
dma->txconf.dst_addr = dma->tx_addr;
|
||||
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
|
||||
UART_FCR_CLEAR_XMIT);
|
||||
serial_out(up, MTK_UART_DMA_EN,
|
||||
MTK_UART_DMA_EN_RX | MTK_UART_DMA_EN_TX);
|
||||
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
serial_out(up, UART_EFR, UART_EFR_ECB);
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
|
||||
if (dmaengine_slave_config(dma->rxchan, &dma->rxconf) != 0)
|
||||
pr_err("failed to configure rx dma channel\n");
|
||||
if (dmaengine_slave_config(dma->txchan, &dma->txconf) != 0)
|
||||
pr_err("failed to configure tx dma channel\n");
|
||||
|
||||
data->rx_status = DMA_RX_RUNNING;
|
||||
data->rx_pos = 0;
|
||||
mtk8250_rx_dma(up);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mtk8250_startup(struct uart_port *port)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct mtk8250_data *data = port->private_data;
|
||||
|
||||
/* disable DMA for console */
|
||||
if (uart_console(port))
|
||||
up->dma = NULL;
|
||||
|
||||
if (up->dma) {
|
||||
data->rx_status = DMA_RX_START;
|
||||
uart_circ_clear(&port->state->xmit);
|
||||
}
|
||||
#endif
|
||||
memset(&port->icount, 0, sizeof(port->icount));
|
||||
|
||||
return serial8250_do_startup(port);
|
||||
}
|
||||
|
||||
static void mtk8250_shutdown(struct uart_port *port)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct mtk8250_data *data = port->private_data;
|
||||
|
||||
if (up->dma)
|
||||
data->rx_status = DMA_RX_SHUTDOWN;
|
||||
#endif
|
||||
|
||||
return serial8250_do_shutdown(port);
|
||||
}
|
||||
|
||||
static void
|
||||
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
|
@ -36,6 +200,17 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
if (up->dma) {
|
||||
if (uart_console(port)) {
|
||||
devm_kfree(up->port.dev, up->dma);
|
||||
up->dma = NULL;
|
||||
} else {
|
||||
mtk8250_dma_enable(up);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
serial8250_do_set_termios(port, termios, old);
|
||||
|
||||
/*
|
||||
|
@ -143,9 +318,20 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
|||
pm_runtime_put_sync_suspend(port->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static bool mtk8250_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
|
||||
struct mtk8250_data *data)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
int dmacnt;
|
||||
#endif
|
||||
|
||||
data->uart_clk = devm_clk_get(&pdev->dev, "baud");
|
||||
if (IS_ERR(data->uart_clk)) {
|
||||
/*
|
||||
|
@ -162,7 +348,23 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
|
|||
}
|
||||
|
||||
data->bus_clk = devm_clk_get(&pdev->dev, "bus");
|
||||
return PTR_ERR_OR_ZERO(data->bus_clk);
|
||||
if (IS_ERR(data->bus_clk))
|
||||
return PTR_ERR(data->bus_clk);
|
||||
|
||||
data->dma = NULL;
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
dmacnt = of_property_count_strings(pdev->dev.of_node, "dma-names");
|
||||
if (dmacnt == 2) {
|
||||
data->dma = devm_kzalloc(&pdev->dev, sizeof(*data->dma),
|
||||
GFP_KERNEL);
|
||||
data->dma->fn = mtk8250_dma_filter;
|
||||
data->dma->rx_size = MTK_UART_RX_SIZE;
|
||||
data->dma->rxconf.src_maxburst = MTK_UART_RX_TRIGGER;
|
||||
data->dma->txconf.dst_maxburst = MTK_UART_TX_TRIGGER;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk8250_probe(struct platform_device *pdev)
|
||||
|
@ -204,8 +406,14 @@ static int mtk8250_probe(struct platform_device *pdev)
|
|||
uart.port.iotype = UPIO_MEM32;
|
||||
uart.port.regshift = 2;
|
||||
uart.port.private_data = data;
|
||||
uart.port.shutdown = mtk8250_shutdown;
|
||||
uart.port.startup = mtk8250_startup;
|
||||
uart.port.set_termios = mtk8250_set_termios;
|
||||
uart.port.uartclk = clk_get_rate(data->uart_clk);
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
if (data->dma)
|
||||
uart.dma = data->dma;
|
||||
#endif
|
||||
|
||||
/* Disable Rate Fix function */
|
||||
writel(0x0, uart.port.membase +
|
||||
|
|
|
@ -240,6 +240,11 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
|||
if (of_property_read_bool(ofdev->dev.of_node, "auto-flow-control"))
|
||||
port8250.capabilities |= UART_CAP_AFE;
|
||||
|
||||
if (of_property_read_u32(ofdev->dev.of_node,
|
||||
"overrun-throttle-ms",
|
||||
&port8250.overrun_backoff_time_ms) != 0)
|
||||
port8250.overrun_backoff_time_ms = 0;
|
||||
|
||||
ret = serial8250_register_8250_port(&port8250);
|
||||
if (ret < 0)
|
||||
goto err_dispose;
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -1085,7 +1089,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
uart_unlock_and_check_sysrq(port, flags);
|
||||
serial8250_rpm_put(up);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1736,7 +1736,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
|
|||
else if (lsr & UART_LSR_FE)
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
if (uart_prepare_sysrq_char(port, ch))
|
||||
return;
|
||||
|
||||
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
|
||||
|
@ -1878,7 +1878,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
|||
if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
uart_unlock_and_check_sysrq(port, flags);
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_handle_irq);
|
||||
|
@ -3239,9 +3239,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
|||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
if (port->sysrq)
|
||||
locked = 0;
|
||||
else if (oops_in_progress)
|
||||
if (oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||
else
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
|
|
@ -2780,6 +2780,7 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
|
|||
.name = "sbsa-uart",
|
||||
.of_match_table = of_match_ptr(sbsa_uart_of_match),
|
||||
.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
|
||||
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2808,6 +2809,7 @@ static struct amba_driver pl011_driver = {
|
|||
.drv = {
|
||||
.name = "uart-pl011",
|
||||
.pm = &pl011_dev_pm_ops,
|
||||
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
|
||||
},
|
||||
.id_table = pl011_ids,
|
||||
.probe = pl011_probe,
|
||||
|
|
|
@ -1479,6 +1479,8 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
else
|
||||
cr1 &= ~UARTCR1_PT;
|
||||
}
|
||||
} else {
|
||||
cr1 &= ~UARTCR1_PE;
|
||||
}
|
||||
|
||||
/* ask the core to calculate the divisor */
|
||||
|
@ -1682,7 +1684,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
ctrl &= ~UARTCTRL_PE;
|
||||
ctrl |= UARTCTRL_M;
|
||||
} else {
|
||||
ctrl |= UARTCR1_PE;
|
||||
ctrl |= UARTCTRL_PE;
|
||||
if ((termios->c_cflag & CSIZE) == CS8)
|
||||
ctrl |= UARTCTRL_M;
|
||||
if (termios->c_cflag & PARODD)
|
||||
|
@ -1690,6 +1692,8 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
else
|
||||
ctrl &= ~UARTCTRL_PT;
|
||||
}
|
||||
} else {
|
||||
ctrl &= ~UARTCTRL_PE;
|
||||
}
|
||||
|
||||
/* ask the core to calculate the divisor */
|
||||
|
|
|
@ -2064,7 +2064,7 @@ imx_uart_console_setup(struct console *co, char *options)
|
|||
|
||||
retval = clk_prepare(sport->clk_per);
|
||||
if (retval)
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
clk_unprepare(sport->clk_ipg);
|
||||
|
||||
error_console:
|
||||
return retval;
|
||||
|
|
|
@ -8,24 +8,23 @@
|
|||
* Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/lantiq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#define PORT_LTQ_ASC 111
|
||||
#define MAXPORTS 2
|
||||
|
@ -105,7 +104,7 @@ static DEFINE_SPINLOCK(ltq_asc_lock);
|
|||
struct ltq_uart_port {
|
||||
struct uart_port port;
|
||||
/* clock used to derive divider */
|
||||
struct clk *fpiclk;
|
||||
struct clk *freqclk;
|
||||
/* clock gating of the ASC core */
|
||||
struct clk *clk;
|
||||
unsigned int tx_irq;
|
||||
|
@ -113,6 +112,13 @@ struct ltq_uart_port {
|
|||
unsigned int err_irq;
|
||||
};
|
||||
|
||||
static inline void asc_update_bits(u32 clear, u32 set, void __iomem *reg)
|
||||
{
|
||||
u32 tmp = readl(reg);
|
||||
|
||||
writel((tmp & ~clear) | set, reg);
|
||||
}
|
||||
|
||||
static inline struct
|
||||
ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
|
||||
{
|
||||
|
@ -138,7 +144,7 @@ lqasc_start_tx(struct uart_port *port)
|
|||
static void
|
||||
lqasc_stop_rx(struct uart_port *port)
|
||||
{
|
||||
ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
|
||||
writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -147,11 +153,11 @@ lqasc_rx_chars(struct uart_port *port)
|
|||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int ch = 0, rsr = 0, fifocnt;
|
||||
|
||||
fifocnt = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
|
||||
fifocnt = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
|
||||
while (fifocnt--) {
|
||||
u8 flag = TTY_NORMAL;
|
||||
ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
|
||||
rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
|
||||
ch = readb(port->membase + LTQ_ASC_RBUF);
|
||||
rsr = (readl(port->membase + LTQ_ASC_STATE)
|
||||
& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
|
||||
tty_flip_buffer_push(tport);
|
||||
port->icount.rx++;
|
||||
|
@ -163,16 +169,16 @@ lqasc_rx_chars(struct uart_port *port)
|
|||
if (rsr & ASCSTATE_ANY) {
|
||||
if (rsr & ASCSTATE_PE) {
|
||||
port->icount.parity++;
|
||||
ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
|
||||
asc_update_bits(0, ASCWHBSTATE_CLRPE,
|
||||
port->membase + LTQ_ASC_WHBSTATE);
|
||||
} else if (rsr & ASCSTATE_FE) {
|
||||
port->icount.frame++;
|
||||
ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
|
||||
asc_update_bits(0, ASCWHBSTATE_CLRFE,
|
||||
port->membase + LTQ_ASC_WHBSTATE);
|
||||
}
|
||||
if (rsr & ASCSTATE_ROE) {
|
||||
port->icount.overrun++;
|
||||
ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
|
||||
asc_update_bits(0, ASCWHBSTATE_CLRROE,
|
||||
port->membase + LTQ_ASC_WHBSTATE);
|
||||
}
|
||||
|
||||
|
@ -211,10 +217,10 @@ lqasc_tx_chars(struct uart_port *port)
|
|||
return;
|
||||
}
|
||||
|
||||
while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
|
||||
while (((readl(port->membase + LTQ_ASC_FSTAT) &
|
||||
ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
|
||||
if (port->x_char) {
|
||||
ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
|
||||
writeb(port->x_char, port->membase + LTQ_ASC_TBUF);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
continue;
|
||||
|
@ -223,7 +229,7 @@ lqasc_tx_chars(struct uart_port *port)
|
|||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
|
||||
writeb(port->state->xmit.buf[port->state->xmit.tail],
|
||||
port->membase + LTQ_ASC_TBUF);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
|
@ -239,7 +245,7 @@ lqasc_tx_int(int irq, void *_port)
|
|||
unsigned long flags;
|
||||
struct uart_port *port = (struct uart_port *)_port;
|
||||
spin_lock_irqsave(<q_asc_lock, flags);
|
||||
ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
|
||||
writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
|
||||
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||
lqasc_start_tx(port);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -252,7 +258,7 @@ lqasc_err_int(int irq, void *_port)
|
|||
struct uart_port *port = (struct uart_port *)_port;
|
||||
spin_lock_irqsave(<q_asc_lock, flags);
|
||||
/* clear any pending interrupts */
|
||||
ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
|
||||
asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
|
||||
ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
|
||||
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -264,7 +270,7 @@ lqasc_rx_int(int irq, void *_port)
|
|||
unsigned long flags;
|
||||
struct uart_port *port = (struct uart_port *)_port;
|
||||
spin_lock_irqsave(<q_asc_lock, flags);
|
||||
ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
|
||||
writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
|
||||
lqasc_rx_chars(port);
|
||||
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -274,7 +280,7 @@ static unsigned int
|
|||
lqasc_tx_empty(struct uart_port *port)
|
||||
{
|
||||
int status;
|
||||
status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
|
||||
status = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
|
||||
return status ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
||||
|
@ -301,18 +307,18 @@ lqasc_startup(struct uart_port *port)
|
|||
int retval;
|
||||
|
||||
if (!IS_ERR(ltq_port->clk))
|
||||
clk_enable(ltq_port->clk);
|
||||
port->uartclk = clk_get_rate(ltq_port->fpiclk);
|
||||
clk_prepare_enable(ltq_port->clk);
|
||||
port->uartclk = clk_get_rate(ltq_port->freqclk);
|
||||
|
||||
ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
|
||||
asc_update_bits(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
|
||||
port->membase + LTQ_ASC_CLC);
|
||||
|
||||
ltq_w32(0, port->membase + LTQ_ASC_PISEL);
|
||||
ltq_w32(
|
||||
writel(0, port->membase + LTQ_ASC_PISEL);
|
||||
writel(
|
||||
((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
|
||||
ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
|
||||
port->membase + LTQ_ASC_TXFCON);
|
||||
ltq_w32(
|
||||
writel(
|
||||
((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
|
||||
| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
|
||||
port->membase + LTQ_ASC_RXFCON);
|
||||
|
@ -320,7 +326,7 @@ lqasc_startup(struct uart_port *port)
|
|||
* setting enable bits
|
||||
*/
|
||||
wmb();
|
||||
ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
|
||||
asc_update_bits(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
|
||||
ASCCON_ROEN, port->membase + LTQ_ASC_CON);
|
||||
|
||||
retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
|
||||
|
@ -344,7 +350,7 @@ lqasc_startup(struct uart_port *port)
|
|||
goto err2;
|
||||
}
|
||||
|
||||
ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
|
||||
writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
|
||||
port->membase + LTQ_ASC_IRNREN);
|
||||
return 0;
|
||||
|
||||
|
@ -363,13 +369,13 @@ lqasc_shutdown(struct uart_port *port)
|
|||
free_irq(ltq_port->rx_irq, port);
|
||||
free_irq(ltq_port->err_irq, port);
|
||||
|
||||
ltq_w32(0, port->membase + LTQ_ASC_CON);
|
||||
ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
|
||||
writel(0, port->membase + LTQ_ASC_CON);
|
||||
asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
|
||||
port->membase + LTQ_ASC_RXFCON);
|
||||
ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
|
||||
asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
|
||||
port->membase + LTQ_ASC_TXFCON);
|
||||
if (!IS_ERR(ltq_port->clk))
|
||||
clk_disable(ltq_port->clk);
|
||||
clk_disable_unprepare(ltq_port->clk);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -438,7 +444,7 @@ lqasc_set_termios(struct uart_port *port,
|
|||
spin_lock_irqsave(<q_asc_lock, flags);
|
||||
|
||||
/* set up CON */
|
||||
ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
|
||||
asc_update_bits(0, con, port->membase + LTQ_ASC_CON);
|
||||
|
||||
/* Set baud rate - take a divider of 2 into account */
|
||||
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
|
||||
|
@ -446,22 +452,22 @@ lqasc_set_termios(struct uart_port *port,
|
|||
divisor = divisor / 2 - 1;
|
||||
|
||||
/* disable the baudrate generator */
|
||||
ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
|
||||
asc_update_bits(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
|
||||
|
||||
/* make sure the fractional divider is off */
|
||||
ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
|
||||
asc_update_bits(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
|
||||
|
||||
/* set up to use divisor of 2 */
|
||||
ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
|
||||
asc_update_bits(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
|
||||
|
||||
/* now we can write the new baudrate into the register */
|
||||
ltq_w32(divisor, port->membase + LTQ_ASC_BG);
|
||||
writel(divisor, port->membase + LTQ_ASC_BG);
|
||||
|
||||
/* turn the baudrate generator back on */
|
||||
ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
|
||||
asc_update_bits(0, ASCCON_R, port->membase + LTQ_ASC_CON);
|
||||
|
||||
/* enable rx */
|
||||
ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
|
||||
writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
|
||||
|
||||
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||
|
||||
|
@ -572,10 +578,10 @@ lqasc_console_putchar(struct uart_port *port, int ch)
|
|||
return;
|
||||
|
||||
do {
|
||||
fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
|
||||
fifofree = (readl(port->membase + LTQ_ASC_FSTAT)
|
||||
& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
|
||||
} while (fifofree == 0);
|
||||
ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
|
||||
writeb(ch, port->membase + LTQ_ASC_TBUF);
|
||||
}
|
||||
|
||||
static void lqasc_serial_port_write(struct uart_port *port, const char *s,
|
||||
|
@ -623,9 +629,9 @@ lqasc_console_setup(struct console *co, char *options)
|
|||
port = <q_port->port;
|
||||
|
||||
if (!IS_ERR(ltq_port->clk))
|
||||
clk_enable(ltq_port->clk);
|
||||
clk_prepare_enable(ltq_port->clk);
|
||||
|
||||
port->uartclk = clk_get_rate(ltq_port->fpiclk);
|
||||
port->uartclk = clk_get_rate(ltq_port->freqclk);
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
@ -688,7 +694,7 @@ lqasc_probe(struct platform_device *pdev)
|
|||
struct ltq_uart_port *ltq_port;
|
||||
struct uart_port *port;
|
||||
struct resource *mmres, irqres[3];
|
||||
int line = 0;
|
||||
int line;
|
||||
int ret;
|
||||
|
||||
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
@ -699,9 +705,20 @@ lqasc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* check if this is the console port */
|
||||
if (mmres->start != CPHYSADDR(LTQ_EARLY_ASC))
|
||||
line = 1;
|
||||
/* get serial id */
|
||||
line = of_alias_get_id(node, "serial");
|
||||
if (line < 0) {
|
||||
if (IS_ENABLED(CONFIG_LANTIQ)) {
|
||||
if (mmres->start == CPHYSADDR(LTQ_EARLY_ASC))
|
||||
line = 0;
|
||||
else
|
||||
line = 1;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
|
||||
line);
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
if (lqasc_port[line]) {
|
||||
dev_err(&pdev->dev, "port %d already allocated\n", line);
|
||||
|
@ -726,14 +743,22 @@ lqasc_probe(struct platform_device *pdev)
|
|||
port->irq = irqres[0].start;
|
||||
port->mapbase = mmres->start;
|
||||
|
||||
ltq_port->fpiclk = clk_get_fpi();
|
||||
if (IS_ERR(ltq_port->fpiclk)) {
|
||||
if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK))
|
||||
ltq_port->freqclk = clk_get_fpi();
|
||||
else
|
||||
ltq_port->freqclk = devm_clk_get(&pdev->dev, "freq");
|
||||
|
||||
|
||||
if (IS_ERR(ltq_port->freqclk)) {
|
||||
pr_err("failed to get fpi clk\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* not all asc ports have clock gates, lets ignore the return code */
|
||||
ltq_port->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK))
|
||||
ltq_port->clk = clk_get(&pdev->dev, NULL);
|
||||
else
|
||||
ltq_port->clk = devm_clk_get(&pdev->dev, "asc");
|
||||
|
||||
ltq_port->tx_irq = irqres[0].start;
|
||||
ltq_port->rx_irq = irqres[1].start;
|
||||
|
@ -759,7 +784,7 @@ static struct platform_driver lqasc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
int __init
|
||||
static int __init
|
||||
init_lqasc(void)
|
||||
{
|
||||
int ret;
|
||||
|
|
|
@ -833,12 +833,9 @@ static void max310x_wq_proc(struct work_struct *ws)
|
|||
|
||||
static unsigned int max310x_tx_empty(struct uart_port *port)
|
||||
{
|
||||
unsigned int lvl, sts;
|
||||
u8 lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
|
||||
|
||||
lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
|
||||
sts = max310x_port_read(port, MAX310X_IRQSTS_REG);
|
||||
|
||||
return ((sts & MAX310X_IRQ_TXEMPTY_BIT) && !lvl) ? TIOCSER_TEMT : 0;
|
||||
return lvl ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
||||
static unsigned int max310x_get_mctrl(struct uart_port *port)
|
||||
|
|
|
@ -72,6 +72,8 @@
|
|||
#define BRDV_BAUD_MASK 0x3FF
|
||||
|
||||
#define UART_OSAMP 0x14
|
||||
#define OSAMP_DEFAULT_DIVISOR 16
|
||||
#define OSAMP_DIVISORS_MASK 0x3F3F3F3F
|
||||
|
||||
#define MVEBU_NR_UARTS 2
|
||||
|
||||
|
@ -444,25 +446,34 @@ static void mvebu_uart_shutdown(struct uart_port *port)
|
|||
static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
|
||||
{
|
||||
struct mvebu_uart *mvuart = to_mvuart(port);
|
||||
unsigned int baud_rate_div;
|
||||
u32 brdv;
|
||||
unsigned int d_divisor, m_divisor;
|
||||
u32 brdv, osamp;
|
||||
|
||||
if (IS_ERR(mvuart->clk))
|
||||
return -PTR_ERR(mvuart->clk);
|
||||
|
||||
/*
|
||||
* The UART clock is divided by the value of the divisor to generate
|
||||
* UCLK_OUT clock, which is 16 times faster than the baudrate.
|
||||
* This prescaler can achieve all standard baudrates until 230400.
|
||||
* Higher baudrates could be achieved for the extended UART by using the
|
||||
* programmable oversampling stack (also called fractional divisor).
|
||||
* The baudrate is derived from the UART clock thanks to two divisors:
|
||||
* > D ("baud generator"): can divide the clock from 2 to 2^10 - 1.
|
||||
* > M ("fractional divisor"): allows a better accuracy for
|
||||
* baudrates higher than 230400.
|
||||
*
|
||||
* As the derivation of M is rather complicated, the code sticks to its
|
||||
* default value (x16) when all the prescalers are zeroed, and only
|
||||
* makes use of D to configure the desired baudrate.
|
||||
*/
|
||||
baud_rate_div = DIV_ROUND_UP(port->uartclk, baud * 16);
|
||||
m_divisor = OSAMP_DEFAULT_DIVISOR;
|
||||
d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor);
|
||||
|
||||
brdv = readl(port->membase + UART_BRDV);
|
||||
brdv &= ~BRDV_BAUD_MASK;
|
||||
brdv |= baud_rate_div;
|
||||
brdv |= d_divisor;
|
||||
writel(brdv, port->membase + UART_BRDV);
|
||||
|
||||
osamp = readl(port->membase + UART_OSAMP);
|
||||
osamp &= ~OSAMP_DIVISORS_MASK;
|
||||
writel(osamp, port->membase + UART_OSAMP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -933,7 +933,6 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
|||
struct scatterlist *sg;
|
||||
int nent;
|
||||
int fifo_size;
|
||||
int tx_empty;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
int num;
|
||||
int i;
|
||||
|
@ -958,11 +957,9 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
|||
}
|
||||
|
||||
fifo_size = max(priv->fifo_size, 1);
|
||||
tx_empty = 1;
|
||||
if (pop_tx_x(priv, xmit->buf)) {
|
||||
pch_uart_hal_write(priv, xmit->buf, 1);
|
||||
port->icount.tx++;
|
||||
tx_empty = 0;
|
||||
fifo_size--;
|
||||
}
|
||||
|
||||
|
|
|
@ -919,6 +919,7 @@ static struct platform_driver pic32_uart_platform_driver = {
|
|||
.driver = {
|
||||
.name = PIC32_DEV_NAME,
|
||||
.of_match_table = of_match_ptr(pic32_serial_dt_ids),
|
||||
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_PIC32),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1648,9 +1648,9 @@ static int __init pmz_probe(void)
|
|||
*/
|
||||
node_a = node_b = NULL;
|
||||
for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {
|
||||
if (strncmp(np->name, "ch-a", 4) == 0)
|
||||
if (of_node_name_prefix(np, "ch-a"))
|
||||
node_a = of_node_get(np);
|
||||
else if (strncmp(np->name, "ch-b", 4) == 0)
|
||||
else if (of_node_name_prefix(np, "ch-b"))
|
||||
node_b = of_node_get(np);
|
||||
}
|
||||
if (!node_a && !node_b) {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
|
||||
|
||||
#if defined(CONFIG_SERIAL_QCOM_GENI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
# define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -89,9 +93,9 @@
|
|||
#define MAX_LOOPBACK_CFG 3
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
#define RX_BYTES_PW 1
|
||||
#define CONSOLE_RX_BYTES_PW 1
|
||||
#else
|
||||
#define RX_BYTES_PW 4
|
||||
#define CONSOLE_RX_BYTES_PW 4
|
||||
#endif
|
||||
|
||||
struct qcom_geni_serial_port {
|
||||
|
@ -113,6 +117,8 @@ struct qcom_geni_serial_port {
|
|||
u32 *rx_fifo;
|
||||
u32 loopback;
|
||||
bool brk;
|
||||
|
||||
unsigned int tx_remaining;
|
||||
};
|
||||
|
||||
static const struct uart_ops qcom_geni_console_pops;
|
||||
|
@ -162,8 +168,7 @@ static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = {
|
|||
static ssize_t loopback_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, sizeof(u32), "%d\n", port->loopback);
|
||||
}
|
||||
|
@ -172,8 +177,7 @@ static ssize_t loopback_store(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
u32 loopback;
|
||||
|
||||
if (kstrtoint(buf, 0, &loopback) || loopback > MAX_LOOPBACK_CFG) {
|
||||
|
@ -435,6 +439,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
|||
struct qcom_geni_serial_port *port;
|
||||
bool locked = true;
|
||||
unsigned long flags;
|
||||
u32 geni_status;
|
||||
u32 irq_en;
|
||||
|
||||
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
|
||||
|
||||
|
@ -448,6 +454,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
|||
else
|
||||
spin_lock_irqsave(&uport->lock, flags);
|
||||
|
||||
geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS);
|
||||
|
||||
/* Cancel the current write to log the fault */
|
||||
if (!locked) {
|
||||
geni_se_cancel_m_cmd(&port->se);
|
||||
|
@ -461,9 +469,26 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
|||
}
|
||||
writel_relaxed(M_CMD_CANCEL_EN, uport->membase +
|
||||
SE_GENI_M_IRQ_CLEAR);
|
||||
} else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
|
||||
/*
|
||||
* It seems we can't interrupt existing transfers if all data
|
||||
* has been sent, in which case we need to look for done first.
|
||||
*/
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
|
||||
if (uart_circ_chars_pending(&uport->state->xmit)) {
|
||||
irq_en = readl_relaxed(uport->membase +
|
||||
SE_GENI_M_IRQ_EN);
|
||||
writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN,
|
||||
uport->membase + SE_GENI_M_IRQ_EN);
|
||||
}
|
||||
}
|
||||
|
||||
__qcom_geni_serial_console_write(uport, s, count);
|
||||
|
||||
if (port->tx_remaining)
|
||||
qcom_geni_serial_setup_tx(uport, port->tx_remaining);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&uport->lock, flags);
|
||||
}
|
||||
|
@ -495,7 +520,8 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
|
|||
continue;
|
||||
}
|
||||
|
||||
sysrq = uart_handle_sysrq_char(uport, buf[c]);
|
||||
sysrq = uart_prepare_sysrq_char(uport, buf[c]);
|
||||
|
||||
if (!sysrq)
|
||||
tty_insert_flip_char(tport, buf[c], TTY_NORMAL);
|
||||
}
|
||||
|
@ -694,40 +720,51 @@ static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop)
|
|||
port->handle_rx(uport, total_bytes, drop);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_handle_tx(struct uart_port *uport)
|
||||
static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
|
||||
bool active)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
|
||||
struct circ_buf *xmit = &uport->state->xmit;
|
||||
size_t avail;
|
||||
size_t remaining;
|
||||
size_t pending;
|
||||
int i;
|
||||
u32 status;
|
||||
u32 irq_en;
|
||||
unsigned int chunk;
|
||||
int tail;
|
||||
u32 irq_en;
|
||||
|
||||
chunk = uart_circ_chars_pending(xmit);
|
||||
status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
|
||||
/* Both FIFO and framework buffer are drained */
|
||||
if (!chunk && !status) {
|
||||
|
||||
/* Complete the current tx command before taking newly added data */
|
||||
if (active)
|
||||
pending = port->tx_remaining;
|
||||
else
|
||||
pending = uart_circ_chars_pending(xmit);
|
||||
|
||||
/* All data has been transmitted and acknowledged as received */
|
||||
if (!pending && !status && done) {
|
||||
qcom_geni_serial_stop_tx(uport);
|
||||
goto out_write_wakeup;
|
||||
}
|
||||
|
||||
if (!uart_console(uport)) {
|
||||
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
irq_en &= ~(M_TX_FIFO_WATERMARK_EN);
|
||||
writel_relaxed(0, uport->membase + SE_GENI_TX_WATERMARK_REG);
|
||||
writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
|
||||
}
|
||||
avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
|
||||
avail *= port->tx_bytes_pw;
|
||||
|
||||
avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw;
|
||||
tail = xmit->tail;
|
||||
chunk = min3((size_t)chunk, (size_t)(UART_XMIT_SIZE - tail), avail);
|
||||
chunk = min(avail, pending);
|
||||
if (!chunk)
|
||||
goto out_write_wakeup;
|
||||
|
||||
qcom_geni_serial_setup_tx(uport, chunk);
|
||||
if (!port->tx_remaining) {
|
||||
qcom_geni_serial_setup_tx(uport, pending);
|
||||
port->tx_remaining = pending;
|
||||
|
||||
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
if (!(irq_en & M_TX_FIFO_WATERMARK_EN))
|
||||
writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN,
|
||||
uport->membase + SE_GENI_M_IRQ_EN);
|
||||
}
|
||||
|
||||
remaining = chunk;
|
||||
for (i = 0; i < chunk; ) {
|
||||
|
@ -737,21 +774,38 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport)
|
|||
|
||||
memset(buf, 0, ARRAY_SIZE(buf));
|
||||
tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw);
|
||||
for (c = 0; c < tx_bytes ; c++)
|
||||
buf[c] = xmit->buf[tail + c];
|
||||
|
||||
for (c = 0; c < tx_bytes ; c++) {
|
||||
buf[c] = xmit->buf[tail++];
|
||||
tail &= UART_XMIT_SIZE - 1;
|
||||
}
|
||||
|
||||
iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
|
||||
|
||||
i += tx_bytes;
|
||||
tail += tx_bytes;
|
||||
uport->icount.tx += tx_bytes;
|
||||
remaining -= tx_bytes;
|
||||
port->tx_remaining -= tx_bytes;
|
||||
}
|
||||
|
||||
xmit->tail = tail & (UART_XMIT_SIZE - 1);
|
||||
if (uart_console(uport))
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
xmit->tail = tail;
|
||||
|
||||
/*
|
||||
* The tx fifo watermark is level triggered and latched. Though we had
|
||||
* cleared it in qcom_geni_serial_isr it will have already reasserted
|
||||
* so we must clear it again here after our writes.
|
||||
*/
|
||||
writel_relaxed(M_TX_FIFO_WATERMARK_EN,
|
||||
uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
|
||||
out_write_wakeup:
|
||||
if (!port->tx_remaining) {
|
||||
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
if (irq_en & M_TX_FIFO_WATERMARK_EN)
|
||||
writel_relaxed(irq_en & ~M_TX_FIFO_WATERMARK_EN,
|
||||
uport->membase + SE_GENI_M_IRQ_EN);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(uport);
|
||||
}
|
||||
|
@ -760,6 +814,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
|
|||
{
|
||||
unsigned int m_irq_status;
|
||||
unsigned int s_irq_status;
|
||||
unsigned int geni_status;
|
||||
struct uart_port *uport = dev;
|
||||
unsigned long flags;
|
||||
unsigned int m_irq_en;
|
||||
|
@ -773,6 +828,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
|
|||
spin_lock_irqsave(&uport->lock, flags);
|
||||
m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
|
||||
s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS);
|
||||
geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS);
|
||||
m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
|
||||
|
@ -785,9 +841,9 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
|
|||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
}
|
||||
|
||||
if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) &&
|
||||
m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
|
||||
qcom_geni_serial_handle_tx(uport);
|
||||
if (m_irq_status & m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
|
||||
qcom_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN,
|
||||
geni_status & M_GENI_CMD_ACTIVE);
|
||||
|
||||
if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) {
|
||||
if (s_irq_status & S_GP_IRQ_0_EN)
|
||||
|
@ -804,7 +860,8 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
|
|||
qcom_geni_serial_handle_rx(uport, drop_rx);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&uport->lock, flags);
|
||||
uart_unlock_and_check_sysrq(uport, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -853,11 +910,13 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
|||
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
|
||||
u32 proto;
|
||||
|
||||
if (uart_console(uport))
|
||||
if (uart_console(uport)) {
|
||||
port->tx_bytes_pw = 1;
|
||||
else
|
||||
port->rx_bytes_pw = CONSOLE_RX_BYTES_PW;
|
||||
} else {
|
||||
port->tx_bytes_pw = 4;
|
||||
port->rx_bytes_pw = RX_BYTES_PW;
|
||||
port->rx_bytes_pw = 4;
|
||||
}
|
||||
|
||||
proto = geni_se_read_proto(&port->se);
|
||||
if (proto != GENI_SE_UART) {
|
||||
|
@ -1322,49 +1381,25 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev)
|
||||
static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
struct uart_port *uport = &port->uport;
|
||||
|
||||
if (uart_console(uport)) {
|
||||
uart_suspend_port(uport->private_data, uport);
|
||||
} else {
|
||||
struct uart_state *state = uport->state;
|
||||
/*
|
||||
* If the port is open, deny system suspend.
|
||||
*/
|
||||
if (state->pm_state == UART_PM_STATE_ON)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return uart_suspend_port(uport->private_data, uport);
|
||||
}
|
||||
|
||||
static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev)
|
||||
static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
struct uart_port *uport = &port->uport;
|
||||
|
||||
if (uart_console(uport) &&
|
||||
console_suspend_enabled && uport->suspended) {
|
||||
uart_resume_port(uport->private_data, uport);
|
||||
/*
|
||||
* uart_suspend_port() invokes port shutdown which in turn
|
||||
* frees the irq. uart_resume_port invokes port startup which
|
||||
* performs request_irq. The request_irq auto-enables the IRQ.
|
||||
* In addition, resume_noirq implicitly enables the IRQ and
|
||||
* leads to an unbalanced IRQ enable warning. Disable the IRQ
|
||||
* before returning so that the warning is suppressed.
|
||||
*/
|
||||
disable_irq(uport->irq);
|
||||
}
|
||||
return 0;
|
||||
return uart_resume_port(uport->private_data, uport);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend_noirq,
|
||||
qcom_geni_serial_sys_resume_noirq)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend,
|
||||
qcom_geni_serial_sys_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_geni_serial_match_table[] = {
|
||||
|
|
|
@ -1287,7 +1287,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|||
* Ask the core to calculate the divisor for us.
|
||||
*/
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, 3000000);
|
||||
quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
|
||||
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
|
||||
quot = port->custom_divisor;
|
||||
|
@ -1365,11 +1365,14 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|||
wr_regl(port, S3C2410_ULCON, ulcon);
|
||||
wr_regl(port, S3C2410_UBRDIV, quot);
|
||||
|
||||
port->status &= ~UPSTAT_AUTOCTS;
|
||||
|
||||
umcon = rd_regl(port, S3C2410_UMCON);
|
||||
if (termios->c_cflag & CRTSCTS) {
|
||||
umcon |= S3C2410_UMCOM_AFC;
|
||||
/* Disable RTS when RX FIFO contains 63 bytes */
|
||||
umcon &= ~S3C2412_UMCON_AFC_8;
|
||||
port->status = UPSTAT_AUTOCTS;
|
||||
} else {
|
||||
umcon &= ~S3C2410_UMCOM_AFC;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#endif
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
@ -47,7 +48,6 @@
|
|||
# define MR2_STOP1 (7 << 0)
|
||||
# define MR2_STOP2 (0xf << 0)
|
||||
#define SCCNXP_SR_REG (0x01)
|
||||
#define SCCNXP_CSR_REG SCCNXP_SR_REG
|
||||
# define SR_RXRDY (1 << 0)
|
||||
# define SR_FULL (1 << 1)
|
||||
# define SR_TXRDY (1 << 2)
|
||||
|
@ -56,6 +56,8 @@
|
|||
# define SR_PE (1 << 5)
|
||||
# define SR_FE (1 << 6)
|
||||
# define SR_BRK (1 << 7)
|
||||
#define SCCNXP_CSR_REG (SCCNXP_SR_REG)
|
||||
# define CSR_TIMER_MODE (0x0d)
|
||||
#define SCCNXP_CR_REG (0x02)
|
||||
# define CR_RX_ENABLE (1 << 0)
|
||||
# define CR_RX_DISABLE (1 << 1)
|
||||
|
@ -82,9 +84,12 @@
|
|||
# define IMR_RXRDY (1 << 1)
|
||||
# define ISR_TXRDY(x) (1 << ((x * 4) + 0))
|
||||
# define ISR_RXRDY(x) (1 << ((x * 4) + 1))
|
||||
#define SCCNXP_CTPU_REG (0x06)
|
||||
#define SCCNXP_CTPL_REG (0x07)
|
||||
#define SCCNXP_IPR_REG (0x0d)
|
||||
#define SCCNXP_OPCR_REG SCCNXP_IPR_REG
|
||||
#define SCCNXP_SOP_REG (0x0e)
|
||||
#define SCCNXP_START_COUNTER_REG SCCNXP_SOP_REG
|
||||
#define SCCNXP_ROP_REG (0x0f)
|
||||
|
||||
/* Route helpers */
|
||||
|
@ -103,6 +108,8 @@ struct sccnxp_chip {
|
|||
unsigned long freq_max;
|
||||
unsigned int flags;
|
||||
unsigned int fifosize;
|
||||
/* Time between read/write cycles */
|
||||
unsigned int trwd;
|
||||
};
|
||||
|
||||
struct sccnxp_port {
|
||||
|
@ -137,6 +144,7 @@ static const struct sccnxp_chip sc2681 = {
|
|||
.freq_max = 4000000,
|
||||
.flags = SCCNXP_HAVE_IO,
|
||||
.fifosize = 3,
|
||||
.trwd = 200,
|
||||
};
|
||||
|
||||
static const struct sccnxp_chip sc2691 = {
|
||||
|
@ -147,6 +155,7 @@ static const struct sccnxp_chip sc2691 = {
|
|||
.freq_max = 4000000,
|
||||
.flags = 0,
|
||||
.fifosize = 3,
|
||||
.trwd = 150,
|
||||
};
|
||||
|
||||
static const struct sccnxp_chip sc2692 = {
|
||||
|
@ -157,6 +166,7 @@ static const struct sccnxp_chip sc2692 = {
|
|||
.freq_max = 4000000,
|
||||
.flags = SCCNXP_HAVE_IO,
|
||||
.fifosize = 3,
|
||||
.trwd = 30,
|
||||
};
|
||||
|
||||
static const struct sccnxp_chip sc2891 = {
|
||||
|
@ -167,6 +177,7 @@ static const struct sccnxp_chip sc2891 = {
|
|||
.freq_max = 8000000,
|
||||
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
||||
.fifosize = 16,
|
||||
.trwd = 27,
|
||||
};
|
||||
|
||||
static const struct sccnxp_chip sc2892 = {
|
||||
|
@ -177,6 +188,7 @@ static const struct sccnxp_chip sc2892 = {
|
|||
.freq_max = 8000000,
|
||||
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
||||
.fifosize = 16,
|
||||
.trwd = 17,
|
||||
};
|
||||
|
||||
static const struct sccnxp_chip sc28202 = {
|
||||
|
@ -187,6 +199,7 @@ static const struct sccnxp_chip sc28202 = {
|
|||
.freq_max = 50000000,
|
||||
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
||||
.fifosize = 256,
|
||||
.trwd = 10,
|
||||
};
|
||||
|
||||
static const struct sccnxp_chip sc68681 = {
|
||||
|
@ -197,6 +210,7 @@ static const struct sccnxp_chip sc68681 = {
|
|||
.freq_max = 4000000,
|
||||
.flags = SCCNXP_HAVE_IO,
|
||||
.fifosize = 3,
|
||||
.trwd = 200,
|
||||
};
|
||||
|
||||
static const struct sccnxp_chip sc68692 = {
|
||||
|
@ -207,24 +221,36 @@ static const struct sccnxp_chip sc68692 = {
|
|||
.freq_max = 4000000,
|
||||
.flags = SCCNXP_HAVE_IO,
|
||||
.fifosize = 3,
|
||||
.trwd = 200,
|
||||
};
|
||||
|
||||
static inline u8 sccnxp_read(struct uart_port *port, u8 reg)
|
||||
static u8 sccnxp_read(struct uart_port *port, u8 reg)
|
||||
{
|
||||
return readb(port->membase + (reg << port->regshift));
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
u8 ret;
|
||||
|
||||
ret = readb(port->membase + (reg << port->regshift));
|
||||
|
||||
ndelay(s->chip->trwd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
|
||||
static void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
|
||||
writeb(v, port->membase + (reg << port->regshift));
|
||||
|
||||
ndelay(s->chip->trwd);
|
||||
}
|
||||
|
||||
static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg)
|
||||
static u8 sccnxp_port_read(struct uart_port *port, u8 reg)
|
||||
{
|
||||
return sccnxp_read(port, (port->line << 3) + reg);
|
||||
}
|
||||
|
||||
static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v)
|
||||
static void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v)
|
||||
{
|
||||
sccnxp_write(port, (port->line << 3) + reg, v);
|
||||
}
|
||||
|
@ -233,7 +259,7 @@ static int sccnxp_update_best_err(int a, int b, int *besterr)
|
|||
{
|
||||
int err = abs(a - b);
|
||||
|
||||
if ((*besterr < 0) || (*besterr > err)) {
|
||||
if (*besterr > err) {
|
||||
*besterr = err;
|
||||
return 0;
|
||||
}
|
||||
|
@ -281,10 +307,22 @@ static const struct {
|
|||
static int sccnxp_set_baud(struct uart_port *port, int baud)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
int div_std, tmp_baud, bestbaud = baud, besterr = -1;
|
||||
int div_std, tmp_baud, bestbaud = INT_MAX, besterr = INT_MAX;
|
||||
struct sccnxp_chip *chip = s->chip;
|
||||
u8 i, acr = 0, csr = 0, mr0 = 0;
|
||||
|
||||
/* Find divisor to load to the timer preset registers */
|
||||
div_std = DIV_ROUND_CLOSEST(port->uartclk, 2 * 16 * baud);
|
||||
if ((div_std >= 2) && (div_std <= 0xffff)) {
|
||||
bestbaud = DIV_ROUND_CLOSEST(port->uartclk, 2 * 16 * div_std);
|
||||
sccnxp_update_best_err(baud, bestbaud, &besterr);
|
||||
csr = CSR_TIMER_MODE;
|
||||
sccnxp_port_write(port, SCCNXP_CTPU_REG, div_std >> 8);
|
||||
sccnxp_port_write(port, SCCNXP_CTPL_REG, div_std);
|
||||
/* Issue start timer/counter command */
|
||||
sccnxp_port_read(port, SCCNXP_START_COUNTER_REG);
|
||||
}
|
||||
|
||||
/* Find best baud from table */
|
||||
for (i = 0; baud_std[i].baud && besterr; i++) {
|
||||
if (baud_std[i].mr0 && !(chip->flags & SCCNXP_HAVE_MR0))
|
||||
|
|
|
@ -746,7 +746,7 @@ static void tegra_uart_stop_rx(struct uart_port *u)
|
|||
if (!tup->rx_in_progress)
|
||||
return;
|
||||
|
||||
tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */
|
||||
tegra_uart_wait_sym_time(tup, 1); /* wait one character interval */
|
||||
|
||||
ier = tup->ier_shadow;
|
||||
ier &= ~(UART_IER_RDI | UART_IER_RLSI | UART_IER_RTOIE |
|
||||
|
@ -887,7 +887,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
|
|||
*
|
||||
* EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when
|
||||
* the DATA is sitting in the FIFO and couldn't be transferred to the
|
||||
* DMA as the DMA size alignment(4 bytes) is not met. EORD will be
|
||||
* DMA as the DMA size alignment (4 bytes) is not met. EORD will be
|
||||
* triggered when there is a pause of the incomming data stream for 4
|
||||
* characters long.
|
||||
*
|
||||
|
@ -1079,7 +1079,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|||
if (tup->rts_active)
|
||||
set_rts(tup, false);
|
||||
|
||||
/* Clear all interrupts as configuration is going to be change */
|
||||
/* Clear all interrupts as configuration is going to be changed */
|
||||
tegra_uart_write(tup, tup->ier_shadow | UART_IER_RDI, UART_IER);
|
||||
tegra_uart_read(tup, UART_IER);
|
||||
tegra_uart_write(tup, 0, UART_IER);
|
||||
|
@ -1165,10 +1165,10 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|||
/* update the port timeout based on new settings */
|
||||
uart_update_timeout(u, termios->c_cflag, baud);
|
||||
|
||||
/* Make sure all write has completed */
|
||||
/* Make sure all writes have completed */
|
||||
tegra_uart_read(tup, UART_IER);
|
||||
|
||||
/* Reenable interrupt */
|
||||
/* Re-enable interrupt */
|
||||
tegra_uart_write(tup, tup->ier_shadow, UART_IER);
|
||||
tegra_uart_read(tup, UART_IER);
|
||||
|
||||
|
|
|
@ -205,10 +205,15 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
|||
if (!state->xmit.buf) {
|
||||
state->xmit.buf = (unsigned char *) page;
|
||||
uart_circ_clear(&state->xmit);
|
||||
uart_port_unlock(uport, flags);
|
||||
} else {
|
||||
uart_port_unlock(uport, flags);
|
||||
/*
|
||||
* Do not free() the page under the port lock, see
|
||||
* uart_shutdown().
|
||||
*/
|
||||
free_page(page);
|
||||
}
|
||||
uart_port_unlock(uport, flags);
|
||||
|
||||
retval = uport->ops->startup(uport);
|
||||
if (retval == 0) {
|
||||
|
@ -268,6 +273,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
|||
struct uart_port *uport = uart_port_check(state);
|
||||
struct tty_port *port = &state->port;
|
||||
unsigned long flags = 0;
|
||||
char *xmit_buf = NULL;
|
||||
|
||||
/*
|
||||
* Set the TTY IO error marker
|
||||
|
@ -298,14 +304,18 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
|||
tty_port_set_suspended(port, 0);
|
||||
|
||||
/*
|
||||
* Free the transmit buffer page.
|
||||
* Do not free() the transmit buffer page under the port lock since
|
||||
* this can create various circular locking scenarios. For instance,
|
||||
* console driver may need to allocate/free a debug object, which
|
||||
* can endup in printk() recursion.
|
||||
*/
|
||||
uart_port_lock(state, flags);
|
||||
if (state->xmit.buf) {
|
||||
free_page((unsigned long)state->xmit.buf);
|
||||
state->xmit.buf = NULL;
|
||||
}
|
||||
xmit_buf = state->xmit.buf;
|
||||
state->xmit.buf = NULL;
|
||||
uart_port_unlock(uport, flags);
|
||||
|
||||
if (xmit_buf)
|
||||
free_page((unsigned long)xmit_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1331,7 +1331,7 @@ static void sci_tx_dma_release(struct sci_port *s)
|
|||
dma_release_channel(chan);
|
||||
}
|
||||
|
||||
static void sci_submit_rx(struct sci_port *s)
|
||||
static int sci_submit_rx(struct sci_port *s, bool port_lock_held)
|
||||
{
|
||||
struct dma_chan *chan = s->chan_rx;
|
||||
struct uart_port *port = &s->port;
|
||||
|
@ -1359,19 +1359,22 @@ static void sci_submit_rx(struct sci_port *s)
|
|||
s->active_rx = s->cookie_rx[0];
|
||||
|
||||
dma_async_issue_pending(chan);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
/* Switch to PIO */
|
||||
if (!port_lock_held)
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (i)
|
||||
dmaengine_terminate_async(chan);
|
||||
for (i = 0; i < 2; i++)
|
||||
s->cookie_rx[i] = -EINVAL;
|
||||
s->active_rx = -EINVAL;
|
||||
/* Switch to PIO */
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
s->active_rx = 0;
|
||||
s->chan_rx = NULL;
|
||||
sci_start_rx(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (!port_lock_held)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static void work_fn_tx(struct work_struct *work)
|
||||
|
@ -1491,7 +1494,7 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t)
|
|||
}
|
||||
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
|
||||
sci_submit_rx(s);
|
||||
sci_submit_rx(s, true);
|
||||
|
||||
/* Direct new serial port interrupts back to CPU */
|
||||
scr = serial_port_in(port, SCSCR);
|
||||
|
@ -1617,7 +1620,7 @@ static void sci_request_dma(struct uart_port *port)
|
|||
s->chan_rx_saved = s->chan_rx = chan;
|
||||
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
|
||||
sci_submit_rx(s);
|
||||
sci_submit_rx(s, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1666,8 +1669,10 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
|||
disable_irq_nosync(irq);
|
||||
scr |= SCSCR_RDRQE;
|
||||
} else {
|
||||
if (sci_submit_rx(s, false) < 0)
|
||||
goto handle_pio;
|
||||
|
||||
scr &= ~SCSCR_RIE;
|
||||
sci_submit_rx(s);
|
||||
}
|
||||
serial_port_out(port, SCSCR, scr);
|
||||
/* Clear current interrupt */
|
||||
|
@ -1679,6 +1684,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
|||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
handle_pio:
|
||||
#endif
|
||||
|
||||
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
|
||||
|
@ -1693,7 +1700,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
|||
* of whether the I_IXOFF is set, otherwise, how is the interrupt
|
||||
* to be disabled?
|
||||
*/
|
||||
sci_receive_chars(ptr);
|
||||
sci_receive_chars(port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -1749,7 +1756,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
|
|||
} else {
|
||||
sci_handle_fifo_overrun(port);
|
||||
if (!s->chan_rx)
|
||||
sci_receive_chars(ptr);
|
||||
sci_receive_chars(port);
|
||||
}
|
||||
|
||||
sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
|
||||
|
|
|
@ -89,14 +89,14 @@ void sunserial_console_termios(struct console *con, struct device_node *uart_dp)
|
|||
int baud, bits, stop, cflag;
|
||||
char parity;
|
||||
|
||||
if (!strcmp(uart_dp->name, "rsc") ||
|
||||
!strcmp(uart_dp->name, "rsc-console") ||
|
||||
!strcmp(uart_dp->name, "rsc-control")) {
|
||||
if (of_node_name_eq(uart_dp, "rsc") ||
|
||||
of_node_name_eq(uart_dp, "rsc-console") ||
|
||||
of_node_name_eq(uart_dp, "rsc-control")) {
|
||||
mode = of_get_property(uart_dp,
|
||||
"ssp-console-modes", NULL);
|
||||
if (!mode)
|
||||
mode = "115200,8,n,1,-";
|
||||
} else if (!strcmp(uart_dp->name, "lom-console")) {
|
||||
} else if (of_node_name_eq(uart_dp, "lom-console")) {
|
||||
mode = "9600,8,n,1,-";
|
||||
} else {
|
||||
struct device_node *dp;
|
||||
|
|
|
@ -1503,8 +1503,8 @@ static int su_probe(struct platform_device *op)
|
|||
up->port.ops = &sunsu_pops;
|
||||
|
||||
ignore_line = false;
|
||||
if (!strcmp(dp->name, "rsc-console") ||
|
||||
!strcmp(dp->name, "lom-console"))
|
||||
if (of_node_name_eq(dp, "rsc-console") ||
|
||||
of_node_name_eq(dp, "lom-console"))
|
||||
ignore_line = true;
|
||||
|
||||
sunserial_console_match(SUNSU_CONSOLE(), dp,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define ULITE_NAME "ttyUL"
|
||||
#define ULITE_MAJOR 204
|
||||
|
@ -54,6 +55,7 @@
|
|||
#define ULITE_CONTROL_RST_TX 0x01
|
||||
#define ULITE_CONTROL_RST_RX 0x02
|
||||
#define ULITE_CONTROL_IE 0x10
|
||||
#define UART_AUTOSUSPEND_TIMEOUT 3000
|
||||
|
||||
/* Static pointer to console port */
|
||||
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
|
||||
|
@ -63,6 +65,7 @@ static struct uart_port *console_port;
|
|||
struct uartlite_data {
|
||||
const struct uartlite_reg_ops *reg_ops;
|
||||
struct clk *clk;
|
||||
struct uart_driver *ulite_uart_driver;
|
||||
};
|
||||
|
||||
struct uartlite_reg_ops {
|
||||
|
@ -390,12 +393,12 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
static void ulite_pm(struct uart_port *port, unsigned int state,
|
||||
unsigned int oldstate)
|
||||
{
|
||||
struct uartlite_data *pdata = port->private_data;
|
||||
|
||||
if (!state)
|
||||
clk_enable(pdata->clk);
|
||||
else
|
||||
clk_disable(pdata->clk);
|
||||
if (!state) {
|
||||
pm_runtime_get_sync(port->dev);
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
|
@ -694,7 +697,9 @@ static int ulite_release(struct device *dev)
|
|||
int rc = 0;
|
||||
|
||||
if (port) {
|
||||
rc = uart_remove_one_port(&ulite_uart_driver, port);
|
||||
struct uartlite_data *pdata = port->private_data;
|
||||
|
||||
rc = uart_remove_one_port(pdata->ulite_uart_driver, port);
|
||||
dev_set_drvdata(dev, NULL);
|
||||
port->mapbase = 0;
|
||||
}
|
||||
|
@ -712,8 +717,11 @@ static int __maybe_unused ulite_suspend(struct device *dev)
|
|||
{
|
||||
struct uart_port *port = dev_get_drvdata(dev);
|
||||
|
||||
if (port)
|
||||
uart_suspend_port(&ulite_uart_driver, port);
|
||||
if (port) {
|
||||
struct uartlite_data *pdata = port->private_data;
|
||||
|
||||
uart_suspend_port(pdata->ulite_uart_driver, port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -728,17 +736,41 @@ static int __maybe_unused ulite_resume(struct device *dev)
|
|||
{
|
||||
struct uart_port *port = dev_get_drvdata(dev);
|
||||
|
||||
if (port)
|
||||
uart_resume_port(&ulite_uart_driver, port);
|
||||
if (port) {
|
||||
struct uartlite_data *pdata = port->private_data;
|
||||
|
||||
uart_resume_port(pdata->ulite_uart_driver, port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ulite_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct uart_port *port = dev_get_drvdata(dev);
|
||||
struct uartlite_data *pdata = port->private_data;
|
||||
|
||||
clk_disable(pdata->clk);
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int __maybe_unused ulite_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct uart_port *port = dev_get_drvdata(dev);
|
||||
struct uartlite_data *pdata = port->private_data;
|
||||
|
||||
clk_enable(pdata->clk);
|
||||
return 0;
|
||||
}
|
||||
/* ---------------------------------------------------------------------
|
||||
* Platform bus binding
|
||||
*/
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume);
|
||||
static const struct dev_pm_ops ulite_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume)
|
||||
SET_RUNTIME_PM_OPS(ulite_runtime_suspend,
|
||||
ulite_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
/* Match table for of_platform binding */
|
||||
|
@ -763,6 +795,22 @@ static int ulite_probe(struct platform_device *pdev)
|
|||
if (prop)
|
||||
id = be32_to_cpup(prop);
|
||||
#endif
|
||||
if (id < 0) {
|
||||
/* Look for a serialN alias */
|
||||
id = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (id < 0)
|
||||
id = 0;
|
||||
}
|
||||
|
||||
if (!ulite_uart_driver.state) {
|
||||
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
|
||||
ret = uart_register_driver(&ulite_uart_driver);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register driver\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
|
@ -788,24 +836,22 @@ static int ulite_probe(struct platform_device *pdev)
|
|||
pdata->clk = NULL;
|
||||
}
|
||||
|
||||
pdata->ulite_uart_driver = &ulite_uart_driver;
|
||||
ret = clk_prepare_enable(pdata->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to prepare clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ulite_uart_driver.state) {
|
||||
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
|
||||
ret = uart_register_driver(&ulite_uart_driver);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register driver\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
|
||||
|
||||
clk_disable(pdata->clk);
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -814,9 +860,14 @@ static int ulite_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct uart_port *port = dev_get_drvdata(&pdev->dev);
|
||||
struct uartlite_data *pdata = port->private_data;
|
||||
int rc;
|
||||
|
||||
clk_disable_unprepare(pdata->clk);
|
||||
return ulite_release(&pdev->dev);
|
||||
clk_unprepare(pdata->clk);
|
||||
rc = ulite_release(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
|
|
|
@ -123,7 +123,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||
#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
|
||||
#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
|
||||
#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
|
||||
#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
|
||||
#define CDNS_UART_IXR_RXMASK 0x000021e7 /* Valid RX bit mask */
|
||||
|
||||
/*
|
||||
* Do not enable parity error interrupt for the following
|
||||
|
@ -364,7 +364,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
|
|||
cdns_uart_handle_tx(dev_id);
|
||||
isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
|
||||
}
|
||||
if (isrstatus & CDNS_UART_IXR_MASK)
|
||||
if (isrstatus & CDNS_UART_IXR_RXMASK)
|
||||
cdns_uart_handle_rx(dev_id, isrstatus);
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
@ -1255,7 +1255,7 @@ static int cdns_uart_suspend(struct device *device)
|
|||
|
||||
may_wake = device_may_wakeup(device);
|
||||
|
||||
if (console_suspend_enabled && may_wake) {
|
||||
if (console_suspend_enabled && uart_console(port) && may_wake) {
|
||||
unsigned long flags = 0;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
@ -1293,7 +1293,7 @@ static int cdns_uart_resume(struct device *device)
|
|||
|
||||
may_wake = device_may_wakeup(device);
|
||||
|
||||
if (console_suspend_enabled && !may_wake) {
|
||||
if (console_suspend_enabled && uart_console(port) && !may_wake) {
|
||||
clk_enable(cdns_uart->pclk);
|
||||
clk_enable(cdns_uart->uartclk);
|
||||
|
||||
|
@ -1508,8 +1508,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
|
||||
GFP_KERNEL);
|
||||
if (!cdns_uart_console)
|
||||
return -ENOMEM;
|
||||
if (!cdns_uart_console) {
|
||||
rc = -ENOMEM;
|
||||
goto err_out_id;
|
||||
}
|
||||
|
||||
strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
|
||||
sizeof(cdns_uart_console->name));
|
||||
|
@ -1624,6 +1626,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
device_init_wakeup(port->dev, true);
|
||||
|
||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
/*
|
||||
|
@ -1702,6 +1705,7 @@ static int cdns_uart_remove(struct platform_device *pdev)
|
|||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
|
||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
if (console_port == port)
|
||||
|
@ -1719,6 +1723,7 @@ static struct platform_driver cdns_uart_platform_driver = {
|
|||
.name = CDNS_UART_NAME,
|
||||
.of_match_table = cdns_uart_of_match,
|
||||
.pm = &cdns_uart_dev_pm_ops,
|
||||
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_XILINX_PS_UART),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -134,17 +134,10 @@ static struct sysrq_key_op sysrq_unraw_op = {
|
|||
|
||||
static void sysrq_handle_crash(int key)
|
||||
{
|
||||
char *killer = NULL;
|
||||
|
||||
/* we need to release the RCU read lock here,
|
||||
* otherwise we get an annoying
|
||||
* 'BUG: sleeping function called from invalid context'
|
||||
* complaint from the kernel before the panic.
|
||||
*/
|
||||
/* release the RCU read lock before crashing */
|
||||
rcu_read_unlock();
|
||||
panic_on_oops = 1; /* force panic */
|
||||
wmb();
|
||||
*killer = 1;
|
||||
|
||||
panic("sysrq triggered crash\n");
|
||||
}
|
||||
static struct sysrq_key_op sysrq_crash_op = {
|
||||
.handler = sysrq_handle_crash,
|
||||
|
@ -660,8 +653,7 @@ static void sysrq_do_reset(struct timer_list *t)
|
|||
|
||||
state->reset_requested = true;
|
||||
|
||||
ksys_sync();
|
||||
kernel_restart(NULL);
|
||||
orderly_reboot();
|
||||
}
|
||||
|
||||
static void sysrq_handle_reset_request(struct sysrq_state *state)
|
||||
|
@ -736,6 +728,8 @@ static void sysrq_of_get_keyreset_config(void)
|
|||
|
||||
/* Get reset timeout if any. */
|
||||
of_property_read_u32(np, "timeout-ms", &sysrq_reset_downtime_ms);
|
||||
|
||||
of_node_put(np);
|
||||
}
|
||||
#else
|
||||
static void sysrq_of_get_keyreset_config(void)
|
||||
|
|
|
@ -1268,14 +1268,16 @@ static int tty_reopen(struct tty_struct *tty)
|
|||
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
|
||||
return -EBUSY;
|
||||
|
||||
tty->count++;
|
||||
|
||||
if (tty->ldisc)
|
||||
return 0;
|
||||
|
||||
retval = tty_ldisc_reinit(tty, tty->termios.c_line);
|
||||
retval = tty_ldisc_lock(tty, 5 * HZ);
|
||||
if (retval)
|
||||
tty->count--;
|
||||
return retval;
|
||||
|
||||
if (!tty->ldisc)
|
||||
retval = tty_ldisc_reinit(tty, tty->termios.c_line);
|
||||
tty_ldisc_unlock(tty);
|
||||
|
||||
if (retval == 0)
|
||||
tty->count++;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -327,6 +327,11 @@ int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
|
|||
{
|
||||
int ret;
|
||||
|
||||
/* Kindly asking blocked readers to release the read side */
|
||||
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
wake_up_interruptible_all(&tty->read_wait);
|
||||
wake_up_interruptible_all(&tty->write_wait);
|
||||
|
||||
ret = __tty_ldisc_lock(tty, timeout);
|
||||
if (!ret)
|
||||
return -EBUSY;
|
||||
|
@ -337,6 +342,8 @@ int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
|
|||
void tty_ldisc_unlock(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
/* Can be cleared here - ldisc_unlock will wake up writers firstly */
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
__tty_ldisc_unlock(tty);
|
||||
}
|
||||
|
||||
|
@ -471,6 +478,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
|
|||
|
||||
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
lockdep_assert_held_exclusive(&tty->ldisc_sem);
|
||||
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||
clear_bit(TTY_LDISC_OPEN, &tty->flags);
|
||||
if (ld->ops->close)
|
||||
|
@ -492,6 +500,7 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld)
|
|||
struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
|
||||
int r;
|
||||
|
||||
lockdep_assert_held_exclusive(&tty->ldisc_sem);
|
||||
if (IS_ERR(disc))
|
||||
return PTR_ERR(disc);
|
||||
tty->ldisc = disc;
|
||||
|
@ -615,6 +624,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc);
|
|||
*/
|
||||
static void tty_ldisc_kill(struct tty_struct *tty)
|
||||
{
|
||||
lockdep_assert_held_exclusive(&tty->ldisc_sem);
|
||||
if (!tty->ldisc)
|
||||
return;
|
||||
/*
|
||||
|
@ -662,6 +672,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
|
|||
struct tty_ldisc *ld;
|
||||
int retval;
|
||||
|
||||
lockdep_assert_held_exclusive(&tty->ldisc_sem);
|
||||
ld = tty_ldisc_get(tty, disc);
|
||||
if (IS_ERR(ld)) {
|
||||
BUG_ON(disc == N_TTY);
|
||||
|
@ -760,6 +771,10 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
return retval;
|
||||
|
||||
if (o_tty) {
|
||||
/*
|
||||
* Called without o_tty->ldisc_sem held, as o_tty has been
|
||||
* just allocated and no one has a reference to it.
|
||||
*/
|
||||
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
|
||||
if (retval) {
|
||||
tty_ldisc_close(tty, tty->ldisc);
|
||||
|
@ -825,6 +840,7 @@ int tty_ldisc_init(struct tty_struct *tty)
|
|||
*/
|
||||
void tty_ldisc_deinit(struct tty_struct *tty)
|
||||
{
|
||||
/* no ldisc_sem, tty is being destroyed */
|
||||
if (tty->ldisc)
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
|
|
|
@ -34,29 +34,6 @@
|
|||
#include <linux/sched/task.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
# define __acq(l, s, t, r, c, n, i) \
|
||||
lock_acquire(&(l)->dep_map, s, t, r, c, n, i)
|
||||
# define __rel(l, n, i) \
|
||||
lock_release(&(l)->dep_map, n, i)
|
||||
#define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 1, NULL, i)
|
||||
#define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 1, n, i)
|
||||
#define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 1, NULL, i)
|
||||
#define lockdep_release(l, n, i) __rel(l, n, i)
|
||||
#else
|
||||
# define lockdep_acquire(l, s, t, i) do { } while (0)
|
||||
# define lockdep_acquire_nest(l, s, t, n, i) do { } while (0)
|
||||
# define lockdep_acquire_read(l, s, t, i) do { } while (0)
|
||||
# define lockdep_release(l, n, i) do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LOCK_STAT
|
||||
# define lock_stat(_lock, stat) lock_##stat(&(_lock)->dep_map, _RET_IP_)
|
||||
#else
|
||||
# define lock_stat(_lock, stat) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
# define LDSEM_ACTIVE_MASK 0xffffffffL
|
||||
#else
|
||||
|
@ -235,6 +212,7 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout)
|
|||
raw_spin_lock_irq(&sem->wait_lock);
|
||||
if (waiter.task) {
|
||||
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
|
||||
sem->wait_readers--;
|
||||
list_del(&waiter.list);
|
||||
raw_spin_unlock_irq(&sem->wait_lock);
|
||||
put_task_struct(waiter.task);
|
||||
|
@ -293,6 +271,16 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
|
|||
if (!locked)
|
||||
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
|
||||
list_del(&waiter.list);
|
||||
|
||||
/*
|
||||
* In case of timeout, wake up every reader who gave the right of way
|
||||
* to writer. Prevent separation readers into two groups:
|
||||
* one that helds semaphore and another that sleeps.
|
||||
* (in case of no contention with a writer)
|
||||
*/
|
||||
if (!locked && list_empty(&sem->write_wait))
|
||||
__ldsem_wake_readers(sem);
|
||||
|
||||
raw_spin_unlock_irq(&sem->wait_lock);
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
@ -310,17 +298,17 @@ static int __ldsem_down_read_nested(struct ld_semaphore *sem,
|
|||
{
|
||||
long count;
|
||||
|
||||
lockdep_acquire_read(sem, subclass, 0, _RET_IP_);
|
||||
rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
|
||||
|
||||
count = atomic_long_add_return(LDSEM_READ_BIAS, &sem->count);
|
||||
if (count <= 0) {
|
||||
lock_stat(sem, contended);
|
||||
lock_contended(&sem->dep_map, _RET_IP_);
|
||||
if (!down_read_failed(sem, count, timeout)) {
|
||||
lockdep_release(sem, 1, _RET_IP_);
|
||||
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
lock_stat(sem, acquired);
|
||||
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -329,17 +317,17 @@ static int __ldsem_down_write_nested(struct ld_semaphore *sem,
|
|||
{
|
||||
long count;
|
||||
|
||||
lockdep_acquire(sem, subclass, 0, _RET_IP_);
|
||||
rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
|
||||
|
||||
count = atomic_long_add_return(LDSEM_WRITE_BIAS, &sem->count);
|
||||
if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) {
|
||||
lock_stat(sem, contended);
|
||||
lock_contended(&sem->dep_map, _RET_IP_);
|
||||
if (!down_write_failed(sem, count, timeout)) {
|
||||
lockdep_release(sem, 1, _RET_IP_);
|
||||
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
lock_stat(sem, acquired);
|
||||
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -362,8 +350,8 @@ int ldsem_down_read_trylock(struct ld_semaphore *sem)
|
|||
|
||||
while (count >= 0) {
|
||||
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_READ_BIAS)) {
|
||||
lockdep_acquire_read(sem, 0, 1, _RET_IP_);
|
||||
lock_stat(sem, acquired);
|
||||
rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
|
||||
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -388,8 +376,8 @@ int ldsem_down_write_trylock(struct ld_semaphore *sem)
|
|||
|
||||
while ((count & LDSEM_ACTIVE_MASK) == 0) {
|
||||
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
|
||||
lockdep_acquire(sem, 0, 1, _RET_IP_);
|
||||
lock_stat(sem, acquired);
|
||||
rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
|
||||
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -403,7 +391,7 @@ void ldsem_up_read(struct ld_semaphore *sem)
|
|||
{
|
||||
long count;
|
||||
|
||||
lockdep_release(sem, 1, _RET_IP_);
|
||||
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
||||
|
||||
count = atomic_long_add_return(-LDSEM_READ_BIAS, &sem->count);
|
||||
if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
|
||||
|
@ -417,7 +405,7 @@ void ldsem_up_write(struct ld_semaphore *sem)
|
|||
{
|
||||
long count;
|
||||
|
||||
lockdep_release(sem, 1, _RET_IP_);
|
||||
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
||||
|
||||
count = atomic_long_add_return(-LDSEM_WRITE_BIAS, &sem->count);
|
||||
if (count < 0)
|
||||
|
|
|
@ -32,6 +32,7 @@ struct font_desc {
|
|||
#define ACORN8x8_IDX 8
|
||||
#define MINI4x6_IDX 9
|
||||
#define FONT6x10_IDX 10
|
||||
#define TER16x32_IDX 11
|
||||
|
||||
extern const struct font_desc font_vga_8x8,
|
||||
font_vga_8x16,
|
||||
|
@ -43,7 +44,8 @@ extern const struct font_desc font_vga_8x8,
|
|||
font_sun_12x22,
|
||||
font_acorn_8x8,
|
||||
font_mini_4x6,
|
||||
font_6x10;
|
||||
font_6x10,
|
||||
font_ter_16x32;
|
||||
|
||||
/* Find a font with a specific name */
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __LINUX_LANTIQ_H
|
||||
#define __LINUX_LANTIQ_H
|
||||
|
||||
#ifdef CONFIG_LANTIQ
|
||||
#include <lantiq_soc.h>
|
||||
#else
|
||||
|
||||
#ifndef LTQ_EARLY_ASC
|
||||
#define LTQ_EARLY_ASC 0
|
||||
#endif
|
||||
|
||||
#ifndef CPHYSADDR
|
||||
#define CPHYSADDR(a) 0
|
||||
#endif
|
||||
|
||||
static inline struct clk *clk_get_fpi(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_LANTIQ */
|
||||
#endif /* __LINUX_LANTIQ_H */
|
|
@ -210,7 +210,7 @@ void serdev_device_wait_until_sent(struct serdev_device *, long);
|
|||
int serdev_device_get_tiocm(struct serdev_device *);
|
||||
int serdev_device_set_tiocm(struct serdev_device *, int, int);
|
||||
void serdev_device_write_wakeup(struct serdev_device *);
|
||||
int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, unsigned long);
|
||||
int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, long);
|
||||
void serdev_device_write_flush(struct serdev_device *);
|
||||
int serdev_device_write_room(struct serdev_device *);
|
||||
|
||||
|
|
|
@ -134,6 +134,10 @@ struct uart_8250_port {
|
|||
void (*dl_write)(struct uart_8250_port *, int);
|
||||
|
||||
struct uart_8250_em485 *em485;
|
||||
|
||||
/* Serial port overrun backoff */
|
||||
struct delayed_work overrun_backoff;
|
||||
u32 overrun_backoff_time_ms;
|
||||
};
|
||||
|
||||
static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -175,6 +176,7 @@ struct uart_port {
|
|||
struct console *cons; /* struct console, if any */
|
||||
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
|
||||
unsigned long sysrq; /* sysrq timeout */
|
||||
unsigned int sysrq_ch; /* char for sysrq */
|
||||
#endif
|
||||
|
||||
/* flags must be updated while holding port mutex */
|
||||
|
@ -485,8 +487,42 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
static inline int
|
||||
uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
if (port->sysrq) {
|
||||
if (ch && time_before(jiffies, port->sysrq)) {
|
||||
port->sysrq_ch = ch;
|
||||
port->sysrq = 0;
|
||||
return 1;
|
||||
}
|
||||
port->sysrq = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static inline void
|
||||
uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
|
||||
{
|
||||
int sysrq_ch;
|
||||
|
||||
sysrq_ch = port->sysrq_ch;
|
||||
port->sysrq_ch = 0;
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, irqflags);
|
||||
|
||||
if (sysrq_ch)
|
||||
handle_sysrq(sysrq_ch);
|
||||
}
|
||||
#else
|
||||
#define uart_handle_sysrq_char(port,ch) ({ (void)port; 0; })
|
||||
static inline int
|
||||
uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) { return 0; }
|
||||
static inline int
|
||||
uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) { return 0; }
|
||||
static inline void
|
||||
uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
|
||||
{
|
||||
spin_unlock_irqrestore(&port->lock, irqflags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -366,6 +366,7 @@ struct tty_file_private {
|
|||
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
|
||||
#define TTY_HUPPED 18 /* Post driver->hangup() */
|
||||
#define TTY_HUPPING 19 /* Hangup in progress */
|
||||
#define TTY_LDISC_CHANGING 20 /* Change pending - non-block IO */
|
||||
#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
|
||||
|
||||
/* Values for tty->flow_change */
|
||||
|
@ -383,6 +384,12 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val)
|
|||
smp_mb();
|
||||
}
|
||||
|
||||
static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
return file->f_flags & O_NONBLOCK ||
|
||||
test_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
}
|
||||
|
||||
static inline bool tty_io_error(struct tty_struct *tty)
|
||||
{
|
||||
return test_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
|
|
@ -109,6 +109,15 @@ config FONT_SUN12x22
|
|||
big letters (like the letters used in the SPARC PROM). If the
|
||||
standard font is unreadable for you, say Y, otherwise say N.
|
||||
|
||||
config FONT_TER16x32
|
||||
bool "Terminus 16x32 font (not supported by all drivers)"
|
||||
depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
|
||||
help
|
||||
Terminus Font is a clean, fixed width bitmap font, designed
|
||||
for long (8 and more hours per day) work with computers.
|
||||
This is the high resolution, large version for use with HiDPI screens.
|
||||
If the standard font is unreadable for you, say Y, otherwise say N.
|
||||
|
||||
config FONT_AUTOSELECT
|
||||
def_bool y
|
||||
depends on !FONT_8x8
|
||||
|
@ -121,6 +130,7 @@ config FONT_AUTOSELECT
|
|||
depends on !FONT_SUN8x16
|
||||
depends on !FONT_SUN12x22
|
||||
depends on !FONT_10x18
|
||||
depends on !FONT_TER16x32
|
||||
select FONT_8x16
|
||||
|
||||
endif # FONT_SUPPORT
|
||||
|
|
|
@ -14,6 +14,7 @@ font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
|
|||
font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
|
||||
font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
|
||||
font-objs-$(CONFIG_FONT_6x10) += font_6x10.o
|
||||
font-objs-$(CONFIG_FONT_TER16x32) += font_ter16x32.o
|
||||
|
||||
font-objs += $(font-objs-y)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -67,6 +67,10 @@ static const struct font_desc *fonts[] = {
|
|||
#undef NO_FONTS
|
||||
&font_6x10,
|
||||
#endif
|
||||
#ifdef CONFIG_FONT_TER16x32
|
||||
#undef NO_FONTS
|
||||
&font_ter_16x32,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define num_fonts ARRAY_SIZE(fonts)
|
||||
|
|
Loading…
Reference in New Issue