Hardware/LPC/W836XX.cs
author moel.mich
Tue, 09 Mar 2010 22:27:10 +0000
changeset 79 9cdbe1d8d12a
parent 63 1a7c13ac7348
child 84 05bf128434c6
permissions -rw-r--r--
Changed the CPU clock calculation. If no invariant TSC is available, then the max CPU clock is estimated at startup under load, otherwise an average over one second is used.
moel@34
     1
/*
moel@34
     2
  
moel@34
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@34
     4
moel@34
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@34
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@34
     7
  the License. You may obtain a copy of the License at
moel@34
     8
 
moel@34
     9
  http://www.mozilla.org/MPL/
moel@34
    10
moel@34
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@34
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@34
    13
  for the specific language governing rights and limitations under the License.
moel@34
    14
moel@34
    15
  The Original Code is the Open Hardware Monitor code.
moel@34
    16
moel@34
    17
  The Initial Developer of the Original Code is 
moel@34
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@34
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@34
    20
  the Initial Developer. All Rights Reserved.
moel@34
    21
moel@34
    22
  Contributor(s):
moel@34
    23
moel@34
    24
  Alternatively, the contents of this file may be used under the terms of
moel@34
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@34
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@34
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@34
    28
  of those above. If you wish to allow use of your version of this file only
moel@34
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@34
    30
  use your version of this file under the terms of the MPL, indicate your
moel@34
    31
  decision by deleting the provisions above and replace them with the notice
moel@34
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@34
    33
  the provisions above, a recipient may use your version of this file under
moel@34
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@34
    35
 
moel@34
    36
*/
moel@34
    37
moel@34
    38
using System;
moel@34
    39
using System.Collections.Generic;
moel@34
    40
using System.Drawing;
moel@34
    41
using System.Text;
moel@34
    42
moel@34
    43
namespace OpenHardwareMonitor.Hardware.LPC {
moel@34
    44
  public class W836XX : LPCHardware, IHardware {
moel@34
    45
moel@34
    46
    private ushort address;
moel@34
    47
    private byte revision;
moel@34
    48
moel@34
    49
    private bool available;
moel@34
    50
moel@34
    51
    private Sensor[] temperatures;
moel@34
    52
    private Sensor[] fans;
moel@34
    53
    private Sensor[] voltages;
moel@34
    54
moel@34
    55
    private float[] voltageGains;
moel@34
    56
    private string[] fanNames;
moel@34
    57
moel@34
    58
    // Consts 
moel@34
    59
    private const ushort WINBOND_VENDOR_ID = 0x5CA3;
moel@34
    60
    private const byte HIGH_BYTE = 0x80;
moel@34
    61
moel@34
    62
    // Hardware Monitor
moel@34
    63
    private const byte ADDRESS_REGISTER_OFFSET = 0x05;
moel@34
    64
    private const byte DATA_REGISTER_OFFSET = 0x06;
moel@34
    65
moel@34
    66
    // Hardware Monitor Registers
moel@34
    67
    private const byte VOLTAGE_BASE_REG = 0x20;
moel@54
    68
    private const byte BANK_SELECT_REGISTER = 0x4E;
moel@34
    69
    private const byte VENDOR_ID_REGISTER = 0x4F;
moel@56
    70
    private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
moel@56
    71
moel@56
    72
    private string[] TEMPERATURE_NAME = 
moel@56
    73
      new string[] {"CPU", "Auxiliary", "System"};
moel@56
    74
    private byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
moel@56
    75
    private byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
moel@34
    76
moel@34
    77
    private byte[] FAN_TACHO_REG = new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
moel@34
    78
    private byte[] FAN_TACHO_BANK = new byte[] { 0, 0, 0, 0, 5 };       
moel@34
    79
    private byte[] FAN_BIT_REG = new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
moel@34
    80
    private byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
moel@34
    81
    private byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
moel@34
    82
    private byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
moel@34
    83
moel@34
    84
    private byte ReadByte(byte bank, byte register) {
moel@34
    85
      WinRing0.WriteIoPortByte(
moel@34
    86
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@34
    87
      WinRing0.WriteIoPortByte(
moel@34
    88
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@34
    89
      WinRing0.WriteIoPortByte(
moel@34
    90
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@34
    91
      return WinRing0.ReadIoPortByte(
moel@34
    92
        (ushort)(address + DATA_REGISTER_OFFSET));
moel@34
    93
    } 
moel@34
    94
moel@56
    95
    private void WriteByte(byte bank, byte register, byte value) {
moel@56
    96
      WinRing0.WriteIoPortByte(
moel@56
    97
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@56
    98
      WinRing0.WriteIoPortByte(
moel@56
    99
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@56
   100
      WinRing0.WriteIoPortByte(
moel@56
   101
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@56
   102
      WinRing0.WriteIoPortByte(
moel@56
   103
         (ushort)(address + DATA_REGISTER_OFFSET), value); 
moel@56
   104
    }
moel@56
   105
   
moel@34
   106
    public W836XX(Chip chip, byte revision, ushort address) 
moel@34
   107
      : base(chip)
moel@34
   108
    {
moel@34
   109
      this.address = address;
moel@34
   110
      this.revision = revision;
moel@34
   111
moel@34
   112
      available = IsWinbondVendor();
moel@34
   113
moel@63
   114
      ParameterDescription[] parameter = new ParameterDescription[] {
moel@63
   115
        new ParameterDescription("Offset", "Temperature offset.", 0)
moel@63
   116
      };
moel@56
   117
      List<Sensor> list = new List<Sensor>();
moel@56
   118
      switch (chip) {
moel@63
   119
        case Chip.W83667HG:
moel@63
   120
        case Chip.W83667HGB:
moel@63
   121
          // do not add temperature sensor registers that read PECI
moel@63
   122
          byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@63
   123
          if ((flag & 0x04) == 0)
moel@63
   124
            list.Add(new Sensor(TEMPERATURE_NAME[0], 0, null,
moel@63
   125
              SensorType.Temperature, this, parameter));
moel@63
   126
          if ((flag & 0x40) == 0)
moel@63
   127
            list.Add(new Sensor(TEMPERATURE_NAME[1], 1, null,
moel@63
   128
              SensorType.Temperature, this, parameter));
moel@63
   129
          list.Add(new Sensor(TEMPERATURE_NAME[2], 2, null,
moel@63
   130
            SensorType.Temperature, this, parameter));
moel@63
   131
          break;
moel@63
   132
        case Chip.W83627DHG:        
moel@63
   133
        case Chip.W83627DHGP:
moel@63
   134
          // do not add temperature sensor registers that read PECI
moel@56
   135
          byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@56
   136
          if ((sel & 0x07) == 0)
moel@63
   137
            list.Add(new Sensor(TEMPERATURE_NAME[0], 0, null,
moel@63
   138
              SensorType.Temperature, this, parameter));
moel@56
   139
          if ((sel & 0x70) == 0)
moel@63
   140
            list.Add(new Sensor(TEMPERATURE_NAME[1], 1, null,
moel@63
   141
              SensorType.Temperature, this, parameter));
moel@63
   142
          list.Add(new Sensor(TEMPERATURE_NAME[2], 2, null,
moel@63
   143
            SensorType.Temperature, this, parameter));
moel@56
   144
          break;
moel@56
   145
        default:
moel@63
   146
          // no PECI support, add all sensors
moel@63
   147
          for (int i = 0; i < TEMPERATURE_NAME.Length; i++)
moel@63
   148
            list.Add(new Sensor(TEMPERATURE_NAME[i], i, null,
moel@63
   149
              SensorType.Temperature, this, parameter));
moel@56
   150
          break;
moel@56
   151
      }
moel@56
   152
      temperatures = list.ToArray();
moel@34
   153
moel@34
   154
      switch (chip) {
moel@34
   155
        case Chip.W83627DHG:
moel@34
   156
        case Chip.W83627DHGP:
moel@34
   157
        case Chip.W83627EHF:
moel@34
   158
        case Chip.W83667HG:
moel@34
   159
        case Chip.W83667HGB: 
moel@34
   160
          fanNames = new string[] { "System", "CPU", "Auxiliary", 
moel@34
   161
            "CPU #2", "Auxiliary #2" };
moel@34
   162
          voltageGains = new float[] { 1, 1, 1, 2, 1, 1, 1, 2 };
moel@34
   163
          voltages = new Sensor[3];
moel@34
   164
          voltages[0] = new Sensor("CPU VCore", 0, SensorType.Voltage, this);
moel@34
   165
          voltages[1] = new Sensor("+3.3V", 3, SensorType.Voltage, this);
moel@34
   166
          voltages[2] = new Sensor("Battery", 7, SensorType.Voltage, this);
moel@34
   167
          break;
moel@54
   168
        case Chip.W83627HF:
moel@54
   169
        case Chip.W83627THF:
moel@67
   170
        case Chip.W83687THF:
moel@54
   171
          fanNames = new string[] { "System", "CPU", "Auxiliary" };
moel@34
   172
          voltageGains = new float[] { 2, 1, 2, 1, 1, 1, 1, 2 };
moel@34
   173
          voltages = new Sensor[3];
moel@34
   174
          voltages[0] = new Sensor("CPU VCore", 0, SensorType.Voltage, this);
moel@34
   175
          voltages[1] = new Sensor("+3.3V", 2, SensorType.Voltage, this);
moel@34
   176
          voltages[2] = new Sensor("Battery", 7, SensorType.Voltage, this);
moel@34
   177
          break;
moel@34
   178
        default: fanNames = new string[0];
moel@34
   179
          break;
moel@34
   180
      }
moel@34
   181
      
moel@34
   182
      fans = new Sensor[fanNames.Length];
moel@34
   183
      for (int i = 0; i < fanNames.Length; i++)
moel@34
   184
        fans[i] = new Sensor(fanNames[i], i, SensorType.Fan, this);
moel@34
   185
    }
moel@34
   186
moel@34
   187
    public bool IsAvailable {
moel@34
   188
      get { return available; }
moel@34
   189
    }        
moel@34
   190
moel@34
   191
    private bool IsWinbondVendor() {
moel@34
   192
      ushort vendorId =
moel@34
   193
        (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
moel@34
   194
           ReadByte(0, VENDOR_ID_REGISTER));
moel@34
   195
      return vendorId == WINBOND_VENDOR_ID;
moel@34
   196
    }
moel@34
   197
moel@34
   198
    public void Update() {
moel@56
   199
moel@34
   200
      foreach (Sensor sensor in voltages) {
moel@34
   201
        if (sensor.Index < 7) {
moel@58
   202
          // two special VCore measurement modes for W83627THF
moel@67
   203
          if ((chip == Chip.W83627HF || chip == Chip.W83627THF || 
moel@67
   204
            chip == Chip.W83687THF) && sensor.Index == 0) 
moel@67
   205
          {
moel@58
   206
            byte vrmConfiguration = ReadByte(0, 0x18);
moel@58
   207
            int value = ReadByte(0, VOLTAGE_BASE_REG);
moel@58
   208
            if ((vrmConfiguration & 0x01) == 0)
moel@58
   209
              sensor.Value = 0.016f * value; // VRM8 formula
moel@58
   210
            else
moel@58
   211
              sensor.Value = 0.00488f * value + 0.69f; // VRM9 formula
moel@58
   212
          } else {
moel@58
   213
            int value = ReadByte(0, (byte)(VOLTAGE_BASE_REG + sensor.Index));
moel@58
   214
            sensor.Value = 0.008f * voltageGains[sensor.Index] * value;
moel@58
   215
          }
moel@34
   216
          if (sensor.Value > 0)
moel@34
   217
            ActivateSensor(sensor);
moel@34
   218
          else
moel@34
   219
            DeactivateSensor(sensor);
moel@34
   220
        } else {
moel@34
   221
          // Battery voltage
moel@34
   222
          bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
moel@34
   223
          if (valid) {
moel@56
   224
            sensor.Value =
moel@34
   225
              0.008f * voltageGains[sensor.Index] * ReadByte(5, 0x51);
moel@34
   226
            ActivateSensor(sensor);
moel@34
   227
          } else
moel@34
   228
            DeactivateSensor(sensor);
moel@34
   229
        }
moel@34
   230
      }
moel@34
   231
moel@34
   232
      foreach (Sensor sensor in temperatures) {
moel@63
   233
        int value = ((sbyte)ReadByte(TEMPERATURE_BANK[sensor.Index],
moel@63
   234
          TEMPERATURE_REG[sensor.Index])) << 1;
moel@63
   235
        if (TEMPERATURE_BANK[sensor.Index] > 0) 
moel@63
   236
          value |= ReadByte(TEMPERATURE_BANK[sensor.Index],
moel@63
   237
            (byte)(TEMPERATURE_REG[sensor.Index] + 1)) >> 7;
moel@63
   238
moel@56
   239
        float temperature = value / 2.0f;
moel@56
   240
        if (temperature <= 125 && temperature >= -55) {
moel@63
   241
          sensor.Value = temperature + sensor.Parameters[0].Value;
moel@56
   242
          ActivateSensor(sensor);
moel@34
   243
        } else {
moel@56
   244
          DeactivateSensor(sensor);
moel@34
   245
        }
moel@34
   246
      }
moel@34
   247
moel@34
   248
      long bits = 0;
moel@34
   249
      for (int i = 0; i < FAN_BIT_REG.Length; i++)
moel@34
   250
        bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
moel@34
   251
      foreach (Sensor sensor in fans) {
moel@34
   252
        int count = ReadByte(FAN_TACHO_BANK[sensor.Index], 
moel@34
   253
          FAN_TACHO_REG[sensor.Index]);
moel@34
   254
        int divisorBits = (int)(
moel@34
   255
          (((bits >> FAN_DIV_BIT2[sensor.Index]) & 1) << 2) |
moel@34
   256
          (((bits >> FAN_DIV_BIT1[sensor.Index]) & 1) << 1) |
moel@34
   257
           ((bits >> FAN_DIV_BIT0[sensor.Index]) & 1));
moel@34
   258
        int divisor = 1 << divisorBits;
moel@34
   259
        float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
moel@34
   260
        sensor.Value = value;
moel@34
   261
        if (value > 0)
moel@34
   262
          ActivateSensor(sensor);        
moel@34
   263
      }     
moel@34
   264
    }
moel@34
   265
moel@34
   266
    public string GetReport() {
moel@34
   267
      StringBuilder r = new StringBuilder();
moel@34
   268
moel@34
   269
      r.AppendLine("LPC " + this.GetType().Name);
moel@34
   270
      r.AppendLine();
moel@34
   271
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@34
   272
      r.Append("Chip revision: 0x"); r.AppendLine(revision.ToString("X"));
moel@34
   273
      r.Append("Base Adress: 0x"); r.AppendLine(address.ToString("X4"));
moel@34
   274
      r.AppendLine();
moel@34
   275
      r.AppendLine("Hardware Monitor Registers");
moel@34
   276
      r.AppendLine();
moel@34
   277
      r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@34
   278
      r.AppendLine();
moel@56
   279
      for (int i = 0; i <= 0x7; i++) {
moel@34
   280
        r.Append(" "); r.Append((i << 4).ToString("X2")); r.Append("  ");
moel@34
   281
        for (int j = 0; j <= 0xF; j++) {
moel@34
   282
          r.Append(" ");
moel@34
   283
          r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString("X2"));
moel@34
   284
        }
moel@34
   285
        r.AppendLine();
moel@34
   286
      }
moel@53
   287
      for (int k = 1; k <= 15; k++) {
moel@34
   288
        r.AppendLine("Bank " + k);
moel@34
   289
        for (int i = 0x5; i < 0x6; i++) {
moel@34
   290
          r.Append(" "); r.Append((i << 4).ToString("X2")); r.Append("  ");
moel@34
   291
          for (int j = 0; j <= 0xF; j++) {
moel@34
   292
            r.Append(" ");
moel@34
   293
            r.Append(ReadByte((byte)(k),
moel@34
   294
              (byte)((i << 4) | j)).ToString("X2"));
moel@34
   295
          }
moel@34
   296
          r.AppendLine();
moel@34
   297
        }
moel@34
   298
      }
moel@34
   299
      r.AppendLine();
moel@34
   300
moel@34
   301
      return r.ToString();
moel@34
   302
    }
moel@34
   303
  }
moel@34
   304
}