diff --git a/Controllers/HyperXDRAMController/HyperXDRAMControllerDetect.cpp b/Controllers/HyperXDRAMController/HyperXDRAMControllerDetect.cpp index 89ffcca6..39334596 100644 --- a/Controllers/HyperXDRAMController/HyperXDRAMControllerDetect.cpp +++ b/Controllers/HyperXDRAMController/HyperXDRAMControllerDetect.cpp @@ -87,6 +87,7 @@ void DetectHyperXDRAMControllers(std::vector &busses) if(TestForHyperXDRAMController(busses[bus], 0x27)) { + // Switch to 2nd SPD page busses[bus]->i2c_smbus_write_byte_data(0x37, 0x00, 0xFF); std::this_thread::sleep_for(1ms); @@ -128,6 +129,11 @@ void DetectHyperXDRAMControllers(std::vector &busses) LOG_DEBUG("[%s] slots_valid=%d fury_detected=%d pred_detected=%d", HYPERX_CONTROLLER_NAME, slots_valid, fury_detected, pred_detected); + // Switch back to 1st SPD page + busses[bus]->i2c_smbus_write_byte_data(0x36, 0x00, 0xFF); + + std::this_thread::sleep_for(1ms); + if(slots_valid != 0) { HyperXDRAMController* controller = new HyperXDRAMController(busses[bus], 0x27, slots_valid); diff --git a/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMController.cpp b/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMController.cpp index 6983dcf8..4cc98915 100644 --- a/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMController.cpp +++ b/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMController.cpp @@ -79,7 +79,7 @@ bool KingstonFuryDRAMController::SmbusRead(int slot_idx, unsigned char reg, unsi res = bus->i2c_smbus_read_word_data(device_addr, reg); if(res >= 0) { - *val = (res >> 8) & 0xff; + *val = (res >> 8) & 0xFF; LOG_DEBUG("[%s] %02X reading register &%02X=%02X; res=%02X", FURY_CONTROLLER_NAME, device_addr, reg, *val, res); return true; diff --git a/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMControllerDetect.cpp b/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMControllerDetect.cpp index 9a728c75..76eef696 100644 --- a/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMControllerDetect.cpp +++ b/Controllers/KingstonFuryDRAMController/KingstonFuryDRAMControllerDetect.cpp @@ -31,32 +31,128 @@ typedef enum RESULT_ERROR = 2 } TestResult; -TestResult TestForFurySlot(i2c_smbus_interface *bus, unsigned int slot_addr, bool (*modelChecker)(char)) +typedef enum { - char model_code = 0; - int res = bus->i2c_smbus_write_quick(slot_addr, I2C_SMBUS_WRITE); + SPD_RESERVED = 0, + SPD_FPM_DRAM = 1, + SPD_EDO = 2, + SPD_NIBBLE = 3, + SPD_SDR_SDRAM = 4, + SPD_MUX_ROM = 5, + SPD_DDR_SGRAM = 6, + SPD_DDR_SDRAM = 7, + SPD_DDR2_SDRAM = 8, + SPD_FB_DIMM = 9, + SPD_FB_PROBE = 10, + SPD_DDR3_SDRAM = 11, + SPD_DDR4_SDRAM = 12, + SPD_RESERVED2 = 13, + SPD_DDR4E_SDRAM = 14, + SPD_LPDDR3_SDRAM = 15, + SPD_LPDDR4_SDRAM = 16, + SPD_LPDDR4X_SDRAM = 17, + SPD_DDR5_SDRAM = 18, + SPD_LPDDR5_SDRAM = 19 +} SPDMemoryType; - LOG_DEBUG("[%s] Probing address %02X, res=%02X", FURY_CONTROLLER_NAME, slot_addr, res); - if(res < 0) - { - return RESULT_FAIL; - } +// DDR5 SPD hub detection +TestResult TestForSPDHub(i2c_smbus_interface *bus, int spd_address, int &mem_type) +{ + int ddr5Magic = bus->i2c_smbus_read_byte_data(spd_address, 0x00); + int ddr5Sensor = bus->i2c_smbus_read_byte_data(spd_address, 0x01); + std::this_thread::sleep_for(1ms); - // Get the model code - res = bus->i2c_smbus_read_word_data(slot_addr, FURY_REG_MODEL); - if(res < 0) + if(ddr5Magic < 0 || ddr5Sensor < 0) { return RESULT_ERROR; } - model_code = res >> 8; - std::this_thread::sleep_for(FURY_DELAY); - LOG_DEBUG("[%s] Reading model code at address %02X register %02X, res=%02X", - FURY_CONTROLLER_NAME, slot_addr, FURY_REG_MODEL, model_code); - if(!modelChecker(model_code)) + if(ddr5Magic == 0x51 && (ddr5Sensor & 0xEF) == 0x08) { - LOG_DEBUG("[%s] Unknown model code 0x%02X", FURY_CONTROLLER_NAME, model_code); - return RESULT_FAIL; + // These values are invalid for any other memory type + mem_type = SPD_DDR5_SDRAM; + return RESULT_PASS; + } + return RESULT_FAIL; +} + +TestResult TestSPDForKingston(i2c_smbus_interface *bus, SPDMemoryType &fury_type, std::vector &slots) +{ + int mem_type = -1; + + for(int slot_index = 0; slot_index < FURY_MAX_SLOTS; slot_index++) + { + int spd_address = 0x50 + slot_index; + + TestResult result = TestForSPDHub(bus, spd_address, mem_type); + if(result == RESULT_ERROR) + { + LOG_TRACE("[%s] SPD Hub check [0x%02X] failed. No device.", + FURY_CONTROLLER_NAME, spd_address); + continue; + } + + if(mem_type != SPD_DDR4_SDRAM && mem_type != SPD_DDR5_SDRAM) + { + // Get memory type from SPD for DDR4 or older + bus->i2c_smbus_write_byte_data(0x36, 0x00, 0xFF); + std::this_thread::sleep_for(1ms); + mem_type = bus->i2c_smbus_read_byte_data(spd_address, 0x02); + } + + if(mem_type != SPD_DDR4_SDRAM && mem_type != SPD_DDR5_SDRAM) + { + LOG_TRACE("[%s] SPD check [0x%02X] - wrong memory type => %02X", + FURY_CONTROLLER_NAME, spd_address, mem_type); + continue; + } + fury_type = static_cast(mem_type); + + LOG_TRACE("[%s] SPD check [0x%02X]: memory type => %02X, ", + FURY_CONTROLLER_NAME, spd_address, mem_type); + // Switch SPD page + if(mem_type == SPD_DDR4_SDRAM) + { + bus->i2c_smbus_write_byte_data(0x37, 0x00, 0xFF); + } + else + { + bus->i2c_smbus_write_byte_data(spd_address, 0x0B, 4); + } + std::this_thread::sleep_for(1ms); + + // Get ManufacturerID + int vendorHi, vendorLo; + if(mem_type == SPD_DDR4_SDRAM) + { + vendorHi = bus->i2c_smbus_read_byte_data(spd_address, 0x40); + vendorLo = bus->i2c_smbus_read_byte_data(spd_address, 0x41); + } + else + { + vendorHi = bus->i2c_smbus_read_byte_data(spd_address, 0x80); + vendorLo = bus->i2c_smbus_read_byte_data(spd_address, 0x81); + } + std::this_thread::sleep_for(1ms); + + LOG_DEBUG("[%s] SPD check [0x%02X]: vendorHi => %02X, vendorLo => %02X, ", + FURY_CONTROLLER_NAME, spd_address, vendorHi, vendorLo); + + // Switch SPD page back to 0 + if(mem_type == SPD_DDR4_SDRAM) + { + bus->i2c_smbus_write_byte_data(0x36, 0x00, 0xFF); + } + else + { + bus->i2c_smbus_write_byte_data(spd_address, 0x0B, 0); + } + std::this_thread::sleep_for(1ms); + + if(vendorHi == 0x01 && vendorLo == 0x98) + { + slots.push_back(slot_index); + } } return RESULT_PASS; } @@ -75,7 +171,7 @@ bool TestDDR5Models(char code) } // Checking Fury signature in the RGB address space -TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr) +TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr, bool (*modelChecker)(char)) { bool passed = true; char test_str[] = "FURY"; @@ -109,7 +205,7 @@ TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr return RESULT_ERROR; } - char shifted = (res >> 8) & 0xff; + char shifted = (res >> 8) & 0xFF; LOG_DEBUG("[%s] Testing address %02X register %02X, res=%02X", FURY_CONTROLLER_NAME, slot_addr, i, shifted); if(shifted != test_str[i-1]) @@ -119,6 +215,22 @@ TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr } } + if(passed) + { + // Get the model code + res = bus->i2c_smbus_read_word_data(slot_addr, FURY_REG_MODEL); + int model_code = res >> 8; + std::this_thread::sleep_for(FURY_DELAY); + LOG_DEBUG("[%s] Reading model code at address %02X register %02X, res=%02X", + FURY_CONTROLLER_NAME, slot_addr, FURY_REG_MODEL, res); + + if(!modelChecker(model_code)) + { + LOG_INFO("[%s] Unknown model code 0x%02X", FURY_CONTROLLER_NAME, model_code); + passed = false; + } + } + // Close transaction res = bus->i2c_smbus_write_byte_data(slot_addr, FURY_REG_APPLY, FURY_END_TRNSFER); if(res < 0) @@ -129,11 +241,7 @@ TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr LOG_DEBUG("[%s] %02X ending transaction; res=%02X", FURY_CONTROLLER_NAME, slot_addr, res); - if(!passed) - { - return RESULT_FAIL; - } - return RESULT_PASS; + return passed ? RESULT_PASS : RESULT_FAIL; } /******************************************************************************************\ @@ -146,50 +254,48 @@ TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr void DetectKingstonFuryDRAMControllers(std::vector &busses) { - enum { FURY_UNKNOWN, FURY_DDR4, FURY_DDR5 } fury_type = FURY_UNKNOWN; + SPDMemoryType fury_type = SPD_RESERVED; for(unsigned int bus = 0; bus < busses.size(); bus++) { IF_DRAM_SMBUS(busses[bus]->pci_vendor, busses[bus]->pci_device) { - std::vector slots; - for(int slot_index = 0; slot_index < FURY_MAX_SLOTS; slot_index++) + TestResult result; + std::vector occupied_slots, fury_slots; + int fury_base_addr; + bool (*modelChecker)(char); + + // Do we have Kingston DRAMs? + result = TestSPDForKingston(busses[bus], fury_type, occupied_slots); + if(result != RESULT_PASS || (fury_type != SPD_DDR4_SDRAM && fury_type != SPD_DDR5_SDRAM)) + { + continue; + } + + if(fury_type == SPD_DDR4_SDRAM) + { + fury_base_addr = FURY_BASE_ADDR_DDR4; + modelChecker = TestDDR4Models; + } + else + { + fury_base_addr = FURY_BASE_ADDR_DDR5; + modelChecker = TestDDR5Models; + } + + // Are these the Kingston Fury DRAMs + for(int slot_index : occupied_slots) { int retries = 0; - TestResult result = RESULT_ERROR; + result = RESULT_ERROR; + while(retries < 3 && result == RESULT_ERROR) { - // Check for DDR4 module (no point, if we already found DDR5 module) - if(fury_type != FURY_DDR5) + result = TestForFurySignature(busses[bus], + fury_base_addr + slot_index, modelChecker); + if(result == RESULT_PASS) { - result = TestForFurySlot(busses[bus], - FURY_BASE_ADDR_DDR4 + slot_index, TestDDR4Models); - if(result == RESULT_PASS) - { - result = TestForFurySignature(busses[bus], - FURY_BASE_ADDR_DDR4 + slot_index); - } - if(result == RESULT_PASS) - { - fury_type = FURY_DDR4; - break; - } - } - // Check for DDR5 module (no point, if we already found DDR4 module) - if(fury_type != FURY_DDR4 && result != RESULT_PASS) - { - result = TestForFurySlot(busses[bus], - FURY_BASE_ADDR_DDR5 + slot_index, TestDDR5Models); - if(result == RESULT_PASS) - { - result = TestForFurySignature(busses[bus], - FURY_BASE_ADDR_DDR5 + slot_index); - } - if(result == RESULT_PASS) - { - fury_type = FURY_DDR5; - break; - } + break; } if(result == RESULT_ERROR) { @@ -204,20 +310,20 @@ void DetectKingstonFuryDRAMControllers(std::vector &busses { LOG_DEBUG("[%s] detected at slot index %d", FURY_CONTROLLER_NAME, slot_index); - slots.push_back(slot_index); + fury_slots.push_back(slot_index); } } - if(!slots.empty() && fury_type != FURY_UNKNOWN) + if(!fury_slots.empty()) { unsigned char base_addr = - (fury_type == FURY_DDR4) ? FURY_BASE_ADDR_DDR4 : FURY_BASE_ADDR_DDR5; + (fury_type == SPD_DDR4_SDRAM) ? FURY_BASE_ADDR_DDR4 : FURY_BASE_ADDR_DDR5; KingstonFuryDRAMController* controller = - new KingstonFuryDRAMController(busses[bus], base_addr, slots); + new KingstonFuryDRAMController(busses[bus], base_addr, fury_slots); RGBController_KingstonFuryDRAM* rgb_controller = new RGBController_KingstonFuryDRAM(controller); rgb_controller->name = - (fury_type == FURY_DDR4) ? "Kingston Fury DDR4 RGB" : "Kingston Fury DDR5 RGB"; + (fury_type == SPD_DDR4_SDRAM) ? "Kingston Fury DDR4 RGB" : "Kingston Fury DDR5 RGB"; ResourceManager::get()->RegisterRGBController(rgb_controller); } }