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