xref: /qemu/tests/qtest/npcm7xx_smbus-test.c (revision b2a3cbb8)
1 /*
2  * QTests for Nuvoton NPCM7xx SMBus Modules.
3  *
4  * Copyright 2020 Google LLC
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  */
16 
17 #include "qemu/osdep.h"
18 #include "qemu/bitops.h"
19 #include "libqos/i2c.h"
20 #include "libqtest.h"
21 #include "hw/sensor/tmp105_regs.h"
22 
23 #define NR_SMBUS_DEVICES    16
24 #define SMBUS_ADDR(x)       (0xf0080000 + 0x1000 * (x))
25 #define SMBUS_IRQ(x)        (64 + (x))
26 
27 #define EVB_DEVICE_ADDR     0x48
28 #define INVALID_DEVICE_ADDR 0x01
29 
30 const int evb_bus_list[] = {0, 1, 2, 6};
31 
32 /* Offsets */
33 enum CommonRegister {
34     OFFSET_SDA     = 0x0,
35     OFFSET_ST      = 0x2,
36     OFFSET_CST     = 0x4,
37     OFFSET_CTL1    = 0x6,
38     OFFSET_ADDR1   = 0x8,
39     OFFSET_CTL2    = 0xa,
40     OFFSET_ADDR2   = 0xc,
41     OFFSET_CTL3    = 0xe,
42     OFFSET_CST2    = 0x18,
43     OFFSET_CST3    = 0x19,
44 };
45 
46 enum NPCM7xxSMBusBank0Register {
47     OFFSET_ADDR3   = 0x10,
48     OFFSET_ADDR7   = 0x11,
49     OFFSET_ADDR4   = 0x12,
50     OFFSET_ADDR8   = 0x13,
51     OFFSET_ADDR5   = 0x14,
52     OFFSET_ADDR9   = 0x15,
53     OFFSET_ADDR6   = 0x16,
54     OFFSET_ADDR10  = 0x17,
55     OFFSET_CTL4    = 0x1a,
56     OFFSET_CTL5    = 0x1b,
57     OFFSET_SCLLT   = 0x1c,
58     OFFSET_FIF_CTL = 0x1d,
59     OFFSET_SCLHT   = 0x1e,
60 };
61 
62 enum NPCM7xxSMBusBank1Register {
63     OFFSET_FIF_CTS  = 0x10,
64     OFFSET_FAIR_PER = 0x11,
65     OFFSET_TXF_CTL  = 0x12,
66     OFFSET_T_OUT    = 0x14,
67     OFFSET_TXF_STS  = 0x1a,
68     OFFSET_RXF_STS  = 0x1c,
69     OFFSET_RXF_CTL  = 0x1e,
70 };
71 
72 /* ST fields */
73 #define ST_STP              BIT(7)
74 #define ST_SDAST            BIT(6)
75 #define ST_BER              BIT(5)
76 #define ST_NEGACK           BIT(4)
77 #define ST_STASTR           BIT(3)
78 #define ST_NMATCH           BIT(2)
79 #define ST_MODE             BIT(1)
80 #define ST_XMIT             BIT(0)
81 
82 /* CST fields */
83 #define CST_ARPMATCH        BIT(7)
84 #define CST_MATCHAF         BIT(6)
85 #define CST_TGSCL           BIT(5)
86 #define CST_TSDA            BIT(4)
87 #define CST_GCMATCH         BIT(3)
88 #define CST_MATCH           BIT(2)
89 #define CST_BB              BIT(1)
90 #define CST_BUSY            BIT(0)
91 
92 /* CST2 fields */
93 #define CST2_INSTTS         BIT(7)
94 #define CST2_MATCH7F        BIT(6)
95 #define CST2_MATCH6F        BIT(5)
96 #define CST2_MATCH5F        BIT(4)
97 #define CST2_MATCH4F        BIT(3)
98 #define CST2_MATCH3F        BIT(2)
99 #define CST2_MATCH2F        BIT(1)
100 #define CST2_MATCH1F        BIT(0)
101 
102 /* CST3 fields */
103 #define CST3_EO_BUSY        BIT(7)
104 #define CST3_MATCH10F       BIT(2)
105 #define CST3_MATCH9F        BIT(1)
106 #define CST3_MATCH8F        BIT(0)
107 
108 /* CTL1 fields */
109 #define CTL1_STASTRE        BIT(7)
110 #define CTL1_NMINTE         BIT(6)
111 #define CTL1_GCMEN          BIT(5)
112 #define CTL1_ACK            BIT(4)
113 #define CTL1_EOBINTE        BIT(3)
114 #define CTL1_INTEN          BIT(2)
115 #define CTL1_STOP           BIT(1)
116 #define CTL1_START          BIT(0)
117 
118 /* CTL2 fields */
119 #define CTL2_SCLFRQ(rv)     extract8((rv), 1, 6)
120 #define CTL2_ENABLE         BIT(0)
121 
122 /* CTL3 fields */
123 #define CTL3_SCL_LVL        BIT(7)
124 #define CTL3_SDA_LVL        BIT(6)
125 #define CTL3_BNK_SEL        BIT(5)
126 #define CTL3_400K_MODE      BIT(4)
127 #define CTL3_IDL_START      BIT(3)
128 #define CTL3_ARPMEN         BIT(2)
129 #define CTL3_SCLFRQ(rv)     extract8((rv), 0, 2)
130 
131 /* ADDR fields */
132 #define ADDR_EN             BIT(7)
133 #define ADDR_A(rv)          extract8((rv), 0, 6)
134 
135 /* FIF_CTL fields */
136 #define FIF_CTL_FIFO_EN         BIT(4)
137 
138 /* FIF_CTS fields */
139 #define FIF_CTS_CLR_FIFO        BIT(6)
140 #define FIF_CTS_RFTE_IE         BIT(3)
141 #define FIF_CTS_RXF_TXE         BIT(1)
142 
143 /* TXF_CTL fields */
144 #define TXF_CTL_THR_TXIE        BIT(6)
145 #define TXF_CTL_TX_THR(rv)      extract8((rv), 0, 5)
146 
147 /* TXF_STS fields */
148 #define TXF_STS_TX_THST         BIT(6)
149 #define TXF_STS_TX_BYTES(rv)    extract8((rv), 0, 5)
150 
151 /* RXF_CTL fields */
152 #define RXF_CTL_THR_RXIE        BIT(6)
153 #define RXF_CTL_LAST            BIT(5)
154 #define RXF_CTL_RX_THR(rv)      extract8((rv), 0, 5)
155 
156 /* RXF_STS fields */
157 #define RXF_STS_RX_THST         BIT(6)
158 #define RXF_STS_RX_BYTES(rv)    extract8((rv), 0, 5)
159 
160 
161 static void choose_bank(QTestState *qts, uint64_t base_addr, uint8_t bank)
162 {
163     uint8_t ctl3 = qtest_readb(qts, base_addr + OFFSET_CTL3);
164 
165     if (bank) {
166         ctl3 |= CTL3_BNK_SEL;
167     } else {
168         ctl3 &= ~CTL3_BNK_SEL;
169     }
170 
171     qtest_writeb(qts, base_addr + OFFSET_CTL3, ctl3);
172 }
173 
174 static void check_running(QTestState *qts, uint64_t base_addr)
175 {
176     g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
177     g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
178 }
179 
180 static void check_stopped(QTestState *qts, uint64_t base_addr)
181 {
182     uint8_t cst3;
183 
184     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
185     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
186     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
187 
188     cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
189     g_assert_true(cst3 & CST3_EO_BUSY);
190     qtest_writeb(qts, base_addr + OFFSET_CST3, cst3);
191     cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
192     g_assert_false(cst3 & CST3_EO_BUSY);
193 }
194 
195 static void enable_bus(QTestState *qts, uint64_t base_addr)
196 {
197     uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
198 
199     ctl2 |= CTL2_ENABLE;
200     qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
201     g_assert_true(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
202 }
203 
204 static void disable_bus(QTestState *qts, uint64_t base_addr)
205 {
206     uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
207 
208     ctl2 &= ~CTL2_ENABLE;
209     qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
210     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
211 }
212 
213 static void start_transfer(QTestState *qts, uint64_t base_addr)
214 {
215     uint8_t ctl1;
216 
217     ctl1 = CTL1_START | CTL1_INTEN | CTL1_STASTRE;
218     qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
219     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==,
220                     CTL1_INTEN | CTL1_STASTRE | CTL1_INTEN);
221     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
222                     ST_MODE | ST_XMIT | ST_SDAST);
223     check_running(qts, base_addr);
224 }
225 
226 static void stop_transfer(QTestState *qts, uint64_t base_addr)
227 {
228     uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
229 
230     ctl1 &= ~(CTL1_START | CTL1_ACK);
231     ctl1 |= CTL1_STOP | CTL1_INTEN | CTL1_EOBINTE;
232     qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
233     ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
234     g_assert_false(ctl1 & CTL1_STOP);
235 }
236 
237 static void send_byte(QTestState *qts, uint64_t base_addr, uint8_t byte)
238 {
239     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
240                     ST_MODE | ST_XMIT | ST_SDAST);
241     qtest_writeb(qts, base_addr + OFFSET_SDA, byte);
242 }
243 
244 static bool check_recv(QTestState *qts, uint64_t base_addr)
245 {
246     uint8_t st, fif_ctl, rxf_ctl, rxf_sts;
247     bool fifo;
248 
249     st = qtest_readb(qts, base_addr + OFFSET_ST);
250     choose_bank(qts, base_addr, 0);
251     fif_ctl = qtest_readb(qts, base_addr + OFFSET_FIF_CTL);
252     fifo = fif_ctl & FIF_CTL_FIFO_EN;
253     if (!fifo) {
254         return st == (ST_MODE | ST_SDAST);
255     }
256 
257     choose_bank(qts, base_addr, 1);
258     rxf_ctl = qtest_readb(qts, base_addr + OFFSET_RXF_CTL);
259     rxf_sts = qtest_readb(qts, base_addr + OFFSET_RXF_STS);
260 
261     if ((rxf_ctl & RXF_CTL_THR_RXIE) && RXF_STS_RX_BYTES(rxf_sts) < 16) {
262         return st == ST_MODE;
263     } else {
264         return st == (ST_MODE | ST_SDAST);
265     }
266 }
267 
268 static uint8_t recv_byte(QTestState *qts, uint64_t base_addr)
269 {
270     g_assert_true(check_recv(qts, base_addr));
271     return qtest_readb(qts, base_addr + OFFSET_SDA);
272 }
273 
274 static void send_address(QTestState *qts, uint64_t base_addr, uint8_t addr,
275                          bool recv, bool valid)
276 {
277     uint8_t encoded_addr = (addr << 1) | (recv ? 1 : 0);
278     uint8_t st;
279 
280     qtest_writeb(qts, base_addr + OFFSET_SDA, encoded_addr);
281     st = qtest_readb(qts, base_addr + OFFSET_ST);
282 
283     if (valid) {
284         if (recv) {
285             g_assert_cmphex(st, ==, ST_MODE | ST_SDAST | ST_STASTR);
286         } else {
287             g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST | ST_STASTR);
288         }
289 
290         qtest_writeb(qts, base_addr + OFFSET_ST, ST_STASTR);
291         st = qtest_readb(qts, base_addr + OFFSET_ST);
292         if (recv) {
293             g_assert_true(check_recv(qts, base_addr));
294         } else {
295             g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST);
296         }
297     } else {
298         if (recv) {
299             g_assert_cmphex(st, ==, ST_MODE | ST_NEGACK);
300         } else {
301             g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_NEGACK);
302         }
303     }
304 }
305 
306 static void send_nack(QTestState *qts, uint64_t base_addr)
307 {
308     uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
309 
310     ctl1 &= ~(CTL1_START | CTL1_STOP);
311     ctl1 |= CTL1_ACK | CTL1_INTEN;
312     qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
313 }
314 
315 static void start_fifo_mode(QTestState *qts, uint64_t base_addr)
316 {
317     choose_bank(qts, base_addr, 0);
318     qtest_writeb(qts, base_addr + OFFSET_FIF_CTL, FIF_CTL_FIFO_EN);
319     g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTL) &
320                   FIF_CTL_FIFO_EN);
321     choose_bank(qts, base_addr, 1);
322     qtest_writeb(qts, base_addr + OFFSET_FIF_CTS,
323                  FIF_CTS_CLR_FIFO | FIF_CTS_RFTE_IE);
324     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_FIF_CTS), ==,
325                     FIF_CTS_RFTE_IE);
326     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_TXF_STS), ==, 0);
327     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_RXF_STS), ==, 0);
328 }
329 
330 static void start_recv_fifo(QTestState *qts, uint64_t base_addr, uint8_t bytes)
331 {
332     choose_bank(qts, base_addr, 1);
333     qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, 0);
334     qtest_writeb(qts, base_addr + OFFSET_RXF_CTL,
335                  RXF_CTL_THR_RXIE | RXF_CTL_LAST | bytes);
336 }
337 
338 /* Check the SMBus's status is set correctly when disabled. */
339 static void test_disable_bus(gconstpointer data)
340 {
341     intptr_t index = (intptr_t)data;
342     uint64_t base_addr = SMBUS_ADDR(index);
343     QTestState *qts = qtest_init("-machine npcm750-evb");
344 
345     disable_bus(qts, base_addr);
346     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==, 0);
347     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
348     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST3) & CST3_EO_BUSY);
349     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CST), ==, 0);
350     qtest_quit(qts);
351 }
352 
353 /* Check the SMBus returns a NACK for an invalid address. */
354 static void test_invalid_addr(gconstpointer data)
355 {
356     intptr_t index = (intptr_t)data;
357     uint64_t base_addr = SMBUS_ADDR(index);
358     int irq = SMBUS_IRQ(index);
359     QTestState *qts = qtest_init("-machine npcm750-evb");
360 
361     qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
362     enable_bus(qts, base_addr);
363     g_assert_false(qtest_get_irq(qts, irq));
364     start_transfer(qts, base_addr);
365     send_address(qts, base_addr, INVALID_DEVICE_ADDR, false, false);
366     g_assert_true(qtest_get_irq(qts, irq));
367     stop_transfer(qts, base_addr);
368     check_running(qts, base_addr);
369     qtest_writeb(qts, base_addr + OFFSET_ST, ST_NEGACK);
370     g_assert_false(qtest_readb(qts, base_addr + OFFSET_ST) & ST_NEGACK);
371     check_stopped(qts, base_addr);
372     qtest_quit(qts);
373 }
374 
375 /* Check the SMBus can send and receive bytes to a device in single mode. */
376 static void test_single_mode(gconstpointer data)
377 {
378     intptr_t index = (intptr_t)data;
379     uint64_t base_addr = SMBUS_ADDR(index);
380     int irq = SMBUS_IRQ(index);
381     uint8_t value = 0x60;
382     QTestState *qts = qtest_init("-machine npcm750-evb");
383 
384     qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
385     enable_bus(qts, base_addr);
386 
387     /* Sending */
388     g_assert_false(qtest_get_irq(qts, irq));
389     start_transfer(qts, base_addr);
390     g_assert_true(qtest_get_irq(qts, irq));
391     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
392     send_byte(qts, base_addr, TMP105_REG_CONFIG);
393     send_byte(qts, base_addr, value);
394     stop_transfer(qts, base_addr);
395     check_stopped(qts, base_addr);
396 
397     /* Receiving */
398     start_transfer(qts, base_addr);
399     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
400     send_byte(qts, base_addr, TMP105_REG_CONFIG);
401     start_transfer(qts, base_addr);
402     send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
403     send_nack(qts, base_addr);
404     stop_transfer(qts, base_addr);
405     check_running(qts, base_addr);
406     g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
407     check_stopped(qts, base_addr);
408     qtest_quit(qts);
409 }
410 
411 /* Check the SMBus can send and receive bytes in FIFO mode. */
412 static void test_fifo_mode(gconstpointer data)
413 {
414     intptr_t index = (intptr_t)data;
415     uint64_t base_addr = SMBUS_ADDR(index);
416     int irq = SMBUS_IRQ(index);
417     uint8_t value = 0x60;
418     QTestState *qts = qtest_init("-machine npcm750-evb");
419 
420     qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
421     enable_bus(qts, base_addr);
422     start_fifo_mode(qts, base_addr);
423     g_assert_false(qtest_get_irq(qts, irq));
424 
425     /* Sending */
426     start_transfer(qts, base_addr);
427     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
428     choose_bank(qts, base_addr, 1);
429     g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
430                   FIF_CTS_RXF_TXE);
431     qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, TXF_CTL_THR_TXIE);
432     send_byte(qts, base_addr, TMP105_REG_CONFIG);
433     send_byte(qts, base_addr, value);
434     g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
435                   FIF_CTS_RXF_TXE);
436     g_assert_true(qtest_readb(qts, base_addr + OFFSET_TXF_STS) &
437                   TXF_STS_TX_THST);
438     g_assert_cmpuint(TXF_STS_TX_BYTES(
439                         qtest_readb(qts, base_addr + OFFSET_TXF_STS)), ==, 0);
440     g_assert_true(qtest_get_irq(qts, irq));
441     stop_transfer(qts, base_addr);
442     check_stopped(qts, base_addr);
443 
444     /* Receiving */
445     start_fifo_mode(qts, base_addr);
446     start_transfer(qts, base_addr);
447     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
448     send_byte(qts, base_addr, TMP105_REG_CONFIG);
449     start_transfer(qts, base_addr);
450     qtest_writeb(qts, base_addr + OFFSET_FIF_CTS, FIF_CTS_RXF_TXE);
451     start_recv_fifo(qts, base_addr, 1);
452     send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
453     g_assert_false(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
454                    FIF_CTS_RXF_TXE);
455     g_assert_true(qtest_readb(qts, base_addr + OFFSET_RXF_STS) &
456                   RXF_STS_RX_THST);
457     g_assert_cmpuint(RXF_STS_RX_BYTES(
458                         qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 1);
459     send_nack(qts, base_addr);
460     stop_transfer(qts, base_addr);
461     check_running(qts, base_addr);
462     g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
463     g_assert_cmpuint(RXF_STS_RX_BYTES(
464                         qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 0);
465     check_stopped(qts, base_addr);
466     qtest_quit(qts);
467 }
468 
469 static void smbus_add_test(const char *name, int index, GTestDataFunc fn)
470 {
471     g_autofree char *full_name = g_strdup_printf(
472             "npcm7xx_smbus[%d]/%s", index, name);
473     qtest_add_data_func(full_name, (void *)(intptr_t)index, fn);
474 }
475 #define add_test(name, td) smbus_add_test(#name, td, test_##name)
476 
477 int main(int argc, char **argv)
478 {
479     int i;
480 
481     g_test_init(&argc, &argv, NULL);
482     g_test_set_nonfatal_assertions();
483 
484     for (i = 0; i < NR_SMBUS_DEVICES; ++i) {
485         add_test(disable_bus, i);
486         add_test(invalid_addr, i);
487     }
488 
489     for (i = 0; i < ARRAY_SIZE(evb_bus_list); ++i) {
490         add_test(single_mode, evb_bus_list[i]);
491         add_test(fifo_mode, evb_bus_list[i]);
492     }
493 
494     return g_test_run();
495 }
496