From patchwork Sat Oct 6 12:40:21 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell King X-Patchwork-Id: 1557271 Return-Path: X-Original-To: patchwork-linux-omap@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id B95C93FD56 for ; Sat, 6 Oct 2012 12:40:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755943Ab2JFMkb (ORCPT ); Sat, 6 Oct 2012 08:40:31 -0400 Received: from caramon.arm.linux.org.uk ([78.32.30.218]:47217 "EHLO caramon.arm.linux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755805Ab2JFMka (ORCPT ); Sat, 6 Oct 2012 08:40:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=arm.linux.org.uk; s=caramon; h=Date:Sender:Message-Id:Subject:Cc:To:From:References:In-Reply-To; bh=ayCnCcl62yWMJnSvXxxZtBWS+LtEZ2tp5KNh4mY74TI=; b=NKyiaZW6gioMQxbpQkyDqdI0xpukyx0U45sBJVDk0wAdJ+fFR6RkG3by00ygrVucy3J45jumzox4RWYcRRBCyDO9P6Pkw+ufTo9JysqJu5v4VsX4olEf2XVe5WuSIZTuiEcb+CzL+/r79woMBMBxTxP2plyKdFWLMyqOXqgK5GE=; Received: from e0022681537dd.dyn.arm.linux.org.uk ([2002:4e20:1eda:1:222:68ff:fe15:37dd]:39593 helo=rmk-PC.arm.linux.org.uk) by caramon.arm.linux.org.uk with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.76) (envelope-from ) id 1TKTg6-00086b-MB; Sat, 06 Oct 2012 13:40:22 +0100 Received: from rmk by rmk-PC.arm.linux.org.uk with local (Exim 4.76) (envelope-from ) id 1TKTg5-0002ma-PI; Sat, 06 Oct 2012 13:40:22 +0100 In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk> References: <20121006123803.GD15246@n2100.arm.linux.org.uk> From: Russell King To: Tony Lindgren , Alan Cox , Greg Kroah-Hartman Cc: linux-arm-kernel@lists.infradead.org, linux-omap@vger.kernel.org, linux-serial@vger.kernel.org Subject: [RFC 04/24] SERIAL: omap: fix MCR TCRTLR bit handling Message-Id: Date: Sat, 06 Oct 2012 13:40:21 +0100 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org 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. Signed-off-by: Russell King --- drivers/tty/serial/omap-serial.c | 32 ++++++++++++++++++-------------- 1 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 5333f19..391087e 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -700,9 +700,10 @@ serial_omap_configure_xonxoff serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); - serial_out(up, UART_EFR, up->efr); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, up->efr); serial_out(up, UART_LCR, up->lcr); } @@ -720,7 +721,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, { struct uart_omap_port *up = (struct uart_omap_port *)port; unsigned char cval = 0; - unsigned char efr = 0; unsigned long flags = 0; unsigned int baud, quot; @@ -832,12 +832,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - up->efr = serial_in(up, UART_EFR); + up->efr = serial_in(up, UART_EFR) & ~UART_EFR_ECB; up->efr &= ~UART_EFR_SCD; serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - up->mcr = serial_in(up, UART_MCR); + up->mcr = serial_in(up, UART_MCR) & ~UART_MCR_TCRTLR; serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); /* FIFO ENABLE, DMA MODE */ @@ -857,9 +857,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_OMAP_SCR, up->scr); - serial_out(up, UART_EFR, up->efr); + /* Reset UART_MCR_TCRTLR: this must be done with the EFR_ECB bit set */ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_out(up, UART_MCR, up->mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); /* Protocol, Baud Rate, and Interrupt Settings */ @@ -900,20 +903,21 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, /* Hardware Flow Control Configuration */ if (termios->c_cflag & CRTSCTS) { - efr |= (UART_EFR_CTS | UART_EFR_RTS); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - - up->mcr = serial_in(up, UART_MCR); - serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); - + /* Enable access to TCR/TLR */ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - up->efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); - serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + + /* Enable AUTORTS and AUTOCTS */ + up->efr |= UART_EFR_CTS | UART_EFR_RTS; + + /* Disable access to TCR/TLR */ serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, up->efr); serial_out(up, UART_LCR, cval); }