aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/cpufreq.c8
-rw-r--r--arch/arm/mach-imx/cpuidle-imx5.c37
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c26
-rw-r--r--arch/arm/mach-imx/cpuidle.c80
-rw-r--r--arch/arm/mach-imx/cpuidle.h10
-rw-r--r--arch/arm/mach-imx/pm-imx5.c30
7 files changed, 48 insertions, 145 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index c4ce0906d76a..cb70961b6239 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
30obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o 30obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
31 31
32ifeq ($(CONFIG_CPU_IDLE),y) 32ifeq ($(CONFIG_CPU_IDLE),y)
33obj-y += cpuidle.o 33obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
34obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o 34obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
35endif 35endif
36 36
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
index d8c75c3c925d..387dc4cceca2 100644
--- a/arch/arm/mach-imx/cpufreq.c
+++ b/arch/arm/mach-imx/cpufreq.c
@@ -87,13 +87,12 @@ static int mxc_set_target(struct cpufreq_policy *policy,
87 87
88 freqs.old = clk_get_rate(cpu_clk) / 1000; 88 freqs.old = clk_get_rate(cpu_clk) / 1000;
89 freqs.new = freq_Hz / 1000; 89 freqs.new = freq_Hz / 1000;
90 freqs.cpu = 0;
91 freqs.flags = 0; 90 freqs.flags = 0;
92 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 91 cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
93 92
94 ret = set_cpu_freq(freq_Hz); 93 ret = set_cpu_freq(freq_Hz);
95 94
96 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 95 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
97 96
98 return ret; 97 return ret;
99} 98}
@@ -145,14 +144,11 @@ static int mxc_cpufreq_init(struct cpufreq_policy *policy)
145 imx_freq_table[i].frequency = CPUFREQ_TABLE_END; 144 imx_freq_table[i].frequency = CPUFREQ_TABLE_END;
146 145
147 policy->cur = clk_get_rate(cpu_clk) / 1000; 146 policy->cur = clk_get_rate(cpu_clk) / 1000;
148 policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min;
149 policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max;
150 147
151 /* Manual states, that PLL stabilizes in two CLK32 periods */ 148 /* Manual states, that PLL stabilizes in two CLK32 periods */
152 policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ; 149 policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ;
153 150
154 ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table); 151 ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table);
155
156 if (ret < 0) { 152 if (ret < 0) {
157 printk(KERN_ERR "%s: failed to register i.MXC CPUfreq with error code %d\n", 153 printk(KERN_ERR "%s: failed to register i.MXC CPUfreq with error code %d\n",
158 __func__, ret); 154 __func__, ret);
diff --git a/arch/arm/mach-imx/cpuidle-imx5.c b/arch/arm/mach-imx/cpuidle-imx5.c
new file mode 100644
index 000000000000..5a47e3c6172f
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx5.c
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2012 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/cpuidle.h>
10#include <linux/module.h>
11#include <asm/system_misc.h>
12
13static int imx5_cpuidle_enter(struct cpuidle_device *dev,
14 struct cpuidle_driver *drv, int index)
15{
16 arm_pm_idle();
17 return index;
18}
19
20static struct cpuidle_driver imx5_cpuidle_driver = {
21 .name = "imx5_cpuidle",
22 .owner = THIS_MODULE,
23 .states[0] = {
24 .enter = imx5_cpuidle_enter,
25 .exit_latency = 2,
26 .target_residency = 1,
27 .flags = CPUIDLE_FLAG_TIME_VALID,
28 .name = "IMX5 SRPG",
29 .desc = "CPU state retained,powered off",
30 },
31 .state_count = 1,
32};
33
34int __init imx5_cpuidle_init(void)
35{
36 return cpuidle_register(&imx5_cpuidle_driver, NULL);
37}
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
index d533e2695f0e..23ddfb693b2d 100644
--- a/arch/arm/mach-imx/cpuidle-imx6q.c
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -6,7 +6,6 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <linux/clockchips.h>
10#include <linux/cpuidle.h> 9#include <linux/cpuidle.h>
11#include <linux/module.h> 10#include <linux/module.h>
12#include <asm/cpuidle.h> 11#include <asm/cpuidle.h>
@@ -21,10 +20,6 @@ static DEFINE_SPINLOCK(master_lock);
21static int imx6q_enter_wait(struct cpuidle_device *dev, 20static int imx6q_enter_wait(struct cpuidle_device *dev,
22 struct cpuidle_driver *drv, int index) 21 struct cpuidle_driver *drv, int index)
23{ 22{
24 int cpu = dev->cpu;
25
26 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
27
28 if (atomic_inc_return(&master) == num_online_cpus()) { 23 if (atomic_inc_return(&master) == num_online_cpus()) {
29 /* 24 /*
30 * With this lock, we prevent other cpu to exit and enter 25 * With this lock, we prevent other cpu to exit and enter
@@ -43,26 +38,13 @@ idle:
43 cpu_do_idle(); 38 cpu_do_idle();
44done: 39done:
45 atomic_dec(&master); 40 atomic_dec(&master);
46 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
47 41
48 return index; 42 return index;
49} 43}
50 44
51/*
52 * For each cpu, setup the broadcast timer because local timer
53 * stops for the states other than WFI.
54 */
55static void imx6q_setup_broadcast_timer(void *arg)
56{
57 int cpu = smp_processor_id();
58
59 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
60}
61
62static struct cpuidle_driver imx6q_cpuidle_driver = { 45static struct cpuidle_driver imx6q_cpuidle_driver = {
63 .name = "imx6q_cpuidle", 46 .name = "imx6q_cpuidle",
64 .owner = THIS_MODULE, 47 .owner = THIS_MODULE,
65 .en_core_tk_irqen = 1,
66 .states = { 48 .states = {
67 /* WFI */ 49 /* WFI */
68 ARM_CPUIDLE_WFI_STATE, 50 ARM_CPUIDLE_WFI_STATE,
@@ -70,7 +52,8 @@ static struct cpuidle_driver imx6q_cpuidle_driver = {
70 { 52 {
71 .exit_latency = 50, 53 .exit_latency = 50,
72 .target_residency = 75, 54 .target_residency = 75,
73 .flags = CPUIDLE_FLAG_TIME_VALID, 55 .flags = CPUIDLE_FLAG_TIME_VALID |
56 CPUIDLE_FLAG_TIMER_STOP,
74 .enter = imx6q_enter_wait, 57 .enter = imx6q_enter_wait,
75 .name = "WAIT", 58 .name = "WAIT",
76 .desc = "Clock off", 59 .desc = "Clock off",
@@ -88,8 +71,5 @@ int __init imx6q_cpuidle_init(void)
88 /* Set chicken bit to get a reliable WAIT mode support */ 71 /* Set chicken bit to get a reliable WAIT mode support */
89 imx6q_set_chicken_bit(); 72 imx6q_set_chicken_bit();
90 73
91 /* Configure the broadcast timer on each cpu */ 74 return cpuidle_register(&imx6q_cpuidle_driver, NULL);
92 on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
93
94 return imx_cpuidle_init(&imx6q_cpuidle_driver);
95} 75}
diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c
deleted file mode 100644
index d4cb511a44a8..000000000000
--- a/arch/arm/mach-imx/cpuidle.c
+++ /dev/null
@@ -1,80 +0,0 @@
1/*
2 * Copyright 2012 Freescale Semiconductor, Inc.
3 * Copyright 2012 Linaro Ltd.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12
13#include <linux/cpuidle.h>
14#include <linux/err.h>
15#include <linux/hrtimer.h>
16#include <linux/io.h>
17#include <linux/kernel.h>
18#include <linux/slab.h>
19
20static struct cpuidle_device __percpu * imx_cpuidle_devices;
21
22static void __init imx_cpuidle_devices_uninit(void)
23{
24 int cpu_id;
25 struct cpuidle_device *dev;
26
27 for_each_possible_cpu(cpu_id) {
28 dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
29 cpuidle_unregister_device(dev);
30 }
31
32 free_percpu(imx_cpuidle_devices);
33}
34
35int __init imx_cpuidle_init(struct cpuidle_driver *drv)
36{
37 struct cpuidle_device *dev;
38 int cpu_id, ret;
39
40 if (drv->state_count > CPUIDLE_STATE_MAX) {
41 pr_err("%s: state_count exceeds maximum\n", __func__);
42 return -EINVAL;
43 }
44
45 ret = cpuidle_register_driver(drv);
46 if (ret) {
47 pr_err("%s: Failed to register cpuidle driver with error: %d\n",
48 __func__, ret);
49 return ret;
50 }
51
52 imx_cpuidle_devices = alloc_percpu(struct cpuidle_device);
53 if (imx_cpuidle_devices == NULL) {
54 ret = -ENOMEM;
55 goto unregister_drv;
56 }
57
58 /* initialize state data for each cpuidle_device */
59 for_each_possible_cpu(cpu_id) {
60 dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
61 dev->cpu = cpu_id;
62 dev->state_count = drv->state_count;
63
64 ret = cpuidle_register_device(dev);
65 if (ret) {
66 pr_err("%s: Failed to register cpu %u, error: %d\n",
67 __func__, cpu_id, ret);
68 goto uninit;
69 }
70 }
71
72 return 0;
73
74uninit:
75 imx_cpuidle_devices_uninit();
76
77unregister_drv:
78 cpuidle_unregister_driver(drv);
79 return ret;
80}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index e092d1359d94..786f98ecc145 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -10,18 +10,16 @@
10 * http://www.gnu.org/copyleft/gpl.html 10 * http://www.gnu.org/copyleft/gpl.html
11 */ 11 */
12 12
13#include <linux/cpuidle.h>
14
15#ifdef CONFIG_CPU_IDLE 13#ifdef CONFIG_CPU_IDLE
16extern int imx_cpuidle_init(struct cpuidle_driver *drv); 14extern int imx5_cpuidle_init(void);
17extern int imx6q_cpuidle_init(void); 15extern int imx6q_cpuidle_init(void);
18#else 16#else
19static inline int imx_cpuidle_init(struct cpuidle_driver *drv) 17static inline int imx5_cpuidle_init(void)
20{ 18{
21 return -ENODEV; 19 return 0;
22} 20}
23static inline int imx6q_cpuidle_init(void) 21static inline int imx6q_cpuidle_init(void)
24{ 22{
25 return -ENODEV; 23 return 0;
26} 24}
27#endif 25#endif
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c
index f67fd7ee8127..82e79c658eb2 100644
--- a/arch/arm/mach-imx/pm-imx5.c
+++ b/arch/arm/mach-imx/pm-imx5.c
@@ -149,33 +149,6 @@ static void imx5_pm_idle(void)
149 imx5_cpu_do_idle(); 149 imx5_cpu_do_idle();
150} 150}
151 151
152static int imx5_cpuidle_enter(struct cpuidle_device *dev,
153 struct cpuidle_driver *drv, int idx)
154{
155 int ret;
156
157 ret = imx5_cpu_do_idle();
158 if (ret < 0)
159 return ret;
160
161 return idx;
162}
163
164static struct cpuidle_driver imx5_cpuidle_driver = {
165 .name = "imx5_cpuidle",
166 .owner = THIS_MODULE,
167 .en_core_tk_irqen = 1,
168 .states[0] = {
169 .enter = imx5_cpuidle_enter,
170 .exit_latency = 2,
171 .target_residency = 1,
172 .flags = CPUIDLE_FLAG_TIME_VALID,
173 .name = "IMX5 SRPG",
174 .desc = "CPU state retained,powered off",
175 },
176 .state_count = 1,
177};
178
179static int __init imx5_pm_common_init(void) 152static int __init imx5_pm_common_init(void)
180{ 153{
181 int ret; 154 int ret;
@@ -193,8 +166,7 @@ static int __init imx5_pm_common_init(void)
193 /* Set the registers to the default cpu idle state. */ 166 /* Set the registers to the default cpu idle state. */
194 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE); 167 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
195 168
196 imx_cpuidle_init(&imx5_cpuidle_driver); 169 return imx5_cpuidle_init();
197 return 0;
198} 170}
199 171
200void __init imx51_pm_init(void) 172void __init imx51_pm_init(void)