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