[PATCH 2/3] tty: serial: OMAP: block idle while the UART is transferring data in PIO mode
Govindraj
govindraj.ti at gmail.com
Fri Jan 27 02:23:04 EST 2012
On Thu, Jan 26, 2012 at 8:20 AM, Paul Walmsley <paul at pwsan.com> wrote:
> 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 at ti.com> for mentioning the erratum i291
> workaround, which led to the development of this approach.
>
> Signed-off-by: Paul Walmsley <paul at pwsan.com>
> Cc: Kevin Hilman <khilman at ti.com>
> Cc: Govindraj.R <govindraj.raja at ti.com>
> Cc: Greg Kroah-Hartman <gregkh at suse.de>
> Cc: Alan Cox <alan at linux.intel.com>
> Cc: Tomi Valkeinen <tomi.valkeinen at ti.com>
Acked-by: Govindraj.R <govindraj.raja at ti.com>
> ---
> arch/arm/mach-omap2/serial.c | 8 ++++----
> drivers/tty/serial/omap-serial.c | 7 +++++++
> 2 files changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 247d894..f590afc 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -107,18 +107,18 @@ static void omap_uart_set_noidle(struct platform_device *pdev)
> omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_NO);
> }
>
> -static void omap_uart_set_forceidle(struct platform_device *pdev)
> +static void omap_uart_set_smartidle(struct platform_device *pdev)
> {
> struct omap_device *od = to_omap_device(pdev);
>
> - omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_FORCE);
> + omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_SMART);
> }
>
> #else
> static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
> {}
> static void omap_uart_set_noidle(struct platform_device *pdev) {}
> -static void omap_uart_set_forceidle(struct platform_device *pdev) {}
> +static void omap_uart_set_smartidle(struct platform_device *pdev) {}
> #endif /* CONFIG_PM */
>
> #ifdef CONFIG_OMAP_MUX
> @@ -349,7 +349,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
> omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
> omap_up.flags = UPF_BOOT_AUTOCONF;
> omap_up.get_context_loss_count = omap_pm_get_dev_context_loss_count;
> - omap_up.set_forceidle = omap_uart_set_forceidle;
> + omap_up.set_forceidle = omap_uart_set_smartidle;
> omap_up.set_noidle = omap_uart_set_noidle;
> omap_up.enable_wakeup = omap_uart_enable_wakeup;
> omap_up.dma_rx_buf_size = info->dma_rx_buf_size;
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index c9c9ba2..11fa156 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)
> 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;
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-serial" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the linux-arm-kernel
mailing list