xref: /openbmc/phosphor-bmc-code-mgmt/i2c-vr/xdpe1x2xx/xdpe1x2xx.cpp (revision 7f2658989dd4e336712a0d373dc66937911b68eb)
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 XDPE152XXConfSize = 1344;
50 constexpr int XDPE152XXDConfSize = 1312;
51 constexpr int XDPE192XXBConfSize = 1416; // Config(728) + PMBus(568) + SVID(120)
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;
62 
63 const char* const AddressField = "PMBus Address :";
64 const char* const ChecksumField = "Checksum :";
65 const char* const DataStartTag = "[Configuration Data]";
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 
75 sdbusplus::async::task<bool> XDPE1X2XX::getDeviceId(uint8_t* deviceID)
76 {
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 
84     if (!(co_await this->i2cInterface.sendReceive(tbuf, tSize, rbuf, rSize)))
85     {
86         error("Failed to get device ID");
87         co_return false;
88     }
89 
90     // According to datasheet:
91     // rbuf[1]: device revision
92     // rbuf[2]: device id
93     std::memcpy(deviceID, &rbuf[1], IFXICDeviceIDLen);
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]);
98 
99     co_return true;
100 }
101 
102 sdbusplus::async::task<bool> XDPE1X2XX::mfrFWcmd(
103     uint8_t cmd, uint16_t processTime, uint8_t* data, uint8_t* resp)
104 {
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);
116         if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf,
117                                                       rSize)))
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;
131     if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf, rSize)))
132     {
133         error("Failed to send MFR command: {CMD}", "CMD",
134               std::string("IFXMFRFwCmd"));
135         co_return false;
136     }
137 
138     co_await sdbusplus::async::sleep_for(
139         ctx, std::chrono::milliseconds(processTime));
140 
141     if (resp)
142     {
143         tBuf[0] = IFXMFRFwCmdData;
144         tSize = 1;
145         rSize = 6;
146         if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf,
147                                                       rSize)))
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 
165 sdbusplus::async::task<bool> XDPE1X2XX::getRemainingWrites(uint8_t* remain)
166 {
167     // According to datasheet:
168     // remaingin OTP size = rBuf[0] + 256 * rBuf[1]
169     uint8_t tBuf[16] = {0};
170     uint8_t rBuf[16] = {0};
171     uint8_t devId[2] = {0};
172 
173     if (!(co_await this->mfrFWcmd(MFRFwCmdRmng, MFRDefaultWaitTime, tBuf,
174                                   rBuf)))
175     {
176         error("Failed to request remaining writes");
177         co_return false;
178     }
179 
180     if (!(co_await this->getDeviceId(devId)))
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 
195     co_return true;
196 }
197 
198 int XDPE1X2XX::getConfigSize(uint8_t deviceId, uint8_t revision)
199 {
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     };
208 
209     auto it = configSizeMap.find({deviceId, revision});
210     if (it != configSizeMap.end())
211     {
212         return it->second;
213     }
214 
215     error("Failed to get configuration size of {DEVID} with revision {REV}",
216           "DEVID", deviceId, "REV", revision);
217     return -1;
218 }
219 
220 sdbusplus::async::task<bool> XDPE1X2XX::getCRC(uint32_t* checksum)
221 {
222     uint8_t tBuf[16] = {0};
223     uint8_t rBuf[16] = {0};
224 
225     if (!(co_await this->mfrFWcmd(MFRFwCmdGetCRC, MFRDefaultWaitTime, tBuf,
226                                   rBuf)))
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 
240 sdbusplus::async::task<bool> XDPE1X2XX::program(bool force)
241 {
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)
249     if (!(co_await getCRC(&sum)))
250     // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
251     {
252         error("Failed to program the VR");
253         co_return -1;
254     }
255 
256     debug("CRC before programming: {CRC}", "CRC", lg2::hex, sum);
257     debug("CRC of configuration: {CRC}", "CRC", lg2::hex, configuration.sumExp);
258 
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)
266     if (!(co_await this->getRemainingWrites(&remain)))
267     // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
268     {
269         error("Failed to program the VR - unable to obtain remaing writes");
270         co_return -1;
271     }
272 
273     debug("Remaining write cycles of VR: {REMAIN}", "REMAIN", remain);
274 
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.
294     debug("Invalidate current Configuration");
295 
296     tBuf[0] = 0xfe;
297     tBuf[1] = 0xfe;
298     tBuf[2] = 0x00;
299     tBuf[3] = 0x00;
300 
301     if (!(co_await this->mfrFWcmd(MFRFwCmdOTPFileInvd,
302                                   MFROTPFileInvalidationWaitTime, tBuf, NULL)))
303     {
304         error("Failed to program the VR - Invalidation of current FW");
305         co_return false;
306     }
307 
308     for (int i = 0; i < configuration.sectCnt; i++)
309     {
310         debug("Programming section: {SEC}", "SEC", i);
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");
316             co_return false;
317         }
318 
319         if ((i <= 0) || (sect->type != configuration.section[i - 1].type))
320         {
321             debug("Section Type: {TYPE}", "TYPE", lg2::hex,
322                   configuration.section[i].type);
323 
324             // clear bit0 of PMBUS_STS_CML
325             tBuf[0] = PMBusSTLCml;
326             tBuf[1] = 0x1;
327             uint8_t tSize = 2;
328             uint8_t rSize = 0;
329             if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf,
330                                                           rSize)))
331             {
332                 error("Failed to program the VR on sendReceive {CMD}", "CMD",
333                       std::string("PMBusSTLCml"));
334                 co_return false;
335             }
336 
337             debug("Invalidating section type: {TYPE}", "TYPE", sect->type);
338             tBuf[0] = sect->type;
339             tBuf[1] = 0x00;
340             tBuf[2] = 0x00;
341             tBuf[3] = 0x00;
342 
343             if (!(co_await this->mfrFWcmd(MFRFwCmdOTPFileInvd,
344                                           MFRSectionInvalidationWaitTime, tBuf,
345                                           NULL)))
346             {
347                 error("Failed to program VR on mfrFWCmd on {CMD}", "CMD",
348                       std::string("MFRFwCmdOTPFileInvd"));
349                 co_return false;
350             }
351 
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);
359 
360             tBuf[0] = IFXMFRAHBAddr;
361             tBuf[1] = 4;
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;
366             tSize = 6;
367             rSize = 0;
368 
369             if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf,
370                                                           rSize)))
371             {
372                 error("Failed to program VR on sendReceive on {CMD}", "CMD",
373                       std::string("IFXMFRAHBAddr"));
374                 co_return false;
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], &sect->data[j], 4);
390             if (!(co_await this->i2cInterface.sendReceive(tBuf, tSize, rBuf,
391                                                           rSize)))
392             {
393                 error("Failed to program the VR on sendReceive {CMD}", "CMD",
394                       std::string("IFXMFRRegWrite"));
395                 co_return false;
396             }
397             co_await sdbusplus::async::sleep_for(ctx,
398                                                  std::chrono::milliseconds(10));
399         }
400 
401         size += sect->dataCnt * 4;
402         if ((i + 1 >= configuration.sectCnt) ||
403             (sect->type != configuration.section[i + 1].type))
404         {
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 
409             // Upload to scratchpad
410             debug("Upload from scratch pad to OTP with soak time: {TIME}ms",
411                   "TIME", soakTime);
412             std::memcpy(tBuf, &size, 2);
413             tBuf[2] = 0x00;
414             tBuf[3] = 0x00;
415             if (!(co_await this->mfrFWcmd(MFRFwCmdOTPConfSTO, soakTime, tBuf,
416                                           NULL)))
417             {
418                 error("Failed to program the VR on mfrFWcmd {CMD}", "CMD",
419                       std::string("MFRFwCmdOTPConfSTO"));
420                 co_return false;
421             }
422 
423             // Read status faults after programming
424             tBuf[0] = PMBusSTLCml;
425             uint8_t tSize = 1;
426             uint8_t rSize = 1;
427             if (!(co_await this->i2cInterface.sendReceive(rBuf, tSize, tBuf,
428                                                           rSize)))
429             {
430                 error("Failed to program VR on sendReceive {CMD}", "CMD",
431                       std::string("PMBusSTLCml"));
432                 co_return false;
433             }
434             if (rBuf[0] & 0x01)
435             {
436                 error("Failed to program VR - status fault indicated error");
437                 co_return false;
438             }
439         }
440     }
441 
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 
464 bool XDPE1X2XX::parseImage(const uint8_t* image, size_t image_size)
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                 {
522                     dWord = (uint32_t)strtoul(tokenList[i], NULL, 16);
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                         {
532                             return false;
533                         }
534 
535                         configuration.section[sectIndex].type = sectType;
536                         configuration.sectCnt = sectIndex + 1;
537                         dataCnt = 0;
538                     }
539 
540                     if (dataCnt >= MaxSectDataCnt)
541                     {
542                         return false;
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 
584     return true;
585 }
586 
587 bool XDPE1X2XX::checkImage()
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");
599             return false;
600         }
601 
602         crc = calcCRC32(&sect->data[0], 2);
603         if (crc != sect->data[2])
604         {
605             error("Failed to check image - first CRC value mismatch");
606             return false;
607         }
608         sum += crc;
609 
610         // check CRC of section data
611         crc = calcCRC32(&sect->data[3], sect->dataCnt - 4);
612         if (crc != sect->data[sect->dataCnt - 1])
613         {
614             error("Failed to check image - second CRC value mismatch");
615             return false;
616         }
617         sum += crc;
618     }
619 
620     if (sum != configuration.sumExp)
621     {
622         debug("Calculated CRC: {CRC}", "CRC", lg2::hex, sum);
623         debug("Config CRC {CRC}", "CRC", lg2::hex, configuration.sumExp);
624         error("Failed to check image - third CRC value mismatch");
625         return false;
626     }
627 
628     return true;
629 }
630 
631 sdbusplus::async::task<bool> XDPE1X2XX::verifyImage(const uint8_t* image,
632                                                     size_t imageSize)
633 {
634     if (!parseImage(image, imageSize))
635     {
636         error("Failed to update firmware on parsing Image");
637         co_return false;
638     }
639 
640     if (!checkImage())
641     {
642         error("Failed to update firmware on check image");
643         co_return false;
644     }
645 
646     co_return true;
647 }
648 
649 sdbusplus::async::task<bool> XDPE1X2XX::getScratchPadAddress()
650 {
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)))
661     {
662         error("mfrFWcmd call failed to retrieve scratchpad address");
663         co_return false;
664     }
665 
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 
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 
716     if (!ret)
717     {
718         co_return false;
719     }
720 
721     co_return true;
722 }
723 
724 sdbusplus::async::task<bool> XDPE1X2XX::reset()
725 {
726     if (!(co_await mfrFWcmd(MFRFwCmdReset, VRResetDelay, NULL, NULL)))
727     {
728         error("Failed to reset the VR");
729         co_return false;
730     }
731 
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
769