[U-Boot] [PATCH] i2c: intel_i2c: SMBus driver PCI addition (e.g. BayTrail)

This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de --- Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Thanks, Stefan
arch/x86/include/asm/arch-ivybridge/pch.h | 26 --- drivers/i2c/intel_i2c.c | 290 ++++++++++++++++++++++++++++-- 2 files changed, 278 insertions(+), 38 deletions(-)
diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h index 4725250..9c51f63 100644 --- a/arch/x86/include/asm/arch-ivybridge/pch.h +++ b/arch/x86/include/asm/arch-ivybridge/pch.h @@ -134,32 +134,6 @@ #define SATA_IOBP_SP0G3IR 0xea000151 #define SATA_IOBP_SP1G3IR 0xea000051
-/* PCI Configuration Space (D31:F3): SMBus */ -#define PCH_SMBUS_DEV PCI_BDF(0, 0x1f, 3) -#define SMB_BASE 0x20 -#define HOSTC 0x40 -#define SMB_RCV_SLVA 0x09 - -/* HOSTC bits */ -#define I2C_EN (1 << 2) -#define SMB_SMI_EN (1 << 1) -#define HST_EN (1 << 0) - -/* SMBus I/O bits. */ -#define SMBHSTSTAT 0x0 -#define SMBHSTCTL 0x2 -#define SMBHSTCMD 0x3 -#define SMBXMITADD 0x4 -#define SMBHSTDAT0 0x5 -#define SMBHSTDAT1 0x6 -#define SMBBLKDAT 0x7 -#define SMBTRNSADD 0x9 -#define SMBSLVDATA 0xa -#define SMLINK_PIN_CTL 0xe -#define SMBUS_PIN_CTL 0xf - -#define SMBUS_TIMEOUT (10 * 1000 * 100) - #define VCH 0x0000 /* 32bit */ #define VCAP1 0x0004 /* 32bit */ #define VCAP2 0x0008 /* 32bit */ diff --git a/drivers/i2c/intel_i2c.c b/drivers/i2c/intel_i2c.c index 3d777ff..8b63916 100644 --- a/drivers/i2c/intel_i2c.c +++ b/drivers/i2c/intel_i2c.c @@ -2,45 +2,263 @@ * Copyright (c) 2015 Google, Inc * Written by Simon Glass sjg@chromium.org * + * SMBus block read/write support added by Stefan Roese: + * Copyright (C) 2016 Stefan Roese sr@denx.de + * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <dm.h> #include <i2c.h> +#include <pci.h> #include <asm/io.h> +#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE #include <asm/arch/pch.h> +#endif + +/* PCI Configuration Space (D31:F3): SMBus */ +#define SMB_BASE 0x20 +#define HOSTC 0x40 +#define HST_EN (1 << 0) +#define SMB_RCV_SLVA 0x09 + +/* SMBus I/O bits. */ +#define SMBHSTSTAT 0x0 +#define SMBHSTCTL 0x2 +#define SMBHSTCMD 0x3 +#define SMBXMITADD 0x4 +#define SMBHSTDAT0 0x5 +#define SMBHSTDAT1 0x6 +#define SMBBLKDAT 0x7 +#define SMBTRNSADD 0x9 +#define SMBSLVDATA 0xa +#define SMBAUXCTL 0xd +#define SMLINK_PIN_CTL 0xe +#define SMBUS_PIN_CTL 0xf + +/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE 0x80 +#define SMBHSTSTS_INUSE_STS 0x40 +#define SMBHSTSTS_SMBALERT_STS 0x20 +#define SMBHSTSTS_FAILED 0x10 +#define SMBHSTSTS_BUS_ERR 0x08 +#define SMBHSTSTS_DEV_ERR 0x04 +#define SMBHSTSTS_INTR 0x02 +#define SMBHSTSTS_HOST_BUSY 0x01 + +/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN 0x01 +#define SMBHSTCNT_KILL 0x02 +#define SMBHSTCNT_LAST_BYTE 0x20 +#define SMBHSTCNT_START 0x40 +#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */ + +/* Auxiliary control register bits, ICH4+ only */ +#define SMBAUXCTL_CRC 1 +#define SMBAUXCTL_E32B 2 + +#define SMBUS_TIMEOUT 100 /* 100 ms */ + +struct intel_i2c { + u32 base; + int running; +}; + +static int smbus_wait_until_ready(u32 base) +{ + unsigned long ts; + u8 byte; + + ts = get_timer(0); + do { + byte = inb(base + SMBHSTSTAT); + if (!(byte & 1)) + return 0; + } while (get_timer(ts) < SMBUS_TIMEOUT); + + return -ETIMEDOUT; +} + +static int smbus_wait_until_done(u32 base) +{ + unsigned long ts; + u8 byte; + + ts = get_timer(0); + do { + byte = inb(base + SMBHSTSTAT); + if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0)) + return 0; + } while (get_timer(ts) < SMBUS_TIMEOUT); + + return -ETIMEDOUT; +} + +static int smbus_block_read(u32 base, u8 dev, u8 *buffer, + int offset, int len) +{ + u8 buf_temp[32]; + int count; + int i; + + debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n", + __func__, __LINE__, dev, offset, len); + if (smbus_wait_until_ready(base) < 0) + return -ETIMEDOUT; + + /* Setup transaction */ + + /* Reset the data buffer index */ + inb(base + SMBHSTCTL); + + /* Set the device I'm talking too */ + outb(((dev & 0x7f) << 1) | 1, base + SMBXMITADD); + /* Set the command/address... */ + outb(offset & 0xff, base + SMBHSTCMD); + /* Set up for a block read */ + outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2), + (base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT); + + /* Start the command */ + outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL); + + /* Poll for transaction completion */ + if (smbus_wait_until_done(base) < 0) { + printf("SMBUS read transaction timeout (dev=0x%x)\n", dev); + return -ETIMEDOUT; + } + + count = inb(base + SMBHSTDAT0); + debug("%s (%d): count=%d (len=%d)\n", __func__, __LINE__, count, len); + if (count == 0) { + debug("ERROR: len=0 on read\n"); + return -EIO; + } + + if (count < len) { + debug("ERROR: too few bytes read\n"); + return -EIO; + } + + /* Read all available bytes from buffer */ + for (i = 0; i < count; i++) + buf_temp[i] = inb(base + SMBBLKDAT); + + memcpy(buffer, buf_temp, len); + + /* Return results of transaction */ + if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR)) + return -EIO; + + return 0; +} + +static int smbus_block_write(u32 base, u8 dev, u8 *buffer, + int offset, int len) +{ + int i;
-int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) + debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n", + __func__, __LINE__, dev, offset, len); + if (smbus_wait_until_ready(base) < 0) + return -ETIMEDOUT; + + /* Setup transaction */ + /* Set the device I'm talking too */ + outb(((dev & 0x7f) << 1) & ~0x01, base + SMBXMITADD); + /* Set the command/address... */ + outb(offset, base + SMBHSTCMD); + /* Set up for a block write */ + outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2), + (base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT); + + /* Write count in DAT0 register */ + outb(len, base + SMBHSTDAT0); + + /* Write data bytes... */ + for (i = 0; i < len; i++) + outb(*buffer++, base + SMBBLKDAT); + + /* Start the command */ + outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL); + + /* Poll for transaction completion */ + if (smbus_wait_until_done(base) < 0) { + printf("SMBUS write transaction timeout (dev=0x%x)\n", dev); + return -ETIMEDOUT; + } + + /* Return results of transaction */ + if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR)) + return -EIO; + + return 0; +} + +static int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) { - return -ENOSYS; + struct intel_i2c *i2c = dev_get_priv(bus); + struct i2c_msg *dmsg, *omsg, dummy; + + debug("i2c_xfer: %d messages\n", nmsgs); + + memset(&dummy, 0, sizeof(struct i2c_msg)); + + /* + * We expect either two messages (one with an offset and one with the + * actucal data) or one message (just data) + */ + if (nmsgs > 2 || nmsgs == 0) { + debug("%s: Only one or two messages are supported", __func__); + return -EIO; + } + + omsg = nmsgs == 1 ? &dummy : msg; + dmsg = nmsgs == 1 ? msg : msg + 1; + + if (dmsg->flags & I2C_M_RD) + return smbus_block_read(i2c->base, dmsg->addr, &dmsg->buf[0], + omsg->buf[0], dmsg->len); + else + return smbus_block_write(i2c->base, dmsg->addr, &dmsg->buf[1], + dmsg->buf[0], dmsg->len - 1); }
-int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr, uint chip_flags) +static int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) { - return -ENOSYS; + struct intel_i2c *i2c = dev_get_priv(bus); + u8 buf[4]; + + return smbus_block_read(i2c->base, chip_addr, buf, 0, 1); }
-int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { return 0; }
static int intel_i2c_probe(struct udevice *dev) { + struct intel_i2c *priv = dev_get_priv(dev); + u32 base; + +#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE + /* Handle ivybridge setup code */ + priv->base = SMBUS_IO_BASE; + base = SMBUS_IO_BASE; + /* - * So far this is just setup code for ivybridge SMbus. When we have - * a full I2C driver this may need to be moved, generalised or made - * dependant on a particular compatible string. - * * Set SMBus I/O base */ dm_pci_write_config32(dev, SMB_BASE, SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
- /* Set SMBus enable. */ - dm_pci_write_config8(dev, HOSTC, HST_EN); - /* Set SMBus I/O space enable. */ dm_pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
@@ -50,6 +268,44 @@ static int intel_i2c_probe(struct udevice *dev) /* Clear any lingering errors, so transactions can run. */ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); debug("SMBus controller enabled\n"); +#else + /* Save base address from PCI BAR */ + priv->base = (u32)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4, + PCI_REGION_IO); + base = priv->base; +#endif + + /* Set SMBus enable. */ + dm_pci_write_config8(dev, HOSTC, HST_EN); + + /* Disable interrupts */ + outb(inb(base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, base + SMBHSTCTL); + + /* Set 32-byte data buffer mode */ + outb(inb(base + SMBAUXCTL) | SMBAUXCTL_E32B, base + SMBAUXCTL); + + return 0; +} + +static int intel_i2c_bind(struct udevice *dev) +{ + static int num_cards; + char name[20]; + + /* Create a unique device name for PCI type devices */ + if (device_is_on_pci_bus(dev)) { + /* + * ToDo: + * Setting req_seq in the driver is probably not recommended. + * But without a DT alias the number is not configured. And + * using this driver is impossible for PCIe I2C devices. + * This can be removed, once a better (correct) way for this + * is found and implemented. + */ + dev->req_seq = num_cards; + sprintf(name, "intel_i2c#%u", num_cards++); + device_set_name(dev, name); + }
return 0; } @@ -71,5 +327,15 @@ U_BOOT_DRIVER(intel_i2c) = { .of_match = intel_i2c_ids, .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), .ops = &intel_i2c_ops, + .priv_auto_alloc_size = sizeof(struct intel_i2c), + .bind = intel_i2c_bind, .probe = intel_i2c_probe, }; + +static struct pci_device_id intel_smbus_pci_supported[] = { + /* Intel BayTrail SMBus on the PCI bus */ + { PCI_VDEVICE(INTEL, 0x0f12) }, + {}, +}; + +U_BOOT_PCI_DEVICE(intel_i2c, intel_smbus_pci_supported);

Hi Simon,
On Tue, Jun 28, 2016 at 9:44 PM, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Can you test this patch on Ivybridge to see if it breaks anything? Is SMBus used on Ivybridge for the memory initialization (eg: reading SPD?)
Regards, Bin

Simon, Heiko,
On Tue, Jul 12, 2016 at 1:22 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Tue, Jun 28, 2016 at 9:44 PM, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Can you test this patch on Ivybridge to see if it breaks anything? Is SMBus used on Ivybridge for the memory initialization (eg: reading SPD?)
Do you have any review comments before it's applied? I believe this needs to be tested on Ivybridge at least.
Regards, Bin

Hi Stefan,
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
Thanks, Stefan
arch/x86/include/asm/arch-ivybridge/pch.h | 26 --- drivers/i2c/intel_i2c.c | 290 ++++++++++++++++++++++++++++-- 2 files changed, 278 insertions(+), 38 deletions(-)
diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h index 4725250..9c51f63 100644 --- a/arch/x86/include/asm/arch-ivybridge/pch.h +++ b/arch/x86/include/asm/arch-ivybridge/pch.h @@ -134,32 +134,6 @@ #define SATA_IOBP_SP0G3IR 0xea000151 #define SATA_IOBP_SP1G3IR 0xea000051
-/* PCI Configuration Space (D31:F3): SMBus */ -#define PCH_SMBUS_DEV PCI_BDF(0, 0x1f, 3) -#define SMB_BASE 0x20 -#define HOSTC 0x40 -#define SMB_RCV_SLVA 0x09
-/* HOSTC bits */ -#define I2C_EN (1 << 2) -#define SMB_SMI_EN (1 << 1) -#define HST_EN (1 << 0)
-/* SMBus I/O bits. */ -#define SMBHSTSTAT 0x0 -#define SMBHSTCTL 0x2 -#define SMBHSTCMD 0x3 -#define SMBXMITADD 0x4 -#define SMBHSTDAT0 0x5 -#define SMBHSTDAT1 0x6 -#define SMBBLKDAT 0x7 -#define SMBTRNSADD 0x9 -#define SMBSLVDATA 0xa -#define SMLINK_PIN_CTL 0xe -#define SMBUS_PIN_CTL 0xf
-#define SMBUS_TIMEOUT (10 * 1000 * 100)
#define VCH 0x0000 /* 32bit */ #define VCAP1 0x0004 /* 32bit */ #define VCAP2 0x0008 /* 32bit */ diff --git a/drivers/i2c/intel_i2c.c b/drivers/i2c/intel_i2c.c index 3d777ff..8b63916 100644 --- a/drivers/i2c/intel_i2c.c +++ b/drivers/i2c/intel_i2c.c @@ -2,45 +2,263 @@
- Copyright (c) 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SMBus block read/write support added by Stefan Roese:
- Copyright (C) 2016 Stefan Roese sr@denx.de
*/
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <dm.h> #include <i2c.h> +#include <pci.h> #include <asm/io.h> +#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE
We should avoid machine-specific #ifdefs in the driver.
#include <asm/arch/pch.h> +#endif
+/* PCI Configuration Space (D31:F3): SMBus */ +#define SMB_BASE 0x20 +#define HOSTC 0x40 +#define HST_EN (1 << 0) +#define SMB_RCV_SLVA 0x09
+/* SMBus I/O bits. */ +#define SMBHSTSTAT 0x0 +#define SMBHSTCTL 0x2 +#define SMBHSTCMD 0x3 +#define SMBXMITADD 0x4 +#define SMBHSTDAT0 0x5 +#define SMBHSTDAT1 0x6 +#define SMBBLKDAT 0x7 +#define SMBTRNSADD 0x9 +#define SMBSLVDATA 0xa +#define SMBAUXCTL 0xd +#define SMLINK_PIN_CTL 0xe +#define SMBUS_PIN_CTL 0xf
+/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE 0x80 +#define SMBHSTSTS_INUSE_STS 0x40 +#define SMBHSTSTS_SMBALERT_STS 0x20 +#define SMBHSTSTS_FAILED 0x10 +#define SMBHSTSTS_BUS_ERR 0x08 +#define SMBHSTSTS_DEV_ERR 0x04 +#define SMBHSTSTS_INTR 0x02 +#define SMBHSTSTS_HOST_BUSY 0x01
+/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN 0x01 +#define SMBHSTCNT_KILL 0x02 +#define SMBHSTCNT_LAST_BYTE 0x20 +#define SMBHSTCNT_START 0x40 +#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
+/* Auxiliary control register bits, ICH4+ only */ +#define SMBAUXCTL_CRC 1 +#define SMBAUXCTL_E32B 2
+#define SMBUS_TIMEOUT 100 /* 100 ms */
+struct intel_i2c {
u32 base;
int running;
+};
+static int smbus_wait_until_ready(u32 base) +{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!(byte & 1))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
+}
+static int smbus_wait_until_done(u32 base) +{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
+}
+static int smbus_block_read(u32 base, u8 dev, u8 *buffer,
int offset, int len)
+{
u8 buf_temp[32];
int count;
int i;
debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
__func__, __LINE__, dev, offset, len);
if (smbus_wait_until_ready(base) < 0)
return -ETIMEDOUT;
/* Setup transaction */
/* Reset the data buffer index */
inb(base + SMBHSTCTL);
/* Set the device I'm talking too */
outb(((dev & 0x7f) << 1) | 1, base + SMBXMITADD);
/* Set the command/address... */
outb(offset & 0xff, base + SMBHSTCMD);
/* Set up for a block read */
outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
(base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
/* Start the command */
outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(base) < 0) {
printf("SMBUS read transaction timeout (dev=0x%x)\n", dev);
return -ETIMEDOUT;
}
count = inb(base + SMBHSTDAT0);
debug("%s (%d): count=%d (len=%d)\n", __func__, __LINE__, count, len);
if (count == 0) {
debug("ERROR: len=0 on read\n");
return -EIO;
}
if (count < len) {
debug("ERROR: too few bytes read\n");
return -EIO;
}
/* Read all available bytes from buffer */
for (i = 0; i < count; i++)
buf_temp[i] = inb(base + SMBBLKDAT);
memcpy(buffer, buf_temp, len);
/* Return results of transaction */
if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
return -EIO;
return 0;
+}
+static int smbus_block_write(u32 base, u8 dev, u8 *buffer,
int offset, int len)
+{
int i;
-int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
__func__, __LINE__, dev, offset, len);
if (smbus_wait_until_ready(base) < 0)
return -ETIMEDOUT;
/* Setup transaction */
/* Set the device I'm talking too */
outb(((dev & 0x7f) << 1) & ~0x01, base + SMBXMITADD);
/* Set the command/address... */
outb(offset, base + SMBHSTCMD);
/* Set up for a block write */
outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
(base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
/* Write count in DAT0 register */
outb(len, base + SMBHSTDAT0);
/* Write data bytes... */
for (i = 0; i < len; i++)
outb(*buffer++, base + SMBBLKDAT);
/* Start the command */
outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(base) < 0) {
printf("SMBUS write transaction timeout (dev=0x%x)\n", dev);
return -ETIMEDOUT;
}
/* Return results of transaction */
if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
return -EIO;
return 0;
+}
+static int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) {
return -ENOSYS;
struct intel_i2c *i2c = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
debug("i2c_xfer: %d messages\n", nmsgs);
memset(&dummy, 0, sizeof(struct i2c_msg));
/*
* We expect either two messages (one with an offset and one with the
* actucal data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported", __func__);
return -EIO;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return smbus_block_read(i2c->base, dmsg->addr, &dmsg->buf[0],
omsg->buf[0], dmsg->len);
else
return smbus_block_write(i2c->base, dmsg->addr, &dmsg->buf[1],
dmsg->buf[0], dmsg->len - 1);
}
-int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr, uint chip_flags) +static int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
return -ENOSYS;
struct intel_i2c *i2c = dev_get_priv(bus);
u8 buf[4];
return smbus_block_read(i2c->base, chip_addr, buf, 0, 1);
}
-int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { return 0; }
static int intel_i2c_probe(struct udevice *dev) {
struct intel_i2c *priv = dev_get_priv(dev);
u32 base;
+#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE
/* Handle ivybridge setup code */
priv->base = SMBUS_IO_BASE;
base = SMBUS_IO_BASE;
/*
* So far this is just setup code for ivybridge SMbus. When we have
* a full I2C driver this may need to be moved, generalised or made
* dependant on a particular compatible string.
* * Set SMBus I/O base */ dm_pci_write_config32(dev, SMB_BASE, SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
/* Set SMBus enable. */
dm_pci_write_config8(dev, HOSTC, HST_EN);
/* Set SMBus I/O space enable. */ dm_pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
@@ -50,6 +268,44 @@ static int intel_i2c_probe(struct udevice *dev) /* Clear any lingering errors, so transactions can run. */ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); debug("SMBus controller enabled\n");
Can this code go in the machine setup? If you want to call the pch driver you should use the ops in struct pch_ops, or add a new one.
+#else
/* Save base address from PCI BAR */
priv->base = (u32)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
PCI_REGION_IO);
base = priv->base;
+#endif
/* Set SMBus enable. */
dm_pci_write_config8(dev, HOSTC, HST_EN);
/* Disable interrupts */
outb(inb(base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, base + SMBHSTCTL);
/* Set 32-byte data buffer mode */
outb(inb(base + SMBAUXCTL) | SMBAUXCTL_E32B, base + SMBAUXCTL);
return 0;
+}
+static int intel_i2c_bind(struct udevice *dev) +{
static int num_cards;
char name[20];
/* Create a unique device name for PCI type devices */
if (device_is_on_pci_bus(dev)) {
/*
* ToDo:
* Setting req_seq in the driver is probably not recommended.
* But without a DT alias the number is not configured. And
* using this driver is impossible for PCIe I2C devices.
* This can be removed, once a better (correct) way for this
* is found and implemented.
*/
dev->req_seq = num_cards;
sprintf(name, "intel_i2c#%u", num_cards++);
device_set_name(dev, name);
} return 0;
} @@ -71,5 +327,15 @@ U_BOOT_DRIVER(intel_i2c) = { .of_match = intel_i2c_ids, .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), .ops = &intel_i2c_ops,
.priv_auto_alloc_size = sizeof(struct intel_i2c),
.bind = intel_i2c_bind, .probe = intel_i2c_probe,
};
+static struct pci_device_id intel_smbus_pci_supported[] = {
/* Intel BayTrail SMBus on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x0f12) },
{},
+};
+U_BOOT_PCI_DEVICE(intel_i2c, intel_smbus_pci_supported);
2.9.0
Regards, Simon

Hi Simon,
On 25.07.2016 04:07, Simon Glass wrote:
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
Thanks for checking. I'll try to find some time this week to look into this.
Thanks, Stefan

Hi Simon,
On 25.07.2016 04:07, Simon Glass wrote:
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
Hmmm, very strange.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
A general question:
Is the SMBus controller on Ivybridge also exported as PCI device? If yes, can't we just use the PCI code as done for BayTrail for this platform as well? And get rid of the platform specific stuff this way?
Could you send me the output of "pci 0 long" on this platform?
Thanks, Stefan

Simon, Stefan,
On Tue, Jul 26, 2016 at 8:13 PM, Stefan Roese sr@denx.de wrote:
Hi Simon,
On 25.07.2016 04:07, Simon Glass wrote:
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
Hmmm, very strange.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
A general question:
Is the SMBus controller on Ivybridge also exported as PCI device? If yes, can't we just use the PCI code as done for BayTrail for this platform as well? And get rid of the platform specific stuff this way?
Could you send me the output of "pci 0 long" on this platform?
Do you plan to get this I2C merged in this release? If so, please work this out .. I don't feel comfortable to apply this at present.
Regards, Bin

Hello Bin,
Am 05.08.2016 um 07:46 schrieb Bin Meng:
Simon, Stefan,
On Tue, Jul 26, 2016 at 8:13 PM, Stefan Roese sr@denx.de wrote:
Hi Simon,
On 25.07.2016 04:07, Simon Glass wrote:
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
Hmmm, very strange.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
A general question:
Is the SMBus controller on Ivybridge also exported as PCI device? If yes, can't we just use the PCI code as done for BayTrail for this platform as well? And get rid of the platform specific stuff this way?
Could you send me the output of "pci 0 long" on this platform?
Do you plan to get this I2C merged in this release? If so, please work this out .. I don't feel comfortable to apply this at present.
Full Ack.
bye, Heiko

On 05.08.2016 09:10, Heiko Schocher wrote:
Hello Bin,
Am 05.08.2016 um 07:46 schrieb Bin Meng:
Simon, Stefan,
On Tue, Jul 26, 2016 at 8:13 PM, Stefan Roese sr@denx.de wrote:
Hi Simon,
On 25.07.2016 04:07, Simon Glass wrote:
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
Hmmm, very strange.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
A general question:
Is the SMBus controller on Ivybridge also exported as PCI device? If yes, can't we just use the PCI code as done for BayTrail for this platform as well? And get rid of the platform specific stuff this way?
Could you send me the output of "pci 0 long" on this platform?
Do you plan to get this I2C merged in this release? If so, please work this out .. I don't feel comfortable to apply this at present.
Full Ack.
I really would like to see this SMBus support upstream. As other patches depend on this. Unfortunately I can't test on the Ivybridge platform. I talked with Simon on #irc some days ago and he "volunteered" (thanks again) to fix / debug this Ivybridge problem on his board - perhaps by moving to a PCI based probing there as well.
Simon, did you find the time to dig into this? Please let me know if there is something that I can do to help / assist you here.
Thanks, Stefan

Hi Stefan,
On 5 August 2016 at 01:18, Stefan Roese sr@denx.de wrote:
On 05.08.2016 09:10, Heiko Schocher wrote:
Hello Bin,
Am 05.08.2016 um 07:46 schrieb Bin Meng:
Simon, Stefan,
On Tue, Jul 26, 2016 at 8:13 PM, Stefan Roese sr@denx.de wrote:
Hi Simon,
On 25.07.2016 04:07, Simon Glass wrote:
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
Hmmm, very strange.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
A general question:
Is the SMBus controller on Ivybridge also exported as PCI device? If yes, can't we just use the PCI code as done for BayTrail for this platform as well? And get rid of the platform specific stuff this way?
Could you send me the output of "pci 0 long" on this platform?
Do you plan to get this I2C merged in this release? If so, please work this out .. I don't feel comfortable to apply this at present.
Full Ack.
I really would like to see this SMBus support upstream. As other patches depend on this. Unfortunately I can't test on the Ivybridge platform. I talked with Simon on #irc some days ago and he "volunteered" (thanks again) to fix / debug this Ivybridge problem on his board - perhaps by moving to a PCI based probing there as well.
Simon, did you find the time to dig into this? Please let me know if there is something that I can do to help / assist you here.
Thanks, Stefan
I found one problem, which is that intel_i2c_bind() writes to BSS before it is available. That fixes the crash. I sent a few patches for that and something else I found.
Also I don't think your code in intel_i2c_probe() is very different from the ivybridge code. SMB_BASE is the same as PCI_BASE_ADDRESS_4. So perhaps just drop the ivybridge code?
Here's the output you asked for.
=> pci 0 long Scanning PCI devices on bus 0
Found PCI device 00.00.00: vendor ID = 0x8086 device ID = 0x0154 command register ID = 0x0006 status register = 0x2090 revision ID = 0x09 class code = 0x06 (Bridge device) sub class code = 0x00 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.02.00: vendor ID = 0x8086 device ID = 0x0166 command register ID = 0x0007 status register = 0x0090 revision ID = 0x09 class code = 0x03 (Display controller) sub class code = 0x00 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0000004 base address 1 = 0x00000000 base address 2 = 0xd000000c base address 3 = 0x00000000 base address 4 = 0x00001001 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.16.00: vendor ID = 0x8086 device ID = 0x1e3a command register ID = 0x0006 status register = 0x0018 revision ID = 0x04 class code = 0x07 (Simple comm. controller) sub class code = 0x80 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x80 BIST = 0x00 base address 0 = 0xe0400004 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1a.00: vendor ID = 0x8086 device ID = 0x1e2d command register ID = 0x0006 status register = 0x0290 revision ID = 0x04 class code = 0x0c (Serial bus controller) sub class code = 0x03 programming interface = 0x20 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0400400 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x5000 sub system ID = 0x4813 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1d.00: vendor ID = 0x8086 device ID = 0x1e26 command register ID = 0x0006 status register = 0x0290 revision ID = 0x04 class code = 0x0c (Serial bus controller) sub class code = 0x03 programming interface = 0x20 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0400800 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x052b sub system ID = 0x00a4 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1f.00: vendor ID = 0x8086 device ID = 0x1e5d command register ID = 0x0007 status register = 0x0210 revision ID = 0x04 class code = 0x06 (Bridge device) sub class code = 0x01 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x80 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1f.02: vendor ID = 0x8086 device ID = 0x1e03 command register ID = 0x0007 status register = 0x02b0 revision ID = 0x04 class code = 0x01 (Mass storage controller) sub class code = 0x06 programming interface = 0x01 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0x00001041 base address 1 = 0x00001049 base address 2 = 0x00001051 base address 3 = 0x00001059 base address 4 = 0x00001061 base address 5 = 0xe0401000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1f.03: vendor ID = 0x8086 device ID = 0x1e22 command register ID = 0x0003 status register = 0x0280 revision ID = 0x04 class code = 0x0c (Serial bus controller) sub class code = 0x05 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0401804 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00001081 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x02 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.16.01: vendor ID = 0x8086 device ID = 0x1e3b command register ID = 0x0006 status register = 0x0018 revision ID = 0x04 class code = 0x07 (Simple comm. controller) sub class code = 0x80 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x80 BIST = 0x00 base address 0 = 0xe0401904 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1b.00: vendor ID = 0x8086 device ID = 0x1e20 command register ID = 0x0006 status register = 0x0010 revision ID = 0x04 class code = 0x04 (Multimedia device) sub class code = 0x03 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0404004 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1c.00: vendor ID = 0x8086 device ID = 0x1e10 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x01 subordinate bus number = 0x01 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe050 memory limit = 0xe040 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.01: vendor ID = 0x8086 device ID = 0x1e12 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x02 subordinate bus number = 0x02 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe050 memory limit = 0xe040 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.02: vendor ID = 0x8086 device ID = 0x1e14 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x03 subordinate bus number = 0x03 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x0000 memory base = 0xe050 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 bridge control = 0x0000
Found PCI device 00.1c.03: vendor ID = 0x8086 device ID = 0x1e16 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x04 subordinate bus number = 0x04 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.04: vendor ID = 0x8086 device ID = 0x1e18 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x05 subordinate bus number = 0x05 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.05: vendor ID = 0x8086 device ID = 0x1e1a command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x06 subordinate bus number = 0x06 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.06: vendor ID = 0x8086 device ID = 0x1e1c command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x07 subordinate bus number = 0x07 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.07: vendor ID = 0x8086 device ID = 0x1e1e command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x08 subordinate bus number = 0x08 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1e.00: vendor ID = 0x8086 device ID = 0x2448 command register ID = 0x0007 status register = 0x0010 revision ID = 0xa4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x01 cache line = 0x00 latency time = 0x00 header type = 0x01 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x09 subordinate bus number = 0x09 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2280 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1f.06: vendor ID = 0x8086 device ID = 0x1e24 command register ID = 0x0006 status register = 0x0010 revision ID = 0x04 class code = 0x11 (DSP) sub class code = 0x80 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0600004 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x03 min Grant = 0x00 max Latency = 0x00 =>
Here's what I get when I try it:
=> i2c dev 0 Setting bus to 0 here intel_i2c#0 SMBus controller enabled => i2c probe Valid chip addresses:smbus_block_read (107): dev=0x0 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x4 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x5 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x6 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x7 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x8 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x9 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xa offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xb offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xc offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xd offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xe offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xf offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x10 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x11 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x12 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x13 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x14 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x15 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x16 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x17 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x18 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x19 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1a offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1c offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1d offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1e offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1f offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x20 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x21 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x22 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x23 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x24 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x25 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x26 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x27 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x28 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x29 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2a offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2c offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2d offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2e offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2f offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x30 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x31 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x32 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x33 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x34 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x35 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x36 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x37 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x38 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x39 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3a offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3c offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3d offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3e offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3f offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x40 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x41 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x42 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x43 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x44 offs=0x0 len=0x1 smbus_block_read (136): count=255 (len=1) Invalid Opcode (Undefined Opcode) EIP: 0010:[<00000058>] EFLAGS: 00010283 Original EIP :[<52fae058>] EAX: c9fffff0 EBX: ffffffff ECX: 00000000 EDX: ffffff00 ESI: ffffffff EDI: 00000004 EBP: ffffffff ESP: acd48fdc DS: 0018 ES: 0018 FS: 0020 GS: 0018 SS: 0018 CR0: 00000033 CR2: 00000000 CR3: 00000000 CR4: 00000000 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Stack: 0xacd4901c : 0xffffffff 0xacd49018 : 0xffffffff 0xacd49014 : 0xffffffff 0xacd49010 : 0xffffffff 0xacd4900c : 0xffffffff 0xacd49008 : 0xffffffff 0xacd49004 : 0xffffffff 0xacd49000 : 0xffffffff 0xacd48ffc : 0xffffffff 0xacd48ff8 : 0xffffffff 0xacd48ff4 : 0xffffffff 0xacd48ff0 : 0xffffffff 0xacd48fec : 0xffffffff 0xacd48fe8 : 0xffffffff 0xacd48fe4 : 0xffffffff 0xacd48fe0 : 0xffffffff --->0xacd48fdc : 0x00000000 0xacd48fd8 : 0x00010283 0xacd48fd4 : 0x00000010 0xacd48fd0 : 0x00000058 ### ERROR ### Please RESET the board ###
Regards Simon

Hi Simon,
On 06.08.2016 05:36, Simon Glass wrote:
On 5 August 2016 at 01:18, Stefan Roese sr@denx.de wrote:
On 05.08.2016 09:10, Heiko Schocher wrote:
Hello Bin,
Am 05.08.2016 um 07:46 schrieb Bin Meng:
Simon, Stefan,
On Tue, Jul 26, 2016 at 8:13 PM, Stefan Roese sr@denx.de wrote:
Hi Simon,
On 25.07.2016 04:07, Simon Glass wrote:
On 28 June 2016 at 07:44, Stefan Roese sr@denx.de wrote: > > > This patch adds support for the SMBus block read/write functionality. > Other protocols like the SMBus quick command need to get added > if this is needed. > > This patch also removed the SMBus related defines from the Ivybridge > pch.h header. As they are integrated in this driver and should be > used from here. This change is added in this patch to avoid compile > breakage to keep the source git bisectable. > > Tested on a congatec BayTrail board to configure the SMSC2513 USB > hub. > > Signed-off-by: Stefan Roese sr@denx.de > Cc: Bin Meng bmeng.cn@gmail.com > Cc: Simon Glass sjg@chromium.org > Cc: Heiko Schocher hs@denx.de > --- > Simon, I'm not sure if this change breaks your Ivybridge targets > using the probe part of this driver. Could you please let me > know if this works? Or let me know what needs changes here?
Yes this breaks booting on link. Something odd is going on because the call to set up I2C in ivybridge's print_cpuinfo() returns a very strange error -726376.
Hmmm, very strange.
But I then enabled CONFIG_CMD_I2C and it boots. However 'i2c probe' produces a lot of errors like this:
ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1)
A general question:
Is the SMBus controller on Ivybridge also exported as PCI device? If yes, can't we just use the PCI code as done for BayTrail for this platform as well? And get rid of the platform specific stuff this way?
Could you send me the output of "pci 0 long" on this platform?
Do you plan to get this I2C merged in this release? If so, please work this out .. I don't feel comfortable to apply this at present.
Full Ack.
I really would like to see this SMBus support upstream. As other patches depend on this. Unfortunately I can't test on the Ivybridge platform. I talked with Simon on #irc some days ago and he "volunteered" (thanks again) to fix / debug this Ivybridge problem on his board - perhaps by moving to a PCI based probing there as well.
Simon, did you find the time to dig into this? Please let me know if there is something that I can do to help / assist you here.
Thanks, Stefan
I found one problem, which is that intel_i2c_bind() writes to BSS before it is available. That fixes the crash. I sent a few patches for that and something else I found.
Great, thanks!
Also I don't think your code in intel_i2c_probe() is very different from the ivybridge code. SMB_BASE is the same as PCI_BASE_ADDRESS_4. So perhaps just drop the ivybridge code?
Thats what I meant with PCI based probing. I will send a v2 of this patch out on Monday and will drop the Ivybrige code in this version. I'll also fix the crash below (thanks to George for spotting a problem here).
Thanks, Stefan
Here's the output you asked for.
=> pci 0 long Scanning PCI devices on bus 0
Found PCI device 00.00.00: vendor ID = 0x8086 device ID = 0x0154 command register ID = 0x0006 status register = 0x2090 revision ID = 0x09 class code = 0x06 (Bridge device) sub class code = 0x00 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.02.00: vendor ID = 0x8086 device ID = 0x0166 command register ID = 0x0007 status register = 0x0090 revision ID = 0x09 class code = 0x03 (Display controller) sub class code = 0x00 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0000004 base address 1 = 0x00000000 base address 2 = 0xd000000c base address 3 = 0x00000000 base address 4 = 0x00001001 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.16.00: vendor ID = 0x8086 device ID = 0x1e3a command register ID = 0x0006 status register = 0x0018 revision ID = 0x04 class code = 0x07 (Simple comm. controller) sub class code = 0x80 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x80 BIST = 0x00 base address 0 = 0xe0400004 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1a.00: vendor ID = 0x8086 device ID = 0x1e2d command register ID = 0x0006 status register = 0x0290 revision ID = 0x04 class code = 0x0c (Serial bus controller) sub class code = 0x03 programming interface = 0x20 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0400400 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x5000 sub system ID = 0x4813 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1d.00: vendor ID = 0x8086 device ID = 0x1e26 command register ID = 0x0006 status register = 0x0290 revision ID = 0x04 class code = 0x0c (Serial bus controller) sub class code = 0x03 programming interface = 0x20 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0400800 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x052b sub system ID = 0x00a4 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1f.00: vendor ID = 0x8086 device ID = 0x1e5d command register ID = 0x0007 status register = 0x0210 revision ID = 0x04 class code = 0x06 (Bridge device) sub class code = 0x01 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x80 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1f.02: vendor ID = 0x8086 device ID = 0x1e03 command register ID = 0x0007 status register = 0x02b0 revision ID = 0x04 class code = 0x01 (Mass storage controller) sub class code = 0x06 programming interface = 0x01 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0x00001041 base address 1 = 0x00001049 base address 2 = 0x00001051 base address 3 = 0x00001059 base address 4 = 0x00001061 base address 5 = 0xe0401000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1f.03: vendor ID = 0x8086 device ID = 0x1e22 command register ID = 0x0003 status register = 0x0280 revision ID = 0x04 class code = 0x0c (Serial bus controller) sub class code = 0x05 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0401804 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00001081 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x02 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.16.01: vendor ID = 0x8086 device ID = 0x1e3b command register ID = 0x0006 status register = 0x0018 revision ID = 0x04 class code = 0x07 (Simple comm. controller) sub class code = 0x80 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x80 BIST = 0x00 base address 0 = 0xe0401904 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1b.00: vendor ID = 0x8086 device ID = 0x1e20 command register ID = 0x0006 status register = 0x0010 revision ID = 0x04 class code = 0x04 (Multimedia device) sub class code = 0x03 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0404004 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 min Grant = 0x00 max Latency = 0x00
Found PCI device 00.1c.00: vendor ID = 0x8086 device ID = 0x1e10 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x01 subordinate bus number = 0x01 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe050 memory limit = 0xe040 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.01: vendor ID = 0x8086 device ID = 0x1e12 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x02 subordinate bus number = 0x02 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe050 memory limit = 0xe040 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.02: vendor ID = 0x8086 device ID = 0x1e14 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x03 subordinate bus number = 0x03 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x0000 memory base = 0xe050 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x01 bridge control = 0x0000
Found PCI device 00.1c.03: vendor ID = 0x8086 device ID = 0x1e16 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x04 subordinate bus number = 0x04 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.04: vendor ID = 0x8086 device ID = 0x1e18 command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x05 subordinate bus number = 0x05 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.05: vendor ID = 0x8086 device ID = 0x1e1a command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x06 subordinate bus number = 0x06 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.06: vendor ID = 0x8086 device ID = 0x1e1c command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x07 subordinate bus number = 0x07 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1c.07: vendor ID = 0x8086 device ID = 0x1e1e command register ID = 0x0007 status register = 0x0010 revision ID = 0xc4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x00 cache line = 0x08 latency time = 0x00 header type = 0x81 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x08 subordinate bus number = 0x08 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2000 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1e.00: vendor ID = 0x8086 device ID = 0x2448 command register ID = 0x0007 status register = 0x0010 revision ID = 0xa4 class code = 0x06 (Bridge device) sub class code = 0x04 programming interface = 0x01 cache line = 0x00 latency time = 0x00 header type = 0x01 BIST = 0x00 base address 0 = 0x00000000 base address 1 = 0x00000000 primary bus number = 0x00 secondary bus number = 0x09 subordinate bus number = 0x09 secondary latency timer = 0x00 IO base = 0x20 IO limit = 0x10 secondary status = 0x2280 memory base = 0xe060 memory limit = 0xe050 prefetch memory base = 0xe001 prefetch memory limit = 0xdff1 prefetch memory base upper = 0x00000000 prefetch memory limit upper = 0x00000000 IO base upper 16 bits = 0x0000 IO limit upper 16 bits = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x00 bridge control = 0x0000
Found PCI device 00.1f.06: vendor ID = 0x8086 device ID = 0x1e24 command register ID = 0x0006 status register = 0x0010 revision ID = 0x04 class code = 0x11 (DSP) sub class code = 0x80 programming interface = 0x00 cache line = 0x00 latency time = 0x00 header type = 0x00 BIST = 0x00 base address 0 = 0xe0600004 base address 1 = 0x00000000 base address 2 = 0x00000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x0000 sub system ID = 0x0000 expansion ROM base address = 0x00000000 interrupt line = 0x00 interrupt pin = 0x03 min Grant = 0x00 max Latency = 0x00 =>
Here's what I get when I try it:
=> i2c dev 0 Setting bus to 0 here intel_i2c#0 SMBus controller enabled => i2c probe Valid chip addresses:smbus_block_read (107): dev=0x0 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x4 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x5 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x6 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x7 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x8 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x9 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xa offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xb offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xc offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xd offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xe offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0xf offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x10 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x11 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x12 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x13 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x14 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x15 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x16 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x17 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x18 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x19 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1a offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1c offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1d offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1e offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x1f offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x20 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x21 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x22 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x23 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x24 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x25 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x26 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x27 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x28 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x29 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2a offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2c offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2d offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2e offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x2f offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x30 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x31 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x32 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x33 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x34 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x35 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x36 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x37 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x38 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x39 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3a offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3b offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3c offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3d offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3e offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x3f offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x40 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x41 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x42 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x43 offs=0x0 len=0x1 smbus_block_read (136): count=0 (len=1) ERROR: len=0 on read smbus_block_read (107): dev=0x44 offs=0x0 len=0x1 smbus_block_read (136): count=255 (len=1) Invalid Opcode (Undefined Opcode) EIP: 0010:[<00000058>] EFLAGS: 00010283 Original EIP :[<52fae058>] EAX: c9fffff0 EBX: ffffffff ECX: 00000000 EDX: ffffff00 ESI: ffffffff EDI: 00000004 EBP: ffffffff ESP: acd48fdc DS: 0018 ES: 0018 FS: 0020 GS: 0018 SS: 0018 CR0: 00000033 CR2: 00000000 CR3: 00000000 CR4: 00000000 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Stack: 0xacd4901c : 0xffffffff 0xacd49018 : 0xffffffff 0xacd49014 : 0xffffffff 0xacd49010 : 0xffffffff 0xacd4900c : 0xffffffff 0xacd49008 : 0xffffffff 0xacd49004 : 0xffffffff 0xacd49000 : 0xffffffff 0xacd48ffc : 0xffffffff 0xacd48ff8 : 0xffffffff 0xacd48ff4 : 0xffffffff 0xacd48ff0 : 0xffffffff 0xacd48fec : 0xffffffff 0xacd48fe8 : 0xffffffff 0xacd48fe4 : 0xffffffff 0xacd48fe0 : 0xffffffff --->0xacd48fdc : 0x00000000 0xacd48fd8 : 0x00010283 0xacd48fd4 : 0x00000010 0xacd48fd0 : 0x00000058 ### ERROR ### Please RESET the board ###
Regards Simon
Viele Grüße, Stefan

On Tue, Jun 28, 2016 at 8:44 AM, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Thanks, Stefan
arch/x86/include/asm/arch-ivybridge/pch.h | 26 --- drivers/i2c/intel_i2c.c | 290 ++++++++++++++++++++++++++++-- 2 files changed, 278 insertions(+), 38 deletions(-)
diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h index 4725250..9c51f63 100644 --- a/arch/x86/include/asm/arch-ivybridge/pch.h +++ b/arch/x86/include/asm/arch-ivybridge/pch.h @@ -134,32 +134,6 @@ #define SATA_IOBP_SP0G3IR 0xea000151 #define SATA_IOBP_SP1G3IR 0xea000051
-/* PCI Configuration Space (D31:F3): SMBus */ -#define PCH_SMBUS_DEV PCI_BDF(0, 0x1f, 3) -#define SMB_BASE 0x20 -#define HOSTC 0x40 -#define SMB_RCV_SLVA 0x09
-/* HOSTC bits */ -#define I2C_EN (1 << 2) -#define SMB_SMI_EN (1 << 1) -#define HST_EN (1 << 0)
-/* SMBus I/O bits. */ -#define SMBHSTSTAT 0x0 -#define SMBHSTCTL 0x2 -#define SMBHSTCMD 0x3 -#define SMBXMITADD 0x4 -#define SMBHSTDAT0 0x5 -#define SMBHSTDAT1 0x6 -#define SMBBLKDAT 0x7 -#define SMBTRNSADD 0x9 -#define SMBSLVDATA 0xa -#define SMLINK_PIN_CTL 0xe -#define SMBUS_PIN_CTL 0xf
-#define SMBUS_TIMEOUT (10 * 1000 * 100)
#define VCH 0x0000 /* 32bit */ #define VCAP1 0x0004 /* 32bit */ #define VCAP2 0x0008 /* 32bit */ diff --git a/drivers/i2c/intel_i2c.c b/drivers/i2c/intel_i2c.c index 3d777ff..8b63916 100644 --- a/drivers/i2c/intel_i2c.c +++ b/drivers/i2c/intel_i2c.c @@ -2,45 +2,263 @@
- Copyright (c) 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SMBus block read/write support added by Stefan Roese:
- Copyright (C) 2016 Stefan Roese sr@denx.de
*/
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <dm.h> #include <i2c.h> +#include <pci.h> #include <asm/io.h> +#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE #include <asm/arch/pch.h> +#endif
+/* PCI Configuration Space (D31:F3): SMBus */ +#define SMB_BASE 0x20 +#define HOSTC 0x40 +#define HST_EN (1 << 0) +#define SMB_RCV_SLVA 0x09
+/* SMBus I/O bits. */ +#define SMBHSTSTAT 0x0 +#define SMBHSTCTL 0x2 +#define SMBHSTCMD 0x3 +#define SMBXMITADD 0x4 +#define SMBHSTDAT0 0x5 +#define SMBHSTDAT1 0x6 +#define SMBBLKDAT 0x7 +#define SMBTRNSADD 0x9 +#define SMBSLVDATA 0xa +#define SMBAUXCTL 0xd +#define SMLINK_PIN_CTL 0xe +#define SMBUS_PIN_CTL 0xf
+/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE 0x80 +#define SMBHSTSTS_INUSE_STS 0x40 +#define SMBHSTSTS_SMBALERT_STS 0x20 +#define SMBHSTSTS_FAILED 0x10 +#define SMBHSTSTS_BUS_ERR 0x08 +#define SMBHSTSTS_DEV_ERR 0x04 +#define SMBHSTSTS_INTR 0x02 +#define SMBHSTSTS_HOST_BUSY 0x01
+/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN 0x01 +#define SMBHSTCNT_KILL 0x02 +#define SMBHSTCNT_LAST_BYTE 0x20 +#define SMBHSTCNT_START 0x40 +#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
+/* Auxiliary control register bits, ICH4+ only */ +#define SMBAUXCTL_CRC 1 +#define SMBAUXCTL_E32B 2
+#define SMBUS_TIMEOUT 100 /* 100 ms */
+struct intel_i2c {
u32 base;
int running;
+};
+static int smbus_wait_until_ready(u32 base) +{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!(byte & 1))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
+}
+static int smbus_wait_until_done(u32 base) +{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
+}
+static int smbus_block_read(u32 base, u8 dev, u8 *buffer,
int offset, int len)
+{
u8 buf_temp[32];
int count;
int i;
debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
__func__, __LINE__, dev, offset, len);
if (smbus_wait_until_ready(base) < 0)
return -ETIMEDOUT;
/* Setup transaction */
/* Reset the data buffer index */
inb(base + SMBHSTCTL);
/* Set the device I'm talking too */
outb(((dev & 0x7f) << 1) | 1, base + SMBXMITADD);
/* Set the command/address... */
outb(offset & 0xff, base + SMBHSTCMD);
/* Set up for a block read */
outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
(base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
/* Start the command */
outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(base) < 0) {
printf("SMBUS read transaction timeout (dev=0x%x)\n", dev);
return -ETIMEDOUT;
}
count = inb(base + SMBHSTDAT0);
I think always doing a block read is a bit problematic. I've tested the driver (on Baytrail) with several SMBus devices.
This example is a PCA9554 8-Bit I2C AND SMBus I/O Expander (datasheet http://www.ti.com/lit/ds/symlink/pca9554.pdf):
i2c md 20 0 5 i2c_xfer: 2 messages smbus_block_read (108): dev=0x20 offs=0x0 len=0x5 smbus_block_read (139): count=127 (len=5) Invalid Opcode (Undefined Opcode) EIP: 0010:[<80000001>] EFLAGS: 00010a92 Original EIP :[<049a0001>] EAX: 00000000 EBX: 7f7ffe7f ECX: 00000000 EDX: 0000b000 ESI: 7f7f7f7f EDI: 7f7f7f7f EBP: 7f7f7f7f ESP: 7b34c3b0 DS: 0018 ES: 0018 FS: 0020 GS: 0018 SS: 0018 CR0: 00000033 CR2: 00000000 CR3: 00000000 CR4: 00000600 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Stack: 0x7b34c3f0 : 0x7b36bd60 0x7b34c3ec : 0x7b7f7f7f 0x7b34c3e8 : 0x7f7f7f7f 0x7b34c3e4 : 0x7f7f7f7f 0x7b34c3e0 : 0x7f7f7f7f 0x7b34c3dc : 0x7f7f7f7f 0x7b34c3d8 : 0x7f7f7f7f 0x7b34c3d4 : 0x7f7f7f7f 0x7b34c3d0 : 0x7f7f7f7f 0x7b34c3cc : 0x7f7f7f7f 0x7b34c3c8 : 0x7f7f7f7f 0x7b34c3c4 : 0x7f7f7f7f 0x7b34c3c0 : 0x7f7f7f7f 0x7b34c3bc : 0x7f7f7f7f 0x7b34c3b8 : 0x7f7f7f7f 0x7b34c3b4 : 0x7f7f7f7f --->0x7b34c3b0 : 0x7f7f7f7f 0x7b34c3ac : 0x00010a92 0x7b34c3a8 : 0x00000010 0x7b34c3a4 : 0x80000001 ### ERROR ### Please RESET the board ###
This device always returns the data instead of providing a proper count. In order for this driver to be usable with this part it needs to support a byte read. Any ideas how we could support both byte and block read?
debug("%s (%d): count=%d (len=%d)\n", __func__, __LINE__, count, len);
if (count == 0) {
debug("ERROR: len=0 on read\n");
return -EIO;
}
if (count < len) {
debug("ERROR: too few bytes read\n");
return -EIO;
}
/* Read all available bytes from buffer */
for (i = 0; i < count; i++)
buf_temp[i] = inb(base + SMBBLKDAT);
No overrun check, if count is > 32 buffer is over run. In my case the data returned by the PCA9554 is interpreted as count and an overrun occurs.
memcpy(buffer, buf_temp, len);
/* Return results of transaction */
if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
return -EIO;
return 0;
+}
+static int smbus_block_write(u32 base, u8 dev, u8 *buffer,
int offset, int len)
+{
int i;
-int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
__func__, __LINE__, dev, offset, len);
if (smbus_wait_until_ready(base) < 0)
return -ETIMEDOUT;
/* Setup transaction */
/* Set the device I'm talking too */
outb(((dev & 0x7f) << 1) & ~0x01, base + SMBXMITADD);
/* Set the command/address... */
outb(offset, base + SMBHSTCMD);
/* Set up for a block write */
outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
(base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
/* Write count in DAT0 register */
outb(len, base + SMBHSTDAT0);
/* Write data bytes... */
for (i = 0; i < len; i++)
outb(*buffer++, base + SMBBLKDAT);
/* Start the command */
outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(base) < 0) {
printf("SMBUS write transaction timeout (dev=0x%x)\n", dev);
return -ETIMEDOUT;
}
/* Return results of transaction */
if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
return -EIO;
return 0;
+}
+static int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) {
return -ENOSYS;
struct intel_i2c *i2c = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
debug("i2c_xfer: %d messages\n", nmsgs);
memset(&dummy, 0, sizeof(struct i2c_msg));
/*
* We expect either two messages (one with an offset and one with the
* actucal data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported", __func__);
return -EIO;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return smbus_block_read(i2c->base, dmsg->addr, &dmsg->buf[0],
omsg->buf[0], dmsg->len);
else
return smbus_block_write(i2c->base, dmsg->addr, &dmsg->buf[1],
dmsg->buf[0], dmsg->len - 1);
}
-int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr, uint chip_flags) +static int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
return -ENOSYS;
struct intel_i2c *i2c = dev_get_priv(bus);
u8 buf[4];
return smbus_block_read(i2c->base, chip_addr, buf, 0, 1);
}
-int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { return 0; }
static int intel_i2c_probe(struct udevice *dev) {
struct intel_i2c *priv = dev_get_priv(dev);
u32 base;
+#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE
/* Handle ivybridge setup code */
priv->base = SMBUS_IO_BASE;
base = SMBUS_IO_BASE;
/*
* So far this is just setup code for ivybridge SMbus. When we have
* a full I2C driver this may need to be moved, generalised or made
* dependant on a particular compatible string.
* * Set SMBus I/O base */ dm_pci_write_config32(dev, SMB_BASE, SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
/* Set SMBus enable. */
dm_pci_write_config8(dev, HOSTC, HST_EN);
/* Set SMBus I/O space enable. */ dm_pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
@@ -50,6 +268,44 @@ static int intel_i2c_probe(struct udevice *dev) /* Clear any lingering errors, so transactions can run. */ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); debug("SMBus controller enabled\n"); +#else
/* Save base address from PCI BAR */
priv->base = (u32)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
PCI_REGION_IO);
base = priv->base;
+#endif
/* Set SMBus enable. */
dm_pci_write_config8(dev, HOSTC, HST_EN);
/* Disable interrupts */
outb(inb(base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, base + SMBHSTCTL);
/* Set 32-byte data buffer mode */
outb(inb(base + SMBAUXCTL) | SMBAUXCTL_E32B, base + SMBAUXCTL);
return 0;
+}
+static int intel_i2c_bind(struct udevice *dev) +{
static int num_cards;
char name[20];
/* Create a unique device name for PCI type devices */
if (device_is_on_pci_bus(dev)) {
/*
* ToDo:
* Setting req_seq in the driver is probably not recommended.
* But without a DT alias the number is not configured. And
* using this driver is impossible for PCIe I2C devices.
* This can be removed, once a better (correct) way for this
* is found and implemented.
*/
dev->req_seq = num_cards;
sprintf(name, "intel_i2c#%u", num_cards++);
device_set_name(dev, name);
} return 0;
} @@ -71,5 +327,15 @@ U_BOOT_DRIVER(intel_i2c) = { .of_match = intel_i2c_ids, .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), .ops = &intel_i2c_ops,
.priv_auto_alloc_size = sizeof(struct intel_i2c),
.bind = intel_i2c_bind, .probe = intel_i2c_probe,
};
+static struct pci_device_id intel_smbus_pci_supported[] = {
/* Intel BayTrail SMBus on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x0f12) },
{},
+};
+U_BOOT_PCI_DEVICE(intel_i2c, intel_smbus_pci_supported);
2.9.0
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi George,
On 05.08.2016 18:09, George McCollister wrote:
On Tue, Jun 28, 2016 at 8:44 AM, Stefan Roese sr@denx.de wrote:
This patch adds support for the SMBus block read/write functionality. Other protocols like the SMBus quick command need to get added if this is needed.
This patch also removed the SMBus related defines from the Ivybridge pch.h header. As they are integrated in this driver and should be used from here. This change is added in this patch to avoid compile breakage to keep the source git bisectable.
Tested on a congatec BayTrail board to configure the SMSC2513 USB hub.
Signed-off-by: Stefan Roese sr@denx.de Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org Cc: Heiko Schocher hs@denx.de
Simon, I'm not sure if this change breaks your Ivybridge targets using the probe part of this driver. Could you please let me know if this works? Or let me know what needs changes here?
Thanks, Stefan
arch/x86/include/asm/arch-ivybridge/pch.h | 26 --- drivers/i2c/intel_i2c.c | 290 ++++++++++++++++++++++++++++-- 2 files changed, 278 insertions(+), 38 deletions(-)
diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h index 4725250..9c51f63 100644 --- a/arch/x86/include/asm/arch-ivybridge/pch.h +++ b/arch/x86/include/asm/arch-ivybridge/pch.h @@ -134,32 +134,6 @@ #define SATA_IOBP_SP0G3IR 0xea000151 #define SATA_IOBP_SP1G3IR 0xea000051
-/* PCI Configuration Space (D31:F3): SMBus */ -#define PCH_SMBUS_DEV PCI_BDF(0, 0x1f, 3) -#define SMB_BASE 0x20 -#define HOSTC 0x40 -#define SMB_RCV_SLVA 0x09
-/* HOSTC bits */ -#define I2C_EN (1 << 2) -#define SMB_SMI_EN (1 << 1) -#define HST_EN (1 << 0)
-/* SMBus I/O bits. */ -#define SMBHSTSTAT 0x0 -#define SMBHSTCTL 0x2 -#define SMBHSTCMD 0x3 -#define SMBXMITADD 0x4 -#define SMBHSTDAT0 0x5 -#define SMBHSTDAT1 0x6 -#define SMBBLKDAT 0x7 -#define SMBTRNSADD 0x9 -#define SMBSLVDATA 0xa -#define SMLINK_PIN_CTL 0xe -#define SMBUS_PIN_CTL 0xf
-#define SMBUS_TIMEOUT (10 * 1000 * 100)
#define VCH 0x0000 /* 32bit */ #define VCAP1 0x0004 /* 32bit */ #define VCAP2 0x0008 /* 32bit */ diff --git a/drivers/i2c/intel_i2c.c b/drivers/i2c/intel_i2c.c index 3d777ff..8b63916 100644 --- a/drivers/i2c/intel_i2c.c +++ b/drivers/i2c/intel_i2c.c @@ -2,45 +2,263 @@
- Copyright (c) 2015 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SMBus block read/write support added by Stefan Roese:
- Copyright (C) 2016 Stefan Roese sr@denx.de
*/
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <dm.h> #include <i2c.h> +#include <pci.h> #include <asm/io.h> +#ifdef CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE #include <asm/arch/pch.h> +#endif
+/* PCI Configuration Space (D31:F3): SMBus */ +#define SMB_BASE 0x20 +#define HOSTC 0x40 +#define HST_EN (1 << 0) +#define SMB_RCV_SLVA 0x09
+/* SMBus I/O bits. */ +#define SMBHSTSTAT 0x0 +#define SMBHSTCTL 0x2 +#define SMBHSTCMD 0x3 +#define SMBXMITADD 0x4 +#define SMBHSTDAT0 0x5 +#define SMBHSTDAT1 0x6 +#define SMBBLKDAT 0x7 +#define SMBTRNSADD 0x9 +#define SMBSLVDATA 0xa +#define SMBAUXCTL 0xd +#define SMLINK_PIN_CTL 0xe +#define SMBUS_PIN_CTL 0xf
+/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE 0x80 +#define SMBHSTSTS_INUSE_STS 0x40 +#define SMBHSTSTS_SMBALERT_STS 0x20 +#define SMBHSTSTS_FAILED 0x10 +#define SMBHSTSTS_BUS_ERR 0x08 +#define SMBHSTSTS_DEV_ERR 0x04 +#define SMBHSTSTS_INTR 0x02 +#define SMBHSTSTS_HOST_BUSY 0x01
+/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN 0x01 +#define SMBHSTCNT_KILL 0x02 +#define SMBHSTCNT_LAST_BYTE 0x20 +#define SMBHSTCNT_START 0x40 +#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
+/* Auxiliary control register bits, ICH4+ only */ +#define SMBAUXCTL_CRC 1 +#define SMBAUXCTL_E32B 2
+#define SMBUS_TIMEOUT 100 /* 100 ms */
+struct intel_i2c {
u32 base;
int running;
+};
+static int smbus_wait_until_ready(u32 base) +{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!(byte & 1))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
+}
+static int smbus_wait_until_done(u32 base) +{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
+}
+static int smbus_block_read(u32 base, u8 dev, u8 *buffer,
int offset, int len)
+{
u8 buf_temp[32];
int count;
int i;
debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
__func__, __LINE__, dev, offset, len);
if (smbus_wait_until_ready(base) < 0)
return -ETIMEDOUT;
/* Setup transaction */
/* Reset the data buffer index */
inb(base + SMBHSTCTL);
/* Set the device I'm talking too */
outb(((dev & 0x7f) << 1) | 1, base + SMBXMITADD);
/* Set the command/address... */
outb(offset & 0xff, base + SMBHSTCMD);
/* Set up for a block read */
outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
(base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
/* Start the command */
outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(base) < 0) {
printf("SMBUS read transaction timeout (dev=0x%x)\n", dev);
return -ETIMEDOUT;
}
count = inb(base + SMBHSTDAT0);
I think always doing a block read is a bit problematic. I've tested the driver (on Baytrail) with several SMBus devices.
This example is a PCA9554 8-Bit I2C AND SMBus I/O Expander (datasheet http://www.ti.com/lit/ds/symlink/pca9554.pdf):
i2c md 20 0 5 i2c_xfer: 2 messages smbus_block_read (108): dev=0x20 offs=0x0 len=0x5 smbus_block_read (139): count=127 (len=5) Invalid Opcode (Undefined Opcode) EIP: 0010:[<80000001>] EFLAGS: 00010a92 Original EIP :[<049a0001>] EAX: 00000000 EBX: 7f7ffe7f ECX: 00000000 EDX: 0000b000 ESI: 7f7f7f7f EDI: 7f7f7f7f EBP: 7f7f7f7f ESP: 7b34c3b0 DS: 0018 ES: 0018 FS: 0020 GS: 0018 SS: 0018 CR0: 00000033 CR2: 00000000 CR3: 00000000 CR4: 00000600 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Stack: 0x7b34c3f0 : 0x7b36bd60 0x7b34c3ec : 0x7b7f7f7f 0x7b34c3e8 : 0x7f7f7f7f 0x7b34c3e4 : 0x7f7f7f7f 0x7b34c3e0 : 0x7f7f7f7f 0x7b34c3dc : 0x7f7f7f7f 0x7b34c3d8 : 0x7f7f7f7f 0x7b34c3d4 : 0x7f7f7f7f 0x7b34c3d0 : 0x7f7f7f7f 0x7b34c3cc : 0x7f7f7f7f 0x7b34c3c8 : 0x7f7f7f7f 0x7b34c3c4 : 0x7f7f7f7f 0x7b34c3c0 : 0x7f7f7f7f 0x7b34c3bc : 0x7f7f7f7f 0x7b34c3b8 : 0x7f7f7f7f 0x7b34c3b4 : 0x7f7f7f7f --->0x7b34c3b0 : 0x7f7f7f7f 0x7b34c3ac : 0x00010a92 0x7b34c3a8 : 0x00000010 0x7b34c3a4 : 0x80000001 ### ERROR ### Please RESET the board ###
This device always returns the data instead of providing a proper count. In order for this driver to be usable with this part it needs to support a byte read. Any ideas how we could support both byte and block read?
The USB device I need to communicate with only supports block read write operations. Thats why I added those functions. I would prefer to get v2 of this SMBus support upstream first. And then work on supporting other SMBus operations (like byte read).
Simon, do you have an idea on how to support byte and block SMBus operations? The easy way would be to add a Kconfig option to select the OP at compile time. But a runtime selection would be much better.
Thanks, Stefan
participants (5)
-
Bin Meng
-
George McCollister
-
Heiko Schocher
-
Simon Glass
-
Stefan Roese