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