All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/12] OMAP2+: Serial: Runtime adaptation + cleanup
@ 2011-06-08 11:23 ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, Govindraj.R

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


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 00/12] OMAP2+: Serial: Runtime adaptation + cleanup
@ 2011-06-08 11:23 ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 01/12] OMAP2+: UART: Remove certain uart calls from sram_idle
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, Govindraj.R

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.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index df3ded6..c405bda 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -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);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index c155c9d..ac7b7f8 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -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;
 }
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index 2723f91..ab1761a 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -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
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 01/12] OMAP2+: UART: Remove certain uart calls from sram_idle
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index df3ded6..c405bda 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -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);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index c155c9d..ac7b7f8 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -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;
 }
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index 2723f91..ab1761a 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -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
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 02/12] OMAP2+: UART: Remove uart clock handling code from serial.c
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, 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.

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/serial.c                  |  754 ++-----------------------
 arch/arm/plat-omap/include/plat/omap-serial.h |   15 +-
 2 files changed, 74 insertions(+), 695 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 1ac361b..b16768a 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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);
-
 	}
 }
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 2682043..2ca885b 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 02/12] OMAP2+: UART: Remove uart clock handling code from serial.c
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/serial.c                  |  754 ++-----------------------
 arch/arm/plat-omap/include/plat/omap-serial.h |   15 +-
 2 files changed, 74 insertions(+), 695 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 1ac361b..b16768a 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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);
-
 	}
 }
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 2682043..2ca885b 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 03/12] OMAP2+: Serial: Add default mux for all uarts.
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, Govindraj.R

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

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/serial.c |  127 +++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 126 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index b16768a..8c1a4c7 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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);
 	}
 }
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 03/12] OMAP2+: Serial: Add default mux for all uarts.
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/serial.c |  127 +++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 126 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index b16768a..8c1a4c7 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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);
 	}
 }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, 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.

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 8c1a4c7..1651c2c 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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;
 
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 2ca885b..ac30de8 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 47cadf4..897416f 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -37,10 +37,14 @@
 #include <linux/clk.h>
 #include <linux/serial_core.h>
 #include <linux/irq.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
 #include <plat/omap-serial.h>
+#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];
 
@@ -94,6 +98,17 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
 	return port->uartclk/(baud * divisor);
 }
 
+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);
+}
+
 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);
 }
 
 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);
@@ -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);
 }
 
 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
-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();
+		serial_omap_pm(&up->port, 3, 0);
+	}
 	return 0;
 }
 
-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();
+	}
+
 	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)
+{
+	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);
+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);
+
+	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 = {
 	.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,
 	},
 };
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 8c1a4c7..1651c2c 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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;
 
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 2ca885b..ac30de8 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 47cadf4..897416f 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -37,10 +37,14 @@
 #include <linux/clk.h>
 #include <linux/serial_core.h>
 #include <linux/irq.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
 #include <plat/omap-serial.h>
+#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];
 
@@ -94,6 +98,17 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
 	return port->uartclk/(baud * divisor);
 }
 
+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);
+}
+
 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);
 }
 
 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);
@@ -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);
 }
 
 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
-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();
+		serial_omap_pm(&up->port, 3, 0);
+	}
 	return 0;
 }
 
-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();
+	}
+
 	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)
+{
+	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);
+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);
+
+	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 = {
 	.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,
 	},
 };
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, 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

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
 1 files changed, 19 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 897416f..ee94291 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
 1 files changed, 19 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 897416f..ee94291 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 06/12] Serial: OMAP2+: Move erratum handling from serial.c
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, Govindraj.R

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

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 drivers/tty/serial/omap-serial.c |   57 ++++++++++++++++++++++++++++++++++---
 1 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index ee94291..2ad8fa0 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 06/12] Serial: OMAP2+: Move erratum handling from serial.c
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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

Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 drivers/tty/serial/omap-serial.c |   57 ++++++++++++++++++++++++++++++++++---
 1 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index ee94291..2ad8fa0 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 07/12] OMAP: Serial: Allow UART parameters to be configured from board file.
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, Govindraj.R, Deepak K, Jon Hunter

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.

Signed-off-by: Deepak K <deepak.k@ti.com>
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index ae2963a..2b44c86 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -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
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 73fa90b..946a558 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -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
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 8d74318..5ab626a 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -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
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 90485fc..c402d03 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -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
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 1651c2c..f38296e 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -44,6 +44,15 @@
 
 static int omap_uart_con_id __initdata = -1;
 
+static struct omap_uart_port_info omap_serial_default_info[] = {
+	{
+		.dma_enabled	= 0,
+		.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+		.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
+		.auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
+	},
+};
+
 static int uart_idle_hwmod(struct omap_device *od)
 {
 	omap_hwmod_idle(od->hwmods[0]);
@@ -313,6 +322,7 @@ core_initcall(omap_serial_early_init);
 /**
  * omap_serial_init_port() - initialize single serial port
  * @bdata: port specific board data pointer
+ * @info: platform specific data pointer
  *
  * This function initialies serial driver for given port only.
  * Platforms can call this function instead of omap_serial_init()
@@ -321,7 +331,8 @@ core_initcall(omap_serial_early_init);
  * Don't mix calls to omap_serial_init_port() and omap_serial_init(),
  * use only one of the two.
  */
-void __init omap_serial_init_port(struct omap_board_data *bdata)
+void __init omap_serial_init_port(struct omap_board_data *bdata,
+			struct omap_uart_port_info *info)
 {
 	struct omap_hwmod *oh;
 	struct omap_device *od;
@@ -339,6 +350,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 	if (!oh)
 		return;
 
+	if (info == NULL)
+		info = omap_serial_default_info;
+
 	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
 		pr_err("Memory allocation for UART pdata failed\n");
@@ -354,6 +368,10 @@ 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->dma_enabled = info->dma_enabled;
+	pdata->dma_rx_buf_size = info->dma_rx_buf_size;
+	pdata->dma_rx_timeout = info->dma_rx_timeout;
+	pdata->auto_sus_timeout = info->auto_sus_timeout;
 	if (bdata->id == omap_uart_con_id)
 		pdata->console_uart = true;
 
@@ -371,17 +389,21 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 }
 
 /**
- * omap_serial_init() - initialize all supported serial ports
+ * omap_serial_board_init() - initialize all supported serial ports
+ * @info: platform specific data pointer
  *
  * Initializes all available UARTs as serial ports. Platforms
  * can call this function when they want to have default behaviour
  * for serial ports (e.g initialize them all as serial ports).
  */
-void __init omap_serial_init(void)
+void __init omap_serial_board_init(struct omap_uart_port_info *info)
 {
 	struct omap_board_data bdata;
 	u8 i;
 
+	if (info == NULL)
+		info = omap_serial_default_info;
+
 	for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
 		bdata.id = i;
 		bdata.flags = 0;
@@ -390,5 +412,19 @@ void __init omap_serial_init(void)
 
 		if (cpu_is_omap44xx() || cpu_is_omap34xx())
 			omap_serial_fill_default_pads(&bdata);
+
+		omap_serial_init_port(&bdata, info);
 	}
 }
+
+/**
+ * omap_serial_init() - initialize all supported serial ports
+ *
+ * Initializes all available UARTs.
+ * Platforms can call this function when they want to have default behaviour
+ * for serial ports (e.g initialize them all as serial ports).
+ */
+void __init omap_serial_init(void)
+{
+	omap_serial_board_init(NULL);
+}
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index ac30de8..4e2dcdc 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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 {
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index ab1761a..ee758d4 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -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
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 2ad8fa0..dc2743a 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 07/12] OMAP: Serial: Allow UART parameters to be configured from board file.
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Deepak K <deepak.k@ti.com>
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index ae2963a..2b44c86 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -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
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 73fa90b..946a558 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -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
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 8d74318..5ab626a 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -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
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 90485fc..c402d03 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -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
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 1651c2c..f38296e 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -44,6 +44,15 @@
 
 static int omap_uart_con_id __initdata = -1;
 
+static struct omap_uart_port_info omap_serial_default_info[] = {
+	{
+		.dma_enabled	= 0,
+		.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+		.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
+		.auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
+	},
+};
+
 static int uart_idle_hwmod(struct omap_device *od)
 {
 	omap_hwmod_idle(od->hwmods[0]);
@@ -313,6 +322,7 @@ core_initcall(omap_serial_early_init);
 /**
  * omap_serial_init_port() - initialize single serial port
  * @bdata: port specific board data pointer
+ * @info: platform specific data pointer
  *
  * This function initialies serial driver for given port only.
  * Platforms can call this function instead of omap_serial_init()
@@ -321,7 +331,8 @@ core_initcall(omap_serial_early_init);
  * Don't mix calls to omap_serial_init_port() and omap_serial_init(),
  * use only one of the two.
  */
-void __init omap_serial_init_port(struct omap_board_data *bdata)
+void __init omap_serial_init_port(struct omap_board_data *bdata,
+			struct omap_uart_port_info *info)
 {
 	struct omap_hwmod *oh;
 	struct omap_device *od;
@@ -339,6 +350,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 	if (!oh)
 		return;
 
+	if (info == NULL)
+		info = omap_serial_default_info;
+
 	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
 		pr_err("Memory allocation for UART pdata failed\n");
@@ -354,6 +368,10 @@ 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->dma_enabled = info->dma_enabled;
+	pdata->dma_rx_buf_size = info->dma_rx_buf_size;
+	pdata->dma_rx_timeout = info->dma_rx_timeout;
+	pdata->auto_sus_timeout = info->auto_sus_timeout;
 	if (bdata->id == omap_uart_con_id)
 		pdata->console_uart = true;
 
@@ -371,17 +389,21 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 }
 
 /**
- * omap_serial_init() - initialize all supported serial ports
+ * omap_serial_board_init() - initialize all supported serial ports
+ * @info: platform specific data pointer
  *
  * Initializes all available UARTs as serial ports. Platforms
  * can call this function when they want to have default behaviour
  * for serial ports (e.g initialize them all as serial ports).
  */
-void __init omap_serial_init(void)
+void __init omap_serial_board_init(struct omap_uart_port_info *info)
 {
 	struct omap_board_data bdata;
 	u8 i;
 
+	if (info == NULL)
+		info = omap_serial_default_info;
+
 	for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
 		bdata.id = i;
 		bdata.flags = 0;
@@ -390,5 +412,19 @@ void __init omap_serial_init(void)
 
 		if (cpu_is_omap44xx() || cpu_is_omap34xx())
 			omap_serial_fill_default_pads(&bdata);
+
+		omap_serial_init_port(&bdata, info);
 	}
 }
+
+/**
+ * omap_serial_init() - initialize all supported serial ports
+ *
+ * Initializes all available UARTs.
+ * Platforms can call this function when they want to have default behaviour
+ * for serial ports (e.g initialize them all as serial ports).
+ */
+void __init omap_serial_init(void)
+{
+	omap_serial_board_init(NULL);
+}
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index ac30de8..4e2dcdc 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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 {
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index ab1761a..ee758d4 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -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
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 2ad8fa0..dc2743a 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 08/12] Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, Jon Hunter, Govindraj.R

From: Jon Hunter <jon-hunter@ti.com>

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.

Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index f38296e..6ac078f 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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)
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 4e2dcdc..c5f4dd9 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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;
 };
 
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index dc2743a..307b7c6 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 08/12] Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jon Hunter <jon-hunter@ti.com>

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.

Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index f38296e..6ac078f 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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)
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 4e2dcdc..c5f4dd9 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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;
 };
 
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index dc2743a..307b7c6 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 09/12] OMAP3: Serial: Remove uart pads from 3430 board file.
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, 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.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/board-3430sdp.c |  100 +----------------------------------
 1 files changed, 1 insertions(+), 99 deletions(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 2b44c86..4e2baf7 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -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);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 09/12] OMAP3: Serial: Remove uart pads from 3430 board file.
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/board-3430sdp.c |  100 +----------------------------------
 1 files changed, 1 insertions(+), 99 deletions(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 2b44c86..4e2baf7 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -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);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 10/12] OMAP: Serial: Use resume call from prcm to enable uart
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, 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.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index c405bda..ba58a1d 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -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;
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index ac7b7f8..3997e92 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -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);
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 6ac078f..4bc5914 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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;
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index c5f4dd9..b5117bd 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index ee758d4..44a42aa 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -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
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 307b7c6..c3561dd 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 10/12] OMAP: Serial: Use resume call from prcm to enable uart
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index c405bda..ba58a1d 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -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;
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index ac7b7f8..3997e92 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -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);
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 6ac078f..4bc5914 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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;
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index c5f4dd9..b5117bd 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index ee758d4..44a42aa 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -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
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 307b7c6..c3561dd 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, 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.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 4bc5914..0a95c95 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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;
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index b5117bd..69e6d4b 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index c3561dd..dbe76f3 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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);
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 4bc5914..0a95c95 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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;
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index b5117bd..69e6d4b 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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__ */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index c3561dd..dbe76f3 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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);
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 12/12] OMAP4: Serial: Set TX_FIFO_THRESHOLD if uart in dma mode for es2.0
  2011-06-08 11:23 ` Govindraj.R
@ 2011-06-08 11:23   ` Govindraj.R
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-omap, linux-serial, linux-arm-kernel
  Cc: Tony Lindgren, Kevin Hilman, Govindraj.R

>From OMAP4430 ES2.0 onwards if uart is configured in dma mode we need to set
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

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 0a95c95..437fc0b 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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);
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 69e6d4b..0d10f72 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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 */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index dbe76f3..a9645ac 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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));
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v3 12/12] OMAP4: Serial: Set TX_FIFO_THRESHOLD if uart in dma mode for es2.0
@ 2011-06-08 11:23   ` Govindraj.R
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj.R @ 2011-06-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel


>From bogus@does.not.exist.com  Wed Jun  1 12:03:18 2011
From: bogus@does.not.exist.com ()
Date: Wed, 01 Jun 2011 16:03:18 -0000
Subject: No subject
Message-ID: <mailman.9.1307532245.24103.linux-arm-kernel@lists.infradead.org>

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

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 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(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 0a95c95..437fc0b 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -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);
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 69e6d4b..0d10f72 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -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 */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index dbe76f3..a9645ac 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -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));
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-08 20:39     ` Jon Hunter
  -1 siblings, 0 replies; 70+ messages in thread
From: Jon Hunter @ 2011-06-08 20:39 UTC (permalink / raw)
  To: Govindraj.R
  Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren, Kevin Hilman

Hi Govindraj,

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

[snip]

> +
> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

[snip]

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-08 20:39     ` Jon Hunter
  0 siblings, 0 replies; 70+ messages in thread
From: Jon Hunter @ 2011-06-08 20:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Govindraj,

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

[snip]

> +
> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */

[snip]

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-08 20:39     ` Jon Hunter
@ 2011-06-09  4:35       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-09  4:35 UTC (permalink / raw)
  To: Jon Hunter
  Cc: Govindraj.R, linux-omap, linux-serial, linux-arm-kernel,
	Tony Lindgren, Kevin Hilman

On Thu, Jun 9, 2011 at 2:09 AM, Jon Hunter <jon-hunter@ti.com> wrote:
> Hi Govindraj,
>
> On 6/8/2011 6:23 AM, Govindraj.R wrote:
>
> [snip]
>
>> +
>> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */
>
> [snip]
>
>> @@ -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?

Intention is to get approx 3 secs timeout for autosuspend.

--
Thanks,
Govindraj.R

>
> Cheers
> Jon
> --
> To unsubscribe from this list: send the line "unsubscribe linux-serial" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-09  4:35       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-09  4:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 9, 2011 at 2:09 AM, Jon Hunter <jon-hunter@ti.com> wrote:
> Hi Govindraj,
>
> On 6/8/2011 6:23 AM, Govindraj.R wrote:
>
> [snip]
>
>> +
>> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */
>
> [snip]
>
>> @@ -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?

Intention is to get approx 3 secs timeout for autosuspend.

--
Thanks,
Govindraj.R

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-09  4:35       ` Govindraj
@ 2011-06-09 20:49         ` Jon Hunter
  -1 siblings, 0 replies; 70+ messages in thread
From: Jon Hunter @ 2011-06-09 20:49 UTC (permalink / raw)
  To: Govindraj
  Cc: Govindraj.R, linux-omap, linux-serial, linux-arm-kernel,
	Tony Lindgren, Kevin Hilman

Hi Govindraj

On 06/08/2011 11:35 PM, Govindraj wrote:
> On Thu, Jun 9, 2011 at 2:09 AM, Jon Hunter<jon-hunter@ti.com>  wrote:
>> Hi Govindraj,
>>
>> On 6/8/2011 6:23 AM, Govindraj.R wrote:
>>
>> [snip]
>>
>>> +
>>> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */
>>
>> [snip]
>>
>>> @@ -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?
>
> 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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-09 20:49         ` Jon Hunter
  0 siblings, 0 replies; 70+ messages in thread
From: Jon Hunter @ 2011-06-09 20:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Govindraj

On 06/08/2011 11:35 PM, Govindraj wrote:
> On Thu, Jun 9, 2011 at 2:09 AM, Jon Hunter<jon-hunter@ti.com>  wrote:
>> Hi Govindraj,
>>
>> On 6/8/2011 6:23 AM, Govindraj.R wrote:
>>
>> [snip]
>>
>>> +
>>> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */
>>
>> [snip]
>>
>>> @@ -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?
>
> 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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-09 20:49         ` Jon Hunter
@ 2011-06-09 20:51           ` Jon Hunter
  -1 siblings, 0 replies; 70+ messages in thread
From: Jon Hunter @ 2011-06-09 20:51 UTC (permalink / raw)
  To: Govindraj
  Cc: Kevin Hilman, Tony Lindgren, Govindraj.R, linux-serial,
	linux-omap, linux-arm-kernel



On 06/09/2011 03:49 PM, Jon Hunter wrote:
> Hi Govindraj
>
> On 06/08/2011 11:35 PM, Govindraj wrote:
>> On Thu, Jun 9, 2011 at 2:09 AM, Jon Hunter<jon-hunter@ti.com> wrote:
>>> Hi Govindraj,
>>>
>>> On 6/8/2011 6:23 AM, Govindraj.R wrote:
>>>
>>> [snip]
>>>
>>>> +
>>>> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */
>>>
>>> [snip]
>>>
>>>> @@ -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?
>>
>> 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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-09 20:51           ` Jon Hunter
  0 siblings, 0 replies; 70+ messages in thread
From: Jon Hunter @ 2011-06-09 20:51 UTC (permalink / raw)
  To: linux-arm-kernel



On 06/09/2011 03:49 PM, Jon Hunter wrote:
> Hi Govindraj
>
> On 06/08/2011 11:35 PM, Govindraj wrote:
>> On Thu, Jun 9, 2011 at 2:09 AM, Jon Hunter<jon-hunter@ti.com> wrote:
>>> Hi Govindraj,
>>>
>>> On 6/8/2011 6:23 AM, Govindraj.R wrote:
>>>
>>> [snip]
>>>
>>>> +
>>>> +#define OMAP_UART_AUTOSUSPEND_DELAY (30 * HZ) /* Value is msecs */
>>>
>>> [snip]
>>>
>>>> @@ -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?
>>
>> 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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 02/12] OMAP2+: UART: Remove uart clock handling code from serial.c
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-24 22:28     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-24 22:28 UTC (permalink / raw)
  To: Govindraj.R; +Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

"Govindraj.R" <govindraj.raja@ti.com> writes:

> 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.
>
> Acked-by: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

[...]

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

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

Rest of this looks fine.

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 02/12] OMAP2+: UART: Remove uart clock handling code from serial.c
@ 2011-06-24 22:28     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-24 22:28 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

> 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.
>
> Acked-by: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

[...]

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

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

Rest of this looks fine.

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 09/12] OMAP3: Serial: Remove uart pads from 3430 board file.
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-24 22:29     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-24 22:29 UTC (permalink / raw)
  To: Govindraj.R; +Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

"Govindraj.R" <govindraj.raja@ti.com> writes:

> The pad values here are same as the default pad values updated in
> serial.c file.
> Avoid structure duplication and use default pads.
>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

This should be folded in with [03/12]

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 09/12] OMAP3: Serial: Remove uart pads from 3430 board file.
@ 2011-06-24 22:29     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-24 22:29 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

> The pad values here are same as the default pad values updated in
> serial.c file.
> Avoid structure duplication and use default pads.
>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

This should be folded in with [03/12]

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-24 23:30     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-24 23:30 UTC (permalink / raw)
  To: Govindraj.R; +Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

"Govindraj.R" <govindraj.raja@ti.com> writes:

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

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

>
> Acked-by: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

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

> ---
>  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(-)
>
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 8c1a4c7..1651c2c 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -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);
> +	}

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?

> +	/* 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;
>  
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index 2ca885b..ac30de8 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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__ */
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 47cadf4..897416f 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -37,10 +37,14 @@
>  #include <linux/clk.h>
>  #include <linux/serial_core.h>
>  #include <linux/irq.h>
> +#include <linux/pm_runtime.h>
>  
>  #include <plat/dma.h>
>  #include <plat/dmtimer.h>
>  #include <plat/omap-serial.h>
> +#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.

>  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);
>  }
>  
> +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...

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

>  }
>  
>  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);
> @@ -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? 

>  }
>  
>  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
> -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()

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

> +	}
>  	return 0;
>  }

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

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

> +	}
> +
>  	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)
> +{
> +	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.

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

> +	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 = {
>  	.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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-24 23:30     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-24 23:30 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

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

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

>
> Acked-by: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

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

> ---
>  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(-)
>
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 8c1a4c7..1651c2c 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -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);
> +	}

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?

> +	/* 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;
>  
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index 2ca885b..ac30de8 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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__ */
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 47cadf4..897416f 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -37,10 +37,14 @@
>  #include <linux/clk.h>
>  #include <linux/serial_core.h>
>  #include <linux/irq.h>
> +#include <linux/pm_runtime.h>
>  
>  #include <plat/dma.h>
>  #include <plat/dmtimer.h>
>  #include <plat/omap-serial.h>
> +#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.

>  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);
>  }
>  
> +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...

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

>  }
>  
>  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);
> @@ -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? 

>  }
>  
>  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
> -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()

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

> +	}
>  	return 0;
>  }

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

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

> +	}
> +
>  	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)
> +{
> +	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.

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

> +	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 = {
>  	.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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-25  0:06     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:06 UTC (permalink / raw)
  To: Govindraj.R; +Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

"Govindraj.R" <govindraj.raja@ti.com> writes:

> 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
>
> Acked-by: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
> ---
>  drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
>  1 files changed, 19 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 897416f..ee94291 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -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?

> +	/*
> +	 * 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/

> +	 * 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.)

> +	 */
> +
> +	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.

>  	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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
@ 2011-06-25  0:06     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:06 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

> 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
>
> Acked-by: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
> ---
>  drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
>  1 files changed, 19 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 897416f..ee94291 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -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?

> +	/*
> +	 * 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/

> +	 * 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.)

> +	 */
> +
> +	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.

>  	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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 07/12] OMAP: Serial: Allow UART parameters to be configured from board file.
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-25  0:12     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:12 UTC (permalink / raw)
  To: Govindraj.R
  Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren,
	Deepak K, Jon Hunter

"Govindraj.R" <govindraj.raja@ti.com> writes:

> 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.
>
> Signed-off-by: Deepak K <deepak.k@ti.com>
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

Nice.  some minor comments below.

[...]

> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index ac30de8..4e2dcdc 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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

> +
>  #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.

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

rename to autosuspend_timeout, drop comment.

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 07/12] OMAP: Serial: Allow UART parameters to be configured from board file.
@ 2011-06-25  0:12     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:12 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

> 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.
>
> Signed-off-by: Deepak K <deepak.k@ti.com>
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

Nice.  some minor comments below.

[...]

> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index ac30de8..4e2dcdc 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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

> +
>  #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.

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

rename to autosuspend_timeout, drop comment.

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 08/12] Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-25  0:16     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:16 UTC (permalink / raw)
  To: Govindraj.R
  Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren, Jon Hunter

"Govindraj.R" <govindraj.raja@ti.com> writes:

> From: Jon Hunter <jon-hunter@ti.com>
>
> 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.
>
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

Acked-by: Kevin Hilman <khilman@ti.com>

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

Kevin



^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 08/12] Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART
@ 2011-06-25  0:16     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:16 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

> From: Jon Hunter <jon-hunter@ti.com>
>
> 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.
>
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>

Acked-by: Kevin Hilman <khilman@ti.com>

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

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 10/12] OMAP: Serial: Use resume call from prcm to enable uart
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-25  0:23     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:23 UTC (permalink / raw)
  To: Govindraj.R; +Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

"Govindraj.R" <govindraj.raja@ti.com> writes:

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

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

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

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

> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
> ---
>  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(-)
>
> diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
> index c405bda..ba58a1d 100644
> --- a/arch/arm/mach-omap2/pm24xx.c
> +++ b/arch/arm/mach-omap2/pm24xx.c
> @@ -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;
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index ac7b7f8..3997e92 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -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);
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 6ac078f..4bc5914 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -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/

> +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;
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index c5f4dd9..b5117bd 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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__ */
> diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
> index ee758d4..44a42aa 100644
> --- a/arch/arm/plat-omap/include/plat/serial.h
> +++ b/arch/arm/plat-omap/include/plat/serial.h
> @@ -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
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 307b7c6..c3561dd 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -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;

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 10/12] OMAP: Serial: Use resume call from prcm to enable uart
@ 2011-06-25  0:23     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:23 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

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

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

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

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

> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
> ---
>  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(-)
>
> diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
> index c405bda..ba58a1d 100644
> --- a/arch/arm/mach-omap2/pm24xx.c
> +++ b/arch/arm/mach-omap2/pm24xx.c
> @@ -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;
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index ac7b7f8..3997e92 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -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);
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 6ac078f..4bc5914 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -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/

> +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;
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index c5f4dd9..b5117bd 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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__ */
> diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
> index ee758d4..44a42aa 100644
> --- a/arch/arm/plat-omap/include/plat/serial.h
> +++ b/arch/arm/plat-omap/include/plat/serial.h
> @@ -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
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 307b7c6..c3561dd 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -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;

Kevin

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
  2011-06-08 11:23   ` Govindraj.R
@ 2011-06-25  0:29     ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:29 UTC (permalink / raw)
  To: Govindraj.R; +Cc: linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

"Govindraj.R" <govindraj.raja@ti.com> writes:

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

> 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

> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
> ---
>  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(-)
>
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 4bc5914..0a95c95 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -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;
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index b5117bd..69e6d4b 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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__ */
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index c3561dd..dbe76f3 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -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);

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
@ 2011-06-25  0:29     ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-25  0:29 UTC (permalink / raw)
  To: linux-arm-kernel

"Govindraj.R" <govindraj.raja@ti.com> writes:

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

> 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

> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
> ---
>  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(-)
>
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 4bc5914..0a95c95 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -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;
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index b5117bd..69e6d4b 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -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__ */
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index c3561dd..dbe76f3 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -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);

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 02/12] OMAP2+: UART: Remove uart clock handling code from serial.c
  2011-06-24 22:28     ` Kevin Hilman
@ 2011-06-27 12:49       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 12:49 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Tony Lindgren, Govindraj.R, linux-omap, linux-arm-kernel, linux-serial

On Sat, Jun 25, 2011 at 3:58 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.
>>
>> Acked-by: Alan Cox <alan@linux.intel.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> [...]
>
>> @@ -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
>
> Minor: only whitespace change here, you converted tabs to spaces.

yes, will correct this.

--
Govindraj.R

>
> 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 02/12] OMAP2+: UART: Remove uart clock handling code from serial.c
@ 2011-06-27 12:49       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 25, 2011 at 3:58 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.
>>
>> Acked-by: Alan Cox <alan@linux.intel.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> [...]
>
>> @@ -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
>
> Minor: only whitespace change here, you converted tabs to spaces.

yes, will correct this.

--
Govindraj.R

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 09/12] OMAP3: Serial: Remove uart pads from 3430 board file.
  2011-06-24 22:29     ` Kevin Hilman
@ 2011-06-27 12:51       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 12:51 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Tony Lindgren, Govindraj.R, linux-omap, linux-arm-kernel, linux-serial

On Sat, Jun 25, 2011 at 3:59 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> The pad values here are same as the default pad values updated in
>> serial.c file.
>> Avoid structure duplication and use default pads.
>>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> This should be folded in with [03/12]

agree.

--
Govindraj.R

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 09/12] OMAP3: Serial: Remove uart pads from 3430 board file.
@ 2011-06-27 12:51       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 12:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 25, 2011 at 3:59 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> The pad values here are same as the default pad values updated in
>> serial.c file.
>> Avoid structure duplication and use default pads.
>>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> This should be folded in with [03/12]

agree.

--
Govindraj.R

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 07/12] OMAP: Serial: Allow UART parameters to be configured from board file.
  2011-06-25  0:12     ` Kevin Hilman
@ 2011-06-27 12:53       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 12:53 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Tony Lindgren, Deepak K, Govindraj.R, Jon Hunter, linux-serial,
	linux-omap, linux-arm-kernel

On Sat, Jun 25, 2011 at 5:42 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.
>>
>> Signed-off-by: Deepak K <deepak.k@ti.com>
>> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> Nice.  some minor comments below.
>
> [...]
>
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index ac30de8..4e2dcdc 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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
>

Yes fine will move them to serial.c

>> +
>>  #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.
>

will drop those comments.

>> +     unsigned int            auto_sus_timeout; /* Auto_suspend timeout */
>
> rename to autosuspend_timeout, drop comment.

ok.

--
Thanks,
Govindraj.R

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 07/12] OMAP: Serial: Allow UART parameters to be configured from board file.
@ 2011-06-27 12:53       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 12:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 25, 2011 at 5:42 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.
>>
>> Signed-off-by: Deepak K <deepak.k@ti.com>
>> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> Nice. ?some minor comments below.
>
> [...]
>
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index ac30de8..4e2dcdc 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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
>

Yes fine will move them to serial.c

>> +
>> ?#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.
>

will drop those comments.

>> + ? ? unsigned int ? ? ? ? ? ?auto_sus_timeout; /* Auto_suspend timeout */
>
> rename to autosuspend_timeout, drop comment.

ok.

--
Thanks,
Govindraj.R

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
  2011-06-25  0:29     ` Kevin Hilman
@ 2011-06-27 13:09       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 13:09 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Tony Lindgren, Govindraj.R, linux-omap, linux-arm-kernel, linux-serial

On Sat, Jun 25, 2011 at 5:59 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.


> 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);
}


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

> Kevin
>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>> ---
>>  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(-)
>>
>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>> index 4bc5914..0a95c95 100644
>> --- a/arch/arm/mach-omap2/serial.c
>> +++ b/arch/arm/mach-omap2/serial.c
>> @@ -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;
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index b5117bd..69e6d4b 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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__ */
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index c3561dd..dbe76f3 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -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);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-serial" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
@ 2011-06-27 13:09       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 13:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 25, 2011 at 5:59 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.


> 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);
}


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

> Kevin
>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>> ---
>> ?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(-)
>>
>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>> index 4bc5914..0a95c95 100644
>> --- a/arch/arm/mach-omap2/serial.c
>> +++ b/arch/arm/mach-omap2/serial.c
>> @@ -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;
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index b5117bd..69e6d4b 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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__ */
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index c3561dd..dbe76f3 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -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);
> --
> 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
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
  2011-06-25  0:06     ` Kevin Hilman
@ 2011-06-27 13:35       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 13:35 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Tony Lindgren, Govindraj.R, linux-omap, linux-arm-kernel, linux-serial

On Sat, Jun 25, 2011 at 5:36 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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
>>
>> Acked-by: Alan Cox <alan@linux.intel.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>> ---
>>  drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
>>  1 files changed, 19 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index 897416f..ee94291 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -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?
>

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.

>> +     /*
>> +      * 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.

>
>> +      * 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.

> I still don't fully understand this problem,

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

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


>
>> +      */
>> +
>> +     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


>>       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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
@ 2011-06-27 13:35       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 13:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 25, 2011 at 5:36 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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
>>
>> Acked-by: Alan Cox <alan@linux.intel.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>> ---
>> ?drivers/tty/serial/omap-serial.c | ? 20 +++++++++++++++++++-
>> ?1 files changed, 19 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index 897416f..ee94291 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -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?
>

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.

>> + ? ? /*
>> + ? ? ?* 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.

>
>> + ? ? ?* 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.

> I still don't fully understand this problem,

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

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


>
>> + ? ? ?*/
>> +
>> + ? ? 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


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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-24 23:30     ` Kevin Hilman
@ 2011-06-27 14:31       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 14:31 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Govindraj.R, linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

On Sat, Jun 25, 2011 at 5:00 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.
>
>> 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.
>
>>
>> Acked-by: Alan Cox <alan@linux.intel.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> This is great!  we're almost there.   Some minor comments below...
>
>> ---
>>  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(-)
>>
>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>> index 8c1a4c7..1651c2c 100644
>> --- a/arch/arm/mach-omap2/serial.c
>> +++ b/arch/arm/mach-omap2/serial.c
>> @@ -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);
>> +     }
>
> 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.


>> +     /* 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;
>>
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index 2ca885b..ac30de8 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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__ */
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index 47cadf4..897416f 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -37,10 +37,14 @@
>>  #include <linux/clk.h>
>>  #include <linux/serial_core.h>
>>  #include <linux/irq.h>
>> +#include <linux/pm_runtime.h>
>>
>>  #include <plat/dma.h>
>>  #include <plat/dmtimer.h>
>>  #include <plat/omap-serial.h>
>> +#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.

>>  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);
>>  }
>>
>> +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.


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

ok. I will check them.

>>  }
>>
>>  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);
>> @@ -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?
>

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

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

>
>>  }
>>
>>  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
>> -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()
>

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.


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


> 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.
>
>> +     }
>>       return 0;
>>  }
>
> Also, device wakeup capability should be checked and enabled/disabled in
> the suspend path (not only the runtime suspend path.)
>

ok.


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

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

>> +     }
>> +
>>       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)
>> +{
>> +     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.
>

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.

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

ok.

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

agree, will use that API.

--
Thanks,
Govindraj.R

>> +     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 = {
>>       .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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-27 14:31       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 25, 2011 at 5:00 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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.
>
>> 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.
>
>>
>> Acked-by: Alan Cox <alan@linux.intel.com>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> This is great! ?we're almost there. ? Some minor comments below...
>
>> ---
>> ?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(-)
>>
>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>> index 8c1a4c7..1651c2c 100644
>> --- a/arch/arm/mach-omap2/serial.c
>> +++ b/arch/arm/mach-omap2/serial.c
>> @@ -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);
>> + ? ? }
>
> 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.


>> + ? ? /* 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;
>>
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index 2ca885b..ac30de8 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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__ */
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index 47cadf4..897416f 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -37,10 +37,14 @@
>> ?#include <linux/clk.h>
>> ?#include <linux/serial_core.h>
>> ?#include <linux/irq.h>
>> +#include <linux/pm_runtime.h>
>>
>> ?#include <plat/dma.h>
>> ?#include <plat/dmtimer.h>
>> ?#include <plat/omap-serial.h>
>> +#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.

>> ?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);
>> ?}
>>
>> +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.


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

ok. I will check them.

>> ?}
>>
>> ?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);
>> @@ -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?
>

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

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

>
>> ?}
>>
>> ?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
>> -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()
>

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.


>> + ? ? ? ? ? ? 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)


> 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.
>
>> + ? ? }
>> ? ? ? return 0;
>> ?}
>
> Also, device wakeup capability should be checked and enabled/disabled in
> the suspend path (not only the runtime suspend path.)
>

ok.


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

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

>> + ? ? }
>> +
>> ? ? ? 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)
>> +{
>> + ? ? 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.
>

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.

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

ok.

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

agree, will use that API.

--
Thanks,
Govindraj.R

>> + ? ? 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 = {
>> ? ? ? .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
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 10/12] OMAP: Serial: Use resume call from prcm to enable uart
  2011-06-25  0:23     ` Kevin Hilman
@ 2011-06-27 15:03       ` Govindraj
  -1 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 15:03 UTC (permalink / raw)
  To: Kevin Hilman, Tero Kristo
  Cc: Govindraj.R, linux-omap, linux-serial, linux-arm-kernel, Tony Lindgren

On Sat, Jun 25, 2011 at 5:53 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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?
>
>> 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)
>
>> 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

>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>> ---
>>  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(-)
>>
>> diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
>> index c405bda..ba58a1d 100644
>> --- a/arch/arm/mach-omap2/pm24xx.c
>> +++ b/arch/arm/mach-omap2/pm24xx.c
>> @@ -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;
>> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
>> index ac7b7f8..3997e92 100644
>> --- a/arch/arm/mach-omap2/pm34xx.c
>> +++ b/arch/arm/mach-omap2/pm34xx.c
>> @@ -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);
>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>> index 6ac078f..4bc5914 100644
>> --- a/arch/arm/mach-omap2/serial.c
>> +++ b/arch/arm/mach-omap2/serial.c
>> @@ -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/
>
>> +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;
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index c5f4dd9..b5117bd 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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__ */
>> diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
>> index ee758d4..44a42aa 100644
>> --- a/arch/arm/plat-omap/include/plat/serial.h
>> +++ b/arch/arm/plat-omap/include/plat/serial.h
>> @@ -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
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index 307b7c6..c3561dd 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -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;
>
> Kevin
> --
> To unsubscribe from this list: send the line "unsubscribe linux-serial" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 10/12] OMAP: Serial: Use resume call from prcm to enable uart
@ 2011-06-27 15:03       ` Govindraj
  0 siblings, 0 replies; 70+ messages in thread
From: Govindraj @ 2011-06-27 15:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 25, 2011 at 5:53 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> 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?
>
>> 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)
>
>> 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

>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>> ---
>> ?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(-)
>>
>> diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
>> index c405bda..ba58a1d 100644
>> --- a/arch/arm/mach-omap2/pm24xx.c
>> +++ b/arch/arm/mach-omap2/pm24xx.c
>> @@ -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;
>> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
>> index ac7b7f8..3997e92 100644
>> --- a/arch/arm/mach-omap2/pm34xx.c
>> +++ b/arch/arm/mach-omap2/pm34xx.c
>> @@ -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);
>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>> index 6ac078f..4bc5914 100644
>> --- a/arch/arm/mach-omap2/serial.c
>> +++ b/arch/arm/mach-omap2/serial.c
>> @@ -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/
>
>> +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;
>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>> index c5f4dd9..b5117bd 100644
>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>> @@ -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__ */
>> diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
>> index ee758d4..44a42aa 100644
>> --- a/arch/arm/plat-omap/include/plat/serial.h
>> +++ b/arch/arm/plat-omap/include/plat/serial.h
>> @@ -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
>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>> index 307b7c6..c3561dd 100644
>> --- a/drivers/tty/serial/omap-serial.c
>> +++ b/drivers/tty/serial/omap-serial.c
>> @@ -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;
>
> 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
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
  2011-06-27 13:09       ` Govindraj
@ 2011-06-27 22:28         ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-27 22:28 UTC (permalink / raw)
  To: Govindraj
  Cc: Tony Lindgren, Govindraj.R, linux-omap, linux-arm-kernel, linux-serial

Govindraj <govindraj.ti@gmail.com> writes:

> On Sat, Jun 25, 2011 at 5:59 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> 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.
>
>
>> 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);
> }

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

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



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag.
@ 2011-06-27 22:28         ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-27 22:28 UTC (permalink / raw)
  To: linux-arm-kernel

Govindraj <govindraj.ti@gmail.com> writes:

> On Sat, Jun 25, 2011 at 5:59 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> 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.
>
>
>> 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);
> }

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

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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
  2011-06-27 13:35       ` Govindraj
@ 2011-06-27 22:41         ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-27 22:41 UTC (permalink / raw)
  To: Govindraj
  Cc: Tony Lindgren, Govindraj.R, linux-omap, linux-arm-kernel, linux-serial

Govindraj <govindraj.ti@gmail.com> writes:

> On Sat, Jun 25, 2011 at 5:36 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> 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
>>>
>>> Acked-by: Alan Cox <alan@linux.intel.com>
>>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>>> ---
>>>  drivers/tty/serial/omap-serial.c |   20 +++++++++++++++++++-
>>>  1 files changed, 19 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>>> index 897416f..ee94291 100644
>>> --- a/drivers/tty/serial/omap-serial.c
>>> +++ b/drivers/tty/serial/omap-serial.c
>>> @@ -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?
>>
>
> 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.

>>> +     /*
>>> +      * 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.
>
>>
>>> +      * 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.

Which as I said, is not well described.

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

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

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

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

>
>>
>>> +      */
>>> +
>>> +     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.

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.

> 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


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage.
@ 2011-06-27 22:41         ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-27 22:41 UTC (permalink / raw)
  To: linux-arm-kernel

Govindraj <govindraj.ti@gmail.com> writes:

> On Sat, Jun 25, 2011 at 5:36 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> 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
>>>
>>> Acked-by: Alan Cox <alan@linux.intel.com>
>>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>>> ---
>>> ?drivers/tty/serial/omap-serial.c | ? 20 +++++++++++++++++++-
>>> ?1 files changed, 19 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>>> index 897416f..ee94291 100644
>>> --- a/drivers/tty/serial/omap-serial.c
>>> +++ b/drivers/tty/serial/omap-serial.c
>>> @@ -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?
>>
>
> 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.

>>> + ? ? /*
>>> + ? ? ?* 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.
>
>>
>>> + ? ? ?* 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.

Which as I said, is not well described.

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

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

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

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

>
>>
>>> + ? ? ?*/
>>> +
>>> + ? ? 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.

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.

> 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

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
  2011-06-27 14:31       ` Govindraj
@ 2011-06-27 22:57         ` Kevin Hilman
  -1 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-27 22:57 UTC (permalink / raw)
  To: Govindraj
  Cc: Tony Lindgren, Govindraj.R, linux-omap, linux-arm-kernel, linux-serial

Govindraj <govindraj.ti@gmail.com> writes:

> On Sat, Jun 25, 2011 at 5:00 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> 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.
>>
>>> 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.
>>
>>>
>>> Acked-by: Alan Cox <alan@linux.intel.com>
>>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>>
>> This is great!  we're almost there.   Some minor comments below...
>>
>>> ---
>>>  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(-)
>>>
>>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>>> index 8c1a4c7..1651c2c 100644
>>> --- a/arch/arm/mach-omap2/serial.c
>>> +++ b/arch/arm/mach-omap2/serial.c
>>> @@ -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);
>>> +     }
>>
>> 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,

where default is the PRCM init code, yes.

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

>>> +     /* 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;
>>>
>>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>>> index 2ca885b..ac30de8 100644
>>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>>> @@ -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__ */
>>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>>> index 47cadf4..897416f 100644
>>> --- a/drivers/tty/serial/omap-serial.c
>>> +++ b/drivers/tty/serial/omap-serial.c
>>> @@ -37,10 +37,14 @@
>>>  #include <linux/clk.h>
>>>  #include <linux/serial_core.h>
>>>  #include <linux/irq.h>
>>> +#include <linux/pm_runtime.h>
>>>
>>>  #include <plat/dma.h>
>>>  #include <plat/dmtimer.h>
>>>  #include <plat/omap-serial.h>
>>> +#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.
>
>>>  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);
>>>  }
>>>
>>> +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.
>
>
>>>  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.
>>
>
> ok. I will check them.
>
>>>  }
>>>
>>>  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);
>>> @@ -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?
>>
>
> yes also during bootup.
> disable the ports immediately that are not used during bootup.
>
>> 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.

>>
>>>  }
>>>
>>>  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
>>> -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()
>>
>
> 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.

> log prints after uart suspend and print them during resume.
>
>
>>> +             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)

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

>> 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.
>>
>>> +     }
>>>       return 0;
>>>  }
>>
>> Also, device wakeup capability should be checked and enabled/disabled in
>> the suspend path (not only the runtime suspend path.)
>>
>
> ok.
>
>
>>> -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?
>>
>
> need to add a flag to check and unlock
> from return status of trylock.
>
>>> +     }
>>> +
>>>       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)
>>> +{
>>> +     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.
>>
>
> 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. 

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

OK


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver
@ 2011-06-27 22:57         ` Kevin Hilman
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin Hilman @ 2011-06-27 22:57 UTC (permalink / raw)
  To: linux-arm-kernel

Govindraj <govindraj.ti@gmail.com> writes:

> On Sat, Jun 25, 2011 at 5:00 AM, Kevin Hilman <khilman@ti.com> wrote:
>> "Govindraj.R" <govindraj.raja@ti.com> writes:
>>
>>> 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.
>>
>>> 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.
>>
>>>
>>> Acked-by: Alan Cox <alan@linux.intel.com>
>>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>>
>> This is great! ?we're almost there. ? Some minor comments below...
>>
>>> ---
>>> ?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(-)
>>>
>>> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
>>> index 8c1a4c7..1651c2c 100644
>>> --- a/arch/arm/mach-omap2/serial.c
>>> +++ b/arch/arm/mach-omap2/serial.c
>>> @@ -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);
>>> + ? ? }
>>
>> 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,

where default is the PRCM init code, yes.

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

>>> + ? ? /* 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;
>>>
>>> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
>>> index 2ca885b..ac30de8 100644
>>> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
>>> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
>>> @@ -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__ */
>>> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
>>> index 47cadf4..897416f 100644
>>> --- a/drivers/tty/serial/omap-serial.c
>>> +++ b/drivers/tty/serial/omap-serial.c
>>> @@ -37,10 +37,14 @@
>>> ?#include <linux/clk.h>
>>> ?#include <linux/serial_core.h>
>>> ?#include <linux/irq.h>
>>> +#include <linux/pm_runtime.h>
>>>
>>> ?#include <plat/dma.h>
>>> ?#include <plat/dmtimer.h>
>>> ?#include <plat/omap-serial.h>
>>> +#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.
>
>>> ?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);
>>> ?}
>>>
>>> +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.
>
>
>>> ?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.
>>
>
> ok. I will check them.
>
>>> ?}
>>>
>>> ?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);
>>> @@ -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?
>>
>
> yes also during bootup.
> disable the ports immediately that are not used during bootup.
>
>> 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.

>>
>>> ?}
>>>
>>> ?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
>>> -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()
>>
>
> 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.

> log prints after uart suspend and print them during resume.
>
>
>>> + ? ? ? ? ? ? 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)

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

>> 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.
>>
>>> + ? ? }
>>> ? ? ? return 0;
>>> ?}
>>
>> Also, device wakeup capability should be checked and enabled/disabled in
>> the suspend path (not only the runtime suspend path.)
>>
>
> ok.
>
>
>>> -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?
>>
>
> need to add a flag to check and unlock
> from return status of trylock.
>
>>> + ? ? }
>>> +
>>> ? ? ? 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)
>>> +{
>>> + ? ? 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.
>>
>
> 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. 

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

OK

^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2011-06-27 22:57 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-08 11:23 [PATCH v3 00/12] OMAP2+: Serial: Runtime adaptation + cleanup Govindraj.R
2011-06-08 11:23 ` Govindraj.R
2011-06-08 11:23 ` [PATCH v3 01/12] OMAP2+: UART: Remove certain uart calls from sram_idle Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-08 11:23 ` [PATCH v3 02/12] OMAP2+: UART: Remove uart clock handling code from serial.c Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-24 22:28   ` Kevin Hilman
2011-06-24 22:28     ` Kevin Hilman
2011-06-27 12:49     ` Govindraj
2011-06-27 12:49       ` Govindraj
2011-06-08 11:23 ` [PATCH v3 03/12] OMAP2+: Serial: Add default mux for all uarts Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-08 11:23 ` [PATCH v3 04/12] Serial: OMAP: Add runtime pm support for omap-serial driver Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-08 20:39   ` Jon Hunter
2011-06-08 20:39     ` Jon Hunter
2011-06-09  4:35     ` Govindraj
2011-06-09  4:35       ` Govindraj
2011-06-09 20:49       ` Jon Hunter
2011-06-09 20:49         ` Jon Hunter
2011-06-09 20:51         ` Jon Hunter
2011-06-09 20:51           ` Jon Hunter
2011-06-24 23:30   ` Kevin Hilman
2011-06-24 23:30     ` Kevin Hilman
2011-06-27 14:31     ` Govindraj
2011-06-27 14:31       ` Govindraj
2011-06-27 22:57       ` Kevin Hilman
2011-06-27 22:57         ` Kevin Hilman
2011-06-08 11:23 ` [PATCH v3 05/12] OMAP: Serial: Hold console lock for console usage Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-25  0:06   ` Kevin Hilman
2011-06-25  0:06     ` Kevin Hilman
2011-06-27 13:35     ` Govindraj
2011-06-27 13:35       ` Govindraj
2011-06-27 22:41       ` Kevin Hilman
2011-06-27 22:41         ` Kevin Hilman
2011-06-08 11:23 ` [PATCH v3 06/12] Serial: OMAP2+: Move erratum handling from serial.c Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-08 11:23 ` [PATCH v3 07/12] OMAP: Serial: Allow UART parameters to be configured from board file Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-25  0:12   ` Kevin Hilman
2011-06-25  0:12     ` Kevin Hilman
2011-06-27 12:53     ` Govindraj
2011-06-27 12:53       ` Govindraj
2011-06-08 11:23 ` [PATCH v3 08/12] Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-25  0:16   ` Kevin Hilman
2011-06-25  0:16     ` Kevin Hilman
2011-06-08 11:23 ` [PATCH v3 09/12] OMAP3: Serial: Remove uart pads from 3430 board file Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-24 22:29   ` Kevin Hilman
2011-06-24 22:29     ` Kevin Hilman
2011-06-27 12:51     ` Govindraj
2011-06-27 12:51       ` Govindraj
2011-06-08 11:23 ` [PATCH v3 10/12] OMAP: Serial: Use resume call from prcm to enable uart Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-25  0:23   ` Kevin Hilman
2011-06-25  0:23     ` Kevin Hilman
2011-06-27 15:03     ` Govindraj
2011-06-27 15:03       ` Govindraj
2011-06-08 11:23 ` [PATCH v3 11/12] OMAP2: Serial: Add has_async_wake flag Govindraj.R
2011-06-08 11:23   ` Govindraj.R
2011-06-25  0:29   ` Kevin Hilman
2011-06-25  0:29     ` Kevin Hilman
2011-06-27 13:09     ` Govindraj
2011-06-27 13:09       ` Govindraj
2011-06-27 22:28       ` Kevin Hilman
2011-06-27 22:28         ` Kevin Hilman
2011-06-08 11:23 ` [PATCH v3 12/12] OMAP4: Serial: Set TX_FIFO_THRESHOLD if uart in dma mode for es2.0 Govindraj.R
2011-06-08 11:23   ` Govindraj.R

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.