aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-10-05 08:54:53 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-11-04 06:54:31 -0500
commit08bd4903c20d9d4bea64b1751386a478faa24ab0 (patch)
tree79659e2199785262744720805ba6ca641df893cb /drivers/tty
parent9363f8fa8930db6383b4089036799a276257fdb7 (diff)
SERIAL: omap: fix MCR TCRTLR bit handling
The MCR TCRTLR bit can only be changed when ECB is set in the EFR. Unfortunately, several places were trying to alter this bit while ECB was clear: - serial_omap_configure_xonxoff() was attempting to clear the bit after explicitly clearing the ECB bit. - serial_omap_set_termios() was trying the same trick after setting the SCR, and when trying to change the TCR register when hardware flow control was enabled. Fix this by ensuring that we always have ECB set whenever the TCRTLR bit is changed. Moreover, we start out by reading the EFR and MCR registers, which may have indeterminent bit settings for the ECB and TCRTLR bits. Ensure that these bits always start off in a known state. In order to avoid any undesired behaviour appearing through fixing this, we also ensure that hardware assisted flow control is disabled while new driver specific parts are not in place. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/omap-serial.c37
1 files changed, 21 insertions, 16 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index fb06def4d98..170be2b1cdb 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -706,9 +706,10 @@ serial_omap_configure_xonxoff
706 serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); 706 serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
707 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 707 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
708 serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); 708 serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
709 serial_out(up, UART_EFR, up->efr);
710 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 709 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
711 serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR); 710 serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
711 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
712 serial_out(up, UART_EFR, up->efr);
712 serial_out(up, UART_LCR, up->lcr); 713 serial_out(up, UART_LCR, up->lcr);
713} 714}
714 715
@@ -729,7 +730,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
729{ 730{
730 struct uart_omap_port *up = to_uart_omap_port(port); 731 struct uart_omap_port *up = to_uart_omap_port(port);
731 unsigned char cval = 0; 732 unsigned char cval = 0;
732 unsigned char efr = 0;
733 unsigned long flags = 0; 733 unsigned long flags = 0;
734 unsigned int baud, quot; 734 unsigned int baud, quot;
735 735
@@ -839,12 +839,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
839 839
840 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 840 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
841 841
842 up->efr = serial_in(up, UART_EFR); 842 up->efr = serial_in(up, UART_EFR) & ~UART_EFR_ECB;
843 up->efr &= ~UART_EFR_SCD; 843 up->efr &= ~UART_EFR_SCD;
844 serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); 844 serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
845 845
846 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 846 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
847 up->mcr = serial_in(up, UART_MCR); 847 up->mcr = serial_in(up, UART_MCR) & ~UART_MCR_TCRTLR;
848 serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); 848 serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
849 /* FIFO ENABLE, DMA MODE */ 849 /* FIFO ENABLE, DMA MODE */
850 850
@@ -863,9 +863,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
863 863
864 serial_out(up, UART_OMAP_SCR, up->scr); 864 serial_out(up, UART_OMAP_SCR, up->scr);
865 865
866 serial_out(up, UART_EFR, up->efr); 866 /* Reset UART_MCR_TCRTLR: this must be done with the EFR_ECB bit set */
867 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 867 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
868 serial_out(up, UART_MCR, up->mcr); 868 serial_out(up, UART_MCR, up->mcr);
869 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
870 serial_out(up, UART_EFR, up->efr);
871 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
869 872
870 /* Protocol, Baud Rate, and Interrupt Settings */ 873 /* Protocol, Baud Rate, and Interrupt Settings */
871 874
@@ -903,21 +906,22 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
903 906
904 /* Hardware Flow Control Configuration */ 907 /* Hardware Flow Control Configuration */
905 908
906 if (termios->c_cflag & CRTSCTS) { 909 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
907 efr |= (UART_EFR_CTS | UART_EFR_RTS); 910 /* Enable access to TCR/TLR */
908 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
909
910 up->mcr = serial_in(up, UART_MCR);
911 serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
912
913 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 911 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
914 up->efr = serial_in(up, UART_EFR);
915 serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); 912 serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
913 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
914 serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
916 915
917 serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); 916 serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
918 serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */ 917
919 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 918 /* Enable AUTORTS and AUTOCTS */
919 up->efr |= UART_EFR_CTS | UART_EFR_RTS;
920
921 /* Disable access to TCR/TLR */
920 serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS); 922 serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
923 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
924 serial_out(up, UART_EFR, up->efr);
921 serial_out(up, UART_LCR, cval); 925 serial_out(up, UART_LCR, cval);
922 } else { 926 } else {
923 /* Disable AUTORTS and AUTOCTS */ 927 /* Disable AUTORTS and AUTOCTS */
@@ -930,7 +934,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
930 934
931 serial_omap_set_mctrl(&up->port, up->port.mctrl); 935 serial_omap_set_mctrl(&up->port, up->port.mctrl);
932 /* Software Flow Control Configuration */ 936 /* Software Flow Control Configuration */
933 serial_omap_configure_xonxoff(up, termios); 937 if (up->port.flags & UPF_SOFT_FLOW)
938 serial_omap_configure_xonxoff(up, termios);
934 939
935 spin_unlock_irqrestore(&up->port.lock, flags); 940 spin_unlock_irqrestore(&up->port.lock, flags);
936 pm_runtime_mark_last_busy(up->dev); 941 pm_runtime_mark_last_busy(up->dev);