Add ASRock X870E Nova WiFi Support (#2012)

* Add ASRock X870E Nova WiFi Support

- Added support for Nuvoton NCT5585D chip
- Added support for Nuvoton NCT6796D-S chip
- Added motherboard-specific switch to select the correct chip due to duplicate chip ID/Revision (see #2005)
- Added chips to disable monitor i/o space lock block
- Added business logic to include chips in _superIOs.Add for the Nct677X() logic.
- Added chips to business logic to properly assign indices for fans, controls, temperatures and voltages.
- Added TSENSOR to the enum for SourceNct67Xxd to display the 3rd thermistor sensor.
- Added Naming and Identification for the X870E Nova WiFi
- Supressed warnings and added documentation

* Corrections

These changes reflect scraping the datasheet for the correct registers, half-registers, halfBits, sourceRegisters and alternateRegisters
- Replaced TSENSOR with AUXTIN5 as it is named in the datasheet
- Corrected Register values
- Reworked indexes and temperature naming

* Requested Changes

- Linked to PR instead of Datasheet which may change.
- Changed descriptions to be more understandable rather than using Datasheet labels

* Removed duplicate TSENSOR in enum
This commit is contained in:
objecttothis
2025-11-06 13:39:13 +01:00
committed by GitHub
parent 71b5e66c0d
commit 517794ce53
6 changed files with 203 additions and 16 deletions
@@ -1,4 +1,4 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// 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.
@@ -716,6 +716,8 @@ internal class Identification
case var _ when name.Equals("X870E Taichi", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("X870E Taichi Lite", StringComparison.OrdinalIgnoreCase):
return Model.X870E_TAICHI;
case var _ when name.Equals("X870E Nova WiFi", StringComparison.OrdinalIgnoreCase):
return Model.X870E_NOVA_WIFI;
case var _ when name.Equals("X670 AORUS ELITE AX", StringComparison.OrdinalIgnoreCase):
return Model.X670_AORUS_ELITE_AX;
case var _ when name.Equals("PROART B760-CREATOR D4", StringComparison.OrdinalIgnoreCase):
@@ -1,4 +1,4 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// 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.
@@ -53,6 +53,7 @@ internal enum Chip : ushort
IT8792E = 0x8733, // Could also be IT8791E, IT8795E
IT87952E = 0x8695,
NCT5585D = 0xFFF0, // Chip reports 0xD42A but that's in use
NCT610XD = 0xC452,
NCT6771F = 0xB470,
NCT6776F = 0xC330,
@@ -64,6 +65,7 @@ internal enum Chip : ushort
NCT6795D = 0xD352,
NCT6796D = 0xD423,
NCT6796DR = 0xD42A,
NCT6796DS = 0xFFF1, // Chip reports 0xD802 but that's in use
NCT6797D = 0xD451,
NCT6798D = 0xD42B,
NCT6686D = 0xD440,
@@ -129,6 +131,7 @@ internal class ChipName
case Chip.IT8792E: return "ITE IT8791E/IT8792E/IT8795E";
case Chip.IT87952E: return "ITE IT87952E";
case Chip.NCT5585D: return "Nuvoton NCT5585D";
case Chip.NCT610XD: return "Nuvoton NCT6102D/NCT6104D/NCT6106D";
case Chip.NCT6771F: return "Nuvoton NCT6771F";
case Chip.NCT6776F: return "Nuvoton NCT6776F";
@@ -140,6 +143,7 @@ internal class ChipName
case Chip.NCT6795D: return "Nuvoton NCT6795D";
case Chip.NCT6796D: return "Nuvoton NCT6796D";
case Chip.NCT6796DR: return "Nuvoton NCT6796D-R";
case Chip.NCT6796DS: return "Nuvoton NCT6796D-S";
case Chip.NCT6797D: return "Nuvoton NCT6797D";
case Chip.NCT6798D: return "Nuvoton NCT6798D";
case Chip.NCT6799D: return "Nuvoton NCT6799D";
@@ -378,7 +378,15 @@ internal class LpcIO
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
break;
case 0x2A:
chip = Chip.NCT6796DR;
switch (motherboard.Model)
{
case Model.X870E_NOVA_WIFI:
chip = Chip.NCT5585D;
break;
default:
chip = Chip.NCT6796DR;
break;
}
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
break;
case 0x51:
@@ -441,7 +449,16 @@ internal class LpcIO
switch (revision)
{
case 0x02:
chip = Chip.NCT6799D;
switch (motherboard.Model)
{
case Model.X870E_NOVA_WIFI:
chip = Chip.NCT6796DS;
break;
default:
chip = Chip.NCT6799D;
break;
}
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
break;
case 0x06:
@@ -473,7 +490,7 @@ internal class LpcIO
// 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 or Chip.NCT6701D)
chip is Chip.NCT6791D or Chip.NCT6792D or Chip.NCT6792DA or Chip.NCT6793D or Chip.NCT6795D or Chip.NCT6796D or Chip.NCT6796DR or Chip.NCT6796DS or Chip.NCT6798D or Chip.NCT6797D or Chip.NCT6799D or Chip.NCT6701D)
{
port.NuvotonDisableIOSpaceLock();
}
@@ -533,6 +550,7 @@ internal class LpcIO
case Chip.NCT6795D:
case Chip.NCT6796D:
case Chip.NCT6796DR:
case Chip.NCT6796DS:
case Chip.NCT6797D:
case Chip.NCT6798D:
case Chip.NCT6799D:
@@ -541,6 +559,7 @@ internal class LpcIO
case Chip.NCT6687DR:
case Chip.NCT6683D:
case Chip.NCT6701D:
case Chip.NCT5585D:
_superIOs.Add(new Nct677X(port, chip, revision, address));
break;
@@ -1,4 +1,4 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// 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.
@@ -10,6 +10,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using System.Threading;
using static System.Net.WebRequestMethods;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
@@ -88,7 +89,7 @@ internal class Nct677X : ISuperIO
VENDOR_ID_HIGH_REGISTER = 0x804F;
VENDOR_ID_LOW_REGISTER = 0x004F;
FAN_PWM_OUT_REG = chip is Chip.NCT6797D or Chip.NCT6798D or Chip.NCT6799D
FAN_PWM_OUT_REG = chip is Chip.NCT6797D or Chip.NCT6798D or Chip.NCT6799D or Chip.NCT6796DS or Chip.NCT5585D
? new ushort[] { 0x001, 0x003, 0x011, 0x013, 0x015, 0xA09, 0xB09 }
: new ushort[] { 0x001, 0x003, 0x011, 0x013, 0x015, 0x017, 0x029 };
@@ -155,10 +156,12 @@ internal class Nct677X : ISuperIO
case Chip.NCT6795D:
case Chip.NCT6796D: // 16 voltages
case Chip.NCT6796DR: // 16 voltages
case Chip.NCT6796DS:
case Chip.NCT6797D:
case Chip.NCT6798D:
case Chip.NCT6799D:
case Chip.NCT6701D:
case Chip.NCT5585D:
switch (chip)
{
case Chip.NCT6779D:
@@ -167,10 +170,12 @@ internal class Nct677X : ISuperIO
break;
case Chip.NCT6796DR:
case Chip.NCT6796DS:
case Chip.NCT6797D:
case Chip.NCT6798D:
case Chip.NCT6799D:
case Chip.NCT6701D:
case Chip.NCT5585D:
Fans = new float?[7];
Controls = new float?[7];
break;
@@ -269,6 +274,33 @@ internal class Nct677X : ISuperIO
});
break;
case Chip.NCT6796DS:
temperaturesSources.AddRange(new TemperatureSourceData[]
{//https://github.com/LibreHardwareMonitor/LibreHardwareMonitor/pull/2012
new(SourceNct67Xxd.CPUTIN, 0x073, 0x074, 7, 0x100, 0x491),
new(SourceNct67Xxd.SYSTIN, 0x075, 0x076, 7, 0x200, 0x490),
new(SourceNct67Xxd.AUXTIN0, 0x077, 0x078, 7, 0x300, 0x492),
new(SourceNct67Xxd.AUXTIN1, 0x079, 0x07A, 7, 0x800, 0x493),
new(SourceNct67Xxd.AUXTIN2, 0x07B, 0x07C, 7, 0x900, 0x494),
new(SourceNct67Xxd.AUXTIN3, 0x07D, 0x07E, 7, 0xA00, 0x495),
new(SourceNct67Xxd.AUXTIN4, 0x027, 0, 4,0xC16 ,0x496),
new(SourceNct67Xxd.AUXTIN5, 0x449, 0, 4, 0x100, 0x4A2),
new(SourceNct67Xxd.SMBUSMASTER0, 0x150, 0x151, 7, 0x622),
new(SourceNct67Xxd.PECI_0, 0x0720, 0, -1, 0),
new(SourceNct67Xxd.VIRTUAL_TEMP, 0)
});
break;
case Chip.NCT5585D:
temperaturesSources.AddRange(new TemperatureSourceData[]
{
new(SourceNct67Xxd.PECI_0, 0x0720, 0, -1, 0x100),
new(SourceNct67Xxd.CPUTIN, 0x075, 0x076, 7, 0x000, 0x073),
new(SourceNct67Xxd.AUXTIN1, 0x07B, 0x07C, 7, 0x900, 0x493),
new(SourceNct67Xxd.AUXTIN3, 0x4A0, 0x49E, 6, 0xB00, 0x495),
});
break;
default:
temperaturesSources.AddRange(new TemperatureSourceData[]
{
@@ -605,9 +637,11 @@ internal class Nct677X : ISuperIO
case Chip.NCT6796D:
case Chip.NCT6796DR:
case Chip.NCT6796DS:
case Chip.NCT6797D:
case Chip.NCT6798D:
case Chip.NCT6799D:
case Chip.NCT5585D:
if (_temperaturesSource[i].Register == 0)
{
System.Diagnostics.Debug.WriteLine("Temperature register {0} skipped, address 0.", i);
@@ -1132,9 +1166,11 @@ internal class Nct677X : ISuperIO
not Chip.NCT6795D and
not Chip.NCT6796D and
not Chip.NCT6796DR and
not Chip.NCT6796DS and
not Chip.NCT6797D and
not Chip.NCT6798D and
not Chip.NCT6799D)
not Chip.NCT6799D and
not Chip.NCT5585D)
{
return;
}
@@ -1202,7 +1238,8 @@ internal class Nct677X : ISuperIO
RESERVED_7 = 30,
VIRTUAL_TEMP = 31,
SPARE_TEMP = 32,
SPARE_TEMP2 = 33
SPARE_TEMP2 = 33,
AUXTIN5 = 34,
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
@@ -1,4 +1,4 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// 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.
@@ -10,6 +10,10 @@ using System.Diagnostics.CodeAnalysis;
namespace LibreHardwareMonitor.Hardware.Motherboard;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
/// <summary>
/// Known motherboard models detected/recognized by LibreHardwareMonitor.
/// </summary>
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "CommentTypo")]
public enum Model
@@ -45,6 +49,7 @@ public enum Model
H61M_DGS,
B850M_STEEL_LEGEND_WIFI,
X870E_TAICHI,
X870E_NOVA_WIFI,
// ASUS
CROSSHAIR_III_FORMULA,
@@ -6,6 +6,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Threading;
using LibreHardwareMonitor.Hardware.Motherboard.Lpc;
@@ -315,6 +317,37 @@ internal sealed class SuperIOHardware : Hardware
c.Add(new Control("Auxiliary Fan", 2));
break;
case Chip.NCT5585D:
switch (manufacturer)
{
case Manufacturer.ASRock when model == Model.X870E_NOVA_WIFI:
// Voltages
v.Add(new Voltage("Vcore", 0));
v.Add(new Voltage("DRAM", 1));
v.Add(new Voltage("+3.3V (AVCC)", 2, 34, 34));
v.Add(new Voltage("+3.3V (3VCC)", 3, 34, 34));
v.Add(new Voltage("VDD Misc", 4));
v.Add(new Voltage("3VSB", 7, 34, 34));
v.Add(new Voltage("VBat", 8, 34, 34));
v.Add(new Voltage("Voltage #2", 12));
v.Add(new Voltage("Voltage #3", 13));
v.Add(new Voltage("Voltage #7", 14));
v.Add(new Voltage("Voltage #9", 15));
// Temperatures
t.Add(new Temperature("MOS", 1));
t.Add(new Temperature("CPU (PECI)", 2));
t.Add(new Temperature("Auxiliary 3", 3)); // AUXTIN3
// Fans
f.Add(new Fan("MOS Fan", 1));
// Controls
c.Add(new Control("MOS Fan", 1));
break;
}
break;
case Chip.NCT6771F:
case Chip.NCT6776F:
GetNuvotonConfigurationF(superIO, manufacturer, model, v, t, f, c);
@@ -379,6 +412,7 @@ internal sealed class SuperIOHardware : Hardware
case Chip.NCT6795D:
case Chip.NCT6796D:
case Chip.NCT6796DR:
case Chip.NCT6796DS:
case Chip.NCT6797D:
case Chip.NCT6798D:
case Chip.NCT6799D:
@@ -3849,7 +3883,57 @@ internal sealed class SuperIOHardware : Hardware
c.Add(new Control("AIO Pump", 3)); // AIO_PUMP
c.Add(new Control("Chassis Fan #1", 0)); // CHA_FAN1
c.Add(new Control("Chassis Fan #2", 4)); // CHA_FAN2
break;
case Model.X870E_NOVA_WIFI: //NCT6796D-S
// Voltages: (VHIF and VIN10 are monitored in HWiNFO but not identified here yet)
v.Add(new Voltage("Vcore", 0)); // CPU Core Voltage
v.Add(new Voltage("+12V", 1, 56, 10)); // +12V
v.Add(new Voltage("Analog VCC", 2, 34, 34)); // AVCC
v.Add(new Voltage("+3.3V", 3, 34, 34)); // +3.3V
v.Add(new Voltage("+5V", 4, 20, 10)); // +5V
v.Add(new Voltage("+1.05 Standby", 5, 0, 1)); // +1.05V_ALW
v.Add(new Voltage("Voltage #4", 6, 0, 1)); // VIN4
v.Add(new Voltage("+3V Standby", 7, 34, 34)); // +3VSB
v.Add(new Voltage("CMOS Battery", 8, 34, 34)); // VBAT
v.Add(new Voltage("CPU Termination", 9, 1, 1)); // VTT
v.Add(new Voltage("SoC", 10, 1, 1)); // VDDCR_SOC
v.Add(new Voltage("Voltage #6", 11, 34, 34, 0)); // VIN6
v.Add(new Voltage("Voltage #2", 12)); // VIN2
v.Add(new Voltage("+1.8V", 13, 10, 10, 0)); // +1.8V
v.Add(new Voltage("Voltage #7", 14, 0, 1, 0)); // VIN7
v.Add(new Voltage("Voltage #9", 15)); // VIN9
// Temperatures
t.Add(new Temperature("CPU Socket", 0)); // CPUTIN
t.Add(new Temperature("Motherboard", 1)); // SYSTIN
t.Add(new Temperature("Auxiliary #0", 2)); // AUXTIN0
t.Add(new Temperature("Auxiliary #1", 3)); // AUXTIN1
t.Add(new Temperature("Thermistor Sensor #1", 4)); // AUXTIN2 (T_SENSOR1)
t.Add(new Temperature("Thermistor Sensor #2", 5)); // AUXTIN3 (T_SENSOR2)
t.Add(new Temperature("Auxiliary #4", 6)); // AUXTIN4
t.Add(new Temperature("Thermistor Sensor #3", 7)); // AUXTIN5 (T_SENSOR3)
t.Add(new Temperature("CPU Core", 8)); // SMBUSMASTER0 (CPU Core)
t.Add(new Temperature("CPU (PECI)", 9)); // CPU (PECI)
t.Add(new Temperature("Virtual", 10)); // VIRTUAL_TEMP
// Fans
f.Add(new Fan("Chassis Fan #1", 0)); // CHA_FAN1
f.Add(new Fan("CPU Fan #1", 1)); // CPU_FAN1
f.Add(new Fan("CPU Fan #2", 2)); // CPU_FAN2
f.Add(new Fan("AIO Pump", 3)); // AIO_PUMP
f.Add(new Fan("Water Pump", 4)); // W_PUMP
f.Add(new Fan("Chassis Fan #2", 5)); // CHA_FAN2
f.Add(new Fan("Chassis Fan #3", 6)); // CHA_FAN3
// Controls
c.Add(new Control("Chassis Fan #1", 0)); // CHA_FAN1
c.Add(new Control("CPU Fan #1", 1)); // CPU_FAN1
c.Add(new Control("CPU Fan #2", 2)); // CPU_FAN2
c.Add(new Control("AIO Pump", 3)); // AIO_PUMP
c.Add(new Control("Water Pump", 4)); // W_PUMP
c.Add(new Control("Chassis Fan #2", 5)); // CHA_FAN2
c.Add(new Control("Chassis Fan #3", 6)); // CHA_FAN3
break;
default:
@@ -4341,8 +4425,7 @@ internal sealed class SuperIOHardware : Hardware
v.Add(new Voltage("Voltage #15", 14));
t.Add(new Temperature("CPU Package", 0)); // Matches CPU Package in HWinfo & Armoury Crate.
t.Add(new Temperature("CPU (Weighted)",
1)); // Unsure about this one. HWinfo & Armoury Crate doesn't have anything that match my values. Varies from 34 (idle) to 42C (under load). Hwinfo is 31-32C for same.
t.Add(new Temperature("CPU (Weighted)", 1)); // Unsure about this one. HWinfo & Armoury Crate doesn't have anything that match my values. Varies from 34 (idle) to 42C (under load). Hwinfo is 31-32C for same.
t.Add(new Temperature("Motherboard", 2)); // Matches MB in HWinfo & Armoury Crate.
//t.Add(new Temperature("Temperature #4", 4)); // Constant at 15C
@@ -5341,7 +5424,7 @@ internal sealed class SuperIOHardware : Hardware
v.Add(new Voltage("+3.3V Standby", 7, 34, 34)); // 3VSB, +3.3V digital power
v.Add(new Voltage("CMOS Battery", 8, 34, 34, 0)); // VBAT
v.Add(new Voltage("CPU 1.8V", 9)); // VTT, CPU_1P8
v.Add(new Voltage("CPU VDDP", 10)); // VIN5
v.Add(new Voltage("CPU VDDP", 10)); // VIN5
v.Add(new Voltage("Voltage #6", 11, true)); // VIN6, temperature input
v.Add(new Voltage("CPU NB/SoC", 12)); // VIN2, VCCP_NB
v.Add(new Voltage("DIMM", 13, 1, 1)); // VIN3
@@ -5352,7 +5435,7 @@ internal sealed class SuperIOHardware : Hardware
t.Add(new Temperature("VRM MOS", 3)); // AUXTIN0, CPUMOSTIN, 10k at left side of cpu vrm
t.Add(new Temperature("Chipset", 5)); // AUXTIN2, 10k at back side of the chipset
t.Add(new Temperature("CPU", 23));
// Add temperature sensors for voltage inputs that are marked ad
// Add temperature sensors for voltage inputs that are marked ad
t.Add(new Temperature("MOS CPU", 24)); // (VIN 4 Voltage) NTC Near MOSFET CPU VRM
t.Add(new Temperature("PCH", 25)); // (Voltage #6) X570 Platform Control HUB TEMP (NTC On Bottom of PCB)
@@ -5676,7 +5759,44 @@ internal sealed class SuperIOHardware : Hardware
public override string GetReport()
{
return _superIO.GetReport();
StringBuilder sb = new();
sb.AppendLine(_superIO.GetReport());
sb.AppendLine();
sb.AppendLine("Temperature debug (SuperIO read):");
try
{
// If there are named sensors created, iterate them; otherwise use superIO.Temperatures
if (_temperatures != null && _temperatures.Count > 0)
{
foreach (Sensor s in _temperatures)
{
int idx = s.Index;
float? v = _readTemperature != null ? _readTemperature(idx) : null;
sb.Append(" Index ").Append(idx).Append(" \"").Append(s.Name).Append("\": ");
sb.AppendLine(v.HasValue ? v.Value.ToString("F2", CultureInfo.InvariantCulture) : "null");
}
}
else
{
// Fallback: dump raw superIO.Temperatures if available
var temps = (_superIO?.Temperatures);
if (temps != null)
{
for (int i = 0; i < temps.Length; i++)
{
sb.Append(" Raw Index ").Append(i).Append(": ");
sb.AppendLine(temps[i].HasValue ? temps[i].Value.ToString("F2", CultureInfo.InvariantCulture) : "null");
}
}
}
}
catch (Exception ex)
{
sb.AppendLine(" Exception while reading temperatures: " + ex.Message);
}
return sb.ToString();
}
public override void Update()
@@ -5711,7 +5831,7 @@ internal sealed class SuperIOHardware : Hardware
{
voltage = (float)_readVoltage(6);
}
else if (sensor.Index == 25)
else if (sensor.Index == 25)
{
voltage = (float)_readVoltage(11);
}