1
2
3
4
5
6
7
8
9#include "qemu/osdep.h"
10#include <math.h>
11#include "hw/i2c/pmbus_device.h"
12#include "libqtest-single.h"
13#include "libqos/qgraph.h"
14#include "libqos/i2c.h"
15#include "qapi/qmp/qdict.h"
16#include "qapi/qmp/qnum.h"
17#include "qemu/bitops.h"
18
19#define TEST_ID "adm1272-test"
20#define TEST_ADDR (0x10)
21
22#define ADM1272_RESTART_TIME 0xCC
23#define ADM1272_MFR_PEAK_IOUT 0xD0
24#define ADM1272_MFR_PEAK_VIN 0xD1
25#define ADM1272_MFR_PEAK_VOUT 0xD2
26#define ADM1272_MFR_PMON_CONTROL 0xD3
27#define ADM1272_MFR_PMON_CONFIG 0xD4
28#define ADM1272_MFR_ALERT1_CONFIG 0xD5
29#define ADM1272_MFR_ALERT2_CONFIG 0xD6
30#define ADM1272_MFR_PEAK_TEMPERATURE 0xD7
31#define ADM1272_MFR_DEVICE_CONFIG 0xD8
32#define ADM1272_MFR_POWER_CYCLE 0xD9
33#define ADM1272_MFR_PEAK_PIN 0xDA
34#define ADM1272_MFR_READ_PIN_EXT 0xDB
35#define ADM1272_MFR_READ_EIN_EXT 0xDC
36
37#define ADM1272_HYSTERESIS_LOW 0xF2
38#define ADM1272_HYSTERESIS_HIGH 0xF3
39#define ADM1272_STATUS_HYSTERESIS 0xF4
40#define ADM1272_STATUS_GPIO 0xF5
41#define ADM1272_STRT_UP_IOUT_LIM 0xF6
42
43
44#define ADM1272_OPERATION_DEFAULT 0x80
45#define ADM1272_CAPABILITY_DEFAULT 0xB0
46#define ADM1272_CAPABILITY_NO_PEC 0x30
47#define ADM1272_DIRECT_MODE 0x40
48#define ADM1272_HIGH_LIMIT_DEFAULT 0x0FFF
49#define ADM1272_PIN_OP_DEFAULT 0x7FFF
50#define ADM1272_PMBUS_REVISION_DEFAULT 0x22
51#define ADM1272_MFR_ID_DEFAULT "ADI"
52#define ADM1272_MODEL_DEFAULT "ADM1272-A1"
53#define ADM1272_MFR_DEFAULT_REVISION "25"
54#define ADM1272_DEFAULT_DATE "160301"
55#define ADM1272_RESTART_TIME_DEFAULT 0x64
56#define ADM1272_PMON_CONTROL_DEFAULT 0x1
57#define ADM1272_PMON_CONFIG_DEFAULT 0x3F35
58#define ADM1272_DEVICE_CONFIG_DEFAULT 0x8
59#define ADM1272_HYSTERESIS_HIGH_DEFAULT 0xFFFF
60#define ADM1272_STRT_UP_IOUT_LIM_DEFAULT 0x000F
61#define ADM1272_VOLT_DEFAULT 12000
62#define ADM1272_IOUT_DEFAULT 25000
63#define ADM1272_PWR_DEFAULT 300
64#define ADM1272_SHUNT 300
65#define ADM1272_VOLTAGE_COEFF_DEFAULT 1
66#define ADM1272_CURRENT_COEFF_DEFAULT 3
67#define ADM1272_PWR_COEFF_DEFAULT 7
68#define ADM1272_IOUT_OFFSET 0x5000
69#define ADM1272_IOUT_OFFSET 0x5000
70
71static const PMBusCoefficients adm1272_coefficients[] = {
72 [0] = { 6770, 0, -2 },
73 [1] = { 4062, 0, -2 },
74 [2] = { 1326, 20480, -1 },
75 [3] = { 663, 20480, -1 },
76 [4] = { 3512, 0, -2 },
77 [5] = { 21071, 0, -3 },
78 [6] = { 17561, 0, -3 },
79 [7] = { 10535, 0, -3 },
80 [8] = { 42, 31871, -1 },
81};
82
83uint16_t pmbus_data2direct_mode(PMBusCoefficients c, uint32_t value)
84{
85
86 uint16_t y = (c.m * value + c.b) * pow(10, c.R);
87 return y;
88}
89
90uint32_t pmbus_direct_mode2data(PMBusCoefficients c, uint16_t value)
91{
92
93 uint32_t x = (value / pow(10, c.R) - c.b) / c.m;
94 return x;
95}
96
97
98static uint16_t adm1272_millivolts_to_direct(uint32_t value)
99{
100 PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
101 c.b = c.b * 1000;
102 c.R = c.R - 3;
103 return pmbus_data2direct_mode(c, value);
104}
105
106static uint32_t adm1272_direct_to_millivolts(uint16_t value)
107{
108 PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
109 c.b = c.b * 1000;
110 c.R = c.R - 3;
111 return pmbus_direct_mode2data(c, value);
112}
113
114static uint16_t adm1272_milliamps_to_direct(uint32_t value)
115{
116 PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
117
118 c.m = c.m * ADM1272_SHUNT / 1000;
119 c.b = c.b * 1000;
120 c.R = c.R - 3;
121 return pmbus_data2direct_mode(c, value);
122}
123
124static uint32_t adm1272_direct_to_milliamps(uint16_t value)
125{
126 PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
127 c.m = c.m * ADM1272_SHUNT / 1000;
128 c.b = c.b * 1000;
129 c.R = c.R - 3;
130 return pmbus_direct_mode2data(c, value);
131}
132
133static uint16_t adm1272_watts_to_direct(uint32_t value)
134{
135 PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
136 c.m = c.m * ADM1272_SHUNT / 1000;
137 return pmbus_data2direct_mode(c, value);
138}
139
140static uint32_t adm1272_direct_to_watts(uint16_t value)
141{
142 PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
143 c.m = c.m * ADM1272_SHUNT / 1000;
144 return pmbus_direct_mode2data(c, value);
145}
146
147static uint16_t qmp_adm1272_get(const char *id, const char *property)
148{
149 QDict *response;
150 uint64_t ret;
151
152 response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
153 "'property': %s } }", id, property);
154 g_assert(qdict_haskey(response, "return"));
155 ret = qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
156 qobject_unref(response);
157 return ret;
158}
159
160static void qmp_adm1272_set(const char *id,
161 const char *property,
162 uint16_t value)
163{
164 QDict *response;
165
166 response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
167 "'property': %s, 'value': %u } }", id, property, value);
168 g_assert(qdict_haskey(response, "return"));
169 qobject_unref(response);
170}
171
172
173static uint16_t adm1272_i2c_get16(QI2CDevice *i2cdev, uint8_t reg)
174{
175 uint8_t resp[2];
176 i2c_read_block(i2cdev, reg, resp, sizeof(resp));
177 return (resp[1] << 8) | resp[0];
178}
179
180
181static void adm1272_i2c_set16(QI2CDevice *i2cdev, uint8_t reg, uint16_t value)
182{
183 uint8_t data[2];
184
185 data[0] = value & 255;
186 data[1] = value >> 8;
187 i2c_write_block(i2cdev, reg, data, sizeof(data));
188}
189
190static void test_defaults(void *obj, void *data, QGuestAllocator *alloc)
191{
192 uint16_t value, i2c_value;
193 int16_t err;
194 QI2CDevice *i2cdev = (QI2CDevice *)obj;
195 value = qmp_adm1272_get(TEST_ID, "vout");
196 err = ADM1272_VOLT_DEFAULT - value;
197 g_assert_cmpuint(abs(err), <, ADM1272_VOLT_DEFAULT / 20);
198
199 i2c_value = i2c_get8(i2cdev, PMBUS_OPERATION);
200 g_assert_cmphex(i2c_value, ==, ADM1272_OPERATION_DEFAULT);
201
202 i2c_value = i2c_get8(i2cdev, PMBUS_VOUT_MODE);
203 g_assert_cmphex(i2c_value, ==, ADM1272_DIRECT_MODE);
204
205 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT);
206 g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
207
208 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT);
209 g_assert_cmphex(i2c_value, ==, 0);
210
211 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_IOUT_OC_WARN_LIMIT);
212 g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
213
214 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_FAULT_LIMIT);
215 g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
216
217 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_WARN_LIMIT);
218 g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
219
220 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_OV_WARN_LIMIT);
221 g_assert_cmphex(i2c_value, ==, ADM1272_HIGH_LIMIT_DEFAULT);
222
223 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_UV_WARN_LIMIT);
224 g_assert_cmphex(i2c_value, ==, 0);
225
226 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_PIN_OP_WARN_LIMIT);
227 g_assert_cmphex(i2c_value, ==, ADM1272_PIN_OP_DEFAULT);
228
229 i2c_value = i2c_get8(i2cdev, PMBUS_REVISION);
230 g_assert_cmphex(i2c_value, ==, ADM1272_PMBUS_REVISION_DEFAULT);
231
232 i2c_value = i2c_get8(i2cdev, ADM1272_MFR_PMON_CONTROL);
233 g_assert_cmphex(i2c_value, ==, ADM1272_PMON_CONTROL_DEFAULT);
234
235 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_PMON_CONFIG);
236 g_assert_cmphex(i2c_value, ==, ADM1272_PMON_CONFIG_DEFAULT);
237
238 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_DEVICE_CONFIG);
239 g_assert_cmphex(i2c_value, ==, ADM1272_DEVICE_CONFIG_DEFAULT);
240
241 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_HYSTERESIS_HIGH);
242 g_assert_cmphex(i2c_value, ==, ADM1272_HYSTERESIS_HIGH_DEFAULT);
243
244 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_STRT_UP_IOUT_LIM);
245 g_assert_cmphex(i2c_value, ==, ADM1272_STRT_UP_IOUT_LIM_DEFAULT);
246}
247
248
249static void test_tx_rx(void *obj, void *data, QGuestAllocator *alloc)
250{
251 uint16_t i2c_value, value, i2c_voltage, i2c_pwr, lossy_value;
252 QI2CDevice *i2cdev = (QI2CDevice *)obj;
253
254
255 lossy_value =
256 adm1272_direct_to_millivolts(adm1272_millivolts_to_direct(1000));
257 qmp_adm1272_set(TEST_ID, "vin", 1000);
258 value = qmp_adm1272_get(TEST_ID, "vin");
259 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VIN);
260 i2c_voltage = adm1272_direct_to_millivolts(i2c_value);
261 g_assert_cmpuint(value, ==, i2c_voltage);
262 g_assert_cmpuint(i2c_voltage, ==, lossy_value);
263
264 lossy_value =
265 adm1272_direct_to_millivolts(adm1272_millivolts_to_direct(1500));
266 qmp_adm1272_set(TEST_ID, "vout", 1500);
267 value = qmp_adm1272_get(TEST_ID, "vout");
268 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VOUT);
269 i2c_voltage = adm1272_direct_to_millivolts(i2c_value);
270 g_assert_cmpuint(value, ==, i2c_voltage);
271 g_assert_cmpuint(i2c_voltage, ==, lossy_value);
272
273 lossy_value =
274 adm1272_direct_to_milliamps(adm1272_milliamps_to_direct(1600));
275 qmp_adm1272_set(TEST_ID, "iout", 1600);
276 value = qmp_adm1272_get(TEST_ID, "iout");
277 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_IOUT);
278 i2c_value = adm1272_direct_to_milliamps(i2c_value);
279 g_assert_cmphex(value, ==, i2c_value);
280 g_assert_cmphex(i2c_value, ==, lossy_value);
281
282 lossy_value =
283 adm1272_direct_to_watts(adm1272_watts_to_direct(320));
284 qmp_adm1272_set(TEST_ID, "pin", 320);
285 value = qmp_adm1272_get(TEST_ID, "pin");
286 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_PIN);
287 i2c_pwr = adm1272_direct_to_watts(i2c_value);
288 g_assert_cmphex(value, ==, i2c_pwr);
289 g_assert_cmphex(i2c_pwr, ==, lossy_value);
290}
291
292
293static void test_rw_regs(void *obj, void *data, QGuestAllocator *alloc)
294{
295 uint16_t i2c_value;
296 QI2CDevice *i2cdev = (QI2CDevice *)obj;
297
298 adm1272_i2c_set16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT, 0xABCD);
299 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT);
300 g_assert_cmphex(i2c_value, ==, 0xABCD);
301
302 adm1272_i2c_set16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT, 0xCDEF);
303 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT);
304 g_assert_cmphex(i2c_value, ==, 0xCDEF);
305
306 adm1272_i2c_set16(i2cdev, PMBUS_IOUT_OC_WARN_LIMIT, 0x1234);
307 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_IOUT_OC_WARN_LIMIT);
308 g_assert_cmphex(i2c_value, ==, 0x1234);
309
310 adm1272_i2c_set16(i2cdev, PMBUS_OT_FAULT_LIMIT, 0x5678);
311 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_FAULT_LIMIT);
312 g_assert_cmphex(i2c_value, ==, 0x5678);
313
314 adm1272_i2c_set16(i2cdev, PMBUS_OT_WARN_LIMIT, 0xABDC);
315 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_OT_WARN_LIMIT);
316 g_assert_cmphex(i2c_value, ==, 0xABDC);
317
318 adm1272_i2c_set16(i2cdev, PMBUS_VIN_OV_WARN_LIMIT, 0xCDEF);
319 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_OV_WARN_LIMIT);
320 g_assert_cmphex(i2c_value, ==, 0xCDEF);
321
322 adm1272_i2c_set16(i2cdev, PMBUS_VIN_UV_WARN_LIMIT, 0x2345);
323 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_VIN_UV_WARN_LIMIT);
324 g_assert_cmphex(i2c_value, ==, 0x2345);
325
326 i2c_set8(i2cdev, ADM1272_RESTART_TIME, 0xF8);
327 i2c_value = i2c_get8(i2cdev, ADM1272_RESTART_TIME);
328 g_assert_cmphex(i2c_value, ==, 0xF8);
329
330 i2c_set8(i2cdev, ADM1272_MFR_PMON_CONTROL, 0);
331 i2c_value = i2c_get8(i2cdev, ADM1272_MFR_PMON_CONTROL);
332 g_assert_cmpuint(i2c_value, ==, 0);
333
334 adm1272_i2c_set16(i2cdev, ADM1272_MFR_PMON_CONFIG, 0xDEF0);
335 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_PMON_CONFIG);
336 g_assert_cmphex(i2c_value, ==, 0xDEF0);
337
338 adm1272_i2c_set16(i2cdev, ADM1272_MFR_ALERT1_CONFIG, 0x0123);
339 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_ALERT1_CONFIG);
340 g_assert_cmphex(i2c_value, ==, 0x0123);
341
342 adm1272_i2c_set16(i2cdev, ADM1272_MFR_ALERT2_CONFIG, 0x9876);
343 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_ALERT2_CONFIG);
344 g_assert_cmphex(i2c_value, ==, 0x9876);
345
346 adm1272_i2c_set16(i2cdev, ADM1272_MFR_DEVICE_CONFIG, 0x3456);
347 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_MFR_DEVICE_CONFIG);
348 g_assert_cmphex(i2c_value, ==, 0x3456);
349
350 adm1272_i2c_set16(i2cdev, ADM1272_HYSTERESIS_LOW, 0xCABA);
351 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_HYSTERESIS_LOW);
352 g_assert_cmphex(i2c_value, ==, 0xCABA);
353
354 adm1272_i2c_set16(i2cdev, ADM1272_HYSTERESIS_HIGH, 0x6789);
355 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_HYSTERESIS_HIGH);
356 g_assert_cmphex(i2c_value, ==, 0x6789);
357
358 adm1272_i2c_set16(i2cdev, ADM1272_STRT_UP_IOUT_LIM, 0x9876);
359 i2c_value = adm1272_i2c_get16(i2cdev, ADM1272_STRT_UP_IOUT_LIM);
360 g_assert_cmphex(i2c_value, ==, 0x9876);
361
362 adm1272_i2c_set16(i2cdev, PMBUS_OPERATION, 0xA);
363 i2c_value = i2c_get8(i2cdev, PMBUS_OPERATION);
364 g_assert_cmphex(i2c_value, ==, 0xA);
365}
366
367
368static void test_ro_regs(void *obj, void *data, QGuestAllocator *alloc)
369{
370 uint16_t i2c_init_value, i2c_value;
371 QI2CDevice *i2cdev = (QI2CDevice *)obj;
372
373 i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VIN);
374 adm1272_i2c_set16(i2cdev, PMBUS_READ_VIN, 0xBEEF);
375 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VIN);
376 g_assert_cmphex(i2c_init_value, ==, i2c_value);
377
378 i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VOUT);
379 adm1272_i2c_set16(i2cdev, PMBUS_READ_VOUT, 0x1234);
380 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_VOUT);
381 g_assert_cmphex(i2c_init_value, ==, i2c_value);
382
383 i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_IOUT);
384 adm1272_i2c_set16(i2cdev, PMBUS_READ_IOUT, 0x6547);
385 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_IOUT);
386 g_assert_cmphex(i2c_init_value, ==, i2c_value);
387
388 i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
389 adm1272_i2c_set16(i2cdev, PMBUS_READ_TEMPERATURE_1, 0x1597);
390 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
391 g_assert_cmphex(i2c_init_value, ==, i2c_value);
392
393 i2c_init_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_PIN);
394 adm1272_i2c_set16(i2cdev, PMBUS_READ_PIN, 0xDEAD);
395 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_READ_PIN);
396 g_assert_cmphex(i2c_init_value, ==, i2c_value);
397}
398
399
400static void test_voltage_faults(void *obj, void *data, QGuestAllocator *alloc)
401{
402 uint16_t i2c_value;
403 uint8_t i2c_byte;
404 QI2CDevice *i2cdev = (QI2CDevice *)obj;
405
406 adm1272_i2c_set16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT,
407 adm1272_millivolts_to_direct(5000));
408 qmp_adm1272_set(TEST_ID, "vout", 5100);
409
410 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
411 i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
412 g_assert_true((i2c_value & PB_STATUS_VOUT) != 0);
413 g_assert_true((i2c_byte & PB_STATUS_VOUT_OV_WARN) != 0);
414
415 qmp_adm1272_set(TEST_ID, "vout", 4500);
416 i2c_set8(i2cdev, PMBUS_CLEAR_FAULTS, 0);
417 i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
418 g_assert_true((i2c_byte & PB_STATUS_VOUT_OV_WARN) == 0);
419
420 adm1272_i2c_set16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT,
421 adm1272_millivolts_to_direct(4600));
422 i2c_value = adm1272_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
423 i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
424 g_assert_true((i2c_value & PB_STATUS_VOUT) != 0);
425 g_assert_true((i2c_byte & PB_STATUS_VOUT_UV_WARN) != 0);
426
427}
428
429static void adm1272_register_nodes(void)
430{
431 QOSGraphEdgeOptions opts = {
432 .extra_device_opts = "id=" TEST_ID ",address=0x10"
433 };
434 add_qi2c_address(&opts, &(QI2CAddress) { TEST_ADDR });
435
436 qos_node_create_driver("adm1272", i2c_device_create);
437 qos_node_consumes("adm1272", "i2c-bus", &opts);
438
439 qos_add_test("test_defaults", "adm1272", test_defaults, NULL);
440 qos_add_test("test_tx_rx", "adm1272", test_tx_rx, NULL);
441 qos_add_test("test_rw_regs", "adm1272", test_rw_regs, NULL);
442 qos_add_test("test_ro_regs", "adm1272", test_ro_regs, NULL);
443 qos_add_test("test_ov_faults", "adm1272", test_voltage_faults, NULL);
444}
445libqos_init(adm1272_register_nodes);
446