aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2010-06-02 15:40:22 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-07-27 05:43:47 -0400
commitac3e3fb424d44109dda3b1a3459e1b30fa60ac4a (patch)
treeb7e537c307e8fe2ed9a2bf0828b4e9f933adb31d
parentec489aa8f993f8d2ec962ce113071faac482aa27 (diff)
ARM: 6158/2: PL011 baudrate extension for ST-Ericssons derivative
Implementation of the ST-Ericsson baudrate extension in the PL011 block. In this modified variant it is possible to change the sampling factor from 16 to 8, and thanks to this we can get higher baudrates while still using the same peripheral clock. Also replace the simple division to determine the baud divisor with DIV_ROUND_CLOSEST() rather than a simple integer division. Cc: Alessandro Rubini <rubini@unipv.it> Cc: Jerzy Kasenberg <jerzy.kasenberg@tieto.com> Signed-off-by: Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-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 */