blob: 25aa9ec52c999d2b8936f3e2f4371b18763492a8 [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
Kevin Tungc284e752025-10-14 20:47:09 +080035/**
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 */
45enum class MPSImageType : uint8_t
46{
47 type0 = 0,
48 type1,
49 typeUnknown = 0xFF
50};
51
Kevin Tungdcf4b602025-07-04 13:14:49 +080052enum class MPSPage : uint8_t
53{
54 page0 = 0,
55 page1,
56 page2,
57 page3,
58 page4,
Kevin Tung3638c242025-10-07 13:48:13 +080059 page5,
60 page6,
61 page7,
Kevin Tung3f2f3e62025-08-15 15:41:07 +080062 page29 = 0x29,
63 page2A = 0x2A,
Kevin Tungdcf4b602025-07-04 13:14:49 +080064};
65
66struct 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
74struct 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 */
88class TokenizedLines
89{
90 public:
Kevin Tungc284e752025-10-14 20:47:09 +080091 TokenizedLines() = default;
Kevin Tungdcf4b602025-07-04 13:14:49 +080092 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
107 Iterator(std::string_view sv) : remaining(sv)
108 {
109 next();
110 }
111
112 reference operator*() const
113 {
114 return currentTokens;
115 }
116
117 pointer operator->() const
118 {
119 return &currentTokens;
120 }
121
122 Iterator& operator++()
123 {
124 next();
125 return *this;
126 }
127
128 Iterator operator++(int)
129 {
130 auto result = *this;
131 ++(*this);
132 return result;
133 }
134
135 friend bool operator==(const Iterator& a, const Iterator& b)
136 {
137 return a.remaining.empty() && b.remaining.empty();
138 }
139
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
149 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
181 Iterator begin() const
182 {
183 return Iterator(data);
184 }
185
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 */
198class MPSImageParser
199{
200 public:
Kevin Tungc284e752025-10-14 20:47:09 +0800201 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;
Kevin Tungdcf4b602025-07-04 13:14:49 +0800207
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>
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 /**
Kevin Tungc284e752025-10-14 20:47:09 +0800263 * @brief Parse image buffer into a list of MPSData entries.
Kevin Tungdcf4b602025-07-04 13:14:49 +0800264 */
Kevin Tungc284e752025-10-14 20:47:09 +0800265 virtual std::vector<MPSData> parse(
266 const uint8_t* image, size_t imageSize,
267 MPSImageType imageType = MPSImageType::typeUnknown);
Kevin Tungdcf4b602025-07-04 13:14:49 +0800268
269 TokenizedLines lineTokens;
Kevin Tungc284e752025-10-14 20:47:09 +0800270
271 private:
272 MPSData extractType0Data(const std::vector<std::string_view>& tokens);
273 MPSData extractType1Data(const std::vector<std::string_view>& tokens);
Kevin Tungdcf4b602025-07-04 13:14:49 +0800274};
275
276/**
277 * @brief Base class for MPS Voltage Regulators.
278 */
279class MPSVoltageRegulator : public VoltageRegulator
280{
281 public:
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 */
Kevin Tungc284e752025-10-14 20:47:09 +0800299 sdbusplus::async::task<bool> parseImage(
300 const uint8_t* image, size_t imageSize,
301 MPSImageType imageType = MPSImageType::typeUnknown);
Kevin Tungdcf4b602025-07-04 13:14:49 +0800302
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;
Kevin Tungc284e752025-10-14 20:47:09 +0800314 std::unique_ptr<MPSImageParser> parser = std::make_unique<MPSImageParser>();
Kevin Tungdcf4b602025-07-04 13:14:49 +0800315 std::unique_ptr<MPSConfig> configuration;
316};
317
318} // namespace phosphor::software::VR