xref: /openbmc/phosphor-bmc-code-mgmt/i2c-vr/tda38640a/tda38640a.cpp (revision c1b36628298d7799677680e70d455f85acf83650)
1*c1b36628SLeo Yang #include "tda38640a.hpp"
2*c1b36628SLeo Yang 
3*c1b36628SLeo Yang #include "common/include/i2c/i2c.hpp"
4*c1b36628SLeo Yang #include "common/include/utils.hpp"
5*c1b36628SLeo Yang 
6*c1b36628SLeo Yang #include <phosphor-logging/lg2.hpp>
7*c1b36628SLeo Yang 
8*c1b36628SLeo Yang #include <iostream>
9*c1b36628SLeo Yang #include <sstream>
10*c1b36628SLeo Yang #include <string>
11*c1b36628SLeo Yang #include <vector>
12*c1b36628SLeo Yang 
13*c1b36628SLeo Yang PHOSPHOR_LOG2_USING;
14*c1b36628SLeo Yang 
15*c1b36628SLeo Yang namespace phosphor::software::VR
16*c1b36628SLeo Yang {
17*c1b36628SLeo Yang 
18*c1b36628SLeo Yang static constexpr size_t progNVMDelay = 300;
19*c1b36628SLeo Yang static constexpr uint8_t NVMDoneMask = 0x80;
20*c1b36628SLeo Yang static constexpr uint8_t NVMErrorMask = 0x40;
21*c1b36628SLeo Yang static constexpr uint8_t pageZero = 0;
22*c1b36628SLeo Yang 
23*c1b36628SLeo Yang enum class TDA38640ACmd : uint8_t
24*c1b36628SLeo Yang {
25*c1b36628SLeo Yang     crcLowReg = 0xB0,
26*c1b36628SLeo Yang     crcHighReg = 0xAE,
27*c1b36628SLeo Yang     userWrRemain = 0xB8,
28*c1b36628SLeo Yang     unlockRegsReg = 0xD4,
29*c1b36628SLeo Yang     unlockRegsVal = 0x03, // Unlock i2c and PMBus address registers.
30*c1b36628SLeo Yang     progCmdLowReg = 0xD6,
31*c1b36628SLeo Yang     progCmdHighReg = 0xD7,
32*c1b36628SLeo Yang     progCmdLowVal = 0x42, // 0x3f42 From datasheet, This will store the user
33*c1b36628SLeo Yang                           // register in the next available nvm user image.
34*c1b36628SLeo Yang     progCmdHighVal = 0x3F,
35*c1b36628SLeo Yang     revisionReg = 0xFD,   // The silicon version value is stored in register
36*c1b36628SLeo Yang                           // 0x00FD [7:0] of page 0.
37*c1b36628SLeo Yang     pageReg = 0xff
38*c1b36628SLeo Yang };
39*c1b36628SLeo Yang 
40*c1b36628SLeo Yang const std::unordered_set<uint16_t> user_section_otp_register{
41*c1b36628SLeo Yang     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
42*c1b36628SLeo Yang     0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051,
43*c1b36628SLeo Yang     0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A,
44*c1b36628SLeo Yang     0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062, 0x0063,
45*c1b36628SLeo Yang     0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C,
46*c1b36628SLeo Yang     0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075,
47*c1b36628SLeo Yang     0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x0202, 0x0204, 0x0220,
48*c1b36628SLeo Yang     0x0240, 0x0242, 0x0243, 0x0248, 0x0249, 0x024A, 0x024B, 0x024C, 0x024D,
49*c1b36628SLeo Yang     0x024E, 0x024F, 0x0250, 0x0251, 0x0252, 0x0256, 0x0257, 0x0266, 0x0267,
50*c1b36628SLeo Yang     0x026A, 0x026C, 0x0270, 0x0272, 0x0273, 0x0280, 0x0281, 0x0282, 0x0288,
51*c1b36628SLeo Yang     0x0289, 0x028A, 0x028C, 0x028D, 0x028E, 0x029E, 0x02A0, 0x02A2, 0x02AA,
52*c1b36628SLeo Yang     0x02AB, 0x02AC, 0x02BC, 0x02BD, 0x02BE, 0x02BF, 0x02C0, 0x02C2, 0x02C8,
53*c1b36628SLeo Yang     0x02CA, 0x0384, 0x0385};
54*c1b36628SLeo Yang 
55*c1b36628SLeo Yang TDA38640A::TDA38640A(sdbusplus::async::context& ctx, uint16_t bus,
56*c1b36628SLeo Yang                      uint16_t address) :
57*c1b36628SLeo Yang     VoltageRegulator(ctx), i2cInterface(phosphor::i2c::I2C(bus, address))
58*c1b36628SLeo Yang {}
59*c1b36628SLeo Yang 
60*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::getUserRemainingWrites(uint8_t* remain)
61*c1b36628SLeo Yang {
62*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
63*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
64*c1b36628SLeo Yang     uint16_t remainBits = 0;
65*c1b36628SLeo Yang 
66*c1b36628SLeo Yang     if (!(co_await setPage(pageZero)))
67*c1b36628SLeo Yang     {
68*c1b36628SLeo Yang         error("getUserRemainingWrites failed at setPage");
69*c1b36628SLeo Yang         co_return false;
70*c1b36628SLeo Yang     }
71*c1b36628SLeo Yang 
72*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::userWrRemain);
73*c1b36628SLeo Yang     rbuf.resize(2);
74*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
75*c1b36628SLeo Yang     {
76*c1b36628SLeo Yang         error("getUserRemainingWrites failed with sendreceive");
77*c1b36628SLeo Yang         co_return false;
78*c1b36628SLeo Yang     }
79*c1b36628SLeo Yang     remainBits = rbuf[0] | (rbuf[1] << 8);
80*c1b36628SLeo Yang 
81*c1b36628SLeo Yang     *remain = (16 - std::popcount(remainBits));
82*c1b36628SLeo Yang 
83*c1b36628SLeo Yang     co_return true;
84*c1b36628SLeo Yang }
85*c1b36628SLeo Yang 
86*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::setPage(uint8_t page)
87*c1b36628SLeo Yang {
88*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
89*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
90*c1b36628SLeo Yang 
91*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::pageReg, page);
92*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
93*c1b36628SLeo Yang     {
94*c1b36628SLeo Yang         error("setPage failed with sendreceive");
95*c1b36628SLeo Yang         co_return false;
96*c1b36628SLeo Yang     }
97*c1b36628SLeo Yang     co_return true;
98*c1b36628SLeo Yang }
99*c1b36628SLeo Yang 
100*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::getDeviceRevision(uint8_t* revision)
101*c1b36628SLeo Yang {
102*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
103*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
104*c1b36628SLeo Yang 
105*c1b36628SLeo Yang     if (!(co_await setPage(pageZero)))
106*c1b36628SLeo Yang     {
107*c1b36628SLeo Yang         error("getDeviceRevision failed at setPage");
108*c1b36628SLeo Yang         co_return false;
109*c1b36628SLeo Yang     }
110*c1b36628SLeo Yang 
111*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::revisionReg);
112*c1b36628SLeo Yang     rbuf.resize(1);
113*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
114*c1b36628SLeo Yang     {
115*c1b36628SLeo Yang         error("getDeviceRevision failed with sendreceive");
116*c1b36628SLeo Yang         co_return false;
117*c1b36628SLeo Yang     }
118*c1b36628SLeo Yang 
119*c1b36628SLeo Yang     *revision = rbuf[0];
120*c1b36628SLeo Yang 
121*c1b36628SLeo Yang     co_return true;
122*c1b36628SLeo Yang }
123*c1b36628SLeo Yang 
124*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::getCRC(uint32_t* sum)
125*c1b36628SLeo Yang {
126*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
127*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
128*c1b36628SLeo Yang 
129*c1b36628SLeo Yang     uint32_t checksum = 0;
130*c1b36628SLeo Yang 
131*c1b36628SLeo Yang     if (!(co_await setPage(pageZero)))
132*c1b36628SLeo Yang     {
133*c1b36628SLeo Yang         error("getCRC failed at setPage");
134*c1b36628SLeo Yang         co_return false;
135*c1b36628SLeo Yang     }
136*c1b36628SLeo Yang 
137*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::crcLowReg);
138*c1b36628SLeo Yang     rbuf.resize(2);
139*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
140*c1b36628SLeo Yang     {
141*c1b36628SLeo Yang         error("getCRC failed with sendreceive");
142*c1b36628SLeo Yang         co_return false;
143*c1b36628SLeo Yang     }
144*c1b36628SLeo Yang 
145*c1b36628SLeo Yang     checksum = rbuf[0] | (rbuf[1] << 8);
146*c1b36628SLeo Yang 
147*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::crcHighReg);
148*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
149*c1b36628SLeo Yang     {
150*c1b36628SLeo Yang         error("getCRC failed with sendreceive");
151*c1b36628SLeo Yang         co_return false;
152*c1b36628SLeo Yang     }
153*c1b36628SLeo Yang 
154*c1b36628SLeo Yang     checksum |= (rbuf[0] << 16) | (rbuf[1] << 24);
155*c1b36628SLeo Yang 
156*c1b36628SLeo Yang     *sum = checksum;
157*c1b36628SLeo Yang 
158*c1b36628SLeo Yang     co_return true;
159*c1b36628SLeo Yang }
160*c1b36628SLeo Yang 
161*c1b36628SLeo Yang bool TDA38640A::parseImage(const uint8_t* image, size_t imageSize)
162*c1b36628SLeo Yang {
163*c1b36628SLeo Yang     std::string content(reinterpret_cast<const char*>(image), imageSize);
164*c1b36628SLeo Yang     std::istringstream imageStream(content);
165*c1b36628SLeo Yang     std::string line;
166*c1b36628SLeo Yang 
167*c1b36628SLeo Yang     configuration.clear();
168*c1b36628SLeo Yang 
169*c1b36628SLeo Yang     bool inConfigData = false;
170*c1b36628SLeo Yang     while (std::getline(imageStream, line))
171*c1b36628SLeo Yang     {
172*c1b36628SLeo Yang         if (line.find("Part Number :") != std::string::npos)
173*c1b36628SLeo Yang         {
174*c1b36628SLeo Yang             if (line.back() == '\r')
175*c1b36628SLeo Yang             {
176*c1b36628SLeo Yang                 line.pop_back();
177*c1b36628SLeo Yang             }
178*c1b36628SLeo Yang             std::string s(1, line.back());
179*c1b36628SLeo Yang             configuration.rev =
180*c1b36628SLeo Yang                 static_cast<uint8_t>(std::stoul(s, nullptr, 16));
181*c1b36628SLeo Yang         }
182*c1b36628SLeo Yang 
183*c1b36628SLeo Yang         if (line.find("Configuration Checksum :") != std::string::npos)
184*c1b36628SLeo Yang         {
185*c1b36628SLeo Yang             size_t pos = line.find("0x");
186*c1b36628SLeo Yang             if (pos != std::string::npos)
187*c1b36628SLeo Yang             {
188*c1b36628SLeo Yang                 std::string hexStr = line.substr(pos + 2);
189*c1b36628SLeo Yang                 configuration.checksum = std::stoul(hexStr, nullptr, 16);
190*c1b36628SLeo Yang             }
191*c1b36628SLeo Yang         }
192*c1b36628SLeo Yang 
193*c1b36628SLeo Yang         if (line.find("[Configuration Data]") != std::string::npos)
194*c1b36628SLeo Yang         {
195*c1b36628SLeo Yang             inConfigData = true;
196*c1b36628SLeo Yang             continue;
197*c1b36628SLeo Yang         }
198*c1b36628SLeo Yang         if (line.find("[End Configuration Data]") != std::string::npos)
199*c1b36628SLeo Yang         {
200*c1b36628SLeo Yang             break;
201*c1b36628SLeo Yang         }
202*c1b36628SLeo Yang         if (inConfigData && !line.empty())
203*c1b36628SLeo Yang         {
204*c1b36628SLeo Yang             std::istringstream lineStream(line);
205*c1b36628SLeo Yang             std::string seg;
206*c1b36628SLeo Yang             std::vector<uint8_t> dataVector;
207*c1b36628SLeo Yang             while (lineStream >> seg)
208*c1b36628SLeo Yang             {
209*c1b36628SLeo Yang                 if (seg.length() == 2)
210*c1b36628SLeo Yang                 {
211*c1b36628SLeo Yang                     uint8_t data =
212*c1b36628SLeo Yang                         static_cast<uint8_t>(std::stoi(seg, nullptr, 16));
213*c1b36628SLeo Yang                     dataVector.push_back(data);
214*c1b36628SLeo Yang                 }
215*c1b36628SLeo Yang                 else
216*c1b36628SLeo Yang                 {
217*c1b36628SLeo Yang                     uint16_t offset =
218*c1b36628SLeo Yang                         static_cast<uint16_t>(std::stoi(seg, nullptr, 16));
219*c1b36628SLeo Yang                     configuration.offsets.push_back(offset);
220*c1b36628SLeo Yang                 }
221*c1b36628SLeo Yang             }
222*c1b36628SLeo Yang             configuration.data.push_back(dataVector);
223*c1b36628SLeo Yang         }
224*c1b36628SLeo Yang     }
225*c1b36628SLeo Yang 
226*c1b36628SLeo Yang     if (configuration.offsets.size() != configuration.data.size())
227*c1b36628SLeo Yang     {
228*c1b36628SLeo Yang         error("parseImage failed. Data line mismatch.");
229*c1b36628SLeo Yang         return false;
230*c1b36628SLeo Yang     }
231*c1b36628SLeo Yang 
232*c1b36628SLeo Yang     return true;
233*c1b36628SLeo Yang }
234*c1b36628SLeo Yang 
235*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::unlockDevice()
236*c1b36628SLeo Yang {
237*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
238*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
239*c1b36628SLeo Yang 
240*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::unlockRegsReg,
241*c1b36628SLeo Yang                            TDA38640ACmd::unlockRegsVal);
242*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
243*c1b36628SLeo Yang     {
244*c1b36628SLeo Yang         error("unlockDevice failed with sendreceive");
245*c1b36628SLeo Yang         co_return false;
246*c1b36628SLeo Yang     }
247*c1b36628SLeo Yang     co_return true;
248*c1b36628SLeo Yang }
249*c1b36628SLeo Yang 
250*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::programmingCmd()
251*c1b36628SLeo Yang {
252*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
253*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
254*c1b36628SLeo Yang 
255*c1b36628SLeo Yang     if (!(co_await setPage(pageZero)))
256*c1b36628SLeo Yang     {
257*c1b36628SLeo Yang         error("programmingCmd failed at setPage 0.");
258*c1b36628SLeo Yang         co_return false;
259*c1b36628SLeo Yang     }
260*c1b36628SLeo Yang 
261*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::progCmdHighReg,
262*c1b36628SLeo Yang                            TDA38640ACmd::progCmdHighVal);
263*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
264*c1b36628SLeo Yang     {
265*c1b36628SLeo Yang         error("programmingCmd high bit failed with sendreceive.");
266*c1b36628SLeo Yang         co_return false;
267*c1b36628SLeo Yang     }
268*c1b36628SLeo Yang 
269*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::progCmdLowReg,
270*c1b36628SLeo Yang                            TDA38640ACmd::progCmdLowVal);
271*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
272*c1b36628SLeo Yang     {
273*c1b36628SLeo Yang         error("programmingCmd low bit failed with sendreceive.");
274*c1b36628SLeo Yang         co_return false;
275*c1b36628SLeo Yang     }
276*c1b36628SLeo Yang     co_return true;
277*c1b36628SLeo Yang }
278*c1b36628SLeo Yang 
279*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::getProgStatus(uint8_t* status)
280*c1b36628SLeo Yang {
281*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
282*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
283*c1b36628SLeo Yang 
284*c1b36628SLeo Yang     tbuf = buildByteVector(TDA38640ACmd::progCmdHighReg);
285*c1b36628SLeo Yang     rbuf.resize(1);
286*c1b36628SLeo Yang     if (!i2cInterface.sendReceive(tbuf, rbuf))
287*c1b36628SLeo Yang     {
288*c1b36628SLeo Yang         error("getProgStatus failed with sendreceive");
289*c1b36628SLeo Yang         co_return false;
290*c1b36628SLeo Yang     }
291*c1b36628SLeo Yang 
292*c1b36628SLeo Yang     *status = rbuf[0];
293*c1b36628SLeo Yang 
294*c1b36628SLeo Yang     co_return true;
295*c1b36628SLeo Yang }
296*c1b36628SLeo Yang 
297*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::program()
298*c1b36628SLeo Yang {
299*c1b36628SLeo Yang     std::vector<uint8_t> tbuf;
300*c1b36628SLeo Yang     std::vector<uint8_t> rbuf;
301*c1b36628SLeo Yang     uint8_t status;
302*c1b36628SLeo Yang     uint8_t retry = 3;
303*c1b36628SLeo Yang 
304*c1b36628SLeo Yang     if (!(co_await unlockDevice()))
305*c1b36628SLeo Yang     {
306*c1b36628SLeo Yang         error("program failed at unlockDevice");
307*c1b36628SLeo Yang         co_return false;
308*c1b36628SLeo Yang     }
309*c1b36628SLeo Yang 
310*c1b36628SLeo Yang     uint8_t page = 0;
311*c1b36628SLeo Yang     uint8_t address = 0;
312*c1b36628SLeo Yang     for (size_t i = 0; i < configuration.offsets.size(); i++)
313*c1b36628SLeo Yang     {
314*c1b36628SLeo Yang         page = configuration.offsets[i] >> 8;
315*c1b36628SLeo Yang         if (!(co_await setPage(page)))
316*c1b36628SLeo Yang         {
317*c1b36628SLeo Yang             error("program failed at setPage");
318*c1b36628SLeo Yang             co_return false;
319*c1b36628SLeo Yang         }
320*c1b36628SLeo Yang 
321*c1b36628SLeo Yang         for (uint8_t bias = 0; bias < 16; bias++)
322*c1b36628SLeo Yang         {
323*c1b36628SLeo Yang             uint16_t full_addr = configuration.offsets[i] + bias;
324*c1b36628SLeo Yang 
325*c1b36628SLeo Yang             if (user_section_otp_register.find(full_addr) ==
326*c1b36628SLeo Yang                 user_section_otp_register.end())
327*c1b36628SLeo Yang             {
328*c1b36628SLeo Yang                 debug(
329*c1b36628SLeo Yang                     "program at address {ADDR} not belone to user_section_otp_register.",
330*c1b36628SLeo Yang                     "ADDR", lg2::hex, full_addr);
331*c1b36628SLeo Yang                 continue;
332*c1b36628SLeo Yang             }
333*c1b36628SLeo Yang 
334*c1b36628SLeo Yang             address = (configuration.offsets[i] & 0xFF) + bias;
335*c1b36628SLeo Yang 
336*c1b36628SLeo Yang             tbuf = buildByteVector(address, configuration.data[i][bias]);
337*c1b36628SLeo Yang             if (!i2cInterface.sendReceive(tbuf, rbuf))
338*c1b36628SLeo Yang             {
339*c1b36628SLeo Yang                 error("program failed with sendreceive");
340*c1b36628SLeo Yang                 co_return false;
341*c1b36628SLeo Yang             }
342*c1b36628SLeo Yang             debug("programming : at {PAGE} {ADDR} with {DATA}", "PAGE",
343*c1b36628SLeo Yang                   lg2::hex, page, "ADDR", lg2::hex, address, "DATA", lg2::hex,
344*c1b36628SLeo Yang                   configuration.data[i][bias]);
345*c1b36628SLeo Yang         }
346*c1b36628SLeo Yang     }
347*c1b36628SLeo Yang 
348*c1b36628SLeo Yang     if (!(co_await programmingCmd()))
349*c1b36628SLeo Yang     {
350*c1b36628SLeo Yang         error("program failed at programmingCmd");
351*c1b36628SLeo Yang         co_return false;
352*c1b36628SLeo Yang     }
353*c1b36628SLeo Yang 
354*c1b36628SLeo Yang     for (uint8_t r = 0; r < retry; r++)
355*c1b36628SLeo Yang     {
356*c1b36628SLeo Yang         co_await sdbusplus::async::sleep_for(
357*c1b36628SLeo Yang             ctx, std::chrono::milliseconds(progNVMDelay));
358*c1b36628SLeo Yang 
359*c1b36628SLeo Yang         if (!(co_await getProgStatus(&status)))
360*c1b36628SLeo Yang         {
361*c1b36628SLeo Yang             error("program failed at getProgStatus");
362*c1b36628SLeo Yang             co_return false;
363*c1b36628SLeo Yang         }
364*c1b36628SLeo Yang 
365*c1b36628SLeo Yang         if ((status & NVMDoneMask) == 0 || (status & NVMErrorMask) != 0)
366*c1b36628SLeo Yang         {
367*c1b36628SLeo Yang             if ((status & NVMDoneMask) == 0)
368*c1b36628SLeo Yang             {
369*c1b36628SLeo Yang                 error(
370*c1b36628SLeo Yang                     "getProgStatus failed with 0x00D7[7] == 0, Programming command not completed. retry...");
371*c1b36628SLeo Yang             }
372*c1b36628SLeo Yang             if ((status & NVMErrorMask) != 0)
373*c1b36628SLeo Yang             {
374*c1b36628SLeo Yang                 error(
375*c1b36628SLeo Yang                     "getProgStatus failed with 0x00D7[6] == 1, The previous NVM operation encountered an error. retry...");
376*c1b36628SLeo Yang             }
377*c1b36628SLeo Yang         }
378*c1b36628SLeo Yang         else
379*c1b36628SLeo Yang         {
380*c1b36628SLeo Yang             debug("ProgStatus ok.");
381*c1b36628SLeo Yang             co_return true;
382*c1b36628SLeo Yang         }
383*c1b36628SLeo Yang     }
384*c1b36628SLeo Yang     co_return false;
385*c1b36628SLeo Yang }
386*c1b36628SLeo Yang 
387*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::verifyImage(const uint8_t* image,
388*c1b36628SLeo Yang                                                     size_t imageSize)
389*c1b36628SLeo Yang {
390*c1b36628SLeo Yang     uint8_t remain = 0;
391*c1b36628SLeo Yang     uint8_t devRev = 0;
392*c1b36628SLeo Yang     uint32_t devCrc = 0;
393*c1b36628SLeo Yang 
394*c1b36628SLeo Yang     if (!parseImage(image, imageSize))
395*c1b36628SLeo Yang     {
396*c1b36628SLeo Yang         error("verifyImage failed at parseImage");
397*c1b36628SLeo Yang         co_return false;
398*c1b36628SLeo Yang     }
399*c1b36628SLeo Yang 
400*c1b36628SLeo Yang     if (!(co_await getUserRemainingWrites(&remain)))
401*c1b36628SLeo Yang     {
402*c1b36628SLeo Yang         error("program failed at getUserRemainingWrites");
403*c1b36628SLeo Yang         co_return false;
404*c1b36628SLeo Yang     }
405*c1b36628SLeo Yang     debug("User Remaining Writes from device: {REMAIN}", "REMAIN", lg2::dec,
406*c1b36628SLeo Yang           remain);
407*c1b36628SLeo Yang 
408*c1b36628SLeo Yang     if (!remain)
409*c1b36628SLeo Yang     {
410*c1b36628SLeo Yang         error("program failed with no user remaining writes left on device");
411*c1b36628SLeo Yang         co_return false;
412*c1b36628SLeo Yang     }
413*c1b36628SLeo Yang 
414*c1b36628SLeo Yang     if (!(co_await getDeviceRevision(&devRev)))
415*c1b36628SLeo Yang     {
416*c1b36628SLeo Yang         error("program failed at getDeviceRevision");
417*c1b36628SLeo Yang         co_return false;
418*c1b36628SLeo Yang     }
419*c1b36628SLeo Yang     debug("Device revision read from device: {REV}", "REV", lg2::hex, devRev);
420*c1b36628SLeo Yang 
421*c1b36628SLeo Yang     if (devRev != configuration.rev)
422*c1b36628SLeo Yang     {
423*c1b36628SLeo Yang         error(
424*c1b36628SLeo Yang             "program failed with revision of device and configuration are not equal");
425*c1b36628SLeo Yang         co_return false;
426*c1b36628SLeo Yang     }
427*c1b36628SLeo Yang 
428*c1b36628SLeo Yang     if (!(co_await getCRC(&devCrc)))
429*c1b36628SLeo Yang     {
430*c1b36628SLeo Yang         error("program failed at getCRC");
431*c1b36628SLeo Yang         co_return false;
432*c1b36628SLeo Yang     }
433*c1b36628SLeo Yang 
434*c1b36628SLeo Yang     debug("CRC from device: {CRC}", "CRC", lg2::hex, devCrc);
435*c1b36628SLeo Yang     debug("CRC from config: {CRC}", "CRC", lg2::hex, configuration.checksum);
436*c1b36628SLeo Yang 
437*c1b36628SLeo Yang     if (devCrc == configuration.checksum)
438*c1b36628SLeo Yang     {
439*c1b36628SLeo Yang         error("program failed with same CRC value at device and configuration");
440*c1b36628SLeo Yang         co_return false;
441*c1b36628SLeo Yang     }
442*c1b36628SLeo Yang 
443*c1b36628SLeo Yang     co_return true;
444*c1b36628SLeo Yang }
445*c1b36628SLeo Yang 
446*c1b36628SLeo Yang bool TDA38640A::forcedUpdateAllowed()
447*c1b36628SLeo Yang {
448*c1b36628SLeo Yang     return true;
449*c1b36628SLeo Yang }
450*c1b36628SLeo Yang 
451*c1b36628SLeo Yang sdbusplus::async::task<bool> TDA38640A::updateFirmware(bool force)
452*c1b36628SLeo Yang {
453*c1b36628SLeo Yang     (void)force;
454*c1b36628SLeo Yang     if (!(co_await program()))
455*c1b36628SLeo Yang     {
456*c1b36628SLeo Yang         error("programing TDA38640A failed");
457*c1b36628SLeo Yang         co_return false;
458*c1b36628SLeo Yang     }
459*c1b36628SLeo Yang 
460*c1b36628SLeo Yang     co_return true;
461*c1b36628SLeo Yang }
462*c1b36628SLeo Yang 
463*c1b36628SLeo Yang } // namespace phosphor::software::VR
464