Re: Suspend broken on 3.3?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Mar 28, 2012 at 3:07 AM, Kevin Hilman <khilman@xxxxxx> wrote:
> "Raja, Govindraj" <govindraj.raja@xxxxxx> writes:
>
>> Hi Kevin,
>>
>> On Tue, Mar 27, 2012 at 6:04 AM, Kevin Hilman <khilman@xxxxxx> wrote:
>>> +Govindraj,
>>>
>>> "Joe Woodward" <jw@xxxxxxxxxxxxxx> writes:
>>>
>>>> Right, I've stepped back a bit and dug out a GUSMTIX Palo43 carrier
>>>> board on which to test the Overo OMAP3530 COM and I've found:
>>>>  - Running a stock 3.3 (with absolutely no changes) does indeed suspend correctly.
>>>>  - Running the 3.3 kernel with my (minor) board modifications
>>>>  (basically defining some buttons) suspends correctly as well.
>>>>
>>>> Then I went back to my original board and the 3.3 still wakes up from
>>>> suspend immediately. So I had a think, and the only real differences
>>>> between my board the the GUMSTIX Palo43 board is that I am using
>>>> multiple UARTs.
>>>>
>>>> Up to this point I've only wanted to wake on the console (ttyO2), and
>>>> not any other UARTs so I've stopped them waking with:
>>>>   echo disabled > /sys/devices/platform/omap/omap_uart.0/power/wakeup
>>>>   echo disabled > /sys/devices/platform/omap/omap_uart.1/power/wakeup
>>>>
>>>> I wanted to check that this still worked, so tried disabling wakeup on
>>>> the console (ttyO2):
>>>>   echo disabled > /sys/devices/platform/omap/omap_uart.2/power/wakeup
>>>>
>>>> And if I do "echo mem > /sys/power/state" I was expecting to stay in
>>>> suspend when I typed on my keyboard... However, the kernel still woke
>>>> from suspend, which leads me to believe that the UART wakeup hasn't
>>>> been disabled?
>>>
>>> Just to confirm: did the above work for you before v3.3?
>>>
>>>> Could you test if this is also the case your end?
>>>
>>> Yes, I get the same behavior, which is indeed broken.
>>>
>>> Govindraj, can you look into this?
>>>
>>> A quick glance suggests that disabling wakeups via the sysfs file is
>>> only disabling runtime PM, but not actually disabling wakups at the
>>> module-level or at the IO ring.
>>>
>>
>> I have started looking into this, disabling and enabling of wake-ups
>> from .runtime_suspend needs some changes as in here[1] with that I see pad
>> wakeup getting disabled and it doesn't wake up after enabling off mode
>> and suspending.
>
> Thanks for looking into this.
>

Looks like the module wakeup event handling left to default
value during runtime clean up is causing the wakeup to happen

Here is the patch[1] to fix the same tested on 3430SDP.

--
Thanks,
Govindraj.R

[1]:


>From 5a5126750d527811547a45de9546c3e0f0fac77d Mon Sep 17 00:00:00 2001
From: "Govindraj.R" <govindraj.raja@xxxxxx>
Date: Tue, 27 Mar 2012 18:55:00 +0530
Subject: [PATCH] OMAP2+: UART: Correct the module level wakeup enable/disable
 mechanism

The commit (62f3ec5  ARM: OMAP2+: UART: Add wakeup mechanism for omap-uarts)
removed module level wakeup enable/disable mechanism and retained only
the pad wakeup handling.

On 24xx/34xx/36xx Module level wakeup events are enabled/disabled using
PM_WKEN1_CORE/PM_WKEN_PER regs. The module level wakeups are enabled by
default from bootloader, however the wakeups can be enabled/disabled
using sysfs entry
echo disabled > /sys/devices/platform/omap/omap_uart.X/power/wakeup
[X=0,1,2,3]

Since module level wakeups were left enabled from bootup and when
wakeups were disabled from sysfs uart module level wakeups were
still happening as they were not getting disabled.

Adding the support to handle module level wakeups for omap2/3 socs.

Signed-off-by: Govindraj.R <govindraj.raja@xxxxxx>
---
 arch/arm/mach-omap2/serial.c |   95 +++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index f590afc..92ff94c 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -56,6 +56,10 @@ struct omap_uart_state {
 	int num;
 	int can_sleep;

+	void __iomem *wk_st;
+	void __iomem *wk_en;
+	u32 wk_mask;
+
 	struct list_head node;
 	struct omap_hwmod *oh;
 	struct platform_device *pdev;
@@ -82,17 +86,46 @@ static struct omap_uart_port_info
omap_serial_default_info[] __initdata = {
 };

 #ifdef CONFIG_PM
+
+static void omap_uart_disable_module_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);
+	}
+}
+
+static void omap_uart_enable_module_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);
+	}
+}
+
 static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
 {
 	struct omap_device *od = to_omap_device(pdev);
+	struct omap_uart_state *uart;

 	if (!od)
 		return;

-	if (enable)
+	list_for_each_entry(uart, &uart_list, node)
+		if (pdev->id == uart->num)
+			break;
+
+	if (enable) {
+		omap_uart_enable_module_wakeup(uart);
 		omap_hwmod_enable_wakeup(od->hwmods[0]);
-	else
+	} else {
+		omap_uart_disable_module_wakeup(uart);
 		omap_hwmod_disable_wakeup(od->hwmods[0]);
+	}
 }

 /*
@@ -114,7 +147,64 @@ static void omap_uart_set_smartidle(struct
platform_device *pdev)
 	omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_SMART);
 }

+static void omap_uart_idle_init(struct omap_uart_state *uart)
+{
+	if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
+		u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+
+		uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
+		uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
+		switch (uart->num) {
+		case 0:
+			uart->wk_mask = OMAP3430_ST_UART1_MASK;
+			break;
+		case 1:
+			uart->wk_mask = OMAP3430_ST_UART2_MASK;
+			break;
+		case 2:
+			uart->wk_mask = OMAP3430_ST_UART3_MASK;
+			break;
+		case 3:
+			uart->wk_mask = OMAP3630_ST_UART4_MASK;
+			break;
+		}
+	} else if (cpu_is_omap24xx()) {
+
+		if (cpu_is_omap2430()) {
+			uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+			uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
+		} else if (cpu_is_omap2420()) {
+			uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+			uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
+		}
+		switch (uart->num) {
+		case 0:
+			uart->wk_mask = OMAP24XX_ST_UART1_MASK;
+			break;
+		case 1:
+			uart->wk_mask = OMAP24XX_ST_UART2_MASK;
+			break;
+		case 2:
+			uart->wk_mask = OMAP24XX_ST_UART3_MASK;
+			break;
+		}
+	} else {
+		uart->wk_en = 0;
+		uart->wk_st = 0;
+		uart->wk_mask = 0;
+	}
+
+	/* Module level wakeups might be left enabled from
+	 * bootloader disable it. Module level wakeup/pad_wakeup
+	 * will be enabled if port is wakeup capaable after gating uart
+	 * port clocks from omap-serial driver.
+	 * Wakeup capability can be enabled or disbaled using sysfs entry.
+	 */
+	omap_uart_disable_module_wakeup(uart);
+}
+
 #else
+static void omap_uart_idle_init(struct omap_uart_state *uart) {}
 static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
 {}
 static void omap_uart_set_noidle(struct platform_device *pdev) {}
@@ -345,6 +435,7 @@ void __init omap_serial_init_port(struct
omap_board_data *bdata,
 	oh = uart->oh;
 	name = DRIVER_NAME;

+	omap_uart_idle_init(uart);
 	omap_up.dma_enabled = info->dma_enabled;
 	omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
 	omap_up.flags = UPF_BOOT_AUTOCONF;
-- 
1.7.5.4
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux