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