uboot/drivers/i2c/intel_i2c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 *
   6 * SMBus block read/write support added by Stefan Roese:
   7 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
   8 */
   9
  10#include <common.h>
  11#include <dm.h>
  12#include <i2c.h>
  13#include <pci.h>
  14#include <asm/io.h>
  15
  16/* PCI Configuration Space (D31:F3): SMBus */
  17#define SMB_BASE                0x20
  18#define HOSTC                   0x40
  19#define  HST_EN                 (1 << 0)
  20#define SMB_RCV_SLVA            0x09
  21
  22/* SMBus I/O bits. */
  23#define SMBHSTSTAT              0x0
  24#define SMBHSTCTL               0x2
  25#define SMBHSTCMD               0x3
  26#define SMBXMITADD              0x4
  27#define SMBHSTDAT0              0x5
  28#define SMBHSTDAT1              0x6
  29#define SMBBLKDAT               0x7
  30#define SMBTRNSADD              0x9
  31#define SMBSLVDATA              0xa
  32#define SMBAUXCTL               0xd
  33#define SMLINK_PIN_CTL          0xe
  34#define SMBUS_PIN_CTL           0xf
  35
  36/* I801 Hosts Status register bits */
  37#define SMBHSTSTS_BYTE_DONE     0x80
  38#define SMBHSTSTS_INUSE_STS     0x40
  39#define SMBHSTSTS_SMBALERT_STS  0x20
  40#define SMBHSTSTS_FAILED        0x10
  41#define SMBHSTSTS_BUS_ERR       0x08
  42#define SMBHSTSTS_DEV_ERR       0x04
  43#define SMBHSTSTS_INTR          0x02
  44#define SMBHSTSTS_HOST_BUSY     0x01
  45
  46/* I801 Host Control register bits */
  47#define SMBHSTCNT_INTREN        0x01
  48#define SMBHSTCNT_KILL          0x02
  49#define SMBHSTCNT_LAST_BYTE     0x20
  50#define SMBHSTCNT_START         0x40
  51#define SMBHSTCNT_PEC_EN        0x80    /* ICH3 and later */
  52
  53/* Auxiliary control register bits, ICH4+ only */
  54#define SMBAUXCTL_CRC           1
  55#define SMBAUXCTL_E32B          2
  56
  57#define SMBUS_TIMEOUT   100     /* 100 ms */
  58
  59struct intel_i2c {
  60        u32 base;
  61        int running;
  62};
  63
  64static int smbus_wait_until_ready(u32 base)
  65{
  66        unsigned long ts;
  67        u8 byte;
  68
  69        ts = get_timer(0);
  70        do {
  71                byte = inb(base + SMBHSTSTAT);
  72                if (!(byte & 1))
  73                        return 0;
  74        } while (get_timer(ts) < SMBUS_TIMEOUT);
  75
  76        return -ETIMEDOUT;
  77}
  78
  79static int smbus_wait_until_done(u32 base)
  80{
  81        unsigned long ts;
  82        u8 byte;
  83
  84        ts = get_timer(0);
  85        do {
  86                byte = inb(base + SMBHSTSTAT);
  87                if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0))
  88                        return 0;
  89        } while (get_timer(ts) < SMBUS_TIMEOUT);
  90
  91        return -ETIMEDOUT;
  92}
  93
  94static int smbus_block_read(u32 base, u8 dev, u8 *buffer,
  95                            int offset, int len)
  96{
  97        u8 buf_temp[32];
  98        int count;
  99        int i;
 100
 101        debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
 102              __func__, __LINE__, dev, offset, len);
 103        if (smbus_wait_until_ready(base) < 0)
 104                return -ETIMEDOUT;
 105
 106        /* Setup transaction */
 107
 108        /* Reset the data buffer index */
 109        inb(base + SMBHSTCTL);
 110
 111        /* Set the device I'm talking too */
 112        outb(((dev & 0x7f) << 1) | 1, base + SMBXMITADD);
 113        /* Set the command/address... */
 114        outb(offset & 0xff, base + SMBHSTCMD);
 115        /* Set up for a block read */
 116        outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
 117             (base + SMBHSTCTL));
 118        /* Clear any lingering errors, so the transaction will run */
 119        outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
 120
 121        /* Start the command */
 122        outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
 123
 124        /* Poll for transaction completion */
 125        if (smbus_wait_until_done(base) < 0) {
 126                printf("SMBUS read transaction timeout (dev=0x%x)\n", dev);
 127                return -ETIMEDOUT;
 128        }
 129
 130        count = inb(base + SMBHSTDAT0);
 131        debug("%s (%d): count=%d (len=%d)\n", __func__, __LINE__, count, len);
 132        if (count == 0) {
 133                debug("ERROR: len=0 on read\n");
 134                return -EIO;
 135        }
 136
 137        if (count < len) {
 138                debug("ERROR: too few bytes read\n");
 139                return -EIO;
 140        }
 141
 142        if (count > 32) {
 143                debug("ERROR: count=%d too high\n", count);
 144                return -EIO;
 145        }
 146
 147        /* Read all available bytes from buffer */
 148        for (i = 0; i < count; i++)
 149                buf_temp[i] = inb(base + SMBBLKDAT);
 150
 151        memcpy(buffer, buf_temp, len);
 152
 153        /* Return results of transaction */
 154        if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
 155                return -EIO;
 156
 157        return 0;
 158}
 159
 160static int smbus_block_write(u32 base, u8 dev, u8 *buffer,
 161                             int offset, int len)
 162{
 163        int i;
 164
 165        debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
 166              __func__, __LINE__, dev, offset, len);
 167        if (smbus_wait_until_ready(base) < 0)
 168                return -ETIMEDOUT;
 169
 170        /* Setup transaction */
 171        /* Set the device I'm talking too */
 172        outb(((dev & 0x7f) << 1) & ~0x01, base + SMBXMITADD);
 173        /* Set the command/address... */
 174        outb(offset, base + SMBHSTCMD);
 175        /* Set up for a block write */
 176        outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
 177             (base + SMBHSTCTL));
 178        /* Clear any lingering errors, so the transaction will run */
 179        outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
 180
 181        /* Write count in DAT0 register */
 182        outb(len, base + SMBHSTDAT0);
 183
 184        /* Write data bytes... */
 185        for (i = 0; i < len; i++)
 186                outb(*buffer++, base + SMBBLKDAT);
 187
 188        /* Start the command */
 189        outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
 190
 191        /* Poll for transaction completion */
 192        if (smbus_wait_until_done(base) < 0) {
 193                printf("SMBUS write transaction timeout (dev=0x%x)\n", dev);
 194                return -ETIMEDOUT;
 195        }
 196
 197        /* Return results of transaction */
 198        if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
 199                return -EIO;
 200
 201        return 0;
 202}
 203
 204static int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
 205{
 206        struct intel_i2c *i2c = dev_get_priv(bus);
 207        struct i2c_msg *dmsg, *omsg, dummy;
 208
 209        debug("i2c_xfer: %d messages\n", nmsgs);
 210
 211        memset(&dummy, 0, sizeof(struct i2c_msg));
 212
 213        /*
 214         * We expect either two messages (one with an offset and one with the
 215         * actucal data) or one message (just data)
 216         */
 217        if (nmsgs > 2 || nmsgs == 0) {
 218                debug("%s: Only one or two messages are supported", __func__);
 219                return -EIO;
 220        }
 221
 222        omsg = nmsgs == 1 ? &dummy : msg;
 223        dmsg = nmsgs == 1 ? msg : msg + 1;
 224
 225        if (dmsg->flags & I2C_M_RD)
 226                return smbus_block_read(i2c->base, dmsg->addr, &dmsg->buf[0],
 227                                        omsg->buf[0], dmsg->len);
 228        else
 229                return smbus_block_write(i2c->base, dmsg->addr, &dmsg->buf[1],
 230                                         dmsg->buf[0], dmsg->len - 1);
 231}
 232
 233static int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr,
 234                                uint chip_flags)
 235{
 236        struct intel_i2c *i2c = dev_get_priv(bus);
 237        u8 buf[4];
 238
 239        return smbus_block_read(i2c->base, chip_addr, buf, 0, 1);
 240}
 241
 242static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
 243{
 244        return 0;
 245}
 246
 247static int intel_i2c_probe(struct udevice *dev)
 248{
 249        struct intel_i2c *priv = dev_get_priv(dev);
 250        ulong base;
 251
 252        /* Save base address from PCI BAR */
 253        priv->base = (ulong)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
 254                                           PCI_REGION_IO);
 255        base = priv->base;
 256
 257        /* Set SMBus enable. */
 258        dm_pci_write_config8(dev, HOSTC, HST_EN);
 259
 260        /* Disable interrupts */
 261        outb(inb(base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, base + SMBHSTCTL);
 262
 263        /* Set 32-byte data buffer mode */
 264        outb(inb(base + SMBAUXCTL) | SMBAUXCTL_E32B, base + SMBAUXCTL);
 265
 266        return 0;
 267}
 268
 269static int intel_i2c_bind(struct udevice *dev)
 270{
 271        static int num_cards __attribute__ ((section(".data")));
 272        char name[20];
 273
 274        /* Create a unique device name for PCI type devices */
 275        if (device_is_on_pci_bus(dev)) {
 276                /*
 277                 * ToDo:
 278                 * Setting req_seq in the driver is probably not recommended.
 279                 * But without a DT alias the number is not configured. And
 280                 * using this driver is impossible for PCIe I2C devices.
 281                 * This can be removed, once a better (correct) way for this
 282                 * is found and implemented.
 283                 */
 284                dev->req_seq = num_cards;
 285                sprintf(name, "intel_i2c#%u", num_cards++);
 286                device_set_name(dev, name);
 287        }
 288
 289        return 0;
 290}
 291
 292static const struct dm_i2c_ops intel_i2c_ops = {
 293        .xfer           = intel_i2c_xfer,
 294        .probe_chip     = intel_i2c_probe_chip,
 295        .set_bus_speed  = intel_i2c_set_bus_speed,
 296};
 297
 298static const struct udevice_id intel_i2c_ids[] = {
 299        { .compatible = "intel,ich-i2c" },
 300        { }
 301};
 302
 303U_BOOT_DRIVER(intel_i2c) = {
 304        .name   = "i2c_intel",
 305        .id     = UCLASS_I2C,
 306        .of_match = intel_i2c_ids,
 307        .ops    = &intel_i2c_ops,
 308        .priv_auto_alloc_size = sizeof(struct intel_i2c),
 309        .bind   = intel_i2c_bind,
 310        .probe  = intel_i2c_probe,
 311};
 312
 313static struct pci_device_id intel_smbus_pci_supported[] = {
 314        /* Intel BayTrail SMBus on the PCI bus */
 315        { PCI_VDEVICE(INTEL, 0x0f12) },
 316        /* Intel IvyBridge (Panther Point PCH) SMBus on the PCI bus */
 317        { PCI_VDEVICE(INTEL, 0x1e22) },
 318        {},
 319};
 320
 321U_BOOT_PCI_DEVICE(intel_i2c, intel_smbus_pci_supported);
 322