xref: /openbmc/phosphor-bmc-code-mgmt/i2c-vr/mps/mp2x6xx.cpp (revision dcf4b607bd2937a8964d68fe9dcc59daaf20c720)
1*dcf4b607SKevin Tung #include "mp2x6xx.hpp"
2*dcf4b607SKevin Tung 
3*dcf4b607SKevin Tung #include "common/include/utils.hpp"
4*dcf4b607SKevin Tung 
5*dcf4b607SKevin Tung #include <phosphor-logging/lg2.hpp>
6*dcf4b607SKevin Tung 
7*dcf4b607SKevin Tung PHOSPHOR_LOG2_USING;
8*dcf4b607SKevin Tung 
9*dcf4b607SKevin Tung namespace phosphor::software::VR
10*dcf4b607SKevin Tung {
11*dcf4b607SKevin Tung 
12*dcf4b607SKevin Tung static constexpr size_t vendorIdLength = 3;
13*dcf4b607SKevin Tung static constexpr size_t deviceIdLength = 4;
14*dcf4b607SKevin Tung static constexpr size_t configIdLength = 2;
15*dcf4b607SKevin Tung static constexpr size_t statusByteLength = 1;
16*dcf4b607SKevin Tung static constexpr size_t crcLength = 2;
17*dcf4b607SKevin Tung 
18*dcf4b607SKevin Tung static constexpr std::string_view productIdRegName = "TRIM_MFR_PRODUCT_ID2";
19*dcf4b607SKevin Tung static constexpr std::string_view crcUserRegName = "CRC_USER";
20*dcf4b607SKevin Tung 
21*dcf4b607SKevin Tung static constexpr uint8_t pageMask = 0x0F;
22*dcf4b607SKevin Tung static constexpr uint8_t configMask = 0xF0;
23*dcf4b607SKevin Tung 
24*dcf4b607SKevin Tung static constexpr uint8_t disableWriteProtect = 0x00;
25*dcf4b607SKevin Tung static constexpr uint16_t disablePage2WriteProtect = 0x128C;
26*dcf4b607SKevin Tung static constexpr uint16_t disablePage3WriteProtect = 0x0082;
27*dcf4b607SKevin Tung 
28*dcf4b607SKevin Tung enum class MP2X6XXCmd : uint8_t
29*dcf4b607SKevin Tung {
30*dcf4b607SKevin Tung     // Page 0 commands
31*dcf4b607SKevin Tung     readCRCReg = 0xED,
32*dcf4b607SKevin Tung     // Page 1 commands
33*dcf4b607SKevin Tung     mfrMTPMemoryCtrl = 0xCC,
34*dcf4b607SKevin Tung     // Page 2 commands
35*dcf4b607SKevin Tung     selectConfigCtrl = 0x1A,
36*dcf4b607SKevin Tung     // Page 3 commands
37*dcf4b607SKevin Tung     mfrMTPMemoryCtrlPage3 = 0x81,
38*dcf4b607SKevin Tung };
39*dcf4b607SKevin Tung 
parseDeviceConfiguration()40*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::parseDeviceConfiguration()
41*dcf4b607SKevin Tung {
42*dcf4b607SKevin Tung     if (!configuration)
43*dcf4b607SKevin Tung     {
44*dcf4b607SKevin Tung         error("Device configuration not initialized");
45*dcf4b607SKevin Tung         co_return false;
46*dcf4b607SKevin Tung     }
47*dcf4b607SKevin Tung 
48*dcf4b607SKevin Tung     configuration->vendorId = 0x4D5053;
49*dcf4b607SKevin Tung 
50*dcf4b607SKevin Tung     for (const auto& tokens : parser->lineTokens)
51*dcf4b607SKevin Tung     {
52*dcf4b607SKevin Tung         if (!parser->isValidDataTokens(tokens))
53*dcf4b607SKevin Tung         {
54*dcf4b607SKevin Tung             continue;
55*dcf4b607SKevin Tung         }
56*dcf4b607SKevin Tung 
57*dcf4b607SKevin Tung         auto regName = parser->getVal<std::string>(tokens, ATE::regName);
58*dcf4b607SKevin Tung         if (regName == productIdRegName)
59*dcf4b607SKevin Tung         {
60*dcf4b607SKevin Tung             configuration->productId =
61*dcf4b607SKevin Tung                 parser->getVal<uint32_t>(tokens, ATE::regDataHex);
62*dcf4b607SKevin Tung             configuration->configId =
63*dcf4b607SKevin Tung                 parser->getVal<uint32_t>(tokens, ATE::configId);
64*dcf4b607SKevin Tung         }
65*dcf4b607SKevin Tung         else if (regName == crcUserRegName)
66*dcf4b607SKevin Tung         {
67*dcf4b607SKevin Tung             configuration->crcUser =
68*dcf4b607SKevin Tung                 parser->getVal<uint32_t>(tokens, ATE::regDataHex);
69*dcf4b607SKevin Tung             break;
70*dcf4b607SKevin Tung         }
71*dcf4b607SKevin Tung     }
72*dcf4b607SKevin Tung 
73*dcf4b607SKevin Tung     co_return true;
74*dcf4b607SKevin Tung }
75*dcf4b607SKevin Tung 
verifyImage(const uint8_t * image,size_t imageSize)76*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::verifyImage(const uint8_t* image,
77*dcf4b607SKevin Tung                                                   size_t imageSize)
78*dcf4b607SKevin Tung {
79*dcf4b607SKevin Tung     if (!co_await parseImage(image, imageSize))
80*dcf4b607SKevin Tung     {
81*dcf4b607SKevin Tung         error("Image verification failed: image parsing failed");
82*dcf4b607SKevin Tung         co_return false;
83*dcf4b607SKevin Tung     }
84*dcf4b607SKevin Tung 
85*dcf4b607SKevin Tung     if (configuration->registersData.empty())
86*dcf4b607SKevin Tung     {
87*dcf4b607SKevin Tung         error("Image verification failed - no data found");
88*dcf4b607SKevin Tung         co_return false;
89*dcf4b607SKevin Tung     }
90*dcf4b607SKevin Tung 
91*dcf4b607SKevin Tung     if (configuration->productId == 0 || configuration->configId == 0)
92*dcf4b607SKevin Tung     {
93*dcf4b607SKevin Tung         error("Image verification failed - missing product or config ID");
94*dcf4b607SKevin Tung         co_return false;
95*dcf4b607SKevin Tung     }
96*dcf4b607SKevin Tung 
97*dcf4b607SKevin Tung     co_return true;
98*dcf4b607SKevin Tung }
99*dcf4b607SKevin Tung 
checkId(PMBusCmd pmBusCmd,uint32_t expected)100*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::checkId(PMBusCmd pmBusCmd,
101*dcf4b607SKevin Tung                                               uint32_t expected)
102*dcf4b607SKevin Tung {
103*dcf4b607SKevin Tung     const uint8_t cmd = static_cast<uint8_t>(pmBusCmd);
104*dcf4b607SKevin Tung     size_t idLen = 0;
105*dcf4b607SKevin Tung     bool blockRead = false;
106*dcf4b607SKevin Tung 
107*dcf4b607SKevin Tung     switch (pmBusCmd)
108*dcf4b607SKevin Tung     {
109*dcf4b607SKevin Tung         case PMBusCmd::mfrId:
110*dcf4b607SKevin Tung             idLen = vendorIdLength;
111*dcf4b607SKevin Tung             blockRead = true;
112*dcf4b607SKevin Tung             break;
113*dcf4b607SKevin Tung         case PMBusCmd::icDeviceId:
114*dcf4b607SKevin Tung             idLen = deviceIdLength;
115*dcf4b607SKevin Tung             blockRead = true;
116*dcf4b607SKevin Tung             break;
117*dcf4b607SKevin Tung         case PMBusCmd::mfrSerial:
118*dcf4b607SKevin Tung             idLen = configIdLength;
119*dcf4b607SKevin Tung             break;
120*dcf4b607SKevin Tung         default:
121*dcf4b607SKevin Tung             error("Invalid command for ID check: {CMD}", "CMD", lg2::hex, cmd);
122*dcf4b607SKevin Tung             co_return false;
123*dcf4b607SKevin Tung     }
124*dcf4b607SKevin Tung 
125*dcf4b607SKevin Tung     std::vector<uint8_t> rbuf;
126*dcf4b607SKevin Tung     std::vector<uint8_t> tbuf;
127*dcf4b607SKevin Tung 
128*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
129*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
130*dcf4b607SKevin Tung     {
131*dcf4b607SKevin Tung         error("Failed to set page 0 for ID check");
132*dcf4b607SKevin Tung         co_return false;
133*dcf4b607SKevin Tung     }
134*dcf4b607SKevin Tung 
135*dcf4b607SKevin Tung     tbuf = {cmd};
136*dcf4b607SKevin Tung     rbuf.resize(idLen + (blockRead ? statusByteLength : 0));
137*dcf4b607SKevin Tung 
138*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
139*dcf4b607SKevin Tung     {
140*dcf4b607SKevin Tung         error("I2C failure during ID check, cmd {CMD}", "CMD", lg2::hex, cmd);
141*dcf4b607SKevin Tung         co_return false;
142*dcf4b607SKevin Tung     }
143*dcf4b607SKevin Tung 
144*dcf4b607SKevin Tung     auto idBytes = std::span(rbuf).subspan(blockRead ? statusByteLength : 0);
145*dcf4b607SKevin Tung     uint32_t id = bytesToInt<uint32_t>(idBytes);
146*dcf4b607SKevin Tung 
147*dcf4b607SKevin Tung     if (id != expected)
148*dcf4b607SKevin Tung     {
149*dcf4b607SKevin Tung         error("ID check failed for cmd {CMD}: got {ID}, expected {EXP}", "CMD",
150*dcf4b607SKevin Tung               lg2::hex, cmd, "ID", lg2::hex, id, "EXP", lg2::hex, expected);
151*dcf4b607SKevin Tung         co_return false;
152*dcf4b607SKevin Tung     }
153*dcf4b607SKevin Tung 
154*dcf4b607SKevin Tung     co_return true;
155*dcf4b607SKevin Tung }
156*dcf4b607SKevin Tung 
unlockWriteProtect()157*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::unlockWriteProtect()
158*dcf4b607SKevin Tung {
159*dcf4b607SKevin Tung     std::vector<uint8_t> tbuf;
160*dcf4b607SKevin Tung     std::vector<uint8_t> rbuf;
161*dcf4b607SKevin Tung 
162*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
163*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
164*dcf4b607SKevin Tung     {
165*dcf4b607SKevin Tung         error("Failed to set page 0 for unlocking write protect");
166*dcf4b607SKevin Tung         co_return false;
167*dcf4b607SKevin Tung     }
168*dcf4b607SKevin Tung 
169*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::writeProtect, disableWriteProtect);
170*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
171*dcf4b607SKevin Tung     {
172*dcf4b607SKevin Tung         error("Failed to disable write protect");
173*dcf4b607SKevin Tung         co_return false;
174*dcf4b607SKevin Tung     }
175*dcf4b607SKevin Tung 
176*dcf4b607SKevin Tung     // unlock page 2 write protect
177*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page1);
178*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
179*dcf4b607SKevin Tung     {
180*dcf4b607SKevin Tung         error("Failed to set page 1 for unlocking write protect for page 2");
181*dcf4b607SKevin Tung         co_return false;
182*dcf4b607SKevin Tung     }
183*dcf4b607SKevin Tung 
184*dcf4b607SKevin Tung     tbuf =
185*dcf4b607SKevin Tung         buildByteVector(MP2X6XXCmd::mfrMTPMemoryCtrl, disablePage2WriteProtect);
186*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
187*dcf4b607SKevin Tung     {
188*dcf4b607SKevin Tung         error("Failed to unlock page 2 write protect");
189*dcf4b607SKevin Tung         co_return false;
190*dcf4b607SKevin Tung     }
191*dcf4b607SKevin Tung 
192*dcf4b607SKevin Tung     // unlock page 3 write protect
193*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page3);
194*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
195*dcf4b607SKevin Tung     {
196*dcf4b607SKevin Tung         error("Failed to set page 3 for unlocking write protect for page 3");
197*dcf4b607SKevin Tung         co_return false;
198*dcf4b607SKevin Tung     }
199*dcf4b607SKevin Tung 
200*dcf4b607SKevin Tung     tbuf = buildByteVector(MP2X6XXCmd::mfrMTPMemoryCtrlPage3,
201*dcf4b607SKevin Tung                            disablePage3WriteProtect);
202*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
203*dcf4b607SKevin Tung     {
204*dcf4b607SKevin Tung         error("Failed to unlock page 3 write protect");
205*dcf4b607SKevin Tung         co_return false;
206*dcf4b607SKevin Tung     }
207*dcf4b607SKevin Tung 
208*dcf4b607SKevin Tung     debug("Unlocked write protect");
209*dcf4b607SKevin Tung 
210*dcf4b607SKevin Tung     co_return true;
211*dcf4b607SKevin Tung }
212*dcf4b607SKevin Tung 
selectConfig(uint8_t config)213*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::selectConfig(uint8_t config)
214*dcf4b607SKevin Tung {
215*dcf4b607SKevin Tung     // MPS config select command:
216*dcf4b607SKevin Tung     // Writes to Page 2 @ 0x1A: value = 0x0F00 | ((config + 7) << 4)
217*dcf4b607SKevin Tung     // For config 1–6 → result: 0x0F80 to 0x0FD0
218*dcf4b607SKevin Tung 
219*dcf4b607SKevin Tung     std::vector<uint8_t> tbuf;
220*dcf4b607SKevin Tung     std::vector<uint8_t> rbuf;
221*dcf4b607SKevin Tung 
222*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page2);
223*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
224*dcf4b607SKevin Tung     {
225*dcf4b607SKevin Tung         error("Failed to set page 2 for configuration switch");
226*dcf4b607SKevin Tung         co_return false;
227*dcf4b607SKevin Tung     }
228*dcf4b607SKevin Tung 
229*dcf4b607SKevin Tung     constexpr uint8_t baseOffset = 7;
230*dcf4b607SKevin Tung     uint8_t encodedNibble = static_cast<uint8_t>((config + baseOffset) << 4);
231*dcf4b607SKevin Tung     uint16_t command = 0x0F00 | encodedNibble;
232*dcf4b607SKevin Tung 
233*dcf4b607SKevin Tung     tbuf = buildByteVector(MP2X6XXCmd::selectConfigCtrl, command);
234*dcf4b607SKevin Tung 
235*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
236*dcf4b607SKevin Tung     {
237*dcf4b607SKevin Tung         error("Failed to write config select command {CMD} for config {CONFIG}",
238*dcf4b607SKevin Tung               "CMD", lg2::hex, command, "CONFIG", config);
239*dcf4b607SKevin Tung         co_return false;
240*dcf4b607SKevin Tung     }
241*dcf4b607SKevin Tung 
242*dcf4b607SKevin Tung     debug("Switched to config {CONFIG}", "CONFIG", config);
243*dcf4b607SKevin Tung     co_return true;
244*dcf4b607SKevin Tung }
245*dcf4b607SKevin Tung 
programConfigData(const std::vector<MPSData> & gdata)246*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::programConfigData(
247*dcf4b607SKevin Tung     const std::vector<MPSData>& gdata)
248*dcf4b607SKevin Tung {
249*dcf4b607SKevin Tung     std::vector<uint8_t> tbuf;
250*dcf4b607SKevin Tung     std::vector<uint8_t> rbuf;
251*dcf4b607SKevin Tung 
252*dcf4b607SKevin Tung     for (const auto& data : gdata)
253*dcf4b607SKevin Tung     {
254*dcf4b607SKevin Tung         uint8_t page = data.page & pageMask;
255*dcf4b607SKevin Tung 
256*dcf4b607SKevin Tung         tbuf = buildByteVector(PMBusCmd::page, page);
257*dcf4b607SKevin Tung         if (!i2cInterface.sendReceive(tbuf, rbuf))
258*dcf4b607SKevin Tung         {
259*dcf4b607SKevin Tung             error("Failed to set page {PAGE} for register {REG}", "PAGE", page,
260*dcf4b607SKevin Tung                   "REG", lg2::hex, data.addr);
261*dcf4b607SKevin Tung             co_return false;
262*dcf4b607SKevin Tung         }
263*dcf4b607SKevin Tung 
264*dcf4b607SKevin Tung         tbuf = {data.addr};
265*dcf4b607SKevin Tung         tbuf.insert(tbuf.end(), data.data.begin(),
266*dcf4b607SKevin Tung                     data.data.begin() + data.length);
267*dcf4b607SKevin Tung 
268*dcf4b607SKevin Tung         if (!i2cInterface.sendReceive(tbuf, rbuf))
269*dcf4b607SKevin Tung         {
270*dcf4b607SKevin Tung             error(
271*dcf4b607SKevin Tung                 "Failed to write data {DATA} to register {REG} on page {PAGE}",
272*dcf4b607SKevin Tung                 "DATA", lg2::hex, bytesToInt<uint32_t>(data.data), "REG",
273*dcf4b607SKevin Tung                 lg2::hex, data.addr, "PAGE", page);
274*dcf4b607SKevin Tung             co_return false;
275*dcf4b607SKevin Tung         }
276*dcf4b607SKevin Tung     }
277*dcf4b607SKevin Tung 
278*dcf4b607SKevin Tung     if (!co_await storeUserCode())
279*dcf4b607SKevin Tung     {
280*dcf4b607SKevin Tung         error("Failed to store user code after programming config data");
281*dcf4b607SKevin Tung         co_return false;
282*dcf4b607SKevin Tung     }
283*dcf4b607SKevin Tung 
284*dcf4b607SKevin Tung     co_return true;
285*dcf4b607SKevin Tung }
286*dcf4b607SKevin Tung 
configAllRegisters()287*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::configAllRegisters()
288*dcf4b607SKevin Tung {
289*dcf4b607SKevin Tung     for (const auto& [config, gdata] : getGroupedConfigData(configMask, 4))
290*dcf4b607SKevin Tung     {
291*dcf4b607SKevin Tung         debug("Configuring registers for config {CONFIG}", "CONFIG", config);
292*dcf4b607SKevin Tung 
293*dcf4b607SKevin Tung         // Select the appropriate config before programming its registers
294*dcf4b607SKevin Tung         if (config > 0 && !co_await selectConfig(config))
295*dcf4b607SKevin Tung         {
296*dcf4b607SKevin Tung             co_return false;
297*dcf4b607SKevin Tung         }
298*dcf4b607SKevin Tung 
299*dcf4b607SKevin Tung         if (!co_await programConfigData(gdata))
300*dcf4b607SKevin Tung         {
301*dcf4b607SKevin Tung             error("Failed to program configuration {CONFIG}", "CONFIG", config);
302*dcf4b607SKevin Tung             co_return false;
303*dcf4b607SKevin Tung         }
304*dcf4b607SKevin Tung 
305*dcf4b607SKevin Tung         debug("Configured {SIZE} registers for config {CONFIG}", "SIZE",
306*dcf4b607SKevin Tung               gdata.size(), "CONFIG", config);
307*dcf4b607SKevin Tung     }
308*dcf4b607SKevin Tung 
309*dcf4b607SKevin Tung     co_return true;
310*dcf4b607SKevin Tung }
311*dcf4b607SKevin Tung 
storeUserCode()312*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::storeUserCode()
313*dcf4b607SKevin Tung {
314*dcf4b607SKevin Tung     std::vector<uint8_t> tbuf;
315*dcf4b607SKevin Tung     std::vector<uint8_t> rbuf;
316*dcf4b607SKevin Tung 
317*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
318*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
319*dcf4b607SKevin Tung     {
320*dcf4b607SKevin Tung         error("Failed to set page 0 for storing user code");
321*dcf4b607SKevin Tung         co_return false;
322*dcf4b607SKevin Tung     }
323*dcf4b607SKevin Tung 
324*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::storeUserCode);
325*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
326*dcf4b607SKevin Tung     {
327*dcf4b607SKevin Tung         error("Failed to store user code");
328*dcf4b607SKevin Tung         co_return false;
329*dcf4b607SKevin Tung     }
330*dcf4b607SKevin Tung 
331*dcf4b607SKevin Tung     // Wait store user code
332*dcf4b607SKevin Tung     co_await sdbusplus::async::sleep_for(ctx, std::chrono::milliseconds(500));
333*dcf4b607SKevin Tung 
334*dcf4b607SKevin Tung     debug("Stored user code");
335*dcf4b607SKevin Tung 
336*dcf4b607SKevin Tung     co_return true;
337*dcf4b607SKevin Tung }
338*dcf4b607SKevin Tung 
getCRC(uint32_t * checksum)339*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::getCRC(uint32_t* checksum)
340*dcf4b607SKevin Tung {
341*dcf4b607SKevin Tung     if (checksum == nullptr)
342*dcf4b607SKevin Tung     {
343*dcf4b607SKevin Tung         error("getCRC() called with null checksum pointer");
344*dcf4b607SKevin Tung         co_return false;
345*dcf4b607SKevin Tung     }
346*dcf4b607SKevin Tung 
347*dcf4b607SKevin Tung     std::vector<uint8_t> tbuf;
348*dcf4b607SKevin Tung     std::vector<uint8_t> rbuf;
349*dcf4b607SKevin Tung 
350*dcf4b607SKevin Tung     tbuf = buildByteVector(PMBusCmd::page, MPSPage::page0);
351*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
352*dcf4b607SKevin Tung     {
353*dcf4b607SKevin Tung         error("Failed to set page 0 for CRC read");
354*dcf4b607SKevin Tung         co_return false;
355*dcf4b607SKevin Tung     }
356*dcf4b607SKevin Tung 
357*dcf4b607SKevin Tung     tbuf = buildByteVector(MP2X6XXCmd::readCRCReg);
358*dcf4b607SKevin Tung     rbuf.resize(crcLength);
359*dcf4b607SKevin Tung     if (!i2cInterface.sendReceive(tbuf, rbuf))
360*dcf4b607SKevin Tung     {
361*dcf4b607SKevin Tung         error("Failed to read CRC from device");
362*dcf4b607SKevin Tung         co_return false;
363*dcf4b607SKevin Tung     }
364*dcf4b607SKevin Tung 
365*dcf4b607SKevin Tung     if (rbuf.size() < crcLength)
366*dcf4b607SKevin Tung     {
367*dcf4b607SKevin Tung         error("CRC read returned insufficient data");
368*dcf4b607SKevin Tung         co_return false;
369*dcf4b607SKevin Tung     }
370*dcf4b607SKevin Tung 
371*dcf4b607SKevin Tung     *checksum = bytesToInt<uint32_t>(rbuf);
372*dcf4b607SKevin Tung 
373*dcf4b607SKevin Tung     debug("Read CRC: {CRC}", "CRC", lg2::hex, *checksum);
374*dcf4b607SKevin Tung 
375*dcf4b607SKevin Tung     co_return true;
376*dcf4b607SKevin Tung }
377*dcf4b607SKevin Tung 
checkMTPCRC()378*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::checkMTPCRC()
379*dcf4b607SKevin Tung {
380*dcf4b607SKevin Tung     uint32_t crc = 0;
381*dcf4b607SKevin Tung     // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
382*dcf4b607SKevin Tung     if (!co_await getCRC(&crc))
383*dcf4b607SKevin Tung     // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
384*dcf4b607SKevin Tung     {
385*dcf4b607SKevin Tung         error("Failed to get CRC for MTP check");
386*dcf4b607SKevin Tung         co_return false;
387*dcf4b607SKevin Tung     }
388*dcf4b607SKevin Tung 
389*dcf4b607SKevin Tung     debug("MTP CRC: {CRC}, Expected: {EXP}", "CRC", lg2::hex, crc, "EXP",
390*dcf4b607SKevin Tung           lg2::hex, configuration->crcUser);
391*dcf4b607SKevin Tung 
392*dcf4b607SKevin Tung     co_return configuration->crcUser == crc;
393*dcf4b607SKevin Tung }
394*dcf4b607SKevin Tung 
forcedUpdateAllowed()395*dcf4b607SKevin Tung bool MP2X6XX::forcedUpdateAllowed()
396*dcf4b607SKevin Tung {
397*dcf4b607SKevin Tung     return true;
398*dcf4b607SKevin Tung }
399*dcf4b607SKevin Tung 
updateFirmware(bool force)400*dcf4b607SKevin Tung sdbusplus::async::task<bool> MP2X6XX::updateFirmware(bool force)
401*dcf4b607SKevin Tung {
402*dcf4b607SKevin Tung     (void)force;
403*dcf4b607SKevin Tung 
404*dcf4b607SKevin Tung     if (!co_await checkId(PMBusCmd::mfrId, configuration->vendorId))
405*dcf4b607SKevin Tung     {
406*dcf4b607SKevin Tung         co_return false;
407*dcf4b607SKevin Tung     }
408*dcf4b607SKevin Tung 
409*dcf4b607SKevin Tung     if (!co_await checkId(PMBusCmd::icDeviceId, configuration->productId))
410*dcf4b607SKevin Tung     {
411*dcf4b607SKevin Tung         co_return false;
412*dcf4b607SKevin Tung     }
413*dcf4b607SKevin Tung 
414*dcf4b607SKevin Tung     if (!co_await checkId(PMBusCmd::mfrSerial, configuration->configId))
415*dcf4b607SKevin Tung     {
416*dcf4b607SKevin Tung         co_return false;
417*dcf4b607SKevin Tung     }
418*dcf4b607SKevin Tung 
419*dcf4b607SKevin Tung     if (!co_await unlockWriteProtect())
420*dcf4b607SKevin Tung     {
421*dcf4b607SKevin Tung         co_return false;
422*dcf4b607SKevin Tung     }
423*dcf4b607SKevin Tung 
424*dcf4b607SKevin Tung     if (!co_await configAllRegisters())
425*dcf4b607SKevin Tung     {
426*dcf4b607SKevin Tung         co_return false;
427*dcf4b607SKevin Tung     }
428*dcf4b607SKevin Tung 
429*dcf4b607SKevin Tung     if (!(co_await checkMTPCRC()))
430*dcf4b607SKevin Tung     {
431*dcf4b607SKevin Tung         co_return false;
432*dcf4b607SKevin Tung     }
433*dcf4b607SKevin Tung 
434*dcf4b607SKevin Tung     co_return true;
435*dcf4b607SKevin Tung }
436*dcf4b607SKevin Tung 
437*dcf4b607SKevin Tung } // namespace phosphor::software::VR
438