Re: [PATCH v5 09/15] OMAP2+: UART: Add runtime pm support for omap-serial driver
Hi, On Wed, Sep 21, 2011 at 8:13 PM, Govindraj.R govindraj.r...@ti.com wrote: Adapts omap-serial driver to use pm_runtime API's. console_unlock(); - if ((cpu_is_omap34xx() bdata-pads) || - (pdata-wk_en pdata-wk_mask)) + if ((cpu_is_omap34xx() bdata-pads)) device_init_wakeup(pdev-dev, true); Just a bit curious, why doesn't the code enable wakeup at default on omap4, which will disable runtime pm of serial port on omap4. I have tested your patches on omap4 panda(enable wakeup at default manually), runtime pm of serial port 2 can work well and remote wakeup too. kfree(pdata); diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 74822b3..8ef81ce 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -62,6 +62,9 @@ struct omap_uart_port_info { upf_t flags; /* UPF_* flags */ u32 errata; + + void (*enable_wakeup)(struct platform_device *, bool); + u32 (*get_context_loss_count)(struct device *); }; struct uart_omap_dma { @@ -113,6 +116,8 @@ struct uart_omap_port { unsigned char msr_saved_flags; char name[20]; unsigned long port_activity; + u32 context_loss_cnt; + u8 wakeups_enabled; }; #endif /* __OMAP_SERIAL_H__ */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 9a0eac2..43c33da 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -37,11 +37,14 @@ #include linux/clk.h #include linux/serial_core.h #include linux/irq.h +#include linux/pm_runtime.h #include plat/dma.h #include plat/dmtimer.h #include plat/omap-serial.h +#define OMAP_UART_AUTOSUSPEND_DELAY -1 + static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ @@ -102,6 +105,8 @@ static void serial_omap_stop_rxdma(struct uart_omap_port *up) omap_free_dma(up-uart_dma.rx_dma_channel); up-uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; up-uart_dma.rx_dma_used = false; + pm_runtime_mark_last_busy(up-pdev-dev); + pm_runtime_put_autosuspend(up-pdev-dev); } } @@ -110,8 +115,11 @@ static void serial_omap_enable_ms(struct uart_port *port) struct uart_omap_port *up = (struct uart_omap_port *)port; dev_dbg(up-port.dev, serial_omap_enable_ms+%d\n, up-pdev-id); + + pm_runtime_get_sync(up-pdev-dev); up-ier |= UART_IER_MSI; serial_out(up, UART_IER, up-ier); + pm_runtime_put(up-pdev-dev); } static void serial_omap_stop_tx(struct uart_port *port) @@ -129,23 +137,32 @@ static void serial_omap_stop_tx(struct uart_port *port) omap_stop_dma(up-uart_dma.tx_dma_channel); omap_free_dma(up-uart_dma.tx_dma_channel); up-uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; + pm_runtime_mark_last_busy(up-pdev-dev); + pm_runtime_put_autosuspend(up-pdev-dev); } + pm_runtime_get_sync(up-pdev-dev); if (up-ier UART_IER_THRI) { up-ier = ~UART_IER_THRI; serial_out(up, UART_IER, up-ier); } + + pm_runtime_mark_last_busy(up-pdev-dev); + pm_runtime_put_autosuspend(up-pdev-dev); } static void serial_omap_stop_rx(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; + pm_runtime_get_sync(up-pdev-dev); if (up-use_dma) serial_omap_stop_rxdma(up); up-ier = ~UART_IER_RLSI; up-port.read_status_mask = ~UART_LSR_DR; serial_out(up, UART_IER, up-ier); + pm_runtime_mark_last_busy(up-pdev-dev); + pm_runtime_put_autosuspend(up-pdev-dev); } static inline void receive_chars(struct uart_omap_port *up, int *status) @@ -262,7 +279,10 @@ static void serial_omap_start_tx(struct uart_port *port) int ret = 0; if (!up-use_dma) { + pm_runtime_get_sync(up-pdev-dev); serial_omap_enable_ier_thri(up); + pm_runtime_mark_last_busy(up-pdev-dev); + pm_runtime_put_autosuspend(up-pdev-dev); return; } @@ -272,6 +292,7 @@ static void serial_omap_start_tx(struct uart_port *port) xmit = up-port.state-xmit; if (up-uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) { + pm_runtime_get_sync(up-pdev-dev); ret = omap_request_dma(up-uart_dma.uart_dma_tx, UART Tx DMA, (void *)uart_tx_dma_callback, up, @@ -354,9 +375,13 @@ static inline irqreturn_t serial_omap_irq(int irq, void
Re: [PATCH v5 09/15] OMAP2+: UART: Add runtime pm support for omap-serial driver
On Thu, Sep 22, 2011 at 1:18 PM, Ming Lei tom.leim...@gmail.com wrote: Hi, On Wed, Sep 21, 2011 at 8:13 PM, Govindraj.R govindraj.r...@ti.com wrote: Adapts omap-serial driver to use pm_runtime API's. console_unlock(); - if ((cpu_is_omap34xx() bdata-pads) || - (pdata-wk_en pdata-wk_mask)) + if ((cpu_is_omap34xx() bdata-pads)) device_init_wakeup(pdev-dev, true); Just a bit curious, why doesn't the code enable wakeup at default on omap4, which will disable runtime pm of serial port on omap4. yes sure will add for omap4. I have tested your patches on omap4 panda(enable wakeup at default manually), runtime pm of serial port 2 can work well and remote wakeup too. Thanks, for testing. -- Govindraj.R -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 09/15] OMAP2+: UART: Add runtime pm support for omap-serial driver
Adapts omap-serial driver to use pm_runtime API's. Use runtime runtime API's to handle uart clocks and obtain device_usage statics. Set runtime API's usage to irq_safe so that we can use get_sync from irq context. Auto-suspend for port specific activities and put for reg access. Use device_may_wakeup to check whether uart has wakeup capabilities and then enable uart runtime usage for the uart. Removing save_context/restore_context functions from serial.c Adding context restore to .runtime_suspend and using reg values from port structure to restore the uart port context based on context_loss_count. Maintain internal state machine using wakeups_enabled field for avoiding repeated enable/disable of uart port wakeup mechanism. Remove omap_uart_disable_wakeup and modify omap_uart_enable_wakeup to accept pdev and bool value to enable/disable the uart wakeup mechanism after uart clock's are cut. omap_hwmod_enable_wakeup is used to set pad wakeup for the uarts. PM_WKEN reg values are left to default. Removed omap_uart_enable/disable_clocks in serial.c now clock handling done with runtime API's. By default uart autosuspend delay is set to -1 to avoid character loss if uart's are autoidled and woken up on rx pin. After boot up UART's can be autoidled by setting autosuspendi delay from sysfs. echo 3000 /sys/devices/platform/omap/omap_uart.X/power/autosuspend_delay_ms X=0,1,2,3 for UART1/2/3/4. Number of uarts available may vary across omap_soc. Acked-by: Alan Cox a...@linux.intel.com Signed-off-by: Govindraj.R govindraj.r...@ti.com --- arch/arm/mach-omap2/serial.c | 206 ++-- arch/arm/plat-omap/include/plat/omap-serial.h |5 + drivers/tty/serial/omap-serial.c | 169 +++-- 3 files changed, 179 insertions(+), 201 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 1561140..43d8f0d 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -32,6 +32,7 @@ #include plat/dma.h #include plat/omap_hwmod.h #include plat/omap_device.h +#include plat/omap-pm.h #include prm2xxx_3xxx.h #include pm.h @@ -40,8 +41,6 @@ #include control.h #include mux.h -#define UART_OMAP_WER 0x17/* Wake-up enable register */ - #define UART_ERRATA_i202_MDR1_ACCESS (0x1 1) /* @@ -56,24 +55,7 @@ struct omap_uart_state { int num; - int can_sleep; u32 dma_enabled; - - int clocked; - - int regshift; -#if defined(CONFIG_ARCH_OMAP3) defined(CONFIG_PM) - int context_valid; - - /* Registers to be saved/restored for OFF-mode */ - u16 dll; - u16 dlh; - u16 ier; - u16 sysc; - u16 scr; - u16 wer; - u16 mcr; -#endif }; static u8 num_uarts; @@ -100,34 +82,6 @@ static struct omap_device_pm_latency omap_uart_latency[] = { }, }; -static inline unsigned int __serial_read_reg(struct uart_port *up, -int offset) -{ - offset = up-regshift; - return (unsigned int)__raw_readb(up-membase + offset); -} - -static inline unsigned int serial_read_reg(struct omap_uart_state *uart, - int offset) -{ - offset = uart-regshift; - return (unsigned int)__raw_readb(uart-membase + offset); -} - -static inline void __serial_write_reg(struct uart_port *up, int offset, - int value) -{ - offset = up-regshift; - __raw_writeb(value, up-membase + offset); -} - -static inline void serial_write_reg(struct omap_uart_state *uart, int offset, - int value) -{ - offset = uart-regshift; - __raw_writeb(value, uart-membase + offset); -} - #if defined(CONFIG_PM) /* @@ -164,134 +118,8 @@ static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val, udelay(1); } } - -static void omap_uart_save_context(struct omap_uart_state *uart) -{ - u16 lcr = 0; - - if (!enable_off_mode) - return; - - lcr = serial_read_reg(uart, UART_LCR); - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B); - uart-dll = serial_read_reg(uart, UART_DLL); - uart-dlh = serial_read_reg(uart, UART_DLM); - serial_write_reg(uart, UART_LCR, lcr); - uart-ier = serial_read_reg(uart, UART_IER); - uart-sysc = serial_read_reg(uart, UART_OMAP_SYSC); - uart-scr = serial_read_reg(uart, UART_OMAP_SCR); - uart-wer = serial_read_reg(uart, UART_OMAP_WER); - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_A); - uart-mcr = serial_read_reg(uart, UART_MCR); - serial_write_reg(uart, UART_LCR, lcr); - - uart-context_valid = 1; -} - -static void omap_uart_restore_context(struct omap_uart_state *uart) -{ - u16 efr = 0; - - if (!enable_off_mode) - return; - - if (!uart-context_valid) - return; - -