blob: b3802f47fca5f43cade4cb2572c0bc8a0c72cbeb [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>
Ken Chend9825682025-07-09 13:49:48 +08008#include <numeric>
Daniel Hsuf6470b52025-02-26 15:03:47 +08009#include <thread>
10#include <vector>
11
Daniel Hsuf6470b52025-02-26 15:03:47 +080012constexpr uint8_t busyWaitmaxRetry = 30;
13constexpr uint8_t busyFlagBit = 0x80;
14constexpr std::chrono::milliseconds waitBusyTime(200);
15
Ken Chen9c05c3c2025-07-24 20:56:34 +080016static constexpr std::string_view tagFuseQuantity = "QF";
17static constexpr std::string_view tagUserCodeHex = "UH";
Daniel Hsuf6470b52025-02-26 15:03:47 +080018static constexpr std::string_view tagCFStart = "L000";
Ken Chend9825682025-07-09 13:49:48 +080019static constexpr std::string_view tagData = "NOTE TAG DATA";
Ken Chen9c05c3c2025-07-24 20:56:34 +080020static constexpr std::string_view tagUserFlashMemory = "NOTE USER MEMORY DATA";
Daniel Hsuf6470b52025-02-26 15:03:47 +080021static constexpr std::string_view tagChecksum = "C";
22static constexpr std::string_view tagUserCode = "NOTE User Electronic";
23static constexpr std::string_view tagEbrInitData = "NOTE EBR_INIT DATA";
Ken Chend9825682025-07-09 13:49:48 +080024static constexpr std::string_view tagEndConfig = "NOTE END CONFIG DATA";
25static constexpr std::string_view tagDevName = "NOTE DEVICE NAME";
Daniel Hsuf6470b52025-02-26 15:03:47 +080026
27constexpr uint8_t isOK = 0;
28constexpr uint8_t isReady = 0;
29constexpr uint8_t busyOrReadyBit = 4;
30constexpr uint8_t failOrOKBit = 5;
31
Daniel Hsuf6470b52025-02-26 15:03:47 +080032enum cpldI2cCmd
33{
34 commandEraseFlash = 0x0E,
35 commandDisableConfigInterface = 0x26,
36 commandReadStatusReg = 0x3C,
37 commandResetConfigFlash = 0x46,
38 commandProgramDone = 0x5E,
39 commandProgramPage = 0x70,
40 commandEnableConfigMode = 0x74,
41 commandReadFwVersion = 0xC0,
42 commandProgramUserCode = 0xC2,
43 commandReadDeviceId = 0xE0,
44 commandReadBusyFlag = 0xF0,
45};
46
47static uint8_t reverse_bit(uint8_t b)
48{
49 b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
50 b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
51 b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
52 return b;
53}
54
Daniel Hsu37a30142025-06-12 17:57:24 +080055std::string uint32ToHexStr(uint32_t value)
56{
57 std::ostringstream oss;
58 oss << std::setfill('0') << std::setw(8) << std::hex << std::uppercase
59 << value;
60 return oss.str();
61}
62
Daniel Hsuf6470b52025-02-26 15:03:47 +080063bool CpldLatticeManager::jedFileParser()
64{
Ken Chend9825682025-07-09 13:49:48 +080065 enum class ParseState
66 {
67 none,
68 cfg,
69 endCfg,
70 ufm,
71 checksum,
72 userCode
73 };
74 ParseState state = ParseState::none;
Daniel Hsuf6470b52025-02-26 15:03:47 +080075
76 if (image == nullptr || imageSize == 0)
77 {
78 lg2::error(
79 "Error: JED file is empty or not found. Please check the file.");
80 return false;
81 }
82
Daniel Hsuf6470b52025-02-26 15:03:47 +080083 std::string content(reinterpret_cast<const char*>(image), imageSize);
Daniel Hsuf6470b52025-02-26 15:03:47 +080084 std::istringstream iss(content);
85 std::string line;
86
Ken Chend9825682025-07-09 13:49:48 +080087 auto pushPage = [](std::string& line, std::vector<uint8_t>& sector) {
88 if (line[0] == '0' || line[0] == '1')
89 {
90 while (line.size() >= 8)
91 {
92 try
93 {
94 sector.push_back(static_cast<uint8_t>(
95 std::stoi(line.substr(0, 8), 0, 2)));
96 line.erase(0, 8);
97 }
98 catch (...)
99 {
100 break;
101 }
102 }
103 }
104 };
105
Daniel Hsuf6470b52025-02-26 15:03:47 +0800106 while (getline(iss, line))
107 {
Ken Chend9825682025-07-09 13:49:48 +0800108 if (!line.empty() && line.back() == '\r')
Daniel Hsuf6470b52025-02-26 15:03:47 +0800109 {
Ken Chend9825682025-07-09 13:49:48 +0800110 line.pop_back();
Daniel Hsuf6470b52025-02-26 15:03:47 +0800111 }
Ken Chend9825682025-07-09 13:49:48 +0800112 if (line.empty())
Daniel Hsuf6470b52025-02-26 15:03:47 +0800113 {
Daniel Hsuf6470b52025-02-26 15:03:47 +0800114 continue;
115 }
Daniel Hsuf6470b52025-02-26 15:03:47 +0800116
Ken Chen9c05c3c2025-07-24 20:56:34 +0800117 if (line.starts_with(tagFuseQuantity))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800118 {
Ken Chend9825682025-07-09 13:49:48 +0800119 ssize_t numberSize = static_cast<ssize_t>(line.find('*')) -
120 static_cast<ssize_t>(line.find('F')) - 1;
121 if (numberSize > 0)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800122 {
Ken Chen9c05c3c2025-07-24 20:56:34 +0800123 fwInfo.fuseQuantity = std::stoul(
124 line.substr(tagFuseQuantity.length(), numberSize));
125 lg2::debug("fuseQuantity Size = {QFSIZE}", "QFSIZE",
126 fwInfo.fuseQuantity);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800127 }
Ken Chend9825682025-07-09 13:49:48 +0800128 }
129 else if (line.starts_with(tagCFStart) ||
130 line.starts_with(tagEbrInitData))
131 {
132 state = ParseState::cfg;
133 continue;
134 }
135 else if (line.starts_with(tagEndConfig))
136 {
137 state = ParseState::endCfg;
138 continue;
139 }
Ken Chen9c05c3c2025-07-24 20:56:34 +0800140 else if (line.starts_with(tagUserFlashMemory) ||
141 line.starts_with(tagData))
Ken Chend9825682025-07-09 13:49:48 +0800142 {
143 state = ParseState::ufm;
144 continue;
145 }
146 else if (line.starts_with(tagUserCode))
147 {
148 state = ParseState::userCode;
149 continue;
150 }
151 else if (line.starts_with(tagChecksum))
152 {
153 state = ParseState::checksum;
154 }
155 else if (line.starts_with(tagDevName))
156 {
157 lg2::debug("{DEVNAME}", "DEVNAME", line);
158 if (line.find(chip) == std::string::npos)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800159 {
Ken Chend9825682025-07-09 13:49:48 +0800160 lg2::debug("STOP UPDATING: The image does not match the chip.");
161 return -1;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800162 }
163 }
164
Ken Chend9825682025-07-09 13:49:48 +0800165 switch (state)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800166 {
Ken Chend9825682025-07-09 13:49:48 +0800167 case ParseState::cfg:
168 pushPage(line, fwInfo.cfgData);
169 break;
170 case ParseState::endCfg:
171 pushPage(line, sumOnly);
172 break;
173 case ParseState::ufm:
174 pushPage(line, fwInfo.ufmData);
175 break;
176 case ParseState::checksum:
177 if (line.size() > 1)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800178 {
Ken Chend9825682025-07-09 13:49:48 +0800179 state = ParseState::none;
180 ssize_t numberSize =
181 static_cast<ssize_t>(line.find('*')) -
182 static_cast<ssize_t>(line.find('C')) - 1;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800183 if (numberSize <= 0)
184 {
Ken Chend9825682025-07-09 13:49:48 +0800185 lg2::debug("Error in parsing checksum");
186 return -1;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800187 }
Ken Chend9825682025-07-09 13:49:48 +0800188 static constexpr auto start = tagChecksum.length();
Daniel Hsuf6470b52025-02-26 15:03:47 +0800189 std::istringstream iss(line.substr(start, numberSize));
Ken Chend9825682025-07-09 13:49:48 +0800190 iss >> std::hex >> fwInfo.checksum;
191 lg2::debug("Checksum = 0x{CHECKSUM}", "CHECKSUM",
192 fwInfo.checksum);
193 }
194 break;
195 case ParseState::userCode:
Ken Chen9c05c3c2025-07-24 20:56:34 +0800196 if (line.starts_with(tagUserCodeHex))
Ken Chend9825682025-07-09 13:49:48 +0800197 {
198 state = ParseState::none;
199 ssize_t numberSize =
200 static_cast<ssize_t>(line.find('*')) -
201 static_cast<ssize_t>(line.find('H')) - 1;
202 if (numberSize <= 0)
203 {
204 lg2::debug("Error in parsing usercode");
205 return -1;
206 }
207 std::istringstream iss(
Ken Chen9c05c3c2025-07-24 20:56:34 +0800208 line.substr(tagUserCodeHex.length(), numberSize));
Daniel Hsuf6470b52025-02-26 15:03:47 +0800209 iss >> std::hex >> fwInfo.version;
Ken Chend9825682025-07-09 13:49:48 +0800210 lg2::debug("UserCode = 0x{USERCODE}", "USERCODE",
Daniel Hsuf6470b52025-02-26 15:03:47 +0800211 fwInfo.version);
212 }
Ken Chend9825682025-07-09 13:49:48 +0800213 break;
214 default:
215 break;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800216 }
Ken Chend9825682025-07-09 13:49:48 +0800217 }
218
219 lg2::debug("CFG Size = {CFGSIZE}", "CFGSIZE", fwInfo.cfgData.size());
220 if (!fwInfo.ufmData.empty())
221 {
Ken Chen9c05c3c2025-07-24 20:56:34 +0800222 lg2::debug("userFlashMemory size = {UFMSIZE}", "UFMSIZE",
223 fwInfo.ufmData.size());
Daniel Hsuf6470b52025-02-26 15:03:47 +0800224 }
225
226 return true;
227}
228
229bool CpldLatticeManager::verifyChecksum()
230{
Ken Chend9825682025-07-09 13:49:48 +0800231 uint32_t calculated = 0U;
232 auto addByte = [](uint32_t sum, uint8_t byte) {
233 return sum + reverse_bit(byte);
234 };
Daniel Hsuf6470b52025-02-26 15:03:47 +0800235
Ken Chend9825682025-07-09 13:49:48 +0800236 calculated = std::accumulate(fwInfo.cfgData.begin(), fwInfo.cfgData.end(),
237 calculated, addByte);
238 calculated =
239 std::accumulate(sumOnly.begin(), sumOnly.end(), calculated, addByte);
240 calculated = std::accumulate(fwInfo.ufmData.begin(), fwInfo.ufmData.end(),
241 calculated, addByte);
242
243 lg2::debug("Calculated checksum = {CALCULATED}", "CALCULATED", lg2::hex,
244 calculated);
245 lg2::debug("Checksum from JED file = {JEDFILECHECKSUM}", "JEDFILECHECKSUM",
246 lg2::hex, fwInfo.checksum);
247
248 if (fwInfo.checksum != (calculated & 0xFFFF))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800249 {
Ken Chend9825682025-07-09 13:49:48 +0800250 lg2::error("JED file checksum compare fail, "
251 "Calculated checksum = {CALCULATED}, "
252 "Checksum from JED file = {JEDFILECHECKSUM}",
253 "CALCULATED", lg2::hex, calculated, "JEDFILECHECKSUM",
254 lg2::hex, fwInfo.checksum);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800255 return false;
256 }
257
Ken Chend9825682025-07-09 13:49:48 +0800258 lg2::debug("JED file checksum compare success");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800259 return true;
260}
261
262sdbusplus::async::task<bool> CpldLatticeManager::readDeviceId()
263{
Daniel Hsu37a30142025-06-12 17:57:24 +0800264 std::vector<uint8_t> request = {commandReadDeviceId, 0x0, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800265 constexpr size_t resSize = 4;
266 std::vector<uint8_t> readData(resSize, 0);
Daniel Hsu37a30142025-06-12 17:57:24 +0800267 bool success = co_await i2cInterface.sendReceive(
268 request.data(), request.size(), readData.data(), resSize);
269
Daniel Hsuf6470b52025-02-26 15:03:47 +0800270 if (!success)
271 {
272 lg2::error(
273 "Fail to read device Id. Please check the I2C bus and address.");
274 co_return false;
275 }
276
Daniel Hsu61e12672025-06-12 19:20:46 +0800277 auto chipWantToUpdate =
278 std::find_if(supportedDeviceMap.begin(), supportedDeviceMap.end(),
279 [this](const auto& pair) {
280 return pair.second.chipName == this->chip;
281 });
Daniel Hsuf6470b52025-02-26 15:03:47 +0800282
Daniel Hsu61e12672025-06-12 19:20:46 +0800283 if (chipWantToUpdate != supportedDeviceMap.end() &&
284 chipWantToUpdate->second.deviceId == readData)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800285 {
286 if (chip.rfind("LCMXO3D", 0) == 0)
287 {
288 isLCMXO3D = true;
289 if (!target.empty() && target != "CFG0" && target != "CFG1")
290 {
291 lg2::error("Unknown target. Only CFG0 and CFG1 are supported.");
292 co_return false;
293 }
294 }
295
296 lg2::debug("Device ID match with chip. Chip name: {CHIPNAME}",
297 "CHIPNAME", chip);
298 co_return true;
299 }
300
Daniel Hsu61e12672025-06-12 19:20:46 +0800301 lg2::error("The device id doesn't match with chip.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800302 co_return false;
303}
304
305sdbusplus::async::task<bool> CpldLatticeManager::enableProgramMode()
306{
Daniel Hsu37a30142025-06-12 17:57:24 +0800307 std::vector<uint8_t> request = {commandEnableConfigMode, 0x08, 0x0, 0x0};
308 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800309
Daniel Hsu37a30142025-06-12 17:57:24 +0800310 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800311 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800312 lg2::error("Failed to send enable program mode request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800313 co_return false;
314 }
315
316 if (!(co_await waitBusyAndVerify()))
317 {
318 lg2::error("Wait busy and verify fail");
319 co_return false;
320 }
321 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
322 co_return true;
323}
324
325sdbusplus::async::task<bool> CpldLatticeManager::eraseFlash()
326{
Daniel Hsu37a30142025-06-12 17:57:24 +0800327 std::vector<uint8_t> request;
328 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800329
330 if (isLCMXO3D)
331 {
332 /*
333 Erase the different internal
334 memories. The bit in YYY defines
335 which memory is erased in Flash
336 access mode.
337 Bit 1=Enable
338 8 Erase CFG0
339 9 Erase CFG1
340 10 Erase UFM0
341 11 Erase UFM1
342 12 Erase UFM2
343 13 Erase UFM3
344 14 Erase CSEC
345 15 Erase USEC
346 16 Erase PUBKEY
347 17 Erase AESKEY
348 18 Erase FEA
349 19 Reserved
350 commandEraseFlash = 0x0E, 0Y YY 00
351 */
352 if (target.empty() || target == "CFG0")
353 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800354 request = {commandEraseFlash, 0x00, 0x01, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800355 }
356 else if (target == "CFG1")
357 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800358 request = {commandEraseFlash, 0x00, 0x02, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800359 }
360 else
361 {
362 lg2::error("Error: unknown target.");
363 co_return false;
364 }
365 }
366 else
367 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800368 request = {commandEraseFlash, 0xC, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800369 }
370
Daniel Hsu37a30142025-06-12 17:57:24 +0800371 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800372 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800373 lg2::error("Failed to send erase flash request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800374 co_return false;
375 }
376
377 if (!(co_await waitBusyAndVerify()))
378 {
379 lg2::error("Wait busy and verify fail");
380 co_return false;
381 }
382 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
383 co_return true;
384}
385
386sdbusplus::async::task<bool> CpldLatticeManager::resetConfigFlash()
387{
Daniel Hsu37a30142025-06-12 17:57:24 +0800388 std::vector<uint8_t> request;
389 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800390 if (isLCMXO3D)
391 {
392 /*
393 Set Page Address pointer to the
394 beginning of the different internal
395 Flash sectors. The bit in YYYY
396 defines which sector is selected.
397 Bit Flash sector selected
398 8 CFG0
399 9 CFG1
400 10 FEA
401 11 PUBKEY
402 12 AESKEY
403 13 CSEC
404 14 UFM0
405 15 UFM1
406 16 UFM2
407 17 UFM3
408 18 USEC
409 19 Reserved
410 20 Reserved
411 21 Reserved
412 22 Reserved
413 commandResetConfigFlash = 0x46, YY YY 00
414 */
415 if (target.empty() || target == "CFG0")
416 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800417 request = {commandResetConfigFlash, 0x00, 0x01, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800418 }
419 else if (target == "CFG1")
420 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800421 request = {commandResetConfigFlash, 0x00, 0x02, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800422 }
423 else
424 {
425 lg2::error(
426 "Error: unknown target. Only CFG0 and CFG1 are supported.");
427 co_return false;
428 }
429 }
430 else
431 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800432 request = {commandResetConfigFlash, 0x0, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800433 }
434
Daniel Hsu37a30142025-06-12 17:57:24 +0800435 co_return i2cInterface.sendReceive(request, response);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800436}
437
438sdbusplus::async::task<bool> CpldLatticeManager::writeProgramPage()
439{
440 /*
441 Program one NVCM/Flash page. Can be
442 used to program the NVCM0/CFG or
443 NVCM1/UFM.
444 */
Daniel Hsu37a30142025-06-12 17:57:24 +0800445 std::vector<uint8_t> request = {commandProgramPage, 0x0, 0x0, 0x01};
446 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800447 size_t iterSize = 16;
448
449 for (size_t i = 0; i < fwInfo.cfgData.size(); i += iterSize)
450 {
451 double progressRate =
452 ((double(i) / double(fwInfo.cfgData.size())) * 100);
453 std::cout << "Update :" << std::fixed << std::dec
454 << std::setprecision(2) << progressRate << "% \r";
455
456 uint8_t len = ((i + iterSize) < fwInfo.cfgData.size())
457 ? iterSize
458 : (fwInfo.cfgData.size() - i);
Daniel Hsu37a30142025-06-12 17:57:24 +0800459 std::vector<uint8_t> data = request;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800460
461 data.insert(
462 data.end(), fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i),
463 fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i + len));
464
Daniel Hsu37a30142025-06-12 17:57:24 +0800465 if (!i2cInterface.sendReceive(data, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800466 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800467 lg2::error("Failed to send program page request. {CURRENT}",
468 "CURRENT", uint32ToHexStr(i));
Daniel Hsuf6470b52025-02-26 15:03:47 +0800469 co_return false;
470 }
471
472 /*
473 Reference spec
474 Important! If don't sleep, it will take a long time to update.
475 */
476 co_await sdbusplus::async::sleep_for(ctx,
477 std::chrono::microseconds(200));
478
479 if (!(co_await waitBusyAndVerify()))
480 {
481 lg2::error("Wait busy and verify fail");
482 co_return false;
483 }
484
485 data.clear();
486 }
487
488 co_return true;
489}
490
491sdbusplus::async::task<bool> CpldLatticeManager::programUserCode()
492{
Daniel Hsu37a30142025-06-12 17:57:24 +0800493 std::vector<uint8_t> request = {commandProgramUserCode, 0x0, 0x0, 0x0};
494 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800495 for (int i = 3; i >= 0; i--)
496 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800497 request.push_back((fwInfo.version >> (i * 8)) & 0xFF);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800498 }
Daniel Hsuf6470b52025-02-26 15:03:47 +0800499
Daniel Hsu37a30142025-06-12 17:57:24 +0800500 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800501 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800502 lg2::error("Failed to send program user code request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800503 co_return false;
504 }
Daniel Hsuf6470b52025-02-26 15:03:47 +0800505 if (!(co_await waitBusyAndVerify()))
506 {
507 lg2::error("Wait busy and verify fail");
508 co_return false;
509 }
510
511 co_return true;
512}
513
514sdbusplus::async::task<bool> CpldLatticeManager::programDone()
515{
Daniel Hsu37a30142025-06-12 17:57:24 +0800516 std::vector<uint8_t> request = {commandProgramDone, 0x0, 0x0, 0x0};
517 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800518
Daniel Hsu37a30142025-06-12 17:57:24 +0800519 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800520 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800521 lg2::error("Failed to send program done request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800522 co_return false;
523 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800524
Daniel Hsuf6470b52025-02-26 15:03:47 +0800525 if (!(co_await waitBusyAndVerify()))
526 {
527 lg2::error("Wait busy and verify fail");
528 co_return false;
529 }
530
531 co_return true;
532}
533
534sdbusplus::async::task<bool> CpldLatticeManager::disableConfigInterface()
535{
Daniel Hsu37a30142025-06-12 17:57:24 +0800536 std::vector<uint8_t> request = {commandDisableConfigInterface, 0x0, 0x0};
537 std::vector<uint8_t> response;
538 co_return i2cInterface.sendReceive(request, response);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800539}
540
541sdbusplus::async::task<bool> CpldLatticeManager::waitBusyAndVerify()
542{
543 uint8_t retry = 0;
544
545 while (retry <= busyWaitmaxRetry)
546 {
547 uint8_t busyFlag = 0xff;
548
Daniel Hsu37a30142025-06-12 17:57:24 +0800549 auto readBusyFlagResult = co_await readBusyFlag(busyFlag);
550 if (!readBusyFlagResult)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800551 {
552 lg2::error("Fail to read busy flag.");
553 co_return false;
554 }
555
556 if (busyFlag & busyFlagBit)
557 {
558 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
559 retry++;
560 if (retry > busyWaitmaxRetry)
561 {
562 lg2::error(
563 "Status Reg : Busy! Please check the I2C bus and address.");
564 co_return false;
565 }
566 }
567 else
568 {
569 break;
570 }
571 } // while loop busy check
572
573 // Check out status reg
Daniel Hsu37a30142025-06-12 17:57:24 +0800574 auto statusReg = std::make_unique<uint8_t>(0xff);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800575
Daniel Hsu37a30142025-06-12 17:57:24 +0800576 if (!(co_await readStatusReg(*statusReg)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800577 {
578 lg2::error("Fail to read status register.");
579 co_return false;
580 }
581
Daniel Hsu37a30142025-06-12 17:57:24 +0800582 if (((*statusReg >> busyOrReadyBit) & 1) == isReady &&
583 ((*statusReg >> failOrOKBit) & 1) == isOK)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800584 {
585 lg2::debug("Status Reg : OK");
586 co_return true;
587 }
588
589 lg2::error("Status Reg : Fail! Please check the I2C bus and address.");
590 co_return false;
591}
592
593sdbusplus::async::task<bool> CpldLatticeManager::readBusyFlag(uint8_t& busyFlag)
594{
Daniel Hsuf6470b52025-02-26 15:03:47 +0800595 constexpr size_t resSize = 1;
Daniel Hsu37a30142025-06-12 17:57:24 +0800596 std::vector<uint8_t> request = {commandReadBusyFlag, 0x0, 0x0, 0x0};
597 std::vector<uint8_t> response(resSize, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800598
Daniel Hsu37a30142025-06-12 17:57:24 +0800599 auto success = i2cInterface.sendReceive(request, response);
600 if (!success && response.size() != resSize)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800601 {
602 co_return false;
603 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800604 busyFlag = response.at(0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800605 co_return true;
606}
607
608sdbusplus::async::task<bool> CpldLatticeManager::readStatusReg(
609 uint8_t& statusReg)
610{
Daniel Hsu37a30142025-06-12 17:57:24 +0800611 std::vector<uint8_t> request = {commandReadStatusReg, 0x0, 0x0, 0x0};
612 std::vector<uint8_t> response(4, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800613
Daniel Hsu37a30142025-06-12 17:57:24 +0800614 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800615 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800616 lg2::error("Failed to send read status register request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800617 co_return false;
618 }
619 /*
620 Read Status Register
621 [LSC_READ_STATUS]
622 0x3C 00 00 00 N/A YY YY YY YY Bit 1 0
623 12 Busy Ready
624 13 Fail OK
Daniel Hsu37a30142025-06-12 17:57:24 +0800625 */
626 statusReg = response.at(2);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800627 co_return true;
628}
629
630sdbusplus::async::task<bool> CpldLatticeManager::readUserCode(
631 uint32_t& userCode)
632{
Daniel Hsuf6470b52025-02-26 15:03:47 +0800633 constexpr size_t resSize = 4;
Daniel Hsu37a30142025-06-12 17:57:24 +0800634 std::vector<uint8_t> request = {commandReadFwVersion, 0x0, 0x0, 0x0};
635 std::vector<uint8_t> response(resSize, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800636
Daniel Hsu37a30142025-06-12 17:57:24 +0800637 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800638 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800639 lg2::error("Failed to send read user code request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800640 co_return false;
641 }
642
643 for (size_t i = 0; i < resSize; i++)
644 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800645 userCode |= response.at(i) << ((3 - i) * 8);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800646 }
647 co_return true;
648}
649
650sdbusplus::async::task<bool> CpldLatticeManager::XO2XO3FamilyUpdate(
651 std::function<bool(int)> progressCallBack)
652{
653 if (progressCallBack == nullptr)
654 {
655 lg2::error("Error: progressCallBack is null.");
656 co_return false;
657 }
658
659 if (!(co_await readDeviceId()))
660 {
661 co_return false;
662 }
663 progressCallBack(10);
664
665 if (!jedFileParser())
666 {
667 lg2::error("JED file parsing failed");
668 co_return false;
669 }
670 progressCallBack(15);
671
672 if (!verifyChecksum())
673 {
674 lg2::error("Checksum verification failed");
675 co_return false;
676 }
677 progressCallBack(20);
678
679 if (!isLCMXO3D)
680 {
681 lg2::error("is not LCMXO3D");
682 }
683
684 lg2::debug("Starts to update ...");
685 lg2::debug("Enable program mode.");
686 progressCallBack(25);
687
688 co_await waitBusyAndVerify();
689
690 if (!(co_await enableProgramMode()))
691 {
692 lg2::error("Enable program mode failed.");
693 co_return false;
694 }
695 progressCallBack(30);
696
697 lg2::debug("Erase flash.");
698 if (!(co_await eraseFlash()))
699 {
700 lg2::error("Erase flash failed.");
701 co_return false;
702 }
703 progressCallBack(40);
704
705 lg2::debug("Reset config flash.");
706 if (!(co_await resetConfigFlash()))
707 {
708 lg2::error("Reset config flash failed.");
709 co_return false;
710 }
711 progressCallBack(50);
712
713 lg2::debug("Write program page ...");
714 if (!(co_await writeProgramPage()))
715 {
716 lg2::error("Write program page failed.");
717 co_return false;
718 }
719 lg2::debug("Write program page done.");
720 progressCallBack(60);
721
722 lg2::debug("Program user code.");
723 if (!(co_await programUserCode()))
724 {
725 lg2::error("Program user code failed.");
726 co_return false;
727 }
728 progressCallBack(70);
729
730 if (!(co_await programDone()))
731 {
732 lg2::error("Program not done.");
733 co_return false;
734 }
735 progressCallBack(80);
736
737 lg2::debug("Disable config interface.");
738 if (!(co_await disableConfigInterface()))
739 {
740 lg2::error("Disable Config Interface failed.");
741 co_return false;
742 }
743 progressCallBack(90);
744
745 lg2::debug("Update completed!");
746
747 co_return true;
748}
749
750sdbusplus::async::task<bool> CpldLatticeManager::updateFirmware(
751 std::function<bool(int)> progressCallBack)
752{
Daniel Hsu61e12672025-06-12 19:20:46 +0800753 co_return co_await XO2XO3FamilyUpdate(progressCallBack);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800754}
755
Daniel Hsuf6470b52025-02-26 15:03:47 +0800756sdbusplus::async::task<bool> CpldLatticeManager::getVersion(
757 std::string& version)
758{
Daniel Hsu37a30142025-06-12 17:57:24 +0800759 auto userCode = std::make_unique<uint32_t>(0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800760
761 if (target.empty())
762 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800763 if (!(co_await readUserCode(*userCode)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800764 {
765 lg2::error("Read usercode failed.");
766 co_return false;
767 }
768
Daniel Hsu37a30142025-06-12 17:57:24 +0800769 lg2::debug("CPLD version: {VERSION}", "VERSION", *userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800770 }
771 else if (target == "CFG0" || target == "CFG1")
772 {
773 isLCMXO3D = true;
774 co_await waitBusyAndVerify();
775
776 if (!(co_await enableProgramMode()))
777 {
778 lg2::error("Enable program mode failed.");
779 co_return false;
780 }
781
782 if (!(co_await resetConfigFlash()))
783 {
784 lg2::error("Reset config flash failed.");
785 co_return false;
786 }
787
Daniel Hsu37a30142025-06-12 17:57:24 +0800788 if (!(co_await readUserCode(*userCode)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800789 {
790 lg2::error("Read usercode failed.");
791 co_return false;
792 }
793
794 if (!(co_await programDone()))
795 {
796 lg2::error("Program not done.");
797 co_return false;
798 }
799
800 if (!(co_await disableConfigInterface()))
801 {
802 lg2::error("Disable Config Interface failed.");
803 co_return false;
804 }
805
806 lg2::debug("CPLD {TARGET} version: {VERSION}", "TARGET", target,
Daniel Hsu37a30142025-06-12 17:57:24 +0800807 "VERSION", *userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800808 }
809 else
810 {
811 lg2::error("Error: unknown target.");
812 co_return false;
813 }
814
Daniel Hsu37a30142025-06-12 17:57:24 +0800815 if (*userCode == 0)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800816 {
817 lg2::error("User code is zero, cannot get version.");
818 co_return false;
819 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800820 version = uint32ToHexStr(*userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800821 co_return true;
822}