scoutos / prex-0.9.0 / bsp / drv / dev / cpufreq / est.c @ 03e9c04a
History | View | Annotate | Download (13.2 KB)
1 |
/* $OpenBSD: est.c,v 1.11 2005/03/07 06:59:14 mbalmer Exp $ */
|
---|---|
2 |
/*
|
3 |
* Copyright (c) 2003 Michael Eriksson.
|
4 |
* All rights reserved.
|
5 |
*
|
6 |
* Redistribution and use in source and binary forms, with or without
|
7 |
* modification, are permitted provided that the following conditions
|
8 |
* are met:
|
9 |
* 1. Redistributions of source code must retain the above copyright
|
10 |
* notice, this list of conditions and the following disclaimer.
|
11 |
* 2. Redistributions in binary form must reproduce the above copyright
|
12 |
* notice, this list of conditions and the following disclaimer in the
|
13 |
* documentation and/or other materials provided with the distribution.
|
14 |
* 3. The name of the author may not be used to endorse or promote products
|
15 |
* derived from this software without specific prior written permission.
|
16 |
*
|
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
18 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
19 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
20 |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
21 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
22 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
26 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27 |
*/
|
28 |
/*
|
29 |
* This is a driver for Intel's Enhanced SpeedStep, as implemented in
|
30 |
* Pentium M processors.
|
31 |
*
|
32 |
* Reference documentation:
|
33 |
*
|
34 |
* - IA-32 Intel Architecture Software Developer's Manual, Volume 3:
|
35 |
* System Programming Guide.
|
36 |
* Section 13.14, Enhanced Intel SpeedStep technology.
|
37 |
* Table B-2, MSRs in Pentium M Processors.
|
38 |
* http://www.intel.com/design/pentium4/manuals/245472.htm
|
39 |
*
|
40 |
* - Intel Pentium M Processor Datasheet.
|
41 |
* Table 5, Voltage and Current Specifications.
|
42 |
* http://www.intel.com/design/mobile/datashts/252612.htm
|
43 |
*
|
44 |
* - Intel Pentium M Processor on 90 nm Process with 2-MB L2 Cache Datasheet
|
45 |
* Table 3-4, Voltage and Current Specifications.
|
46 |
* http://www.intel.com/design/mobile/datashts/302189.htm
|
47 |
*
|
48 |
* - Linux cpufreq patches, speedstep-centrino.c.
|
49 |
* Encoding of MSR_PERF_CTL and MSR_PERF_STATUS.
|
50 |
* http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz
|
51 |
*/
|
52 |
|
53 |
/*
|
54 |
* est.c - Intel enhanced speedstep driver from OpenBSD.
|
55 |
*/
|
56 |
|
57 |
#include <driver.h> |
58 |
#include <cpufreq.h> |
59 |
#include <cpufunc.h> |
60 |
#include <sys/ioctl.h> |
61 |
|
62 |
/* #define DEBUG_EST 1 */
|
63 |
|
64 |
#ifdef DEBUG_EST
|
65 |
#define DPRINTF(a) printf a
|
66 |
#else
|
67 |
#define DPRINTF(a)
|
68 |
#endif
|
69 |
|
70 |
/* Status/control registers (from the IA-32 System Programming Guide). */
|
71 |
#define MSR_PERF_STATUS 0x198 |
72 |
#define MSR_PERF_CTL 0x199 |
73 |
|
74 |
/* Register and bit for enabling SpeedStep. */
|
75 |
#define MSR_MISC_ENABLE 0x1a0 |
76 |
#define MSR_SS_ENABLE (1<<16) |
77 |
|
78 |
static int est_probe(struct driver *); |
79 |
static int est_init(struct driver *); |
80 |
static int est_setperf(int); |
81 |
static int est_getperf(void); |
82 |
static void est_getinfo(struct cpufreqinfo *); |
83 |
static int est_identify(char *); |
84 |
|
85 |
static struct cpufreq_ops est_ops = { |
86 |
/* setperf */ est_setperf,
|
87 |
/* getpref */ est_getperf,
|
88 |
/* getinfo */ est_getinfo,
|
89 |
}; |
90 |
|
91 |
struct driver est_driver = {
|
92 |
/* name */ "est", |
93 |
/* devops */ NULL, |
94 |
/* flags */ 0, |
95 |
/* flags */ 0, |
96 |
/* probe */ est_probe,
|
97 |
/* init */ est_init,
|
98 |
/* shutdown */ NULL, |
99 |
}; |
100 |
|
101 |
/*
|
102 |
* Frequency tables
|
103 |
*/
|
104 |
struct fq_info {
|
105 |
int mhz;
|
106 |
int mv;
|
107 |
}; |
108 |
|
109 |
/* Ultra Low Voltage Intel Pentium M processor 900 MHz */
|
110 |
static const struct fq_info pentium_m_900[] = { |
111 |
{ 900, 1004 }, |
112 |
{ 800, 988 }, |
113 |
{ 600, 844 }, |
114 |
}; |
115 |
|
116 |
/* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
|
117 |
static const struct fq_info pentium_m_1000[] = { |
118 |
{ 1000, 1004 }, |
119 |
{ 900, 988 }, |
120 |
{ 800, 972 }, |
121 |
{ 600, 844 }, |
122 |
}; |
123 |
|
124 |
/* Low Voltage Intel Pentium M processor 1.10 GHz */
|
125 |
static const struct fq_info pentium_m_1100[] = { |
126 |
{ 1100, 1180 }, |
127 |
{ 1000, 1164 }, |
128 |
{ 900, 1100 }, |
129 |
{ 800, 1020 }, |
130 |
{ 600, 956 }, |
131 |
}; |
132 |
|
133 |
/* Low Voltage Intel Pentium M processor 1.20 GHz */
|
134 |
static const struct fq_info pentium_m_1200[] = { |
135 |
{ 1200, 1180 }, |
136 |
{ 1100, 1164 }, |
137 |
{ 1000, 1100 }, |
138 |
{ 900, 1020 }, |
139 |
{ 800, 1004 }, |
140 |
{ 600, 956 }, |
141 |
}; |
142 |
|
143 |
/* Intel Pentium M processor 1.30 GHz */
|
144 |
static const struct fq_info pentium_m_1300[] = { |
145 |
{ 1300, 1388 }, |
146 |
{ 1200, 1356 }, |
147 |
{ 1000, 1292 }, |
148 |
{ 800, 1260 }, |
149 |
{ 600, 956 }, |
150 |
}; |
151 |
|
152 |
/* Intel Pentium M processor 1.40 GHz */
|
153 |
static const struct fq_info pentium_m_1400[] = { |
154 |
{ 1400, 1484 }, |
155 |
{ 1200, 1436 }, |
156 |
{ 1000, 1308 }, |
157 |
{ 800, 1180 }, |
158 |
{ 600, 956 } |
159 |
}; |
160 |
|
161 |
/* Intel Pentium M processor 1.50 GHz */
|
162 |
static const struct fq_info pentium_m_1500[] = { |
163 |
{ 1500, 1484 }, |
164 |
{ 1400, 1452 }, |
165 |
{ 1200, 1356 }, |
166 |
{ 1000, 1228 }, |
167 |
{ 800, 1116 }, |
168 |
{ 600, 956 } |
169 |
}; |
170 |
|
171 |
/* Intel Pentium M processor 1.60 GHz */
|
172 |
static const struct fq_info pentium_m_1600[] = { |
173 |
{ 1600, 1484 }, |
174 |
{ 1400, 1420 }, |
175 |
{ 1200, 1276 }, |
176 |
{ 1000, 1164 }, |
177 |
{ 800, 1036 }, |
178 |
{ 600, 956 } |
179 |
}; |
180 |
|
181 |
/* Intel Pentium M processor 1.70 GHz */
|
182 |
static const struct fq_info pentium_m_1700[] = { |
183 |
{ 1700, 1484 }, |
184 |
{ 1400, 1308 }, |
185 |
{ 1200, 1228 }, |
186 |
{ 1000, 1116 }, |
187 |
{ 800, 1004 }, |
188 |
{ 600, 956 } |
189 |
}; |
190 |
|
191 |
|
192 |
/* Intel Pentium M processor 723 1.0 GHz */
|
193 |
static const struct fq_info pentium_m_n723[] = { |
194 |
{ 1000, 940 }, |
195 |
{ 900, 908 }, |
196 |
{ 800, 876 }, |
197 |
{ 600, 812 } |
198 |
}; |
199 |
|
200 |
/* Intel Pentium M processor 733 1.1 GHz */
|
201 |
static const struct fq_info pentium_m_n733[] = { |
202 |
{ 1100, 940 }, |
203 |
{ 1000, 924 }, |
204 |
{ 900, 892 }, |
205 |
{ 800, 876 }, |
206 |
{ 600, 812 } |
207 |
}; |
208 |
|
209 |
/* Intel Pentium M processor 753 1.2 GHz */
|
210 |
static const struct fq_info pentium_m_n753[] = { |
211 |
{ 1200, 940 }, |
212 |
{ 1100, 924 }, |
213 |
{ 1000, 908 }, |
214 |
{ 900, 876 }, |
215 |
{ 800, 860 }, |
216 |
{ 600, 812 } |
217 |
}; |
218 |
|
219 |
/* Intel Pentium M processor 738 1.4 GHz */
|
220 |
static const struct fq_info pentium_m_n738[] = { |
221 |
{ 1400, 1116 }, |
222 |
{ 1300, 1116 }, |
223 |
{ 1200, 1100 }, |
224 |
{ 1100, 1068 }, |
225 |
{ 1000, 1052 }, |
226 |
{ 900, 1036 }, |
227 |
{ 800, 1020 }, |
228 |
{ 600, 988 } |
229 |
}; |
230 |
|
231 |
#if 0
|
232 |
/* Intel Pentium M processor 758 1.5 GHz */
|
233 |
static const struct fq_info pentium_m_n758[] = {
|
234 |
{ 1500, 1116 },
|
235 |
{ 1400, 1116 },
|
236 |
{ 1300, 1100 },
|
237 |
{ 1200, 1084 },
|
238 |
{ 1100, 1068 },
|
239 |
{ 1000, 1052 },
|
240 |
{ 900, 1036 },
|
241 |
{ 800, 1020 },
|
242 |
{ 600, 988 }
|
243 |
};
|
244 |
#endif
|
245 |
|
246 |
/* Intel Pentium M processor 715 1.5 GHz */
|
247 |
static const struct fq_info pentium_m_n715[] = { |
248 |
{ 1500, 1340 }, |
249 |
{ 1200, 1228 }, |
250 |
{ 1000, 1148 }, |
251 |
{ 800, 1068 }, |
252 |
{ 600, 988 } |
253 |
}; |
254 |
|
255 |
/* Intel Pentium M processor 725 1.6 GHz */
|
256 |
static const struct fq_info pentium_m_n725[] = { |
257 |
{ 1600, 1340 }, |
258 |
{ 1400, 1276 }, |
259 |
{ 1200, 1212 }, |
260 |
{ 1000, 1132 }, |
261 |
{ 800, 1068 }, |
262 |
{ 600, 988 } |
263 |
}; |
264 |
|
265 |
/* Intel Pentium M processor 735 1.7 GHz */
|
266 |
static const struct fq_info pentium_m_n735[] = { |
267 |
{ 1700, 1340 }, |
268 |
{ 1400, 1244 }, |
269 |
{ 1200, 1180 }, |
270 |
{ 1000, 1116 }, |
271 |
{ 800, 1052 }, |
272 |
{ 600, 988 } |
273 |
}; |
274 |
|
275 |
/* Intel Pentium M processor 745 1.8 GHz */
|
276 |
static const struct fq_info pentium_m_n745[] = { |
277 |
{ 1800, 1340 }, |
278 |
{ 1600, 1292 }, |
279 |
{ 1400, 1228 }, |
280 |
{ 1200, 1164 }, |
281 |
{ 1000, 1116 }, |
282 |
{ 800, 1052 }, |
283 |
{ 600, 988 } |
284 |
}; |
285 |
|
286 |
/* Intel Pentium M processor 755 2.0 GHz */
|
287 |
static const struct fq_info pentium_m_n755[] = { |
288 |
{ 2000, 1340 }, |
289 |
{ 1800, 1292 }, |
290 |
{ 1600, 1244 }, |
291 |
{ 1400, 1196 }, |
292 |
{ 1200, 1148 }, |
293 |
{ 1000, 1100 }, |
294 |
{ 800, 1052 }, |
295 |
{ 600, 988 } |
296 |
}; |
297 |
|
298 |
/* Intel Pentium M processor 765 2.1 GHz */
|
299 |
static const struct fq_info pentium_m_n765[] = { |
300 |
{ 2100, 1340 }, |
301 |
{ 1800, 1276 }, |
302 |
{ 1600, 1228 }, |
303 |
{ 1400, 1180 }, |
304 |
{ 1200, 1132 }, |
305 |
{ 1000, 1084 }, |
306 |
{ 800, 1036 }, |
307 |
{ 600, 988 } |
308 |
}; |
309 |
|
310 |
struct fqlist {
|
311 |
const char *brand_tag; |
312 |
const struct fq_info *table; |
313 |
int n;
|
314 |
}; |
315 |
|
316 |
static const struct fqlist pentium_m[] = { |
317 |
#define ENTRY(s, v) { s, v, (int)(sizeof(v) / sizeof((v)[0])) } |
318 |
ENTRY(" 900", pentium_m_900),
|
319 |
ENTRY("1000", pentium_m_1000),
|
320 |
ENTRY("1100", pentium_m_1100),
|
321 |
ENTRY("1200", pentium_m_1200),
|
322 |
ENTRY("1300", pentium_m_1300),
|
323 |
ENTRY("1400", pentium_m_1400),
|
324 |
ENTRY("1500", pentium_m_1500),
|
325 |
ENTRY("1600", pentium_m_1600),
|
326 |
ENTRY("1700", pentium_m_1700),
|
327 |
#undef ENTRY
|
328 |
}; |
329 |
|
330 |
static const struct fqlist pentium_m_dothan[] = { |
331 |
#define ENTRY(s, v) { s, v, (int)(sizeof(v) / sizeof((v)[0])) } |
332 |
ENTRY("1.00", pentium_m_n723),
|
333 |
ENTRY("1.10", pentium_m_n733),
|
334 |
ENTRY("1.20", pentium_m_n753),
|
335 |
ENTRY("1.40", pentium_m_n738),
|
336 |
#if 0
|
337 |
ENTRY("1.50", pentium_m_n758),
|
338 |
#endif
|
339 |
ENTRY("1.50", pentium_m_n715),
|
340 |
ENTRY("1.60", pentium_m_n725),
|
341 |
ENTRY("1.70", pentium_m_n735),
|
342 |
ENTRY("1.80", pentium_m_n745),
|
343 |
ENTRY("2.00", pentium_m_n755),
|
344 |
ENTRY("2.10", pentium_m_n765),
|
345 |
#undef ENTRY
|
346 |
}; |
347 |
|
348 |
struct est_cpu {
|
349 |
const char *brand_prefix; |
350 |
const char *brand_suffix; |
351 |
const struct fqlist *list; |
352 |
int n;
|
353 |
}; |
354 |
|
355 |
static const struct est_cpu est_cpus[] = { |
356 |
{ |
357 |
"Intel(R) Pentium(R) M processor ", "MHz", |
358 |
pentium_m, |
359 |
(int)(sizeof(pentium_m) / sizeof(pentium_m[0])) |
360 |
}, |
361 |
{ |
362 |
"Intel(R) Pentium(R) M processor ", "GHz", |
363 |
pentium_m_dothan, |
364 |
(int)(sizeof(pentium_m_dothan) / sizeof(pentium_m_dothan[0])) |
365 |
}, |
366 |
}; |
367 |
|
368 |
#define NESTCPUS (int)(sizeof(est_cpus) / sizeof(est_cpus[0])) |
369 |
|
370 |
|
371 |
#define MSRVALUE(mhz, mv) ((((mhz) / 100) << 8) | (((mv) - 700) / 16)) |
372 |
#define MSR2MHZ(msr) (int)((((u_int) (msr) >> 8) & 0xff) * 100) |
373 |
#define MSR2MV(msr) (((int) (msr) & 0xff) * 16 + 700) |
374 |
|
375 |
static const struct fqlist *est_fqlist; |
376 |
|
377 |
static int maxfreq; /* max speed in Mhz */ |
378 |
static int maxvolts; /* max voltage in mV */ |
379 |
static int curfreq; /* current speed in Mhz */ |
380 |
static int curvolts; /* current voltage in mV */ |
381 |
#ifdef CONFIG_DVS_EMULATION
|
382 |
static int bochs; /* true if bochs is active */ |
383 |
#endif
|
384 |
|
385 |
/*
|
386 |
* Set CPU performance
|
387 |
*
|
388 |
* @level: percent of cpu speed
|
389 |
*/
|
390 |
static int |
391 |
est_setperf(int level)
|
392 |
{ |
393 |
int i;
|
394 |
int fq, max_mhz;
|
395 |
u_int msr_lo, msr_hi; |
396 |
|
397 |
max_mhz = est_fqlist->table[0].mhz;
|
398 |
fq = max_mhz * level / 100;
|
399 |
|
400 |
for (i = est_fqlist->n - 1; i > 0; i--) |
401 |
if (est_fqlist->table[i].mhz >= fq)
|
402 |
break;
|
403 |
|
404 |
if (est_fqlist->table[i].mhz == curfreq)
|
405 |
return 0; |
406 |
|
407 |
curfreq = est_fqlist->table[i].mhz; |
408 |
curvolts = est_fqlist->table[i].mv; |
409 |
#ifdef DEBUG_EST
|
410 |
DPRINTF(("setperf: %dMHz %dmV\n", curfreq, curvolts));
|
411 |
#endif
|
412 |
#ifdef CONFIG_DVS_EMULATION
|
413 |
if (bochs)
|
414 |
return 0; |
415 |
#endif
|
416 |
rdmsr(MSR_PERF_CTL, &msr_lo, &msr_hi); |
417 |
msr_lo = (msr_lo & ~0xffff) |
|
418 |
MSRVALUE(est_fqlist->table[i].mhz, est_fqlist->table[i].mv); |
419 |
wrmsr(MSR_PERF_CTL, msr_lo, msr_hi); |
420 |
return 0; |
421 |
} |
422 |
|
423 |
/*
|
424 |
* Get CPU performance
|
425 |
*/
|
426 |
static int |
427 |
est_getperf(void)
|
428 |
{ |
429 |
int max_mhz;
|
430 |
int level;
|
431 |
|
432 |
max_mhz = est_fqlist->table[0].mhz;
|
433 |
ASSERT(max_mhz); |
434 |
level = curfreq * 100 / max_mhz;
|
435 |
return level;
|
436 |
} |
437 |
|
438 |
static void |
439 |
est_getinfo(struct cpufreqinfo *info)
|
440 |
{ |
441 |
|
442 |
info->maxfreq = maxfreq; |
443 |
info->maxvolts = maxvolts; |
444 |
info->freq = curfreq; |
445 |
info->volts = curvolts; |
446 |
} |
447 |
|
448 |
static int |
449 |
est_identify(char *brand_str)
|
450 |
{ |
451 |
int i, j, mhz, mv;
|
452 |
size_t len; |
453 |
const struct est_cpu *cpu; |
454 |
u_int msr_lo, msr_hi; |
455 |
char *tag;
|
456 |
const struct fqlist *fql; |
457 |
|
458 |
DPRINTF(("CPU brand: %s\n", brand_str));
|
459 |
|
460 |
#ifdef CONFIG_DVS_EMULATION
|
461 |
if (bochs) {
|
462 |
msr_lo = 0x1031;
|
463 |
cpu = &est_cpus[0];
|
464 |
est_fqlist = &cpu->list[7];
|
465 |
} else
|
466 |
rdmsr(MSR_PERF_STATUS, &msr_lo, &msr_hi); |
467 |
#else
|
468 |
rdmsr(MSR_PERF_STATUS, &msr_lo, &msr_hi); |
469 |
#endif
|
470 |
mhz = MSR2MHZ(msr_lo); |
471 |
mv = MSR2MV(msr_lo); |
472 |
|
473 |
#ifdef CONFIG_DVS_EMULATION
|
474 |
if (!bochs) {
|
475 |
#endif
|
476 |
/*
|
477 |
* Look for a CPU matching brand_str.
|
478 |
*/
|
479 |
for (i = 0; est_fqlist == NULL && i < NESTCPUS; i++) { |
480 |
cpu = &est_cpus[i]; |
481 |
len = strnlen(cpu->brand_prefix, 48);
|
482 |
if (strncmp(cpu->brand_prefix, brand_str, len) != 0) |
483 |
continue;
|
484 |
tag = brand_str + len; |
485 |
for (j = 0; j < cpu->n; j++) { |
486 |
fql = &cpu->list[j]; |
487 |
len = strnlen(fql->brand_tag, 48);
|
488 |
if (!strncmp(fql->brand_tag, tag, len) &&
|
489 |
!strncmp(cpu->brand_suffix, tag + len, 48)) {
|
490 |
est_fqlist = fql; |
491 |
break;
|
492 |
} |
493 |
} |
494 |
} |
495 |
if (est_fqlist == NULL) { |
496 |
DPRINTF(("Unknown EST cpu, no changes possible\n"));
|
497 |
return ENXIO;
|
498 |
} |
499 |
|
500 |
/*
|
501 |
* Check that the current operating point is in our list.
|
502 |
*/
|
503 |
for (i = est_fqlist->n - 1; i >= 0; i--) |
504 |
if (est_fqlist->table[i].mhz == mhz)
|
505 |
break;
|
506 |
if (i < 0) { |
507 |
DPRINTF((" (not in table)\n"));
|
508 |
return ENXIO;
|
509 |
} |
510 |
#ifdef CONFIG_DVS_EMULATION
|
511 |
} |
512 |
#endif
|
513 |
/*
|
514 |
* Store current state
|
515 |
*/
|
516 |
maxfreq = est_fqlist->table[0].mhz;
|
517 |
maxvolts = est_fqlist->table[0].mv;
|
518 |
curfreq = mhz; |
519 |
curvolts = mv; |
520 |
return 0; |
521 |
} |
522 |
|
523 |
static int |
524 |
est_probe(struct driver *self)
|
525 |
{ |
526 |
u_int regs[4];
|
527 |
char brand_str[49]; |
528 |
char *p, *q;
|
529 |
u_int cpu_id; |
530 |
|
531 |
#ifdef CONFIG_DVS_EMULATION
|
532 |
bochs = 0;
|
533 |
if (bus_read_8(0xe9) == 0xe9) { |
534 |
/*
|
535 |
* Detect Bochs. Fake the cpuid value.
|
536 |
*/
|
537 |
bochs = 1;
|
538 |
cpu_id = 0x6d6;
|
539 |
strlcpy(brand_str, |
540 |
"Intel(R) Pentium(R) M processor 1600MHz",
|
541 |
sizeof(brand_str));
|
542 |
DPRINTF(("CPU ID: %08x\n", cpu_id));
|
543 |
return est_identify(brand_str);
|
544 |
} |
545 |
#endif
|
546 |
/*
|
547 |
* Check enhanced speed step capability
|
548 |
*/
|
549 |
cpuid(1, regs);
|
550 |
cpu_id = regs[0];
|
551 |
DPRINTF(("CPU ID: %08x\n", cpu_id));
|
552 |
if ((regs[2] & 0x80) == 0) { |
553 |
DPRINTF(("cpu: clock control not supported\n"));
|
554 |
return ENXIO;
|
555 |
} |
556 |
|
557 |
/*
|
558 |
* Get CPU brand string
|
559 |
*/
|
560 |
cpuid(0x80000002, regs);
|
561 |
memcpy(brand_str, regs, sizeof(regs));
|
562 |
cpuid(0x80000003, regs);
|
563 |
memcpy(brand_str + 16, regs, sizeof(regs)); |
564 |
cpuid(0x80000004, regs);
|
565 |
memcpy(brand_str + 32, regs, sizeof(regs)); |
566 |
|
567 |
/* Store string with lef-align */
|
568 |
p = q = brand_str; |
569 |
while (*p == ' ') |
570 |
p++; |
571 |
while (*p)
|
572 |
*q++ = *p++; |
573 |
*q = '\0';
|
574 |
|
575 |
return est_identify(brand_str);
|
576 |
} |
577 |
|
578 |
static int |
579 |
est_init(struct driver *self)
|
580 |
{ |
581 |
#ifdef DEBUG
|
582 |
int i;
|
583 |
#endif
|
584 |
|
585 |
cpufreq_attach(&est_ops); |
586 |
|
587 |
#ifdef DEBUG
|
588 |
printf("Enhanced SpeedStep %d MHz (%d mV)\n", curfreq, curvolts);
|
589 |
printf("Speeds: ");
|
590 |
for (i = 0; i < est_fqlist->n; i++) |
591 |
printf("%d%s", est_fqlist->table[i].mhz,
|
592 |
i < est_fqlist->n - 1 ? ", " : " MHz\n"); |
593 |
#endif
|
594 |
return 0; |
595 |
} |