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