linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ARM: imx: add cpuidle support for i.mx6sl
@ 2014-01-07 17:50 Anson Huang
  2014-01-08 14:29 ` Shawn Guo
  0 siblings, 1 reply; 11+ messages in thread
From: Anson Huang @ 2014-01-07 17:50 UTC (permalink / raw)
  To: linux-arm-kernel

Add cpuidle support for i.MX6SL, currently only support
two level cpuidle(ARM wfi and WAIT mode), as there is no
hardware fix for WAIT mode issue, so we need to ensure
ARM:IPG clock ratio is maintained within 12:5 before
entering WAIT mode.

Signed-off-by: Anson Huang <b20788@freescale.com>
---
 arch/arm/mach-imx/Makefile         |    1 +
 arch/arm/mach-imx/clk-imx6sl.c     |   21 ++++++++++++++
 arch/arm/mach-imx/common.h         |    1 +
 arch/arm/mach-imx/cpuidle-imx6sl.c |   53 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-imx/cpuidle.h        |    5 ++++
 arch/arm/mach-imx/mach-imx6sl.c    |    7 +++++
 6 files changed, 88 insertions(+)
 create mode 100644 arch/arm/mach-imx/cpuidle-imx6sl.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index d8205fb..1fcd273 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
 obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
+obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o
 endif
 
 ifdef CONFIG_SND_IMX_SOC
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
index e6900e9..cb6cbce 100644
--- a/arch/arm/mach-imx/clk-imx6sl.c
+++ b/arch/arm/mach-imx/clk-imx6sl.c
@@ -66,6 +66,27 @@ static struct clk_div_table video_div_table[] = {
 static struct clk *clks[IMX6SL_CLK_END];
 static struct clk_onecell_data clk_data;
 
+/*
+ * On i.MX6SL, need to ensure that the ARM:IPG clock ratio is maintained
+ * within 12:5 when the clocks to ARM are gated when the SOC enters
+ * WAIT mode. This is necessary to avoid WAIT mode issue (an early
+ * interrupt waking up the ARM).
+ * This function will set the ARM clk to max value within the 12:5 limit.
+ */
+void imx6sl_set_wait_clk(bool enter)
+{
+	static u32 saved_arm_rate;
+
+	if (enter) {
+		u32 ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]);
+		u32 max_arm_wait_rate = (12 * ipg_rate) / 5;
+		saved_arm_rate = clk_get_rate(clks[IMX6SL_CLK_ARM]);
+		clk_set_rate(clks[IMX6SL_CLK_ARM], max_arm_wait_rate);
+	} else {
+		clk_set_rate(clks[IMX6SL_CLK_ARM], saved_arm_rate);
+	}
+}
+
 static void __init imx6sl_clocks_init(struct device_node *ccm_node)
 {
 	struct device_node *np;
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 2b0151f..524c4cb 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -140,6 +140,7 @@ void imx_anatop_pre_suspend(void);
 void imx_anatop_post_resume(void);
 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
 void imx6q_set_chicken_bit(void);
+void imx6sl_set_wait_clk(bool enter);
 
 void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
new file mode 100644
index 0000000..676831a
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+
+#include "common.h"
+#include "cpuidle.h"
+
+static int imx6sl_enter_wait(struct cpuidle_device *dev,
+			    struct cpuidle_driver *drv, int index)
+{
+	imx6q_set_lpm(WAIT_UNCLOCKED);
+	imx6sl_set_wait_clk(true);
+	cpu_do_idle();
+	imx6sl_set_wait_clk(false);
+	imx6q_set_lpm(WAIT_CLOCKED);
+
+	return index;
+}
+
+static struct cpuidle_driver imx6sl_cpuidle_driver = {
+	.name = "imx6sl_cpuidle",
+	.owner = THIS_MODULE,
+	.states = {
+		/* WFI */
+		ARM_CPUIDLE_WFI_STATE,
+		/* WAIT */
+		{
+			.exit_latency = 50,
+			.target_residency = 75,
+			.flags = CPUIDLE_FLAG_TIME_VALID |
+				CPUIDLE_FLAG_TIMER_STOP,
+			.enter = imx6sl_enter_wait,
+			.name = "WAIT",
+			.desc = "Clock off",
+		},
+	},
+	.state_count = 2,
+	.safe_state_index = 0,
+};
+
+int __init imx6sl_cpuidle_init(void)
+{
+	return cpuidle_register(&imx6sl_cpuidle_driver, NULL);
+}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index 786f98e..24e3367 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -13,6 +13,7 @@
 #ifdef CONFIG_CPU_IDLE
 extern int imx5_cpuidle_init(void);
 extern int imx6q_cpuidle_init(void);
+extern int imx6sl_cpuidle_init(void);
 #else
 static inline int imx5_cpuidle_init(void)
 {
@@ -22,4 +23,8 @@ static inline int imx6q_cpuidle_init(void)
 {
 	return 0;
 }
+static inline int imx6sl_cpuidle_init(void)
+{
+	return 0;
+}
 #endif
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
index 7fdd4e8..1cb6f6e 100644
--- a/arch/arm/mach-imx/mach-imx6sl.c
+++ b/arch/arm/mach-imx/mach-imx6sl.c
@@ -17,6 +17,7 @@
 #include <asm/mach/map.h>
 
 #include "common.h"
+#include "cpuidle.h"
 
 static void __init imx6sl_fec_init(void)
 {
@@ -52,6 +53,11 @@ static void __init imx6sl_init_machine(void)
 	imx6q_pm_init();
 }
 
+static void __init imx6sl_init_late(void)
+{
+	imx6sl_cpuidle_init();
+}
+
 static void __init imx6sl_map_io(void)
 {
 	debug_ll_io_init();
@@ -78,4 +84,5 @@ DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)")
 	.init_machine	= imx6sl_init_machine,
 	.dt_compat	= imx6sl_dt_compat,
 	.restart	= mxc_restart,
+	.init_late      = imx6sl_init_late,
 MACHINE_END
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 11+ messages in thread
* [PATCH] ARM: imx: add cpuidle support for i.mx6sl
@ 2014-01-17 23:42 John Tobias
  2014-01-17 23:53 ` Anson.Huang at freescale.com
  0 siblings, 1 reply; 11+ messages in thread
From: John Tobias @ 2014-01-17 23:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Anson,

My kernel for iMX6SL has a imx6q-cpufreq and I used your patch.
Unfortunately, the kernel crashes if the imx6sl_set_wait_clk being
called in imx6sl_enter_wait.

[  288.166905] [<80044b80>] (dequeue_task+0x0/0xc8) from [<80045650>]
(deactivate_task+0x30/0x34)
[  288.176403] [<80045620>] (deactivate_task+0x0/0x34) from
[<8050ac88>] (__schedule+0x318/0x58c)
[  288.185848] [<8050a970>] (__schedule+0x0/0x58c) from [<8050af34>]
(schedule+0x38/0x88)
[  288.194758] [<8050aefc>] (schedule+0x0/0x88) from [<8050b1c8>]
(schedule_preempt_disabled+0x10/0x14)
[  288.204858] [<8050b1b8>] (schedule_preempt_disabled+0x0/0x14) from
[<8050bcd4>] (mutex_lock_nested+0x16c/0x334)
[  288.215850] [<8050bb68>] (mutex_lock_nested+0x0/0x334) from
[<8034763c>] (clk_prepare_lock+0x90/0x104)
[  288.226041] [<803475ac>] (clk_prepare_lock+0x0/0x104) from
[<80349254>] (clk_set_rate+0x1c/0xbc)
[  288.235535]  r6:806fd360 r5:00000000 r4:bf817f80 r3:80713d80
[  288.242679] [<80349238>] (clk_set_rate+0x0/0xbc) from [<8001e574>]
(imx6sl_set_wait_clk+0x28/0x70)
[  288.252354]  r5:00000043 r4:00000001
[  288.256585] [<8001e54c>] (imx6sl_set_wait_clk+0x0/0x70) from
[<8001def4>] (imx6sl_enter_wait+0x24/0x2c)
[  288.266684]  r5:00000043 r4:00000001
[  288.270949] [<8001ded0>] (imx6sl_enter_wait+0x0/0x2c) from
[<80317608>] (cpuidle_enter_state+0x44/0xfc)
[  288.281051]  r4:13bf2645 r3:8001ded0
[  288.285682] [<803175c4>] (cpuidle_enter_state+0x0/0xfc) from
[<803177bc>] (cpuidle_idle_call+0xfc/0x150)
[  288.295871]  r8:806e00d8 r7:00000001 r6:00000000 r5:80c58034 r4:806fd360
[  288.304428] [<803176c0>] (cpuidle_idle_call+0x0/0x150) from
[<8000fa68>] (arch_cpu_idle+0x10/0x44)
[  288.314108]  r9:8070970a r8:8070970a r7:806d2000 r6:806da0dc r5:806d2000
r4:806d2000
[  288.323611] [<8000fa58>] (arch_cpu_idle+0x0/0x44) from [<800590f4>]
(cpu_startup_entry+0xe0/0x120)
[  288.333460] [<80059014>] (cpu_startup_entry+0x0/0x120) from
[<80503c8c>] (rest_init+0xcc/0xdc)
[  288.342810]  r7:ffffffff r3:00000000
[  288.347115] [<80503bc0>] (rest_init+0x0/0xdc) from [<806a2b00>]
(start_kernel+0x348/0x354)
[  288.356099]  r6:806da040 r5:806da040 r4:806da150
[  288.361972] [<806a27b8>] (start_kernel+0x0/0x354) from [<80008070>]
(0x80008070)


Regards,

john

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

end of thread, other threads:[~2014-01-27  6:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-07 17:50 [PATCH] ARM: imx: add cpuidle support for i.mx6sl Anson Huang
2014-01-08 14:29 ` Shawn Guo
  -- strict thread matches above, loose matches on Subject: below --
2014-01-17 23:42 John Tobias
2014-01-17 23:53 ` Anson.Huang at freescale.com
2014-01-20  9:03   ` Anson.Huang at freescale.com
2014-01-23 20:16     ` John Tobias
2014-01-24  2:05       ` Anson.Huang at freescale.com
2014-01-24  2:23         ` John Tobias
2014-01-24  2:31           ` Anson.Huang at freescale.com
2014-01-27  6:14         ` Shawn Guo
2014-01-27  6:23           ` Anson.Huang at freescale.com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).