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 "libqos/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