qemu/tests/qtest/npcm7xx_smbus-test.c
<<
>>
Prefs
   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
  30const int evb_bus_list[] = {0, 1, 2, 6};
  31
  32/* Offsets */
  33enum 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
  46enum 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
  62enum 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
 161static 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
 174static 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
 180static 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
 195static 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
 204static 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
 213static 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
 226static 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
 237static 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
 244static 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
 268static 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
 274static 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
 306static 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
 315static 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
 330static 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. */
 339static 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. */
 354static 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. */
 376static 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. */
 412static 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
 469static 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
 477int 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