xref: /openbmc/phosphor-bmc-code-mgmt/cpld/lattice/lattice_base_cpld.cpp (revision b602aad5026847e2a4895598c6b5b7b08a377282)
1*b602aad5SDaniel Hsu #include "lattice_base_cpld.hpp"
2*b602aad5SDaniel Hsu 
3*b602aad5SDaniel Hsu #include <algorithm>
4*b602aad5SDaniel Hsu #include <cstddef>
5*b602aad5SDaniel Hsu #include <fstream>
6*b602aad5SDaniel Hsu #include <map>
7*b602aad5SDaniel Hsu #include <numeric>
8*b602aad5SDaniel Hsu #include <vector>
9*b602aad5SDaniel Hsu 
10*b602aad5SDaniel Hsu namespace phosphor::software::cpld
11*b602aad5SDaniel Hsu {
12*b602aad5SDaniel Hsu 
13*b602aad5SDaniel Hsu constexpr uint8_t busyWaitmaxRetry = 30;
14*b602aad5SDaniel Hsu constexpr uint8_t busyFlagBit = 0x80;
15*b602aad5SDaniel Hsu 
16*b602aad5SDaniel Hsu static constexpr std::string_view tagFuseQuantity = "QF";
17*b602aad5SDaniel Hsu static constexpr std::string_view tagUserCodeHex = "UH";
18*b602aad5SDaniel Hsu static constexpr std::string_view tagCFStart = "L000";
19*b602aad5SDaniel Hsu static constexpr std::string_view tagData = "NOTE TAG DATA";
20*b602aad5SDaniel Hsu static constexpr std::string_view tagUserFlashMemory = "NOTE USER MEMORY DATA";
21*b602aad5SDaniel Hsu static constexpr std::string_view tagChecksum = "C";
22*b602aad5SDaniel Hsu static constexpr std::string_view tagUserCode = "NOTE User Electronic";
23*b602aad5SDaniel Hsu static constexpr std::string_view tagEbrInitData = "NOTE EBR_INIT DATA";
24*b602aad5SDaniel Hsu static constexpr std::string_view tagEndConfig = "NOTE END CONFIG DATA";
25*b602aad5SDaniel Hsu static constexpr std::string_view tagDevName = "NOTE DEVICE NAME";
26*b602aad5SDaniel Hsu 
27*b602aad5SDaniel Hsu constexpr uint8_t isOK = 0;
28*b602aad5SDaniel Hsu constexpr uint8_t isReady = 0;
29*b602aad5SDaniel Hsu constexpr uint8_t busyOrReadyBit = 4;
30*b602aad5SDaniel Hsu constexpr uint8_t failOrOKBit = 5;
31*b602aad5SDaniel Hsu 
reverse_bit(uint8_t b)32*b602aad5SDaniel Hsu static uint8_t reverse_bit(uint8_t b)
33*b602aad5SDaniel Hsu {
34*b602aad5SDaniel Hsu     b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
35*b602aad5SDaniel Hsu     b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
36*b602aad5SDaniel Hsu     b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
37*b602aad5SDaniel Hsu     return b;
38*b602aad5SDaniel Hsu }
39*b602aad5SDaniel Hsu 
uint32ToHexStr(uint32_t value)40*b602aad5SDaniel Hsu std::string LatticeBaseCPLD::uint32ToHexStr(uint32_t value)
41*b602aad5SDaniel Hsu {
42*b602aad5SDaniel Hsu     std::ostringstream oss;
43*b602aad5SDaniel Hsu     oss << std::setfill('0') << std::setw(8) << std::hex << std::uppercase
44*b602aad5SDaniel Hsu         << value;
45*b602aad5SDaniel Hsu     return oss.str();
46*b602aad5SDaniel Hsu }
47*b602aad5SDaniel Hsu 
updateFirmware(const uint8_t * image,size_t imageSize,std::function<bool (int)> progressCallBack)48*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::updateFirmware(
49*b602aad5SDaniel Hsu     const uint8_t* image, size_t imageSize,
50*b602aad5SDaniel Hsu     std::function<bool(int)> progressCallBack)
51*b602aad5SDaniel Hsu {
52*b602aad5SDaniel Hsu     if (progressCallBack == nullptr)
53*b602aad5SDaniel Hsu     {
54*b602aad5SDaniel Hsu         lg2::error("Error: progressCallBack is null.");
55*b602aad5SDaniel Hsu         co_return false;
56*b602aad5SDaniel Hsu     }
57*b602aad5SDaniel Hsu 
58*b602aad5SDaniel Hsu     if (!image || imageSize == 0)
59*b602aad5SDaniel Hsu     {
60*b602aad5SDaniel Hsu         lg2::error("Error: image is null.");
61*b602aad5SDaniel Hsu         co_return false;
62*b602aad5SDaniel Hsu     }
63*b602aad5SDaniel Hsu 
64*b602aad5SDaniel Hsu     lg2::debug("CPLD image size: {IMAGESIZE}", "IMAGESIZE", imageSize);
65*b602aad5SDaniel Hsu     auto result = co_await prepareUpdate(image, imageSize);
66*b602aad5SDaniel Hsu     if (!result)
67*b602aad5SDaniel Hsu     {
68*b602aad5SDaniel Hsu         lg2::error("Prepare update failed.");
69*b602aad5SDaniel Hsu         co_return false;
70*b602aad5SDaniel Hsu     }
71*b602aad5SDaniel Hsu     lg2::debug("Prepare update success");
72*b602aad5SDaniel Hsu     progressCallBack(50);
73*b602aad5SDaniel Hsu 
74*b602aad5SDaniel Hsu     result = co_await doUpdate();
75*b602aad5SDaniel Hsu     if (!result)
76*b602aad5SDaniel Hsu     {
77*b602aad5SDaniel Hsu         lg2::error("Do update failed.");
78*b602aad5SDaniel Hsu         co_return false;
79*b602aad5SDaniel Hsu     }
80*b602aad5SDaniel Hsu     lg2::debug("Do update success");
81*b602aad5SDaniel Hsu     progressCallBack(90);
82*b602aad5SDaniel Hsu 
83*b602aad5SDaniel Hsu     result = co_await finishUpdate();
84*b602aad5SDaniel Hsu     if (!result)
85*b602aad5SDaniel Hsu     {
86*b602aad5SDaniel Hsu         lg2::error("Finish update failed.");
87*b602aad5SDaniel Hsu         co_return false;
88*b602aad5SDaniel Hsu     }
89*b602aad5SDaniel Hsu     lg2::debug("Finish update success");
90*b602aad5SDaniel Hsu     progressCallBack(100);
91*b602aad5SDaniel Hsu 
92*b602aad5SDaniel Hsu     co_return true;
93*b602aad5SDaniel Hsu }
94*b602aad5SDaniel Hsu 
jedFileParser(const uint8_t * image,size_t imageSize)95*b602aad5SDaniel Hsu bool LatticeBaseCPLD::jedFileParser(const uint8_t* image, size_t imageSize)
96*b602aad5SDaniel Hsu {
97*b602aad5SDaniel Hsu     enum class ParseState
98*b602aad5SDaniel Hsu     {
99*b602aad5SDaniel Hsu         none,
100*b602aad5SDaniel Hsu         cfg,
101*b602aad5SDaniel Hsu         endCfg,
102*b602aad5SDaniel Hsu         ufm,
103*b602aad5SDaniel Hsu         checksum,
104*b602aad5SDaniel Hsu         userCode
105*b602aad5SDaniel Hsu     };
106*b602aad5SDaniel Hsu     ParseState state = ParseState::none;
107*b602aad5SDaniel Hsu 
108*b602aad5SDaniel Hsu     if (image == nullptr || imageSize == 0)
109*b602aad5SDaniel Hsu     {
110*b602aad5SDaniel Hsu         lg2::error(
111*b602aad5SDaniel Hsu             "Error: JED file is empty or not found. Please check the file.");
112*b602aad5SDaniel Hsu         return false;
113*b602aad5SDaniel Hsu     }
114*b602aad5SDaniel Hsu 
115*b602aad5SDaniel Hsu     std::string content(reinterpret_cast<const char*>(image), imageSize);
116*b602aad5SDaniel Hsu     std::istringstream iss(content);
117*b602aad5SDaniel Hsu     std::string line;
118*b602aad5SDaniel Hsu 
119*b602aad5SDaniel Hsu     auto pushPage = [](std::string& line, std::vector<uint8_t>& sector) {
120*b602aad5SDaniel Hsu         if (line[0] == '0' || line[0] == '1')
121*b602aad5SDaniel Hsu         {
122*b602aad5SDaniel Hsu             while (line.size() >= 8)
123*b602aad5SDaniel Hsu             {
124*b602aad5SDaniel Hsu                 try
125*b602aad5SDaniel Hsu                 {
126*b602aad5SDaniel Hsu                     sector.push_back(static_cast<uint8_t>(
127*b602aad5SDaniel Hsu                         std::stoi(line.substr(0, 8), 0, 2)));
128*b602aad5SDaniel Hsu                     line.erase(0, 8);
129*b602aad5SDaniel Hsu                 }
130*b602aad5SDaniel Hsu                 catch (...)
131*b602aad5SDaniel Hsu                 {
132*b602aad5SDaniel Hsu                     break;
133*b602aad5SDaniel Hsu                 }
134*b602aad5SDaniel Hsu             }
135*b602aad5SDaniel Hsu         }
136*b602aad5SDaniel Hsu     };
137*b602aad5SDaniel Hsu 
138*b602aad5SDaniel Hsu     while (getline(iss, line))
139*b602aad5SDaniel Hsu     {
140*b602aad5SDaniel Hsu         if (!line.empty() && line.back() == '\r')
141*b602aad5SDaniel Hsu         {
142*b602aad5SDaniel Hsu             line.pop_back();
143*b602aad5SDaniel Hsu         }
144*b602aad5SDaniel Hsu         if (line.empty())
145*b602aad5SDaniel Hsu         {
146*b602aad5SDaniel Hsu             continue;
147*b602aad5SDaniel Hsu         }
148*b602aad5SDaniel Hsu 
149*b602aad5SDaniel Hsu         if (line.starts_with(tagFuseQuantity))
150*b602aad5SDaniel Hsu         {
151*b602aad5SDaniel Hsu             ssize_t numberSize = static_cast<ssize_t>(line.find('*')) -
152*b602aad5SDaniel Hsu                                  static_cast<ssize_t>(line.find('F')) - 1;
153*b602aad5SDaniel Hsu             if (numberSize > 0)
154*b602aad5SDaniel Hsu             {
155*b602aad5SDaniel Hsu                 fwInfo.fuseQuantity = std::stoul(
156*b602aad5SDaniel Hsu                     line.substr(tagFuseQuantity.length(), numberSize));
157*b602aad5SDaniel Hsu                 lg2::debug("fuseQuantity Size = {QFSIZE}", "QFSIZE",
158*b602aad5SDaniel Hsu                            fwInfo.fuseQuantity);
159*b602aad5SDaniel Hsu             }
160*b602aad5SDaniel Hsu         }
161*b602aad5SDaniel Hsu         else if (line.starts_with(tagCFStart) ||
162*b602aad5SDaniel Hsu                  line.starts_with(tagEbrInitData))
163*b602aad5SDaniel Hsu         {
164*b602aad5SDaniel Hsu             state = ParseState::cfg;
165*b602aad5SDaniel Hsu             continue;
166*b602aad5SDaniel Hsu         }
167*b602aad5SDaniel Hsu         else if (line.starts_with(tagEndConfig))
168*b602aad5SDaniel Hsu         {
169*b602aad5SDaniel Hsu             state = ParseState::endCfg;
170*b602aad5SDaniel Hsu             continue;
171*b602aad5SDaniel Hsu         }
172*b602aad5SDaniel Hsu         else if (line.starts_with(tagUserFlashMemory) ||
173*b602aad5SDaniel Hsu                  line.starts_with(tagData))
174*b602aad5SDaniel Hsu         {
175*b602aad5SDaniel Hsu             state = ParseState::ufm;
176*b602aad5SDaniel Hsu             continue;
177*b602aad5SDaniel Hsu         }
178*b602aad5SDaniel Hsu         else if (line.starts_with(tagUserCode))
179*b602aad5SDaniel Hsu         {
180*b602aad5SDaniel Hsu             state = ParseState::userCode;
181*b602aad5SDaniel Hsu             continue;
182*b602aad5SDaniel Hsu         }
183*b602aad5SDaniel Hsu         else if (line.starts_with(tagChecksum))
184*b602aad5SDaniel Hsu         {
185*b602aad5SDaniel Hsu             state = ParseState::checksum;
186*b602aad5SDaniel Hsu         }
187*b602aad5SDaniel Hsu         else if (line.starts_with(tagDevName))
188*b602aad5SDaniel Hsu         {
189*b602aad5SDaniel Hsu             lg2::debug("{DEVNAME}", "DEVNAME", line);
190*b602aad5SDaniel Hsu             if (line.find(chip) == std::string::npos)
191*b602aad5SDaniel Hsu             {
192*b602aad5SDaniel Hsu                 lg2::debug("STOP UPDATING: The image does not match the chip.");
193*b602aad5SDaniel Hsu                 return -1;
194*b602aad5SDaniel Hsu             }
195*b602aad5SDaniel Hsu         }
196*b602aad5SDaniel Hsu 
197*b602aad5SDaniel Hsu         switch (state)
198*b602aad5SDaniel Hsu         {
199*b602aad5SDaniel Hsu             case ParseState::cfg:
200*b602aad5SDaniel Hsu                 pushPage(line, fwInfo.cfgData);
201*b602aad5SDaniel Hsu                 break;
202*b602aad5SDaniel Hsu             case ParseState::endCfg:
203*b602aad5SDaniel Hsu                 pushPage(line, sumOnly);
204*b602aad5SDaniel Hsu                 break;
205*b602aad5SDaniel Hsu             case ParseState::ufm:
206*b602aad5SDaniel Hsu                 pushPage(line, fwInfo.ufmData);
207*b602aad5SDaniel Hsu                 break;
208*b602aad5SDaniel Hsu             case ParseState::checksum:
209*b602aad5SDaniel Hsu                 if (line.size() > 1)
210*b602aad5SDaniel Hsu                 {
211*b602aad5SDaniel Hsu                     state = ParseState::none;
212*b602aad5SDaniel Hsu                     ssize_t numberSize =
213*b602aad5SDaniel Hsu                         static_cast<ssize_t>(line.find('*')) -
214*b602aad5SDaniel Hsu                         static_cast<ssize_t>(line.find('C')) - 1;
215*b602aad5SDaniel Hsu                     if (numberSize <= 0)
216*b602aad5SDaniel Hsu                     {
217*b602aad5SDaniel Hsu                         lg2::debug("Error in parsing checksum");
218*b602aad5SDaniel Hsu                         return -1;
219*b602aad5SDaniel Hsu                     }
220*b602aad5SDaniel Hsu                     static constexpr auto start = tagChecksum.length();
221*b602aad5SDaniel Hsu                     std::istringstream iss(line.substr(start, numberSize));
222*b602aad5SDaniel Hsu                     iss >> std::hex >> fwInfo.checksum;
223*b602aad5SDaniel Hsu                     lg2::debug("Checksum = 0x{CHECKSUM}", "CHECKSUM",
224*b602aad5SDaniel Hsu                                fwInfo.checksum);
225*b602aad5SDaniel Hsu                 }
226*b602aad5SDaniel Hsu                 break;
227*b602aad5SDaniel Hsu             case ParseState::userCode:
228*b602aad5SDaniel Hsu                 if (line.starts_with(tagUserCodeHex))
229*b602aad5SDaniel Hsu                 {
230*b602aad5SDaniel Hsu                     state = ParseState::none;
231*b602aad5SDaniel Hsu                     ssize_t numberSize =
232*b602aad5SDaniel Hsu                         static_cast<ssize_t>(line.find('*')) -
233*b602aad5SDaniel Hsu                         static_cast<ssize_t>(line.find('H')) - 1;
234*b602aad5SDaniel Hsu                     if (numberSize <= 0)
235*b602aad5SDaniel Hsu                     {
236*b602aad5SDaniel Hsu                         lg2::debug("Error in parsing usercode");
237*b602aad5SDaniel Hsu                         return -1;
238*b602aad5SDaniel Hsu                     }
239*b602aad5SDaniel Hsu                     std::istringstream iss(
240*b602aad5SDaniel Hsu                         line.substr(tagUserCodeHex.length(), numberSize));
241*b602aad5SDaniel Hsu                     iss >> std::hex >> fwInfo.version;
242*b602aad5SDaniel Hsu                     lg2::debug("UserCode = 0x{USERCODE}", "USERCODE",
243*b602aad5SDaniel Hsu                                fwInfo.version);
244*b602aad5SDaniel Hsu                 }
245*b602aad5SDaniel Hsu                 break;
246*b602aad5SDaniel Hsu             default:
247*b602aad5SDaniel Hsu                 break;
248*b602aad5SDaniel Hsu         }
249*b602aad5SDaniel Hsu     }
250*b602aad5SDaniel Hsu 
251*b602aad5SDaniel Hsu     lg2::debug("CFG Size = {CFGSIZE}", "CFGSIZE", fwInfo.cfgData.size());
252*b602aad5SDaniel Hsu     if (!fwInfo.ufmData.empty())
253*b602aad5SDaniel Hsu     {
254*b602aad5SDaniel Hsu         lg2::debug("userFlashMemory size = {UFMSIZE}", "UFMSIZE",
255*b602aad5SDaniel Hsu                    fwInfo.ufmData.size());
256*b602aad5SDaniel Hsu     }
257*b602aad5SDaniel Hsu 
258*b602aad5SDaniel Hsu     return true;
259*b602aad5SDaniel Hsu }
260*b602aad5SDaniel Hsu 
verifyChecksum()261*b602aad5SDaniel Hsu bool LatticeBaseCPLD::verifyChecksum()
262*b602aad5SDaniel Hsu {
263*b602aad5SDaniel Hsu     uint32_t calculated = 0U;
264*b602aad5SDaniel Hsu     auto addByte = [](uint32_t sum, uint8_t byte) {
265*b602aad5SDaniel Hsu         return sum + reverse_bit(byte);
266*b602aad5SDaniel Hsu     };
267*b602aad5SDaniel Hsu 
268*b602aad5SDaniel Hsu     calculated = std::accumulate(fwInfo.cfgData.begin(), fwInfo.cfgData.end(),
269*b602aad5SDaniel Hsu                                  calculated, addByte);
270*b602aad5SDaniel Hsu     calculated =
271*b602aad5SDaniel Hsu         std::accumulate(sumOnly.begin(), sumOnly.end(), calculated, addByte);
272*b602aad5SDaniel Hsu     calculated = std::accumulate(fwInfo.ufmData.begin(), fwInfo.ufmData.end(),
273*b602aad5SDaniel Hsu                                  calculated, addByte);
274*b602aad5SDaniel Hsu 
275*b602aad5SDaniel Hsu     lg2::debug("Calculated checksum = {CALCULATED}", "CALCULATED", lg2::hex,
276*b602aad5SDaniel Hsu                calculated);
277*b602aad5SDaniel Hsu     lg2::debug("Checksum from JED file = {JEDFILECHECKSUM}", "JEDFILECHECKSUM",
278*b602aad5SDaniel Hsu                lg2::hex, fwInfo.checksum);
279*b602aad5SDaniel Hsu 
280*b602aad5SDaniel Hsu     if (fwInfo.checksum != (calculated & 0xFFFF))
281*b602aad5SDaniel Hsu     {
282*b602aad5SDaniel Hsu         lg2::error("JED file checksum compare fail, "
283*b602aad5SDaniel Hsu                    "Calculated checksum = {CALCULATED}, "
284*b602aad5SDaniel Hsu                    "Checksum from JED file = {JEDFILECHECKSUM}",
285*b602aad5SDaniel Hsu                    "CALCULATED", lg2::hex, calculated, "JEDFILECHECKSUM",
286*b602aad5SDaniel Hsu                    lg2::hex, fwInfo.checksum);
287*b602aad5SDaniel Hsu         return false;
288*b602aad5SDaniel Hsu     }
289*b602aad5SDaniel Hsu 
290*b602aad5SDaniel Hsu     lg2::debug("JED file checksum compare success");
291*b602aad5SDaniel Hsu     return true;
292*b602aad5SDaniel Hsu }
293*b602aad5SDaniel Hsu 
enableProgramMode()294*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::enableProgramMode()
295*b602aad5SDaniel Hsu {
296*b602aad5SDaniel Hsu     std::vector<uint8_t> request = {commandEnableConfigMode, 0x08, 0x0, 0x0};
297*b602aad5SDaniel Hsu     std::vector<uint8_t> response;
298*b602aad5SDaniel Hsu 
299*b602aad5SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
300*b602aad5SDaniel Hsu     {
301*b602aad5SDaniel Hsu         lg2::error("Failed to send enable program mode request.");
302*b602aad5SDaniel Hsu         co_return false;
303*b602aad5SDaniel Hsu     }
304*b602aad5SDaniel Hsu 
305*b602aad5SDaniel Hsu     if (!(co_await waitBusyAndVerify()))
306*b602aad5SDaniel Hsu     {
307*b602aad5SDaniel Hsu         lg2::error("Wait busy and verify fail");
308*b602aad5SDaniel Hsu         co_return false;
309*b602aad5SDaniel Hsu     }
310*b602aad5SDaniel Hsu     co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
311*b602aad5SDaniel Hsu     co_return true;
312*b602aad5SDaniel Hsu }
313*b602aad5SDaniel Hsu 
resetConfigFlash()314*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::resetConfigFlash()
315*b602aad5SDaniel Hsu {
316*b602aad5SDaniel Hsu     std::vector<uint8_t> request;
317*b602aad5SDaniel Hsu     std::vector<uint8_t> response;
318*b602aad5SDaniel Hsu     if (isLCMXO3D)
319*b602aad5SDaniel Hsu     {
320*b602aad5SDaniel Hsu         /*
321*b602aad5SDaniel Hsu         Set Page Address pointer to the
322*b602aad5SDaniel Hsu         beginning of the different internal
323*b602aad5SDaniel Hsu         Flash sectors. The bit in YYYY
324*b602aad5SDaniel Hsu         defines which sector is selected.
325*b602aad5SDaniel Hsu         Bit Flash sector selected
326*b602aad5SDaniel Hsu         8 CFG0
327*b602aad5SDaniel Hsu         9 CFG1
328*b602aad5SDaniel Hsu         10 FEA
329*b602aad5SDaniel Hsu         11 PUBKEY
330*b602aad5SDaniel Hsu         12 AESKEY
331*b602aad5SDaniel Hsu         13 CSEC
332*b602aad5SDaniel Hsu         14 UFM0
333*b602aad5SDaniel Hsu         15 UFM1
334*b602aad5SDaniel Hsu         16 UFM2
335*b602aad5SDaniel Hsu         17 UFM3
336*b602aad5SDaniel Hsu         18 USEC
337*b602aad5SDaniel Hsu         19 Reserved
338*b602aad5SDaniel Hsu         20 Reserved
339*b602aad5SDaniel Hsu         21 Reserved
340*b602aad5SDaniel Hsu         22 Reserved
341*b602aad5SDaniel Hsu         commandResetConfigFlash = 0x46, YY YY 00
342*b602aad5SDaniel Hsu         */
343*b602aad5SDaniel Hsu         if (target.empty() || target == "CFG0")
344*b602aad5SDaniel Hsu         {
345*b602aad5SDaniel Hsu             request = {commandResetConfigFlash, 0x00, 0x01, 0x00};
346*b602aad5SDaniel Hsu         }
347*b602aad5SDaniel Hsu         else if (target == "CFG1")
348*b602aad5SDaniel Hsu         {
349*b602aad5SDaniel Hsu             request = {commandResetConfigFlash, 0x00, 0x02, 0x00};
350*b602aad5SDaniel Hsu         }
351*b602aad5SDaniel Hsu         else
352*b602aad5SDaniel Hsu         {
353*b602aad5SDaniel Hsu             lg2::error(
354*b602aad5SDaniel Hsu                 "Error: unknown target. Only CFG0 and CFG1 are supported.");
355*b602aad5SDaniel Hsu             co_return false;
356*b602aad5SDaniel Hsu         }
357*b602aad5SDaniel Hsu     }
358*b602aad5SDaniel Hsu     else
359*b602aad5SDaniel Hsu     {
360*b602aad5SDaniel Hsu         request = {commandResetConfigFlash, 0x0, 0x0, 0x0};
361*b602aad5SDaniel Hsu     }
362*b602aad5SDaniel Hsu 
363*b602aad5SDaniel Hsu     co_return i2cInterface.sendReceive(request, response);
364*b602aad5SDaniel Hsu }
365*b602aad5SDaniel Hsu 
programDone()366*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::programDone()
367*b602aad5SDaniel Hsu {
368*b602aad5SDaniel Hsu     std::vector<uint8_t> request = {commandProgramDone, 0x0, 0x0, 0x0};
369*b602aad5SDaniel Hsu     std::vector<uint8_t> response;
370*b602aad5SDaniel Hsu 
371*b602aad5SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
372*b602aad5SDaniel Hsu     {
373*b602aad5SDaniel Hsu         lg2::error("Failed to send program done request.");
374*b602aad5SDaniel Hsu         co_return false;
375*b602aad5SDaniel Hsu     }
376*b602aad5SDaniel Hsu 
377*b602aad5SDaniel Hsu     if (!(co_await waitBusyAndVerify()))
378*b602aad5SDaniel Hsu     {
379*b602aad5SDaniel Hsu         lg2::error("Wait busy and verify fail");
380*b602aad5SDaniel Hsu         co_return false;
381*b602aad5SDaniel Hsu     }
382*b602aad5SDaniel Hsu 
383*b602aad5SDaniel Hsu     co_return true;
384*b602aad5SDaniel Hsu }
385*b602aad5SDaniel Hsu 
disableConfigInterface()386*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::disableConfigInterface()
387*b602aad5SDaniel Hsu {
388*b602aad5SDaniel Hsu     std::vector<uint8_t> request = {commandDisableConfigInterface, 0x0, 0x0};
389*b602aad5SDaniel Hsu     std::vector<uint8_t> response;
390*b602aad5SDaniel Hsu     co_return i2cInterface.sendReceive(request, response);
391*b602aad5SDaniel Hsu }
392*b602aad5SDaniel Hsu 
waitBusyAndVerify()393*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::waitBusyAndVerify()
394*b602aad5SDaniel Hsu {
395*b602aad5SDaniel Hsu     uint8_t retry = 0;
396*b602aad5SDaniel Hsu 
397*b602aad5SDaniel Hsu     while (retry <= busyWaitmaxRetry)
398*b602aad5SDaniel Hsu     {
399*b602aad5SDaniel Hsu         uint8_t busyFlag = 0xff;
400*b602aad5SDaniel Hsu 
401*b602aad5SDaniel Hsu         auto readBusyFlagResult = co_await readBusyFlag(busyFlag);
402*b602aad5SDaniel Hsu         if (!readBusyFlagResult)
403*b602aad5SDaniel Hsu         {
404*b602aad5SDaniel Hsu             lg2::error("Fail to read busy flag.");
405*b602aad5SDaniel Hsu             co_return false;
406*b602aad5SDaniel Hsu         }
407*b602aad5SDaniel Hsu 
408*b602aad5SDaniel Hsu         if (busyFlag & busyFlagBit)
409*b602aad5SDaniel Hsu         {
410*b602aad5SDaniel Hsu             co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
411*b602aad5SDaniel Hsu             retry++;
412*b602aad5SDaniel Hsu             if (retry > busyWaitmaxRetry)
413*b602aad5SDaniel Hsu             {
414*b602aad5SDaniel Hsu                 lg2::error(
415*b602aad5SDaniel Hsu                     "Status Reg : Busy! Please check the I2C bus and address.");
416*b602aad5SDaniel Hsu                 co_return false;
417*b602aad5SDaniel Hsu             }
418*b602aad5SDaniel Hsu         }
419*b602aad5SDaniel Hsu         else
420*b602aad5SDaniel Hsu         {
421*b602aad5SDaniel Hsu             break;
422*b602aad5SDaniel Hsu         }
423*b602aad5SDaniel Hsu     } // while loop busy check
424*b602aad5SDaniel Hsu 
425*b602aad5SDaniel Hsu     // Check out status reg
426*b602aad5SDaniel Hsu     auto statusReg = std::make_unique<uint8_t>(0xff);
427*b602aad5SDaniel Hsu 
428*b602aad5SDaniel Hsu     if (!(co_await readStatusReg(*statusReg)))
429*b602aad5SDaniel Hsu     {
430*b602aad5SDaniel Hsu         lg2::error("Fail to read status register.");
431*b602aad5SDaniel Hsu         co_return false;
432*b602aad5SDaniel Hsu     }
433*b602aad5SDaniel Hsu 
434*b602aad5SDaniel Hsu     if (((*statusReg >> busyOrReadyBit) & 1) == isReady &&
435*b602aad5SDaniel Hsu         ((*statusReg >> failOrOKBit) & 1) == isOK)
436*b602aad5SDaniel Hsu     {
437*b602aad5SDaniel Hsu         lg2::debug("Status Reg : OK");
438*b602aad5SDaniel Hsu         co_return true;
439*b602aad5SDaniel Hsu     }
440*b602aad5SDaniel Hsu 
441*b602aad5SDaniel Hsu     lg2::error("Status Reg : Fail! Please check the I2C bus and address.");
442*b602aad5SDaniel Hsu     co_return false;
443*b602aad5SDaniel Hsu }
444*b602aad5SDaniel Hsu 
readBusyFlag(uint8_t & busyFlag)445*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::readBusyFlag(uint8_t& busyFlag)
446*b602aad5SDaniel Hsu {
447*b602aad5SDaniel Hsu     constexpr size_t resSize = 1;
448*b602aad5SDaniel Hsu     std::vector<uint8_t> request = {commandReadBusyFlag, 0x0, 0x0, 0x0};
449*b602aad5SDaniel Hsu     std::vector<uint8_t> response(resSize, 0);
450*b602aad5SDaniel Hsu 
451*b602aad5SDaniel Hsu     auto success = i2cInterface.sendReceive(request, response);
452*b602aad5SDaniel Hsu     if (!success && response.size() != resSize)
453*b602aad5SDaniel Hsu     {
454*b602aad5SDaniel Hsu         co_return false;
455*b602aad5SDaniel Hsu     }
456*b602aad5SDaniel Hsu     busyFlag = response.at(0);
457*b602aad5SDaniel Hsu     co_return true;
458*b602aad5SDaniel Hsu }
459*b602aad5SDaniel Hsu 
readStatusReg(uint8_t & statusReg)460*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::readStatusReg(uint8_t& statusReg)
461*b602aad5SDaniel Hsu {
462*b602aad5SDaniel Hsu     std::vector<uint8_t> request = {commandReadStatusReg, 0x0, 0x0, 0x0};
463*b602aad5SDaniel Hsu     std::vector<uint8_t> response(4, 0);
464*b602aad5SDaniel Hsu 
465*b602aad5SDaniel Hsu     if (!i2cInterface.sendReceive(request, response))
466*b602aad5SDaniel Hsu     {
467*b602aad5SDaniel Hsu         lg2::error("Failed to send read status register request.");
468*b602aad5SDaniel Hsu         co_return false;
469*b602aad5SDaniel Hsu     }
470*b602aad5SDaniel Hsu     /*
471*b602aad5SDaniel Hsu     Read Status Register
472*b602aad5SDaniel Hsu     [LSC_READ_STATUS]
473*b602aad5SDaniel Hsu     0x3C 00 00 00 N/A YY YY YY YY Bit 1 0
474*b602aad5SDaniel Hsu     12 Busy Ready
475*b602aad5SDaniel Hsu     13 Fail OK
476*b602aad5SDaniel Hsu     */
477*b602aad5SDaniel Hsu     statusReg = response.at(2);
478*b602aad5SDaniel Hsu     co_return true;
479*b602aad5SDaniel Hsu }
480*b602aad5SDaniel Hsu 
getVersion(std::string & version)481*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeBaseCPLD::getVersion(std::string& version)
482*b602aad5SDaniel Hsu {
483*b602aad5SDaniel Hsu     auto userCode = std::make_unique<uint32_t>(0);
484*b602aad5SDaniel Hsu 
485*b602aad5SDaniel Hsu     if (target.empty())
486*b602aad5SDaniel Hsu     {
487*b602aad5SDaniel Hsu         if (!(co_await readUserCode(*userCode)))
488*b602aad5SDaniel Hsu         {
489*b602aad5SDaniel Hsu             lg2::error("Read usercode failed.");
490*b602aad5SDaniel Hsu             co_return false;
491*b602aad5SDaniel Hsu         }
492*b602aad5SDaniel Hsu 
493*b602aad5SDaniel Hsu         lg2::debug("CPLD version: {VERSION}", "VERSION", *userCode);
494*b602aad5SDaniel Hsu     }
495*b602aad5SDaniel Hsu     else if (target == "CFG0" || target == "CFG1")
496*b602aad5SDaniel Hsu     {
497*b602aad5SDaniel Hsu         isLCMXO3D = true;
498*b602aad5SDaniel Hsu         co_await waitBusyAndVerify();
499*b602aad5SDaniel Hsu 
500*b602aad5SDaniel Hsu         if (!(co_await enableProgramMode()))
501*b602aad5SDaniel Hsu         {
502*b602aad5SDaniel Hsu             lg2::error("Enable program mode failed.");
503*b602aad5SDaniel Hsu             co_return false;
504*b602aad5SDaniel Hsu         }
505*b602aad5SDaniel Hsu 
506*b602aad5SDaniel Hsu         if (!(co_await resetConfigFlash()))
507*b602aad5SDaniel Hsu         {
508*b602aad5SDaniel Hsu             lg2::error("Reset config flash failed.");
509*b602aad5SDaniel Hsu             co_return false;
510*b602aad5SDaniel Hsu         }
511*b602aad5SDaniel Hsu 
512*b602aad5SDaniel Hsu         if (!(co_await readUserCode(*userCode)))
513*b602aad5SDaniel Hsu         {
514*b602aad5SDaniel Hsu             lg2::error("Read usercode failed.");
515*b602aad5SDaniel Hsu             co_return false;
516*b602aad5SDaniel Hsu         }
517*b602aad5SDaniel Hsu 
518*b602aad5SDaniel Hsu         if (!(co_await programDone()))
519*b602aad5SDaniel Hsu         {
520*b602aad5SDaniel Hsu             lg2::error("Program not done.");
521*b602aad5SDaniel Hsu             co_return false;
522*b602aad5SDaniel Hsu         }
523*b602aad5SDaniel Hsu 
524*b602aad5SDaniel Hsu         if (!(co_await disableConfigInterface()))
525*b602aad5SDaniel Hsu         {
526*b602aad5SDaniel Hsu             lg2::error("Disable Config Interface failed.");
527*b602aad5SDaniel Hsu             co_return false;
528*b602aad5SDaniel Hsu         }
529*b602aad5SDaniel Hsu 
530*b602aad5SDaniel Hsu         lg2::debug("CPLD {TARGET} version: {VERSION}", "TARGET", target,
531*b602aad5SDaniel Hsu                    "VERSION", *userCode);
532*b602aad5SDaniel Hsu     }
533*b602aad5SDaniel Hsu     else
534*b602aad5SDaniel Hsu     {
535*b602aad5SDaniel Hsu         lg2::error("Error: unknown target.");
536*b602aad5SDaniel Hsu         co_return false;
537*b602aad5SDaniel Hsu     }
538*b602aad5SDaniel Hsu 
539*b602aad5SDaniel Hsu     if (*userCode == 0)
540*b602aad5SDaniel Hsu     {
541*b602aad5SDaniel Hsu         lg2::error("User code is zero, cannot get version.");
542*b602aad5SDaniel Hsu         co_return false;
543*b602aad5SDaniel Hsu     }
544*b602aad5SDaniel Hsu     version = uint32ToHexStr(*userCode);
545*b602aad5SDaniel Hsu     co_return true;
546*b602aad5SDaniel Hsu }
547*b602aad5SDaniel Hsu 
548*b602aad5SDaniel Hsu } // namespace phosphor::software::cpld
549