blob: 87ae2f01276e021281facb157bbe1a3bfdda8033 [file] [log] [blame]
Daniel Hsuf6470b52025-02-26 15:03:47 +08001#include "lattice.hpp"
2
3#include <phosphor-logging/lg2.hpp>
4
5#include <algorithm>
6#include <fstream>
7#include <map>
8#include <thread>
9#include <vector>
10
Daniel Hsuf6470b52025-02-26 15:03:47 +080011constexpr uint8_t busyWaitmaxRetry = 30;
12constexpr uint8_t busyFlagBit = 0x80;
13constexpr std::chrono::milliseconds waitBusyTime(200);
14
15static constexpr std::string_view tagQF = "QF";
16static constexpr std::string_view tagUH = "UH";
17static constexpr std::string_view tagCFStart = "L000";
18static constexpr std::string_view tagChecksum = "C";
19static constexpr std::string_view tagUserCode = "NOTE User Electronic";
20static constexpr std::string_view tagEbrInitData = "NOTE EBR_INIT DATA";
21
22constexpr uint8_t isOK = 0;
23constexpr uint8_t isReady = 0;
24constexpr uint8_t busyOrReadyBit = 4;
25constexpr uint8_t failOrOKBit = 5;
26
27constexpr bool enableUpdateEbrInit = false;
28
29enum cpldI2cCmd
30{
31 commandEraseFlash = 0x0E,
32 commandDisableConfigInterface = 0x26,
33 commandReadStatusReg = 0x3C,
34 commandResetConfigFlash = 0x46,
35 commandProgramDone = 0x5E,
36 commandProgramPage = 0x70,
37 commandEnableConfigMode = 0x74,
38 commandReadFwVersion = 0xC0,
39 commandProgramUserCode = 0xC2,
40 commandReadDeviceId = 0xE0,
41 commandReadBusyFlag = 0xF0,
42};
43
44static uint8_t reverse_bit(uint8_t b)
45{
46 b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
47 b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
48 b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
49 return b;
50}
51
Daniel Hsuf6470b52025-02-26 15:03:47 +080052static int findNumberSize(const std::string& end, const std::string& start,
53 const std::string& line)
54{
55 auto pos1 = line.find(start);
56 auto pos2 = line.find(end);
57
58 if (pos1 == std::string::npos || pos2 == std::string::npos || pos1 >= pos2)
59 {
60 return false;
61 }
62
63 return static_cast<int>(pos2 - pos1 - 1);
64}
65
Daniel Hsu37a30142025-06-12 17:57:24 +080066std::string uint32ToHexStr(uint32_t value)
67{
68 std::ostringstream oss;
69 oss << std::setfill('0') << std::setw(8) << std::hex << std::uppercase
70 << value;
71 return oss.str();
72}
73
Daniel Hsuf6470b52025-02-26 15:03:47 +080074bool CpldLatticeManager::jedFileParser()
75{
76 bool cfStart = false;
77 bool ufmStart = false; // for isLCMXO3D
78 bool ufmPrepare = false;
79 bool versionStart = false;
80 bool checksumStart = false;
81 bool ebrInitDataStart = false;
82 int numberSize = 0;
83
84 if (image == nullptr || imageSize == 0)
85 {
86 lg2::error(
87 "Error: JED file is empty or not found. Please check the file.");
88 return false;
89 }
90
91 // Convert binary data to a string
92 std::string content(reinterpret_cast<const char*>(image), imageSize);
93 // Use stringstream to simulate file reading
94 std::istringstream iss(content);
95 std::string line;
96
97 // Parsing JED file
98 while (getline(iss, line))
99 {
100 if (line.rfind(tagQF, 0) == 0)
101 {
102 numberSize = findNumberSize("*", "F", line);
103 if (numberSize <= 0)
104 {
105 lg2::error("Error in parsing QF tag");
106 return false;
107 }
108 static constexpr auto start = tagQF.length();
109 fwInfo.QF = std::stoul(line.substr(start, numberSize));
110
111 lg2::debug("QF Size = {QF}", "QF", fwInfo.QF);
112 }
113 else if (line.rfind(tagCFStart, 0) == 0)
114 {
115 cfStart = true;
116 }
117 else if (enableUpdateEbrInit && line.rfind(tagEbrInitData, 0) == 0)
118 {
119 ebrInitDataStart = true;
120 }
121 else if (ufmPrepare)
122 {
123 ufmPrepare = false;
124 ufmStart = true;
125 continue;
126 }
127 else if (line.rfind(tagUserCode, 0) == 0)
128 {
129 versionStart = true;
130 }
131 else if (line.rfind(tagChecksum, 0) == 0)
132 {
133 checksumStart = true;
134 }
135
136 if (line.rfind("NOTE DEVICE NAME:", 0) == 0)
137 {
138 lg2::error(line.c_str());
139 if (line.find(chip) != std::string::npos)
140 {
141 lg2::debug("[OK] The image device name match with chip name");
142 }
143 else
144 {
Daniel Hsu61e12672025-06-12 19:20:46 +0800145 lg2::debug("Abort update as image doesn't match the chip name");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800146 return false;
147 }
148 }
149
150 if (cfStart)
151 {
152 // L000
153 if ((line.rfind(tagCFStart, 0)) && (line.size() != 1))
154 {
155 if ((line.rfind('0', 0) == 0) || (line.rfind('1', 0) == 0))
156 {
157 while (!line.empty())
158 {
159 auto binaryStr = line.substr(0, 8);
160 try
161 {
162 fwInfo.cfgData.push_back(
163 std::stoi(binaryStr, 0, 2));
164 line.erase(0, 8);
165 }
166 catch (const std::invalid_argument& error)
167 {
168 break;
169 }
170 catch (...)
171 {
172 lg2::error("Error while parsing CF section");
173 return false;
174 }
175 }
176 }
177 else
178 {
179 lg2::debug("CF size = {CF}", "CF", fwInfo.cfgData.size());
180 cfStart = false;
181 if (!ebrInitDataStart)
182 {
183 ufmPrepare = true;
184 }
185 }
186 }
187 }
188 else if (enableUpdateEbrInit && ebrInitDataStart)
189 {
190 // NOTE EBR_INIT DATA
191 if ((line.rfind(tagEbrInitData, 0)) && (line.size() != 1))
192 {
193 if ((line.rfind('L', 0)) && (line.size() != 1))
194 {
195 if ((line.rfind('0', 0) == 0) || (line.rfind('1', 0) == 0))
196 {
197 while (!line.empty())
198 {
199 auto binaryStr = line.substr(0, 8);
200 try
201 {
202 fwInfo.cfgData.push_back(
203 std::stoi(binaryStr, 0, 2));
204 line.erase(0, 8);
205 }
206 catch (const std::invalid_argument& error)
207 {
208 break;
209 }
210 catch (...)
211 {
212 lg2::error("Error while parsing CF section");
213 return false;
214 }
215 }
216 }
217 else
218 {
219 lg2::debug("CF size with EBR_INIT Data = {CF}", "CF",
220 fwInfo.cfgData.size());
221 ebrInitDataStart = false;
222 ufmPrepare = true;
223 }
224 }
225 }
226 }
227 else if ((checksumStart) && (line.size() != 1))
228 {
229 checksumStart = false;
230 numberSize = findNumberSize("*", "C", line);
231 if (numberSize <= 0)
232 {
233 lg2::error("Error in parsing checksum");
234 return false;
235 }
236 static constexpr auto start = tagChecksum.length();
237 std::istringstream iss(line.substr(start, numberSize));
238 iss >> std::hex >> fwInfo.checksum;
239
240 lg2::debug("Checksum = {CHECKSUM}", "CHECKSUM", fwInfo.checksum);
241 }
242 else if (versionStart)
243 {
244 if ((line.rfind(tagUserCode, 0)) && (line.size() != 1))
245 {
246 versionStart = false;
247
248 if (line.rfind(tagUH, 0) == 0)
249 {
250 numberSize = findNumberSize("*", "H", line);
251 if (numberSize <= 0)
252 {
253 lg2::error("Error in parsing version");
254 return false;
255 }
256 static constexpr auto start = tagUH.length();
257 std::istringstream iss(line.substr(start, numberSize));
258 iss >> std::hex >> fwInfo.version;
259
260 lg2::debug("UserCode = {USERCODE}", "USERCODE",
261 fwInfo.version);
262 }
263 }
264 }
265 else if (ufmStart)
266 {
267 if ((line.rfind('L', 0)) && (line.size() != 1))
268 {
269 if ((line.rfind('0', 0) == 0) || (line.rfind('1', 0) == 0))
270 {
271 while (!line.empty())
272 {
273 auto binaryStr = line.substr(0, 8);
274 try
275 {
276 fwInfo.ufmData.push_back(
277 std::stoi(binaryStr, 0, 2));
278 line.erase(0, 8);
279 }
280 catch (const std::invalid_argument& error)
281 {
282 break;
283 }
284 catch (...)
285 {
286 lg2::error("Error while parsing UFM section");
287 return false;
288 }
289 }
290 }
291 else
292 {
293 lg2::debug("UFM size = {UFM}", "UFM",
294 fwInfo.ufmData.size());
295 ufmStart = false;
296 }
297 }
298 }
299 }
300
301 return true;
302}
303
304bool CpldLatticeManager::verifyChecksum()
305{
306 // Compute check sum
307 unsigned int jedFileCheckSum = 0;
308 for (unsigned i = 0; i < fwInfo.cfgData.size(); i++)
309 {
310 jedFileCheckSum += reverse_bit(fwInfo.cfgData.at(i));
311 }
312 for (unsigned i = 0; i < fwInfo.ufmData.size(); i++)
313 {
314 jedFileCheckSum += reverse_bit(fwInfo.ufmData.at(i));
315 }
316 lg2::debug("jedFileCheckSum = {JEDFILECHECKSUM}", "JEDFILECHECKSUM",
317 jedFileCheckSum);
318 jedFileCheckSum = jedFileCheckSum & 0xffff;
319
320 if ((fwInfo.checksum != jedFileCheckSum) || (fwInfo.checksum == 0))
321 {
322 lg2::error("CPLD JED File CheckSum Error = {JEDFILECHECKSUM}",
323 "JEDFILECHECKSUM", jedFileCheckSum);
324 return false;
325 }
326
327 lg2::debug("JED File Checksum compare success");
328 return true;
329}
330
331sdbusplus::async::task<bool> CpldLatticeManager::readDeviceId()
332{
Daniel Hsu37a30142025-06-12 17:57:24 +0800333 std::vector<uint8_t> request = {commandReadDeviceId, 0x0, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800334 constexpr size_t resSize = 4;
335 std::vector<uint8_t> readData(resSize, 0);
Daniel Hsu37a30142025-06-12 17:57:24 +0800336 bool success = co_await i2cInterface.sendReceive(
337 request.data(), request.size(), readData.data(), resSize);
338
Daniel Hsuf6470b52025-02-26 15:03:47 +0800339 if (!success)
340 {
341 lg2::error(
342 "Fail to read device Id. Please check the I2C bus and address.");
343 co_return false;
344 }
345
Daniel Hsu61e12672025-06-12 19:20:46 +0800346 auto chipWantToUpdate =
347 std::find_if(supportedDeviceMap.begin(), supportedDeviceMap.end(),
348 [this](const auto& pair) {
349 return pair.second.chipName == this->chip;
350 });
Daniel Hsuf6470b52025-02-26 15:03:47 +0800351
Daniel Hsu61e12672025-06-12 19:20:46 +0800352 if (chipWantToUpdate != supportedDeviceMap.end() &&
353 chipWantToUpdate->second.deviceId == readData)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800354 {
355 if (chip.rfind("LCMXO3D", 0) == 0)
356 {
357 isLCMXO3D = true;
358 if (!target.empty() && target != "CFG0" && target != "CFG1")
359 {
360 lg2::error("Unknown target. Only CFG0 and CFG1 are supported.");
361 co_return false;
362 }
363 }
364
365 lg2::debug("Device ID match with chip. Chip name: {CHIPNAME}",
366 "CHIPNAME", chip);
367 co_return true;
368 }
369
Daniel Hsu61e12672025-06-12 19:20:46 +0800370 lg2::error("The device id doesn't match with chip.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800371 co_return false;
372}
373
374sdbusplus::async::task<bool> CpldLatticeManager::enableProgramMode()
375{
Daniel Hsu37a30142025-06-12 17:57:24 +0800376 std::vector<uint8_t> request = {commandEnableConfigMode, 0x08, 0x0, 0x0};
377 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800378
Daniel Hsu37a30142025-06-12 17:57:24 +0800379 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800380 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800381 lg2::error("Failed to send enable program mode request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800382 co_return false;
383 }
384
385 if (!(co_await waitBusyAndVerify()))
386 {
387 lg2::error("Wait busy and verify fail");
388 co_return false;
389 }
390 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
391 co_return true;
392}
393
394sdbusplus::async::task<bool> CpldLatticeManager::eraseFlash()
395{
Daniel Hsu37a30142025-06-12 17:57:24 +0800396 std::vector<uint8_t> request;
397 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800398
399 if (isLCMXO3D)
400 {
401 /*
402 Erase the different internal
403 memories. The bit in YYY defines
404 which memory is erased in Flash
405 access mode.
406 Bit 1=Enable
407 8 Erase CFG0
408 9 Erase CFG1
409 10 Erase UFM0
410 11 Erase UFM1
411 12 Erase UFM2
412 13 Erase UFM3
413 14 Erase CSEC
414 15 Erase USEC
415 16 Erase PUBKEY
416 17 Erase AESKEY
417 18 Erase FEA
418 19 Reserved
419 commandEraseFlash = 0x0E, 0Y YY 00
420 */
421 if (target.empty() || target == "CFG0")
422 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800423 request = {commandEraseFlash, 0x00, 0x01, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800424 }
425 else if (target == "CFG1")
426 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800427 request = {commandEraseFlash, 0x00, 0x02, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800428 }
429 else
430 {
431 lg2::error("Error: unknown target.");
432 co_return false;
433 }
434 }
435 else
436 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800437 request = {commandEraseFlash, 0xC, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800438 }
439
Daniel Hsu37a30142025-06-12 17:57:24 +0800440 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800441 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800442 lg2::error("Failed to send erase flash request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800443 co_return false;
444 }
445
446 if (!(co_await waitBusyAndVerify()))
447 {
448 lg2::error("Wait busy and verify fail");
449 co_return false;
450 }
451 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
452 co_return true;
453}
454
455sdbusplus::async::task<bool> CpldLatticeManager::resetConfigFlash()
456{
Daniel Hsu37a30142025-06-12 17:57:24 +0800457 std::vector<uint8_t> request;
458 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800459 if (isLCMXO3D)
460 {
461 /*
462 Set Page Address pointer to the
463 beginning of the different internal
464 Flash sectors. The bit in YYYY
465 defines which sector is selected.
466 Bit Flash sector selected
467 8 CFG0
468 9 CFG1
469 10 FEA
470 11 PUBKEY
471 12 AESKEY
472 13 CSEC
473 14 UFM0
474 15 UFM1
475 16 UFM2
476 17 UFM3
477 18 USEC
478 19 Reserved
479 20 Reserved
480 21 Reserved
481 22 Reserved
482 commandResetConfigFlash = 0x46, YY YY 00
483 */
484 if (target.empty() || target == "CFG0")
485 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800486 request = {commandResetConfigFlash, 0x00, 0x01, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800487 }
488 else if (target == "CFG1")
489 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800490 request = {commandResetConfigFlash, 0x00, 0x02, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800491 }
492 else
493 {
494 lg2::error(
495 "Error: unknown target. Only CFG0 and CFG1 are supported.");
496 co_return false;
497 }
498 }
499 else
500 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800501 request = {commandResetConfigFlash, 0x0, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800502 }
503
Daniel Hsu37a30142025-06-12 17:57:24 +0800504 co_return i2cInterface.sendReceive(request, response);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800505}
506
507sdbusplus::async::task<bool> CpldLatticeManager::writeProgramPage()
508{
509 /*
510 Program one NVCM/Flash page. Can be
511 used to program the NVCM0/CFG or
512 NVCM1/UFM.
513 */
Daniel Hsu37a30142025-06-12 17:57:24 +0800514 std::vector<uint8_t> request = {commandProgramPage, 0x0, 0x0, 0x01};
515 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800516 size_t iterSize = 16;
517
518 for (size_t i = 0; i < fwInfo.cfgData.size(); i += iterSize)
519 {
520 double progressRate =
521 ((double(i) / double(fwInfo.cfgData.size())) * 100);
522 std::cout << "Update :" << std::fixed << std::dec
523 << std::setprecision(2) << progressRate << "% \r";
524
525 uint8_t len = ((i + iterSize) < fwInfo.cfgData.size())
526 ? iterSize
527 : (fwInfo.cfgData.size() - i);
Daniel Hsu37a30142025-06-12 17:57:24 +0800528 std::vector<uint8_t> data = request;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800529
530 data.insert(
531 data.end(), fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i),
532 fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i + len));
533
Daniel Hsu37a30142025-06-12 17:57:24 +0800534 if (!i2cInterface.sendReceive(data, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800535 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800536 lg2::error("Failed to send program page request. {CURRENT}",
537 "CURRENT", uint32ToHexStr(i));
Daniel Hsuf6470b52025-02-26 15:03:47 +0800538 co_return false;
539 }
540
541 /*
542 Reference spec
543 Important! If don't sleep, it will take a long time to update.
544 */
545 co_await sdbusplus::async::sleep_for(ctx,
546 std::chrono::microseconds(200));
547
548 if (!(co_await waitBusyAndVerify()))
549 {
550 lg2::error("Wait busy and verify fail");
551 co_return false;
552 }
553
554 data.clear();
555 }
556
557 co_return true;
558}
559
560sdbusplus::async::task<bool> CpldLatticeManager::programUserCode()
561{
Daniel Hsu37a30142025-06-12 17:57:24 +0800562 std::vector<uint8_t> request = {commandProgramUserCode, 0x0, 0x0, 0x0};
563 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800564 for (int i = 3; i >= 0; i--)
565 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800566 request.push_back((fwInfo.version >> (i * 8)) & 0xFF);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800567 }
Daniel Hsuf6470b52025-02-26 15:03:47 +0800568
Daniel Hsu37a30142025-06-12 17:57:24 +0800569 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800570 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800571 lg2::error("Failed to send program user code request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800572 co_return false;
573 }
Daniel Hsuf6470b52025-02-26 15:03:47 +0800574 if (!(co_await waitBusyAndVerify()))
575 {
576 lg2::error("Wait busy and verify fail");
577 co_return false;
578 }
579
580 co_return true;
581}
582
583sdbusplus::async::task<bool> CpldLatticeManager::programDone()
584{
Daniel Hsu37a30142025-06-12 17:57:24 +0800585 std::vector<uint8_t> request = {commandProgramDone, 0x0, 0x0, 0x0};
586 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800587
Daniel Hsu37a30142025-06-12 17:57:24 +0800588 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800589 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800590 lg2::error("Failed to send program done request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800591 co_return false;
592 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800593
Daniel Hsuf6470b52025-02-26 15:03:47 +0800594 if (!(co_await waitBusyAndVerify()))
595 {
596 lg2::error("Wait busy and verify fail");
597 co_return false;
598 }
599
600 co_return true;
601}
602
603sdbusplus::async::task<bool> CpldLatticeManager::disableConfigInterface()
604{
Daniel Hsu37a30142025-06-12 17:57:24 +0800605 std::vector<uint8_t> request = {commandDisableConfigInterface, 0x0, 0x0};
606 std::vector<uint8_t> response;
607 co_return i2cInterface.sendReceive(request, response);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800608}
609
610sdbusplus::async::task<bool> CpldLatticeManager::waitBusyAndVerify()
611{
612 uint8_t retry = 0;
613
614 while (retry <= busyWaitmaxRetry)
615 {
616 uint8_t busyFlag = 0xff;
617
Daniel Hsu37a30142025-06-12 17:57:24 +0800618 auto readBusyFlagResult = co_await readBusyFlag(busyFlag);
619 if (!readBusyFlagResult)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800620 {
621 lg2::error("Fail to read busy flag.");
622 co_return false;
623 }
624
625 if (busyFlag & busyFlagBit)
626 {
627 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
628 retry++;
629 if (retry > busyWaitmaxRetry)
630 {
631 lg2::error(
632 "Status Reg : Busy! Please check the I2C bus and address.");
633 co_return false;
634 }
635 }
636 else
637 {
638 break;
639 }
640 } // while loop busy check
641
642 // Check out status reg
Daniel Hsu37a30142025-06-12 17:57:24 +0800643 auto statusReg = std::make_unique<uint8_t>(0xff);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800644
Daniel Hsu37a30142025-06-12 17:57:24 +0800645 if (!(co_await readStatusReg(*statusReg)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800646 {
647 lg2::error("Fail to read status register.");
648 co_return false;
649 }
650
Daniel Hsu37a30142025-06-12 17:57:24 +0800651 if (((*statusReg >> busyOrReadyBit) & 1) == isReady &&
652 ((*statusReg >> failOrOKBit) & 1) == isOK)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800653 {
654 lg2::debug("Status Reg : OK");
655 co_return true;
656 }
657
658 lg2::error("Status Reg : Fail! Please check the I2C bus and address.");
659 co_return false;
660}
661
662sdbusplus::async::task<bool> CpldLatticeManager::readBusyFlag(uint8_t& busyFlag)
663{
Daniel Hsuf6470b52025-02-26 15:03:47 +0800664 constexpr size_t resSize = 1;
Daniel Hsu37a30142025-06-12 17:57:24 +0800665 std::vector<uint8_t> request = {commandReadBusyFlag, 0x0, 0x0, 0x0};
666 std::vector<uint8_t> response(resSize, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800667
Daniel Hsu37a30142025-06-12 17:57:24 +0800668 auto success = i2cInterface.sendReceive(request, response);
669 if (!success && response.size() != resSize)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800670 {
671 co_return false;
672 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800673 busyFlag = response.at(0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800674 co_return true;
675}
676
677sdbusplus::async::task<bool> CpldLatticeManager::readStatusReg(
678 uint8_t& statusReg)
679{
Daniel Hsu37a30142025-06-12 17:57:24 +0800680 std::vector<uint8_t> request = {commandReadStatusReg, 0x0, 0x0, 0x0};
681 std::vector<uint8_t> response(4, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800682
Daniel Hsu37a30142025-06-12 17:57:24 +0800683 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800684 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800685 lg2::error("Failed to send read status register request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800686 co_return false;
687 }
688 /*
689 Read Status Register
690 [LSC_READ_STATUS]
691 0x3C 00 00 00 N/A YY YY YY YY Bit 1 0
692 12 Busy Ready
693 13 Fail OK
Daniel Hsu37a30142025-06-12 17:57:24 +0800694 */
695 statusReg = response.at(2);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800696 co_return true;
697}
698
699sdbusplus::async::task<bool> CpldLatticeManager::readUserCode(
700 uint32_t& userCode)
701{
Daniel Hsuf6470b52025-02-26 15:03:47 +0800702 constexpr size_t resSize = 4;
Daniel Hsu37a30142025-06-12 17:57:24 +0800703 std::vector<uint8_t> request = {commandReadFwVersion, 0x0, 0x0, 0x0};
704 std::vector<uint8_t> response(resSize, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800705
Daniel Hsu37a30142025-06-12 17:57:24 +0800706 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800707 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800708 lg2::error("Failed to send read user code request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800709 co_return false;
710 }
711
712 for (size_t i = 0; i < resSize; i++)
713 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800714 userCode |= response.at(i) << ((3 - i) * 8);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800715 }
716 co_return true;
717}
718
719sdbusplus::async::task<bool> CpldLatticeManager::XO2XO3FamilyUpdate(
720 std::function<bool(int)> progressCallBack)
721{
722 if (progressCallBack == nullptr)
723 {
724 lg2::error("Error: progressCallBack is null.");
725 co_return false;
726 }
727
728 if (!(co_await readDeviceId()))
729 {
730 co_return false;
731 }
732 progressCallBack(10);
733
734 if (!jedFileParser())
735 {
736 lg2::error("JED file parsing failed");
737 co_return false;
738 }
739 progressCallBack(15);
740
741 if (!verifyChecksum())
742 {
743 lg2::error("Checksum verification failed");
744 co_return false;
745 }
746 progressCallBack(20);
747
748 if (!isLCMXO3D)
749 {
750 lg2::error("is not LCMXO3D");
751 }
752
753 lg2::debug("Starts to update ...");
754 lg2::debug("Enable program mode.");
755 progressCallBack(25);
756
757 co_await waitBusyAndVerify();
758
759 if (!(co_await enableProgramMode()))
760 {
761 lg2::error("Enable program mode failed.");
762 co_return false;
763 }
764 progressCallBack(30);
765
766 lg2::debug("Erase flash.");
767 if (!(co_await eraseFlash()))
768 {
769 lg2::error("Erase flash failed.");
770 co_return false;
771 }
772 progressCallBack(40);
773
774 lg2::debug("Reset config flash.");
775 if (!(co_await resetConfigFlash()))
776 {
777 lg2::error("Reset config flash failed.");
778 co_return false;
779 }
780 progressCallBack(50);
781
782 lg2::debug("Write program page ...");
783 if (!(co_await writeProgramPage()))
784 {
785 lg2::error("Write program page failed.");
786 co_return false;
787 }
788 lg2::debug("Write program page done.");
789 progressCallBack(60);
790
791 lg2::debug("Program user code.");
792 if (!(co_await programUserCode()))
793 {
794 lg2::error("Program user code failed.");
795 co_return false;
796 }
797 progressCallBack(70);
798
799 if (!(co_await programDone()))
800 {
801 lg2::error("Program not done.");
802 co_return false;
803 }
804 progressCallBack(80);
805
806 lg2::debug("Disable config interface.");
807 if (!(co_await disableConfigInterface()))
808 {
809 lg2::error("Disable Config Interface failed.");
810 co_return false;
811 }
812 progressCallBack(90);
813
814 lg2::debug("Update completed!");
815
816 co_return true;
817}
818
819sdbusplus::async::task<bool> CpldLatticeManager::updateFirmware(
820 std::function<bool(int)> progressCallBack)
821{
Daniel Hsu61e12672025-06-12 19:20:46 +0800822 co_return co_await XO2XO3FamilyUpdate(progressCallBack);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800823}
824
Daniel Hsuf6470b52025-02-26 15:03:47 +0800825sdbusplus::async::task<bool> CpldLatticeManager::getVersion(
826 std::string& version)
827{
Daniel Hsu37a30142025-06-12 17:57:24 +0800828 auto userCode = std::make_unique<uint32_t>(0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800829
830 if (target.empty())
831 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800832 if (!(co_await readUserCode(*userCode)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800833 {
834 lg2::error("Read usercode failed.");
835 co_return false;
836 }
837
Daniel Hsu37a30142025-06-12 17:57:24 +0800838 lg2::debug("CPLD version: {VERSION}", "VERSION", *userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800839 }
840 else if (target == "CFG0" || target == "CFG1")
841 {
842 isLCMXO3D = true;
843 co_await waitBusyAndVerify();
844
845 if (!(co_await enableProgramMode()))
846 {
847 lg2::error("Enable program mode failed.");
848 co_return false;
849 }
850
851 if (!(co_await resetConfigFlash()))
852 {
853 lg2::error("Reset config flash failed.");
854 co_return false;
855 }
856
Daniel Hsu37a30142025-06-12 17:57:24 +0800857 if (!(co_await readUserCode(*userCode)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800858 {
859 lg2::error("Read usercode failed.");
860 co_return false;
861 }
862
863 if (!(co_await programDone()))
864 {
865 lg2::error("Program not done.");
866 co_return false;
867 }
868
869 if (!(co_await disableConfigInterface()))
870 {
871 lg2::error("Disable Config Interface failed.");
872 co_return false;
873 }
874
875 lg2::debug("CPLD {TARGET} version: {VERSION}", "TARGET", target,
Daniel Hsu37a30142025-06-12 17:57:24 +0800876 "VERSION", *userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800877 }
878 else
879 {
880 lg2::error("Error: unknown target.");
881 co_return false;
882 }
883
Daniel Hsu37a30142025-06-12 17:57:24 +0800884 if (*userCode == 0)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800885 {
886 lg2::error("User code is zero, cannot get version.");
887 co_return false;
888 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800889 version = uint32ToHexStr(*userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800890 co_return true;
891}