Skip to contentSkip to conversation

OMAP2+: Serial: Runtime adaptation + cleanup

PATCH Superseded Govindraj.R 4 participants 35 messages Jun 8, 2011 – Jun 27, 2011

Subsystems (5)

v3 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v3 cover OMAP2+: Serial: Runtime adaptation + cleanup

Converting uart driver to adapt to pm runtime api's. Code re-org + cleanup.
Moving some functionality from serial.c to omap-serial.c

Changes involves:
================
1.) Cleaning up certain uart calls from sram_idle func.
2.) Removed all types of uart clock handling code from serial.c
3.) Using hwmod_mux api enable wakeup capability for uart pad during
hwmod_idle state i.e., when uart clocks are disabled we can enable io-pad wakeup capability for uart if mux_data is available for
given uart. Also during during resume from idle call to uart we need to enable clocks back conditionally and this can be done only when io-pad wakeup event bit is set for uart_rx pad. So we need a hwmod api which can probe the uart pad and let us know whether a uart wakeup happened. So omap_hmwod_pad_wakeup_status api is added to meet this requirement.
3.) Adapted omap-serial driver to use runtime api's.
4.) Modify serial_init calls to accept certain uart parameters from board file. 5.) using resume_call to enable uart port back untill we have irq_chaining available.

Patch series is based on 3.0-rc2.
Hosted at: https://gitorious.org/runtime_3-0/runtime_3-0/commits/master

Dependency Patches:
----------
This patch series depends on patch [1], [2] posted earlier. 3.0-rc2 needs [3] patch for core to hit low power states.

[1] http://www.spinics.net/lists/arm-kernel/msg124495.html

[2] http://www.spinics.net/lists/arm-kernel/msg124493.html

[3] http://git.kernel.org/?p=linux/kernel/git/khilman/linux-omap-pm.git;
	a=commit;h=345f79b3de7f6d651e4dba794af7c7303bdfd649

Testing updates:
----------------
3430SDP:
retention, off_mode, system_wide suspend is tested. (earlyprintk & no_console_suspend checked)

OMAP3630 - Zoom3:
pm-retention checked, off mode for per domain checked. [uart3/uart4 in per domain on omap3630].
[ZOOM3 tested with uart3 as console uart and pm-ret checked]

OMAP4430-SDP/PANDA: Boot tested.
OMAP2420/2430SDP: Boot tested.
-------------
Govindraj.R (11):
OMAP2+: UART: Remove certain uart calls from sram_idle OMAP2+: UART: Remove uart clock handling code from serial.c OMAP2+: Serial: Add default mux for all uarts.
Serial: OMAP: Add runtime pm support for omap-serial driver
OMAP: Serial: Hold console lock for console usage.
Serial: OMAP2+: Move erratum handling from serial.c
OMAP: Serial: Allow UART parameters to be configured from board file.
OMAP3: Serial: Remove uart pads from 3430 board file.
OMAP: Serial: Use resume call from prcm to enable uart
OMAP2: Serial: Add has_async_wake flag.
OMAP4: Serial: Set TX_FIFO_THRESHOLD if uart in dma mode for es2.0

Jon Hunter (1):
Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each
UART

 arch/arm/mach-omap2/board-3430sdp.c           |  100 +---
 arch/arm/mach-omap2/board-4430sdp.c           |    8 +-
 arch/arm/mach-omap2/board-n8x0.c              |    6 +-
 arch/arm/mach-omap2/board-omap4panda.c        |    8 +-
 arch/arm/mach-omap2/pm24xx.c                  |   19 +-
 arch/arm/mach-omap2/pm34xx.c                  |   26 +-
 arch/arm/mach-omap2/serial.c                  |  929 +++++++------------------
 arch/arm/plat-omap/include/plat/omap-serial.h |   49 ++-
 arch/arm/plat-omap/include/plat/serial.h      |   12 +-
 drivers/tty/serial/omap-serial.c              |  336 ++++++++-
 10 files changed, 620 insertions(+), 873 deletions(-)
#1 lore raw

PATCH v3 1/12 OMAP2+: UART: Remove certain uart calls from sram_idle

In preparation to UART runtime conversion. Remove certain uart specific calls from sram_idle path in pm24xx/34xx files.
These func calls will no more be used with upcoming uart runtime design.

1.) Removing console lock holding :- Now can be handled with omap-serial file
itself.
2.) omap_uart_can_sleep :- not needed driver can autosuspend based on usage_count
and autosuspend delay.
3.) omap_uart_prepare_suspend :- omap-serial can be taken care with driver
suspend/resume hooks.
4.) Also remove individual uart_prepare/resume calls.

---
 arch/arm/mach-omap2/pm24xx.c             |   19 -------------------
 arch/arm/mach-omap2/pm34xx.c             |   24 ------------------------
 arch/arm/plat-omap/include/plat/serial.h |    6 ------
 3 files changed, 0 insertions(+), 49 deletions(-)
arch/arm/mach-omap2/pm24xx.c +0 -19
index df3ded6..c405bda 100644
@@ -132,27 +132,11 @@ static void omap2_enter_full_retention(void)
 	if (omap_irq_pending())
 		goto no_sleep;
 
-	/* Block console output in case it is on one of the OMAP UARTs */
-	if (!is_suspending())
-		if (!console_trylock())
-			goto no_sleep;
-
-	omap_uart_prepare_idle(0);
-	omap_uart_prepare_idle(1);
-	omap_uart_prepare_idle(2);
-
 	/* Jump to SRAM suspend code */
 	omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
 			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
 			   OMAP_SDRC_REGADDR(SDRC_POWER));
 
-	omap_uart_resume_idle(2);
-	omap_uart_resume_idle(1);
-	omap_uart_resume_idle(0);
-
-	if (!is_suspending())
-		console_unlock();
-
 no_sleep:
 	if (omap2_pm_debug) {
 		unsigned long long tmp;
@@ -267,8 +251,6 @@ static int omap2_can_sleep(void)
 {
 	if (omap2_fclks_active())
 		return 0;
-	if (!omap_uart_can_sleep())
-		return 0;
 	if (osc_ck->usecount > 1)
 		return 0;
 	if (omap_dma_running())
@@ -319,7 +301,6 @@ static int omap2_pm_suspend(void)
 	mir1 = omap_readl(0x480fe0a4);
 	omap_writel(1 << 5, 0x480fe0ac);
 
-	omap_uart_prepare_suspend();
 	omap2_enter_full_retention();
 
 	omap_writel(mir1, 0x480fe0a4);
arch/arm/mach-omap2/pm34xx.c +0 -24
index c155c9d..ac7b7f8 100644
@@ -391,18 +391,9 @@ void omap_sram_idle(void)
 		omap3_enable_io_chain();
 	}
 
-	/* Block console output in case it is on one of the OMAP UARTs */
-	if (!is_suspending())
-		if (per_next_state < PWRDM_POWER_ON ||
-		    core_next_state < PWRDM_POWER_ON)
-			if (!console_trylock())
-				goto console_still_active;
-
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
 		per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
-		omap_uart_prepare_idle(2);
-		omap_uart_prepare_idle(3);
 		omap2_gpio_prepare_for_idle(per_going_off);
 		if (per_next_state == PWRDM_POWER_OFF)
 				omap3_per_save_context();
@@ -410,8 +401,6 @@ void omap_sram_idle(void)
 
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
-		omap_uart_prepare_idle(0);
-		omap_uart_prepare_idle(1);
 		if (core_next_state == PWRDM_POWER_OFF) {
 			omap3_core_save_context();
 			omap3_cm_save_context();
@@ -458,8 +447,6 @@ void omap_sram_idle(void)
 			omap3_sram_restore_context();
 			omap2_sms_restore_context();
 		}
-		omap_uart_resume_idle(0);
-		omap_uart_resume_idle(1);
 		if (core_next_state == PWRDM_POWER_OFF)
 			omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
 					       OMAP3430_GR_MOD,
@@ -473,14 +460,8 @@ void omap_sram_idle(void)
 		omap2_gpio_resume_after_idle();
 		if (per_prev_state == PWRDM_POWER_OFF)
 			omap3_per_restore_context();
-		omap_uart_resume_idle(2);
-		omap_uart_resume_idle(3);
 	}
 
-	if (!is_suspending())
-		console_unlock();
-
-console_still_active:
 	/* Disable IO-PAD and IO-CHAIN wakeup */
 	if (omap3_has_io_wakeup() &&
 	    (per_next_state < PWRDM_POWER_ON ||
@@ -499,8 +480,6 @@ int omap3_can_sleep(void)
 {
 	if (!sleep_while_idle)
 		return 0;
-	if (!omap_uart_can_sleep())
-		return 0;
 	return 1;
 }
 
@@ -549,7 +528,6 @@ static int omap3_pm_suspend(void)
 			goto restore;
 	}
 
-	omap_uart_prepare_suspend();
 	omap3_intc_suspend();
 
 	omap_sram_idle();
@@ -596,14 +574,12 @@ static int omap3_pm_begin(suspend_state_t state)
 {
 	disable_hlt();
 	suspend_state = state;
-	omap_uart_enable_irqs(0);
 	return 0;
 }
 
 static void omap3_pm_end(void)
 {
 	suspend_state = PM_SUSPEND_ON;
-	omap_uart_enable_irqs(1);
 	enable_hlt();
 	return;
 }
arch/arm/plat-omap/include/plat/serial.h +0 -6
index 2723f91..ab1761a 100644
@@ -106,12 +106,6 @@ struct omap_board_data;
 
 extern void omap_serial_init(void);
 extern void omap_serial_init_port(struct omap_board_data *bdata);
-extern int omap_uart_can_sleep(void);
-extern void omap_uart_check_wakeup(void);
-extern void omap_uart_prepare_suspend(void);
-extern void omap_uart_prepare_idle(int num);
-extern void omap_uart_resume_idle(int num);
-extern void omap_uart_enable_irqs(int enable);
 #endif
 
 #endif
Signature · 1 line
1.7.0.4
#2 lore raw

PATCH v3 2/12 OMAP2+: UART: Remove uart clock handling code from serial.c

In reply to Govindraj.R

Cleanup serial.c file in preparation to addition of runtime api's in omap-serial file. Remove all clock handling mechanism as this will be taken care with pm runtime api's in omap-serial.c file itself.

1.) Remove omap-device enable and disable. We can can use get_sync/put_sync api's 2.) Remove context save/restore can be done with runtime_resume callback for
get_sync call. No need to save context as all reg details available in uart_port structure can be used for restore, so add missing regs in uart port struct.
3.) Add func to identify console uart.
4.) Erratum handling informed as flag to driver and func to handle erratum
can be moved to omap-serial driver itself.

---
 arch/arm/mach-omap2/serial.c                  |  754 ++-----------------------
 arch/arm/plat-omap/include/plat/omap-serial.h |   15 +-
 2 files changed, 74 insertions(+), 695 deletions(-)
arch/arm/mach-omap2/serial.c +62 -692
index 1ac361b..b16768a 100644
@@ -19,25 +19,18 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/serial_reg.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/serial_8250.h>
 #include <linux/pm_runtime.h>
-#include <linux/console.h>
 
-#ifdef CONFIG_SERIAL_OMAP
 #include <plat/omap-serial.h>
-#endif
-
 #include <plat/common.h>
 #include <plat/board.h>
 #include <plat/clock.h>
 #include <plat/dma.h>
-#include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
 
 #include "prm2xxx_3xxx.h"
@@ -47,65 +40,9 @@
 #include "control.h"
 #include "mux.h"
 
-#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV	0x52
-#define UART_OMAP_WER		0x17	/* Wake-up enable register */
-
-#define UART_ERRATA_FIFO_FULL_ABORT	(0x1 << 0)
-#define UART_ERRATA_i202_MDR1_ACCESS	(0x1 << 1)
-
-/*
- * NOTE: By default the serial timeout is disabled as it causes lost characters
- * over the serial ports. This means that the UART clocks will stay on until
- * disabled via sysfs. This also causes that any deeper omap sleep states are
- * blocked. 
- */
-#define DEFAULT_TIMEOUT 0
-
-#define MAX_UART_HWMOD_NAME_LEN		16
+#define MAX_UART_HWMOD_NAME_LEN                16
 
-struct omap_uart_state {
-	int num;
-	int can_sleep;
-	struct timer_list timer;
-	u32 timeout;
-
-	void __iomem *wk_st;
-	void __iomem *wk_en;
-	u32 wk_mask;
-	u32 padconf;
-	u32 dma_enabled;
-
-	struct clk *ick;
-	struct clk *fck;
-	int clocked;
-
-	int irq;
-	int regshift;
-	int irqflags;
-	void __iomem *membase;
-	resource_size_t mapbase;
-
-	struct list_head node;
-	struct omap_hwmod *oh;
-	struct platform_device *pdev;
-
-	u32 errata;
-#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 LIST_HEAD(uart_list);
-static u8 num_uarts;
+static int omap_uart_con_id __initdata = -1;
 
 static int uart_idle_hwmod(struct omap_device *od)
 {
@@ -129,396 +66,35 @@ 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);
-}
-
-/*
- * Internal UARTs need to be initialized for the 8250 autoconfig to work
- * properly. Note that the TX watermark initialization may not be needed
- * once the 8250.c watermark handling code is merged.
- */
-
-static inline void __init omap_uart_reset(struct omap_uart_state *uart)
-{
-	serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
-	serial_write_reg(uart, UART_OMAP_SCR, 0x08);
-	serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
-}
-
-#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
-
-/*
- * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6)
- * The access to uart register after MDR1 Access
- * causes UART to corrupt data.
- *
- * Need a delay =
- * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
- * give 10 times as much
- */
-static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
-		u8 fcr_val)
-{
-	u8 timeout = 255;
-
-	serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
-	udelay(2);
-	serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
-			UART_FCR_CLEAR_RCVR);
-	/*
-	 * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
-	 * TX_FIFO_E bit is 1.
-	 */
-	while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
-				(UART_LSR_THRE | UART_LSR_DR))) {
-		timeout--;
-		if (!timeout) {
-			/* Should *never* happen. we warn and carry on */
-			dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
-			serial_read_reg(uart, UART_LSR));
-			break;
-		}
-		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)
+static void omap_uart_idle_init(struct omap_uart_port_info *uart,
+				unsigned short num)
 {
-	u16 efr = 0;
-
-	if (!enable_off_mode)
-		return;
-
-	if (!uart->context_valid)
-		return;
-
-	uart->context_valid = 0;
-
-	if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
-		omap_uart_mdr1_errataset(uart, UART_OMAP_MDR1_DISABLE, 0xA0);
-	else
-		serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
-
-	serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B);
-	efr = serial_read_reg(uart, UART_EFR);
-	serial_write_reg(uart, UART_EFR, UART_EFR_ECB);
-	serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
-	serial_write_reg(uart, UART_IER, 0x0);
-	serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B);
-	serial_write_reg(uart, UART_DLL, uart->dll);
-	serial_write_reg(uart, UART_DLM, uart->dlh);
-	serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
-	serial_write_reg(uart, UART_IER, uart->ier);
-	serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_A);
-	serial_write_reg(uart, UART_MCR, uart->mcr);
-	serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B);
-	serial_write_reg(uart, UART_EFR, efr);
-	serial_write_reg(uart, UART_LCR, UART_LCR_WLEN8);
-	serial_write_reg(uart, UART_OMAP_SCR, uart->scr);
-	serial_write_reg(uart, UART_OMAP_WER, uart->wer);
-	serial_write_reg(uart, UART_OMAP_SYSC, uart->sysc);
-
-	if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
-		omap_uart_mdr1_errataset(uart, UART_OMAP_MDR1_16X_MODE, 0xA1);
-	else
-		/* UART 16x mode */
-		serial_write_reg(uart, UART_OMAP_MDR1,
-				UART_OMAP_MDR1_16X_MODE);
-}
-#else
-static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
-static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
-#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
-
-static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
-{
-	if (uart->clocked)
-		return;
-
-	omap_device_enable(uart->pdev);
-	uart->clocked = 1;
-	omap_uart_restore_context(uart);
-}
-
-#ifdef CONFIG_PM
-
-static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
-{
-	if (!uart->clocked)
-		return;
-
-	omap_uart_save_context(uart);
-	uart->clocked = 0;
-	omap_device_idle(uart->pdev);
-}
-
-static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
-{
-	/* Set wake-enable bit */
-	if (uart->wk_en && uart->wk_mask) {
-		u32 v = __raw_readl(uart->wk_en);
-		v |= uart->wk_mask;
-		__raw_writel(v, uart->wk_en);
-	}
-
-	/* Ensure IOPAD wake-enables are set */
-	if (cpu_is_omap34xx() && uart->padconf) {
-		u16 v = omap_ctrl_readw(uart->padconf);
-		v |= OMAP3_PADCONF_WAKEUPENABLE0;
-		omap_ctrl_writew(v, uart->padconf);
-	}
-}
-
-static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
-{
-	/* Clear wake-enable bit */
-	if (uart->wk_en && uart->wk_mask) {
-		u32 v = __raw_readl(uart->wk_en);
-		v &= ~uart->wk_mask;
-		__raw_writel(v, uart->wk_en);
-	}
-
-	/* Ensure IOPAD wake-enables are cleared */
-	if (cpu_is_omap34xx() && uart->padconf) {
-		u16 v = omap_ctrl_readw(uart->padconf);
-		v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
-		omap_ctrl_writew(v, uart->padconf);
-	}
-}
-
-static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
-					       int enable)
-{
-	u8 idlemode;
-
-	if (enable) {
-		/**
-		 * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
-		 * in Smartidle Mode When Configured for DMA Operations.
-		 */
-		if (uart->dma_enabled)
-			idlemode = HWMOD_IDLEMODE_FORCE;
-		else
-			idlemode = HWMOD_IDLEMODE_SMART;
-	} else {
-		idlemode = HWMOD_IDLEMODE_NO;
-	}
-
-	omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
-}
-
-static void omap_uart_block_sleep(struct omap_uart_state *uart)
-{
-	omap_uart_enable_clocks(uart);
-
-	omap_uart_smart_idle_enable(uart, 0);
-	uart->can_sleep = 0;
-	if (uart->timeout)
-		mod_timer(&uart->timer, jiffies + uart->timeout);
-	else
-		del_timer(&uart->timer);
-}
-
-static void omap_uart_allow_sleep(struct omap_uart_state *uart)
-{
-	if (device_may_wakeup(&uart->pdev->dev))
-		omap_uart_enable_wakeup(uart);
-	else
-		omap_uart_disable_wakeup(uart);
-
-	if (!uart->clocked)
-		return;
-
-	omap_uart_smart_idle_enable(uart, 1);
-	uart->can_sleep = 1;
-	del_timer(&uart->timer);
-}
-
-static void omap_uart_idle_timer(unsigned long data)
-{
-	struct omap_uart_state *uart = (struct omap_uart_state *)data;
-
-	omap_uart_allow_sleep(uart);
-}
-
-void omap_uart_prepare_idle(int num)
-{
-	struct omap_uart_state *uart;
-
-	list_for_each_entry(uart, &uart_list, node) {
-		if (num == uart->num && uart->can_sleep) {
-			omap_uart_disable_clocks(uart);
-			return;
-		}
-	}
-}
-
-void omap_uart_resume_idle(int num)
-{
-	struct omap_uart_state *uart;
-
-	list_for_each_entry(uart, &uart_list, node) {
-		if (num == uart->num && uart->can_sleep) {
-			omap_uart_enable_clocks(uart);
-
-			/* Check for IO pad wakeup */
-			if (cpu_is_omap34xx() && uart->padconf) {
-				u16 p = omap_ctrl_readw(uart->padconf);
-
-				if (p & OMAP3_PADCONF_WAKEUPEVENT0)
-					omap_uart_block_sleep(uart);
-			}
-
-			/* Check for normal UART wakeup */
-			if (__raw_readl(uart->wk_st) & uart->wk_mask)
-				omap_uart_block_sleep(uart);
-			return;
-		}
-	}
-}
-
-void omap_uart_prepare_suspend(void)
-{
-	struct omap_uart_state *uart;
-
-	list_for_each_entry(uart, &uart_list, node) {
-		omap_uart_allow_sleep(uart);
-	}
-}
-
-int omap_uart_can_sleep(void)
-{
-	struct omap_uart_state *uart;
-	int can_sleep = 1;
-
-	list_for_each_entry(uart, &uart_list, node) {
-		if (!uart->clocked)
-			continue;
-
-		if (!uart->can_sleep) {
-			can_sleep = 0;
-			continue;
-		}
-
-		/* This UART can now safely sleep. */
-		omap_uart_allow_sleep(uart);
-	}
-
-	return can_sleep;
-}
-
-/**
- * omap_uart_interrupt()
- *
- * This handler is used only to detect that *any* UART interrupt has
- * occurred.  It does _nothing_ to handle the interrupt.  Rather,
- * any UART interrupt will trigger the inactivity timer so the
- * UART will not idle or sleep for its timeout period.
- *
- **/
-/* static int first_interrupt; */
-static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
-{
-	struct omap_uart_state *uart = dev_id;
-
-	omap_uart_block_sleep(uart);
-
-	return IRQ_NONE;
-}
-
-static void omap_uart_idle_init(struct omap_uart_state *uart)
-{
-	int ret;
-
-	uart->can_sleep = 0;
-	uart->timeout = DEFAULT_TIMEOUT;
-	setup_timer(&uart->timer, omap_uart_idle_timer,
-		    (unsigned long) uart);
-	if (uart->timeout)
-		mod_timer(&uart->timer, jiffies + uart->timeout);
-	omap_uart_smart_idle_enable(uart, 0);
-
-	if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
-		u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
+	if (cpu_is_omap34xx()) {
+		u32 mod = num > 1 ? OMAP3430_PER_MOD : CORE_MOD;
 		u32 wk_mask = 0;
-		u32 padconf = 0;
 
-		/* XXX These PRM accesses do not belong here */
 		uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
 		uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
-		switch (uart->num) {
+		switch (num) {
 		case 0:
 			wk_mask = OMAP3430_ST_UART1_MASK;
-			padconf = 0x182;
 			break;
 		case 1:
 			wk_mask = OMAP3430_ST_UART2_MASK;
-			padconf = 0x17a;
 			break;
 		case 2:
 			wk_mask = OMAP3430_ST_UART3_MASK;
-			padconf = 0x19e;
 			break;
 		case 3:
 			wk_mask = OMAP3630_ST_UART4_MASK;
-			padconf = 0x0d2;
 			break;
 		}
 		uart->wk_mask = wk_mask;
-		uart->padconf = padconf;
 	} else if (cpu_is_omap24xx()) {
 		u32 wk_mask = 0;
 		u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
 
-		switch (uart->num) {
+		switch (num) {
 		case 0:
 			wk_mask = OMAP24XX_ST_UART1_MASK;
 			break;
@@ -543,155 +119,49 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
 		uart->wk_en = NULL;
 		uart->wk_st = NULL;
 		uart->wk_mask = 0;
-		uart->padconf = 0;
-	}
-
-	uart->irqflags |= IRQF_SHARED;
-	ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
-				   IRQF_SHARED, "serial idle", (void *)uart);
-	WARN_ON(ret);
-}
-
-void omap_uart_enable_irqs(int enable)
-{
-	int ret;
-	struct omap_uart_state *uart;
-
-	list_for_each_entry(uart, &uart_list, node) {
-		if (enable) {
-			pm_runtime_put_sync(&uart->pdev->dev);
-			ret = request_threaded_irq(uart->irq, NULL,
-						   omap_uart_interrupt,
-						   IRQF_SHARED,
-						   "serial idle",
-						   (void *)uart);
-		} else {
-			pm_runtime_get_noresume(&uart->pdev->dev);
-			free_irq(uart->irq, (void *)uart);
-		}
-	}
-}
-
-static ssize_t sleep_timeout_show(struct device *dev,
-				  struct device_attribute *attr,
-				  char *buf)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct omap_device *odev = to_omap_device(pdev);
-	struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
-
-	return sprintf(buf, "%u\n", uart->timeout / HZ);
-}
-
-static ssize_t sleep_timeout_store(struct device *dev,
-				   struct device_attribute *attr,
-				   const char *buf, size_t n)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct omap_device *odev = to_omap_device(pdev);
-	struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
-	unsigned int value;
-
-	if (sscanf(buf, "%u", &value) != 1) {
-		dev_err(dev, "sleep_timeout_store: Invalid value\n");
-		return -EINVAL;
 	}
-
-	uart->timeout = value * HZ;
-	if (uart->timeout)
-		mod_timer(&uart->timer, jiffies + uart->timeout);
-	else
-		/* A zero value means disable timeout feature */
-		omap_uart_block_sleep(uart);
-
-	return n;
-}
-
-static DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show,
-		sleep_timeout_store);
-#define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr))
-#else
-static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
-static void omap_uart_block_sleep(struct omap_uart_state *uart)
-{
-	/* Needed to enable UART clocks when built without CONFIG_PM */
-	omap_uart_enable_clocks(uart);
 }
-#define DEV_CREATE_FILE(dev, attr)
-#endif /* CONFIG_PM */
 
-#ifndef CONFIG_SERIAL_OMAP
-/*
- * Override the default 8250 read handler: mem_serial_in()
- * Empty RX fifo read causes an abort on omap3630 and omap4
- * This function makes sure that an empty rx fifo is not read on these silicons
- * (OMAP1/2/3430 are not affected)
- */
-static unsigned int serial_in_override(struct uart_port *up, int offset)
+char *cmdline_find_option(char *str)
 {
-	if (UART_RX == offset) {
-		unsigned int lsr;
-		lsr = __serial_read_reg(up, UART_LSR);
-		if (!(lsr & UART_LSR_DR))
-			return -EPERM;
-	}
+	extern char *saved_command_line;
 
-	return __serial_read_reg(up, offset);
+	return strstr(saved_command_line, str);
 }
 
-static void serial_out_override(struct uart_port *up, int offset, int value)
+struct omap_hwmod *omap_uart_hwmod_lookup(int num)
 {
-	unsigned int status, tmout = 10000;
+	struct omap_hwmod *oh;
+	char oh_name[MAX_UART_HWMOD_NAME_LEN];
 
-	status = __serial_read_reg(up, UART_LSR);
-	while (!(status & UART_LSR_THRE)) {
-		/* Wait up to 10ms for the character(s) to be sent. */
-		if (--tmout == 0)
-			break;
-		udelay(1);
-		status = __serial_read_reg(up, UART_LSR);
-	}
-	__serial_write_reg(up, offset, value);
+	snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, "uart%d", num + 1);
+	oh = omap_hwmod_lookup(oh_name);
+	WARN(IS_ERR(oh), "Could not lookup hmwod info for %s\n",
+					oh_name);
+	return oh;
 }
-#endif
 
 static int __init omap_serial_early_init(void)
 {
+#ifdef CONFIG_EARLY_PRINTK
 	int i = 0;
+	char omap_tty_name[MAX_UART_HWMOD_NAME_LEN];
+	struct omap_hwmod *oh;
 
-	do {
-		char oh_name[MAX_UART_HWMOD_NAME_LEN];
-		struct omap_hwmod *oh;
-		struct omap_uart_state *uart;
-
-		snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
-			 "uart%d", i + 1);
-		oh = omap_hwmod_lookup(oh_name);
-		if (!oh)
-			break;
-
-		uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
-		if (WARN_ON(!uart))
-			return -ENODEV;
-
-		uart->oh = oh;
-		uart->num = i++;
-		list_add_tail(&uart->node, &uart_list);
-		num_uarts++;
-
-		/*
-		 * NOTE: omap_hwmod_setup*() has not yet been called,
-		 *       so no hwmod functions will work yet.
-		 */
-
-		/*
-		 * During UART early init, device need to be probed
-		 * to determine SoC specific init before omap_device
-		 * is ready.  Therefore, don't allow idle here
-		 */
-		uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
-	} while (1);
-
+	if (!cmdline_find_option("earlyprintk"))
+		return 0;
+
+	for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
+		snprintf(omap_tty_name, MAX_UART_HWMOD_NAME_LEN,
+			"%s%d", OMAP_SERIAL_NAME, i);
+		if (cmdline_find_option(omap_tty_name)) {
+			omap_uart_con_id = i;
+			oh = omap_uart_hwmod_lookup(i);
+			oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
+			return 0;
+		}
+	}
+#endif
 	return 0;
 }
 core_initcall(omap_serial_early_init);
@@ -709,149 +179,50 @@ core_initcall(omap_serial_early_init);
  */
 void __init omap_serial_init_port(struct omap_board_data *bdata)
 {
-	struct omap_uart_state *uart;
 	struct omap_hwmod *oh;
 	struct omap_device *od;
-	void *pdata = NULL;
-	u32 pdata_size = 0;
-	char *name;
-#ifndef CONFIG_SERIAL_OMAP
-	struct plat_serial8250_port ports[2] = {
-		{},
-		{.flags = 0},
-	};
-	struct plat_serial8250_port *p = &ports[0];
-#else
-	struct omap_uart_port_info omap_up;
-#endif
+	struct omap_uart_port_info *pdata;
+	char *name = DRIVER_NAME;
 
 	if (WARN_ON(!bdata))
 		return;
 	if (WARN_ON(bdata->id < 0))
 		return;
-	if (WARN_ON(bdata->id >= num_uarts))
+	if (WARN_ON(bdata->id >= OMAP_MAX_HSUART_PORTS))
 		return;
 
-	list_for_each_entry(uart, &uart_list, node)
-		if (bdata->id == uart->num)
-			break;
-
-	oh = uart->oh;
-	uart->dma_enabled = 0;
-#ifndef CONFIG_SERIAL_OMAP
-	name = "serial8250";
-
-	/*
-	 * !! 8250 driver does not use standard IORESOURCE* It
-	 * has it's own custom pdata that can be taken from
-	 * the hwmod resource data.  But, this needs to be
-	 * done after the build.
-	 *
-	 * ?? does it have to be done before the register ??
-	 * YES, because platform_device_data_add() copies
-	 * pdata, it does not use a pointer.
-	 */
-	p->flags = UPF_BOOT_AUTOCONF;
-	p->iotype = UPIO_MEM;
-	p->regshift = 2;
-	p->uartclk = OMAP24XX_BASE_BAUD * 16;
-	p->irq = oh->mpu_irqs[0].irq;
-	p->mapbase = oh->slaves[0]->addr->pa_start;
-	p->membase = omap_hwmod_get_mpu_rt_va(oh);
-	p->irqflags = IRQF_SHARED;
-	p->private_data = uart;
-
-	/*
-	 * omap44xx, ti816x: Never read empty UART fifo
-	 * omap3xxx: Never read empty UART fifo on UARTs
-	 * with IP rev >=0x52
-	 */
-	uart->regshift = p->regshift;
-	uart->membase = p->membase;
-	if (cpu_is_omap44xx() || cpu_is_ti816x())
-		uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
-	else if ((serial_read_reg(uart, UART_OMAP_MVER) & 0xFF)
-			>= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
-		uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
+	oh = omap_uart_hwmod_lookup(bdata->id);
+	if (!oh)
+		return;
 
-	if (uart->errata & UART_ERRATA_FIFO_FULL_ABORT) {
-		p->serial_in = serial_in_override;
-		p->serial_out = serial_out_override;
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		pr_err("Memory allocation for UART pdata failed\n");
+		return;
 	}
 
-	pdata = &ports[0];
-	pdata_size = 2 * sizeof(struct plat_serial8250_port);
-#else
-
-	name = DRIVER_NAME;
-
-	omap_up.dma_enabled = uart->dma_enabled;
-	omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
-	omap_up.mapbase = oh->slaves[0]->addr->pa_start;
-	omap_up.membase = omap_hwmod_get_mpu_rt_va(oh);
-	omap_up.irqflags = IRQF_SHARED;
-	omap_up.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+	/* Enable the MDR1 errata for OMAP3 */
+	if (cpu_is_omap34xx())
+		pdata->errata |= UART_ERRATA_i202_MDR1_ACCESS;
 
-	pdata = &omap_up;
-	pdata_size = sizeof(struct omap_uart_port_info);
-#endif
+	omap_uart_idle_init(pdata, bdata->id);
 
-	if (WARN_ON(!oh))
-		return;
+	pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
+	pdata->flags = UPF_BOOT_AUTOCONF;
+	if (bdata->id == omap_uart_con_id)
+		pdata->console_uart = true;
 
-	od = omap_device_build(name, uart->num, oh, pdata, pdata_size,
-			       omap_uart_latency,
-			       ARRAY_SIZE(omap_uart_latency), false);
+	od = omap_device_build(name, bdata->id, oh, pdata,
+				sizeof(*pdata), omap_uart_latency,
+				ARRAY_SIZE(omap_uart_latency), false);
 	WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n",
 	     name, oh->name);
 
 	oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
-
-	uart->irq = oh->mpu_irqs[0].irq;
-	uart->regshift = 2;
-	uart->mapbase = oh->slaves[0]->addr->pa_start;
-	uart->membase = omap_hwmod_get_mpu_rt_va(oh);
-	uart->pdev = &od->pdev;
-
-	oh->dev_attr = uart;
-
-	console_lock(); /* in case the earlycon is on the UART */
-
-	/*
-	 * Because of early UART probing, UART did not get idled
-	 * on init.  Now that omap_device is ready, ensure full idle
-	 * before doing omap_device_enable().
-	 */
-	omap_hwmod_idle(uart->oh);
-
-	omap_device_enable(uart->pdev);
-	omap_uart_idle_init(uart);
-	omap_uart_reset(uart);
-	omap_hwmod_enable_wakeup(uart->oh);
-	omap_device_idle(uart->pdev);
-
-	/*
-	 * Need to block sleep long enough for interrupt driven
-	 * driver to start.  Console driver is in polling mode
-	 * so device needs to be kept enabled while polling driver
-	 * is in use.
-	 */
-	if (uart->timeout)
-		uart->timeout = (30 * HZ);
-	omap_uart_block_sleep(uart);
-	uart->timeout = DEFAULT_TIMEOUT;
-
-	console_unlock();
-
-	if ((cpu_is_omap34xx() && uart->padconf) ||
-	    (uart->wk_en && uart->wk_mask)) {
+	if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads) ||
+	    (pdata->wk_en && pdata->wk_mask)) {
 		device_init_wakeup(&od->pdev.dev, true);
-		DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout);
 	}
-
-	/* Enable the MDR1 errata for OMAP3 */
-	if (cpu_is_omap34xx() && !cpu_is_ti816x())
-		uart->errata |= UART_ERRATA_i202_MDR1_ACCESS;
 }
 
 /**
@@ -863,15 +234,14 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
  */
 void __init omap_serial_init(void)
 {
-	struct omap_uart_state *uart;
 	struct omap_board_data bdata;
+	u8 i;
 
-	list_for_each_entry(uart, &uart_list, node) {
-		bdata.id = uart->num;
+	for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
+		bdata.id = i;
 		bdata.flags = 0;
 		bdata.pads = NULL;
 		bdata.pads_cnt = 0;
 		omap_serial_init_port(&bdata);
-
 	}
 }
arch/arm/plat-omap/include/plat/omap-serial.h +12 -3
index 2682043..2ca885b 100644
@@ -56,13 +56,18 @@
 
 #define MSR_SAVE_FLAGS		UART_MSR_ANY_DELTA
 
+#define UART_ERRATA_i202_MDR1_ACCESS	BIT(0)
+
 struct omap_uart_port_info {
 	bool			dma_enabled;	/* To specify DMA Mode */
 	unsigned int		uartclk;	/* UART clock rate */
-	void __iomem		*membase;	/* ioremap cookie or NULL */
-	resource_size_t		mapbase;	/* resource base */
-	unsigned long		irqflags;	/* request_irq flags */
 	upf_t			flags;		/* UPF_* flags */
+	unsigned int		errata;
+	unsigned int		console_uart;
+
+	void __iomem *wk_st;
+	void __iomem *wk_en;
+	u32 wk_mask;
 };
 
 struct uart_omap_dma {
@@ -100,6 +105,9 @@ struct uart_omap_port {
 	unsigned char		mcr;
 	unsigned char		fcr;
 	unsigned char		efr;
+	unsigned char		dll;
+	unsigned char		dlh;
+	unsigned char		mdr1;
 
 	int			use_dma;
 	/*
@@ -111,6 +119,7 @@ struct uart_omap_port {
 	unsigned char		msr_saved_flags;
 	char			name[20];
 	unsigned long		port_activity;
+	unsigned int		errata;
 };
 
 #endif /* __OMAP_SERIAL_H__ */
Signature · 1 line
1.7.0.4
#3 lore raw

PATCH v3 2/12 OMAP2+: UART: Remove uart clock handling code from serial.c

Quoted 15 lines · Govindraj.R

Cleanup serial.c file in preparation to addition of runtime api's in omap-serial file. Remove all clock handling mechanism as this will be taken care with pm runtime api's in omap-serial.c file itself.

1.) Remove omap-device enable and disable. We can can use get_sync/put_sync api's 2.) Remove context save/restore can be done with runtime_resume callback for
get_sync call. No need to save context as all reg details available in uart_port structure can be used for restore, so add missing regs in uart port struct.
3.) Add func to identify console uart.
4.) Erratum handling informed as flag to driver and func to handle erratum
can be moved to omap-serial driver itself.

[...]

Quoted 10 lines
arch/arm/mach-omap2/serial.c +0 -6
@@ -47,65 +40,9 @@
 #include "control.h"
 #include "mux.h"
 
-#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV	0x52
-#define UART_OMAP_WER		0x17	/* Wake-up enable register */
-
-#define UART_ERRATA_FIFO_FULL_ABORT	(0x1 << 0)
-#define UART_ERRATA_i202_MDR1_ACCESS	(0x1 << 1)
-

arch/arm/mach-omap2/serial.c line 43

Quoted 10 lines
arch/arm/mach-omap2/serial.c +1 -9
-/*
- * NOTE: By default the serial timeout is disabled as it causes lost characters
- * over the serial ports. This means that the UART clocks will stay on until
- * disabled via sysfs. This also causes that any deeper omap sleep states are
- * blocked. 
- */
-#define DEFAULT_TIMEOUT 0
-
-#define MAX_UART_HWMOD_NAME_LEN		16
+#define MAX_UART_HWMOD_NAME_LEN                16

Minor: only whitespace change here, you converted tabs to spaces.

Rest of this looks fine.

Kevin

#4 lore raw

PATCH v3 2/12 OMAP2+: UART: Remove uart clock handling code from serial.c

Quoted 34 lines · Kevin Hilman
Quoted 15 lines · Govindraj.R

Cleanup serial.c file in preparation to addition of runtime api's in omap-serial file. Remove all clock handling mechanism as this will be taken care with pm runtime api's in omap-serial.c file itself.

1.) Remove omap-device enable and disable. We can can use get_sync/put_sync api's 2.) Remove context save/restore can be done with runtime_resume callback for ? ? get_sync call. No need to save context as all reg details available in ? ? uart_port structure can be used for restore, so add missing regs in ? ? uart port struct.
3.) Add func to identify console uart.
4.) Erratum handling informed as flag to driver and func to handle erratum ? ? can be moved to omap-serial driver itself.

[...]

Quoted 14 lines
(quoted diff) +0 -0
@@ -47,65 +40,9 @@

?#include "control.h"
?#include "mux.h"

arch/arm/mach-omap2/serial.c +0 -10
-#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV ?0x52
-#define UART_OMAP_WER ? ? ? ? ? ? ? ?0x17 ? ?/* Wake-up enable register */
-
-#define UART_ERRATA_FIFO_FULL_ABORT ?(0x1 << 0)
-#define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1)
-
-/*
- * NOTE: By default the serial timeout is disabled as it causes lost characters
- * over the serial ports. This means that the UART clocks will stay on until
- * disabled via sysfs. This also causes that any deeper omap sleep states are
Quoted 8 lines

arch/arm/mach-omap2/serial.c

Quoted 6 lines

- * blocked.
- */

arch/arm/mach-omap2/serial.c +1 -3
-#define DEFAULT_TIMEOUT 0
-
-#define MAX_UART_HWMOD_NAME_LEN ? ? ? ? ? ? ?16
+#define MAX_UART_HWMOD_NAME_LEN ? ? ? ? ? ? ? ?16

Minor: only whitespace change here, you converted tabs to spaces.

yes, will correct this.

--
Govindraj.R

Quoted 9 lines

Rest of this looks fine.

Kevin
--
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

#5 lore raw

PATCH v3 3/12 OMAP2+: Serial: Add default mux for all uarts.

In reply to Govindraj.R

Add default mux data for all uarts if mux info is not passed from board file to avoid breaking any board support.

---
 arch/arm/mach-omap2/serial.c |  127 +++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 126 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/serial.c +126 -1
index b16768a..8c1a4c7 100644
@@ -66,6 +66,129 @@ static struct omap_device_pm_latency omap_uart_latency[] = {
 	},
 };
 
+#ifdef CONFIG_OMAP_MUX
+static struct omap_device_pad default_uart1_pads[] __initdata = {
+	{
+		.name	= "uart1_cts.uart1_cts",
+		.enable	= OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart1_rts.uart1_rts",
+		.enable	= OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart1_tx.uart1_tx",
+		.enable	= OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart1_rx.uart1_rx",
+		.flags	= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
+		.enable	= OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
+	},
+};
+
+static struct omap_device_pad default_uart2_pads[] __initdata = {
+	{
+		.name	= "uart2_cts.uart2_cts",
+		.enable	= OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart2_rts.uart2_rts",
+		.enable	= OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart2_tx.uart2_tx",
+		.enable	= OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart2_rx.uart2_rx",
+		.flags	= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
+		.enable	= OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
+	},
+};
+
+static struct omap_device_pad default_uart3_pads[] __initdata = {
+	{
+		.name	= "uart3_cts_rctx.uart3_cts_rctx",
+		.enable	= OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart3_rts_sd.uart3_rts_sd",
+		.enable	= OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart3_tx_irtx.uart3_tx_irtx",
+		.enable	= OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart3_rx_irrx.uart3_rx_irrx",
+		.flags	= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
+		.enable	= OMAP_PIN_INPUT | OMAP_MUX_MODE0,
+	},
+};
+
+static struct omap_device_pad default_omap36xx_uart4_pads[] __initdata = {
+	{
+		.name   = "gpmc_wait2.uart4_tx",
+		.enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "gpmc_wait3.uart4_rx",
+		.flags	= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
+		.enable	= OMAP_PIN_INPUT | OMAP_MUX_MODE2,
+	},
+};
+
+static struct omap_device_pad default_omap4_uart4_pads[] __initdata = {
+	{
+		.name	= "uart4_tx.uart4_tx",
+		.enable	= OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+	},
+	{
+		.name	= "uart4_rx.uart4_rx",
+		.flags	= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
+		.enable	= OMAP_PIN_INPUT | OMAP_MUX_MODE0,
+	},
+};
+#else
+static struct omap_device_pad default_uart1_pads[] __initdata = {};
+static struct omap_device_pad default_uart2_pads[] __initdata = {};
+static struct omap_device_pad default_uart3_pads[] __initdata = {};
+static struct omap_device_pad default_omap36xx_uart4_pads[] __initdata = {};
+static struct omap_device_pad default_omap4_uart4_pads[] __initdata = {};
+#endif
+
+static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
+{
+	switch (bdata->id) {
+	case 0:
+		bdata->pads = default_uart1_pads;
+		bdata->pads_cnt = ARRAY_SIZE(default_uart1_pads);
+		break;
+	case 1:
+		bdata->pads = default_uart2_pads;
+		bdata->pads_cnt = ARRAY_SIZE(default_uart2_pads);
+		break;
+	case 2:
+		bdata->pads = default_uart3_pads;
+		bdata->pads_cnt = ARRAY_SIZE(default_uart3_pads);
+		break;
+	case 3:
+		if (cpu_is_omap44xx()) {
+			bdata->pads = default_omap4_uart4_pads;
+			bdata->pads_cnt =
+				ARRAY_SIZE(default_omap4_uart4_pads);
+		} else {
+			bdata->pads = default_omap36xx_uart4_pads;
+			bdata->pads_cnt =
+				ARRAY_SIZE(default_omap36xx_uart4_pads);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
 static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 				unsigned short num)
 {
@@ -242,6 +365,8 @@ void __init omap_serial_init(void)
 		bdata.flags = 0;
 		bdata.pads = NULL;
 		bdata.pads_cnt = 0;
-		omap_serial_init_port(&bdata);
+
+		if (cpu_is_omap44xx() || cpu_is_omap34xx())
+			omap_serial_fill_default_pads(&bdata);
 	}
 }
Signature · 1 line
1.7.0.4
#6 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

In reply to Govindraj.R

Adapts omap-serial driver to use pm_runtime api's.

1.) Populate reg values to uart port which can be used for context restore. 2.) Moving context_restore func to driver from serial.c
3.) Adding port_enable/disable func to enable/disable given uart port.
enable port using get_sync and disable using autosuspend.
4.) using runtime irq safe api to make get_sync be called from irq context.

---
 arch/arm/mach-omap2/serial.c                  |   22 +++
 arch/arm/plat-omap/include/plat/omap-serial.h |    2 +
 drivers/tty/serial/omap-serial.c              |  212 ++++++++++++++++++++++---
 3 files changed, 210 insertions(+), 26 deletions(-)
arch/arm/mach-omap2/serial.c +22 -0
index 8c1a4c7..1651c2c 100644
@@ -189,6 +189,27 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
 	}
 }
 
+static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable)
+{
+	struct omap_uart_port_info *up = pdev->dev.platform_data;
+
+	/* Set or clear wake-enable bit */
+	if (up->wk_en && up->wk_mask) {
+		u32 v = __raw_readl(up->wk_en);
+		if (enable)
+			v |= up->wk_mask;
+		else
+			v &= ~up->wk_mask;
+		__raw_writel(v, up->wk_en);
+	}
+
+	/* Enable or clear io-pad wakeup */
+	if (enable)
+		omap_device_enable_ioring_wakeup(pdev);
+	else
+		omap_device_disable_ioring_wakeup(pdev);
+}
+
 static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 				unsigned short num)
 {
@@ -332,6 +353,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 
 	pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
 	pdata->flags = UPF_BOOT_AUTOCONF;
+	pdata->enable_wakeup = omap_uart_wakeup_enable;
 	if (bdata->id == omap_uart_con_id)
 		pdata->console_uart = true;
 
arch/arm/plat-omap/include/plat/omap-serial.h +2 -0
index 2ca885b..ac30de8 100644
@@ -65,6 +65,7 @@ struct omap_uart_port_info {
 	unsigned int		errata;
 	unsigned int		console_uart;
 
+	void (*enable_wakeup)(struct platform_device *, bool);
 	void __iomem *wk_st;
 	void __iomem *wk_en;
 	u32 wk_mask;
@@ -120,6 +121,7 @@ struct uart_omap_port {
 	char			name[20];
 	unsigned long		port_activity;
 	unsigned int		errata;
+	void (*enable_wakeup)(struct platform_device *, bool);
 };
 
 #endif /* __OMAP_SERIAL_H__ */
drivers/tty/serial/omap-serial.c +186 -26

518 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#7 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

Hi Govindraj,

On 6/8/2011 6:23 AM, Govindraj.R wrote:

[snip]

Quoted 2 lines
drivers/tty/serial/omap-serial.c +2 -0
+
+#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

[snip]

drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1386

Quoted 7 lines
drivers/tty/serial/omap-serial.c +3 -0
@@ -1295,18 +1381,36 @@ static int serial_omap_probe(struct platform_device *pdev)
  		up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
  	}
 
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev,
+			OMAP_UART_AUTOSUSPEND_DELAY);

Something is weird here...DEFAULT_AUTOSUSPEND_DELAY is defined as (30*HZ) which would appear to be jiffies (ticks per second) and NOT msecs. However, pm_runtime_set_autosuspend is clearly expecting msecs. So this seems to conflict. By default 30*HZ for omap would be 30*128 = 3840ms so not quite 4 seconds.

What were you intending here?

Cheers
Jon

#8 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

Quoted 26 lines · Jon Hunter

Hi Govindraj,

On 6/8/2011 6:23 AM, Govindraj.R wrote:

[snip]

Quoted 2 lines
drivers/tty/serial/omap-serial.c +2 -0
+
+#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

[snip]

Review static int serial_omap_probe(struct · line 1387

Quoted 8 lines
(quoted diff) +3 -0
@@ -1295,18 +1381,36 @@ static int serial_omap_probe(struct
 platform_device *pdev)
 ? ? ? ? ? ? ? ?up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
 ? ? ? ?}
 
+ ? ? ? pm_runtime_use_autosuspend(&pdev->dev);
+ ? ? ? pm_runtime_set_autosuspend_delay(&pdev->dev,
+ ? ? ? ? ? ? ? ? ? ? ? OMAP_UART_AUTOSUSPEND_DELAY);

Something is weird here...DEFAULT_AUTOSUSPEND_DELAY is defined as (30*HZ) which would appear to be jiffies (ticks per second) and NOT msecs. However, pm_runtime_set_autosuspend is clearly expecting msecs. So this seems to conflict. By default 30*HZ for omap would be 30*128 = 3840ms so not quite 4 seconds.

Quoted 1 line

What were you intending here?

Intention is to get approx 3 secs timeout for autosuspend.

--
Thanks,
Govindraj.R

Quoted 8 lines

Cheers
Jon
--
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

#9 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

Hi Govindraj

Quoted 27 lines · Govindraj
Quoted 26 lines · Jon Hunter

Hi Govindraj,

On 6/8/2011 6:23 AM, Govindraj.R wrote:

[snip]

Quoted 2 lines
drivers/tty/serial/omap-serial.c +2 -0
+
+#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

[snip]

drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct · line 1387

Quoted 8 lines
drivers/tty/serial/omap-serial.c +3 -0
@@ -1295,18 +1381,36 @@ static int serial_omap_probe(struct
 platform_device *pdev)
                up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
        }
 
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev,
+                       OMAP_UART_AUTOSUSPEND_DELAY);

Something is weird here...DEFAULT_AUTOSUSPEND_DELAY is defined as (30*HZ) which would appear to be jiffies (ticks per second) and NOT msecs. However, pm_runtime_set_autosuspend is clearly expecting msecs. So this seems to conflict. By default 30*HZ for omap would be 30*128 = 3840ms so not quite 4 seconds.

Quoted 3 lines
Quoted 1 line

What were you intending here?

Intention is to get approx 3 secs timeout for autosuspend.

In that case you should just define DEFAULT_AUTOSUSPEND_DELAY as 30000. The above is just confusing as you are mixing time types and hence, it is not clear what you intend the default timeout to be.

Jon

#10 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

Quoted 33 lines · Jon Hunter

Hi Govindraj

Quoted 30 lines · Govindraj
Quoted 29 lines · Jon Hunter

Hi Govindraj,

On 6/8/2011 6:23 AM, Govindraj.R wrote:

[snip]

Quoted 2 lines
drivers/tty/serial/omap-serial.c +2 -0
+
+#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

[snip]

drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct · line 1387

Quoted 8 lines
drivers/tty/serial/omap-serial.c +3 -0
@@ -1295,18 +1381,36 @@ static int serial_omap_probe(struct
 platform_device *pdev)
 up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
 }
 
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ OMAP_UART_AUTOSUSPEND_DELAY);

Something is weird here...DEFAULT_AUTOSUSPEND_DELAY is defined as (30*HZ)
which would appear to be jiffies (ticks per second) and NOT msecs. However,
pm_runtime_set_autosuspend is clearly expecting msecs. So this seems to conflict. By default 30*HZ for omap would be 30*128 = 3840ms so not quite 4
seconds.

Quoted 7 lines
Quoted 3 lines
Quoted 1 line

What were you intending here?

Intention is to get approx 3 secs timeout for autosuspend.

In that case you should just define DEFAULT_AUTOSUSPEND_DELAY as 30000. The above is just confusing as you are mixing time types and hence, it is not clear what you intend the default timeout to be.

Sorry, I meant 3000 and not 30000 above, if you want 3 secs.

Jon

#11 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

In reply to Govindraj.R
Quoted 3 lines · Govindraj.R

Adapts omap-serial driver to use pm_runtime api's.

1.) Populate reg values to uart port which can be used for context restore.

Please make this part a separate patch.

Quoted 8 lines

2.) Moving context_restore func to driver from serial.c
3.) Adding port_enable/disable func to enable/disable given uart port.
enable port using get_sync and disable using autosuspend.
4.) using runtime irq safe api to make get_sync be called from irq context.

This is great! we're almost there. Some minor comments below...

Quoted 17 lines
---
 arch/arm/mach-omap2/serial.c                  |   22 +++
 arch/arm/plat-omap/include/plat/omap-serial.h |    2 +
 drivers/tty/serial/omap-serial.c              |  212 ++++++++++++++++++++++---
 3 files changed, 210 insertions(+), 26 deletions(-)
arch/arm/mach-omap2/serial.c +3 -0
index 8c1a4c7..1651c2c 100644
@@ -189,6 +189,27 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
 	}
 }
 
+static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable)
+{
+	struct omap_uart_port_info *up = pdev->dev.platform_data;

arch/arm/mach-omap2/serial.c static void omap_serial_fill_default_pads(struct omap_board_data *bdata) · line 204

Quoted 10 lines
arch/arm/mach-omap2/serial.c +10 -0
+
+	/* Set or clear wake-enable bit */
+	if (up->wk_en && up->wk_mask) {
+		u32 v = __raw_readl(up->wk_en);
+		if (enable)
+			v |= up->wk_mask;
+		else
+			v &= ~up->wk_mask;
+		__raw_writel(v, up->wk_en);
+	}

I think I asked this in previous series, but can't remember the answer now... can't we enable bits in the WKEN registers once at init time, and then just use omap_hwmod_[enable|disable]_wakeup() here?

Quoted 44 lines
arch/arm/mach-omap2/serial.c +8 -0
+	/* Enable or clear io-pad wakeup */
+	if (enable)
+		omap_device_enable_ioring_wakeup(pdev);
+	else
+		omap_device_disable_ioring_wakeup(pdev);
+}
+
 static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 				unsigned short num)
 {
@@ -332,6 +353,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 
 	pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
 	pdata->flags = UPF_BOOT_AUTOCONF;
+	pdata->enable_wakeup = omap_uart_wakeup_enable;
 	if (bdata->id == omap_uart_con_id)
 		pdata->console_uart = true;
 
arch/arm/plat-omap/include/plat/omap-serial.h +2 -0
index 2ca885b..ac30de8 100644
@@ -65,6 +65,7 @@ struct omap_uart_port_info {
 	unsigned int		errata;
 	unsigned int		console_uart;
 
+	void (*enable_wakeup)(struct platform_device *, bool);
 	void __iomem *wk_st;
 	void __iomem *wk_en;
 	u32 wk_mask;
@@ -120,6 +121,7 @@ struct uart_omap_port {
 	char			name[20];
 	unsigned long		port_activity;
 	unsigned int		errata;
+	void (*enable_wakeup)(struct platform_device *, bool);
 };
 
 #endif /* __OMAP_SERIAL_H__ */
drivers/tty/serial/omap-serial.c +0 -0
index 47cadf4..897416f 100644
@@ -37,10 +37,14 @@
 #include <linux/clk.h>

drivers/tty/serial/omap-serial.c line 47

Quoted 10 lines
drivers/tty/serial/omap-serial.c +4 -0
 #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>
+#include <plat/omap_device.h>
+
+#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

As Jon already pointed out, the HZ here is wrong. Please define this value in msecs.

Quoted 6 lines
drivers/tty/serial/omap-serial.c +0 -0
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
@@ -94,6 +98,17 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
 	return port->uartclk/(baud * divisor);
 }
 

drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 110

Quoted 10 lines
drivers/tty/serial/omap-serial.c +10 -0
+static inline void serial_omap_port_disable(struct uart_omap_port *up)
+{
+	pm_runtime_mark_last_busy(&up->pdev->dev);
+	pm_runtime_put_autosuspend(&up->pdev->dev);
+}
+
+static inline void serial_omap_port_enable(struct uart_omap_port *up)
+{
+	pm_runtime_get_sync(&up->pdev->dev);
+}

These inlines are not needed. Please use runtime PM calls directly in the code. For _enable(), this is straight forward. For _disable() though, I don't think you want (or need) to _mark_last_busy() for every instance of omap_port_disable(). You only need to do this for ones TX/RX transactions...

drivers/tty/serial/omap-serial.c static void serial_omap_enable_ms(struct uart_port *port) · line 132

Quoted 12 lines
drivers/tty/serial/omap-serial.c +3 -0
 static void serial_omap_stop_rxdma(struct uart_omap_port *up)
 {
 	if (up->uart_dma.rx_dma_used) {
@@ -110,8 +125,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);
+
+	serial_omap_port_enable(up);
 	up->ier |= UART_IER_MSI;
 	serial_out(up, UART_IER, up->ier);
+	serial_omap_port_disable(up);

...for example, this one is not really activity based, so should probably just be pm_runtime_get_sync(), write the register, then pm_runtime_put() (async version.)

I didn't look at all the others below, but they should be looked at individually.

Quoted 228 lines
drivers/tty/serial/omap-serial.c +43 -8
 }
 
 static void serial_omap_stop_tx(struct uart_port *port)
@@ -131,21 +149,26 @@ static void serial_omap_stop_tx(struct uart_port *port)
 		up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
 	}
 
+	serial_omap_port_enable(up);
 	if (up->ier & UART_IER_THRI) {
 		up->ier &= ~UART_IER_THRI;
 		serial_out(up, UART_IER, up->ier);
 	}
+
+	serial_omap_port_disable(up);
 }
 
 static void serial_omap_stop_rx(struct uart_port *port)
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 
+	serial_omap_port_enable(up);
 	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);
+	serial_omap_port_disable(up);
 }
 
 static inline void receive_chars(struct uart_omap_port *up, int *status)
@@ -261,8 +284,10 @@ static void serial_omap_start_tx(struct uart_port *port)
 	unsigned int start;
 	int ret = 0;
 
+	serial_omap_port_enable(up);
 	if (!up->use_dma) {
 		serial_omap_enable_ier_thri(up);
+		serial_omap_port_disable(up);
 		return;
 	}
 
@@ -354,9 +379,12 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
 	unsigned int iir, lsr;
 	unsigned long flags;
 
+	serial_omap_port_enable(up);
 	iir = serial_in(up, UART_IIR);
-	if (iir & UART_IIR_NO_INT)
+	if (iir & UART_IIR_NO_INT) {
+		serial_omap_port_disable(up);
 		return IRQ_NONE;
+	}
 
 	spin_lock_irqsave(&up->port.lock, flags);
 	lsr = serial_in(up, UART_LSR);
@@ -378,6 +406,8 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
 		transmit_chars(up);
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
+	serial_omap_port_disable(up);
+
 	up->port_activity = jiffies;
 	return IRQ_HANDLED;
 }
@@ -388,11 +418,12 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
 	unsigned long flags = 0;
 	unsigned int ret = 0;
 
+	serial_omap_port_enable(up);
 	dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
 	spin_lock_irqsave(&up->port.lock, flags);
 	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
 	spin_unlock_irqrestore(&up->port.lock, flags);
-
+	serial_omap_port_disable(up);
 	return ret;
 }
 
@@ -402,7 +433,10 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
 	unsigned char status;
 	unsigned int ret = 0;
 
+	serial_omap_port_enable(up);
 	status = check_modem_status(up);
+	serial_omap_port_disable(up);
+
 	dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
 
 	if (status & UART_MSR_DCD)
@@ -434,7 +468,9 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
 		mcr |= UART_MCR_LOOP;
 
 	mcr |= up->mcr;
+	serial_omap_port_enable(up);
 	serial_out(up, UART_MCR, mcr);
+	serial_omap_port_disable(up);
 }
 
 static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -443,6 +479,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
 	unsigned long flags = 0;
 
 	dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+	serial_omap_port_enable(up);
 	spin_lock_irqsave(&up->port.lock, flags);
 	if (break_state == -1)
 		up->lcr |= UART_LCR_SBC;
@@ -450,6 +487,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
 		up->lcr &= ~UART_LCR_SBC;
 	serial_out(up, UART_LCR, up->lcr);
 	spin_unlock_irqrestore(&up->port.lock, flags);
+	serial_omap_port_disable(up);
 }
 
 static int serial_omap_startup(struct uart_port *port)
@@ -468,6 +506,7 @@ static int serial_omap_startup(struct uart_port *port)
 
 	dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
 
+	serial_omap_port_enable(up);
 	/*
 	 * Clear the FIFO buffers and disable them.
 	 * (they will be reenabled in set_termios())
@@ -523,6 +562,7 @@ static int serial_omap_startup(struct uart_port *port)
 	/* Enable module level wake up */
 	serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);
 
+	serial_omap_port_disable(up);
 	up->port_activity = jiffies;
 	return 0;
 }
@@ -533,6 +573,8 @@ static void serial_omap_shutdown(struct uart_port *port)
 	unsigned long flags = 0;
 
 	dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+
+	serial_omap_port_enable(up);
 	/*
 	 * Disable interrupts from this port
 	 */
@@ -566,6 +608,7 @@ static void serial_omap_shutdown(struct uart_port *port)
 			up->uart_dma.rx_buf_dma_phys);
 		up->uart_dma.rx_buf = NULL;
 	}
+	serial_omap_port_disable(up);
 	free_irq(up->port.irq, up);
 }
 
@@ -671,6 +714,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
 	quot = serial_omap_get_divisor(port, baud);
 
+	up->dll = quot & 0xff;
+	up->dlh = quot >> 8;
+	up->mdr1 = UART_OMAP_MDR1_DISABLE;
+
 	up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
 			UART_FCR_ENABLE_FIFO;
 	if (up->use_dma)
@@ -680,6 +727,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	 * Ok, we're now changing the port state. Do it with
 	 * interrupts disabled.
 	 */
+	serial_omap_port_enable(up);
 	spin_lock_irqsave(&up->port.lock, flags);
 
 	/*
@@ -723,6 +771,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 		up->ier |= UART_IER_MSI;
 	serial_out(up, UART_IER, up->ier);
 	serial_out(up, UART_LCR, cval);		/* reset DLAB */
+	up->lcr = cval;
 
 	/* FIFOs and DMA Settings */
 
@@ -758,8 +807,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	serial_out(up, UART_MCR, up->mcr);
 
 	/* Protocol, Baud Rate, and Interrupt Settings */
-
-	serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
+	serial_out(up, UART_OMAP_MDR1, up->mdr1);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 
 	up->efr = serial_in(up, UART_EFR);
@@ -769,8 +817,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	serial_out(up, UART_IER, 0);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 
-	serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
-	serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+	serial_out(up, UART_DLL, up->dll);	/* LS of divisor */
+	serial_out(up, UART_DLM, up->dlh);	/* MS of divisor */
 
 	serial_out(up, UART_LCR, 0);
 	serial_out(up, UART_IER, up->ier);
@@ -780,9 +828,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	serial_out(up, UART_LCR, cval);
 
 	if (baud > 230400 && baud != 3000000)
-		serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
+		up->mdr1 = UART_OMAP_MDR1_13X_MODE;
 	else
-		serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
+		up->mdr1 = UART_OMAP_MDR1_16X_MODE;
+
+	serial_out(up, UART_OMAP_MDR1, up->mdr1)
 
 	/* Hardware Flow Control Configuration */
 
@@ -810,6 +860,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 		serial_omap_configure_xonxoff(up, termios);
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
+	serial_omap_port_disable(up);
 	dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
 }
 
@@ -821,6 +872,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
 	unsigned char efr;
 
 	dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+
+	serial_omap_port_enable(up);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 	efr = serial_in(up, UART_EFR);
 	serial_out(up, UART_EFR, efr | UART_EFR_ECB);

drivers/tty/serial/omap-serial.c serial_omap_pm(struct uart_port *port, unsigned int state, · line 889

Quoted 7 lines
drivers/tty/serial/omap-serial.c +4 -0
@@ -830,6 +883,10 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 	serial_out(up, UART_EFR, efr);
 	serial_out(up, UART_LCR, 0);
+	if (state)
+		pm_runtime_put_sync(&up->pdev->dev);
+	else
+		serial_omap_port_disable(up);

OK, so this boils down to either a _put_sync() or a _mark_last_busy + _put_autosuspend(), depending on whether this is suspending or resuming, right?

Why the difference?

Quoted 60 lines
drivers/tty/serial/omap-serial.c +12 -4
 }
 
 static void serial_omap_release_port(struct uart_port *port)
@@ -907,25 +964,31 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
 static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+	serial_omap_port_enable(up);
 	wait_for_xmitr(up);
 	serial_out(up, UART_TX, ch);
+	serial_omap_port_disable(up);
 }
 
 static int serial_omap_poll_get_char(struct uart_port *port)
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
-	unsigned int status = serial_in(up, UART_LSR);
+	unsigned int status;
 
+	serial_omap_port_enable(up);
+	status = serial_in(up, UART_LSR);
 	if (!(status & UART_LSR_DR))
 		return NO_POLL_CHAR;
 
-	return serial_in(up, UART_RX);
+	status = serial_in(up, UART_RX);
+	serial_omap_port_disable(up);
+	return status;
 }
 
 #endif /* CONFIG_CONSOLE_POLL */
 
 #ifdef CONFIG_SERIAL_OMAP_CONSOLE
-
 static struct uart_omap_port *serial_omap_console_ports[4];
 
 static struct uart_driver serial_omap_reg;
@@ -955,6 +1018,8 @@ serial_omap_console_write(struct console *co, const char *s,
 	else
 		spin_lock(&up->port.lock);
 
+	serial_omap_port_enable(up);
+
 	/*
 	 * First save the IER then disable the interrupts
 	 */
@@ -979,6 +1044,7 @@ serial_omap_console_write(struct console *co, const char *s,
 	if (up->msr_saved_flags)
 		check_modem_status(up);
 
+	serial_omap_port_disable(up);
 	if (locked)
 		spin_unlock(&up->port.lock);
 	local_irq_restore(flags);
@@ -1061,22 +1127,27 @@ static struct uart_driver serial_omap_reg = {
 	.cons		= OMAP_CONSOLE,
 };
 
-static int

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1136

Quoted 10 lines
drivers/tty/serial/omap-serial.c +4 -3
-serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+static int serial_omap_suspend(struct device *dev)
 {
-	struct uart_omap_port *up = platform_get_drvdata(pdev);
+	struct uart_omap_port *up = dev_get_drvdata(dev);
 
-	if (up)
+	if (up) {
 		uart_suspend_port(&serial_omap_reg, &up->port);
+		console_trylock();

This locking needs to be explained. Why it is needed, but very importantly, why you are not checking the return value of the _trylock()

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1137

Quoted 1 line
drivers/tty/serial/omap-serial.c +1 -0
+		serial_omap_pm(&up->port, 3, 0);

Why is this call needed?

uart_suspend_port() calls uart_change_pm() which should call the ->pm method of struct uart_ops (which is serial_omap_pm). What am I missing?

Also notice you're not calling serial_omap_pm() in the resume method below to change it back.

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1140

Quoted 3 lines
drivers/tty/serial/omap-serial.c +1 -0
+	}
 	return 0;
 }

Also, device wakeup capability should be checked and enabled/disabled in the suspend path (not only the runtime suspend path.)

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1148

Quoted 10 lines
drivers/tty/serial/omap-serial.c +4 -3
-static int serial_omap_resume(struct platform_device *dev)
+static int serial_omap_resume(struct device *dev)
 {
-	struct uart_omap_port *up = platform_get_drvdata(dev);
+	struct uart_omap_port *up = dev_get_drvdata(dev);
 
-	if (up)
+	if (up) {
 		uart_resume_port(&serial_omap_reg, &up->port);
+		console_unlock();

Again, please describe locking in comments.

Also, what happens here if the console_trylock() in your suspend method failed?

Quoted 150 lines
drivers/tty/serial/omap-serial.c +67 -5
+	}
+
 	return 0;
 }
 
@@ -1097,6 +1168,7 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 			serial_omap_stop_rxdma(up);
 			up->ier |= (UART_IER_RDI | UART_IER_RLSI);
 			serial_out(up, UART_IER, up->ier);
+			serial_omap_port_disable(up);
 		}
 		return;
 	}
@@ -1128,6 +1200,9 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 
 static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
 {
+	struct uart_omap_port *up = (struct uart_omap_port *)data;
+
+	serial_omap_port_disable(up);
 	return;
 }
 
@@ -1135,6 +1210,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up)
 {
 	int ret = 0;
 
+	serial_omap_port_enable(up);
 	if (up->uart_dma.rx_dma_channel == -1) {
 		ret = omap_request_dma(up->uart_dma.uart_dma_rx,
 				"UART Rx DMA",
@@ -1214,6 +1290,7 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
 		serial_omap_stop_tx(&up->port);
 		up->uart_dma.tx_dma_used = false;
 		spin_unlock(&(up->uart_dma.tx_lock));
+		serial_omap_port_disable(up);
 	} else {
 		omap_stop_dma(up->uart_dma.tx_dma_channel);
 		serial_omap_continue_tx(up);
@@ -1224,9 +1301,10 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
 
 static int serial_omap_probe(struct platform_device *pdev)
 {
-	struct uart_omap_port	*up;
+	struct uart_omap_port	*up = NULL;
 	struct resource		*mem, *irq, *dma_tx, *dma_rx;
 	struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+	struct omap_device *od;
 	int ret = -ENOSPC;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1276,12 +1354,20 @@ static int serial_omap_probe(struct platform_device *pdev)
 	up->port.ops = &serial_omap_pops;
 	up->port.line = pdev->id;
 
-	up->port.membase = omap_up_info->membase;
-	up->port.mapbase = omap_up_info->mapbase;
+	up->port.mapbase = mem->start;
+	up->port.membase = ioremap(mem->start, mem->end - mem->start);
+
+	if (!up->port.membase) {
+		dev_err(&pdev->dev, "can't ioremap UART\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
 	up->port.flags = omap_up_info->flags;
-	up->port.irqflags = omap_up_info->irqflags;
 	up->port.uartclk = omap_up_info->uartclk;
 	up->uart_dma.uart_base = mem->start;
+	up->errata = omap_up_info->errata;
+	up->enable_wakeup = omap_up_info->enable_wakeup;
 
 	if (omap_up_info->dma_enabled) {
 		up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1295,18 +1381,36 @@ static int serial_omap_probe(struct platform_device *pdev)
 		up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
 	}
 
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev,
+			OMAP_UART_AUTOSUSPEND_DELAY);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_irq_safe(&pdev->dev);
+
+	if (omap_up_info->console_uart) {
+		od = to_omap_device(up->pdev);
+		omap_hwmod_idle(od->hwmods[0]);
+		serial_omap_port_enable(up);
+		serial_omap_port_disable(up);
+	}
+
 	ui[pdev->id] = up;
 	serial_omap_add_console_port(up);
 
 	ret = uart_add_one_port(&serial_omap_reg, &up->port);
 	if (ret != 0)
-		goto do_release_region;
+		goto err1;
 
+	dev_set_drvdata(&pdev->dev, up);
 	platform_set_drvdata(pdev, up);
+
 	return 0;
 err:
 	dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
 				pdev->id, __func__, ret);
+err1:
+	kfree(up);
 do_release_region:
 	release_mem_region(mem->start, (mem->end - mem->start) + 1);
 	return ret;
@@ -1318,20 +1422,76 @@ static int serial_omap_remove(struct platform_device *dev)
 
 	platform_set_drvdata(dev, NULL);
 	if (up) {
+		pm_runtime_disable(&up->pdev->dev);
 		uart_remove_one_port(&serial_omap_reg, &up->port);
 		kfree(up);
 	}
 	return 0;
 }
 
+static void omap_uart_restore_context(struct uart_omap_port *up)
+{
+	u16 efr = 0;
+
+	serial_out(up, UART_OMAP_MDR1, up->mdr1);
+	serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+	efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, UART_EFR_ECB);
+	serial_out(up, UART_LCR, 0x0); /* Operational mode */
+	serial_out(up, UART_IER, 0x0);
+	serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+	serial_out(up, UART_DLL, up->dll);
+	serial_out(up, UART_DLM, up->dlh);
+	serial_out(up, UART_LCR, 0x0); /* Operational mode */
+	serial_out(up, UART_IER, up->ier);
+	serial_out(up, UART_FCR, up->fcr);
+	serial_out(up, UART_LCR, 0x80);
+	serial_out(up, UART_MCR, up->mcr);
+	serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+	serial_out(up, UART_EFR, efr);
+	serial_out(up, UART_LCR, up->lcr);
+	/* UART 16x mode */
+	serial_out(up, UART_OMAP_MDR1, up->mdr1);
+}
+
+static int omap_serial_runtime_suspend(struct device *dev)

drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1467

Quoted 10 lines
drivers/tty/serial/omap-serial.c +10 -0
+{
+	struct uart_omap_port *up = dev_get_drvdata(dev);
+
+	if (!up)
+		goto done;
+
+	if (device_may_wakeup(dev))
+		up->enable_wakeup(up->pdev, true);
+	else
+		up->enable_wakeup(up->pdev, false);

I know the earlier code was doing it this way too, but an optimization would be to have the driver keep state whether the wakeups are enabled or disabled, so you don't have to keep calling this function (which can be expensive with the PRCM reads/writes.

That state can also be used in the suspend path, which should also be managing wakeups.

drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1477

Quoted 10 lines
drivers/tty/serial/omap-serial.c +10 -0
+done:
+	return 0;
+}
+
+static int omap_serial_runtime_resume(struct device *dev)
+{
+	struct uart_omap_port *up = dev_get_drvdata(dev);
+
+	if (up)
+		omap_uart_restore_context(up);

You only need to restore context when returning from off-mode. You should be using omap_device_get_context_loss_count (called via pdata function pointer) for this. See the MMC driver or DSS driver for how this is done.

Quoted 11 lines
drivers/tty/serial/omap-serial.c +10 -0
+	return 0;
+}
+
+static const struct dev_pm_ops omap_serial_dev_pm_ops = {
+	.suspend = serial_omap_suspend,
+	.resume	= serial_omap_resume,
+	.runtime_suspend = omap_serial_runtime_suspend,
+	.runtime_resume = omap_serial_runtime_resume,
+};
+
 static struct platform_driver serial_omap_driver = {

drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1496

Quoted 10 lines
drivers/tty/serial/omap-serial.c +1 -3
 	.probe          = serial_omap_probe,
 	.remove         = serial_omap_remove,
-
-	.suspend	= serial_omap_suspend,
-	.resume		= serial_omap_resume,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.pm = &omap_serial_dev_pm_ops,
 	},
 };

Kevin

#12 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

Quoted 42 lines · Kevin Hilman
Quoted 3 lines · Govindraj.R

Adapts omap-serial driver to use pm_runtime api's.

1.) Populate reg values to uart port which can be used for context restore.

Please make this part a separate patch.

Quoted 8 lines

2.) Moving context_restore func to driver from serial.c
3.) Adding port_enable/disable func to enable/disable given uart port. ? ? enable port using get_sync and disable using autosuspend. 4.) using runtime irq safe api to make get_sync be called from irq context.

This is great! ?we're almost there. ? Some minor comments below...

Quoted 23 lines

---

?arch/arm/mach-omap2/serial.c ? ? ? ? ? ? ? ? ?| ? 22 +++
?arch/arm/plat-omap/include/plat/omap-serial.h | ? ?2 +
?drivers/tty/serial/omap-serial.c ? ? ? ? ? ? ?| ?212 ++++++++++++++++++++++---

?3 files changed, 210 insertions(+), 26 deletions(-)

arch/arm/mach-omap2/serial.c +9 -0
index 8c1a4c7..1651c2c 100644
@@ -189,6 +189,27 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
 ? ? ? }
 ?}
 
+static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable)
+{
+ ? ? struct omap_uart_port_info *up = pdev->dev.platform_data;
+
+ ? ? /* Set or clear wake-enable bit */
+ ? ? if (up->wk_en && up->wk_mask) {
+ ? ? ? ? ? ? u32 v = __raw_readl(up->wk_en);
+ ? ? ? ? ? ? if (enable)
+ ? ? ? ? ? ? ? ? ? ? v |= up->wk_mask;
Quoted 9 lines

arch/arm/mach-omap2/serial.c static void omap_serial_fill_default_pads(struct omap_board_data *bdata) · line 204

Quoted 4 lines
arch/arm/mach-omap2/serial.c +4 -0
+ ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? v &= ~up->wk_mask;
+ ? ? ? ? ? ? __raw_writel(v, up->wk_en);
+ ? ? }

I think I asked this in previous series, but can't remember the answer now... ?can't we enable bits in the WKEN registers once at init time, and then just use omap_hwmod_[enable|disable]_wakeup() here?

by default all bits are enabled in WKEN,

I will use omap_hwmod_[enable|disable]_wakeup() api's

if these API's take care of WKEN regs, then no issue using the same.

Quoted 48 lines
Quoted 48 lines
arch/arm/mach-omap2/serial.c +8 -0
+ ? ? /* Enable or clear io-pad wakeup */
+ ? ? if (enable)
+ ? ? ? ? ? ? omap_device_enable_ioring_wakeup(pdev);
+ ? ? else
+ ? ? ? ? ? ? omap_device_disable_ioring_wakeup(pdev);
+}
+
 ?static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned short num)
 ?{
@@ -332,6 +353,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 
 ? ? ? pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
 ? ? ? pdata->flags = UPF_BOOT_AUTOCONF;
+ ? ? pdata->enable_wakeup = omap_uart_wakeup_enable;
 ? ? ? if (bdata->id == omap_uart_con_id)
 ? ? ? ? ? ? ? pdata->console_uart = true;
 
arch/arm/plat-omap/include/plat/omap-serial.h +2 -0
index 2ca885b..ac30de8 100644
@@ -65,6 +65,7 @@ struct omap_uart_port_info {
 ? ? ? unsigned int ? ? ? ? ? ?errata;
 ? ? ? unsigned int ? ? ? ? ? ?console_uart;
 
+ ? ? void (*enable_wakeup)(struct platform_device *, bool);
 ? ? ? void __iomem *wk_st;
 ? ? ? void __iomem *wk_en;
 ? ? ? u32 wk_mask;
@@ -120,6 +121,7 @@ struct uart_omap_port {
 ? ? ? char ? ? ? ? ? ? ? ? ? ?name[20];
 ? ? ? unsigned long ? ? ? ? ? port_activity;
 ? ? ? unsigned int ? ? ? ? ? ?errata;
+ ? ? void (*enable_wakeup)(struct platform_device *, bool);
 ?};
 

?#endif /* __OMAP_SERIAL_H__ */

drivers/tty/serial/omap-serial.c +0 -0
index 47cadf4..897416f 100644
@@ -37,10 +37,14 @@

?#include <linux/clk.h>
?#include <linux/serial_core.h>
?#include <linux/irq.h>
+#include <linux/pm_runtime.h>

Quoted 10 lines

drivers/tty/serial/omap-serial.c line 47

Quoted 6 lines

?#include <plat/dma.h>
?#include <plat/dmtimer.h>
?#include <plat/omap-serial.h>

drivers/tty/serial/omap-serial.c +3 -0
+#include <plat/omap_device.h>
+
+#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

As Jon already pointed out, the HZ here is wrong. ?Please define this value in msecs.

corrected.

Quoted 6 lines
Quoted 6 lines

?static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];

drivers/tty/serial/omap-serial.c +0 -0
@@ -94,6 +98,17 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
 ? ? ? return port->uartclk/(baud * divisor);
 ?}
 
Quoted 17 lines

drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 110

Quoted 10 lines
drivers/tty/serial/omap-serial.c +10 -0
+static inline void serial_omap_port_disable(struct uart_omap_port *up)
+{
+ ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
+ ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
+}
+
+static inline void serial_omap_port_enable(struct uart_omap_port *up)
+{
+ ? ? pm_runtime_get_sync(&up->pdev->dev);
+}

These inlines are not needed. ?Please use runtime PM calls directly in the code. ?For _enable(), this is straight forward. ?For _disable() though, I don't think you want (or need) to _mark_last_busy() for every instance of omap_port_disable(). ?You only need to do this for ones TX/RX transactions...

Fine. will modify.

Quoted 17 lines

drivers/tty/serial/omap-serial.c static void serial_omap_enable_ms(struct uart_port *port) · line 132

Quoted 12 lines
drivers/tty/serial/omap-serial.c +3 -0
 ?static void serial_omap_stop_rxdma(struct uart_omap_port *up)
 ?{
 ? ? ? if (up->uart_dma.rx_dma_used) {
@@ -110,8 +125,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);
+
+ ? ? serial_omap_port_enable(up);
 ? ? ? up->ier |= UART_IER_MSI;
 ? ? ? serial_out(up, UART_IER, up->ier);
+ ? ? serial_omap_port_disable(up);

...for example, this one is not really activity based, so should probably just be pm_runtime_get_sync(), write the register, then pm_runtime_put() (async version.)

Quoted 3 lines

I didn't look at all the others below, but they should be looked at individually.

ok. I will check them.

Quoted 231 lines
Quoted 231 lines
drivers/tty/serial/omap-serial.c +23 -2
 ?}
 
 ?static void serial_omap_stop_tx(struct uart_port *port)
@@ -131,21 +149,26 @@ static void serial_omap_stop_tx(struct uart_port *port)
 ? ? ? ? ? ? ? up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
 ? ? ? }
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? if (up->ier & UART_IER_THRI) {
 ? ? ? ? ? ? ? up->ier &= ~UART_IER_THRI;
 ? ? ? ? ? ? ? serial_out(up, UART_IER, up->ier);
 ? ? ? }
+
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static void serial_omap_stop_rx(struct uart_port *port)
 ?{
 ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? 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);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static inline void receive_chars(struct uart_omap_port *up, int *status)
@@ -261,8 +284,10 @@ static void serial_omap_start_tx(struct uart_port *port)
 ? ? ? unsigned int start;
 ? ? ? int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? if (!up->use_dma) {
 ? ? ? ? ? ? ? serial_omap_enable_ier_thri(up);
+ ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? ? ? ? ? return;
 ? ? ? }
 
@@ -354,9 +379,12 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
 ? ? ? unsigned int iir, lsr;
 ? ? ? unsigned long flags;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? iir = serial_in(up, UART_IIR);
- ? ? if (iir & UART_IIR_NO_INT)
+ ? ? if (iir & UART_IIR_NO_INT) {
+ ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? ? ? ? ? return IRQ_NONE;
+ ? ? }
 
 ? ? ? spin_lock_irqsave(&up->port.lock, flags);
 ? ? ? lsr = serial_in(up, UART_LSR);
@@ -378,6 +406,8 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
 ? ? ? ? ? ? ? transmit_chars(up);
 
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
+ ? ? serial_omap_port_disable(up);
+
 ? ? ? up->port_activity = jiffies;
 ? ? ? return IRQ_HANDLED;
 ?}
@@ -388,11 +418,12 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
 ? ? ? unsigned long flags = 0;
 ? ? ? unsigned int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
 ? ? ? spin_lock_irqsave(&up->port.lock, flags);
 ? ? ? ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
-
+ ? ? serial_omap_port_disable(up);
 ? ? ? return ret;
 ?}
 
@@ -402,7 +433,10 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
 ? ? ? unsigned char status;
 ? ? ? unsigned int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? status = check_modem_status(up);
+ ? ? serial_omap_port_disable(up);
+
 ? ? ? dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
 
 ? ? ? if (status & UART_MSR_DCD)
@@ -434,7 +468,9 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
 ? ? ? ? ? ? ? mcr |= UART_MCR_LOOP;
 
 ? ? ? mcr |= up->mcr;
+ ? ? serial_omap_port_enable(up);
 ? ? ? serial_out(up, UART_MCR, mcr);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -443,6 +479,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
 ? ? ? unsigned long flags = 0;
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+ ? ? serial_omap_port_enable(up);
 ? ? ? spin_lock_irqsave(&up->port.lock, flags);
 ? ? ? if (break_state == -1)
 ? ? ? ? ? ? ? up->lcr |= UART_LCR_SBC;
@@ -450,6 +487,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
 ? ? ? ? ? ? ? up->lcr &= ~UART_LCR_SBC;
 ? ? ? serial_out(up, UART_LCR, up->lcr);
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static int serial_omap_startup(struct uart_port *port)
@@ -468,6 +506,7 @@ static int serial_omap_startup(struct uart_port *port)
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
 
+ ? ? serial_omap_port_enable(up);

? ? ? /*
? ? ? ?* Clear the FIFO buffers and disable them. ? ? ? ?* (they will be reenabled in set_termios())

drivers/tty/serial/omap-serial.c +0 -0
@@ -523,6 +562,7 @@ static int serial_omap_startup(struct uart_port *port)

? ? ? /* Enable module level wake up */
? ? ? serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);

+ ? ? serial_omap_port_disable(up);
? ? ? up->port_activity = jiffies;
? ? ? return 0;
?}

drivers/tty/serial/omap-serial.c +2 -0
@@ -533,6 +573,8 @@ static void serial_omap_shutdown(struct uart_port *port)
 ? ? ? unsigned long flags = 0;
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+
+ ? ? serial_omap_port_enable(up);

? ? ? /*
? ? ? ?* Disable interrupts from this port
? ? ? ?*/

drivers/tty/serial/omap-serial.c +5 -0
@@ -566,6 +608,7 @@ static void serial_omap_shutdown(struct uart_port *port)
 ? ? ? ? ? ? ? ? ? ? ? up->uart_dma.rx_buf_dma_phys);
 ? ? ? ? ? ? ? up->uart_dma.rx_buf = NULL;
 ? ? ? }
+ ? ? serial_omap_port_disable(up);
 ? ? ? free_irq(up->port.irq, up);
 ?}
 
@@ -671,6 +714,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
 ? ? ? quot = serial_omap_get_divisor(port, baud);
 
+ ? ? up->dll = quot & 0xff;
+ ? ? up->dlh = quot >> 8;
+ ? ? up->mdr1 = UART_OMAP_MDR1_DISABLE;
+

? ? ? up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 | ? ? ? ? ? ? ? ? ? ? ? UART_FCR_ENABLE_FIFO;
? ? ? if (up->use_dma)

drivers/tty/serial/omap-serial.c +0 -0
@@ -680,6 +727,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,

? ? ? ?* Ok, we're now changing the port state. Do it with ? ? ? ?* interrupts disabled.
? ? ? ?*/
+ ? ? serial_omap_port_enable(up);
? ? ? spin_lock_irqsave(&up->port.lock, flags);

? ? ? /*

drivers/tty/serial/omap-serial.c +0 -0
@@ -723,6 +771,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? ? ? ? ? up->ier |= UART_IER_MSI;
 ? ? ? serial_out(up, UART_IER, up->ier);

? ? ? serial_out(up, UART_LCR, cval); ? ? ? ? /* reset DLAB */
+ ? ? up->lcr = cval;

? ? ? /* FIFOs and DMA Settings */

drivers/tty/serial/omap-serial.c +0 -0
@@ -758,8 +807,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? serial_out(up, UART_MCR, up->mcr);
 

? ? ? /* Protocol, Baud Rate, and Interrupt Settings */ -
- ? ? serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

? ? ? up->efr = serial_in(up, UART_EFR);

drivers/tty/serial/omap-serial.c +3 -3
@@ -769,8 +817,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? serial_out(up, UART_IER, 0);
 ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 
- ? ? serial_out(up, UART_DLL, quot & 0xff); ? ? ? ? ?/* LS of divisor */
- ? ? serial_out(up, UART_DLM, quot >> 8); ? ? ? ? ? ?/* MS of divisor */
+ ? ? serial_out(up, UART_DLL, up->dll); ? ? ?/* LS of divisor */
+ ? ? serial_out(up, UART_DLM, up->dlh); ? ? ?/* MS of divisor */
 
 ? ? ? serial_out(up, UART_LCR, 0);
 ? ? ? serial_out(up, UART_IER, up->ier);
@@ -780,9 +828,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? serial_out(up, UART_LCR, cval);
 
 ? ? ? if (baud > 230400 && baud != 3000000)
- ? ? ? ? ? ? serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
+ ? ? ? ? ? ? up->mdr1 = UART_OMAP_MDR1_13X_MODE;

? ? ? else
- ? ? ? ? ? ? serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
+ ? ? ? ? ? ? up->mdr1 = UART_OMAP_MDR1_16X_MODE;
+
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1)

? ? ? /* Hardware Flow Control Configuration */

drivers/tty/serial/omap-serial.c +3 -0
@@ -810,6 +860,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? ? ? ? ? serial_omap_configure_xonxoff(up, termios);
 
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
+ ? ? serial_omap_port_disable(up);
 ? ? ? dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
 ?}
 
@@ -821,6 +872,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
 ? ? ? unsigned char efr;
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+
+ ? ? serial_omap_port_enable(up);
 ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 ? ? ? efr = serial_in(up, UART_EFR);
 ? ? ? serial_out(up, UART_EFR, efr | UART_EFR_ECB);
@@ -830,6 +883,10 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
 ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 ? ? ? serial_out(up, UART_EFR, efr);
 ? ? ? serial_out(up, UART_LCR, 0);
Quoted 9 lines

drivers/tty/serial/omap-serial.c serial_omap_pm(struct uart_port *port, unsigned int state, · line 889

Quoted 4 lines
drivers/tty/serial/omap-serial.c +4 -0
+ ? ? if (state)
+ ? ? ? ? ? ? pm_runtime_put_sync(&up->pdev->dev);
+ ? ? else
+ ? ? ? ? ? ? serial_omap_port_disable(up);

OK, so this boils down to either a _put_sync() or a _mark_last_busy + _put_autosuspend(), depending on whether this is suspending or resuming, right?

yes also during bootup.
disable the ports immediately that are not used during bootup.

Quoted 1 line

Why the difference?

Need to put the ports down immediately during system wide suspend other wise autosuspend delay will prevent system to enter suspend state immediately.

Quoted 67 lines
Quoted 67 lines
drivers/tty/serial/omap-serial.c +9 -2
 ?}
 
 ?static void serial_omap_release_port(struct uart_port *port)
@@ -907,25 +964,31 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
 ?static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
 ?{
 ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ ? ? serial_omap_port_enable(up);
 ? ? ? wait_for_xmitr(up);
 ? ? ? serial_out(up, UART_TX, ch);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static int serial_omap_poll_get_char(struct uart_port *port)
 ?{
 ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port;
- ? ? unsigned int status = serial_in(up, UART_LSR);
+ ? ? unsigned int status;
 
+ ? ? serial_omap_port_enable(up);
+ ? ? status = serial_in(up, UART_LSR);
 ? ? ? if (!(status & UART_LSR_DR))
 ? ? ? ? ? ? ? return NO_POLL_CHAR;
 
- ? ? return serial_in(up, UART_RX);
+ ? ? status = serial_in(up, UART_RX);
+ ? ? serial_omap_port_disable(up);
+ ? ? return status;
 ?}
 

?#endif /* CONFIG_CONSOLE_POLL */

?#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-
?static struct uart_omap_port *serial_omap_console_ports[4];

?static struct uart_driver serial_omap_reg;

drivers/tty/serial/omap-serial.c +0 -0
@@ -955,6 +1018,8 @@ serial_omap_console_write(struct console *co, const char *s,

? ? ? else
? ? ? ? ? ? ? spin_lock(&up->port.lock);

+ ? ? serial_omap_port_enable(up);
+
? ? ? /*
? ? ? ?* First save the IER then disable the interrupts ? ? ? ?*/

drivers/tty/serial/omap-serial.c +3 -3
@@ -979,6 +1044,7 @@ serial_omap_console_write(struct console *co, const char *s,
 ? ? ? if (up->msr_saved_flags)
 ? ? ? ? ? ? ? check_modem_status(up);
 
+ ? ? serial_omap_port_disable(up);
 ? ? ? if (locked)
 ? ? ? ? ? ? ? spin_unlock(&up->port.lock);
 ? ? ? local_irq_restore(flags);
@@ -1061,22 +1127,27 @@ static struct uart_driver serial_omap_reg = {
 ? ? ? .cons ? ? ? ? ? = OMAP_CONSOLE,
 ?};
 
-static int
-serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+static int serial_omap_suspend(struct device *dev)
 ?{
- ? ? struct uart_omap_port *up = platform_get_drvdata(pdev);
+ ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
 
Quoted 8 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1136

Quoted 4 lines
drivers/tty/serial/omap-serial.c +2 -1
- ? ? if (up)
+ ? ? if (up) {
 ? ? ? ? ? ? ? uart_suspend_port(&serial_omap_reg, &up->port);
+ ? ? ? ? ? ? console_trylock();

This locking needs to be explained. ?Why it is needed, but very importantly, why you are not checking the return value of the _trylock()

any print after this point can result in failure of immediate system suspending due to delayed autosuspend from omap_console_write.

log prints after uart suspend and print them during resume.

Quoted 4 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1137

Quoted 1 line
drivers/tty/serial/omap-serial.c +1 -0
+ ? ? ? ? ? ? serial_omap_pm(&up->port, 3, 0);

Why is this call needed?

Actually this is needed if no_console_suspend is used, for that case the console will remain active since serial_omap_pm is not getting called from serial_core and port is not suspended immediately with put_sync.

prints during system wide suspend and delayed autosuspend from console_write keeps system active in no_console_suspend case so put in forced suspend state and log all prints to be printed later.

probably needs to a condition check if (no_console_suspend)

Quoted 6 lines

uart_suspend_port() calls uart_change_pm() which should call the ->pm method of struct uart_ops (which is serial_omap_pm). ?What am I missing?

Also notice you're not calling serial_omap_pm() in the resume method below to change it back.

Quoted 7 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1140

Quoted 3 lines
drivers/tty/serial/omap-serial.c +1 -0
+ ? ? }
 ? ? ? return 0;
 ?}

Also, device wakeup capability should be checked and enabled/disabled in the suspend path (not only the runtime suspend path.)

ok.

Quoted 13 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1147

Quoted 10 lines
drivers/tty/serial/omap-serial.c +4 -3
-static int serial_omap_resume(struct platform_device *dev)
+static int serial_omap_resume(struct device *dev)
 ?{
- ? ? struct uart_omap_port *up = platform_get_drvdata(dev);
+ ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
 
- ? ? if (up)
+ ? ? if (up) {
 ? ? ? ? ? ? ? uart_resume_port(&serial_omap_reg, &up->port);
+ ? ? ? ? ? ? console_unlock();

Again, please describe locking in comments.

Quoted 3 lines

Also, what happens here if the console_trylock() in your suspend method failed?

need to add a flag to check and unlock
from return status of trylock.

Quoted 157 lines
Quoted 157 lines
drivers/tty/serial/omap-serial.c +38 -5
+ ? ? }
+
 ? ? ? return 0;
 ?}
 
@@ -1097,6 +1168,7 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 ? ? ? ? ? ? ? ? ? ? ? serial_omap_stop_rxdma(up);
 ? ? ? ? ? ? ? ? ? ? ? up->ier |= (UART_IER_RDI | UART_IER_RLSI);
 ? ? ? ? ? ? ? ? ? ? ? serial_out(up, UART_IER, up->ier);
+ ? ? ? ? ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? ? ? ? ? }
 ? ? ? ? ? ? ? return;
 ? ? ? }
@@ -1128,6 +1200,9 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 
 ?static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
 ?{
+ ? ? struct uart_omap_port *up = (struct uart_omap_port *)data;
+
+ ? ? serial_omap_port_disable(up);
 ? ? ? return;
 ?}
 
@@ -1135,6 +1210,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up)
 ?{
 ? ? ? int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? if (up->uart_dma.rx_dma_channel == -1) {
 ? ? ? ? ? ? ? ret = omap_request_dma(up->uart_dma.uart_dma_rx,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "UART Rx DMA",
@@ -1214,6 +1290,7 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
 ? ? ? ? ? ? ? serial_omap_stop_tx(&up->port);
 ? ? ? ? ? ? ? up->uart_dma.tx_dma_used = false;
 ? ? ? ? ? ? ? spin_unlock(&(up->uart_dma.tx_lock));
+ ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? } else {
 ? ? ? ? ? ? ? omap_stop_dma(up->uart_dma.tx_dma_channel);
 ? ? ? ? ? ? ? serial_omap_continue_tx(up);
@@ -1224,9 +1301,10 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
 
 ?static int serial_omap_probe(struct platform_device *pdev)
 ?{
- ? ? struct uart_omap_port ? *up;
+ ? ? struct uart_omap_port ? *up = NULL;
 ? ? ? struct resource ? ? ? ? *mem, *irq, *dma_tx, *dma_rx;
 ? ? ? struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+ ? ? struct omap_device *od;
 ? ? ? int ret = -ENOSPC;
 
 ? ? ? mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1276,12 +1354,20 @@ static int serial_omap_probe(struct platform_device *pdev)
 ? ? ? up->port.ops = &serial_omap_pops;
 ? ? ? up->port.line = pdev->id;
 
- ? ? up->port.membase = omap_up_info->membase;
- ? ? up->port.mapbase = omap_up_info->mapbase;
+ ? ? up->port.mapbase = mem->start;
+ ? ? up->port.membase = ioremap(mem->start, mem->end - mem->start);
+
+ ? ? if (!up->port.membase) {
+ ? ? ? ? ? ? dev_err(&pdev->dev, "can't ioremap UART\n");
+ ? ? ? ? ? ? ret = -ENOMEM;
+ ? ? ? ? ? ? goto err1;
+ ? ? }
+
 ? ? ? up->port.flags = omap_up_info->flags;
- ? ? up->port.irqflags = omap_up_info->irqflags;
 ? ? ? up->port.uartclk = omap_up_info->uartclk;
 ? ? ? up->uart_dma.uart_base = mem->start;
+ ? ? up->errata = omap_up_info->errata;
+ ? ? up->enable_wakeup = omap_up_info->enable_wakeup;
 
 ? ? ? if (omap_up_info->dma_enabled) {
 ? ? ? ? ? ? ? up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1295,18 +1381,36 @@ static int serial_omap_probe(struct platform_device *pdev)
 ? ? ? ? ? ? ? up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
 ? ? ? }
 
+ ? ? pm_runtime_use_autosuspend(&pdev->dev);
+ ? ? pm_runtime_set_autosuspend_delay(&pdev->dev,
+ ? ? ? ? ? ? ? ? ? ? OMAP_UART_AUTOSUSPEND_DELAY);
+
+ ? ? pm_runtime_enable(&pdev->dev);
+ ? ? pm_runtime_irq_safe(&pdev->dev);
+
+ ? ? if (omap_up_info->console_uart) {
+ ? ? ? ? ? ? od = to_omap_device(up->pdev);
+ ? ? ? ? ? ? omap_hwmod_idle(od->hwmods[0]);
+ ? ? ? ? ? ? serial_omap_port_enable(up);
+ ? ? ? ? ? ? serial_omap_port_disable(up);
+ ? ? }
+
 ? ? ? ui[pdev->id] = up;
 ? ? ? serial_omap_add_console_port(up);
 
 ? ? ? ret = uart_add_one_port(&serial_omap_reg, &up->port);
 ? ? ? if (ret != 0)
- ? ? ? ? ? ? goto do_release_region;
+ ? ? ? ? ? ? goto err1;
 
+ ? ? dev_set_drvdata(&pdev->dev, up);
 ? ? ? platform_set_drvdata(pdev, up);
+
 ? ? ? return 0;

?err:
? ? ? dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pdev->id, __func__, ret); +err1:
+ ? ? kfree(up);
?do_release_region:
? ? ? release_mem_region(mem->start, (mem->end - mem->start) + 1); ? ? ? return ret;

drivers/tty/serial/omap-serial.c +34 -0
@@ -1318,20 +1422,76 @@ static int serial_omap_remove(struct platform_device *dev)
 
 ? ? ? platform_set_drvdata(dev, NULL);
 ? ? ? if (up) {
+ ? ? ? ? ? ? pm_runtime_disable(&up->pdev->dev);
 ? ? ? ? ? ? ? uart_remove_one_port(&serial_omap_reg, &up->port);
 ? ? ? ? ? ? ? kfree(up);
 ? ? ? }
 ? ? ? return 0;
 ?}
 
+static void omap_uart_restore_context(struct uart_omap_port *up)
+{
+ ? ? u16 efr = 0;
+
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
+ ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ ? ? efr = serial_in(up, UART_EFR);
+ ? ? serial_out(up, UART_EFR, UART_EFR_ECB);
+ ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */
+ ? ? serial_out(up, UART_IER, 0x0);
+ ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ ? ? serial_out(up, UART_DLL, up->dll);
+ ? ? serial_out(up, UART_DLM, up->dlh);
+ ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */
+ ? ? serial_out(up, UART_IER, up->ier);
+ ? ? serial_out(up, UART_FCR, up->fcr);
+ ? ? serial_out(up, UART_LCR, 0x80);
+ ? ? serial_out(up, UART_MCR, up->mcr);
+ ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ ? ? serial_out(up, UART_EFR, efr);
+ ? ? serial_out(up, UART_LCR, up->lcr);
+ ? ? /* UART 16x mode */
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
+}
+
+static int omap_serial_runtime_suspend(struct device *dev)
+{
+ ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
+
+ ? ? if (!up)
+ ? ? ? ? ? ? goto done;
+
+ ? ? if (device_may_wakeup(dev))
Quoted 9 lines

drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1467

Quoted 3 lines
drivers/tty/serial/omap-serial.c +3 -0
+ ? ? ? ? ? ? up->enable_wakeup(up->pdev, true);
+ ? ? else
+ ? ? ? ? ? ? up->enable_wakeup(up->pdev, false);

I know the earlier code was doing it this way too, but an optimization would be to have the driver keep state whether the wakeups are enabled or disabled, so you don't have to keep calling this function (which can be expensive with the PRCM reads/writes.

if dynamically disabled from user space from sys-fs interface. it may not reflect disable_wakup immediately if internal state machine of wakeup is maintained within uart driver.

also need to modify the internals of this func pointer to use hmwod API's as commented above.

Quoted 3 lines

That state can also be used in the suspend path, which should also be managing wakeups.

ok.

Quoted 7 lines
Quoted 7 lines
drivers/tty/serial/omap-serial.c +7 -0
+done:
+ ? ? return 0;
+}
+
+static int omap_serial_runtime_resume(struct device *dev)
+{
+ ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
Quoted 9 lines

drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1477

Quoted 3 lines
drivers/tty/serial/omap-serial.c +3 -0
+
+ ? ? if (up)
+ ? ? ? ? ? ? omap_uart_restore_context(up);

You only need to restore context when returning from off-mode. ?You should be using omap_device_get_context_loss_count (called via pdata function pointer) for this. ?See the MMC driver or DSS driver for how this is done.

agree, will use that API.

--
Thanks,
Govindraj.R

Quoted 28 lines
Quoted 11 lines
drivers/tty/serial/omap-serial.c +10 -0
+ ? ? return 0;
+}
+
+static const struct dev_pm_ops omap_serial_dev_pm_ops = {
+ ? ? .suspend = serial_omap_suspend,
+ ? ? .resume = serial_omap_resume,
+ ? ? .runtime_suspend = omap_serial_runtime_suspend,
+ ? ? .runtime_resume = omap_serial_runtime_resume,
+};
+
 ?static struct platform_driver serial_omap_driver = {

drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1495

Quoted 10 lines
drivers/tty/serial/omap-serial.c +1 -3
 ? ? ? .probe ? ? ? ? ?= serial_omap_probe,
 ? ? ? .remove ? ? ? ? = serial_omap_remove,
-
- ? ? .suspend ? ? ? ?= serial_omap_suspend,
- ? ? .resume ? ? ? ? = serial_omap_resume,
 ? ? ? .driver ? ? ? ? = {
 ? ? ? ? ? ? ? .name ? = DRIVER_NAME,
+ ? ? ? ? ? ? .pm = &omap_serial_dev_pm_ops,
 ? ? ? },
 ?};

Kevin
--
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

#13 lore raw

PATCH v3 4/12 Serial: OMAP: Add runtime pm support for omap-serial driver

Quoted 53 lines · Govindraj
Quoted 42 lines · Kevin Hilman
Quoted 3 lines · Govindraj.R

Adapts omap-serial driver to use pm_runtime api's.

1.) Populate reg values to uart port which can be used for context restore.

Please make this part a separate patch.

Quoted 8 lines

2.) Moving context_restore func to driver from serial.c
3.) Adding port_enable/disable func to enable/disable given uart port. ? ? enable port using get_sync and disable using autosuspend. 4.) using runtime irq safe api to make get_sync be called from irq context.

This is great! ?we're almost there. ? Some minor comments below...

Quoted 23 lines

---

?arch/arm/mach-omap2/serial.c ? ? ? ? ? ? ? ? ?| ? 22 +++
?arch/arm/plat-omap/include/plat/omap-serial.h | ? ?2 +
?drivers/tty/serial/omap-serial.c ? ? ? ? ? ? ?| ?212 ++++++++++++++++++++++---

?3 files changed, 210 insertions(+), 26 deletions(-)

arch/arm/mach-omap2/serial.c +9 -0
index 8c1a4c7..1651c2c 100644
@@ -189,6 +189,27 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
 ? ? ? }
 ?}
 
+static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable)
+{
+ ? ? struct omap_uart_port_info *up = pdev->dev.platform_data;
+
+ ? ? /* Set or clear wake-enable bit */
+ ? ? if (up->wk_en && up->wk_mask) {
+ ? ? ? ? ? ? u32 v = __raw_readl(up->wk_en);
+ ? ? ? ? ? ? if (enable)
+ ? ? ? ? ? ? ? ? ? ? v |= up->wk_mask;
Quoted 9 lines

arch/arm/mach-omap2/serial.c static void omap_serial_fill_default_pads(struct omap_board_data *bdata) · line 204

Quoted 4 lines
arch/arm/mach-omap2/serial.c +4 -0
+ ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? v &= ~up->wk_mask;
+ ? ? ? ? ? ? __raw_writel(v, up->wk_en);
+ ? ? }

I think I asked this in previous series, but can't remember the answer now... ?can't we enable bits in the WKEN registers once at init time, and then just use omap_hwmod_[enable|disable]_wakeup() here?

Quoted 1 line

by default all bits are enabled in WKEN,

where default is the PRCM init code, yes.

Quoted 4 lines

I will use omap_hwmod_[enable|disable]_wakeup() api's

if these API's take care of WKEN regs, then no issue using the same.

No, these APIs only affect the module-level wakeup bit in the modules SYSCONFIG register (ENAWAKEUP bit.)

My question is assuming the PRCM WKEN bits are just left enabled, is simply toggling the modules SYSCONFIG.ENAWAKEUP bit enough to enable/disable module wakeups. I assume so, but have not validated it.

Quoted 352 lines
Quoted 48 lines
Quoted 48 lines
arch/arm/mach-omap2/serial.c +8 -0
+ ? ? /* Enable or clear io-pad wakeup */
+ ? ? if (enable)
+ ? ? ? ? ? ? omap_device_enable_ioring_wakeup(pdev);
+ ? ? else
+ ? ? ? ? ? ? omap_device_disable_ioring_wakeup(pdev);
+}
+
 ?static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned short num)
 ?{
@@ -332,6 +353,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 
 ? ? ? pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
 ? ? ? pdata->flags = UPF_BOOT_AUTOCONF;
+ ? ? pdata->enable_wakeup = omap_uart_wakeup_enable;
 ? ? ? if (bdata->id == omap_uart_con_id)
 ? ? ? ? ? ? ? pdata->console_uart = true;
 
arch/arm/plat-omap/include/plat/omap-serial.h +2 -0
index 2ca885b..ac30de8 100644
@@ -65,6 +65,7 @@ struct omap_uart_port_info {
 ? ? ? unsigned int ? ? ? ? ? ?errata;
 ? ? ? unsigned int ? ? ? ? ? ?console_uart;
 
+ ? ? void (*enable_wakeup)(struct platform_device *, bool);
 ? ? ? void __iomem *wk_st;
 ? ? ? void __iomem *wk_en;
 ? ? ? u32 wk_mask;
@@ -120,6 +121,7 @@ struct uart_omap_port {
 ? ? ? char ? ? ? ? ? ? ? ? ? ?name[20];
 ? ? ? unsigned long ? ? ? ? ? port_activity;
 ? ? ? unsigned int ? ? ? ? ? ?errata;
+ ? ? void (*enable_wakeup)(struct platform_device *, bool);
 ?};
 

?#endif /* __OMAP_SERIAL_H__ */

drivers/tty/serial/omap-serial.c +0 -0
index 47cadf4..897416f 100644
@@ -37,10 +37,14 @@

?#include <linux/clk.h>
?#include <linux/serial_core.h>
?#include <linux/irq.h>
+#include <linux/pm_runtime.h>

Quoted 10 lines

drivers/tty/serial/omap-serial.c line 47

Quoted 6 lines

?#include <plat/dma.h>
?#include <plat/dmtimer.h>
?#include <plat/omap-serial.h>

drivers/tty/serial/omap-serial.c +3 -0
+#include <plat/omap_device.h>
+
+#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

As Jon already pointed out, the HZ here is wrong. ?Please define this value in msecs.

corrected.

Quoted 6 lines
Quoted 6 lines

?static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];

drivers/tty/serial/omap-serial.c +0 -0
@@ -94,6 +98,17 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
 ? ? ? return port->uartclk/(baud * divisor);
 ?}
 
Quoted 17 lines

drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 110

Quoted 10 lines
drivers/tty/serial/omap-serial.c +10 -0
+static inline void serial_omap_port_disable(struct uart_omap_port *up)
+{
+ ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
+ ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
+}
+
+static inline void serial_omap_port_enable(struct uart_omap_port *up)
+{
+ ? ? pm_runtime_get_sync(&up->pdev->dev);
+}

These inlines are not needed. ?Please use runtime PM calls directly in the code. ?For _enable(), this is straight forward. ?For _disable() though, I don't think you want (or need) to _mark_last_busy() for every instance of omap_port_disable(). ?You only need to do this for ones TX/RX transactions...

Fine. will modify.

Quoted 17 lines

drivers/tty/serial/omap-serial.c static void serial_omap_enable_ms(struct uart_port *port) · line 132

Quoted 12 lines
drivers/tty/serial/omap-serial.c +3 -0
 ?static void serial_omap_stop_rxdma(struct uart_omap_port *up)
 ?{
 ? ? ? if (up->uart_dma.rx_dma_used) {
@@ -110,8 +125,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);
+
+ ? ? serial_omap_port_enable(up);
 ? ? ? up->ier |= UART_IER_MSI;
 ? ? ? serial_out(up, UART_IER, up->ier);
+ ? ? serial_omap_port_disable(up);

...for example, this one is not really activity based, so should probably just be pm_runtime_get_sync(), write the register, then pm_runtime_put() (async version.)

Quoted 3 lines

I didn't look at all the others below, but they should be looked at individually.

ok. I will check them.

Quoted 231 lines
Quoted 231 lines
drivers/tty/serial/omap-serial.c +23 -2
 ?}
 
 ?static void serial_omap_stop_tx(struct uart_port *port)
@@ -131,21 +149,26 @@ static void serial_omap_stop_tx(struct uart_port *port)
 ? ? ? ? ? ? ? up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
 ? ? ? }
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? if (up->ier & UART_IER_THRI) {
 ? ? ? ? ? ? ? up->ier &= ~UART_IER_THRI;
 ? ? ? ? ? ? ? serial_out(up, UART_IER, up->ier);
 ? ? ? }
+
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static void serial_omap_stop_rx(struct uart_port *port)
 ?{
 ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? 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);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static inline void receive_chars(struct uart_omap_port *up, int *status)
@@ -261,8 +284,10 @@ static void serial_omap_start_tx(struct uart_port *port)
 ? ? ? unsigned int start;
 ? ? ? int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? if (!up->use_dma) {
 ? ? ? ? ? ? ? serial_omap_enable_ier_thri(up);
+ ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? ? ? ? ? return;
 ? ? ? }
 
@@ -354,9 +379,12 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
 ? ? ? unsigned int iir, lsr;
 ? ? ? unsigned long flags;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? iir = serial_in(up, UART_IIR);
- ? ? if (iir & UART_IIR_NO_INT)
+ ? ? if (iir & UART_IIR_NO_INT) {
+ ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? ? ? ? ? return IRQ_NONE;
+ ? ? }
 
 ? ? ? spin_lock_irqsave(&up->port.lock, flags);
 ? ? ? lsr = serial_in(up, UART_LSR);
@@ -378,6 +406,8 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
 ? ? ? ? ? ? ? transmit_chars(up);
 
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
+ ? ? serial_omap_port_disable(up);
+
 ? ? ? up->port_activity = jiffies;
 ? ? ? return IRQ_HANDLED;
 ?}
@@ -388,11 +418,12 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
 ? ? ? unsigned long flags = 0;
 ? ? ? unsigned int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
 ? ? ? spin_lock_irqsave(&up->port.lock, flags);
 ? ? ? ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
-
+ ? ? serial_omap_port_disable(up);
 ? ? ? return ret;
 ?}
 
@@ -402,7 +433,10 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
 ? ? ? unsigned char status;
 ? ? ? unsigned int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? status = check_modem_status(up);
+ ? ? serial_omap_port_disable(up);
+
 ? ? ? dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
 
 ? ? ? if (status & UART_MSR_DCD)
@@ -434,7 +468,9 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
 ? ? ? ? ? ? ? mcr |= UART_MCR_LOOP;
 
 ? ? ? mcr |= up->mcr;
+ ? ? serial_omap_port_enable(up);
 ? ? ? serial_out(up, UART_MCR, mcr);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -443,6 +479,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
 ? ? ? unsigned long flags = 0;
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+ ? ? serial_omap_port_enable(up);
 ? ? ? spin_lock_irqsave(&up->port.lock, flags);
 ? ? ? if (break_state == -1)
 ? ? ? ? ? ? ? up->lcr |= UART_LCR_SBC;
@@ -450,6 +487,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
 ? ? ? ? ? ? ? up->lcr &= ~UART_LCR_SBC;
 ? ? ? serial_out(up, UART_LCR, up->lcr);
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static int serial_omap_startup(struct uart_port *port)
@@ -468,6 +506,7 @@ static int serial_omap_startup(struct uart_port *port)
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
 
+ ? ? serial_omap_port_enable(up);

? ? ? /*
? ? ? ?* Clear the FIFO buffers and disable them. ? ? ? ?* (they will be reenabled in set_termios())

drivers/tty/serial/omap-serial.c +0 -0
@@ -523,6 +562,7 @@ static int serial_omap_startup(struct uart_port *port)

? ? ? /* Enable module level wake up */
? ? ? serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);

+ ? ? serial_omap_port_disable(up);
? ? ? up->port_activity = jiffies;
? ? ? return 0;
?}

drivers/tty/serial/omap-serial.c +2 -0
@@ -533,6 +573,8 @@ static void serial_omap_shutdown(struct uart_port *port)
 ? ? ? unsigned long flags = 0;
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+
+ ? ? serial_omap_port_enable(up);

? ? ? /*
? ? ? ?* Disable interrupts from this port
? ? ? ?*/

drivers/tty/serial/omap-serial.c +5 -0
@@ -566,6 +608,7 @@ static void serial_omap_shutdown(struct uart_port *port)
 ? ? ? ? ? ? ? ? ? ? ? up->uart_dma.rx_buf_dma_phys);
 ? ? ? ? ? ? ? up->uart_dma.rx_buf = NULL;
 ? ? ? }
+ ? ? serial_omap_port_disable(up);
 ? ? ? free_irq(up->port.irq, up);
 ?}
 
@@ -671,6 +714,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
 ? ? ? quot = serial_omap_get_divisor(port, baud);
 
+ ? ? up->dll = quot & 0xff;
+ ? ? up->dlh = quot >> 8;
+ ? ? up->mdr1 = UART_OMAP_MDR1_DISABLE;
+

? ? ? up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 | ? ? ? ? ? ? ? ? ? ? ? UART_FCR_ENABLE_FIFO;
? ? ? if (up->use_dma)

drivers/tty/serial/omap-serial.c +0 -0
@@ -680,6 +727,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,

? ? ? ?* Ok, we're now changing the port state. Do it with ? ? ? ?* interrupts disabled.
? ? ? ?*/
+ ? ? serial_omap_port_enable(up);
? ? ? spin_lock_irqsave(&up->port.lock, flags);

? ? ? /*

drivers/tty/serial/omap-serial.c +0 -0
@@ -723,6 +771,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? ? ? ? ? up->ier |= UART_IER_MSI;
 ? ? ? serial_out(up, UART_IER, up->ier);

? ? ? serial_out(up, UART_LCR, cval); ? ? ? ? /* reset DLAB */
+ ? ? up->lcr = cval;

? ? ? /* FIFOs and DMA Settings */

drivers/tty/serial/omap-serial.c +0 -0
@@ -758,8 +807,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? serial_out(up, UART_MCR, up->mcr);
 

? ? ? /* Protocol, Baud Rate, and Interrupt Settings */ -
- ? ? serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

? ? ? up->efr = serial_in(up, UART_EFR);

drivers/tty/serial/omap-serial.c +3 -3
@@ -769,8 +817,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? serial_out(up, UART_IER, 0);
 ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 
- ? ? serial_out(up, UART_DLL, quot & 0xff); ? ? ? ? ?/* LS of divisor */
- ? ? serial_out(up, UART_DLM, quot >> 8); ? ? ? ? ? ?/* MS of divisor */
+ ? ? serial_out(up, UART_DLL, up->dll); ? ? ?/* LS of divisor */
+ ? ? serial_out(up, UART_DLM, up->dlh); ? ? ?/* MS of divisor */
 
 ? ? ? serial_out(up, UART_LCR, 0);
 ? ? ? serial_out(up, UART_IER, up->ier);
@@ -780,9 +828,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? serial_out(up, UART_LCR, cval);
 
 ? ? ? if (baud > 230400 && baud != 3000000)
- ? ? ? ? ? ? serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
+ ? ? ? ? ? ? up->mdr1 = UART_OMAP_MDR1_13X_MODE;

? ? ? else
- ? ? ? ? ? ? serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
+ ? ? ? ? ? ? up->mdr1 = UART_OMAP_MDR1_16X_MODE;
+
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1)

? ? ? /* Hardware Flow Control Configuration */

drivers/tty/serial/omap-serial.c +3 -0
@@ -810,6 +860,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 ? ? ? ? ? ? ? serial_omap_configure_xonxoff(up, termios);
 
 ? ? ? spin_unlock_irqrestore(&up->port.lock, flags);
+ ? ? serial_omap_port_disable(up);
 ? ? ? dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
 ?}
 
@@ -821,6 +872,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
 ? ? ? unsigned char efr;
 
 ? ? ? dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+
+ ? ? serial_omap_port_enable(up);
 ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 ? ? ? efr = serial_in(up, UART_EFR);
 ? ? ? serial_out(up, UART_EFR, efr | UART_EFR_ECB);
@@ -830,6 +883,10 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
 ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 ? ? ? serial_out(up, UART_EFR, efr);
 ? ? ? serial_out(up, UART_LCR, 0);
Quoted 9 lines

drivers/tty/serial/omap-serial.c serial_omap_pm(struct uart_port *port, unsigned int state, · line 889

Quoted 4 lines
drivers/tty/serial/omap-serial.c +4 -0
+ ? ? if (state)
+ ? ? ? ? ? ? pm_runtime_put_sync(&up->pdev->dev);
+ ? ? else
+ ? ? ? ? ? ? serial_omap_port_disable(up);

OK, so this boils down to either a _put_sync() or a _mark_last_busy + _put_autosuspend(), depending on whether this is suspending or resuming, right?

Quoted 8 lines

yes also during bootup.
disable the ports immediately that are not used during bootup.

Quoted 1 line

Why the difference?

Need to put the ports down immediately during system wide suspend other wise autosuspend delay will prevent system to enter suspend state immediately.

OK, as I stated above. All of these serial_omap_port_disable() calls need to be removed and replaced with runtime PM API calls directly.

Here, I think it can always be a basic _put() for suspend and _get_sync() for resume.

Incendentally, the 'else' clause of that code (state == 0) should be the resume case, but you're calling _disable(). That doesn't look right.

Quoted 76 lines
Quoted 67 lines
Quoted 67 lines
drivers/tty/serial/omap-serial.c +9 -2
 ?}
 
 ?static void serial_omap_release_port(struct uart_port *port)
@@ -907,25 +964,31 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
 ?static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
 ?{
 ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ ? ? serial_omap_port_enable(up);
 ? ? ? wait_for_xmitr(up);
 ? ? ? serial_out(up, UART_TX, ch);
+ ? ? serial_omap_port_disable(up);
 ?}
 
 ?static int serial_omap_poll_get_char(struct uart_port *port)
 ?{
 ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port;
- ? ? unsigned int status = serial_in(up, UART_LSR);
+ ? ? unsigned int status;
 
+ ? ? serial_omap_port_enable(up);
+ ? ? status = serial_in(up, UART_LSR);
 ? ? ? if (!(status & UART_LSR_DR))
 ? ? ? ? ? ? ? return NO_POLL_CHAR;
 
- ? ? return serial_in(up, UART_RX);
+ ? ? status = serial_in(up, UART_RX);
+ ? ? serial_omap_port_disable(up);
+ ? ? return status;
 ?}
 

?#endif /* CONFIG_CONSOLE_POLL */

?#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-
?static struct uart_omap_port *serial_omap_console_ports[4];

?static struct uart_driver serial_omap_reg;

drivers/tty/serial/omap-serial.c +0 -0
@@ -955,6 +1018,8 @@ serial_omap_console_write(struct console *co, const char *s,

? ? ? else
? ? ? ? ? ? ? spin_lock(&up->port.lock);

+ ? ? serial_omap_port_enable(up);
+
? ? ? /*
? ? ? ?* First save the IER then disable the interrupts ? ? ? ?*/

drivers/tty/serial/omap-serial.c +3 -3
@@ -979,6 +1044,7 @@ serial_omap_console_write(struct console *co, const char *s,
 ? ? ? if (up->msr_saved_flags)
 ? ? ? ? ? ? ? check_modem_status(up);
 
+ ? ? serial_omap_port_disable(up);
 ? ? ? if (locked)
 ? ? ? ? ? ? ? spin_unlock(&up->port.lock);
 ? ? ? local_irq_restore(flags);
@@ -1061,22 +1127,27 @@ static struct uart_driver serial_omap_reg = {
 ? ? ? .cons ? ? ? ? ? = OMAP_CONSOLE,
 ?};
 
-static int
-serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+static int serial_omap_suspend(struct device *dev)
 ?{
- ? ? struct uart_omap_port *up = platform_get_drvdata(pdev);
+ ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
 
Quoted 8 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1136

Quoted 4 lines
drivers/tty/serial/omap-serial.c +2 -1
- ? ? if (up)
+ ? ? if (up) {
 ? ? ? ? ? ? ? uart_suspend_port(&serial_omap_reg, &up->port);
+ ? ? ? ? ? ? console_trylock();

This locking needs to be explained. ?Why it is needed, but very importantly, why you are not checking the return value of the _trylock()

Quoted 2 lines

any print after this point can result in failure of immediate system suspending due to delayed autosuspend from omap_console_write.

I mean explained in the changelog and preferrably the code.

Also, technically speaking, it's not until the clocks are cut (after the devices runtime_suspend callback is called) that UART writes will fault.

Quoted 13 lines

log prints after uart suspend and print them during resume.

Quoted 4 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1137

Quoted 1 line
drivers/tty/serial/omap-serial.c +1 -0
+ ? ? ? ? ? ? serial_omap_pm(&up->port, 3, 0);

Why is this call needed?

Actually this is needed if no_console_suspend is used, for that case the console will remain active since serial_omap_pm is not getting called from serial_core and port is not suspended immediately with put_sync.

Quoted 5 lines

prints during system wide suspend and delayed autosuspend from console_write keeps system active in no_console_suspend case so put in forced suspend state and log all prints to be printed later.

probably needs to a condition check if (no_console_suspend)

No. If the user has requested no_console_suspend, then the user should expect that the UARTs remain active and thus prevent low-power.

Quoted 204 lines
Quoted 6 lines

uart_suspend_port() calls uart_change_pm() which should call the ->pm method of struct uart_ops (which is serial_omap_pm). ?What am I missing?

Also notice you're not calling serial_omap_pm() in the resume method below to change it back.

Quoted 7 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1140

Quoted 3 lines
drivers/tty/serial/omap-serial.c +1 -0
+ ? ? }
 ? ? ? return 0;
 ?}

Also, device wakeup capability should be checked and enabled/disabled in the suspend path (not only the runtime suspend path.)

ok.

Quoted 13 lines

drivers/tty/serial/omap-serial.c static struct uart_driver serial_omap_reg = { · line 1147

Quoted 10 lines
drivers/tty/serial/omap-serial.c +4 -3
-static int serial_omap_resume(struct platform_device *dev)
+static int serial_omap_resume(struct device *dev)
 ?{
- ? ? struct uart_omap_port *up = platform_get_drvdata(dev);
+ ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
 
- ? ? if (up)
+ ? ? if (up) {
 ? ? ? ? ? ? ? uart_resume_port(&serial_omap_reg, &up->port);
+ ? ? ? ? ? ? console_unlock();

Again, please describe locking in comments.

Quoted 3 lines

Also, what happens here if the console_trylock() in your suspend method failed?

need to add a flag to check and unlock
from return status of trylock.

Quoted 157 lines
Quoted 157 lines
drivers/tty/serial/omap-serial.c +38 -5
+ ? ? }
+
 ? ? ? return 0;
 ?}
 
@@ -1097,6 +1168,7 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 ? ? ? ? ? ? ? ? ? ? ? serial_omap_stop_rxdma(up);
 ? ? ? ? ? ? ? ? ? ? ? up->ier |= (UART_IER_RDI | UART_IER_RLSI);
 ? ? ? ? ? ? ? ? ? ? ? serial_out(up, UART_IER, up->ier);
+ ? ? ? ? ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? ? ? ? ? }
 ? ? ? ? ? ? ? return;
 ? ? ? }
@@ -1128,6 +1200,9 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 
 ?static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
 ?{
+ ? ? struct uart_omap_port *up = (struct uart_omap_port *)data;
+
+ ? ? serial_omap_port_disable(up);
 ? ? ? return;
 ?}
 
@@ -1135,6 +1210,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up)
 ?{
 ? ? ? int ret = 0;
 
+ ? ? serial_omap_port_enable(up);
 ? ? ? if (up->uart_dma.rx_dma_channel == -1) {
 ? ? ? ? ? ? ? ret = omap_request_dma(up->uart_dma.uart_dma_rx,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "UART Rx DMA",
@@ -1214,6 +1290,7 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
 ? ? ? ? ? ? ? serial_omap_stop_tx(&up->port);
 ? ? ? ? ? ? ? up->uart_dma.tx_dma_used = false;
 ? ? ? ? ? ? ? spin_unlock(&(up->uart_dma.tx_lock));
+ ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? } else {
 ? ? ? ? ? ? ? omap_stop_dma(up->uart_dma.tx_dma_channel);
 ? ? ? ? ? ? ? serial_omap_continue_tx(up);
@@ -1224,9 +1301,10 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
 
 ?static int serial_omap_probe(struct platform_device *pdev)
 ?{
- ? ? struct uart_omap_port ? *up;
+ ? ? struct uart_omap_port ? *up = NULL;
 ? ? ? struct resource ? ? ? ? *mem, *irq, *dma_tx, *dma_rx;
 ? ? ? struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+ ? ? struct omap_device *od;
 ? ? ? int ret = -ENOSPC;
 
 ? ? ? mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1276,12 +1354,20 @@ static int serial_omap_probe(struct platform_device *pdev)
 ? ? ? up->port.ops = &serial_omap_pops;
 ? ? ? up->port.line = pdev->id;
 
- ? ? up->port.membase = omap_up_info->membase;
- ? ? up->port.mapbase = omap_up_info->mapbase;
+ ? ? up->port.mapbase = mem->start;
+ ? ? up->port.membase = ioremap(mem->start, mem->end - mem->start);
+
+ ? ? if (!up->port.membase) {
+ ? ? ? ? ? ? dev_err(&pdev->dev, "can't ioremap UART\n");
+ ? ? ? ? ? ? ret = -ENOMEM;
+ ? ? ? ? ? ? goto err1;
+ ? ? }
+
 ? ? ? up->port.flags = omap_up_info->flags;
- ? ? up->port.irqflags = omap_up_info->irqflags;
 ? ? ? up->port.uartclk = omap_up_info->uartclk;
 ? ? ? up->uart_dma.uart_base = mem->start;
+ ? ? up->errata = omap_up_info->errata;
+ ? ? up->enable_wakeup = omap_up_info->enable_wakeup;
 
 ? ? ? if (omap_up_info->dma_enabled) {
 ? ? ? ? ? ? ? up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1295,18 +1381,36 @@ static int serial_omap_probe(struct platform_device *pdev)
 ? ? ? ? ? ? ? up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
 ? ? ? }
 
+ ? ? pm_runtime_use_autosuspend(&pdev->dev);
+ ? ? pm_runtime_set_autosuspend_delay(&pdev->dev,
+ ? ? ? ? ? ? ? ? ? ? OMAP_UART_AUTOSUSPEND_DELAY);
+
+ ? ? pm_runtime_enable(&pdev->dev);
+ ? ? pm_runtime_irq_safe(&pdev->dev);
+
+ ? ? if (omap_up_info->console_uart) {
+ ? ? ? ? ? ? od = to_omap_device(up->pdev);
+ ? ? ? ? ? ? omap_hwmod_idle(od->hwmods[0]);
+ ? ? ? ? ? ? serial_omap_port_enable(up);
+ ? ? ? ? ? ? serial_omap_port_disable(up);
+ ? ? }
+
 ? ? ? ui[pdev->id] = up;
 ? ? ? serial_omap_add_console_port(up);
 
 ? ? ? ret = uart_add_one_port(&serial_omap_reg, &up->port);
 ? ? ? if (ret != 0)
- ? ? ? ? ? ? goto do_release_region;
+ ? ? ? ? ? ? goto err1;
 
+ ? ? dev_set_drvdata(&pdev->dev, up);
 ? ? ? platform_set_drvdata(pdev, up);
+
 ? ? ? return 0;

?err:
? ? ? dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pdev->id, __func__, ret); +err1:
+ ? ? kfree(up);
?do_release_region:
? ? ? release_mem_region(mem->start, (mem->end - mem->start) + 1); ? ? ? return ret;

drivers/tty/serial/omap-serial.c +34 -0
@@ -1318,20 +1422,76 @@ static int serial_omap_remove(struct platform_device *dev)
 
 ? ? ? platform_set_drvdata(dev, NULL);
 ? ? ? if (up) {
+ ? ? ? ? ? ? pm_runtime_disable(&up->pdev->dev);
 ? ? ? ? ? ? ? uart_remove_one_port(&serial_omap_reg, &up->port);
 ? ? ? ? ? ? ? kfree(up);
 ? ? ? }
 ? ? ? return 0;
 ?}
 
+static void omap_uart_restore_context(struct uart_omap_port *up)
+{
+ ? ? u16 efr = 0;
+
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
+ ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ ? ? efr = serial_in(up, UART_EFR);
+ ? ? serial_out(up, UART_EFR, UART_EFR_ECB);
+ ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */
+ ? ? serial_out(up, UART_IER, 0x0);
+ ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ ? ? serial_out(up, UART_DLL, up->dll);
+ ? ? serial_out(up, UART_DLM, up->dlh);
+ ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */
+ ? ? serial_out(up, UART_IER, up->ier);
+ ? ? serial_out(up, UART_FCR, up->fcr);
+ ? ? serial_out(up, UART_LCR, 0x80);
+ ? ? serial_out(up, UART_MCR, up->mcr);
+ ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ ? ? serial_out(up, UART_EFR, efr);
+ ? ? serial_out(up, UART_LCR, up->lcr);
+ ? ? /* UART 16x mode */
+ ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
+}
+
+static int omap_serial_runtime_suspend(struct device *dev)
+{
+ ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
+
+ ? ? if (!up)
+ ? ? ? ? ? ? goto done;
+
+ ? ? if (device_may_wakeup(dev))
Quoted 9 lines

drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1467

Quoted 3 lines
drivers/tty/serial/omap-serial.c +3 -0
+ ? ? ? ? ? ? up->enable_wakeup(up->pdev, true);
+ ? ? else
+ ? ? ? ? ? ? up->enable_wakeup(up->pdev, false);

I know the earlier code was doing it this way too, but an optimization would be to have the driver keep state whether the wakeups are enabled or disabled, so you don't have to keep calling this function (which can be expensive with the PRCM reads/writes.

Quoted 3 lines

if dynamically disabled from user space from sys-fs interface. it may not reflect disable_wakup immediately if internal state machine of wakeup is maintained within uart driver.

Why does that matter? It does not need to take effect immedately, it only needs to take effect on suspend.

Just update internal state whenever you change the hardware, and whenver you're about to change the hardware again, check device_may_wakeup() and check the driver's internal state.

Quoted 2 lines

also need to modify the internals of this func pointer to use hmwod API's as commented above.

OK

#14 lore raw

PATCH v3 5/12 OMAP: Serial: Hold console lock for console usage.

In reply to Govindraj.R

Acquire console lock before enabling and writing to console-uart to avoid any recursive prints from console write.
for ex:

        --> printk
          --> uart_console_write
            --> get_sync
              --> printk from omap_device enable
                --> uart_console write

Use RPM_SUSPENDING check to avoid below scenario during bootup As during bootup console_lock is not available.

       --> uart_add_one_port
           --> console_register
               --> console_lock
                --> console_unlock
                     --> call_console_drivers (here yet console_lock is not released)
                          --> uart_console_write
---
 drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
 1 files changed, 19 insertions(+), 1 deletions(-)
drivers/tty/serial/omap-serial.c +19 -1
index 897416f..ee94291 100644
@@ -1008,7 +1008,22 @@ serial_omap_console_write(struct console *co, const char *s,
 	struct uart_omap_port *up = serial_omap_console_ports[co->index];
 	unsigned long flags;
 	unsigned int ier;
-	int locked = 1;
+	int console_lock = 0, locked = 1;
+
+	if (console_trylock())
+		console_lock = 1;
+
+	/*
+	 * If console_lock is not available and we are in suspending
+	 * state then we can avoid the console usage scenario
+	 * as this may introduce recursive prints.
+	 * Basically this scenario occurs during boot while
+	 * printing debug bootlogs.
+	 */
+
+	if (!console_lock &&
+		up->pdev->dev.power.runtime_status == RPM_SUSPENDING)
+		return;
 
 	local_irq_save(flags);
 	if (up->port.sysrq)
@@ -1044,6 +1059,9 @@ serial_omap_console_write(struct console *co, const char *s,
 	if (up->msr_saved_flags)
 		check_modem_status(up);
 
+	if (console_lock)
+		console_unlock();
+
 	serial_omap_port_disable(up);
 	if (locked)
 		spin_unlock(&up->port.lock);
Signature · 1 line
1.7.0.4
#15 lore raw

PATCH v3 5/12 OMAP: Serial: Hold console lock for console usage.

Quoted 29 lines · Govindraj.R

Acquire console lock before enabling and writing to console-uart to avoid any recursive prints from console write.
for ex:

        --> printk
          --> uart_console_write
            --> get_sync
              --> printk from omap_device enable
                --> uart_console write

Use RPM_SUSPENDING check to avoid below scenario during bootup As during bootup console_lock is not available.

       --> uart_add_one_port
           --> console_register
               --> console_lock
                --> console_unlock
                     --> call_console_drivers (here yet console_lock is not released)
                          --> uart_console_write
---
 drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
 1 files changed, 19 insertions(+), 1 deletions(-)
drivers/tty/serial/omap-serial.c +0 -0
index 897416f..ee94291 100644

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1014

Quoted 8 lines
drivers/tty/serial/omap-serial.c +4 -1
@@ -1008,7 +1008,22 @@ serial_omap_console_write(struct console *co, const char *s,
 	struct uart_omap_port *up = serial_omap_console_ports[co->index];
 	unsigned long flags;
 	unsigned int ier;
-	int locked = 1;
+	int console_lock = 0, locked = 1;
+
+	if (console_trylock())
+		console_lock = 1;

So now we take the console lock on *every* console write? Even if the
device is not about to be idled? This is rather over-protective, don't
you think?

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1018

Quoted 3 lines
drivers/tty/serial/omap-serial.c +3 -0
+	/*
+	 * If console_lock is not available and we are in suspending
+	 * state then we can avoid the console usage scenario

s/in suspending state/runtime suspending/

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1021

Quoted 3 lines
drivers/tty/serial/omap-serial.c +3 -0
+	 * as this may introduce recursive prints.
+	 * Basically this scenario occurs during boot while
+	 * printing debug bootlogs.

The exact scenario for triggering this still not well described, and thus still I don't get it.

I still don't fully understand this problem, but if it's isolated to runtime suspending, maybe you need a console lock in the runtime_suspend path (like you already have in the static suspend path.)

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1026

Quoted 5 lines
drivers/tty/serial/omap-serial.c +5 -0
+	 */
+
+	if (!console_lock &&
+		up->pdev->dev.power.runtime_status == RPM_SUSPENDING)
+		return;

Assuming this was a printk, it's now lost, right? Not sure that's an
acceptable solution.

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1067

Quoted 12 lines
drivers/tty/serial/omap-serial.c +3 -0
 	local_irq_save(flags);
 	if (up->port.sysrq)
@@ -1044,6 +1059,9 @@ serial_omap_console_write(struct console *co, const char *s,
 	if (up->msr_saved_flags)
 		check_modem_status(up);
 
+	if (console_lock)
+		console_unlock();
+
 	serial_omap_port_disable(up);
 	if (locked)
 		spin_unlock(&up->port.lock);

Kevin

#16 lore raw

PATCH v3 5/12 OMAP: Serial: Hold console lock for console usage.

Quoted 35 lines · Kevin Hilman
Quoted 33 lines · Govindraj.R

Acquire console lock before enabling and writing to console-uart to avoid any recursive prints from console write.
for ex:
? ? ? ? --> printk
? ? ? ? ? --> uart_console_write
? ? ? ? ? ? --> get_sync
? ? ? ? ? ? ? --> printk from omap_device enable
? ? ? ? ? ? ? ? --> uart_console write

Use RPM_SUSPENDING check to avoid below scenario during bootup
As during bootup console_lock is not available.
? ? ? ?--> uart_add_one_port
? ? ? ? ? ?--> console_register
? ? ? ? ? ? ? ?--> console_lock
? ? ? ? ? ? ? ? --> console_unlock
? ? ? ? ? ? ? ? ? ? ?--> call_console_drivers (here yet console_lock is not released) ? ? ? ? ? ? ? ? ? ? ? ? ? --> uart_console_write

---
?drivers/tty/serial/omap-serial.c | ? 20 +++++++++++++++++++- ?1 files changed, 19 insertions(+), 1 deletions(-)

drivers/tty/serial/omap-serial.c +0 -1
index 897416f..ee94291 100644
@@ -1008,7 +1008,22 @@ serial_omap_console_write(struct console *co, const char *s,
 ? ? ? struct uart_omap_port *up = serial_omap_console_ports[co->index];
 ? ? ? unsigned long flags;
 ? ? ? unsigned int ier;
- ? ? int locked = 1;
Quoted 9 lines

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1014

Quoted 4 lines
drivers/tty/serial/omap-serial.c +4 -0
+ ? ? int console_lock = 0, locked = 1;
+
+ ? ? if (console_trylock())
+ ? ? ? ? ? ? console_lock = 1;

So now we take the console lock on *every* console write? ?Even if the device is not about to be idled? ? This is rather over-protective, don't you think?

This scenario is because of print from omap_uart_console_write --> get_sync --> omap_enable_enable trying to print worst activate or deactivate latency some times.

will result in recursive print scenario.

holding console lock will only ensure that the print from get_sync gets logged to be printed later to console.

Quoted 5 lines

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1017

Quoted 3 lines
drivers/tty/serial/omap-serial.c +3 -0
+ ? ? /*
+ ? ? ?* If console_lock is not available and we are in suspending
+ ? ? ?* state then we can avoid the console usage scenario

s/in suspending state/runtime suspending/

ok.

Quoted 8 lines

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1020

Quoted 4 lines
drivers/tty/serial/omap-serial.c +3 -0
+ ? ? ?* as this may introduce recursive prints.
+ ? ? ?* Basically this scenario occurs during boot while
+ ? ? ?* printing debug bootlogs.

The exact scenario for triggering this still not well described, and thus still I don't get it.

scenario is same as said above.

omap_uart_console_write --> get_sync --> omap_device

printk worst activate latency calls omap_uart_console write.

after boot up we have access to console lock, but during boot up we don't have console lock available and results in printk recursiveness.

Quoted 1 line

I still don't fully understand this problem,

basically its due to recursive printk during bootup and also after bootup as said above.

Quoted 3 lines

but if it's isolated to
runtime suspending, maybe you need a console lock in the runtime_suspend path (like you already have in the static suspend path.)

console_lock in runtime_suspend will not help
during bootup and due to printk emerging out from
omap_device enable after system bootup.

Quoted 10 lines

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1025

Quoted 6 lines
drivers/tty/serial/omap-serial.c +5 -0
+ ? ? ?*/
+
+ ? ? if (!console_lock &&
+ ? ? ? ? ? ? up->pdev->dev.power.runtime_status == RPM_SUSPENDING)
+ ? ? ? ? ? ? return;

Assuming this was a printk, it's now lost, right? ? Not sure that's an acceptable solution.

AFAIK it gets logged prints later.

to summarize holding console lock helps after bootup since during boot up console lock is not available need to use above runtime_status check.

--
Thanks,
Govindraj.R

Quoted 19 lines

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1067

Quoted 12 lines
drivers/tty/serial/omap-serial.c +3 -0
 ? ? ? local_irq_save(flags);
 ? ? ? if (up->port.sysrq)
@@ -1044,6 +1059,9 @@ serial_omap_console_write(struct console *co, const char *s,
 ? ? ? if (up->msr_saved_flags)
 ? ? ? ? ? ? ? check_modem_status(up);
 
+ ? ? if (console_lock)
+ ? ? ? ? ? ? console_unlock();
+
 ? ? ? serial_omap_port_disable(up);
 ? ? ? if (locked)
 ? ? ? ? ? ? ? spin_unlock(&up->port.lock);

Kevin
--
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

#17 lore raw

PATCH v3 5/12 OMAP: Serial: Hold console lock for console usage.

Quoted 46 lines · Govindraj
Quoted 35 lines · Kevin Hilman
Quoted 33 lines · Govindraj.R

Acquire console lock before enabling and writing to console-uart to avoid any recursive prints from console write.
for ex:
? ? ? ? --> printk
? ? ? ? ? --> uart_console_write
? ? ? ? ? ? --> get_sync
? ? ? ? ? ? ? --> printk from omap_device enable
? ? ? ? ? ? ? ? --> uart_console write

Use RPM_SUSPENDING check to avoid below scenario during bootup
As during bootup console_lock is not available.
? ? ? ?--> uart_add_one_port
? ? ? ? ? ?--> console_register
? ? ? ? ? ? ? ?--> console_lock
? ? ? ? ? ? ? ? --> console_unlock
? ? ? ? ? ? ? ? ? ? ?--> call_console_drivers (here yet console_lock is not released) ? ? ? ? ? ? ? ? ? ? ? ? ? --> uart_console_write

---
?drivers/tty/serial/omap-serial.c | ? 20 +++++++++++++++++++- ?1 files changed, 19 insertions(+), 1 deletions(-)

drivers/tty/serial/omap-serial.c +0 -1
index 897416f..ee94291 100644
@@ -1008,7 +1008,22 @@ serial_omap_console_write(struct console *co, const char *s,
 ? ? ? struct uart_omap_port *up = serial_omap_console_ports[co->index];
 ? ? ? unsigned long flags;
 ? ? ? unsigned int ier;
- ? ? int locked = 1;
Quoted 9 lines

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1014

Quoted 4 lines
drivers/tty/serial/omap-serial.c +4 -0
+ ? ? int console_lock = 0, locked = 1;
+
+ ? ? if (console_trylock())
+ ? ? ? ? ? ? console_lock = 1;

So now we take the console lock on *every* console write? ?Even if the device is not about to be idled? ? This is rather over-protective, don't you think?

Quoted 8 lines

This scenario is because of print from omap_uart_console_write --> get_sync --> omap_enable_enable trying to print worst activate or deactivate latency some times.

will result in recursive print scenario.

holding console lock will only ensure that the print from get_sync gets logged to be printed later to console.

Yes, but my problem is you now hold a lock for *every* console write, even when the UART is not in the process of being enabled/disabled.

The point is that it should only be held when you're about to disable the UART (or you know it's already disabled), and the point where you know this is exactly at the .runtime_suspend callback.

Quoted 13 lines
Quoted 5 lines

drivers/tty/serial/omap-serial.c serial_omap_console_write(struct console *co, const char *s, · line 1017

Quoted 3 lines
drivers/tty/serial/omap-serial.c +3 -0
+ ? ? /*
+ ? ? ?* If console_lock is not available and we are in suspending
+ ? ? ?* state then we can avoid the console usage scenario

s/in suspending state/runtime suspending/

ok.

Quoted 5 lines
Quoted 4 lines
drivers/tty/serial/omap-serial.c +3 -0
+ ? ? ?* as this may introduce recursive prints.
+ ? ? ?* Basically this scenario occurs during boot while
+ ? ? ?* printing debug bootlogs.
Quoted 5 lines
Quoted 3 lines

The exact scenario for triggering this still not well described, and thus still I don't get it.

scenario is same as said above.

Which as I said, is not well described.

Quoted 7 lines

omap_uart_console_write --> get_sync --> omap_device

printk worst activate latency calls omap_uart_console write.

after boot up we have access to console lock, but during boot up we don't have console lock available and results in printk recursiveness.

Then leave UART runtime PM disabled during bootup.

Quoted 4 lines
Quoted 1 line

I still don't fully understand this problem,

basically its due to recursive printk during bootup and also after bootup as said above.

You've said all of these things, but are mixing them together in a way that is very difficult to understand.

Please separate out the boot-up problem from the recursive write problem and make 2 separate patches with two separate descriptive changelogs for them.

Quoted 6 lines
Quoted 3 lines

but if it's isolated to
runtime suspending, maybe you need a console lock in the runtime_suspend path (like you already have in the static suspend path.)

console_lock in runtime_suspend will not help
during bootup

I understand it wont help when the console lock has not been initialized, and this is a separate problem (and needs a separate fix), but...

Quoted 2 lines

and due to printk emerging out from omap_device enable after system bootup.

Why doesn't a printk after an omap_device *enable* work? The UART should be enabled by that point.

In any case, the omap_device_enable is the result of a runtime PM request, so the locking for this problem should be handled in the runtime PM callbacks.

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
drivers/tty/serial/omap-serial.c +5 -0
+ ? ? ?*/
+
+ ? ? if (!console_lock &&
+ ? ? ? ? ? ? up->pdev->dev.power.runtime_status == RPM_SUSPENDING)
+ ? ? ? ? ? ? return;
Quoted 5 lines
Quoted 3 lines

Assuming this was a printk, it's now lost, right? ? Not sure that's an acceptable solution.

AFAIK it gets logged prints later.

How will it get written later? There is no return value to this function, so he caller can't know if it has succeeded or failed, so it obviously assumes that the data was written to the UART.

Quoted 3 lines

to summarize holding console lock helps after bootup since during boot up console lock is not available need to use above runtime_status check.

The point is you've fixed a small problem with a very big-hammer solution.

The problem you have occurs because of two different causes that need two different well-targeted solutions.

Kevin

#18 lore raw

PATCH v3 6/12 Serial: OMAP2+: Move erratum handling from serial.c

In reply to Govindraj.R

Move the erratum handling mechanism from serial.c to driver file and utilise the same func. in driver file.

---
 drivers/tty/serial/omap-serial.c |   57 ++++++++++++++++++++++++++++++++++---
 1 files changed, 52 insertions(+), 5 deletions(-)
drivers/tty/serial/omap-serial.c +52 -5
index ee94291..2ad8fa0 100644
@@ -52,6 +52,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
 static void serial_omap_rx_timeout(unsigned long uart_no);
 static int serial_omap_start_rxdma(struct uart_omap_port *up);
+static void omap_uart_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
 
 static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
 {
@@ -807,7 +808,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	serial_out(up, UART_MCR, up->mcr);
 
 	/* Protocol, Baud Rate, and Interrupt Settings */
-	serial_out(up, UART_OMAP_MDR1, up->mdr1);
+	if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
+		omap_uart_mdr1_errataset(up, up->mdr1);
+	else
+		serial_out(up, UART_OMAP_MDR1, up->mdr1);
+
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 
 	up->efr = serial_in(up, UART_EFR);
@@ -832,7 +837,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	else
 		up->mdr1 = UART_OMAP_MDR1_16X_MODE;
 
-	serial_out(up, UART_OMAP_MDR1, up->mdr1)
+	if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
+		omap_uart_mdr1_errataset(up, up->mdr1);
+	else
+		serial_out(up, UART_OMAP_MDR1, up->mdr1);
 
 	/* Hardware Flow Control Configuration */
 
@@ -1447,11 +1455,48 @@ static int serial_omap_remove(struct platform_device *dev)
 	return 0;
 }
 
+/*
+ * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6)
+ * The access to uart register after MDR1 Access
+ * causes UART to corrupt data.
+ *
+ * Need a delay =
+ * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
+ * give 10 times as much
+ */
+static void omap_uart_mdr1_errataset(struct uart_omap_port *up, u8 mdr1)
+{
+	u8 timeout = 255;
+
+	serial_out(up, UART_OMAP_MDR1, mdr1);
+	udelay(2);
+	serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT |
+			UART_FCR_CLEAR_RCVR);
+	/*
+	 * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
+	 * TX_FIFO_E bit is 1.
+	 */
+	while (UART_LSR_THRE != (serial_in(up, UART_LSR) &
+				(UART_LSR_THRE | UART_LSR_DR))) {
+		timeout--;
+		if (!timeout) {
+			/* Should *never* happen. we warn and carry on */
+			dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n",
+						serial_in(up, UART_LSR));
+			break;
+		}
+		udelay(1);
+	}
+}
+
 static void omap_uart_restore_context(struct uart_omap_port *up)
 {
 	u16 efr = 0;
 
-	serial_out(up, UART_OMAP_MDR1, up->mdr1);
+	if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
+		omap_uart_mdr1_errataset(up, UART_OMAP_MDR1_DISABLE);
+	else
+		serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
 	serial_out(up, UART_LCR, 0xBF); /* Config B mode */
 	efr = serial_in(up, UART_EFR);
 	serial_out(up, UART_EFR, UART_EFR_ECB);
@@ -1468,8 +1513,10 @@ static void omap_uart_restore_context(struct uart_omap_port *up)
 	serial_out(up, UART_LCR, 0xBF); /* Config B mode */
 	serial_out(up, UART_EFR, efr);
 	serial_out(up, UART_LCR, up->lcr);
-	/* UART 16x mode */
-	serial_out(up, UART_OMAP_MDR1, up->mdr1);
+	if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
+		omap_uart_mdr1_errataset(up, up->mdr1);
+	else
+		serial_out(up, UART_OMAP_MDR1, up->mdr1);
 }
 
 static int omap_serial_runtime_suspend(struct device *dev)
Signature · 1 line
1.7.0.4
#19 lore raw

PATCH v3 7/12 OMAP: Serial: Allow UART parameters to be configured from board file.

In reply to Govindraj.R

The following UART parameters are defined within the UART driver:

1). Whether the UART uses DMA (dma_enabled), by default set to 0 2). The size of dma buffer (set to 4096 bytes)
3). The time after which the dma should stop if no more data is received. 4). The auto suspend delay that will be passed for pm_runtime_autosuspend
where uart will be disabled after timeout

Different UARTs may be used for different purpose such as the console, for interfacing bluetooth chip, for interfacing to a modem chip, etc. Therefore, it is necessary to be able to customize the above settings for a given board on a per UART basis.

This change allows these parameters to be configured from the board file and allows the parameters to be configured for each UART independently.

If a board does not define its own custom parameters for the UARTs, then use the default parameters in the structure "omap_serial_default_info". The default parameters are defined to be the same as the current settings in the UART driver to avoid breaking the UART for any board. By default, make all boards use the default UART parameters.

---
 arch/arm/mach-omap2/board-3430sdp.c           |    6 ++--
 arch/arm/mach-omap2/board-4430sdp.c           |    8 ++--
 arch/arm/mach-omap2/board-n8x0.c              |    6 ++--
 arch/arm/mach-omap2/board-omap4panda.c        |    8 ++--
 arch/arm/mach-omap2/serial.c                  |   42 +++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/omap-serial.h |   14 ++++++--
 arch/arm/plat-omap/include/plat/serial.h      |    5 ++-
 drivers/tty/serial/omap-serial.c              |    8 ++---
 8 files changed, 71 insertions(+), 26 deletions(-)
arch/arm/mach-omap2/board-3430sdp.c +3 -3
index ae2963a..2b44c86 100644
@@ -642,9 +642,9 @@ static struct omap_board_data serial3_data = {
 
 static inline void board_serial_init(void)
 {
-	omap_serial_init_port(&serial1_data);
-	omap_serial_init_port(&serial2_data);
-	omap_serial_init_port(&serial3_data);
+	omap_serial_init_port(&serial1_data, NULL);
+	omap_serial_init_port(&serial2_data, NULL);
+	omap_serial_init_port(&serial3_data, NULL);
 }
 #else
 #define board_mux	NULL
arch/arm/mach-omap2/board-4430sdp.c +4 -4
index 73fa90b..946a558 100644
@@ -707,11 +707,11 @@ static inline void board_serial_init(void)
 	bdata.pads_cnt	= 0;
 	bdata.id	= 0;
 	/* pass dummy data for UART1 */
-	omap_serial_init_port(&bdata);
+	omap_serial_init_port(&bdata, NULL);
 
-	omap_serial_init_port(&serial2_data);
-	omap_serial_init_port(&serial3_data);
-	omap_serial_init_port(&serial4_data);
+	omap_serial_init_port(&serial2_data, NULL);
+	omap_serial_init_port(&serial3_data, NULL);
+	omap_serial_init_port(&serial4_data, NULL);
 }
 #else
 #define board_mux	NULL
arch/arm/mach-omap2/board-n8x0.c +3 -3
index 8d74318..5ab626a 100644
@@ -656,15 +656,15 @@ static inline void board_serial_init(void)
 	bdata.pads_cnt = 0;
 
 	bdata.id = 0;
-	omap_serial_init_port(&bdata);
+	omap_serial_init_port(&bdata, NULL);
 
 	bdata.id = 1;
-	omap_serial_init_port(&bdata);
+	omap_serial_init_port(&bdata, NULL);
 
 	bdata.id = 2;
 	bdata.pads = serial2_pads;
 	bdata.pads_cnt = ARRAY_SIZE(serial2_pads);
-	omap_serial_init_port(&bdata);
+	omap_serial_init_port(&bdata, NULL);
 }
 
 #else
arch/arm/mach-omap2/board-omap4panda.c +4 -4
index 90485fc..c402d03 100644
@@ -552,11 +552,11 @@ static inline void board_serial_init(void)
 	bdata.pads_cnt  = 0;
 	bdata.id        = 0;
 	/* pass dummy data for UART1 */
-	omap_serial_init_port(&bdata);
+	omap_serial_init_port(&bdata, NULL);
 
-	omap_serial_init_port(&serial2_data);
-	omap_serial_init_port(&serial3_data);
-	omap_serial_init_port(&serial4_data);
+	omap_serial_init_port(&serial2_data, NULL);
+	omap_serial_init_port(&serial3_data, NULL);
+	omap_serial_init_port(&serial4_data, NULL);
 }
 #else
 #define board_mux	NULL
arch/arm/mach-omap2/serial.c +39 -3

92 lines not on this page · raw message

arch/arm/plat-omap/include/plat/omap-serial.h +11 -3
index ac30de8..4e2dcdc 100644
@@ -51,7 +51,12 @@
 
 #define OMAP_UART_DMA_CH_FREE	-1
 
-#define RX_TIMEOUT		(3 * HZ)
+#define RX_TIMEOUT		(3 * HZ)	/* RX DMA timeout (jiffies) */
+#define DEFAULT_RXDMA_TIMEOUT	1		/* RX DMA polling rate (us) */
+#define DEFAULT_RXDMA_BUFSIZE	4096		/* RX DMA buffer size */
+#define DEFAULT_AUTOSUSPEND_DELAY (30 * HZ) /* Runtime autosuspend (msecs) */
+
+
 #define OMAP_MAX_HSUART_PORTS	4
 
 #define MSR_SAVE_FLAGS		UART_MSR_ANY_DELTA
@@ -64,6 +69,9 @@ struct omap_uart_port_info {
 	upf_t			flags;		/* UPF_* flags */
 	unsigned int		errata;
 	unsigned int		console_uart;
+	unsigned int		dma_rx_buf_size;/* DMA Rx Buffer Size */
+	unsigned int		dma_rx_timeout;	/* DMA RX timeout */
+	unsigned int		auto_sus_timeout; /* Auto_suspend timeout */
 
 	void (*enable_wakeup)(struct platform_device *, bool);
 	void __iomem *wk_st;
@@ -92,8 +100,8 @@ struct uart_omap_dma {
 	spinlock_t		rx_lock;
 	/* timer to poll activity on rx dma */
 	struct timer_list	rx_timer;
-	int			rx_buf_size;
-	int			rx_timeout;
+	unsigned int		rx_buf_size;
+	unsigned int		rx_timeout;
 };
 
 struct uart_omap_port {
arch/arm/plat-omap/include/plat/serial.h +4 -1
index ab1761a..ee758d4 100644
@@ -103,9 +103,12 @@
 #ifndef __ASSEMBLER__
 
 struct omap_board_data;
+struct omap_uart_port_info;
 
 extern void omap_serial_init(void);
-extern void omap_serial_init_port(struct omap_board_data *bdata);
+extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
+extern void omap_serial_init_port(struct omap_board_data *bdata,
+		struct omap_uart_port_info *platform_data);
 #endif
 
 #endif
drivers/tty/serial/omap-serial.c +3 -5
index 2ad8fa0..dc2743a 100644
@@ -44,8 +44,6 @@
 #include <plat/omap-serial.h>
 #include <plat/omap_device.h>
 
-#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */
-
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
 /* Forward declaration of functions */
@@ -1399,8 +1397,8 @@ static int serial_omap_probe(struct platform_device *pdev)
 		up->uart_dma.uart_dma_tx = dma_tx->start;
 		up->uart_dma.uart_dma_rx = dma_rx->start;
 		up->use_dma = 1;
-		up->uart_dma.rx_buf_size = 4096;
-		up->uart_dma.rx_timeout = 2;
+		up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size;
+		up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout;
 		spin_lock_init(&(up->uart_dma.tx_lock));
 		spin_lock_init(&(up->uart_dma.rx_lock));
 		up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
@@ -1409,7 +1407,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_set_autosuspend_delay(&pdev->dev,
-			OMAP_UART_AUTOSUSPEND_DELAY);
+			omap_up_info->auto_sus_timeout);
 
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_irq_safe(&pdev->dev);
Signature · 1 line
1.7.0.4
#20 lore raw

PATCH v3 7/12 OMAP: Serial: Allow UART parameters to be configured from board file.

Quoted 22 lines · Govindraj.R

The following UART parameters are defined within the UART driver:

1). Whether the UART uses DMA (dma_enabled), by default set to 0 2). The size of dma buffer (set to 4096 bytes)
3). The time after which the dma should stop if no more data is received. 4). The auto suspend delay that will be passed for pm_runtime_autosuspend
where uart will be disabled after timeout

Different UARTs may be used for different purpose such as the console, for interfacing bluetooth chip, for interfacing to a modem chip, etc. Therefore, it is necessary to be able to customize the above settings for a given board on a per UART basis.

This change allows these parameters to be configured from the board file and allows the parameters to be configured for each UART independently.

If a board does not define its own custom parameters for the UARTs, then use the default parameters in the structure "omap_serial_default_info". The default parameters are defined to be the same as the current settings in the UART driver to avoid breaking the UART for any board. By default, make all boards use the default UART parameters.

Quoted 3 lines

Nice. some minor comments below.

[...]

arch/arm/plat-omap/include/plat/omap-serial.h line 57

Quoted 13 lines
arch/arm/plat-omap/include/plat/omap-serial.h +4 -1
index ac30de8..4e2dcdc 100644
@@ -51,7 +51,12 @@
 
 #define OMAP_UART_DMA_CH_FREE	-1
 
-#define RX_TIMEOUT		(3 * HZ)
+#define RX_TIMEOUT		(3 * HZ)	/* RX DMA timeout (jiffies) */
+#define DEFAULT_RXDMA_TIMEOUT	1		/* RX DMA polling rate (us) */
+#define DEFAULT_RXDMA_BUFSIZE	4096		/* RX DMA buffer size */
+#define DEFAULT_AUTOSUSPEND_DELAY (30 * HZ) /* Runtime autosuspend (msecs) */

These don't need to be in omap-serial.h since neither the driver code or the board file should be using them. They can stay in mach-omap2/serial.c

arch/arm/plat-omap/include/plat/omap-serial.h struct omap_uart_port_info { · line 73

Quoted 10 lines
arch/arm/plat-omap/include/plat/omap-serial.h +3 -0
+
 #define OMAP_MAX_HSUART_PORTS	4
 
 #define MSR_SAVE_FLAGS		UART_MSR_ANY_DELTA
@@ -64,6 +69,9 @@ struct omap_uart_port_info {
 	upf_t			flags;		/* UPF_* flags */
 	unsigned int		errata;
 	unsigned int		console_uart;
+	unsigned int		dma_rx_buf_size;/* DMA Rx Buffer Size */
+	unsigned int		dma_rx_timeout;	/* DMA RX timeout */

Comments don't add value over variable name.

arch/arm/plat-omap/include/plat/omap-serial.h struct omap_uart_port_info { · line 74

Quoted 1 line
arch/arm/plat-omap/include/plat/omap-serial.h +1 -0
+	unsigned int		auto_sus_timeout; /* Auto_suspend timeout */

rename to autosuspend_timeout, drop comment.

Kevin

#21 lore raw

PATCH v3 7/12 OMAP: Serial: Allow UART parameters to be configured from board file.

Quoted 40 lines · Kevin Hilman
Quoted 22 lines · Govindraj.R

The following UART parameters are defined within the UART driver:

1). Whether the UART uses DMA (dma_enabled), by default set to 0 2). The size of dma buffer (set to 4096 bytes)
3). The time after which the dma should stop if no more data is received. 4). The auto suspend delay that will be passed for pm_runtime_autosuspend ? ? where uart will be disabled after timeout

Different UARTs may be used for different purpose such as the console, for interfacing bluetooth chip, for interfacing to a modem chip, etc. Therefore, it is necessary to be able to customize the above settings for a given board on a per UART basis.

This change allows these parameters to be configured from the board file and allows the parameters to be configured for each UART independently.

If a board does not define its own custom parameters for the UARTs, then use the default parameters in the structure "omap_serial_default_info". The default parameters are defined to be the same as the current settings in the UART driver to avoid breaking the UART for any board. By default, make all boards use the default UART parameters.

Quoted 3 lines

Nice. ?some minor comments below.

[...]

Quoted 8 lines
arch/arm/plat-omap/include/plat/omap-serial.h +0 -0
index ac30de8..4e2dcdc 100644
@@ -51,7 +51,12 @@
 

?#define OMAP_UART_DMA_CH_FREE ? ? ? ?-1

Quoted 9 lines

arch/arm/plat-omap/include/plat/omap-serial.h

Quoted 5 lines
arch/arm/plat-omap/include/plat/omap-serial.h +4 -1
-#define RX_TIMEOUT ? ? ? ? ? (3 * HZ)
+#define RX_TIMEOUT ? ? ? ? ? (3 * HZ) ? ? ? ?/* RX DMA timeout (jiffies) */
+#define DEFAULT_RXDMA_TIMEOUT ? ? ? ?1 ? ? ? ? ? ? ? /* RX DMA polling rate (us) */
+#define DEFAULT_RXDMA_BUFSIZE ? ? ? ?4096 ? ? ? ? ? ?/* RX DMA buffer size */
+#define DEFAULT_AUTOSUSPEND_DELAY (30 * HZ) /* Runtime autosuspend (msecs) */

These don't need to be in omap-serial.h since neither the driver code or the board file should be using them. ?They can stay in mach-omap2/serial.c

Yes fine will move them to serial.c

Quoted 13 lines
Quoted 10 lines

+
?#define OMAP_MAX_HSUART_PORTS ? ? ? ?4

?#define MSR_SAVE_FLAGS ? ? ? ? ? ? ? UART_MSR_ANY_DELTA

arch/arm/plat-omap/include/plat/omap-serial.h +0 -0
@@ -64,6 +69,9 @@ struct omap_uart_port_info {

? ? ? upf_t ? ? ? ? ? ? ? ? ? flags; ? ? ? ? ?/* UPF_* flags */ ? ? ? unsigned int ? ? ? ? ? ?errata;
? ? ? unsigned int ? ? ? ? ? ?console_uart;
+ ? ? unsigned int ? ? ? ? ? ?dma_rx_buf_size;/* DMA Rx Buffer Size */
+ ? ? unsigned int ? ? ? ? ? ?dma_rx_timeout; /* DMA RX timeout */

Comments don't add value over variable name.

will drop those comments.

Quoted 3 lines
Quoted 1 line

+ ? ? unsigned int ? ? ? ? ? ?auto_sus_timeout; /* Auto_suspend timeout */

rename to autosuspend_timeout, drop comment.

ok.

--
Thanks,
Govindraj.R

Quoted 7 lines

Kevin
--
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

#22 lore raw

PATCH v3 8/12 Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART

In reply to Govindraj.R

From: Jon Hunter <[email protected]>

When using DMA there are two timeouts defined. The first timeout, rx_timeout, is really a polling rate in which software polls the DMA status to see if the DMA has finished. This is necessary for the RX side because we do not know how much data we will receive. The secound timeout, RX_TIMEOUT, is a timeout after which the DMA will be stopped if no more data is received. To make this clearer, rename rx_timeout as rx_poll_rate and rename the function serial_omap_rx_timeout() to serial_omap_rxdma_poll().

The OMAP-Serial driver defines an RX_TIMEOUT of 3 seconds that is used to indicate when the DMA for UART can be stopped if no more data is received. The value is a global definition that is applied to all instances of the UART.

Each UART may be used for a different purpose and so the timeout required may differ. Make this value configurable for each UART so that this value can be optimised for power savings.

---
 arch/arm/mach-omap2/serial.c                  |    2 ++
 arch/arm/plat-omap/include/plat/omap-serial.h |    6 ++++--
 drivers/tty/serial/omap-serial.c              |   15 ++++++++-------
 3 files changed, 14 insertions(+), 9 deletions(-)
arch/arm/mach-omap2/serial.c +2 -0
index f38296e..6ac078f 100644
@@ -48,6 +48,7 @@ static struct omap_uart_port_info omap_serial_default_info[] = {
 	{
 		.dma_enabled	= 0,
 		.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+		.dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
 		.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
 		.auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
 	},
@@ -370,6 +371,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 	pdata->enable_wakeup = omap_uart_wakeup_enable;
 	pdata->dma_enabled = info->dma_enabled;
 	pdata->dma_rx_buf_size = info->dma_rx_buf_size;
+	pdata->dma_rx_poll_rate = info->dma_rx_poll_rate;
 	pdata->dma_rx_timeout = info->dma_rx_timeout;
 	pdata->auto_sus_timeout = info->auto_sus_timeout;
 	if (bdata->id == omap_uart_con_id)
arch/arm/plat-omap/include/plat/omap-serial.h +4 -2
index 4e2dcdc..c5f4dd9 100644
@@ -51,8 +51,8 @@
 
 #define OMAP_UART_DMA_CH_FREE	-1
 
-#define RX_TIMEOUT		(3 * HZ)	/* RX DMA timeout (jiffies) */
-#define DEFAULT_RXDMA_TIMEOUT	1		/* RX DMA polling rate (us) */
+#define DEFAULT_RXDMA_TIMEOUT	(3 * HZ)	/* RX DMA timeout (jiffies) */
+#define DEFAULT_RXDMA_POLLRATE	1		/* RX DMA polling rate (us) */
 #define DEFAULT_RXDMA_BUFSIZE	4096		/* RX DMA buffer size */
 #define DEFAULT_AUTOSUSPEND_DELAY (30 * HZ) /* Runtime autosuspend (msecs) */
 
@@ -71,6 +71,7 @@ struct omap_uart_port_info {
 	unsigned int		console_uart;
 	unsigned int		dma_rx_buf_size;/* DMA Rx Buffer Size */
 	unsigned int		dma_rx_timeout;	/* DMA RX timeout */
+	unsigned int		dma_rx_poll_rate; /* DMA RX timeout */
 	unsigned int		auto_sus_timeout; /* Auto_suspend timeout */
 
 	void (*enable_wakeup)(struct platform_device *, bool);
@@ -101,6 +102,7 @@ struct uart_omap_dma {
 	/* timer to poll activity on rx dma */
 	struct timer_list	rx_timer;
 	unsigned int		rx_buf_size;
+	unsigned int		rx_poll_rate;
 	unsigned int		rx_timeout;
 };
 
drivers/tty/serial/omap-serial.c +8 -7
index dc2743a..307b7c6 100644
@@ -48,7 +48,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
 /* Forward declaration of functions */
 static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
-static void serial_omap_rx_timeout(unsigned long uart_no);
+static void serial_omap_rxdma_poll(unsigned long uart_no);
 static int serial_omap_start_rxdma(struct uart_omap_port *up);
 static void omap_uart_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
 
@@ -543,7 +543,7 @@ static int serial_omap_startup(struct uart_port *port)
 			(dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
 			0);
 		init_timer(&(up->uart_dma.rx_timer));
-		up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
+		up->uart_dma.rx_timer.function = serial_omap_rxdma_poll;
 		up->uart_dma.rx_timer.data = up->pdev->id;
 		/* Currently the buffer size is 4KB. Can increase it */
 		up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
@@ -1175,7 +1175,7 @@ static int serial_omap_resume(struct device *dev)
 	return 0;
 }
 
-static void serial_omap_rx_timeout(unsigned long uart_no)
+static void serial_omap_rxdma_poll(unsigned long uart_no)
 {
 	struct uart_omap_port *up = ui[uart_no];
 	unsigned int curr_dma_pos, curr_transmitted_size;
@@ -1185,9 +1185,9 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 	if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
 			     (curr_dma_pos == 0)) {
 		if (jiffies_to_msecs(jiffies - up->port_activity) <
-							RX_TIMEOUT) {
+						up->uart_dma.rx_timeout) {
 			mod_timer(&up->uart_dma.rx_timer, jiffies +
-				usecs_to_jiffies(up->uart_dma.rx_timeout));
+				usecs_to_jiffies(up->uart_dma.rx_poll_rate));
 		} else {
 			serial_omap_stop_rxdma(up);
 			up->ier |= (UART_IER_RDI | UART_IER_RLSI);
@@ -1217,7 +1217,7 @@ static void serial_omap_rx_timeout(unsigned long uart_no)
 		}
 	} else  {
 		mod_timer(&up->uart_dma.rx_timer, jiffies +
-			usecs_to_jiffies(up->uart_dma.rx_timeout));
+			usecs_to_jiffies(up->uart_dma.rx_poll_rate));
 	}
 	up->port_activity = jiffies;
 }
@@ -1259,7 +1259,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up)
 	/* FIXME: Cache maintenance needed here? */
 	omap_start_dma(up->uart_dma.rx_dma_channel);
 	mod_timer(&up->uart_dma.rx_timer, jiffies +
-				usecs_to_jiffies(up->uart_dma.rx_timeout));
+				usecs_to_jiffies(up->uart_dma.rx_poll_rate));
 	up->uart_dma.rx_dma_used = true;
 	return ret;
 }
@@ -1399,6 +1399,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 		up->use_dma = 1;
 		up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size;
 		up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout;
+		up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate;
 		spin_lock_init(&(up->uart_dma.tx_lock));
 		spin_lock_init(&(up->uart_dma.rx_lock));
 		up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
Signature · 1 line
1.7.0.4
#23 lore raw

PATCH v3 8/12 Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART

Quoted 16 lines · Govindraj.R

From: Jon Hunter <[email protected]>

When using DMA there are two timeouts defined. The first timeout, rx_timeout, is really a polling rate in which software polls the DMA status to see if the DMA has finished. This is necessary for the RX side because we do not know how much data we will receive. The secound timeout, RX_TIMEOUT, is a timeout after which the DMA will be stopped if no more data is received. To make this clearer, rename rx_timeout as rx_poll_rate and rename the function serial_omap_rx_timeout() to serial_omap_rxdma_poll().

The OMAP-Serial driver defines an RX_TIMEOUT of 3 seconds that is used to indicate when the DMA for UART can be stopped if no more data is received. The value is a global definition that is applied to all instances of the UART.

Quoted 6 lines

Each UART may be used for a different purpose and so the timeout required may differ. Make this value configurable for each UART so that this value can be optimised for power savings.

Jon, thanks (again) for the well-written, descriptive changelog.

Kevin

#24 lore raw

PATCH v3 9/12 OMAP3: Serial: Remove uart pads from 3430 board file.

In reply to Govindraj.R

The pad values here are same as the default pad values updated in serial.c file.
Avoid structure duplication and use default pads.

---
 arch/arm/mach-omap2/board-3430sdp.c |  100 +----------------------------------
 1 files changed, 1 insertions(+), 99 deletions(-)
arch/arm/mach-omap2/board-3430sdp.c +1 -99
index 2b44c86..4e2baf7 100644
@@ -553,106 +553,8 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 static struct omap_board_mux board_mux[] __initdata = {
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
-
-static struct omap_device_pad serial1_pads[] __initdata = {
-	/*
-	 * Note that off output enable is an active low
-	 * signal. So setting this means pin is a
-	 * input enabled in off mode
-	 */
-	OMAP_MUX_STATIC("uart1_cts.uart1_cts",
-			 OMAP_PIN_INPUT |
-			 OMAP_PIN_OFF_INPUT_PULLDOWN |
-			 OMAP_OFFOUT_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart1_rts.uart1_rts",
-			 OMAP_PIN_OUTPUT |
-			 OMAP_OFF_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart1_rx.uart1_rx",
-			 OMAP_PIN_INPUT |
-			 OMAP_PIN_OFF_INPUT_PULLDOWN |
-			 OMAP_OFFOUT_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart1_tx.uart1_tx",
-			 OMAP_PIN_OUTPUT |
-			 OMAP_OFF_EN |
-			 OMAP_MUX_MODE0),
-};
-
-static struct omap_device_pad serial2_pads[] __initdata = {
-	OMAP_MUX_STATIC("uart2_cts.uart2_cts",
-			 OMAP_PIN_INPUT_PULLUP |
-			 OMAP_PIN_OFF_INPUT_PULLDOWN |
-			 OMAP_OFFOUT_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart2_rts.uart2_rts",
-			 OMAP_PIN_OUTPUT |
-			 OMAP_OFF_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart2_rx.uart2_rx",
-			 OMAP_PIN_INPUT |
-			 OMAP_PIN_OFF_INPUT_PULLDOWN |
-			 OMAP_OFFOUT_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart2_tx.uart2_tx",
-			 OMAP_PIN_OUTPUT |
-			 OMAP_OFF_EN |
-			 OMAP_MUX_MODE0),
-};
-
-static struct omap_device_pad serial3_pads[] __initdata = {
-	OMAP_MUX_STATIC("uart3_cts_rctx.uart3_cts_rctx",
-			 OMAP_PIN_INPUT_PULLDOWN |
-			 OMAP_PIN_OFF_INPUT_PULLDOWN |
-			 OMAP_OFFOUT_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart3_rts_sd.uart3_rts_sd",
-			 OMAP_PIN_OUTPUT |
-			 OMAP_OFF_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart3_rx_irrx.uart3_rx_irrx",
-			 OMAP_PIN_INPUT |
-			 OMAP_PIN_OFF_INPUT_PULLDOWN |
-			 OMAP_OFFOUT_EN |
-			 OMAP_MUX_MODE0),
-	OMAP_MUX_STATIC("uart3_tx_irtx.uart3_tx_irtx",
-			 OMAP_PIN_OUTPUT |
-			 OMAP_OFF_EN |
-			 OMAP_MUX_MODE0),
-};
-
-static struct omap_board_data serial1_data = {
-	.id		= 0,
-	.pads		= serial1_pads,
-	.pads_cnt	= ARRAY_SIZE(serial1_pads),
-};
-
-static struct omap_board_data serial2_data = {
-	.id		= 1,
-	.pads		= serial2_pads,
-	.pads_cnt	= ARRAY_SIZE(serial2_pads),
-};
-
-static struct omap_board_data serial3_data = {
-	.id		= 2,
-	.pads		= serial3_pads,
-	.pads_cnt	= ARRAY_SIZE(serial3_pads),
-};
-
-static inline void board_serial_init(void)
-{
-	omap_serial_init_port(&serial1_data, NULL);
-	omap_serial_init_port(&serial2_data, NULL);
-	omap_serial_init_port(&serial3_data, NULL);
-}
 #else
 #define board_mux	NULL
-
-static inline void board_serial_init(void)
-{
-	omap_serial_init();
-}
 #endif
 
 /*
@@ -789,7 +691,7 @@ static void __init omap_3430sdp_init(void)
 	else
 		gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV1;
 	omap_ads7846_init(1, gpio_pendown, 310, NULL);
-	board_serial_init();
+	omap_serial_init();
 	usb_musb_init(NULL);
 	board_smc91x_init();
 	board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
Signature · 1 line
1.7.0.4
#25 lore raw

PATCH v3 9/12 OMAP3: Serial: Remove uart pads from 3430 board file.

Quoted 5 lines · Govindraj.R

The pad values here are same as the default pad values updated in serial.c file.
Avoid structure duplication and use default pads.

This should be folded in with [03/12]

Kevin

#26 lore raw

PATCH v3 9/12 OMAP3: Serial: Remove uart pads from 3430 board file.

Quoted 9 lines · Kevin Hilman
Quoted 5 lines · Govindraj.R

The pad values here are same as the default pad values updated in serial.c file.
Avoid structure duplication and use default pads.

This should be folded in with [03/12]

agree.

--
Govindraj.R

Quoted 7 lines

Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html

#27 lore raw

PATCH v3 10/12 OMAP: Serial: Use resume call from prcm to enable uart

In reply to Govindraj.R

Use resume idle call from prcm_irq to enable uart_port from low power states. Add api to check pad wakeup status which will we used from uart_resume func. to enable back uart port if a wakeup event occurred.

UART_Resume func. can be removed once we have irq_chaining functionality available.

---
 arch/arm/mach-omap2/pm24xx.c                  |    2 ++
 arch/arm/mach-omap2/pm34xx.c                  |    2 ++
 arch/arm/mach-omap2/serial.c                  |   23 +++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap-serial.h |    2 ++
 arch/arm/plat-omap/include/plat/serial.h      |    1 +
 drivers/tty/serial/omap-serial.c              |   23 +++++++++++++++++++++++
 6 files changed, 53 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/pm24xx.c +2 -0
index c405bda..ba58a1d 100644
@@ -137,6 +137,8 @@ static void omap2_enter_full_retention(void)
 			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
 			   OMAP_SDRC_REGADDR(SDRC_POWER));
 
+	omap_uart_resume_idle();
+
 no_sleep:
 	if (omap2_pm_debug) {
 		unsigned long long tmp;
arch/arm/mach-omap2/pm34xx.c +2 -0
index ac7b7f8..3997e92 100644
@@ -216,6 +216,8 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 
 	wkst = omap2_prm_read_mod_reg(module, wkst_off);
 	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+
+	c += omap_uart_resume_idle();
 	if (wkst) {
 		iclk = omap2_cm_read_mod_reg(module, iclk_off);
 		fclk = omap2_cm_read_mod_reg(module, fclk_off);
arch/arm/mach-omap2/serial.c +23 -0
index 6ac078f..4bc5914 100644
@@ -199,6 +199,28 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
 	}
 }
 
+/* TBD: Will be removed once we have irq-chaing mechanism */
+static bool omap_uart_chk_wakeup(struct platform_device *pdev)
+{
+	struct omap_uart_port_info *up = pdev->dev.platform_data;
+	struct omap_device *od;
+	u32 wkst = 0;
+	bool ret = false;
+
+	od = to_omap_device(pdev);
+	if (omap_hmwod_pad_get_wakeup_status(od->hwmods[0]))
+		ret = true;
+
+	/* Check for normal UART wakeup (and clear it) */
+	wkst = __raw_readl(up->wk_st) & up->wk_mask;
+	if (wkst) {
+		__raw_writel(wkst, up->wk_st);
+		ret = true;
+	}
+
+	return ret;
+}
+
 static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable)
 {
 	struct omap_uart_port_info *up = pdev->dev.platform_data;
@@ -369,6 +391,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 	pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
 	pdata->flags = UPF_BOOT_AUTOCONF;
 	pdata->enable_wakeup = omap_uart_wakeup_enable;
+	pdata->chk_wakeup = omap_uart_chk_wakeup;
 	pdata->dma_enabled = info->dma_enabled;
 	pdata->dma_rx_buf_size = info->dma_rx_buf_size;
 	pdata->dma_rx_poll_rate = info->dma_rx_poll_rate;
arch/arm/plat-omap/include/plat/omap-serial.h +2 -0
index c5f4dd9..b5117bd 100644
@@ -75,6 +75,7 @@ struct omap_uart_port_info {
 	unsigned int		auto_sus_timeout; /* Auto_suspend timeout */
 
 	void (*enable_wakeup)(struct platform_device *, bool);
+	bool (*chk_wakeup)(struct platform_device *);
 	void __iomem *wk_st;
 	void __iomem *wk_en;
 	u32 wk_mask;
@@ -132,6 +133,7 @@ struct uart_omap_port {
 	unsigned long		port_activity;
 	unsigned int		errata;
 	void (*enable_wakeup)(struct platform_device *, bool);
+	bool (*chk_wakeup)(struct platform_device *);
 };
 
 #endif /* __OMAP_SERIAL_H__ */
arch/arm/plat-omap/include/plat/serial.h +1 -0
index ee758d4..44a42aa 100644
@@ -109,6 +109,7 @@ extern void omap_serial_init(void);
 extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
 extern void omap_serial_init_port(struct omap_board_data *bdata,
 		struct omap_uart_port_info *platform_data);
+extern u32 omap_uart_resume_idle(void);
 #endif
 
 #endif
drivers/tty/serial/omap-serial.c +23 -0
index 307b7c6..c3561dd 100644
@@ -43,6 +43,7 @@
 #include <plat/dmtimer.h>
 #include <plat/omap-serial.h>
 #include <plat/omap_device.h>
+#include <plat/serial.h>
 
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
@@ -108,6 +109,27 @@ static inline void serial_omap_port_enable(struct uart_omap_port *up)
 	pm_runtime_get_sync(&up->pdev->dev);
 }
 
+/* TBD: Should be removed once we irq-chaining mechanism in place */
+u32 omap_uart_resume_idle()
+{
+	int i;
+	u32 ret = 0;
+
+	for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
+		struct uart_omap_port *up = ui[i];
+
+		if (!up)
+			continue;
+
+		if (up->chk_wakeup(up->pdev)) {
+			serial_omap_port_enable(up);
+			serial_omap_port_disable(up);
+			ret++;
+		}
+	}
+	return ret;
+}
+
 static void serial_omap_stop_rxdma(struct uart_omap_port *up)
 {
 	if (up->uart_dma.rx_dma_used) {
@@ -1392,6 +1414,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 	up->uart_dma.uart_base = mem->start;
 	up->errata = omap_up_info->errata;
 	up->enable_wakeup = omap_up_info->enable_wakeup;
+	up->chk_wakeup = omap_up_info->chk_wakeup;
 
 	if (omap_up_info->dma_enabled) {
 		up->uart_dma.uart_dma_tx = dma_tx->start;
Signature · 1 line
1.7.0.4
#28 lore raw

PATCH v3 10/12 OMAP: Serial: Use resume call from prcm to enable uart

Quoted 1 line · Govindraj.R

Use resume idle call from prcm_irq to enable uart_port from low power states.

Comment is valid for OMAP3 but not for OMAP2. Maybe [01/12] should just leave this call in for OMAP2 instead of having to add it back here?

Quoted 2 lines

Add api to check pad wakeup status which will we used from uart_resume func. to enable back uart port if a wakeup event occurred.

s/api/API/ (same for PRCM, UART, int subject)

Quoted 2 lines

UART_Resume func. can be removed once we have irq_chaining functionality available.

Have you tested removing this when using with Tero's series?

Quoted 41 lines
---
 arch/arm/mach-omap2/pm24xx.c                  |    2 ++
 arch/arm/mach-omap2/pm34xx.c                  |    2 ++
 arch/arm/mach-omap2/serial.c                  |   23 +++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap-serial.h |    2 ++
 arch/arm/plat-omap/include/plat/serial.h      |    1 +
 drivers/tty/serial/omap-serial.c              |   23 +++++++++++++++++++++++
 6 files changed, 53 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/pm24xx.c +2 -0
index c405bda..ba58a1d 100644
@@ -137,6 +137,8 @@ static void omap2_enter_full_retention(void)
 			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
 			   OMAP_SDRC_REGADDR(SDRC_POWER));
 
+	omap_uart_resume_idle();
+
 no_sleep:
 	if (omap2_pm_debug) {
 		unsigned long long tmp;
arch/arm/mach-omap2/pm34xx.c +2 -0
index ac7b7f8..3997e92 100644
@@ -216,6 +216,8 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 
 	wkst = omap2_prm_read_mod_reg(module, wkst_off);
 	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+
+	c += omap_uart_resume_idle();
 	if (wkst) {
 		iclk = omap2_cm_read_mod_reg(module, iclk_off);
 		fclk = omap2_cm_read_mod_reg(module, fclk_off);
arch/arm/mach-omap2/serial.c +0 -0
index 6ac078f..4bc5914 100644

arch/arm/mach-omap2/serial.c static void omap_serial_fill_default_pads(struct omap_board_data *bdata) · line 202

Quoted 4 lines
arch/arm/mach-omap2/serial.c +1 -0
@@ -199,6 +199,28 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
 	}
 }
 
+/* TBD: Will be removed once we have irq-chaing mechanism */

s/TBD/FIXME/

Quoted 105 lines
arch/arm/mach-omap2/serial.c +22 -0
+static bool omap_uart_chk_wakeup(struct platform_device *pdev)
+{
+	struct omap_uart_port_info *up = pdev->dev.platform_data;
+	struct omap_device *od;
+	u32 wkst = 0;
+	bool ret = false;
+
+	od = to_omap_device(pdev);
+	if (omap_hmwod_pad_get_wakeup_status(od->hwmods[0]))
+		ret = true;
+
+	/* Check for normal UART wakeup (and clear it) */
+	wkst = __raw_readl(up->wk_st) & up->wk_mask;
+	if (wkst) {
+		__raw_writel(wkst, up->wk_st);
+		ret = true;
+	}
+
+	return ret;
+}
+
 static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable)
 {
 	struct omap_uart_port_info *up = pdev->dev.platform_data;
@@ -369,6 +391,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 	pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
 	pdata->flags = UPF_BOOT_AUTOCONF;
 	pdata->enable_wakeup = omap_uart_wakeup_enable;
+	pdata->chk_wakeup = omap_uart_chk_wakeup;
 	pdata->dma_enabled = info->dma_enabled;
 	pdata->dma_rx_buf_size = info->dma_rx_buf_size;
 	pdata->dma_rx_poll_rate = info->dma_rx_poll_rate;
arch/arm/plat-omap/include/plat/omap-serial.h +2 -0
index c5f4dd9..b5117bd 100644
@@ -75,6 +75,7 @@ struct omap_uart_port_info {
 	unsigned int		auto_sus_timeout; /* Auto_suspend timeout */
 
 	void (*enable_wakeup)(struct platform_device *, bool);
+	bool (*chk_wakeup)(struct platform_device *);
 	void __iomem *wk_st;
 	void __iomem *wk_en;
 	u32 wk_mask;
@@ -132,6 +133,7 @@ struct uart_omap_port {
 	unsigned long		port_activity;
 	unsigned int		errata;
 	void (*enable_wakeup)(struct platform_device *, bool);
+	bool (*chk_wakeup)(struct platform_device *);
 };
 
 #endif /* __OMAP_SERIAL_H__ */
arch/arm/plat-omap/include/plat/serial.h +1 -0
index ee758d4..44a42aa 100644
@@ -109,6 +109,7 @@ extern void omap_serial_init(void);
 extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
 extern void omap_serial_init_port(struct omap_board_data *bdata,
 		struct omap_uart_port_info *platform_data);
+extern u32 omap_uart_resume_idle(void);
 #endif
 
 #endif
drivers/tty/serial/omap-serial.c +22 -0
index 307b7c6..c3561dd 100644
@@ -43,6 +43,7 @@
 #include <plat/dmtimer.h>
 #include <plat/omap-serial.h>
 #include <plat/omap_device.h>
+#include <plat/serial.h>
 
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
@@ -108,6 +109,27 @@ static inline void serial_omap_port_enable(struct uart_omap_port *up)
 	pm_runtime_get_sync(&up->pdev->dev);
 }
 
+/* TBD: Should be removed once we irq-chaining mechanism in place */
+u32 omap_uart_resume_idle()
+{
+	int i;
+	u32 ret = 0;
+
+	for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
+		struct uart_omap_port *up = ui[i];
+
+		if (!up)
+			continue;
+
+		if (up->chk_wakeup(up->pdev)) {
+			serial_omap_port_enable(up);
+			serial_omap_port_disable(up);
+			ret++;
+		}
+	}
+	return ret;
+}
+
 static void serial_omap_stop_rxdma(struct uart_omap_port *up)
 {
 	if (up->uart_dma.rx_dma_used) {

drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1420

Quoted 7 lines
drivers/tty/serial/omap-serial.c +1 -0
@@ -1392,6 +1414,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 	up->uart_dma.uart_base = mem->start;
 	up->errata = omap_up_info->errata;
 	up->enable_wakeup = omap_up_info->enable_wakeup;
+	up->chk_wakeup = omap_up_info->chk_wakeup;
 
 	if (omap_up_info->dma_enabled) {
 		up->uart_dma.uart_dma_tx = dma_tx->start;

Kevin

#29 lore raw

PATCH v3 10/12 OMAP: Serial: Use resume call from prcm to enable uart

Quoted 10 lines · Kevin Hilman
Quoted 1 line · Govindraj.R

Use resume idle call from prcm_irq to enable uart_port from low power states.

Comment is valid for OMAP3 but not for OMAP2. ?Maybe [01/12] should just leave this call in for OMAP2 instead of having to add it back here?

Quoted 2 lines

Add api to check pad wakeup status which will we used from uart_resume func. to enable back uart port if a wakeup event occurred.

Quoted 6 lines

s/api/API/ ?(same for PRCM, UART, int subject)

Quoted 2 lines

UART_Resume func. can be removed once we have irq_chaining functionality available.

Have you tested removing this when using with Tero's series?

I added Tero's v3 patch 1,2,3,4 on top of my runtime changes

console gets looped with below prints during bootup [1] not sure whats happening need to look into it.

[1]:
http://pastebin.com/C55gtGhp

<<SNIP>>

[    2.740692] Registering the dns_resolver key type
[    2.746490] VFP support v0.3: implementor 41 architecture 3 part 30
variant c rev 1
[    2.754669] ThumbEE CPU extension supported.
[    2.772583] irq 368, desc: c0635540, depth: 1, count: 0, unhandled: 0
[    2.779388] ->handle_irq():  c00e494c, handle_bad_irq+0x0/0x260
[    2.785675] ->irq_data.chip(): c067f254, no_irq_chip+0x0/0x5c
[    2.791748] ->action():   (null)
[    2.795166]    IRQ_NOPROBE set
[    2.798370]  IRQ_NOREQUEST set
[    2.801605] irq 368, desc: c0635540, depth: 1, count: 0, unhandled: 0
[    2.808380] ->handle_irq():  c00e494c, handle_bad_irq+0x0/0x260
[    2.814636] ->irq_data.chip(): c067f254, no_irq_chip+0x0/0x5c
[    2.820709] ->action():   (null)
[    2.824127]    IRQ_NOPROBE set
[    2.827331]  IRQ_NOREQUEST set
[    2.830566] irq 368, desc: c0635540, depth: 1, count: 0, unhandled: 0
[    2.837371] ->handle_irq():  c00e494c, handle_bad_irq+0x0/0x260
[    2.843627] ->irq_data.chip(): c067f254, no_irq_chip+0x0/0x5c
[    2.849700] ->action():   (null)

<<SNIP>>

--
Thanks,
Govindraj.R

Quoted 168 lines
Quoted 42 lines

---

?arch/arm/mach-omap2/pm24xx.c ? ? ? ? ? ? ? ? ?| ? ?2 ++
?arch/arm/mach-omap2/pm34xx.c ? ? ? ? ? ? ? ? ?| ? ?2 ++
?arch/arm/mach-omap2/serial.c ? ? ? ? ? ? ? ? ?| ? 23 +++++++++++++++++++++++
?arch/arm/plat-omap/include/plat/omap-serial.h | ? ?2 ++
?arch/arm/plat-omap/include/plat/serial.h ? ? ?| ? ?1 +
?drivers/tty/serial/omap-serial.c ? ? ? ? ? ? ?| ? 23 +++++++++++++++++++++++

?6 files changed, 53 insertions(+), 0 deletions(-)

arch/arm/mach-omap2/pm24xx.c +2 -0
index c405bda..ba58a1d 100644
@@ -137,6 +137,8 @@ static void omap2_enter_full_retention(void)
 ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
 ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_SDRC_REGADDR(SDRC_POWER));
 
+ ? ? omap_uart_resume_idle();
+

?no_sleep:
? ? ? if (omap2_pm_debug) {
? ? ? ? ? ? ? unsigned long long tmp;

arch/arm/mach-omap2/pm34xx.c +2 -0
index ac7b7f8..3997e92 100644
@@ -216,6 +216,8 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 
 ? ? ? wkst = omap2_prm_read_mod_reg(module, wkst_off);
 ? ? ? wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+
+ ? ? c += omap_uart_resume_idle();
 ? ? ? if (wkst) {
 ? ? ? ? ? ? ? iclk = omap2_cm_read_mod_reg(module, iclk_off);
 ? ? ? ? ? ? ? fclk = omap2_cm_read_mod_reg(module, fclk_off);
arch/arm/mach-omap2/serial.c +0 -0
index 6ac078f..4bc5914 100644

arch/arm/mach-omap2/serial.c static void omap_serial_fill_default_pads(struct omap_board_data *bdata) · line 202

Quoted 4 lines
arch/arm/mach-omap2/serial.c +1 -0
@@ -199,6 +199,28 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
 ? ? ? }
 ?}
 
+/* TBD: Will be removed once we have irq-chaing mechanism */

s/TBD/FIXME/

Quoted 105 lines
arch/arm/mach-omap2/serial.c +22 -0
+static bool omap_uart_chk_wakeup(struct platform_device *pdev)
+{
+ ? ? struct omap_uart_port_info *up = pdev->dev.platform_data;
+ ? ? struct omap_device *od;
+ ? ? u32 wkst = 0;
+ ? ? bool ret = false;
+
+ ? ? od = to_omap_device(pdev);
+ ? ? if (omap_hmwod_pad_get_wakeup_status(od->hwmods[0]))
+ ? ? ? ? ? ? ret = true;
+
+ ? ? /* Check for normal UART wakeup (and clear it) */
+ ? ? wkst = __raw_readl(up->wk_st) & up->wk_mask;
+ ? ? if (wkst) {
+ ? ? ? ? ? ? __raw_writel(wkst, up->wk_st);
+ ? ? ? ? ? ? ret = true;
+ ? ? }
+
+ ? ? return ret;
+}
+
 ?static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable)
 ?{
 ? ? ? struct omap_uart_port_info *up = pdev->dev.platform_data;
@@ -369,6 +391,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 ? ? ? pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
 ? ? ? pdata->flags = UPF_BOOT_AUTOCONF;
 ? ? ? pdata->enable_wakeup = omap_uart_wakeup_enable;
+ ? ? pdata->chk_wakeup = omap_uart_chk_wakeup;
 ? ? ? pdata->dma_enabled = info->dma_enabled;
 ? ? ? pdata->dma_rx_buf_size = info->dma_rx_buf_size;
 ? ? ? pdata->dma_rx_poll_rate = info->dma_rx_poll_rate;
arch/arm/plat-omap/include/plat/omap-serial.h +0 -0
index c5f4dd9..b5117bd 100644
@@ -75,6 +75,7 @@ struct omap_uart_port_info {

? ? ? unsigned int ? ? ? ? ? ?auto_sus_timeout; /* Auto_suspend timeout */

? ? ? void (*enable_wakeup)(struct platform_device *, bool);
+ ? ? bool (*chk_wakeup)(struct platform_device *); ? ? ? void __iomem *wk_st;
? ? ? void __iomem *wk_en;
? ? ? u32 wk_mask;

arch/arm/plat-omap/include/plat/omap-serial.h +1 -0
@@ -132,6 +133,7 @@ struct uart_omap_port {
 ? ? ? unsigned long ? ? ? ? ? port_activity;
 ? ? ? unsigned int ? ? ? ? ? ?errata;
 ? ? ? void (*enable_wakeup)(struct platform_device *, bool);
+ ? ? bool (*chk_wakeup)(struct platform_device *);
 ?};
 

?#endif /* __OMAP_SERIAL_H__ */

arch/arm/plat-omap/include/plat/serial.h +1 -0
index ee758d4..44a42aa 100644
@@ -109,6 +109,7 @@ extern void omap_serial_init(void);
 ?extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
 ?extern void omap_serial_init_port(struct omap_board_data *bdata,
 ? ? ? ? ? ? ? struct omap_uart_port_info *platform_data);
+extern u32 omap_uart_resume_idle(void);

?#endif

?#endif

drivers/tty/serial/omap-serial.c +0 -0
index 307b7c6..c3561dd 100644
@@ -43,6 +43,7 @@

?#include <plat/dmtimer.h>
?#include <plat/omap-serial.h>
?#include <plat/omap_device.h>
+#include <plat/serial.h>

?static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];

drivers/tty/serial/omap-serial.c +21 -0
@@ -108,6 +109,27 @@ static inline void serial_omap_port_enable(struct uart_omap_port *up)
 ? ? ? pm_runtime_get_sync(&up->pdev->dev);
 ?}
 
+/* TBD: Should be removed once we irq-chaining mechanism in place */
+u32 omap_uart_resume_idle()
+{
+ ? ? int i;
+ ? ? u32 ret = 0;
+
+ ? ? for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
+ ? ? ? ? ? ? struct uart_omap_port *up = ui[i];
+
+ ? ? ? ? ? ? if (!up)
+ ? ? ? ? ? ? ? ? ? ? continue;
+
+ ? ? ? ? ? ? if (up->chk_wakeup(up->pdev)) {
+ ? ? ? ? ? ? ? ? ? ? serial_omap_port_enable(up);
+ ? ? ? ? ? ? ? ? ? ? serial_omap_port_disable(up);
+ ? ? ? ? ? ? ? ? ? ? ret++;
+ ? ? ? ? ? ? }
+ ? ? }
+ ? ? return ret;
+}
+
 ?static void serial_omap_stop_rxdma(struct uart_omap_port *up)
 ?{
 ? ? ? if (up->uart_dma.rx_dma_used) {

drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1420

Quoted 7 lines
drivers/tty/serial/omap-serial.c +1 -0
@@ -1392,6 +1414,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 ? ? ? up->uart_dma.uart_base = mem->start;
 ? ? ? up->errata = omap_up_info->errata;
 ? ? ? up->enable_wakeup = omap_up_info->enable_wakeup;
+ ? ? up->chk_wakeup = omap_up_info->chk_wakeup;
 
 ? ? ? if (omap_up_info->dma_enabled) {
 ? ? ? ? ? ? ? up->uart_dma.uart_dma_tx = dma_tx->start;

Kevin
--
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

#30 lore raw

PATCH v3 11/12 OMAP2: Serial: Add has_async_wake flag.

In reply to Govindraj.R

Prior to this patch the uart_clock was cut using prepare/resume calls since these funcs are no more available with runtime changes use has_async_wake flag to keep clock active during bootup otherwise uart port will disabled during boot-up and cannot be enabled back. Also based on this flag we can disable uart port during suspend and enable back during resume for omap_socs that have not set has_async_wake.

---
 arch/arm/mach-omap2/serial.c                  |    1 +
 arch/arm/plat-omap/include/plat/omap-serial.h |    3 +++
 drivers/tty/serial/omap-serial.c              |   14 ++++++++++++++
 3 files changed, 18 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/serial.c +1 -0
index 4bc5914..0a95c95 100644
@@ -266,6 +266,7 @@ static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 			break;
 		}
 		uart->wk_mask = wk_mask;
+		uart->has_async_wake = true;
 	} else if (cpu_is_omap24xx()) {
 		u32 wk_mask = 0;
 		u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
arch/arm/plat-omap/include/plat/omap-serial.h +3 -0
index b5117bd..69e6d4b 100644
@@ -79,6 +79,7 @@ struct omap_uart_port_info {
 	void __iomem *wk_st;
 	void __iomem *wk_en;
 	u32 wk_mask;
+	bool			has_async_wake;
 };
 
 struct uart_omap_dma {
@@ -134,6 +135,8 @@ struct uart_omap_port {
 	unsigned int		errata;
 	void (*enable_wakeup)(struct platform_device *, bool);
 	bool (*chk_wakeup)(struct platform_device *);
+
+	bool			has_async_wake;
 };
 
 #endif /* __OMAP_SERIAL_H__ */
drivers/tty/serial/omap-serial.c +14 -0
index c3561dd..dbe76f3 100644
@@ -1181,6 +1181,13 @@ static int serial_omap_suspend(struct device *dev)
 		uart_suspend_port(&serial_omap_reg, &up->port);
 		console_trylock();
 		serial_omap_pm(&up->port, 3, 0);
+
+		/* OMAP2 dont have async wakeup from prcm.
+		 * For such socs clocks will be kept active from probe and
+		 * cut only in suspend path.
+		 */
+		if (!up->has_async_wake)
+			serial_omap_port_disable(up);
 	}
 	return 0;
 }
@@ -1192,6 +1199,9 @@ static int serial_omap_resume(struct device *dev)
 	if (up) {
 		uart_resume_port(&serial_omap_reg, &up->port);
 		console_unlock();
+
+		if (!up->has_async_wake)
+			serial_omap_port_enable(up);
 	}
 
 	return 0;
@@ -1415,6 +1425,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 	up->errata = omap_up_info->errata;
 	up->enable_wakeup = omap_up_info->enable_wakeup;
 	up->chk_wakeup = omap_up_info->chk_wakeup;
+	up->has_async_wake = omap_up_info->has_async_wake;
 
 	if (omap_up_info->dma_enabled) {
 		up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1443,6 +1454,9 @@ static int serial_omap_probe(struct platform_device *pdev)
 		serial_omap_port_disable(up);
 	}
 
+	if (!up->has_async_wake)
+		serial_omap_port_enable(up);
+
 	ui[pdev->id] = up;
 	serial_omap_add_console_port(up);
 
Signature · 1 line
1.7.0.4
#31 lore raw

PATCH v3 11/12 OMAP2: Serial: Add has_async_wake flag.

Quoted 4 lines · Govindraj.R

Prior to this patch the uart_clock was cut using prepare/resume calls since these funcs are no more available with runtime changes use has_async_wake flag to keep clock active during bootup otherwise uart port will disabled during boot-up and cannot be enabled back.

Is this only a bootup issue, or a runtime PM issue? It appears to me that with this patch, runtime PM is effectively disabled for the whole time.

Why not just use pm_runtime_disable() in _probe() for devices with no async wakeup.

Quoted 3 lines

Also based on this flag we can disable uart port during suspend and enable back during resume for omap_socs that have not set has_async_wake.

Then you can use pm_runtime_enable() in ->prepare() and pm_runtime_disable() in ->complete()

Kevin

Quoted 85 lines
---
 arch/arm/mach-omap2/serial.c                  |    1 +
 arch/arm/plat-omap/include/plat/omap-serial.h |    3 +++
 drivers/tty/serial/omap-serial.c              |   14 ++++++++++++++
 3 files changed, 18 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/serial.c +1 -0
index 4bc5914..0a95c95 100644
@@ -266,6 +266,7 @@ static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 			break;
 		}
 		uart->wk_mask = wk_mask;
+		uart->has_async_wake = true;
 	} else if (cpu_is_omap24xx()) {
 		u32 wk_mask = 0;
 		u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
arch/arm/plat-omap/include/plat/omap-serial.h +3 -0
index b5117bd..69e6d4b 100644
@@ -79,6 +79,7 @@ struct omap_uart_port_info {
 	void __iomem *wk_st;
 	void __iomem *wk_en;
 	u32 wk_mask;
+	bool			has_async_wake;
 };
 
 struct uart_omap_dma {
@@ -134,6 +135,8 @@ struct uart_omap_port {
 	unsigned int		errata;
 	void (*enable_wakeup)(struct platform_device *, bool);
 	bool (*chk_wakeup)(struct platform_device *);
+
+	bool			has_async_wake;
 };
 
 #endif /* __OMAP_SERIAL_H__ */
drivers/tty/serial/omap-serial.c +14 -0
index c3561dd..dbe76f3 100644
@@ -1181,6 +1181,13 @@ static int serial_omap_suspend(struct device *dev)
 		uart_suspend_port(&serial_omap_reg, &up->port);
 		console_trylock();
 		serial_omap_pm(&up->port, 3, 0);
+
+		/* OMAP2 dont have async wakeup from prcm.
+		 * For such socs clocks will be kept active from probe and
+		 * cut only in suspend path.
+		 */
+		if (!up->has_async_wake)
+			serial_omap_port_disable(up);
 	}
 	return 0;
 }
@@ -1192,6 +1199,9 @@ static int serial_omap_resume(struct device *dev)
 	if (up) {
 		uart_resume_port(&serial_omap_reg, &up->port);
 		console_unlock();
+
+		if (!up->has_async_wake)
+			serial_omap_port_enable(up);
 	}
 
 	return 0;
@@ -1415,6 +1425,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 	up->errata = omap_up_info->errata;
 	up->enable_wakeup = omap_up_info->enable_wakeup;
 	up->chk_wakeup = omap_up_info->chk_wakeup;
+	up->has_async_wake = omap_up_info->has_async_wake;
 
 	if (omap_up_info->dma_enabled) {
 		up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1443,6 +1454,9 @@ static int serial_omap_probe(struct platform_device *pdev)
 		serial_omap_port_disable(up);
 	}
 
+	if (!up->has_async_wake)
+		serial_omap_port_enable(up);
+
 	ui[pdev->id] = up;
 	serial_omap_add_console_port(up);
#32 lore raw

PATCH v3 11/12 OMAP2: Serial: Add has_async_wake flag.

Quoted 11 lines · Kevin Hilman
Quoted 4 lines · Govindraj.R

Prior to this patch the uart_clock was cut using prepare/resume calls since these funcs are no more available with runtime changes use has_async_wake flag to keep clock active during bootup otherwise uart port will disabled during boot-up and cannot be enabled back.

Is this only a bootup issue, or a runtime PM issue? ?It appears to me that with this patch, runtime PM is effectively disabled for the whole time.

it boots up fine, its a runtime PM issue where there is no mechanism to wakeup after clock cutting from runtime autosuspend.

Quoted 3 lines

Why not just use pm_runtime_disable() in _probe() for devices with no async wakeup.

Agree.
can drop of this patch and bind below changes in runtime conversion patch 04/12

do pm_runtime_enable only if device_may_wakeup
is true in probe.

<<SNIP>>
in serial_omap_probe

if (device_may_wakeup(&pdev->dev)) {
	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_set_autosuspend_delay(&pdev->dev,
				OMAP_UART_AUTOSUSPEND_DELAY);
	pm_runtime_enable(&pdev->dev);
	pm_runtime_irq_safe(&pdev->dev);
}
Quoted 7 lines
Quoted 3 lines

Also based on this flag we can disable uart port during suspend and enable back during resume for omap_socs that have not set has_async_wake.

Then you can use pm_runtime_enable() in ->prepare() and pm_runtime_disable() in ->complete()

u mean runtime enable in suspend and runtime disable in resume if device_may_wakeup is false.

<<SNIP>>
in serial_omap_suspend

if (!device_may_wakeup(&pdev->dev))

	pm_runtime_enable(&pdev->dev);

--
Thanks,
Govindraj.R

Quoted 92 lines

Kevin

Quoted 77 lines

---

?arch/arm/mach-omap2/serial.c ? ? ? ? ? ? ? ? ?| ? ?1 +
?arch/arm/plat-omap/include/plat/omap-serial.h | ? ?3 +++
?drivers/tty/serial/omap-serial.c ? ? ? ? ? ? ?| ? 14 ++++++++++++++

?3 files changed, 18 insertions(+), 0 deletions(-)

arch/arm/mach-omap2/serial.c +1 -0
index 4bc5914..0a95c95 100644
@@ -266,6 +266,7 @@ static void omap_uart_idle_init(struct omap_uart_port_info *uart,
 ? ? ? ? ? ? ? ? ? ? ? break;
 ? ? ? ? ? ? ? }
 ? ? ? ? ? ? ? uart->wk_mask = wk_mask;
+ ? ? ? ? ? ? uart->has_async_wake = true;
 ? ? ? } else if (cpu_is_omap24xx()) {
 ? ? ? ? ? ? ? u32 wk_mask = 0;
 ? ? ? ? ? ? ? u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
arch/arm/plat-omap/include/plat/omap-serial.h +3 -0
index b5117bd..69e6d4b 100644
@@ -79,6 +79,7 @@ struct omap_uart_port_info {
 ? ? ? void __iomem *wk_st;
 ? ? ? void __iomem *wk_en;
 ? ? ? u32 wk_mask;
+ ? ? bool ? ? ? ? ? ? ? ? ? ?has_async_wake;
 ?};
 
 ?struct uart_omap_dma {
@@ -134,6 +135,8 @@ struct uart_omap_port {
 ? ? ? unsigned int ? ? ? ? ? ?errata;
 ? ? ? void (*enable_wakeup)(struct platform_device *, bool);
 ? ? ? bool (*chk_wakeup)(struct platform_device *);
+
+ ? ? bool ? ? ? ? ? ? ? ? ? ?has_async_wake;
 ?};
 

?#endif /* __OMAP_SERIAL_H__ */

drivers/tty/serial/omap-serial.c +11 -0
index c3561dd..dbe76f3 100644
@@ -1181,6 +1181,13 @@ static int serial_omap_suspend(struct device *dev)
 ? ? ? ? ? ? ? uart_suspend_port(&serial_omap_reg, &up->port);
 ? ? ? ? ? ? ? console_trylock();
 ? ? ? ? ? ? ? serial_omap_pm(&up->port, 3, 0);
+
+ ? ? ? ? ? ? /* OMAP2 dont have async wakeup from prcm.
+ ? ? ? ? ? ? ?* For such socs clocks will be kept active from probe and
+ ? ? ? ? ? ? ?* cut only in suspend path.
+ ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? if (!up->has_async_wake)
+ ? ? ? ? ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? }
 ? ? ? return 0;
 ?}
@@ -1192,6 +1199,9 @@ static int serial_omap_resume(struct device *dev)
 ? ? ? if (up) {
 ? ? ? ? ? ? ? uart_resume_port(&serial_omap_reg, &up->port);
 ? ? ? ? ? ? ? console_unlock();
+
+ ? ? ? ? ? ? if (!up->has_async_wake)
+ ? ? ? ? ? ? ? ? ? ? serial_omap_port_enable(up);
 ? ? ? }
 
 ? ? ? return 0;
@@ -1415,6 +1425,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 ? ? ? up->errata = omap_up_info->errata;
 ? ? ? up->enable_wakeup = omap_up_info->enable_wakeup;
 ? ? ? up->chk_wakeup = omap_up_info->chk_wakeup;
+ ? ? up->has_async_wake = omap_up_info->has_async_wake;
 
 ? ? ? if (omap_up_info->dma_enabled) {
 ? ? ? ? ? ? ? up->uart_dma.uart_dma_tx = dma_tx->start;

drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1461

Quoted 8 lines
drivers/tty/serial/omap-serial.c +3 -0
@@ -1443,6 +1454,9 @@ static int serial_omap_probe(struct platform_device *pdev)
 ? ? ? ? ? ? ? serial_omap_port_disable(up);
 ? ? ? }
 
+ ? ? if (!up->has_async_wake)
+ ? ? ? ? ? ? serial_omap_port_enable(up);
+
 ? ? ? ui[pdev->id] = up;
 ? ? ? serial_omap_add_console_port(up);

--
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

#33 lore raw

PATCH v3 11/12 OMAP2: Serial: Add has_async_wake flag.

Quoted 31 lines · Govindraj
Quoted 11 lines · Kevin Hilman
Quoted 4 lines · Govindraj.R

Prior to this patch the uart_clock was cut using prepare/resume calls since these funcs are no more available with runtime changes use has_async_wake flag to keep clock active during bootup otherwise uart port will disabled during boot-up and cannot be enabled back.

Is this only a bootup issue, or a runtime PM issue? ?It appears to me that with this patch, runtime PM is effectively disabled for the whole time.

it boots up fine, its a runtime PM issue where there is no mechanism to wakeup after clock cutting from runtime autosuspend.

Quoted 3 lines

Why not just use pm_runtime_disable() in _probe() for devices with no async wakeup.

Agree.
can drop of this patch and bind below changes in runtime conversion patch 04/12

do pm_runtime_enable only if device_may_wakeup
is true in probe.

<<SNIP>>
in serial_omap_probe

Quoted 7 lines
if (device_may_wakeup(&pdev->dev)) {
	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_set_autosuspend_delay(&pdev->dev,
				OMAP_UART_AUTOSUSPEND_DELAY);
	pm_runtime_enable(&pdev->dev);
	pm_runtime_irq_safe(&pdev->dev);
}

Well, I think only the _enable() should be conditional.

Quoted 10 lines
Quoted 7 lines
Quoted 3 lines

Also based on this flag we can disable uart port during suspend and enable back during resume for omap_socs that have not set has_async_wake.

Then you can use pm_runtime_enable() in ->prepare() and pm_runtime_disable() in ->complete()

u mean runtime enable in suspend and runtime disable in resume if device_may_wakeup is false.

No, I meant the .prepare (runs before .suspend) and .complete (runs after .resume) callbacks.

Kevin

#34 lore raw

PATCH v3 12/12 OMAP4: Serial: Set TX_FIFO_THRESHOLD if uart in dma mode for es2.0

In reply to Govindraj.R
Quoted 2 lines

From [email protected] Wed Jun 1 12:03:18 2011

From: [email protected] ()
Date: Wed, 01 Jun 2011 16:03:18 -0000
Subject: No subject
Message-ID: <[email protected]>

uart tx threshold value using the new register UART_TX_DMA_THRESHOLD, this register can used if UART_MDR3 bit(2) is set. We have to ensure tx_threshold + tx_trigger <= 63 from es2.0 onwards. By default we are using tx_trigger of 1 so we can set threshold to 62 to satisfy above criteria. Without the threshold setting we hit dma_sync lost errors on tx channel leading to data loss on rx side

---
 arch/arm/mach-omap2/serial.c                  |    4 ++++
 arch/arm/plat-omap/include/plat/omap-serial.h |   11 +++++++++++
 drivers/tty/serial/omap-serial.c              |    5 +++++
 3 files changed, 20 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/serial.c +4 -0
index 0a95c95..437fc0b 100644
@@ -401,6 +401,10 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 	if (bdata->id == omap_uart_con_id)
 		pdata->console_uart = true;
 
+	if (pdata->dma_enabled &&
+			cpu_is_omap44xx() && omap_rev() > OMAP4430_REV_ES1_0)
+		pdata->errata |= OMAP4_UART_ERRATA_i659_TX_THR;
+
 	od = omap_device_build(name, bdata->id, oh, pdata,
 				sizeof(*pdata), omap_uart_latency,
 				ARRAY_SIZE(omap_uart_latency), false);
arch/arm/plat-omap/include/plat/omap-serial.h +11 -0
index 69e6d4b..0d10f72 100644
@@ -56,12 +56,23 @@
 #define DEFAULT_RXDMA_BUFSIZE	4096		/* RX DMA buffer size */
 #define DEFAULT_AUTOSUSPEND_DELAY (30 * HZ) /* Runtime autosuspend (msecs) */
 
+/*
+ * (Errata i659) - From OMAP4430 ES 2.0 onwards set
+ * tx_threshold while using UART in DMA Mode
+ * and ensure tx_threshold + tx_trigger <= 63
+ */
+#define UART_MDR3		0x20
+#define UART_TX_DMA_THRESHOLD	0x21
+#define SET_DMA_TX_THRESHOLD	BIT(2)
+/* Setting TX Threshold Level to 62 */
+#define TX_FIFO_THR_LVL		0x3E
 
 #define OMAP_MAX_HSUART_PORTS	4
 
 #define MSR_SAVE_FLAGS		UART_MSR_ANY_DELTA
 
 #define UART_ERRATA_i202_MDR1_ACCESS	BIT(0)
+#define OMAP4_UART_ERRATA_i659_TX_THR	BIT(1)
 
 struct omap_uart_port_info {
 	bool			dma_enabled;	/* To specify DMA Mode */
drivers/tty/serial/omap-serial.c +5 -0
index dbe76f3..a9645ac 100644
@@ -818,6 +818,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
 
 	if (up->use_dma) {
+		if (up->errata & OMAP4_UART_ERRATA_i659_TX_THR) {
+			serial_out(up, UART_MDR3, SET_DMA_TX_THRESHOLD);
+			serial_out(up, UART_TX_DMA_THRESHOLD, TX_FIFO_THR_LVL);
+		}
+
 		serial_out(up, UART_TI752_TLR, 0);
 		serial_out(up, UART_OMAP_SCR,
 			(UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
Signature · 1 line
1.7.0.4