Merge tag 'tty-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial updates from Greg KH: "Here is the large set of TTY and Serial driver patches for 5.9-rc1. Lots of bugfixes in here, thanks to syzbot fuzzing for serial and vt and console code. Other highlights include: - much needed vt/vc code cleanup from Jiri Slaby - 8250 driver fixes and additions - various serial driver updates and feature enhancements - locking cleanup for serial/console initializations - other minor cleanups All of these have been in linux-next with no reported issues" * tag 'tty-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (90 commits) MAINTAINERS: enlist Greg formally for console stuff vgacon: Fix for missing check in scrollback handling Revert "serial: 8250: Let serial core initialise spin lock" serial: 8250: Let serial core initialise spin lock tty: keyboard, do not speculate on func_table index serial: stm32: Add RS485 RTS GPIO control serial: 8250_dw: Fix common clocks usage race condition serial: 8250_dw: Pass the same rate to the clk round and set rate methods serial: 8250_dw: Simplify the ref clock rate setting procedure serial: 8250: Add 8250 port clock update method tty: serial: imx: add imx earlycon driver tty: serial: imx: enable imx serial console port as module tty/synclink: remove leftover bits of non-PCI card support tty: Use the preferred form for passing the size of a structure type tty: Fix identation issues in struct serial_struct32 tty: Avoid the use of one-element arrays serial: msm_serial: add sparse context annotation serial: pmac_zilog: add sparse context annotation newport_con: vc_color is now in state serial: imx: use hrtimers for rs485 delays ...
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -43,6 +45,8 @@ struct dw8250_data {
|
||||
int msr_mask_off;
|
||||
struct clk *clk;
|
||||
struct clk *pclk;
|
||||
struct notifier_block clk_notifier;
|
||||
struct work_struct clk_work;
|
||||
struct reset_control *rst;
|
||||
|
||||
unsigned int skip_autocfg:1;
|
||||
@@ -54,6 +58,16 @@ static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
|
||||
return container_of(data, struct dw8250_data, data);
|
||||
}
|
||||
|
||||
static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
|
||||
{
|
||||
return container_of(nb, struct dw8250_data, clk_notifier);
|
||||
}
|
||||
|
||||
static inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work)
|
||||
{
|
||||
return container_of(work, struct dw8250_data, clk_work);
|
||||
}
|
||||
|
||||
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
@@ -260,6 +274,46 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw8250_clk_work_cb(struct work_struct *work)
|
||||
{
|
||||
struct dw8250_data *d = work_to_dw8250_data(work);
|
||||
struct uart_8250_port *up;
|
||||
unsigned long rate;
|
||||
|
||||
rate = clk_get_rate(d->clk);
|
||||
if (rate <= 0)
|
||||
return;
|
||||
|
||||
up = serial8250_get_port(d->data.line);
|
||||
|
||||
serial8250_update_uartclk(&up->port, rate);
|
||||
}
|
||||
|
||||
static int dw8250_clk_notifier_cb(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct dw8250_data *d = clk_to_dw8250_data(nb);
|
||||
|
||||
/*
|
||||
* We have no choice but to defer the uartclk update due to two
|
||||
* deadlocks. First one is caused by a recursive mutex lock which
|
||||
* happens when clk_set_rate() is called from dw8250_set_termios().
|
||||
* Second deadlock is more tricky and is caused by an inverted order of
|
||||
* the clk and tty-port mutexes lock. It happens if clock rate change
|
||||
* is requested asynchronously while set_termios() is executed between
|
||||
* tty-port mutex lock and clk_set_rate() function invocation and
|
||||
* vise-versa. Anyway if we didn't have the reference clock alteration
|
||||
* in the dw8250_set_termios() method we wouldn't have needed this
|
||||
* deferred event handling complication.
|
||||
*/
|
||||
if (event == POST_RATE_CHANGE) {
|
||||
queue_work(system_unbound_wq, &d->clk_work);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void
|
||||
dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
{
|
||||
@@ -275,27 +329,27 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud = tty_termios_baud_rate(termios);
|
||||
unsigned long newrate = tty_termios_baud_rate(termios) * 16;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
long rate;
|
||||
int ret;
|
||||
|
||||
clk_disable_unprepare(d->clk);
|
||||
rate = clk_round_rate(d->clk, baud * 16);
|
||||
if (rate < 0)
|
||||
ret = rate;
|
||||
else if (rate == 0)
|
||||
ret = -ENOENT;
|
||||
else
|
||||
ret = clk_set_rate(d->clk, rate);
|
||||
rate = clk_round_rate(d->clk, newrate);
|
||||
if (rate > 0) {
|
||||
/*
|
||||
* Premilinary set the uartclk to the new clock rate so the
|
||||
* clock update event handler caused by the clk_set_rate()
|
||||
* calling wouldn't actually update the UART divisor since
|
||||
* we about to do this anyway.
|
||||
*/
|
||||
swap(p->uartclk, rate);
|
||||
ret = clk_set_rate(d->clk, newrate);
|
||||
if (ret)
|
||||
swap(p->uartclk, rate);
|
||||
}
|
||||
clk_prepare_enable(d->clk);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
p->uartclk = rate;
|
||||
|
||||
out:
|
||||
p->status &= ~UPSTAT_AUTOCTS;
|
||||
if (termios->c_cflag & CRTSCTS)
|
||||
p->status |= UPSTAT_AUTOCTS;
|
||||
@@ -319,6 +373,39 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
|
||||
serial8250_do_set_ldisc(p, termios);
|
||||
}
|
||||
|
||||
static int dw8250_startup(struct uart_port *p)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Some platforms may provide a reference clock shared between several
|
||||
* devices. In this case before using the serial port first we have to
|
||||
* make sure that any clock state change is known to the UART port at
|
||||
* least post factum.
|
||||
*/
|
||||
if (d->clk) {
|
||||
ret = clk_notifier_register(d->clk, &d->clk_notifier);
|
||||
if (ret)
|
||||
dev_warn(p->dev, "Failed to set the clock notifier\n");
|
||||
}
|
||||
|
||||
return serial8250_do_startup(p);
|
||||
}
|
||||
|
||||
static void dw8250_shutdown(struct uart_port *p)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
serial8250_do_shutdown(p);
|
||||
|
||||
if (d->clk) {
|
||||
clk_notifier_unregister(d->clk, &d->clk_notifier);
|
||||
|
||||
flush_work(&d->clk_work);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dw8250_fallback_dma_filter will prevent the UART from getting just any free
|
||||
* channel on platforms that have DMA engines, but don't have any channels
|
||||
@@ -414,6 +501,8 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
p->serial_out = dw8250_serial_out;
|
||||
p->set_ldisc = dw8250_set_ldisc;
|
||||
p->set_termios = dw8250_set_termios;
|
||||
p->startup = dw8250_startup;
|
||||
p->shutdown = dw8250_shutdown;
|
||||
|
||||
p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
|
||||
if (!p->membase)
|
||||
@@ -475,6 +564,9 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(data->clk))
|
||||
return PTR_ERR(data->clk);
|
||||
|
||||
INIT_WORK(&data->clk_work, dw8250_clk_work_cb);
|
||||
data->clk_notifier.notifier_call = dw8250_clk_notifier_cb;
|
||||
|
||||
err = clk_prepare_enable(data->clk);
|
||||
if (err)
|
||||
dev_warn(dev, "could not enable optional baudclk: %d\n", err);
|
||||
|
@@ -78,14 +78,18 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
|
||||
static int serial8250_em_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct serial8250_em_priv *priv;
|
||||
struct uart_8250_port up;
|
||||
int ret;
|
||||
struct resource *regs;
|
||||
int irq, ret;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "missing registers or irq\n");
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs) {
|
||||
dev_err(&pdev->dev, "missing registers\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -101,7 +105,7 @@ static int serial8250_em_probe(struct platform_device *pdev)
|
||||
|
||||
memset(&up, 0, sizeof(up));
|
||||
up.port.mapbase = regs->start;
|
||||
up.port.irq = irq->start;
|
||||
up.port.irq = irq;
|
||||
up.port.type = PORT_UNKNOWN;
|
||||
up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
|
||||
up.port.dev = &pdev->dev;
|
||||
|
@@ -207,12 +207,11 @@ static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset)
|
||||
static int ingenic_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port uart = {};
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct ingenic_uart_data *data;
|
||||
const struct ingenic_uart_config *cdata;
|
||||
const struct of_device_id *match;
|
||||
int err, line;
|
||||
struct resource *regs;
|
||||
int irq, err, line;
|
||||
|
||||
match = of_match_device(of_match, &pdev->dev);
|
||||
if (!match) {
|
||||
@@ -221,8 +220,13 @@ static int ingenic_uart_probe(struct platform_device *pdev)
|
||||
}
|
||||
cdata = match->data;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "no registers/irq defined\n");
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs) {
|
||||
dev_err(&pdev->dev, "no registers defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -238,7 +242,7 @@ static int ingenic_uart_probe(struct platform_device *pdev)
|
||||
uart.port.regshift = 2;
|
||||
uart.port.serial_out = ingenic_uart_serial_out;
|
||||
uart.port.serial_in = ingenic_uart_serial_in;
|
||||
uart.port.irq = irq->start;
|
||||
uart.port.irq = irq;
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.fifosize = cdata->fifosize;
|
||||
uart.tx_loadsz = cdata->tx_loadsz;
|
||||
|
@@ -51,7 +51,7 @@ static u32 men_lookup_uartclk(struct mcb_device *mdev)
|
||||
return clkval;
|
||||
}
|
||||
|
||||
static unsigned int get_num_ports(struct mcb_device *mdev,
|
||||
static int get_num_ports(struct mcb_device *mdev,
|
||||
void __iomem *membase)
|
||||
{
|
||||
switch (mdev->id) {
|
||||
@@ -140,7 +140,7 @@ static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
|
||||
return;
|
||||
|
||||
num_ports = get_num_ports(mdev, data[0].uart.port.membase);
|
||||
if (num_ports < 0 || num_ports > 4) {
|
||||
if (num_ports <= 0 || num_ports > 4) {
|
||||
dev_err(&mdev->dev, "error retrieving number of ports!\n");
|
||||
return;
|
||||
}
|
||||
|
@@ -512,13 +512,17 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
|
||||
static int mtk8250_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port uart = {};
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct mtk8250_data *data;
|
||||
int err;
|
||||
struct resource *regs;
|
||||
int irq, err;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "no registers/irq defined\n");
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs) {
|
||||
dev_err(&pdev->dev, "no registers defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -542,7 +546,7 @@ static int mtk8250_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&uart.port.lock);
|
||||
uart.port.mapbase = regs->start;
|
||||
uart.port.irq = irq->start;
|
||||
uart.port.irq = irq;
|
||||
uart.port.pm = mtk8250_do_pm;
|
||||
uart.port.type = PORT_16550;
|
||||
uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
|
||||
|
@@ -1209,17 +1209,21 @@ MODULE_DEVICE_TABLE(of, omap8250_dt_ids);
|
||||
|
||||
static int omap8250_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct omap8250_priv *priv;
|
||||
const struct omap8250_platdata *pdata;
|
||||
struct uart_8250_port up;
|
||||
int ret;
|
||||
struct resource *regs;
|
||||
void __iomem *membase;
|
||||
int irq, ret;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "missing registers or irq\n");
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs) {
|
||||
dev_err(&pdev->dev, "missing registers\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1236,7 +1240,7 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
up.port.dev = &pdev->dev;
|
||||
up.port.mapbase = regs->start;
|
||||
up.port.membase = membase;
|
||||
up.port.irq = irq->start;
|
||||
up.port.irq = irq;
|
||||
/*
|
||||
* It claims to be 16C750 compatible however it is a little different.
|
||||
* It has EFR and has no FCR7_64byte bit. The AFE (which it claims to
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -2631,6 +2632,46 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
|
||||
(port->uartclk + tolerance) / 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note in order to avoid the tty port mutex deadlock don't use the next method
|
||||
* within the uart port callbacks. Primarily it's supposed to be utilized to
|
||||
* handle a sudden reference clock rate change.
|
||||
*/
|
||||
void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned int baud, quot, frac = 0;
|
||||
struct ktermios *termios;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&port->state->port.mutex);
|
||||
|
||||
if (port->uartclk == uartclk)
|
||||
goto out_lock;
|
||||
|
||||
port->uartclk = uartclk;
|
||||
termios = &port->state->port.tty->termios;
|
||||
|
||||
baud = serial8250_get_baud_rate(port, termios, NULL);
|
||||
quot = serial8250_get_divisor(port, baud, &frac);
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
serial8250_set_divisor(port, baud, quot, frac);
|
||||
serial_port_out(port, UART_LCR, up->lcr);
|
||||
serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
serial8250_rpm_put(up);
|
||||
|
||||
out_lock:
|
||||
mutex_unlock(&port->state->port.mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_update_uartclk);
|
||||
|
||||
void
|
||||
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
|
@@ -18,7 +18,6 @@
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -93,12 +92,15 @@ static int serial_pxa_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port uart = {};
|
||||
struct pxa8250_data *data;
|
||||
struct resource *mmres, *irqres;
|
||||
int ret;
|
||||
struct resource *mmres;
|
||||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!mmres || !irqres)
|
||||
if (!mmres)
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
@@ -121,7 +123,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
|
||||
uart.port.iotype = UPIO_MEM32;
|
||||
uart.port.mapbase = mmres->start;
|
||||
uart.port.regshift = 2;
|
||||
uart.port.irq = irqres->start;
|
||||
uart.port.irq = irq;
|
||||
uart.port.fifosize = 64;
|
||||
uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE;
|
||||
uart.port.dev = &pdev->dev;
|
||||
|
@@ -222,7 +222,7 @@ config SERIAL_8250_MANY_PORTS
|
||||
Say Y here if you have dumb serial boards other than the four
|
||||
standard COM 1/2/3/4 ports. This may happen if you have an AST
|
||||
FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
|
||||
from <http://www.tldp.org/docs.html#howto>), or other custom
|
||||
from <https://www.tldp.org/docs.html#howto>), or other custom
|
||||
serial port hardware which acts similar to standard serial port
|
||||
hardware. If you only use the standard COM 1/2/3/4 ports, you can
|
||||
say N here to save some memory. You can also say Y if you have an
|
||||
@@ -266,7 +266,7 @@ config SERIAL_8250_BOCA
|
||||
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
|
||||
help
|
||||
Say Y here if you have a Boca serial board. Please read the Boca
|
||||
mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>
|
||||
mini-HOWTO, available from <https://www.tldp.org/docs.html#howto>
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called 8250_boca.
|
||||
|
@@ -502,20 +502,27 @@ config SERIAL_IMX
|
||||
can enable its onboard serial port by enabling this option.
|
||||
|
||||
config SERIAL_IMX_CONSOLE
|
||||
bool "Console on IMX serial port"
|
||||
depends on SERIAL_IMX=y
|
||||
tristate "Console on IMX serial port"
|
||||
depends on SERIAL_IMX
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON if OF
|
||||
help
|
||||
If you have enabled the serial port on the Freescale IMX
|
||||
CPU you can make it the console by answering Y to this option.
|
||||
CPU you can make it the console by answering Y/M to this option.
|
||||
|
||||
Even if you say Y here, the currently visible virtual console
|
||||
Even if you say Y/M here, the currently visible virtual console
|
||||
(/dev/tty0) will still be used as the system console by default, but
|
||||
you can alter that using a kernel command line option such as
|
||||
"console=ttymxc0". (Try "man bootparam" or see the documentation of
|
||||
your bootloader about how to pass options to the kernel at boot time.)
|
||||
|
||||
config SERIAL_IMX_EARLYCON
|
||||
bool "Earlycon on IMX serial port"
|
||||
depends on OF
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
If you have enabled the earlycon on the Freescale IMX
|
||||
CPU you can make it the earlycon by answering Y to this option.
|
||||
|
||||
config SERIAL_UARTLITE
|
||||
tristate "Xilinx uartlite serial port support"
|
||||
depends on HAS_IOMEM
|
||||
|
@@ -27,7 +27,7 @@
|
||||
|
||||
/*
|
||||
* Altera JTAG UART register definitions according to the Altera JTAG UART
|
||||
* datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
|
||||
* datasheet: https://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
|
||||
*/
|
||||
|
||||
#define ALTERA_JTAGUART_SIZE 8
|
||||
|
@@ -2607,7 +2607,6 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
|
||||
uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE);
|
||||
uap->port.flags = UPF_BOOT_AUTOCONF;
|
||||
uap->port.line = index;
|
||||
spin_lock_init(&uap->port.lock);
|
||||
|
||||
amba_ports[index] = uap;
|
||||
|
||||
|
@@ -1925,6 +1925,9 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
|
||||
tmp_sbr++;
|
||||
}
|
||||
|
||||
if (tmp_sbr > UARTBAUD_SBR_MASK)
|
||||
continue;
|
||||
|
||||
if (tmp_diff <= baud_diff) {
|
||||
baud_diff = tmp_diff;
|
||||
osr = tmp_osr;
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <linux/serial.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/rational.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -188,6 +189,13 @@ struct imx_uart_data {
|
||||
enum imx_uart_type devtype;
|
||||
};
|
||||
|
||||
enum imx_tx_state {
|
||||
OFF,
|
||||
WAIT_AFTER_RTS,
|
||||
SEND,
|
||||
WAIT_AFTER_SEND,
|
||||
};
|
||||
|
||||
struct imx_port {
|
||||
struct uart_port port;
|
||||
struct timer_list timer;
|
||||
@@ -224,6 +232,10 @@ struct imx_port {
|
||||
unsigned int dma_tx_nents;
|
||||
unsigned int saved_reg[10];
|
||||
bool context_saved;
|
||||
|
||||
enum imx_tx_state tx_state;
|
||||
struct hrtimer trigger_start_tx;
|
||||
struct hrtimer trigger_stop_tx;
|
||||
};
|
||||
|
||||
struct imx_port_ucrs {
|
||||
@@ -361,7 +373,7 @@ static inline int imx_uart_is_imx6q(struct imx_port *sport)
|
||||
/*
|
||||
* Save and restore functions for UCR1, UCR2 and UCR3 registers
|
||||
*/
|
||||
#if defined(CONFIG_SERIAL_IMX_CONSOLE)
|
||||
#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
|
||||
static void imx_uart_ucrs_save(struct imx_port *sport,
|
||||
struct imx_port_ucrs *ucr)
|
||||
{
|
||||
@@ -400,6 +412,15 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
|
||||
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
|
||||
}
|
||||
|
||||
static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
|
||||
{
|
||||
long sec = msec / MSEC_PER_SEC;
|
||||
long nsec = (msec % MSEC_PER_SEC) * 1000000;
|
||||
ktime_t t = ktime_set(sec, nsec);
|
||||
|
||||
hrtimer_start(hrt, t, HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
/* called with port.lock taken and irqs off */
|
||||
static void imx_uart_start_rx(struct uart_port *port)
|
||||
{
|
||||
@@ -427,7 +448,10 @@ static void imx_uart_start_rx(struct uart_port *port)
|
||||
static void imx_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
u32 ucr1;
|
||||
u32 ucr1, ucr4, usr2;
|
||||
|
||||
if (sport->tx_state == OFF)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We are maybe in the SMP context, so if the DMA TX thread is running
|
||||
@@ -439,21 +463,44 @@ static void imx_uart_stop_tx(struct uart_port *port)
|
||||
ucr1 = imx_uart_readl(sport, UCR1);
|
||||
imx_uart_writel(sport, ucr1 & ~UCR1_TRDYEN, UCR1);
|
||||
|
||||
/* in rs485 mode disable transmitter if shifter is empty */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED &&
|
||||
imx_uart_readl(sport, USR2) & USR2_TXDC) {
|
||||
u32 ucr2 = imx_uart_readl(sport, UCR2), ucr4;
|
||||
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
imx_uart_rts_active(sport, &ucr2);
|
||||
else
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
usr2 = imx_uart_readl(sport, USR2);
|
||||
if (!(usr2 & USR2_TXDC)) {
|
||||
/* The shifter is still busy, so retry once TC triggers */
|
||||
return;
|
||||
}
|
||||
|
||||
imx_uart_start_rx(port);
|
||||
ucr4 = imx_uart_readl(sport, UCR4);
|
||||
ucr4 &= ~UCR4_TCEN;
|
||||
imx_uart_writel(sport, ucr4, UCR4);
|
||||
|
||||
ucr4 = imx_uart_readl(sport, UCR4);
|
||||
ucr4 &= ~UCR4_TCEN;
|
||||
imx_uart_writel(sport, ucr4, UCR4);
|
||||
/* in rs485 mode disable transmitter */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (sport->tx_state == SEND) {
|
||||
sport->tx_state = WAIT_AFTER_SEND;
|
||||
start_hrtimer_ms(&sport->trigger_stop_tx,
|
||||
port->rs485.delay_rts_after_send);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sport->tx_state == WAIT_AFTER_RTS ||
|
||||
sport->tx_state == WAIT_AFTER_SEND) {
|
||||
u32 ucr2;
|
||||
|
||||
hrtimer_try_to_cancel(&sport->trigger_start_tx);
|
||||
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
imx_uart_rts_active(sport, &ucr2);
|
||||
else
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
imx_uart_start_rx(port);
|
||||
|
||||
sport->tx_state = OFF;
|
||||
}
|
||||
} else {
|
||||
sport->tx_state = OFF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,28 +698,50 @@ static void imx_uart_start_tx(struct uart_port *port)
|
||||
if (!sport->port.x_char && uart_circ_empty(&port->state->xmit))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We cannot simply do nothing here if sport->tx_state == SEND already
|
||||
* because UCR1_TXMPTYEN might already have been cleared in
|
||||
* imx_uart_stop_tx(), but tx_state is still SEND.
|
||||
*/
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
u32 ucr2;
|
||||
if (sport->tx_state == OFF) {
|
||||
u32 ucr2 = imx_uart_readl(sport, UCR2);
|
||||
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
imx_uart_rts_active(sport, &ucr2);
|
||||
else
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
imx_uart_rts_active(sport, &ucr2);
|
||||
else
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
imx_uart_stop_rx(port);
|
||||
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
imx_uart_stop_rx(port);
|
||||
|
||||
/*
|
||||
* Enable transmitter and shifter empty irq only if DMA is off.
|
||||
* In the DMA case this is done in the tx-callback.
|
||||
*/
|
||||
if (!sport->dma_is_enabled) {
|
||||
u32 ucr4 = imx_uart_readl(sport, UCR4);
|
||||
ucr4 |= UCR4_TCEN;
|
||||
imx_uart_writel(sport, ucr4, UCR4);
|
||||
sport->tx_state = WAIT_AFTER_RTS;
|
||||
start_hrtimer_ms(&sport->trigger_start_tx,
|
||||
port->rs485.delay_rts_before_send);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sport->tx_state == WAIT_AFTER_SEND
|
||||
|| sport->tx_state == WAIT_AFTER_RTS) {
|
||||
|
||||
hrtimer_try_to_cancel(&sport->trigger_stop_tx);
|
||||
|
||||
/*
|
||||
* Enable transmitter and shifter empty irq only if DMA
|
||||
* is off. In the DMA case this is done in the
|
||||
* tx-callback.
|
||||
*/
|
||||
if (!sport->dma_is_enabled) {
|
||||
u32 ucr4 = imx_uart_readl(sport, UCR4);
|
||||
ucr4 |= UCR4_TCEN;
|
||||
imx_uart_writel(sport, ucr4, UCR4);
|
||||
}
|
||||
|
||||
sport->tx_state = SEND;
|
||||
}
|
||||
} else {
|
||||
sport->tx_state = SEND;
|
||||
}
|
||||
|
||||
if (!sport->dma_is_enabled) {
|
||||
@@ -1630,7 +1699,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
|
||||
if (termios->c_cflag & CRTSCTS)
|
||||
ucr2 &= ~UCR2_IRTS;
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
ucr2 |= UCR2_STPB;
|
||||
if (termios->c_cflag & PARENB) {
|
||||
@@ -1857,10 +1925,6 @@ static int imx_uart_rs485_config(struct uart_port *port,
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
u32 ucr2;
|
||||
|
||||
/* unimplemented */
|
||||
rs485conf->delay_rts_before_send = 0;
|
||||
rs485conf->delay_rts_after_send = 0;
|
||||
|
||||
/* RTS is required to control the transmitter */
|
||||
if (!sport->have_rtscts && !sport->have_rtsgpio)
|
||||
rs485conf->flags &= ~SER_RS485_ENABLED;
|
||||
@@ -1915,7 +1979,7 @@ static const struct uart_ops imx_uart_pops = {
|
||||
|
||||
static struct imx_port *imx_uart_ports[UART_NR];
|
||||
|
||||
#ifdef CONFIG_SERIAL_IMX_CONSOLE
|
||||
#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
|
||||
static void imx_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
@@ -2112,39 +2176,6 @@ static struct console imx_uart_console = {
|
||||
|
||||
#define IMX_CONSOLE &imx_uart_console
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
|
||||
while (imx_uart_readl(sport, IMX21_UTS) & UTS_TXFULL)
|
||||
cpu_relax();
|
||||
|
||||
imx_uart_writel(sport, ch, URTX0);
|
||||
}
|
||||
|
||||
static void imx_uart_console_early_write(struct console *con, const char *s,
|
||||
unsigned count)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar);
|
||||
}
|
||||
|
||||
static int __init
|
||||
imx_console_early_setup(struct earlycon_device *dev, const char *opt)
|
||||
{
|
||||
if (!dev->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
dev->con->write = imx_uart_console_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
|
||||
OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define IMX_CONSOLE NULL
|
||||
#endif
|
||||
@@ -2223,6 +2254,32 @@ static void imx_uart_probe_pdata(struct imx_port *sport,
|
||||
sport->have_rtscts = 1;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t)
|
||||
{
|
||||
struct imx_port *sport = container_of(t, struct imx_port, trigger_start_tx);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (sport->tx_state == WAIT_AFTER_RTS)
|
||||
imx_uart_start_tx(&sport->port);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
|
||||
{
|
||||
struct imx_port *sport = container_of(t, struct imx_port, trigger_stop_tx);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (sport->tx_state == WAIT_AFTER_SEND)
|
||||
imx_uart_stop_tx(&sport->port);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static int imx_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_port *sport;
|
||||
@@ -2369,6 +2426,11 @@ static int imx_uart_probe(struct platform_device *pdev)
|
||||
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
|
||||
hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
sport->trigger_start_tx.function = imx_trigger_start_tx;
|
||||
sport->trigger_stop_tx.function = imx_trigger_stop_tx;
|
||||
|
||||
/*
|
||||
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
|
||||
* chips only have one interrupt.
|
||||
@@ -2406,9 +2468,6 @@ static int imx_uart_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to initialize lock even for non-registered console */
|
||||
spin_lock_init(&sport->port.lock);
|
||||
|
||||
imx_uart_ports[sport->port.line] = sport;
|
||||
|
||||
platform_set_drvdata(pdev, sport);
|
||||
|
50
drivers/tty/serial/imx_earlycon.c
Normal file
50
drivers/tty/serial/imx_earlycon.c
Normal file
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2020 NXP
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#define URTX0 0x40 /* Transmitter Register */
|
||||
#define UTS_TXFULL (1<<4) /* TxFIFO full */
|
||||
#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
|
||||
|
||||
static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL)
|
||||
cpu_relax();
|
||||
|
||||
writel_relaxed(ch, port->membase + URTX0);
|
||||
}
|
||||
|
||||
static void imx_uart_console_early_write(struct console *con, const char *s,
|
||||
unsigned count)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar);
|
||||
}
|
||||
|
||||
static int __init
|
||||
imx_console_early_setup(struct earlycon_device *dev, const char *opt)
|
||||
{
|
||||
if (!dev->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
dev->con->write = imx_uart_console_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
|
||||
OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
|
||||
|
||||
MODULE_AUTHOR("NXP");
|
||||
MODULE_DESCRIPTION("IMX earlycon driver");
|
||||
MODULE_LICENSE("GPL");
|
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "jsm.h"
|
||||
|
||||
MODULE_AUTHOR("Digi International, http://www.digi.com");
|
||||
MODULE_AUTHOR("Digi International, https://www.digi.com");
|
||||
MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("jsm");
|
||||
|
@@ -538,7 +538,8 @@ static int __init kgdboc_earlycon_init(char *opt)
|
||||
|
||||
if (!con) {
|
||||
/*
|
||||
* Both earlycon and kgdboc_earlycon are initialized during * early parameter parsing. We cannot guarantee earlycon gets
|
||||
* Both earlycon and kgdboc_earlycon are initialized during
|
||||
* early parameter parsing. We cannot guarantee earlycon gets
|
||||
* in first and, in any case, on ACPI systems earlycon may
|
||||
* defer its own initialization (usually to somewhere within
|
||||
* setup_arch() ). To cope with either of these situations
|
||||
|
@@ -696,6 +696,7 @@ static void msm_enable_ms(struct uart_port *port)
|
||||
}
|
||||
|
||||
static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
__must_hold(&port->lock)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int sr;
|
||||
@@ -771,6 +772,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
}
|
||||
|
||||
static void msm_handle_rx(struct uart_port *port)
|
||||
__must_hold(&port->lock)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int sr;
|
||||
|
@@ -1857,41 +1857,24 @@ static void pch_uart_pci_remove(struct pci_dev *pdev)
|
||||
kfree(priv);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_PM
|
||||
static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
||||
static int __maybe_unused pch_uart_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct eg20t_port *priv = pci_get_drvdata(pdev);
|
||||
struct eg20t_port *priv = dev_get_drvdata(dev);
|
||||
|
||||
uart_suspend_port(&pch_uart_driver, &priv->port);
|
||||
|
||||
pci_save_state(pdev);
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pch_uart_pci_resume(struct pci_dev *pdev)
|
||||
static int __maybe_unused pch_uart_pci_resume(struct device *dev)
|
||||
{
|
||||
struct eg20t_port *priv = pci_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s-pci_enable_device failed(ret=%d) ", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
struct eg20t_port *priv = dev_get_drvdata(dev);
|
||||
|
||||
uart_resume_port(&pch_uart_driver, &priv->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pch_uart_pci_suspend NULL
|
||||
#define pch_uart_pci_resume NULL
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id pch_uart_pci_id[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
|
||||
@@ -1945,13 +1928,16 @@ probe_error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pch_uart_pci_pm_ops,
|
||||
pch_uart_pci_suspend,
|
||||
pch_uart_pci_resume);
|
||||
|
||||
static struct pci_driver pch_uart_pci_driver = {
|
||||
.name = "pch_uart",
|
||||
.id_table = pch_uart_pci_id,
|
||||
.probe = pch_uart_pci_probe,
|
||||
.remove = pch_uart_pci_remove,
|
||||
.suspend = pch_uart_pci_suspend,
|
||||
.resume = pch_uart_pci_resume,
|
||||
.driver.pm = &pch_uart_pci_pm_ops,
|
||||
};
|
||||
|
||||
static int __init pch_uart_module_init(void)
|
||||
|
@@ -213,6 +213,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
|
||||
}
|
||||
|
||||
static bool pmz_receive_chars(struct uart_pmac_port *uap)
|
||||
__must_hold(&uap->port.lock)
|
||||
{
|
||||
struct tty_port *port;
|
||||
unsigned char ch, r1, drop, flag;
|
||||
|
@@ -768,7 +768,7 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
|
||||
u8 buf[sizeof(u32)];
|
||||
int c;
|
||||
|
||||
memset(buf, 0, ARRAY_SIZE(buf));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
tx_bytes = min_t(size_t, remaining, BYTES_PER_FIFO_WORD);
|
||||
|
||||
for (c = 0; c < tx_bytes ; c++) {
|
||||
|
@@ -6,7 +6,7 @@
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*/
|
||||
|
||||
/* Hote on 2410 error handling
|
||||
/* Note on 2410 error handling
|
||||
*
|
||||
* The s3c2410 manual has a love/hate affair with the contents of the
|
||||
* UERSTAT register in the UART blocks, and keeps marking some of the
|
||||
@@ -327,7 +327,6 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
|
||||
unsigned long flags;
|
||||
int count;
|
||||
|
||||
|
||||
dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
|
||||
count = dma->tx_bytes_requested - state.residue;
|
||||
async_tx_ack(dma->tx_desc);
|
||||
@@ -409,7 +408,6 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct s3c24xx_uart_dma *dma = ourport->dma;
|
||||
|
||||
|
||||
if (ourport->tx_mode != S3C24XX_TX_DMA)
|
||||
enable_tx_dma(ourport);
|
||||
|
||||
@@ -816,7 +814,6 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
@@ -842,8 +839,8 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
|
||||
count >= ourport->min_dma_size) {
|
||||
int align = dma_get_cache_alignment() -
|
||||
(xmit->tail & (dma_get_cache_alignment() - 1));
|
||||
if (count-align >= ourport->min_dma_size) {
|
||||
dma_count = count-align;
|
||||
if (count - align >= ourport->min_dma_size) {
|
||||
dma_count = count - align;
|
||||
count = align;
|
||||
}
|
||||
}
|
||||
@@ -1589,7 +1586,6 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
|
||||
|
||||
static struct console s3c24xx_serial_console;
|
||||
@@ -1672,7 +1668,6 @@ s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
|
||||
}
|
||||
},
|
||||
#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
|
||||
|
||||
[2] = {
|
||||
.port = {
|
||||
.lock = __PORT_LOCK_UNLOCKED(2),
|
||||
@@ -1728,7 +1723,6 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
|
||||
|
||||
static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
|
||||
@@ -1903,9 +1897,9 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
|
||||
port->mapbase = res->start;
|
||||
ret = platform_get_irq(platdev, 0);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
port->irq = 0;
|
||||
else {
|
||||
} else {
|
||||
port->irq = ret;
|
||||
ourport->rx_irq = ret;
|
||||
ourport->tx_irq = ret + 1;
|
||||
@@ -1977,8 +1971,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[];
|
||||
|
||||
static int probe_index;
|
||||
|
||||
static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data(
|
||||
struct platform_device *pdev)
|
||||
static inline struct s3c24xx_serial_drv_data *
|
||||
s3c24xx_get_driver_data(struct platform_device *pdev)
|
||||
{
|
||||
#ifdef CONFIG_OF
|
||||
if (pdev->dev.of_node) {
|
||||
@@ -2329,7 +2323,6 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
|
||||
*baud = rate / (16 * (ubrdiv + 1));
|
||||
dev_dbg(port->dev, "calculated baud %d\n", *baud);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int __init
|
||||
@@ -2696,6 +2689,7 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
|
||||
device->port.private_data = &s3c2410_early_console_data;
|
||||
return samsung_early_console_setup(device, opt);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
|
||||
s3c2410_early_console_setup);
|
||||
|
||||
@@ -2710,6 +2704,7 @@ static int __init s3c2440_early_console_setup(struct earlycon_device *device,
|
||||
device->port.private_data = &s3c2440_early_console_data;
|
||||
return samsung_early_console_setup(device, opt);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
|
||||
s3c2440_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
|
||||
@@ -2728,6 +2723,7 @@ static int __init s5pv210_early_console_setup(struct earlycon_device *device,
|
||||
device->port.private_data = &s5pv210_early_console_data;
|
||||
return samsung_early_console_setup(device, opt);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
|
||||
s5pv210_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
|
||||
|
@@ -439,16 +439,16 @@ static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup,
|
||||
/* Overrrun error */
|
||||
flag = TTY_OVERRUN;
|
||||
tup->uport.icount.overrun++;
|
||||
dev_err(tup->uport.dev, "Got overrun errors\n");
|
||||
dev_dbg(tup->uport.dev, "Got overrun errors\n");
|
||||
} else if (lsr & UART_LSR_PE) {
|
||||
/* Parity error */
|
||||
flag = TTY_PARITY;
|
||||
tup->uport.icount.parity++;
|
||||
dev_err(tup->uport.dev, "Got Parity errors\n");
|
||||
dev_dbg(tup->uport.dev, "Got Parity errors\n");
|
||||
} else if (lsr & UART_LSR_FE) {
|
||||
flag = TTY_FRAME;
|
||||
tup->uport.icount.frame++;
|
||||
dev_err(tup->uport.dev, "Got frame errors\n");
|
||||
dev_dbg(tup->uport.dev, "Got frame errors\n");
|
||||
} else if (lsr & UART_LSR_BI) {
|
||||
/*
|
||||
* Break error
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
@@ -1120,7 +1121,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
|
||||
static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
|
||||
{
|
||||
struct tty_port *port = &state->port;
|
||||
struct uart_port *uport;
|
||||
@@ -1523,6 +1524,7 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||
/* Handle transition away from B0 status */
|
||||
else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
|
||||
unsigned int mask = TIOCM_DTR;
|
||||
|
||||
if (!(cflag & CRTSCTS) || !tty_throttled(tty))
|
||||
mask |= TIOCM_RTS;
|
||||
uart_set_mctrl(uport, mask);
|
||||
@@ -2279,6 +2281,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
if (console_suspend_enabled || !uart_console(uport)) {
|
||||
/* Protected by port mutex for now */
|
||||
struct tty_struct *tty = port->tty;
|
||||
|
||||
ret = ops->startup(uport);
|
||||
if (ret == 0) {
|
||||
if (tty)
|
||||
|
@@ -3301,9 +3301,6 @@ static int sci_probe_single(struct platform_device *dev,
|
||||
sciport->port.flags |= UPF_HARD_FLOW;
|
||||
}
|
||||
|
||||
if (sci_uart_driver.cons->index == sciport->port.line)
|
||||
spin_lock_init(&sciport->port.lock);
|
||||
|
||||
ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
|
||||
if (ret) {
|
||||
sci_cleanup_single(sciport);
|
||||
|
@@ -883,7 +883,6 @@ console_initcall(sifive_console_init);
|
||||
|
||||
static void __ssp_add_console_port(struct sifive_serial_port *ssp)
|
||||
{
|
||||
spin_lock_init(&ssp->port.lock);
|
||||
sifive_serial_console_ports[ssp->port.line] = ssp;
|
||||
}
|
||||
|
||||
|
@@ -129,9 +129,13 @@ static int stm32_config_rs485(struct uart_port *port,
|
||||
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
|
||||
cr3 &= ~USART_CR3_DEP;
|
||||
rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
mctrl_gpio_set(stm32_port->gpios,
|
||||
stm32_port->port.mctrl & ~TIOCM_RTS);
|
||||
} else {
|
||||
cr3 |= USART_CR3_DEP;
|
||||
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
|
||||
mctrl_gpio_set(stm32_port->gpios,
|
||||
stm32_port->port.mctrl | TIOCM_RTS);
|
||||
}
|
||||
|
||||
writel_relaxed(cr3, port->membase + ofs->cr3);
|
||||
@@ -847,9 +851,13 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
|
||||
cr3 &= ~USART_CR3_DEP;
|
||||
rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
mctrl_gpio_set(stm32_port->gpios,
|
||||
stm32_port->port.mctrl & ~TIOCM_RTS);
|
||||
} else {
|
||||
cr3 |= USART_CR3_DEP;
|
||||
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
|
||||
mctrl_gpio_set(stm32_port->gpios,
|
||||
stm32_port->port.mctrl | TIOCM_RTS);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1033,8 +1041,9 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
|
||||
if (WARN_ON(id >= STM32_MAX_PORTS))
|
||||
return NULL;
|
||||
|
||||
stm32_ports[id].hw_flow_control = of_property_read_bool(np,
|
||||
"st,hw-flow-ctrl");
|
||||
stm32_ports[id].hw_flow_control =
|
||||
of_property_read_bool (np, "st,hw-flow-ctrl") /*deprecated*/ ||
|
||||
of_property_read_bool (np, "uart-has-rtscts");
|
||||
stm32_ports[id].port.line = id;
|
||||
stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
|
||||
stm32_ports[id].cr3_irq = 0;
|
||||
|
@@ -567,9 +567,6 @@ static int hv_probe(struct platform_device *op)
|
||||
sunserial_console_match(&sunhv_console, op->dev.of_node,
|
||||
&sunhv_reg, port->line, false);
|
||||
|
||||
/* We need to initialize lock even for non-registered console */
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
err = uart_add_one_port(&sunhv_reg, port);
|
||||
if (err)
|
||||
goto out_unregister_driver;
|
||||
|
@@ -32,7 +32,7 @@
|
||||
* Register definitions
|
||||
*
|
||||
* For register details see datasheet:
|
||||
* http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
|
||||
* https://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
|
||||
*/
|
||||
|
||||
#define ULITE_RX 0x00
|
||||
|
Reference in New Issue
Block a user