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)
111 rdmsr(0x2c, msr_lo
, msr_hi
);
113 dprintk(KERN_DEBUG
"speedstep-lib: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo
, msr_hi
);
116 return (msr_lo
* 100000);
120 unsigned int speedstep_get_processor_frequency(unsigned int processor
)
123 case SPEEDSTEP_PROCESSOR_P4M
:
124 return pentium4_get_frequency();
125 case SPEEDSTEP_PROCESSOR_PIII_T
:
126 case SPEEDSTEP_PROCESSOR_PIII_C
:
127 case SPEEDSTEP_PROCESSOR_PIII_C_EARLY
:
128 return pentium3_get_frequency(processor
);
134 EXPORT_SYMBOL_GPL(speedstep_get_processor_frequency
);
137 /*********************************************************************
138 * DETECT SPEEDSTEP-CAPABLE PROCESSOR *
139 *********************************************************************/
141 unsigned int speedstep_detect_processor (void)
143 struct cpuinfo_x86
*c
= cpu_data
;
144 u32 ebx
, msr_lo
, msr_hi
;
146 if ((c
->x86_vendor
!= X86_VENDOR_INTEL
) ||
147 ((c
->x86
!= 6) && (c
->x86
!= 0xF)))
151 /* Intel Mobile Pentium 4-M
152 * or Intel Mobile Pentium 4 with 533 MHz FSB */
153 if (c
->x86_model
!= 2)
156 if ((c
->x86_mask
!= 4) && /* B-stepping [M-P4-M] */
157 (c
->x86_mask
!= 7) && /* C-stepping [M-P4-M] */
158 (c
->x86_mask
!= 9)) /* D-stepping [M-P4-M or M-P4/533] */
161 ebx
= cpuid_ebx(0x00000001);
163 if ((ebx
!= 0x0e) && (ebx
!= 0x0f))
166 return SPEEDSTEP_PROCESSOR_P4M
;
169 switch (c
->x86_model
) {
170 case 0x0B: /* Intel PIII [Tualatin] */
171 /* cpuid_ebx(1) is 0x04 for desktop PIII,
172 0x06 for mobile PIII-M */
173 ebx
= cpuid_ebx(0x00000001);
179 /* So far all PIII-M processors support SpeedStep. See
180 * Intel's 24540640.pdf of June 2003
183 return SPEEDSTEP_PROCESSOR_PIII_T
;
185 case 0x08: /* Intel PIII [Coppermine] */
187 /* all mobile PIII Coppermines have FSB 100 MHz
188 * ==> sort out a few desktop PIIIs. */
189 rdmsr(MSR_IA32_EBL_CR_POWERON
, msr_lo
, msr_hi
);
190 dprintk(KERN_DEBUG
"cpufreq: Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo
, msr_hi
);
192 if (msr_lo
!= 0x0080000)
196 * If the processor is a mobile version,
197 * platform ID has bit 50 set
198 * it has SpeedStep technology if either
199 * bit 56 or 57 is set
201 rdmsr(MSR_IA32_PLATFORM_ID
, msr_lo
, msr_hi
);
202 dprintk(KERN_DEBUG
"cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo
, msr_hi
);
203 if ((msr_hi
& (1<<18)) && (msr_hi
& (3<<24))) {
204 if (c
->x86_mask
== 0x01)
205 return SPEEDSTEP_PROCESSOR_PIII_C_EARLY
;
207 return SPEEDSTEP_PROCESSOR_PIII_C
;
214 EXPORT_SYMBOL_GPL(speedstep_detect_processor
);
217 /*********************************************************************
218 * DETECT SPEEDSTEP SPEEDS *
219 *********************************************************************/
221 unsigned int speedstep_get_freqs(unsigned int processor
,
222 unsigned int *low_speed
,
223 unsigned int *high_speed
,
224 void (*set_state
) (unsigned int state
,
228 unsigned int prev_speed
;
229 unsigned int ret
= 0;
232 if ((!processor
) || (!low_speed
) || (!high_speed
) || (!set_state
))
235 /* get current speed */
236 prev_speed
= speedstep_get_processor_frequency(processor
);
240 local_irq_save(flags
);
242 /* switch to low state */
243 set_state(SPEEDSTEP_LOW
, 0);
244 *low_speed
= speedstep_get_processor_frequency(processor
);
250 /* switch to high state */
251 set_state(SPEEDSTEP_HIGH
, 0);
252 *high_speed
= speedstep_get_processor_frequency(processor
);
258 if (*low_speed
== *high_speed
) {
263 /* switch to previous state, if necessary */
264 if (*high_speed
!= prev_speed
)
265 set_state(SPEEDSTEP_LOW
, 0);
268 local_irq_restore(flags
);
271 EXPORT_SYMBOL_GPL(speedstep_get_freqs
);
273 MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
274 MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
275 MODULE_LICENSE ("GPL");