xref: /openbmc/phosphor-bmc-code-mgmt/i2c-vr/mps/mps.hpp (revision dcf4b607bd2937a8964d68fe9dcc59daaf20c720)
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 &currentTokens;
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