diff --git a/Docs/Configuration.tex b/Docs/Configuration.tex
index 750009b6..e4962dc2 100755
--- a/Docs/Configuration.tex
+++ b/Docs/Configuration.tex
@@ -656,6 +656,7 @@ Add \texttt{.clang\_complete} file with similar content to the UDK root:
-I/UefiPackages/OpenCorePkg/Include/Generic
-I/UefiPackages/OpenCorePkg/Include/Intel
-I/UefiPackages/OpenCorePkg/Include/Microsoft
+-I/UefiPackages/OpenCorePkg/Include/Nvidia
-I/UefiPackages/OpenCorePkg/Include/VMware
-I/UefiPackages/OvmfPkg/Include
-I/UefiPackages/UefiCpuPkg/Include
diff --git a/Include/Nvidia/IndustryStandard/MpcMemoryController.h b/Include/Nvidia/IndustryStandard/MpcMemoryController.h
new file mode 100644
index 00000000..f752c266
--- /dev/null
+++ b/Include/Nvidia/IndustryStandard/MpcMemoryController.h
@@ -0,0 +1,42 @@
+/** @file
+ Copyright (C) 2021, vit9696. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause
+**/
+
+#ifndef NVIDIA_MPC_MEMORY_CONTROLLER_H
+#define NVIDIA_MPC_MEMORY_CONTROLLER_H
+
+/**
+ I/O port to obtain current DDR frequency on NVIDIA nForce MPC89
+ and possibly others. Example value: 1066666664.
+**/
+#define R_NVIDIA_MPC89_DDR_PLL 0x580
+
+/**
+ MMIO base to NVIDIA nForce MPC79 and MPC89 memory controller.
+**/
+#define B_NVIDIA_MPC_MC_BASE 0xF001B000
+
+/**
+ Common PCI identifiers for nForce MPC79 and MPC89 memory controllers.
+**/
+#define V_NVIDIA_MPC_MC_VENDOR 0x10DE
+#define V_NVIDIA_MPC79_MC_DEVICE 0x0A89
+#define V_NVIDIA_MPC89_MC_DEVICE 0x0D69
+
+/**
+ MPC79 and MPC89 memory controller registers, not much is known.
+**/
+#define R_NVIDIA_MPC_MC_UN44 0x44
+#define R_NVIDIA_MPC_MC_MPCC 0x48
+#define R_NVIDIA_MPC_MC_UN78 0x78
+#define R_NVIDIA_MPC_MC_MPLM 0xC8
+#define R_NVIDIA_MPC_MC_MPLN 0xC9
+
+#define NVIDIA_MPC79_GET_FSB_FREQUENCY_DIVIDEND(Un44, Un78) \
+ (25000000ULL * (((Un44) >> 9U) & 0xFFU) * (((Un78) >> 8U) & 0xFFU))
+
+#define NVIDIA_MPC79_GET_FSB_FREQUENCY_DIVISOR(Un44, Un78) \
+ (((Un44) & 0xFFU) * ((Un78) & 0xFFU) * (1 << (((Un44) >> 26U) & 3U)))
+
+#endif // NVIDIA_MPC_MEMORY_CONTROLLER_H
diff --git a/Library/OcCpuLib/FrequencyDetect.c b/Library/OcCpuLib/FrequencyDetect.c
index 6ded4c88..26f57583 100644
--- a/Library/OcCpuLib/FrequencyDetect.c
+++ b/Library/OcCpuLib/FrequencyDetect.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -236,22 +237,21 @@ InternalSelectAppleFsbFrequency (
IN UINT32 FsbFrequncyCount
)
{
- UINT32 Freq;
+ UINT32 Pll;
if (FsbFrequncyCount < 5) {
return 0 /* Invalid */;
}
//
- // This one is for nForce MCP89 installed in MacBook7,1.
- // Not sure what it reads from.
+ // Tested on nForce MCP89 installed in MacBook7,1.
//
- Freq = IoRead32 (0x580);
+ Pll = IoRead32 (R_NVIDIA_MPC89_DDR_PLL);
DEBUG ((
DEBUG_INFO,
- "OCCPU: Selecting freq by %u from %Lu %Lu %Lu %Lu %Lu\n",
- Freq,
+ "OCCPU: Selecting FSB freq by PLL freq %u from %Lu %Lu %Lu %Lu %Lu\n",
+ Pll,
FsbFrequency[0],
FsbFrequency[1],
FsbFrequency[2],
@@ -259,24 +259,24 @@ InternalSelectAppleFsbFrequency (
FsbFrequency[4]
));
- Freq /= 1000000;
+ Pll /= 1000000;
- if (Freq == 16) {
+ if (Pll == 16) {
return FsbFrequency[0];
}
- if (Freq >= 1063 && Freq <= 1069) {
+ if (Pll >= 1063 && Pll <= 1069) {
return FsbFrequency[0];
}
- if (Freq >= 530 && Freq <= 536) {
+ if (Pll >= 530 && Pll <= 536) {
return FsbFrequency[1];
}
- if (Freq >= 797 && Freq <= 803) {
+ if (Pll >= 797 && Pll <= 803) {
return FsbFrequency[2];
}
- if (Freq >= 663 && Freq <= 669) {
+ if (Pll >= 663 && Pll <= 669) {
return FsbFrequency[3];
}
- if (Freq >= 1330 && Freq <= 1336) {
+ if (Pll >= 1330 && Pll <= 1336) {
return FsbFrequency[4];
}
return 0 /* Invalid */;
@@ -299,6 +299,10 @@ InternalCalculateTSCFromApplePlatformInfo (
APPLE_PLATFORM_INFO_DATABASE_PROTOCOL *PlatformInfo;
UINT32 Size;
UINT64 *FsbFreqs;
+ UINT32 Un44;
+ UINT32 Un78;
+ UINT64 Dividend;
+ UINT32 Divisor;
if (Recalculate) {
ObtainedFreqs = FALSE;
@@ -315,26 +319,25 @@ InternalCalculateTSCFromApplePlatformInfo (
NULL,
(VOID **) &PlatformInfo
);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_VERBOSE, "OCCPU: Failed to locate ApplePlatformInfo protocol - %r\n", Status));
- return 0;
- }
-
- Status = OcReadApplePlatformFirstData (
- PlatformInfo,
- &gAppleFsbFrequencyPlatformInfoGuid,
- &Size,
- &FsbFreq
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency first data - %r, trying HOB method\n", Status));
- Status = OcReadApplePlatformData (
+ if (!EFI_ERROR (Status)) {
+ Status = OcReadApplePlatformFirstData (
PlatformInfo,
&gAppleFsbFrequencyPlatformInfoGuid,
- &gAppleFsbFrequencyPlatformInfoIndexHobGuid,
&Size,
&FsbFreq
);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency first data - %r, trying HOB method\n", Status));
+ Status = OcReadApplePlatformData (
+ PlatformInfo,
+ &gAppleFsbFrequencyPlatformInfoGuid,
+ &gAppleFsbFrequencyPlatformInfoIndexHobGuid,
+ &Size,
+ &FsbFreq
+ );
+ }
+
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency data using HOB method - %r, trying legacy\n", Status));
Status = OcReadApplePlatformFirstDataAlloc (
@@ -343,21 +346,56 @@ InternalCalculateTSCFromApplePlatformInfo (
&Size,
(VOID **) &FsbFreqs
);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency data using legacy method - %r\n", Status));
- return 0;
- }
+ if (!EFI_ERROR (Status)) {
+ if (Size >= sizeof (UINT64) && Size % sizeof (UINT64) == 0) {
+ FsbFreq = InternalSelectAppleFsbFrequency (FsbFreqs, Size / sizeof (UINT64));
+ } else {
+ DEBUG ((DEBUG_INFO, "OCCPU: Invalid FSBFrequency list size %u - %r\n", Size, Status));
+ Status = EFI_INVALID_PARAMETER;
+ }
- if (Size < sizeof (UINT64) || Size % sizeof (UINT64) != 0) {
- DEBUG ((DEBUG_INFO, "OCCPU: Invalid FSBFrequency list size %u - %r\n", Size, Status));
FreePool (FsbFreqs);
- return 0;
}
-
- FsbFreq = InternalSelectAppleFsbFrequency (FsbFreqs, Size / sizeof (UINT64));
-
- FreePool (FsbFreqs);
}
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "OCCPU: Failed to locate ApplePlatformInfo protocol - %r\n", Status));
+ }
+
+ //
+ // This is not necessarily Apple, but keep it here for the time being.
+ // Should work on more or less any MPC79 device.
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency data using Apple Platform Info - %r\n", Status));
+
+ if (MmioRead16 (B_NVIDIA_MPC_MC_BASE) == V_NVIDIA_MPC_MC_VENDOR) {
+ Un44 = MmioRead32 (B_NVIDIA_MPC_MC_BASE + R_NVIDIA_MPC_MC_UN44);
+ Un78 = MmioRead32 (B_NVIDIA_MPC_MC_BASE + R_NVIDIA_MPC_MC_UN78);
+
+ Dividend = NVIDIA_MPC79_GET_FSB_FREQUENCY_DIVIDEND (Un44, Un78);
+ Divisor = NVIDIA_MPC79_GET_FSB_FREQUENCY_DIVISOR (Un44, Un78);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "OCCPU: Found nForce MPC MC 0x%08X (UN44 0x%08X, UN78 0x%08X, DVD 0x%016Lx, DIV 0x%08X)\n",
+ MmioRead32 (B_NVIDIA_MPC_MC_BASE),
+ Un44,
+ Un78,
+ Dividend,
+ Divisor
+ ));
+
+ if (Divisor != 0) {
+ FsbFreq = DivU64x32 (Dividend, Divisor);
+ if (FsbFreq != 0) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return 0;
}
TscFreq = InternalConvertAppleFSBToTSCFrequency (FsbFreq);
diff --git a/OpenCorePkg.dec b/OpenCorePkg.dec
index a7c36ed8..c308ab94 100755
--- a/OpenCorePkg.dec
+++ b/OpenCorePkg.dec
@@ -26,6 +26,7 @@
Include/Generic
Include/Intel
Include/Microsoft
+ Include/Nvidia
Include/VMware
[Includes.AArch64]
@@ -35,6 +36,7 @@
# Include/Generic/AArch64
# Include/Intel/AArch64
# Include/Microsoft/AArch64
+ # Include/Nvidia/AArch64
# Include/VMware/AArch64
[Includes.Arm]
@@ -44,6 +46,7 @@
# Include/Generic/Arm
# Include/Intel/Arm
# Include/Microsoft/Arm
+ # Include/Nvidia/Arm
# Include/VMware/Arm
[Includes.Ebc]
@@ -53,6 +56,7 @@
# Include/Generic/Ebc
# Include/Intel/Ebc
# Include/Microsoft/Ebc
+ # Include/Nvidia/Ebc
# Include/VMware/Ebc
[Includes.Ia32]
@@ -62,6 +66,7 @@
# Include/Generic/Ia32
# Include/Intel/Ia32
# Include/Microsoft/Ia32
+ # Include/Nvidia/Ia32
# Include/VMware/Ia32
[Includes.X64]
@@ -71,6 +76,7 @@
# Include/Generic/X64
# Include/Intel/X64
# Include/Microsoft/X64
+ # Include/Nvidia/X64
# Include/VMware/X64
[Guids]