blob: 077afddac688646345a5c1db79d1d02c2884b750 [file] [log] [blame]
Christopher Meisf00ce802025-04-08 08:07:31 +02001#include "isl69269.hpp"
2
3#include "common/include/i2c/i2c.hpp"
4
5#include <phosphor-logging/lg2.hpp>
6
7#include <string>
8
9PHOSPHOR_LOG2_USING;
10
11namespace phosphor::software::VR
12{
13
14constexpr uint8_t regProgStatus = 0x7E;
15constexpr uint8_t regHexModeCFG0 = 0x87;
16constexpr uint8_t regCRC = 0x94;
17constexpr uint8_t regHexModeCFG1 = 0xBD;
18constexpr uint8_t regDMAData = 0xC5;
19constexpr uint8_t regDMAAddr = 0xC7;
20constexpr uint8_t regRestoreCfg = 0xF2;
21
22constexpr uint8_t regRemainginWrites = 0x35;
23
24constexpr uint8_t gen3SWRevMin = 0x06;
25constexpr uint8_t deviceIdLength = 4;
26
27constexpr uint8_t gen3Legacy = 1;
28constexpr uint8_t gen3Production = 2;
cchoux86a2fd02025-08-20 16:22:12 +080029constexpr uint8_t gen2Hex = 3;
Leo Yangb5938702025-09-30 15:51:54 +080030constexpr uint8_t gen3p5 = 4;
Christopher Meisf00ce802025-04-08 08:07:31 +020031
32constexpr uint16_t cfgId = 7;
33constexpr uint16_t gen3FileHead = 5;
34constexpr uint16_t gen3LegacyCRC = 276 - gen3FileHead;
35constexpr uint16_t gen3ProductionCRC = 290 - gen3FileHead;
36constexpr uint8_t checksumLen = 4;
37constexpr uint8_t deviceRevisionLen = 4;
38
39// Common pmBus Command codes
40constexpr uint8_t pmBusDeviceId = 0xAD;
41constexpr uint8_t pmBusDeviceRev = 0xAE;
42
43// Config file constants
44constexpr char recordTypeData = 0x00;
45constexpr char recordTypeHeader = 0x49;
46
47constexpr uint8_t defaultBufferSize = 16;
48constexpr uint8_t programBufferSize = 32;
49
50constexpr uint8_t zeroByteLen = 0;
51constexpr uint8_t oneByteLen = 1;
52constexpr uint8_t threeByteLen = 3;
53constexpr uint8_t fourByteLen = 4;
54
cchoux86a2fd02025-08-20 16:22:12 +080055// RAA Gen2
56constexpr uint8_t gen2RegProgStatus = 0x07;
57constexpr uint8_t gen2RegCRC = 0x3F;
58constexpr uint8_t gen2RegRemainginWrites = 0xC2;
59
60constexpr uint32_t gen2RevMin = 0x02000003;
61
62constexpr uint8_t hexFileRev = 0x00;
63constexpr uint16_t gen2FileHead = 6;
64constexpr uint16_t gen2CRC = 600 - gen2FileHead;
65
Leo Yangb5938702025-09-30 15:51:54 +080066// RAA Gen3p5
67constexpr uint8_t regGen3p5ProgStatus = 0x83;
68constexpr uint8_t gen3p5RegCRC = 0xF8;
69constexpr uint8_t gen3p5HWRevMax = 0x06;
70constexpr uint8_t gen3p5HWRevMin = 0x03;
71constexpr uint16_t gen3p5cfgId = 3;
72constexpr uint16_t gen3p5FileHead = 5;
73constexpr uint16_t gen3p5CRC = 336 - gen3p5FileHead;
74
Christopher Meisf00ce802025-04-08 08:07:31 +020075ISL69269::ISL69269(sdbusplus::async::context& ctx, uint16_t bus,
cchoux86a2fd02025-08-20 16:22:12 +080076 uint16_t address, Gen gen) :
77 VoltageRegulator(ctx), i2cInterface(phosphor::i2c::I2C(bus, address)),
78 generation(gen)
Christopher Meisf00ce802025-04-08 08:07:31 +020079{}
80
81inline void shiftLeftFromLSB(const uint8_t* data, uint32_t* result)
82{
83 *result = (static_cast<uint32_t>(data[3]) << 24) |
84 (static_cast<uint32_t>(data[2]) << 16) |
85 (static_cast<uint32_t>(data[1]) << 8) |
86 (static_cast<uint32_t>(data[0]));
87}
88
89inline void shiftLeftFromMSB(const uint8_t* data, uint32_t* result)
90{
91 *result = (static_cast<uint32_t>(data[0]) << 24) |
92 (static_cast<uint32_t>(data[1]) << 16) |
93 (static_cast<uint32_t>(data[2]) << 8) |
94 (static_cast<uint32_t>(data[3]));
95}
96
97static uint8_t calcCRC8(const uint8_t* data, uint8_t len)
98{
99 uint8_t crc = 0x00;
100 int i = 0;
101 int b = 0;
102
103 for (i = 0; i < len; i++)
104 {
105 crc ^= data[i];
106 for (b = 0; b < 8; b++)
107 {
108 if (crc & 0x80)
109 {
110 crc = (crc << 1) ^ 0x07; // polynomial 0x07
111 }
112 else
113 {
114 crc = (crc << 1);
115 }
116 }
117 }
118
119 return crc;
120}
121
122sdbusplus::async::task<bool> ISL69269::dmaReadWrite(uint8_t* reg, uint8_t* resp)
123{
Kevin Tungee551172025-08-22 16:49:40 +0800124 if (reg == nullptr || resp == nullptr)
125 {
126 error("dmaReadWrite invalid input");
127 co_return false;
128 }
129
Christopher Meisf00ce802025-04-08 08:07:31 +0200130 uint8_t tbuf[defaultBufferSize] = {0};
131 uint8_t tlen = threeByteLen;
132 uint8_t rbuf[defaultBufferSize] = {0};
133 uint8_t rlen = zeroByteLen;
134
135 tbuf[0] = regDMAAddr;
136 std::memcpy(&tbuf[1], reg, 2);
137
138 // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
139 if (!(co_await i2cInterface.sendReceive(tbuf, tlen, rbuf, rlen)))
140 // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
141 {
142 error("dmaReadWrite failed with {CMD}", "CMD",
143 std::string("_REG_DMA_ADDR"));
144 co_return false;
145 }
146
147 tlen = oneByteLen;
148 rlen = fourByteLen;
149
150 tbuf[0] = regDMAData;
151 if (!(co_await i2cInterface.sendReceive(tbuf, tlen, resp, rlen)))
152 {
153 error("dmaReadWrite failed with {CMD}", "CMD",
154 std::string("_REG_DMA_DATA"));
155 co_return false;
156 }
157
158 co_return true;
159}
160
161sdbusplus::async::task<bool> ISL69269::getRemainingWrites(uint8_t* remain)
162{
163 uint8_t tbuf[defaultBufferSize] = {0};
164 uint8_t rbuf[defaultBufferSize] = {0};
165
cchoux86a2fd02025-08-20 16:22:12 +0800166 tbuf[0] =
167 (generation == Gen::Gen2) ? gen2RegRemainginWrites : regRemainginWrites;
Christopher Meisf00ce802025-04-08 08:07:31 +0200168 tbuf[1] = 0x00;
169 if (!(co_await dmaReadWrite(tbuf, rbuf)))
170 {
171 error("getRemainingWrites failed");
172 co_return false;
173 }
174
175 *remain = rbuf[0];
176 co_return true;
177}
178
179sdbusplus::async::task<bool> ISL69269::getHexMode(uint8_t* mode)
180{
cchoux86a2fd02025-08-20 16:22:12 +0800181 if (generation == Gen::Gen2)
182 {
183 *mode = gen2Hex;
184 co_return true;
185 }
Leo Yangb5938702025-09-30 15:51:54 +0800186 else if (generation == Gen::Gen3p5)
187 {
188 uint32_t devID = 0;
189 if (!(co_await getDeviceId(&devID)))
190 {
191 error("program failed at getDeviceId");
192 co_return false;
193 }
194 devID = (devID >> 8) & 0xFF;
195
196 if (devID >= 0xBA)
197 {
198 *mode = gen3p5;
199 }
200 co_return true;
201 }
cchoux86a2fd02025-08-20 16:22:12 +0800202
Christopher Meisf00ce802025-04-08 08:07:31 +0200203 uint8_t tbuf[defaultBufferSize] = {0};
204 uint8_t rbuf[defaultBufferSize] = {0};
205
206 tbuf[0] = regHexModeCFG0;
207 tbuf[1] = regHexModeCFG1;
208 if (!(co_await dmaReadWrite(tbuf, rbuf)))
209 {
210 error("getHexMode failed");
211 co_return false;
212 }
213
214 *mode = (rbuf[0] == 0) ? gen3Legacy : gen3Production;
215
216 co_return true;
217}
218
219sdbusplus::async::task<bool> ISL69269::getDeviceId(uint32_t* deviceId)
220{
Kevin Tungee551172025-08-22 16:49:40 +0800221 if (deviceId == nullptr)
222 {
223 error("getDeviceId invalid input");
224 co_return false;
225 }
226
Christopher Meisf00ce802025-04-08 08:07:31 +0200227 uint8_t tbuf[defaultBufferSize] = {0};
228 uint8_t tLen = oneByteLen;
229 uint8_t rbuf[defaultBufferSize] = {0};
230 uint8_t rLen = deviceIdLength + 1;
231
232 tbuf[0] = pmBusDeviceId;
233
234 if (!(co_await i2cInterface.sendReceive(tbuf, tLen, rbuf, rLen)))
235 {
236 error("getDeviceId failed");
237 co_return false;
238 }
239
240 std::memcpy(deviceId, &rbuf[1], deviceIdLength);
241
242 co_return true;
243}
244
245sdbusplus::async::task<bool> ISL69269::getDeviceRevision(uint32_t* revision)
246{
Kevin Tungee551172025-08-22 16:49:40 +0800247 if (revision == nullptr)
248 {
249 error("getDeviceRevision invalid input");
250 co_return false;
251 }
252
Christopher Meisf00ce802025-04-08 08:07:31 +0200253 uint8_t tbuf[defaultBufferSize] = {0};
254 uint8_t tlen = oneByteLen;
255 uint8_t rbuf[defaultBufferSize] = {0};
256 uint8_t rlen = deviceRevisionLen + 1;
257
258 tbuf[0] = pmBusDeviceRev;
cchoux86a2fd02025-08-20 16:22:12 +0800259 // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
Christopher Meisf00ce802025-04-08 08:07:31 +0200260 if (!(co_await i2cInterface.sendReceive(tbuf, tlen, rbuf, rlen)))
cchoux86a2fd02025-08-20 16:22:12 +0800261 // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
Christopher Meisf00ce802025-04-08 08:07:31 +0200262 {
263 error("getDeviceRevision failed with sendreceive");
264 co_return false;
265 }
266
Leo Yangb5938702025-09-30 15:51:54 +0800267 if (mode == gen3Legacy || mode == gen3p5)
Christopher Meisf00ce802025-04-08 08:07:31 +0200268 {
269 std::memcpy(revision, &rbuf[1], deviceRevisionLen);
270 }
271 else
272 {
273 shiftLeftFromLSB(rbuf + 1, revision);
274 }
275
276 co_return true;
277}
278
279sdbusplus::async::task<bool> ISL69269::getCRC(uint32_t* sum)
280{
281 uint8_t tbuf[defaultBufferSize] = {0};
282 uint8_t rbuf[defaultBufferSize] = {0};
283
Leo Yangb5938702025-09-30 15:51:54 +0800284 switch (generation)
285 {
286 case Gen::Gen2:
287 tbuf[0] = gen2RegCRC;
288 break;
289 case Gen::Gen3p5:
290 tbuf[0] = gen3p5RegCRC;
291 break;
292 default:
293 tbuf[0] = regCRC;
294 break;
295 }
296
Christopher Meisf00ce802025-04-08 08:07:31 +0200297 if (!(co_await dmaReadWrite(tbuf, rbuf)))
298 {
299 error("getCRC failed");
300 co_return false;
301 }
302 std::memcpy(sum, rbuf, sizeof(uint32_t));
303
304 co_return true;
305}
306
307bool ISL69269::parseImage(const uint8_t* image, size_t imageSize)
308{
309 size_t nextLineStart = 0;
310 int dcnt = 0;
311
312 for (size_t i = 0; i < imageSize; i++)
313 {
314 if (image[i] == '\n') // We have a hex file, so we check new line.
315 {
316 char line[40];
317 char xdigit[8] = {0};
318 uint8_t sepLine[32] = {0};
319
320 size_t lineLen = i - nextLineStart;
321 std::memcpy(line, image + nextLineStart, lineLen);
322 int k = 0;
323 size_t j = 0;
324 for (k = 0, j = 0; j < lineLen; k++, j += 2)
325 {
326 // Convert two chars into a array of single values
327 std::memcpy(xdigit, &line[j], 2);
328 sepLine[k] = (uint8_t)std::strtol(xdigit, NULL, 16);
329 }
330
331 if (sepLine[0] == recordTypeHeader)
332 {
333 if (sepLine[3] == pmBusDeviceId)
334 {
335 shiftLeftFromMSB(sepLine + 4, &configuration.devIdExp);
336 debug("device id from configuration: {ID}", "ID", lg2::hex,
337 configuration.devIdExp);
Leo Yangb5938702025-09-30 15:51:54 +0800338 // GEN3p5 IC_DEVICE_ID Byte ID[1]
339 if (generation == Gen::Gen3p5 && sepLine[6] >= 0xBA)
340 {
341 debug("Gen3p5 hex file format recognized");
342 configuration.mode = gen3p5;
343 }
Christopher Meisf00ce802025-04-08 08:07:31 +0200344 }
345 else if (sepLine[3] == pmBusDeviceRev)
346 {
347 shiftLeftFromMSB(sepLine + 4, &configuration.devRevExp);
348 debug("device revision from config: {ID}", "ID", lg2::hex,
349 configuration.devRevExp);
350
Leo Yangb5938702025-09-30 15:51:54 +0800351 if (generation == Gen::Gen3)
Christopher Meisf00ce802025-04-08 08:07:31 +0200352 {
cchoux86a2fd02025-08-20 16:22:12 +0800353 // According to programing guide:
354 // If legacy hex file
355 // MSB device revision == 0x00 | 0x01
356 if (configuration.devRevExp < (gen3SWRevMin << 24))
357 {
358 debug("Legacy hex file format recognized");
359 configuration.mode = gen3Legacy;
360 }
361 else
362 {
363 debug("Production hex file format recognized");
364 configuration.mode = gen3Production;
365 }
Christopher Meisf00ce802025-04-08 08:07:31 +0200366 }
cchoux86a2fd02025-08-20 16:22:12 +0800367 }
368 else if (sepLine[3] == hexFileRev)
369 {
370 debug("Gen2 hex file format recognized");
371 configuration.mode = gen2Hex;
Christopher Meisf00ce802025-04-08 08:07:31 +0200372 }
373 }
374 else if (sepLine[0] == recordTypeData)
375 {
376 if (((sepLine[1] + 2) >= (uint8_t)sizeof(sepLine)))
377 {
378 dcnt = 0;
379 break;
380 }
381 // According to documentation:
382 // 00 05 C2 E7 08 00 F6
383 // | | | | | | |
384 // | | | | | | - Packet Error Code (CRC8)
385 // | | | | - - Data
386 // | | | - Command Code
387 // | | - Address
388 // | - Size of data (including Addr, Cmd, CRC8)
389 // - Line type (0x00 - Data, 0x49 header information)
390 configuration.pData[dcnt].len = sepLine[1] - 2;
391 configuration.pData[dcnt].pec =
392 sepLine[3 + configuration.pData[dcnt].len];
393 configuration.pData[dcnt].addr = sepLine[2];
394 configuration.pData[dcnt].cmd = sepLine[3];
395 std::memcpy(configuration.pData[dcnt].data, sepLine + 2,
396 configuration.pData[dcnt].len + 1);
397 switch (dcnt)
398 {
399 case cfgId:
Leo Yangb5938702025-09-30 15:51:54 +0800400 if (configuration.mode != gen3p5)
401 {
402 configuration.cfgId = sepLine[4] & 0x0F;
403 debug("Config ID: {ID}", "ID", lg2::hex,
404 configuration.cfgId);
405 }
406 break;
407 case gen3p5cfgId:
408 if (configuration.mode == gen3p5)
409 {
410 configuration.cfgId = sepLine[4];
411 debug("Config ID: {ID}", "ID", lg2::hex,
412 configuration.cfgId);
413 }
Christopher Meisf00ce802025-04-08 08:07:31 +0200414 break;
415 case gen3LegacyCRC:
416 if (configuration.mode == gen3Legacy)
417 {
418 std::memcpy(&configuration.crcExp, &sepLine[4],
419 checksumLen);
420 debug("Config Legacy CRC: {CRC}", "CRC", lg2::hex,
421 configuration.crcExp);
422 }
423 break;
424 case gen3ProductionCRC:
425 if (configuration.mode == gen3Production)
426 {
427 std::memcpy(&configuration.crcExp, &sepLine[4],
428 checksumLen);
429 debug("Config Production CRC: {CRC}", "CRC",
430 lg2::hex, configuration.crcExp);
431 }
432 break;
cchoux86a2fd02025-08-20 16:22:12 +0800433 case gen2CRC:
434 if (configuration.mode == gen2Hex)
435 {
436 std::memcpy(&configuration.crcExp, &sepLine[4],
437 checksumLen);
438 debug("Config Gen2 CRC: {CRC}", "CRC", lg2::hex,
439 configuration.crcExp);
440 }
441 break;
Leo Yangb5938702025-09-30 15:51:54 +0800442 case gen3p5CRC:
443 if (configuration.mode == gen3p5)
444 {
445 std::memcpy(&configuration.crcExp, &sepLine[4],
446 checksumLen);
447 debug("Config Gen3p5 CRC: {CRC}", "CRC", lg2::hex,
448 configuration.crcExp);
449 }
450 break;
Christopher Meisf00ce802025-04-08 08:07:31 +0200451 }
452 dcnt++;
453 }
454 else
455 {
456 error("parseImage failed. Unknown recordType");
457 return false;
458 }
459
460 nextLineStart = i + 1;
461 }
462 }
463 configuration.wrCnt = dcnt;
464 return true;
465}
466
467bool ISL69269::checkImage()
468{
469 uint8_t crc8 = 0;
470
471 for (int i = 0; i < configuration.wrCnt; i++)
472 {
473 crc8 = calcCRC8(configuration.pData[i].data,
474 configuration.pData[i].len + 1);
475 if (crc8 != configuration.pData[i].pec)
476 {
477 debug(
478 "Config line: {LINE}, failed to calculate CRC. Have {HAVE}, Want: {WANT}",
479 "LINE", i, "HAVE", lg2::hex, crc8, "WANT", lg2::hex,
480 configuration.pData[i].pec);
481 return false;
482 }
483 }
484
485 return true;
486}
487
488sdbusplus::async::task<bool> ISL69269::program()
489{
490 uint8_t tbuf[programBufferSize] = {0};
491 uint8_t rbuf[programBufferSize] = {0};
492 uint8_t rlen = zeroByteLen;
493
494 for (int i = 0; i < configuration.wrCnt; i++)
495 {
cchouxf4482ab2025-08-19 21:05:36 +0800496 std::memcpy(tbuf, configuration.pData[i].data + 1,
497 configuration.pData[i].len);
Christopher Meisf00ce802025-04-08 08:07:31 +0200498
499 if (!(co_await i2cInterface.sendReceive(
500 tbuf, configuration.pData[i].len, rbuf, rlen)))
501 {
502 error("program failed at writing data to voltage regulator");
503 }
504 }
505
Kevin Tungee551172025-08-22 16:49:40 +0800506 if (!(co_await getProgStatus()))
507 {
508 error("program failed at getProgStatus");
509 co_return false;
510 }
511
Christopher Meisf00ce802025-04-08 08:07:31 +0200512 co_return true;
513}
514
515sdbusplus::async::task<bool> ISL69269::getProgStatus()
516{
517 uint8_t tbuf[programBufferSize] = {0};
518 uint8_t rbuf[programBufferSize] = {0};
519 int retry = 3;
520
cchoux86a2fd02025-08-20 16:22:12 +0800521 if (generation == Gen::Gen2)
522 {
523 tbuf[0] = gen2RegProgStatus;
524 tbuf[1] = gen2RegProgStatus;
525 }
Leo Yangb5938702025-09-30 15:51:54 +0800526 else if (generation == Gen::Gen3p5)
527 {
528 tbuf[0] = regGen3p5ProgStatus;
529 tbuf[1] = 0x00;
530 }
cchoux86a2fd02025-08-20 16:22:12 +0800531 else
532 {
533 tbuf[0] = regProgStatus;
534 tbuf[1] = 0x00;
535 }
Christopher Meisf00ce802025-04-08 08:07:31 +0200536
537 do
538 {
539 // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
540 if (!(co_await dmaReadWrite(tbuf, rbuf)))
541 // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
542 {
543 error("getProgStatus failed on dmaReadWrite");
544 co_return false;
545 }
546
547 if (rbuf[0] & 0x01)
548 {
cchoux86a2fd02025-08-20 16:22:12 +0800549 debug("Programming successful");
Christopher Meisf00ce802025-04-08 08:07:31 +0200550 break;
551 }
552 if (--retry == 0)
553 {
554 if ((!(rbuf[1] & 0x1)) || (rbuf[1] & 0x2))
555 {
556 error("programming the device failed");
557 }
558 if (!(rbuf[1] & 0x4))
559 {
560 error(
561 "HEX file contains more configurations than are available");
562 }
563 if (!(rbuf[1] & 0x8))
564 {
565 error(
566 "A CRC mismatch exists within the configuration data. Programming failed before TP banks are consumed");
567 }
568 if (!(rbuf[1] & 0x10))
569 {
570 error(
571 "CRC check fails on the OTP memory. Programming fails after OTP banks are consumed");
572 }
573 if (!(rbuf[1] & 0x20))
574 {
575 error("Programming fails after OTP banks are consumed.");
576 }
577
578 error("failed to program the device after exceeding retries");
579 co_return false;
580 }
581 co_await sdbusplus::async::sleep_for(ctx, std::chrono::seconds(1));
582 } while (retry > 0);
583
584 co_return true;
585}
586
587sdbusplus::async::task<bool> ISL69269::restoreCfg()
588{
589 uint8_t tbuf[defaultBufferSize] = {0};
590 uint8_t rbuf[defaultBufferSize] = {0};
591
592 tbuf[0] = regRestoreCfg;
593 tbuf[1] = configuration.cfgId;
594
cchoux86a2fd02025-08-20 16:22:12 +0800595 debug("Restore configuration ID: {ID}", "ID", lg2::hex,
596 configuration.cfgId);
Christopher Meisf00ce802025-04-08 08:07:31 +0200597
598 if (!(co_await dmaReadWrite(tbuf, rbuf)))
599 {
600 error("restoreCfg failed at dmaReadWrite");
601 co_return false;
602 }
603
604 co_return true;
605}
606
607sdbusplus::async::task<bool> ISL69269::verifyImage(const uint8_t* image,
608 size_t imageSize)
609{
610 uint8_t mode = 0xFF;
611 uint8_t remain = 0;
612 uint32_t devID = 0;
613 uint32_t devRev = 0;
614 uint32_t crc = 0;
615
616 if (!(co_await getHexMode(&mode)))
617 {
618 error("program failed at getHexMode");
619 co_return false;
620 }
621
622 if (!parseImage(image, imageSize))
623 {
624 error("verifyImage failed at parseImage");
625 co_return false;
626 }
627
628 if (!checkImage())
629 {
630 error("verifyImage failed at checkImage");
631 co_return false;
632 }
633
634 if (mode != configuration.mode)
635 {
636 error(
637 "program failed with mode of device and configuration are not equal");
638 co_return false;
639 }
640
641 if (!(co_await getRemainingWrites(&remain)))
642 {
643 error("program failed at getRemainingWrites");
644 co_return false;
645 }
646
647 if (!remain)
648 {
649 error("program failed with no remaining writes left on device");
650 co_return false;
651 }
652
653 if (!(co_await getDeviceId(&devID)))
654 {
655 error("program failed at getDeviceId");
656 co_return false;
657 }
658
659 if (devID != configuration.devIdExp)
660 {
661 error(
662 "program failed with not matching device id of device and config");
663 co_return false;
664 }
665
666 if (!(co_await getDeviceRevision(&devRev)))
667 {
668 error("program failed at getDeviceRevision");
669 co_return false;
670 }
671 debug("Device revision read from device: {REV}", "REV", lg2::hex, devRev);
672
673 switch (mode)
674 {
675 case gen3Legacy:
676 if (((devRev >> 24) >= gen3SWRevMin) &&
677 (configuration.devRevExp <= 0x1))
678 {
679 debug("Legacy mode revision checks out");
680 }
681 else
682 {
683 error(
684 "revision requirements for legacy mode device not fulfilled");
685 }
686 break;
687 case gen3Production:
688 if (((devRev >> 24) >= gen3SWRevMin) &&
689 (configuration.devRevExp >= gen3SWRevMin))
690 {
691 debug("Production mode revision checks out");
692 }
693 else
694 {
695 error(
696 "revision requirements for production mode device not fulfilled");
697 }
698 break;
cchoux86a2fd02025-08-20 16:22:12 +0800699 case gen2Hex:
700 if (devRev >= gen2RevMin)
701 {
702 debug("Gen2 mode revision checks out");
703 }
704 else
705 {
706 error("revision requirements for Gen2 device not fulfilled");
707 }
708 break;
Leo Yangb5938702025-09-30 15:51:54 +0800709 case gen3p5:
710 if (((devRev >> 24) >= gen3p5HWRevMin) &&
711 ((devRev >> 24) <= gen3p5HWRevMax))
712 {
713 debug("Gen3p5 revision checks out");
714 }
715 else
716 {
717 error("revision requirements for Gen3p5 device not fulfilled");
718 }
719 break;
Christopher Meisf00ce802025-04-08 08:07:31 +0200720 }
721
722 if (!(co_await getCRC(&crc)))
723 {
724 error("program failed at getCRC");
725 co_return false;
726 }
727
728 debug("CRC from device: {CRC}", "CRC", lg2::hex, crc);
729 debug("CRC from config: {CRC}", "CRC", lg2::hex, configuration.crcExp);
730
731 if (crc == configuration.crcExp)
732 {
733 error("program failed with same CRC value at device and configuration");
734 co_return false;
735 }
736
737 co_return true;
738}
739
Christopher Meisf00ce802025-04-08 08:07:31 +0200740bool ISL69269::forcedUpdateAllowed()
741{
742 return true;
743}
744
745sdbusplus::async::task<bool> ISL69269::updateFirmware(bool force)
746{
747 (void)force;
Kevin Tungee551172025-08-22 16:49:40 +0800748 // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
Christopher Meisf00ce802025-04-08 08:07:31 +0200749 if (!(co_await program()))
Kevin Tungee551172025-08-22 16:49:40 +0800750 // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
Christopher Meisf00ce802025-04-08 08:07:31 +0200751 {
752 error("programing ISL69269 failed");
753 co_return false;
754 }
755
756 co_return true;
757}
758
759} // namespace phosphor::software::VR