1 #pragma once 2 3 #include "common/include/i2c/i2c.hpp" 4 #include "i2c-vr/vr.hpp" 5 6 #include <phosphor-logging/lg2.hpp> 7 8 #include <cstdint> 9 #include <iterator> 10 #include <memory> 11 #include <string_view> 12 #include <vector> 13 14 namespace phosphor::software::VR 15 { 16 17 /** 18 * @brief 19 * Columns of an Automated Test Equipment (ATE) format configuration file. 20 * Each enumerator corresponds to a tab-separated column index. 21 */ 22 enum class ATE : uint8_t 23 { 24 configId = 0, 25 pageNum, 26 regAddrHex, 27 regAddrDec, 28 regName, 29 regDataHex, 30 regDataDec, 31 writeType, 32 colCount, 33 }; 34 35 /** 36 * @brief Represents the format of an MPS configuration image. 37 * 38 * type0: 7-columns ATE image without write/read command information. 39 * 40 * type1: 8-columns ATE image that includes write/read command information, 41 * specifying byte, word, block, or process call operations. 42 * 43 * typeUnknown: Unknown or unsupported image format. 44 */ 45 enum class MPSImageType : uint8_t 46 { 47 type0 = 0, 48 type1, 49 typeUnknown = 0xFF 50 }; 51 52 enum class MPSPage : uint8_t 53 { 54 page0 = 0, 55 page1, 56 page2, 57 page3, 58 page4, 59 page5, 60 page6, 61 page7, 62 page29 = 0x29, 63 page2A = 0x2A, 64 }; 65 66 struct MPSData 67 { 68 uint8_t page = 0; 69 uint8_t addr = 0; 70 uint8_t length = 0; 71 std::array<uint8_t, 4> data{}; 72 }; 73 74 struct MPSConfig 75 { 76 uint32_t vendorId = 0; 77 uint32_t productId = 0; 78 uint32_t configId = 0; 79 uint32_t crcUser = 0; 80 uint32_t crcMulti = 0; 81 std::vector<MPSData> registersData; 82 }; 83 84 /** 85 * @brief 86 * Utility class to iterate over lines and tokenize them by tab characters. 87 */ 88 class TokenizedLines 89 { 90 public: 91 TokenizedLines() = default; TokenizedLines(const uint8_t * d,size_t s)92 TokenizedLines(const uint8_t* d, size_t s) : 93 data(reinterpret_cast<const char*>(d), s) 94 {} 95 /** 96 * @brief Iterator over tokenized lines. 97 */ 98 struct Iterator 99 { 100 using iterator_category = std::forward_iterator_tag; 101 using value_type = std::vector<std::string_view>; 102 using difference_type = std::ptrdiff_t; 103 using pointer = const value_type*; 104 using reference = const value_type&; 105 106 Iterator() = default; // End iterator Iteratorphosphor::software::VR::TokenizedLines::Iterator107 Iterator(std::string_view sv) : remaining(sv) 108 { 109 next(); 110 } 111 operator *phosphor::software::VR::TokenizedLines::Iterator112 reference operator*() const 113 { 114 return currentTokens; 115 } 116 operator ->phosphor::software::VR::TokenizedLines::Iterator117 pointer operator->() const 118 { 119 return ¤tTokens; 120 } 121 operator ++phosphor::software::VR::TokenizedLines::Iterator122 Iterator& operator++() 123 { 124 next(); 125 return *this; 126 } 127 operator ++phosphor::software::VR::TokenizedLines::Iterator128 Iterator operator++(int) 129 { 130 auto result = *this; 131 ++(*this); 132 return result; 133 } 134 operator ==(const Iterator & a,const Iterator & b)135 friend bool operator==(const Iterator& a, const Iterator& b) 136 { 137 return a.remaining.empty() && b.remaining.empty(); 138 } 139 operator !=(const Iterator & a,const Iterator & b)140 friend bool operator!=(const Iterator& a, const Iterator& b) 141 { 142 return !(a == b); 143 } 144 145 private: 146 std::string_view remaining; 147 std::vector<std::string_view> currentTokens; 148 nextphosphor::software::VR::TokenizedLines::Iterator149 void next() 150 { 151 currentTokens.clear(); 152 if (remaining.empty()) 153 { 154 return; 155 } 156 157 // Extract current line 158 auto newlinePos = remaining.find('\n'); 159 std::string_view line = remaining.substr(0, newlinePos); 160 remaining = (newlinePos == std::string_view::npos) 161 ? std::string_view{} 162 : remaining.substr(newlinePos + 1); 163 164 // Tokenize by tab 165 size_t start = 0; 166 while (start < line.size()) 167 { 168 start = line.find_first_not_of('\t', start); 169 if (start == std::string_view::npos) 170 { 171 break; 172 } 173 174 auto end = line.find('\t', start); 175 currentTokens.emplace_back(line.substr(start, end - start)); 176 start = (end == std::string_view::npos) ? line.size() : end; 177 } 178 } 179 }; 180 begin() const181 Iterator begin() const 182 { 183 return Iterator(data); 184 } 185 end()186 static Iterator end() 187 { 188 return Iterator(); 189 } 190 191 private: 192 std::string_view data; 193 }; 194 195 /** 196 * @brief Base parser for MPS configuration images. 197 */ 198 class MPSImageParser 199 { 200 public: 201 MPSImageParser() = default; 202 virtual ~MPSImageParser() = default; 203 MPSImageParser(const MPSImageParser&) = delete; 204 MPSImageParser& operator=(const MPSImageParser&) = delete; 205 MPSImageParser(MPSImageParser&&) = default; 206 MPSImageParser& operator=(MPSImageParser&&) = default; 207 208 template <typename> 209 inline static constexpr bool always_false = false; 210 211 /** 212 * @brief Extract a typed value from a tokenized line. 213 * @tparam T Return type (string or integral type) 214 * @param tokens Tokenized line 215 * @param index Column index (ATE enum) 216 * @return Parsed value or default if invalid 217 */ 218 template <typename T> getVal(const std::vector<std::string_view> & tokens,ATE index)219 T getVal(const std::vector<std::string_view>& tokens, ATE index) 220 { 221 size_t idx = static_cast<size_t>(index); 222 223 if (tokens.size() <= idx) 224 { 225 lg2::error("Index out of range for ATE enum: {INDEX}", "INDEX", 226 static_cast<uint32_t>(idx)); 227 return T{}; 228 } 229 230 std::string_view token = tokens[idx]; 231 232 if constexpr (std::is_same_v<T, std::string>) 233 { 234 return std::string(token); 235 } 236 else if constexpr (std::is_integral_v<T>) 237 { 238 unsigned long val = 0; 239 try 240 { 241 val = std::stoul(std::string(token), nullptr, 16); 242 } 243 catch (...) 244 { 245 lg2::error("Invalid hex value: {INDEX}", "INDEX", 246 static_cast<uint32_t>(idx)); 247 return T{}; 248 } 249 return static_cast<T>(val); 250 } 251 else 252 { 253 static_assert(always_false<T>, "Unsupported type in getVal"); 254 } 255 } 256 257 /** 258 * @brief Check if a tokenized line contains valid register data. 259 */ 260 static bool isValidDataTokens(const std::vector<std::string_view>& tokens); 261 262 /** 263 * @brief Parse image buffer into a list of MPSData entries. 264 */ 265 virtual std::vector<MPSData> parse( 266 const uint8_t* image, size_t imageSize, 267 MPSImageType imageType = MPSImageType::typeUnknown); 268 269 TokenizedLines lineTokens; 270 271 private: 272 MPSData extractType0Data(const std::vector<std::string_view>& tokens); 273 MPSData extractType1Data(const std::vector<std::string_view>& tokens); 274 }; 275 276 /** 277 * @brief Base class for MPS Voltage Regulators. 278 */ 279 class MPSVoltageRegulator : public VoltageRegulator 280 { 281 public: MPSVoltageRegulator(sdbusplus::async::context & ctx,uint16_t bus,uint16_t address)282 MPSVoltageRegulator(sdbusplus::async::context& ctx, uint16_t bus, 283 uint16_t address) : 284 VoltageRegulator(ctx), i2cInterface(phosphor::i2c::I2C(bus, address)) 285 {} 286 287 /** 288 * @brief Parse device-specific configuration from the loaded image. 289 * @return async task returning true if parsing succeeds 290 */ 291 virtual sdbusplus::async::task<bool> parseDeviceConfiguration() = 0; 292 293 /** 294 * @brief Parse an image file into internal MPS configuration. 295 * @param image Pointer to the image data 296 * @param imageSize Size of the image data 297 * @return async task returning true if parsing succeeds 298 */ 299 sdbusplus::async::task<bool> parseImage( 300 const uint8_t* image, size_t imageSize, 301 MPSImageType imageType = MPSImageType::typeUnknown); 302 303 /** 304 * @brief Group register data by page, optionally masked and shifted. 305 * @param configMask Bitmask to select relevant page bits (default 0xFF) 306 * @param shift Number of bits to shift masked value to obtain group key 307 * @return map of page keys to vector of MPSData 308 */ 309 std::map<uint8_t, std::vector<MPSData>> getGroupedConfigData( 310 uint8_t configMask = 0xFF, uint8_t shift = 0); 311 312 protected: 313 phosphor::i2c::I2C i2cInterface; 314 std::unique_ptr<MPSImageParser> parser = std::make_unique<MPSImageParser>(); 315 std::unique_ptr<MPSConfig> configuration; 316 }; 317 318 } // namespace phosphor::software::VR 319