xref: /openbmc/phosphor-bmc-code-mgmt/cpld/lattice/lattice.cpp (revision 61e12672130e6724256f4fd3806e1032d0112940)
1f6470b5eSDaniel Hsu #include "lattice.hpp"
2f6470b5eSDaniel Hsu 
3f6470b5eSDaniel Hsu #include <phosphor-logging/lg2.hpp>
4f6470b5eSDaniel Hsu 
5f6470b5eSDaniel Hsu #include <algorithm>
6f6470b5eSDaniel Hsu #include <fstream>
7f6470b5eSDaniel Hsu #include <map>
8f6470b5eSDaniel Hsu #include <thread>
9f6470b5eSDaniel Hsu #include <vector>
10f6470b5eSDaniel Hsu 
11f6470b5eSDaniel Hsu constexpr uint8_t busyWaitmaxRetry = 30;
12f6470b5eSDaniel Hsu constexpr uint8_t busyFlagBit = 0x80;
13f6470b5eSDaniel Hsu constexpr std::chrono::milliseconds waitBusyTime(200);
14f6470b5eSDaniel Hsu 
15f6470b5eSDaniel Hsu static constexpr std::string_view tagQF = "QF";
16f6470b5eSDaniel Hsu static constexpr std::string_view tagUH = "UH";
17f6470b5eSDaniel Hsu static constexpr std::string_view tagCFStart = "L000";
18f6470b5eSDaniel Hsu static constexpr std::string_view tagChecksum = "C";
19f6470b5eSDaniel Hsu static constexpr std::string_view tagUserCode = "NOTE User Electronic";
20f6470b5eSDaniel Hsu static constexpr std::string_view tagEbrInitData = "NOTE EBR_INIT DATA";
21f6470b5eSDaniel Hsu 
22f6470b5eSDaniel Hsu constexpr uint8_t isOK = 0;
23f6470b5eSDaniel Hsu constexpr uint8_t isReady = 0;
24f6470b5eSDaniel Hsu constexpr uint8_t busyOrReadyBit = 4;
25f6470b5eSDaniel Hsu constexpr uint8_t failOrOKBit = 5;
26f6470b5eSDaniel Hsu 
27f6470b5eSDaniel Hsu constexpr bool enableUpdateEbrInit = false;
28f6470b5eSDaniel Hsu 
29f6470b5eSDaniel Hsu enum cpldI2cCmd
30f6470b5eSDaniel Hsu {
31f6470b5eSDaniel Hsu     commandEraseFlash = 0x0E,
32f6470b5eSDaniel Hsu     commandDisableConfigInterface = 0x26,
33f6470b5eSDaniel Hsu     commandReadStatusReg = 0x3C,
34f6470b5eSDaniel Hsu     commandResetConfigFlash = 0x46,
35f6470b5eSDaniel Hsu     commandProgramDone = 0x5E,
36f6470b5eSDaniel Hsu     commandProgramPage = 0x70,
37f6470b5eSDaniel Hsu     commandEnableConfigMode = 0x74,
38f6470b5eSDaniel Hsu     commandReadFwVersion = 0xC0,
39f6470b5eSDaniel Hsu     commandProgramUserCode = 0xC2,
40f6470b5eSDaniel Hsu     commandReadDeviceId = 0xE0,
41f6470b5eSDaniel Hsu     commandReadBusyFlag = 0xF0,
42f6470b5eSDaniel Hsu };
43f6470b5eSDaniel Hsu 
44f6470b5eSDaniel Hsu static uint8_t reverse_bit(uint8_t b)
45f6470b5eSDaniel Hsu {
reverse_bit(uint8_t b)46f6470b5eSDaniel Hsu     b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
47f6470b5eSDaniel Hsu     b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
48f6470b5eSDaniel Hsu     b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
49f6470b5eSDaniel Hsu     return b;
50f6470b5eSDaniel Hsu }
51f6470b5eSDaniel Hsu 
52f6470b5eSDaniel Hsu static int findNumberSize(const std::string& end, const std::string& start,
53f6470b5eSDaniel Hsu                           const std::string& line)
54f6470b5eSDaniel Hsu {
55f6470b5eSDaniel Hsu     auto pos1 = line.find(start);
56f6470b5eSDaniel Hsu     auto pos2 = line.find(end);
57f6470b5eSDaniel Hsu 
58f6470b5eSDaniel Hsu     if (pos1 == std::string::npos || pos2 == std::string::npos || pos1 >= pos2)
59f6470b5eSDaniel Hsu     {
60f6470b5eSDaniel Hsu         return false;
61f6470b5eSDaniel Hsu     }
findNumberSize(const std::string & end,const std::string & start,const std::string & line)62f6470b5eSDaniel Hsu 
63f6470b5eSDaniel Hsu     return static_cast<int>(pos2 - pos1 - 1);
64f6470b5eSDaniel Hsu }
65f6470b5eSDaniel Hsu 
6637a30143SDaniel Hsu std::string uint32ToHexStr(uint32_t value)
6737a30143SDaniel Hsu {
6837a30143SDaniel Hsu     std::ostringstream oss;
6937a30143SDaniel Hsu     oss << std::setfill('0') << std::setw(8) << std::hex << std::uppercase
7037a30143SDaniel Hsu         << value;
7137a30143SDaniel Hsu     return oss.str();
7237a30143SDaniel Hsu }
7337a30143SDaniel Hsu 
74f6470b5eSDaniel Hsu bool CpldLatticeManager::jedFileParser()
75f6470b5eSDaniel Hsu {
jedFileParser()76f6470b5eSDaniel Hsu     bool cfStart = false;
77f6470b5eSDaniel Hsu     bool ufmStart = false; // for isLCMXO3D
78f6470b5eSDaniel Hsu     bool ufmPrepare = false;
79f6470b5eSDaniel Hsu     bool versionStart = false;
80f6470b5eSDaniel Hsu     bool checksumStart = false;
81f6470b5eSDaniel Hsu     bool ebrInitDataStart = false;
82f6470b5eSDaniel Hsu     int numberSize = 0;
83f6470b5eSDaniel Hsu 
84f6470b5eSDaniel Hsu     if (image == nullptr || imageSize == 0)
85f6470b5eSDaniel Hsu     {
86f6470b5eSDaniel Hsu         lg2::error(
87f6470b5eSDaniel Hsu             "Error: JED file is empty or not found. Please check the file.");
88f6470b5eSDaniel Hsu         return false;
89f6470b5eSDaniel Hsu     }
90f6470b5eSDaniel Hsu 
91f6470b5eSDaniel Hsu     // Convert binary data to a string
92f6470b5eSDaniel Hsu     std::string content(reinterpret_cast<const char*>(image), imageSize);
93f6470b5eSDaniel Hsu     // Use stringstream to simulate file reading
94f6470b5eSDaniel Hsu     std::istringstream iss(content);
95f6470b5eSDaniel Hsu     std::string line;
96f6470b5eSDaniel Hsu 
97f6470b5eSDaniel Hsu     // Parsing JED file
98f6470b5eSDaniel Hsu     while (getline(iss, line))
99f6470b5eSDaniel Hsu     {
100f6470b5eSDaniel Hsu         if (line.rfind(tagQF, 0) == 0)
101f6470b5eSDaniel Hsu         {
102f6470b5eSDaniel Hsu             numberSize = findNumberSize("*", "F", line);
103f6470b5eSDaniel Hsu             if (numberSize <= 0)
104f6470b5eSDaniel Hsu             {
105f6470b5eSDaniel Hsu                 lg2::error("Error in parsing QF tag");
106f6470b5eSDaniel Hsu                 return false;
107f6470b5eSDaniel Hsu             }
108f6470b5eSDaniel Hsu             static constexpr auto start = tagQF.length();
109f6470b5eSDaniel Hsu             fwInfo.QF = std::stoul(line.substr(start, numberSize));
110f6470b5eSDaniel Hsu 
111f6470b5eSDaniel Hsu             lg2::debug("QF Size = {QF}", "QF", fwInfo.QF);
112f6470b5eSDaniel Hsu         }
113f6470b5eSDaniel Hsu         else if (line.rfind(tagCFStart, 0) == 0)
114f6470b5eSDaniel Hsu         {
115f6470b5eSDaniel Hsu             cfStart = true;
116f6470b5eSDaniel Hsu         }
117f6470b5eSDaniel Hsu         else if (enableUpdateEbrInit && line.rfind(tagEbrInitData, 0) == 0)
118f6470b5eSDaniel Hsu         {
119f6470b5eSDaniel Hsu             ebrInitDataStart = true;
120f6470b5eSDaniel Hsu         }
121f6470b5eSDaniel Hsu         else if (ufmPrepare)
122f6470b5eSDaniel Hsu         {
123f6470b5eSDaniel Hsu             ufmPrepare = false;
124f6470b5eSDaniel Hsu             ufmStart = true;
125f6470b5eSDaniel Hsu             continue;
126f6470b5eSDaniel Hsu         }
127f6470b5eSDaniel Hsu         else if (line.rfind(tagUserCode, 0) == 0)
128f6470b5eSDaniel Hsu         {
129f6470b5eSDaniel Hsu             versionStart = true;
130f6470b5eSDaniel Hsu         }
131f6470b5eSDaniel Hsu         else if (line.rfind(tagChecksum, 0) == 0)
132f6470b5eSDaniel Hsu         {
133f6470b5eSDaniel Hsu             checksumStart = true;
134f6470b5eSDaniel Hsu         }
135f6470b5eSDaniel Hsu 
136f6470b5eSDaniel Hsu         if (line.rfind("NOTE DEVICE NAME:", 0) == 0)
137f6470b5eSDaniel Hsu         {
138f6470b5eSDaniel Hsu             lg2::error(line.c_str());
139f6470b5eSDaniel Hsu             if (line.find(chip) != std::string::npos)
140f6470b5eSDaniel Hsu             {
141f6470b5eSDaniel Hsu                 lg2::debug("[OK] The image device name match with chip name");
142f6470b5eSDaniel Hsu             }
143f6470b5eSDaniel Hsu             else
144f6470b5eSDaniel Hsu             {
145*61e12672SDaniel Hsu                 lg2::debug("Abort update as image doesn't match the chip name");
146f6470b5eSDaniel Hsu                 return false;
147f6470b5eSDaniel Hsu             }
148f6470b5eSDaniel Hsu         }
149f6470b5eSDaniel Hsu 
150f6470b5eSDaniel Hsu         if (cfStart)
151f6470b5eSDaniel Hsu         {
152f6470b5eSDaniel Hsu             // L000
153f6470b5eSDaniel Hsu             if ((line.rfind(tagCFStart, 0)) && (line.size() != 1))
154f6470b5eSDaniel Hsu             {
155f6470b5eSDaniel Hsu                 if ((line.rfind('0', 0) == 0) || (line.rfind('1', 0) == 0))
156f6470b5eSDaniel Hsu                 {
157f6470b5eSDaniel Hsu                     while (!line.empty())
158f6470b5eSDaniel Hsu                     {
159f6470b5eSDaniel Hsu                         auto binaryStr = line.substr(0, 8);
160f6470b5eSDaniel Hsu                         try
161f6470b5eSDaniel Hsu                         {
162f6470b5eSDaniel Hsu                             fwInfo.cfgData.push_back(
163f6470b5eSDaniel Hsu                                 std::stoi(binaryStr, 0, 2));
164f6470b5eSDaniel Hsu                             line.erase(0, 8);
165f6470b5eSDaniel Hsu                         }
166f6470b5eSDaniel Hsu                         catch (const std::invalid_argument& error)
167f6470b5eSDaniel Hsu                         {
168f6470b5eSDaniel Hsu                             break;
169f6470b5eSDaniel Hsu                         }
170f6470b5eSDaniel Hsu                         catch (...)
171f6470b5eSDaniel Hsu                         {
172f6470b5eSDaniel Hsu                             lg2::error("Error while parsing CF section");
173f6470b5eSDaniel Hsu                             return false;
174f6470b5eSDaniel Hsu                         }
175f6470b5eSDaniel Hsu                     }
176f6470b5eSDaniel Hsu                 }
177f6470b5eSDaniel Hsu                 else
178f6470b5eSDaniel Hsu                 {
179f6470b5eSDaniel Hsu                     lg2::debug("CF size = {CF}", "CF", fwInfo.cfgData.size());
180f6470b5eSDaniel Hsu                     cfStart = false;
181f6470b5eSDaniel Hsu                     if (!ebrInitDataStart)
182f6470b5eSDaniel Hsu                     {
183f6470b5eSDaniel Hsu                         ufmPrepare = true;
184f6470b5eSDaniel Hsu                     }
185f6470b5eSDaniel Hsu                 }
186f6470b5eSDaniel Hsu             }
187f6470b5eSDaniel Hsu         }
188f6470b5eSDaniel Hsu         else if (enableUpdateEbrInit && ebrInitDataStart)
189f6470b5eSDaniel Hsu         {
190f6470b5eSDaniel Hsu             // NOTE EBR_INIT DATA
191f6470b5eSDaniel Hsu             if ((line.rfind(tagEbrInitData, 0)) && (line.size() != 1))
192f6470b5eSDaniel Hsu             {
193f6470b5eSDaniel Hsu                 if ((line.rfind('L', 0)) && (line.size() != 1))
194f6470b5eSDaniel Hsu                 {
195f6470b5eSDaniel Hsu                     if ((line.rfind('0', 0) == 0) || (line.rfind('1', 0) == 0))
196f6470b5eSDaniel Hsu                     {
197f6470b5eSDaniel Hsu                         while (!line.empty())
198f6470b5eSDaniel Hsu                         {
199f6470b5eSDaniel Hsu                             auto binaryStr = line.substr(0, 8);
200f6470b5eSDaniel Hsu                             try
201f6470b5eSDaniel Hsu                             {
202f6470b5eSDaniel Hsu                                 fwInfo.cfgData.push_back(
203f6470b5eSDaniel Hsu                                     std::stoi(binaryStr, 0, 2));
204f6470b5eSDaniel Hsu                                 line.erase(0, 8);
205f6470b5eSDaniel Hsu                             }
206f6470b5eSDaniel Hsu                             catch (const std::invalid_argument& error)
207f6470b5eSDaniel Hsu                             {
208f6470b5eSDaniel Hsu                                 break;
209f6470b5eSDaniel Hsu                             }
210f6470b5eSDaniel Hsu                             catch (...)
211f6470b5eSDaniel Hsu                             {
212f6470b5eSDaniel Hsu                                 lg2::error("Error while parsing CF section");
213f6470b5eSDaniel Hsu                                 return false;
214f6470b5eSDaniel Hsu                             }
215f6470b5eSDaniel Hsu                         }
216f6470b5eSDaniel Hsu                     }
217f6470b5eSDaniel Hsu                     else
218f6470b5eSDaniel Hsu                     {
219f6470b5eSDaniel Hsu                         lg2::debug("CF size with EBR_INIT Data = {CF}", "CF",
220f6470b5eSDaniel Hsu                                    fwInfo.cfgData.size());
221f6470b5eSDaniel Hsu                         ebrInitDataStart = false;
222f6470b5eSDaniel Hsu                         ufmPrepare = true;
223f6470b5eSDaniel Hsu                     }
224f6470b5eSDaniel Hsu                 }
225f6470b5eSDaniel Hsu             }
226f6470b5eSDaniel Hsu         }
227f6470b5eSDaniel Hsu         else if ((checksumStart) && (line.size() != 1))
228f6470b5eSDaniel Hsu         {
229f6470b5eSDaniel Hsu             checksumStart = false;
230f6470b5eSDaniel Hsu             numberSize = findNumberSize("*", "C", line);
231f6470b5eSDaniel Hsu             if (numberSize <= 0)
232f6470b5eSDaniel Hsu             {
233f6470b5eSDaniel Hsu                 lg2::error("Error in parsing checksum");
234f6470b5eSDaniel Hsu                 return false;
235f6470b5eSDaniel Hsu             }
236f6470b5eSDaniel Hsu             static constexpr auto start = tagChecksum.length();
237f6470b5eSDaniel Hsu             std::istringstream iss(line.substr(start, numberSize));
238f6470b5eSDaniel Hsu             iss >> std::hex >> fwInfo.checksum;
239f6470b5eSDaniel Hsu 
240f6470b5eSDaniel Hsu             lg2::debug("Checksum = {CHECKSUM}", "CHECKSUM", fwInfo.checksum);
241f6470b5eSDaniel Hsu         }
242f6470b5eSDaniel Hsu         else if (versionStart)
243f6470b5eSDaniel Hsu         {
244f6470b5eSDaniel Hsu             if ((line.rfind(tagUserCode, 0)) && (line.size() != 1))
245f6470b5eSDaniel Hsu             {
246f6470b5eSDaniel Hsu                 versionStart = false;
247f6470b5eSDaniel Hsu 
248f6470b5eSDaniel Hsu                 if (line.rfind(tagUH, 0) == 0)
249f6470b5eSDaniel Hsu                 {
250f6470b5eSDaniel Hsu                     numberSize = findNumberSize("*", "H", line);
251f6470b5eSDaniel Hsu                     if (numberSize <= 0)
252f6470b5eSDaniel Hsu                     {
253f6470b5eSDaniel Hsu                         lg2::error("Error in parsing version");
254f6470b5eSDaniel Hsu                         return false;
255f6470b5eSDaniel Hsu                     }
256f6470b5eSDaniel Hsu                     static constexpr auto start = tagUH.length();
257f6470b5eSDaniel Hsu                     std::istringstream iss(line.substr(start, numberSize));
258f6470b5eSDaniel Hsu                     iss >> std::hex >> fwInfo.version;
259f6470b5eSDaniel Hsu 
260f6470b5eSDaniel Hsu                     lg2::debug("UserCode = {USERCODE}", "USERCODE",
261f6470b5eSDaniel Hsu                                fwInfo.version);
262f6470b5eSDaniel Hsu                 }
263f6470b5eSDaniel Hsu             }
264f6470b5eSDaniel Hsu         }
265f6470b5eSDaniel Hsu         else if (ufmStart)
266f6470b5eSDaniel Hsu         {
267f6470b5eSDaniel Hsu             if ((line.rfind('L', 0)) && (line.size() != 1))
268f6470b5eSDaniel Hsu             {
269f6470b5eSDaniel Hsu                 if ((line.rfind('0', 0) == 0) || (line.rfind('1', 0) == 0))
270f6470b5eSDaniel Hsu                 {
271f6470b5eSDaniel Hsu                     while (!line.empty())
272f6470b5eSDaniel Hsu                     {
273f6470b5eSDaniel Hsu                         auto binaryStr = line.substr(0, 8);
274f6470b5eSDaniel Hsu                         try
275f6470b5eSDaniel Hsu                         {
276f6470b5eSDaniel Hsu                             fwInfo.ufmData.push_back(
277f6470b5eSDaniel Hsu                                 std::stoi(binaryStr, 0, 2));
278f6470b5eSDaniel Hsu                             line.erase(0, 8);
279f6470b5eSDaniel Hsu                         }
280f6470b5eSDaniel Hsu                         catch (const std::invalid_argument& error)
281f6470b5eSDaniel Hsu                         {
282f6470b5eSDaniel Hsu                             break;
283f6470b5eSDaniel Hsu                         }
284f6470b5eSDaniel Hsu                         catch (...)
285f6470b5eSDaniel Hsu                         {
286f6470b5eSDaniel Hsu                             lg2::error("Error while parsing UFM section");
287f6470b5eSDaniel Hsu                             return false;
288f6470b5eSDaniel Hsu                         }
289f6470b5eSDaniel Hsu                     }
290f6470b5eSDaniel Hsu                 }
291f6470b5eSDaniel Hsu                 else
292f6470b5eSDaniel Hsu                 {
293f6470b5eSDaniel Hsu                     lg2::debug("UFM size = {UFM}", "UFM",
294f6470b5eSDaniel Hsu                                fwInfo.ufmData.size());
295f6470b5eSDaniel Hsu                     ufmStart = false;
296f6470b5eSDaniel Hsu                 }
297f6470b5eSDaniel Hsu             }
298f6470b5eSDaniel Hsu         }
299f6470b5eSDaniel Hsu     }
300f6470b5eSDaniel Hsu 
301f6470b5eSDaniel Hsu     return true;
302f6470b5eSDaniel Hsu }
303f6470b5eSDaniel Hsu 
304f6470b5eSDaniel Hsu bool CpldLatticeManager::verifyChecksum()
305f6470b5eSDaniel Hsu {
verifyChecksum()306f6470b5eSDaniel Hsu     // Compute check sum
307f6470b5eSDaniel Hsu     unsigned int jedFileCheckSum = 0;
308f6470b5eSDaniel Hsu     for (unsigned i = 0; i < fwInfo.cfgData.size(); i++)
309f6470b5eSDaniel Hsu     {
310f6470b5eSDaniel Hsu         jedFileCheckSum += reverse_bit(fwInfo.cfgData.at(i));
311f6470b5eSDaniel Hsu     }
312f6470b5eSDaniel Hsu     for (unsigned i = 0; i < fwInfo.ufmData.size(); i++)
313f6470b5eSDaniel Hsu     {
314f6470b5eSDaniel Hsu         jedFileCheckSum += reverse_bit(fwInfo.ufmData.at(i));
315f6470b5eSDaniel Hsu     }
316f6470b5eSDaniel Hsu     lg2::debug("jedFileCheckSum = {JEDFILECHECKSUM}", "JEDFILECHECKSUM",
317f6470b5eSDaniel Hsu                jedFileCheckSum);
318f6470b5eSDaniel Hsu     jedFileCheckSum = jedFileCheckSum & 0xffff;
319f6470b5eSDaniel Hsu 
320f6470b5eSDaniel Hsu     if ((fwInfo.checksum != jedFileCheckSum) || (fwInfo.checksum == 0))
321f6470b5eSDaniel Hsu     {
322f6470b5eSDaniel Hsu         lg2::error("CPLD JED File CheckSum Error = {JEDFILECHECKSUM}",
323f6470b5eSDaniel Hsu                    "JEDFILECHECKSUM", jedFileCheckSum);
324f6470b5eSDaniel Hsu         return false;
325f6470b5eSDaniel Hsu     }
326f6470b5eSDaniel Hsu 
327f6470b5eSDaniel Hsu     lg2::debug("JED File Checksum compare success");
328f6470b5eSDaniel Hsu     return true;
329f6470b5eSDaniel Hsu }
330f6470b5eSDaniel Hsu 
331f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::readDeviceId()
332f6470b5eSDaniel Hsu {
readDeviceId()33337a30143SDaniel Hsu     std::vector<uint8_t> request = {commandReadDeviceId, 0x0, 0x0, 0x0};
334f6470b5eSDaniel Hsu     constexpr size_t resSize = 4;
335f6470b5eSDaniel Hsu     std::vector<uint8_t> readData(resSize, 0);
33637a30143SDaniel Hsu     bool success = co_await i2cInterface.sendReceive(
33737a30143SDaniel Hsu         request.data(), request.size(), readData.data(), resSize);
33837a30143SDaniel Hsu 
339f6470b5eSDaniel Hsu     if (!success)
340f6470b5eSDaniel Hsu     {
341f6470b5eSDaniel Hsu         lg2::error(
342f6470b5eSDaniel Hsu             "Fail to read device Id. Please check the I2C bus and address.");
343f6470b5eSDaniel Hsu         co_return false;
344f6470b5eSDaniel Hsu     }
345f6470b5eSDaniel Hsu 
346*61e12672SDaniel Hsu     auto chipWantToUpdate =
347*61e12672SDaniel Hsu         std::find_if(supportedDeviceMap.begin(), supportedDeviceMap.end(),
348*61e12672SDaniel Hsu                      [this](const auto& pair) {
349*61e12672SDaniel Hsu                          return pair.second.chipName == this->chip;
350*61e12672SDaniel Hsu                      });
351f6470b5eSDaniel Hsu 
352*61e12672SDaniel Hsu     if (chipWantToUpdate != supportedDeviceMap.end() &&
353*61e12672SDaniel Hsu         chipWantToUpdate->second.deviceId == readData)
354f6470b5eSDaniel Hsu     {
355f6470b5eSDaniel Hsu         if (chip.rfind("LCMXO3D", 0) == 0)
356f6470b5eSDaniel Hsu         {
357f6470b5eSDaniel Hsu             isLCMXO3D = true;
358f6470b5eSDaniel Hsu             if (!target.empty() && target != "CFG0" && target != "CFG1")
359f6470b5eSDaniel Hsu             {
360f6470b5eSDaniel Hsu                 lg2::error("Unknown target. Only CFG0 and CFG1 are supported.");
361f6470b5eSDaniel Hsu                 co_return false;
362f6470b5eSDaniel Hsu             }
363f6470b5eSDaniel Hsu         }
364f6470b5eSDaniel Hsu 
365f6470b5eSDaniel Hsu         lg2::debug("Device ID match with chip. Chip name: {CHIPNAME}",
366f6470b5eSDaniel Hsu                    "CHIPNAME", chip);
367f6470b5eSDaniel Hsu         co_return true;
368f6470b5eSDaniel Hsu     }
369f6470b5eSDaniel Hsu 
370*61e12672SDaniel Hsu     lg2::error("The device id doesn't match with chip.");
371f6470b5eSDaniel Hsu     co_return false;
372f6470b5eSDaniel Hsu }
373f6470b5eSDaniel Hsu 
374f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::enableProgramMode()
375f6470b5eSDaniel Hsu {
37637a30143SDaniel Hsu     std::vector<uint8_t> request = {commandEnableConfigMode, 0x08, 0x0, 0x0};
37737a30143SDaniel Hsu     std::vector<uint8_t> response;
enableProgramMode()378f6470b5eSDaniel Hsu 
37937a30143SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
380f6470b5eSDaniel Hsu     {
38137a30143SDaniel Hsu         lg2::error("Failed to send enable program mode request.");
382f6470b5eSDaniel Hsu         co_return false;
383f6470b5eSDaniel Hsu     }
384f6470b5eSDaniel Hsu 
385f6470b5eSDaniel Hsu     if (!(co_await waitBusyAndVerify()))
386f6470b5eSDaniel Hsu     {
387f6470b5eSDaniel Hsu         lg2::error("Wait busy and verify fail");
388f6470b5eSDaniel Hsu         co_return false;
389f6470b5eSDaniel Hsu     }
390f6470b5eSDaniel Hsu     co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
391f6470b5eSDaniel Hsu     co_return true;
392f6470b5eSDaniel Hsu }
393f6470b5eSDaniel Hsu 
394f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::eraseFlash()
395f6470b5eSDaniel Hsu {
39637a30143SDaniel Hsu     std::vector<uint8_t> request;
39737a30143SDaniel Hsu     std::vector<uint8_t> response;
398f6470b5eSDaniel Hsu 
399f6470b5eSDaniel Hsu     if (isLCMXO3D)
eraseFlash()400f6470b5eSDaniel Hsu     {
401f6470b5eSDaniel Hsu         /*
402f6470b5eSDaniel Hsu         Erase the different internal
403f6470b5eSDaniel Hsu         memories. The bit in YYY defines
404f6470b5eSDaniel Hsu         which memory is erased in Flash
405f6470b5eSDaniel Hsu         access mode.
406f6470b5eSDaniel Hsu         Bit 1=Enable
407f6470b5eSDaniel Hsu         8 Erase CFG0
408f6470b5eSDaniel Hsu         9 Erase CFG1
409f6470b5eSDaniel Hsu         10 Erase UFM0
410f6470b5eSDaniel Hsu         11 Erase UFM1
411f6470b5eSDaniel Hsu         12 Erase UFM2
412f6470b5eSDaniel Hsu         13 Erase UFM3
413f6470b5eSDaniel Hsu         14 Erase CSEC
414f6470b5eSDaniel Hsu         15 Erase USEC
415f6470b5eSDaniel Hsu         16 Erase PUBKEY
416f6470b5eSDaniel Hsu         17 Erase AESKEY
417f6470b5eSDaniel Hsu         18 Erase FEA
418f6470b5eSDaniel Hsu         19 Reserved
419f6470b5eSDaniel Hsu         commandEraseFlash = 0x0E, 0Y YY 00
420f6470b5eSDaniel Hsu         */
421f6470b5eSDaniel Hsu         if (target.empty() || target == "CFG0")
422f6470b5eSDaniel Hsu         {
42337a30143SDaniel Hsu             request = {commandEraseFlash, 0x00, 0x01, 0x00};
424f6470b5eSDaniel Hsu         }
425f6470b5eSDaniel Hsu         else if (target == "CFG1")
426f6470b5eSDaniel Hsu         {
42737a30143SDaniel Hsu             request = {commandEraseFlash, 0x00, 0x02, 0x00};
428f6470b5eSDaniel Hsu         }
429f6470b5eSDaniel Hsu         else
430f6470b5eSDaniel Hsu         {
431f6470b5eSDaniel Hsu             lg2::error("Error: unknown target.");
432f6470b5eSDaniel Hsu             co_return false;
433f6470b5eSDaniel Hsu         }
434f6470b5eSDaniel Hsu     }
435f6470b5eSDaniel Hsu     else
436f6470b5eSDaniel Hsu     {
43737a30143SDaniel Hsu         request = {commandEraseFlash, 0xC, 0x0, 0x0};
438f6470b5eSDaniel Hsu     }
439f6470b5eSDaniel Hsu 
44037a30143SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
441f6470b5eSDaniel Hsu     {
44237a30143SDaniel Hsu         lg2::error("Failed to send erase flash request.");
443f6470b5eSDaniel Hsu         co_return false;
444f6470b5eSDaniel Hsu     }
445f6470b5eSDaniel Hsu 
446f6470b5eSDaniel Hsu     if (!(co_await waitBusyAndVerify()))
447f6470b5eSDaniel Hsu     {
448f6470b5eSDaniel Hsu         lg2::error("Wait busy and verify fail");
449f6470b5eSDaniel Hsu         co_return false;
450f6470b5eSDaniel Hsu     }
451f6470b5eSDaniel Hsu     co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
452f6470b5eSDaniel Hsu     co_return true;
453f6470b5eSDaniel Hsu }
454f6470b5eSDaniel Hsu 
455f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::resetConfigFlash()
456f6470b5eSDaniel Hsu {
45737a30143SDaniel Hsu     std::vector<uint8_t> request;
45837a30143SDaniel Hsu     std::vector<uint8_t> response;
459f6470b5eSDaniel Hsu     if (isLCMXO3D)
460f6470b5eSDaniel Hsu     {
461f6470b5eSDaniel Hsu         /*
462f6470b5eSDaniel Hsu         Set Page Address pointer to the
resetConfigFlash()463f6470b5eSDaniel Hsu         beginning of the different internal
464f6470b5eSDaniel Hsu         Flash sectors. The bit in YYYY
465f6470b5eSDaniel Hsu         defines which sector is selected.
466f6470b5eSDaniel Hsu         Bit Flash sector selected
467f6470b5eSDaniel Hsu         8 CFG0
468f6470b5eSDaniel Hsu         9 CFG1
469f6470b5eSDaniel Hsu         10 FEA
470f6470b5eSDaniel Hsu         11 PUBKEY
471f6470b5eSDaniel Hsu         12 AESKEY
472f6470b5eSDaniel Hsu         13 CSEC
473f6470b5eSDaniel Hsu         14 UFM0
474f6470b5eSDaniel Hsu         15 UFM1
475f6470b5eSDaniel Hsu         16 UFM2
476f6470b5eSDaniel Hsu         17 UFM3
477f6470b5eSDaniel Hsu         18 USEC
478f6470b5eSDaniel Hsu         19 Reserved
479f6470b5eSDaniel Hsu         20 Reserved
480f6470b5eSDaniel Hsu         21 Reserved
481f6470b5eSDaniel Hsu         22 Reserved
482f6470b5eSDaniel Hsu         commandResetConfigFlash = 0x46, YY YY 00
483f6470b5eSDaniel Hsu         */
484f6470b5eSDaniel Hsu         if (target.empty() || target == "CFG0")
485f6470b5eSDaniel Hsu         {
48637a30143SDaniel Hsu             request = {commandResetConfigFlash, 0x00, 0x01, 0x00};
487f6470b5eSDaniel Hsu         }
488f6470b5eSDaniel Hsu         else if (target == "CFG1")
489f6470b5eSDaniel Hsu         {
49037a30143SDaniel Hsu             request = {commandResetConfigFlash, 0x00, 0x02, 0x00};
491f6470b5eSDaniel Hsu         }
492f6470b5eSDaniel Hsu         else
493f6470b5eSDaniel Hsu         {
494f6470b5eSDaniel Hsu             lg2::error(
495f6470b5eSDaniel Hsu                 "Error: unknown target. Only CFG0 and CFG1 are supported.");
496f6470b5eSDaniel Hsu             co_return false;
497f6470b5eSDaniel Hsu         }
498f6470b5eSDaniel Hsu     }
499f6470b5eSDaniel Hsu     else
500f6470b5eSDaniel Hsu     {
50137a30143SDaniel Hsu         request = {commandResetConfigFlash, 0x0, 0x0, 0x0};
502f6470b5eSDaniel Hsu     }
503f6470b5eSDaniel Hsu 
50437a30143SDaniel Hsu     co_return i2cInterface.sendReceive(request, response);
505f6470b5eSDaniel Hsu }
506f6470b5eSDaniel Hsu 
507f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::writeProgramPage()
508f6470b5eSDaniel Hsu {
509f6470b5eSDaniel Hsu     /*
510f6470b5eSDaniel Hsu     Program one NVCM/Flash page. Can be
511f6470b5eSDaniel Hsu     used to program the NVCM0/CFG or
512f6470b5eSDaniel Hsu     NVCM1/UFM.
513f6470b5eSDaniel Hsu     */
51437a30143SDaniel Hsu     std::vector<uint8_t> request = {commandProgramPage, 0x0, 0x0, 0x01};
51537a30143SDaniel Hsu     std::vector<uint8_t> response;
516f6470b5eSDaniel Hsu     size_t iterSize = 16;
writeProgramPage()517f6470b5eSDaniel Hsu 
518f6470b5eSDaniel Hsu     for (size_t i = 0; i < fwInfo.cfgData.size(); i += iterSize)
519f6470b5eSDaniel Hsu     {
520f6470b5eSDaniel Hsu         double progressRate =
521f6470b5eSDaniel Hsu             ((double(i) / double(fwInfo.cfgData.size())) * 100);
522f6470b5eSDaniel Hsu         std::cout << "Update :" << std::fixed << std::dec
523f6470b5eSDaniel Hsu                   << std::setprecision(2) << progressRate << "% \r";
524f6470b5eSDaniel Hsu 
525f6470b5eSDaniel Hsu         uint8_t len = ((i + iterSize) < fwInfo.cfgData.size())
526f6470b5eSDaniel Hsu                           ? iterSize
527f6470b5eSDaniel Hsu                           : (fwInfo.cfgData.size() - i);
52837a30143SDaniel Hsu         std::vector<uint8_t> data = request;
529f6470b5eSDaniel Hsu 
530f6470b5eSDaniel Hsu         data.insert(
531f6470b5eSDaniel Hsu             data.end(), fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i),
532f6470b5eSDaniel Hsu             fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(i + len));
533f6470b5eSDaniel Hsu 
53437a30143SDaniel Hsu         if (!i2cInterface.sendReceive(data, response))
535f6470b5eSDaniel Hsu         {
53637a30143SDaniel Hsu             lg2::error("Failed to send program page request. {CURRENT}",
53737a30143SDaniel Hsu                        "CURRENT", uint32ToHexStr(i));
538f6470b5eSDaniel Hsu             co_return false;
539f6470b5eSDaniel Hsu         }
540f6470b5eSDaniel Hsu 
541f6470b5eSDaniel Hsu         /*
542f6470b5eSDaniel Hsu          Reference spec
543f6470b5eSDaniel Hsu          Important! If don't sleep, it will take a long time to update.
544f6470b5eSDaniel Hsu         */
545f6470b5eSDaniel Hsu         co_await sdbusplus::async::sleep_for(ctx,
546f6470b5eSDaniel Hsu                                              std::chrono::microseconds(200));
547f6470b5eSDaniel Hsu 
548f6470b5eSDaniel Hsu         if (!(co_await waitBusyAndVerify()))
549f6470b5eSDaniel Hsu         {
550f6470b5eSDaniel Hsu             lg2::error("Wait busy and verify fail");
551f6470b5eSDaniel Hsu             co_return false;
552f6470b5eSDaniel Hsu         }
553f6470b5eSDaniel Hsu 
554f6470b5eSDaniel Hsu         data.clear();
555f6470b5eSDaniel Hsu     }
556f6470b5eSDaniel Hsu 
557f6470b5eSDaniel Hsu     co_return true;
558f6470b5eSDaniel Hsu }
559f6470b5eSDaniel Hsu 
560f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::programUserCode()
561f6470b5eSDaniel Hsu {
56237a30143SDaniel Hsu     std::vector<uint8_t> request = {commandProgramUserCode, 0x0, 0x0, 0x0};
56337a30143SDaniel Hsu     std::vector<uint8_t> response;
564f6470b5eSDaniel Hsu     for (int i = 3; i >= 0; i--)
565f6470b5eSDaniel Hsu     {
56637a30143SDaniel Hsu         request.push_back((fwInfo.version >> (i * 8)) & 0xFF);
567f6470b5eSDaniel Hsu     }
568f6470b5eSDaniel Hsu 
56937a30143SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
570f6470b5eSDaniel Hsu     {
programUserCode()57137a30143SDaniel Hsu         lg2::error("Failed to send program user code request.");
572f6470b5eSDaniel Hsu         co_return false;
573f6470b5eSDaniel Hsu     }
574f6470b5eSDaniel Hsu     if (!(co_await waitBusyAndVerify()))
575f6470b5eSDaniel Hsu     {
576f6470b5eSDaniel Hsu         lg2::error("Wait busy and verify fail");
577f6470b5eSDaniel Hsu         co_return false;
578f6470b5eSDaniel Hsu     }
579f6470b5eSDaniel Hsu 
580f6470b5eSDaniel Hsu     co_return true;
581f6470b5eSDaniel Hsu }
582f6470b5eSDaniel Hsu 
583f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::programDone()
584f6470b5eSDaniel Hsu {
58537a30143SDaniel Hsu     std::vector<uint8_t> request = {commandProgramDone, 0x0, 0x0, 0x0};
58637a30143SDaniel Hsu     std::vector<uint8_t> response;
587f6470b5eSDaniel Hsu 
58837a30143SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
589f6470b5eSDaniel Hsu     {
59037a30143SDaniel Hsu         lg2::error("Failed to send program done request.");
591f6470b5eSDaniel Hsu         co_return false;
592f6470b5eSDaniel Hsu     }
59337a30143SDaniel Hsu 
594f6470b5eSDaniel Hsu     if (!(co_await waitBusyAndVerify()))
595f6470b5eSDaniel Hsu     {
596f6470b5eSDaniel Hsu         lg2::error("Wait busy and verify fail");
programDone()597f6470b5eSDaniel Hsu         co_return false;
598f6470b5eSDaniel Hsu     }
599f6470b5eSDaniel Hsu 
600f6470b5eSDaniel Hsu     co_return true;
601f6470b5eSDaniel Hsu }
602f6470b5eSDaniel Hsu 
603f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::disableConfigInterface()
604f6470b5eSDaniel Hsu {
60537a30143SDaniel Hsu     std::vector<uint8_t> request = {commandDisableConfigInterface, 0x0, 0x0};
60637a30143SDaniel Hsu     std::vector<uint8_t> response;
60737a30143SDaniel Hsu     co_return i2cInterface.sendReceive(request, response);
608f6470b5eSDaniel Hsu }
609f6470b5eSDaniel Hsu 
610f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::waitBusyAndVerify()
611f6470b5eSDaniel Hsu {
612f6470b5eSDaniel Hsu     uint8_t retry = 0;
613f6470b5eSDaniel Hsu 
614f6470b5eSDaniel Hsu     while (retry <= busyWaitmaxRetry)
615f6470b5eSDaniel Hsu     {
616f6470b5eSDaniel Hsu         uint8_t busyFlag = 0xff;
617f6470b5eSDaniel Hsu 
disableConfigInterface()61837a30143SDaniel Hsu         auto readBusyFlagResult = co_await readBusyFlag(busyFlag);
61937a30143SDaniel Hsu         if (!readBusyFlagResult)
620f6470b5eSDaniel Hsu         {
621f6470b5eSDaniel Hsu             lg2::error("Fail to read busy flag.");
622f6470b5eSDaniel Hsu             co_return false;
623f6470b5eSDaniel Hsu         }
624f6470b5eSDaniel Hsu 
625f6470b5eSDaniel Hsu         if (busyFlag & busyFlagBit)
626f6470b5eSDaniel Hsu         {
627f6470b5eSDaniel Hsu             co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
628f6470b5eSDaniel Hsu             retry++;
629f6470b5eSDaniel Hsu             if (retry > busyWaitmaxRetry)
waitBusyAndVerify()630f6470b5eSDaniel Hsu             {
631f6470b5eSDaniel Hsu                 lg2::error(
632f6470b5eSDaniel Hsu                     "Status Reg : Busy! Please check the I2C bus and address.");
633f6470b5eSDaniel Hsu                 co_return false;
634f6470b5eSDaniel Hsu             }
635f6470b5eSDaniel Hsu         }
636f6470b5eSDaniel Hsu         else
637f6470b5eSDaniel Hsu         {
638f6470b5eSDaniel Hsu             break;
639f6470b5eSDaniel Hsu         }
640f6470b5eSDaniel Hsu     } // while loop busy check
641f6470b5eSDaniel Hsu 
642f6470b5eSDaniel Hsu     // Check out status reg
64337a30143SDaniel Hsu     auto statusReg = std::make_unique<uint8_t>(0xff);
644f6470b5eSDaniel Hsu 
64537a30143SDaniel Hsu     if (!(co_await readStatusReg(*statusReg)))
646f6470b5eSDaniel Hsu     {
647f6470b5eSDaniel Hsu         lg2::error("Fail to read status register.");
648f6470b5eSDaniel Hsu         co_return false;
649f6470b5eSDaniel Hsu     }
650f6470b5eSDaniel Hsu 
65137a30143SDaniel Hsu     if (((*statusReg >> busyOrReadyBit) & 1) == isReady &&
65237a30143SDaniel Hsu         ((*statusReg >> failOrOKBit) & 1) == isOK)
653f6470b5eSDaniel Hsu     {
654f6470b5eSDaniel Hsu         lg2::debug("Status Reg : OK");
655f6470b5eSDaniel Hsu         co_return true;
656f6470b5eSDaniel Hsu     }
657f6470b5eSDaniel Hsu 
658f6470b5eSDaniel Hsu     lg2::error("Status Reg : Fail! Please check the I2C bus and address.");
659f6470b5eSDaniel Hsu     co_return false;
660f6470b5eSDaniel Hsu }
661f6470b5eSDaniel Hsu 
662f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::readBusyFlag(uint8_t& busyFlag)
663f6470b5eSDaniel Hsu {
664f6470b5eSDaniel Hsu     constexpr size_t resSize = 1;
66537a30143SDaniel Hsu     std::vector<uint8_t> request = {commandReadBusyFlag, 0x0, 0x0, 0x0};
66637a30143SDaniel Hsu     std::vector<uint8_t> response(resSize, 0);
667f6470b5eSDaniel Hsu 
66837a30143SDaniel Hsu     auto success = i2cInterface.sendReceive(request, response);
66937a30143SDaniel Hsu     if (!success && response.size() != resSize)
670f6470b5eSDaniel Hsu     {
671f6470b5eSDaniel Hsu         co_return false;
672f6470b5eSDaniel Hsu     }
67337a30143SDaniel Hsu     busyFlag = response.at(0);
674f6470b5eSDaniel Hsu     co_return true;
675f6470b5eSDaniel Hsu }
676f6470b5eSDaniel Hsu 
677f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::readStatusReg(
678f6470b5eSDaniel Hsu     uint8_t& statusReg)
679f6470b5eSDaniel Hsu {
68037a30143SDaniel Hsu     std::vector<uint8_t> request = {commandReadStatusReg, 0x0, 0x0, 0x0};
readBusyFlag(uint8_t & busyFlag)68137a30143SDaniel Hsu     std::vector<uint8_t> response(4, 0);
682f6470b5eSDaniel Hsu 
68337a30143SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
684f6470b5eSDaniel Hsu     {
68537a30143SDaniel Hsu         lg2::error("Failed to send read status register request.");
686f6470b5eSDaniel Hsu         co_return false;
687f6470b5eSDaniel Hsu     }
688f6470b5eSDaniel Hsu     /*
689f6470b5eSDaniel Hsu     Read Status Register
690f6470b5eSDaniel Hsu     [LSC_READ_STATUS]
691f6470b5eSDaniel Hsu     0x3C 00 00 00 N/A YY YY YY YY Bit 1 0
692f6470b5eSDaniel Hsu     12 Busy Ready
693f6470b5eSDaniel Hsu     13 Fail OK
694f6470b5eSDaniel Hsu     */
69537a30143SDaniel Hsu     statusReg = response.at(2);
696f6470b5eSDaniel Hsu     co_return true;
697f6470b5eSDaniel Hsu }
698f6470b5eSDaniel Hsu 
readStatusReg(uint8_t & statusReg)699f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::readUserCode(
700f6470b5eSDaniel Hsu     uint32_t& userCode)
701f6470b5eSDaniel Hsu {
702f6470b5eSDaniel Hsu     constexpr size_t resSize = 4;
70337a30143SDaniel Hsu     std::vector<uint8_t> request = {commandReadFwVersion, 0x0, 0x0, 0x0};
70437a30143SDaniel Hsu     std::vector<uint8_t> response(resSize, 0);
705f6470b5eSDaniel Hsu 
70637a30143SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
707f6470b5eSDaniel Hsu     {
70837a30143SDaniel Hsu         lg2::error("Failed to send read user code request.");
709f6470b5eSDaniel Hsu         co_return false;
710f6470b5eSDaniel Hsu     }
711f6470b5eSDaniel Hsu 
712f6470b5eSDaniel Hsu     for (size_t i = 0; i < resSize; i++)
713f6470b5eSDaniel Hsu     {
71437a30143SDaniel Hsu         userCode |= response.at(i) << ((3 - i) * 8);
715f6470b5eSDaniel Hsu     }
716f6470b5eSDaniel Hsu     co_return true;
717f6470b5eSDaniel Hsu }
718f6470b5eSDaniel Hsu 
719f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::XO2XO3FamilyUpdate(
720f6470b5eSDaniel Hsu     std::function<bool(int)> progressCallBack)
721f6470b5eSDaniel Hsu {
722f6470b5eSDaniel Hsu     if (progressCallBack == nullptr)
723f6470b5eSDaniel Hsu     {
724f6470b5eSDaniel Hsu         lg2::error("Error: progressCallBack is null.");
readUserCode(uint32_t & userCode)725f6470b5eSDaniel Hsu         co_return false;
726f6470b5eSDaniel Hsu     }
727f6470b5eSDaniel Hsu 
728f6470b5eSDaniel Hsu     if (!(co_await readDeviceId()))
729f6470b5eSDaniel Hsu     {
730f6470b5eSDaniel Hsu         co_return false;
731f6470b5eSDaniel Hsu     }
732f6470b5eSDaniel Hsu     progressCallBack(10);
733f6470b5eSDaniel Hsu 
734f6470b5eSDaniel Hsu     if (!jedFileParser())
735f6470b5eSDaniel Hsu     {
736f6470b5eSDaniel Hsu         lg2::error("JED file parsing failed");
737f6470b5eSDaniel Hsu         co_return false;
738f6470b5eSDaniel Hsu     }
739f6470b5eSDaniel Hsu     progressCallBack(15);
740f6470b5eSDaniel Hsu 
741f6470b5eSDaniel Hsu     if (!verifyChecksum())
742f6470b5eSDaniel Hsu     {
743f6470b5eSDaniel Hsu         lg2::error("Checksum verification failed");
744f6470b5eSDaniel Hsu         co_return false;
745f6470b5eSDaniel Hsu     }
746f6470b5eSDaniel Hsu     progressCallBack(20);
747f6470b5eSDaniel Hsu 
XO2XO3FamilyUpdate(std::function<bool (int)> progressCallBack)748f6470b5eSDaniel Hsu     if (!isLCMXO3D)
749f6470b5eSDaniel Hsu     {
750f6470b5eSDaniel Hsu         lg2::error("is not LCMXO3D");
751f6470b5eSDaniel Hsu     }
752f6470b5eSDaniel Hsu 
753f6470b5eSDaniel Hsu     lg2::debug("Starts to update ...");
754f6470b5eSDaniel Hsu     lg2::debug("Enable program mode.");
755f6470b5eSDaniel Hsu     progressCallBack(25);
756f6470b5eSDaniel Hsu 
757f6470b5eSDaniel Hsu     co_await waitBusyAndVerify();
758f6470b5eSDaniel Hsu 
759f6470b5eSDaniel Hsu     if (!(co_await enableProgramMode()))
760f6470b5eSDaniel Hsu     {
761f6470b5eSDaniel Hsu         lg2::error("Enable program mode failed.");
762f6470b5eSDaniel Hsu         co_return false;
763f6470b5eSDaniel Hsu     }
764f6470b5eSDaniel Hsu     progressCallBack(30);
765f6470b5eSDaniel Hsu 
766f6470b5eSDaniel Hsu     lg2::debug("Erase flash.");
767f6470b5eSDaniel Hsu     if (!(co_await eraseFlash()))
768f6470b5eSDaniel Hsu     {
769f6470b5eSDaniel Hsu         lg2::error("Erase flash failed.");
770f6470b5eSDaniel Hsu         co_return false;
771f6470b5eSDaniel Hsu     }
772f6470b5eSDaniel Hsu     progressCallBack(40);
773f6470b5eSDaniel Hsu 
774f6470b5eSDaniel Hsu     lg2::debug("Reset config flash.");
775f6470b5eSDaniel Hsu     if (!(co_await resetConfigFlash()))
776f6470b5eSDaniel Hsu     {
777f6470b5eSDaniel Hsu         lg2::error("Reset config flash failed.");
778f6470b5eSDaniel Hsu         co_return false;
779f6470b5eSDaniel Hsu     }
780f6470b5eSDaniel Hsu     progressCallBack(50);
781f6470b5eSDaniel Hsu 
782f6470b5eSDaniel Hsu     lg2::debug("Write program page ...");
783f6470b5eSDaniel Hsu     if (!(co_await writeProgramPage()))
784f6470b5eSDaniel Hsu     {
785f6470b5eSDaniel Hsu         lg2::error("Write program page failed.");
786f6470b5eSDaniel Hsu         co_return false;
787f6470b5eSDaniel Hsu     }
788f6470b5eSDaniel Hsu     lg2::debug("Write program page done.");
789f6470b5eSDaniel Hsu     progressCallBack(60);
790f6470b5eSDaniel Hsu 
791f6470b5eSDaniel Hsu     lg2::debug("Program user code.");
792f6470b5eSDaniel Hsu     if (!(co_await programUserCode()))
793f6470b5eSDaniel Hsu     {
794f6470b5eSDaniel Hsu         lg2::error("Program user code failed.");
795f6470b5eSDaniel Hsu         co_return false;
796f6470b5eSDaniel Hsu     }
797f6470b5eSDaniel Hsu     progressCallBack(70);
798f6470b5eSDaniel Hsu 
799f6470b5eSDaniel Hsu     if (!(co_await programDone()))
800f6470b5eSDaniel Hsu     {
801f6470b5eSDaniel Hsu         lg2::error("Program not done.");
802f6470b5eSDaniel Hsu         co_return false;
803f6470b5eSDaniel Hsu     }
804f6470b5eSDaniel Hsu     progressCallBack(80);
805f6470b5eSDaniel Hsu 
806f6470b5eSDaniel Hsu     lg2::debug("Disable config interface.");
807f6470b5eSDaniel Hsu     if (!(co_await disableConfigInterface()))
808f6470b5eSDaniel Hsu     {
809f6470b5eSDaniel Hsu         lg2::error("Disable Config Interface failed.");
810f6470b5eSDaniel Hsu         co_return false;
811f6470b5eSDaniel Hsu     }
812f6470b5eSDaniel Hsu     progressCallBack(90);
813f6470b5eSDaniel Hsu 
814f6470b5eSDaniel Hsu     lg2::debug("Update completed!");
815f6470b5eSDaniel Hsu 
816f6470b5eSDaniel Hsu     co_return true;
817f6470b5eSDaniel Hsu }
818f6470b5eSDaniel Hsu 
819f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::updateFirmware(
820f6470b5eSDaniel Hsu     std::function<bool(int)> progressCallBack)
821f6470b5eSDaniel Hsu {
822f6470b5eSDaniel Hsu     co_return co_await XO2XO3FamilyUpdate(progressCallBack);
823f6470b5eSDaniel Hsu }
824f6470b5eSDaniel Hsu 
825f6470b5eSDaniel Hsu sdbusplus::async::task<bool> CpldLatticeManager::getVersion(
826f6470b5eSDaniel Hsu     std::string& version)
827f6470b5eSDaniel Hsu {
82837a30143SDaniel Hsu     auto userCode = std::make_unique<uint32_t>(0);
829f6470b5eSDaniel Hsu 
830f6470b5eSDaniel Hsu     if (target.empty())
831f6470b5eSDaniel Hsu     {
83237a30143SDaniel Hsu         if (!(co_await readUserCode(*userCode)))
833f6470b5eSDaniel Hsu         {
834f6470b5eSDaniel Hsu             lg2::error("Read usercode failed.");
835f6470b5eSDaniel Hsu             co_return false;
836f6470b5eSDaniel Hsu         }
837f6470b5eSDaniel Hsu 
83837a30143SDaniel Hsu         lg2::debug("CPLD version: {VERSION}", "VERSION", *userCode);
839f6470b5eSDaniel Hsu     }
840f6470b5eSDaniel Hsu     else if (target == "CFG0" || target == "CFG1")
841f6470b5eSDaniel Hsu     {
842f6470b5eSDaniel Hsu         isLCMXO3D = true;
843f6470b5eSDaniel Hsu         co_await waitBusyAndVerify();
844f6470b5eSDaniel Hsu 
845f6470b5eSDaniel Hsu         if (!(co_await enableProgramMode()))
846f6470b5eSDaniel Hsu         {
847f6470b5eSDaniel Hsu             lg2::error("Enable program mode failed.");
updateFirmware(std::function<bool (int)> progressCallBack)848f6470b5eSDaniel Hsu             co_return false;
849f6470b5eSDaniel Hsu         }
850f6470b5eSDaniel Hsu 
851f6470b5eSDaniel Hsu         if (!(co_await resetConfigFlash()))
852f6470b5eSDaniel Hsu         {
853f6470b5eSDaniel Hsu             lg2::error("Reset config flash failed.");
854f6470b5eSDaniel Hsu             co_return false;
855f6470b5eSDaniel Hsu         }
856f6470b5eSDaniel Hsu 
85737a30143SDaniel Hsu         if (!(co_await readUserCode(*userCode)))
858f6470b5eSDaniel Hsu         {
uint32ToHexStr(uint32_t value)859f6470b5eSDaniel Hsu             lg2::error("Read usercode failed.");
860f6470b5eSDaniel Hsu             co_return false;
861f6470b5eSDaniel Hsu         }
862f6470b5eSDaniel Hsu 
863f6470b5eSDaniel Hsu         if (!(co_await programDone()))
864f6470b5eSDaniel Hsu         {
865f6470b5eSDaniel Hsu             lg2::error("Program not done.");
866f6470b5eSDaniel Hsu             co_return false;
getVersion(std::string & version)867f6470b5eSDaniel Hsu         }
868f6470b5eSDaniel Hsu 
869f6470b5eSDaniel Hsu         if (!(co_await disableConfigInterface()))
870f6470b5eSDaniel Hsu         {
871f6470b5eSDaniel Hsu             lg2::error("Disable Config Interface failed.");
872f6470b5eSDaniel Hsu             co_return false;
873f6470b5eSDaniel Hsu         }
874f6470b5eSDaniel Hsu 
875f6470b5eSDaniel Hsu         lg2::debug("CPLD {TARGET} version: {VERSION}", "TARGET", target,
87637a30143SDaniel Hsu                    "VERSION", *userCode);
877f6470b5eSDaniel Hsu     }
878f6470b5eSDaniel Hsu     else
879f6470b5eSDaniel Hsu     {
880f6470b5eSDaniel Hsu         lg2::error("Error: unknown target.");
881f6470b5eSDaniel Hsu         co_return false;
882f6470b5eSDaniel Hsu     }
883f6470b5eSDaniel Hsu 
88437a30143SDaniel Hsu     if (*userCode == 0)
885f6470b5eSDaniel Hsu     {
886f6470b5eSDaniel Hsu         lg2::error("User code is zero, cannot get version.");
887f6470b5eSDaniel Hsu         co_return false;
888f6470b5eSDaniel Hsu     }
88937a30143SDaniel Hsu     version = uint32ToHexStr(*userCode);
890f6470b5eSDaniel Hsu     co_return true;
891f6470b5eSDaniel Hsu }
892