Hardware/LPC/NCT677X.cs
author moel.mich
Wed, 27 Jul 2011 18:27:16 +0000
changeset 317 1ccf99e620a9
parent 265 961c07a3bd78
child 323 3f2d9ebacf38
permissions -rw-r--r--
Added support for Intel CPU power sensors (package and cores).
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2010-2011
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System.Globalization;
    39 using System.Text;
    40 
    41 namespace OpenHardwareMonitor.Hardware.LPC {
    42   internal class NCT677X : ISuperIO {
    43 
    44     private readonly ushort port;
    45     private readonly byte revision;
    46 
    47     private readonly Chip chip;
    48 
    49     private readonly float?[] voltages = new float?[9];
    50     private readonly float?[] temperatures = new float?[4];
    51     private readonly float?[] fans = new float?[0];
    52 
    53     // Hardware Monitor
    54     private const uint ADDRESS_REGISTER_OFFSET = 0x05;
    55     private const uint DATA_REGISTER_OFFSET = 0x06;
    56     private const byte BANK_SELECT_REGISTER = 0x4E;
    57 
    58     private byte ReadByte(ushort address) {
    59       byte bank = (byte)(address >> 8);
    60       byte register = (byte)(address & 0xFF);
    61       Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER);
    62       Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank);
    63       Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register);
    64       return Ring0.ReadIoPort(port + DATA_REGISTER_OFFSET);
    65     } 
    66 
    67     // Consts 
    68     private const ushort NUVOTON_VENDOR_ID = 0x5CA3;
    69 
    70     // Hardware Monitor Registers    
    71     private const ushort VENDOR_ID_HIGH_REGISTER = 0x804F;
    72     private const ushort VENDOR_ID_LOW_REGISTER = 0x004F;
    73     private const ushort VOLTAGE_VBAT_REG = 0x0551;
    74 
    75     private readonly ushort[] TEMPERATURE_REG = 
    76       { 0x027, 0x73, 0x75, 0x77, 0x150, 0x250, 0x62B, 0x62C, 0x62D };
    77     private readonly ushort[] TEMPERATURE_HALF_REG = 
    78       { 0, 0x74, 0x76, 0x78, 0x151, 0x251, 0x62E, 0x62E, 0x62E };    
    79     private readonly ushort[] TEMPERATURE_SRC_REG = 
    80       { 0x621, 0x100, 0x200, 0x300, 0x622, 0x623, 0x624, 0x625, 0x626 };
    81     private readonly int[] TEMPERATURE_HALF_BIT =
    82       { -1, 7, 7, 7, 7, 7, 0, 1, 2 };
    83     private readonly ushort[] VOLTAGE_REG = 
    84       { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551 };
    85     private readonly ushort[] FAN_RPM_REG = 
    86       { 0x656, 0x658, 0x65A, 0x65C, 0x65E};
    87 
    88     private readonly int minFanRPM;
    89 
    90     private enum SourceNCT6771F : byte {
    91       SYSTIN = 1,
    92       CPUTIN = 2,
    93       AUXTIN = 3,
    94       SMBUSMASTER = 4,
    95       PECI_0 = 5, 
    96       PECI_1 = 6, 
    97       PECI_2 = 7,
    98       PECI_3 = 8,
    99       PECI_4 = 9,
   100       PECI_5 = 10,
   101       PECI_6 = 11,
   102       PECI_7 = 12,
   103       PCH_CHIP_CPU_MAX_TEMP = 13,
   104       PCH_CHIP_TEMP = 14,
   105       PCH_CPU_TEMP = 15,
   106       PCH_MCH_TEMP = 16, 
   107       PCH_DIM0_TEMP = 17,
   108       PCH_DIM1_TEMP = 18,
   109       PCH_DIM2_TEMP = 19,
   110       PCH_DIM3_TEMP = 20
   111     }
   112 
   113     private enum SourceNCT6776F : byte {
   114       SYSTIN = 1,
   115       CPUTIN = 2,
   116       AUXTIN = 3,
   117       SMBUSMASTER_0 = 4,
   118       SMBUSMASTER_1 = 5,
   119       SMBUSMASTER_2 = 6,
   120       SMBUSMASTER_3 = 7,
   121       SMBUSMASTER_4 = 8,
   122       SMBUSMASTER_5 = 9,
   123       SMBUSMASTER_6 = 10,
   124       SMBUSMASTER_7 = 11,
   125       PECI_0 = 12,
   126       PECI_1 = 13,
   127       PCH_CHIP_CPU_MAX_TEMP = 14,
   128       PCH_CHIP_TEMP = 15,
   129       PCH_CPU_TEMP = 16,
   130       PCH_MCH_TEMP = 17,
   131       PCH_DIM0_TEMP = 18,
   132       PCH_DIM1_TEMP = 19,
   133       PCH_DIM2_TEMP = 20,
   134       PCH_DIM3_TEMP = 21,
   135       BYTE_TEMP = 22
   136     }
   137 
   138     public NCT677X(Chip chip, byte revision, ushort port) {
   139       this.chip = chip;
   140       this.revision = revision;
   141       this.port = port;
   142 
   143       if (!IsNuvotonVendor())
   144         return;
   145 
   146       switch (chip) {
   147         case LPC.Chip.NCT6771F:
   148           fans = new float?[4];
   149           // min value RPM value with 16-bit fan counter
   150           minFanRPM = (int)(1.35e6 / 0xFFFF);
   151           break;
   152         case LPC.Chip.NCT6776F:
   153           fans = new float?[5];
   154           // min value RPM value with 13-bit fan counter
   155           minFanRPM = (int)(1.35e6 / 0x1FFF);
   156           break;        
   157       }
   158     }
   159 
   160     private bool IsNuvotonVendor() {
   161       return ((ReadByte(VENDOR_ID_HIGH_REGISTER) << 8) |
   162         ReadByte(VENDOR_ID_LOW_REGISTER)) == NUVOTON_VENDOR_ID;
   163     }
   164 
   165     public byte? ReadGPIO(int index) {
   166       return null;
   167     }
   168 
   169     public void WriteGPIO(int index, byte value) { }
   170 
   171     public Chip Chip { get { return chip; } }
   172     public float?[] Voltages { get { return voltages; } }
   173     public float?[] Temperatures { get { return temperatures; } }
   174     public float?[] Fans { get { return fans; } }
   175 
   176     public void Update() {
   177       if (!Ring0.WaitIsaBusMutex(10))
   178         return;
   179 
   180       for (int i = 0; i < voltages.Length; i++) {
   181         float value = 0.008f * ReadByte(VOLTAGE_REG[i]);
   182         bool valid = value > 0;
   183 
   184         // check if battery voltage monitor is enabled
   185         if (valid && VOLTAGE_REG[i] == VOLTAGE_VBAT_REG) 
   186           valid = (ReadByte(0x005D) & 0x01) > 0;
   187 
   188         voltages[i] = valid ? value : (float?)null;
   189       }
   190 
   191       for (int i = TEMPERATURE_REG.Length - 1; i >= 0 ; i--) {
   192         int value = ((sbyte)ReadByte(TEMPERATURE_REG[i])) << 1;
   193         if (TEMPERATURE_HALF_BIT[i] > 0) {
   194           value |= ((ReadByte(TEMPERATURE_HALF_REG[i]) >>
   195             TEMPERATURE_HALF_BIT[i]) & 0x1);
   196         }
   197 
   198         byte source = ReadByte(TEMPERATURE_SRC_REG[i]);
   199 
   200         float? temperature = 0.5f * value;
   201         if (temperature > 125 || temperature < -55)
   202           temperature = null;
   203 
   204         switch (chip) {
   205           case Chip.NCT6771F:
   206             switch ((SourceNCT6771F)source) {
   207               case SourceNCT6771F.PECI_0: temperatures[0] = temperature; break;
   208               case SourceNCT6771F.CPUTIN: temperatures[1] = temperature; break;
   209               case SourceNCT6771F.AUXTIN: temperatures[2] = temperature; break;
   210               case SourceNCT6771F.SYSTIN: temperatures[3] = temperature; break;
   211               
   212             } break;
   213           case Chip.NCT6776F:
   214             switch ((SourceNCT6776F)source) {
   215               case SourceNCT6776F.PECI_0: temperatures[0] = temperature; break;
   216               case SourceNCT6776F.CPUTIN: temperatures[1] = temperature; break;
   217               case SourceNCT6776F.AUXTIN: temperatures[2] = temperature; break;
   218               case SourceNCT6776F.SYSTIN: temperatures[3] = temperature; break;              
   219             } break;
   220         }  
   221       }
   222 
   223       for (int i = 0; i < fans.Length; i++) {
   224         byte high = ReadByte(FAN_RPM_REG[i]);
   225         byte low = ReadByte((ushort)(FAN_RPM_REG[i] + 1));
   226         int value = (high << 8) | low;
   227 
   228         fans[i] = value > minFanRPM ? value : 0;
   229       }
   230 
   231       Ring0.ReleaseIsaBusMutex();
   232     }
   233 
   234     public string GetReport() {
   235       StringBuilder r = new StringBuilder();
   236 
   237       r.AppendLine("LPC " + this.GetType().Name);
   238       r.AppendLine();
   239       r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
   240       r.Append("Chip revision: 0x");
   241       r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
   242       r.Append("Base Adress: 0x");
   243       r.AppendLine(port.ToString("X4", CultureInfo.InvariantCulture));
   244       r.AppendLine();
   245 
   246       if (!Ring0.WaitIsaBusMutex(100))
   247         return r.ToString();
   248 
   249       ushort[] addresses = new ushort[] { 
   250         0x000, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070,
   251         0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 
   252         0x200,        0x220, 0x230, 0x240, 0x250,
   253         0x300,        0x320, 0x330, 0x340, 
   254         0x400, 0x410, 0x420,        0x440, 0x450, 0x460, 
   255         0x500,                             0x550, 
   256         0x600, 0x610 ,0x620, 0x630, 0x640, 0x650, 0x660, 0x670, 
   257         0xA00, 0xA10, 0xA20, 0xA30,        0xA50, 0xA60, 0xA70, 
   258         0xB00, 0xB10, 0xB20, 0xB30,        0xB50, 0xB60, 0xB70, 
   259         0xC00, 0xC10, 0xC20, 0xC30,        0xC50, 0xC60, 0xC70,
   260         0xD00, 0xD10, 0xD20, 0xD30,        0xD50, 0xD60, 
   261         0xE00, 0xE10, 0xE20, 0xE30, 
   262         0xF00, 0xF10, 0xF20, 0xF30};
   263 
   264       r.AppendLine("Hardware Monitor Registers");
   265       r.AppendLine();
   266       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   267       r.AppendLine();
   268       foreach (ushort address in addresses) {
   269           r.Append(" ");
   270           r.Append(address.ToString("X3", CultureInfo.InvariantCulture));
   271           r.Append("  ");
   272           for (ushort j = 0; j <= 0xF; j++) {
   273             r.Append(" ");
   274             r.Append(ReadByte((ushort)(address | j)).ToString(
   275               "X2", CultureInfo.InvariantCulture));
   276           }
   277           r.AppendLine();
   278       }
   279       r.AppendLine();
   280 
   281       Ring0.ReleaseIsaBusMutex();
   282 
   283       return r.ToString();
   284     }
   285   }
   286 }