mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 17:11:46 +00:00
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>
This commit is contained in:
parent
63ba1e00f1
commit
b7639b0b15
2 changed files with 29 additions and 6 deletions
|
@ -163,7 +163,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "snps,dw-apb-uart";
|
compatible = "marvell,armada-38x-uart";
|
||||||
reg = <0x12000 0x100>;
|
reg = <0x12000 0x100>;
|
||||||
reg-shift = <2>;
|
reg-shift = <2>;
|
||||||
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
@ -173,7 +173,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
uart1: serial@12100 {
|
uart1: serial@12100 {
|
||||||
compatible = "snps,dw-apb-uart";
|
compatible = "marvell,armada-38x-uart";
|
||||||
reg = <0x12100 0x100>;
|
reg = <0x12100 0x100>;
|
||||||
reg-shift = <2>;
|
reg-shift = <2>;
|
||||||
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
|
|
@ -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 */
|
/* 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;
|
unsigned int lsr;
|
||||||
|
|
||||||
while (tries--) {
|
while (tries--) {
|
||||||
lsr = readb (p->membase + (UART_LSR << p->regshift));
|
lsr = readb (p->membase + (UART_LSR << p->regshift));
|
||||||
if (lsr & UART_LSR_TEMT)
|
if (lsr & UART_LSR_TEMT)
|
||||||
break;
|
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;
|
struct dw8250_data *d = p->private_data;
|
||||||
|
|
||||||
/* Allow the TX to drain before we reconfigure */
|
/* Allow the TX to drain before we reconfigure */
|
||||||
if (offset == UART_LCR)
|
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));
|
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_in = dw8250_serial_in32be;
|
||||||
p->serial_out = dw8250_serial_out32be;
|
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)) {
|
} else if (acpi_dev_present("APMC0D08", NULL, -1)) {
|
||||||
p->iotype = UPIO_MEM32;
|
p->iotype = UPIO_MEM32;
|
||||||
p->regshift = 2;
|
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[] = {
|
static const struct of_device_id dw8250_of_match[] = {
|
||||||
{ .compatible = "snps,dw-apb-uart" },
|
{ .compatible = "snps,dw-apb-uart" },
|
||||||
{ .compatible = "cavium,octeon-3860-uart" },
|
{ .compatible = "cavium,octeon-3860-uart" },
|
||||||
|
{ .compatible = "marvell,armada-38x-uart" },
|
||||||
{ /* Sentinel */ }
|
{ /* Sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dw8250_of_match);
|
MODULE_DEVICE_TABLE(of, dw8250_of_match);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue