1*b602aad5SDaniel Hsu #include "lattice_xo3_cpld.hpp"
2*b602aad5SDaniel Hsu
3*b602aad5SDaniel Hsu #include <phosphor-logging/lg2.hpp>
4*b602aad5SDaniel Hsu
5*b602aad5SDaniel Hsu #include <fstream>
6*b602aad5SDaniel Hsu #include <vector>
7*b602aad5SDaniel Hsu
8*b602aad5SDaniel Hsu namespace phosphor::software::cpld
9*b602aad5SDaniel Hsu {
10*b602aad5SDaniel Hsu
readDeviceId()11*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::readDeviceId()
12*b602aad5SDaniel Hsu {
13*b602aad5SDaniel Hsu std::vector<uint8_t> request = {commandReadDeviceId, 0x0, 0x0, 0x0};
14*b602aad5SDaniel Hsu std::vector<uint8_t> response = {0, 0, 0, 0};
15*b602aad5SDaniel Hsu
16*b602aad5SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
17*b602aad5SDaniel Hsu {
18*b602aad5SDaniel Hsu lg2::error(
19*b602aad5SDaniel Hsu "Fail to read device Id. Please check the I2C bus and address.");
20*b602aad5SDaniel Hsu co_return false;
21*b602aad5SDaniel Hsu }
22*b602aad5SDaniel Hsu
23*b602aad5SDaniel Hsu auto chipWantToUpdate = std::find_if(
24*b602aad5SDaniel Hsu supportedDeviceMap.begin(), supportedDeviceMap.end(),
25*b602aad5SDaniel Hsu [this](const auto& pair) {
26*b602aad5SDaniel Hsu auto chipModel =
27*b602aad5SDaniel Hsu getLatticeChipStr(pair.first, latticeStringType::modelString);
28*b602aad5SDaniel Hsu return chipModel == this->chip;
29*b602aad5SDaniel Hsu });
30*b602aad5SDaniel Hsu
31*b602aad5SDaniel Hsu if (chipWantToUpdate != supportedDeviceMap.end() &&
32*b602aad5SDaniel Hsu chipWantToUpdate->second.deviceId == response)
33*b602aad5SDaniel Hsu {
34*b602aad5SDaniel Hsu if (chip.rfind("LCMXO3D", 0) == 0)
35*b602aad5SDaniel Hsu {
36*b602aad5SDaniel Hsu isLCMXO3D = true;
37*b602aad5SDaniel Hsu if (!target.empty() && target != "CFG0" && target != "CFG1")
38*b602aad5SDaniel Hsu {
39*b602aad5SDaniel Hsu lg2::error("Unknown target. Only CFG0 and CFG1 are supported.");
40*b602aad5SDaniel Hsu co_return false;
41*b602aad5SDaniel Hsu }
42*b602aad5SDaniel Hsu }
43*b602aad5SDaniel Hsu
44*b602aad5SDaniel Hsu lg2::debug("Device ID match with chip. Chip name: {CHIPNAME}",
45*b602aad5SDaniel Hsu "CHIPNAME", chip);
46*b602aad5SDaniel Hsu co_return true;
47*b602aad5SDaniel Hsu }
48*b602aad5SDaniel Hsu
49*b602aad5SDaniel Hsu lg2::error("The device id doesn't match with chip.");
50*b602aad5SDaniel Hsu co_return false;
51*b602aad5SDaniel Hsu }
52*b602aad5SDaniel Hsu
eraseFlash()53*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::eraseFlash()
54*b602aad5SDaniel Hsu {
55*b602aad5SDaniel Hsu std::vector<uint8_t> request;
56*b602aad5SDaniel Hsu std::vector<uint8_t> response;
57*b602aad5SDaniel Hsu
58*b602aad5SDaniel Hsu if (isLCMXO3D)
59*b602aad5SDaniel Hsu {
60*b602aad5SDaniel Hsu /*
61*b602aad5SDaniel Hsu Erase the different internal
62*b602aad5SDaniel Hsu memories. The bit in YYY defines
63*b602aad5SDaniel Hsu which memory is erased in Flash
64*b602aad5SDaniel Hsu access mode.
65*b602aad5SDaniel Hsu Bit 1=Enable
66*b602aad5SDaniel Hsu 8 Erase CFG0
67*b602aad5SDaniel Hsu 9 Erase CFG1
68*b602aad5SDaniel Hsu 10 Erase UFM0
69*b602aad5SDaniel Hsu 11 Erase UFM1
70*b602aad5SDaniel Hsu 12 Erase UFM2
71*b602aad5SDaniel Hsu 13 Erase UFM3
72*b602aad5SDaniel Hsu 14 Erase CSEC
73*b602aad5SDaniel Hsu 15 Erase USEC
74*b602aad5SDaniel Hsu 16 Erase PUBKEY
75*b602aad5SDaniel Hsu 17 Erase AESKEY
76*b602aad5SDaniel Hsu 18 Erase FEA
77*b602aad5SDaniel Hsu 19 Reserved
78*b602aad5SDaniel Hsu commandEraseFlash = 0x0E, 0Y YY 00
79*b602aad5SDaniel Hsu */
80*b602aad5SDaniel Hsu if (target.empty() || target == "CFG0")
81*b602aad5SDaniel Hsu {
82*b602aad5SDaniel Hsu request = {commandEraseFlash, 0x00, 0x01, 0x00};
83*b602aad5SDaniel Hsu }
84*b602aad5SDaniel Hsu else if (target == "CFG1")
85*b602aad5SDaniel Hsu {
86*b602aad5SDaniel Hsu request = {commandEraseFlash, 0x00, 0x02, 0x00};
87*b602aad5SDaniel Hsu }
88*b602aad5SDaniel Hsu else
89*b602aad5SDaniel Hsu {
90*b602aad5SDaniel Hsu lg2::error("Error: unknown target.");
91*b602aad5SDaniel Hsu co_return false;
92*b602aad5SDaniel Hsu }
93*b602aad5SDaniel Hsu }
94*b602aad5SDaniel Hsu else
95*b602aad5SDaniel Hsu {
96*b602aad5SDaniel Hsu request = {commandEraseFlash, 0xC, 0x0, 0x0};
97*b602aad5SDaniel Hsu }
98*b602aad5SDaniel Hsu
99*b602aad5SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
100*b602aad5SDaniel Hsu {
101*b602aad5SDaniel Hsu lg2::error("Failed to send erase flash request.");
102*b602aad5SDaniel Hsu co_return false;
103*b602aad5SDaniel Hsu }
104*b602aad5SDaniel Hsu
105*b602aad5SDaniel Hsu if (!(co_await waitBusyAndVerify()))
106*b602aad5SDaniel Hsu {
107*b602aad5SDaniel Hsu lg2::error("Wait busy and verify fail");
108*b602aad5SDaniel Hsu co_return false;
109*b602aad5SDaniel Hsu }
110*b602aad5SDaniel Hsu co_await sdbusplus::async::sleep_for(ctx, waitBusyTime);
111*b602aad5SDaniel Hsu co_return true;
112*b602aad5SDaniel Hsu }
113*b602aad5SDaniel Hsu
writeProgramPage()114*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::writeProgramPage()
115*b602aad5SDaniel Hsu {
116*b602aad5SDaniel Hsu /*
117*b602aad5SDaniel Hsu Program one NVCM/Flash page. Can be
118*b602aad5SDaniel Hsu used to program the NVCM0/CFG or
119*b602aad5SDaniel Hsu NVCM1/UFM.
120*b602aad5SDaniel Hsu */
121*b602aad5SDaniel Hsu size_t iterSize = 16;
122*b602aad5SDaniel Hsu
123*b602aad5SDaniel Hsu for (size_t i = 0; (i * iterSize) < fwInfo.cfgData.size(); i++)
124*b602aad5SDaniel Hsu {
125*b602aad5SDaniel Hsu size_t byteOffset = i * iterSize;
126*b602aad5SDaniel Hsu double progressRate =
127*b602aad5SDaniel Hsu ((double(byteOffset) / double(fwInfo.cfgData.size())) * 100);
128*b602aad5SDaniel Hsu std::cout << "Update :" << std::fixed << std::dec
129*b602aad5SDaniel Hsu << std::setprecision(2) << progressRate << "% \r";
130*b602aad5SDaniel Hsu
131*b602aad5SDaniel Hsu uint8_t len = ((byteOffset + iterSize) < fwInfo.cfgData.size())
132*b602aad5SDaniel Hsu ? iterSize
133*b602aad5SDaniel Hsu : (fwInfo.cfgData.size() - byteOffset);
134*b602aad5SDaniel Hsu auto pageData = std::vector<uint8_t>(
135*b602aad5SDaniel Hsu fwInfo.cfgData.begin() + static_cast<std::ptrdiff_t>(byteOffset),
136*b602aad5SDaniel Hsu fwInfo.cfgData.begin() +
137*b602aad5SDaniel Hsu static_cast<std::ptrdiff_t>(byteOffset + len));
138*b602aad5SDaniel Hsu
139*b602aad5SDaniel Hsu size_t retry = 0;
140*b602aad5SDaniel Hsu const size_t maxWriteRetry = 10;
141*b602aad5SDaniel Hsu while (retry < maxWriteRetry)
142*b602aad5SDaniel Hsu {
143*b602aad5SDaniel Hsu if (!(co_await programSinglePage(i, pageData)))
144*b602aad5SDaniel Hsu {
145*b602aad5SDaniel Hsu retry++;
146*b602aad5SDaniel Hsu continue;
147*b602aad5SDaniel Hsu }
148*b602aad5SDaniel Hsu
149*b602aad5SDaniel Hsu if (!(co_await verifySinglePage(i, pageData)))
150*b602aad5SDaniel Hsu {
151*b602aad5SDaniel Hsu retry++;
152*b602aad5SDaniel Hsu continue;
153*b602aad5SDaniel Hsu }
154*b602aad5SDaniel Hsu
155*b602aad5SDaniel Hsu break;
156*b602aad5SDaniel Hsu }
157*b602aad5SDaniel Hsu
158*b602aad5SDaniel Hsu if (retry >= maxWriteRetry)
159*b602aad5SDaniel Hsu {
160*b602aad5SDaniel Hsu lg2::error("Program and verify page failed");
161*b602aad5SDaniel Hsu co_return false;
162*b602aad5SDaniel Hsu }
163*b602aad5SDaniel Hsu }
164*b602aad5SDaniel Hsu
165*b602aad5SDaniel Hsu if (!(co_await waitBusyAndVerify()))
166*b602aad5SDaniel Hsu {
167*b602aad5SDaniel Hsu lg2::error("Wait busy and verify fail");
168*b602aad5SDaniel Hsu co_return false;
169*b602aad5SDaniel Hsu }
170*b602aad5SDaniel Hsu
171*b602aad5SDaniel Hsu co_return true;
172*b602aad5SDaniel Hsu }
173*b602aad5SDaniel Hsu
readUserCode(uint32_t & userCode)174*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::readUserCode(uint32_t& userCode)
175*b602aad5SDaniel Hsu {
176*b602aad5SDaniel Hsu constexpr size_t resSize = 4;
177*b602aad5SDaniel Hsu std::vector<uint8_t> request = {commandReadFwVersion, 0x0, 0x0, 0x0};
178*b602aad5SDaniel Hsu std::vector<uint8_t> response(resSize, 0);
179*b602aad5SDaniel Hsu
180*b602aad5SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
181*b602aad5SDaniel Hsu {
182*b602aad5SDaniel Hsu lg2::error("Failed to send read user code request.");
183*b602aad5SDaniel Hsu co_return false;
184*b602aad5SDaniel Hsu }
185*b602aad5SDaniel Hsu
186*b602aad5SDaniel Hsu for (size_t i = 0; i < resSize; i++)
187*b602aad5SDaniel Hsu {
188*b602aad5SDaniel Hsu userCode |= response.at(i) << ((3 - i) * 8);
189*b602aad5SDaniel Hsu }
190*b602aad5SDaniel Hsu co_return true;
191*b602aad5SDaniel Hsu }
192*b602aad5SDaniel Hsu
programUserCode()193*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::programUserCode()
194*b602aad5SDaniel Hsu {
195*b602aad5SDaniel Hsu std::vector<uint8_t> request = {commandProgramUserCode, 0x0, 0x0, 0x0};
196*b602aad5SDaniel Hsu std::vector<uint8_t> response;
197*b602aad5SDaniel Hsu for (int i = 3; i >= 0; i--)
198*b602aad5SDaniel Hsu {
199*b602aad5SDaniel Hsu request.push_back((fwInfo.version >> (i * 8)) & 0xFF);
200*b602aad5SDaniel Hsu }
201*b602aad5SDaniel Hsu
202*b602aad5SDaniel Hsu if (!i2cInterface.sendReceive(request, response))
203*b602aad5SDaniel Hsu {
204*b602aad5SDaniel Hsu lg2::error("Failed to send program user code request.");
205*b602aad5SDaniel Hsu co_return false;
206*b602aad5SDaniel Hsu }
207*b602aad5SDaniel Hsu if (!(co_await waitBusyAndVerify()))
208*b602aad5SDaniel Hsu {
209*b602aad5SDaniel Hsu lg2::error("Wait busy and verify fail");
210*b602aad5SDaniel Hsu co_return false;
211*b602aad5SDaniel Hsu }
212*b602aad5SDaniel Hsu
213*b602aad5SDaniel Hsu co_return true;
214*b602aad5SDaniel Hsu }
215*b602aad5SDaniel Hsu
prepareUpdate(const uint8_t * image,size_t imageSize)216*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::prepareUpdate(const uint8_t* image,
217*b602aad5SDaniel Hsu size_t imageSize)
218*b602aad5SDaniel Hsu {
219*b602aad5SDaniel Hsu if (!(co_await readDeviceId()))
220*b602aad5SDaniel Hsu {
221*b602aad5SDaniel Hsu co_return false;
222*b602aad5SDaniel Hsu }
223*b602aad5SDaniel Hsu
224*b602aad5SDaniel Hsu if (!jedFileParser(image, imageSize))
225*b602aad5SDaniel Hsu {
226*b602aad5SDaniel Hsu lg2::error("JED file parsing failed");
227*b602aad5SDaniel Hsu co_return false;
228*b602aad5SDaniel Hsu }
229*b602aad5SDaniel Hsu lg2::debug("JED file parsing success");
230*b602aad5SDaniel Hsu
231*b602aad5SDaniel Hsu if (!verifyChecksum())
232*b602aad5SDaniel Hsu {
233*b602aad5SDaniel Hsu lg2::error("Checksum verification failed");
234*b602aad5SDaniel Hsu co_return false;
235*b602aad5SDaniel Hsu }
236*b602aad5SDaniel Hsu
237*b602aad5SDaniel Hsu if (!isLCMXO3D)
238*b602aad5SDaniel Hsu {
239*b602aad5SDaniel Hsu lg2::error("is not LCMXO3D");
240*b602aad5SDaniel Hsu }
241*b602aad5SDaniel Hsu
242*b602aad5SDaniel Hsu co_return true;
243*b602aad5SDaniel Hsu }
244*b602aad5SDaniel Hsu
doUpdate()245*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::doUpdate()
246*b602aad5SDaniel Hsu {
247*b602aad5SDaniel Hsu co_await waitBusyAndVerify();
248*b602aad5SDaniel Hsu
249*b602aad5SDaniel Hsu if (!(co_await enableProgramMode()))
250*b602aad5SDaniel Hsu {
251*b602aad5SDaniel Hsu lg2::error("Enable program mode failed.");
252*b602aad5SDaniel Hsu co_return false;
253*b602aad5SDaniel Hsu }
254*b602aad5SDaniel Hsu
255*b602aad5SDaniel Hsu if (!(co_await eraseFlash()))
256*b602aad5SDaniel Hsu {
257*b602aad5SDaniel Hsu lg2::error("Erase flash failed.");
258*b602aad5SDaniel Hsu co_return false;
259*b602aad5SDaniel Hsu }
260*b602aad5SDaniel Hsu
261*b602aad5SDaniel Hsu if (!(co_await resetConfigFlash()))
262*b602aad5SDaniel Hsu {
263*b602aad5SDaniel Hsu lg2::error("Reset config flash failed.");
264*b602aad5SDaniel Hsu co_return false;
265*b602aad5SDaniel Hsu }
266*b602aad5SDaniel Hsu
267*b602aad5SDaniel Hsu if (!(co_await writeProgramPage()))
268*b602aad5SDaniel Hsu {
269*b602aad5SDaniel Hsu lg2::error("Write program page failed.");
270*b602aad5SDaniel Hsu co_return false;
271*b602aad5SDaniel Hsu }
272*b602aad5SDaniel Hsu
273*b602aad5SDaniel Hsu if (!(co_await programUserCode()))
274*b602aad5SDaniel Hsu {
275*b602aad5SDaniel Hsu lg2::error("Program user code failed.");
276*b602aad5SDaniel Hsu co_return false;
277*b602aad5SDaniel Hsu }
278*b602aad5SDaniel Hsu
279*b602aad5SDaniel Hsu if (!(co_await programDone()))
280*b602aad5SDaniel Hsu {
281*b602aad5SDaniel Hsu lg2::error("Program not done.");
282*b602aad5SDaniel Hsu co_return false;
283*b602aad5SDaniel Hsu }
284*b602aad5SDaniel Hsu
285*b602aad5SDaniel Hsu co_return true;
286*b602aad5SDaniel Hsu }
287*b602aad5SDaniel Hsu
finishUpdate()288*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::finishUpdate()
289*b602aad5SDaniel Hsu {
290*b602aad5SDaniel Hsu // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Branch)
291*b602aad5SDaniel Hsu if (!(co_await disableConfigInterface()))
292*b602aad5SDaniel Hsu {
293*b602aad5SDaniel Hsu lg2::error("Disable Config Interface failed.");
294*b602aad5SDaniel Hsu co_return false;
295*b602aad5SDaniel Hsu }
296*b602aad5SDaniel Hsu
297*b602aad5SDaniel Hsu co_return true;
298*b602aad5SDaniel Hsu }
299*b602aad5SDaniel Hsu
programSinglePage(uint16_t pageOffset,std::span<const uint8_t> pageData)300*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::programSinglePage(
301*b602aad5SDaniel Hsu uint16_t pageOffset, std::span<const uint8_t> pageData)
302*b602aad5SDaniel Hsu {
303*b602aad5SDaniel Hsu // Set Page Offset
304*b602aad5SDaniel Hsu std::vector<uint8_t> emptyResp(0);
305*b602aad5SDaniel Hsu std::vector<uint8_t> setPageAddrCmd = {
306*b602aad5SDaniel Hsu commandSetPageAddress, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x00};
307*b602aad5SDaniel Hsu setPageAddrCmd[6] = static_cast<uint8_t>(pageOffset >> 8); // high byte
308*b602aad5SDaniel Hsu setPageAddrCmd[7] = static_cast<uint8_t>(pageOffset); // low byte
309*b602aad5SDaniel Hsu
310*b602aad5SDaniel Hsu // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Branch)
311*b602aad5SDaniel Hsu bool success = co_await i2cInterface.sendReceive(
312*b602aad5SDaniel Hsu setPageAddrCmd.data(), setPageAddrCmd.size(), nullptr, 0);
313*b602aad5SDaniel Hsu if (!success)
314*b602aad5SDaniel Hsu {
315*b602aad5SDaniel Hsu lg2::error("Write page address failed");
316*b602aad5SDaniel Hsu co_return false;
317*b602aad5SDaniel Hsu }
318*b602aad5SDaniel Hsu
319*b602aad5SDaniel Hsu // Write Page Data
320*b602aad5SDaniel Hsu constexpr uint8_t pageCount = 1;
321*b602aad5SDaniel Hsu std::vector<uint8_t> writeCmd = {commandProgramPage, 0x0, 0x0, pageCount};
322*b602aad5SDaniel Hsu writeCmd.insert(writeCmd.end(), pageData.begin(), pageData.end());
323*b602aad5SDaniel Hsu
324*b602aad5SDaniel Hsu success = co_await i2cInterface.sendReceive(writeCmd.data(),
325*b602aad5SDaniel Hsu writeCmd.size(), nullptr, 0);
326*b602aad5SDaniel Hsu if (!success)
327*b602aad5SDaniel Hsu {
328*b602aad5SDaniel Hsu lg2::error("Write page data failed");
329*b602aad5SDaniel Hsu co_return false;
330*b602aad5SDaniel Hsu }
331*b602aad5SDaniel Hsu
332*b602aad5SDaniel Hsu co_await sdbusplus::async::sleep_for(ctx, std::chrono::microseconds(200));
333*b602aad5SDaniel Hsu
334*b602aad5SDaniel Hsu if (!(co_await waitBusyAndVerify()))
335*b602aad5SDaniel Hsu {
336*b602aad5SDaniel Hsu lg2::error("Wait busy and verify fail");
337*b602aad5SDaniel Hsu co_return false;
338*b602aad5SDaniel Hsu }
339*b602aad5SDaniel Hsu
340*b602aad5SDaniel Hsu co_return true;
341*b602aad5SDaniel Hsu }
342*b602aad5SDaniel Hsu
verifySinglePage(uint16_t pageOffset,std::span<const uint8_t> pageData)343*b602aad5SDaniel Hsu sdbusplus::async::task<bool> LatticeXO3CPLD::verifySinglePage(
344*b602aad5SDaniel Hsu uint16_t pageOffset, std::span<const uint8_t> pageData)
345*b602aad5SDaniel Hsu {
346*b602aad5SDaniel Hsu // Set Page Offset
347*b602aad5SDaniel Hsu std::vector<uint8_t> emptyResp(0);
348*b602aad5SDaniel Hsu std::vector<uint8_t> setPageAddrCmd = {
349*b602aad5SDaniel Hsu commandSetPageAddress, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x00};
350*b602aad5SDaniel Hsu setPageAddrCmd[6] = static_cast<uint8_t>(pageOffset >> 8); // high byte
351*b602aad5SDaniel Hsu setPageAddrCmd[7] = static_cast<uint8_t>(pageOffset); // low byte
352*b602aad5SDaniel Hsu
353*b602aad5SDaniel Hsu if (!i2cInterface.sendReceive(setPageAddrCmd, emptyResp))
354*b602aad5SDaniel Hsu {
355*b602aad5SDaniel Hsu lg2::error("Write page address failed");
356*b602aad5SDaniel Hsu co_return false;
357*b602aad5SDaniel Hsu }
358*b602aad5SDaniel Hsu
359*b602aad5SDaniel Hsu // Read Page Data
360*b602aad5SDaniel Hsu constexpr uint8_t pageCount = 1;
361*b602aad5SDaniel Hsu std::vector<uint8_t> readData(pageData.size());
362*b602aad5SDaniel Hsu std::vector<uint8_t> readCmd = {commandReadPage, 0x0, 0x0, pageCount};
363*b602aad5SDaniel Hsu
364*b602aad5SDaniel Hsu if (!i2cInterface.sendReceive(readCmd, readData))
365*b602aad5SDaniel Hsu {
366*b602aad5SDaniel Hsu lg2::error("Read page data failed");
367*b602aad5SDaniel Hsu co_return false;
368*b602aad5SDaniel Hsu }
369*b602aad5SDaniel Hsu
370*b602aad5SDaniel Hsu constexpr size_t pageSize = 16;
371*b602aad5SDaniel Hsu auto mismatch_pair =
372*b602aad5SDaniel Hsu std::mismatch(pageData.begin(), pageData.end(), readData.begin());
373*b602aad5SDaniel Hsu if (mismatch_pair.first != pageData.end())
374*b602aad5SDaniel Hsu {
375*b602aad5SDaniel Hsu size_t idx = std::distance(pageData.begin(), mismatch_pair.first);
376*b602aad5SDaniel Hsu lg2::error("Verify failed at {INDEX}", "INDEX",
377*b602aad5SDaniel Hsu ((static_cast<size_t>(pageSize * pageOffset)) + idx));
378*b602aad5SDaniel Hsu co_return false;
379*b602aad5SDaniel Hsu }
380*b602aad5SDaniel Hsu
381*b602aad5SDaniel Hsu co_return true;
382*b602aad5SDaniel Hsu }
383*b602aad5SDaniel Hsu
384*b602aad5SDaniel Hsu } // namespace phosphor::software::cpld
385