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 page29 = 0x29, 60 page2A = 0x2A, 61 }; 62 63 struct MPSData 64 { 65 uint8_t page = 0; 66 uint8_t addr = 0; 67 uint8_t length = 0; 68 std::array<uint8_t, 4> data{}; 69 }; 70 71 struct MPSConfig 72 { 73 uint32_t vendorId = 0; 74 uint32_t productId = 0; 75 uint32_t configId = 0; 76 uint32_t crcUser = 0; 77 uint32_t crcMulti = 0; 78 std::vector<MPSData> registersData; 79 }; 80 81 /** 82 * @brief 83 * Utility class to iterate over lines and tokenize them by tab characters. 84 */ 85 class TokenizedLines 86 { 87 public: 88 TokenizedLines() = default; TokenizedLines(const uint8_t * d,size_t s)89 TokenizedLines(const uint8_t* d, size_t s) : 90 data(reinterpret_cast<const char*>(d), s) 91 {} 92 /** 93 * @brief Iterator over tokenized lines. 94 */ 95 struct Iterator 96 { 97 using iterator_category = std::forward_iterator_tag; 98 using value_type = std::vector<std::string_view>; 99 using difference_type = std::ptrdiff_t; 100 using pointer = const value_type*; 101 using reference = const value_type&; 102 103 Iterator() = default; // End iterator Iteratorphosphor::software::VR::TokenizedLines::Iterator104 Iterator(std::string_view sv) : remaining(sv) 105 { 106 next(); 107 } 108 operator *phosphor::software::VR::TokenizedLines::Iterator109 reference operator*() const 110 { 111 return currentTokens; 112 } 113 operator ->phosphor::software::VR::TokenizedLines::Iterator114 pointer operator->() const 115 { 116 return ¤tTokens; 117 } 118 operator ++phosphor::software::VR::TokenizedLines::Iterator119 Iterator& operator++() 120 { 121 next(); 122 return *this; 123 } 124 operator ++phosphor::software::VR::TokenizedLines::Iterator125 Iterator operator++(int) 126 { 127 auto result = *this; 128 ++(*this); 129 return result; 130 } 131 operator ==(const Iterator & a,const Iterator & b)132 friend bool operator==(const Iterator& a, const Iterator& b) 133 { 134 return a.remaining.empty() && b.remaining.empty(); 135 } 136 operator !=(const Iterator & a,const Iterator & b)137 friend bool operator!=(const Iterator& a, const Iterator& b) 138 { 139 return !(a == b); 140 } 141 142 private: 143 std::string_view remaining; 144 std::vector<std::string_view> currentTokens; 145 nextphosphor::software::VR::TokenizedLines::Iterator146 void next() 147 { 148 currentTokens.clear(); 149 if (remaining.empty()) 150 { 151 return; 152 } 153 154 // Extract current line 155 auto newlinePos = remaining.find('\n'); 156 std::string_view line = remaining.substr(0, newlinePos); 157 remaining = (newlinePos == std::string_view::npos) 158 ? std::string_view{} 159 : remaining.substr(newlinePos + 1); 160 161 // Tokenize by tab 162 size_t start = 0; 163 while (start < line.size()) 164 { 165 start = line.find_first_not_of('\t', start); 166 if (start == std::string_view::npos) 167 { 168 break; 169 } 170 171 auto end = line.find('\t', start); 172 currentTokens.emplace_back(line.substr(start, end - start)); 173 start = (end == std::string_view::npos) ? line.size() : end; 174 } 175 } 176 }; 177 begin() const178 Iterator begin() const 179 { 180 return Iterator(data); 181 } 182 end()183 static Iterator end() 184 { 185 return Iterator(); 186 } 187 188 private: 189 std::string_view data; 190 }; 191 192 /** 193 * @brief Base parser for MPS configuration images. 194 */ 195 class MPSImageParser 196 { 197 public: 198 MPSImageParser() = default; 199 virtual ~MPSImageParser() = default; 200 MPSImageParser(const MPSImageParser&) = delete; 201 MPSImageParser& operator=(const MPSImageParser&) = delete; 202 MPSImageParser(MPSImageParser&&) = default; 203 MPSImageParser& operator=(MPSImageParser&&) = default; 204 205 template <typename> 206 inline static constexpr bool always_false = false; 207 208 /** 209 * @brief Extract a typed value from a tokenized line. 210 * @tparam T Return type (string or integral type) 211 * @param tokens Tokenized line 212 * @param index Column index (ATE enum) 213 * @return Parsed value or default if invalid 214 */ 215 template <typename T> getVal(const std::vector<std::string_view> & tokens,ATE index)216 T getVal(const std::vector<std::string_view>& tokens, ATE index) 217 { 218 size_t idx = static_cast<size_t>(index); 219 220 if (tokens.size() <= idx) 221 { 222 lg2::error("Index out of range for ATE enum: {INDEX}", "INDEX", 223 static_cast<uint32_t>(idx)); 224 return T{}; 225 } 226 227 std::string_view token = tokens[idx]; 228 229 if constexpr (std::is_same_v<T, std::string>) 230 { 231 return std::string(token); 232 } 233 else if constexpr (std::is_integral_v<T>) 234 { 235 unsigned long val = 0; 236 try 237 { 238 val = std::stoul(std::string(token), nullptr, 16); 239 } 240 catch (...) 241 { 242 lg2::error("Invalid hex value: {INDEX}", "INDEX", 243 static_cast<uint32_t>(idx)); 244 return T{}; 245 } 246 return static_cast<T>(val); 247 } 248 else 249 { 250 static_assert(always_false<T>, "Unsupported type in getVal"); 251 } 252 } 253 254 /** 255 * @brief Check if a tokenized line contains valid register data. 256 */ 257 static bool isValidDataTokens(const std::vector<std::string_view>& tokens); 258 259 /** 260 * @brief Parse image buffer into a list of MPSData entries. 261 */ 262 virtual std::vector<MPSData> parse( 263 const uint8_t* image, size_t imageSize, 264 MPSImageType imageType = MPSImageType::typeUnknown); 265 266 TokenizedLines lineTokens; 267 268 private: 269 MPSData extractType0Data(const std::vector<std::string_view>& tokens); 270 MPSData extractType1Data(const std::vector<std::string_view>& tokens); 271 }; 272 273 /** 274 * @brief Base class for MPS Voltage Regulators. 275 */ 276 class MPSVoltageRegulator : public VoltageRegulator 277 { 278 public: MPSVoltageRegulator(sdbusplus::async::context & ctx,uint16_t bus,uint16_t address)279 MPSVoltageRegulator(sdbusplus::async::context& ctx, uint16_t bus, 280 uint16_t address) : 281 VoltageRegulator(ctx), i2cInterface(phosphor::i2c::I2C(bus, address)) 282 {} 283 284 /** 285 * @brief Parse device-specific configuration from the loaded image. 286 * @return async task returning true if parsing succeeds 287 */ 288 virtual sdbusplus::async::task<bool> parseDeviceConfiguration() = 0; 289 290 /** 291 * @brief Parse an image file into internal MPS configuration. 292 * @param image Pointer to the image data 293 * @param imageSize Size of the image data 294 * @return async task returning true if parsing succeeds 295 */ 296 sdbusplus::async::task<bool> parseImage( 297 const uint8_t* image, size_t imageSize, 298 MPSImageType imageType = MPSImageType::typeUnknown); 299 300 /** 301 * @brief Group register data by page, optionally masked and shifted. 302 * @param configMask Bitmask to select relevant page bits (default 0xFF) 303 * @param shift Number of bits to shift masked value to obtain group key 304 * @return map of page keys to vector of MPSData 305 */ 306 std::map<uint8_t, std::vector<MPSData>> getGroupedConfigData( 307 uint8_t configMask = 0xFF, uint8_t shift = 0); 308 309 protected: 310 phosphor::i2c::I2C i2cInterface; 311 std::unique_ptr<MPSImageParser> parser = std::make_unique<MPSImageParser>(); 312 std::unique_ptr<MPSConfig> configuration; 313 }; 314 315 } // namespace phosphor::software::VR 316