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