xref: /openbmc/phosphor-bmc-code-mgmt/cpld/lattice/lattice_xo5_cpld.cpp (revision a3902c83e3b65c3612e419cc1e616c56be65ff41)
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