1*a3902c83SDaniel Hsu #include "lattice_xo5_cpld.hpp"
2*a3902c83SDaniel Hsu
3*a3902c83SDaniel Hsu #include <phosphor-logging/lg2.hpp>
4*a3902c83SDaniel Hsu
5*a3902c83SDaniel Hsu namespace phosphor::software::cpld
6*a3902c83SDaniel Hsu {
7*a3902c83SDaniel Hsu
8*a3902c83SDaniel Hsu constexpr std::chrono::milliseconds ReadyPollInterval(10);
9*a3902c83SDaniel Hsu constexpr std::chrono::milliseconds ReadyTimeout(1000);
10*a3902c83SDaniel Hsu
11*a3902c83SDaniel Hsu enum class xo5Cmd : uint8_t
12*a3902c83SDaniel Hsu {
13*a3902c83SDaniel Hsu sectorErase = 0xd8,
14*a3902c83SDaniel Hsu pageProgram = 0x02,
15*a3902c83SDaniel Hsu pageRead = 0x0b,
16*a3902c83SDaniel Hsu readUsercode = 0xc0
17*a3902c83SDaniel Hsu };
18*a3902c83SDaniel Hsu
19*a3902c83SDaniel Hsu enum class xo5Status : uint8_t
20*a3902c83SDaniel Hsu {
21*a3902c83SDaniel Hsu ready = 0x00,
22*a3902c83SDaniel Hsu notReady = 0xff
23*a3902c83SDaniel Hsu };
24*a3902c83SDaniel Hsu
25*a3902c83SDaniel Hsu struct xo5Cfg
26*a3902c83SDaniel Hsu {
27*a3902c83SDaniel Hsu static constexpr size_t pageSize = 256;
28*a3902c83SDaniel Hsu static constexpr size_t pagesPerBlock = 256;
29*a3902c83SDaniel Hsu static constexpr size_t blocksPerCfg = 11;
30*a3902c83SDaniel Hsu };
31*a3902c83SDaniel Hsu
getStartBlock(uint8_t cfg,uint8_t & startBlock)32*a3902c83SDaniel Hsu static bool getStartBlock(uint8_t cfg, uint8_t& startBlock)
33*a3902c83SDaniel Hsu {
34*a3902c83SDaniel Hsu static constexpr std::array<uint8_t, 3> cfgStartBlocks = {0x01, 0x10, 0x1F};
35*a3902c83SDaniel Hsu
36*a3902c83SDaniel Hsu if (cfg >= cfgStartBlocks.size())
37*a3902c83SDaniel Hsu {
38*a3902c83SDaniel Hsu return false;
39*a3902c83SDaniel Hsu }
40*a3902c83SDaniel Hsu
41*a3902c83SDaniel Hsu startBlock = cfgStartBlocks[cfg];
42*a3902c83SDaniel Hsu return true;
43*a3902c83SDaniel Hsu }
44*a3902c83SDaniel Hsu
waitUntilReady(std::chrono::milliseconds timeout)45*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::waitUntilReady(
46*a3902c83SDaniel Hsu std::chrono::milliseconds timeout)
47*a3902c83SDaniel Hsu {
48*a3902c83SDaniel Hsu const auto endTime = std::chrono::steady_clock::now() + timeout;
49*a3902c83SDaniel Hsu
50*a3902c83SDaniel Hsu auto readDummy = [this]() -> sdbusplus::async::task<bool> {
51*a3902c83SDaniel Hsu std::vector<uint8_t> request = {};
52*a3902c83SDaniel Hsu std::vector<uint8_t> response = {0xff};
53*a3902c83SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
54*a3902c83SDaniel Hsu {
55*a3902c83SDaniel Hsu lg2::error("Failed to read.");
56*a3902c83SDaniel Hsu co_return false;
57*a3902c83SDaniel Hsu }
58*a3902c83SDaniel Hsu if (response.at(0) == static_cast<uint8_t>(xo5Status::ready))
59*a3902c83SDaniel Hsu {
60*a3902c83SDaniel Hsu co_return true;
61*a3902c83SDaniel Hsu }
62*a3902c83SDaniel Hsu co_return false;
63*a3902c83SDaniel Hsu };
64*a3902c83SDaniel Hsu
65*a3902c83SDaniel Hsu while (std::chrono::steady_clock::now() < endTime)
66*a3902c83SDaniel Hsu {
67*a3902c83SDaniel Hsu if (co_await readDummy())
68*a3902c83SDaniel Hsu {
69*a3902c83SDaniel Hsu co_return true;
70*a3902c83SDaniel Hsu }
71*a3902c83SDaniel Hsu co_await sdbusplus::async::sleep_for(ctx, ReadyPollInterval);
72*a3902c83SDaniel Hsu }
73*a3902c83SDaniel Hsu
74*a3902c83SDaniel Hsu lg2::error("Timeout waiting for device ready");
75*a3902c83SDaniel Hsu co_return false;
76*a3902c83SDaniel Hsu }
77*a3902c83SDaniel Hsu
eraseCfg()78*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::eraseCfg()
79*a3902c83SDaniel Hsu {
80*a3902c83SDaniel Hsu auto cfgIndex = (target == "CFG0") ? 0 : 1;
81*a3902c83SDaniel Hsu uint8_t startBlock;
82*a3902c83SDaniel Hsu if (!getStartBlock(cfgIndex, startBlock))
83*a3902c83SDaniel Hsu {
84*a3902c83SDaniel Hsu lg2::error("Error: invalid cfg index.");
85*a3902c83SDaniel Hsu co_return false;
86*a3902c83SDaniel Hsu }
87*a3902c83SDaniel Hsu const auto endBlock = startBlock + xo5Cfg::blocksPerCfg;
88*a3902c83SDaniel Hsu
89*a3902c83SDaniel Hsu auto eraseBlock = [this](uint8_t block) -> sdbusplus::async::task<bool> {
90*a3902c83SDaniel Hsu std::vector<uint8_t> request;
91*a3902c83SDaniel Hsu std::vector<uint8_t> response = {};
92*a3902c83SDaniel Hsu request.reserve(4);
93*a3902c83SDaniel Hsu request.push_back(static_cast<uint8_t>(xo5Cmd::sectorErase));
94*a3902c83SDaniel Hsu request.push_back(block);
95*a3902c83SDaniel Hsu request.push_back(0x0);
96*a3902c83SDaniel Hsu request.push_back(0x0);
97*a3902c83SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
98*a3902c83SDaniel Hsu {
99*a3902c83SDaniel Hsu lg2::error("Failed to erase block");
100*a3902c83SDaniel Hsu co_return false;
101*a3902c83SDaniel Hsu }
102*a3902c83SDaniel Hsu co_return true;
103*a3902c83SDaniel Hsu };
104*a3902c83SDaniel Hsu
105*a3902c83SDaniel Hsu for (size_t block = startBlock; block < endBlock; ++block)
106*a3902c83SDaniel Hsu {
107*a3902c83SDaniel Hsu if (!(co_await eraseBlock(block)))
108*a3902c83SDaniel Hsu {
109*a3902c83SDaniel Hsu lg2::error("Erase failed: Block {BLOCK}", "BLOCK", block);
110*a3902c83SDaniel Hsu co_return false;
111*a3902c83SDaniel Hsu }
112*a3902c83SDaniel Hsu if (!(co_await waitUntilReady(ReadyTimeout)))
113*a3902c83SDaniel Hsu {
114*a3902c83SDaniel Hsu lg2::error("Failed to wait until ready");
115*a3902c83SDaniel Hsu co_return false;
116*a3902c83SDaniel Hsu }
117*a3902c83SDaniel Hsu }
118*a3902c83SDaniel Hsu co_return true;
119*a3902c83SDaniel Hsu }
120*a3902c83SDaniel Hsu
programPage(uint8_t block,uint8_t page,const std::vector<uint8_t> & data)121*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::programPage(
122*a3902c83SDaniel Hsu uint8_t block, uint8_t page, const std::vector<uint8_t>& data)
123*a3902c83SDaniel Hsu {
124*a3902c83SDaniel Hsu std::vector<uint8_t> request;
125*a3902c83SDaniel Hsu std::vector<uint8_t> response = {};
126*a3902c83SDaniel Hsu request.reserve(4 + data.size());
127*a3902c83SDaniel Hsu request.push_back(static_cast<uint8_t>(xo5Cmd::pageProgram));
128*a3902c83SDaniel Hsu request.push_back(block);
129*a3902c83SDaniel Hsu request.push_back(page);
130*a3902c83SDaniel Hsu request.push_back(0x0);
131*a3902c83SDaniel Hsu request.insert(request.end(), data.begin(), data.end());
132*a3902c83SDaniel Hsu
133*a3902c83SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
134*a3902c83SDaniel Hsu {
135*a3902c83SDaniel Hsu co_return false;
136*a3902c83SDaniel Hsu }
137*a3902c83SDaniel Hsu co_return true;
138*a3902c83SDaniel Hsu }
139*a3902c83SDaniel Hsu
programCfg()140*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::programCfg()
141*a3902c83SDaniel Hsu {
142*a3902c83SDaniel Hsu using diff_t = std::vector<uint8_t>::difference_type;
143*a3902c83SDaniel Hsu
144*a3902c83SDaniel Hsu auto cfgIndex = (target == "CFG0") ? 0 : 1;
145*a3902c83SDaniel Hsu uint8_t startBlock;
146*a3902c83SDaniel Hsu if (!getStartBlock(cfgIndex, startBlock))
147*a3902c83SDaniel Hsu {
148*a3902c83SDaniel Hsu lg2::error("Error: invalid cfg index.");
149*a3902c83SDaniel Hsu co_return false;
150*a3902c83SDaniel Hsu }
151*a3902c83SDaniel Hsu const auto endBlock = startBlock + xo5Cfg::blocksPerCfg;
152*a3902c83SDaniel Hsu const auto& cfgData = fwInfo.cfgData;
153*a3902c83SDaniel Hsu const auto totalBytes = cfgData.size();
154*a3902c83SDaniel Hsu size_t bytesWritten = 0;
155*a3902c83SDaniel Hsu
156*a3902c83SDaniel Hsu for (size_t block = startBlock; block < endBlock; ++block)
157*a3902c83SDaniel Hsu {
158*a3902c83SDaniel Hsu for (size_t page = 0; page < xo5Cfg::pagesPerBlock; ++page)
159*a3902c83SDaniel Hsu {
160*a3902c83SDaniel Hsu if (bytesWritten >= totalBytes)
161*a3902c83SDaniel Hsu {
162*a3902c83SDaniel Hsu co_return true;
163*a3902c83SDaniel Hsu }
164*a3902c83SDaniel Hsu
165*a3902c83SDaniel Hsu auto offset = static_cast<diff_t>(bytesWritten);
166*a3902c83SDaniel Hsu auto remaining = static_cast<diff_t>(totalBytes - bytesWritten);
167*a3902c83SDaniel Hsu const auto chunkSize =
168*a3902c83SDaniel Hsu std::min(static_cast<diff_t>(xo5Cfg::pageSize), remaining);
169*a3902c83SDaniel Hsu std::vector<uint8_t> chunk(
170*a3902c83SDaniel Hsu std::next(cfgData.begin(), offset),
171*a3902c83SDaniel Hsu std::next(cfgData.begin(), offset + chunkSize));
172*a3902c83SDaniel Hsu
173*a3902c83SDaniel Hsu auto success = false;
174*a3902c83SDaniel Hsu success |= co_await programPage(block, page, chunk);
175*a3902c83SDaniel Hsu co_await sdbusplus::async::sleep_for(ctx, ReadyPollInterval);
176*a3902c83SDaniel Hsu success |= co_await waitUntilReady(ReadyTimeout);
177*a3902c83SDaniel Hsu if (!success)
178*a3902c83SDaniel Hsu {
179*a3902c83SDaniel Hsu lg2::error("Failed to program block {BLOCK} page {PAGE}",
180*a3902c83SDaniel Hsu "BLOCK", block, "PAGE", page);
181*a3902c83SDaniel Hsu co_return false;
182*a3902c83SDaniel Hsu }
183*a3902c83SDaniel Hsu bytesWritten += chunkSize;
184*a3902c83SDaniel Hsu }
185*a3902c83SDaniel Hsu }
186*a3902c83SDaniel Hsu
187*a3902c83SDaniel Hsu co_return true;
188*a3902c83SDaniel Hsu }
189*a3902c83SDaniel Hsu
readPage(uint8_t block,uint8_t page,std::vector<uint8_t> & data)190*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::readPage(
191*a3902c83SDaniel Hsu uint8_t block, uint8_t page, std::vector<uint8_t>& data)
192*a3902c83SDaniel Hsu {
193*a3902c83SDaniel Hsu if (data.empty())
194*a3902c83SDaniel Hsu {
195*a3902c83SDaniel Hsu lg2::error("Error: data vector is empty.");
196*a3902c83SDaniel Hsu co_return false;
197*a3902c83SDaniel Hsu }
198*a3902c83SDaniel Hsu std::vector<uint8_t> request = {};
199*a3902c83SDaniel Hsu std::vector<uint8_t> response = {};
200*a3902c83SDaniel Hsu request.reserve(4);
201*a3902c83SDaniel Hsu request.push_back(static_cast<uint8_t>(xo5Cmd::pageRead));
202*a3902c83SDaniel Hsu request.push_back(block);
203*a3902c83SDaniel Hsu request.push_back(page);
204*a3902c83SDaniel Hsu request.push_back(0x0);
205*a3902c83SDaniel Hsu
206*a3902c83SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
207*a3902c83SDaniel Hsu {
208*a3902c83SDaniel Hsu co_return false;
209*a3902c83SDaniel Hsu }
210*a3902c83SDaniel Hsu lg2::debug("Read page {BLOCK} {PAGE} succeeded", "BLOCK", block, "PAGE",
211*a3902c83SDaniel Hsu page);
212*a3902c83SDaniel Hsu request.clear();
213*a3902c83SDaniel Hsu
214*a3902c83SDaniel Hsu std::this_thread::sleep_for(std::chrono::milliseconds(1));
215*a3902c83SDaniel Hsu
216*a3902c83SDaniel Hsu if (!(co_await waitUntilReady(ReadyTimeout)))
217*a3902c83SDaniel Hsu {
218*a3902c83SDaniel Hsu co_return false;
219*a3902c83SDaniel Hsu }
220*a3902c83SDaniel Hsu
221*a3902c83SDaniel Hsu if (!i2cInterface.sendReceive(request, data))
222*a3902c83SDaniel Hsu {
223*a3902c83SDaniel Hsu co_return false;
224*a3902c83SDaniel Hsu }
225*a3902c83SDaniel Hsu
226*a3902c83SDaniel Hsu co_return data[0] == static_cast<uint8_t>(xo5Status::ready);
227*a3902c83SDaniel Hsu }
228*a3902c83SDaniel Hsu
verifyCfg()229*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::verifyCfg()
230*a3902c83SDaniel Hsu {
231*a3902c83SDaniel Hsu using diff_t = std::vector<uint8_t>::difference_type;
232*a3902c83SDaniel Hsu
233*a3902c83SDaniel Hsu auto cfgIndex = (target == "CFG0") ? 0 : 1;
234*a3902c83SDaniel Hsu uint8_t startBlock;
235*a3902c83SDaniel Hsu if (!getStartBlock(cfgIndex, startBlock))
236*a3902c83SDaniel Hsu {
237*a3902c83SDaniel Hsu lg2::error("Error: invalid cfg index.");
238*a3902c83SDaniel Hsu co_return false;
239*a3902c83SDaniel Hsu }
240*a3902c83SDaniel Hsu const auto endBlock = startBlock + xo5Cfg::blocksPerCfg;
241*a3902c83SDaniel Hsu const auto& cfgData = fwInfo.cfgData;
242*a3902c83SDaniel Hsu const auto totalBytes = cfgData.size();
243*a3902c83SDaniel Hsu uint8_t readBuffer[1 + xo5Cfg::pageSize];
244*a3902c83SDaniel Hsu size_t bytesVerified = 0;
245*a3902c83SDaniel Hsu
246*a3902c83SDaniel Hsu for (size_t block = startBlock; block < endBlock; ++block)
247*a3902c83SDaniel Hsu {
248*a3902c83SDaniel Hsu for (size_t page = 0; page < xo5Cfg::pagesPerBlock; ++page)
249*a3902c83SDaniel Hsu {
250*a3902c83SDaniel Hsu if (bytesVerified >= totalBytes)
251*a3902c83SDaniel Hsu {
252*a3902c83SDaniel Hsu co_return true;
253*a3902c83SDaniel Hsu }
254*a3902c83SDaniel Hsu
255*a3902c83SDaniel Hsu auto offset = static_cast<diff_t>(bytesVerified);
256*a3902c83SDaniel Hsu auto remaining = static_cast<diff_t>(totalBytes - bytesVerified);
257*a3902c83SDaniel Hsu const auto chunkSize =
258*a3902c83SDaniel Hsu std::min(static_cast<diff_t>(xo5Cfg::pageSize), remaining);
259*a3902c83SDaniel Hsu
260*a3902c83SDaniel Hsu std::vector<uint8_t> expected(
261*a3902c83SDaniel Hsu std::next(cfgData.begin(), offset),
262*a3902c83SDaniel Hsu std::next(cfgData.begin(), offset + chunkSize));
263*a3902c83SDaniel Hsu
264*a3902c83SDaniel Hsu std::vector<uint8_t> chunk;
265*a3902c83SDaniel Hsu {
266*a3902c83SDaniel Hsu std::vector<uint8_t> readVec(readBuffer,
267*a3902c83SDaniel Hsu readBuffer + 1 + chunkSize);
268*a3902c83SDaniel Hsu
269*a3902c83SDaniel Hsu if (co_await readPage(block, page, readVec))
270*a3902c83SDaniel Hsu {
271*a3902c83SDaniel Hsu chunk.assign(readVec.begin() + 1, readVec.end());
272*a3902c83SDaniel Hsu }
273*a3902c83SDaniel Hsu else
274*a3902c83SDaniel Hsu {
275*a3902c83SDaniel Hsu chunk.clear();
276*a3902c83SDaniel Hsu }
277*a3902c83SDaniel Hsu }
278*a3902c83SDaniel Hsu
279*a3902c83SDaniel Hsu if (chunk.empty())
280*a3902c83SDaniel Hsu {
281*a3902c83SDaniel Hsu lg2::error("Failed to read Block {BLOCK} Page {PAGE}", "BLOCK",
282*a3902c83SDaniel Hsu block, "PAGE", page);
283*a3902c83SDaniel Hsu co_return false;
284*a3902c83SDaniel Hsu }
285*a3902c83SDaniel Hsu if (!std::equal(chunk.begin(), chunk.end(), expected.begin()))
286*a3902c83SDaniel Hsu {
287*a3902c83SDaniel Hsu lg2::error("VERIFY FAILED: Block {BLOCK} Page {PAGE}", "BLOCK",
288*a3902c83SDaniel Hsu block, "PAGE", page);
289*a3902c83SDaniel Hsu co_return false;
290*a3902c83SDaniel Hsu }
291*a3902c83SDaniel Hsu
292*a3902c83SDaniel Hsu bytesVerified += chunkSize;
293*a3902c83SDaniel Hsu }
294*a3902c83SDaniel Hsu }
295*a3902c83SDaniel Hsu co_return true;
296*a3902c83SDaniel Hsu }
297*a3902c83SDaniel Hsu
readUserCode(uint32_t & userCode)298*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::readUserCode(uint32_t& userCode)
299*a3902c83SDaniel Hsu {
300*a3902c83SDaniel Hsu constexpr size_t resSize = 5;
301*a3902c83SDaniel Hsu std::vector<uint8_t> request = {commandReadFwVersion, 0x0, 0x0, 0x0};
302*a3902c83SDaniel Hsu std::vector<uint8_t> response(resSize, 0);
303*a3902c83SDaniel Hsu
304*a3902c83SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
305*a3902c83SDaniel Hsu {
306*a3902c83SDaniel Hsu lg2::error("Failed to send read user code request.");
307*a3902c83SDaniel Hsu co_return false;
308*a3902c83SDaniel Hsu }
309*a3902c83SDaniel Hsu
310*a3902c83SDaniel Hsu userCode |= response[4] << 24;
311*a3902c83SDaniel Hsu userCode |= response[3] << 16;
312*a3902c83SDaniel Hsu userCode |= response[2] << 8;
313*a3902c83SDaniel Hsu userCode |= response[1];
314*a3902c83SDaniel Hsu
315*a3902c83SDaniel Hsu co_return true;
316*a3902c83SDaniel Hsu }
317*a3902c83SDaniel Hsu
prepareUpdate(const uint8_t * image,size_t imageSize)318*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::prepareUpdate(const uint8_t* image,
319*a3902c83SDaniel Hsu size_t imageSize)
320*a3902c83SDaniel Hsu {
321*a3902c83SDaniel Hsu if (target.empty())
322*a3902c83SDaniel Hsu {
323*a3902c83SDaniel Hsu target = "CFG0";
324*a3902c83SDaniel Hsu }
325*a3902c83SDaniel Hsu else if (target != "CFG0" && target != "CFG1")
326*a3902c83SDaniel Hsu {
327*a3902c83SDaniel Hsu lg2::error("Error: unknown target.");
328*a3902c83SDaniel Hsu co_return false;
329*a3902c83SDaniel Hsu }
330*a3902c83SDaniel Hsu
331*a3902c83SDaniel Hsu if (!jedFileParser(image, imageSize))
332*a3902c83SDaniel Hsu {
333*a3902c83SDaniel Hsu lg2::error("JED file parsing failed");
334*a3902c83SDaniel Hsu co_return false;
335*a3902c83SDaniel Hsu }
336*a3902c83SDaniel Hsu lg2::debug("JED file parsing success");
337*a3902c83SDaniel Hsu
338*a3902c83SDaniel Hsu if (!(co_await waitUntilReady(ReadyTimeout)))
339*a3902c83SDaniel Hsu {
340*a3902c83SDaniel Hsu lg2::error("Error: Device not ready.");
341*a3902c83SDaniel Hsu co_return false;
342*a3902c83SDaniel Hsu }
343*a3902c83SDaniel Hsu
344*a3902c83SDaniel Hsu co_return true;
345*a3902c83SDaniel Hsu }
346*a3902c83SDaniel Hsu
doUpdate()347*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::doUpdate()
348*a3902c83SDaniel Hsu {
349*a3902c83SDaniel Hsu lg2::debug("Erasing {TARGET}...", "TARGET", target);
350*a3902c83SDaniel Hsu if (!(co_await eraseCfg()))
351*a3902c83SDaniel Hsu {
352*a3902c83SDaniel Hsu lg2::error("Erase cfg data failed.");
353*a3902c83SDaniel Hsu co_return false;
354*a3902c83SDaniel Hsu }
355*a3902c83SDaniel Hsu
356*a3902c83SDaniel Hsu lg2::debug("Programming {TARGET}...", "TARGET", target);
357*a3902c83SDaniel Hsu if (!(co_await programCfg()))
358*a3902c83SDaniel Hsu {
359*a3902c83SDaniel Hsu lg2::error("Program cfg data failed.");
360*a3902c83SDaniel Hsu co_return false;
361*a3902c83SDaniel Hsu }
362*a3902c83SDaniel Hsu
363*a3902c83SDaniel Hsu co_return true;
364*a3902c83SDaniel Hsu }
365*a3902c83SDaniel Hsu
finishUpdate()366*a3902c83SDaniel Hsu sdbusplus::async::task<bool> LatticeXO5CPLD::finishUpdate()
367*a3902c83SDaniel Hsu {
368*a3902c83SDaniel Hsu lg2::debug("Verifying {TARGET}...", "TARGET", target);
369*a3902c83SDaniel Hsu if (!(co_await verifyCfg()))
370*a3902c83SDaniel Hsu {
371*a3902c83SDaniel Hsu lg2::error("Verify cfg data failed.");
372*a3902c83SDaniel Hsu co_return false;
373*a3902c83SDaniel Hsu }
374*a3902c83SDaniel Hsu co_return true;
375*a3902c83SDaniel Hsu }
376*a3902c83SDaniel Hsu
377*a3902c83SDaniel Hsu } // namespace phosphor::software::cpld
378