aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2012-01-25 21:50:52 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-09 13:48:34 -0500
commitbe4b0281956c5cae4f63f31f11d07625a6988766 (patch)
treec75f6d88a142889eec90c5ae2e023b31fb3445df /drivers/tty/serial
parent0ba5f66836c9253c67c469fb4016f94ea30ff2ce (diff)
tty: serial: OMAP: block idle while the UART is transferring data in PIO mode
Prevent OMAP UARTs from going idle while they are still transferring data in PIO mode. This works around an oversight in the OMAP UART hardware present in OMAP34xx and earlier: an idle UART won't send a wakeup when the TX FIFO threshold is reached. This causes long delays during data transmission when the MPU powerdomain enters a low-power mode. The MPU interrupt controller is not able to respond to interrupts when it's in a low-power state, so the TX buffer is not refilled until another wakeup event occurs. This fix changes the erratum i291 DMA idle workaround. Rather than toggling between force-idle and no-idle, it will toggle between smart-idle and no-idle. The important part of the workaround is the no-idle part, so this shouldn't result in any change in behavior. This fix should work on all OMAP UARTs. Future patches intended for the 3.4 merge window will make this workaround conditional on a "feature" flag, and will use the OMAP36xx+ TX event wakeup support. Thanks to Kevin Hilman <khilman@ti.com> for mentioning the erratum i291 workaround, which led to the development of this approach. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Alan Cox <alan@linux.intel.com> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Govindraj.R <govindraj.raja@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Tested-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/omap-serial.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index a3f5ea46f345..18d13248d9ba 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -136,6 +136,7 @@ static void serial_omap_enable_ms(struct uart_port *port)
136static void serial_omap_stop_tx(struct uart_port *port) 136static void serial_omap_stop_tx(struct uart_port *port)
137{ 137{
138 struct uart_omap_port *up = (struct uart_omap_port *)port; 138 struct uart_omap_port *up = (struct uart_omap_port *)port;
139 struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
139 140
140 if (up->use_dma && 141 if (up->use_dma &&
141 up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) { 142 up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
@@ -158,6 +159,9 @@ static void serial_omap_stop_tx(struct uart_port *port)
158 serial_out(up, UART_IER, up->ier); 159 serial_out(up, UART_IER, up->ier);
159 } 160 }
160 161
162 if (!up->use_dma && pdata->set_forceidle)
163 pdata->set_forceidle(up->pdev);
164
161 pm_runtime_mark_last_busy(&up->pdev->dev); 165 pm_runtime_mark_last_busy(&up->pdev->dev);
162 pm_runtime_put_autosuspend(&up->pdev->dev); 166 pm_runtime_put_autosuspend(&up->pdev->dev);
163} 167}
@@ -286,6 +290,7 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
286static void serial_omap_start_tx(struct uart_port *port) 290static void serial_omap_start_tx(struct uart_port *port)
287{ 291{
288 struct uart_omap_port *up = (struct uart_omap_port *)port; 292 struct uart_omap_port *up = (struct uart_omap_port *)port;
293 struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
289 struct circ_buf *xmit; 294 struct circ_buf *xmit;
290 unsigned int start; 295 unsigned int start;
291 int ret = 0; 296 int ret = 0;
@@ -293,6 +298,8 @@ static void serial_omap_start_tx(struct uart_port *port)
293 if (!up->use_dma) { 298 if (!up->use_dma) {
294 pm_runtime_get_sync(&up->pdev->dev); 299 pm_runtime_get_sync(&up->pdev->dev);
295 serial_omap_enable_ier_thri(up); 300 serial_omap_enable_ier_thri(up);
301 if (pdata->set_noidle)
302 pdata->set_noidle(up->pdev);
296 pm_runtime_mark_last_busy(&up->pdev->dev); 303 pm_runtime_mark_last_busy(&up->pdev->dev);
297 pm_runtime_put_autosuspend(&up->pdev->dev); 304 pm_runtime_put_autosuspend(&up->pdev->dev);
298 return; 305 return;