mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
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 <[email protected]> for mentioning the erratum i291 workaround, which led to the development of this approach. Signed-off-by: Paul Walmsley <[email protected]> Cc: Alan Cox <[email protected]> Cc: Tomi Valkeinen <[email protected]> Acked-by: Govindraj.R <[email protected]> Reviewed-by: Kevin Hilman <[email protected]> Tested-by: Kevin Hilman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
This commit is contained in:
parent
0ba5f66836
commit
be4b028195
2 changed files with 11 additions and 4 deletions
|
|
@ -136,6 +136,7 @@ static void serial_omap_enable_ms(struct uart_port *port)
|
|||
static void serial_omap_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_omap_port *up = (struct uart_omap_port *)port;
|
||||
struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
|
||||
|
||||
if (up->use_dma &&
|
||||
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)
|
|||
serial_out(up, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
if (!up->use_dma && pdata->set_forceidle)
|
||||
pdata->set_forceidle(up->pdev);
|
||||
|
||||
pm_runtime_mark_last_busy(&up->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&up->pdev->dev);
|
||||
}
|
||||
|
|
@ -286,6 +290,7 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
|
|||
static void serial_omap_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_omap_port *up = (struct uart_omap_port *)port;
|
||||
struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
|
||||
struct circ_buf *xmit;
|
||||
unsigned int start;
|
||||
int ret = 0;
|
||||
|
|
@ -293,6 +298,8 @@ static void serial_omap_start_tx(struct uart_port *port)
|
|||
if (!up->use_dma) {
|
||||
pm_runtime_get_sync(&up->pdev->dev);
|
||||
serial_omap_enable_ier_thri(up);
|
||||
if (pdata->set_noidle)
|
||||
pdata->set_noidle(up->pdev);
|
||||
pm_runtime_mark_last_busy(&up->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&up->pdev->dev);
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in a new issue