xref: /qemu/hw/i2c/npcm7xx_smbus.c (revision 6b6e7570d6ebc8bc6d9bc1356ae46708f02d3eeb)
194e77879SHao Wu /*
294e77879SHao Wu  * Nuvoton NPCM7xx SMBus Module.
394e77879SHao Wu  *
494e77879SHao Wu  * Copyright 2020 Google LLC
594e77879SHao Wu  *
694e77879SHao Wu  * This program is free software; you can redistribute it and/or modify it
794e77879SHao Wu  * under the terms of the GNU General Public License as published by the
894e77879SHao Wu  * Free Software Foundation; either version 2 of the License, or
994e77879SHao Wu  * (at your option) any later version.
1094e77879SHao Wu  *
1194e77879SHao Wu  * This program is distributed in the hope that it will be useful, but WITHOUT
1294e77879SHao Wu  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1394e77879SHao Wu  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1494e77879SHao Wu  * for more details.
1594e77879SHao Wu  */
1694e77879SHao Wu 
1794e77879SHao Wu #include "qemu/osdep.h"
1894e77879SHao Wu 
1994e77879SHao Wu #include "hw/i2c/npcm7xx_smbus.h"
2094e77879SHao Wu #include "migration/vmstate.h"
2194e77879SHao Wu #include "qemu/bitops.h"
2294e77879SHao Wu #include "qemu/guest-random.h"
2394e77879SHao Wu #include "qemu/log.h"
2494e77879SHao Wu #include "qemu/module.h"
2594e77879SHao Wu #include "qemu/units.h"
2694e77879SHao Wu 
2794e77879SHao Wu #include "trace.h"
2894e77879SHao Wu 
2994e77879SHao Wu enum NPCM7xxSMBusCommonRegister {
3094e77879SHao Wu     NPCM7XX_SMB_SDA     = 0x0,
3194e77879SHao Wu     NPCM7XX_SMB_ST      = 0x2,
3294e77879SHao Wu     NPCM7XX_SMB_CST     = 0x4,
3394e77879SHao Wu     NPCM7XX_SMB_CTL1    = 0x6,
3494e77879SHao Wu     NPCM7XX_SMB_ADDR1   = 0x8,
3594e77879SHao Wu     NPCM7XX_SMB_CTL2    = 0xa,
3694e77879SHao Wu     NPCM7XX_SMB_ADDR2   = 0xc,
3794e77879SHao Wu     NPCM7XX_SMB_CTL3    = 0xe,
3894e77879SHao Wu     NPCM7XX_SMB_CST2    = 0x18,
3994e77879SHao Wu     NPCM7XX_SMB_CST3    = 0x19,
4094e77879SHao Wu     NPCM7XX_SMB_VER     = 0x1f,
4194e77879SHao Wu };
4294e77879SHao Wu 
4394e77879SHao Wu enum NPCM7xxSMBusBank0Register {
4494e77879SHao Wu     NPCM7XX_SMB_ADDR3   = 0x10,
4594e77879SHao Wu     NPCM7XX_SMB_ADDR7   = 0x11,
4694e77879SHao Wu     NPCM7XX_SMB_ADDR4   = 0x12,
4794e77879SHao Wu     NPCM7XX_SMB_ADDR8   = 0x13,
4894e77879SHao Wu     NPCM7XX_SMB_ADDR5   = 0x14,
4994e77879SHao Wu     NPCM7XX_SMB_ADDR9   = 0x15,
5094e77879SHao Wu     NPCM7XX_SMB_ADDR6   = 0x16,
5194e77879SHao Wu     NPCM7XX_SMB_ADDR10  = 0x17,
5294e77879SHao Wu     NPCM7XX_SMB_CTL4    = 0x1a,
5394e77879SHao Wu     NPCM7XX_SMB_CTL5    = 0x1b,
5494e77879SHao Wu     NPCM7XX_SMB_SCLLT   = 0x1c,
5594e77879SHao Wu     NPCM7XX_SMB_FIF_CTL = 0x1d,
5694e77879SHao Wu     NPCM7XX_SMB_SCLHT   = 0x1e,
5794e77879SHao Wu };
5894e77879SHao Wu 
5994e77879SHao Wu enum NPCM7xxSMBusBank1Register {
6094e77879SHao Wu     NPCM7XX_SMB_FIF_CTS  = 0x10,
6194e77879SHao Wu     NPCM7XX_SMB_FAIR_PER = 0x11,
6294e77879SHao Wu     NPCM7XX_SMB_TXF_CTL  = 0x12,
6394e77879SHao Wu     NPCM7XX_SMB_T_OUT    = 0x14,
6494e77879SHao Wu     NPCM7XX_SMB_TXF_STS  = 0x1a,
6594e77879SHao Wu     NPCM7XX_SMB_RXF_STS  = 0x1c,
6694e77879SHao Wu     NPCM7XX_SMB_RXF_CTL  = 0x1e,
6794e77879SHao Wu };
6894e77879SHao Wu 
6994e77879SHao Wu /* ST fields */
7094e77879SHao Wu #define NPCM7XX_SMBST_STP           BIT(7)
7194e77879SHao Wu #define NPCM7XX_SMBST_SDAST         BIT(6)
7294e77879SHao Wu #define NPCM7XX_SMBST_BER           BIT(5)
7394e77879SHao Wu #define NPCM7XX_SMBST_NEGACK        BIT(4)
7494e77879SHao Wu #define NPCM7XX_SMBST_STASTR        BIT(3)
7594e77879SHao Wu #define NPCM7XX_SMBST_NMATCH        BIT(2)
7694e77879SHao Wu #define NPCM7XX_SMBST_MODE          BIT(1)
7794e77879SHao Wu #define NPCM7XX_SMBST_XMIT          BIT(0)
7894e77879SHao Wu 
7994e77879SHao Wu /* CST fields */
8094e77879SHao Wu #define NPCM7XX_SMBCST_ARPMATCH        BIT(7)
8194e77879SHao Wu #define NPCM7XX_SMBCST_MATCHAF         BIT(6)
8294e77879SHao Wu #define NPCM7XX_SMBCST_TGSCL           BIT(5)
8394e77879SHao Wu #define NPCM7XX_SMBCST_TSDA            BIT(4)
8494e77879SHao Wu #define NPCM7XX_SMBCST_GCMATCH         BIT(3)
8594e77879SHao Wu #define NPCM7XX_SMBCST_MATCH           BIT(2)
8694e77879SHao Wu #define NPCM7XX_SMBCST_BB              BIT(1)
8794e77879SHao Wu #define NPCM7XX_SMBCST_BUSY            BIT(0)
8894e77879SHao Wu 
8994e77879SHao Wu /* CST2 fields */
9094e77879SHao Wu #define NPCM7XX_SMBCST2_INTSTS         BIT(7)
9194e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH7F        BIT(6)
9294e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH6F        BIT(5)
9394e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH5F        BIT(4)
9494e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH4F        BIT(3)
9594e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH3F        BIT(2)
9694e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH2F        BIT(1)
9794e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH1F        BIT(0)
9894e77879SHao Wu 
9994e77879SHao Wu /* CST3 fields */
10094e77879SHao Wu #define NPCM7XX_SMBCST3_EO_BUSY        BIT(7)
10194e77879SHao Wu #define NPCM7XX_SMBCST3_MATCH10F       BIT(2)
10294e77879SHao Wu #define NPCM7XX_SMBCST3_MATCH9F        BIT(1)
10394e77879SHao Wu #define NPCM7XX_SMBCST3_MATCH8F        BIT(0)
10494e77879SHao Wu 
10594e77879SHao Wu /* CTL1 fields */
10694e77879SHao Wu #define NPCM7XX_SMBCTL1_STASTRE     BIT(7)
10794e77879SHao Wu #define NPCM7XX_SMBCTL1_NMINTE      BIT(6)
10894e77879SHao Wu #define NPCM7XX_SMBCTL1_GCMEN       BIT(5)
10994e77879SHao Wu #define NPCM7XX_SMBCTL1_ACK         BIT(4)
11094e77879SHao Wu #define NPCM7XX_SMBCTL1_EOBINTE     BIT(3)
11194e77879SHao Wu #define NPCM7XX_SMBCTL1_INTEN       BIT(2)
11294e77879SHao Wu #define NPCM7XX_SMBCTL1_STOP        BIT(1)
11394e77879SHao Wu #define NPCM7XX_SMBCTL1_START       BIT(0)
11494e77879SHao Wu 
11594e77879SHao Wu /* CTL2 fields */
11694e77879SHao Wu #define NPCM7XX_SMBCTL2_SCLFRQ(rv)  extract8((rv), 1, 6)
11794e77879SHao Wu #define NPCM7XX_SMBCTL2_ENABLE      BIT(0)
11894e77879SHao Wu 
11994e77879SHao Wu /* CTL3 fields */
12094e77879SHao Wu #define NPCM7XX_SMBCTL3_SCL_LVL     BIT(7)
12194e77879SHao Wu #define NPCM7XX_SMBCTL3_SDA_LVL     BIT(6)
12294e77879SHao Wu #define NPCM7XX_SMBCTL3_BNK_SEL     BIT(5)
12394e77879SHao Wu #define NPCM7XX_SMBCTL3_400K_MODE   BIT(4)
12494e77879SHao Wu #define NPCM7XX_SMBCTL3_IDL_START   BIT(3)
12594e77879SHao Wu #define NPCM7XX_SMBCTL3_ARPMEN      BIT(2)
12694e77879SHao Wu #define NPCM7XX_SMBCTL3_SCLFRQ(rv)  extract8((rv), 0, 2)
12794e77879SHao Wu 
12894e77879SHao Wu /* ADDR fields */
12994e77879SHao Wu #define NPCM7XX_ADDR_EN             BIT(7)
13094e77879SHao Wu #define NPCM7XX_ADDR_A(rv)          extract8((rv), 0, 6)
13194e77879SHao Wu 
132*6b6e7570SHao Wu /* FIFO Mode Register Fields */
133*6b6e7570SHao Wu /* FIF_CTL fields */
134*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FIFO_EN          BIT(4)
135*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FAIR_RDY_IE      BIT(2)
136*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FAIR_RDY         BIT(1)
137*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FAIR_BUSY        BIT(0)
138*6b6e7570SHao Wu /* FIF_CTS fields */
139*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_STR              BIT(7)
140*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_CLR_FIFO         BIT(6)
141*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_RFTE_IE          BIT(3)
142*6b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_RXF_TXE          BIT(1)
143*6b6e7570SHao Wu /* TXF_CTL fields */
144*6b6e7570SHao Wu #define NPCM7XX_SMBTXF_CTL_THR_TXIE         BIT(6)
145*6b6e7570SHao Wu #define NPCM7XX_SMBTXF_CTL_TX_THR(rv)       extract8((rv), 0, 5)
146*6b6e7570SHao Wu /* T_OUT fields */
147*6b6e7570SHao Wu #define NPCM7XX_SMBT_OUT_ST                 BIT(7)
148*6b6e7570SHao Wu #define NPCM7XX_SMBT_OUT_IE                 BIT(6)
149*6b6e7570SHao Wu #define NPCM7XX_SMBT_OUT_CLKDIV(rv)         extract8((rv), 0, 6)
150*6b6e7570SHao Wu /* TXF_STS fields */
151*6b6e7570SHao Wu #define NPCM7XX_SMBTXF_STS_TX_THST          BIT(6)
152*6b6e7570SHao Wu #define NPCM7XX_SMBTXF_STS_TX_BYTES(rv)     extract8((rv), 0, 5)
153*6b6e7570SHao Wu /* RXF_STS fields */
154*6b6e7570SHao Wu #define NPCM7XX_SMBRXF_STS_RX_THST          BIT(6)
155*6b6e7570SHao Wu #define NPCM7XX_SMBRXF_STS_RX_BYTES(rv)     extract8((rv), 0, 5)
156*6b6e7570SHao Wu /* RXF_CTL fields */
157*6b6e7570SHao Wu #define NPCM7XX_SMBRXF_CTL_THR_RXIE         BIT(6)
158*6b6e7570SHao Wu #define NPCM7XX_SMBRXF_CTL_LAST             BIT(5)
159*6b6e7570SHao Wu #define NPCM7XX_SMBRXF_CTL_RX_THR(rv)       extract8((rv), 0, 5)
160*6b6e7570SHao Wu 
16194e77879SHao Wu #define KEEP_OLD_BIT(o, n, b)       (((n) & (~(b))) | ((o) & (b)))
16294e77879SHao Wu #define WRITE_ONE_CLEAR(o, n, b)    ((n) & (b) ? (o) & (~(b)) : (o))
16394e77879SHao Wu 
16494e77879SHao Wu #define NPCM7XX_SMBUS_ENABLED(s)    ((s)->ctl2 & NPCM7XX_SMBCTL2_ENABLE)
165*6b6e7570SHao Wu #define NPCM7XX_SMBUS_FIFO_ENABLED(s) ((s)->fif_ctl & \
166*6b6e7570SHao Wu                                        NPCM7XX_SMBFIF_CTL_FIFO_EN)
16794e77879SHao Wu 
16894e77879SHao Wu /* VERSION fields values, read-only. */
16994e77879SHao Wu #define NPCM7XX_SMBUS_VERSION_NUMBER 1
170*6b6e7570SHao Wu #define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 1
17194e77879SHao Wu 
17294e77879SHao Wu /* Reset values */
17394e77879SHao Wu #define NPCM7XX_SMB_ST_INIT_VAL     0x00
17494e77879SHao Wu #define NPCM7XX_SMB_CST_INIT_VAL    0x10
17594e77879SHao Wu #define NPCM7XX_SMB_CST2_INIT_VAL   0x00
17694e77879SHao Wu #define NPCM7XX_SMB_CST3_INIT_VAL   0x00
17794e77879SHao Wu #define NPCM7XX_SMB_CTL1_INIT_VAL   0x00
17894e77879SHao Wu #define NPCM7XX_SMB_CTL2_INIT_VAL   0x00
17994e77879SHao Wu #define NPCM7XX_SMB_CTL3_INIT_VAL   0xc0
18094e77879SHao Wu #define NPCM7XX_SMB_CTL4_INIT_VAL   0x07
18194e77879SHao Wu #define NPCM7XX_SMB_CTL5_INIT_VAL   0x00
18294e77879SHao Wu #define NPCM7XX_SMB_ADDR_INIT_VAL   0x00
18394e77879SHao Wu #define NPCM7XX_SMB_SCLLT_INIT_VAL  0x00
18494e77879SHao Wu #define NPCM7XX_SMB_SCLHT_INIT_VAL  0x00
185*6b6e7570SHao Wu #define NPCM7XX_SMB_FIF_CTL_INIT_VAL 0x00
186*6b6e7570SHao Wu #define NPCM7XX_SMB_FIF_CTS_INIT_VAL 0x00
187*6b6e7570SHao Wu #define NPCM7XX_SMB_FAIR_PER_INIT_VAL 0x00
188*6b6e7570SHao Wu #define NPCM7XX_SMB_TXF_CTL_INIT_VAL 0x00
189*6b6e7570SHao Wu #define NPCM7XX_SMB_T_OUT_INIT_VAL 0x3f
190*6b6e7570SHao Wu #define NPCM7XX_SMB_TXF_STS_INIT_VAL 0x00
191*6b6e7570SHao Wu #define NPCM7XX_SMB_RXF_STS_INIT_VAL 0x00
192*6b6e7570SHao Wu #define NPCM7XX_SMB_RXF_CTL_INIT_VAL 0x01
19394e77879SHao Wu 
19494e77879SHao Wu static uint8_t npcm7xx_smbus_get_version(void)
19594e77879SHao Wu {
19694e77879SHao Wu     return NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED << 7 |
19794e77879SHao Wu            NPCM7XX_SMBUS_VERSION_NUMBER;
19894e77879SHao Wu }
19994e77879SHao Wu 
20094e77879SHao Wu static void npcm7xx_smbus_update_irq(NPCM7xxSMBusState *s)
20194e77879SHao Wu {
20294e77879SHao Wu     int level;
20394e77879SHao Wu 
20494e77879SHao Wu     if (s->ctl1 & NPCM7XX_SMBCTL1_INTEN) {
20594e77879SHao Wu         level = !!((s->ctl1 & NPCM7XX_SMBCTL1_NMINTE &&
20694e77879SHao Wu                     s->st & NPCM7XX_SMBST_NMATCH) ||
20794e77879SHao Wu                    (s->st & NPCM7XX_SMBST_BER) ||
20894e77879SHao Wu                    (s->st & NPCM7XX_SMBST_NEGACK) ||
20994e77879SHao Wu                    (s->st & NPCM7XX_SMBST_SDAST) ||
21094e77879SHao Wu                    (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE &&
21194e77879SHao Wu                     s->st & NPCM7XX_SMBST_SDAST) ||
21294e77879SHao Wu                    (s->ctl1 & NPCM7XX_SMBCTL1_EOBINTE &&
213*6b6e7570SHao Wu                     s->cst3 & NPCM7XX_SMBCST3_EO_BUSY) ||
214*6b6e7570SHao Wu                    (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE &&
215*6b6e7570SHao Wu                     s->rxf_sts & NPCM7XX_SMBRXF_STS_RX_THST) ||
216*6b6e7570SHao Wu                    (s->txf_ctl & NPCM7XX_SMBTXF_CTL_THR_TXIE &&
217*6b6e7570SHao Wu                     s->txf_sts & NPCM7XX_SMBTXF_STS_TX_THST) ||
218*6b6e7570SHao Wu                    (s->fif_cts & NPCM7XX_SMBFIF_CTS_RFTE_IE &&
219*6b6e7570SHao Wu                     s->fif_cts & NPCM7XX_SMBFIF_CTS_RXF_TXE));
22094e77879SHao Wu 
22194e77879SHao Wu         if (level) {
22294e77879SHao Wu             s->cst2 |= NPCM7XX_SMBCST2_INTSTS;
22394e77879SHao Wu         } else {
22494e77879SHao Wu             s->cst2 &= ~NPCM7XX_SMBCST2_INTSTS;
22594e77879SHao Wu         }
22694e77879SHao Wu         qemu_set_irq(s->irq, level);
22794e77879SHao Wu     }
22894e77879SHao Wu }
22994e77879SHao Wu 
23094e77879SHao Wu static void npcm7xx_smbus_nack(NPCM7xxSMBusState *s)
23194e77879SHao Wu {
23294e77879SHao Wu     s->st &= ~NPCM7XX_SMBST_SDAST;
23394e77879SHao Wu     s->st |= NPCM7XX_SMBST_NEGACK;
23494e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_NEGACK;
23594e77879SHao Wu }
23694e77879SHao Wu 
237*6b6e7570SHao Wu static void npcm7xx_smbus_clear_buffer(NPCM7xxSMBusState *s)
238*6b6e7570SHao Wu {
239*6b6e7570SHao Wu     s->fif_cts &= ~NPCM7XX_SMBFIF_CTS_RXF_TXE;
240*6b6e7570SHao Wu     s->txf_sts = 0;
241*6b6e7570SHao Wu     s->rxf_sts = 0;
242*6b6e7570SHao Wu }
243*6b6e7570SHao Wu 
24494e77879SHao Wu static void npcm7xx_smbus_send_byte(NPCM7xxSMBusState *s, uint8_t value)
24594e77879SHao Wu {
24694e77879SHao Wu     int rv = i2c_send(s->bus, value);
24794e77879SHao Wu 
24894e77879SHao Wu     if (rv) {
24994e77879SHao Wu         npcm7xx_smbus_nack(s);
25094e77879SHao Wu     } else {
25194e77879SHao Wu         s->st |= NPCM7XX_SMBST_SDAST;
252*6b6e7570SHao Wu         if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
253*6b6e7570SHao Wu             s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
254*6b6e7570SHao Wu             if (NPCM7XX_SMBTXF_STS_TX_BYTES(s->txf_sts) ==
255*6b6e7570SHao Wu                 NPCM7XX_SMBTXF_CTL_TX_THR(s->txf_ctl)) {
256*6b6e7570SHao Wu                 s->txf_sts = NPCM7XX_SMBTXF_STS_TX_THST;
257*6b6e7570SHao Wu             } else {
258*6b6e7570SHao Wu                 s->txf_sts = 0;
259*6b6e7570SHao Wu             }
260*6b6e7570SHao Wu         }
26194e77879SHao Wu     }
26294e77879SHao Wu     trace_npcm7xx_smbus_send_byte((DEVICE(s)->canonical_path), value, !rv);
26394e77879SHao Wu     npcm7xx_smbus_update_irq(s);
26494e77879SHao Wu }
26594e77879SHao Wu 
26694e77879SHao Wu static void npcm7xx_smbus_recv_byte(NPCM7xxSMBusState *s)
26794e77879SHao Wu {
26894e77879SHao Wu     s->sda = i2c_recv(s->bus);
26994e77879SHao Wu     s->st |= NPCM7XX_SMBST_SDAST;
27094e77879SHao Wu     if (s->st & NPCM7XX_SMBCTL1_ACK) {
27194e77879SHao Wu         trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
27294e77879SHao Wu         i2c_nack(s->bus);
27394e77879SHao Wu         s->st &= NPCM7XX_SMBCTL1_ACK;
27494e77879SHao Wu     }
27594e77879SHao Wu     trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path), s->sda);
27694e77879SHao Wu     npcm7xx_smbus_update_irq(s);
27794e77879SHao Wu }
27894e77879SHao Wu 
279*6b6e7570SHao Wu static void npcm7xx_smbus_recv_fifo(NPCM7xxSMBusState *s)
280*6b6e7570SHao Wu {
281*6b6e7570SHao Wu     uint8_t expected_bytes = NPCM7XX_SMBRXF_CTL_RX_THR(s->rxf_ctl);
282*6b6e7570SHao Wu     uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
283*6b6e7570SHao Wu     uint8_t pos;
284*6b6e7570SHao Wu 
285*6b6e7570SHao Wu     if (received_bytes == expected_bytes) {
286*6b6e7570SHao Wu         return;
287*6b6e7570SHao Wu     }
288*6b6e7570SHao Wu 
289*6b6e7570SHao Wu     while (received_bytes < expected_bytes &&
290*6b6e7570SHao Wu            received_bytes < NPCM7XX_SMBUS_FIFO_SIZE) {
291*6b6e7570SHao Wu         pos = (s->rx_cur + received_bytes) % NPCM7XX_SMBUS_FIFO_SIZE;
292*6b6e7570SHao Wu         s->rx_fifo[pos] = i2c_recv(s->bus);
293*6b6e7570SHao Wu         trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path),
294*6b6e7570SHao Wu                                       s->rx_fifo[pos]);
295*6b6e7570SHao Wu         ++received_bytes;
296*6b6e7570SHao Wu     }
297*6b6e7570SHao Wu 
298*6b6e7570SHao Wu     trace_npcm7xx_smbus_recv_fifo((DEVICE(s)->canonical_path),
299*6b6e7570SHao Wu                                   received_bytes, expected_bytes);
300*6b6e7570SHao Wu     s->rxf_sts = received_bytes;
301*6b6e7570SHao Wu     if (unlikely(received_bytes < expected_bytes)) {
302*6b6e7570SHao Wu         qemu_log_mask(LOG_GUEST_ERROR,
303*6b6e7570SHao Wu                       "%s: invalid rx_thr value: 0x%02x\n",
304*6b6e7570SHao Wu                       DEVICE(s)->canonical_path, expected_bytes);
305*6b6e7570SHao Wu         return;
306*6b6e7570SHao Wu     }
307*6b6e7570SHao Wu 
308*6b6e7570SHao Wu     s->rxf_sts |= NPCM7XX_SMBRXF_STS_RX_THST;
309*6b6e7570SHao Wu     if (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_LAST) {
310*6b6e7570SHao Wu         trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
311*6b6e7570SHao Wu         i2c_nack(s->bus);
312*6b6e7570SHao Wu         s->rxf_ctl &= ~NPCM7XX_SMBRXF_CTL_LAST;
313*6b6e7570SHao Wu     }
314*6b6e7570SHao Wu     if (received_bytes == NPCM7XX_SMBUS_FIFO_SIZE) {
315*6b6e7570SHao Wu         s->st |= NPCM7XX_SMBST_SDAST;
316*6b6e7570SHao Wu         s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
317*6b6e7570SHao Wu     } else if (!(s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE)) {
318*6b6e7570SHao Wu         s->st |= NPCM7XX_SMBST_SDAST;
319*6b6e7570SHao Wu     } else {
320*6b6e7570SHao Wu         s->st &= ~NPCM7XX_SMBST_SDAST;
321*6b6e7570SHao Wu     }
322*6b6e7570SHao Wu     npcm7xx_smbus_update_irq(s);
323*6b6e7570SHao Wu }
324*6b6e7570SHao Wu 
325*6b6e7570SHao Wu static void npcm7xx_smbus_read_byte_fifo(NPCM7xxSMBusState *s)
326*6b6e7570SHao Wu {
327*6b6e7570SHao Wu     uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
328*6b6e7570SHao Wu 
329*6b6e7570SHao Wu     if (received_bytes == 0) {
330*6b6e7570SHao Wu         npcm7xx_smbus_recv_fifo(s);
331*6b6e7570SHao Wu         return;
332*6b6e7570SHao Wu     }
333*6b6e7570SHao Wu 
334*6b6e7570SHao Wu     s->sda = s->rx_fifo[s->rx_cur];
335*6b6e7570SHao Wu     s->rx_cur = (s->rx_cur + 1u) % NPCM7XX_SMBUS_FIFO_SIZE;
336*6b6e7570SHao Wu     --s->rxf_sts;
337*6b6e7570SHao Wu     npcm7xx_smbus_update_irq(s);
338*6b6e7570SHao Wu }
339*6b6e7570SHao Wu 
34094e77879SHao Wu static void npcm7xx_smbus_start(NPCM7xxSMBusState *s)
34194e77879SHao Wu {
34294e77879SHao Wu     /*
34394e77879SHao Wu      * We can start the bus if one of these is true:
34494e77879SHao Wu      * 1. The bus is idle (so we can request it)
34594e77879SHao Wu      * 2. We are the occupier (it's a repeated start condition.)
34694e77879SHao Wu      */
34794e77879SHao Wu     int available = !i2c_bus_busy(s->bus) ||
34894e77879SHao Wu                     s->status != NPCM7XX_SMBUS_STATUS_IDLE;
34994e77879SHao Wu 
35094e77879SHao Wu     if (available) {
35194e77879SHao Wu         s->st |= NPCM7XX_SMBST_MODE | NPCM7XX_SMBST_XMIT | NPCM7XX_SMBST_SDAST;
35294e77879SHao Wu         s->cst |= NPCM7XX_SMBCST_BUSY;
353*6b6e7570SHao Wu         if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
354*6b6e7570SHao Wu             s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
355*6b6e7570SHao Wu         }
35694e77879SHao Wu     } else {
35794e77879SHao Wu         s->st &= ~NPCM7XX_SMBST_MODE;
35894e77879SHao Wu         s->cst &= ~NPCM7XX_SMBCST_BUSY;
35994e77879SHao Wu         s->st |= NPCM7XX_SMBST_BER;
36094e77879SHao Wu     }
36194e77879SHao Wu 
36294e77879SHao Wu     trace_npcm7xx_smbus_start(DEVICE(s)->canonical_path, available);
36394e77879SHao Wu     s->cst |= NPCM7XX_SMBCST_BB;
36494e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
36594e77879SHao Wu     npcm7xx_smbus_update_irq(s);
36694e77879SHao Wu }
36794e77879SHao Wu 
36894e77879SHao Wu static void npcm7xx_smbus_send_address(NPCM7xxSMBusState *s, uint8_t value)
36994e77879SHao Wu {
37094e77879SHao Wu     int recv;
37194e77879SHao Wu     int rv;
37294e77879SHao Wu 
37394e77879SHao Wu     recv = value & BIT(0);
37494e77879SHao Wu     rv = i2c_start_transfer(s->bus, value >> 1, recv);
37594e77879SHao Wu     trace_npcm7xx_smbus_send_address(DEVICE(s)->canonical_path,
37694e77879SHao Wu                                      value >> 1, recv, !rv);
37794e77879SHao Wu     if (rv) {
37894e77879SHao Wu         qemu_log_mask(LOG_GUEST_ERROR,
37994e77879SHao Wu                       "%s: requesting i2c bus for 0x%02x failed: %d\n",
38094e77879SHao Wu                       DEVICE(s)->canonical_path, value, rv);
38194e77879SHao Wu         /* Failed to start transfer. NACK to reject.*/
38294e77879SHao Wu         if (recv) {
38394e77879SHao Wu             s->st &= ~NPCM7XX_SMBST_XMIT;
38494e77879SHao Wu         } else {
38594e77879SHao Wu             s->st |= NPCM7XX_SMBST_XMIT;
38694e77879SHao Wu         }
38794e77879SHao Wu         npcm7xx_smbus_nack(s);
38894e77879SHao Wu         npcm7xx_smbus_update_irq(s);
38994e77879SHao Wu         return;
39094e77879SHao Wu     }
39194e77879SHao Wu 
39294e77879SHao Wu     s->st &= ~NPCM7XX_SMBST_NEGACK;
39394e77879SHao Wu     if (recv) {
39494e77879SHao Wu         s->status = NPCM7XX_SMBUS_STATUS_RECEIVING;
39594e77879SHao Wu         s->st &= ~NPCM7XX_SMBST_XMIT;
39694e77879SHao Wu     } else {
39794e77879SHao Wu         s->status = NPCM7XX_SMBUS_STATUS_SENDING;
39894e77879SHao Wu         s->st |= NPCM7XX_SMBST_XMIT;
39994e77879SHao Wu     }
40094e77879SHao Wu 
40194e77879SHao Wu     if (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE) {
40294e77879SHao Wu         s->st |= NPCM7XX_SMBST_STASTR;
40394e77879SHao Wu         if (!recv) {
40494e77879SHao Wu             s->st |= NPCM7XX_SMBST_SDAST;
40594e77879SHao Wu         }
40694e77879SHao Wu     } else if (recv) {
407*6b6e7570SHao Wu         s->st |= NPCM7XX_SMBST_SDAST;
408*6b6e7570SHao Wu         if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
409*6b6e7570SHao Wu             npcm7xx_smbus_recv_fifo(s);
410*6b6e7570SHao Wu         } else {
41194e77879SHao Wu             npcm7xx_smbus_recv_byte(s);
41294e77879SHao Wu         }
413*6b6e7570SHao Wu     } else if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
414*6b6e7570SHao Wu         s->st |= NPCM7XX_SMBST_SDAST;
415*6b6e7570SHao Wu         s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
416*6b6e7570SHao Wu     }
41794e77879SHao Wu     npcm7xx_smbus_update_irq(s);
41894e77879SHao Wu }
41994e77879SHao Wu 
42094e77879SHao Wu static void npcm7xx_smbus_execute_stop(NPCM7xxSMBusState *s)
42194e77879SHao Wu {
42294e77879SHao Wu     i2c_end_transfer(s->bus);
42394e77879SHao Wu     s->st = 0;
42494e77879SHao Wu     s->cst = 0;
42594e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
42694e77879SHao Wu     s->cst3 |= NPCM7XX_SMBCST3_EO_BUSY;
42794e77879SHao Wu     trace_npcm7xx_smbus_stop(DEVICE(s)->canonical_path);
42894e77879SHao Wu     npcm7xx_smbus_update_irq(s);
42994e77879SHao Wu }
43094e77879SHao Wu 
43194e77879SHao Wu 
43294e77879SHao Wu static void npcm7xx_smbus_stop(NPCM7xxSMBusState *s)
43394e77879SHao Wu {
43494e77879SHao Wu     if (s->st & NPCM7XX_SMBST_MODE) {
43594e77879SHao Wu         switch (s->status) {
43694e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_RECEIVING:
43794e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
43894e77879SHao Wu             s->status = NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE;
43994e77879SHao Wu             break;
44094e77879SHao Wu 
44194e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_NEGACK:
44294e77879SHao Wu             s->status = NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK;
44394e77879SHao Wu             break;
44494e77879SHao Wu 
44594e77879SHao Wu         default:
44694e77879SHao Wu             npcm7xx_smbus_execute_stop(s);
44794e77879SHao Wu             break;
44894e77879SHao Wu         }
44994e77879SHao Wu     }
45094e77879SHao Wu }
45194e77879SHao Wu 
45294e77879SHao Wu static uint8_t npcm7xx_smbus_read_sda(NPCM7xxSMBusState *s)
45394e77879SHao Wu {
45494e77879SHao Wu     uint8_t value = s->sda;
45594e77879SHao Wu 
45694e77879SHao Wu     switch (s->status) {
45794e77879SHao Wu     case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
458*6b6e7570SHao Wu         if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
459*6b6e7570SHao Wu             if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) <= 1) {
46094e77879SHao Wu                 npcm7xx_smbus_execute_stop(s);
461*6b6e7570SHao Wu             }
462*6b6e7570SHao Wu             if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) == 0) {
463*6b6e7570SHao Wu                 qemu_log_mask(LOG_GUEST_ERROR,
464*6b6e7570SHao Wu                               "%s: read to SDA with an empty rx-fifo buffer, "
465*6b6e7570SHao Wu                               "result undefined: %u\n",
466*6b6e7570SHao Wu                               DEVICE(s)->canonical_path, s->sda);
467*6b6e7570SHao Wu                 break;
468*6b6e7570SHao Wu             }
469*6b6e7570SHao Wu             npcm7xx_smbus_read_byte_fifo(s);
470*6b6e7570SHao Wu             value = s->sda;
471*6b6e7570SHao Wu         } else {
472*6b6e7570SHao Wu             npcm7xx_smbus_execute_stop(s);
473*6b6e7570SHao Wu         }
47494e77879SHao Wu         break;
47594e77879SHao Wu 
47694e77879SHao Wu     case NPCM7XX_SMBUS_STATUS_RECEIVING:
477*6b6e7570SHao Wu         if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
478*6b6e7570SHao Wu             npcm7xx_smbus_read_byte_fifo(s);
479*6b6e7570SHao Wu             value = s->sda;
480*6b6e7570SHao Wu         } else {
48194e77879SHao Wu             npcm7xx_smbus_recv_byte(s);
482*6b6e7570SHao Wu         }
48394e77879SHao Wu         break;
48494e77879SHao Wu 
48594e77879SHao Wu     default:
48694e77879SHao Wu         /* Do nothing */
48794e77879SHao Wu         break;
48894e77879SHao Wu     }
48994e77879SHao Wu 
49094e77879SHao Wu     return value;
49194e77879SHao Wu }
49294e77879SHao Wu 
49394e77879SHao Wu static void npcm7xx_smbus_write_sda(NPCM7xxSMBusState *s, uint8_t value)
49494e77879SHao Wu {
49594e77879SHao Wu     s->sda = value;
49694e77879SHao Wu     if (s->st & NPCM7XX_SMBST_MODE) {
49794e77879SHao Wu         switch (s->status) {
49894e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_IDLE:
49994e77879SHao Wu             npcm7xx_smbus_send_address(s, value);
50094e77879SHao Wu             break;
50194e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_SENDING:
50294e77879SHao Wu             npcm7xx_smbus_send_byte(s, value);
50394e77879SHao Wu             break;
50494e77879SHao Wu         default:
50594e77879SHao Wu             qemu_log_mask(LOG_GUEST_ERROR,
50694e77879SHao Wu                           "%s: write to SDA in invalid status %d: %u\n",
50794e77879SHao Wu                           DEVICE(s)->canonical_path, s->status, value);
50894e77879SHao Wu             break;
50994e77879SHao Wu         }
51094e77879SHao Wu     }
51194e77879SHao Wu }
51294e77879SHao Wu 
51394e77879SHao Wu static void npcm7xx_smbus_write_st(NPCM7xxSMBusState *s, uint8_t value)
51494e77879SHao Wu {
51594e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STP);
51694e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_BER);
51794e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STASTR);
51894e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_NMATCH);
51994e77879SHao Wu 
52094e77879SHao Wu     if (value & NPCM7XX_SMBST_NEGACK) {
52194e77879SHao Wu         s->st &= ~NPCM7XX_SMBST_NEGACK;
52294e77879SHao Wu         if (s->status == NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK) {
52394e77879SHao Wu             npcm7xx_smbus_execute_stop(s);
52494e77879SHao Wu         }
52594e77879SHao Wu     }
52694e77879SHao Wu 
52794e77879SHao Wu     if (value & NPCM7XX_SMBST_STASTR &&
52894e77879SHao Wu         s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
529*6b6e7570SHao Wu         if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
530*6b6e7570SHao Wu             npcm7xx_smbus_recv_fifo(s);
531*6b6e7570SHao Wu         } else {
53294e77879SHao Wu             npcm7xx_smbus_recv_byte(s);
53394e77879SHao Wu         }
534*6b6e7570SHao Wu     }
53594e77879SHao Wu 
53694e77879SHao Wu     npcm7xx_smbus_update_irq(s);
53794e77879SHao Wu }
53894e77879SHao Wu 
53994e77879SHao Wu static void npcm7xx_smbus_write_cst(NPCM7xxSMBusState *s, uint8_t value)
54094e77879SHao Wu {
54194e77879SHao Wu     uint8_t new_value = s->cst;
54294e77879SHao Wu 
54394e77879SHao Wu     s->cst = WRITE_ONE_CLEAR(new_value, value, NPCM7XX_SMBCST_BB);
54494e77879SHao Wu     npcm7xx_smbus_update_irq(s);
54594e77879SHao Wu }
54694e77879SHao Wu 
54794e77879SHao Wu static void npcm7xx_smbus_write_cst3(NPCM7xxSMBusState *s, uint8_t value)
54894e77879SHao Wu {
54994e77879SHao Wu     s->cst3 = WRITE_ONE_CLEAR(s->cst3, value, NPCM7XX_SMBCST3_EO_BUSY);
55094e77879SHao Wu     npcm7xx_smbus_update_irq(s);
55194e77879SHao Wu }
55294e77879SHao Wu 
55394e77879SHao Wu static void npcm7xx_smbus_write_ctl1(NPCM7xxSMBusState *s, uint8_t value)
55494e77879SHao Wu {
55594e77879SHao Wu     s->ctl1 = KEEP_OLD_BIT(s->ctl1, value,
55694e77879SHao Wu             NPCM7XX_SMBCTL1_START | NPCM7XX_SMBCTL1_STOP | NPCM7XX_SMBCTL1_ACK);
55794e77879SHao Wu 
55894e77879SHao Wu     if (value & NPCM7XX_SMBCTL1_START) {
55994e77879SHao Wu         npcm7xx_smbus_start(s);
56094e77879SHao Wu     }
56194e77879SHao Wu 
56294e77879SHao Wu     if (value & NPCM7XX_SMBCTL1_STOP) {
56394e77879SHao Wu         npcm7xx_smbus_stop(s);
56494e77879SHao Wu     }
56594e77879SHao Wu 
56694e77879SHao Wu     npcm7xx_smbus_update_irq(s);
56794e77879SHao Wu }
56894e77879SHao Wu 
56994e77879SHao Wu static void npcm7xx_smbus_write_ctl2(NPCM7xxSMBusState *s, uint8_t value)
57094e77879SHao Wu {
57194e77879SHao Wu     s->ctl2 = value;
57294e77879SHao Wu 
57394e77879SHao Wu     if (!NPCM7XX_SMBUS_ENABLED(s)) {
57494e77879SHao Wu         /* Disable this SMBus module. */
57594e77879SHao Wu         s->ctl1 = 0;
57694e77879SHao Wu         s->st = 0;
57794e77879SHao Wu         s->cst3 = s->cst3 & (~NPCM7XX_SMBCST3_EO_BUSY);
57894e77879SHao Wu         s->cst = 0;
579*6b6e7570SHao Wu         npcm7xx_smbus_clear_buffer(s);
58094e77879SHao Wu     }
58194e77879SHao Wu }
58294e77879SHao Wu 
58394e77879SHao Wu static void npcm7xx_smbus_write_ctl3(NPCM7xxSMBusState *s, uint8_t value)
58494e77879SHao Wu {
58594e77879SHao Wu     uint8_t old_ctl3 = s->ctl3;
58694e77879SHao Wu 
58794e77879SHao Wu     /* Write to SDA and SCL bits are ignored. */
58894e77879SHao Wu     s->ctl3 =  KEEP_OLD_BIT(old_ctl3, value,
58994e77879SHao Wu                             NPCM7XX_SMBCTL3_SCL_LVL | NPCM7XX_SMBCTL3_SDA_LVL);
59094e77879SHao Wu }
59194e77879SHao Wu 
592*6b6e7570SHao Wu static void npcm7xx_smbus_write_fif_ctl(NPCM7xxSMBusState *s, uint8_t value)
593*6b6e7570SHao Wu {
594*6b6e7570SHao Wu     uint8_t new_ctl = value;
595*6b6e7570SHao Wu 
596*6b6e7570SHao Wu     new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
597*6b6e7570SHao Wu     new_ctl = WRITE_ONE_CLEAR(new_ctl, value, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
598*6b6e7570SHao Wu     new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_BUSY);
599*6b6e7570SHao Wu     s->fif_ctl = new_ctl;
600*6b6e7570SHao Wu }
601*6b6e7570SHao Wu 
602*6b6e7570SHao Wu static void npcm7xx_smbus_write_fif_cts(NPCM7xxSMBusState *s, uint8_t value)
603*6b6e7570SHao Wu {
604*6b6e7570SHao Wu     s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_STR);
605*6b6e7570SHao Wu     s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_RXF_TXE);
606*6b6e7570SHao Wu     s->fif_cts = KEEP_OLD_BIT(value, s->fif_cts, NPCM7XX_SMBFIF_CTS_RFTE_IE);
607*6b6e7570SHao Wu 
608*6b6e7570SHao Wu     if (value & NPCM7XX_SMBFIF_CTS_CLR_FIFO) {
609*6b6e7570SHao Wu         npcm7xx_smbus_clear_buffer(s);
610*6b6e7570SHao Wu     }
611*6b6e7570SHao Wu }
612*6b6e7570SHao Wu 
613*6b6e7570SHao Wu static void npcm7xx_smbus_write_txf_ctl(NPCM7xxSMBusState *s, uint8_t value)
614*6b6e7570SHao Wu {
615*6b6e7570SHao Wu     s->txf_ctl = value;
616*6b6e7570SHao Wu }
617*6b6e7570SHao Wu 
618*6b6e7570SHao Wu static void npcm7xx_smbus_write_t_out(NPCM7xxSMBusState *s, uint8_t value)
619*6b6e7570SHao Wu {
620*6b6e7570SHao Wu     uint8_t new_t_out = value;
621*6b6e7570SHao Wu 
622*6b6e7570SHao Wu     if ((value & NPCM7XX_SMBT_OUT_ST) || (!(s->t_out & NPCM7XX_SMBT_OUT_ST))) {
623*6b6e7570SHao Wu         new_t_out &= ~NPCM7XX_SMBT_OUT_ST;
624*6b6e7570SHao Wu     } else {
625*6b6e7570SHao Wu         new_t_out |= NPCM7XX_SMBT_OUT_ST;
626*6b6e7570SHao Wu     }
627*6b6e7570SHao Wu 
628*6b6e7570SHao Wu     s->t_out = new_t_out;
629*6b6e7570SHao Wu }
630*6b6e7570SHao Wu 
631*6b6e7570SHao Wu static void npcm7xx_smbus_write_txf_sts(NPCM7xxSMBusState *s, uint8_t value)
632*6b6e7570SHao Wu {
633*6b6e7570SHao Wu     s->txf_sts = WRITE_ONE_CLEAR(s->txf_sts, value, NPCM7XX_SMBTXF_STS_TX_THST);
634*6b6e7570SHao Wu }
635*6b6e7570SHao Wu 
636*6b6e7570SHao Wu static void npcm7xx_smbus_write_rxf_sts(NPCM7xxSMBusState *s, uint8_t value)
637*6b6e7570SHao Wu {
638*6b6e7570SHao Wu     if (value & NPCM7XX_SMBRXF_STS_RX_THST) {
639*6b6e7570SHao Wu         s->rxf_sts &= ~NPCM7XX_SMBRXF_STS_RX_THST;
640*6b6e7570SHao Wu         if (s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
641*6b6e7570SHao Wu             npcm7xx_smbus_recv_fifo(s);
642*6b6e7570SHao Wu         }
643*6b6e7570SHao Wu     }
644*6b6e7570SHao Wu }
645*6b6e7570SHao Wu 
646*6b6e7570SHao Wu static void npcm7xx_smbus_write_rxf_ctl(NPCM7xxSMBusState *s, uint8_t value)
647*6b6e7570SHao Wu {
648*6b6e7570SHao Wu     uint8_t new_ctl = value;
649*6b6e7570SHao Wu 
650*6b6e7570SHao Wu     if (!(value & NPCM7XX_SMBRXF_CTL_LAST)) {
651*6b6e7570SHao Wu         new_ctl = KEEP_OLD_BIT(s->rxf_ctl, new_ctl, NPCM7XX_SMBRXF_CTL_LAST);
652*6b6e7570SHao Wu     }
653*6b6e7570SHao Wu     s->rxf_ctl = new_ctl;
654*6b6e7570SHao Wu }
655*6b6e7570SHao Wu 
65694e77879SHao Wu static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
65794e77879SHao Wu {
65894e77879SHao Wu     NPCM7xxSMBusState *s = opaque;
65994e77879SHao Wu     uint64_t value = 0;
66094e77879SHao Wu     uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
66194e77879SHao Wu 
66294e77879SHao Wu     /* The order of the registers are their order in memory. */
66394e77879SHao Wu     switch (offset) {
66494e77879SHao Wu     case NPCM7XX_SMB_SDA:
66594e77879SHao Wu         value = npcm7xx_smbus_read_sda(s);
66694e77879SHao Wu         break;
66794e77879SHao Wu 
66894e77879SHao Wu     case NPCM7XX_SMB_ST:
66994e77879SHao Wu         value = s->st;
67094e77879SHao Wu         break;
67194e77879SHao Wu 
67294e77879SHao Wu     case NPCM7XX_SMB_CST:
67394e77879SHao Wu         value = s->cst;
67494e77879SHao Wu         break;
67594e77879SHao Wu 
67694e77879SHao Wu     case NPCM7XX_SMB_CTL1:
67794e77879SHao Wu         value = s->ctl1;
67894e77879SHao Wu         break;
67994e77879SHao Wu 
68094e77879SHao Wu     case NPCM7XX_SMB_ADDR1:
68194e77879SHao Wu         value = s->addr[0];
68294e77879SHao Wu         break;
68394e77879SHao Wu 
68494e77879SHao Wu     case NPCM7XX_SMB_CTL2:
68594e77879SHao Wu         value = s->ctl2;
68694e77879SHao Wu         break;
68794e77879SHao Wu 
68894e77879SHao Wu     case NPCM7XX_SMB_ADDR2:
68994e77879SHao Wu         value = s->addr[1];
69094e77879SHao Wu         break;
69194e77879SHao Wu 
69294e77879SHao Wu     case NPCM7XX_SMB_CTL3:
69394e77879SHao Wu         value = s->ctl3;
69494e77879SHao Wu         break;
69594e77879SHao Wu 
69694e77879SHao Wu     case NPCM7XX_SMB_CST2:
69794e77879SHao Wu         value = s->cst2;
69894e77879SHao Wu         break;
69994e77879SHao Wu 
70094e77879SHao Wu     case NPCM7XX_SMB_CST3:
70194e77879SHao Wu         value = s->cst3;
70294e77879SHao Wu         break;
70394e77879SHao Wu 
70494e77879SHao Wu     case NPCM7XX_SMB_VER:
70594e77879SHao Wu         value = npcm7xx_smbus_get_version();
70694e77879SHao Wu         break;
70794e77879SHao Wu 
70894e77879SHao Wu     /* This register is either invalid or banked at this point. */
70994e77879SHao Wu     default:
71094e77879SHao Wu         if (bank) {
71194e77879SHao Wu             /* Bank 1 */
712*6b6e7570SHao Wu             switch (offset) {
713*6b6e7570SHao Wu             case NPCM7XX_SMB_FIF_CTS:
714*6b6e7570SHao Wu                 value = s->fif_cts;
715*6b6e7570SHao Wu                 break;
716*6b6e7570SHao Wu 
717*6b6e7570SHao Wu             case NPCM7XX_SMB_FAIR_PER:
718*6b6e7570SHao Wu                 value = s->fair_per;
719*6b6e7570SHao Wu                 break;
720*6b6e7570SHao Wu 
721*6b6e7570SHao Wu             case NPCM7XX_SMB_TXF_CTL:
722*6b6e7570SHao Wu                 value = s->txf_ctl;
723*6b6e7570SHao Wu                 break;
724*6b6e7570SHao Wu 
725*6b6e7570SHao Wu             case NPCM7XX_SMB_T_OUT:
726*6b6e7570SHao Wu                 value = s->t_out;
727*6b6e7570SHao Wu                 break;
728*6b6e7570SHao Wu 
729*6b6e7570SHao Wu             case NPCM7XX_SMB_TXF_STS:
730*6b6e7570SHao Wu                 value = s->txf_sts;
731*6b6e7570SHao Wu                 break;
732*6b6e7570SHao Wu 
733*6b6e7570SHao Wu             case NPCM7XX_SMB_RXF_STS:
734*6b6e7570SHao Wu                 value = s->rxf_sts;
735*6b6e7570SHao Wu                 break;
736*6b6e7570SHao Wu 
737*6b6e7570SHao Wu             case NPCM7XX_SMB_RXF_CTL:
738*6b6e7570SHao Wu                 value = s->rxf_ctl;
739*6b6e7570SHao Wu                 break;
740*6b6e7570SHao Wu 
741*6b6e7570SHao Wu             default:
74294e77879SHao Wu                 qemu_log_mask(LOG_GUEST_ERROR,
74394e77879SHao Wu                         "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
74494e77879SHao Wu                         DEVICE(s)->canonical_path, offset);
745*6b6e7570SHao Wu                 break;
746*6b6e7570SHao Wu             }
74794e77879SHao Wu         } else {
74894e77879SHao Wu             /* Bank 0 */
74994e77879SHao Wu             switch (offset) {
75094e77879SHao Wu             case NPCM7XX_SMB_ADDR3:
75194e77879SHao Wu                 value = s->addr[2];
75294e77879SHao Wu                 break;
75394e77879SHao Wu 
75494e77879SHao Wu             case NPCM7XX_SMB_ADDR7:
75594e77879SHao Wu                 value = s->addr[6];
75694e77879SHao Wu                 break;
75794e77879SHao Wu 
75894e77879SHao Wu             case NPCM7XX_SMB_ADDR4:
75994e77879SHao Wu                 value = s->addr[3];
76094e77879SHao Wu                 break;
76194e77879SHao Wu 
76294e77879SHao Wu             case NPCM7XX_SMB_ADDR8:
76394e77879SHao Wu                 value = s->addr[7];
76494e77879SHao Wu                 break;
76594e77879SHao Wu 
76694e77879SHao Wu             case NPCM7XX_SMB_ADDR5:
76794e77879SHao Wu                 value = s->addr[4];
76894e77879SHao Wu                 break;
76994e77879SHao Wu 
77094e77879SHao Wu             case NPCM7XX_SMB_ADDR9:
77194e77879SHao Wu                 value = s->addr[8];
77294e77879SHao Wu                 break;
77394e77879SHao Wu 
77494e77879SHao Wu             case NPCM7XX_SMB_ADDR6:
77594e77879SHao Wu                 value = s->addr[5];
77694e77879SHao Wu                 break;
77794e77879SHao Wu 
77894e77879SHao Wu             case NPCM7XX_SMB_ADDR10:
77994e77879SHao Wu                 value = s->addr[9];
78094e77879SHao Wu                 break;
78194e77879SHao Wu 
78294e77879SHao Wu             case NPCM7XX_SMB_CTL4:
78394e77879SHao Wu                 value = s->ctl4;
78494e77879SHao Wu                 break;
78594e77879SHao Wu 
78694e77879SHao Wu             case NPCM7XX_SMB_CTL5:
78794e77879SHao Wu                 value = s->ctl5;
78894e77879SHao Wu                 break;
78994e77879SHao Wu 
79094e77879SHao Wu             case NPCM7XX_SMB_SCLLT:
79194e77879SHao Wu                 value = s->scllt;
79294e77879SHao Wu                 break;
79394e77879SHao Wu 
794*6b6e7570SHao Wu             case NPCM7XX_SMB_FIF_CTL:
795*6b6e7570SHao Wu                 value = s->fif_ctl;
796*6b6e7570SHao Wu                 break;
797*6b6e7570SHao Wu 
79894e77879SHao Wu             case NPCM7XX_SMB_SCLHT:
79994e77879SHao Wu                 value = s->sclht;
80094e77879SHao Wu                 break;
80194e77879SHao Wu 
80294e77879SHao Wu             default:
80394e77879SHao Wu                 qemu_log_mask(LOG_GUEST_ERROR,
80494e77879SHao Wu                         "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
80594e77879SHao Wu                         DEVICE(s)->canonical_path, offset);
80694e77879SHao Wu                 break;
80794e77879SHao Wu             }
80894e77879SHao Wu         }
80994e77879SHao Wu         break;
81094e77879SHao Wu     }
81194e77879SHao Wu 
81294e77879SHao Wu     trace_npcm7xx_smbus_read(DEVICE(s)->canonical_path, offset, value, size);
81394e77879SHao Wu 
81494e77879SHao Wu     return value;
81594e77879SHao Wu }
81694e77879SHao Wu 
81794e77879SHao Wu static void npcm7xx_smbus_write(void *opaque, hwaddr offset, uint64_t value,
81894e77879SHao Wu                               unsigned size)
81994e77879SHao Wu {
82094e77879SHao Wu     NPCM7xxSMBusState *s = opaque;
82194e77879SHao Wu     uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
82294e77879SHao Wu 
82394e77879SHao Wu     trace_npcm7xx_smbus_write(DEVICE(s)->canonical_path, offset, value, size);
82494e77879SHao Wu 
82594e77879SHao Wu     /* The order of the registers are their order in memory. */
82694e77879SHao Wu     switch (offset) {
82794e77879SHao Wu     case NPCM7XX_SMB_SDA:
82894e77879SHao Wu         npcm7xx_smbus_write_sda(s, value);
82994e77879SHao Wu         break;
83094e77879SHao Wu 
83194e77879SHao Wu     case NPCM7XX_SMB_ST:
83294e77879SHao Wu         npcm7xx_smbus_write_st(s, value);
83394e77879SHao Wu         break;
83494e77879SHao Wu 
83594e77879SHao Wu     case NPCM7XX_SMB_CST:
83694e77879SHao Wu         npcm7xx_smbus_write_cst(s, value);
83794e77879SHao Wu         break;
83894e77879SHao Wu 
83994e77879SHao Wu     case NPCM7XX_SMB_CTL1:
84094e77879SHao Wu         npcm7xx_smbus_write_ctl1(s, value);
84194e77879SHao Wu         break;
84294e77879SHao Wu 
84394e77879SHao Wu     case NPCM7XX_SMB_ADDR1:
84494e77879SHao Wu         s->addr[0] = value;
84594e77879SHao Wu         break;
84694e77879SHao Wu 
84794e77879SHao Wu     case NPCM7XX_SMB_CTL2:
84894e77879SHao Wu         npcm7xx_smbus_write_ctl2(s, value);
84994e77879SHao Wu         break;
85094e77879SHao Wu 
85194e77879SHao Wu     case NPCM7XX_SMB_ADDR2:
85294e77879SHao Wu         s->addr[1] = value;
85394e77879SHao Wu         break;
85494e77879SHao Wu 
85594e77879SHao Wu     case NPCM7XX_SMB_CTL3:
85694e77879SHao Wu         npcm7xx_smbus_write_ctl3(s, value);
85794e77879SHao Wu         break;
85894e77879SHao Wu 
85994e77879SHao Wu     case NPCM7XX_SMB_CST2:
86094e77879SHao Wu         qemu_log_mask(LOG_GUEST_ERROR,
86194e77879SHao Wu                 "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
86294e77879SHao Wu                 DEVICE(s)->canonical_path, offset);
86394e77879SHao Wu         break;
86494e77879SHao Wu 
86594e77879SHao Wu     case NPCM7XX_SMB_CST3:
86694e77879SHao Wu         npcm7xx_smbus_write_cst3(s, value);
86794e77879SHao Wu         break;
86894e77879SHao Wu 
86994e77879SHao Wu     case NPCM7XX_SMB_VER:
87094e77879SHao Wu         qemu_log_mask(LOG_GUEST_ERROR,
87194e77879SHao Wu                 "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
87294e77879SHao Wu                 DEVICE(s)->canonical_path, offset);
87394e77879SHao Wu         break;
87494e77879SHao Wu 
87594e77879SHao Wu     /* This register is either invalid or banked at this point. */
87694e77879SHao Wu     default:
87794e77879SHao Wu         if (bank) {
87894e77879SHao Wu             /* Bank 1 */
879*6b6e7570SHao Wu             switch (offset) {
880*6b6e7570SHao Wu             case NPCM7XX_SMB_FIF_CTS:
881*6b6e7570SHao Wu                 npcm7xx_smbus_write_fif_cts(s, value);
882*6b6e7570SHao Wu                 break;
883*6b6e7570SHao Wu 
884*6b6e7570SHao Wu             case NPCM7XX_SMB_FAIR_PER:
885*6b6e7570SHao Wu                 s->fair_per = value;
886*6b6e7570SHao Wu                 break;
887*6b6e7570SHao Wu 
888*6b6e7570SHao Wu             case NPCM7XX_SMB_TXF_CTL:
889*6b6e7570SHao Wu                 npcm7xx_smbus_write_txf_ctl(s, value);
890*6b6e7570SHao Wu                 break;
891*6b6e7570SHao Wu 
892*6b6e7570SHao Wu             case NPCM7XX_SMB_T_OUT:
893*6b6e7570SHao Wu                 npcm7xx_smbus_write_t_out(s, value);
894*6b6e7570SHao Wu                 break;
895*6b6e7570SHao Wu 
896*6b6e7570SHao Wu             case NPCM7XX_SMB_TXF_STS:
897*6b6e7570SHao Wu                 npcm7xx_smbus_write_txf_sts(s, value);
898*6b6e7570SHao Wu                 break;
899*6b6e7570SHao Wu 
900*6b6e7570SHao Wu             case NPCM7XX_SMB_RXF_STS:
901*6b6e7570SHao Wu                 npcm7xx_smbus_write_rxf_sts(s, value);
902*6b6e7570SHao Wu                 break;
903*6b6e7570SHao Wu 
904*6b6e7570SHao Wu             case NPCM7XX_SMB_RXF_CTL:
905*6b6e7570SHao Wu                 npcm7xx_smbus_write_rxf_ctl(s, value);
906*6b6e7570SHao Wu                 break;
907*6b6e7570SHao Wu 
908*6b6e7570SHao Wu             default:
90994e77879SHao Wu                 qemu_log_mask(LOG_GUEST_ERROR,
91094e77879SHao Wu                         "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
91194e77879SHao Wu                         DEVICE(s)->canonical_path, offset);
912*6b6e7570SHao Wu                 break;
913*6b6e7570SHao Wu             }
91494e77879SHao Wu         } else {
91594e77879SHao Wu             /* Bank 0 */
91694e77879SHao Wu             switch (offset) {
91794e77879SHao Wu             case NPCM7XX_SMB_ADDR3:
91894e77879SHao Wu                 s->addr[2] = value;
91994e77879SHao Wu                 break;
92094e77879SHao Wu 
92194e77879SHao Wu             case NPCM7XX_SMB_ADDR7:
92294e77879SHao Wu                 s->addr[6] = value;
92394e77879SHao Wu                 break;
92494e77879SHao Wu 
92594e77879SHao Wu             case NPCM7XX_SMB_ADDR4:
92694e77879SHao Wu                 s->addr[3] = value;
92794e77879SHao Wu                 break;
92894e77879SHao Wu 
92994e77879SHao Wu             case NPCM7XX_SMB_ADDR8:
93094e77879SHao Wu                 s->addr[7] = value;
93194e77879SHao Wu                 break;
93294e77879SHao Wu 
93394e77879SHao Wu             case NPCM7XX_SMB_ADDR5:
93494e77879SHao Wu                 s->addr[4] = value;
93594e77879SHao Wu                 break;
93694e77879SHao Wu 
93794e77879SHao Wu             case NPCM7XX_SMB_ADDR9:
93894e77879SHao Wu                 s->addr[8] = value;
93994e77879SHao Wu                 break;
94094e77879SHao Wu 
94194e77879SHao Wu             case NPCM7XX_SMB_ADDR6:
94294e77879SHao Wu                 s->addr[5] = value;
94394e77879SHao Wu                 break;
94494e77879SHao Wu 
94594e77879SHao Wu             case NPCM7XX_SMB_ADDR10:
94694e77879SHao Wu                 s->addr[9] = value;
94794e77879SHao Wu                 break;
94894e77879SHao Wu 
94994e77879SHao Wu             case NPCM7XX_SMB_CTL4:
95094e77879SHao Wu                 s->ctl4 = value;
95194e77879SHao Wu                 break;
95294e77879SHao Wu 
95394e77879SHao Wu             case NPCM7XX_SMB_CTL5:
95494e77879SHao Wu                 s->ctl5 = value;
95594e77879SHao Wu                 break;
95694e77879SHao Wu 
95794e77879SHao Wu             case NPCM7XX_SMB_SCLLT:
95894e77879SHao Wu                 s->scllt = value;
95994e77879SHao Wu                 break;
96094e77879SHao Wu 
961*6b6e7570SHao Wu             case NPCM7XX_SMB_FIF_CTL:
962*6b6e7570SHao Wu                 npcm7xx_smbus_write_fif_ctl(s, value);
963*6b6e7570SHao Wu                 break;
964*6b6e7570SHao Wu 
96594e77879SHao Wu             case NPCM7XX_SMB_SCLHT:
96694e77879SHao Wu                 s->sclht = value;
96794e77879SHao Wu                 break;
96894e77879SHao Wu 
96994e77879SHao Wu             default:
97094e77879SHao Wu                 qemu_log_mask(LOG_GUEST_ERROR,
97194e77879SHao Wu                         "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
97294e77879SHao Wu                         DEVICE(s)->canonical_path, offset);
97394e77879SHao Wu                 break;
97494e77879SHao Wu             }
97594e77879SHao Wu         }
97694e77879SHao Wu         break;
97794e77879SHao Wu     }
97894e77879SHao Wu }
97994e77879SHao Wu 
98094e77879SHao Wu static const MemoryRegionOps npcm7xx_smbus_ops = {
98194e77879SHao Wu     .read = npcm7xx_smbus_read,
98294e77879SHao Wu     .write = npcm7xx_smbus_write,
98394e77879SHao Wu     .endianness = DEVICE_LITTLE_ENDIAN,
98494e77879SHao Wu     .valid = {
98594e77879SHao Wu         .min_access_size = 1,
98694e77879SHao Wu         .max_access_size = 1,
98794e77879SHao Wu         .unaligned = false,
98894e77879SHao Wu     },
98994e77879SHao Wu };
99094e77879SHao Wu 
99194e77879SHao Wu static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
99294e77879SHao Wu {
99394e77879SHao Wu     NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
99494e77879SHao Wu 
99594e77879SHao Wu     s->st = NPCM7XX_SMB_ST_INIT_VAL;
99694e77879SHao Wu     s->cst = NPCM7XX_SMB_CST_INIT_VAL;
99794e77879SHao Wu     s->cst2 = NPCM7XX_SMB_CST2_INIT_VAL;
99894e77879SHao Wu     s->cst3 = NPCM7XX_SMB_CST3_INIT_VAL;
99994e77879SHao Wu     s->ctl1 = NPCM7XX_SMB_CTL1_INIT_VAL;
100094e77879SHao Wu     s->ctl2 = NPCM7XX_SMB_CTL2_INIT_VAL;
100194e77879SHao Wu     s->ctl3 = NPCM7XX_SMB_CTL3_INIT_VAL;
100294e77879SHao Wu     s->ctl4 = NPCM7XX_SMB_CTL4_INIT_VAL;
100394e77879SHao Wu     s->ctl5 = NPCM7XX_SMB_CTL5_INIT_VAL;
100494e77879SHao Wu 
100594e77879SHao Wu     for (int i = 0; i < NPCM7XX_SMBUS_NR_ADDRS; ++i) {
100694e77879SHao Wu         s->addr[i] = NPCM7XX_SMB_ADDR_INIT_VAL;
100794e77879SHao Wu     }
100894e77879SHao Wu     s->scllt = NPCM7XX_SMB_SCLLT_INIT_VAL;
100994e77879SHao Wu     s->sclht = NPCM7XX_SMB_SCLHT_INIT_VAL;
101094e77879SHao Wu 
1011*6b6e7570SHao Wu     s->fif_ctl = NPCM7XX_SMB_FIF_CTL_INIT_VAL;
1012*6b6e7570SHao Wu     s->fif_cts = NPCM7XX_SMB_FIF_CTS_INIT_VAL;
1013*6b6e7570SHao Wu     s->fair_per = NPCM7XX_SMB_FAIR_PER_INIT_VAL;
1014*6b6e7570SHao Wu     s->txf_ctl = NPCM7XX_SMB_TXF_CTL_INIT_VAL;
1015*6b6e7570SHao Wu     s->t_out = NPCM7XX_SMB_T_OUT_INIT_VAL;
1016*6b6e7570SHao Wu     s->txf_sts = NPCM7XX_SMB_TXF_STS_INIT_VAL;
1017*6b6e7570SHao Wu     s->rxf_sts = NPCM7XX_SMB_RXF_STS_INIT_VAL;
1018*6b6e7570SHao Wu     s->rxf_ctl = NPCM7XX_SMB_RXF_CTL_INIT_VAL;
1019*6b6e7570SHao Wu 
1020*6b6e7570SHao Wu     npcm7xx_smbus_clear_buffer(s);
102194e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
1022*6b6e7570SHao Wu     s->rx_cur = 0;
102394e77879SHao Wu }
102494e77879SHao Wu 
102594e77879SHao Wu static void npcm7xx_smbus_hold_reset(Object *obj)
102694e77879SHao Wu {
102794e77879SHao Wu     NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
102894e77879SHao Wu 
102994e77879SHao Wu     qemu_irq_lower(s->irq);
103094e77879SHao Wu }
103194e77879SHao Wu 
103294e77879SHao Wu static void npcm7xx_smbus_init(Object *obj)
103394e77879SHao Wu {
103494e77879SHao Wu     NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
103594e77879SHao Wu     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
103694e77879SHao Wu 
103794e77879SHao Wu     sysbus_init_irq(sbd, &s->irq);
103894e77879SHao Wu     memory_region_init_io(&s->iomem, obj, &npcm7xx_smbus_ops, s,
103994e77879SHao Wu                           "regs", 4 * KiB);
104094e77879SHao Wu     sysbus_init_mmio(sbd, &s->iomem);
104194e77879SHao Wu 
104294e77879SHao Wu     s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
104394e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
104494e77879SHao Wu }
104594e77879SHao Wu 
104694e77879SHao Wu static const VMStateDescription vmstate_npcm7xx_smbus = {
104794e77879SHao Wu     .name = "npcm7xx-smbus",
104894e77879SHao Wu     .version_id = 0,
104994e77879SHao Wu     .minimum_version_id = 0,
105094e77879SHao Wu     .fields = (VMStateField[]) {
105194e77879SHao Wu         VMSTATE_UINT8(sda, NPCM7xxSMBusState),
105294e77879SHao Wu         VMSTATE_UINT8(st, NPCM7xxSMBusState),
105394e77879SHao Wu         VMSTATE_UINT8(cst, NPCM7xxSMBusState),
105494e77879SHao Wu         VMSTATE_UINT8(cst2, NPCM7xxSMBusState),
105594e77879SHao Wu         VMSTATE_UINT8(cst3, NPCM7xxSMBusState),
105694e77879SHao Wu         VMSTATE_UINT8(ctl1, NPCM7xxSMBusState),
105794e77879SHao Wu         VMSTATE_UINT8(ctl2, NPCM7xxSMBusState),
105894e77879SHao Wu         VMSTATE_UINT8(ctl3, NPCM7xxSMBusState),
105994e77879SHao Wu         VMSTATE_UINT8(ctl4, NPCM7xxSMBusState),
106094e77879SHao Wu         VMSTATE_UINT8(ctl5, NPCM7xxSMBusState),
106194e77879SHao Wu         VMSTATE_UINT8_ARRAY(addr, NPCM7xxSMBusState, NPCM7XX_SMBUS_NR_ADDRS),
106294e77879SHao Wu         VMSTATE_UINT8(scllt, NPCM7xxSMBusState),
106394e77879SHao Wu         VMSTATE_UINT8(sclht, NPCM7xxSMBusState),
1064*6b6e7570SHao Wu         VMSTATE_UINT8(fif_ctl, NPCM7xxSMBusState),
1065*6b6e7570SHao Wu         VMSTATE_UINT8(fif_cts, NPCM7xxSMBusState),
1066*6b6e7570SHao Wu         VMSTATE_UINT8(fair_per, NPCM7xxSMBusState),
1067*6b6e7570SHao Wu         VMSTATE_UINT8(txf_ctl, NPCM7xxSMBusState),
1068*6b6e7570SHao Wu         VMSTATE_UINT8(t_out, NPCM7xxSMBusState),
1069*6b6e7570SHao Wu         VMSTATE_UINT8(txf_sts, NPCM7xxSMBusState),
1070*6b6e7570SHao Wu         VMSTATE_UINT8(rxf_sts, NPCM7xxSMBusState),
1071*6b6e7570SHao Wu         VMSTATE_UINT8(rxf_ctl, NPCM7xxSMBusState),
1072*6b6e7570SHao Wu         VMSTATE_UINT8_ARRAY(rx_fifo, NPCM7xxSMBusState,
1073*6b6e7570SHao Wu                             NPCM7XX_SMBUS_FIFO_SIZE),
1074*6b6e7570SHao Wu         VMSTATE_UINT8(rx_cur, NPCM7xxSMBusState),
107594e77879SHao Wu         VMSTATE_END_OF_LIST(),
107694e77879SHao Wu     },
107794e77879SHao Wu };
107894e77879SHao Wu 
107994e77879SHao Wu static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data)
108094e77879SHao Wu {
108194e77879SHao Wu     ResettableClass *rc = RESETTABLE_CLASS(klass);
108294e77879SHao Wu     DeviceClass *dc = DEVICE_CLASS(klass);
108394e77879SHao Wu 
108494e77879SHao Wu     dc->desc = "NPCM7xx System Management Bus";
108594e77879SHao Wu     dc->vmsd = &vmstate_npcm7xx_smbus;
108694e77879SHao Wu     rc->phases.enter = npcm7xx_smbus_enter_reset;
108794e77879SHao Wu     rc->phases.hold = npcm7xx_smbus_hold_reset;
108894e77879SHao Wu }
108994e77879SHao Wu 
109094e77879SHao Wu static const TypeInfo npcm7xx_smbus_types[] = {
109194e77879SHao Wu     {
109294e77879SHao Wu         .name = TYPE_NPCM7XX_SMBUS,
109394e77879SHao Wu         .parent = TYPE_SYS_BUS_DEVICE,
109494e77879SHao Wu         .instance_size = sizeof(NPCM7xxSMBusState),
109594e77879SHao Wu         .class_init = npcm7xx_smbus_class_init,
109694e77879SHao Wu         .instance_init = npcm7xx_smbus_init,
109794e77879SHao Wu     },
109894e77879SHao Wu };
109994e77879SHao Wu DEFINE_TYPES(npcm7xx_smbus_types);
1100