2005-04-17 02:20:36 +04:00
/*
2008-08-07 00:41:06 +04:00
* hwmon - vid . c - VID / VRM / VRD voltage conversions
*
* Copyright ( c ) 2004 Rudolf Marek < r . marek @ assembler . cz >
*
* Partly imported from i2c - vid . h of the lm_sensors project
* Copyright ( c ) 2002 Mark D . Studebaker < mdsxyz123 @ yahoo . com >
* With assistance from Trent Piepho < xyzzy @ speakeasy . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/kernel.h>
2005-07-31 23:52:01 +04:00
# include <linux/hwmon-vid.h>
2005-04-17 02:20:36 +04:00
2005-08-02 00:50:08 +04:00
/*
2008-08-07 00:41:06 +04:00
* Common code for decoding VID pins .
*
* References :
*
* For VRM 8.4 to 9.1 , " VRM x.y DC-DC Converter Design Guidelines " ,
* available at http : //developer.intel.com/.
*
* For VRD 10.0 and up , " VRD x.y Design Guide " ,
* available at http : //developer.intel.com/.
*
2008-08-15 12:58:05 +04:00
* AMD Athlon 64 and AMD Opteron Processors , AMD Publication 26094 ,
* http : //www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF
* Table 74. VID Code Voltages
* This corresponds to an arbitrary VRM code of 24 in the functions below .
* These CPU models ( K8 revision < = E ) have 5 VID pins . See also :
* Revision Guide for AMD Athlon 64 and AMD Opteron Processors , AMD Publication 25759 ,
* http : //www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25759.pdf
*
* AMD NPT Family 0F h Processors , AMD Publication 32559 ,
2008-08-07 00:41:06 +04:00
* http : //www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
* Table 71. VID Code Voltages
2008-08-15 12:58:05 +04:00
* This corresponds to an arbitrary VRM code of 25 in the functions below .
* These CPU models ( K8 revision > = F ) have 6 VID pins . See also :
* Revision Guide for AMD NPT Family 0F h Processors , AMD Publication 33610 ,
* http : //www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/33610.pdf
2008-08-07 00:41:06 +04:00
*
* The 17 specification is in fact Intel Mobile Voltage Positioning -
* ( IMVP - II ) . You can find more information in the datasheet of Max1718
* http : //www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
*
* The 13 specification corresponds to the Intel Pentium M series . There
* doesn ' t seem to be any named specification for these . The conversion
* tables are detailed directly in the various Pentium M datasheets :
* http : //www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
*
* The 14 specification corresponds to Intel Core series . There
* doesn ' t seem to be any named specification for these . The conversion
* tables are detailed directly in the various Pentium Core datasheets :
* http : //www.intel.com/design/mobile/datashts/309221.htm
*
* The 110 ( VRM 11 ) specification corresponds to Intel Conroe based series .
* http : //www.intel.com/design/processor/applnots/313214.htm
*/
/*
* vrm is the VRM / VRD document version multiplied by 10.
* val is the 4 - bit or more VID code .
* Returned value is in mV to avoid floating point in the kernel .
* Some VID have some bits in uV scale , this is rounded to mV .
*/
2005-12-18 18:36:52 +03:00
int vid_from_reg ( int val , u8 vrm )
2005-08-02 00:50:08 +04:00
{
int vid ;
switch ( vrm ) {
case 100 : /* VRD 10.0 */
2006-06-13 00:00:53 +04:00
/* compute in uV, round to mV */
2006-04-25 16:24:46 +04:00
val & = 0x3f ;
2005-08-02 00:50:08 +04:00
if ( ( val & 0x1f ) = = 0x1f )
return 0 ;
if ( ( val & 0x1f ) < = 0x09 | | val = = 0x0a )
2006-06-13 00:00:53 +04:00
vid = 1087500 - ( val & 0x1f ) * 25000 ;
2005-08-02 00:50:08 +04:00
else
2006-06-13 00:00:53 +04:00
vid = 1862500 - ( val & 0x1f ) * 25000 ;
2005-08-02 00:50:08 +04:00
if ( val & 0x20 )
2006-06-13 00:00:53 +04:00
vid - = 12500 ;
return ( ( vid + 500 ) / 1000 ) ;
2005-08-02 00:50:08 +04:00
2006-06-13 00:00:53 +04:00
case 110 : /* Intel Conroe */
/* compute in uV, round to mV */
val & = 0xff ;
2007-01-19 00:14:23 +03:00
if ( val < 0x02 | | val > 0xb2 )
2006-06-13 00:00:53 +04:00
return 0 ;
return ( ( 1600000 - ( val - 2 ) * 6250 + 500 ) / 1000 ) ;
2008-08-07 00:41:06 +04:00
2008-08-15 12:58:05 +04:00
case 24 : /* Athlon64 & Opteron */
val & = 0x1f ;
if ( val = = 0x1f )
return 0 ;
/* fall through */
case 25 : /* AMD NPT 0Fh */
2008-08-07 00:41:06 +04:00
val & = 0x3f ;
return ( val < 32 ) ? 1550 - 25 * val
: 775 - ( 25 * ( val - 31 ) ) / 2 ;
2005-08-02 00:50:08 +04:00
case 91 : /* VRM 9.1 */
case 90 : /* VRM 9.0 */
2006-04-25 16:24:46 +04:00
val & = 0x1f ;
2005-08-02 00:50:08 +04:00
return ( val = = 0x1f ? 0 :
1850 - val * 25 ) ;
case 85 : /* VRM 8.5 */
2006-04-25 16:24:46 +04:00
val & = 0x1f ;
2005-08-02 00:50:08 +04:00
return ( ( val & 0x10 ? 25 : 0 ) +
( ( val & 0x0f ) > 0x04 ? 2050 : 1250 ) -
( ( val & 0x0f ) * 50 ) ) ;
case 84 : /* VRM 8.4 */
val & = 0x0f ;
/* fall through */
2005-12-18 18:36:52 +03:00
case 82 : /* VRM 8.2 */
2006-04-25 16:24:46 +04:00
val & = 0x1f ;
2005-08-02 00:50:08 +04:00
return ( val = = 0x1f ? 0 :
val & 0x10 ? 5100 - ( val ) * 100 :
2050 - ( val ) * 50 ) ;
2005-12-18 18:36:52 +03:00
case 17 : /* Intel IMVP-II */
2006-04-25 16:24:46 +04:00
val & = 0x1f ;
2005-12-18 18:36:52 +03:00
return ( val & 0x10 ? 975 - ( val & 0xF ) * 25 :
1750 - val * 50 ) ;
2006-02-06 01:21:05 +03:00
case 13 :
2006-04-25 16:24:46 +04:00
val & = 0x3f ;
return ( 1708 - val * 16 ) ;
2006-06-13 00:00:53 +04:00
case 14 : /* Intel Core */
/* compute in uV, round to mV */
val & = 0x7f ;
return ( val > 0x77 ? 0 : ( 1500000 - ( val * 12500 ) + 500 ) / 1000 ) ;
2005-12-18 18:36:52 +03:00
default : /* report 0 for unknown */
2007-05-28 00:17:43 +04:00
if ( vrm )
printk ( KERN_WARNING " hwmon-vid: Requested unsupported "
" VRM version (%u) \n " , ( unsigned int ) vrm ) ;
2005-12-18 18:36:52 +03:00
return 0 ;
2005-08-02 00:50:08 +04:00
}
}
/*
2008-08-07 00:41:06 +04:00
* After this point is the code to automatically determine which
* VRM / VRD specification should be used depending on the CPU .
*/
2005-08-02 00:50:08 +04:00
2005-04-17 02:20:36 +04:00
struct vrm_model {
u8 vendor ;
u8 eff_family ;
u8 eff_model ;
2005-12-18 18:36:52 +03:00
u8 eff_stepping ;
u8 vrm_type ;
2005-04-17 02:20:36 +04:00
} ;
# define ANY 0xFF
# ifdef CONFIG_X86
2008-08-15 12:58:05 +04:00
/*
* The stepping parameter is highest acceptable stepping for current line .
* The model match must be exact for 4 - bit values . For model values 0x10
* and above ( extended model ) , all models below the parameter will match .
*/
2005-12-18 18:36:52 +03:00
2005-04-17 02:20:36 +04:00
static struct vrm_model vrm_models [ ] = {
2005-12-18 18:36:52 +03:00
{ X86_VENDOR_AMD , 0x6 , ANY , ANY , 90 } , /* Athlon Duron etc */
2008-08-15 12:58:05 +04:00
{ X86_VENDOR_AMD , 0xF , 0x3F , ANY , 24 } , /* Athlon 64, Opteron */
{ X86_VENDOR_AMD , 0xF , ANY , ANY , 25 } , /* NPT family 0Fh */
2008-10-26 19:04:39 +03:00
{ X86_VENDOR_AMD , 0x10 , ANY , ANY , 25 } , /* NPT family 10h */
2006-02-06 01:21:05 +03:00
{ X86_VENDOR_INTEL , 0x6 , 0x9 , ANY , 13 } , /* Pentium M (130 nm) */
2005-12-18 18:36:52 +03:00
{ X86_VENDOR_INTEL , 0x6 , 0xB , ANY , 85 } , /* Tualatin */
2006-02-06 01:21:05 +03:00
{ X86_VENDOR_INTEL , 0x6 , 0xD , ANY , 13 } , /* Pentium M (90 nm) */
2006-06-13 00:00:53 +04:00
{ X86_VENDOR_INTEL , 0x6 , 0xE , ANY , 14 } , /* Intel Core (65 nm) */
{ X86_VENDOR_INTEL , 0x6 , 0xF , ANY , 110 } , /* Intel Conroe */
2005-12-18 18:36:52 +03:00
{ X86_VENDOR_INTEL , 0x6 , ANY , ANY , 82 } , /* any P6 */
{ X86_VENDOR_INTEL , 0xF , 0x0 , ANY , 90 } , /* P4 */
{ X86_VENDOR_INTEL , 0xF , 0x1 , ANY , 90 } , /* P4 Willamette */
{ X86_VENDOR_INTEL , 0xF , 0x2 , ANY , 90 } , /* P4 Northwood */
{ X86_VENDOR_INTEL , 0xF , ANY , ANY , 100 } , /* Prescott and above assume VRD 10 */
{ X86_VENDOR_CENTAUR , 0x6 , 0x7 , ANY , 85 } , /* Eden ESP/Ezra */
{ X86_VENDOR_CENTAUR , 0x6 , 0x8 , 0x7 , 85 } , /* Ezra T */
{ X86_VENDOR_CENTAUR , 0x6 , 0x9 , 0x7 , 85 } , /* Nemiah */
2007-05-08 19:21:59 +04:00
{ X86_VENDOR_CENTAUR , 0x6 , 0x9 , ANY , 17 } , /* C3-M, Eden-N */
{ X86_VENDOR_CENTAUR , 0x6 , 0xA , 0x7 , 0 } , /* No information */
{ X86_VENDOR_CENTAUR , 0x6 , 0xA , ANY , 13 } , /* C7, Esther */
2005-12-18 18:36:52 +03:00
{ X86_VENDOR_UNKNOWN , ANY , ANY , ANY , 0 } /* stop here */
2005-07-31 23:54:28 +04:00
} ;
2005-04-17 02:20:36 +04:00
2005-12-18 18:36:52 +03:00
static u8 find_vrm ( u8 eff_family , u8 eff_model , u8 eff_stepping , u8 vendor )
2005-04-17 02:20:36 +04:00
{
int i = 0 ;
while ( vrm_models [ i ] . vendor ! = X86_VENDOR_UNKNOWN ) {
if ( vrm_models [ i ] . vendor = = vendor )
2005-07-31 23:54:28 +04:00
if ( ( vrm_models [ i ] . eff_family = = eff_family )
& & ( ( vrm_models [ i ] . eff_model = = eff_model ) | |
2008-08-15 12:58:05 +04:00
( vrm_models [ i ] . eff_model > = 0x10 & &
eff_model < = vrm_models [ i ] . eff_model ) | |
2005-12-18 18:36:52 +03:00
( vrm_models [ i ] . eff_model = = ANY ) ) & &
( eff_stepping < = vrm_models [ i ] . eff_stepping ) )
2005-04-17 02:20:36 +04:00
return vrm_models [ i ] . vrm_type ;
i + + ;
}
return 0 ;
}
2005-12-18 18:36:52 +03:00
u8 vid_which_vrm ( void )
2005-04-17 02:20:36 +04:00
{
2007-10-19 22:35:04 +04:00
struct cpuinfo_x86 * c = & cpu_data ( 0 ) ;
2005-04-17 02:20:36 +04:00
u32 eax ;
2005-12-18 18:36:52 +03:00
u8 eff_family , eff_model , eff_stepping , vrm_ret ;
2005-04-17 02:20:36 +04:00
2005-07-31 23:54:28 +04:00
if ( c - > x86 < 6 ) /* Any CPU with family lower than 6 */
return 0 ; /* doesn't have VID and/or CPUID */
2005-04-17 02:20:36 +04:00
eax = cpuid_eax ( 1 ) ;
eff_family = ( ( eax & 0x00000F00 ) > > 8 ) ;
eff_model = ( ( eax & 0x000000F0 ) > > 4 ) ;
2005-12-18 18:36:52 +03:00
eff_stepping = eax & 0xF ;
2005-04-17 02:20:36 +04:00
if ( eff_family = = 0xF ) { /* use extended model & family */
eff_family + = ( ( eax & 0x00F00000 ) > > 20 ) ;
eff_model + = ( ( eax & 0x000F0000 ) > > 16 ) < < 4 ;
}
2005-12-18 18:36:52 +03:00
vrm_ret = find_vrm ( eff_family , eff_model , eff_stepping , c - > x86_vendor ) ;
2005-04-17 02:20:36 +04:00
if ( vrm_ret = = 0 )
2005-07-31 23:54:28 +04:00
printk ( KERN_INFO " hwmon-vid: Unknown VRM version of your "
" x86 CPU \n " ) ;
2005-04-17 02:20:36 +04:00
return vrm_ret ;
}
2005-12-18 18:36:52 +03:00
/* and now for something completely different for the non-x86 world */
2005-04-17 02:20:36 +04:00
# else
2005-12-18 18:36:52 +03:00
u8 vid_which_vrm ( void )
2005-04-17 02:20:36 +04:00
{
2005-07-31 23:52:01 +04:00
printk ( KERN_INFO " hwmon-vid: Unknown VRM version of your CPU \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# endif
2005-08-02 00:50:08 +04:00
EXPORT_SYMBOL ( vid_from_reg ) ;
2005-07-31 23:52:01 +04:00
EXPORT_SYMBOL ( vid_which_vrm ) ;
2005-07-31 23:45:27 +04:00
2006-12-12 20:18:30 +03:00
MODULE_AUTHOR ( " Rudolf Marek <r.marek@assembler.cz> " ) ;
2005-07-31 23:45:27 +04:00
2005-07-31 23:52:01 +04:00
MODULE_DESCRIPTION ( " hwmon-vid driver " ) ;
2005-07-31 23:45:27 +04:00
MODULE_LICENSE ( " GPL " ) ;