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