2 * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
4 * Licensed under the terms of the GNU GPL License version 2.
6 * Library for common functions for Intel SpeedStep v.1 and v.2 support
8 * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/cpufreq.h>
15 #include <linux/pci.h>
16 #include <linux/slab.h>
19 #include "speedstep-lib.h"
23 * Define it if you want verbose debug output, e.g. for bug reporting
25 //#define SPEEDSTEP_DEBUG
27 #ifdef SPEEDSTEP_DEBUG
28 #define dprintk(msg...) printk(msg)
30 #define dprintk(msg...) do { } while(0)
33 /*********************************************************************
34 * GET PROCESSOR CORE SPEED IN KHZ *
35 *********************************************************************/
37 static unsigned int pentium3_get_frequency (unsigned int processor)
39 /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
41 unsigned int ratio; /* Frequency Multiplier (x10) */
42 u8 bitmap; /* power on configuration bits
43 [27, 25:22] (in MSR 0x2a) */
44 } msr_decode_mult [] = {
59 { 0, 0xff } /* error or unknown value */
62 /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */
64 unsigned int value; /* Front Side Bus speed in MHz */
65 u8 bitmap; /* power on configuration bits [18: 19]
67 } msr_decode_fsb [] = {
77 /* read MSR 0x2a - we only need the low 32 bits */
78 rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
79 dprintk(KERN_DEBUG "speedstep-lib: P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
85 while (msr_tmp != msr_decode_fsb[i].bitmap) {
86 if (msr_decode_fsb[i].bitmap == 0xff)
91 /* decode the multiplier */
92 if (processor == SPEEDSTEP_PROCESSOR_PIII_C_EARLY)
97 while (msr_lo != msr_decode_mult[j].bitmap) {
98 if (msr_decode_mult[j].bitmap == 0xff)
103 return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100);
107 static unsigned int pentium4_get_frequency(void)
109 struct cpuinfo_x86 *c = &boot_cpu_data;
110 u32 msr_lo, msr_hi, mult;
111 unsigned int fsb = 0;
113 rdmsr(0x2c, msr_lo, msr_hi);
115 dprintk(KERN_DEBUG "speedstep-lib: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
117 /* decode the FSB: see IA-32 Intel (C) Architecture Software
118 * Developer's Manual, Volume 3: System Prgramming Guide,
119 * revision #12 in Table B-1: MSRs in the Pentium 4 and
120 * Intel Xeon Processors, on page B-4 and B-5.
122 if (c->x86_model < 2)
125 u8 fsb_code = (msr_lo >> 16) & 0x7;
140 printk(KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <linux@brodo.de>\n");
145 dprintk(KERN_DEBUG "speedstep-lib: P4 - FSB %u kHz; Multiplier %u\n", fsb, mult);
151 unsigned int speedstep_get_processor_frequency(unsigned int processor)
154 case SPEEDSTEP_PROCESSOR_P4M:
155 return pentium4_get_frequency();
156 case SPEEDSTEP_PROCESSOR_PIII_T:
157 case SPEEDSTEP_PROCESSOR_PIII_C:
158 case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
159 return pentium3_get_frequency(processor);
165 EXPORT_SYMBOL_GPL(speedstep_get_processor_frequency);
168 /*********************************************************************
169 * DETECT SPEEDSTEP-CAPABLE PROCESSOR *
170 *********************************************************************/
172 unsigned int speedstep_detect_processor (void)
174 struct cpuinfo_x86 *c = cpu_data;
175 u32 ebx, msr_lo, msr_hi;
177 if ((c->x86_vendor != X86_VENDOR_INTEL) ||
178 ((c->x86 != 6) && (c->x86 != 0xF)))
182 /* Intel Mobile Pentium 4-M
183 * or Intel Mobile Pentium 4 with 533 MHz FSB */
184 if (c->x86_model != 2)
187 if ((c->x86_mask != 4) && /* B-stepping [M-P4-M] */
188 (c->x86_mask != 7) && /* C-stepping [M-P4-M] */
189 (c->x86_mask != 9)) /* D-stepping [M-P4-M or M-P4/533] */
192 ebx = cpuid_ebx(0x00000001);
194 if ((ebx != 0x0e) && (ebx != 0x0f))
197 return SPEEDSTEP_PROCESSOR_P4M;
200 switch (c->x86_model) {
201 case 0x0B: /* Intel PIII [Tualatin] */
202 /* cpuid_ebx(1) is 0x04 for desktop PIII,
203 0x06 for mobile PIII-M */
204 ebx = cpuid_ebx(0x00000001);
210 /* So far all PIII-M processors support SpeedStep. See
211 * Intel's 24540640.pdf of June 2003
214 return SPEEDSTEP_PROCESSOR_PIII_T;
216 case 0x08: /* Intel PIII [Coppermine] */
218 /* all mobile PIII Coppermines have FSB 100 MHz
219 * ==> sort out a few desktop PIIIs. */
220 rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
221 dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi);
223 if (msr_lo != 0x0080000)
227 * If the processor is a mobile version,
228 * platform ID has bit 50 set
229 * it has SpeedStep technology if either
230 * bit 56 or 57 is set
232 rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
233 dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
234 if ((msr_hi & (1<<18)) && (msr_hi & (3<<24))) {
235 if (c->x86_mask == 0x01)
236 return SPEEDSTEP_PROCESSOR_PIII_C_EARLY;
238 return SPEEDSTEP_PROCESSOR_PIII_C;
245 EXPORT_SYMBOL_GPL(speedstep_detect_processor);
248 /*********************************************************************
249 * DETECT SPEEDSTEP SPEEDS *
250 *********************************************************************/
252 unsigned int speedstep_get_freqs(unsigned int processor,
253 unsigned int *low_speed,
254 unsigned int *high_speed,
255 void (*set_state) (unsigned int state,
259 unsigned int prev_speed;
260 unsigned int ret = 0;
263 if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
266 /* get current speed */
267 prev_speed = speedstep_get_processor_frequency(processor);
271 local_irq_save(flags);
273 /* switch to low state */
274 set_state(SPEEDSTEP_LOW, 0);
275 *low_speed = speedstep_get_processor_frequency(processor);
281 /* switch to high state */
282 set_state(SPEEDSTEP_HIGH, 0);
283 *high_speed = speedstep_get_processor_frequency(processor);
289 if (*low_speed == *high_speed) {
294 /* switch to previous state, if necessary */
295 if (*high_speed != prev_speed)
296 set_state(SPEEDSTEP_LOW, 0);
299 local_irq_restore(flags);
302 EXPORT_SYMBOL_GPL(speedstep_get_freqs);
304 MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
305 MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
306 MODULE_LICENSE ("GPL");