* Rename IT8795E to IT87952E IT8795E and IT87952E are distinct chips (with their own IC markings). The IT8795E, as the IT8791E and IT8792E, reports chip ID 0x8733 whereas the IT87952E identifies as 0x8695. * Gigabyte EC: Fix typo in LPC register restore When the AMD LPC Bridge registers are restored after configuring memory mapping, restore the correct value for the "Memory Address for LPC target cycles" register. * Add IT87952E fan control for Gigabyte boards IT87952E (ID 0x8695) has a third byte in SuperIO config space (LDN 0x0F) that determines more bits of the host address for LPC memory mapping. Also the base address for Gigabyte boards is 0xFC000000 instead of 0xFF000000 (as is the case with IT8790/1/2/5). This should make additional fan controls work on Gigabyte mainboards where the settings had no effect previously, e.g: X570S AORUS MASTER and X670E AORUS MASTER. (cf. Issue #251) It does not yet work for Intel boards as the LPC bridge requires different programming. * Update LpcIO.cs --------- Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
726 lines
24 KiB
C#
726 lines
24 KiB
C#
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
// Copyright (C) LibreHardwareMonitor and Contributors.
|
|
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
|
// All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using LibreHardwareMonitor.Hardware.Cpu;
|
|
|
|
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
|
|
|
|
internal class LpcIO
|
|
{
|
|
private readonly StringBuilder _report = new();
|
|
private readonly List<ISuperIO> _superIOs = new();
|
|
|
|
public LpcIO(Motherboard motherboard)
|
|
{
|
|
if (!Ring0.IsOpen || !Ring0.WaitIsaBusMutex(100))
|
|
return;
|
|
|
|
Detect(motherboard);
|
|
|
|
Ring0.ReleaseIsaBusMutex();
|
|
|
|
if (Ipmi.IsBmcPresent())
|
|
_superIOs.Add(new Ipmi(motherboard.Manufacturer));
|
|
}
|
|
|
|
public ISuperIO[] SuperIO => _superIOs.ToArray();
|
|
|
|
private void ReportUnknownChip(LpcPort port, string type, int chip)
|
|
{
|
|
_report.Append("Chip ID: Unknown ");
|
|
_report.Append(type);
|
|
_report.Append(" with ID 0x");
|
|
_report.Append(chip.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.Append(" at 0x");
|
|
_report.Append(port.RegisterPort.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.Append("/0x");
|
|
_report.AppendLine(port.ValuePort.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.AppendLine();
|
|
}
|
|
|
|
private bool DetectSmsc(LpcPort port)
|
|
{
|
|
port.SmscEnter();
|
|
|
|
ushort chipId = port.ReadWord(CHIP_ID_REGISTER);
|
|
|
|
if (chipId is not 0 and not 0xffff)
|
|
{
|
|
port.SmscExit();
|
|
ReportUnknownChip(port, "SMSC", chipId);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void Detect(Motherboard motherboard)
|
|
{
|
|
for (int i = 0; i < REGISTER_PORTS.Length; i++)
|
|
{
|
|
var port = new LpcPort(REGISTER_PORTS[i], VALUE_PORTS[i]);
|
|
|
|
if (DetectWinbondFintek(port)) continue;
|
|
|
|
if (DetectIT87(port, motherboard)) continue;
|
|
|
|
if (DetectSmsc(port)) continue;
|
|
}
|
|
}
|
|
|
|
public string GetReport()
|
|
{
|
|
if (_report.Length > 0)
|
|
{
|
|
return "LpcIO" + Environment.NewLine + Environment.NewLine + _report;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private bool DetectWinbondFintek(LpcPort port)
|
|
{
|
|
port.WinbondNuvotonFintekEnter();
|
|
|
|
byte logicalDeviceNumber = 0;
|
|
byte id = port.ReadByte(CHIP_ID_REGISTER);
|
|
byte revision = port.ReadByte(CHIP_REVISION_REGISTER);
|
|
Chip chip = Chip.Unknown;
|
|
|
|
switch (id)
|
|
{
|
|
case 0x05:
|
|
switch (revision)
|
|
{
|
|
case 0x07:
|
|
chip = Chip.F71858;
|
|
logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x41:
|
|
chip = Chip.F71882;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x06:
|
|
switch (revision)
|
|
{
|
|
case 0x01:
|
|
chip = Chip.F71862;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x07:
|
|
switch (revision)
|
|
{
|
|
case 0x23:
|
|
chip = Chip.F71889F;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x08:
|
|
switch (revision)
|
|
{
|
|
case 0x14:
|
|
chip = Chip.F71869;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x09:
|
|
switch (revision)
|
|
{
|
|
case 0x01:
|
|
chip = Chip.F71808E;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x09:
|
|
chip = Chip.F71889ED;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x10:
|
|
switch (revision)
|
|
{
|
|
case 0x05:
|
|
chip = Chip.F71889AD;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x07:
|
|
chip = Chip.F71869A;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x11:
|
|
switch (revision)
|
|
{
|
|
case 0x06:
|
|
chip = Chip.F71878AD;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x18:
|
|
chip = Chip.F71811;
|
|
logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x52:
|
|
switch (revision)
|
|
{
|
|
case 0x17:
|
|
case 0x3A:
|
|
case 0x41:
|
|
chip = Chip.W83627HF;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x82:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x80:
|
|
chip = Chip.W83627THF;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x85:
|
|
switch (revision)
|
|
{
|
|
case 0x41:
|
|
chip = Chip.W83687THF;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0x88:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x50:
|
|
case 0x60:
|
|
chip = Chip.W83627EHF;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xA0:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x20:
|
|
chip = Chip.W83627DHG;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xA5:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x10:
|
|
chip = Chip.W83667HG;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xB0:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x70:
|
|
chip = Chip.W83627DHGP;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xB3:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x50:
|
|
chip = Chip.W83667HGB;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xB4:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x70:
|
|
chip = Chip.NCT6771F;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xC3:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x30:
|
|
chip = Chip.NCT6776F;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xC4:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x50:
|
|
chip = Chip.NCT610XD;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xC5:
|
|
switch (revision & 0xF0)
|
|
{
|
|
case 0x60:
|
|
chip = Chip.NCT6779D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xC7:
|
|
switch (revision)
|
|
{
|
|
case 0x32:
|
|
chip = Chip.NCT6683D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xC8:
|
|
switch (revision)
|
|
{
|
|
case 0x03:
|
|
chip = Chip.NCT6791D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xC9:
|
|
switch (revision)
|
|
{
|
|
case 0x11:
|
|
chip = Chip.NCT6792D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x13:
|
|
chip = Chip.NCT6792DA;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xD1:
|
|
switch (revision)
|
|
{
|
|
case 0x21:
|
|
chip = Chip.NCT6793D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xD3:
|
|
switch (revision)
|
|
{
|
|
case 0x52:
|
|
chip = Chip.NCT6795D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xD4:
|
|
switch (revision)
|
|
{
|
|
case 0x23:
|
|
chip = Chip.NCT6796D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x2A:
|
|
chip = Chip.NCT6796DR;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x51:
|
|
chip = Chip.NCT6797D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x2B:
|
|
chip = Chip.NCT6798D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
case 0x40:
|
|
case 0x41:
|
|
chip = Chip.NCT6686D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xD5:
|
|
switch (revision)
|
|
{
|
|
case 0x92:
|
|
chip = Chip.NCT6687D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 0xD8:
|
|
switch (revision)
|
|
{
|
|
case 0x02:
|
|
chip = Chip.NCT6799D;
|
|
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (chip == Chip.Unknown)
|
|
{
|
|
if (id is not 0 and not 0xff)
|
|
{
|
|
port.WinbondNuvotonFintekExit();
|
|
ReportUnknownChip(port, "Winbond / Nuvoton / Fintek", (id << 8) | revision);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
port.Select(logicalDeviceNumber);
|
|
ushort address = port.ReadWord(BASE_ADDRESS_REGISTER);
|
|
Thread.Sleep(1);
|
|
ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER);
|
|
|
|
ushort vendorId = port.ReadWord(FINTEK_VENDOR_ID_REGISTER);
|
|
|
|
// disable the hardware monitor i/o space lock on NCT679XD chips
|
|
if (address == verify &&
|
|
chip is Chip.NCT6791D or Chip.NCT6792D or Chip.NCT6792DA or Chip.NCT6793D or Chip.NCT6795D or Chip.NCT6796D or Chip.NCT6796DR or Chip.NCT6798D or Chip.NCT6797D or Chip.NCT6799D)
|
|
{
|
|
port.NuvotonDisableIOSpaceLock();
|
|
}
|
|
|
|
port.WinbondNuvotonFintekExit();
|
|
|
|
if (address != verify)
|
|
{
|
|
_report.Append("Chip ID: 0x");
|
|
_report.AppendLine(chip.ToString("X"));
|
|
_report.Append("Chip revision: 0x");
|
|
_report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.AppendLine("Error: Address verification failed");
|
|
_report.AppendLine();
|
|
|
|
return false;
|
|
}
|
|
|
|
// some Fintek chips have address register offset 0x05 added already
|
|
if ((address & 0x07) == 0x05)
|
|
address &= 0xFFF8;
|
|
|
|
if (address < 0x100 || (address & 0xF007) != 0)
|
|
{
|
|
_report.Append("Chip ID: 0x");
|
|
_report.AppendLine(chip.ToString("X"));
|
|
_report.Append("Chip revision: 0x");
|
|
_report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.Append("Error: Invalid address 0x");
|
|
_report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.AppendLine();
|
|
|
|
return false;
|
|
}
|
|
|
|
switch (chip)
|
|
{
|
|
case Chip.W83627DHG:
|
|
case Chip.W83627DHGP:
|
|
case Chip.W83627EHF:
|
|
case Chip.W83627HF:
|
|
case Chip.W83627THF:
|
|
case Chip.W83667HG:
|
|
case Chip.W83667HGB:
|
|
case Chip.W83687THF:
|
|
_superIOs.Add(new W836XX(chip, revision, address));
|
|
break;
|
|
|
|
case Chip.NCT610XD:
|
|
case Chip.NCT6771F:
|
|
case Chip.NCT6776F:
|
|
case Chip.NCT6779D:
|
|
case Chip.NCT6791D:
|
|
case Chip.NCT6792D:
|
|
case Chip.NCT6792DA:
|
|
case Chip.NCT6793D:
|
|
case Chip.NCT6795D:
|
|
case Chip.NCT6796D:
|
|
case Chip.NCT6796DR:
|
|
case Chip.NCT6797D:
|
|
case Chip.NCT6798D:
|
|
case Chip.NCT6799D:
|
|
case Chip.NCT6686D:
|
|
case Chip.NCT6687D:
|
|
case Chip.NCT6683D:
|
|
_superIOs.Add(new Nct677X(chip, revision, address, port));
|
|
break;
|
|
|
|
case Chip.F71858:
|
|
case Chip.F71862:
|
|
case Chip.F71869:
|
|
case Chip.F71878AD:
|
|
case Chip.F71869A:
|
|
case Chip.F71882:
|
|
case Chip.F71889AD:
|
|
case Chip.F71889ED:
|
|
case Chip.F71889F:
|
|
case Chip.F71808E:
|
|
if (vendorId != FINTEK_VENDOR_ID)
|
|
{
|
|
_report.Append("Chip ID: 0x");
|
|
_report.AppendLine(chip.ToString("X"));
|
|
_report.Append("Chip revision: 0x");
|
|
_report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.Append("Error: Invalid vendor ID 0x");
|
|
_report.AppendLine(vendorId.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.AppendLine();
|
|
|
|
return false;
|
|
}
|
|
|
|
_superIOs.Add(new F718XX(chip, address));
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool DetectIT87(LpcPort port, Motherboard motherboard)
|
|
{
|
|
// IT87XX can enter only on port 0x2E
|
|
// IT8792 using 0x4E
|
|
if (port.RegisterPort is not 0x2E and not 0x4E)
|
|
return false;
|
|
|
|
port.IT87Enter();
|
|
|
|
ushort chipId = port.ReadWord(CHIP_ID_REGISTER);
|
|
Chip chip = chipId switch
|
|
{
|
|
0x8613 => Chip.IT8613E,
|
|
0x8620 => Chip.IT8620E,
|
|
0x8625 => Chip.IT8625E,
|
|
0x8628 => Chip.IT8628E,
|
|
0x8631 => Chip.IT8631E,
|
|
0x8665 => Chip.IT8665E,
|
|
0x8655 => Chip.IT8655E,
|
|
0x8686 => Chip.IT8686E,
|
|
0x8688 => Chip.IT8688E,
|
|
0x8689 => Chip.IT8689E,
|
|
0x8705 => Chip.IT8705F,
|
|
0x8712 => Chip.IT8712F,
|
|
0x8716 => Chip.IT8716F,
|
|
0x8718 => Chip.IT8718F,
|
|
0x8720 => Chip.IT8720F,
|
|
0x8721 => Chip.IT8721F,
|
|
0x8726 => Chip.IT8726F,
|
|
0x8728 => Chip.IT8728F,
|
|
0x8771 => Chip.IT8771E,
|
|
0x8772 => Chip.IT8772E,
|
|
0x8790 => Chip.IT8790E,
|
|
0x8733 => Chip.IT8792E,
|
|
0x8695 => Chip.IT87952E,
|
|
_ => Chip.Unknown
|
|
};
|
|
|
|
if (chip == Chip.Unknown)
|
|
{
|
|
if (chipId is not 0 and not 0xffff)
|
|
{
|
|
port.IT87Exit();
|
|
|
|
ReportUnknownChip(port, "ITE", chipId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
port.Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
|
|
|
|
ushort address = port.ReadWord(BASE_ADDRESS_REGISTER);
|
|
Thread.Sleep(1);
|
|
ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER);
|
|
|
|
byte version = (byte)(port.ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
|
|
|
|
ushort gpioAddress;
|
|
ushort gpioVerify;
|
|
|
|
if (chip == Chip.IT8705F)
|
|
{
|
|
port.Select(IT8705_GPIO_LDN);
|
|
gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER);
|
|
Thread.Sleep(1);
|
|
gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER);
|
|
}
|
|
else
|
|
{
|
|
port.Select(IT87XX_GPIO_LDN);
|
|
gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER + 2);
|
|
Thread.Sleep(1);
|
|
gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER + 2);
|
|
}
|
|
|
|
GigabyteController gigabyteController = FindGigabyteEC(port, chip, motherboard);
|
|
|
|
port.IT87Exit();
|
|
|
|
if (address != verify || address < 0x100 || (address & 0xF007) != 0)
|
|
{
|
|
_report.Append("Chip ID: 0x");
|
|
_report.AppendLine(chip.ToString("X"));
|
|
_report.Append("Error: Invalid address 0x");
|
|
_report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.AppendLine();
|
|
|
|
return false;
|
|
}
|
|
|
|
if (gpioAddress != gpioVerify || gpioAddress < 0x100 || (gpioAddress & 0xF007) != 0)
|
|
{
|
|
_report.Append("Chip ID: 0x");
|
|
_report.AppendLine(chip.ToString("X"));
|
|
_report.Append("Error: Invalid GPIO address 0x");
|
|
_report.AppendLine(gpioAddress.ToString("X", CultureInfo.InvariantCulture));
|
|
_report.AppendLine();
|
|
|
|
return false;
|
|
}
|
|
|
|
_superIOs.Add(new IT87XX(chip, address, gpioAddress, version, motherboard, gigabyteController));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private GigabyteController FindGigabyteEC(LpcPort port, Chip chip, Motherboard motherboard)
|
|
{
|
|
// The controller only affects the 2nd ITE chip if present, and only a few
|
|
// models are known to use this controller.
|
|
// IT8795E likely to need this too, but may use different registers.
|
|
if (motherboard.Manufacturer != Manufacturer.Gigabyte || port.RegisterPort != 0x4E || chip is not (Chip.IT8790E or Chip.IT8792E or Chip.IT87952E))
|
|
return null;
|
|
|
|
port.Select(IT87XX_SMFI_LDN);
|
|
|
|
// Check if the SMFI logical device is enabled
|
|
byte enabled = port.ReadByte(IT87_LD_ACTIVE_REGISTER);
|
|
Thread.Sleep(1);
|
|
byte enabledVerify = port.ReadByte(IT87_LD_ACTIVE_REGISTER);
|
|
|
|
// The EC has no SMFI or it's RAM access is not enabled, assume the controller is not present
|
|
if (enabled != enabledVerify || enabled == 0)
|
|
return null;
|
|
|
|
// Read the host RAM address that maps to the Embedded Controller's RAM (two registers).
|
|
uint addressHi = 0;
|
|
uint addressHiVerify = 0;
|
|
uint address = port.ReadWord(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER);
|
|
if (chip == Chip.IT87952E)
|
|
addressHi = port.ReadByte(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER_HIGH);
|
|
|
|
Thread.Sleep(1);
|
|
uint addressVerify = port.ReadWord(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER);
|
|
if (chip == Chip.IT87952E)
|
|
addressHiVerify = port.ReadByte(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER_HIGH);
|
|
|
|
if ((address != addressVerify) || (addressHi != addressHiVerify))
|
|
return null;
|
|
|
|
// Address is xryy, Host Address is FFyyx000
|
|
// For IT87952E, Address is rzxryy, Host Address is (0xFC000000 | 0x0zyyx000)
|
|
uint hostAddress;
|
|
if (chip == Chip.IT87952E)
|
|
hostAddress = 0xFC000000;
|
|
else
|
|
hostAddress = 0xFF000000;
|
|
|
|
hostAddress |= (address & 0xF000) | ((address & 0xFF) << 16) | ((addressHi & 0xF) << 24);
|
|
|
|
return new GigabyteController(hostAddress, DetectVendor());
|
|
|
|
Vendor DetectVendor()
|
|
{
|
|
string manufacturer = motherboard.SMBios.Processors[0].ManufacturerName;
|
|
if (manufacturer.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) != -1)
|
|
return Vendor.Intel;
|
|
|
|
if (manufacturer.IndexOf("Advanced Micro Devices", StringComparison.OrdinalIgnoreCase) != -1 || manufacturer.StartsWith("AMD", StringComparison.OrdinalIgnoreCase))
|
|
return Vendor.AMD;
|
|
|
|
return Vendor.Unknown;
|
|
}
|
|
}
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
private const byte BASE_ADDRESS_REGISTER = 0x60;
|
|
private const byte CHIP_ID_REGISTER = 0x20;
|
|
private const byte CHIP_REVISION_REGISTER = 0x21;
|
|
|
|
private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
|
|
private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
|
|
private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
|
|
private const byte IT8705_GPIO_LDN = 0x05;
|
|
private const byte IT87XX_GPIO_LDN = 0x07;
|
|
|
|
// Shared Memory/Flash Interface
|
|
private const byte IT87XX_SMFI_LDN = 0x0F;
|
|
private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B;
|
|
|
|
private const ushort FINTEK_VENDOR_ID = 0x1934;
|
|
|
|
private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
|
|
private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
|
|
private const byte IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER = 0xF5;
|
|
private const byte IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER_HIGH = 0xFC;
|
|
private const byte IT87_LD_ACTIVE_REGISTER = 0x30;
|
|
|
|
private readonly ushort[] REGISTER_PORTS = { 0x2E, 0x4E };
|
|
private readonly ushort[] VALUE_PORTS = { 0x2F, 0x4F };
|
|
// ReSharper restore InconsistentNaming
|
|
}
|