]> git.proxmox.com Git - mirror_qemu.git/blame - tests/qtest/pnv-host-i2c-test.c
Merge tag 'pull-request-2024-03-25' of https://gitlab.com/thuth/qemu into staging
[mirror_qemu.git] / tests / qtest / pnv-host-i2c-test.c
CommitLineData
4d2cd2d8
GM
1/*
2 * QTest testcase for PowerNV 10 Host I2C Communications
3 *
4 * Copyright (c) 2023, IBM Corporation.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or
7 * later. See the COPYING file in the top-level directory.
8 */
9#include "qemu/osdep.h"
10#include "libqtest.h"
6328d8ff
CLG
11#include "hw/gpio/pca9554_regs.h"
12#include "hw/gpio/pca9552_regs.h"
4d2cd2d8
GM
13#include "pnv-xscom.h"
14
15#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
16#define PPC_BIT32(bit) (0x80000000 >> (bit))
17#define PPC_BIT8(bit) (0x80 >> (bit))
18#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
19#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \
20 PPC_BIT32(bs))
21
22#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1)
23#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
24#define SETFIELD(m, v, val) \
25 (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
26
27#define PNV10_XSCOM_I2CM_BASE 0xa0000
28#define PNV10_XSCOM_I2CM_SIZE 0x1000
29
30#include "hw/i2c/pnv_i2c_regs.h"
31
32typedef struct {
33 QTestState *qts;
34 const PnvChip *chip;
35 int engine;
36} PnvI2cCtlr;
37
38typedef struct {
39 PnvI2cCtlr *ctlr;
40 int port;
41 uint8_t addr;
42} PnvI2cDev;
43
44
45static uint64_t pnv_i2c_xscom_addr(PnvI2cCtlr *ctlr, uint32_t reg)
46{
47 return pnv_xscom_addr(ctlr->chip, PNV10_XSCOM_I2CM_BASE +
48 (PNV10_XSCOM_I2CM_SIZE * ctlr->engine) + reg);
49}
50
51static uint64_t pnv_i2c_xscom_read(PnvI2cCtlr *ctlr, uint32_t reg)
52{
53 return qtest_readq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg));
54}
55
56static void pnv_i2c_xscom_write(PnvI2cCtlr *ctlr, uint32_t reg, uint64_t val)
57{
58 qtest_writeq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg), val);
59}
60
61/* Write len bytes from buf to i2c device with given addr and port */
62static void pnv_i2c_send(PnvI2cDev *dev, const uint8_t *buf, uint16_t len)
63{
64 int byte_num;
65 uint64_t reg64;
66
67 /* select requested port */
68 reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be);
69 reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port);
70 pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64);
71
72 /* check status for cmd complete and bus idle */
73 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
74 g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
75 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
76 g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
77 I2C_STAT_CMD_COMP);
78
79 /* Send start, with stop, with address and len bytes of data */
80 reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR | I2C_CMD_WITH_STOP;
81 reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr);
82 reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len);
83 pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64);
84
85 /* check status for errors */
86 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
87 g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0);
88
89 /* write data bytes to fifo register */
90 for (byte_num = 0; byte_num < len; byte_num++) {
91 reg64 = SETFIELD(I2C_FIFO, 0ull, buf[byte_num]);
92 pnv_i2c_xscom_write(dev->ctlr, I2C_FIFO_REG, reg64);
93 }
94
95 /* check status for cmd complete and bus idle */
96 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
97 g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
98 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
99 g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
100 I2C_STAT_CMD_COMP);
101}
102
103/* Recieve len bytes into buf from i2c device with given addr and port */
104static void pnv_i2c_recv(PnvI2cDev *dev, uint8_t *buf, uint16_t len)
105{
106 int byte_num;
107 uint64_t reg64;
108
109 /* select requested port */
110 reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be);
111 reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port);
112 pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64);
113
114 /* check status for cmd complete and bus idle */
115 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
116 g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
117 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
118 g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
119 I2C_STAT_CMD_COMP);
120
121 /* Send start, with stop, with address and len bytes of data */
122 reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR |
123 I2C_CMD_WITH_STOP | I2C_CMD_READ_NOT_WRITE;
124 reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr);
125 reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len);
126 pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64);
127
128 /* check status for errors */
129 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
130 g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0);
131
132 /* Read data bytes from fifo register */
133 for (byte_num = 0; byte_num < len; byte_num++) {
134 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_FIFO_REG);
135 buf[byte_num] = GETFIELD(I2C_FIFO, reg64);
136 }
137
138 /* check status for cmd complete and bus idle */
139 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
140 g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
141 reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
142 g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
143 I2C_STAT_CMD_COMP);
144}
145
146static void pnv_i2c_pca9554_default_cfg(PnvI2cDev *dev)
147{
148 uint8_t buf[2];
149
150 /* input register bits are not inverted */
151 buf[0] = PCA9554_POLARITY;
152 buf[1] = 0;
153 pnv_i2c_send(dev, buf, 2);
154
155 /* All pins are inputs */
156 buf[0] = PCA9554_CONFIG;
157 buf[1] = 0xff;
158 pnv_i2c_send(dev, buf, 2);
159
160 /* Output value for when pins are outputs */
161 buf[0] = PCA9554_OUTPUT;
162 buf[1] = 0xff;
163 pnv_i2c_send(dev, buf, 2);
164}
165
166static void pnv_i2c_pca9554_set_pin(PnvI2cDev *dev, int pin, bool high)
167{
168 uint8_t send_buf[2];
169 uint8_t recv_buf[2];
170 uint8_t mask = 0x1 << pin;
171 uint8_t new_value = ((high) ? 1 : 0) << pin;
172
173 /* read current OUTPUT value */
174 send_buf[0] = PCA9554_OUTPUT;
175 pnv_i2c_send(dev, send_buf, 1);
176 pnv_i2c_recv(dev, recv_buf, 1);
177
178 /* write new OUTPUT value */
179 send_buf[1] = (recv_buf[0] & ~mask) | new_value;
180 pnv_i2c_send(dev, send_buf, 2);
181
182 /* Update config bit for output */
183 send_buf[0] = PCA9554_CONFIG;
184 pnv_i2c_send(dev, send_buf, 1);
185 pnv_i2c_recv(dev, recv_buf, 1);
186 send_buf[1] = recv_buf[0] & ~mask;
187 pnv_i2c_send(dev, send_buf, 2);
188}
189
190static uint8_t pnv_i2c_pca9554_read_pins(PnvI2cDev *dev)
191{
192 uint8_t send_buf[1];
193 uint8_t recv_buf[1];
194 uint8_t inputs;
195 send_buf[0] = PCA9554_INPUT;
196 pnv_i2c_send(dev, send_buf, 1);
197 pnv_i2c_recv(dev, recv_buf, 1);
198 inputs = recv_buf[0];
199 return inputs;
200}
201
202static void pnv_i2c_pca9554_flip_polarity(PnvI2cDev *dev)
203{
204 uint8_t recv_buf[1];
205 uint8_t send_buf[2];
206
207 send_buf[0] = PCA9554_POLARITY;
208 pnv_i2c_send(dev, send_buf, 1);
209 pnv_i2c_recv(dev, recv_buf, 1);
210 send_buf[1] = recv_buf[0] ^ 0xff;
211 pnv_i2c_send(dev, send_buf, 2);
212}
213
214static void pnv_i2c_pca9554_default_inputs(PnvI2cDev *dev)
215{
216 uint8_t pin_values = pnv_i2c_pca9554_read_pins(dev);
217 g_assert_cmphex(pin_values, ==, 0xff);
218}
219
220/* Check that setting pin values and polarity changes inputs as expected */
221static void pnv_i2c_pca554_set_pins(PnvI2cDev *dev)
222{
223 uint8_t pin_values;
224 pnv_i2c_pca9554_set_pin(dev, 0, 0);
225 pin_values = pnv_i2c_pca9554_read_pins(dev);
226 g_assert_cmphex(pin_values, ==, 0xfe);
227 pnv_i2c_pca9554_flip_polarity(dev);
228 pin_values = pnv_i2c_pca9554_read_pins(dev);
229 g_assert_cmphex(pin_values, ==, 0x01);
230 pnv_i2c_pca9554_set_pin(dev, 2, 0);
231 pin_values = pnv_i2c_pca9554_read_pins(dev);
232 g_assert_cmphex(pin_values, ==, 0x05);
233 pnv_i2c_pca9554_flip_polarity(dev);
234 pin_values = pnv_i2c_pca9554_read_pins(dev);
235 g_assert_cmphex(pin_values, ==, 0xfa);
236 pnv_i2c_pca9554_default_cfg(dev);
237 pin_values = pnv_i2c_pca9554_read_pins(dev);
238 g_assert_cmphex(pin_values, ==, 0xff);
239}
240
241static void pnv_i2c_pca9552_default_cfg(PnvI2cDev *dev)
242{
243 uint8_t buf[2];
244 /* configure pwm/psc regs */
245 buf[0] = PCA9552_PSC0;
246 buf[1] = 0xff;
247 pnv_i2c_send(dev, buf, 2);
248 buf[0] = PCA9552_PWM0;
249 buf[1] = 0x80;
250 pnv_i2c_send(dev, buf, 2);
251 buf[0] = PCA9552_PSC1;
252 buf[1] = 0xff;
253 pnv_i2c_send(dev, buf, 2);
254 buf[0] = PCA9552_PWM1;
255 buf[1] = 0x80;
256 pnv_i2c_send(dev, buf, 2);
257
258 /* configure all pins as inputs */
259 buf[0] = PCA9552_LS0;
260 buf[1] = 0x55;
261 pnv_i2c_send(dev, buf, 2);
262 buf[0] = PCA9552_LS1;
263 buf[1] = 0x55;
264 pnv_i2c_send(dev, buf, 2);
265 buf[0] = PCA9552_LS2;
266 buf[1] = 0x55;
267 pnv_i2c_send(dev, buf, 2);
268 buf[0] = PCA9552_LS3;
269 buf[1] = 0x55;
270 pnv_i2c_send(dev, buf, 2);
271}
272
273static void pnv_i2c_pca9552_set_pin(PnvI2cDev *dev, int pin, bool high)
274{
275 uint8_t send_buf[2];
276 uint8_t recv_buf[2];
277 uint8_t reg = PCA9552_LS0 + (pin / 4);
278 uint8_t shift = (pin % 4) * 2;
279 uint8_t mask = ~(0x3 << shift);
280 uint8_t new_value = ((high) ? 1 : 0) << shift;
281
282 /* read current LSx value */
283 send_buf[0] = reg;
284 pnv_i2c_send(dev, send_buf, 1);
285 pnv_i2c_recv(dev, recv_buf, 1);
286
287 /* write new value to LSx */
288 send_buf[1] = (recv_buf[0] & mask) | new_value;
289 pnv_i2c_send(dev, send_buf, 2);
290}
291
292static uint16_t pnv_i2c_pca9552_read_pins(PnvI2cDev *dev)
293{
294 uint8_t send_buf[2];
295 uint8_t recv_buf[2];
296 uint16_t inputs;
297 send_buf[0] = PCA9552_INPUT0;
298 pnv_i2c_send(dev, send_buf, 1);
299 pnv_i2c_recv(dev, recv_buf, 1);
300 inputs = recv_buf[0];
301 send_buf[0] = PCA9552_INPUT1;
302 pnv_i2c_send(dev, send_buf, 1);
303 pnv_i2c_recv(dev, recv_buf, 1);
304 inputs |= recv_buf[0] << 8;
305 return inputs;
306}
307
308static void pnv_i2c_pca9552_default_inputs(PnvI2cDev *dev)
309{
310 uint16_t pin_values = pnv_i2c_pca9552_read_pins(dev);
311 g_assert_cmphex(pin_values, ==, 0xffff);
312}
313
314/*
315 * Set pins 0-4 one at a time and verify that pins 5-9 are
316 * set to the same value
317 */
318static void pnv_i2c_pca552_set_pins(PnvI2cDev *dev)
319{
320 uint16_t pin_values;
321
322 /* set pin 0 low */
323 pnv_i2c_pca9552_set_pin(dev, 0, 0);
324 pin_values = pnv_i2c_pca9552_read_pins(dev);
325
326 /* pins 0 and 5 should be low */
327 g_assert_cmphex(pin_values, ==, 0xffde);
328
329 /* set pin 1 low */
330 pnv_i2c_pca9552_set_pin(dev, 1, 0);
331 pin_values = pnv_i2c_pca9552_read_pins(dev);
332
333 /* pins 0, 1, 5 and 6 should be low */
334 g_assert_cmphex(pin_values, ==, 0xff9c);
335
336 /* set pin 2 low */
337 pnv_i2c_pca9552_set_pin(dev, 2, 0);
338 pin_values = pnv_i2c_pca9552_read_pins(dev);
339
340 /* pins 0, 1, 2, 5, 6 and 7 should be low */
341 g_assert_cmphex(pin_values, ==, 0xff18);
342
343 /* set pin 3 low */
344 pnv_i2c_pca9552_set_pin(dev, 3, 0);
345 pin_values = pnv_i2c_pca9552_read_pins(dev);
346
347 /* pins 0, 1, 2, 3, 5, 6, 7 and 8 should be low */
348 g_assert_cmphex(pin_values, ==, 0xfe10);
349
350 /* set pin 4 low */
351 pnv_i2c_pca9552_set_pin(dev, 4, 0);
352 pin_values = pnv_i2c_pca9552_read_pins(dev);
353
354 /* pins 0, 1, 2, 3, 5, 6, 7, 8 and 9 should be low */
355 g_assert_cmphex(pin_values, ==, 0xfc00);
356
357 /* reset all pins to the high state */
358 pnv_i2c_pca9552_default_cfg(dev);
359 pin_values = pnv_i2c_pca9552_read_pins(dev);
360
361 /* verify all pins went back to the high state */
362 g_assert_cmphex(pin_values, ==, 0xffff);
363}
364
365static void reset_engine(PnvI2cCtlr *ctlr)
366{
367 pnv_i2c_xscom_write(ctlr, I2C_RESET_I2C_REG, 0);
368}
369
370static void check_i2cm_por_regs(QTestState *qts, const PnvChip *chip)
371{
372 int engine;
373 for (engine = 0; engine < chip->num_i2c; engine++) {
374 PnvI2cCtlr ctlr;
375 ctlr.qts = qts;
376 ctlr.chip = chip;
377 ctlr.engine = engine;
378
379 /* Check version in Extended Status Register */
380 uint64_t value = pnv_i2c_xscom_read(&ctlr, I2C_EXTD_STAT_REG);
381 g_assert_cmphex(value & I2C_EXTD_STAT_I2C_VERSION, ==, 0x1700000000);
382
383 /* Check for command complete and bus idle in Status Register */
384 value = pnv_i2c_xscom_read(&ctlr, I2C_STAT_REG);
385 g_assert_cmphex(value & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP),
386 ==,
387 I2C_STAT_CMD_COMP);
388 }
389}
390
391static void reset_all(QTestState *qts, const PnvChip *chip)
392{
393 int engine;
394 for (engine = 0; engine < chip->num_i2c; engine++) {
395 PnvI2cCtlr ctlr;
396 ctlr.qts = qts;
397 ctlr.chip = chip;
398 ctlr.engine = engine;
399 reset_engine(&ctlr);
400 pnv_i2c_xscom_write(&ctlr, I2C_MODE_REG, 0x02be040000000000);
401 }
402}
403
404static void test_host_i2c(const void *data)
405{
406 const PnvChip *chip = data;
407 QTestState *qts;
408 const char *machine = "powernv8";
409 PnvI2cCtlr ctlr;
410 PnvI2cDev pca9552;
411 PnvI2cDev pca9554;
412
413 if (chip->chip_type == PNV_CHIP_POWER9) {
414 machine = "powernv9";
415 } else if (chip->chip_type == PNV_CHIP_POWER10) {
416 machine = "powernv10-rainier";
417 }
418
419 qts = qtest_initf("-M %s -smp %d,cores=1,threads=%d -nographic "
420 "-nodefaults -serial mon:stdio -S "
421 "-d guest_errors",
422 machine, SMT, SMT);
423
424 /* Check the I2C master status registers after POR */
425 check_i2cm_por_regs(qts, chip);
426
427 /* Now do a forced "immediate" reset on all engines */
428 reset_all(qts, chip);
429
430 /* Check that the status values are still good */
431 check_i2cm_por_regs(qts, chip);
432
433 /* P9 doesn't have any i2c devices attached at this time */
434 if (chip->chip_type != PNV_CHIP_POWER10) {
435 qtest_quit(qts);
436 return;
437 }
438
439 /* Initialize for a P10 pca9552 hotplug device */
440 ctlr.qts = qts;
441 ctlr.chip = chip;
442 ctlr.engine = 2;
443 pca9552.ctlr = &ctlr;
444 pca9552.port = 1;
445 pca9552.addr = 0x63;
446
447 /* Set all pca9552 pins as inputs */
448 pnv_i2c_pca9552_default_cfg(&pca9552);
449
450 /* Check that all pins of the pca9552 are high */
451 pnv_i2c_pca9552_default_inputs(&pca9552);
452
453 /* perform individual pin tests */
454 pnv_i2c_pca552_set_pins(&pca9552);
455
456 /* Initialize for a P10 pca9554 CableCard Presence detection device */
457 pca9554.ctlr = &ctlr;
458 pca9554.port = 1;
459 pca9554.addr = 0x25;
460
461 /* Set all pca9554 pins as inputs */
462 pnv_i2c_pca9554_default_cfg(&pca9554);
463
464 /* Check that all pins of the pca9554 are high */
465 pnv_i2c_pca9554_default_inputs(&pca9554);
466
467 /* perform individual pin tests */
468 pnv_i2c_pca554_set_pins(&pca9554);
469
470 qtest_quit(qts);
471}
472
473static void add_test(const char *name, void (*test)(const void *data))
474{
475 int i;
476
477 for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
478 char *tname = g_strdup_printf("pnv-xscom/%s/%s", name,
479 pnv_chips[i].cpu_model);
480 qtest_add_data_func(tname, &pnv_chips[i], test);
481 g_free(tname);
482 }
483}
484
485int main(int argc, char **argv)
486{
487 g_test_init(&argc, &argv, NULL);
488
489 add_test("host-i2c", test_host_i2c);
490 return g_test_run();
491}