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