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