From patchwork Wed Jun 1 16:26:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 69046 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp192703qge; Wed, 1 Jun 2016 09:35:18 -0700 (PDT) X-Received: by 10.237.42.103 with SMTP id c94mr4647981qtd.64.1464798918476; Wed, 01 Jun 2016 09:35:18 -0700 (PDT) Return-Path: Received: from lists.gnu.org (lists.gnu.org. [208.118.235.17]) by mx.google.com with ESMTPS id v3si35296849qkc.276.2016.06.01.09.35.18 for (version=TLS1 cipher=AES128-SHA bits=128/128); Wed, 01 Jun 2016 09:35:18 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org Received: from localhost ([::1]:43068 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8970-0002Bx-1a for patch@linaro.org; Wed, 01 Jun 2016 12:35:18 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49578) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b88zF-0005Rt-DS for qemu-devel@nongnu.org; Wed, 01 Jun 2016 12:27:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1b88z8-00058J-6C for qemu-devel@nongnu.org; Wed, 01 Jun 2016 12:27:16 -0400 Received: from mail-pf0-x243.google.com ([2607:f8b0:400e:c00::243]:35224) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b88z7-000580-Ov for qemu-devel@nongnu.org; Wed, 01 Jun 2016 12:27:10 -0400 Received: by mail-pf0-x243.google.com with SMTP id f144so4475121pfa.2 for ; Wed, 01 Jun 2016 09:27:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=1YOFWgGmuZAGEB07VEmAoLaJRMKttvvGSxVZuA7a6Vw=; b=oMBE4lLQX0j52E14hH6T2ZA5Uw32JNNxcjmCiesNuwV6qv7OnQcyFJ/Pb+DhMBQotj naaeW6mqNezLBF9ld5Da9w3HW5SHrOcXCevXrg5/MoZP3N0oXyW/0rYFE2Kaf0FeXzzU j8Ua0JkWS70h8lbWi5lliLFmVPM1SwNp9tVAEZ2JgvTqPj5m0rd4NucAY3dQh+rMN/Km GlEUI9waTbylauQhU16qSU/uTmfa+birIsuwuD+peobAdmkFFTG3nfm1tn7FBTKwE716 zGpTvJvOqY57PzUyj/xu2PF9JBMxqs9kETuXPROhd0R7I7uWyantluAi1vltd+hIawOx FrRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=1YOFWgGmuZAGEB07VEmAoLaJRMKttvvGSxVZuA7a6Vw=; b=ikvPyq9juEi3tiCQPBOz5ugvXgRQxEzOtUYPyWd6SHIPz62Oh/aixfb7kXxIhAsZrU HWbfv3ylVFiC7CSWrc21K2qEiFHXCHE+Az9adNP8Oz8S1qAWkLjvFcNW3FesUexoUbp6 6WvbdmKOSYvid4l8h/+6jW1WivI+rjOSnhH5m9oQLh7RP1X+mjdpAt1OFByRIvo0k9Mb 4m5sXsEVdixnX2uA0n/f4BFRMoAB2w9D99Z4zwzKJzKARIBzGS10DM0P/3Q7E4toeg1j o7ZOyE15lDgj+ace4NnCwfOAENLruQDl0A3+ryivAD6GyUe5NTGqICD8K21iR31nrQiJ 7y7w== X-Gm-Message-State: ALyK8tJQGL7OR2EupZZOtNKXPhaUSf4BJal0b/cs6Pcf+4YEFANWag492A5sRnC53RdlRA== X-Received: by 10.98.12.143 with SMTP id 15mr10318484pfm.12.1464798428892; Wed, 01 Jun 2016 09:27:08 -0700 (PDT) Received: from serve.minyard.net ([108.19.215.157]) by smtp.gmail.com with ESMTPSA id q127sm20941658pfb.34.2016.06.01.09.27.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 01 Jun 2016 09:27:07 -0700 (PDT) Received: from t430.minyard.net (unknown [IPv6:2001:470:b8f6:1b:c93f:6d1d:c142:8409]) by serve.minyard.net (Postfix) with ESMTPA id E6C561993; Wed, 1 Jun 2016 11:27:04 -0500 (CDT) Received: by t430.minyard.net (Postfix, from userid 1000) id 249B1300522; Wed, 1 Jun 2016 11:27:02 -0500 (CDT) From: minyard@acm.org To: Igor Mammedov , "Michael S . Tsirkin" , Paolo Bonzini , qemu-devel@nongnu.org, minyard@acm.org, cminyard@mvista.com Date: Wed, 1 Jun 2016 11:26:54 -0500 Message-Id: <1464798420-12018-2-git-send-email-minyard@acm.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1464798420-12018-1-git-send-email-minyard@acm.org> References: <1464798420-12018-1-git-send-email-minyard@acm.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400e:c00::243 Subject: [Qemu-devel] [PATCH v2 1/7] i2c: Fix the PM SMBus driver so it actually works correctly X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" From: Corey Minyard The PM SMBus driver really just didn't work. This patch fixes it to be fairly hardware compliant with the actual hardware. Plus it adds interrupts and working block transfers. Signed-off-by: Corey Minyard --- hw/i2c/pm_smbus.c | 212 +++++++++++++++++++++++++++++++++++++++------- hw/i2c/smbus.c | 25 ++++-- hw/i2c/smbus_ich9.c | 28 +++++- include/hw/i2c/pm_smbus.h | 23 ++++- include/hw/i2c/smbus.h | 5 +- 5 files changed, 245 insertions(+), 48 deletions(-) -- 2.7.4 diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 6fc3923..17d253f 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -23,8 +23,6 @@ #include "hw/i2c/pm_smbus.h" #include "hw/i2c/smbus.h" -/* no save/load? */ - #define SMBHSTSTS 0x00 #define SMBHSTCNT 0x02 #define SMBHSTCMD 0x03 @@ -32,23 +30,42 @@ #define SMBHSTDAT0 0x05 #define SMBHSTDAT1 0x06 #define SMBBLKDAT 0x07 +#define SMBAUXCTL 0x0d -#define STS_HOST_BUSY (1) -#define STS_INTR (1<<1) -#define STS_DEV_ERR (1<<2) -#define STS_BUS_ERR (1<<3) -#define STS_FAILED (1<<4) -#define STS_SMBALERT (1<<5) -#define STS_INUSE_STS (1<<6) -#define STS_BYTE_DONE (1<<7) +#define STS_HOST_BUSY (1 << 0) +#define STS_INTR (1 << 1) +#define STS_DEV_ERR (1 << 2) +#define STS_BUS_ERR (1 << 3) +#define STS_FAILED (1 << 4) +#define STS_SMBALERT (1 << 5) +#define STS_INUSE_STS (1 << 6) +#define STS_BYTE_DONE (1 << 7) /* Signs of successfully transaction end : * ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR ) */ -//#define DEBUG +#define CTL_INTREN (1 << 0) +#define CTL_KILL (1 << 1) +#define CTL_LAST_BYTE (1 << 5) +#define CTL_START (1 << 6) +#define CTL_PEC_EN (1 << 7) + +#define PROT_QUICK 0 +#define PROT_BYTE 1 +#define PROT_BYTE_DATA 2 +#define PROT_WORD_DATA 3 +#define PROT_PROC_CALL 4 +#define PROT_BLOCK_DATA 5 +#define PROT_I2C_BLOCK_DATA 6 + +#define AUX_PEC (1 << 0) +#define AUX_BLK (1 << 1) +#define AUX_MASK 0x3 + +/*#define DEBUG*/ #ifdef DEBUG -# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +# define SMBUS_DPRINTF(format, ...) fprintf(stderr, format, ## __VA_ARGS__) #else # define SMBUS_DPRINTF(format, ...) do { } while (0) #endif @@ -61,6 +78,7 @@ static void smb_transaction(PMSMBus *s) uint8_t cmd = s->smb_cmd; uint8_t addr = s->smb_addr >> 1; I2CBus *bus = s->smbus; + bool i2c_enable = s->i2c_enable; int ret; SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); @@ -68,11 +86,12 @@ static void smb_transaction(PMSMBus *s) if ((s->smb_stat & STS_DEV_ERR) != 0) { goto error; } + switch(prot) { - case 0x0: + case PROT_QUICK: ret = smbus_quick_command(bus, addr, read); goto done; - case 0x1: + case PROT_BYTE: if (read) { ret = smbus_receive_byte(bus, addr); goto data8; @@ -80,7 +99,7 @@ static void smb_transaction(PMSMBus *s) ret = smbus_send_byte(bus, addr, cmd); goto done; } - case 0x2: + case PROT_BYTE_DATA: if (read) { ret = smbus_read_byte(bus, addr, cmd); goto data8; @@ -89,22 +108,58 @@ static void smb_transaction(PMSMBus *s) goto done; } break; - case 0x3: + case PROT_WORD_DATA: if (read) { ret = smbus_read_word(bus, addr, cmd); goto data16; } else { - ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); + ret = smbus_write_word(bus, addr, cmd, + (s->smb_data1 << 8) | s->smb_data0); goto done; } break; - case 0x5: + case PROT_I2C_BLOCK_DATA: + cmd = s->smb_data1; + if (s->smb_ctl & CTL_LAST_BYTE) { + s->smb_data0 = 1; + } else { + s->smb_data0 = PM_SMBUS_MAX_MSG_SIZE; + } + read = true; + i2c_enable = true; + /* Fallthrough */ + case PROT_BLOCK_DATA: if (read) { - ret = smbus_read_block(bus, addr, cmd, s->smb_data); - goto data8; + ret = smbus_read_block(bus, addr, cmd, s->smb_data, + sizeof(s->smb_data), !i2c_enable); + s->smb_index = 0; + s->op_done = false; + if (s->smb_auxctl & AUX_BLK) { + s->smb_stat |= STS_INTR; + } else { + s->smb_stat |= STS_HOST_BUSY; + } + goto datablk; } else { - ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); - goto done; + if (s->smb_auxctl & AUX_BLK || s->smb_index == s->smb_data0) { + if (s->smb_index != s->smb_data0) { + s->smb_index = 0; + goto error; + } + /* Data is already all written to the queue, just do + the operation. */ + ret = smbus_write_block(bus, addr, cmd, s->smb_data, + s->smb_data0, !i2c_enable); + s->op_done = true; + s->smb_index = 0; + s->smb_stat |= STS_INTR; + s->smb_stat &= ~STS_HOST_BUSY; + } else { + s->op_done = false; + s->smb_stat |= STS_HOST_BUSY; + ret = 0; + } + goto doneblk; } break; default: @@ -128,11 +183,27 @@ done: } s->smb_stat |= STS_BYTE_DONE | STS_INTR; return; +datablk: + if (ret < 0) { + goto error; + } + s->smb_data0 = ret; +doneblk: + if (ret < 0) { + goto error; + } + s->smb_stat |= STS_BYTE_DONE; + return; error: s->smb_stat |= STS_DEV_ERR; return; +} +static bool +smb_irq_value(PMSMBus *s) +{ + return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN); } static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, @@ -140,17 +211,30 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, { PMSMBus *s = opaque; - SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx - " val=0x%02" PRIx64 "\n", addr, val); + SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "\n", + addr, val); switch(addr) { case SMBHSTSTS: - s->smb_stat = (~(val & 0xff)) & s->smb_stat; - s->smb_index = 0; + s->smb_stat &= ~(val & ~STS_HOST_BUSY); + if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) { + s->smb_stat |= STS_BYTE_DONE; + } break; case SMBHSTCNT: s->smb_ctl = val; - if (val & 0x40) + if (s->smb_ctl & CTL_START) { + if (!s->op_done) { + s->smb_index = 0; + s->op_done = true; + } smb_transaction(s); + } + if (s->smb_ctl & CTL_KILL) { + s->op_done = true; + s->smb_index = 0; + s->smb_stat |= STS_FAILED; + s->smb_stat &= ~STS_HOST_BUSY; + } break; case SMBHSTCMD: s->smb_cmd = val; @@ -165,13 +249,28 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, s->smb_data1 = val; break; case SMBBLKDAT: - s->smb_data[s->smb_index++] = val; - if (s->smb_index > 31) + if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { s->smb_index = 0; + } + s->smb_data[s->smb_index++] = val; + if (!(s->smb_auxctl & AUX_BLK) && s->smb_ctl & CTL_START && + !s->op_done && s->smb_index == s->smb_data0) { + smb_transaction(s); + s->op_done = true; + s->smb_stat |= STS_INTR; + s->smb_stat &= ~STS_HOST_BUSY; + } + break; + case SMBAUXCTL: + s->smb_auxctl = val & AUX_MASK; break; default: break; } + + if (s->set_irq) { + s->set_irq(s, smb_irq_value(s)); + } } static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) @@ -184,7 +283,6 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) val = s->smb_stat; break; case SMBHSTCNT: - s->smb_index = 0; val = s->smb_ctl & 0x1f; break; case SMBHSTCMD: @@ -200,18 +298,47 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) val = s->smb_data1; break; case SMBBLKDAT: + if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { + s->smb_index = 0; + } val = s->smb_data[s->smb_index++]; - if (s->smb_index > 31) + if (s->smb_ctl & CTL_START && !s->op_done && + s->smb_index == s->smb_data0) { + s->op_done = true; + s->smb_index = 0; + s->smb_stat &= ~STS_HOST_BUSY; + } + if (s->smb_ctl & CTL_LAST_BYTE) { + s->op_done = true; s->smb_index = 0; + s->smb_stat |= STS_INTR; + s->smb_stat &= ~STS_HOST_BUSY; + } + break; + case SMBAUXCTL: + val = s->smb_auxctl; break; default: val = 0; break; } - SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", addr, val); + SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", + addr, val); + + if (s->set_irq) { + s->set_irq(s, smb_irq_value(s)); + } + return val; } +static void pm_smbus_reset(PMSMBus *s) +{ + s->op_done = true; + s->smb_index = 0; + s->smb_stat = 0; +} + static const MemoryRegionOps pm_smbus_ops = { .read = smb_ioport_readb, .write = smb_ioport_writeb, @@ -220,8 +347,29 @@ static const MemoryRegionOps pm_smbus_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +const VMStateDescription pmsmb_vmstate = { + .name = "pmsmb", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(smb_stat, PMSMBus), + VMSTATE_UINT8(smb_ctl, PMSMBus), + VMSTATE_UINT8(smb_cmd, PMSMBus), + VMSTATE_UINT8(smb_addr, PMSMBus), + VMSTATE_UINT8(smb_data0, PMSMBus), + VMSTATE_UINT8(smb_data1, PMSMBus), + VMSTATE_VBUFFER_UINT32(smb_data, PMSMBus, 1, NULL, 0, smb_index), + VMSTATE_UINT8(smb_auxctl, PMSMBus), + VMSTATE_BOOL(i2c_enable, PMSMBus), + VMSTATE_BOOL(op_done, PMSMBus), + VMSTATE_END_OF_LIST() + } +}; + void pm_smbus_init(DeviceState *parent, PMSMBus *smb) { + smb->op_done = true; + smb->reset = pm_smbus_reset; smb->smbus = i2c_init_bus(parent, "i2c"); memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb, "pm-smbus", 64); diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c index 3979b3d..c984bd7 100644 --- a/hw/i2c/smbus.c +++ b/hw/i2c/smbus.c @@ -293,9 +293,10 @@ int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) return 0; } -int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) +int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, + int len, bool recv_len) { - int len; + int rlen; int i; if (i2c_start_transfer(bus, addr, 0)) { @@ -303,20 +304,24 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) } i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); - len = i2c_recv(bus); - if (len > 32) { - len = 0; + if (recv_len) { + rlen = i2c_recv(bus); + } else { + rlen = len; } - for (i = 0; i < len; i++) { + if (rlen > len) { + rlen = 0; + } + for (i = 0; i < rlen; i++) { data[i] = i2c_recv(bus); } i2c_nack(bus); i2c_end_transfer(bus); - return len; + return rlen; } int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len) + int len, bool send_len) { int i; @@ -327,7 +332,9 @@ int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, return -1; } i2c_send(bus, command); - i2c_send(bus, len); + if (send_len) { + i2c_send(bus, len); + } for (i = 0; i < len; i++) { i2c_send(bus, data[i]); } diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index 498f03e..a01cb92 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -42,6 +42,8 @@ typedef struct ICH9SMBState { PCIDevice dev; + bool irq_enabled; + PMSMBus smb; } ICH9SMBState; @@ -50,7 +52,9 @@ static const VMStateDescription vmstate_ich9_smbus = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState), + VMSTATE_PCI_DEVICE(dev, ICH9SMBState), + VMSTATE_BOOL(irq_enabled, ICH9SMBState), + VMSTATE_STRUCT(smb, ICH9SMBState, 1, pmsmb_vmstate, struct PMSMBus), VMSTATE_END_OF_LIST() } }; @@ -63,12 +67,16 @@ static void ich9_smbus_write_config(PCIDevice *d, uint32_t address, pci_default_write_config(d, address, val, len); if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) { uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC]; - if ((hostc & ICH9_SMB_HOSTC_HST_EN) && - !(hostc & ICH9_SMB_HOSTC_I2C_EN)) { + if (hostc & ICH9_SMB_HOSTC_HST_EN) { memory_region_set_enabled(&s->smb.io, true); } else { memory_region_set_enabled(&s->smb.io, false); } + s->smb.i2c_enable = (hostc & ICH9_SMB_HOSTC_I2C_EN) != 0; + if (hostc & ICH9_SMB_HOSTC_SSRESET) { + s->smb.reset(&s->smb); + s->dev.config[ICH9_SMB_HOSTC] &= ~ICH9_SMB_HOSTC_SSRESET; + } } } @@ -107,11 +115,25 @@ static void ich9_smb_class_init(ObjectClass *klass, void *data) dc->cannot_instantiate_with_device_add_yet = true; } +static void ich9_smb_set_irq(PMSMBus *pmsmb, bool enabled) +{ + ICH9SMBState *s = pmsmb->opaque; + + if (enabled == s->irq_enabled) { + return; + } + + s->irq_enabled = enabled; + pci_set_irq(&s->dev, enabled); +} + I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base) { PCIDevice *d = pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE); ICH9SMBState *s = ICH9_SMB_DEVICE(d); + s->smb.set_irq = ich9_smb_set_irq; + s->smb.opaque = s; return s->smb.smbus; } diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h index 926603f..bfe740a 100644 --- a/include/hw/i2c/pm_smbus.h +++ b/include/hw/i2c/pm_smbus.h @@ -1,6 +1,8 @@ #ifndef PM_SMBUS_H #define PM_SMBUS_H +#define PM_SMBUS_MAX_MSG_SIZE 32 + typedef struct PMSMBus { I2CBus *smbus; MemoryRegion io; @@ -11,10 +13,27 @@ typedef struct PMSMBus { uint8_t smb_addr; uint8_t smb_data0; uint8_t smb_data1; - uint8_t smb_data[32]; - uint8_t smb_index; + uint8_t smb_data[PM_SMBUS_MAX_MSG_SIZE]; + uint8_t smb_auxctl; + uint32_t smb_index; + + /* Set by pm_smbus.c */ + void (*reset)(struct PMSMBus *s); + + /* Set by the user. */ + bool i2c_enable; + void (*set_irq)(struct PMSMBus *s, bool enabled); + void *opaque; + + /* Internally used by pm_smbus. */ + + /* Set on block transfers after the last byte has been read, so the + INTR bit can be set at the right time. */ + bool op_done; } PMSMBus; void pm_smbus_init(DeviceState *parent, PMSMBus *smb); +extern const VMStateDescription pmsmb_vmstate; + #endif /* !PM_SMBUS_H */ diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h index 544bbc1..1270691 100644 --- a/include/hw/i2c/smbus.h +++ b/include/hw/i2c/smbus.h @@ -73,9 +73,10 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command); int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data); int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command); int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data); -int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data); +int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, + int len, bool recv_len); int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len); + int len, bool send_len); void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int size);