blob: fea4b364c407a8669178540b716acad63d27ca22 [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
16static constexpr std::string_view tagQF = "QF";
17static constexpr std::string_view tagUH = "UH";
18static constexpr std::string_view tagCFStart = "L000";
Ken Chend9825682025-07-09 13:49:48 +080019static constexpr std::string_view tagData = "NOTE TAG DATA";
20static constexpr std::string_view tagUFM = "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 Chend9825682025-07-09 13:49:48 +0800117 if (line.starts_with(tagQF))
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 Chend9825682025-07-09 13:49:48 +0800123 fwInfo.QF = std::stoul(line.substr(tagQF.length(), numberSize));
124 lg2::debug("QF Size = {QFSIZE}", "QFSIZE", fwInfo.QF);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800125 }
Ken Chend9825682025-07-09 13:49:48 +0800126 }
127 else if (line.starts_with(tagCFStart) ||
128 line.starts_with(tagEbrInitData))
129 {
130 state = ParseState::cfg;
131 continue;
132 }
133 else if (line.starts_with(tagEndConfig))
134 {
135 state = ParseState::endCfg;
136 continue;
137 }
138 else if (line.starts_with(tagUFM) || line.starts_with(tagData))
139 {
140 state = ParseState::ufm;
141 continue;
142 }
143 else if (line.starts_with(tagUserCode))
144 {
145 state = ParseState::userCode;
146 continue;
147 }
148 else if (line.starts_with(tagChecksum))
149 {
150 state = ParseState::checksum;
151 }
152 else if (line.starts_with(tagDevName))
153 {
154 lg2::debug("{DEVNAME}", "DEVNAME", line);
155 if (line.find(chip) == std::string::npos)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800156 {
Ken Chend9825682025-07-09 13:49:48 +0800157 lg2::debug("STOP UPDATING: The image does not match the chip.");
158 return -1;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800159 }
160 }
161
Ken Chend9825682025-07-09 13:49:48 +0800162 switch (state)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800163 {
Ken Chend9825682025-07-09 13:49:48 +0800164 case ParseState::cfg:
165 pushPage(line, fwInfo.cfgData);
166 break;
167 case ParseState::endCfg:
168 pushPage(line, sumOnly);
169 break;
170 case ParseState::ufm:
171 pushPage(line, fwInfo.ufmData);
172 break;
173 case ParseState::checksum:
174 if (line.size() > 1)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800175 {
Ken Chend9825682025-07-09 13:49:48 +0800176 state = ParseState::none;
177 ssize_t numberSize =
178 static_cast<ssize_t>(line.find('*')) -
179 static_cast<ssize_t>(line.find('C')) - 1;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800180 if (numberSize <= 0)
181 {
Ken Chend9825682025-07-09 13:49:48 +0800182 lg2::debug("Error in parsing checksum");
183 return -1;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800184 }
Ken Chend9825682025-07-09 13:49:48 +0800185 static constexpr auto start = tagChecksum.length();
Daniel Hsuf6470b52025-02-26 15:03:47 +0800186 std::istringstream iss(line.substr(start, numberSize));
Ken Chend9825682025-07-09 13:49:48 +0800187 iss >> std::hex >> fwInfo.checksum;
188 lg2::debug("Checksum = 0x{CHECKSUM}", "CHECKSUM",
189 fwInfo.checksum);
190 }
191 break;
192 case ParseState::userCode:
193 if (line.starts_with(tagUH))
194 {
195 state = ParseState::none;
196 ssize_t numberSize =
197 static_cast<ssize_t>(line.find('*')) -
198 static_cast<ssize_t>(line.find('H')) - 1;
199 if (numberSize <= 0)
200 {
201 lg2::debug("Error in parsing usercode");
202 return -1;
203 }
204 std::istringstream iss(
205 line.substr(tagUH.length(), numberSize));
Daniel Hsuf6470b52025-02-26 15:03:47 +0800206 iss >> std::hex >> fwInfo.version;
Ken Chend9825682025-07-09 13:49:48 +0800207 lg2::debug("UserCode = 0x{USERCODE}", "USERCODE",
Daniel Hsuf6470b52025-02-26 15:03:47 +0800208 fwInfo.version);
209 }
Ken Chend9825682025-07-09 13:49:48 +0800210 break;
211 default:
212 break;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800213 }
Ken Chend9825682025-07-09 13:49:48 +0800214 }
215
216 lg2::debug("CFG Size = {CFGSIZE}", "CFGSIZE", fwInfo.cfgData.size());
217 if (!fwInfo.ufmData.empty())
218 {
219 lg2::debug("UFM size = {UFMSIZE}", "UFMSIZE", fwInfo.ufmData.size());
Daniel Hsuf6470b52025-02-26 15:03:47 +0800220 }
221
222 return true;
223}
224
225bool CpldLatticeManager::verifyChecksum()
226{
Ken Chend9825682025-07-09 13:49:48 +0800227 uint32_t calculated = 0U;
228 auto addByte = [](uint32_t sum, uint8_t byte) {
229 return sum + reverse_bit(byte);
230 };
Daniel Hsuf6470b52025-02-26 15:03:47 +0800231
Ken Chend9825682025-07-09 13:49:48 +0800232 calculated = std::accumulate(fwInfo.cfgData.begin(), fwInfo.cfgData.end(),
233 calculated, addByte);
234 calculated =
235 std::accumulate(sumOnly.begin(), sumOnly.end(), calculated, addByte);
236 calculated = std::accumulate(fwInfo.ufmData.begin(), fwInfo.ufmData.end(),
237 calculated, addByte);
238
239 lg2::debug("Calculated checksum = {CALCULATED}", "CALCULATED", lg2::hex,
240 calculated);
241 lg2::debug("Checksum from JED file = {JEDFILECHECKSUM}", "JEDFILECHECKSUM",
242 lg2::hex, fwInfo.checksum);
243
244 if (fwInfo.checksum != (calculated & 0xFFFF))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800245 {
Ken Chend9825682025-07-09 13:49:48 +0800246 lg2::error("JED file checksum compare fail, "
247 "Calculated checksum = {CALCULATED}, "
248 "Checksum from JED file = {JEDFILECHECKSUM}",
249 "CALCULATED", lg2::hex, calculated, "JEDFILECHECKSUM",
250 lg2::hex, fwInfo.checksum);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800251 return false;
252 }
253
Ken Chend9825682025-07-09 13:49:48 +0800254 lg2::debug("JED file checksum compare success");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800255 return true;
256}
257
258sdbusplus::async::task<bool> CpldLatticeManager::readDeviceId()
259{
Daniel Hsu37a30142025-06-12 17:57:24 +0800260 std::vector<uint8_t> request = {commandReadDeviceId, 0x0, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800261 constexpr size_t resSize = 4;
262 std::vector<uint8_t> readData(resSize, 0);
Daniel Hsu37a30142025-06-12 17:57:24 +0800263 bool success = co_await i2cInterface.sendReceive(
264 request.data(), request.size(), readData.data(), resSize);
265
Daniel Hsuf6470b52025-02-26 15:03:47 +0800266 if (!success)
267 {
268 lg2::error(
269 "Fail to read device Id. Please check the I2C bus and address.");
270 co_return false;
271 }
272
Daniel Hsu61e12672025-06-12 19:20:46 +0800273 auto chipWantToUpdate =
274 std::find_if(supportedDeviceMap.begin(), supportedDeviceMap.end(),
275 [this](const auto& pair) {
276 return pair.second.chipName == this->chip;
277 });
Daniel Hsuf6470b52025-02-26 15:03:47 +0800278
Daniel Hsu61e12672025-06-12 19:20:46 +0800279 if (chipWantToUpdate != supportedDeviceMap.end() &&
280 chipWantToUpdate->second.deviceId == readData)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800281 {
282 if (chip.rfind("LCMXO3D", 0) == 0)
283 {
284 isLCMXO3D = true;
285 if (!target.empty() && target != "CFG0" && target != "CFG1")
286 {
287 lg2::error("Unknown target. Only CFG0 and CFG1 are supported.");
288 co_return false;
289 }
290 }
291
292 lg2::debug("Device ID match with chip. Chip name: {CHIPNAME}",
293 "CHIPNAME", chip);
294 co_return true;
295 }
296
Daniel Hsu61e12672025-06-12 19:20:46 +0800297 lg2::error("The device id doesn't match with chip.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800298 co_return false;
299}
300
301sdbusplus::async::task<bool> CpldLatticeManager::enableProgramMode()
302{
Daniel Hsu37a30142025-06-12 17:57:24 +0800303 std::vector<uint8_t> request = {commandEnableConfigMode, 0x08, 0x0, 0x0};
304 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800305
Daniel Hsu37a30142025-06-12 17:57:24 +0800306 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800307 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800308 lg2::error("Failed to send enable program mode request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800309 co_return false;
310 }
311
312 if (!(co_await waitBusyAndVerify()))
313 {
314 lg2::error("Wait busy and verify fail");
315 co_return false;
316 }
317 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
318 co_return true;
319}
320
321sdbusplus::async::task<bool> CpldLatticeManager::eraseFlash()
322{
Daniel Hsu37a30142025-06-12 17:57:24 +0800323 std::vector<uint8_t> request;
324 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800325
326 if (isLCMXO3D)
327 {
328 /*
329 Erase the different internal
330 memories. The bit in YYY defines
331 which memory is erased in Flash
332 access mode.
333 Bit 1=Enable
334 8 Erase CFG0
335 9 Erase CFG1
336 10 Erase UFM0
337 11 Erase UFM1
338 12 Erase UFM2
339 13 Erase UFM3
340 14 Erase CSEC
341 15 Erase USEC
342 16 Erase PUBKEY
343 17 Erase AESKEY
344 18 Erase FEA
345 19 Reserved
346 commandEraseFlash = 0x0E, 0Y YY 00
347 */
348 if (target.empty() || target == "CFG0")
349 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800350 request = {commandEraseFlash, 0x00, 0x01, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800351 }
352 else if (target == "CFG1")
353 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800354 request = {commandEraseFlash, 0x00, 0x02, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800355 }
356 else
357 {
358 lg2::error("Error: unknown target.");
359 co_return false;
360 }
361 }
362 else
363 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800364 request = {commandEraseFlash, 0xC, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800365 }
366
Daniel Hsu37a30142025-06-12 17:57:24 +0800367 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800368 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800369 lg2::error("Failed to send erase flash request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800370 co_return false;
371 }
372
373 if (!(co_await waitBusyAndVerify()))
374 {
375 lg2::error("Wait busy and verify fail");
376 co_return false;
377 }
378 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
379 co_return true;
380}
381
382sdbusplus::async::task<bool> CpldLatticeManager::resetConfigFlash()
383{
Daniel Hsu37a30142025-06-12 17:57:24 +0800384 std::vector<uint8_t> request;
385 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800386 if (isLCMXO3D)
387 {
388 /*
389 Set Page Address pointer to the
390 beginning of the different internal
391 Flash sectors. The bit in YYYY
392 defines which sector is selected.
393 Bit Flash sector selected
394 8 CFG0
395 9 CFG1
396 10 FEA
397 11 PUBKEY
398 12 AESKEY
399 13 CSEC
400 14 UFM0
401 15 UFM1
402 16 UFM2
403 17 UFM3
404 18 USEC
405 19 Reserved
406 20 Reserved
407 21 Reserved
408 22 Reserved
409 commandResetConfigFlash = 0x46, YY YY 00
410 */
411 if (target.empty() || target == "CFG0")
412 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800413 request = {commandResetConfigFlash, 0x00, 0x01, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800414 }
415 else if (target == "CFG1")
416 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800417 request = {commandResetConfigFlash, 0x00, 0x02, 0x00};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800418 }
419 else
420 {
421 lg2::error(
422 "Error: unknown target. Only CFG0 and CFG1 are supported.");
423 co_return false;
424 }
425 }
426 else
427 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800428 request = {commandResetConfigFlash, 0x0, 0x0, 0x0};
Daniel Hsuf6470b52025-02-26 15:03:47 +0800429 }
430
Daniel Hsu37a30142025-06-12 17:57:24 +0800431 co_return i2cInterface.sendReceive(request, response);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800432}
433
434sdbusplus::async::task<bool> CpldLatticeManager::writeProgramPage()
435{
436 /*
437 Program one NVCM/Flash page. Can be
438 used to program the NVCM0/CFG or
439 NVCM1/UFM.
440 */
Daniel Hsu37a30142025-06-12 17:57:24 +0800441 std::vector<uint8_t> request = {commandProgramPage, 0x0, 0x0, 0x01};
442 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800443 size_t iterSize = 16;
444
445 for (size_t i = 0; i < fwInfo.cfgData.size(); i += iterSize)
446 {
447 double progressRate =
448 ((double(i) / double(fwInfo.cfgData.size())) * 100);
449 std::cout << "Update :" << std::fixed << std::dec
450 << std::setprecision(2) << progressRate << "% \r";
451
452 uint8_t len = ((i + iterSize) < fwInfo.cfgData.size())
453 ? iterSize
454 : (fwInfo.cfgData.size() - i);
Daniel Hsu37a30142025-06-12 17:57:24 +0800455 std::vector<uint8_t> data = request;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800456
457 data.insert(
458 data.end(), fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i),
459 fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i + len));
460
Daniel Hsu37a30142025-06-12 17:57:24 +0800461 if (!i2cInterface.sendReceive(data, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800462 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800463 lg2::error("Failed to send program page request. {CURRENT}",
464 "CURRENT", uint32ToHexStr(i));
Daniel Hsuf6470b52025-02-26 15:03:47 +0800465 co_return false;
466 }
467
468 /*
469 Reference spec
470 Important! If don't sleep, it will take a long time to update.
471 */
472 co_await sdbusplus::async::sleep_for(ctx,
473 std::chrono::microseconds(200));
474
475 if (!(co_await waitBusyAndVerify()))
476 {
477 lg2::error("Wait busy and verify fail");
478 co_return false;
479 }
480
481 data.clear();
482 }
483
484 co_return true;
485}
486
487sdbusplus::async::task<bool> CpldLatticeManager::programUserCode()
488{
Daniel Hsu37a30142025-06-12 17:57:24 +0800489 std::vector<uint8_t> request = {commandProgramUserCode, 0x0, 0x0, 0x0};
490 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800491 for (int i = 3; i >= 0; i--)
492 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800493 request.push_back((fwInfo.version >> (i * 8)) & 0xFF);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800494 }
Daniel Hsuf6470b52025-02-26 15:03:47 +0800495
Daniel Hsu37a30142025-06-12 17:57:24 +0800496 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800497 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800498 lg2::error("Failed to send program user code request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800499 co_return false;
500 }
Daniel Hsuf6470b52025-02-26 15:03:47 +0800501 if (!(co_await waitBusyAndVerify()))
502 {
503 lg2::error("Wait busy and verify fail");
504 co_return false;
505 }
506
507 co_return true;
508}
509
510sdbusplus::async::task<bool> CpldLatticeManager::programDone()
511{
Daniel Hsu37a30142025-06-12 17:57:24 +0800512 std::vector<uint8_t> request = {commandProgramDone, 0x0, 0x0, 0x0};
513 std::vector<uint8_t> response;
Daniel Hsuf6470b52025-02-26 15:03:47 +0800514
Daniel Hsu37a30142025-06-12 17:57:24 +0800515 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800516 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800517 lg2::error("Failed to send program done request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800518 co_return false;
519 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800520
Daniel Hsuf6470b52025-02-26 15:03:47 +0800521 if (!(co_await waitBusyAndVerify()))
522 {
523 lg2::error("Wait busy and verify fail");
524 co_return false;
525 }
526
527 co_return true;
528}
529
530sdbusplus::async::task<bool> CpldLatticeManager::disableConfigInterface()
531{
Daniel Hsu37a30142025-06-12 17:57:24 +0800532 std::vector<uint8_t> request = {commandDisableConfigInterface, 0x0, 0x0};
533 std::vector<uint8_t> response;
534 co_return i2cInterface.sendReceive(request, response);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800535}
536
537sdbusplus::async::task<bool> CpldLatticeManager::waitBusyAndVerify()
538{
539 uint8_t retry = 0;
540
541 while (retry <= busyWaitmaxRetry)
542 {
543 uint8_t busyFlag = 0xff;
544
Daniel Hsu37a30142025-06-12 17:57:24 +0800545 auto readBusyFlagResult = co_await readBusyFlag(busyFlag);
546 if (!readBusyFlagResult)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800547 {
548 lg2::error("Fail to read busy flag.");
549 co_return false;
550 }
551
552 if (busyFlag & busyFlagBit)
553 {
554 co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
555 retry++;
556 if (retry > busyWaitmaxRetry)
557 {
558 lg2::error(
559 "Status Reg : Busy! Please check the I2C bus and address.");
560 co_return false;
561 }
562 }
563 else
564 {
565 break;
566 }
567 } // while loop busy check
568
569 // Check out status reg
Daniel Hsu37a30142025-06-12 17:57:24 +0800570 auto statusReg = std::make_unique<uint8_t>(0xff);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800571
Daniel Hsu37a30142025-06-12 17:57:24 +0800572 if (!(co_await readStatusReg(*statusReg)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800573 {
574 lg2::error("Fail to read status register.");
575 co_return false;
576 }
577
Daniel Hsu37a30142025-06-12 17:57:24 +0800578 if (((*statusReg >> busyOrReadyBit) & 1) == isReady &&
579 ((*statusReg >> failOrOKBit) & 1) == isOK)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800580 {
581 lg2::debug("Status Reg : OK");
582 co_return true;
583 }
584
585 lg2::error("Status Reg : Fail! Please check the I2C bus and address.");
586 co_return false;
587}
588
589sdbusplus::async::task<bool> CpldLatticeManager::readBusyFlag(uint8_t& busyFlag)
590{
Daniel Hsuf6470b52025-02-26 15:03:47 +0800591 constexpr size_t resSize = 1;
Daniel Hsu37a30142025-06-12 17:57:24 +0800592 std::vector<uint8_t> request = {commandReadBusyFlag, 0x0, 0x0, 0x0};
593 std::vector<uint8_t> response(resSize, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800594
Daniel Hsu37a30142025-06-12 17:57:24 +0800595 auto success = i2cInterface.sendReceive(request, response);
596 if (!success && response.size() != resSize)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800597 {
598 co_return false;
599 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800600 busyFlag = response.at(0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800601 co_return true;
602}
603
604sdbusplus::async::task<bool> CpldLatticeManager::readStatusReg(
605 uint8_t& statusReg)
606{
Daniel Hsu37a30142025-06-12 17:57:24 +0800607 std::vector<uint8_t> request = {commandReadStatusReg, 0x0, 0x0, 0x0};
608 std::vector<uint8_t> response(4, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800609
Daniel Hsu37a30142025-06-12 17:57:24 +0800610 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800611 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800612 lg2::error("Failed to send read status register request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800613 co_return false;
614 }
615 /*
616 Read Status Register
617 [LSC_READ_STATUS]
618 0x3C 00 00 00 N/A YY YY YY YY Bit 1 0
619 12 Busy Ready
620 13 Fail OK
Daniel Hsu37a30142025-06-12 17:57:24 +0800621 */
622 statusReg = response.at(2);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800623 co_return true;
624}
625
626sdbusplus::async::task<bool> CpldLatticeManager::readUserCode(
627 uint32_t& userCode)
628{
Daniel Hsuf6470b52025-02-26 15:03:47 +0800629 constexpr size_t resSize = 4;
Daniel Hsu37a30142025-06-12 17:57:24 +0800630 std::vector<uint8_t> request = {commandReadFwVersion, 0x0, 0x0, 0x0};
631 std::vector<uint8_t> response(resSize, 0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800632
Daniel Hsu37a30142025-06-12 17:57:24 +0800633 if (!i2cInterface.sendReceive(request, response))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800634 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800635 lg2::error("Failed to send read user code request.");
Daniel Hsuf6470b52025-02-26 15:03:47 +0800636 co_return false;
637 }
638
639 for (size_t i = 0; i < resSize; i++)
640 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800641 userCode |= response.at(i) << ((3 - i) * 8);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800642 }
643 co_return true;
644}
645
646sdbusplus::async::task<bool> CpldLatticeManager::XO2XO3FamilyUpdate(
647 std::function<bool(int)> progressCallBack)
648{
649 if (progressCallBack == nullptr)
650 {
651 lg2::error("Error: progressCallBack is null.");
652 co_return false;
653 }
654
655 if (!(co_await readDeviceId()))
656 {
657 co_return false;
658 }
659 progressCallBack(10);
660
661 if (!jedFileParser())
662 {
663 lg2::error("JED file parsing failed");
664 co_return false;
665 }
666 progressCallBack(15);
667
668 if (!verifyChecksum())
669 {
670 lg2::error("Checksum verification failed");
671 co_return false;
672 }
673 progressCallBack(20);
674
675 if (!isLCMXO3D)
676 {
677 lg2::error("is not LCMXO3D");
678 }
679
680 lg2::debug("Starts to update ...");
681 lg2::debug("Enable program mode.");
682 progressCallBack(25);
683
684 co_await waitBusyAndVerify();
685
686 if (!(co_await enableProgramMode()))
687 {
688 lg2::error("Enable program mode failed.");
689 co_return false;
690 }
691 progressCallBack(30);
692
693 lg2::debug("Erase flash.");
694 if (!(co_await eraseFlash()))
695 {
696 lg2::error("Erase flash failed.");
697 co_return false;
698 }
699 progressCallBack(40);
700
701 lg2::debug("Reset config flash.");
702 if (!(co_await resetConfigFlash()))
703 {
704 lg2::error("Reset config flash failed.");
705 co_return false;
706 }
707 progressCallBack(50);
708
709 lg2::debug("Write program page ...");
710 if (!(co_await writeProgramPage()))
711 {
712 lg2::error("Write program page failed.");
713 co_return false;
714 }
715 lg2::debug("Write program page done.");
716 progressCallBack(60);
717
718 lg2::debug("Program user code.");
719 if (!(co_await programUserCode()))
720 {
721 lg2::error("Program user code failed.");
722 co_return false;
723 }
724 progressCallBack(70);
725
726 if (!(co_await programDone()))
727 {
728 lg2::error("Program not done.");
729 co_return false;
730 }
731 progressCallBack(80);
732
733 lg2::debug("Disable config interface.");
734 if (!(co_await disableConfigInterface()))
735 {
736 lg2::error("Disable Config Interface failed.");
737 co_return false;
738 }
739 progressCallBack(90);
740
741 lg2::debug("Update completed!");
742
743 co_return true;
744}
745
746sdbusplus::async::task<bool> CpldLatticeManager::updateFirmware(
747 std::function<bool(int)> progressCallBack)
748{
Daniel Hsu61e12672025-06-12 19:20:46 +0800749 co_return co_await XO2XO3FamilyUpdate(progressCallBack);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800750}
751
Daniel Hsuf6470b52025-02-26 15:03:47 +0800752sdbusplus::async::task<bool> CpldLatticeManager::getVersion(
753 std::string& version)
754{
Daniel Hsu37a30142025-06-12 17:57:24 +0800755 auto userCode = std::make_unique<uint32_t>(0);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800756
757 if (target.empty())
758 {
Daniel Hsu37a30142025-06-12 17:57:24 +0800759 if (!(co_await readUserCode(*userCode)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800760 {
761 lg2::error("Read usercode failed.");
762 co_return false;
763 }
764
Daniel Hsu37a30142025-06-12 17:57:24 +0800765 lg2::debug("CPLD version: {VERSION}", "VERSION", *userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800766 }
767 else if (target == "CFG0" || target == "CFG1")
768 {
769 isLCMXO3D = true;
770 co_await waitBusyAndVerify();
771
772 if (!(co_await enableProgramMode()))
773 {
774 lg2::error("Enable program mode failed.");
775 co_return false;
776 }
777
778 if (!(co_await resetConfigFlash()))
779 {
780 lg2::error("Reset config flash failed.");
781 co_return false;
782 }
783
Daniel Hsu37a30142025-06-12 17:57:24 +0800784 if (!(co_await readUserCode(*userCode)))
Daniel Hsuf6470b52025-02-26 15:03:47 +0800785 {
786 lg2::error("Read usercode failed.");
787 co_return false;
788 }
789
790 if (!(co_await programDone()))
791 {
792 lg2::error("Program not done.");
793 co_return false;
794 }
795
796 if (!(co_await disableConfigInterface()))
797 {
798 lg2::error("Disable Config Interface failed.");
799 co_return false;
800 }
801
802 lg2::debug("CPLD {TARGET} version: {VERSION}", "TARGET", target,
Daniel Hsu37a30142025-06-12 17:57:24 +0800803 "VERSION", *userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800804 }
805 else
806 {
807 lg2::error("Error: unknown target.");
808 co_return false;
809 }
810
Daniel Hsu37a30142025-06-12 17:57:24 +0800811 if (*userCode == 0)
Daniel Hsuf6470b52025-02-26 15:03:47 +0800812 {
813 lg2::error("User code is zero, cannot get version.");
814 co_return false;
815 }
Daniel Hsu37a30142025-06-12 17:57:24 +0800816 version = uint32ToHexStr(*userCode);
Daniel Hsuf6470b52025-02-26 15:03:47 +0800817 co_return true;
818}