| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 1 | #include "xdpe1x2xx.hpp" | 
 | 2 |  | 
 | 3 | #include "common/include/i2c/i2c.hpp" | 
 | 4 |  | 
 | 5 | #include <unistd.h> | 
 | 6 |  | 
 | 7 | #include <phosphor-logging/lg2.hpp> | 
 | 8 |  | 
 | 9 | #include <cstdio> | 
 | 10 |  | 
 | 11 | #define REMAINING_TIMES(x, y) (((((x)[1]) << 8) | ((x)[0])) / (y)) | 
 | 12 |  | 
 | 13 | PHOSPHOR_LOG2_USING; | 
 | 14 |  | 
 | 15 | namespace phosphor::software::VR | 
 | 16 | { | 
 | 17 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 18 | enum RevisionCode | 
 | 19 | { | 
 | 20 |     REV_A = 0x00, | 
 | 21 |     REV_B, | 
 | 22 |     REV_C, | 
 | 23 |     REV_D, | 
 | 24 | }; | 
 | 25 |  | 
 | 26 | enum ProductID | 
 | 27 | { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 28 |     ProductIDXDPE15254 = 0x90,   // Revision C,D | 
 | 29 |     ProductIDXDPE15284 = 0x8A,   // Revision A,B,C,D | 
 | 30 |     ProductIDXDPE19283AC = 0x95, // Revision A,B,C | 
 | 31 |     ProductIDXDPE19283D = 0xAE,  // Revision D | 
 | 32 |     ProductIDXDPE192C3AC = 0x96, // Revision A,B,C | 
 | 33 |     ProductIDXDPE192C3D = 0xAF,  // Revision D | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 34 | }; | 
 | 35 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 36 | constexpr uint8_t PMBusICDeviceID = 0xAD; | 
 | 37 | constexpr uint8_t PMBusSTLCml = 0x7E; | 
 | 38 | constexpr uint8_t IFXICDeviceIDLen = 2; | 
 | 39 | constexpr uint8_t IFXMFRAHBAddr = 0xCE; | 
 | 40 | constexpr uint8_t IFXMFRRegWrite = 0xDE; | 
 | 41 | constexpr uint8_t IFXMFRFwCmdData = 0xFD; | 
 | 42 | constexpr uint8_t IFXMFRFwCmd = 0xFE; | 
 | 43 | constexpr uint8_t MFRFwCmdReset = 0x0e; | 
 | 44 | constexpr uint8_t MFRFwCmdRmng = 0x10; | 
 | 45 | constexpr uint8_t MFRFwCmdGetHWAddress = 0x2E; | 
 | 46 | constexpr uint8_t MFRFwCmdOTPConfSTO = 0x11; | 
 | 47 | constexpr uint8_t MFRFwCmdOTPFileInvd = 0x12; | 
 | 48 | constexpr uint8_t MFRFwCmdGetCRC = 0x2D; | 
| Daniel Hsu | 7e0ecac | 2025-06-27 11:02:11 +0800 | [diff] [blame] | 49 | constexpr int XDPE152XXConfSize = 1344; | 
 | 50 | constexpr int XDPE152XXDConfSize = 1312; | 
 | 51 | constexpr int XDPE192XXBConfSize = 1416; // Config(728) + PMBus(568) + SVID(120) | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 52 | constexpr uint8_t VRWarnRemaining = 3; | 
 | 53 | constexpr uint8_t SectTrim = 0x02; | 
 | 54 |  | 
 | 55 | constexpr uint16_t MFRDefaultWaitTime = 20; | 
 | 56 | constexpr uint16_t MFRGetHWAddressWaitTime = 5; | 
 | 57 | constexpr uint16_t MFROTPFileInvalidationWaitTime = 100; | 
 | 58 | constexpr uint16_t MFRSectionInvalidationWaitTime = 4; | 
 | 59 | constexpr uint16_t VRResetDelay = 500; | 
 | 60 |  | 
 | 61 | constexpr uint32_t CRC32Poly = 0xEDB88320; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 62 |  | 
 | 63 | const char* const AddressField = "PMBus Address :"; | 
 | 64 | const char* const ChecksumField = "Checksum :"; | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 65 | const char* const DataStartTag = "[Configuration Data]"; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 66 | const char* const DataEndTag = "[End Configuration Data]"; | 
 | 67 | const char* const DataComment = "//"; | 
 | 68 | const char* const DataXV = "XV"; | 
 | 69 |  | 
 | 70 | XDPE1X2XX::XDPE1X2XX(sdbusplus::async::context& ctx, uint16_t bus, | 
 | 71 |                      uint16_t address) : | 
 | 72 |     VoltageRegulator(ctx), i2cInterface(phosphor::i2c::I2C(bus, address)) | 
 | 73 | {} | 
 | 74 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 75 | sdbusplus::async::task<bool> XDPE1X2XX::getDeviceId(uint8_t* deviceID) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 76 | { | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 77 |     uint8_t tbuf[16] = {0}; | 
 | 78 |     tbuf[0] = PMBusICDeviceID; | 
 | 79 |     tbuf[1] = 2; | 
 | 80 |     uint8_t tSize = 1; | 
 | 81 |     uint8_t rbuf[16] = {0}; | 
 | 82 |     uint8_t rSize = IFXICDeviceIDLen + 1; | 
 | 83 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 84 |     if (!(co_await this->i2cInterface.sendReceive(tbuf, tSize, rbuf, rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 85 |     { | 
 | 86 |         error("Failed to get device ID"); | 
 | 87 |         co_return false; | 
 | 88 |     } | 
 | 89 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 90 |     // According to datasheet: | 
 | 91 |     // rbuf[1]: device revision | 
 | 92 |     // rbuf[2]: device id | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 93 |     std::memcpy(deviceID, &rbuf[1], IFXICDeviceIDLen); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 94 |     info.deviceRev = deviceID[0]; | 
 | 95 |     info.deviceId = deviceID[1]; | 
 | 96 |     debug("VR Device ID: {ID}", "ID", lg2::hex, rbuf[2]); | 
 | 97 |     debug("VR Device Rev: {REV}", "REV", lg2::hex, rbuf[1]); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 98 |  | 
 | 99 |     co_return true; | 
 | 100 | } | 
 | 101 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 102 | sdbusplus::async::task<bool> XDPE1X2XX::mfrFWcmd( | 
 | 103 |     uint8_t cmd, uint16_t processTime, uint8_t* data, uint8_t* resp) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 104 | { | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 105 |     uint8_t tBuf[16] = {0}; | 
 | 106 |     uint8_t rBuf[16] = {0}; | 
 | 107 |     uint8_t tSize = 0; | 
 | 108 |     uint8_t rSize = 0; | 
 | 109 |  | 
 | 110 |     if (data) | 
 | 111 |     { | 
 | 112 |         tBuf[0] = IFXMFRFwCmdData; | 
 | 113 |         tBuf[1] = 4; // Block write 4 bytes | 
 | 114 |         tSize = 6; | 
 | 115 |         std::memcpy(&tBuf[2], data, 4); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 116 |         if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf, | 
 | 117 |                                                       rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 118 |         { | 
 | 119 |             error("Failed to send MFR command: {CMD}", "CMD", | 
 | 120 |                   std::string("IFXMFRFwCmdDAta")); | 
 | 121 |             co_return false; | 
 | 122 |         } | 
 | 123 |     } | 
 | 124 |  | 
 | 125 |     co_await sdbusplus::async::sleep_for(ctx, std::chrono::microseconds(300)); | 
 | 126 |  | 
 | 127 |     tBuf[0] = IFXMFRFwCmd; | 
 | 128 |     tBuf[1] = cmd; | 
 | 129 |     tSize = 2; | 
 | 130 |     rSize = 0; | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 131 |     if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf, rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 132 |     { | 
 | 133 |         error("Failed to send MFR command: {CMD}", "CMD", | 
 | 134 |               std::string("IFXMFRFwCmd")); | 
 | 135 |         co_return false; | 
 | 136 |     } | 
 | 137 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 138 |     co_await sdbusplus::async::sleep_for( | 
 | 139 |         ctx, std::chrono::milliseconds(processTime)); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 140 |  | 
 | 141 |     if (resp) | 
 | 142 |     { | 
 | 143 |         tBuf[0] = IFXMFRFwCmdData; | 
 | 144 |         tSize = 1; | 
 | 145 |         rSize = 6; | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 146 |         if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf, | 
 | 147 |                                                       rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 148 |         { | 
 | 149 |             error("Failed to send MFR command: {CMD}", "CMD", | 
 | 150 |                   std::string("IFXMFRFwCmdData")); | 
 | 151 |             co_return false; | 
 | 152 |         } | 
 | 153 |         if (rBuf[0] != 4) | 
 | 154 |         { | 
 | 155 |             error( | 
 | 156 |                 "Failed to receive MFR response with unexpected response size"); | 
 | 157 |             co_return false; | 
 | 158 |         } | 
 | 159 |         std::memcpy(resp, rBuf + 1, 4); | 
 | 160 |     } | 
 | 161 |  | 
 | 162 |     co_return true; | 
 | 163 | } | 
 | 164 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 165 | sdbusplus::async::task<bool> XDPE1X2XX::getRemainingWrites(uint8_t* remain) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 166 | { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 167 |     // According to datasheet: | 
 | 168 |     // remaingin OTP size = rBuf[0] + 256 * rBuf[1] | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 169 |     uint8_t tBuf[16] = {0}; | 
 | 170 |     uint8_t rBuf[16] = {0}; | 
 | 171 |     uint8_t devId[2] = {0}; | 
 | 172 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 173 |     if (!(co_await this->mfrFWcmd(MFRFwCmdRmng, MFRDefaultWaitTime, tBuf, | 
 | 174 |                                   rBuf))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 175 |     { | 
 | 176 |         error("Failed to request remaining writes"); | 
 | 177 |         co_return false; | 
 | 178 |     } | 
 | 179 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 180 |     if (!(co_await this->getDeviceId(devId))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 181 |     { | 
 | 182 |         error("Failed to request device ID for remaining writes"); | 
 | 183 |         co_return false; | 
 | 184 |     } | 
 | 185 |  | 
 | 186 |     int configSize = getConfigSize(devId[1], devId[0]); | 
 | 187 |     if (configSize < 0) | 
 | 188 |     { | 
 | 189 |         error("Failed to request valid configuration size"); | 
 | 190 |         co_return false; | 
 | 191 |     } | 
 | 192 |  | 
 | 193 |     *remain = REMAINING_TIMES(rBuf, configSize); | 
 | 194 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 195 |     co_return true; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 196 | } | 
 | 197 |  | 
 | 198 | int XDPE1X2XX::getConfigSize(uint8_t deviceId, uint8_t revision) | 
 | 199 | { | 
| Daniel Hsu | 7e0ecac | 2025-06-27 11:02:11 +0800 | [diff] [blame] | 200 |     static const std::map<std::pair<uint8_t, uint8_t>, int> configSizeMap = { | 
 | 201 |         {{ProductIDXDPE19283AC, REV_B}, XDPE192XXBConfSize}, | 
 | 202 |         {{ProductIDXDPE15284, REV_A}, XDPE152XXConfSize}, | 
 | 203 |         {{ProductIDXDPE15284, REV_B}, XDPE152XXConfSize}, | 
 | 204 |         {{ProductIDXDPE15284, REV_C}, XDPE152XXConfSize}, | 
 | 205 |         {{ProductIDXDPE15284, REV_D}, XDPE152XXDConfSize}, | 
 | 206 |         {{ProductIDXDPE192C3AC, REV_B}, XDPE192XXBConfSize}, | 
 | 207 |     }; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 208 |  | 
| Daniel Hsu | 7e0ecac | 2025-06-27 11:02:11 +0800 | [diff] [blame] | 209 |     auto it = configSizeMap.find({deviceId, revision}); | 
 | 210 |     if (it != configSizeMap.end()) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 211 |     { | 
| Daniel Hsu | 7e0ecac | 2025-06-27 11:02:11 +0800 | [diff] [blame] | 212 |         return it->second; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 213 |     } | 
 | 214 |  | 
| Daniel Hsu | 7e0ecac | 2025-06-27 11:02:11 +0800 | [diff] [blame] | 215 |     error("Failed to get configuration size of {DEVID} with revision {REV}", | 
 | 216 |           "DEVID", deviceId, "REV", revision); | 
 | 217 |     return -1; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 218 | } | 
 | 219 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 220 | sdbusplus::async::task<bool> XDPE1X2XX::getCRC(uint32_t* checksum) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 221 | { | 
 | 222 |     uint8_t tBuf[16] = {0}; | 
 | 223 |     uint8_t rBuf[16] = {0}; | 
 | 224 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 225 |     if (!(co_await this->mfrFWcmd(MFRFwCmdGetCRC, MFRDefaultWaitTime, tBuf, | 
 | 226 |                                   rBuf))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 227 |     { | 
 | 228 |         error("Failed to get CRC value"); | 
 | 229 |         co_return false; | 
 | 230 |     } | 
 | 231 |  | 
 | 232 |     *checksum = (static_cast<uint32_t>(rBuf[3]) << 24) | | 
 | 233 |                 (static_cast<uint32_t>(rBuf[2]) << 16) | | 
 | 234 |                 (static_cast<uint32_t>(rBuf[1]) << 8) | | 
 | 235 |                 (static_cast<uint32_t>(rBuf[0])); | 
 | 236 |  | 
 | 237 |     co_return true; | 
 | 238 | } | 
 | 239 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 240 | sdbusplus::async::task<bool> XDPE1X2XX::program(bool force) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 241 | { | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 242 |     uint8_t tBuf[16] = {0}; | 
 | 243 |     uint8_t rBuf[16] = {0}; | 
 | 244 |     uint8_t remain = 0; | 
 | 245 |     uint32_t sum = 0; | 
 | 246 |     int size = 0; | 
 | 247 |  | 
 | 248 |     // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch) | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 249 |     if (!(co_await getCRC(&sum))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 250 |     // NOLINTEND(clang-analyzer-core.uninitialized.Branch) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 251 |     { | 
 | 252 |         error("Failed to program the VR"); | 
 | 253 |         co_return -1; | 
 | 254 |     } | 
 | 255 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 256 |     debug("CRC before programming: {CRC}", "CRC", lg2::hex, sum); | 
 | 257 |     debug("CRC of configuration: {CRC}", "CRC", lg2::hex, configuration.sumExp); | 
 | 258 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 259 |     if (!force && (sum == configuration.sumExp)) | 
 | 260 |     { | 
 | 261 |         error("Failed to program the VR - CRC value are equal with no force"); | 
 | 262 |         co_return -1; | 
 | 263 |     } | 
 | 264 |  | 
 | 265 |     // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch) | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 266 |     if (!(co_await this->getRemainingWrites(&remain))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 267 |     // NOLINTEND(clang-analyzer-core.uninitialized.Branch) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 268 |     { | 
 | 269 |         error("Failed to program the VR - unable to obtain remaing writes"); | 
 | 270 |         co_return -1; | 
 | 271 |     } | 
 | 272 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 273 |     debug("Remaining write cycles of VR: {REMAIN}", "REMAIN", remain); | 
 | 274 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 275 |     if (!remain) | 
 | 276 |     { | 
 | 277 |         error("Failed to program the VR - no remaining write cycles left"); | 
 | 278 |         co_return -1; | 
 | 279 |     } | 
 | 280 |  | 
 | 281 |     if (!force && (remain <= VRWarnRemaining)) | 
 | 282 |     { | 
 | 283 |         error( | 
 | 284 |             "Failed to program the VR - {REMAIN} remaining writes left and not force", | 
 | 285 |             "REMAIN", remain); | 
 | 286 |         co_return -1; | 
 | 287 |     } | 
 | 288 |  | 
 | 289 |     // Added reprogramming of the entire configuration file. | 
 | 290 |     // Except for the trim section, all other data will be replaced. | 
 | 291 |     // 0xfe 0xfe 0x00 0x00 instructs the command to reprogram all header codes | 
 | 292 |     // and XVcode. If the old sections are not invalidated in OTP, they can | 
 | 293 |     // affect the CRC calculation. | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 294 |     debug("Invalidate current Configuration"); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 295 |  | 
 | 296 |     tBuf[0] = 0xfe; | 
 | 297 |     tBuf[1] = 0xfe; | 
 | 298 |     tBuf[2] = 0x00; | 
 | 299 |     tBuf[3] = 0x00; | 
 | 300 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 301 |     if (!(co_await this->mfrFWcmd(MFRFwCmdOTPFileInvd, | 
 | 302 |                                   MFROTPFileInvalidationWaitTime, tBuf, NULL))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 303 |     { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 304 |         error("Failed to program the VR - Invalidation of current FW"); | 
 | 305 |         co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 306 |     } | 
 | 307 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 308 |     for (int i = 0; i < configuration.sectCnt; i++) | 
 | 309 |     { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 310 |         debug("Programming section: {SEC}", "SEC", i); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 311 |         struct configSect* sect = &configuration.section[i]; | 
 | 312 |         if (sect == NULL) | 
 | 313 |         { | 
 | 314 |             error( | 
 | 315 |                 "Failed to program the VR - unexpected NULL section in config"); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 316 |             co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 317 |         } | 
 | 318 |  | 
 | 319 |         if ((i <= 0) || (sect->type != configuration.section[i - 1].type)) | 
 | 320 |         { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 321 |             debug("Section Type: {TYPE}", "TYPE", lg2::hex, | 
 | 322 |                   configuration.section[i].type); | 
 | 323 |  | 
 | 324 |             // clear bit0 of PMBUS_STS_CML | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 325 |             tBuf[0] = PMBusSTLCml; | 
 | 326 |             tBuf[1] = 0x1; | 
 | 327 |             uint8_t tSize = 2; | 
 | 328 |             uint8_t rSize = 0; | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 329 |             if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf, | 
 | 330 |                                                           rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 331 |             { | 
 | 332 |                 error("Failed to program the VR on sendReceive {CMD}", "CMD", | 
 | 333 |                       std::string("PMBusSTLCml")); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 334 |                 co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 335 |             } | 
 | 336 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 337 |             debug("Invalidating section type: {TYPE}", "TYPE", sect->type); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 338 |             tBuf[0] = sect->type; | 
 | 339 |             tBuf[1] = 0x00; | 
 | 340 |             tBuf[2] = 0x00; | 
 | 341 |             tBuf[3] = 0x00; | 
 | 342 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 343 |             if (!(co_await this->mfrFWcmd(MFRFwCmdOTPFileInvd, | 
 | 344 |                                           MFRSectionInvalidationWaitTime, tBuf, | 
 | 345 |                                           NULL))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 346 |             { | 
 | 347 |                 error("Failed to program VR on mfrFWCmd on {CMD}", "CMD", | 
 | 348 |                       std::string("MFRFwCmdOTPFileInvd")); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 349 |                 co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 350 |             } | 
 | 351 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 352 |             // set scratchpad addr | 
 | 353 |             // XDPE192XX Rev A/B: 0x2005e000 | 
 | 354 |             //           Rev C  : 0x2005e400 | 
 | 355 |             //           Rev D  : 0x2005f000 | 
 | 356 |  | 
 | 357 |             debug("Setting scratchpad address: {ADDR}", "ADDR", lg2::hex, | 
 | 358 |                   info.scratchPadAddress); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 359 |  | 
 | 360 |             tBuf[0] = IFXMFRAHBAddr; | 
 | 361 |             tBuf[1] = 4; | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 362 |             tBuf[2] = (info.scratchPadAddress) & 0xFF; | 
 | 363 |             tBuf[3] = (info.scratchPadAddress >> 8) & 0xFF; | 
 | 364 |             tBuf[4] = (info.scratchPadAddress >> 16) & 0xFF; | 
 | 365 |             tBuf[5] = (info.scratchPadAddress >> 24) & 0xFF; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 366 |             tSize = 6; | 
 | 367 |             rSize = 0; | 
 | 368 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 369 |             if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf, | 
 | 370 |                                                           rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 371 |             { | 
 | 372 |                 error("Failed to program VR on sendReceive on {CMD}", "CMD", | 
 | 373 |                       std::string("IFXMFRAHBAddr")); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 374 |                 co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 375 |             } | 
 | 376 |  | 
 | 377 |             co_await sdbusplus::async::sleep_for( | 
 | 378 |                 ctx, std::chrono::microseconds(10000)); | 
 | 379 |             size = 0; | 
 | 380 |         } | 
 | 381 |  | 
 | 382 |         // programm into scratchpad | 
 | 383 |         for (int j = 0; j < sect->dataCnt; j++) | 
 | 384 |         { | 
 | 385 |             tBuf[0] = IFXMFRRegWrite; | 
 | 386 |             tBuf[1] = 4; | 
 | 387 |             uint8_t tSize = 6; | 
 | 388 |             uint8_t rSize = 0; | 
 | 389 |             memcpy(&tBuf[2], §->data[j], 4); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 390 |             if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf, | 
 | 391 |                                                           rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 392 |             { | 
 | 393 |                 error("Failed to program the VR on sendReceive {CMD}", "CMD", | 
 | 394 |                       std::string("IFXMFRRegWrite")); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 395 |                 co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 396 |             } | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 397 |             co_await sdbusplus::async::sleep_for(ctx, | 
 | 398 |                                                  std::chrono::milliseconds(10)); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 399 |         } | 
 | 400 |  | 
 | 401 |         size += sect->dataCnt * 4; | 
 | 402 |         if ((i + 1 >= configuration.sectCnt) || | 
 | 403 |             (sect->type != configuration.section[i + 1].type)) | 
 | 404 |         { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 405 |             // wait for programming soak (2ms/byte, at least 200ms) | 
 | 406 |             // ex: Config (604 bytes): (604 / 50) + 2 = 14 (1400 ms) | 
 | 407 |             uint16_t soakTime = 100 * ((size / 50) + 2); | 
 | 408 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 409 |             // Upload to scratchpad | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 410 |             debug("Upload from scratch pad to OTP with soak time: {TIME}ms", | 
 | 411 |                   "TIME", soakTime); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 412 |             std::memcpy(tBuf, &size, 2); | 
 | 413 |             tBuf[2] = 0x00; | 
 | 414 |             tBuf[3] = 0x00; | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 415 |             if (!(co_await this->mfrFWcmd(MFRFwCmdOTPConfSTO, soakTime, tBuf, | 
 | 416 |                                           NULL))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 417 |             { | 
 | 418 |                 error("Failed to program the VR on mfrFWcmd {CMD}", "CMD", | 
 | 419 |                       std::string("MFRFwCmdOTPConfSTO")); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 420 |                 co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 421 |             } | 
 | 422 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 423 |             // Read status faults after programming | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 424 |             tBuf[0] = PMBusSTLCml; | 
 | 425 |             uint8_t tSize = 1; | 
 | 426 |             uint8_t rSize = 1; | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 427 |             if (!(co_await this->i2cInterface.sendReceive(rBuf, tSize, tBuf, | 
 | 428 |                                                           rSize))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 429 |             { | 
 | 430 |                 error("Failed to program VR on sendReceive {CMD}", "CMD", | 
 | 431 |                       std::string("PMBusSTLCml")); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 432 |                 co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 433 |             } | 
 | 434 |             if (rBuf[0] & 0x01) | 
 | 435 |             { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 436 |                 error("Failed to program VR - status fault indicated error"); | 
 | 437 |                 co_return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 438 |             } | 
 | 439 |         } | 
 | 440 |     } | 
 | 441 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 442 |     co_return true; | 
 | 443 | } | 
 | 444 |  | 
 | 445 | int XDPE1X2XX::lineSplit(char** dest, char* src, char* delim) | 
 | 446 | { | 
 | 447 |     char* s = strtok(src, delim); | 
 | 448 |     int size = 0; | 
 | 449 |     int maxSz = 5; | 
 | 450 |  | 
 | 451 |     while (s) | 
 | 452 |     { | 
 | 453 |         *dest++ = s; | 
 | 454 |         if ((++size) >= maxSz) | 
 | 455 |         { | 
 | 456 |             break; | 
 | 457 |         } | 
 | 458 |         s = strtok(NULL, delim); | 
 | 459 |     } | 
 | 460 |  | 
 | 461 |     return size; | 
 | 462 | } | 
 | 463 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 464 | bool XDPE1X2XX::parseImage(const uint8_t* image, size_t image_size) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 465 | { | 
 | 466 |     size_t lenEndTag = strlen(DataEndTag); | 
 | 467 |     size_t lenStartTag = strlen(DataStartTag); | 
 | 468 |     size_t lenComment = strlen(DataComment); | 
 | 469 |     size_t lenXV = strlen(DataXV); | 
 | 470 |     size_t start = 0; | 
 | 471 |     const int maxLineLength = 40; | 
 | 472 |     char line[maxLineLength]; | 
 | 473 |     char* token = NULL; | 
 | 474 |     bool isData = false; | 
 | 475 |     char delim = ' '; | 
 | 476 |     uint16_t offset; | 
 | 477 |     uint8_t sectType = 0x0; | 
 | 478 |     uint32_t dWord; | 
 | 479 |     int dataCnt = 0; | 
 | 480 |     int sectIndex = -1; | 
 | 481 |  | 
 | 482 |     for (size_t i = 0; i < image_size; i++) | 
 | 483 |     { | 
 | 484 |         if (image[i] == '\n') | 
 | 485 |         { | 
 | 486 |             std::memcpy(line, image + start, i - start); | 
 | 487 |             if (!strncmp(line, DataComment, lenComment)) | 
 | 488 |             { | 
 | 489 |                 token = line + lenComment; | 
 | 490 |                 if (!strncmp(token, DataXV, lenXV)) | 
 | 491 |                 { | 
 | 492 |                     debug("Parsing: {OBJ}", "OBJ", | 
 | 493 |                           reinterpret_cast<const char*>(line)); | 
 | 494 |                 } | 
 | 495 |                 start = i + 1; | 
 | 496 |                 continue; | 
 | 497 |             } | 
 | 498 |             if (!strncmp(line, DataEndTag, lenEndTag)) | 
 | 499 |             { | 
 | 500 |                 debug("Parsing: {OBJ}", "OBJ", | 
 | 501 |                       reinterpret_cast<const char*>(line)); | 
 | 502 |                 break; | 
 | 503 |             } | 
 | 504 |             else if (isData) | 
 | 505 |             { | 
 | 506 |                 char* tokenList[8] = {0}; | 
 | 507 |                 int tokenSize = lineSplit(tokenList, line, &delim); | 
 | 508 |                 if (tokenSize < 1) | 
 | 509 |                 { | 
 | 510 |                     start = i + 1; | 
 | 511 |                     continue; | 
 | 512 |                 } | 
 | 513 |  | 
 | 514 |                 offset = (uint16_t)strtol(tokenList[0], NULL, 16); | 
 | 515 |                 if (sectType == SectTrim && offset != 0x0) | 
 | 516 |                 { | 
 | 517 |                     continue; | 
 | 518 |                 } | 
 | 519 |  | 
 | 520 |                 for (int i = 1; i < tokenSize; i++) | 
 | 521 |                 { | 
| Daniel Hsu | 7e0ecac | 2025-06-27 11:02:11 +0800 | [diff] [blame] | 522 |                     dWord = (uint32_t)strtoul(tokenList[i], NULL, 16); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 523 |                     if ((offset == 0x0) && (i == 1)) | 
 | 524 |                     { | 
 | 525 |                         sectType = (uint8_t)dWord; | 
 | 526 |                         if (sectType == SectTrim) | 
 | 527 |                         { | 
 | 528 |                             break; | 
 | 529 |                         } | 
 | 530 |                         if ((++sectIndex) >= MaxSectCnt) | 
 | 531 |                         { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 532 |                             return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 533 |                         } | 
 | 534 |  | 
 | 535 |                         configuration.section[sectIndex].type = sectType; | 
 | 536 |                         configuration.sectCnt = sectIndex + 1; | 
 | 537 |                         dataCnt = 0; | 
 | 538 |                     } | 
 | 539 |  | 
 | 540 |                     if (dataCnt >= MaxSectDataCnt) | 
 | 541 |                     { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 542 |                         return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 543 |                     } | 
 | 544 |  | 
 | 545 |                     configuration.section[sectIndex].data[dataCnt++] = dWord; | 
 | 546 |                     configuration.section[sectIndex].dataCnt = dataCnt; | 
 | 547 |                     configuration.totalCnt++; | 
 | 548 |                 } | 
 | 549 |             } | 
 | 550 |             else | 
 | 551 |             { | 
 | 552 |                 if ((token = strstr(line, AddressField)) != NULL) | 
 | 553 |                 { | 
 | 554 |                     if ((token = strstr(token, "0x")) != NULL) | 
 | 555 |                     { | 
 | 556 |                         configuration.addr = | 
 | 557 |                             (uint8_t)(strtoul(token, NULL, 16) << 1); | 
 | 558 |                     } | 
 | 559 |                 } | 
 | 560 |                 else if ((token = strstr(line, ChecksumField)) != NULL) | 
 | 561 |                 { | 
 | 562 |                     if ((token = strstr(token, "0x")) != NULL) | 
 | 563 |                     { | 
 | 564 |                         configuration.sumExp = | 
 | 565 |                             (uint32_t)strtoul(token, NULL, 16); | 
 | 566 |                     } | 
 | 567 |                 } | 
 | 568 |                 else if (!strncmp(line, DataStartTag, lenStartTag)) | 
 | 569 |                 { | 
 | 570 |                     isData = true; | 
 | 571 |                     start = i + 1; | 
 | 572 |                     continue; | 
 | 573 |                 } | 
 | 574 |                 else | 
 | 575 |                 { | 
 | 576 |                     start = i + 1; | 
 | 577 |                     continue; | 
 | 578 |                 } | 
 | 579 |             } | 
 | 580 |             start = i + 1; | 
 | 581 |         } | 
 | 582 |     } | 
 | 583 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 584 |     return true; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 585 | } | 
 | 586 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 587 | bool XDPE1X2XX::checkImage() | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 588 | { | 
 | 589 |     uint8_t i; | 
 | 590 |     uint32_t crc; | 
 | 591 |     uint32_t sum = 0; | 
 | 592 |  | 
 | 593 |     for (i = 0; i < configuration.sectCnt; i++) | 
 | 594 |     { | 
 | 595 |         struct configSect* sect = &configuration.section[i]; | 
 | 596 |         if (sect == NULL) | 
 | 597 |         { | 
 | 598 |             error("Failed to check image - unexpected NULL section"); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 599 |             return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 600 |         } | 
 | 601 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 602 |         crc = calcCRC32(§->data[0], 2); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 603 |         if (crc != sect->data[2]) | 
 | 604 |         { | 
 | 605 |             error("Failed to check image - first CRC value mismatch"); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 606 |             return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 607 |         } | 
 | 608 |         sum += crc; | 
 | 609 |  | 
 | 610 |         // check CRC of section data | 
 | 611 |         crc = calcCRC32(§->data[3], sect->dataCnt - 4); | 
 | 612 |         if (crc != sect->data[sect->dataCnt - 1]) | 
 | 613 |         { | 
 | 614 |             error("Failed to check image - second CRC value mismatch"); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 615 |             return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 616 |         } | 
 | 617 |         sum += crc; | 
 | 618 |     } | 
 | 619 |  | 
 | 620 |     if (sum != configuration.sumExp) | 
 | 621 |     { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 622 |         debug("Calculated CRC: {CRC}", "CRC", lg2::hex, sum); | 
 | 623 |         debug("Config CRC {CRC}", "CRC", lg2::hex, configuration.sumExp); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 624 |         error("Failed to check image - third CRC value mismatch"); | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 625 |         return false; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 626 |     } | 
 | 627 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 628 |     return true; | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 629 | } | 
 | 630 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 631 | sdbusplus::async::task<bool> XDPE1X2XX::verifyImage(const uint8_t* image, | 
 | 632 |                                                     size_t imageSize) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 633 | { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 634 |     if (!parseImage(image, imageSize)) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 635 |     { | 
 | 636 |         error("Failed to update firmware on parsing Image"); | 
 | 637 |         co_return false; | 
 | 638 |     } | 
 | 639 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 640 |     if (!checkImage()) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 641 |     { | 
 | 642 |         error("Failed to update firmware on check image"); | 
 | 643 |         co_return false; | 
 | 644 |     } | 
 | 645 |  | 
 | 646 |     co_return true; | 
 | 647 | } | 
 | 648 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 649 | sdbusplus::async::task<bool> XDPE1X2XX::getScratchPadAddress() | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 650 | { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 651 |     uint8_t tbuf[16] = {0}; | 
 | 652 |     uint8_t rbuf[16] = {0}; | 
 | 653 |  | 
 | 654 |     tbuf[0] = 0x02; | 
 | 655 |     tbuf[1] = 0x00; | 
 | 656 |     tbuf[2] = 0x00; | 
 | 657 |     tbuf[3] = 0x00; | 
 | 658 |  | 
 | 659 |     if (!(co_await mfrFWcmd(MFRFwCmdGetHWAddress, MFRGetHWAddressWaitTime, tbuf, | 
 | 660 |                             rbuf))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 661 |     { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 662 |         error("mfrFWcmd call failed to retrieve scratchpad address"); | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 663 |         co_return false; | 
 | 664 |     } | 
 | 665 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 666 |     info.scratchPadAddress = (static_cast<uint32_t>(rbuf[3]) << 24) | | 
 | 667 |                              (static_cast<uint32_t>(rbuf[2]) << 16) | | 
 | 668 |                              (static_cast<uint32_t>(rbuf[1]) << 8) | | 
 | 669 |                              (static_cast<uint32_t>(rbuf[0])); | 
 | 670 |  | 
 | 671 |     debug("Scratchpad Address: {ADDR}", "ADDR", lg2::hex, | 
 | 672 |           info.scratchPadAddress); | 
 | 673 |  | 
 | 674 |     co_return true; | 
 | 675 | } | 
 | 676 |  | 
 | 677 | sdbusplus::async::task<bool> XDPE1X2XX::updateFirmware(bool force) | 
 | 678 | { | 
 | 679 |     bool ret = true; | 
 | 680 |     if (!(co_await getScratchPadAddress())) | 
 | 681 |     { | 
 | 682 |         error("Failed to retrieve scratchpad address"); | 
 | 683 |         co_return false; | 
 | 684 |     } | 
 | 685 |  | 
 | 686 |     // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch) | 
 | 687 |     ret = co_await program(force); | 
 | 688 |     if (!ret) | 
 | 689 |     // NOLINTEND(clang-analyzer-core.uninitialized.Branch) | 
 | 690 |     { | 
 | 691 |         error("Failed to update firmware on program"); | 
 | 692 |     } | 
 | 693 |  | 
 | 694 |     info.deviceId = 0; | 
 | 695 |     info.deviceRev = 0; | 
 | 696 |     info.remainingWrites = 0; | 
 | 697 |     info.scratchPadAddress = 0; | 
 | 698 |     info.actualCRC = 0; | 
 | 699 |     info.configSize = 0; | 
 | 700 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 701 |     // Reset the configuration | 
 | 702 |     configuration.addr = 0; | 
 | 703 |     configuration.totalCnt = 0; | 
 | 704 |     configuration.sumExp = 0; | 
 | 705 |     configuration.sectCnt = 0; | 
 | 706 |     for (int i = 0; i <= MaxSectCnt - 1; i++) | 
 | 707 |     { | 
 | 708 |         configuration.section[i].type = 0; | 
 | 709 |         configuration.section[i].dataCnt = 0; | 
 | 710 |         for (int j = 0; j <= MaxSectDataCnt; j++) | 
 | 711 |         { | 
 | 712 |             configuration.section[i].data[j] = 0; | 
 | 713 |         } | 
 | 714 |     } | 
 | 715 |  | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 716 |     if (!ret) | 
 | 717 |     { | 
 | 718 |         co_return false; | 
 | 719 |     } | 
 | 720 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 721 |     co_return true; | 
 | 722 | } | 
 | 723 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 724 | sdbusplus::async::task<bool> XDPE1X2XX::reset() | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 725 | { | 
| Christopher Meis | fd34144 | 2025-06-16 14:34:51 +0200 | [diff] [blame] | 726 |     if (!(co_await mfrFWcmd(MFRFwCmdReset, VRResetDelay, NULL, NULL))) | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 727 |     { | 
 | 728 |         error("Failed to reset the VR"); | 
 | 729 |         co_return false; | 
 | 730 |     } | 
 | 731 |  | 
| Christopher Meis | 7e446a4 | 2024-10-22 09:36:41 +0200 | [diff] [blame] | 732 |     co_return true; | 
 | 733 | } | 
 | 734 |  | 
 | 735 | uint32_t XDPE1X2XX::calcCRC32(const uint32_t* data, int len) | 
 | 736 | { | 
 | 737 |     if (data == NULL) | 
 | 738 |     { | 
 | 739 |         return 0; | 
 | 740 |     } | 
 | 741 |  | 
 | 742 |     uint32_t crc = 0xFFFFFFFF; | 
 | 743 |     for (int i = 0; i < len; i++) | 
 | 744 |     { | 
 | 745 |         crc ^= data[i]; | 
 | 746 |  | 
 | 747 |         for (int b = 0; b < 32; b++) | 
 | 748 |         { | 
 | 749 |             if (crc & 0x1) | 
 | 750 |             { | 
 | 751 |                 crc = (crc >> 1) ^ CRC32Poly; // lsb-first | 
 | 752 |             } | 
 | 753 |             else | 
 | 754 |             { | 
 | 755 |                 crc >>= 1; | 
 | 756 |             } | 
 | 757 |         } | 
 | 758 |     } | 
 | 759 |  | 
 | 760 |     return ~crc; | 
 | 761 | } | 
 | 762 |  | 
 | 763 | bool XDPE1X2XX::forcedUpdateAllowed() | 
 | 764 | { | 
 | 765 |     return true; | 
 | 766 | } | 
 | 767 |  | 
 | 768 | } // namespace phosphor::software::VR |