-
-
Notifications
You must be signed in to change notification settings - Fork 222
/
Copy pathDDR5DirectAccessor.cpp
122 lines (103 loc) · 4.03 KB
/
DDR5DirectAccessor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*---------------------------------------------------------*\
| DDR5DirectAccessor.cpp |
| |
| DDR5 SPD accessor implementation using direct i2c |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include "DDR5DirectAccessor.h"
#include "LogManager.h"
using namespace std::chrono_literals;
DDR5DirectAccessor::DDR5DirectAccessor(i2c_smbus_interface *bus, uint8_t spd_addr)
: DDR5Accessor(bus, spd_addr)
{
}
DDR5DirectAccessor::~DDR5DirectAccessor()
{
}
bool DDR5DirectAccessor::isAvailable(i2c_smbus_interface *bus, uint8_t spd_addr)
{
bool retry = true;
while(true)
{
std::this_thread::sleep_for(SPD_IO_DELAY);
int ddr5Magic = bus->i2c_smbus_read_byte_data(spd_addr, 0x00);
std::this_thread::sleep_for(SPD_IO_DELAY);
int ddr5Sensor = bus->i2c_smbus_read_byte_data(spd_addr, 0x01);
std::this_thread::sleep_for(SPD_IO_DELAY);
if(ddr5Magic < 0 || ddr5Sensor < 0)
{
break;
}
LOG_TRACE("[DDR5DirectAccessor] SPD Hub Magic: 0x%02x 0x%02x", ddr5Magic, ddr5Sensor);
if(ddr5Magic == 0x51 && (ddr5Sensor & 0xEF) == 0x08)
{
return true;
}
int page = bus->i2c_smbus_read_byte_data(spd_addr, SPD_DDR5_MREG_VIRTUAL_PAGE);
std::this_thread::sleep_for(SPD_IO_DELAY);
LOG_TRACE("[DDR5DirectAccessor] SPD Page: 0x%02x", page);
if(page < 0)
{
break;
}
else if(retry && page > 0 && page < (SPD_DDR5_EEPROM_LENGTH >> SPD_DDR5_EEPROM_PAGE_SHIFT))
{
// This still might be a DDR5 module, just the page is off
bus->i2c_smbus_write_byte_data(spd_addr, SPD_DDR5_MREG_VIRTUAL_PAGE, 0);
std::this_thread::sleep_for(SPD_IO_DELAY);
retry = false;
}
else
{
break;
}
}
return false;
}
SPDAccessor *DDR5DirectAccessor::copy()
{
DDR5DirectAccessor *access = new DDR5DirectAccessor(bus, address);
access->current_page = this->current_page;
return access;
}
uint8_t DDR5DirectAccessor::at(uint16_t addr)
{
/*-----------------------------------------------------*\
| Ensure address is valid |
\*-----------------------------------------------------*/
if(addr >= SPD_DDR5_EEPROM_LENGTH)
{
return 0xFF;
}
/*-----------------------------------------------------*\
| Switch to the page containing address |
\*-----------------------------------------------------*/
set_page(addr >> SPD_DDR5_EEPROM_PAGE_SHIFT);
/*-----------------------------------------------------*\
| Calculate offset |
\*-----------------------------------------------------*/
uint8_t offset = (uint8_t)(addr & SPD_DDR5_EEPROM_PAGE_MASK) | 0x80;
/*-----------------------------------------------------*\
| Read value at address |
\*-----------------------------------------------------*/
uint32_t value = bus->i2c_smbus_read_byte_data(address, offset);
std::this_thread::sleep_for(SPD_IO_DELAY);
/*-----------------------------------------------------*\
| Return value |
\*-----------------------------------------------------*/
return((uint8_t)value);
}
void DDR5DirectAccessor::set_page(uint8_t page)
{
/*-----------------------------------------------------*\
| Switch page if not already active |
\*-----------------------------------------------------*/
if(current_page != page)
{
bus->i2c_smbus_write_byte_data(address, SPD_DDR5_MREG_VIRTUAL_PAGE, page);
current_page = page;
std::this_thread::sleep_for(SPD_IO_DELAY);
}
}