aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/serial/amba-pl011.c27
-rw-r--r--include/linux/amba/serial.h1
2 files changed, 26 insertions, 2 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 5644cf2385bb..f67e09da6d33 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -74,6 +74,7 @@ struct uart_amba_port {
74 unsigned int ifls; /* vendor-specific */ 74 unsigned int ifls; /* vendor-specific */
75 unsigned int lcrh_tx; /* vendor-specific */ 75 unsigned int lcrh_tx; /* vendor-specific */
76 unsigned int lcrh_rx; /* vendor-specific */ 76 unsigned int lcrh_rx; /* vendor-specific */
77 bool oversampling; /* vendor-specific */
77 bool autorts; 78 bool autorts;
78}; 79};
79 80
@@ -83,6 +84,7 @@ struct vendor_data {
83 unsigned int fifosize; 84 unsigned int fifosize;
84 unsigned int lcrh_tx; 85 unsigned int lcrh_tx;
85 unsigned int lcrh_rx; 86 unsigned int lcrh_rx;
87 bool oversampling;
86}; 88};
87 89
88static struct vendor_data vendor_arm = { 90static struct vendor_data vendor_arm = {
@@ -90,6 +92,7 @@ static struct vendor_data vendor_arm = {
90 .fifosize = 16, 92 .fifosize = 16,
91 .lcrh_tx = UART011_LCRH, 93 .lcrh_tx = UART011_LCRH,
92 .lcrh_rx = UART011_LCRH, 94 .lcrh_rx = UART011_LCRH,
95 .oversampling = false,
93}; 96};
94 97
95static struct vendor_data vendor_st = { 98static struct vendor_data vendor_st = {
@@ -97,6 +100,7 @@ static struct vendor_data vendor_st = {
97 .fifosize = 64, 100 .fifosize = 64,
98 .lcrh_tx = ST_UART011_LCRH_TX, 101 .lcrh_tx = ST_UART011_LCRH_TX,
99 .lcrh_rx = ST_UART011_LCRH_RX, 102 .lcrh_rx = ST_UART011_LCRH_RX,
103 .oversampling = true,
100}; 104};
101 105
102static void pl011_stop_tx(struct uart_port *port) 106static void pl011_stop_tx(struct uart_port *port)
@@ -499,8 +503,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
499 /* 503 /*
500 * Ask the core to calculate the divisor for us. 504 * Ask the core to calculate the divisor for us.
501 */ 505 */
502 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 506 baud = uart_get_baud_rate(port, termios, old, 0,
503 quot = port->uartclk * 4 / baud; 507 port->uartclk/(uap->oversampling ? 8 : 16));
508
509 if (baud > port->uartclk/16)
510 quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
511 else
512 quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
504 513
505 switch (termios->c_cflag & CSIZE) { 514 switch (termios->c_cflag & CSIZE) {
506 case CS5: 515 case CS5:
@@ -579,6 +588,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
579 uap->autorts = false; 588 uap->autorts = false;
580 } 589 }
581 590
591 if (uap->oversampling) {
592 if (baud > port->uartclk/16)
593 old_cr |= ST_UART011_CR_OVSFACT;
594 else
595 old_cr &= ~ST_UART011_CR_OVSFACT;
596 }
597
582 /* Set baud rate */ 598 /* Set baud rate */
583 writew(quot & 0x3f, port->membase + UART011_FBRD); 599 writew(quot & 0x3f, port->membase + UART011_FBRD);
584 writew(quot >> 6, port->membase + UART011_IBRD); 600 writew(quot >> 6, port->membase + UART011_IBRD);
@@ -744,6 +760,12 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
744 fbrd = readw(uap->port.membase + UART011_FBRD); 760 fbrd = readw(uap->port.membase + UART011_FBRD);
745 761
746 *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); 762 *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
763
764 if (uap->oversampling) {
765 if (readw(uap->port.membase + UART011_CR)
766 & ST_UART011_CR_OVSFACT)
767 *baud *= 2;
768 }
747 } 769 }
748} 770}
749 771
@@ -839,6 +861,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
839 uap->ifls = vendor->ifls; 861 uap->ifls = vendor->ifls;
840 uap->lcrh_rx = vendor->lcrh_rx; 862 uap->lcrh_rx = vendor->lcrh_rx;
841 uap->lcrh_tx = vendor->lcrh_tx; 863 uap->lcrh_tx = vendor->lcrh_tx;
864 uap->oversampling = vendor->oversampling;
842 uap->port.dev = &dev->dev; 865 uap->port.dev = &dev->dev;
843 uap->port.mapbase = dev->res.start; 866 uap->port.mapbase = dev->res.start;
844 uap->port.membase = base; 867 uap->port.membase = base;
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 93c96a66c518..e1b634b635f2 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -86,6 +86,7 @@
86#define UART010_CR_TIE 0x0020 86#define UART010_CR_TIE 0x0020
87#define UART010_CR_RIE 0x0010 87#define UART010_CR_RIE 0x0010
88#define UART010_CR_MSIE 0x0008 88#define UART010_CR_MSIE 0x0008
89#define ST_UART011_CR_OVSFACT 0x0008 /* Oversampling factor */
89#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */ 90#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */
90#define UART01x_CR_SIREN 0x0002 /* SIR enable */ 91#define UART01x_CR_SIREN 0x0002 /* SIR enable */
91#define UART01x_CR_UARTEN 0x0001 /* UART enable */ 92#define UART01x_CR_UARTEN 0x0001 /* UART enable */