Skip to contentSkip to conversation

ARM: S3C64XX: Add basic cpuidle driver

PATCH New Mark Brown 3 participants 6 messages Dec 5, 2011 – Mar 30, 2012

Subsystems (3)
lore
Share & tools
lore

Mark Brown

author
#0 lore raw

PATCH 1/1 ARM: S3C64XX: Add basic cpuidle driver

Add a very basic cpuidle driver for S3C64xx which merely drives the CPU into IDLE mode. We could do this with pm_idle but the more modern idiom is to use cpuidle and the intention is to go further and support STOP and DEEP-STOP states in conjunction with the pm_domain framework.

The actual state entry code was lifted from Tomasz Figa's work on spica.

---
 arch/arm/mach-s3c64xx/Makefile  |    1 +
 arch/arm/mach-s3c64xx/cpuidle.c |   91 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s3c64xx/cpuidle.c
arch/arm/mach-s3c64xx/Makefile +1 -0
index e32093c..8f5574b 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_PM)		+= sleep.o
 obj-$(CONFIG_PM)		+= irq-pm.o
+obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 
 # Machine support
 
arch/arm/mach-s3c64xx/cpuidle.c new file +91 -0

91 lines not on this page · raw message

Signature · 1 line
1.7.7.3
#1 lore raw

PATCH 1/1 ARM: S3C64XX: Add basic cpuidle driver

Am Montag, 5. Dezember 2011, 21:32:49 schrieb Mark Brown:

Quoted 4 lines

Add a very basic cpuidle driver for S3C64xx which merely drives the CPU into IDLE mode. We could do this with pm_idle but the more modern idiom is to use cpuidle and the intention is to go further and support STOP and DEEP-STOP states in conjunction with the pm_domain framework.

cool :-)

My S3C2416 playground is quite similar in its low power modes and their wakeup sources and I've got a idle driver for it in a similar state sitting here.

So I'm really looking forward to seeing a possible example on how to support the STOP and DEEP-STOP modes best.

Quoted 3 lines

The actual state entry code was lifted from Tomasz Figa's work on spica.

Quoted 116 lines
---
 arch/arm/mach-s3c64xx/Makefile  |    1 +
 arch/arm/mach-s3c64xx/cpuidle.c |   91
+++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+),
0 deletions(-)
 create mode 100644 arch/arm/mach-s3c64xx/cpuidle.c
(quoted diff) +0 -0

b/arch/arm/mach-s3c64xx/Makefile index e32093c..8f5574b 100644

arch/arm/mach-s3c64xx/Makefile +0 -0
@@ -40,6 +40,7 @@ obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) +=

setup-sdhci-gpio.o obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_PM) += sleep.o
obj-$(CONFIG_PM) += irq-pm.o

arch/arm/mach-s3c64xx/Makefile +1 -0
+obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 
 # Machine support
(quoted diff) +0 -0

b/arch/arm/mach-s3c64xx/cpuidle.c new file mode 100644 index 0000000..625d2c7

arch/arm/mach-s3c64xx/cpuidle.c new file +91 -0
@@ -0,0 +1,91 @@
+/* linux/arch/arm/mach-s3c64xx/cpuidle.c
+ *
+ * Copyright (c) 2011 Wolfson Microelectronics, plc
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <linux/export.h>
+#include <linux/time.h>
+
+#include <asm/proc-fns.h>
+
+#include <mach/map.h>
+
+#include <mach/regs-sys.h>
+#include <mach/regs-syscon-power.h>
+
+static int s3c64xx_enter_idle(struct cpuidle_device *dev,
+			      struct cpuidle_driver *drv,
+			      int index)
+{
+	struct timeval before, after;
+	unsigned long tmp;
+	int idle_time;
+
+	local_irq_disable();
+	do_gettimeofday(&before);
+
+	/* Setup PWRCFG to enter idle mode */
+	tmp = __raw_readl(S3C64XX_PWR_CFG);
+	tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
+	tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE;
+	__raw_writel(tmp, S3C64XX_PWR_CFG);
+
+	cpu_do_idle();
+
+	do_gettimeofday(&after);
+	local_irq_enable();
+	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+		    (after.tv_usec - before.tv_usec);
+
+	dev->last_residency = idle_time;
+	return index;
+}
+
+static struct cpuidle_state s3c64xx_cpuidle_set[] = {
+	[0] = {
+		.enter			= s3c64xx_enter_idle,
+		.exit_latency		= 1,
+		.target_residency	= 100000,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "IDLE",
+		.desc			= "System active, ARM gated",
+	},
+};
+
+static struct cpuidle_driver s3c64xx_cpuidle_driver = {
+	.name		= "s3c64xx_cpuidle",
+	.owner		= THIS_MODULE,
+	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static struct cpuidle_device s3c64xx_cpuidle_device = {
+	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static int __init s3c64xx_init_cpuidle(void)
+{
+	int ret;
+
+	memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set,
+	       sizeof(s3c64xx_cpuidle_set));
+	cpuidle_register_driver(&s3c64xx_cpuidle_driver);
+
+	ret = cpuidle_register_device(&s3c64xx_cpuidle_device);
+	if (ret) {
+		pr_err("Failed to register cpuidle device: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+device_initcall(s3c64xx_init_cpuidle);
author
#2 lore raw

PATCH 1/1 ARM: S3C64XX: Add basic cpuidle driver

Quoted 2 lines · Heiko St?bner

My S3C2416 playground is quite similar in its low power modes and their wakeup sources and I've got a idle driver for it in a similar state sitting here.

Yeah, there's a lot of ARM systems look like this.

Quoted 2 lines

So I'm really looking forward to seeing a possible example on how to support the STOP and DEEP-STOP modes best.

My plan there for the s3c64xx was to use pm_domain to figure out if the system is idle enough to drop down, I've been adding some pm_runtime support to provide the information to the core to let it figure this out.

#3 lore raw

PATCH 1/1 ARM: S3C64XX: Add basic cpuidle driver

Hi Mark,

Am Donnerstag, 22. Dezember 2011, 19:13:59 schrieb Mark Brown:

Quoted 7 lines · Heiko St?bner
Quoted 2 lines

So I'm really looking forward to seeing a possible example on how to support the STOP and DEEP-STOP modes best.

My plan there for the s3c64xx was to use pm_domain to figure out if the system is idle enough to drop down, I've been adding some pm_runtime support to provide the information to the core to let it figure this out.

sorry for digging this up again, but do you happen to have some preliminary code laying around for this, that I could "borrow"?

Thanks
Heiko

author
#4 lore raw

PATCH 1/1 ARM: S3C64XX: Add basic cpuidle driver

Quoted 8 lines · Heiko St?bner

Am Donnerstag, 22. Dezember 2011, 19:13:59 schrieb Mark Brown:

Quoted 3 lines

My plan there for the s3c64xx was to use pm_domain to figure out if the system is idle enough to drop down, I've been adding some pm_runtime support to provide the information to the core to let it figure this out.

sorry for digging this up again, but do you happen to have some preliminary code laying around for this, that I could "borrow"?

No, sorry. The big problem is putting all the devices in power domains
since the Samsung port always has every single machine driver directly
register devices. Until that problem is solved it's not possible to
figure out if we're idle.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120330/75918690/attachment-0001.sig>

#5 lore raw

PATCH 1/1 ARM: S3C64XX: Add basic cpuidle driver

In reply to Mark Brown
Quoted 129 lines · Mark Brown

Add a very basic cpuidle driver for S3C64xx which merely drives the CPU into IDLE mode. We could do this with pm_idle but the more modern idiom is to use cpuidle and the intention is to go further and support STOP and DEEP-STOP states in conjunction with the pm_domain framework.

The actual state entry code was lifted from Tomasz Figa's work on spica.

---
 arch/arm/mach-s3c64xx/Makefile  |    1 +
 arch/arm/mach-s3c64xx/cpuidle.c |   91
+++++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s3c64xx/cpuidle.c
arch/arm/mach- renamed from arch/arm/mach-s3c64xx/Makefile +0 -0

s3c64xx/Makefile
index e32093c..8f5574b 100644

arch/arm/mach-s3c64xx/Makefile +0 -0
@@ -40,6 +40,7 @@ obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-

gpio.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_PM) += sleep.o
obj-$(CONFIG_PM) += irq-pm.o

arch/arm/mach-s3c64xx/Makefile +1 -0
+obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 
 # Machine support
arch/arm/mach- renamed from arch/arm/mach-s3c64xx/cpuidle.c +0 -0

s3c64xx/cpuidle.c
new file mode 100644
index 0000000..625d2c7

arch/arm/mach-s3c64xx/cpuidle.c new file +91 -1
@@ -0,0 +1,91 @@
+/* linux/arch/arm/mach-s3c64xx/cpuidle.c
+ *
+ * Copyright (c) 2011 Wolfson Microelectronics, plc
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <linux/export.h>
+#include <linux/time.h>
+
+#include <asm/proc-fns.h>
+
+#include <mach/map.h>
+
+#include <mach/regs-sys.h>
+#include <mach/regs-syscon-power.h>
+
+static int s3c64xx_enter_idle(struct cpuidle_device *dev,
+			      struct cpuidle_driver *drv,
+			      int index)
+{
+	struct timeval before, after;
+	unsigned long tmp;
+	int idle_time;
+
+	local_irq_disable();
+	do_gettimeofday(&before);
+
+	/* Setup PWRCFG to enter idle mode */
+	tmp = __raw_readl(S3C64XX_PWR_CFG);
+	tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
+	tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE;
+	__raw_writel(tmp, S3C64XX_PWR_CFG);
+
+	cpu_do_idle();
+
+	do_gettimeofday(&after);
+	local_irq_enable();
+	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+		    (after.tv_usec - before.tv_usec);
+
+	dev->last_residency = idle_time;
+	return index;
+}
+
+static struct cpuidle_state s3c64xx_cpuidle_set[] = {
+	[0] = {
+		.enter			= s3c64xx_enter_idle,
+		.exit_latency		= 1,
+		.target_residency	= 100000,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "IDLE",
+		.desc			= "System active, ARM gated",
+	},
+};
+
+static struct cpuidle_driver s3c64xx_cpuidle_driver = {
+	.name		= "s3c64xx_cpuidle",
+	.owner		= THIS_MODULE,
+	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static struct cpuidle_device s3c64xx_cpuidle_device = {
+	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static int __init s3c64xx_init_cpuidle(void)
+{
+	int ret;
+
+	memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set,
+	       sizeof(s3c64xx_cpuidle_set));
+	cpuidle_register_driver(&s3c64xx_cpuidle_driver);
+
+	ret = cpuidle_register_device(&s3c64xx_cpuidle_device);
+	if (ret) {
+		pr_err("Failed to register cpuidle device: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+device_initcall(s3c64xx_init_cpuidle);
--
Quoted 1 line

1.7.7.3

Hi Mark,

Looks ok to me, will apply.
Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.