xref: /qemu/tests/qtest/npcm7xx_smbus-test.c (revision 2e3408b3cc7de4e87a9adafc8c19bfce3abec947)
1d986bf72SHao Wu /*
2d986bf72SHao Wu  * QTests for Nuvoton NPCM7xx SMBus Modules.
3d986bf72SHao Wu  *
4d986bf72SHao Wu  * Copyright 2020 Google LLC
5d986bf72SHao Wu  *
6d986bf72SHao Wu  * This program is free software; you can redistribute it and/or modify it
7d986bf72SHao Wu  * under the terms of the GNU General Public License as published by the
8d986bf72SHao Wu  * Free Software Foundation; either version 2 of the License, or
9d986bf72SHao Wu  * (at your option) any later version.
10d986bf72SHao Wu  *
11d986bf72SHao Wu  * This program is distributed in the hope that it will be useful, but WITHOUT
12d986bf72SHao Wu  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13d986bf72SHao Wu  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14d986bf72SHao Wu  * for more details.
15d986bf72SHao Wu  */
16d986bf72SHao Wu 
17d986bf72SHao Wu #include "qemu/osdep.h"
18d986bf72SHao Wu #include "qemu/bitops.h"
19d986bf72SHao Wu #include "libqos/i2c.h"
20*907b5105SMarc-André Lureau #include "libqtest.h"
215e9ae4b1SCorey Minyard #include "hw/sensor/tmp105_regs.h"
22d986bf72SHao Wu 
23d986bf72SHao Wu #define NR_SMBUS_DEVICES    16
24d986bf72SHao Wu #define SMBUS_ADDR(x)       (0xf0080000 + 0x1000 * (x))
25d986bf72SHao Wu #define SMBUS_IRQ(x)        (64 + (x))
26d986bf72SHao Wu 
27d986bf72SHao Wu #define EVB_DEVICE_ADDR     0x48
28d986bf72SHao Wu #define INVALID_DEVICE_ADDR 0x01
29d986bf72SHao Wu 
30d986bf72SHao Wu const int evb_bus_list[] = {0, 1, 2, 6};
31d986bf72SHao Wu 
32d986bf72SHao Wu /* Offsets */
33d986bf72SHao Wu enum CommonRegister {
34d986bf72SHao Wu     OFFSET_SDA     = 0x0,
35d986bf72SHao Wu     OFFSET_ST      = 0x2,
36d986bf72SHao Wu     OFFSET_CST     = 0x4,
37d986bf72SHao Wu     OFFSET_CTL1    = 0x6,
38d986bf72SHao Wu     OFFSET_ADDR1   = 0x8,
39d986bf72SHao Wu     OFFSET_CTL2    = 0xa,
40d986bf72SHao Wu     OFFSET_ADDR2   = 0xc,
41d986bf72SHao Wu     OFFSET_CTL3    = 0xe,
42d986bf72SHao Wu     OFFSET_CST2    = 0x18,
43d986bf72SHao Wu     OFFSET_CST3    = 0x19,
44d986bf72SHao Wu };
45d986bf72SHao Wu 
46d986bf72SHao Wu enum NPCM7xxSMBusBank0Register {
47d986bf72SHao Wu     OFFSET_ADDR3   = 0x10,
48d986bf72SHao Wu     OFFSET_ADDR7   = 0x11,
49d986bf72SHao Wu     OFFSET_ADDR4   = 0x12,
50d986bf72SHao Wu     OFFSET_ADDR8   = 0x13,
51d986bf72SHao Wu     OFFSET_ADDR5   = 0x14,
52d986bf72SHao Wu     OFFSET_ADDR9   = 0x15,
53d986bf72SHao Wu     OFFSET_ADDR6   = 0x16,
54d986bf72SHao Wu     OFFSET_ADDR10  = 0x17,
55d986bf72SHao Wu     OFFSET_CTL4    = 0x1a,
56d986bf72SHao Wu     OFFSET_CTL5    = 0x1b,
57d986bf72SHao Wu     OFFSET_SCLLT   = 0x1c,
58d986bf72SHao Wu     OFFSET_FIF_CTL = 0x1d,
59d986bf72SHao Wu     OFFSET_SCLHT   = 0x1e,
60d986bf72SHao Wu };
61d986bf72SHao Wu 
62d986bf72SHao Wu enum NPCM7xxSMBusBank1Register {
63d986bf72SHao Wu     OFFSET_FIF_CTS  = 0x10,
64d986bf72SHao Wu     OFFSET_FAIR_PER = 0x11,
65d986bf72SHao Wu     OFFSET_TXF_CTL  = 0x12,
66d986bf72SHao Wu     OFFSET_T_OUT    = 0x14,
67d986bf72SHao Wu     OFFSET_TXF_STS  = 0x1a,
68d986bf72SHao Wu     OFFSET_RXF_STS  = 0x1c,
69d986bf72SHao Wu     OFFSET_RXF_CTL  = 0x1e,
70d986bf72SHao Wu };
71d986bf72SHao Wu 
72d986bf72SHao Wu /* ST fields */
73d986bf72SHao Wu #define ST_STP              BIT(7)
74d986bf72SHao Wu #define ST_SDAST            BIT(6)
75d986bf72SHao Wu #define ST_BER              BIT(5)
76d986bf72SHao Wu #define ST_NEGACK           BIT(4)
77d986bf72SHao Wu #define ST_STASTR           BIT(3)
78d986bf72SHao Wu #define ST_NMATCH           BIT(2)
79d986bf72SHao Wu #define ST_MODE             BIT(1)
80d986bf72SHao Wu #define ST_XMIT             BIT(0)
81d986bf72SHao Wu 
82d986bf72SHao Wu /* CST fields */
83d986bf72SHao Wu #define CST_ARPMATCH        BIT(7)
84d986bf72SHao Wu #define CST_MATCHAF         BIT(6)
85d986bf72SHao Wu #define CST_TGSCL           BIT(5)
86d986bf72SHao Wu #define CST_TSDA            BIT(4)
87d986bf72SHao Wu #define CST_GCMATCH         BIT(3)
88d986bf72SHao Wu #define CST_MATCH           BIT(2)
89d986bf72SHao Wu #define CST_BB              BIT(1)
90d986bf72SHao Wu #define CST_BUSY            BIT(0)
91d986bf72SHao Wu 
92d986bf72SHao Wu /* CST2 fields */
93d986bf72SHao Wu #define CST2_INSTTS         BIT(7)
94d986bf72SHao Wu #define CST2_MATCH7F        BIT(6)
95d986bf72SHao Wu #define CST2_MATCH6F        BIT(5)
96d986bf72SHao Wu #define CST2_MATCH5F        BIT(4)
97d986bf72SHao Wu #define CST2_MATCH4F        BIT(3)
98d986bf72SHao Wu #define CST2_MATCH3F        BIT(2)
99d986bf72SHao Wu #define CST2_MATCH2F        BIT(1)
100d986bf72SHao Wu #define CST2_MATCH1F        BIT(0)
101d986bf72SHao Wu 
102d986bf72SHao Wu /* CST3 fields */
103d986bf72SHao Wu #define CST3_EO_BUSY        BIT(7)
104d986bf72SHao Wu #define CST3_MATCH10F       BIT(2)
105d986bf72SHao Wu #define CST3_MATCH9F        BIT(1)
106d986bf72SHao Wu #define CST3_MATCH8F        BIT(0)
107d986bf72SHao Wu 
108d986bf72SHao Wu /* CTL1 fields */
109d986bf72SHao Wu #define CTL1_STASTRE        BIT(7)
110d986bf72SHao Wu #define CTL1_NMINTE         BIT(6)
111d986bf72SHao Wu #define CTL1_GCMEN          BIT(5)
112d986bf72SHao Wu #define CTL1_ACK            BIT(4)
113d986bf72SHao Wu #define CTL1_EOBINTE        BIT(3)
114d986bf72SHao Wu #define CTL1_INTEN          BIT(2)
115d986bf72SHao Wu #define CTL1_STOP           BIT(1)
116d986bf72SHao Wu #define CTL1_START          BIT(0)
117d986bf72SHao Wu 
118d986bf72SHao Wu /* CTL2 fields */
119d986bf72SHao Wu #define CTL2_SCLFRQ(rv)     extract8((rv), 1, 6)
120d986bf72SHao Wu #define CTL2_ENABLE         BIT(0)
121d986bf72SHao Wu 
122d986bf72SHao Wu /* CTL3 fields */
123d986bf72SHao Wu #define CTL3_SCL_LVL        BIT(7)
124d986bf72SHao Wu #define CTL3_SDA_LVL        BIT(6)
125d986bf72SHao Wu #define CTL3_BNK_SEL        BIT(5)
126d986bf72SHao Wu #define CTL3_400K_MODE      BIT(4)
127d986bf72SHao Wu #define CTL3_IDL_START      BIT(3)
128d986bf72SHao Wu #define CTL3_ARPMEN         BIT(2)
129d986bf72SHao Wu #define CTL3_SCLFRQ(rv)     extract8((rv), 0, 2)
130d986bf72SHao Wu 
131d986bf72SHao Wu /* ADDR fields */
132d986bf72SHao Wu #define ADDR_EN             BIT(7)
133d986bf72SHao Wu #define ADDR_A(rv)          extract8((rv), 0, 6)
134d986bf72SHao Wu 
1356b6e7570SHao Wu /* FIF_CTL fields */
1366b6e7570SHao Wu #define FIF_CTL_FIFO_EN         BIT(4)
1376b6e7570SHao Wu 
1386b6e7570SHao Wu /* FIF_CTS fields */
1396b6e7570SHao Wu #define FIF_CTS_CLR_FIFO        BIT(6)
1406b6e7570SHao Wu #define FIF_CTS_RFTE_IE         BIT(3)
1416b6e7570SHao Wu #define FIF_CTS_RXF_TXE         BIT(1)
1426b6e7570SHao Wu 
1436b6e7570SHao Wu /* TXF_CTL fields */
1446b6e7570SHao Wu #define TXF_CTL_THR_TXIE        BIT(6)
1456b6e7570SHao Wu #define TXF_CTL_TX_THR(rv)      extract8((rv), 0, 5)
1466b6e7570SHao Wu 
1476b6e7570SHao Wu /* TXF_STS fields */
1486b6e7570SHao Wu #define TXF_STS_TX_THST         BIT(6)
1496b6e7570SHao Wu #define TXF_STS_TX_BYTES(rv)    extract8((rv), 0, 5)
1506b6e7570SHao Wu 
1516b6e7570SHao Wu /* RXF_CTL fields */
1526b6e7570SHao Wu #define RXF_CTL_THR_RXIE        BIT(6)
1536b6e7570SHao Wu #define RXF_CTL_LAST            BIT(5)
1546b6e7570SHao Wu #define RXF_CTL_RX_THR(rv)      extract8((rv), 0, 5)
1556b6e7570SHao Wu 
1566b6e7570SHao Wu /* RXF_STS fields */
1576b6e7570SHao Wu #define RXF_STS_RX_THST         BIT(6)
1586b6e7570SHao Wu #define RXF_STS_RX_BYTES(rv)    extract8((rv), 0, 5)
1596b6e7570SHao Wu 
1606b6e7570SHao Wu 
choose_bank(QTestState * qts,uint64_t base_addr,uint8_t bank)1616b6e7570SHao Wu static void choose_bank(QTestState *qts, uint64_t base_addr, uint8_t bank)
1626b6e7570SHao Wu {
1636b6e7570SHao Wu     uint8_t ctl3 = qtest_readb(qts, base_addr + OFFSET_CTL3);
1646b6e7570SHao Wu 
1656b6e7570SHao Wu     if (bank) {
1666b6e7570SHao Wu         ctl3 |= CTL3_BNK_SEL;
1676b6e7570SHao Wu     } else {
1686b6e7570SHao Wu         ctl3 &= ~CTL3_BNK_SEL;
1696b6e7570SHao Wu     }
1706b6e7570SHao Wu 
1716b6e7570SHao Wu     qtest_writeb(qts, base_addr + OFFSET_CTL3, ctl3);
1726b6e7570SHao Wu }
173d986bf72SHao Wu 
check_running(QTestState * qts,uint64_t base_addr)174d986bf72SHao Wu static void check_running(QTestState *qts, uint64_t base_addr)
175d986bf72SHao Wu {
176d986bf72SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
177d986bf72SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
178d986bf72SHao Wu }
179d986bf72SHao Wu 
check_stopped(QTestState * qts,uint64_t base_addr)180d986bf72SHao Wu static void check_stopped(QTestState *qts, uint64_t base_addr)
181d986bf72SHao Wu {
182d986bf72SHao Wu     uint8_t cst3;
183d986bf72SHao Wu 
184d986bf72SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
185d986bf72SHao Wu     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
186d986bf72SHao Wu     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
187d986bf72SHao Wu 
188d986bf72SHao Wu     cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
189d986bf72SHao Wu     g_assert_true(cst3 & CST3_EO_BUSY);
190d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_CST3, cst3);
191d986bf72SHao Wu     cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
192d986bf72SHao Wu     g_assert_false(cst3 & CST3_EO_BUSY);
193d986bf72SHao Wu }
194d986bf72SHao Wu 
enable_bus(QTestState * qts,uint64_t base_addr)195d986bf72SHao Wu static void enable_bus(QTestState *qts, uint64_t base_addr)
196d986bf72SHao Wu {
197d986bf72SHao Wu     uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
198d986bf72SHao Wu 
199d986bf72SHao Wu     ctl2 |= CTL2_ENABLE;
200d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
201d986bf72SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
202d986bf72SHao Wu }
203d986bf72SHao Wu 
disable_bus(QTestState * qts,uint64_t base_addr)204d986bf72SHao Wu static void disable_bus(QTestState *qts, uint64_t base_addr)
205d986bf72SHao Wu {
206d986bf72SHao Wu     uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
207d986bf72SHao Wu 
208d986bf72SHao Wu     ctl2 &= ~CTL2_ENABLE;
209d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
210d986bf72SHao Wu     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
211d986bf72SHao Wu }
212d986bf72SHao Wu 
start_transfer(QTestState * qts,uint64_t base_addr)213d986bf72SHao Wu static void start_transfer(QTestState *qts, uint64_t base_addr)
214d986bf72SHao Wu {
215d986bf72SHao Wu     uint8_t ctl1;
216d986bf72SHao Wu 
217d986bf72SHao Wu     ctl1 = CTL1_START | CTL1_INTEN | CTL1_STASTRE;
218d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
219d986bf72SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==,
220d986bf72SHao Wu                     CTL1_INTEN | CTL1_STASTRE | CTL1_INTEN);
221d986bf72SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
222d986bf72SHao Wu                     ST_MODE | ST_XMIT | ST_SDAST);
223d986bf72SHao Wu     check_running(qts, base_addr);
224d986bf72SHao Wu }
225d986bf72SHao Wu 
stop_transfer(QTestState * qts,uint64_t base_addr)226d986bf72SHao Wu static void stop_transfer(QTestState *qts, uint64_t base_addr)
227d986bf72SHao Wu {
228d986bf72SHao Wu     uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
229d986bf72SHao Wu 
230d986bf72SHao Wu     ctl1 &= ~(CTL1_START | CTL1_ACK);
231d986bf72SHao Wu     ctl1 |= CTL1_STOP | CTL1_INTEN | CTL1_EOBINTE;
232d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
233d986bf72SHao Wu     ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
234d986bf72SHao Wu     g_assert_false(ctl1 & CTL1_STOP);
235d986bf72SHao Wu }
236d986bf72SHao Wu 
send_byte(QTestState * qts,uint64_t base_addr,uint8_t byte)237d986bf72SHao Wu static void send_byte(QTestState *qts, uint64_t base_addr, uint8_t byte)
238d986bf72SHao Wu {
239d986bf72SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
240d986bf72SHao Wu                     ST_MODE | ST_XMIT | ST_SDAST);
241d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_SDA, byte);
242d986bf72SHao Wu }
243d986bf72SHao Wu 
check_recv(QTestState * qts,uint64_t base_addr)2446b6e7570SHao Wu static bool check_recv(QTestState *qts, uint64_t base_addr)
2456b6e7570SHao Wu {
2466b6e7570SHao Wu     uint8_t st, fif_ctl, rxf_ctl, rxf_sts;
2476b6e7570SHao Wu     bool fifo;
2486b6e7570SHao Wu 
2496b6e7570SHao Wu     st = qtest_readb(qts, base_addr + OFFSET_ST);
2506b6e7570SHao Wu     choose_bank(qts, base_addr, 0);
2516b6e7570SHao Wu     fif_ctl = qtest_readb(qts, base_addr + OFFSET_FIF_CTL);
2526b6e7570SHao Wu     fifo = fif_ctl & FIF_CTL_FIFO_EN;
2536b6e7570SHao Wu     if (!fifo) {
2546b6e7570SHao Wu         return st == (ST_MODE | ST_SDAST);
2556b6e7570SHao Wu     }
2566b6e7570SHao Wu 
2576b6e7570SHao Wu     choose_bank(qts, base_addr, 1);
2586b6e7570SHao Wu     rxf_ctl = qtest_readb(qts, base_addr + OFFSET_RXF_CTL);
2596b6e7570SHao Wu     rxf_sts = qtest_readb(qts, base_addr + OFFSET_RXF_STS);
2606b6e7570SHao Wu 
2616b6e7570SHao Wu     if ((rxf_ctl & RXF_CTL_THR_RXIE) && RXF_STS_RX_BYTES(rxf_sts) < 16) {
2626b6e7570SHao Wu         return st == ST_MODE;
2636b6e7570SHao Wu     } else {
2646b6e7570SHao Wu         return st == (ST_MODE | ST_SDAST);
2656b6e7570SHao Wu     }
2666b6e7570SHao Wu }
2676b6e7570SHao Wu 
recv_byte(QTestState * qts,uint64_t base_addr)268d986bf72SHao Wu static uint8_t recv_byte(QTestState *qts, uint64_t base_addr)
269d986bf72SHao Wu {
2706b6e7570SHao Wu     g_assert_true(check_recv(qts, base_addr));
271d986bf72SHao Wu     return qtest_readb(qts, base_addr + OFFSET_SDA);
272d986bf72SHao Wu }
273d986bf72SHao Wu 
send_address(QTestState * qts,uint64_t base_addr,uint8_t addr,bool recv,bool valid)274d986bf72SHao Wu static void send_address(QTestState *qts, uint64_t base_addr, uint8_t addr,
275d986bf72SHao Wu                          bool recv, bool valid)
276d986bf72SHao Wu {
277d986bf72SHao Wu     uint8_t encoded_addr = (addr << 1) | (recv ? 1 : 0);
278d986bf72SHao Wu     uint8_t st;
279d986bf72SHao Wu 
280d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_SDA, encoded_addr);
281d986bf72SHao Wu     st = qtest_readb(qts, base_addr + OFFSET_ST);
282d986bf72SHao Wu 
283d986bf72SHao Wu     if (valid) {
284d986bf72SHao Wu         if (recv) {
285d986bf72SHao Wu             g_assert_cmphex(st, ==, ST_MODE | ST_SDAST | ST_STASTR);
286d986bf72SHao Wu         } else {
287d986bf72SHao Wu             g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST | ST_STASTR);
288d986bf72SHao Wu         }
289d986bf72SHao Wu 
290d986bf72SHao Wu         qtest_writeb(qts, base_addr + OFFSET_ST, ST_STASTR);
291d986bf72SHao Wu         st = qtest_readb(qts, base_addr + OFFSET_ST);
292d986bf72SHao Wu         if (recv) {
2936b6e7570SHao Wu             g_assert_true(check_recv(qts, base_addr));
294d986bf72SHao Wu         } else {
295d986bf72SHao Wu             g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST);
296d986bf72SHao Wu         }
297d986bf72SHao Wu     } else {
298d986bf72SHao Wu         if (recv) {
299d986bf72SHao Wu             g_assert_cmphex(st, ==, ST_MODE | ST_NEGACK);
300d986bf72SHao Wu         } else {
301d986bf72SHao Wu             g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_NEGACK);
302d986bf72SHao Wu         }
303d986bf72SHao Wu     }
304d986bf72SHao Wu }
305d986bf72SHao Wu 
send_nack(QTestState * qts,uint64_t base_addr)306d986bf72SHao Wu static void send_nack(QTestState *qts, uint64_t base_addr)
307d986bf72SHao Wu {
308d986bf72SHao Wu     uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
309d986bf72SHao Wu 
310d986bf72SHao Wu     ctl1 &= ~(CTL1_START | CTL1_STOP);
311d986bf72SHao Wu     ctl1 |= CTL1_ACK | CTL1_INTEN;
312d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
313d986bf72SHao Wu }
314d986bf72SHao Wu 
start_fifo_mode(QTestState * qts,uint64_t base_addr)3156b6e7570SHao Wu static void start_fifo_mode(QTestState *qts, uint64_t base_addr)
3166b6e7570SHao Wu {
3176b6e7570SHao Wu     choose_bank(qts, base_addr, 0);
3186b6e7570SHao Wu     qtest_writeb(qts, base_addr + OFFSET_FIF_CTL, FIF_CTL_FIFO_EN);
3196b6e7570SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTL) &
3206b6e7570SHao Wu                   FIF_CTL_FIFO_EN);
3216b6e7570SHao Wu     choose_bank(qts, base_addr, 1);
3226b6e7570SHao Wu     qtest_writeb(qts, base_addr + OFFSET_FIF_CTS,
3236b6e7570SHao Wu                  FIF_CTS_CLR_FIFO | FIF_CTS_RFTE_IE);
3246b6e7570SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_FIF_CTS), ==,
3256b6e7570SHao Wu                     FIF_CTS_RFTE_IE);
3266b6e7570SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_TXF_STS), ==, 0);
3276b6e7570SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_RXF_STS), ==, 0);
3286b6e7570SHao Wu }
3296b6e7570SHao Wu 
start_recv_fifo(QTestState * qts,uint64_t base_addr,uint8_t bytes)3306b6e7570SHao Wu static void start_recv_fifo(QTestState *qts, uint64_t base_addr, uint8_t bytes)
3316b6e7570SHao Wu {
3326b6e7570SHao Wu     choose_bank(qts, base_addr, 1);
3336b6e7570SHao Wu     qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, 0);
3346b6e7570SHao Wu     qtest_writeb(qts, base_addr + OFFSET_RXF_CTL,
3356b6e7570SHao Wu                  RXF_CTL_THR_RXIE | RXF_CTL_LAST | bytes);
3366b6e7570SHao Wu }
3376b6e7570SHao Wu 
338d986bf72SHao Wu /* Check the SMBus's status is set correctly when disabled. */
test_disable_bus(gconstpointer data)339d986bf72SHao Wu static void test_disable_bus(gconstpointer data)
340d986bf72SHao Wu {
341d986bf72SHao Wu     intptr_t index = (intptr_t)data;
342d986bf72SHao Wu     uint64_t base_addr = SMBUS_ADDR(index);
343d986bf72SHao Wu     QTestState *qts = qtest_init("-machine npcm750-evb");
344d986bf72SHao Wu 
345d986bf72SHao Wu     disable_bus(qts, base_addr);
346d986bf72SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==, 0);
347d986bf72SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
348d986bf72SHao Wu     g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST3) & CST3_EO_BUSY);
349d986bf72SHao Wu     g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CST), ==, 0);
350d986bf72SHao Wu     qtest_quit(qts);
351d986bf72SHao Wu }
352d986bf72SHao Wu 
353d986bf72SHao Wu /* Check the SMBus returns a NACK for an invalid address. */
test_invalid_addr(gconstpointer data)354d986bf72SHao Wu static void test_invalid_addr(gconstpointer data)
355d986bf72SHao Wu {
356d986bf72SHao Wu     intptr_t index = (intptr_t)data;
357d986bf72SHao Wu     uint64_t base_addr = SMBUS_ADDR(index);
358d986bf72SHao Wu     int irq = SMBUS_IRQ(index);
359d986bf72SHao Wu     QTestState *qts = qtest_init("-machine npcm750-evb");
360d986bf72SHao Wu 
361d986bf72SHao Wu     qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
362d986bf72SHao Wu     enable_bus(qts, base_addr);
363d986bf72SHao Wu     g_assert_false(qtest_get_irq(qts, irq));
364d986bf72SHao Wu     start_transfer(qts, base_addr);
365d986bf72SHao Wu     send_address(qts, base_addr, INVALID_DEVICE_ADDR, false, false);
366d986bf72SHao Wu     g_assert_true(qtest_get_irq(qts, irq));
367d986bf72SHao Wu     stop_transfer(qts, base_addr);
368d986bf72SHao Wu     check_running(qts, base_addr);
369d986bf72SHao Wu     qtest_writeb(qts, base_addr + OFFSET_ST, ST_NEGACK);
370d986bf72SHao Wu     g_assert_false(qtest_readb(qts, base_addr + OFFSET_ST) & ST_NEGACK);
371d986bf72SHao Wu     check_stopped(qts, base_addr);
372d986bf72SHao Wu     qtest_quit(qts);
373d986bf72SHao Wu }
374d986bf72SHao Wu 
375d986bf72SHao Wu /* Check the SMBus can send and receive bytes to a device in single mode. */
test_single_mode(gconstpointer data)376d986bf72SHao Wu static void test_single_mode(gconstpointer data)
377d986bf72SHao Wu {
378d986bf72SHao Wu     intptr_t index = (intptr_t)data;
379d986bf72SHao Wu     uint64_t base_addr = SMBUS_ADDR(index);
380d986bf72SHao Wu     int irq = SMBUS_IRQ(index);
381d986bf72SHao Wu     uint8_t value = 0x60;
382d986bf72SHao Wu     QTestState *qts = qtest_init("-machine npcm750-evb");
383d986bf72SHao Wu 
384d986bf72SHao Wu     qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
385d986bf72SHao Wu     enable_bus(qts, base_addr);
386d986bf72SHao Wu 
387d986bf72SHao Wu     /* Sending */
388d986bf72SHao Wu     g_assert_false(qtest_get_irq(qts, irq));
389d986bf72SHao Wu     start_transfer(qts, base_addr);
390d986bf72SHao Wu     g_assert_true(qtest_get_irq(qts, irq));
391d986bf72SHao Wu     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
392d986bf72SHao Wu     send_byte(qts, base_addr, TMP105_REG_CONFIG);
393d986bf72SHao Wu     send_byte(qts, base_addr, value);
394d986bf72SHao Wu     stop_transfer(qts, base_addr);
395d986bf72SHao Wu     check_stopped(qts, base_addr);
396d986bf72SHao Wu 
397d986bf72SHao Wu     /* Receiving */
398d986bf72SHao Wu     start_transfer(qts, base_addr);
399d986bf72SHao Wu     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
400d986bf72SHao Wu     send_byte(qts, base_addr, TMP105_REG_CONFIG);
401d986bf72SHao Wu     start_transfer(qts, base_addr);
402d986bf72SHao Wu     send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
403d986bf72SHao Wu     send_nack(qts, base_addr);
404d986bf72SHao Wu     stop_transfer(qts, base_addr);
405d986bf72SHao Wu     check_running(qts, base_addr);
406d986bf72SHao Wu     g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
407d986bf72SHao Wu     check_stopped(qts, base_addr);
408d986bf72SHao Wu     qtest_quit(qts);
409d986bf72SHao Wu }
410d986bf72SHao Wu 
4116b6e7570SHao Wu /* Check the SMBus can send and receive bytes in FIFO mode. */
test_fifo_mode(gconstpointer data)4126b6e7570SHao Wu static void test_fifo_mode(gconstpointer data)
4136b6e7570SHao Wu {
4146b6e7570SHao Wu     intptr_t index = (intptr_t)data;
4156b6e7570SHao Wu     uint64_t base_addr = SMBUS_ADDR(index);
4166b6e7570SHao Wu     int irq = SMBUS_IRQ(index);
4176b6e7570SHao Wu     uint8_t value = 0x60;
4186b6e7570SHao Wu     QTestState *qts = qtest_init("-machine npcm750-evb");
4196b6e7570SHao Wu 
4206b6e7570SHao Wu     qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
4216b6e7570SHao Wu     enable_bus(qts, base_addr);
4226b6e7570SHao Wu     start_fifo_mode(qts, base_addr);
4236b6e7570SHao Wu     g_assert_false(qtest_get_irq(qts, irq));
4246b6e7570SHao Wu 
4256b6e7570SHao Wu     /* Sending */
4266b6e7570SHao Wu     start_transfer(qts, base_addr);
4276b6e7570SHao Wu     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
4286b6e7570SHao Wu     choose_bank(qts, base_addr, 1);
4296b6e7570SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
4306b6e7570SHao Wu                   FIF_CTS_RXF_TXE);
4316b6e7570SHao Wu     qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, TXF_CTL_THR_TXIE);
4326b6e7570SHao Wu     send_byte(qts, base_addr, TMP105_REG_CONFIG);
4336b6e7570SHao Wu     send_byte(qts, base_addr, value);
4346b6e7570SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
4356b6e7570SHao Wu                   FIF_CTS_RXF_TXE);
4366b6e7570SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_TXF_STS) &
4376b6e7570SHao Wu                   TXF_STS_TX_THST);
4386b6e7570SHao Wu     g_assert_cmpuint(TXF_STS_TX_BYTES(
4396b6e7570SHao Wu                         qtest_readb(qts, base_addr + OFFSET_TXF_STS)), ==, 0);
4406b6e7570SHao Wu     g_assert_true(qtest_get_irq(qts, irq));
4416b6e7570SHao Wu     stop_transfer(qts, base_addr);
4426b6e7570SHao Wu     check_stopped(qts, base_addr);
4436b6e7570SHao Wu 
4446b6e7570SHao Wu     /* Receiving */
4456b6e7570SHao Wu     start_fifo_mode(qts, base_addr);
4466b6e7570SHao Wu     start_transfer(qts, base_addr);
4476b6e7570SHao Wu     send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
4486b6e7570SHao Wu     send_byte(qts, base_addr, TMP105_REG_CONFIG);
4496b6e7570SHao Wu     start_transfer(qts, base_addr);
4506b6e7570SHao Wu     qtest_writeb(qts, base_addr + OFFSET_FIF_CTS, FIF_CTS_RXF_TXE);
4516b6e7570SHao Wu     start_recv_fifo(qts, base_addr, 1);
4526b6e7570SHao Wu     send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
4536b6e7570SHao Wu     g_assert_false(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
4546b6e7570SHao Wu                    FIF_CTS_RXF_TXE);
4556b6e7570SHao Wu     g_assert_true(qtest_readb(qts, base_addr + OFFSET_RXF_STS) &
4566b6e7570SHao Wu                   RXF_STS_RX_THST);
4576b6e7570SHao Wu     g_assert_cmpuint(RXF_STS_RX_BYTES(
4586b6e7570SHao Wu                         qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 1);
4596b6e7570SHao Wu     send_nack(qts, base_addr);
4606b6e7570SHao Wu     stop_transfer(qts, base_addr);
4616b6e7570SHao Wu     check_running(qts, base_addr);
4626b6e7570SHao Wu     g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
4636b6e7570SHao Wu     g_assert_cmpuint(RXF_STS_RX_BYTES(
4646b6e7570SHao Wu                         qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 0);
4656b6e7570SHao Wu     check_stopped(qts, base_addr);
4666b6e7570SHao Wu     qtest_quit(qts);
4676b6e7570SHao Wu }
4686b6e7570SHao Wu 
smbus_add_test(const char * name,int index,GTestDataFunc fn)469d986bf72SHao Wu static void smbus_add_test(const char *name, int index, GTestDataFunc fn)
470d986bf72SHao Wu {
471d986bf72SHao Wu     g_autofree char *full_name = g_strdup_printf(
472d986bf72SHao Wu             "npcm7xx_smbus[%d]/%s", index, name);
473d986bf72SHao Wu     qtest_add_data_func(full_name, (void *)(intptr_t)index, fn);
474d986bf72SHao Wu }
475d986bf72SHao Wu #define add_test(name, td) smbus_add_test(#name, td, test_##name)
476d986bf72SHao Wu 
main(int argc,char ** argv)477d986bf72SHao Wu int main(int argc, char **argv)
478d986bf72SHao Wu {
479d986bf72SHao Wu     int i;
480d986bf72SHao Wu 
481d986bf72SHao Wu     g_test_init(&argc, &argv, NULL);
482d986bf72SHao Wu     g_test_set_nonfatal_assertions();
483d986bf72SHao Wu 
484d986bf72SHao Wu     for (i = 0; i < NR_SMBUS_DEVICES; ++i) {
485d986bf72SHao Wu         add_test(disable_bus, i);
486d986bf72SHao Wu         add_test(invalid_addr, i);
487d986bf72SHao Wu     }
488d986bf72SHao Wu 
489d986bf72SHao Wu     for (i = 0; i < ARRAY_SIZE(evb_bus_list); ++i) {
490d986bf72SHao Wu         add_test(single_mode, evb_bus_list[i]);
4916b6e7570SHao Wu         add_test(fifo_mode, evb_bus_list[i]);
492d986bf72SHao Wu     }
493d986bf72SHao Wu 
494d986bf72SHao Wu     return g_test_run();
495d986bf72SHao Wu }
496