aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/amba-pl011.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial/amba-pl011.c')
-rw-r--r--drivers/serial/amba-pl011.c90
1 files changed, 76 insertions, 14 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index eb4cb480b93e..6ca7a44f29c2 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -69,9 +69,12 @@
69struct uart_amba_port { 69struct uart_amba_port {
70 struct uart_port port; 70 struct uart_port port;
71 struct clk *clk; 71 struct clk *clk;
72 unsigned int im; /* interrupt mask */ 72 unsigned int im; /* interrupt mask */
73 unsigned int old_status; 73 unsigned int old_status;
74 unsigned int ifls; /* vendor-specific */ 74 unsigned int ifls; /* vendor-specific */
75 unsigned int lcrh_tx; /* vendor-specific */
76 unsigned int lcrh_rx; /* vendor-specific */
77 bool oversampling; /* vendor-specific */
75 bool autorts; 78 bool autorts;
76}; 79};
77 80
@@ -79,16 +82,25 @@ struct uart_amba_port {
79struct vendor_data { 82struct vendor_data {
80 unsigned int ifls; 83 unsigned int ifls;
81 unsigned int fifosize; 84 unsigned int fifosize;
85 unsigned int lcrh_tx;
86 unsigned int lcrh_rx;
87 bool oversampling;
82}; 88};
83 89
84static struct vendor_data vendor_arm = { 90static struct vendor_data vendor_arm = {
85 .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, 91 .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
86 .fifosize = 16, 92 .fifosize = 16,
93 .lcrh_tx = UART011_LCRH,
94 .lcrh_rx = UART011_LCRH,
95 .oversampling = false,
87}; 96};
88 97
89static struct vendor_data vendor_st = { 98static struct vendor_data vendor_st = {
90 .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, 99 .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
91 .fifosize = 64, 100 .fifosize = 64,
101 .lcrh_tx = ST_UART011_LCRH_TX,
102 .lcrh_rx = ST_UART011_LCRH_RX,
103 .oversampling = true,
92}; 104};
93 105
94static void pl011_stop_tx(struct uart_port *port) 106static void pl011_stop_tx(struct uart_port *port)
@@ -327,12 +339,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
327 unsigned int lcr_h; 339 unsigned int lcr_h;
328 340
329 spin_lock_irqsave(&uap->port.lock, flags); 341 spin_lock_irqsave(&uap->port.lock, flags);
330 lcr_h = readw(uap->port.membase + UART011_LCRH); 342 lcr_h = readw(uap->port.membase + uap->lcrh_tx);
331 if (break_state == -1) 343 if (break_state == -1)
332 lcr_h |= UART01x_LCRH_BRK; 344 lcr_h |= UART01x_LCRH_BRK;
333 else 345 else
334 lcr_h &= ~UART01x_LCRH_BRK; 346 lcr_h &= ~UART01x_LCRH_BRK;
335 writew(lcr_h, uap->port.membase + UART011_LCRH); 347 writew(lcr_h, uap->port.membase + uap->lcrh_tx);
336 spin_unlock_irqrestore(&uap->port.lock, flags); 348 spin_unlock_irqrestore(&uap->port.lock, flags);
337} 349}
338 350
@@ -393,7 +405,17 @@ static int pl011_startup(struct uart_port *port)
393 writew(cr, uap->port.membase + UART011_CR); 405 writew(cr, uap->port.membase + UART011_CR);
394 writew(0, uap->port.membase + UART011_FBRD); 406 writew(0, uap->port.membase + UART011_FBRD);
395 writew(1, uap->port.membase + UART011_IBRD); 407 writew(1, uap->port.membase + UART011_IBRD);
396 writew(0, uap->port.membase + UART011_LCRH); 408 writew(0, uap->port.membase + uap->lcrh_rx);
409 if (uap->lcrh_tx != uap->lcrh_rx) {
410 int i;
411 /*
412 * Wait 10 PCLKs before writing LCRH_TX register,
413 * to get this delay write read only register 10 times
414 */
415 for (i = 0; i < 10; ++i)
416 writew(0xff, uap->port.membase + UART011_MIS);
417 writew(0, uap->port.membase + uap->lcrh_tx);
418 }
397 writew(0, uap->port.membase + UART01x_DR); 419 writew(0, uap->port.membase + UART01x_DR);
398 while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) 420 while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
399 barrier(); 421 barrier();
@@ -422,10 +444,19 @@ static int pl011_startup(struct uart_port *port)
422 return retval; 444 return retval;
423} 445}
424 446
447static void pl011_shutdown_channel(struct uart_amba_port *uap,
448 unsigned int lcrh)
449{
450 unsigned long val;
451
452 val = readw(uap->port.membase + lcrh);
453 val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
454 writew(val, uap->port.membase + lcrh);
455}
456
425static void pl011_shutdown(struct uart_port *port) 457static void pl011_shutdown(struct uart_port *port)
426{ 458{
427 struct uart_amba_port *uap = (struct uart_amba_port *)port; 459 struct uart_amba_port *uap = (struct uart_amba_port *)port;
428 unsigned long val;
429 460
430 /* 461 /*
431 * disable all interrupts 462 * disable all interrupts
@@ -450,9 +481,9 @@ static void pl011_shutdown(struct uart_port *port)
450 /* 481 /*
451 * disable break condition and fifos 482 * disable break condition and fifos
452 */ 483 */
453 val = readw(uap->port.membase + UART011_LCRH); 484 pl011_shutdown_channel(uap, uap->lcrh_rx);
454 val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); 485 if (uap->lcrh_rx != uap->lcrh_tx)
455 writew(val, uap->port.membase + UART011_LCRH); 486 pl011_shutdown_channel(uap, uap->lcrh_tx);
456 487
457 /* 488 /*
458 * Shut down the clock producer 489 * Shut down the clock producer
@@ -472,8 +503,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
472 /* 503 /*
473 * Ask the core to calculate the divisor for us. 504 * Ask the core to calculate the divisor for us.
474 */ 505 */
475 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 506 baud = uart_get_baud_rate(port, termios, old, 0,
476 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);
477 513
478 switch (termios->c_cflag & CSIZE) { 514 switch (termios->c_cflag & CSIZE) {
479 case CS5: 515 case CS5:
@@ -552,6 +588,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
552 uap->autorts = false; 588 uap->autorts = false;
553 } 589 }
554 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
555 /* Set baud rate */ 598 /* Set baud rate */
556 writew(quot & 0x3f, port->membase + UART011_FBRD); 599 writew(quot & 0x3f, port->membase + UART011_FBRD);
557 writew(quot >> 6, port->membase + UART011_IBRD); 600 writew(quot >> 6, port->membase + UART011_IBRD);
@@ -561,7 +604,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
561 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L 604 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
562 * ----------^----------^----------^----------^----- 605 * ----------^----------^----------^----------^-----
563 */ 606 */
564 writew(lcr_h, port->membase + UART011_LCRH); 607 writew(lcr_h, port->membase + uap->lcrh_rx);
608 if (uap->lcrh_rx != uap->lcrh_tx) {
609 int i;
610 /*
611 * Wait 10 PCLKs before writing LCRH_TX register,
612 * to get this delay write read only register 10 times
613 */
614 for (i = 0; i < 10; ++i)
615 writew(0xff, uap->port.membase + UART011_MIS);
616 writew(lcr_h, port->membase + uap->lcrh_tx);
617 }
565 writew(old_cr, port->membase + UART011_CR); 618 writew(old_cr, port->membase + UART011_CR);
566 619
567 spin_unlock_irqrestore(&port->lock, flags); 620 spin_unlock_irqrestore(&port->lock, flags);
@@ -688,7 +741,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
688 if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { 741 if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
689 unsigned int lcr_h, ibrd, fbrd; 742 unsigned int lcr_h, ibrd, fbrd;
690 743
691 lcr_h = readw(uap->port.membase + UART011_LCRH); 744 lcr_h = readw(uap->port.membase + uap->lcrh_tx);
692 745
693 *parity = 'n'; 746 *parity = 'n';
694 if (lcr_h & UART01x_LCRH_PEN) { 747 if (lcr_h & UART01x_LCRH_PEN) {
@@ -707,6 +760,12 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
707 fbrd = readw(uap->port.membase + UART011_FBRD); 760 fbrd = readw(uap->port.membase + UART011_FBRD);
708 761
709 *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 }
710 } 769 }
711} 770}
712 771
@@ -800,6 +859,9 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
800 } 859 }
801 860
802 uap->ifls = vendor->ifls; 861 uap->ifls = vendor->ifls;
862 uap->lcrh_rx = vendor->lcrh_rx;
863 uap->lcrh_tx = vendor->lcrh_tx;
864 uap->oversampling = vendor->oversampling;
803 uap->port.dev = &dev->dev; 865 uap->port.dev = &dev->dev;
804 uap->port.mapbase = dev->res.start; 866 uap->port.mapbase = dev->res.start;
805 uap->port.membase = base; 867 uap->port.membase = base;
@@ -868,7 +930,7 @@ static int pl011_resume(struct amba_device *dev)
868} 930}
869#endif 931#endif
870 932
871static struct amba_id pl011_ids[] __initdata = { 933static struct amba_id pl011_ids[] = {
872 { 934 {
873 .id = 0x00041011, 935 .id = 0x00041011,
874 .mask = 0x000fffff, 936 .mask = 0x000fffff,