mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2025-02-25 18:55:23 -06:00
Add Memory Controller Registers polling to get current DRAM Timings/Frequency (#306)
Read the memory controller configuration (instead of just relying on SPD data) to get the actual live settings. Currently supported platforms: * Intel SNB to RPL (Core 2nd Gen to Core 13th Gen) - Desktop only (no Server nor Mobile) * AMD SMR to RPL (Zen to Zen4) - Desktop only (no Server, Mobile nor APU). Individual commits below for archival: * First functions skeleton for reading IMC/ECC Registers * Change directory name from 'chipsets' to 'mch' (Memory Controller Hub) * Add Intel HSW and fix new files encoding * First Intel HSW IMC implementation * Add an option to disable MCH registers polling * Remove old include from Makefiles * Better Makefile and padding fixes * Statically init 'imc' struct to generate string relocation record * Small typos & code fixes * Add IMC support for Intel Core 6/7/8/9th Gen (SKL/KBL/CFL/CML) This is a bit more complex than Haswell and below because MMIO switched to 64-bit with Skylake (lot of) betatesting needed * Add IMC read support for Intel SNB/IVB (2nd/3rd gen Core) * Fix hard-lock on Intel SNB/IVB due to wrong access type on MCHBAR pointer * Move AMD SMN Registers & offsets to a specific header file * Add IMC Read support for AMD Zen/Zen2 CPUs * Change 'IMC' to 'MCH' in Makefiles to match actual mch/ directory * Add IMC Reading support for Intel ADL&RPL CPUs (Core Gen12&13) * Add support for Intel Rocket Lake (Core 11th Gen) and AMD Vermeer * Add IMC reading for AMD Zen4 'Raphael' AM5 CPUs * Various Cleanup #1 Change terminology from Intel-based 'MCH' (Memory Controller Hub) to more universal 'IMC' (Integrated Memory Controller) Integrate imc_type var into imc struct. Remove previously created AMD SNM header file * Various Cleanup 2 * Change DDR5 display format for IMC specs DDR5 Freq can be > 10000 and timings up to 63-127-127-127, which overwflow the available space. This commit remove the raw frequency on DDR5 (which may be incorrect due to Gear mechanism) and leave a bit of space to display the Gear engaged in the future
This commit is contained in:
parent
5dcd424ea7
commit
7aeac7271f
@ -133,6 +133,8 @@ recognised:
|
||||
* disables the big PASS/FAIL pop-up status display
|
||||
* nosm
|
||||
* disables SMBUS/SPD parsing, DMI decoding and memory benchmark
|
||||
* nomch
|
||||
* disables memory controller configuration polling
|
||||
* nopause
|
||||
* skips the pause for configuration at startup
|
||||
* keyboard=*type*
|
||||
|
@ -97,6 +97,7 @@ bool enable_trace = false;
|
||||
|
||||
bool enable_sm = true;
|
||||
bool enable_bench = true;
|
||||
bool enable_mch_read = true;
|
||||
|
||||
bool pause_at_start = true;
|
||||
|
||||
@ -209,6 +210,8 @@ static void parse_option(const char *option, const char *params)
|
||||
enable_big_status = false;
|
||||
} else if (strncmp(option, "noehci", 7) == 0) {
|
||||
usb_init_options |= USB_IGNORE_EHCI;
|
||||
} else if (strncmp(option, "nomch", 6) == 0) {
|
||||
enable_mch_read = false;
|
||||
} else if (strncmp(option, "nopause", 8) == 0) {
|
||||
pause_at_start = false;
|
||||
} else if (strncmp(option, "nosm", 5) == 0) {
|
||||
|
@ -58,6 +58,7 @@ extern bool enable_trace;
|
||||
extern bool enable_sm;
|
||||
extern bool enable_tty;
|
||||
extern bool enable_bench;
|
||||
extern bool enable_mch_read;
|
||||
|
||||
extern bool pause_at_start;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "hwctrl.h"
|
||||
#include "io.h"
|
||||
#include "keyboard.h"
|
||||
#include "memctrl.h"
|
||||
#include "serial.h"
|
||||
#include "pmem.h"
|
||||
#include "smbios.h"
|
||||
@ -262,10 +263,14 @@ void post_display_init(void)
|
||||
print_smbios_startup_info();
|
||||
print_smbus_startup_info();
|
||||
|
||||
if (false) {
|
||||
// Try to get RAM information from IMC (TODO)
|
||||
if (imc.freq) {
|
||||
// Try to get RAM information from IMC
|
||||
display_spec_mode("IMC: ");
|
||||
display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tCL_dec, ram.tRCD, ram.tRP, ram.tRAS);
|
||||
if (imc.type[3] == '5') {
|
||||
display_spec_ddr5(imc.freq, imc.type, imc.tCL, imc.tCL_dec, imc.tRCD, imc.tRP, imc.tRAS);
|
||||
} else {
|
||||
display_spec_ddr(imc.freq, imc.type, imc.tCL, imc.tCL_dec, imc.tRCD, imc.tRP, imc.tRAS);
|
||||
}
|
||||
display_mode = DISPLAY_MODE_IMC;
|
||||
} else if (ram.freq > 0 && ram.tCL > 0) {
|
||||
// If not available, grab max memory specs from SPD
|
||||
|
@ -102,6 +102,10 @@ typedef enum {
|
||||
#define display_spec_mode(mode) \
|
||||
prints(8,0, mode);
|
||||
|
||||
#define display_spec_ddr5(freq, type, cl, cl_dec, rcd, rp, ras) \
|
||||
printf(8,5, "%s-%u / CAS %u%s-%u-%u-%u", \
|
||||
type, freq, cl, cl_dec?".5":"", rcd, rp, ras);
|
||||
|
||||
#define display_spec_ddr(freq, type, cl, cl_dec, rcd, rp, ras) \
|
||||
printf(8,5, "%uMHz (%s-%u) CAS %u%s-%u-%u-%u", \
|
||||
freq / 2, type, freq, cl, cl_dec?".5":"", rcd, rp, ras);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "io.h"
|
||||
#include "keyboard.h"
|
||||
#include "pmem.h"
|
||||
#include "memctrl.h"
|
||||
#include "memsize.h"
|
||||
#include "pci.h"
|
||||
#include "screen.h"
|
||||
@ -235,6 +236,8 @@ static void global_init(void)
|
||||
|
||||
config_init();
|
||||
|
||||
memctrl_init();
|
||||
|
||||
tty_init();
|
||||
|
||||
smp_init(smp_enabled);
|
||||
|
@ -25,6 +25,7 @@ SYS_OBJS = system/acpi.o \
|
||||
system/hwquirks.o \
|
||||
system/keyboard.o \
|
||||
system/ohci.o \
|
||||
system/memctrl.o \
|
||||
system/pci.o \
|
||||
system/pmem.o \
|
||||
system/reloc.o \
|
||||
@ -40,6 +41,9 @@ SYS_OBJS = system/acpi.o \
|
||||
system/vmem.o \
|
||||
system/xhci.o
|
||||
|
||||
IMC_SRCS = $(wildcard ../system/imc/*.c)
|
||||
IMC_OBJS = $(subst ../,,$(IMC_SRCS:.c=.o))
|
||||
|
||||
LIB_OBJS = lib/barrier.o \
|
||||
lib/div64.o \
|
||||
lib/print.o \
|
||||
@ -65,12 +69,13 @@ APP_OBJS = app/badram.o \
|
||||
app/interrupt.o \
|
||||
app/main.o
|
||||
|
||||
OBJS = boot/startup.o boot/efisetup.o $(SYS_OBJS) $(LIB_OBJS) $(TST_OBJS) $(APP_OBJS)
|
||||
OBJS = boot/startup.o boot/efisetup.o $(SYS_OBJS) $(IMC_OBJS) $(LIB_OBJS) $(TST_OBJS) $(APP_OBJS)
|
||||
|
||||
all: memtest.bin memtest.efi
|
||||
|
||||
-include boot/efisetup.d
|
||||
-include $(subst .o,.d,$(SYS_OBJS))
|
||||
-include $(subst .o,.d,$(IMC_OBJS))
|
||||
-include $(subst .o,.d,$(LIB_OBJS))
|
||||
-include $(subst .o,.d,$(TST_OBJS))
|
||||
-include $(subst .o,.d,$(APP_OBJS))
|
||||
@ -97,6 +102,10 @@ system/%.o: ../system/%.c
|
||||
@mkdir -p system
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
system/imc/%.o: ../system/imc/%.c
|
||||
@mkdir -p system/imc
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
lib/%.o: ../lib/%.c
|
||||
@mkdir -p lib
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
@ -25,6 +25,7 @@ SYS_OBJS = system/acpi.o \
|
||||
system/hwquirks.o \
|
||||
system/keyboard.o \
|
||||
system/ohci.o \
|
||||
system/memctrl.o \
|
||||
system/pci.o \
|
||||
system/pmem.o \
|
||||
system/reloc.o \
|
||||
@ -40,6 +41,9 @@ SYS_OBJS = system/acpi.o \
|
||||
system/vmem.o \
|
||||
system/xhci.o
|
||||
|
||||
IMC_SRCS = $(wildcard ../system/imc/*.c)
|
||||
IMC_OBJS = $(subst ../,,$(IMC_SRCS:.c=.o))
|
||||
|
||||
LIB_OBJS = lib/barrier.o \
|
||||
lib/print.o \
|
||||
lib/read.o \
|
||||
@ -64,12 +68,13 @@ APP_OBJS = app/badram.o \
|
||||
app/interrupt.o \
|
||||
app/main.o
|
||||
|
||||
OBJS = boot/startup.o boot/efisetup.o $(SYS_OBJS) $(LIB_OBJS) $(TST_OBJS) $(APP_OBJS)
|
||||
OBJS = boot/startup.o boot/efisetup.o $(SYS_OBJS) $(IMC_OBJS) $(LIB_OBJS) $(TST_OBJS) $(APP_OBJS)
|
||||
|
||||
all: memtest.bin memtest.efi
|
||||
|
||||
-include boot/efisetup.d
|
||||
-include $(subst .o,.d,$(SYS_OBJS))
|
||||
-include $(subst .o,.d,$(IMC_OBJS))
|
||||
-include $(subst .o,.d,$(LIB_OBJS))
|
||||
-include $(subst .o,.d,$(TST_OBJS))
|
||||
-include $(subst .o,.d,$(APP_OBJS))
|
||||
@ -96,6 +101,10 @@ system/%.o: ../system/%.c
|
||||
@mkdir -p system
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
system/imc/%.o: ../system/imc/%.c
|
||||
@mkdir -p system/imc
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
lib/%.o: ../lib/%.c
|
||||
@mkdir -p lib
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
104
system/cpuinfo.c
104
system/cpuinfo.c
@ -1,11 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// Derived from an extract of memtest86+ init.c:
|
||||
//
|
||||
// MemTest86+ V5 Specific code (GPL V2.0)
|
||||
// By Samuel DEMEULEMEESTER, sdemeule@memtest.org
|
||||
// http://www.canardpc.com - http://www.memtest.org
|
||||
// ------------------------------------------------
|
||||
// init.c - MemTest-86 Version 3.6
|
||||
//
|
||||
@ -24,6 +23,7 @@
|
||||
#include "config.h"
|
||||
#include "pmem.h"
|
||||
#include "vmem.h"
|
||||
#include "memctrl.h"
|
||||
#include "memsize.h"
|
||||
#include "hwquirks.h"
|
||||
|
||||
@ -41,8 +41,6 @@
|
||||
|
||||
const char *cpu_model = NULL;
|
||||
|
||||
uint16_t imc_type = 0;
|
||||
|
||||
int l1_cache = 0;
|
||||
int l2_cache = 0;
|
||||
int l3_cache = 0;
|
||||
@ -304,37 +302,37 @@ static void determine_imc(void)
|
||||
switch (cpuid_info.version.extendedFamily)
|
||||
{
|
||||
case 0x0:
|
||||
imc_type = IMC_K8; // Old K8
|
||||
imc.family = IMC_K8; // Old K8
|
||||
break;
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
imc_type = IMC_K10; // K10 (Family 10h & 11h)
|
||||
imc.family = IMC_K10; // K10 (Family 10h & 11h)
|
||||
break;
|
||||
case 0x3:
|
||||
imc_type = IMC_K12; // A-Series APU (Family 12h)
|
||||
imc.family = IMC_K12; // A-Series APU (Family 12h)
|
||||
break;
|
||||
case 0x5:
|
||||
imc_type = IMC_K14; // C- / E- / Z- Series APU (Family 14h)
|
||||
imc.family = IMC_K14; // C- / E- / Z- Series APU (Family 14h)
|
||||
break;
|
||||
case 0x6:
|
||||
imc_type = IMC_K15; // FX Series (Family 15h)
|
||||
imc.family = IMC_K15; // FX Series (Family 15h)
|
||||
break;
|
||||
case 0x7:
|
||||
imc_type = IMC_K16; // Kabini & related (Family 16h)
|
||||
imc.family = IMC_K16; // Kabini & related (Family 16h)
|
||||
break;
|
||||
case 0x8:
|
||||
imc_type = IMC_K17; // Zen & Zen2 (Family 17h)
|
||||
imc.family = IMC_K17; // Zen & Zen2 (Family 17h)
|
||||
break;
|
||||
case 0x9:
|
||||
imc_type = IMC_K18; // Hygon (Family 18h)
|
||||
imc.family = IMC_K18; // Hygon (Family 18h)
|
||||
break;
|
||||
case 0xA:
|
||||
if (cpuid_info.version.extendedModel == 5) {
|
||||
imc_type = IMC_K19_CZN; // AMD Cezanne APU (Model 0x50-5F - Family 19h)
|
||||
imc.family = IMC_K19_CZN; // AMD Cezanne APU (Model 0x50-5F - Family 19h)
|
||||
} else if (cpuid_info.version.extendedModel >= 6) {
|
||||
imc_type = IMC_K19_RPL; // Zen4 (Family 19h)
|
||||
imc.family = IMC_K19_RPL; // Zen4 (Family 19h - Raphael AM5)
|
||||
} else {
|
||||
imc_type = IMC_K19; // Zen3 (Family 19h)
|
||||
imc.family = IMC_K19_VRM; // Zen3 (Family 19h - Vermeer AM4)
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@ -349,16 +347,16 @@ static void determine_imc(void)
|
||||
case 0x5:
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 2:
|
||||
imc_type = IMC_NHM; // Core i3/i5 1st Gen 45 nm (Nehalem/Bloomfield)
|
||||
imc.family = IMC_NHM; // Core i3/i5 1st Gen 45 nm (Nehalem/Bloomfield)
|
||||
break;
|
||||
case 3:
|
||||
no_temperature = true; // Atom Clover Trail
|
||||
no_temperature = true; // Atom Clover Trail
|
||||
break;
|
||||
case 4:
|
||||
imc_type = IMC_HSW_ULT; // Core 4th Gen (Haswell-ULT)
|
||||
imc.family = IMC_HSW_ULT; // Core 4th Gen (Haswell-ULT)
|
||||
break;
|
||||
case 5:
|
||||
imc_type = IMC_SKL_SP; // Skylake/Cascade Lake/Cooper Lake (Server)
|
||||
imc.family = IMC_SKL_SP; // Skylake/Cascade Lake/Cooper Lake (Server)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -368,17 +366,17 @@ static void determine_imc(void)
|
||||
case 0x6:
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 3:
|
||||
imc_type = IMC_CDT; // Atom Cedar Trail
|
||||
imc.family = IMC_CDT; // Atom Cedar Trail
|
||||
no_temperature = true;
|
||||
break;
|
||||
case 4:
|
||||
imc_type = IMC_HSW; // Core 4th Gen (Haswell w/ GT3e)
|
||||
imc.family = IMC_HSW; // Core 4th Gen (Haswell w/ GT3e)
|
||||
break;
|
||||
case 5:
|
||||
imc_type = IMC_BDW_DE; // Broadwell-DE (Server)
|
||||
imc.family = IMC_BDW_DE; // Broadwell-DE (Server)
|
||||
break;
|
||||
case 6:
|
||||
imc_type = IMC_CNL; // Cannon Lake
|
||||
imc.family = IMC_CNL; // Cannon Lake
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -388,19 +386,19 @@ static void determine_imc(void)
|
||||
case 0x7:
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 0x3:
|
||||
imc_type = IMC_BYT; // Atom Bay Trail
|
||||
imc.family = IMC_BYT; // Atom Bay Trail
|
||||
break;
|
||||
case 0x4:
|
||||
imc_type = IMC_BDW; // Core 5th Gen (Broadwell)
|
||||
imc.family = IMC_BDW; // Core 5th Gen (Broadwell)
|
||||
break;
|
||||
case 0x9:
|
||||
imc_type = IMC_ADL; // Core 12th Gen (Alder Lake-P)
|
||||
imc.family = IMC_ADL; // Core 12th Gen (Alder Lake-P)
|
||||
break;
|
||||
case 0xA:
|
||||
imc_type = IMC_RKL; // Core 11th Gen (Rocket Lake)
|
||||
imc.family = IMC_RKL; // Core 11th Gen (Rocket Lake)
|
||||
break;
|
||||
case 0xB:
|
||||
imc_type = IMC_RPL; // Core 13th Gen (Raptor Lake)
|
||||
imc.family = IMC_RPL; // Core 13th Gen (Raptor Lake)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -410,19 +408,19 @@ static void determine_imc(void)
|
||||
case 0xA:
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 0x1:
|
||||
imc_type = IMC_NHM_E; // Core i7 1st Gen 45 nm (NHME)
|
||||
imc.family = IMC_NHM_E; // Core i7 1st Gen 45 nm (NHME)
|
||||
break;
|
||||
case 0x2:
|
||||
imc_type = IMC_SNB; // Core 2nd Gen (Sandy Bridge)
|
||||
imc.family = IMC_SNB; // Core 2nd Gen (Sandy Bridge)
|
||||
break;
|
||||
case 0x3:
|
||||
imc_type = IMC_IVB; // Core 3rd Gen (Ivy Bridge)
|
||||
imc.family = IMC_IVB; // Core 3rd Gen (Ivy Bridge)
|
||||
break;
|
||||
case 0x6:
|
||||
imc_type = IMC_ICL_SP; // Ice Lake-SP/DE (Server)
|
||||
imc.family = IMC_ICL_SP; // Ice Lake-SP/DE (Server)
|
||||
break;
|
||||
case 0x9:
|
||||
imc_type = IMC_ADL; // Core 12th Gen (Alder Lake-S)
|
||||
imc.family = IMC_ADL; // Core 12th Gen (Alder Lake-S)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -433,18 +431,18 @@ static void determine_imc(void)
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 0x1:
|
||||
if (cpuid_info.version.stepping > 9) {
|
||||
imc_type = 0x0008; // Atom PineView
|
||||
imc.family = 0x0008; // Atom PineView
|
||||
}
|
||||
no_temperature = true;
|
||||
break;
|
||||
case 0x2:
|
||||
imc_type = IMC_WMR; // Core i7 1st Gen 32 nm (Westmere)
|
||||
imc.family = IMC_WMR; // Core i7 1st Gen 32 nm (Westmere)
|
||||
break;
|
||||
case 0x3:
|
||||
imc_type = IMC_HSW; // Core 4th Gen (Haswell)
|
||||
imc.family = IMC_HSW; // Core 4th Gen (Haswell)
|
||||
break;
|
||||
case 0x8:
|
||||
imc_type = IMC_TGL; // Core 11th Gen (Tiger Lake-U)
|
||||
imc.family = IMC_TGL; // Core 11th Gen (Tiger Lake-U)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -454,13 +452,13 @@ static void determine_imc(void)
|
||||
case 0xD:
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 0x2:
|
||||
imc_type = IMC_SNB_E; // Core 2nd Gen (Sandy Bridge-E)
|
||||
imc.family = IMC_SNB_E; // Core 2nd Gen (Sandy Bridge-E)
|
||||
break;
|
||||
case 0x7:
|
||||
imc_type = IMC_ICL; // Core 10th Gen (IceLake-Y)
|
||||
imc.family = IMC_ICL; // Core 10th Gen (IceLake-Y)
|
||||
break;
|
||||
case 0x8:
|
||||
imc_type = IMC_TGL; // Core 11th Gen (Tiger Lake-Y)
|
||||
imc.family = IMC_TGL; // Core 11th Gen (Tiger Lake-Y)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -470,31 +468,31 @@ static void determine_imc(void)
|
||||
case 0xE:
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 0x1:
|
||||
imc_type = IMC_NHM; // Core i7 1st Gen 45 nm (Nehalem/Bloomfield)
|
||||
imc.family = IMC_NHM; // Core i7 1st Gen 45 nm (Nehalem/Bloomfield)
|
||||
break;
|
||||
case 0x2:
|
||||
imc_type = IMC_SNB_E; // Core 2nd Gen (Sandy Bridge-E)
|
||||
imc.family = IMC_SNB_E; // Core 2nd Gen (Sandy Bridge-E)
|
||||
break;
|
||||
case 0x3:
|
||||
imc_type = IMC_IVB_E; // Core 3rd Gen (Ivy Bridge-E)
|
||||
imc.family = IMC_IVB_E; // Core 3rd Gen (Ivy Bridge-E)
|
||||
break;
|
||||
case 0x4:
|
||||
imc_type = IMC_SKL_UY; // Core 6th Gen (Sky Lake-U/Y)
|
||||
imc.family = IMC_SKL_UY; // Core 6th Gen (Sky Lake-U/Y)
|
||||
break;
|
||||
case 0x5:
|
||||
imc_type = IMC_SKL; // Core 6th Gen (Sky Lake-S/H/E)
|
||||
imc.family = IMC_SKL; // Core 6th Gen (Sky Lake-S/H/E)
|
||||
break;
|
||||
case 0x7:
|
||||
imc_type = IMC_ICL; // Core 10th Gen (IceLake-U)
|
||||
imc.family = IMC_ICL; // Core 10th Gen (IceLake-U)
|
||||
break;
|
||||
case 0x8:
|
||||
imc_type = IMC_KBL_UY; // Core 7/8/9th Gen (Kaby/Coffee/Comet/Amber Lake-U/Y)
|
||||
imc.family = IMC_KBL_UY; // Core 7/8/9th Gen (Kaby/Coffee/Comet/Amber Lake-U/Y)
|
||||
break;
|
||||
case 0x9:
|
||||
imc_type = IMC_KBL; // Core 7/8/9th Gen (Kaby/Coffee/Comet Lake)
|
||||
imc.family = IMC_KBL; // Core 7/8/9th Gen (Kaby/Coffee/Comet Lake)
|
||||
break;
|
||||
case 0xB:
|
||||
imc_type = IMC_ADL_N; // Core 12th Gen (Alder Lake-N - Gracemont E-Cores only)
|
||||
imc.family = IMC_ADL_N; // Core 12th Gen (Alder Lake-N - Gracemont E-Cores only)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -504,13 +502,13 @@ static void determine_imc(void)
|
||||
case 0xF:
|
||||
switch (cpuid_info.version.extendedModel) {
|
||||
case 0x3:
|
||||
imc_type = IMC_HSW_E; // Core 3rd Gen (Haswell-E)
|
||||
imc.family = IMC_HSW_E; // Core 3rd Gen (Haswell-E)
|
||||
break;
|
||||
case 0x4:
|
||||
imc_type = IMC_BDW_E; // Broadwell-E (Server)
|
||||
imc.family = IMC_BDW_E; // Broadwell-E (Server)
|
||||
break;
|
||||
case 0x8:
|
||||
imc_type = IMC_SPR; // Sapphire Rapids (Server)
|
||||
imc.family = IMC_SPR; // Sapphire Rapids (Server)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -813,7 +811,7 @@ static void determine_cpu_model(void)
|
||||
// All VIA/Centaur family values >= 6 have brand string
|
||||
break;
|
||||
}
|
||||
} else { /* CyrixInstead */
|
||||
} else { // CyrixInstead
|
||||
switch (cpuid_info.version.family) {
|
||||
case 4:
|
||||
switch (cpuid_info.version.model) {
|
||||
|
@ -60,20 +60,16 @@
|
||||
#define IMC_K16 0x8050 // Kabini & related (Family 16h)
|
||||
#define IMC_K17 0x8060 // Zen & Zen2 (Family 17h)
|
||||
#define IMC_K18 0x8070 // Hygon (Family 18h)
|
||||
#define IMC_K19 0x8080 // Zen3 (Family 19h)
|
||||
#define IMC_K19_VRM 0x8080 // Zen3 (Family 19h - Vermeer)
|
||||
#define IMC_K19_CZN 0x8081 // Cezanne APU
|
||||
#define IMC_K19_RPL 0x8091 // Zen4 (Family 19h)
|
||||
|
||||
#define IMC_K19_RPL 0x8100 // Zen4 (Family 19h - Raphael (AM5))
|
||||
|
||||
/**
|
||||
* A string identifying the CPU make and model.
|
||||
*/
|
||||
extern const char *cpu_model;
|
||||
|
||||
/**
|
||||
* A number identifying the integrated memory controller type.
|
||||
*/
|
||||
extern uint16_t imc_type;
|
||||
|
||||
/**
|
||||
* The size of the L1 cache in KB.
|
||||
*/
|
||||
|
71
system/imc/amd_zen.c
Normal file
71
system/imc/amd_zen.c
Normal file
@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
//
|
||||
// Platform-specific code for AMD Zen CPUs
|
||||
//
|
||||
|
||||
#include "cpuinfo.h"
|
||||
#include "memctrl.h"
|
||||
#include "msr.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "imc.h"
|
||||
|
||||
#define AMD_SMN_UMC_BAR 0x050000
|
||||
#define AMD_SMN_UMC_CHB_OFFSET 0x100000
|
||||
#define AMD_SMN_UMC_DRAM_CONFIG AMD_SMN_UMC_BAR + 0x200
|
||||
#define AMD_SMN_UMC_DRAM_TIMINGS1 AMD_SMN_UMC_BAR + 0x204
|
||||
#define AMD_SMN_UMC_DRAM_TIMINGS2 AMD_SMN_UMC_BAR + 0x208
|
||||
|
||||
void get_imc_config_amd_zen(void)
|
||||
{
|
||||
uint32_t smn_reg, offset;
|
||||
uint32_t reg_cha, reg_chb;
|
||||
|
||||
imc.tCL_dec = 0;
|
||||
|
||||
// Get Memory Mapped Register Base Address (Enable MMIO if needed)
|
||||
reg_cha = amd_smn_read(AMD_SMN_UMC_DRAM_CONFIG) & 0x7F;
|
||||
reg_chb = amd_smn_read(AMD_SMN_UMC_DRAM_CONFIG + AMD_SMN_UMC_CHB_OFFSET) & 0x7F;
|
||||
|
||||
offset = reg_cha ? 0x0 : AMD_SMN_UMC_CHB_OFFSET;
|
||||
|
||||
// Populate IMC width
|
||||
imc.width = (reg_cha && reg_chb) ? 128 : 64;
|
||||
|
||||
// Get DRAM Frequency
|
||||
smn_reg = amd_smn_read(AMD_SMN_UMC_DRAM_CONFIG + offset);
|
||||
if (imc.family >= IMC_K19_RPL) {
|
||||
imc.type = "DDR5";
|
||||
imc.freq = smn_reg & 0xFFFF;
|
||||
if ((smn_reg >> 18) & 1) imc.freq *= 2; // GearDown
|
||||
} else {
|
||||
imc.type = "DDR4";
|
||||
smn_reg = amd_smn_read(AMD_SMN_UMC_DRAM_CONFIG + offset) & 0x7F;
|
||||
imc.freq = (float)smn_reg * 66.67f;
|
||||
}
|
||||
|
||||
if (imc.freq < 200 || imc.freq > 12000) {
|
||||
imc.freq = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Timings
|
||||
smn_reg = amd_smn_read(AMD_SMN_UMC_DRAM_TIMINGS1 + offset);
|
||||
|
||||
// CAS Latency (tCAS)
|
||||
imc.tCL = smn_reg & 0x3F;
|
||||
|
||||
// RAS Active to precharge (tRAS)
|
||||
imc.tRAS = (smn_reg >> 8) & 0x7F;
|
||||
|
||||
// RAS-To-CAS (tRC)
|
||||
imc.tRCD = (smn_reg >> 16) & 0x3F;
|
||||
|
||||
smn_reg = amd_smn_read(AMD_SMN_UMC_DRAM_TIMINGS2 + offset);
|
||||
|
||||
// RAS Precharge (tRP)
|
||||
imc.tRP = (smn_reg >> 16) & 0x3F;
|
||||
}
|
24
system/imc/imc.h
Normal file
24
system/imc/imc.h
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
#ifndef _IMC_H_
|
||||
#define _IMC_H_
|
||||
|
||||
/* Memory configuration Detection for AMD Zen CPUs */
|
||||
void get_imc_config_amd_zen(void);
|
||||
|
||||
/* Memory configuration Detection for Intel Sandy Bridge */
|
||||
void get_imc_config_intel_snb(void);
|
||||
|
||||
/* Memory configuration Detection for Intel Haswell */
|
||||
void get_imc_config_intel_hsw(void);
|
||||
|
||||
/* Memory configuration Detection for Intel Skylake */
|
||||
void get_imc_config_intel_skl(void);
|
||||
|
||||
/* Memory configuration Detection for Intel Ice Lake */
|
||||
void get_imc_config_intel_icl(void);
|
||||
|
||||
/* Memory configuration Detection for Intel Alder Lake */
|
||||
void get_imc_config_intel_adl(void);
|
||||
|
||||
#endif /* _IMC_H_ */
|
100
system/imc/intel_adl.c
Normal file
100
system/imc/intel_adl.c
Normal file
@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
//
|
||||
// Platform-specific code for Intel Alder Lake CPUs (ADL-S)
|
||||
//
|
||||
|
||||
#include "cpuinfo.h"
|
||||
#include "memctrl.h"
|
||||
#include "msr.h"
|
||||
#include "pci.h"
|
||||
#include "vmem.h"
|
||||
|
||||
#include "imc.h"
|
||||
|
||||
#define ADL_MMR_BASE_REG_LOW 0x48
|
||||
#define ADL_MMR_BASE_REG_HIGH 0x4C
|
||||
|
||||
#define ADL_MMR_WINDOW_RANGE (1UL << 17)
|
||||
#define ADL_MMR_BASE_MASK 0x3FFFFFE0000
|
||||
|
||||
#define ADL_MMR_MC1_OFFSET 0x10000
|
||||
#define ADL_MMR_CH1_OFFSET 0x800
|
||||
|
||||
#define ADL_MMR_IC_DECODE 0xD800
|
||||
#define ADL_MMR_CH0_DIMM_REG 0xD80C
|
||||
#define ADL_MMR_MC0_REG 0xE000
|
||||
#define ADL_MMR_ODT_TCL_REG 0xE070
|
||||
#define ADL_MMR_MC_INIT_REG 0xE454
|
||||
|
||||
#define ADL_MMR_SA_PERF_REG 0x5918
|
||||
#define ADL_MMR_MC_BIOS_REG 0x5E04
|
||||
#define ADL_MMR_BLCK_REG 0x5F60
|
||||
|
||||
void get_imc_config_intel_adl(void)
|
||||
{
|
||||
uint64_t mmio_reg;
|
||||
uint32_t cha, chb, offset;
|
||||
float bclk;
|
||||
uintptr_t *ptr;
|
||||
uint32_t *ptr32;
|
||||
|
||||
// Get Memory Mapped Register Base Address (Enable MMIO if needed)
|
||||
mmio_reg = pci_config_read32(0, 0, 0, ADL_MMR_BASE_REG_LOW);
|
||||
if (!(mmio_reg & 0x1)) {
|
||||
pci_config_write32( 0, 0, 0, ADL_MMR_BASE_REG_LOW, mmio_reg | 1);
|
||||
mmio_reg = pci_config_read32(0, 0, 0, ADL_MMR_BASE_REG_LOW);
|
||||
if (!(mmio_reg & 0x1)) return;
|
||||
}
|
||||
|
||||
mmio_reg |= (uint64_t)pci_config_read32(0, 0, 0, ADL_MMR_BASE_REG_HIGH) << 32;
|
||||
mmio_reg &= ADL_MMR_BASE_MASK;
|
||||
|
||||
#ifndef __x86_64__
|
||||
if (mmio_reg >= (1ULL << 32)) return; // MMIO is outside reachable range (> 32bit)
|
||||
#endif
|
||||
|
||||
uintptr_t mchbar_addr = map_region(mmio_reg, ADL_MMR_WINDOW_RANGE, false);
|
||||
|
||||
// Get channel configuration & IMC width
|
||||
cha = *(uintptr_t*)(mchbar_addr + ADL_MMR_CH0_DIMM_REG);
|
||||
cha = ~cha ? (((cha >> 16) & 0x7F) + (cha & 0x7F)) : 0;
|
||||
|
||||
chb = *(uintptr_t*)(mchbar_addr + ADL_MMR_CH0_DIMM_REG + ADL_MMR_MC1_OFFSET);
|
||||
chb = ~chb ? (((chb >> 16) & 0x7F) + (chb & 0x7F)) : 0;
|
||||
|
||||
offset = cha ? 0x0 : ADL_MMR_MC1_OFFSET;
|
||||
imc.width = (cha && chb) ? 64 : 128;
|
||||
|
||||
// Get Memory Type (ADL supports DDR4 & DDR5)
|
||||
cha = *(uintptr_t*)(mchbar_addr + offset + ADL_MMR_IC_DECODE) & 0x7;
|
||||
imc.type = (cha == 1 || cha == 2) ? "DDR5" : "DDR4";
|
||||
|
||||
// Get SoC Base Clock
|
||||
ptr = (uintptr_t*)(mchbar_addr + ADL_MMR_BLCK_REG);
|
||||
bclk = (*ptr & 0xFFFFFFFF) / 1000.0f;
|
||||
|
||||
// Get Memory Clock (QClk), apply Gear & clock ratio
|
||||
ptr = (uintptr_t*)(mchbar_addr + ADL_MMR_SA_PERF_REG);
|
||||
imc.freq = ((*ptr >> 2) & 0xFF) * bclk;
|
||||
|
||||
ptr = (uintptr_t*)(mchbar_addr + ADL_MMR_MC_BIOS_REG);
|
||||
imc.freq <<= (*ptr >> 12) & 0x3;
|
||||
|
||||
if ((*ptr & 0xF00) == 0) {
|
||||
imc.freq *= 133.34f / 100.0f;
|
||||
}
|
||||
|
||||
// Get DRAM Timings
|
||||
ptr = (uintptr_t*)(mchbar_addr + offset + ADL_MMR_ODT_TCL_REG);
|
||||
imc.tCL = (*ptr >> 16) & 0x7F;
|
||||
|
||||
ptr = (uintptr_t*)(mchbar_addr + offset + ADL_MMR_MC0_REG);
|
||||
imc.tRP = *ptr & 0xFF;
|
||||
|
||||
ptr32 = (uint32_t*)((uintptr_t)mchbar_addr + offset + ADL_MMR_MC0_REG + 4);
|
||||
imc.tRAS = (*ptr32 >> 10) & 0x1FF;
|
||||
imc.tRCD = (*ptr32 >> 19) & 0xFF;
|
||||
}
|
92
system/imc/intel_hsw.c
Normal file
92
system/imc/intel_hsw.c
Normal file
@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
//
|
||||
// Platform-specific code for Intel Haswell CPUs (HSW)
|
||||
//
|
||||
|
||||
#include "cpuinfo.h"
|
||||
#include "memctrl.h"
|
||||
#include "msr.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "imc.h"
|
||||
|
||||
#define HSW_MMR_BASE_REG 0x48
|
||||
#define HSW_REG_MAIN_CHAN0 0x5004
|
||||
#define HSW_REG_MAIN_CHAN1 0x5008
|
||||
#define HSW_REG_MCH_CFG 0x5E04
|
||||
#define HSW_REG_TIMING_CAS 0x4014
|
||||
#define HSW_REG_TIMING_RCD 0x4000
|
||||
|
||||
void get_imc_config_intel_hsw(void)
|
||||
{
|
||||
uint32_t mmio_reg, mch_cfg, offset;
|
||||
uint32_t reg0, reg1;
|
||||
float cpu_ratio, dram_ratio;
|
||||
uintptr_t *ptr;
|
||||
|
||||
imc.type = "DDR3";
|
||||
imc.tCL_dec = 0;
|
||||
|
||||
// Get Memory Mapped Register Base Address (Enable MMIO if needed)
|
||||
mmio_reg = pci_config_read32(0, 0, 0, HSW_MMR_BASE_REG);
|
||||
if (!(mmio_reg & 0x1)) {
|
||||
pci_config_write32( 0, 0, 0, HSW_MMR_BASE_REG, mmio_reg | 1);
|
||||
mmio_reg = pci_config_read32(0, 0, 0, HSW_MMR_BASE_REG);
|
||||
if (!(mmio_reg & 0x1)) return;
|
||||
}
|
||||
mmio_reg &= 0xFFFFC000;
|
||||
|
||||
// Get DRAM Ratio
|
||||
ptr = (uintptr_t*)((uintptr_t)mmio_reg + HSW_REG_MCH_CFG);
|
||||
mch_cfg = *ptr & 0xFFFF;
|
||||
|
||||
if ((mch_cfg >> 8) & 1) {
|
||||
dram_ratio = (float)(*ptr & 0x1F) * (100.0f / 100.0f);
|
||||
} else {
|
||||
dram_ratio = (float)(*ptr & 0x1F) * (133.34f / 100.0f);
|
||||
}
|
||||
|
||||
// Get CPU Ratio
|
||||
rdmsr(MSR_IA32_PLATFORM_INFO, reg0, reg1);
|
||||
cpu_ratio = (float)((reg0 >> 8) & 0xFF);
|
||||
|
||||
if (!cpu_ratio) return;
|
||||
|
||||
// Compute DRAM Frequency
|
||||
imc.freq = ((clks_per_msec / 1000) / cpu_ratio) * dram_ratio * 2;
|
||||
|
||||
if (imc.freq < 350 || imc.freq > 5000) {
|
||||
imc.freq = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Main Memory Controller Register for both channels
|
||||
ptr = (uintptr_t*)((uintptr_t)mmio_reg + HSW_REG_MAIN_CHAN0);
|
||||
reg0 = *ptr & 0xFFFF;
|
||||
|
||||
ptr = (uintptr_t*)((uintptr_t)mmio_reg + HSW_REG_MAIN_CHAN1);
|
||||
reg1 = *ptr & 0xFFFF;
|
||||
|
||||
// Populate IMC width
|
||||
imc.width = (reg0 && reg1) ? 128 : 64;
|
||||
|
||||
// Define offset (ie: which channel is really used)
|
||||
offset = reg0 ? 0x0000 : 0x4000;
|
||||
|
||||
// CAS Latency (tCAS)
|
||||
ptr = (uintptr_t*)((uintptr_t)mmio_reg + offset + HSW_REG_TIMING_CAS);
|
||||
imc.tCL = *ptr & 0x1F;
|
||||
|
||||
// RAS-To-CAS (tRCD)
|
||||
ptr = (uintptr_t*)((uintptr_t)mmio_reg + offset + HSW_REG_TIMING_RCD);
|
||||
imc.tRCD = *ptr & 0x1F;
|
||||
|
||||
// RAS Precharge (tRP)
|
||||
imc.tRP = (*ptr >> 5) & 0x1F;
|
||||
|
||||
// RAS Active to precharge (tRAS)
|
||||
imc.tRAS = (*ptr >> 10) & 0x3F;
|
||||
}
|
99
system/imc/intel_icl.c
Normal file
99
system/imc/intel_icl.c
Normal file
@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
//
|
||||
// Platform-specific code for Intel IceLake CPUs (ICL)
|
||||
//
|
||||
|
||||
#include "cpuinfo.h"
|
||||
#include "memctrl.h"
|
||||
#include "msr.h"
|
||||
#include "pci.h"
|
||||
#include "vmem.h"
|
||||
|
||||
#include "imc.h"
|
||||
|
||||
#define ICL_MMR_BASE_REG_LOW 0x48
|
||||
#define ICL_MMR_BASE_REG_HIGH 0x4C
|
||||
#define ICL_MMR_TIMINGS 0x4000
|
||||
#define ICL_MMR_TIMING_CAS 0x4070
|
||||
#define ICL_MMR_MAD_CHAN0 0x500C
|
||||
#define ICL_MMR_MAD_CHAN1 0x5010
|
||||
#define ICL_MMR_DRAM_CLOCK 0x5E00
|
||||
|
||||
#define ICL_MMR_MC_BIOS_REG 0x5E04
|
||||
#define ICL_MMR_BLCK_REG 0x5F60
|
||||
|
||||
#define ICL_MMR_WINDOW_RANGE (1UL << 15)
|
||||
|
||||
#define ICL_MMR_BASE_MASK 0x7FFFFF8000
|
||||
#define ICL_MMR_MAD_IN_USE_MASK 0x003F003F
|
||||
|
||||
void get_imc_config_intel_icl(void)
|
||||
{
|
||||
uint64_t mmio_reg;
|
||||
uint32_t reg0, reg1, offset;
|
||||
float bclk;
|
||||
uintptr_t *ptr;
|
||||
|
||||
// Get Memory Mapped Register Base Address (Enable MMIO if needed)
|
||||
mmio_reg = pci_config_read32(0, 0, 0, ICL_MMR_BASE_REG_LOW);
|
||||
if (!(mmio_reg & 0x1)) {
|
||||
pci_config_write32( 0, 0, 0, ICL_MMR_BASE_REG_LOW, mmio_reg | 1);
|
||||
mmio_reg = pci_config_read32(0, 0, 0, ICL_MMR_BASE_REG_LOW);
|
||||
if (!(mmio_reg & 0x1)) return;
|
||||
}
|
||||
|
||||
mmio_reg |= (uint64_t)pci_config_read32(0, 0, 0, ICL_MMR_BASE_REG_HIGH) << 32;
|
||||
mmio_reg &= ICL_MMR_BASE_MASK;
|
||||
|
||||
#ifndef __x86_64__
|
||||
if (mmio_reg >= (1ULL << 32)) return; // MMIO is outside reachable range
|
||||
#endif
|
||||
|
||||
uintptr_t mchbar_addr = map_region(mmio_reg, ICL_MMR_WINDOW_RANGE, false);
|
||||
|
||||
imc.type = "DDR4";
|
||||
|
||||
// Get SoC Base Clock
|
||||
ptr = (uintptr_t*)(mchbar_addr + ICL_MMR_BLCK_REG);
|
||||
bclk = (*ptr & 0xFFFFFFFF) / 1000.0f;
|
||||
|
||||
// Get Memory Clock (QClk), apply Gear & clock ratio
|
||||
ptr = (uintptr_t*)(mchbar_addr + ICL_MMR_MC_BIOS_REG);
|
||||
imc.freq = (*ptr & 0xFF) * bclk;
|
||||
|
||||
if (*ptr & 0x10000) {
|
||||
imc.freq *= 2;
|
||||
}
|
||||
|
||||
if ((*ptr & 0xF00) == 0) {
|
||||
imc.freq *= 133.34f / 100.0f;
|
||||
}
|
||||
|
||||
// Get Main Memory Controller Register for both channels
|
||||
ptr = (uintptr_t*)(mchbar_addr + ICL_MMR_MAD_CHAN0);
|
||||
reg0 = *ptr & ICL_MMR_MAD_IN_USE_MASK;
|
||||
|
||||
ptr = (uintptr_t*)(mchbar_addr + ICL_MMR_MAD_CHAN1);
|
||||
reg1 = *ptr & ICL_MMR_MAD_IN_USE_MASK;
|
||||
|
||||
// Populate IMC width
|
||||
imc.width = (reg0 && reg1) ? 128 : 64;
|
||||
|
||||
// Define offset (ie: which channel is really used)
|
||||
offset = reg0 ? 0x0000 : 0x0400;
|
||||
|
||||
// CAS Latency (tCAS)
|
||||
ptr = (uintptr_t*)(mchbar_addr + offset + ICL_MMR_TIMING_CAS);
|
||||
imc.tCL = (*ptr >> 16) & 0x1F;
|
||||
imc.tCL_dec = 0;
|
||||
|
||||
// RAS-To-CAS (tRCD) & RAS Precharge (tRP)
|
||||
ptr = (uintptr_t*)(mchbar_addr + offset + ICL_MMR_TIMINGS);
|
||||
imc.tRP = imc.tRCD = *ptr & 0x3F;
|
||||
|
||||
// RAS Active to precharge (tRAS)
|
||||
imc.tRAS = (*ptr >> 9) & 0x7F;
|
||||
}
|
105
system/imc/intel_skl.c
Normal file
105
system/imc/intel_skl.c
Normal file
@ -0,0 +1,105 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
//
|
||||
// Platform-specific code for Intel Skylake CPUs (SKL)
|
||||
//
|
||||
|
||||
#include "cpuinfo.h"
|
||||
#include "memctrl.h"
|
||||
#include "msr.h"
|
||||
#include "pci.h"
|
||||
#include "vmem.h"
|
||||
|
||||
#include "imc.h"
|
||||
|
||||
#define SKL_MMR_BASE_REG_LOW 0x48
|
||||
#define SKL_MMR_BASE_REG_HIGH 0x4C
|
||||
#define SKL_MMR_TIMINGS 0x4000
|
||||
#define SKL_MMR_SCHEDULER_CONF 0x401C
|
||||
#define SKL_MMR_TIMING_CAS 0x4070
|
||||
#define SKL_MMR_MAD_CHAN0 0x500C
|
||||
#define SKL_MMR_MAD_CHAN1 0x5010
|
||||
#define SKL_MMR_DRAM_CLOCK 0x5E00
|
||||
|
||||
#define SKL_MMR_WINDOW_RANGE (1UL << 15)
|
||||
|
||||
#define SKL_MMR_BASE_MASK 0x7FFFFF8000
|
||||
#define SKL_MMR_MAD_IN_USE_MASK 0x003F003F
|
||||
|
||||
void get_imc_config_intel_skl(void)
|
||||
{
|
||||
uint64_t mmio_reg;
|
||||
uint32_t reg0, reg1, offset;
|
||||
float cpu_ratio, dram_ratio;
|
||||
uintptr_t *ptr;
|
||||
|
||||
// Get Memory Mapped Register Base Address (Enable MMIO if needed)
|
||||
mmio_reg = pci_config_read32(0, 0, 0, SKL_MMR_BASE_REG_LOW);
|
||||
if (!(mmio_reg & 0x1)) {
|
||||
pci_config_write32( 0, 0, 0, SKL_MMR_BASE_REG_LOW, mmio_reg | 1);
|
||||
mmio_reg = pci_config_read32(0, 0, 0, SKL_MMR_BASE_REG_LOW);
|
||||
if (!(mmio_reg & 0x1)) return;
|
||||
}
|
||||
|
||||
mmio_reg |= (uint64_t)pci_config_read32(0, 0, 0, SKL_MMR_BASE_REG_HIGH) << 32;
|
||||
mmio_reg &= SKL_MMR_BASE_MASK;
|
||||
|
||||
#ifndef __x86_64__
|
||||
if (mmio_reg >= (1ULL << 32)) return; // MMIO is outside reachable range
|
||||
#endif
|
||||
|
||||
uintptr_t mchbar_addr = map_region(mmio_reg, SKL_MMR_WINDOW_RANGE, false);
|
||||
|
||||
// Get DRAM Ratio
|
||||
ptr = (uintptr_t*)(mchbar_addr + SKL_MMR_DRAM_CLOCK);
|
||||
reg0 = *ptr & 0xF;
|
||||
|
||||
if (reg0 < 3) return;
|
||||
|
||||
dram_ratio = reg0 * (133.34f / 100.0f);
|
||||
|
||||
// Get CPU Ratio
|
||||
rdmsr(MSR_IA32_PLATFORM_INFO, reg0, reg1);
|
||||
cpu_ratio = (float)((reg0 >> 8) & 0xFF);
|
||||
|
||||
if (!cpu_ratio) return;
|
||||
|
||||
// Compute DRAM Frequency
|
||||
imc.freq = ((clks_per_msec / 1000) / cpu_ratio) * dram_ratio * 2;
|
||||
|
||||
if (imc.freq < 150 || imc.freq > 8000) {
|
||||
imc.freq = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Main Memory Controller Register for both channels
|
||||
ptr = (uintptr_t*)(mchbar_addr + SKL_MMR_MAD_CHAN0);
|
||||
reg0 = *ptr & SKL_MMR_MAD_IN_USE_MASK;
|
||||
|
||||
ptr = (uintptr_t*)(mchbar_addr + SKL_MMR_MAD_CHAN1);
|
||||
reg1 = *ptr & SKL_MMR_MAD_IN_USE_MASK;
|
||||
|
||||
// Populate IMC width
|
||||
imc.width = (reg0 && reg1) ? 128 : 64;
|
||||
|
||||
// Define offset (ie: which channel is really used)
|
||||
offset = reg0 ? 0x0000 : 0x0400;
|
||||
|
||||
// SKL supports DDR3 & DDR4. Check DDR Type.
|
||||
ptr = (uintptr_t*)(mchbar_addr + offset + SKL_MMR_SCHEDULER_CONF);
|
||||
imc.type = (*ptr & 0x3) ? "DDR3" : "DDR4";
|
||||
|
||||
// CAS Latency (tCAS)
|
||||
ptr = (uintptr_t*)(mchbar_addr + offset + SKL_MMR_TIMING_CAS);
|
||||
imc.tCL = (*ptr >> 16) & 0x1F;
|
||||
imc.tCL_dec = 0;
|
||||
|
||||
// RAS-To-CAS (tRCD) & RAS Precharge (tRP)
|
||||
ptr = (uintptr_t*)(mchbar_addr + offset + SKL_MMR_TIMINGS);
|
||||
imc.tRP = imc.tRCD = *ptr & 0x3F;
|
||||
|
||||
// RAS Active to precharge (tRAS)
|
||||
imc.tRAS = (*ptr >> 8) & 0x7F;
|
||||
}
|
93
system/imc/intel_snb.c
Normal file
93
system/imc/intel_snb.c
Normal file
@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
//
|
||||
// Platform-specific code for Intel Sandy Bridge CPUs (SNB)
|
||||
//
|
||||
|
||||
#include "cpuinfo.h"
|
||||
#include "memctrl.h"
|
||||
#include "msr.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "imc.h"
|
||||
|
||||
#define SNB_MMR_BASE_REG 0x48
|
||||
#define SNB_REG_MAIN_CHAN0 0x5004
|
||||
#define SNB_REG_MAIN_CHAN1 0x5008
|
||||
#define SNB_REG_MCH_CFG 0x5E04
|
||||
#define SNB_REG_TIMING 0x4000
|
||||
|
||||
void get_imc_config_intel_snb(void)
|
||||
{
|
||||
uint32_t mmio_reg, offset;
|
||||
uint32_t mch_cfg, reg0, reg1;
|
||||
float cpu_ratio, dram_ratio;
|
||||
uint32_t *ptr;
|
||||
|
||||
imc.type = "DDR3";
|
||||
imc.tCL_dec = 0;
|
||||
|
||||
// Get Memory Mapped Register Base Address (Enable MMIO if needed)
|
||||
mmio_reg = pci_config_read32(0, 0, 0, SNB_MMR_BASE_REG);
|
||||
|
||||
if (!(mmio_reg & 0x1)) {
|
||||
pci_config_write32( 0, 0, 0, SNB_MMR_BASE_REG, mmio_reg | 1);
|
||||
mmio_reg = pci_config_read32(0, 0, 0, SNB_MMR_BASE_REG);
|
||||
if (!(mmio_reg & 0x1)) return;
|
||||
}
|
||||
mmio_reg &= 0xFFFFC000;
|
||||
|
||||
// Get DRAM Ratio
|
||||
ptr = (uint32_t*)((uintptr_t)mmio_reg + SNB_REG_MCH_CFG);
|
||||
mch_cfg = *ptr & 0xFFFF;
|
||||
|
||||
if ((mch_cfg >> 8) & 1) {
|
||||
dram_ratio = (float)(*ptr & 0x1F) * (100.0f / 100.0f);
|
||||
} else {
|
||||
dram_ratio = (float)(*ptr & 0x1F) * (133.34f / 100.0f);
|
||||
}
|
||||
|
||||
// Get CPU Ratio
|
||||
rdmsr(MSR_IA32_PLATFORM_INFO, reg0, reg1);
|
||||
cpu_ratio = (float)((reg0 >> 8) & 0xFF);
|
||||
|
||||
if (!cpu_ratio) return;
|
||||
|
||||
// Compute DRAM Frequency
|
||||
imc.freq = ((clks_per_msec / 1000) / cpu_ratio) * dram_ratio * 2;
|
||||
|
||||
if (imc.freq < 350 || imc.freq > 5000) {
|
||||
imc.freq = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Main Memory Controller Register for both channels
|
||||
ptr = (uint32_t*)((uintptr_t)mmio_reg + SNB_REG_MAIN_CHAN0);
|
||||
reg0 = *ptr & 0xFFFF;
|
||||
|
||||
ptr = (uint32_t*)((uintptr_t)mmio_reg + SNB_REG_MAIN_CHAN1);
|
||||
reg1 = *ptr & 0xFFFF;
|
||||
|
||||
// Populate IMC width
|
||||
imc.width = (reg0 && reg1) ? 128 : 64;
|
||||
|
||||
// Define offset (chan A or B used)
|
||||
offset = reg0 ? 0x0 : 0x0400;
|
||||
|
||||
// Get Main timing register
|
||||
reg0 = *(uint32_t*)((uintptr_t)mmio_reg + offset + SNB_REG_TIMING);
|
||||
|
||||
// CAS Latency (tCAS)
|
||||
imc.tCL = (reg0 >> 8) & 0xF;
|
||||
|
||||
// RAS-To-CAS (tRCD)
|
||||
imc.tRCD = reg0 & 0xF;
|
||||
|
||||
// RAS Precharge (tRP)
|
||||
imc.tRP = (reg0 >> 4) & 0xF;
|
||||
|
||||
// RAS Active to precharge (tRAS)
|
||||
imc.tRAS = (reg0 >> 16) & 0xFF;
|
||||
}
|
65
system/memctrl.c
Normal file
65
system/memctrl.c
Normal file
@ -0,0 +1,65 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
//
|
||||
// Platform-specific code for IMC configuration, ECC support, etc.
|
||||
//
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "cpuinfo.h"
|
||||
|
||||
#include "memctrl.h"
|
||||
#include "imc/imc.h"
|
||||
|
||||
imc_info_t imc = {"UNDEF", 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
ecc_info_t ecc_status = {false, ECC_ERR_NONE, 0, 0, 0, 0, 0};
|
||||
|
||||
// ---------------------
|
||||
// -- Public function --
|
||||
// ---------------------
|
||||
|
||||
void memctrl_init(void)
|
||||
{
|
||||
ecc_status.ecc_enabled = false;
|
||||
|
||||
if (!enable_mch_read) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(imc.family) {
|
||||
case IMC_K17:
|
||||
case IMC_K19_VRM:
|
||||
case IMC_K19_RPL:
|
||||
get_imc_config_amd_zen();
|
||||
break;
|
||||
case IMC_SNB:
|
||||
case IMC_IVB:
|
||||
get_imc_config_intel_snb();
|
||||
break;
|
||||
case IMC_HSW:
|
||||
get_imc_config_intel_hsw();
|
||||
break;
|
||||
case IMC_SKL:
|
||||
case IMC_KBL:
|
||||
get_imc_config_intel_skl();
|
||||
break;
|
||||
case IMC_RKL:
|
||||
get_imc_config_intel_icl();
|
||||
break;
|
||||
case IMC_RPL:
|
||||
case IMC_ADL:
|
||||
get_imc_config_intel_adl();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Consistency check
|
||||
if (imc.tCL == 0 || imc.tRCD == 0 || imc.tRP == 0 || imc.tRCD == 0) {
|
||||
imc.freq = 0;
|
||||
}
|
||||
}
|
57
system/memctrl.h
Normal file
57
system/memctrl.h
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef MEMCTRL_H
|
||||
#define MEMCTRL_H
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Provides information about the memory controller status
|
||||
* (running DRAM configuration, ECC, ...) and other
|
||||
* platform-specific data
|
||||
*
|
||||
*//*
|
||||
* Copyright (C) 2004-2023 Sam Demeulemeester.
|
||||
*/
|
||||
|
||||
typedef struct __attribute__((packed)) imc_infos {
|
||||
char *type;
|
||||
uint16_t family;
|
||||
uint16_t freq;
|
||||
uint16_t width;
|
||||
uint16_t tCL;
|
||||
uint8_t tCL_dec;
|
||||
uint16_t tRCD;
|
||||
uint16_t tRP;
|
||||
uint16_t tRAS;
|
||||
} imc_info_t;
|
||||
|
||||
typedef enum {
|
||||
ECC_ERR_NONE,
|
||||
ECC_ERR_CORRECTED,
|
||||
ECC_ERR_UNCORRECTED
|
||||
} ecc_error_type_t;
|
||||
|
||||
typedef struct __attribute__((packed)) ecc_status {
|
||||
bool ecc_enabled;
|
||||
ecc_error_type_t err_type;
|
||||
uint64_t err_adr;
|
||||
uint32_t err_col;
|
||||
uint32_t err_row;
|
||||
uint32_t err_rank;
|
||||
uint32_t err_bank;
|
||||
} ecc_info_t;
|
||||
|
||||
/**
|
||||
* Current DRAM configuration of the Integrated Memory Controller
|
||||
*/
|
||||
|
||||
extern imc_info_t imc;
|
||||
|
||||
/**
|
||||
* Current ECC Status of the Integrated Memory Controller
|
||||
*/
|
||||
|
||||
extern ecc_info_t ecc_status;
|
||||
|
||||
void memctrl_init(void);
|
||||
|
||||
#endif // MEMCTRL_H
|
@ -17,6 +17,7 @@
|
||||
#define MSR_IA32_PLATFORM_ID 0x17
|
||||
#define MSR_IA32_APIC_BASE 0x1b
|
||||
#define MSR_IA32_EBL_CR_POWERON 0x2a
|
||||
#define MSR_IA32_PLATFORM_INFO 0xce
|
||||
#define MSR_IA32_MCG_CTL 0x17b
|
||||
#define MSR_IA32_PERF_STATUS 0x198
|
||||
#define MSR_IA32_THERM_STATUS 0x19c
|
||||
|
@ -86,15 +86,9 @@ void pci_config_write32(int bus, int dev, int func, int reg, uint32_t value);
|
||||
void lpc_outb(uint8_t cmd, uint8_t data);
|
||||
uint8_t lpc_inb(uint8_t reg);
|
||||
|
||||
/*
|
||||
* Add some SNM related function (S.DEMEULEMEESTER)
|
||||
*/
|
||||
|
||||
#define SMN_SMUIO_THM 0x00059800
|
||||
#define SMN_THM_TCON_CUR_TMP (SMN_SMUIO_THM + 0x00)
|
||||
|
||||
/**
|
||||
* Read & Write to AMD Family 17h SNM
|
||||
* Read & Write to AMD SNM
|
||||
*/
|
||||
uint32_t amd_smn_read(uint32_t adr);
|
||||
void amd_smn_write(uint32_t adr, uint32_t data);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "string.h"
|
||||
|
||||
#include "cpuinfo.h"
|
||||
#include "memctrl.h"
|
||||
#include "smbus.h"
|
||||
#include "smbios.h"
|
||||
#include "jedec_id.h"
|
||||
@ -1407,7 +1408,7 @@ static bool fch_zen_get_smb(void)
|
||||
pm_reg |= __inb(AMD_DATA_IO_PORT);
|
||||
|
||||
// Special case for AMD Family 19h & Extended Model > 4 (get smb address in memory)
|
||||
if ((imc_type == IMC_K19_CZN || imc_type == IMC_K19_RPL) && pm_reg == 0xFFFF) {
|
||||
if ((imc.family == IMC_K19_CZN || imc.family == IMC_K19_RPL) && pm_reg == 0xFFFF) {
|
||||
smbusbase = ((*(const uint32_t *)(0xFED80000 + 0x300) >> 8) & 0xFF) << 8;
|
||||
return true;
|
||||
}
|
||||
|
@ -14,6 +14,10 @@
|
||||
#define AMD_TEMP_REG_K8 0xE4
|
||||
#define AMD_TEMP_REG_K10 0xA4
|
||||
|
||||
// Temp Registers on AMD ZEN System Management Network
|
||||
#define SMN_SMUIO_THM 0x00059800
|
||||
#define SMN_THM_TCON_CUR_TMP (SMN_SMUIO_THM + 0x00)
|
||||
|
||||
/**
|
||||
* Global CPU Temperature offset
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user