xref: /openbmc/phosphor-bmc-code-mgmt/i2c-vr/mps/mp5998.cpp (revision 782d6eed913236bc78c533551876389f176bf121)
1*782d6eedSFreddieJheng #include "mp5998.hpp"
2*782d6eedSFreddieJheng 
3*782d6eedSFreddieJheng #include "common/include/utils.hpp"
4*782d6eedSFreddieJheng 
5*782d6eedSFreddieJheng #include <phosphor-logging/lg2.hpp>
6*782d6eedSFreddieJheng 
7*782d6eedSFreddieJheng #include <fstream>
8*782d6eedSFreddieJheng 
9*782d6eedSFreddieJheng PHOSPHOR_LOG2_USING;
10*782d6eedSFreddieJheng 
11*782d6eedSFreddieJheng namespace phosphor::software::VR
12*782d6eedSFreddieJheng {
13*782d6eedSFreddieJheng 
14*782d6eedSFreddieJheng static constexpr std::string_view crcUserRegName = "CRC_USER";
15*782d6eedSFreddieJheng static constexpr uint8_t eepromFaultBit = 0x01;
16*782d6eedSFreddieJheng static constexpr uint8_t unlockData = 0x00;
17*782d6eedSFreddieJheng static constexpr size_t statusByteLength = 1;
18*782d6eedSFreddieJheng 
19*782d6eedSFreddieJheng enum class MP5998Cmd : uint8_t
20*782d6eedSFreddieJheng {
21*782d6eedSFreddieJheng     crcUser = 0xF8,
22*782d6eedSFreddieJheng     passwordReg = 0x0E,
23*782d6eedSFreddieJheng };
24*782d6eedSFreddieJheng 
parseDeviceConfiguration()25*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::parseDeviceConfiguration()
26*782d6eedSFreddieJheng {
27*782d6eedSFreddieJheng     if (!configuration)
28*782d6eedSFreddieJheng     {
29*782d6eedSFreddieJheng         error("Device configuration not initialized");
30*782d6eedSFreddieJheng         co_return false;
31*782d6eedSFreddieJheng     }
32*782d6eedSFreddieJheng 
33*782d6eedSFreddieJheng     configuration->vendorId = 0x4D5053;
34*782d6eedSFreddieJheng     configuration->productId = 0x35393938;
35*782d6eedSFreddieJheng 
36*782d6eedSFreddieJheng     for (const auto& tokens : parser->lineTokens)
37*782d6eedSFreddieJheng     {
38*782d6eedSFreddieJheng         if (!parser->isValidDataTokens(tokens))
39*782d6eedSFreddieJheng         {
40*782d6eedSFreddieJheng             continue;
41*782d6eedSFreddieJheng         }
42*782d6eedSFreddieJheng 
43*782d6eedSFreddieJheng         auto regName = parser->getVal<std::string>(tokens, ATE::regName);
44*782d6eedSFreddieJheng 
45*782d6eedSFreddieJheng         if (regName == crcUserRegName)
46*782d6eedSFreddieJheng         {
47*782d6eedSFreddieJheng             configuration->configId =
48*782d6eedSFreddieJheng                 parser->getVal<uint32_t>(tokens, ATE::configId);
49*782d6eedSFreddieJheng             configuration->crcUser =
50*782d6eedSFreddieJheng                 parser->getVal<uint32_t>(tokens, ATE::regDataHex);
51*782d6eedSFreddieJheng         }
52*782d6eedSFreddieJheng     }
53*782d6eedSFreddieJheng 
54*782d6eedSFreddieJheng     co_return true;
55*782d6eedSFreddieJheng }
56*782d6eedSFreddieJheng 
verifyImage(const uint8_t * image,size_t imageSize)57*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::verifyImage(const uint8_t* image,
58*782d6eedSFreddieJheng                                                  size_t imageSize)
59*782d6eedSFreddieJheng {
60*782d6eedSFreddieJheng     if (!co_await parseImage(image, imageSize))
61*782d6eedSFreddieJheng     {
62*782d6eedSFreddieJheng         error("Image verification failed: image parsing failed");
63*782d6eedSFreddieJheng         co_return false;
64*782d6eedSFreddieJheng     }
65*782d6eedSFreddieJheng 
66*782d6eedSFreddieJheng     if (configuration->registersData.empty())
67*782d6eedSFreddieJheng     {
68*782d6eedSFreddieJheng         error("Image verification failed - no register data found");
69*782d6eedSFreddieJheng         co_return false;
70*782d6eedSFreddieJheng     }
71*782d6eedSFreddieJheng 
72*782d6eedSFreddieJheng     if (configuration->configId == 0)
73*782d6eedSFreddieJheng     {
74*782d6eedSFreddieJheng         error("Image verification failed - missing config ID");
75*782d6eedSFreddieJheng         co_return false;
76*782d6eedSFreddieJheng     }
77*782d6eedSFreddieJheng 
78*782d6eedSFreddieJheng     co_return true;
79*782d6eedSFreddieJheng }
80*782d6eedSFreddieJheng 
checkId(PMBusCmd idCmd,uint32_t expected)81*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::checkId(PMBusCmd idCmd, uint32_t expected)
82*782d6eedSFreddieJheng {
83*782d6eedSFreddieJheng     static constexpr size_t mfrIdLength = 3;
84*782d6eedSFreddieJheng     static constexpr size_t mfrModelLength = 5;
85*782d6eedSFreddieJheng 
86*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf;
87*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
88*782d6eedSFreddieJheng 
89*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
90*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
91*782d6eedSFreddieJheng     {
92*782d6eedSFreddieJheng         error("MP5998: Failed to set page 0 for ID check");
93*782d6eedSFreddieJheng         co_return false;
94*782d6eedSFreddieJheng     }
95*782d6eedSFreddieJheng 
96*782d6eedSFreddieJheng     size_t bufferSize;
97*782d6eedSFreddieJheng 
98*782d6eedSFreddieJheng     if (idCmd == PMBusCmd::mfrId)
99*782d6eedSFreddieJheng     {
100*782d6eedSFreddieJheng         bufferSize = statusByteLength + mfrIdLength;
101*782d6eedSFreddieJheng     }
102*782d6eedSFreddieJheng     else if (idCmd == PMBusCmd::mfrModel)
103*782d6eedSFreddieJheng     {
104*782d6eedSFreddieJheng         bufferSize = statusByteLength + mfrModelLength;
105*782d6eedSFreddieJheng     }
106*782d6eedSFreddieJheng     else
107*782d6eedSFreddieJheng     {
108*782d6eedSFreddieJheng         error("MP5998: Unsupported ID command: 0x{CMD}", "CMD", lg2::hex,
109*782d6eedSFreddieJheng               static_cast<uint8_t>(idCmd));
110*782d6eedSFreddieJheng         co_return false;
111*782d6eedSFreddieJheng     }
112*782d6eedSFreddieJheng 
113*782d6eedSFreddieJheng     tbuf = buildByteVector(idCmd);
114*782d6eedSFreddieJheng     rbuf.resize(bufferSize);
115*782d6eedSFreddieJheng 
116*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
117*782d6eedSFreddieJheng     {
118*782d6eedSFreddieJheng         error("MP5998: I2C sendReceive failed for command 0x{CMD}", "CMD",
119*782d6eedSFreddieJheng               lg2::hex, static_cast<uint8_t>(idCmd));
120*782d6eedSFreddieJheng         co_return false;
121*782d6eedSFreddieJheng     }
122*782d6eedSFreddieJheng 
123*782d6eedSFreddieJheng     auto idBytes = std::span(rbuf).subspan(statusByteLength);
124*782d6eedSFreddieJheng     uint32_t id;
125*782d6eedSFreddieJheng     if (idCmd == PMBusCmd::mfrModel)
126*782d6eedSFreddieJheng     {
127*782d6eedSFreddieJheng         auto productBytes = idBytes.subspan(1, 4);
128*782d6eedSFreddieJheng         id = bytesToInt<uint32_t>(productBytes);
129*782d6eedSFreddieJheng     }
130*782d6eedSFreddieJheng     else
131*782d6eedSFreddieJheng     {
132*782d6eedSFreddieJheng         id = bytesToInt<uint32_t>(idBytes);
133*782d6eedSFreddieJheng     }
134*782d6eedSFreddieJheng 
135*782d6eedSFreddieJheng     debug("Check ID cmd {CMD}: Got={ID}, Expected={EXP}", "CMD", lg2::hex,
136*782d6eedSFreddieJheng           static_cast<uint8_t>(idCmd), "ID", lg2::hex, id, "EXP", lg2::hex,
137*782d6eedSFreddieJheng           expected);
138*782d6eedSFreddieJheng 
139*782d6eedSFreddieJheng     co_return id == expected;
140*782d6eedSFreddieJheng }
141*782d6eedSFreddieJheng 
unlockPasswordProtection()142*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::unlockPasswordProtection()
143*782d6eedSFreddieJheng {
144*782d6eedSFreddieJheng     constexpr uint8_t passwordUnlockBit = 0x08;
145*782d6eedSFreddieJheng     constexpr uint16_t passwordData = 0x0000;
146*782d6eedSFreddieJheng 
147*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf;
148*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
149*782d6eedSFreddieJheng 
150*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
151*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
152*782d6eedSFreddieJheng     {
153*782d6eedSFreddieJheng         error("Failed to set page 0 for password unlock");
154*782d6eedSFreddieJheng         co_return false;
155*782d6eedSFreddieJheng     }
156*782d6eedSFreddieJheng 
157*782d6eedSFreddieJheng     tbuf = buildByteVector(MP5998Cmd::passwordReg, passwordData);
158*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
159*782d6eedSFreddieJheng     {
160*782d6eedSFreddieJheng         error("Failed to write password");
161*782d6eedSFreddieJheng         co_return false;
162*782d6eedSFreddieJheng     }
163*782d6eedSFreddieJheng 
164*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::statusCML);
165*782d6eedSFreddieJheng     rbuf.resize(statusByteLength);
166*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
167*782d6eedSFreddieJheng     {
168*782d6eedSFreddieJheng         error("Failed to read STATUS_CML");
169*782d6eedSFreddieJheng         co_return false;
170*782d6eedSFreddieJheng     }
171*782d6eedSFreddieJheng 
172*782d6eedSFreddieJheng     bool unlocked = (rbuf[0] & passwordUnlockBit) == 0;
173*782d6eedSFreddieJheng 
174*782d6eedSFreddieJheng     co_return unlocked;
175*782d6eedSFreddieJheng }
176*782d6eedSFreddieJheng 
unlockWriteProtection()177*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::unlockWriteProtection()
178*782d6eedSFreddieJheng {
179*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf;
180*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
181*782d6eedSFreddieJheng 
182*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
183*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
184*782d6eedSFreddieJheng     {
185*782d6eedSFreddieJheng         error("Failed to set page 0 for write protection unlock");
186*782d6eedSFreddieJheng         co_return false;
187*782d6eedSFreddieJheng     }
188*782d6eedSFreddieJheng 
189*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::writeProtect, unlockData);
190*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
191*782d6eedSFreddieJheng     {
192*782d6eedSFreddieJheng         error("Failed to unlock write protection");
193*782d6eedSFreddieJheng         co_return false;
194*782d6eedSFreddieJheng     }
195*782d6eedSFreddieJheng 
196*782d6eedSFreddieJheng     debug("Write protection unlocked");
197*782d6eedSFreddieJheng     co_return true;
198*782d6eedSFreddieJheng }
199*782d6eedSFreddieJheng 
programAllRegisters()200*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::programAllRegisters()
201*782d6eedSFreddieJheng {
202*782d6eedSFreddieJheng     uint8_t currentPage = 0xFF;
203*782d6eedSFreddieJheng 
204*782d6eedSFreddieJheng     for (const auto& regData : configuration->registersData)
205*782d6eedSFreddieJheng     {
206*782d6eedSFreddieJheng         if (regData.page != currentPage)
207*782d6eedSFreddieJheng         {
208*782d6eedSFreddieJheng             std::vector<uint8_t> tbuf =
209*782d6eedSFreddieJheng                 buildByteVector(PMBusCmd::page, regData.page);
210*782d6eedSFreddieJheng             std::vector<uint8_t> rbuf;
211*782d6eedSFreddieJheng             if (!i2cInterface.sendReceive(tbuf, rbuf))
212*782d6eedSFreddieJheng             {
213*782d6eedSFreddieJheng                 error("Failed to set page {PAGE}", "PAGE", regData.page);
214*782d6eedSFreddieJheng                 co_return false;
215*782d6eedSFreddieJheng             }
216*782d6eedSFreddieJheng             currentPage = regData.page;
217*782d6eedSFreddieJheng         }
218*782d6eedSFreddieJheng 
219*782d6eedSFreddieJheng         std::vector<uint8_t> tbuf;
220*782d6eedSFreddieJheng         std::vector<uint8_t> rbuf;
221*782d6eedSFreddieJheng 
222*782d6eedSFreddieJheng         tbuf.push_back(regData.addr);
223*782d6eedSFreddieJheng 
224*782d6eedSFreddieJheng         for (uint8_t i = 0; i < regData.length && i < 4; ++i)
225*782d6eedSFreddieJheng         {
226*782d6eedSFreddieJheng             tbuf.push_back(regData.data[i]);
227*782d6eedSFreddieJheng         }
228*782d6eedSFreddieJheng 
229*782d6eedSFreddieJheng         if (!i2cInterface.sendReceive(tbuf, rbuf))
230*782d6eedSFreddieJheng         {
231*782d6eedSFreddieJheng             error("Failed to write register 0x{REG} on page {PAGE}", "REG",
232*782d6eedSFreddieJheng                   lg2::hex, regData.addr, "PAGE", regData.page);
233*782d6eedSFreddieJheng             co_return false;
234*782d6eedSFreddieJheng         }
235*782d6eedSFreddieJheng     }
236*782d6eedSFreddieJheng 
237*782d6eedSFreddieJheng     debug("All registers programmed successfully");
238*782d6eedSFreddieJheng     co_return true;
239*782d6eedSFreddieJheng }
240*782d6eedSFreddieJheng 
storeMTP()241*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::storeMTP()
242*782d6eedSFreddieJheng {
243*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf;
244*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
245*782d6eedSFreddieJheng 
246*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
247*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
248*782d6eedSFreddieJheng     {
249*782d6eedSFreddieJheng         error("Failed to set page 0 for MTP store");
250*782d6eedSFreddieJheng         co_return false;
251*782d6eedSFreddieJheng     }
252*782d6eedSFreddieJheng 
253*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::storeUserCode);
254*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
255*782d6eedSFreddieJheng     {
256*782d6eedSFreddieJheng         error("Failed to send STORE_USER_ALL command");
257*782d6eedSFreddieJheng         co_return false;
258*782d6eedSFreddieJheng     }
259*782d6eedSFreddieJheng 
260*782d6eedSFreddieJheng     co_return true;
261*782d6eedSFreddieJheng }
262*782d6eedSFreddieJheng 
waitForMTPComplete()263*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::waitForMTPComplete()
264*782d6eedSFreddieJheng {
265*782d6eedSFreddieJheng     constexpr uint16_t mtpStoreWaitmS = 1200;
266*782d6eedSFreddieJheng     co_await sdbusplus::async::sleep_for(
267*782d6eedSFreddieJheng         ctx, std::chrono::milliseconds(mtpStoreWaitmS));
268*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf = buildByteVector(PMBusCmd::statusCML);
269*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
270*782d6eedSFreddieJheng     rbuf.resize(statusByteLength);
271*782d6eedSFreddieJheng 
272*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
273*782d6eedSFreddieJheng     {
274*782d6eedSFreddieJheng         error("Failed to read STATUS_CML after MTP store");
275*782d6eedSFreddieJheng         co_return false;
276*782d6eedSFreddieJheng     }
277*782d6eedSFreddieJheng 
278*782d6eedSFreddieJheng     bool eepromFault = rbuf[0] & eepromFaultBit;
279*782d6eedSFreddieJheng 
280*782d6eedSFreddieJheng     if (eepromFault)
281*782d6eedSFreddieJheng     {
282*782d6eedSFreddieJheng         error("EEPROM fault detected after MTP store");
283*782d6eedSFreddieJheng         co_return false;
284*782d6eedSFreddieJheng     }
285*782d6eedSFreddieJheng 
286*782d6eedSFreddieJheng     co_return true;
287*782d6eedSFreddieJheng }
288*782d6eedSFreddieJheng 
verifyCRC()289*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::verifyCRC()
290*782d6eedSFreddieJheng {
291*782d6eedSFreddieJheng     uint32_t deviceCRC{0};
292*782d6eedSFreddieJheng     // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
293*782d6eedSFreddieJheng     bool getCRCSuccess = co_await getCRC(&deviceCRC);
294*782d6eedSFreddieJheng     // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
295*782d6eedSFreddieJheng     if (!getCRCSuccess)
296*782d6eedSFreddieJheng     {
297*782d6eedSFreddieJheng         error("Failed to read CRC from device");
298*782d6eedSFreddieJheng         co_return false;
299*782d6eedSFreddieJheng     }
300*782d6eedSFreddieJheng 
301*782d6eedSFreddieJheng     bool crcMatch = (deviceCRC == configuration->crcUser);
302*782d6eedSFreddieJheng 
303*782d6eedSFreddieJheng     co_return crcMatch;
304*782d6eedSFreddieJheng }
305*782d6eedSFreddieJheng 
getCRC(uint32_t * checksum)306*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::getCRC(uint32_t* checksum)
307*782d6eedSFreddieJheng {
308*782d6eedSFreddieJheng     constexpr size_t crcLength = 2;
309*782d6eedSFreddieJheng 
310*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf;
311*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
312*782d6eedSFreddieJheng 
313*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
314*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
315*782d6eedSFreddieJheng     {
316*782d6eedSFreddieJheng         error("Failed to set page 0 for CRC read");
317*782d6eedSFreddieJheng         co_return false;
318*782d6eedSFreddieJheng     }
319*782d6eedSFreddieJheng 
320*782d6eedSFreddieJheng     tbuf = buildByteVector(MP5998Cmd::crcUser);
321*782d6eedSFreddieJheng     rbuf.resize(crcLength);
322*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
323*782d6eedSFreddieJheng     {
324*782d6eedSFreddieJheng         error("Failed to read CRC_USER register");
325*782d6eedSFreddieJheng         co_return false;
326*782d6eedSFreddieJheng     }
327*782d6eedSFreddieJheng 
328*782d6eedSFreddieJheng     *checksum = bytesToInt<uint32_t>(rbuf);
329*782d6eedSFreddieJheng 
330*782d6eedSFreddieJheng     co_return true;
331*782d6eedSFreddieJheng }
332*782d6eedSFreddieJheng 
sendRestoreMTPCommand()333*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::sendRestoreMTPCommand()
334*782d6eedSFreddieJheng {
335*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf;
336*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
337*782d6eedSFreddieJheng 
338*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
339*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
340*782d6eedSFreddieJheng     {
341*782d6eedSFreddieJheng         error("Failed to set page 0 for MTP restore");
342*782d6eedSFreddieJheng         co_return false;
343*782d6eedSFreddieJheng     }
344*782d6eedSFreddieJheng 
345*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::restoreUserAll);
346*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
347*782d6eedSFreddieJheng     {
348*782d6eedSFreddieJheng         error("Failed to send RESTORE_ALL command");
349*782d6eedSFreddieJheng         co_return false;
350*782d6eedSFreddieJheng     }
351*782d6eedSFreddieJheng 
352*782d6eedSFreddieJheng     co_return true;
353*782d6eedSFreddieJheng }
354*782d6eedSFreddieJheng 
checkEEPROMFaultAfterRestore()355*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::checkEEPROMFaultAfterRestore()
356*782d6eedSFreddieJheng {
357*782d6eedSFreddieJheng     std::vector<uint8_t> tbuf;
358*782d6eedSFreddieJheng     std::vector<uint8_t> rbuf;
359*782d6eedSFreddieJheng 
360*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
361*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
362*782d6eedSFreddieJheng     {
363*782d6eedSFreddieJheng         error("Failed to set page 0 for EEPROM fault check");
364*782d6eedSFreddieJheng         co_return false;
365*782d6eedSFreddieJheng     }
366*782d6eedSFreddieJheng 
367*782d6eedSFreddieJheng     tbuf = buildByteVector(PMBusCmd::statusCML);
368*782d6eedSFreddieJheng     rbuf.resize(1);
369*782d6eedSFreddieJheng     if (!i2cInterface.sendReceive(tbuf, rbuf))
370*782d6eedSFreddieJheng     {
371*782d6eedSFreddieJheng         error("Failed to read STATUS_CML register");
372*782d6eedSFreddieJheng         co_return false;
373*782d6eedSFreddieJheng     }
374*782d6eedSFreddieJheng 
375*782d6eedSFreddieJheng     bool eepromFault = (rbuf[0] & eepromFaultBit) != 0;
376*782d6eedSFreddieJheng 
377*782d6eedSFreddieJheng     co_return !eepromFault;
378*782d6eedSFreddieJheng }
379*782d6eedSFreddieJheng 
restoreMTPAndVerify()380*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::restoreMTPAndVerify()
381*782d6eedSFreddieJheng {
382*782d6eedSFreddieJheng     constexpr uint16_t mtpRestoreWait = 1600;
383*782d6eedSFreddieJheng 
384*782d6eedSFreddieJheng     if (!co_await sendRestoreMTPCommand())
385*782d6eedSFreddieJheng     {
386*782d6eedSFreddieJheng         error("Failed to send RESTORE_ALL command");
387*782d6eedSFreddieJheng         co_return false;
388*782d6eedSFreddieJheng     }
389*782d6eedSFreddieJheng 
390*782d6eedSFreddieJheng     co_await sdbusplus::async::sleep_for(
391*782d6eedSFreddieJheng         ctx, std::chrono::microseconds(mtpRestoreWait));
392*782d6eedSFreddieJheng     if (!co_await checkEEPROMFaultAfterRestore())
393*782d6eedSFreddieJheng     {
394*782d6eedSFreddieJheng         error("EEPROM fault detected after MTP restore");
395*782d6eedSFreddieJheng         co_return false;
396*782d6eedSFreddieJheng     }
397*782d6eedSFreddieJheng 
398*782d6eedSFreddieJheng     co_return true;
399*782d6eedSFreddieJheng }
400*782d6eedSFreddieJheng 
forcedUpdateAllowed()401*782d6eedSFreddieJheng bool MP5998::forcedUpdateAllowed()
402*782d6eedSFreddieJheng {
403*782d6eedSFreddieJheng     return true;
404*782d6eedSFreddieJheng }
405*782d6eedSFreddieJheng 
updateFirmware(bool force)406*782d6eedSFreddieJheng sdbusplus::async::task<bool> MP5998::updateFirmware(bool force)
407*782d6eedSFreddieJheng {
408*782d6eedSFreddieJheng     (void)force;
409*782d6eedSFreddieJheng 
410*782d6eedSFreddieJheng     if (!co_await checkId(PMBusCmd::mfrId, configuration->vendorId))
411*782d6eedSFreddieJheng     {
412*782d6eedSFreddieJheng         co_return false;
413*782d6eedSFreddieJheng     }
414*782d6eedSFreddieJheng 
415*782d6eedSFreddieJheng     if (!co_await checkId(PMBusCmd::mfrModel, configuration->productId))
416*782d6eedSFreddieJheng     {
417*782d6eedSFreddieJheng         co_return false;
418*782d6eedSFreddieJheng     }
419*782d6eedSFreddieJheng 
420*782d6eedSFreddieJheng     if (!co_await unlockWriteProtection())
421*782d6eedSFreddieJheng     {
422*782d6eedSFreddieJheng         co_return false;
423*782d6eedSFreddieJheng     }
424*782d6eedSFreddieJheng 
425*782d6eedSFreddieJheng     if (!co_await programAllRegisters())
426*782d6eedSFreddieJheng     {
427*782d6eedSFreddieJheng         co_return false;
428*782d6eedSFreddieJheng     }
429*782d6eedSFreddieJheng 
430*782d6eedSFreddieJheng     if (!co_await storeMTP())
431*782d6eedSFreddieJheng     {
432*782d6eedSFreddieJheng         co_return false;
433*782d6eedSFreddieJheng     }
434*782d6eedSFreddieJheng 
435*782d6eedSFreddieJheng     if (!co_await waitForMTPComplete())
436*782d6eedSFreddieJheng     {
437*782d6eedSFreddieJheng         co_return false;
438*782d6eedSFreddieJheng     }
439*782d6eedSFreddieJheng 
440*782d6eedSFreddieJheng     if (!co_await verifyCRC())
441*782d6eedSFreddieJheng     {
442*782d6eedSFreddieJheng         co_return false;
443*782d6eedSFreddieJheng     }
444*782d6eedSFreddieJheng 
445*782d6eedSFreddieJheng     if (!co_await restoreMTPAndVerify())
446*782d6eedSFreddieJheng     {
447*782d6eedSFreddieJheng         co_return false;
448*782d6eedSFreddieJheng     }
449*782d6eedSFreddieJheng 
450*782d6eedSFreddieJheng     co_return true;
451*782d6eedSFreddieJheng }
452*782d6eedSFreddieJheng 
453*782d6eedSFreddieJheng } // namespace phosphor::software::VR
454