diff options
Diffstat (limited to 'drivers/tty/serial/amba-pl011.c')
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 9ae024025ff3..6800f5f26241 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -159,6 +159,7 @@ struct uart_amba_port { | |||
159 | unsigned int fifosize; /* vendor-specific */ | 159 | unsigned int fifosize; /* vendor-specific */ |
160 | unsigned int lcrh_tx; /* vendor-specific */ | 160 | unsigned int lcrh_tx; /* vendor-specific */ |
161 | unsigned int lcrh_rx; /* vendor-specific */ | 161 | unsigned int lcrh_rx; /* vendor-specific */ |
162 | unsigned int old_cr; /* state during shutdown */ | ||
162 | bool autorts; | 163 | bool autorts; |
163 | char type[12]; | 164 | char type[12]; |
164 | bool interrupt_may_hang; /* vendor-specific */ | 165 | bool interrupt_may_hang; /* vendor-specific */ |
@@ -1411,7 +1412,9 @@ static int pl011_startup(struct uart_port *port) | |||
1411 | while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) | 1412 | while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) |
1412 | barrier(); | 1413 | barrier(); |
1413 | 1414 | ||
1414 | cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; | 1415 | /* restore RTS and DTR */ |
1416 | cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); | ||
1417 | cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; | ||
1415 | writew(cr, uap->port.membase + UART011_CR); | 1418 | writew(cr, uap->port.membase + UART011_CR); |
1416 | 1419 | ||
1417 | /* Clear pending error interrupts */ | 1420 | /* Clear pending error interrupts */ |
@@ -1469,6 +1472,7 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap, | |||
1469 | static void pl011_shutdown(struct uart_port *port) | 1472 | static void pl011_shutdown(struct uart_port *port) |
1470 | { | 1473 | { |
1471 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 1474 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
1475 | unsigned int cr; | ||
1472 | 1476 | ||
1473 | /* | 1477 | /* |
1474 | * disable all interrupts | 1478 | * disable all interrupts |
@@ -1488,9 +1492,16 @@ static void pl011_shutdown(struct uart_port *port) | |||
1488 | 1492 | ||
1489 | /* | 1493 | /* |
1490 | * disable the port | 1494 | * disable the port |
1495 | * disable the port. It should not disable RTS and DTR. | ||
1496 | * Also RTS and DTR state should be preserved to restore | ||
1497 | * it during startup(). | ||
1491 | */ | 1498 | */ |
1492 | uap->autorts = false; | 1499 | uap->autorts = false; |
1493 | writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR); | 1500 | cr = readw(uap->port.membase + UART011_CR); |
1501 | uap->old_cr = cr; | ||
1502 | cr &= UART011_CR_RTS | UART011_CR_DTR; | ||
1503 | cr |= UART01x_CR_UARTEN | UART011_CR_TXE; | ||
1504 | writew(cr, uap->port.membase + UART011_CR); | ||
1494 | 1505 | ||
1495 | /* | 1506 | /* |
1496 | * disable break condition and fifos | 1507 | * disable break condition and fifos |
@@ -1740,9 +1751,19 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) | |||
1740 | { | 1751 | { |
1741 | struct uart_amba_port *uap = amba_ports[co->index]; | 1752 | struct uart_amba_port *uap = amba_ports[co->index]; |
1742 | unsigned int status, old_cr, new_cr; | 1753 | unsigned int status, old_cr, new_cr; |
1754 | unsigned long flags; | ||
1755 | int locked = 1; | ||
1743 | 1756 | ||
1744 | clk_enable(uap->clk); | 1757 | clk_enable(uap->clk); |
1745 | 1758 | ||
1759 | local_irq_save(flags); | ||
1760 | if (uap->port.sysrq) | ||
1761 | locked = 0; | ||
1762 | else if (oops_in_progress) | ||
1763 | locked = spin_trylock(&uap->port.lock); | ||
1764 | else | ||
1765 | spin_lock(&uap->port.lock); | ||
1766 | |||
1746 | /* | 1767 | /* |
1747 | * First save the CR then disable the interrupts | 1768 | * First save the CR then disable the interrupts |
1748 | */ | 1769 | */ |
@@ -1762,6 +1783,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) | |||
1762 | } while (status & UART01x_FR_BUSY); | 1783 | } while (status & UART01x_FR_BUSY); |
1763 | writew(old_cr, uap->port.membase + UART011_CR); | 1784 | writew(old_cr, uap->port.membase + UART011_CR); |
1764 | 1785 | ||
1786 | if (locked) | ||
1787 | spin_unlock(&uap->port.lock); | ||
1788 | local_irq_restore(flags); | ||
1789 | |||
1765 | clk_disable(uap->clk); | 1790 | clk_disable(uap->clk); |
1766 | } | 1791 | } |
1767 | 1792 | ||
@@ -1905,6 +1930,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) | |||
1905 | uap->vendor = vendor; | 1930 | uap->vendor = vendor; |
1906 | uap->lcrh_rx = vendor->lcrh_rx; | 1931 | uap->lcrh_rx = vendor->lcrh_rx; |
1907 | uap->lcrh_tx = vendor->lcrh_tx; | 1932 | uap->lcrh_tx = vendor->lcrh_tx; |
1933 | uap->old_cr = 0; | ||
1908 | uap->fifosize = vendor->fifosize; | 1934 | uap->fifosize = vendor->fifosize; |
1909 | uap->interrupt_may_hang = vendor->interrupt_may_hang; | 1935 | uap->interrupt_may_hang = vendor->interrupt_may_hang; |
1910 | uap->port.dev = &dev->dev; | 1936 | uap->port.dev = &dev->dev; |