diff options
author | Joshua Scott <joshua.scott@alliedtelesis.co.nz> | 2018-03-16 13:42:00 +1300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-04-23 10:11:13 +0200 |
commit | b7639b0b15ddd1a4686b0142e70dfb122eefc88f (patch) | |
tree | e2c3f53b29dc09f7a73f99a1f2ad54d539b29362 /drivers/tty/serial/8250 | |
parent | 63ba1e00f178a4483b473489cadc4eb52a77df2a (diff) | |
download | linux-b7639b0b15ddd1a4686b0142e70dfb122eefc88f.tar.bz2 |
serial: 8250_dw: Limit dw8250_tx_wait_empty quirk to armada-38x devices
The previous implementation has had a detrimental effect on devices using
high bitrates (bluetooth), as the fifo being non-empty for a single check
would result in a 10 µs delay.
Limit the change to devices with the new "marvell,armada-38x-uart"
compatible string. Also update the code to allow the first 1000 retries
to not perform a delay.
The maximum duration of retries has been increased to cover a worst-case
seen on the Armada 385 SoC. "dmesg ; resize", will fill the buffer with
text to output before doing a resize. At 9600 baud this took up to 13 ms
to flush all characters and avoid some getting lost.
Signed-off-by: Joshua Scott <joshua.scott@alliedtelesis.co.nz>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 6fcdb90f616a..0529b5cc094b 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -121,25 +121,44 @@ static void dw8250_check_lcr(struct uart_port *p, int value) } /* Returns once the transmitter is empty or we run out of retries */ -static void dw8250_tx_wait_empty(struct uart_port *p, int tries) +static void dw8250_tx_wait_empty(struct uart_port *p) { + unsigned int tries = 20000; + unsigned int delay_threshold = tries - 1000; unsigned int lsr; while (tries--) { lsr = readb (p->membase + (UART_LSR << p->regshift)); if (lsr & UART_LSR_TEMT) break; - udelay (10); + + /* The device is first given a chance to empty without delay, + * to avoid slowdowns at high bitrates. If after 1000 tries + * the buffer has still not emptied, allow more time for low- + * speed links. */ + if (tries < delay_threshold) + udelay (1); } } -static void dw8250_serial_out(struct uart_port *p, int offset, int value) +static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; /* Allow the TX to drain before we reconfigure */ if (offset == UART_LCR) - dw8250_tx_wait_empty(p, 1000); + dw8250_tx_wait_empty(p); + + writeb(value, p->membase + (offset << p->regshift)); + + if (offset == UART_LCR && !d->uart_16550_compatible) + dw8250_check_lcr(p, value); +} + + +static void dw8250_serial_out(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; writeb(value, p->membase + (offset << p->regshift)); @@ -357,6 +376,9 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) p->serial_in = dw8250_serial_in32be; p->serial_out = dw8250_serial_out32be; } + if (of_device_is_compatible(np, "marvell,armada-38x-uart")) + p->serial_out = dw8250_serial_out38x; + } else if (acpi_dev_present("APMC0D08", NULL, -1)) { p->iotype = UPIO_MEM32; p->regshift = 2; @@ -666,6 +688,7 @@ static const struct dev_pm_ops dw8250_pm_ops = { static const struct of_device_id dw8250_of_match[] = { { .compatible = "snps,dw-apb-uart" }, { .compatible = "cavium,octeon-3860-uart" }, + { .compatible = "marvell,armada-38x-uart" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dw8250_of_match); |