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