Added thermal and voltage/frequency MSRs for K8 CPUs, fixed chars-per-line limit
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
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
9 http://www.mozilla.org/MPL/
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.
15 The Original Code is the Open Hardware Monitor code.
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) 2009-2010
20 the Initial Developer. All Rights Reserved.
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.
39 using System.Globalization;
42 namespace OpenHardwareMonitor.Hardware.LPC {
43 internal class W836XX : ISuperIO {
45 private ushort address;
46 private byte revision;
50 private float?[] voltages = new float?[0];
51 private float?[] temperatures = new float?[0];
52 private float?[] fans = new float?[0];
54 private bool[] peciTemperature = new bool[0];
55 private byte[] voltageRegister = new byte[0];
56 private byte[] voltageBank = new byte[0];
57 private float voltageGain = 0.008f;
60 private const ushort WINBOND_VENDOR_ID = 0x5CA3;
61 private const byte HIGH_BYTE = 0x80;
64 private const byte ADDRESS_REGISTER_OFFSET = 0x05;
65 private const byte DATA_REGISTER_OFFSET = 0x06;
67 // Hardware Monitor Registers
68 private const byte VOLTAGE_VBAT_REG = 0x51;
69 private const byte BANK_SELECT_REGISTER = 0x4E;
70 private const byte VENDOR_ID_REGISTER = 0x4F;
71 private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
73 private byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
74 private byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
76 private byte[] FAN_TACHO_REG = new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
77 private byte[] FAN_TACHO_BANK = new byte[] { 0, 0, 0, 0, 5 };
78 private byte[] FAN_BIT_REG = new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
79 private byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
80 private byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
81 private byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
83 private byte ReadByte(byte bank, byte register) {
84 WinRing0.WriteIoPortByte(
85 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
86 WinRing0.WriteIoPortByte(
87 (ushort)(address + DATA_REGISTER_OFFSET), bank);
88 WinRing0.WriteIoPortByte(
89 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
90 return WinRing0.ReadIoPortByte(
91 (ushort)(address + DATA_REGISTER_OFFSET));
94 private void WriteByte(byte bank, byte register, byte value) {
95 WinRing0.WriteIoPortByte(
96 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
97 WinRing0.WriteIoPortByte(
98 (ushort)(address + DATA_REGISTER_OFFSET), bank);
99 WinRing0.WriteIoPortByte(
100 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
101 WinRing0.WriteIoPortByte(
102 (ushort)(address + DATA_REGISTER_OFFSET), value);
105 public W836XX(Chip chip, byte revision, ushort address) {
106 this.address = address;
107 this.revision = revision;
110 if (!IsWinbondVendor())
113 temperatures = new float?[3];
114 peciTemperature = new bool[3];
118 // note temperature sensor registers that read PECI
119 byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
120 peciTemperature[0] = (flag & 0x04) != 0;
121 peciTemperature[1] = (flag & 0x40) != 0;
122 peciTemperature[2] = false;
125 case Chip.W83627DHGP:
126 // note temperature sensor registers that read PECI
127 byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
128 peciTemperature[0] = (sel & 0x07) != 0;
129 peciTemperature[1] = (sel & 0x70) != 0;
130 peciTemperature[2] = false;
134 peciTemperature[0] = false;
135 peciTemperature[1] = false;
136 peciTemperature[2] = false;
142 voltages = new float?[10];
143 voltageRegister = new byte[] {
144 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
145 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
146 voltageGain = 0.008f;
147 fans = new float?[5];
150 case Chip.W83627DHGP:
153 voltages = new float?[9];
154 voltageRegister = new byte[] {
155 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
156 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
157 voltageGain = 0.008f;
158 fans = new float?[5];
163 voltages = new float?[7];
164 voltageRegister = new byte[] {
165 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
166 voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
167 voltageGain = 0.016f;
168 fans = new float?[3];
173 private bool IsWinbondVendor() {
175 (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
176 ReadByte(0, VENDOR_ID_REGISTER));
177 return vendorId == WINBOND_VENDOR_ID;
180 private static ulong SetBit(ulong target, int bit, int value) {
181 if ((value & 1) != value)
182 throw new ArgumentException("Value must be one bit only.");
184 if (bit < 0 || bit > 63)
185 throw new ArgumentException("Bit out of range.");
187 ulong mask = (((ulong)1) << bit);
188 return value > 0 ? target | mask : target & ~mask;
191 public Chip Chip { get { return chip; } }
192 public float?[] Voltages { get { return voltages; } }
193 public float?[] Temperatures { get { return temperatures; } }
194 public float?[] Fans { get { return fans; } }
196 public void Update() {
197 if (!WinRing0.WaitIsaBusMutex(10))
200 for (int i = 0; i < voltages.Length; i++) {
201 if (voltageRegister[i] != VOLTAGE_VBAT_REG) {
202 // two special VCore measurement modes for W83627THF
204 if ((chip == Chip.W83627HF || chip == Chip.W83627THF ||
205 chip == Chip.W83687THF) && i == 0)
207 byte vrmConfiguration = ReadByte(0, 0x18);
208 int value = ReadByte(voltageBank[i], voltageRegister[i]);
209 if ((vrmConfiguration & 0x01) == 0)
210 fvalue = 0.016f * value; // VRM8 formula
212 fvalue = 0.00488f * value + 0.69f; // VRM9 formula
214 int value = ReadByte(voltageBank[i], voltageRegister[i]);
215 fvalue = voltageGain * value;
218 voltages[i] = fvalue;
223 bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
225 voltages[i] = voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
232 for (int i = 0; i < temperatures.Length; i++) {
233 int value = ((sbyte)ReadByte(TEMPERATURE_BANK[i],
234 TEMPERATURE_REG[i])) << 1;
235 if (TEMPERATURE_BANK[i] > 0)
236 value |= ReadByte(TEMPERATURE_BANK[i],
237 (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
239 float temperature = value / 2.0f;
240 if (temperature <= 125 && temperature >= -55 && !peciTemperature[i]) {
241 temperatures[i] = temperature;
243 temperatures[i] = null;
248 for (int i = 0; i < FAN_BIT_REG.Length; i++)
249 bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
250 ulong newBits = bits;
251 for (int i = 0; i < fans.Length; i++) {
252 int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
254 // assemble fan divisor
255 int divisorBits = (int)(
256 (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
257 (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
258 ((bits >> FAN_DIV_BIT0[i]) & 1));
259 int divisor = 1 << divisorBits;
261 float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
264 // update fan divisor
265 if (count > 192 && divisorBits < 7)
267 if (count < 96 && divisorBits > 0)
270 newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
271 newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
272 newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
275 // write new fan divisors
276 for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
277 byte oldByte = (byte)(bits & 0xFF);
278 byte newByte = (byte)(newBits & 0xFF);
280 newBits = newBits >> 8;
281 if (oldByte != newByte)
282 WriteByte(0, FAN_BIT_REG[i], newByte);
285 WinRing0.ReleaseIsaBusMutex();
288 public string GetReport() {
289 StringBuilder r = new StringBuilder();
291 r.AppendLine("LPC " + this.GetType().Name);
293 r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
294 r.Append("Chip revision: 0x");
295 r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
296 r.Append("Base Adress: 0x");
297 r.AppendLine(address.ToString("X4", CultureInfo.InvariantCulture));
300 if (!WinRing0.WaitIsaBusMutex(100))
303 r.AppendLine("Hardware Monitor Registers");
305 r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
307 for (int i = 0; i <= 0x7; i++) {
309 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
311 for (int j = 0; j <= 0xF; j++) {
313 r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString(
314 "X2", CultureInfo.InvariantCulture));
318 for (int k = 1; k <= 15; k++) {
319 r.AppendLine("Bank " + k);
320 for (int i = 0x5; i < 0x6; i++) {
322 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
324 for (int j = 0; j <= 0xF; j++) {
326 r.Append(ReadByte((byte)(k), (byte)((i << 4) | j)).ToString(
327 "X2", CultureInfo.InvariantCulture));
334 WinRing0.ReleaseIsaBusMutex();