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
XDPE1X2XX(sdbusplus::async::context & ctx,uint16_t bus,uint16_t address)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
getDeviceId(uint8_t * deviceID)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
mfrFWcmd(uint8_t cmd,uint16_t processTime,uint8_t * data,uint8_t * resp)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
getRemainingWrites(uint8_t * remain)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
getConfigSize(uint8_t deviceId,uint8_t revision)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
getCRC(uint32_t * checksum)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
program(bool force)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
lineSplit(char ** dest,char * src,char * delim)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
parseImage(const uint8_t * image,size_t image_size)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
checkImage()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
verifyImage(const uint8_t * image,size_t imageSize)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
getScratchPadAddress()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
updateFirmware(bool force)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
calcCRC32(const uint32_t * data,int len)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
forcedUpdateAllowed()769 bool XDPE1X2XX::forcedUpdateAllowed()
770 {
771 return true;
772 }
773
774 } // namespace phosphor::software::VR
775