2 * Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
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.
8 * CPU support functions
10 #include <linux/module.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/cpufreq.h>
14 #include <linux/sched.h>
15 #include <linux/smp.h>
16 #include <linux/init.h>
18 #include <linux/platform_device.h>
20 #include <linux/of_address.h>
22 #include <asm/mach-types.h>
23 #include <asm/hardware/icst.h>
25 static void __iomem
*cm_base
;
26 /* The cpufreq driver only use the OSC register */
27 #define INTEGRATOR_HDR_OSC_OFFSET 0x08
28 #define INTEGRATOR_HDR_LOCK_OFFSET 0x14
30 static struct cpufreq_driver integrator_driver
;
32 static const struct icst_params lclk_params
= {
34 .vco_max
= ICST525_VCO_MAX_5V
,
35 .vco_min
= ICST525_VCO_MIN
,
40 .s2div
= icst525_s2div
,
41 .idx2s
= icst525_idx2s
,
44 static const struct icst_params cclk_params
= {
46 .vco_max
= ICST525_VCO_MAX_5V
,
47 .vco_min
= ICST525_VCO_MIN
,
52 .s2div
= icst525_s2div
,
53 .idx2s
= icst525_idx2s
,
57 * Validate the speed policy.
59 static int integrator_verify_policy(struct cpufreq_policy
*policy
)
63 cpufreq_verify_within_limits(policy
,
64 policy
->cpuinfo
.min_freq
,
65 policy
->cpuinfo
.max_freq
);
67 vco
= icst_hz_to_vco(&cclk_params
, policy
->max
* 1000);
68 policy
->max
= icst_hz(&cclk_params
, vco
) / 1000;
70 vco
= icst_hz_to_vco(&cclk_params
, policy
->min
* 1000);
71 policy
->min
= icst_hz(&cclk_params
, vco
) / 1000;
73 cpufreq_verify_within_limits(policy
,
74 policy
->cpuinfo
.min_freq
,
75 policy
->cpuinfo
.max_freq
);
81 static int integrator_set_target(struct cpufreq_policy
*policy
,
82 unsigned int target_freq
,
83 unsigned int relation
)
85 cpumask_t cpus_allowed
;
86 int cpu
= policy
->cpu
;
88 struct cpufreq_freqs freqs
;
92 * Save this threads cpus_allowed mask.
94 cpus_allowed
= current
->cpus_allowed
;
97 * Bind to the specified CPU. When this call returns,
98 * we should be running on the right CPU.
100 set_cpus_allowed(current
, cpumask_of_cpu(cpu
));
101 BUG_ON(cpu
!= smp_processor_id());
103 /* get current setting */
104 cm_osc
= __raw_readl(cm_base
+ INTEGRATOR_HDR_OSC_OFFSET
);
106 if (machine_is_integrator()) {
107 vco
.s
= (cm_osc
>> 8) & 7;
108 } else if (machine_is_cintegrator()) {
111 vco
.v
= cm_osc
& 255;
113 freqs
.old
= icst_hz(&cclk_params
, vco
) / 1000;
115 /* icst_hz_to_vco rounds down -- so we need the next
116 * larger freq in case of CPUFREQ_RELATION_L.
118 if (relation
== CPUFREQ_RELATION_L
)
120 if (target_freq
> policy
->max
)
121 target_freq
= policy
->max
;
122 vco
= icst_hz_to_vco(&cclk_params
, target_freq
* 1000);
123 freqs
.new = icst_hz(&cclk_params
, vco
) / 1000;
125 if (freqs
.old
== freqs
.new) {
126 set_cpus_allowed(current
, cpus_allowed
);
130 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_PRECHANGE
);
132 cm_osc
= __raw_readl(cm_base
+ INTEGRATOR_HDR_OSC_OFFSET
);
134 if (machine_is_integrator()) {
135 cm_osc
&= 0xfffff800;
136 cm_osc
|= vco
.s
<< 8;
137 } else if (machine_is_cintegrator()) {
138 cm_osc
&= 0xffffff00;
142 __raw_writel(0xa05f, cm_base
+ INTEGRATOR_HDR_LOCK_OFFSET
);
143 __raw_writel(cm_osc
, cm_base
+ INTEGRATOR_HDR_OSC_OFFSET
);
144 __raw_writel(0, cm_base
+ INTEGRATOR_HDR_LOCK_OFFSET
);
147 * Restore the CPUs allowed mask.
149 set_cpus_allowed(current
, cpus_allowed
);
151 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_POSTCHANGE
);
156 static unsigned int integrator_get(unsigned int cpu
)
158 cpumask_t cpus_allowed
;
159 unsigned int current_freq
;
163 cpus_allowed
= current
->cpus_allowed
;
165 set_cpus_allowed(current
, cpumask_of_cpu(cpu
));
166 BUG_ON(cpu
!= smp_processor_id());
168 /* detect memory etc. */
169 cm_osc
= __raw_readl(cm_base
+ INTEGRATOR_HDR_OSC_OFFSET
);
171 if (machine_is_integrator()) {
172 vco
.s
= (cm_osc
>> 8) & 7;
176 vco
.v
= cm_osc
& 255;
179 current_freq
= icst_hz(&cclk_params
, vco
) / 1000; /* current freq */
181 set_cpus_allowed(current
, cpus_allowed
);
186 static int integrator_cpufreq_init(struct cpufreq_policy
*policy
)
189 /* set default policy and cpuinfo */
190 policy
->cpuinfo
.max_freq
= 160000;
191 policy
->cpuinfo
.min_freq
= 12000;
192 policy
->cpuinfo
.transition_latency
= 1000000; /* 1 ms, assumed */
193 policy
->cur
= policy
->min
= policy
->max
= integrator_get(policy
->cpu
);
198 static struct cpufreq_driver integrator_driver
= {
199 .verify
= integrator_verify_policy
,
200 .target
= integrator_set_target
,
201 .get
= integrator_get
,
202 .init
= integrator_cpufreq_init
,
203 .name
= "integrator",
206 static int __init
integrator_cpufreq_probe(struct platform_device
*pdev
)
208 struct resource
*res
;
210 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
214 cm_base
= devm_ioremap(&pdev
->dev
, res
->start
, resource_size(res
));
218 return cpufreq_register_driver(&integrator_driver
);
221 static void __exit
integrator_cpufreq_remove(struct platform_device
*pdev
)
223 cpufreq_unregister_driver(&integrator_driver
);
226 static const struct of_device_id integrator_cpufreq_match
[] = {
227 { .compatible
= "arm,core-module-integrator"},
231 static struct platform_driver integrator_cpufreq_driver
= {
233 .name
= "integrator-cpufreq",
234 .owner
= THIS_MODULE
,
235 .of_match_table
= integrator_cpufreq_match
,
237 .remove
= __exit_p(integrator_cpufreq_remove
),
240 module_platform_driver_probe(integrator_cpufreq_driver
,
241 integrator_cpufreq_probe
);
243 MODULE_AUTHOR ("Russell M. King");
244 MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
245 MODULE_LICENSE ("GPL");