Also to freescale list, since there is no such driver in freescale bsp so far.
Yong
From: Yong Shen yong.shen@freescale.com
implement cpu idle driver which allow different imx SOCs and boards to register their own cpuidle parameters
Signed-off-by: Yong Shen yong.shen@freescale.com --- arch/arm/plat-mxc/Makefile | 1 + arch/arm/plat-mxc/cpuidle.c | 74 ++++++++++++++++++++++++++++++ arch/arm/plat-mxc/include/mach/cpuidle.h | 6 ++ 3 files changed, 81 insertions(+), 0 deletions(-) create mode 100644 arch/arm/plat-mxc/cpuidle.c create mode 100644 arch/arm/plat-mxc/include/mach/cpuidle.h
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 5fd20e9..e6ba9c2 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o +obj-$(CONFIG_CPU_IDLE) += cpuidle.o ifdef CONFIG_SND_IMX_SOC obj-y += ssi-fiq.o obj-y += ssi-fiq-ksym.o diff --git a/arch/arm/plat-mxc/cpuidle.c b/arch/arm/plat-mxc/cpuidle.c new file mode 100644 index 0000000..ca5f759 --- /dev/null +++ b/arch/arm/plat-mxc/cpuidle.c @@ -0,0 +1,74 @@ +/* + * arch/arm/plat-mxc/cpuidle.c + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/cpuidle.h> +#include <mach/cpuidle.h> +#include <linux/platform_device.h> + +static struct cpuidle_driver imx_cpuidle_driver = { + .name = "imx_idle", + .owner = THIS_MODULE, +}; + +static DEFINE_PER_CPU(struct cpuidle_device, imx_cpuidle_device); + +static int imx_cpuidle_register(struct imx_cpuidle_state *pstate) +{ + struct cpuidle_device *device; + struct cpuidle_state *state = pstate->state; + int i; + + cpuidle_register_driver(&imx_cpuidle_driver); + + device = &per_cpu(imx_cpuidle_device, smp_processor_id()); + device->state_count = pstate->state_number; + + for (i = 0; i < device->state_count; i++) { + device->states[i].enter = state[i].enter; + device->states[i].exit_latency = state[i].exit_latency; + device->states[i].target_residency = state[i].target_residency; + device->states[i].flags = state[i].flags; + strcpy(device->states[i].name, state[i].name); + strcpy(device->states[i].desc, state[i].desc); + } + + if (cpuidle_register_device(device)) { + printk(KERN_ERR "imx_cpuidle_register: Failed registering\n"); + return -EIO; + } + return 0; +} + +static int __devinit imx_cpuidle_probe(struct platform_device *pdev) +{ + struct imx_cpuidle_state *state = pdev->dev.platform_data; + + return imx_cpuidle_register(state); +} + +static struct platform_driver imx_cpuidle_platform_driver = { + .driver = { + .name = "imx_cpuidle", + }, + .probe = imx_cpuidle_probe, +}; + +static int __init imx_cpuidle_init(void) +{ + return platform_driver_register(&imx_cpuidle_platform_driver); +} +arch_initcall(imx_cpuidle_init); + +static void __exit imx_cpuidle_exit(void) +{ + platform_driver_unregister(&imx_cpuidle_platform_driver); +} +module_exit(imx_cpuidle_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yong Shen yong.shen@freescale.com"); diff --git a/arch/arm/plat-mxc/include/mach/cpuidle.h b/arch/arm/plat-mxc/include/mach/cpuidle.h new file mode 100644 index 0000000..4d672aa --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/cpuidle.h @@ -0,0 +1,6 @@ +#include <linux/cpuidle.h> + +struct imx_cpuidle_state { + unsigned short state_number; + struct cpuidle_state *state; +};
From: Yong Shen yong.shen@freescale.com
Add cpuidle parameters to make cpuidle driver workable, but these parameters need further tuning
Signed-off-by: Yong Shen yong.shen@freescale.com --- arch/arm/mach-mx5/board-mx51_babbage.c | 114 ++++++++++++++++++++++++++++++++ arch/arm/mach-mx5/devices.c | 4 + arch/arm/mach-mx5/devices.h | 1 + 3 files changed, 119 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index d9d402e..3c661e9 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -22,11 +22,13 @@ #include <linux/input.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> +#include <linux/cpuidle.h>
#include <mach/common.h> #include <mach/hardware.h> #include <mach/iomux-mx51.h> #include <mach/mxc_ehci.h> +#include <mach/cpuidle.h>
#include <asm/irq.h> #include <asm/setup.h> @@ -37,6 +39,7 @@ #include "devices-imx51.h" #include "devices.h" #include "cpu_op-mx51.h" +#include "crm_regs.h"
#define BABBAGE_USB_HUB_RESET IMX_GPIO_NR(1, 7) #define BABBAGE_USBH1_STP IMX_GPIO_NR(1, 27) @@ -333,6 +336,117 @@ static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = { .num_chipselect = ARRAY_SIZE(mx51_babbage_spi_cs), };
+extern int tzic_enable_wake(int is_idle); +static int imx51_enter_idle(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + struct timeval before, after; + int idle_time; + u32 plat_lpc, arm_srpgcr, ccm_clpcr; + u32 empgc0, empgc1; + int stop_mode = 0; + + local_irq_disable(); + do_gettimeofday(&before); + + plat_lpc = __raw_readl(MXC_CORTEXA8_PLAT_LPC) & + ~(MXC_CORTEXA8_PLAT_LPC_DSM); + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); + arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR); + empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR); + empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_PCR); + + if (state == &dev->states[0]) { + /* Wait clocked */ + ; + } else if (state == &dev->states[1]) { + /* Wait unclocked */ + ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); + } else { + plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM + | MXC_CORTEXA8_PLAT_LPC_DBG_DSM; + arm_srpgcr |= MXC_SRPGCR_PCR; + if (state == &dev->states[2]) { + /* Wait unclocked, power off */ + ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); + ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; + stop_mode = 0; + } else if (state == &dev->states[3]) { + /* Stop power off */ + ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); + ccm_clpcr |= (0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET); + ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; + ccm_clpcr |= MXC_CCM_CLPCR_SBYOS; + empgc0 |= MXC_SRPGCR_PCR; + empgc1 |= MXC_SRPGCR_PCR; + stop_mode = 1; + } + if (tzic_enable_wake(1) != 0) { + local_irq_enable(); + return 0; + } + } + + __raw_writel(plat_lpc, MXC_CORTEXA8_PLAT_LPC); + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); + __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR); + + if (stop_mode) { + __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); + } + + 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); + return idle_time; +} + +static struct cpuidle_state babbage_cpuidle_state[] = { + { + .enter = imx51_enter_idle, + .exit_latency = 1, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "WFI", + .desc = "Wait with clock on", + }, + { + .enter = imx51_enter_idle, + .exit_latency = 100, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "WFI", + .desc = "Wait with clock off", + }, + { + .enter = imx51_enter_idle, + .exit_latency = 10000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "WFI", + .desc = "Wait with clock off/power gating", + }, + { + .enter = imx51_enter_idle, + .exit_latency = 1000000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "SR", + .desc = "state retention", + }, +}; + +static struct imx_cpuidle_state babbage_cpuidle_data = { + .state_number = ARRAY_SIZE(babbage_cpuidle_state), + .state = babbage_cpuidle_state, +}; + +static int imx51_init_cpuidle(void) +{ + return mxc_register_device(&mxc_cpuidle_device, &babbage_cpuidle_data); +} +device_initcall(imx51_init_cpuidle); /* * Board specific initialization. */ diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c index 153ada5..8daf5f6 100644 --- a/arch/arm/mach-mx5/devices.c +++ b/arch/arm/mach-mx5/devices.c @@ -37,6 +37,10 @@ struct platform_device mxc_hsi2c_device = { .resource = mxc_hsi2c_resources };
+struct platform_device mxc_cpuidle_device = { + .name = "imx_cpuidle", +}; + static u64 usb_dma_mask = DMA_BIT_MASK(32);
static struct resource usbotg_resources[] = { diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h index 55a5129..49e441c 100644 --- a/arch/arm/mach-mx5/devices.h +++ b/arch/arm/mach-mx5/devices.h @@ -3,3 +3,4 @@ extern struct platform_device mxc_usbh1_device; extern struct platform_device mxc_usbh2_device; extern struct platform_device mxc_usbdr_udc_device; extern struct platform_device mxc_hsi2c_device; +extern struct platform_device mxc_cpuidle_device;
yong.shen@linaro.org writes:
Hi,
From: Yong Shen yong.shen@freescale.com
Add cpuidle parameters to make cpuidle driver workable, but these parameters need further tuning
Signed-off-by: Yong Shen yong.shen@freescale.com
arch/arm/mach-mx5/board-mx51_babbage.c | 114 ++++++++++++++++++++++++++++++++ arch/arm/mach-mx5/devices.c | 4 + arch/arm/mach-mx5/devices.h | 1 + 3 files changed, 119 insertions(+), 0 deletions(-)
I didn't look at how it's working nor did a review but from a very quick look, I'm wondering why it's in board-mx51_babbage.c. Can you explain to me what makes this code specific to babbage ?
Arnaud
Hi Arnaud,
I also took a while to think about this before posting patches. I prefer to put it in board related code since the various PMIC used on each boards may have influence on cpuidle latency or other charactors, although it could be minor.
Yong
On Tue, Feb 8, 2011 at 4:29 PM, Arnaud Patard arnaud.patard@rtp-net.orgwrote:
yong.shen@linaro.org writes:
Hi,
From: Yong Shen yong.shen@freescale.com
Add cpuidle parameters to make cpuidle driver workable, but these parameters need further tuning
Signed-off-by: Yong Shen yong.shen@freescale.com
arch/arm/mach-mx5/board-mx51_babbage.c | 114
++++++++++++++++++++++++++++++++
arch/arm/mach-mx5/devices.c | 4 + arch/arm/mach-mx5/devices.h | 1 + 3 files changed, 119 insertions(+), 0 deletions(-)
I didn't look at how it's working nor did a review but from a very quick look, I'm wondering why it's in board-mx51_babbage.c. Can you explain to me what makes this code specific to babbage ?
Arnaud
On 11 Feb 08, Yong Shen wrote:
Hi Arnaud,
I also took a while to think about this before posting patches. I prefer to put it in board related code since the various PMIC used on each boards may have influence on cpuidle latency or other charactors, although it could be minor.
Then those minor differences can be addressed in the common driver by using #ifdef conditionals.
The cpuidle driver certainly shouldn't be board-specific.
/Amit
Amit Kucheria amit.kucheria@linaro.org writes:
On 11 Feb 08, Yong Shen wrote:
Hi Arnaud,
I also took a while to think about this before posting patches. I prefer to put it in board related code since the various PMIC used on each boards may have influence on cpuidle latency or other charactors, although it could be minor.
Then those minor differences can be addressed in the common driver by using #ifdef conditionals.
The cpuidle driver certainly shouldn't be board-specific.
agreed, except on #ifdef. One should be able to build one kernel for several imx51 boards and #ifdef will probably prevent that.
Arnaud
On 11 Feb 08, Arnaud Patard wrote:
Amit Kucheria amit.kucheria@linaro.org writes:
On 11 Feb 08, Yong Shen wrote:
Hi Arnaud,
I also took a while to think about this before posting patches. I prefer to put it in board related code since the various PMIC used on each boards may have influence on cpuidle latency or other charactors, although it could be minor.
Then those minor differences can be addressed in the common driver by using #ifdef conditionals.
The cpuidle driver certainly shouldn't be board-specific.
agreed, except on #ifdef. One should be able to build one kernel for several imx51 boards and #ifdef will probably prevent that.
You're right. I should've said runtime detection.
On 02/08/2011 09:51 AM, Yong Shen wrote:
Hi Arnaud,
I also took a while to think about this before posting patches. I prefer to put it in board related code since the various PMIC used on each boards may have influence on cpuidle latency or other charactors, although it could be minor.
But you are not going to be doing voltage scaling in idle. Is it even possible to do sleeping operations like accessing a PMIC in idle?
The core is powergated, so lowering voltage would not help. Doing bus scaling or DDR self-refresh are the only likely additional operations.
Rob
On Tue, Feb 8, 2011 at 6:50 PM, Rob Herring robherring2@gmail.com wrote:
On 02/08/2011 09:51 AM, Yong Shen wrote:
Hi Arnaud,
I also took a while to think about this before posting patches. I prefer to put it in board related code since the various PMIC used on each boards may have influence on cpuidle latency or other charactors, although it could be minor.
But you are not going to be doing voltage scaling in idle. Is it even possible to do sleeping operations like accessing a PMIC in idle?
I guess you are asking if modes like 'state retention' are possible for idle state. so far there is no official mapping between c-states and various arm idle states, which is something linaro power management group is working on. Therefore I also treat 'state retention' as a c-state.
ps. remove lpdk in cc list to avoid auto-reply messages. Yong
The core is powergated, so lowering voltage would not help. Doing bus scaling or DDR self-refresh are the only likely additional operations.
Rob
Yong,
On Tue, Feb 8, 2011 at 9:21 PM, Yong Shen yong.shen@linaro.org wrote:
Hi Arnaud, I also took a while to think about this before posting patches. I prefer to put it in board related code since the various PMIC used on each boards may have influence on cpuidle latency or other charactors, although it could be minor.
WHy don't you define cpuidle_latency table per board file and use the right one inside the common cpuidle driver. Then you can take care of board related latencies cleanly.
Vishwa
Yong
On Tue, Feb 8, 2011 at 4:29 PM, Arnaud Patard arnaud.patard@rtp-net.org wrote:
yong.shen@linaro.org writes:
Hi,
From: Yong Shen yong.shen@freescale.com
Add cpuidle parameters to make cpuidle driver workable, but these parameters need further tuning
Signed-off-by: Yong Shen yong.shen@freescale.com
arch/arm/mach-mx5/board-mx51_babbage.c | 114 ++++++++++++++++++++++++++++++++ arch/arm/mach-mx5/devices.c | 4 + arch/arm/mach-mx5/devices.h | 1 + 3 files changed, 119 insertions(+), 0 deletions(-)
I didn't look at how it's working nor did a review but from a very quick look, I'm wondering why it's in board-mx51_babbage.c. Can you explain to me what makes this code specific to babbage ?
Arnaud
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Hi Vishwanath,
Thanks. I will take it as a reference.
Yong
On Wed, Feb 9, 2011 at 11:52 AM, Vishwanath Sripathy < vishwanath.sripathy@linaro.org> wrote:
Yong,
On Tue, Feb 8, 2011 at 9:21 PM, Yong Shen yong.shen@linaro.org wrote:
Hi Arnaud, I also took a while to think about this before posting patches. I prefer
to
put it in board related code since the various PMIC used on each boards
may
have influence on cpuidle latency or other charactors, although it could
be
minor.
WHy don't you define cpuidle_latency table per board file and use the right one inside the common cpuidle driver. Then you can take care of board related latencies cleanly.
Vishwa
Yong
On Tue, Feb 8, 2011 at 4:29 PM, Arnaud Patard <arnaud.patard@rtp-net.org
wrote:
yong.shen@linaro.org writes:
Hi,
From: Yong Shen yong.shen@freescale.com
Add cpuidle parameters to make cpuidle driver workable, but these parameters need further tuning
Signed-off-by: Yong Shen yong.shen@freescale.com
arch/arm/mach-mx5/board-mx51_babbage.c | 114 ++++++++++++++++++++++++++++++++ arch/arm/mach-mx5/devices.c | 4 + arch/arm/mach-mx5/devices.h | 1 + 3 files changed, 119 insertions(+), 0 deletions(-)
I didn't look at how it's working nor did a review but from a very quick look, I'm wondering why it's in board-mx51_babbage.c. Can you explain to me what makes this code specific to babbage ?
Arnaud
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev