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
choose_bank(QTestState * qts,uint64_t base_addr,uint8_t bank)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
check_running(QTestState * qts,uint64_t base_addr)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
check_stopped(QTestState * qts,uint64_t base_addr)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
enable_bus(QTestState * qts,uint64_t base_addr)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
disable_bus(QTestState * qts,uint64_t base_addr)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
start_transfer(QTestState * qts,uint64_t base_addr)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
stop_transfer(QTestState * qts,uint64_t base_addr)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
send_byte(QTestState * qts,uint64_t base_addr,uint8_t byte)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
check_recv(QTestState * qts,uint64_t base_addr)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
recv_byte(QTestState * qts,uint64_t base_addr)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
send_address(QTestState * qts,uint64_t base_addr,uint8_t addr,bool recv,bool valid)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
send_nack(QTestState * qts,uint64_t base_addr)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
start_fifo_mode(QTestState * qts,uint64_t base_addr)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
start_recv_fifo(QTestState * qts,uint64_t base_addr,uint8_t bytes)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. */
test_disable_bus(gconstpointer data)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. */
test_invalid_addr(gconstpointer data)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. */
test_single_mode(gconstpointer data)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. */
test_fifo_mode(gconstpointer data)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
smbus_add_test(const char * name,int index,GTestDataFunc fn)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
main(int argc,char ** argv)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