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