Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-integrator/cpu.c
10817 views
1
/*
2
* linux/arch/arm/mach-integrator/cpu.c
3
*
4
* Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2 as
8
* published by the Free Software Foundation.
9
*
10
* CPU support functions
11
*/
12
#include <linux/module.h>
13
#include <linux/types.h>
14
#include <linux/kernel.h>
15
#include <linux/cpufreq.h>
16
#include <linux/sched.h>
17
#include <linux/smp.h>
18
#include <linux/init.h>
19
#include <linux/io.h>
20
21
#include <mach/hardware.h>
22
#include <mach/platform.h>
23
#include <asm/mach-types.h>
24
#include <asm/hardware/icst.h>
25
26
static struct cpufreq_driver integrator_driver;
27
28
#define CM_ID IO_ADDRESS(INTEGRATOR_HDR_ID)
29
#define CM_OSC IO_ADDRESS(INTEGRATOR_HDR_OSC)
30
#define CM_STAT IO_ADDRESS(INTEGRATOR_HDR_STAT)
31
#define CM_LOCK IO_ADDRESS(INTEGRATOR_HDR_LOCK)
32
33
static const struct icst_params lclk_params = {
34
.ref = 24000000,
35
.vco_max = ICST525_VCO_MAX_5V,
36
.vco_min = ICST525_VCO_MIN,
37
.vd_min = 8,
38
.vd_max = 132,
39
.rd_min = 24,
40
.rd_max = 24,
41
.s2div = icst525_s2div,
42
.idx2s = icst525_idx2s,
43
};
44
45
static const struct icst_params cclk_params = {
46
.ref = 24000000,
47
.vco_max = ICST525_VCO_MAX_5V,
48
.vco_min = ICST525_VCO_MIN,
49
.vd_min = 12,
50
.vd_max = 160,
51
.rd_min = 24,
52
.rd_max = 24,
53
.s2div = icst525_s2div,
54
.idx2s = icst525_idx2s,
55
};
56
57
/*
58
* Validate the speed policy.
59
*/
60
static int integrator_verify_policy(struct cpufreq_policy *policy)
61
{
62
struct icst_vco vco;
63
64
cpufreq_verify_within_limits(policy,
65
policy->cpuinfo.min_freq,
66
policy->cpuinfo.max_freq);
67
68
vco = icst_hz_to_vco(&cclk_params, policy->max * 1000);
69
policy->max = icst_hz(&cclk_params, vco) / 1000;
70
71
vco = icst_hz_to_vco(&cclk_params, policy->min * 1000);
72
policy->min = icst_hz(&cclk_params, vco) / 1000;
73
74
cpufreq_verify_within_limits(policy,
75
policy->cpuinfo.min_freq,
76
policy->cpuinfo.max_freq);
77
78
return 0;
79
}
80
81
82
static int integrator_set_target(struct cpufreq_policy *policy,
83
unsigned int target_freq,
84
unsigned int relation)
85
{
86
cpumask_t cpus_allowed;
87
int cpu = policy->cpu;
88
struct icst_vco vco;
89
struct cpufreq_freqs freqs;
90
u_int cm_osc;
91
92
/*
93
* Save this threads cpus_allowed mask.
94
*/
95
cpus_allowed = current->cpus_allowed;
96
97
/*
98
* Bind to the specified CPU. When this call returns,
99
* we should be running on the right CPU.
100
*/
101
set_cpus_allowed(current, cpumask_of_cpu(cpu));
102
BUG_ON(cpu != smp_processor_id());
103
104
/* get current setting */
105
cm_osc = __raw_readl(CM_OSC);
106
107
if (machine_is_integrator()) {
108
vco.s = (cm_osc >> 8) & 7;
109
} else if (machine_is_cintegrator()) {
110
vco.s = 1;
111
}
112
vco.v = cm_osc & 255;
113
vco.r = 22;
114
freqs.old = icst_hz(&cclk_params, vco) / 1000;
115
116
/* icst_hz_to_vco rounds down -- so we need the next
117
* larger freq in case of CPUFREQ_RELATION_L.
118
*/
119
if (relation == CPUFREQ_RELATION_L)
120
target_freq += 999;
121
if (target_freq > policy->max)
122
target_freq = policy->max;
123
vco = icst_hz_to_vco(&cclk_params, target_freq * 1000);
124
freqs.new = icst_hz(&cclk_params, vco) / 1000;
125
126
freqs.cpu = policy->cpu;
127
128
if (freqs.old == freqs.new) {
129
set_cpus_allowed(current, cpus_allowed);
130
return 0;
131
}
132
133
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
134
135
cm_osc = __raw_readl(CM_OSC);
136
137
if (machine_is_integrator()) {
138
cm_osc &= 0xfffff800;
139
cm_osc |= vco.s << 8;
140
} else if (machine_is_cintegrator()) {
141
cm_osc &= 0xffffff00;
142
}
143
cm_osc |= vco.v;
144
145
__raw_writel(0xa05f, CM_LOCK);
146
__raw_writel(cm_osc, CM_OSC);
147
__raw_writel(0, CM_LOCK);
148
149
/*
150
* Restore the CPUs allowed mask.
151
*/
152
set_cpus_allowed(current, cpus_allowed);
153
154
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
155
156
return 0;
157
}
158
159
static unsigned int integrator_get(unsigned int cpu)
160
{
161
cpumask_t cpus_allowed;
162
unsigned int current_freq;
163
u_int cm_osc;
164
struct icst_vco vco;
165
166
cpus_allowed = current->cpus_allowed;
167
168
set_cpus_allowed(current, cpumask_of_cpu(cpu));
169
BUG_ON(cpu != smp_processor_id());
170
171
/* detect memory etc. */
172
cm_osc = __raw_readl(CM_OSC);
173
174
if (machine_is_integrator()) {
175
vco.s = (cm_osc >> 8) & 7;
176
} else {
177
vco.s = 1;
178
}
179
vco.v = cm_osc & 255;
180
vco.r = 22;
181
182
current_freq = icst_hz(&cclk_params, vco) / 1000; /* current freq */
183
184
set_cpus_allowed(current, cpus_allowed);
185
186
return current_freq;
187
}
188
189
static int integrator_cpufreq_init(struct cpufreq_policy *policy)
190
{
191
192
/* set default policy and cpuinfo */
193
policy->cpuinfo.max_freq = 160000;
194
policy->cpuinfo.min_freq = 12000;
195
policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
196
policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
197
198
return 0;
199
}
200
201
static struct cpufreq_driver integrator_driver = {
202
.verify = integrator_verify_policy,
203
.target = integrator_set_target,
204
.get = integrator_get,
205
.init = integrator_cpufreq_init,
206
.name = "integrator",
207
};
208
209
static int __init integrator_cpu_init(void)
210
{
211
return cpufreq_register_driver(&integrator_driver);
212
}
213
214
static void __exit integrator_cpu_exit(void)
215
{
216
cpufreq_unregister_driver(&integrator_driver);
217
}
218
219
MODULE_AUTHOR ("Russell M. King");
220
MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
221
MODULE_LICENSE ("GPL");
222
223
module_init(integrator_cpu_init);
224
module_exit(integrator_cpu_exit);
225
226