aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/Kconfig18
-rw-r--r--arch/sh/include/asm/suspend.h4
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/cpu/shmobile/cpuidle.c101
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm.c3
-rw-r--r--arch/sh/kernel/cpufreq.c201
6 files changed, 45 insertions, 283 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 1ea597c6497a..78d8ace57272 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -622,25 +622,7 @@ config SH_CLK_CPG_LEGACY
622endmenu 622endmenu
623 623
624menu "CPU Frequency scaling" 624menu "CPU Frequency scaling"
625
626source "drivers/cpufreq/Kconfig" 625source "drivers/cpufreq/Kconfig"
627
628config SH_CPU_FREQ
629 tristate "SuperH CPU Frequency driver"
630 depends on CPU_FREQ
631 select CPU_FREQ_TABLE
632 help
633 This adds the cpufreq driver for SuperH. Any CPU that supports
634 clock rate rounding through the clock framework can use this
635 driver. While it will make the kernel slightly larger, this is
636 harmless for CPUs that don't support rate rounding. The driver
637 will also generate a notice in the boot log before disabling
638 itself if the CPU in question is not capable of rate rounding.
639
640 For details, take a look at <file:Documentation/cpu-freq>.
641
642 If unsure, say N.
643
644endmenu 626endmenu
645 627
646source "arch/sh/drivers/Kconfig" 628source "arch/sh/drivers/Kconfig"
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h
index e14567a7e9a1..70ae0b2888ab 100644
--- a/arch/sh/include/asm/suspend.h
+++ b/arch/sh/include/asm/suspend.h
@@ -14,9 +14,9 @@ struct swsusp_arch_regs {
14void sh_mobile_call_standby(unsigned long mode); 14void sh_mobile_call_standby(unsigned long mode);
15 15
16#ifdef CONFIG_CPU_IDLE 16#ifdef CONFIG_CPU_IDLE
17void sh_mobile_setup_cpuidle(void); 17int sh_mobile_setup_cpuidle(void);
18#else 18#else
19static inline void sh_mobile_setup_cpuidle(void) {} 19static inline int sh_mobile_setup_cpuidle(void) { return 0; }
20#endif 20#endif
21 21
22/* notifier chains for pre/post sleep hooks */ 22/* notifier chains for pre/post sleep hooks */
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index f259b37874e9..261c8bfd75ce 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -31,7 +31,6 @@ obj-$(CONFIG_VSYSCALL) += vsyscall/
31obj-$(CONFIG_SMP) += smp.o 31obj-$(CONFIG_SMP) += smp.o
32obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o 32obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
33obj-$(CONFIG_KGDB) += kgdb.o 33obj-$(CONFIG_KGDB) += kgdb.o
34obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
35obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o 34obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o
36obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o 35obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
37obj-$(CONFIG_CRASH_DUMP) += crash_dump.o 36obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 1ddc876d3b26..d30622592116 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -51,70 +51,53 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev,
51 return k; 51 return k;
52} 52}
53 53
54static struct cpuidle_device cpuidle_dev;
55static struct cpuidle_driver cpuidle_driver = { 54static struct cpuidle_driver cpuidle_driver = {
56 .name = "sh_idle", 55 .name = "sh_idle",
57 .owner = THIS_MODULE, 56 .owner = THIS_MODULE,
58 .en_core_tk_irqen = 1, 57 .states = {
58 {
59 .exit_latency = 1,
60 .target_residency = 1 * 2,
61 .power_usage = 3,
62 .flags = CPUIDLE_FLAG_TIME_VALID,
63 .enter = cpuidle_sleep_enter,
64 .name = "C1",
65 .desc = "SuperH Sleep Mode",
66 },
67 {
68 .exit_latency = 100,
69 .target_residency = 1 * 2,
70 .power_usage = 1,
71 .flags = CPUIDLE_FLAG_TIME_VALID,
72 .enter = cpuidle_sleep_enter,
73 .name = "C2",
74 .desc = "SuperH Sleep Mode [SF]",
75 .disabled = true,
76 },
77 {
78 .exit_latency = 2300,
79 .target_residency = 1 * 2,
80 .power_usage = 1,
81 .flags = CPUIDLE_FLAG_TIME_VALID,
82 .enter = cpuidle_sleep_enter,
83 .name = "C3",
84 .desc = "SuperH Mobile Standby Mode [SF]",
85 .disabled = true,
86 },
87 },
88 .safe_state_index = 0,
89 .state_count = 3,
59}; 90};
60 91
61void sh_mobile_setup_cpuidle(void) 92int __init sh_mobile_setup_cpuidle(void)
62{ 93{
63 struct cpuidle_device *dev = &cpuidle_dev; 94 int ret;
64 struct cpuidle_driver *drv = &cpuidle_driver;
65 struct cpuidle_state *state;
66 int i;
67 95
96 if (sh_mobile_sleep_supported & SUSP_SH_SF)
97 cpuidle_driver.states[1].disabled = false;
68 98
69 for (i = 0; i < CPUIDLE_STATE_MAX; i++) { 99 if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
70 drv->states[i].name[0] = '\0'; 100 cpuidle_driver.states[2].disabled = false;
71 drv->states[i].desc[0] = '\0';
72 }
73 101
74 i = CPUIDLE_DRIVER_STATE_START; 102 return cpuidle_register(&cpuidle_driver);
75
76 state = &drv->states[i++];
77 snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
78 strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
79 state->exit_latency = 1;
80 state->target_residency = 1 * 2;
81 state->power_usage = 3;
82 state->flags = 0;
83 state->flags |= CPUIDLE_FLAG_TIME_VALID;
84 state->enter = cpuidle_sleep_enter;
85
86 drv->safe_state_index = i-1;
87
88 if (sh_mobile_sleep_supported & SUSP_SH_SF) {
89 state = &drv->states[i++];
90 snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
91 strncpy(state->desc, "SuperH Sleep Mode [SF]",
92 CPUIDLE_DESC_LEN);
93 state->exit_latency = 100;
94 state->target_residency = 1 * 2;
95 state->power_usage = 1;
96 state->flags = 0;
97 state->flags |= CPUIDLE_FLAG_TIME_VALID;
98 state->enter = cpuidle_sleep_enter;
99 }
100
101 if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
102 state = &drv->states[i++];
103 snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
104 strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
105 CPUIDLE_DESC_LEN);
106 state->exit_latency = 2300;
107 state->target_residency = 1 * 2;
108 state->power_usage = 1;
109 state->flags = 0;
110 state->flags |= CPUIDLE_FLAG_TIME_VALID;
111 state->enter = cpuidle_sleep_enter;
112 }
113
114 drv->state_count = i;
115 dev->state_count = i;
116
117 cpuidle_register_driver(&cpuidle_driver);
118
119 cpuidle_register_device(dev);
120} 103}
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
index 08d27fac8d08..ac37b7234f85 100644
--- a/arch/sh/kernel/cpu/shmobile/pm.c
+++ b/arch/sh/kernel/cpu/shmobile/pm.c
@@ -150,8 +150,7 @@ static const struct platform_suspend_ops sh_pm_ops = {
150static int __init sh_pm_init(void) 150static int __init sh_pm_init(void)
151{ 151{
152 suspend_set_ops(&sh_pm_ops); 152 suspend_set_ops(&sh_pm_ops);
153 sh_mobile_setup_cpuidle(); 153 return sh_mobile_setup_cpuidle();
154 return 0;
155} 154}
156 155
157late_initcall(sh_pm_init); 156late_initcall(sh_pm_init);
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
deleted file mode 100644
index e68b45b6f3f9..000000000000
--- a/arch/sh/kernel/cpufreq.c
+++ /dev/null
@@ -1,201 +0,0 @@
1/*
2 * arch/sh/kernel/cpufreq.c
3 *
4 * cpufreq driver for the SuperH processors.
5 *
6 * Copyright (C) 2002 - 2012 Paul Mundt
7 * Copyright (C) 2002 M. R. Brown
8 *
9 * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
10 *
11 * Copyright (C) 2004-2007 Atmel Corporation
12 *
13 * This file is subject to the terms and conditions of the GNU General Public
14 * License. See the file "COPYING" in the main directory of this archive
15 * for more details.
16 */
17#define pr_fmt(fmt) "cpufreq: " fmt
18
19#include <linux/types.h>
20#include <linux/cpufreq.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/err.h>
25#include <linux/cpumask.h>
26#include <linux/cpu.h>
27#include <linux/smp.h>
28#include <linux/sched.h> /* set_cpus_allowed() */
29#include <linux/clk.h>
30#include <linux/percpu.h>
31#include <linux/sh_clk.h>
32
33static DEFINE_PER_CPU(struct clk, sh_cpuclk);
34
35static unsigned int sh_cpufreq_get(unsigned int cpu)
36{
37 return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000;
38}
39
40/*
41 * Here we notify other drivers of the proposed change and the final change.
42 */
43static int sh_cpufreq_target(struct cpufreq_policy *policy,
44 unsigned int target_freq,
45 unsigned int relation)
46{
47 unsigned int cpu = policy->cpu;
48 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
49 cpumask_t cpus_allowed;
50 struct cpufreq_freqs freqs;
51 struct device *dev;
52 long freq;
53
54 if (!cpu_online(cpu))
55 return -ENODEV;
56
57 cpus_allowed = current->cpus_allowed;
58 set_cpus_allowed_ptr(current, cpumask_of(cpu));
59
60 BUG_ON(smp_processor_id() != cpu);
61
62 dev = get_cpu_device(cpu);
63
64 /* Convert target_freq from kHz to Hz */
65 freq = clk_round_rate(cpuclk, target_freq * 1000);
66
67 if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
68 return -EINVAL;
69
70 dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000);
71
72 freqs.cpu = cpu;
73 freqs.old = sh_cpufreq_get(cpu);
74 freqs.new = (freq + 500) / 1000;
75 freqs.flags = 0;
76
77 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
78 set_cpus_allowed_ptr(current, &cpus_allowed);
79 clk_set_rate(cpuclk, freq);
80 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
81
82 dev_dbg(dev, "set frequency %lu Hz\n", freq);
83
84 return 0;
85}
86
87static int sh_cpufreq_verify(struct cpufreq_policy *policy)
88{
89 struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
90 struct cpufreq_frequency_table *freq_table;
91
92 freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
93 if (freq_table)
94 return cpufreq_frequency_table_verify(policy, freq_table);
95
96 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
97 policy->cpuinfo.max_freq);
98
99 policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000;
100 policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
101
102 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
103 policy->cpuinfo.max_freq);
104
105 return 0;
106}
107
108static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
109{
110 unsigned int cpu = policy->cpu;
111 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
112 struct cpufreq_frequency_table *freq_table;
113 struct device *dev;
114
115 if (!cpu_online(cpu))
116 return -ENODEV;
117
118 dev = get_cpu_device(cpu);
119
120 cpuclk = clk_get(dev, "cpu_clk");
121 if (IS_ERR(cpuclk)) {
122 dev_err(dev, "couldn't get CPU clk\n");
123 return PTR_ERR(cpuclk);
124 }
125
126 policy->cur = policy->min = policy->max = sh_cpufreq_get(cpu);
127
128 freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
129 if (freq_table) {
130 int result;
131
132 result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
133 if (!result)
134 cpufreq_frequency_table_get_attr(freq_table, cpu);
135 } else {
136 dev_notice(dev, "no frequency table found, falling back "
137 "to rate rounding.\n");
138
139 policy->cpuinfo.min_freq =
140 (clk_round_rate(cpuclk, 1) + 500) / 1000;
141 policy->cpuinfo.max_freq =
142 (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
143 }
144
145 policy->min = policy->cpuinfo.min_freq;
146 policy->max = policy->cpuinfo.max_freq;
147
148 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
149
150 dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, "
151 "Maximum %u.%03u MHz.\n",
152 policy->min / 1000, policy->min % 1000,
153 policy->max / 1000, policy->max % 1000);
154
155 return 0;
156}
157
158static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
159{
160 unsigned int cpu = policy->cpu;
161 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
162
163 cpufreq_frequency_table_put_attr(cpu);
164 clk_put(cpuclk);
165
166 return 0;
167}
168
169static struct freq_attr *sh_freq_attr[] = {
170 &cpufreq_freq_attr_scaling_available_freqs,
171 NULL,
172};
173
174static struct cpufreq_driver sh_cpufreq_driver = {
175 .owner = THIS_MODULE,
176 .name = "sh",
177 .get = sh_cpufreq_get,
178 .target = sh_cpufreq_target,
179 .verify = sh_cpufreq_verify,
180 .init = sh_cpufreq_cpu_init,
181 .exit = sh_cpufreq_cpu_exit,
182 .attr = sh_freq_attr,
183};
184
185static int __init sh_cpufreq_module_init(void)
186{
187 pr_notice("SuperH CPU frequency driver.\n");
188 return cpufreq_register_driver(&sh_cpufreq_driver);
189}
190
191static void __exit sh_cpufreq_module_exit(void)
192{
193 cpufreq_unregister_driver(&sh_cpufreq_driver);
194}
195
196module_init(sh_cpufreq_module_init);
197module_exit(sh_cpufreq_module_exit);
198
199MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
200MODULE_DESCRIPTION("cpufreq driver for SuperH");
201MODULE_LICENSE("GPL");