aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/serial/amba-pl011.c61
-rw-r--r--include/linux/amba/serial.h2
2 files changed, 52 insertions, 11 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index eb4cb480b93e..5644cf2385bb 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -69,9 +69,11 @@
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 */
75 bool autorts; 77 bool autorts;
76}; 78};
77 79
@@ -79,16 +81,22 @@ struct uart_amba_port {
79struct vendor_data { 81struct vendor_data {
80 unsigned int ifls; 82 unsigned int ifls;
81 unsigned int fifosize; 83 unsigned int fifosize;
84 unsigned int lcrh_tx;
85 unsigned int lcrh_rx;
82}; 86};
83 87
84static struct vendor_data vendor_arm = { 88static struct vendor_data vendor_arm = {
85 .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, 89 .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
86 .fifosize = 16, 90 .fifosize = 16,
91 .lcrh_tx = UART011_LCRH,
92 .lcrh_rx = UART011_LCRH,
87}; 93};
88 94
89static struct vendor_data vendor_st = { 95static struct vendor_data vendor_st = {
90 .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, 96 .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
91 .fifosize = 64, 97 .fifosize = 64,
98 .lcrh_tx = ST_UART011_LCRH_TX,
99 .lcrh_rx = ST_UART011_LCRH_RX,
92}; 100};
93 101
94static void pl011_stop_tx(struct uart_port *port) 102static void pl011_stop_tx(struct uart_port *port)
@@ -327,12 +335,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
327 unsigned int lcr_h; 335 unsigned int lcr_h;
328 336
329 spin_lock_irqsave(&uap->port.lock, flags); 337 spin_lock_irqsave(&uap->port.lock, flags);
330 lcr_h = readw(uap->port.membase + UART011_LCRH); 338 lcr_h = readw(uap->port.membase + uap->lcrh_tx);
331 if (break_state == -1) 339 if (break_state == -1)
332 lcr_h |= UART01x_LCRH_BRK; 340 lcr_h |= UART01x_LCRH_BRK;
333 else 341 else
334 lcr_h &= ~UART01x_LCRH_BRK; 342 lcr_h &= ~UART01x_LCRH_BRK;
335 writew(lcr_h, uap->port.membase + UART011_LCRH); 343 writew(lcr_h, uap->port.membase + uap->lcrh_tx);
336 spin_unlock_irqrestore(&uap->port.lock, flags); 344 spin_unlock_irqrestore(&uap->port.lock, flags);
337} 345}
338 346
@@ -393,7 +401,17 @@ static int pl011_startup(struct uart_port *port)
393 writew(cr, uap->port.membase + UART011_CR); 401 writew(cr, uap->port.membase + UART011_CR);
394 writew(0, uap->port.membase + UART011_FBRD); 402 writew(0, uap->port.membase + UART011_FBRD);
395 writew(1, uap->port.membase + UART011_IBRD); 403 writew(1, uap->port.membase + UART011_IBRD);
396 writew(0, uap->port.membase + UART011_LCRH); 404 writew(0, uap->port.membase + uap->lcrh_rx);
405 if (uap->lcrh_tx != uap->lcrh_rx) {
406 int i;
407 /*
408 * Wait 10 PCLKs before writing LCRH_TX register,
409 * to get this delay write read only register 10 times
410 */
411 for (i = 0; i < 10; ++i)
412 writew(0xff, uap->port.membase + UART011_MIS);
413 writew(0, uap->port.membase + uap->lcrh_tx);
414 }
397 writew(0, uap->port.membase + UART01x_DR); 415 writew(0, uap->port.membase + UART01x_DR);
398 while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) 416 while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
399 barrier(); 417 barrier();
@@ -422,10 +440,19 @@ static int pl011_startup(struct uart_port *port)
422 return retval; 440 return retval;
423} 441}
424 442
443static void pl011_shutdown_channel(struct uart_amba_port *uap,
444 unsigned int lcrh)
445{
446 unsigned long val;
447
448 val = readw(uap->port.membase + lcrh);
449 val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
450 writew(val, uap->port.membase + lcrh);
451}
452
425static void pl011_shutdown(struct uart_port *port) 453static void pl011_shutdown(struct uart_port *port)
426{ 454{
427 struct uart_amba_port *uap = (struct uart_amba_port *)port; 455 struct uart_amba_port *uap = (struct uart_amba_port *)port;
428 unsigned long val;
429 456
430 /* 457 /*
431 * disable all interrupts 458 * disable all interrupts
@@ -450,9 +477,9 @@ static void pl011_shutdown(struct uart_port *port)
450 /* 477 /*
451 * disable break condition and fifos 478 * disable break condition and fifos
452 */ 479 */
453 val = readw(uap->port.membase + UART011_LCRH); 480 pl011_shutdown_channel(uap, uap->lcrh_rx);
454 val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); 481 if (uap->lcrh_rx != uap->lcrh_tx)
455 writew(val, uap->port.membase + UART011_LCRH); 482 pl011_shutdown_channel(uap, uap->lcrh_tx);
456 483
457 /* 484 /*
458 * Shut down the clock producer 485 * Shut down the clock producer
@@ -561,7 +588,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
561 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L 588 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
562 * ----------^----------^----------^----------^----- 589 * ----------^----------^----------^----------^-----
563 */ 590 */
564 writew(lcr_h, port->membase + UART011_LCRH); 591 writew(lcr_h, port->membase + uap->lcrh_rx);
592 if (uap->lcrh_rx != uap->lcrh_tx) {
593 int i;
594 /*
595 * Wait 10 PCLKs before writing LCRH_TX register,
596 * to get this delay write read only register 10 times
597 */
598 for (i = 0; i < 10; ++i)
599 writew(0xff, uap->port.membase + UART011_MIS);
600 writew(lcr_h, port->membase + uap->lcrh_tx);
601 }
565 writew(old_cr, port->membase + UART011_CR); 602 writew(old_cr, port->membase + UART011_CR);
566 603
567 spin_unlock_irqrestore(&port->lock, flags); 604 spin_unlock_irqrestore(&port->lock, flags);
@@ -688,7 +725,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
688 if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { 725 if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
689 unsigned int lcr_h, ibrd, fbrd; 726 unsigned int lcr_h, ibrd, fbrd;
690 727
691 lcr_h = readw(uap->port.membase + UART011_LCRH); 728 lcr_h = readw(uap->port.membase + uap->lcrh_tx);
692 729
693 *parity = 'n'; 730 *parity = 'n';
694 if (lcr_h & UART01x_LCRH_PEN) { 731 if (lcr_h & UART01x_LCRH_PEN) {
@@ -800,6 +837,8 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
800 } 837 }
801 838
802 uap->ifls = vendor->ifls; 839 uap->ifls = vendor->ifls;
840 uap->lcrh_rx = vendor->lcrh_rx;
841 uap->lcrh_tx = vendor->lcrh_tx;
803 uap->port.dev = &dev->dev; 842 uap->port.dev = &dev->dev;
804 uap->port.mapbase = dev->res.start; 843 uap->port.mapbase = dev->res.start;
805 uap->port.membase = base; 844 uap->port.membase = base;
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 5a5a7fd62490..93c96a66c518 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -38,10 +38,12 @@
38#define UART01x_FR 0x18 /* Flag register (Read only). */ 38#define UART01x_FR 0x18 /* Flag register (Read only). */
39#define UART010_IIR 0x1C /* Interrupt indentification register (Read). */ 39#define UART010_IIR 0x1C /* Interrupt indentification register (Read). */
40#define UART010_ICR 0x1C /* Interrupt clear register (Write). */ 40#define UART010_ICR 0x1C /* Interrupt clear register (Write). */
41#define ST_UART011_LCRH_RX 0x1C /* Rx line control register. */
41#define UART01x_ILPR 0x20 /* IrDA low power counter register. */ 42#define UART01x_ILPR 0x20 /* IrDA low power counter register. */
42#define UART011_IBRD 0x24 /* Integer baud rate divisor register. */ 43#define UART011_IBRD 0x24 /* Integer baud rate divisor register. */
43#define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */ 44#define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */
44#define UART011_LCRH 0x2c /* Line control register. */ 45#define UART011_LCRH 0x2c /* Line control register. */
46#define ST_UART011_LCRH_TX 0x2c /* Tx Line control register. */
45#define UART011_CR 0x30 /* Control register. */ 47#define UART011_CR 0x30 /* Control register. */
46#define UART011_IFLS 0x34 /* Interrupt fifo level select. */ 48#define UART011_IFLS 0x34 /* Interrupt fifo level select. */
47#define UART011_IMSC 0x38 /* Interrupt mask. */ 49#define UART011_IMSC 0x38 /* Interrupt mask. */