1 #include "mps.hpp" 2 3 namespace phosphor::software::VR 4 { 5 6 bool MPSImageParser::isValidDataTokens( 7 const std::vector<std::string_view>& tokens) 8 { 9 return tokens.size() > static_cast<size_t>(ATE::regName) && 10 !tokens[0].starts_with('*'); 11 } 12 13 MPSData MPSImageParser::extractType0Data( 14 const std::vector<std::string_view>& tokens) 15 { 16 MPSData data; 17 static constexpr size_t type0TokensSize = 7; 18 19 if (tokens.size() != type0TokensSize) 20 { 21 lg2::error("Invalid token count for Type0 image line: " 22 "expected {EXPECTED}, got {ACTUAL}", 23 "EXPECTED", type0TokensSize, "ACTUAL", tokens.size()); 24 return data; 25 } 26 27 data.page = getVal<uint8_t>(tokens, ATE::pageNum); 28 data.addr = getVal<uint8_t>(tokens, ATE::regAddrHex); 29 30 std::string regData = getVal<std::string>(tokens, ATE::regDataHex); 31 size_t byteCount = std::min(regData.length() / 2, size_t(4)); 32 for (size_t i = 0; i < byteCount; ++i) 33 { 34 data.data[byteCount - 1 - i] = static_cast<uint8_t>( 35 std::stoul(regData.substr(i * 2, 2), nullptr, 16)); 36 } 37 38 data.length = static_cast<uint8_t>(byteCount); 39 return data; 40 } 41 42 MPSData MPSImageParser::extractType1Data( 43 const std::vector<std::string_view>& tokens) 44 { 45 MPSData data; 46 static constexpr size_t type0TokensSize = 8; 47 48 if (tokens.size() != type0TokensSize) 49 { 50 lg2::error("Invalid token count for Type1 image line: " 51 "expected {EXPECTED}, got {ACTUAL}", 52 "EXPECTED", type0TokensSize, "ACTUAL", tokens.size()); 53 return data; 54 } 55 56 data.page = getVal<uint8_t>(tokens, ATE::pageNum); 57 auto addr = getVal<uint16_t>(tokens, ATE::regAddrHex); 58 auto cmdType = getVal<std::string>(tokens, ATE::writeType); 59 int blockDataBytes = 0; 60 61 if (cmdType.starts_with("P")) 62 { 63 // Check if these tokens represent a P1 or P2 process call. 64 // The upper byte of 'addr' is the command code, and the lower byte 65 // is the LSB of the data. 66 // Example: 67 // addr = 0x0F11 and data = 0x18, this sends 0x1811 to command 0x0F 68 static constexpr uint16_t processCallAddrMask = 0xFF00; 69 data.data[0] = static_cast<uint8_t>(addr & ~processCallAddrMask); 70 data.data[1] = getVal<uint8_t>(tokens, ATE::regDataHex); 71 data.addr = static_cast<uint8_t>((addr & processCallAddrMask) >> 8); 72 data.length = 2; 73 return data; 74 } 75 else if (cmdType.starts_with("B")) 76 { 77 // Command types starting with 'B' indicate block r/w commands. 78 // The number following 'B' specifies the number of data bytes. 79 if (cmdType.size() > 1 && std::isdigit(cmdType[1])) 80 { 81 blockDataBytes = std::stoi(cmdType.substr(1)); 82 } 83 } 84 85 std::string regData = getVal<std::string>(tokens, ATE::regDataHex); 86 size_t byteCount = std::min(regData.length() / 2, size_t(4)); 87 size_t dataIndex = 0; 88 89 if (blockDataBytes > 0) 90 { 91 data.data[dataIndex++] = static_cast<uint8_t>(blockDataBytes); 92 } 93 94 for (size_t i = 0; i < byteCount; ++i) 95 { 96 data.data[dataIndex + (byteCount - 1 - i)] = static_cast<uint8_t>( 97 std::stoul(regData.substr(i * 2, 2), nullptr, 16)); 98 } 99 data.length = static_cast<uint8_t>(dataIndex + byteCount); 100 data.addr = getVal<uint8_t>(tokens, ATE::regAddrHex); 101 return data; 102 } 103 104 std::vector<MPSData> MPSImageParser::parse( 105 const uint8_t* image, size_t imageSize, MPSImageType imageType) 106 { 107 lineTokens = TokenizedLines(image, imageSize); 108 std::vector<MPSData> results; 109 110 using ExtractDataFunc = 111 std::function<MPSData(const std::vector<std::string_view>&)>; 112 ExtractDataFunc extractDataFunc; 113 114 switch (imageType) 115 { 116 case MPSImageType::type0: 117 extractDataFunc = [this](const auto& tokens) { 118 return extractType0Data(tokens); 119 }; 120 break; 121 case MPSImageType::type1: 122 extractDataFunc = [this](const auto& tokens) { 123 return extractType1Data(tokens); 124 }; 125 break; 126 default: 127 lg2::error("Unsupported or unknown MPS image type: {TYPE}", "TYPE", 128 static_cast<int>(imageType)); 129 return results; 130 } 131 132 for (const auto& tokens : lineTokens) 133 { 134 if (tokens[0].starts_with("END")) 135 { 136 break; 137 } 138 139 if (isValidDataTokens(tokens)) 140 { 141 auto data = extractDataFunc(tokens); 142 if (data.length == 0) 143 { 144 return {}; 145 } 146 results.push_back(data); 147 } 148 } 149 150 return results; 151 } 152 153 sdbusplus::async::task<bool> MPSVoltageRegulator::parseImage( 154 const uint8_t* image, size_t imageSize, MPSImageType imageType) 155 { 156 configuration = std::make_unique<MPSConfig>(); 157 158 try 159 { 160 configuration->registersData = 161 parser->parse(image, imageSize, imageType); 162 163 if (!co_await parseDeviceConfiguration()) 164 { 165 co_return false; 166 } 167 } 168 catch (const std::exception& e) 169 { 170 lg2::error("Failed to parse MPS image: {ERR}", "ERR", e.what()); 171 co_return false; 172 } 173 174 lg2::debug( 175 "Parsed configuration: Data Size={SIZE}, Vendor ID={VID}, " 176 "Product ID={PID}, Config ID={CID}, CRC User={CRCUSR}, " 177 "CRC Multi={CRCMULTI}", 178 "SIZE", configuration->registersData.size(), "VID", lg2::hex, 179 configuration->vendorId, "PID", lg2::hex, configuration->productId, 180 "CID", lg2::hex, configuration->configId, "CRCUSR", lg2::hex, 181 configuration->crcUser, "CRCMULTI", lg2::hex, configuration->crcMulti); 182 183 co_return true; 184 } 185 186 std::map<uint8_t, std::vector<MPSData>> 187 MPSVoltageRegulator::getGroupedConfigData(uint8_t configMask, uint8_t shift) 188 { 189 std::map<uint8_t, std::vector<MPSData>> groupedData; 190 191 if (!configuration) 192 { 193 return groupedData; 194 } 195 196 for (const auto& data : configuration->registersData) 197 { 198 uint8_t config = (data.page & configMask) >> shift; 199 groupedData[config].push_back(data); 200 } 201 202 return groupedData; 203 } 204 205 } // namespace phosphor::software::VR 206