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
|
- tx-threshold: Specify the TX FIFO low water indication for parts with
|
||||||
programmable TX FIFO thresholds.
|
programmable TX FIFO thresholds.
|
||||||
- resets : phandle + reset specifier pairs
|
- resets : phandle + reset specifier pairs
|
||||||
|
- overrun-throttle-ms : how long to pause uart rx when input overrun is encountered.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
* fsl,ns16550:
|
* fsl,ns16550:
|
||||||
|
|
|
@ -8,6 +8,8 @@ Required properties:
|
||||||
on LS1021A SoC with 32-bit big-endian register organization
|
on LS1021A SoC with 32-bit big-endian register organization
|
||||||
- "fsl,imx7ulp-lpuart" for lpuart compatible with the one integrated
|
- "fsl,imx7ulp-lpuart" for lpuart compatible with the one integrated
|
||||||
on i.MX7ULP SoC with 32-bit little-endian register organization
|
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
|
- reg : Address and length of the register set for the device
|
||||||
- interrupts : Should contain uart interrupt
|
- interrupts : Should contain uart interrupt
|
||||||
- clocks : phandle + clock specifier pairs, one for each entry in clock-names
|
- 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
|
- interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier
|
||||||
depends on the interrupt-parent interrupt controller.
|
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:
|
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 {
|
asc1: serial@e100c00 {
|
||||||
compatible = "lantiq,asc";
|
compatible = "lantiq,asc";
|
||||||
reg = <0xE100C00 0x400>;
|
reg = <0xE100C00 0x400>;
|
||||||
|
|
|
@ -24,6 +24,10 @@ Required properties:
|
||||||
- "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
|
- "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
|
||||||
- "renesas,scif-r8a77470" for R8A77470 (RZ/G1C) SCIF compatible UART.
|
- "renesas,scif-r8a77470" for R8A77470 (RZ/G1C) SCIF compatible UART.
|
||||||
- "renesas,hscif-r8a77470" for R8A77470 (RZ/G1C) HSCIF 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-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART.
|
||||||
- "renesas,scif-r8a7779" for R8A7779 (R-Car H1) 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.
|
- "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,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||||
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB 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-gen1-scif" for R-Car Gen1 SCIF compatible UART,
|
||||||
- "renesas,rcar-gen2-scif" for R-Car Gen2 SCIF compatible UART,
|
- "renesas,rcar-gen2-scif" for R-Car Gen2 and RZ/G1 SCIF compatible UART,
|
||||||
- "renesas,rcar-gen3-scif" for R-Car Gen3 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 SCIFA compatible UART,
|
- "renesas,rcar-gen2-scifa" for R-Car Gen2 and RZ/G1 SCIFA compatible UART,
|
||||||
- "renesas,rcar-gen2-scifb" for R-Car Gen2 SCIFB 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-gen1-hscif" for R-Car Gen1 HSCIF compatible UART,
|
||||||
- "renesas,rcar-gen2-hscif" for R-Car Gen2 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 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,scif" for generic SCIF compatible UART.
|
||||||
- "renesas,scifa" for generic SCIFA compatible UART.
|
- "renesas,scifa" for generic SCIFA compatible UART.
|
||||||
- "renesas,scifb" for generic SCIFB compatible UART.
|
- "renesas,scifb" for generic SCIFB compatible UART.
|
||||||
|
|
|
@ -66,6 +66,14 @@ config TTY_PRINTK
|
||||||
|
|
||||||
If unsure, say N.
|
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
|
config PRINTER
|
||||||
tristate "Parallel printer support"
|
tristate "Parallel printer support"
|
||||||
depends on PARPORT
|
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_STR_SIZE 508 /* should be bigger then max expected line length */
|
||||||
#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
|
#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 int tpk_curr;
|
||||||
|
|
||||||
static char tpk_buffer[TPK_STR_SIZE + 4];
|
static char tpk_buffer[TPK_STR_SIZE + 4];
|
||||||
|
@ -45,7 +47,7 @@ static void tpk_flush(void)
|
||||||
{
|
{
|
||||||
if (tpk_curr > 0) {
|
if (tpk_curr > 0) {
|
||||||
tpk_buffer[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;
|
tpk_curr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ static int gnss_serial_write_raw(struct gnss_device *gdev,
|
||||||
|
|
||||||
/* write is only buffered synchronously */
|
/* write is only buffered synchronously */
|
||||||
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||||
if (ret < 0)
|
if (ret < 0 || ret < count)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* FIXME: determine if interrupted? */
|
/* 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 */
|
/* write is only buffered synchronously */
|
||||||
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||||
if (ret < 0)
|
if (ret < 0 || ret < count)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* FIXME: determine if interrupted? */
|
/* FIXME: determine if interrupted? */
|
||||||
|
|
|
@ -353,7 +353,7 @@ void __init hvc_opal_init_early(void)
|
||||||
if (!opal)
|
if (!opal)
|
||||||
return;
|
return;
|
||||||
for_each_child_of_node(opal, np) {
|
for_each_child_of_node(opal, np) {
|
||||||
if (!strcmp(np->name, "serial")) {
|
if (of_node_name_eq(np, "serial")) {
|
||||||
stdout_node = np;
|
stdout_node = np;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,20 +371,11 @@ device_initcall(hvc_vio_init); /* after drivers/tty/hvc/hvc_console.c */
|
||||||
void __init hvc_vio_init_early(void)
|
void __init hvc_vio_init_early(void)
|
||||||
{
|
{
|
||||||
const __be32 *termno;
|
const __be32 *termno;
|
||||||
const char *name;
|
|
||||||
const struct hv_ops *ops;
|
const struct hv_ops *ops;
|
||||||
|
|
||||||
/* find the boot console from /chosen/stdout */
|
/* 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 */
|
/* Check if it's a virtual terminal */
|
||||||
if (strncmp(name, "vty", 3) != 0)
|
if (!of_node_name_prefix(of_stdout, "vty"))
|
||||||
return;
|
return;
|
||||||
termno = of_get_property(of_stdout, "reg", NULL);
|
termno = of_get_property(of_stdout, "reg", NULL);
|
||||||
if (termno == NULL)
|
if (termno == NULL)
|
||||||
|
|
|
@ -612,7 +612,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no data */
|
/* no data */
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (tty_io_nonblock(tty, file)) {
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -679,7 +679,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
|
||||||
if (tbuf)
|
if (tbuf)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (tty_io_nonblock(tty, file)) {
|
||||||
error = -EAGAIN;
|
error = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1085,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||||
pMsg = remove_msg(pInfo, pClient);
|
pMsg = remove_msg(pInfo, pClient);
|
||||||
if (pMsg == NULL) {
|
if (pMsg == NULL) {
|
||||||
/* no messages available. */
|
/* no messages available. */
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (tty_io_nonblock(tty, file)) {
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1702,7 +1702,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
||||||
|
|
||||||
down_read(&tty->termios_rwsem);
|
down_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
while (1) {
|
do {
|
||||||
/*
|
/*
|
||||||
* When PARMRK is set, each input char may take up to 3 chars
|
* When PARMRK is set, each input char may take up to 3 chars
|
||||||
* in the read buf; reduce the buffer space avail by 3x
|
* 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;
|
fp += n;
|
||||||
count -= n;
|
count -= n;
|
||||||
rcvd += n;
|
rcvd += n;
|
||||||
}
|
} while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
|
||||||
|
|
||||||
tty->receive_room = room;
|
tty->receive_room = room;
|
||||||
|
|
||||||
|
@ -2211,7 +2211,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||||
break;
|
break;
|
||||||
if (!timeout)
|
if (!timeout)
|
||||||
break;
|
break;
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (tty_io_nonblock(tty, file)) {
|
||||||
retval = -EAGAIN;
|
retval = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2365,7 +2365,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
|
||||||
}
|
}
|
||||||
if (!nr)
|
if (!nr)
|
||||||
break;
|
break;
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (tty_io_nonblock(tty, file)) {
|
||||||
retval = -EAGAIN;
|
retval = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/pm_domain.h>
|
#include <linux/pm_domain.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
#include <linux/serdev.h>
|
#include <linux/serdev.h>
|
||||||
#include <linux/slab.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);
|
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,
|
int serdev_device_write_buf(struct serdev_device *serdev,
|
||||||
const unsigned char *buf, size_t count)
|
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);
|
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,
|
int serdev_device_write(struct serdev_device *serdev,
|
||||||
const unsigned char *buf, size_t count,
|
const unsigned char *buf, size_t count,
|
||||||
unsigned long timeout)
|
long timeout)
|
||||||
{
|
{
|
||||||
struct serdev_controller *ctrl = serdev->ctrl;
|
struct serdev_controller *ctrl = serdev->ctrl;
|
||||||
|
int written = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!ctrl || !ctrl->ops->write_buf ||
|
if (!ctrl || !ctrl->ops->write_buf || !serdev->ops->write_wakeup)
|
||||||
(timeout && !serdev->ops->write_wakeup))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (timeout == 0)
|
||||||
|
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||||
|
|
||||||
mutex_lock(&serdev->write_lock);
|
mutex_lock(&serdev->write_lock);
|
||||||
do {
|
do {
|
||||||
reinit_completion(&serdev->write_comp);
|
reinit_completion(&serdev->write_comp);
|
||||||
|
@ -247,14 +288,29 @@ int serdev_device_write(struct serdev_device *serdev,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
written += ret;
|
||||||
buf += ret;
|
buf += ret;
|
||||||
count -= ret;
|
count -= ret;
|
||||||
|
|
||||||
} while (count &&
|
if (count == 0)
|
||||||
(timeout = wait_for_completion_timeout(&serdev->write_comp,
|
break;
|
||||||
timeout)));
|
|
||||||
|
timeout = wait_for_completion_interruptible_timeout(&serdev->write_comp,
|
||||||
|
timeout);
|
||||||
|
} while (timeout > 0);
|
||||||
mutex_unlock(&serdev->write_lock);
|
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);
|
EXPORT_SYMBOL_GPL(serdev_device_write);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
* Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp.
|
* Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp.
|
||||||
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, 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/device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_address.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)
|
if (lsr & UART_LSR_THRE)
|
||||||
serial8250_tx_chars(up);
|
serial8250_tx_chars(up);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
uart_unlock_and_check_sysrq(port, flags);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -942,6 +942,21 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
||||||
return NULL;
|
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
|
* serial8250_register_8250_port - register a serial port
|
||||||
* @up: serial port template
|
* @up: serial port template
|
||||||
|
@ -1056,6 +1071,16 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||||
ret = 0;
|
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);
|
mutex_unlock(&serial_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// 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_reg.h>
|
||||||
#include <linux/serial_8250.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);
|
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);
|
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);
|
serial8250_modem_status(up);
|
||||||
|
|
||||||
|
@ -54,7 +79,7 @@ int fsl8250_handle_irq(struct uart_port *port)
|
||||||
serial8250_tx_chars(up);
|
serial8250_tx_chars(up);
|
||||||
|
|
||||||
up->lsr_saved_flags = orig_lsr;
|
up->lsr_saved_flags = orig_lsr;
|
||||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
uart_unlock_and_check_sysrq(&up->port, flags);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
|
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
#include <linux/serial_reg.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"
|
#include "8250.h"
|
||||||
|
|
||||||
|
@ -22,12 +26,172 @@
|
||||||
#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
|
#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
|
||||||
#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix 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 {
|
struct mtk8250_data {
|
||||||
int line;
|
int line;
|
||||||
|
unsigned int rx_pos;
|
||||||
struct clk *uart_clk;
|
struct clk *uart_clk;
|
||||||
struct clk *bus_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
|
static void
|
||||||
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
struct ktermios *old)
|
struct ktermios *old)
|
||||||
|
@ -36,6 +200,17 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int baud, quot;
|
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);
|
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);
|
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,
|
static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
|
||||||
struct mtk8250_data *data)
|
struct mtk8250_data *data)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SERIAL_8250_DMA
|
||||||
|
int dmacnt;
|
||||||
|
#endif
|
||||||
|
|
||||||
data->uart_clk = devm_clk_get(&pdev->dev, "baud");
|
data->uart_clk = devm_clk_get(&pdev->dev, "baud");
|
||||||
if (IS_ERR(data->uart_clk)) {
|
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");
|
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)
|
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.iotype = UPIO_MEM32;
|
||||||
uart.port.regshift = 2;
|
uart.port.regshift = 2;
|
||||||
uart.port.private_data = data;
|
uart.port.private_data = data;
|
||||||
|
uart.port.shutdown = mtk8250_shutdown;
|
||||||
|
uart.port.startup = mtk8250_startup;
|
||||||
uart.port.set_termios = mtk8250_set_termios;
|
uart.port.set_termios = mtk8250_set_termios;
|
||||||
uart.port.uartclk = clk_get_rate(data->uart_clk);
|
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 */
|
/* Disable Rate Fix function */
|
||||||
writel(0x0, uart.port.membase +
|
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"))
|
if (of_property_read_bool(ofdev->dev.of_node, "auto-flow-control"))
|
||||||
port8250.capabilities |= UART_CAP_AFE;
|
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);
|
ret = serial8250_register_8250_port(&port8250);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_dispose;
|
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/device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/module.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);
|
serial8250_rpm_put(up);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1736,7 +1736,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
|
||||||
else if (lsr & UART_LSR_FE)
|
else if (lsr & UART_LSR_FE)
|
||||||
flag = TTY_FRAME;
|
flag = TTY_FRAME;
|
||||||
}
|
}
|
||||||
if (uart_handle_sysrq_char(port, ch))
|
if (uart_prepare_sysrq_char(port, ch))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
|
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))
|
if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
|
||||||
serial8250_tx_chars(up);
|
serial8250_tx_chars(up);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
uart_unlock_and_check_sysrq(port, flags);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(serial8250_handle_irq);
|
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);
|
serial8250_rpm_get(up);
|
||||||
|
|
||||||
if (port->sysrq)
|
if (oops_in_progress)
|
||||||
locked = 0;
|
|
||||||
else if (oops_in_progress)
|
|
||||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||||
else
|
else
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
|
|
@ -2780,6 +2780,7 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
|
||||||
.name = "sbsa-uart",
|
.name = "sbsa-uart",
|
||||||
.of_match_table = of_match_ptr(sbsa_uart_of_match),
|
.of_match_table = of_match_ptr(sbsa_uart_of_match),
|
||||||
.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_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 = {
|
.drv = {
|
||||||
.name = "uart-pl011",
|
.name = "uart-pl011",
|
||||||
.pm = &pl011_dev_pm_ops,
|
.pm = &pl011_dev_pm_ops,
|
||||||
|
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
|
||||||
},
|
},
|
||||||
.id_table = pl011_ids,
|
.id_table = pl011_ids,
|
||||||
.probe = pl011_probe,
|
.probe = pl011_probe,
|
||||||
|
|
|
@ -1479,6 +1479,8 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
else
|
else
|
||||||
cr1 &= ~UARTCR1_PT;
|
cr1 &= ~UARTCR1_PT;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cr1 &= ~UARTCR1_PE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ask the core to calculate the divisor */
|
/* 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_PE;
|
||||||
ctrl |= UARTCTRL_M;
|
ctrl |= UARTCTRL_M;
|
||||||
} else {
|
} else {
|
||||||
ctrl |= UARTCR1_PE;
|
ctrl |= UARTCTRL_PE;
|
||||||
if ((termios->c_cflag & CSIZE) == CS8)
|
if ((termios->c_cflag & CSIZE) == CS8)
|
||||||
ctrl |= UARTCTRL_M;
|
ctrl |= UARTCTRL_M;
|
||||||
if (termios->c_cflag & PARODD)
|
if (termios->c_cflag & PARODD)
|
||||||
|
@ -1690,6 +1692,8 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
else
|
else
|
||||||
ctrl &= ~UARTCTRL_PT;
|
ctrl &= ~UARTCTRL_PT;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ctrl &= ~UARTCTRL_PE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ask the core to calculate the divisor */
|
/* 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);
|
retval = clk_prepare(sport->clk_per);
|
||||||
if (retval)
|
if (retval)
|
||||||
clk_disable_unprepare(sport->clk_ipg);
|
clk_unprepare(sport->clk_ipg);
|
||||||
|
|
||||||
error_console:
|
error_console:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
@ -8,24 +8,23 @@
|
||||||
* Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
|
* Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/ioport.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
#include <linux/sysrq.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/tty.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/tty_flip.h>
|
#include <linux/init.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/io.h>
|
||||||
#include <linux/serial.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/lantiq.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/io.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/serial_core.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include <lantiq_soc.h>
|
#include <linux/sysrq.h>
|
||||||
|
#include <linux/tty.h>
|
||||||
|
#include <linux/tty_flip.h>
|
||||||
|
|
||||||
#define PORT_LTQ_ASC 111
|
#define PORT_LTQ_ASC 111
|
||||||
#define MAXPORTS 2
|
#define MAXPORTS 2
|
||||||
|
@ -105,7 +104,7 @@ static DEFINE_SPINLOCK(ltq_asc_lock);
|
||||||
struct ltq_uart_port {
|
struct ltq_uart_port {
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
/* clock used to derive divider */
|
/* clock used to derive divider */
|
||||||
struct clk *fpiclk;
|
struct clk *freqclk;
|
||||||
/* clock gating of the ASC core */
|
/* clock gating of the ASC core */
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
unsigned int tx_irq;
|
unsigned int tx_irq;
|
||||||
|
@ -113,6 +112,13 @@ struct ltq_uart_port {
|
||||||
unsigned int err_irq;
|
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
|
static inline struct
|
||||||
ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
|
ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
|
||||||
{
|
{
|
||||||
|
@ -138,7 +144,7 @@ lqasc_start_tx(struct uart_port *port)
|
||||||
static void
|
static void
|
||||||
lqasc_stop_rx(struct uart_port *port)
|
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
|
static int
|
||||||
|
@ -147,11 +153,11 @@ lqasc_rx_chars(struct uart_port *port)
|
||||||
struct tty_port *tport = &port->state->port;
|
struct tty_port *tport = &port->state->port;
|
||||||
unsigned int ch = 0, rsr = 0, fifocnt;
|
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--) {
|
while (fifocnt--) {
|
||||||
u8 flag = TTY_NORMAL;
|
u8 flag = TTY_NORMAL;
|
||||||
ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
|
ch = readb(port->membase + LTQ_ASC_RBUF);
|
||||||
rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
|
rsr = (readl(port->membase + LTQ_ASC_STATE)
|
||||||
& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
|
& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
|
||||||
tty_flip_buffer_push(tport);
|
tty_flip_buffer_push(tport);
|
||||||
port->icount.rx++;
|
port->icount.rx++;
|
||||||
|
@ -163,16 +169,16 @@ lqasc_rx_chars(struct uart_port *port)
|
||||||
if (rsr & ASCSTATE_ANY) {
|
if (rsr & ASCSTATE_ANY) {
|
||||||
if (rsr & ASCSTATE_PE) {
|
if (rsr & ASCSTATE_PE) {
|
||||||
port->icount.parity++;
|
port->icount.parity++;
|
||||||
ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
|
asc_update_bits(0, ASCWHBSTATE_CLRPE,
|
||||||
port->membase + LTQ_ASC_WHBSTATE);
|
port->membase + LTQ_ASC_WHBSTATE);
|
||||||
} else if (rsr & ASCSTATE_FE) {
|
} else if (rsr & ASCSTATE_FE) {
|
||||||
port->icount.frame++;
|
port->icount.frame++;
|
||||||
ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
|
asc_update_bits(0, ASCWHBSTATE_CLRFE,
|
||||||
port->membase + LTQ_ASC_WHBSTATE);
|
port->membase + LTQ_ASC_WHBSTATE);
|
||||||
}
|
}
|
||||||
if (rsr & ASCSTATE_ROE) {
|
if (rsr & ASCSTATE_ROE) {
|
||||||
port->icount.overrun++;
|
port->icount.overrun++;
|
||||||
ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
|
asc_update_bits(0, ASCWHBSTATE_CLRROE,
|
||||||
port->membase + LTQ_ASC_WHBSTATE);
|
port->membase + LTQ_ASC_WHBSTATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,10 +217,10 @@ lqasc_tx_chars(struct uart_port *port)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
|
while (((readl(port->membase + LTQ_ASC_FSTAT) &
|
||||||
ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
|
ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
|
||||||
if (port->x_char) {
|
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->icount.tx++;
|
||||||
port->x_char = 0;
|
port->x_char = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -223,7 +229,7 @@ lqasc_tx_chars(struct uart_port *port)
|
||||||
if (uart_circ_empty(xmit))
|
if (uart_circ_empty(xmit))
|
||||||
break;
|
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);
|
port->membase + LTQ_ASC_TBUF);
|
||||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||||
port->icount.tx++;
|
port->icount.tx++;
|
||||||
|
@ -239,7 +245,7 @@ lqasc_tx_int(int irq, void *_port)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct uart_port *port = (struct uart_port *)_port;
|
struct uart_port *port = (struct uart_port *)_port;
|
||||||
spin_lock_irqsave(<q_asc_lock, flags);
|
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);
|
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||||
lqasc_start_tx(port);
|
lqasc_start_tx(port);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -252,7 +258,7 @@ lqasc_err_int(int irq, void *_port)
|
||||||
struct uart_port *port = (struct uart_port *)_port;
|
struct uart_port *port = (struct uart_port *)_port;
|
||||||
spin_lock_irqsave(<q_asc_lock, flags);
|
spin_lock_irqsave(<q_asc_lock, flags);
|
||||||
/* clear any pending interrupts */
|
/* 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);
|
ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
|
||||||
spin_unlock_irqrestore(<q_asc_lock, flags);
|
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -264,7 +270,7 @@ lqasc_rx_int(int irq, void *_port)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct uart_port *port = (struct uart_port *)_port;
|
struct uart_port *port = (struct uart_port *)_port;
|
||||||
spin_lock_irqsave(<q_asc_lock, flags);
|
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);
|
lqasc_rx_chars(port);
|
||||||
spin_unlock_irqrestore(<q_asc_lock, flags);
|
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -274,7 +280,7 @@ static unsigned int
|
||||||
lqasc_tx_empty(struct uart_port *port)
|
lqasc_tx_empty(struct uart_port *port)
|
||||||
{
|
{
|
||||||
int status;
|
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;
|
return status ? 0 : TIOCSER_TEMT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,18 +307,18 @@ lqasc_startup(struct uart_port *port)
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (!IS_ERR(ltq_port->clk))
|
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);
|
||||||
|
|
||||||
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);
|
port->membase + LTQ_ASC_CLC);
|
||||||
|
|
||||||
ltq_w32(0, port->membase + LTQ_ASC_PISEL);
|
writel(0, port->membase + LTQ_ASC_PISEL);
|
||||||
ltq_w32(
|
writel(
|
||||||
((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
|
((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
|
||||||
ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
|
ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
|
||||||
port->membase + LTQ_ASC_TXFCON);
|
port->membase + LTQ_ASC_TXFCON);
|
||||||
ltq_w32(
|
writel(
|
||||||
((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
|
((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
|
||||||
| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
|
| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
|
||||||
port->membase + LTQ_ASC_RXFCON);
|
port->membase + LTQ_ASC_RXFCON);
|
||||||
|
@ -320,7 +326,7 @@ lqasc_startup(struct uart_port *port)
|
||||||
* setting enable bits
|
* setting enable bits
|
||||||
*/
|
*/
|
||||||
wmb();
|
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);
|
ASCCON_ROEN, port->membase + LTQ_ASC_CON);
|
||||||
|
|
||||||
retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
|
retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
|
||||||
|
@ -344,7 +350,7 @@ lqasc_startup(struct uart_port *port)
|
||||||
goto err2;
|
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);
|
port->membase + LTQ_ASC_IRNREN);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -363,13 +369,13 @@ lqasc_shutdown(struct uart_port *port)
|
||||||
free_irq(ltq_port->rx_irq, port);
|
free_irq(ltq_port->rx_irq, port);
|
||||||
free_irq(ltq_port->err_irq, port);
|
free_irq(ltq_port->err_irq, port);
|
||||||
|
|
||||||
ltq_w32(0, port->membase + LTQ_ASC_CON);
|
writel(0, port->membase + LTQ_ASC_CON);
|
||||||
ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
|
asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
|
||||||
port->membase + LTQ_ASC_RXFCON);
|
port->membase + LTQ_ASC_RXFCON);
|
||||||
ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
|
asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
|
||||||
port->membase + LTQ_ASC_TXFCON);
|
port->membase + LTQ_ASC_TXFCON);
|
||||||
if (!IS_ERR(ltq_port->clk))
|
if (!IS_ERR(ltq_port->clk))
|
||||||
clk_disable(ltq_port->clk);
|
clk_disable_unprepare(ltq_port->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -438,7 +444,7 @@ lqasc_set_termios(struct uart_port *port,
|
||||||
spin_lock_irqsave(<q_asc_lock, flags);
|
spin_lock_irqsave(<q_asc_lock, flags);
|
||||||
|
|
||||||
/* set up CON */
|
/* 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 */
|
/* Set baud rate - take a divider of 2 into account */
|
||||||
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
|
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;
|
divisor = divisor / 2 - 1;
|
||||||
|
|
||||||
/* disable the baudrate generator */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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);
|
spin_unlock_irqrestore(<q_asc_lock, flags);
|
||||||
|
|
||||||
|
@ -572,10 +578,10 @@ lqasc_console_putchar(struct uart_port *port, int ch)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
|
fifofree = (readl(port->membase + LTQ_ASC_FSTAT)
|
||||||
& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
|
& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
|
||||||
} while (fifofree == 0);
|
} 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,
|
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;
|
port = <q_port->port;
|
||||||
|
|
||||||
if (!IS_ERR(ltq_port->clk))
|
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)
|
if (options)
|
||||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
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 ltq_uart_port *ltq_port;
|
||||||
struct uart_port *port;
|
struct uart_port *port;
|
||||||
struct resource *mmres, irqres[3];
|
struct resource *mmres, irqres[3];
|
||||||
int line = 0;
|
int line;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
@ -699,9 +705,20 @@ lqasc_probe(struct platform_device *pdev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if this is the console port */
|
/* get serial id */
|
||||||
if (mmres->start != CPHYSADDR(LTQ_EARLY_ASC))
|
line = of_alias_get_id(node, "serial");
|
||||||
line = 1;
|
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]) {
|
if (lqasc_port[line]) {
|
||||||
dev_err(&pdev->dev, "port %d already allocated\n", 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->irq = irqres[0].start;
|
||||||
port->mapbase = mmres->start;
|
port->mapbase = mmres->start;
|
||||||
|
|
||||||
ltq_port->fpiclk = clk_get_fpi();
|
if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK))
|
||||||
if (IS_ERR(ltq_port->fpiclk)) {
|
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");
|
pr_err("failed to get fpi clk\n");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not all asc ports have clock gates, lets ignore the return code */
|
/* 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->tx_irq = irqres[0].start;
|
||||||
ltq_port->rx_irq = irqres[1].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)
|
init_lqasc(void)
|
||||||
{
|
{
|
||||||
int ret;
|
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)
|
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);
|
return lvl ? 0 : TIOCSER_TEMT;
|
||||||
sts = max310x_port_read(port, MAX310X_IRQSTS_REG);
|
|
||||||
|
|
||||||
return ((sts & MAX310X_IRQ_TXEMPTY_BIT) && !lvl) ? TIOCSER_TEMT : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int max310x_get_mctrl(struct uart_port *port)
|
static unsigned int max310x_get_mctrl(struct uart_port *port)
|
||||||
|
|
|
@ -72,6 +72,8 @@
|
||||||
#define BRDV_BAUD_MASK 0x3FF
|
#define BRDV_BAUD_MASK 0x3FF
|
||||||
|
|
||||||
#define UART_OSAMP 0x14
|
#define UART_OSAMP 0x14
|
||||||
|
#define OSAMP_DEFAULT_DIVISOR 16
|
||||||
|
#define OSAMP_DIVISORS_MASK 0x3F3F3F3F
|
||||||
|
|
||||||
#define MVEBU_NR_UARTS 2
|
#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)
|
static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
|
||||||
{
|
{
|
||||||
struct mvebu_uart *mvuart = to_mvuart(port);
|
struct mvebu_uart *mvuart = to_mvuart(port);
|
||||||
unsigned int baud_rate_div;
|
unsigned int d_divisor, m_divisor;
|
||||||
u32 brdv;
|
u32 brdv, osamp;
|
||||||
|
|
||||||
if (IS_ERR(mvuart->clk))
|
if (IS_ERR(mvuart->clk))
|
||||||
return -PTR_ERR(mvuart->clk);
|
return -PTR_ERR(mvuart->clk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The UART clock is divided by the value of the divisor to generate
|
* The baudrate is derived from the UART clock thanks to two divisors:
|
||||||
* UCLK_OUT clock, which is 16 times faster than the baudrate.
|
* > D ("baud generator"): can divide the clock from 2 to 2^10 - 1.
|
||||||
* This prescaler can achieve all standard baudrates until 230400.
|
* > M ("fractional divisor"): allows a better accuracy for
|
||||||
* Higher baudrates could be achieved for the extended UART by using the
|
* baudrates higher than 230400.
|
||||||
* programmable oversampling stack (also called fractional divisor).
|
*
|
||||||
|
* 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 = readl(port->membase + UART_BRDV);
|
||||||
brdv &= ~BRDV_BAUD_MASK;
|
brdv &= ~BRDV_BAUD_MASK;
|
||||||
brdv |= baud_rate_div;
|
brdv |= d_divisor;
|
||||||
writel(brdv, port->membase + UART_BRDV);
|
writel(brdv, port->membase + UART_BRDV);
|
||||||
|
|
||||||
|
osamp = readl(port->membase + UART_OSAMP);
|
||||||
|
osamp &= ~OSAMP_DIVISORS_MASK;
|
||||||
|
writel(osamp, port->membase + UART_OSAMP);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -933,7 +933,6 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
int nent;
|
int nent;
|
||||||
int fifo_size;
|
int fifo_size;
|
||||||
int tx_empty;
|
|
||||||
struct dma_async_tx_descriptor *desc;
|
struct dma_async_tx_descriptor *desc;
|
||||||
int num;
|
int num;
|
||||||
int i;
|
int i;
|
||||||
|
@ -958,11 +957,9 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
||||||
}
|
}
|
||||||
|
|
||||||
fifo_size = max(priv->fifo_size, 1);
|
fifo_size = max(priv->fifo_size, 1);
|
||||||
tx_empty = 1;
|
|
||||||
if (pop_tx_x(priv, xmit->buf)) {
|
if (pop_tx_x(priv, xmit->buf)) {
|
||||||
pch_uart_hal_write(priv, xmit->buf, 1);
|
pch_uart_hal_write(priv, xmit->buf, 1);
|
||||||
port->icount.tx++;
|
port->icount.tx++;
|
||||||
tx_empty = 0;
|
|
||||||
fifo_size--;
|
fifo_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -919,6 +919,7 @@ static struct platform_driver pic32_uart_platform_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = PIC32_DEV_NAME,
|
.name = PIC32_DEV_NAME,
|
||||||
.of_match_table = of_match_ptr(pic32_serial_dt_ids),
|
.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;
|
node_a = node_b = NULL;
|
||||||
for (np = NULL; (np = of_get_next_child(node_p, np)) != 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);
|
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);
|
node_b = of_node_get(np);
|
||||||
}
|
}
|
||||||
if (!node_a && !node_b) {
|
if (!node_a && !node_b) {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
|
// 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/clk.h>
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -89,9 +93,9 @@
|
||||||
#define MAX_LOOPBACK_CFG 3
|
#define MAX_LOOPBACK_CFG 3
|
||||||
|
|
||||||
#ifdef CONFIG_CONSOLE_POLL
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
#define RX_BYTES_PW 1
|
#define CONSOLE_RX_BYTES_PW 1
|
||||||
#else
|
#else
|
||||||
#define RX_BYTES_PW 4
|
#define CONSOLE_RX_BYTES_PW 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct qcom_geni_serial_port {
|
struct qcom_geni_serial_port {
|
||||||
|
@ -113,6 +117,8 @@ struct qcom_geni_serial_port {
|
||||||
u32 *rx_fifo;
|
u32 *rx_fifo;
|
||||||
u32 loopback;
|
u32 loopback;
|
||||||
bool brk;
|
bool brk;
|
||||||
|
|
||||||
|
unsigned int tx_remaining;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct uart_ops qcom_geni_console_pops;
|
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,
|
static ssize_t loopback_show(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||||
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
return snprintf(buf, sizeof(u32), "%d\n", port->loopback);
|
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,
|
struct device_attribute *attr, const char *buf,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||||
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
|
|
||||||
u32 loopback;
|
u32 loopback;
|
||||||
|
|
||||||
if (kstrtoint(buf, 0, &loopback) || loopback > MAX_LOOPBACK_CFG) {
|
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;
|
struct qcom_geni_serial_port *port;
|
||||||
bool locked = true;
|
bool locked = true;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u32 geni_status;
|
||||||
|
u32 irq_en;
|
||||||
|
|
||||||
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
|
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
|
else
|
||||||
spin_lock_irqsave(&uport->lock, flags);
|
spin_lock_irqsave(&uport->lock, flags);
|
||||||
|
|
||||||
|
geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS);
|
||||||
|
|
||||||
/* Cancel the current write to log the fault */
|
/* Cancel the current write to log the fault */
|
||||||
if (!locked) {
|
if (!locked) {
|
||||||
geni_se_cancel_m_cmd(&port->se);
|
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 +
|
writel_relaxed(M_CMD_CANCEL_EN, uport->membase +
|
||||||
SE_GENI_M_IRQ_CLEAR);
|
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);
|
__qcom_geni_serial_console_write(uport, s, count);
|
||||||
|
|
||||||
|
if (port->tx_remaining)
|
||||||
|
qcom_geni_serial_setup_tx(uport, port->tx_remaining);
|
||||||
|
|
||||||
if (locked)
|
if (locked)
|
||||||
spin_unlock_irqrestore(&uport->lock, flags);
|
spin_unlock_irqrestore(&uport->lock, flags);
|
||||||
}
|
}
|
||||||
|
@ -495,7 +520,8 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sysrq = uart_handle_sysrq_char(uport, buf[c]);
|
sysrq = uart_prepare_sysrq_char(uport, buf[c]);
|
||||||
|
|
||||||
if (!sysrq)
|
if (!sysrq)
|
||||||
tty_insert_flip_char(tport, buf[c], TTY_NORMAL);
|
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);
|
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 qcom_geni_serial_port *port = to_dev_port(uport, uport);
|
||||||
struct circ_buf *xmit = &uport->state->xmit;
|
struct circ_buf *xmit = &uport->state->xmit;
|
||||||
size_t avail;
|
size_t avail;
|
||||||
size_t remaining;
|
size_t remaining;
|
||||||
|
size_t pending;
|
||||||
int i;
|
int i;
|
||||||
u32 status;
|
u32 status;
|
||||||
|
u32 irq_en;
|
||||||
unsigned int chunk;
|
unsigned int chunk;
|
||||||
int tail;
|
int tail;
|
||||||
u32 irq_en;
|
|
||||||
|
|
||||||
chunk = uart_circ_chars_pending(xmit);
|
|
||||||
status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
|
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);
|
qcom_geni_serial_stop_tx(uport);
|
||||||
goto out_write_wakeup;
|
goto out_write_wakeup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uart_console(uport)) {
|
avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
|
||||||
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
|
avail *= port->tx_bytes_pw;
|
||||||
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 - port->tx_wm) * port->tx_bytes_pw;
|
|
||||||
tail = xmit->tail;
|
tail = xmit->tail;
|
||||||
chunk = min3((size_t)chunk, (size_t)(UART_XMIT_SIZE - tail), avail);
|
chunk = min(avail, pending);
|
||||||
if (!chunk)
|
if (!chunk)
|
||||||
goto out_write_wakeup;
|
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;
|
remaining = chunk;
|
||||||
for (i = 0; i < 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));
|
memset(buf, 0, ARRAY_SIZE(buf));
|
||||||
tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw);
|
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);
|
iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
|
||||||
|
|
||||||
i += tx_bytes;
|
i += tx_bytes;
|
||||||
tail += tx_bytes;
|
|
||||||
uport->icount.tx += tx_bytes;
|
uport->icount.tx += tx_bytes;
|
||||||
remaining -= tx_bytes;
|
remaining -= tx_bytes;
|
||||||
|
port->tx_remaining -= tx_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmit->tail = tail & (UART_XMIT_SIZE - 1);
|
xmit->tail = tail;
|
||||||
if (uart_console(uport))
|
|
||||||
qcom_geni_serial_poll_tx_done(uport);
|
/*
|
||||||
|
* 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:
|
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)
|
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||||
uart_write_wakeup(uport);
|
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 m_irq_status;
|
||||||
unsigned int s_irq_status;
|
unsigned int s_irq_status;
|
||||||
|
unsigned int geni_status;
|
||||||
struct uart_port *uport = dev;
|
struct uart_port *uport = dev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int m_irq_en;
|
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);
|
spin_lock_irqsave(&uport->lock, flags);
|
||||||
m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
|
m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
|
||||||
s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_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);
|
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(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||||
writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_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);
|
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) &&
|
if (m_irq_status & m_irq_en & (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, m_irq_status & M_CMD_DONE_EN,
|
||||||
qcom_geni_serial_handle_tx(uport);
|
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 || s_irq_status & S_GP_IRQ_1_EN) {
|
||||||
if (s_irq_status & S_GP_IRQ_0_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);
|
qcom_geni_serial_handle_rx(uport, drop_rx);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock_irqrestore(&uport->lock, flags);
|
uart_unlock_and_check_sysrq(uport, flags);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
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;
|
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
|
||||||
u32 proto;
|
u32 proto;
|
||||||
|
|
||||||
if (uart_console(uport))
|
if (uart_console(uport)) {
|
||||||
port->tx_bytes_pw = 1;
|
port->tx_bytes_pw = 1;
|
||||||
else
|
port->rx_bytes_pw = CONSOLE_RX_BYTES_PW;
|
||||||
|
} else {
|
||||||
port->tx_bytes_pw = 4;
|
port->tx_bytes_pw = 4;
|
||||||
port->rx_bytes_pw = RX_BYTES_PW;
|
port->rx_bytes_pw = 4;
|
||||||
|
}
|
||||||
|
|
||||||
proto = geni_se_read_proto(&port->se);
|
proto = geni_se_read_proto(&port->se);
|
||||||
if (proto != GENI_SE_UART) {
|
if (proto != GENI_SE_UART) {
|
||||||
|
@ -1322,49 +1381,25 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
|
||||||
return 0;
|
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 qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||||
struct uart_port *uport = &port->uport;
|
struct uart_port *uport = &port->uport;
|
||||||
|
|
||||||
if (uart_console(uport)) {
|
return uart_suspend_port(uport->private_data, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||||
struct uart_port *uport = &port->uport;
|
struct uart_port *uport = &port->uport;
|
||||||
|
|
||||||
if (uart_console(uport) &&
|
return uart_resume_port(uport->private_data, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
|
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
|
||||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend_noirq,
|
SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend,
|
||||||
qcom_geni_serial_sys_resume_noirq)
|
qcom_geni_serial_sys_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id qcom_geni_serial_match_table[] = {
|
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.
|
* 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);
|
quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
|
||||||
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
|
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
|
||||||
quot = port->custom_divisor;
|
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_ULCON, ulcon);
|
||||||
wr_regl(port, S3C2410_UBRDIV, quot);
|
wr_regl(port, S3C2410_UBRDIV, quot);
|
||||||
|
|
||||||
|
port->status &= ~UPSTAT_AUTOCTS;
|
||||||
|
|
||||||
umcon = rd_regl(port, S3C2410_UMCON);
|
umcon = rd_regl(port, S3C2410_UMCON);
|
||||||
if (termios->c_cflag & CRTSCTS) {
|
if (termios->c_cflag & CRTSCTS) {
|
||||||
umcon |= S3C2410_UMCOM_AFC;
|
umcon |= S3C2410_UMCOM_AFC;
|
||||||
/* Disable RTS when RX FIFO contains 63 bytes */
|
/* Disable RTS when RX FIFO contains 63 bytes */
|
||||||
umcon &= ~S3C2412_UMCON_AFC_8;
|
umcon &= ~S3C2412_UMCON_AFC_8;
|
||||||
|
port->status = UPSTAT_AUTOCTS;
|
||||||
} else {
|
} else {
|
||||||
umcon &= ~S3C2410_UMCOM_AFC;
|
umcon &= ~S3C2410_UMCOM_AFC;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mod_devicetable.h>
|
#include <linux/mod_devicetable.h>
|
||||||
|
@ -47,7 +48,6 @@
|
||||||
# define MR2_STOP1 (7 << 0)
|
# define MR2_STOP1 (7 << 0)
|
||||||
# define MR2_STOP2 (0xf << 0)
|
# define MR2_STOP2 (0xf << 0)
|
||||||
#define SCCNXP_SR_REG (0x01)
|
#define SCCNXP_SR_REG (0x01)
|
||||||
#define SCCNXP_CSR_REG SCCNXP_SR_REG
|
|
||||||
# define SR_RXRDY (1 << 0)
|
# define SR_RXRDY (1 << 0)
|
||||||
# define SR_FULL (1 << 1)
|
# define SR_FULL (1 << 1)
|
||||||
# define SR_TXRDY (1 << 2)
|
# define SR_TXRDY (1 << 2)
|
||||||
|
@ -56,6 +56,8 @@
|
||||||
# define SR_PE (1 << 5)
|
# define SR_PE (1 << 5)
|
||||||
# define SR_FE (1 << 6)
|
# define SR_FE (1 << 6)
|
||||||
# define SR_BRK (1 << 7)
|
# define SR_BRK (1 << 7)
|
||||||
|
#define SCCNXP_CSR_REG (SCCNXP_SR_REG)
|
||||||
|
# define CSR_TIMER_MODE (0x0d)
|
||||||
#define SCCNXP_CR_REG (0x02)
|
#define SCCNXP_CR_REG (0x02)
|
||||||
# define CR_RX_ENABLE (1 << 0)
|
# define CR_RX_ENABLE (1 << 0)
|
||||||
# define CR_RX_DISABLE (1 << 1)
|
# define CR_RX_DISABLE (1 << 1)
|
||||||
|
@ -82,9 +84,12 @@
|
||||||
# define IMR_RXRDY (1 << 1)
|
# define IMR_RXRDY (1 << 1)
|
||||||
# define ISR_TXRDY(x) (1 << ((x * 4) + 0))
|
# define ISR_TXRDY(x) (1 << ((x * 4) + 0))
|
||||||
# define ISR_RXRDY(x) (1 << ((x * 4) + 1))
|
# 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_IPR_REG (0x0d)
|
||||||
#define SCCNXP_OPCR_REG SCCNXP_IPR_REG
|
#define SCCNXP_OPCR_REG SCCNXP_IPR_REG
|
||||||
#define SCCNXP_SOP_REG (0x0e)
|
#define SCCNXP_SOP_REG (0x0e)
|
||||||
|
#define SCCNXP_START_COUNTER_REG SCCNXP_SOP_REG
|
||||||
#define SCCNXP_ROP_REG (0x0f)
|
#define SCCNXP_ROP_REG (0x0f)
|
||||||
|
|
||||||
/* Route helpers */
|
/* Route helpers */
|
||||||
|
@ -103,6 +108,8 @@ struct sccnxp_chip {
|
||||||
unsigned long freq_max;
|
unsigned long freq_max;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned int fifosize;
|
unsigned int fifosize;
|
||||||
|
/* Time between read/write cycles */
|
||||||
|
unsigned int trwd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sccnxp_port {
|
struct sccnxp_port {
|
||||||
|
@ -137,6 +144,7 @@ static const struct sccnxp_chip sc2681 = {
|
||||||
.freq_max = 4000000,
|
.freq_max = 4000000,
|
||||||
.flags = SCCNXP_HAVE_IO,
|
.flags = SCCNXP_HAVE_IO,
|
||||||
.fifosize = 3,
|
.fifosize = 3,
|
||||||
|
.trwd = 200,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sccnxp_chip sc2691 = {
|
static const struct sccnxp_chip sc2691 = {
|
||||||
|
@ -147,6 +155,7 @@ static const struct sccnxp_chip sc2691 = {
|
||||||
.freq_max = 4000000,
|
.freq_max = 4000000,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.fifosize = 3,
|
.fifosize = 3,
|
||||||
|
.trwd = 150,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sccnxp_chip sc2692 = {
|
static const struct sccnxp_chip sc2692 = {
|
||||||
|
@ -157,6 +166,7 @@ static const struct sccnxp_chip sc2692 = {
|
||||||
.freq_max = 4000000,
|
.freq_max = 4000000,
|
||||||
.flags = SCCNXP_HAVE_IO,
|
.flags = SCCNXP_HAVE_IO,
|
||||||
.fifosize = 3,
|
.fifosize = 3,
|
||||||
|
.trwd = 30,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sccnxp_chip sc2891 = {
|
static const struct sccnxp_chip sc2891 = {
|
||||||
|
@ -167,6 +177,7 @@ static const struct sccnxp_chip sc2891 = {
|
||||||
.freq_max = 8000000,
|
.freq_max = 8000000,
|
||||||
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
||||||
.fifosize = 16,
|
.fifosize = 16,
|
||||||
|
.trwd = 27,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sccnxp_chip sc2892 = {
|
static const struct sccnxp_chip sc2892 = {
|
||||||
|
@ -177,6 +188,7 @@ static const struct sccnxp_chip sc2892 = {
|
||||||
.freq_max = 8000000,
|
.freq_max = 8000000,
|
||||||
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
||||||
.fifosize = 16,
|
.fifosize = 16,
|
||||||
|
.trwd = 17,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sccnxp_chip sc28202 = {
|
static const struct sccnxp_chip sc28202 = {
|
||||||
|
@ -187,6 +199,7 @@ static const struct sccnxp_chip sc28202 = {
|
||||||
.freq_max = 50000000,
|
.freq_max = 50000000,
|
||||||
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
|
||||||
.fifosize = 256,
|
.fifosize = 256,
|
||||||
|
.trwd = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sccnxp_chip sc68681 = {
|
static const struct sccnxp_chip sc68681 = {
|
||||||
|
@ -197,6 +210,7 @@ static const struct sccnxp_chip sc68681 = {
|
||||||
.freq_max = 4000000,
|
.freq_max = 4000000,
|
||||||
.flags = SCCNXP_HAVE_IO,
|
.flags = SCCNXP_HAVE_IO,
|
||||||
.fifosize = 3,
|
.fifosize = 3,
|
||||||
|
.trwd = 200,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sccnxp_chip sc68692 = {
|
static const struct sccnxp_chip sc68692 = {
|
||||||
|
@ -207,24 +221,36 @@ static const struct sccnxp_chip sc68692 = {
|
||||||
.freq_max = 4000000,
|
.freq_max = 4000000,
|
||||||
.flags = SCCNXP_HAVE_IO,
|
.flags = SCCNXP_HAVE_IO,
|
||||||
.fifosize = 3,
|
.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));
|
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);
|
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);
|
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);
|
int err = abs(a - b);
|
||||||
|
|
||||||
if ((*besterr < 0) || (*besterr > err)) {
|
if (*besterr > err) {
|
||||||
*besterr = err;
|
*besterr = err;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -281,10 +307,22 @@ static const struct {
|
||||||
static int sccnxp_set_baud(struct uart_port *port, int baud)
|
static int sccnxp_set_baud(struct uart_port *port, int baud)
|
||||||
{
|
{
|
||||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
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;
|
struct sccnxp_chip *chip = s->chip;
|
||||||
u8 i, acr = 0, csr = 0, mr0 = 0;
|
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 */
|
/* Find best baud from table */
|
||||||
for (i = 0; baud_std[i].baud && besterr; i++) {
|
for (i = 0; baud_std[i].baud && besterr; i++) {
|
||||||
if (baud_std[i].mr0 && !(chip->flags & SCCNXP_HAVE_MR0))
|
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)
|
if (!tup->rx_in_progress)
|
||||||
return;
|
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 = tup->ier_shadow;
|
||||||
ier &= ~(UART_IER_RDI | UART_IER_RLSI | UART_IER_RTOIE |
|
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
|
* 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
|
* 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
|
* triggered when there is a pause of the incomming data stream for 4
|
||||||
* characters long.
|
* characters long.
|
||||||
*
|
*
|
||||||
|
@ -1079,7 +1079,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
||||||
if (tup->rts_active)
|
if (tup->rts_active)
|
||||||
set_rts(tup, false);
|
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_write(tup, tup->ier_shadow | UART_IER_RDI, UART_IER);
|
||||||
tegra_uart_read(tup, UART_IER);
|
tegra_uart_read(tup, UART_IER);
|
||||||
tegra_uart_write(tup, 0, 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 */
|
/* update the port timeout based on new settings */
|
||||||
uart_update_timeout(u, termios->c_cflag, baud);
|
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);
|
tegra_uart_read(tup, UART_IER);
|
||||||
|
|
||||||
/* Reenable interrupt */
|
/* Re-enable interrupt */
|
||||||
tegra_uart_write(tup, tup->ier_shadow, UART_IER);
|
tegra_uart_write(tup, tup->ier_shadow, UART_IER);
|
||||||
tegra_uart_read(tup, 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) {
|
if (!state->xmit.buf) {
|
||||||
state->xmit.buf = (unsigned char *) page;
|
state->xmit.buf = (unsigned char *) page;
|
||||||
uart_circ_clear(&state->xmit);
|
uart_circ_clear(&state->xmit);
|
||||||
|
uart_port_unlock(uport, flags);
|
||||||
} else {
|
} else {
|
||||||
|
uart_port_unlock(uport, flags);
|
||||||
|
/*
|
||||||
|
* Do not free() the page under the port lock, see
|
||||||
|
* uart_shutdown().
|
||||||
|
*/
|
||||||
free_page(page);
|
free_page(page);
|
||||||
}
|
}
|
||||||
uart_port_unlock(uport, flags);
|
|
||||||
|
|
||||||
retval = uport->ops->startup(uport);
|
retval = uport->ops->startup(uport);
|
||||||
if (retval == 0) {
|
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 uart_port *uport = uart_port_check(state);
|
||||||
struct tty_port *port = &state->port;
|
struct tty_port *port = &state->port;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
|
char *xmit_buf = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the TTY IO error marker
|
* 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);
|
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);
|
uart_port_lock(state, flags);
|
||||||
if (state->xmit.buf) {
|
xmit_buf = state->xmit.buf;
|
||||||
free_page((unsigned long)state->xmit.buf);
|
state->xmit.buf = NULL;
|
||||||
state->xmit.buf = NULL;
|
|
||||||
}
|
|
||||||
uart_port_unlock(uport, flags);
|
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);
|
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 dma_chan *chan = s->chan_rx;
|
||||||
struct uart_port *port = &s->port;
|
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];
|
s->active_rx = s->cookie_rx[0];
|
||||||
|
|
||||||
dma_async_issue_pending(chan);
|
dma_async_issue_pending(chan);
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
/* Switch to PIO */
|
||||||
|
if (!port_lock_held)
|
||||||
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
if (i)
|
if (i)
|
||||||
dmaengine_terminate_async(chan);
|
dmaengine_terminate_async(chan);
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
s->cookie_rx[i] = -EINVAL;
|
s->cookie_rx[i] = -EINVAL;
|
||||||
s->active_rx = -EINVAL;
|
s->active_rx = 0;
|
||||||
/* Switch to PIO */
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
|
||||||
s->chan_rx = NULL;
|
s->chan_rx = NULL;
|
||||||
sci_start_rx(port);
|
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)
|
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)
|
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 */
|
/* Direct new serial port interrupts back to CPU */
|
||||||
scr = serial_port_in(port, SCSCR);
|
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;
|
s->chan_rx_saved = s->chan_rx = chan;
|
||||||
|
|
||||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
|
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);
|
disable_irq_nosync(irq);
|
||||||
scr |= SCSCR_RDRQE;
|
scr |= SCSCR_RDRQE;
|
||||||
} else {
|
} else {
|
||||||
|
if (sci_submit_rx(s, false) < 0)
|
||||||
|
goto handle_pio;
|
||||||
|
|
||||||
scr &= ~SCSCR_RIE;
|
scr &= ~SCSCR_RIE;
|
||||||
sci_submit_rx(s);
|
|
||||||
}
|
}
|
||||||
serial_port_out(port, SCSCR, scr);
|
serial_port_out(port, SCSCR, scr);
|
||||||
/* Clear current interrupt */
|
/* Clear current interrupt */
|
||||||
|
@ -1679,6 +1684,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle_pio:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
|
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
|
* of whether the I_IXOFF is set, otherwise, how is the interrupt
|
||||||
* to be disabled?
|
* to be disabled?
|
||||||
*/
|
*/
|
||||||
sci_receive_chars(ptr);
|
sci_receive_chars(port);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -1749,7 +1756,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
|
||||||
} else {
|
} else {
|
||||||
sci_handle_fifo_overrun(port);
|
sci_handle_fifo_overrun(port);
|
||||||
if (!s->chan_rx)
|
if (!s->chan_rx)
|
||||||
sci_receive_chars(ptr);
|
sci_receive_chars(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(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;
|
int baud, bits, stop, cflag;
|
||||||
char parity;
|
char parity;
|
||||||
|
|
||||||
if (!strcmp(uart_dp->name, "rsc") ||
|
if (of_node_name_eq(uart_dp, "rsc") ||
|
||||||
!strcmp(uart_dp->name, "rsc-console") ||
|
of_node_name_eq(uart_dp, "rsc-console") ||
|
||||||
!strcmp(uart_dp->name, "rsc-control")) {
|
of_node_name_eq(uart_dp, "rsc-control")) {
|
||||||
mode = of_get_property(uart_dp,
|
mode = of_get_property(uart_dp,
|
||||||
"ssp-console-modes", NULL);
|
"ssp-console-modes", NULL);
|
||||||
if (!mode)
|
if (!mode)
|
||||||
mode = "115200,8,n,1,-";
|
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,-";
|
mode = "9600,8,n,1,-";
|
||||||
} else {
|
} else {
|
||||||
struct device_node *dp;
|
struct device_node *dp;
|
||||||
|
|
|
@ -1503,8 +1503,8 @@ static int su_probe(struct platform_device *op)
|
||||||
up->port.ops = &sunsu_pops;
|
up->port.ops = &sunsu_pops;
|
||||||
|
|
||||||
ignore_line = false;
|
ignore_line = false;
|
||||||
if (!strcmp(dp->name, "rsc-console") ||
|
if (of_node_name_eq(dp, "rsc-console") ||
|
||||||
!strcmp(dp->name, "lom-console"))
|
of_node_name_eq(dp, "lom-console"))
|
||||||
ignore_line = true;
|
ignore_line = true;
|
||||||
|
|
||||||
sunserial_console_match(SUNSU_CONSOLE(), dp,
|
sunserial_console_match(SUNSU_CONSOLE(), dp,
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#define ULITE_NAME "ttyUL"
|
#define ULITE_NAME "ttyUL"
|
||||||
#define ULITE_MAJOR 204
|
#define ULITE_MAJOR 204
|
||||||
|
@ -54,6 +55,7 @@
|
||||||
#define ULITE_CONTROL_RST_TX 0x01
|
#define ULITE_CONTROL_RST_TX 0x01
|
||||||
#define ULITE_CONTROL_RST_RX 0x02
|
#define ULITE_CONTROL_RST_RX 0x02
|
||||||
#define ULITE_CONTROL_IE 0x10
|
#define ULITE_CONTROL_IE 0x10
|
||||||
|
#define UART_AUTOSUSPEND_TIMEOUT 3000
|
||||||
|
|
||||||
/* Static pointer to console port */
|
/* Static pointer to console port */
|
||||||
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
|
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
|
||||||
|
@ -63,6 +65,7 @@ static struct uart_port *console_port;
|
||||||
struct uartlite_data {
|
struct uartlite_data {
|
||||||
const struct uartlite_reg_ops *reg_ops;
|
const struct uartlite_reg_ops *reg_ops;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
struct uart_driver *ulite_uart_driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uartlite_reg_ops {
|
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,
|
static void ulite_pm(struct uart_port *port, unsigned int state,
|
||||||
unsigned int oldstate)
|
unsigned int oldstate)
|
||||||
{
|
{
|
||||||
struct uartlite_data *pdata = port->private_data;
|
if (!state) {
|
||||||
|
pm_runtime_get_sync(port->dev);
|
||||||
if (!state)
|
} else {
|
||||||
clk_enable(pdata->clk);
|
pm_runtime_mark_last_busy(port->dev);
|
||||||
else
|
pm_runtime_put_autosuspend(port->dev);
|
||||||
clk_disable(pdata->clk);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CONSOLE_POLL
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
|
@ -694,7 +697,9 @@ static int ulite_release(struct device *dev)
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (port) {
|
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);
|
dev_set_drvdata(dev, NULL);
|
||||||
port->mapbase = 0;
|
port->mapbase = 0;
|
||||||
}
|
}
|
||||||
|
@ -712,8 +717,11 @@ static int __maybe_unused ulite_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_port *port = dev_get_drvdata(dev);
|
struct uart_port *port = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (port)
|
if (port) {
|
||||||
uart_suspend_port(&ulite_uart_driver, port);
|
struct uartlite_data *pdata = port->private_data;
|
||||||
|
|
||||||
|
uart_suspend_port(pdata->ulite_uart_driver, port);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -728,17 +736,41 @@ static int __maybe_unused ulite_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_port *port = dev_get_drvdata(dev);
|
struct uart_port *port = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (port)
|
if (port) {
|
||||||
uart_resume_port(&ulite_uart_driver, port);
|
struct uartlite_data *pdata = port->private_data;
|
||||||
|
|
||||||
|
uart_resume_port(pdata->ulite_uart_driver, port);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
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
|
* 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)
|
#if defined(CONFIG_OF)
|
||||||
/* Match table for of_platform binding */
|
/* Match table for of_platform binding */
|
||||||
|
@ -763,6 +795,22 @@ static int ulite_probe(struct platform_device *pdev)
|
||||||
if (prop)
|
if (prop)
|
||||||
id = be32_to_cpup(prop);
|
id = be32_to_cpup(prop);
|
||||||
#endif
|
#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),
|
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
|
@ -788,24 +836,22 @@ static int ulite_probe(struct platform_device *pdev)
|
||||||
pdata->clk = NULL;
|
pdata->clk = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pdata->ulite_uart_driver = &ulite_uart_driver;
|
||||||
ret = clk_prepare_enable(pdata->clk);
|
ret = clk_prepare_enable(pdata->clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Failed to prepare clock\n");
|
dev_err(&pdev->dev, "Failed to prepare clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ulite_uart_driver.state) {
|
pm_runtime_use_autosuspend(&pdev->dev);
|
||||||
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
|
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
|
||||||
ret = uart_register_driver(&ulite_uart_driver);
|
pm_runtime_set_active(&pdev->dev);
|
||||||
if (ret < 0) {
|
pm_runtime_enable(&pdev->dev);
|
||||||
dev_err(&pdev->dev, "Failed to register driver\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -814,9 +860,14 @@ static int ulite_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct uart_port *port = dev_get_drvdata(&pdev->dev);
|
struct uart_port *port = dev_get_drvdata(&pdev->dev);
|
||||||
struct uartlite_data *pdata = port->private_data;
|
struct uartlite_data *pdata = port->private_data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
clk_disable_unprepare(pdata->clk);
|
clk_unprepare(pdata->clk);
|
||||||
return ulite_release(&pdev->dev);
|
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 */
|
/* 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_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
|
||||||
#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full 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_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
|
* 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);
|
cdns_uart_handle_tx(dev_id);
|
||||||
isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
|
isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
|
||||||
}
|
}
|
||||||
if (isrstatus & CDNS_UART_IXR_MASK)
|
if (isrstatus & CDNS_UART_IXR_RXMASK)
|
||||||
cdns_uart_handle_rx(dev_id, isrstatus);
|
cdns_uart_handle_rx(dev_id, isrstatus);
|
||||||
|
|
||||||
spin_unlock(&port->lock);
|
spin_unlock(&port->lock);
|
||||||
|
@ -1255,7 +1255,7 @@ static int cdns_uart_suspend(struct device *device)
|
||||||
|
|
||||||
may_wake = device_may_wakeup(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;
|
unsigned long flags = 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
@ -1293,7 +1293,7 @@ static int cdns_uart_resume(struct device *device)
|
||||||
|
|
||||||
may_wake = device_may_wakeup(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->pclk);
|
||||||
clk_enable(cdns_uart->uartclk);
|
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
|
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||||
cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
|
cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!cdns_uart_console)
|
if (!cdns_uart_console) {
|
||||||
return -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
goto err_out_id;
|
||||||
|
}
|
||||||
|
|
||||||
strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
|
strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
|
||||||
sizeof(cdns_uart_console->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_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
|
||||||
pm_runtime_set_active(&pdev->dev);
|
pm_runtime_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
device_init_wakeup(port->dev, true);
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
#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_disable(&pdev->dev);
|
||||||
pm_runtime_set_suspended(&pdev->dev);
|
pm_runtime_set_suspended(&pdev->dev);
|
||||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||||
|
device_init_wakeup(&pdev->dev, false);
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||||
if (console_port == port)
|
if (console_port == port)
|
||||||
|
@ -1719,6 +1723,7 @@ static struct platform_driver cdns_uart_platform_driver = {
|
||||||
.name = CDNS_UART_NAME,
|
.name = CDNS_UART_NAME,
|
||||||
.of_match_table = cdns_uart_of_match,
|
.of_match_table = cdns_uart_of_match,
|
||||||
.pm = &cdns_uart_dev_pm_ops,
|
.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)
|
static void sysrq_handle_crash(int key)
|
||||||
{
|
{
|
||||||
char *killer = NULL;
|
/* release the RCU read lock before crashing */
|
||||||
|
|
||||||
/* 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.
|
|
||||||
*/
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
panic_on_oops = 1; /* force panic */
|
|
||||||
wmb();
|
panic("sysrq triggered crash\n");
|
||||||
*killer = 1;
|
|
||||||
}
|
}
|
||||||
static struct sysrq_key_op sysrq_crash_op = {
|
static struct sysrq_key_op sysrq_crash_op = {
|
||||||
.handler = sysrq_handle_crash,
|
.handler = sysrq_handle_crash,
|
||||||
|
@ -660,8 +653,7 @@ static void sysrq_do_reset(struct timer_list *t)
|
||||||
|
|
||||||
state->reset_requested = true;
|
state->reset_requested = true;
|
||||||
|
|
||||||
ksys_sync();
|
orderly_reboot();
|
||||||
kernel_restart(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sysrq_handle_reset_request(struct sysrq_state *state)
|
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. */
|
/* Get reset timeout if any. */
|
||||||
of_property_read_u32(np, "timeout-ms", &sysrq_reset_downtime_ms);
|
of_property_read_u32(np, "timeout-ms", &sysrq_reset_downtime_ms);
|
||||||
|
|
||||||
|
of_node_put(np);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void sysrq_of_get_keyreset_config(void)
|
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))
|
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
tty->count++;
|
retval = tty_ldisc_lock(tty, 5 * HZ);
|
||||||
|
|
||||||
if (tty->ldisc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
retval = tty_ldisc_reinit(tty, tty->termios.c_line);
|
|
||||||
if (retval)
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,6 +327,11 @@ int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
|
||||||
{
|
{
|
||||||
int ret;
|
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);
|
ret = __tty_ldisc_lock(tty, timeout);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return -EBUSY;
|
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)
|
void tty_ldisc_unlock(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
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);
|
__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)
|
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));
|
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||||
clear_bit(TTY_LDISC_OPEN, &tty->flags);
|
clear_bit(TTY_LDISC_OPEN, &tty->flags);
|
||||||
if (ld->ops->close)
|
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);
|
struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
lockdep_assert_held_exclusive(&tty->ldisc_sem);
|
||||||
if (IS_ERR(disc))
|
if (IS_ERR(disc))
|
||||||
return PTR_ERR(disc);
|
return PTR_ERR(disc);
|
||||||
tty->ldisc = disc;
|
tty->ldisc = disc;
|
||||||
|
@ -615,6 +624,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc);
|
||||||
*/
|
*/
|
||||||
static void tty_ldisc_kill(struct tty_struct *tty)
|
static void tty_ldisc_kill(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
|
lockdep_assert_held_exclusive(&tty->ldisc_sem);
|
||||||
if (!tty->ldisc)
|
if (!tty->ldisc)
|
||||||
return;
|
return;
|
||||||
/*
|
/*
|
||||||
|
@ -662,6 +672,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
|
||||||
struct tty_ldisc *ld;
|
struct tty_ldisc *ld;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
lockdep_assert_held_exclusive(&tty->ldisc_sem);
|
||||||
ld = tty_ldisc_get(tty, disc);
|
ld = tty_ldisc_get(tty, disc);
|
||||||
if (IS_ERR(ld)) {
|
if (IS_ERR(ld)) {
|
||||||
BUG_ON(disc == N_TTY);
|
BUG_ON(disc == N_TTY);
|
||||||
|
@ -760,6 +771,10 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (o_tty) {
|
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);
|
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
tty_ldisc_close(tty, tty->ldisc);
|
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)
|
void tty_ldisc_deinit(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
|
/* no ldisc_sem, tty is being destroyed */
|
||||||
if (tty->ldisc)
|
if (tty->ldisc)
|
||||||
tty_ldisc_put(tty->ldisc);
|
tty_ldisc_put(tty->ldisc);
|
||||||
tty->ldisc = NULL;
|
tty->ldisc = NULL;
|
||||||
|
|
|
@ -34,29 +34,6 @@
|
||||||
#include <linux/sched/task.h>
|
#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
|
#if BITS_PER_LONG == 64
|
||||||
# define LDSEM_ACTIVE_MASK 0xffffffffL
|
# define LDSEM_ACTIVE_MASK 0xffffffffL
|
||||||
#else
|
#else
|
||||||
|
@ -235,6 +212,7 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout)
|
||||||
raw_spin_lock_irq(&sem->wait_lock);
|
raw_spin_lock_irq(&sem->wait_lock);
|
||||||
if (waiter.task) {
|
if (waiter.task) {
|
||||||
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
|
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
|
||||||
|
sem->wait_readers--;
|
||||||
list_del(&waiter.list);
|
list_del(&waiter.list);
|
||||||
raw_spin_unlock_irq(&sem->wait_lock);
|
raw_spin_unlock_irq(&sem->wait_lock);
|
||||||
put_task_struct(waiter.task);
|
put_task_struct(waiter.task);
|
||||||
|
@ -293,6 +271,16 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
|
||||||
if (!locked)
|
if (!locked)
|
||||||
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
|
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
|
||||||
list_del(&waiter.list);
|
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);
|
raw_spin_unlock_irq(&sem->wait_lock);
|
||||||
|
|
||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
|
@ -310,17 +298,17 @@ static int __ldsem_down_read_nested(struct ld_semaphore *sem,
|
||||||
{
|
{
|
||||||
long count;
|
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);
|
count = atomic_long_add_return(LDSEM_READ_BIAS, &sem->count);
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
lock_stat(sem, contended);
|
lock_contended(&sem->dep_map, _RET_IP_);
|
||||||
if (!down_read_failed(sem, count, timeout)) {
|
if (!down_read_failed(sem, count, timeout)) {
|
||||||
lockdep_release(sem, 1, _RET_IP_);
|
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock_stat(sem, acquired);
|
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,17 +317,17 @@ static int __ldsem_down_write_nested(struct ld_semaphore *sem,
|
||||||
{
|
{
|
||||||
long count;
|
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);
|
count = atomic_long_add_return(LDSEM_WRITE_BIAS, &sem->count);
|
||||||
if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) {
|
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)) {
|
if (!down_write_failed(sem, count, timeout)) {
|
||||||
lockdep_release(sem, 1, _RET_IP_);
|
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock_stat(sem, acquired);
|
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,8 +350,8 @@ int ldsem_down_read_trylock(struct ld_semaphore *sem)
|
||||||
|
|
||||||
while (count >= 0) {
|
while (count >= 0) {
|
||||||
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_READ_BIAS)) {
|
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_READ_BIAS)) {
|
||||||
lockdep_acquire_read(sem, 0, 1, _RET_IP_);
|
rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
|
||||||
lock_stat(sem, acquired);
|
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,8 +376,8 @@ int ldsem_down_write_trylock(struct ld_semaphore *sem)
|
||||||
|
|
||||||
while ((count & LDSEM_ACTIVE_MASK) == 0) {
|
while ((count & LDSEM_ACTIVE_MASK) == 0) {
|
||||||
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
|
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
|
||||||
lockdep_acquire(sem, 0, 1, _RET_IP_);
|
rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
|
||||||
lock_stat(sem, acquired);
|
lock_acquired(&sem->dep_map, _RET_IP_);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +391,7 @@ void ldsem_up_read(struct ld_semaphore *sem)
|
||||||
{
|
{
|
||||||
long count;
|
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);
|
count = atomic_long_add_return(-LDSEM_READ_BIAS, &sem->count);
|
||||||
if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
|
if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
|
||||||
|
@ -417,7 +405,7 @@ void ldsem_up_write(struct ld_semaphore *sem)
|
||||||
{
|
{
|
||||||
long count;
|
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);
|
count = atomic_long_add_return(-LDSEM_WRITE_BIAS, &sem->count);
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
|
|
|
@ -32,6 +32,7 @@ struct font_desc {
|
||||||
#define ACORN8x8_IDX 8
|
#define ACORN8x8_IDX 8
|
||||||
#define MINI4x6_IDX 9
|
#define MINI4x6_IDX 9
|
||||||
#define FONT6x10_IDX 10
|
#define FONT6x10_IDX 10
|
||||||
|
#define TER16x32_IDX 11
|
||||||
|
|
||||||
extern const struct font_desc font_vga_8x8,
|
extern const struct font_desc font_vga_8x8,
|
||||||
font_vga_8x16,
|
font_vga_8x16,
|
||||||
|
@ -43,7 +44,8 @@ extern const struct font_desc font_vga_8x8,
|
||||||
font_sun_12x22,
|
font_sun_12x22,
|
||||||
font_acorn_8x8,
|
font_acorn_8x8,
|
||||||
font_mini_4x6,
|
font_mini_4x6,
|
||||||
font_6x10;
|
font_6x10,
|
||||||
|
font_ter_16x32;
|
||||||
|
|
||||||
/* Find a font with a specific name */
|
/* 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_get_tiocm(struct serdev_device *);
|
||||||
int serdev_device_set_tiocm(struct serdev_device *, int, int);
|
int serdev_device_set_tiocm(struct serdev_device *, int, int);
|
||||||
void serdev_device_write_wakeup(struct serdev_device *);
|
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 *);
|
void serdev_device_write_flush(struct serdev_device *);
|
||||||
int serdev_device_write_room(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);
|
void (*dl_write)(struct uart_8250_port *, int);
|
||||||
|
|
||||||
struct uart_8250_em485 *em485;
|
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)
|
static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/console.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/circ_buf.h>
|
#include <linux/circ_buf.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
@ -175,6 +176,7 @@ struct uart_port {
|
||||||
struct console *cons; /* struct console, if any */
|
struct console *cons; /* struct console, if any */
|
||||||
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
|
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
|
||||||
unsigned long sysrq; /* sysrq timeout */
|
unsigned long sysrq; /* sysrq timeout */
|
||||||
|
unsigned int sysrq_ch; /* char for sysrq */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* flags must be updated while holding port mutex */
|
/* 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;
|
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
|
#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
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -366,6 +366,7 @@ struct tty_file_private {
|
||||||
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
|
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
|
||||||
#define TTY_HUPPED 18 /* Post driver->hangup() */
|
#define TTY_HUPPED 18 /* Post driver->hangup() */
|
||||||
#define TTY_HUPPING 19 /* Hangup in progress */
|
#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 */
|
#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
|
||||||
|
|
||||||
/* Values for tty->flow_change */
|
/* Values for tty->flow_change */
|
||||||
|
@ -383,6 +384,12 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val)
|
||||||
smp_mb();
|
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)
|
static inline bool tty_io_error(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
return test_bit(TTY_IO_ERROR, &tty->flags);
|
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
|
big letters (like the letters used in the SPARC PROM). If the
|
||||||
standard font is unreadable for you, say Y, otherwise say N.
|
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
|
config FONT_AUTOSELECT
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on !FONT_8x8
|
depends on !FONT_8x8
|
||||||
|
@ -121,6 +130,7 @@ config FONT_AUTOSELECT
|
||||||
depends on !FONT_SUN8x16
|
depends on !FONT_SUN8x16
|
||||||
depends on !FONT_SUN12x22
|
depends on !FONT_SUN12x22
|
||||||
depends on !FONT_10x18
|
depends on !FONT_10x18
|
||||||
|
depends on !FONT_TER16x32
|
||||||
select FONT_8x16
|
select FONT_8x16
|
||||||
|
|
||||||
endif # FONT_SUPPORT
|
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_ACORN_8x8) += font_acorn_8x8.o
|
||||||
font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
|
font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
|
||||||
font-objs-$(CONFIG_FONT_6x10) += font_6x10.o
|
font-objs-$(CONFIG_FONT_6x10) += font_6x10.o
|
||||||
|
font-objs-$(CONFIG_FONT_TER16x32) += font_ter16x32.o
|
||||||
|
|
||||||
font-objs += $(font-objs-y)
|
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
|
#undef NO_FONTS
|
||||||
&font_6x10,
|
&font_6x10,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_FONT_TER16x32
|
||||||
|
#undef NO_FONTS
|
||||||
|
&font_ter_16x32,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define num_fonts ARRAY_SIZE(fonts)
|
#define num_fonts ARRAY_SIZE(fonts)
|
||||||
|
|
Loading…
Reference in New Issue