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
1326b6e7570SHao Wu /* FIFO Mode Register Fields */
1336b6e7570SHao Wu /* FIF_CTL fields */
1346b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FIFO_EN BIT(4)
1356b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FAIR_RDY_IE BIT(2)
1366b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FAIR_RDY BIT(1)
1376b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTL_FAIR_BUSY BIT(0)
1386b6e7570SHao Wu /* FIF_CTS fields */
1396b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_STR BIT(7)
1406b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_CLR_FIFO BIT(6)
1416b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_RFTE_IE BIT(3)
1426b6e7570SHao Wu #define NPCM7XX_SMBFIF_CTS_RXF_TXE BIT(1)
1436b6e7570SHao Wu /* TXF_CTL fields */
1446b6e7570SHao Wu #define NPCM7XX_SMBTXF_CTL_THR_TXIE BIT(6)
1456b6e7570SHao Wu #define NPCM7XX_SMBTXF_CTL_TX_THR(rv) extract8((rv), 0, 5)
1466b6e7570SHao Wu /* T_OUT fields */
1476b6e7570SHao Wu #define NPCM7XX_SMBT_OUT_ST BIT(7)
1486b6e7570SHao Wu #define NPCM7XX_SMBT_OUT_IE BIT(6)
1496b6e7570SHao Wu #define NPCM7XX_SMBT_OUT_CLKDIV(rv) extract8((rv), 0, 6)
1506b6e7570SHao Wu /* TXF_STS fields */
1516b6e7570SHao Wu #define NPCM7XX_SMBTXF_STS_TX_THST BIT(6)
1526b6e7570SHao Wu #define NPCM7XX_SMBTXF_STS_TX_BYTES(rv) extract8((rv), 0, 5)
1536b6e7570SHao Wu /* RXF_STS fields */
1546b6e7570SHao Wu #define NPCM7XX_SMBRXF_STS_RX_THST BIT(6)
1556b6e7570SHao Wu #define NPCM7XX_SMBRXF_STS_RX_BYTES(rv) extract8((rv), 0, 5)
1566b6e7570SHao Wu /* RXF_CTL fields */
1576b6e7570SHao Wu #define NPCM7XX_SMBRXF_CTL_THR_RXIE BIT(6)
1586b6e7570SHao Wu #define NPCM7XX_SMBRXF_CTL_LAST BIT(5)
1596b6e7570SHao Wu #define NPCM7XX_SMBRXF_CTL_RX_THR(rv) extract8((rv), 0, 5)
1606b6e7570SHao 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)
1656b6e7570SHao Wu #define NPCM7XX_SMBUS_FIFO_ENABLED(s) ((s)->fif_ctl & \
1666b6e7570SHao Wu NPCM7XX_SMBFIF_CTL_FIFO_EN)
16794e77879SHao Wu
16894e77879SHao Wu /* VERSION fields values, read-only. */
16994e77879SHao Wu #define NPCM7XX_SMBUS_VERSION_NUMBER 1
1706b6e7570SHao 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
1856b6e7570SHao Wu #define NPCM7XX_SMB_FIF_CTL_INIT_VAL 0x00
1866b6e7570SHao Wu #define NPCM7XX_SMB_FIF_CTS_INIT_VAL 0x00
1876b6e7570SHao Wu #define NPCM7XX_SMB_FAIR_PER_INIT_VAL 0x00
1886b6e7570SHao Wu #define NPCM7XX_SMB_TXF_CTL_INIT_VAL 0x00
1896b6e7570SHao Wu #define NPCM7XX_SMB_T_OUT_INIT_VAL 0x3f
1906b6e7570SHao Wu #define NPCM7XX_SMB_TXF_STS_INIT_VAL 0x00
1916b6e7570SHao Wu #define NPCM7XX_SMB_RXF_STS_INIT_VAL 0x00
1926b6e7570SHao Wu #define NPCM7XX_SMB_RXF_CTL_INIT_VAL 0x01
19394e77879SHao Wu
npcm7xx_smbus_get_version(void)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
npcm7xx_smbus_update_irq(NPCM7xxSMBusState * s)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 &&
2136b6e7570SHao Wu s->cst3 & NPCM7XX_SMBCST3_EO_BUSY) ||
2146b6e7570SHao Wu (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE &&
2156b6e7570SHao Wu s->rxf_sts & NPCM7XX_SMBRXF_STS_RX_THST) ||
2166b6e7570SHao Wu (s->txf_ctl & NPCM7XX_SMBTXF_CTL_THR_TXIE &&
2176b6e7570SHao Wu s->txf_sts & NPCM7XX_SMBTXF_STS_TX_THST) ||
2186b6e7570SHao Wu (s->fif_cts & NPCM7XX_SMBFIF_CTS_RFTE_IE &&
2196b6e7570SHao 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
npcm7xx_smbus_nack(NPCM7xxSMBusState * s)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
npcm7xx_smbus_clear_buffer(NPCM7xxSMBusState * s)2376b6e7570SHao Wu static void npcm7xx_smbus_clear_buffer(NPCM7xxSMBusState *s)
2386b6e7570SHao Wu {
2396b6e7570SHao Wu s->fif_cts &= ~NPCM7XX_SMBFIF_CTS_RXF_TXE;
2406b6e7570SHao Wu s->txf_sts = 0;
2416b6e7570SHao Wu s->rxf_sts = 0;
2426b6e7570SHao Wu }
2436b6e7570SHao Wu
npcm7xx_smbus_send_byte(NPCM7xxSMBusState * s,uint8_t value)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;
2526b6e7570SHao Wu if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
2536b6e7570SHao Wu s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
2546b6e7570SHao Wu if (NPCM7XX_SMBTXF_STS_TX_BYTES(s->txf_sts) ==
2556b6e7570SHao Wu NPCM7XX_SMBTXF_CTL_TX_THR(s->txf_ctl)) {
2566b6e7570SHao Wu s->txf_sts = NPCM7XX_SMBTXF_STS_TX_THST;
2576b6e7570SHao Wu } else {
2586b6e7570SHao Wu s->txf_sts = 0;
2596b6e7570SHao Wu }
2606b6e7570SHao 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
npcm7xx_smbus_recv_byte(NPCM7xxSMBusState * s)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
npcm7xx_smbus_recv_fifo(NPCM7xxSMBusState * s)2796b6e7570SHao Wu static void npcm7xx_smbus_recv_fifo(NPCM7xxSMBusState *s)
2806b6e7570SHao Wu {
2816b6e7570SHao Wu uint8_t expected_bytes = NPCM7XX_SMBRXF_CTL_RX_THR(s->rxf_ctl);
2826b6e7570SHao Wu uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
2836b6e7570SHao Wu uint8_t pos;
2846b6e7570SHao Wu
2856b6e7570SHao Wu if (received_bytes == expected_bytes) {
2866b6e7570SHao Wu return;
2876b6e7570SHao Wu }
2886b6e7570SHao Wu
2896b6e7570SHao Wu while (received_bytes < expected_bytes &&
2906b6e7570SHao Wu received_bytes < NPCM7XX_SMBUS_FIFO_SIZE) {
2916b6e7570SHao Wu pos = (s->rx_cur + received_bytes) % NPCM7XX_SMBUS_FIFO_SIZE;
2926b6e7570SHao Wu s->rx_fifo[pos] = i2c_recv(s->bus);
2936b6e7570SHao Wu trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path),
2946b6e7570SHao Wu s->rx_fifo[pos]);
2956b6e7570SHao Wu ++received_bytes;
2966b6e7570SHao Wu }
2976b6e7570SHao Wu
2986b6e7570SHao Wu trace_npcm7xx_smbus_recv_fifo((DEVICE(s)->canonical_path),
2996b6e7570SHao Wu received_bytes, expected_bytes);
3006b6e7570SHao Wu s->rxf_sts = received_bytes;
3016b6e7570SHao Wu if (unlikely(received_bytes < expected_bytes)) {
3026b6e7570SHao Wu qemu_log_mask(LOG_GUEST_ERROR,
3036b6e7570SHao Wu "%s: invalid rx_thr value: 0x%02x\n",
3046b6e7570SHao Wu DEVICE(s)->canonical_path, expected_bytes);
3056b6e7570SHao Wu return;
3066b6e7570SHao Wu }
3076b6e7570SHao Wu
3086b6e7570SHao Wu s->rxf_sts |= NPCM7XX_SMBRXF_STS_RX_THST;
3096b6e7570SHao Wu if (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_LAST) {
3106b6e7570SHao Wu trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
3116b6e7570SHao Wu i2c_nack(s->bus);
3126b6e7570SHao Wu s->rxf_ctl &= ~NPCM7XX_SMBRXF_CTL_LAST;
3136b6e7570SHao Wu }
3146b6e7570SHao Wu if (received_bytes == NPCM7XX_SMBUS_FIFO_SIZE) {
3156b6e7570SHao Wu s->st |= NPCM7XX_SMBST_SDAST;
3166b6e7570SHao Wu s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
3176b6e7570SHao Wu } else if (!(s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE)) {
3186b6e7570SHao Wu s->st |= NPCM7XX_SMBST_SDAST;
3196b6e7570SHao Wu } else {
3206b6e7570SHao Wu s->st &= ~NPCM7XX_SMBST_SDAST;
3216b6e7570SHao Wu }
3226b6e7570SHao Wu npcm7xx_smbus_update_irq(s);
3236b6e7570SHao Wu }
3246b6e7570SHao Wu
npcm7xx_smbus_read_byte_fifo(NPCM7xxSMBusState * s)3256b6e7570SHao Wu static void npcm7xx_smbus_read_byte_fifo(NPCM7xxSMBusState *s)
3266b6e7570SHao Wu {
3276b6e7570SHao Wu uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
3286b6e7570SHao Wu
3296b6e7570SHao Wu if (received_bytes == 0) {
3306b6e7570SHao Wu npcm7xx_smbus_recv_fifo(s);
3316b6e7570SHao Wu return;
3326b6e7570SHao Wu }
3336b6e7570SHao Wu
3346b6e7570SHao Wu s->sda = s->rx_fifo[s->rx_cur];
3356b6e7570SHao Wu s->rx_cur = (s->rx_cur + 1u) % NPCM7XX_SMBUS_FIFO_SIZE;
3366b6e7570SHao Wu --s->rxf_sts;
3376b6e7570SHao Wu npcm7xx_smbus_update_irq(s);
3386b6e7570SHao Wu }
3396b6e7570SHao Wu
npcm7xx_smbus_start(NPCM7xxSMBusState * s)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;
3536b6e7570SHao Wu if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
3546b6e7570SHao Wu s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
3556b6e7570SHao 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
npcm7xx_smbus_send_address(NPCM7xxSMBusState * s,uint8_t value)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) {
4076b6e7570SHao Wu s->st |= NPCM7XX_SMBST_SDAST;
4086b6e7570SHao Wu if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
4096b6e7570SHao Wu npcm7xx_smbus_recv_fifo(s);
4106b6e7570SHao Wu } else {
41194e77879SHao Wu npcm7xx_smbus_recv_byte(s);
41294e77879SHao Wu }
4136b6e7570SHao Wu } else if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
4146b6e7570SHao Wu s->st |= NPCM7XX_SMBST_SDAST;
4156b6e7570SHao Wu s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
4166b6e7570SHao Wu }
41794e77879SHao Wu npcm7xx_smbus_update_irq(s);
41894e77879SHao Wu }
41994e77879SHao Wu
npcm7xx_smbus_execute_stop(NPCM7xxSMBusState * s)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
npcm7xx_smbus_stop(NPCM7xxSMBusState * s)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
npcm7xx_smbus_read_sda(NPCM7xxSMBusState * s)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:
4586b6e7570SHao Wu if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
4596b6e7570SHao Wu if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) <= 1) {
46094e77879SHao Wu npcm7xx_smbus_execute_stop(s);
4616b6e7570SHao Wu }
4626b6e7570SHao Wu if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) == 0) {
4636b6e7570SHao Wu qemu_log_mask(LOG_GUEST_ERROR,
4646b6e7570SHao Wu "%s: read to SDA with an empty rx-fifo buffer, "
4656b6e7570SHao Wu "result undefined: %u\n",
4666b6e7570SHao Wu DEVICE(s)->canonical_path, s->sda);
4676b6e7570SHao Wu break;
4686b6e7570SHao Wu }
4696b6e7570SHao Wu npcm7xx_smbus_read_byte_fifo(s);
4706b6e7570SHao Wu value = s->sda;
4716b6e7570SHao Wu } else {
4726b6e7570SHao Wu npcm7xx_smbus_execute_stop(s);
4736b6e7570SHao Wu }
47494e77879SHao Wu break;
47594e77879SHao Wu
47694e77879SHao Wu case NPCM7XX_SMBUS_STATUS_RECEIVING:
4776b6e7570SHao Wu if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
4786b6e7570SHao Wu npcm7xx_smbus_read_byte_fifo(s);
4796b6e7570SHao Wu value = s->sda;
4806b6e7570SHao Wu } else {
48194e77879SHao Wu npcm7xx_smbus_recv_byte(s);
4826b6e7570SHao 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
npcm7xx_smbus_write_sda(NPCM7xxSMBusState * s,uint8_t value)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
npcm7xx_smbus_write_st(NPCM7xxSMBusState * s,uint8_t value)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) {
5296b6e7570SHao Wu if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
5306b6e7570SHao Wu npcm7xx_smbus_recv_fifo(s);
5316b6e7570SHao Wu } else {
53294e77879SHao Wu npcm7xx_smbus_recv_byte(s);
53394e77879SHao Wu }
5346b6e7570SHao Wu }
53594e77879SHao Wu
53694e77879SHao Wu npcm7xx_smbus_update_irq(s);
53794e77879SHao Wu }
53894e77879SHao Wu
npcm7xx_smbus_write_cst(NPCM7xxSMBusState * s,uint8_t value)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
npcm7xx_smbus_write_cst3(NPCM7xxSMBusState * s,uint8_t value)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
npcm7xx_smbus_write_ctl1(NPCM7xxSMBusState * s,uint8_t value)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
npcm7xx_smbus_write_ctl2(NPCM7xxSMBusState * s,uint8_t value)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;
5796b6e7570SHao Wu npcm7xx_smbus_clear_buffer(s);
58094e77879SHao Wu }
58194e77879SHao Wu }
58294e77879SHao Wu
npcm7xx_smbus_write_ctl3(NPCM7xxSMBusState * s,uint8_t value)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
npcm7xx_smbus_write_fif_ctl(NPCM7xxSMBusState * s,uint8_t value)5926b6e7570SHao Wu static void npcm7xx_smbus_write_fif_ctl(NPCM7xxSMBusState *s, uint8_t value)
5936b6e7570SHao Wu {
5946b6e7570SHao Wu uint8_t new_ctl = value;
5956b6e7570SHao Wu
5966b6e7570SHao Wu new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
5976b6e7570SHao Wu new_ctl = WRITE_ONE_CLEAR(new_ctl, value, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
5986b6e7570SHao Wu new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_BUSY);
5996b6e7570SHao Wu s->fif_ctl = new_ctl;
6006b6e7570SHao Wu }
6016b6e7570SHao Wu
npcm7xx_smbus_write_fif_cts(NPCM7xxSMBusState * s,uint8_t value)6026b6e7570SHao Wu static void npcm7xx_smbus_write_fif_cts(NPCM7xxSMBusState *s, uint8_t value)
6036b6e7570SHao Wu {
6046b6e7570SHao Wu s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_STR);
6056b6e7570SHao Wu s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_RXF_TXE);
6066b6e7570SHao Wu s->fif_cts = KEEP_OLD_BIT(value, s->fif_cts, NPCM7XX_SMBFIF_CTS_RFTE_IE);
6076b6e7570SHao Wu
6086b6e7570SHao Wu if (value & NPCM7XX_SMBFIF_CTS_CLR_FIFO) {
6096b6e7570SHao Wu npcm7xx_smbus_clear_buffer(s);
6106b6e7570SHao Wu }
6116b6e7570SHao Wu }
6126b6e7570SHao Wu
npcm7xx_smbus_write_txf_ctl(NPCM7xxSMBusState * s,uint8_t value)6136b6e7570SHao Wu static void npcm7xx_smbus_write_txf_ctl(NPCM7xxSMBusState *s, uint8_t value)
6146b6e7570SHao Wu {
6156b6e7570SHao Wu s->txf_ctl = value;
6166b6e7570SHao Wu }
6176b6e7570SHao Wu
npcm7xx_smbus_write_t_out(NPCM7xxSMBusState * s,uint8_t value)6186b6e7570SHao Wu static void npcm7xx_smbus_write_t_out(NPCM7xxSMBusState *s, uint8_t value)
6196b6e7570SHao Wu {
6206b6e7570SHao Wu uint8_t new_t_out = value;
6216b6e7570SHao Wu
6226b6e7570SHao Wu if ((value & NPCM7XX_SMBT_OUT_ST) || (!(s->t_out & NPCM7XX_SMBT_OUT_ST))) {
6236b6e7570SHao Wu new_t_out &= ~NPCM7XX_SMBT_OUT_ST;
6246b6e7570SHao Wu } else {
6256b6e7570SHao Wu new_t_out |= NPCM7XX_SMBT_OUT_ST;
6266b6e7570SHao Wu }
6276b6e7570SHao Wu
6286b6e7570SHao Wu s->t_out = new_t_out;
6296b6e7570SHao Wu }
6306b6e7570SHao Wu
npcm7xx_smbus_write_txf_sts(NPCM7xxSMBusState * s,uint8_t value)6316b6e7570SHao Wu static void npcm7xx_smbus_write_txf_sts(NPCM7xxSMBusState *s, uint8_t value)
6326b6e7570SHao Wu {
6336b6e7570SHao Wu s->txf_sts = WRITE_ONE_CLEAR(s->txf_sts, value, NPCM7XX_SMBTXF_STS_TX_THST);
6346b6e7570SHao Wu }
6356b6e7570SHao Wu
npcm7xx_smbus_write_rxf_sts(NPCM7xxSMBusState * s,uint8_t value)6366b6e7570SHao Wu static void npcm7xx_smbus_write_rxf_sts(NPCM7xxSMBusState *s, uint8_t value)
6376b6e7570SHao Wu {
6386b6e7570SHao Wu if (value & NPCM7XX_SMBRXF_STS_RX_THST) {
6396b6e7570SHao Wu s->rxf_sts &= ~NPCM7XX_SMBRXF_STS_RX_THST;
6406b6e7570SHao Wu if (s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
6416b6e7570SHao Wu npcm7xx_smbus_recv_fifo(s);
6426b6e7570SHao Wu }
6436b6e7570SHao Wu }
6446b6e7570SHao Wu }
6456b6e7570SHao Wu
npcm7xx_smbus_write_rxf_ctl(NPCM7xxSMBusState * s,uint8_t value)6466b6e7570SHao Wu static void npcm7xx_smbus_write_rxf_ctl(NPCM7xxSMBusState *s, uint8_t value)
6476b6e7570SHao Wu {
6486b6e7570SHao Wu uint8_t new_ctl = value;
6496b6e7570SHao Wu
6506b6e7570SHao Wu if (!(value & NPCM7XX_SMBRXF_CTL_LAST)) {
6516b6e7570SHao Wu new_ctl = KEEP_OLD_BIT(s->rxf_ctl, new_ctl, NPCM7XX_SMBRXF_CTL_LAST);
6526b6e7570SHao Wu }
6536b6e7570SHao Wu s->rxf_ctl = new_ctl;
6546b6e7570SHao Wu }
6556b6e7570SHao Wu
npcm7xx_smbus_read(void * opaque,hwaddr offset,unsigned size)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 */
7126b6e7570SHao Wu switch (offset) {
7136b6e7570SHao Wu case NPCM7XX_SMB_FIF_CTS:
7146b6e7570SHao Wu value = s->fif_cts;
7156b6e7570SHao Wu break;
7166b6e7570SHao Wu
7176b6e7570SHao Wu case NPCM7XX_SMB_FAIR_PER:
7186b6e7570SHao Wu value = s->fair_per;
7196b6e7570SHao Wu break;
7206b6e7570SHao Wu
7216b6e7570SHao Wu case NPCM7XX_SMB_TXF_CTL:
7226b6e7570SHao Wu value = s->txf_ctl;
7236b6e7570SHao Wu break;
7246b6e7570SHao Wu
7256b6e7570SHao Wu case NPCM7XX_SMB_T_OUT:
7266b6e7570SHao Wu value = s->t_out;
7276b6e7570SHao Wu break;
7286b6e7570SHao Wu
7296b6e7570SHao Wu case NPCM7XX_SMB_TXF_STS:
7306b6e7570SHao Wu value = s->txf_sts;
7316b6e7570SHao Wu break;
7326b6e7570SHao Wu
7336b6e7570SHao Wu case NPCM7XX_SMB_RXF_STS:
7346b6e7570SHao Wu value = s->rxf_sts;
7356b6e7570SHao Wu break;
7366b6e7570SHao Wu
7376b6e7570SHao Wu case NPCM7XX_SMB_RXF_CTL:
7386b6e7570SHao Wu value = s->rxf_ctl;
7396b6e7570SHao Wu break;
7406b6e7570SHao Wu
7416b6e7570SHao 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);
7456b6e7570SHao Wu break;
7466b6e7570SHao 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
7946b6e7570SHao Wu case NPCM7XX_SMB_FIF_CTL:
7956b6e7570SHao Wu value = s->fif_ctl;
7966b6e7570SHao Wu break;
7976b6e7570SHao 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
npcm7xx_smbus_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)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 */
8796b6e7570SHao Wu switch (offset) {
8806b6e7570SHao Wu case NPCM7XX_SMB_FIF_CTS:
8816b6e7570SHao Wu npcm7xx_smbus_write_fif_cts(s, value);
8826b6e7570SHao Wu break;
8836b6e7570SHao Wu
8846b6e7570SHao Wu case NPCM7XX_SMB_FAIR_PER:
8856b6e7570SHao Wu s->fair_per = value;
8866b6e7570SHao Wu break;
8876b6e7570SHao Wu
8886b6e7570SHao Wu case NPCM7XX_SMB_TXF_CTL:
8896b6e7570SHao Wu npcm7xx_smbus_write_txf_ctl(s, value);
8906b6e7570SHao Wu break;
8916b6e7570SHao Wu
8926b6e7570SHao Wu case NPCM7XX_SMB_T_OUT:
8936b6e7570SHao Wu npcm7xx_smbus_write_t_out(s, value);
8946b6e7570SHao Wu break;
8956b6e7570SHao Wu
8966b6e7570SHao Wu case NPCM7XX_SMB_TXF_STS:
8976b6e7570SHao Wu npcm7xx_smbus_write_txf_sts(s, value);
8986b6e7570SHao Wu break;
8996b6e7570SHao Wu
9006b6e7570SHao Wu case NPCM7XX_SMB_RXF_STS:
9016b6e7570SHao Wu npcm7xx_smbus_write_rxf_sts(s, value);
9026b6e7570SHao Wu break;
9036b6e7570SHao Wu
9046b6e7570SHao Wu case NPCM7XX_SMB_RXF_CTL:
9056b6e7570SHao Wu npcm7xx_smbus_write_rxf_ctl(s, value);
9066b6e7570SHao Wu break;
9076b6e7570SHao Wu
9086b6e7570SHao 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);
9126b6e7570SHao Wu break;
9136b6e7570SHao 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
9616b6e7570SHao Wu case NPCM7XX_SMB_FIF_CTL:
9626b6e7570SHao Wu npcm7xx_smbus_write_fif_ctl(s, value);
9636b6e7570SHao Wu break;
9646b6e7570SHao 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
npcm7xx_smbus_enter_reset(Object * obj,ResetType type)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
10116b6e7570SHao Wu s->fif_ctl = NPCM7XX_SMB_FIF_CTL_INIT_VAL;
10126b6e7570SHao Wu s->fif_cts = NPCM7XX_SMB_FIF_CTS_INIT_VAL;
10136b6e7570SHao Wu s->fair_per = NPCM7XX_SMB_FAIR_PER_INIT_VAL;
10146b6e7570SHao Wu s->txf_ctl = NPCM7XX_SMB_TXF_CTL_INIT_VAL;
10156b6e7570SHao Wu s->t_out = NPCM7XX_SMB_T_OUT_INIT_VAL;
10166b6e7570SHao Wu s->txf_sts = NPCM7XX_SMB_TXF_STS_INIT_VAL;
10176b6e7570SHao Wu s->rxf_sts = NPCM7XX_SMB_RXF_STS_INIT_VAL;
10186b6e7570SHao Wu s->rxf_ctl = NPCM7XX_SMB_RXF_CTL_INIT_VAL;
10196b6e7570SHao Wu
10206b6e7570SHao Wu npcm7xx_smbus_clear_buffer(s);
102194e77879SHao Wu s->status = NPCM7XX_SMBUS_STATUS_IDLE;
10226b6e7570SHao Wu s->rx_cur = 0;
102394e77879SHao Wu }
102494e77879SHao Wu
npcm7xx_smbus_hold_reset(Object * obj,ResetType type)1025*ad80e367SPeter Maydell static void npcm7xx_smbus_hold_reset(Object *obj, ResetType type)
102694e77879SHao Wu {
102794e77879SHao Wu NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
102894e77879SHao Wu
102994e77879SHao Wu qemu_irq_lower(s->irq);
103094e77879SHao Wu }
103194e77879SHao Wu
npcm7xx_smbus_init(Object * obj)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 }
104494e77879SHao Wu
104594e77879SHao Wu static const VMStateDescription vmstate_npcm7xx_smbus = {
104694e77879SHao Wu .name = "npcm7xx-smbus",
104794e77879SHao Wu .version_id = 0,
104894e77879SHao Wu .minimum_version_id = 0,
104901d9442aSRichard Henderson .fields = (const VMStateField[]) {
105094e77879SHao Wu VMSTATE_UINT8(sda, NPCM7xxSMBusState),
105194e77879SHao Wu VMSTATE_UINT8(st, NPCM7xxSMBusState),
105294e77879SHao Wu VMSTATE_UINT8(cst, NPCM7xxSMBusState),
105394e77879SHao Wu VMSTATE_UINT8(cst2, NPCM7xxSMBusState),
105494e77879SHao Wu VMSTATE_UINT8(cst3, NPCM7xxSMBusState),
105594e77879SHao Wu VMSTATE_UINT8(ctl1, NPCM7xxSMBusState),
105694e77879SHao Wu VMSTATE_UINT8(ctl2, NPCM7xxSMBusState),
105794e77879SHao Wu VMSTATE_UINT8(ctl3, NPCM7xxSMBusState),
105894e77879SHao Wu VMSTATE_UINT8(ctl4, NPCM7xxSMBusState),
105994e77879SHao Wu VMSTATE_UINT8(ctl5, NPCM7xxSMBusState),
106094e77879SHao Wu VMSTATE_UINT8_ARRAY(addr, NPCM7xxSMBusState, NPCM7XX_SMBUS_NR_ADDRS),
106194e77879SHao Wu VMSTATE_UINT8(scllt, NPCM7xxSMBusState),
106294e77879SHao Wu VMSTATE_UINT8(sclht, NPCM7xxSMBusState),
10636b6e7570SHao Wu VMSTATE_UINT8(fif_ctl, NPCM7xxSMBusState),
10646b6e7570SHao Wu VMSTATE_UINT8(fif_cts, NPCM7xxSMBusState),
10656b6e7570SHao Wu VMSTATE_UINT8(fair_per, NPCM7xxSMBusState),
10666b6e7570SHao Wu VMSTATE_UINT8(txf_ctl, NPCM7xxSMBusState),
10676b6e7570SHao Wu VMSTATE_UINT8(t_out, NPCM7xxSMBusState),
10686b6e7570SHao Wu VMSTATE_UINT8(txf_sts, NPCM7xxSMBusState),
10696b6e7570SHao Wu VMSTATE_UINT8(rxf_sts, NPCM7xxSMBusState),
10706b6e7570SHao Wu VMSTATE_UINT8(rxf_ctl, NPCM7xxSMBusState),
10716b6e7570SHao Wu VMSTATE_UINT8_ARRAY(rx_fifo, NPCM7xxSMBusState,
10726b6e7570SHao Wu NPCM7XX_SMBUS_FIFO_SIZE),
10736b6e7570SHao Wu VMSTATE_UINT8(rx_cur, NPCM7xxSMBusState),
107494e77879SHao Wu VMSTATE_END_OF_LIST(),
107594e77879SHao Wu },
107694e77879SHao Wu };
107794e77879SHao Wu
npcm7xx_smbus_class_init(ObjectClass * klass,void * data)107894e77879SHao Wu static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data)
107994e77879SHao Wu {
108094e77879SHao Wu ResettableClass *rc = RESETTABLE_CLASS(klass);
108194e77879SHao Wu DeviceClass *dc = DEVICE_CLASS(klass);
108294e77879SHao Wu
108394e77879SHao Wu dc->desc = "NPCM7xx System Management Bus";
108494e77879SHao Wu dc->vmsd = &vmstate_npcm7xx_smbus;
108594e77879SHao Wu rc->phases.enter = npcm7xx_smbus_enter_reset;
108694e77879SHao Wu rc->phases.hold = npcm7xx_smbus_hold_reset;
108794e77879SHao Wu }
108894e77879SHao Wu
108994e77879SHao Wu static const TypeInfo npcm7xx_smbus_types[] = {
109094e77879SHao Wu {
109194e77879SHao Wu .name = TYPE_NPCM7XX_SMBUS,
109294e77879SHao Wu .parent = TYPE_SYS_BUS_DEVICE,
109394e77879SHao Wu .instance_size = sizeof(NPCM7xxSMBusState),
109494e77879SHao Wu .class_init = npcm7xx_smbus_class_init,
109594e77879SHao Wu .instance_init = npcm7xx_smbus_init,
109694e77879SHao Wu },
109794e77879SHao Wu };
109894e77879SHao Wu DEFINE_TYPES(npcm7xx_smbus_types);
1099