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