xref: /openbmc/qemu/tests/qtest/max34451-test.c (revision 52ed9f45)
1 /*
2  * QTests for the MAX34451 device
3  *
4  * Copyright 2021 Google LLC
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "qemu/osdep.h"
10 #include "hw/i2c/pmbus_device.h"
11 #include "libqtest-single.h"
12 #include "libqos/qgraph.h"
13 #include "libqos/i2c.h"
14 #include "qapi/qmp/qdict.h"
15 #include "qapi/qmp/qnum.h"
16 #include "qemu/bitops.h"
17 
18 #define TEST_ID "max34451-test"
19 #define TEST_ADDR (0x4e)
20 
21 #define MAX34451_MFR_MODE               0xD1
22 #define MAX34451_MFR_VOUT_PEAK          0xD4
23 #define MAX34451_MFR_IOUT_PEAK          0xD5
24 #define MAX34451_MFR_TEMPERATURE_PEAK   0xD6
25 #define MAX34451_MFR_VOUT_MIN           0xD7
26 
27 #define DEFAULT_VOUT                    0
28 #define DEFAULT_UV_LIMIT                0
29 #define DEFAULT_TEMPERATURE             2500
30 #define DEFAULT_SCALE                   0x7FFF
31 #define DEFAULT_OV_LIMIT                0x7FFF
32 #define DEFAULT_OC_LIMIT                0x7FFF
33 #define DEFAULT_OT_LIMIT                0x7FFF
34 #define DEFAULT_VMIN                    0x7FFF
35 #define DEFAULT_TON_FAULT_LIMIT         0xFFFF
36 #define DEFAULT_CHANNEL_CONFIG          0x20
37 #define DEFAULT_TEXT                    0x20
38 
39 #define MAX34451_NUM_PWR_DEVICES        16
40 #define MAX34451_NUM_TEMP_DEVICES       5
41 
42 
43 static uint16_t qmp_max34451_get(const char *id, const char *property)
44 {
45     QDict *response;
46     uint16_t ret;
47     response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
48                    "'property': %s } }", id, property);
49     g_assert(qdict_haskey(response, "return"));
50     ret = qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
51     qobject_unref(response);
52     return ret;
53 }
54 
55 static void qmp_max34451_set(const char *id,
56                              const char *property,
57                              uint16_t value)
58 {
59     QDict *response;
60 
61     response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
62                    "'property': %s, 'value': %u } }",
63                    id, property, value);
64     g_assert(qdict_haskey(response, "return"));
65     qobject_unref(response);
66 }
67 
68 /* PMBus commands are little endian vs i2c_set16 in i2c.h which is big endian */
69 static uint16_t max34451_i2c_get16(QI2CDevice *i2cdev, uint8_t reg)
70 {
71     uint8_t resp[2];
72     i2c_read_block(i2cdev, reg, resp, sizeof(resp));
73     return (resp[1] << 8) | resp[0];
74 }
75 
76 /* PMBus commands are little endian vs i2c_set16 in i2c.h which is big endian */
77 static void max34451_i2c_set16(QI2CDevice *i2cdev, uint8_t reg, uint16_t value)
78 {
79     uint8_t data[2];
80 
81     data[0] = value & 255;
82     data[1] = value >> 8;
83     i2c_write_block(i2cdev, reg, data, sizeof(data));
84 }
85 
86 /* Test default values */
87 static void test_defaults(void *obj, void *data, QGuestAllocator *alloc)
88 {
89     uint16_t value, i2c_value;
90     QI2CDevice *i2cdev = (QI2CDevice *)obj;
91     char *path;
92 
93     /* Default temperatures and temperature fault limits */
94     for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
95         path = g_strdup_printf("temperature[%d]", i);
96         value = qmp_max34451_get(TEST_ID, path);
97         g_assert_cmpuint(value, ==, DEFAULT_TEMPERATURE);
98         g_free(path);
99 
100         /* Temperature sensors start on page 16 */
101         i2c_set8(i2cdev, PMBUS_PAGE, i + 16);
102         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
103         g_assert_cmpuint(i2c_value, ==, DEFAULT_TEMPERATURE);
104 
105         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_OT_FAULT_LIMIT);
106         g_assert_cmpuint(i2c_value, ==, DEFAULT_OT_LIMIT);
107 
108         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_OT_WARN_LIMIT);
109         g_assert_cmpuint(i2c_value, ==, DEFAULT_OT_LIMIT);
110     }
111 
112     /* Default voltages and fault limits */
113     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
114         path = g_strdup_printf("vout[%d]", i);
115         value = qmp_max34451_get(TEST_ID, path);
116         g_assert_cmpuint(value, ==, DEFAULT_VOUT);
117         g_free(path);
118 
119         i2c_set8(i2cdev, PMBUS_PAGE, i);
120         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_READ_VOUT);
121         g_assert_cmpuint(i2c_value, ==, DEFAULT_VOUT);
122 
123         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_OV_FAULT_LIMIT);
124         g_assert_cmpuint(i2c_value, ==, DEFAULT_OV_LIMIT);
125 
126         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT);
127         g_assert_cmpuint(i2c_value, ==, DEFAULT_OV_LIMIT);
128 
129         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT);
130         g_assert_cmpuint(i2c_value, ==, DEFAULT_UV_LIMIT);
131 
132         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_UV_FAULT_LIMIT);
133         g_assert_cmpuint(i2c_value, ==, DEFAULT_UV_LIMIT);
134 
135         i2c_value = max34451_i2c_get16(i2cdev, MAX34451_MFR_VOUT_MIN);
136         g_assert_cmpuint(i2c_value, ==, DEFAULT_VMIN);
137     }
138 
139     i2c_value = i2c_get8(i2cdev, PMBUS_VOUT_MODE);
140     g_assert_cmphex(i2c_value, ==, 0x40); /* DIRECT mode */
141 
142     i2c_value = i2c_get8(i2cdev, PMBUS_REVISION);
143     g_assert_cmphex(i2c_value, ==, 0x11); /* Rev 1.1 */
144 }
145 
146 /* Test setting temperature */
147 static void test_temperature(void *obj, void *data, QGuestAllocator *alloc)
148 {
149     uint16_t value, i2c_value;
150     QI2CDevice *i2cdev = (QI2CDevice *)obj;
151     char *path;
152 
153     for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
154         path = g_strdup_printf("temperature[%d]", i);
155         qmp_max34451_set(TEST_ID, path, 0xBE00 + i);
156         value = qmp_max34451_get(TEST_ID, path);
157         g_assert_cmphex(value, ==, 0xBE00 + i);
158         g_free(path);
159     }
160 
161     /* compare qmp read with i2c read separately */
162     for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
163         /* temperature[0] is on page 16 */
164         i2c_set8(i2cdev, PMBUS_PAGE, i + 16);
165         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
166         g_assert_cmphex(i2c_value, ==, 0xBE00 + i);
167 
168         i2c_value = max34451_i2c_get16(i2cdev, MAX34451_MFR_TEMPERATURE_PEAK);
169         g_assert_cmphex(i2c_value, ==, 0xBE00 + i);
170     }
171 }
172 
173 /* Test setting voltage */
174 static void test_voltage(void *obj, void *data, QGuestAllocator *alloc)
175 {
176     uint16_t value, i2c_value;
177     QI2CDevice *i2cdev = (QI2CDevice *)obj;
178     char *path;
179 
180     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
181         path = g_strdup_printf("vout[%d]", i);
182         qmp_max34451_set(TEST_ID, path, 3000 + i);
183         value = qmp_max34451_get(TEST_ID, path);
184         g_assert_cmpuint(value, ==, 3000 + i);
185         g_free(path);
186     }
187 
188     /* compare qmp read with i2c read separately */
189     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
190         i2c_set8(i2cdev, PMBUS_PAGE, i);
191         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_READ_VOUT);
192         g_assert_cmpuint(i2c_value, ==, 3000 + i);
193 
194         i2c_value = max34451_i2c_get16(i2cdev, MAX34451_MFR_VOUT_PEAK);
195         g_assert_cmpuint(i2c_value, ==, 3000 + i);
196 
197         i2c_value = max34451_i2c_get16(i2cdev, MAX34451_MFR_VOUT_MIN);
198         g_assert_cmpuint(i2c_value, ==, 3000 + i);
199     }
200 }
201 
202 /* Test setting some read/write registers */
203 static void test_rw_regs(void *obj, void *data, QGuestAllocator *alloc)
204 {
205     uint16_t i2c_value;
206     QI2CDevice *i2cdev = (QI2CDevice *)obj;
207 
208     i2c_set8(i2cdev, PMBUS_PAGE, 11);
209     i2c_value = i2c_get8(i2cdev, PMBUS_PAGE);
210     g_assert_cmpuint(i2c_value, ==, 11);
211 
212     i2c_set8(i2cdev, PMBUS_OPERATION, 1);
213     i2c_value = i2c_get8(i2cdev, PMBUS_OPERATION);
214     g_assert_cmpuint(i2c_value, ==, 1);
215 
216     max34451_i2c_set16(i2cdev, PMBUS_VOUT_MARGIN_HIGH, 5000);
217     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_MARGIN_HIGH);
218     g_assert_cmpuint(i2c_value, ==, 5000);
219 
220     max34451_i2c_set16(i2cdev, PMBUS_VOUT_MARGIN_LOW, 4000);
221     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_MARGIN_LOW);
222     g_assert_cmpuint(i2c_value, ==, 4000);
223 
224     max34451_i2c_set16(i2cdev, PMBUS_VOUT_OV_FAULT_LIMIT, 5500);
225     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_OV_FAULT_LIMIT);
226     g_assert_cmpuint(i2c_value, ==, 5500);
227 
228     max34451_i2c_set16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT, 5600);
229     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_OV_WARN_LIMIT);
230     g_assert_cmpuint(i2c_value, ==, 5600);
231 
232     max34451_i2c_set16(i2cdev, PMBUS_VOUT_UV_FAULT_LIMIT, 5700);
233     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_UV_FAULT_LIMIT);
234     g_assert_cmpuint(i2c_value, ==, 5700);
235 
236     max34451_i2c_set16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT, 5800);
237     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_VOUT_UV_WARN_LIMIT);
238     g_assert_cmpuint(i2c_value, ==, 5800);
239 
240     max34451_i2c_set16(i2cdev, PMBUS_POWER_GOOD_ON, 5900);
241     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_POWER_GOOD_ON);
242     g_assert_cmpuint(i2c_value, ==, 5900);
243 
244     max34451_i2c_set16(i2cdev, PMBUS_POWER_GOOD_OFF, 6100);
245     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_POWER_GOOD_OFF);
246     g_assert_cmpuint(i2c_value, ==, 6100);
247 }
248 
249 /* Test that Read only registers can't be written */
250 static void test_ro_regs(void *obj, void *data, QGuestAllocator *alloc)
251 {
252     uint16_t i2c_value, i2c_init_value;
253     QI2CDevice *i2cdev = (QI2CDevice *)obj;
254 
255     i2c_set8(i2cdev, PMBUS_PAGE, 1); /* move to page 1 */
256     i2c_init_value = i2c_get8(i2cdev, PMBUS_CAPABILITY);
257     i2c_set8(i2cdev, PMBUS_CAPABILITY, 0xF9);
258     i2c_value = i2c_get8(i2cdev, PMBUS_CAPABILITY);
259     g_assert_cmpuint(i2c_init_value, ==, i2c_value);
260 
261     i2c_init_value = max34451_i2c_get16(i2cdev, PMBUS_READ_VOUT);
262     max34451_i2c_set16(i2cdev, PMBUS_READ_VOUT, 0xDEAD);
263     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_READ_VOUT);
264     g_assert_cmpuint(i2c_init_value, ==, i2c_value);
265     g_assert_cmphex(i2c_value, !=, 0xDEAD);
266 
267     i2c_set8(i2cdev, PMBUS_PAGE, 16); /* move to page 16 */
268     i2c_init_value = max34451_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
269     max34451_i2c_set16(i2cdev, PMBUS_READ_TEMPERATURE_1, 0xABBA);
270     i2c_value = max34451_i2c_get16(i2cdev, PMBUS_READ_TEMPERATURE_1);
271     g_assert_cmpuint(i2c_init_value, ==, i2c_value);
272     g_assert_cmphex(i2c_value, !=, 0xABBA);
273 }
274 
275 /* test over voltage faults */
276 static void test_ov_faults(void *obj, void *data, QGuestAllocator *alloc)
277 {
278     uint16_t i2c_value;
279     uint8_t i2c_byte;
280     QI2CDevice *i2cdev = (QI2CDevice *)obj;
281     char *path;
282     /* Test ov fault reporting */
283     for (int i = 0; i < MAX34451_NUM_PWR_DEVICES; i++) {
284         path = g_strdup_printf("vout[%d]", i);
285         i2c_set8(i2cdev, PMBUS_PAGE, i);
286         max34451_i2c_set16(i2cdev, PMBUS_VOUT_OV_FAULT_LIMIT, 5000);
287         qmp_max34451_set(TEST_ID, path, 5100);
288         g_free(path);
289 
290         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
291         i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_VOUT);
292         g_assert_true((i2c_value & PB_STATUS_VOUT) != 0);
293         g_assert_true((i2c_byte & PB_STATUS_VOUT_OV_FAULT) != 0);
294     }
295 }
296 
297 /* test over temperature faults */
298 static void test_ot_faults(void *obj, void *data, QGuestAllocator *alloc)
299 {
300     uint16_t i2c_value;
301     uint8_t i2c_byte;
302     QI2CDevice *i2cdev = (QI2CDevice *)obj;
303     char *path;
304 
305     for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES; i++) {
306         path = g_strdup_printf("temperature[%d]", i);
307         i2c_set8(i2cdev, PMBUS_PAGE, i + 16);
308         max34451_i2c_set16(i2cdev, PMBUS_OT_FAULT_LIMIT, 6000);
309         qmp_max34451_set(TEST_ID, path, 6100);
310         g_free(path);
311 
312         i2c_value = max34451_i2c_get16(i2cdev, PMBUS_STATUS_WORD);
313         i2c_byte = i2c_get8(i2cdev, PMBUS_STATUS_TEMPERATURE);
314         g_assert_true((i2c_value & PB_STATUS_TEMPERATURE) != 0);
315         g_assert_true((i2c_byte & PB_STATUS_OT_FAULT) != 0);
316     }
317 }
318 
319 #define RAND_ON_OFF_CONFIG  0x12
320 #define RAND_MFR_MODE       0x3456
321 
322 /* test writes to all pages */
323 static void test_all_pages(void *obj, void *data, QGuestAllocator *alloc)
324 {
325     uint16_t i2c_value;
326     QI2CDevice *i2cdev = (QI2CDevice *)obj;
327 
328     i2c_set8(i2cdev, PMBUS_PAGE, PB_ALL_PAGES);
329     i2c_set8(i2cdev, PMBUS_ON_OFF_CONFIG, RAND_ON_OFF_CONFIG);
330     max34451_i2c_set16(i2cdev, MAX34451_MFR_MODE, RAND_MFR_MODE);
331 
332     for (int i = 0; i < MAX34451_NUM_TEMP_DEVICES + MAX34451_NUM_PWR_DEVICES;
333          i++) {
334         i2c_value = i2c_get8(i2cdev, PMBUS_ON_OFF_CONFIG);
335         g_assert_cmphex(i2c_value, ==, RAND_ON_OFF_CONFIG);
336         i2c_value = max34451_i2c_get16(i2cdev, MAX34451_MFR_MODE);
337         g_assert_cmphex(i2c_value, ==, RAND_MFR_MODE);
338     }
339 }
340 
341 static void max34451_register_nodes(void)
342 {
343     QOSGraphEdgeOptions opts = {
344         .extra_device_opts = "id=" TEST_ID ",address=0x4e"
345     };
346     add_qi2c_address(&opts, &(QI2CAddress) { TEST_ADDR });
347 
348     qos_node_create_driver("max34451", i2c_device_create);
349     qos_node_consumes("max34451", "i2c-bus", &opts);
350 
351     qos_add_test("test_defaults", "max34451", test_defaults, NULL);
352     qos_add_test("test_temperature", "max34451", test_temperature, NULL);
353     qos_add_test("test_voltage", "max34451", test_voltage, NULL);
354     qos_add_test("test_rw_regs", "max34451", test_rw_regs, NULL);
355     qos_add_test("test_ro_regs", "max34451", test_ro_regs, NULL);
356     qos_add_test("test_ov_faults", "max34451", test_ov_faults, NULL);
357     qos_add_test("test_ot_faults", "max34451", test_ot_faults, NULL);
358     qos_add_test("test_all_pages", "max34451", test_all_pages, NULL);
359 }
360 libqos_init(max34451_register_nodes);
361