]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/tpm/tpm_tis_i2c.c
tpm: tpm_tis_i2c: Use a consistent tpm_tis_i2c_ prefix
[karo-tx-uboot.git] / drivers / tpm / tpm_tis_i2c.c
index c1bbed4eb5833054c53db2a9b927e9e3144cd6f8..e04e8f547baf0694910c4bde1cd0ada9441df77d 100644 (file)
  *
  * Version: 2.1.1
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
 #include <common.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <linux/compiler.h>
 #include <i2c.h>
 #include <linux/types.h>
 #include <linux/unaligned/be_byteshift.h>
 
-#include "tpm_private.h"
+#include "tpm_tis_i2c.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Address of the TPM on the I2C bus */
-#define TPM_I2C_ADDR           0x20
-
-/* Max buffer size supported by our tpm */
-#define TPM_DEV_BUFSIZE                1260
-
-/* Max number of iterations after i2c NAK */
-#define MAX_COUNT              3
-
-/*
- * Max number of iterations after i2c NAK for 'long' commands
- *
- * We need this especially for sending TPM_READY, since the cleanup after the
- * transtion to the ready state may take some time, but it is unpredictable
- * how long it will take.
- */
-#define MAX_COUNT_LONG         50
-
-#define SLEEP_DURATION         60      /* in usec */
-#define SLEEP_DURATION_LONG    210     /* in usec */
-
-#define TPM_HEADER_SIZE                10
-
-/*
- * Expected value for DIDVID register
- *
- * The only device the system knows about at this moment is Infineon slb9635.
- */
-#define TPM_TIS_I2C_DID_VID    0x000b15d1L
-
-enum tis_access {
-       TPM_ACCESS_VALID                = 0x80,
-       TPM_ACCESS_ACTIVE_LOCALITY      = 0x20,
-       TPM_ACCESS_REQUEST_PENDING      = 0x04,
-       TPM_ACCESS_REQUEST_USE          = 0x02,
-};
-
-enum tis_status {
-       TPM_STS_VALID                   = 0x80,
-       TPM_STS_COMMAND_READY           = 0x40,
-       TPM_STS_GO                      = 0x20,
-       TPM_STS_DATA_AVAIL              = 0x10,
-       TPM_STS_DATA_EXPECT             = 0x08,
-};
-
-enum tis_defaults {
-       TIS_SHORT_TIMEOUT               = 750,  /* ms */
-       TIS_LONG_TIMEOUT                = 2000, /* ms */
-};
-
-/* expected value for DIDVID register */
-#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
-#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
-
-enum i2c_chip_type {
-       SLB9635,
-       SLB9645,
-       UNKNOWN,
-};
-
 static const char * const chip_name[] = {
        [SLB9635] = "slb9635tt",
        [SLB9645] = "slb9645tt",
        [UNKNOWN] = "unknown/fallback to slb9635",
 };
 
-#define        TPM_ACCESS(l)                   (0x0000 | ((l) << 4))
-#define        TPM_STS(l)                      (0x0001 | ((l) << 4))
-#define        TPM_DATA_FIFO(l)                (0x0005 | ((l) << 4))
-#define        TPM_DID_VID(l)                  (0x0006 | ((l) << 4))
-
-/* Structure to store I2C TPM specific stuff */
-struct tpm_dev {
-       uint addr;
-       u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)];  /* Max buffer size + addr */
-       enum i2c_chip_type chip_type;
-};
-
-static struct tpm_dev tpm_dev = {
-       .addr = TPM_I2C_ADDR
-};
-
-static struct tpm_dev tpm_dev;
+static struct tpm_chip g_chip;
 
 /*
- * iic_tpm_read() - read from TPM register
+ * tpm_tis_i2c_read() - read from TPM register
  * @addr: register address to read from
  * @buffer: provided by caller
  * @len: number of bytes to read
@@ -147,17 +56,16 @@ static struct tpm_dev tpm_dev;
  *
  * Return -EIO on error, 0 on success.
  */
-static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len)
 {
        int rc;
        int count;
        uint32_t addrbuf = addr;
 
-       if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) {
+       if ((g_chip.chip_type == SLB9635) || (g_chip.chip_type == UNKNOWN)) {
                /* slb9635 protocol should work in both cases */
                for (count = 0; count < MAX_COUNT; count++) {
-                       rc = i2c_write(tpm_dev.addr, 0, 0,
-                                      (uchar *)&addrbuf, 1);
+                       rc = dm_i2c_write(g_chip.dev, 0, (uchar *)&addrbuf, 1);
                        if (rc == 0)
                                break;  /* Success, break to skip sleep */
                        udelay(SLEEP_DURATION);
@@ -171,7 +79,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
                 */
                for (count = 0; count < MAX_COUNT; count++) {
                        udelay(SLEEP_DURATION);
-                       rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len);
+                       rc = dm_i2c_read(g_chip.dev, 0, buffer, len);
                        if (rc == 0)
                                break;  /* success, break to skip sleep */
                }
@@ -184,7 +92,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
                 * be safe on the safe side.
                 */
                for (count = 0; count < MAX_COUNT; count++) {
-                       rc = i2c_read(tpm_dev.addr, addr, 1, buffer, len);
+                       rc = dm_i2c_read(g_chip.dev, addr, buffer, len);
                        if (rc == 0)
                                break;  /* break here to skip sleep */
                        udelay(SLEEP_DURATION);
@@ -199,25 +107,21 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
        return 0;
 }
 
-static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
-               unsigned int sleep_time, u8 max_count)
+static int tpm_tis_i2c_write_generic(u8 addr, u8 *buffer, size_t len,
+                                    unsigned int sleep_time, u8 max_count)
 {
        int rc = 0;
        int count;
 
-       /* Prepare send buffer */
-       tpm_dev.buf[0] = addr;
-       memcpy(&(tpm_dev.buf[1]), buffer, len);
-
        for (count = 0; count < max_count; count++) {
-               rc = i2c_write(tpm_dev.addr, 0, 0, tpm_dev.buf, len + 1);
+               rc = dm_i2c_write(g_chip.dev, addr, buffer, len);
                if (rc == 0)
                        break;  /* Success, break to skip sleep */
                udelay(sleep_time);
        }
 
        /* take care of 'guard time' */
-       udelay(SLEEP_DURATION);
+       udelay(sleep_time);
        if (rc)
                return -rc;
 
@@ -225,7 +129,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
 }
 
 /*
- * iic_tpm_write() - write to TPM register
+ * tpm_tis_i2c_write() - write to TPM register
  * @addr: register address to write to
  * @buffer: containing data to be written
  * @len: number of bytes to write
@@ -236,13 +140,13 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
  * NOTE: TPM is big-endian for multi-byte values. Multi-byte
  * values have to be swapped.
  *
- * NOTE: use this function instead of the iic_tpm_write_generic function.
+ * NOTE: use this function instead of the tpm_tis_i2c_write_generic function.
  *
  * Return -EIO on error, 0 on success
  */
-static int iic_tpm_write(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_write(u8 addr, u8 *buffer, size_t len)
 {
-       return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION,
+       return tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION,
                        MAX_COUNT);
 }
 
@@ -250,59 +154,63 @@ static int iic_tpm_write(u8 addr, u8 *buffer, size_t len)
  * This function is needed especially for the cleanup situation after
  * sending TPM_READY
  */
-static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_write_long(u8 addr, u8 *buffer, size_t len)
 {
-       return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG,
+       return tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION_LONG,
                        MAX_COUNT_LONG);
 }
 
-static int check_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_check_locality(struct tpm_chip *chip, int loc)
 {
        const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID;
        u8 buf;
        int rc;
 
-       rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1);
+       rc = tpm_tis_i2c_read(TPM_ACCESS(loc), &buf, 1);
        if (rc < 0)
                return rc;
 
        if ((buf & mask) == mask) {
-               chip->vendor.locality = loc;
+               chip->locality = loc;
                return loc;
        }
 
        return -1;
 }
 
-static void release_locality(struct tpm_chip *chip, int loc, int force)
+static void tpm_tis_i2c_release_locality(struct tpm_chip *chip, int loc,
+                                        int force)
 {
        const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID;
        u8 buf;
 
-       if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0)
+       if (tpm_tis_i2c_read(TPM_ACCESS(loc), &buf, 1) < 0)
                return;
 
        if (force || (buf & mask) == mask) {
                buf = TPM_ACCESS_ACTIVE_LOCALITY;
-               iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
+               tpm_tis_i2c_write(TPM_ACCESS(loc), &buf, 1);
        }
 }
 
-static int request_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_request_locality(struct tpm_chip *chip, int loc)
 {
        unsigned long start, stop;
        u8 buf = TPM_ACCESS_REQUEST_USE;
+       int rc;
 
-       if (check_locality(chip, loc) >= 0)
+       if (tpm_tis_i2c_check_locality(chip, loc) >= 0)
                return loc;  /* We already have the locality */
 
-       iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
+       rc = tpm_tis_i2c_write(TPM_ACCESS(loc), &buf, 1);
+       if (rc)
+               return rc;
 
        /* Wait for burstcount */
        start = get_timer(0);
-       stop = chip->vendor.timeout_a;
+       stop = chip->timeout_a;
        do {
-               if (check_locality(chip, loc) >= 0)
+               if (tpm_tis_i2c_check_locality(chip, loc) >= 0)
                        return loc;
                udelay(TPM_TIMEOUT * 1000);
        } while (get_timer(start) < stop);
@@ -315,7 +223,7 @@ static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
        /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */
        u8 buf;
 
-       if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
+       if (tpm_tis_i2c_read(TPM_STS(chip->locality), &buf, 1) < 0)
                return 0;
        else
                return buf;
@@ -323,13 +231,18 @@ static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
 
 static void tpm_tis_i2c_ready(struct tpm_chip *chip)
 {
+       int rc;
+
        /* This causes the current command to be aborted */
        u8 buf = TPM_STS_COMMAND_READY;
 
-       iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1);
+       debug("%s\n", __func__);
+       rc = tpm_tis_i2c_write_long(TPM_STS(chip->locality), &buf, 1);
+       if (rc)
+               debug("%s: rc=%d\n", __func__, rc);
 }
 
-static ssize_t get_burstcount(struct tpm_chip *chip)
+static ssize_t tpm_tis_i2c_get_burstcount(struct tpm_chip *chip)
 {
        unsigned long start, stop;
        ssize_t burstcnt;
@@ -338,11 +251,11 @@ static ssize_t get_burstcount(struct tpm_chip *chip)
        /* Wait for burstcount */
        /* XXX: Which timeout value? Spec has 2 answers (c & d) */
        start = get_timer(0);
-       stop = chip->vendor.timeout_d;
+       stop = chip->timeout_d;
        do {
                /* Note: STS is little endian */
-               addr = TPM_STS(chip->vendor.locality) + 1;
-               if (iic_tpm_read(addr, buf, 3) < 0)
+               addr = TPM_STS(chip->locality) + 1;
+               if (tpm_tis_i2c_read(addr, buf, 3) < 0)
                        burstcnt = 0;
                else
                        burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
@@ -355,8 +268,8 @@ static ssize_t get_burstcount(struct tpm_chip *chip)
        return -EBUSY;
 }
 
-static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
-               int *status)
+static int tpm_tis_i2c_wait_for_stat(struct tpm_chip *chip, u8 mask,
+                                    unsigned long timeout, int *status)
 {
        unsigned long start, stop;
 
@@ -377,14 +290,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
        return -ETIME;
 }
 
-static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_i2c_recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        size_t size = 0;
        ssize_t burstcnt;
        int rc;
 
        while (size < count) {
-               burstcnt = get_burstcount(chip);
+               burstcnt = tpm_tis_i2c_get_burstcount(chip);
 
                /* burstcount < 0 -> tpm is busy */
                if (burstcnt < 0)
@@ -394,7 +307,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
                if (burstcnt > (count - size))
                        burstcnt = count - size;
 
-               rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality),
+               rc = tpm_tis_i2c_read(TPM_DATA_FIFO(chip->locality),
                                &(buf[size]), burstcnt);
                if (rc == 0)
                        size += burstcnt;
@@ -414,7 +327,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
        }
 
        /* Read first 10 bytes, including tag, paramsize, and result */
-       size = recv_data(chip, buf, TPM_HEADER_SIZE);
+       size = tpm_tis_i2c_recv_data(chip, buf, TPM_HEADER_SIZE);
        if (size < TPM_HEADER_SIZE) {
                error("Unable to read header\n");
                goto out;
@@ -422,19 +335,22 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 
        expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE);
        if ((size_t)expected > count) {
+               error("Error size=%x, expected=%x, count=%x\n", size, expected,
+                     count);
                size = -EIO;
                goto out;
        }
 
-       size += recv_data(chip, &buf[TPM_HEADER_SIZE],
-                       expected - TPM_HEADER_SIZE);
+       size += tpm_tis_i2c_recv_data(chip, &buf[TPM_HEADER_SIZE],
+                                     expected - TPM_HEADER_SIZE);
        if (size < expected) {
                error("Unable to read remainder of result\n");
                size = -ETIME;
                goto out;
        }
 
-       wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
+       tpm_tis_i2c_wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c,
+                                 &status);
        if (status & TPM_STS_DATA_AVAIL) {  /* Retry? */
                error("Error left over data\n");
                size = -EIO;
@@ -448,7 +364,7 @@ out:
         * so we sleep rather than keeping the bus busy
         */
        udelay(2000);
-       release_locality(chip, chip->vendor.locality, 0);
+       tpm_tis_i2c_release_locality(chip, chip->locality, 0);
 
        return size;
 }
@@ -456,50 +372,59 @@ out:
 static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
 {
        int rc, status;
-       ssize_t burstcnt;
+       size_t burstcnt;
        size_t count = 0;
        int retry = 0;
        u8 sts = TPM_STS_GO;
 
+       debug("%s: len=%d\n", __func__, len);
        if (len > TPM_DEV_BUFSIZE)
                return -E2BIG;  /* Command is too long for our tpm, sorry */
 
-       if (request_locality(chip, 0) < 0)
+       if (tpm_tis_i2c_request_locality(chip, 0) < 0)
                return -EBUSY;
 
        status = tpm_tis_i2c_status(chip);
        if ((status & TPM_STS_COMMAND_READY) == 0) {
                tpm_tis_i2c_ready(chip);
-               if (wait_for_stat(chip, TPM_STS_COMMAND_READY,
-                                 chip->vendor.timeout_b, &status) < 0) {
+               if (tpm_tis_i2c_wait_for_stat(chip, TPM_STS_COMMAND_READY,
+                                             chip->timeout_b, &status) < 0) {
                        rc = -ETIME;
                        goto out_err;
                }
        }
 
-       burstcnt = get_burstcount(chip);
+       burstcnt = tpm_tis_i2c_get_burstcount(chip);
 
        /* burstcount < 0 -> tpm is busy */
        if (burstcnt < 0)
                return burstcnt;
 
-       while (count < len - 1) {
-               if (burstcnt > len - 1 - count)
-                       burstcnt = len - 1 - count;
+       while (count < len) {
+               udelay(300);
+               if (burstcnt > len - count)
+                       burstcnt = len - count;
 
 #ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION
                if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION)
                        burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION;
 #endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */
 
-               rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality),
+               rc = tpm_tis_i2c_write(TPM_DATA_FIFO(chip->locality),
                                &(buf[count]), burstcnt);
                if (rc == 0)
                        count += burstcnt;
                else {
-                       retry++;
-                       wait_for_stat(chip, TPM_STS_VALID,
-                                     chip->vendor.timeout_c, &status);
+                       debug("%s: error\n", __func__);
+                       if (retry++ > 10) {
+                               rc = -EIO;
+                               goto out_err;
+                       }
+                       rc = tpm_tis_i2c_wait_for_stat(chip, TPM_STS_VALID,
+                                                      chip->timeout_c,
+                                                      &status);
+                       if (rc)
+                               goto out_err;
 
                        if ((status & TPM_STS_DATA_EXPECT) == 0) {
                                rc = -EIO;
@@ -508,45 +433,28 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
                }
        }
 
-       /* Write last byte */
-       iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1);
-       wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
-       if ((status & TPM_STS_DATA_EXPECT) != 0) {
-               rc = -EIO;
-               goto out_err;
-       }
-
        /* Go and do it */
-       iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1);
+       tpm_tis_i2c_write(TPM_STS(chip->locality), &sts, 1);
+       debug("done\n");
 
        return len;
 
 out_err:
+       debug("%s: out_err\n", __func__);
        tpm_tis_i2c_ready(chip);
        /*
         * The TPM needs some time to clean up here,
         * so we sleep rather than keeping the bus busy
         */
        udelay(2000);
-       release_locality(chip, chip->vendor.locality, 0);
+       tpm_tis_i2c_release_locality(chip, chip->locality, 0);
 
        return rc;
 }
 
-static struct tpm_vendor_specific tpm_tis_i2c = {
-       .status = tpm_tis_i2c_status,
-       .recv = tpm_tis_i2c_recv,
-       .send = tpm_tis_i2c_send,
-       .cancel = tpm_tis_i2c_ready,
-       .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-       .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-       .req_canceled = TPM_STS_COMMAND_READY,
-};
-
-
-static enum i2c_chip_type tpm_vendor_chip_type(void)
+static enum i2c_chip_type tpm_tis_i2c_chip_type(void)
 {
-#ifdef CONFIG_OF_CONTROL
+#if CONFIG_IS_ENABLED(OF_CONTROL)
        const void *blob = gd->fdt_blob;
 
        if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9645_TPM) >= 0)
@@ -558,48 +466,38 @@ static enum i2c_chip_type tpm_vendor_chip_type(void)
        return UNKNOWN;
 }
 
-/* Initialisation of i2c tpm */
-int tpm_vendor_init(uint32_t dev_addr)
+static int tpm_tis_i2c_init(struct udevice *dev)
 {
+       struct tpm_chip *chip = &g_chip;
        u32 vendor;
        u32 expected_did_vid;
-       uint old_addr;
-       int rc = 0;
-       struct tpm_chip *chip;
-
-       old_addr = tpm_dev.addr;
-       if (dev_addr != 0)
-               tpm_dev.addr = dev_addr;
 
-       tpm_dev.chip_type = tpm_vendor_chip_type();
-
-       chip = tpm_register_hardware(&tpm_tis_i2c);
-       if (chip < 0) {
-               rc = -ENODEV;
-               goto out_err;
-       }
+       g_chip.dev = dev;
+       g_chip.chip_type = tpm_tis_i2c_chip_type();
+       chip->is_open = 1;
 
        /* Disable interrupts (not supported) */
-       chip->vendor.irq = 0;
+       chip->irq = 0;
 
-       /* Default timeouts */
-       chip->vendor.timeout_a = TIS_SHORT_TIMEOUT;
-       chip->vendor.timeout_b = TIS_LONG_TIMEOUT;
-       chip->vendor.timeout_c = TIS_SHORT_TIMEOUT;
-       chip->vendor.timeout_d = TIS_SHORT_TIMEOUT;
+       /* Default timeouts - these could move to the device tree */
+       chip->timeout_a = TIS_SHORT_TIMEOUT;
+       chip->timeout_b = TIS_LONG_TIMEOUT;
+       chip->timeout_c = TIS_SHORT_TIMEOUT;
+       chip->timeout_d = TIS_SHORT_TIMEOUT;
+       chip->req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID;
+       chip->req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID;
+       chip->req_canceled = TPM_STS_COMMAND_READY;
 
-       if (request_locality(chip, 0) < 0) {
-               rc = -ENODEV;
-               goto out_err;
-       }
+       if (tpm_tis_i2c_request_locality(chip, 0) < 0)
+               return  -ENODEV;
 
        /* Read four bytes from DID_VID register */
-       if (iic_tpm_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
-               rc = -EIO;
-               goto out_release;
+       if (tpm_tis_i2c_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
+               tpm_tis_i2c_release_locality(chip, 0, 1);
+               return -EIO;
        }
 
-       if (tpm_dev.chip_type == SLB9635) {
+       if (g_chip.chip_type == SLB9635) {
                vendor = be32_to_cpu(vendor);
                expected_did_vid = TPM_TIS_I2C_DID_VID_9635;
        } else {
@@ -607,14 +505,13 @@ int tpm_vendor_init(uint32_t dev_addr)
                expected_did_vid = TPM_TIS_I2C_DID_VID_9645;
        }
 
-       if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) {
+       if (g_chip.chip_type != UNKNOWN && vendor != expected_did_vid) {
                error("Vendor id did not match! ID was %08x\n", vendor);
-               rc = -ENODEV;
-               goto out_release;
+               return -ENODEV;
        }
 
        debug("1.2 TPM (chip type %s device-id 0x%X)\n",
-             chip_name[tpm_dev.chip_type], vendor >> 16);
+             chip_name[g_chip.chip_type], vendor >> 16);
 
        /*
         * A timeout query to TPM can be placed here.
@@ -622,16 +519,227 @@ int tpm_vendor_init(uint32_t dev_addr)
         */
 
        return 0;
+}
 
-out_release:
-       release_locality(chip, 0, 1);
+/* Returns max number of milliseconds to wait */
+static unsigned long tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip *chip,
+                                                      u32 ordinal)
+{
+       int duration_idx = TPM_UNDEFINED;
+       int duration = 0;
+
+       if (ordinal < TPM_MAX_ORDINAL) {
+               duration_idx = tpm_ordinal_duration[ordinal];
+       } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
+                       TPM_MAX_PROTECTED_ORDINAL) {
+               duration_idx = tpm_protected_ordinal_duration[
+                               ordinal & TPM_PROTECTED_ORDINAL_MASK];
+       }
 
-out_err:
-       tpm_dev.addr = old_addr;
+       if (duration_idx != TPM_UNDEFINED)
+               duration = chip->duration[duration_idx];
+
+       if (duration <= 0)
+               return 2 * 60 * HZ; /* Two minutes timeout */
+       else
+               return duration;
+}
+
+static ssize_t tpm_tis_i2c_transmit(const unsigned char *buf, size_t bufsiz)
+{
+       int rc;
+       u32 count, ordinal;
+       unsigned long start, stop;
+
+       struct tpm_chip *chip = &g_chip;
+
+       /* switch endianess: big->little */
+       count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE);
+       ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE);
+
+       if (count == 0) {
+               error("no data\n");
+               return -ENODATA;
+       }
+       if (count > bufsiz) {
+               error("invalid count value %x %zx\n", count, bufsiz);
+               return -E2BIG;
+       }
+
+       debug("Calling send\n");
+       rc = tpm_tis_i2c_send(chip, (u8 *)buf, count);
+       debug("   ... done calling send\n");
+       if (rc < 0) {
+               error("tpm_transmit: tpm_send: error %d\n", rc);
+               goto out;
+       }
+
+       if (chip->irq)
+               goto out_recv;
+
+       start = get_timer(0);
+       stop = tpm_tis_i2c_calc_ordinal_duration(chip, ordinal);
+       do {
+               debug("waiting for status... %ld %ld\n", start, stop);
+               u8 status = tpm_tis_i2c_status(chip);
+               if ((status & chip->req_complete_mask) ==
+                   chip->req_complete_val) {
+                       debug("...got it;\n");
+                       goto out_recv;
+               }
+
+               if (status == chip->req_canceled) {
+                       error("Operation Canceled\n");
+                       rc = -ECANCELED;
+                       goto out;
+               }
+               udelay(TPM_TIMEOUT * 1000);
+       } while (get_timer(start) < stop);
+
+       tpm_tis_i2c_ready(chip);
+       error("Operation Timed out\n");
+       rc = -ETIME;
+       goto out;
+
+out_recv:
+       debug("out_recv: reading response...\n");
+       rc = tpm_tis_i2c_recv(chip, (u8 *)buf, TPM_BUFSIZE);
+       if (rc < 0)
+               error("tpm_transmit: tpm_recv: error %d\n", rc);
+
+out:
        return rc;
 }
 
-void tpm_vendor_cleanup(struct tpm_chip *chip)
+/**
+ * Decode TPM configuration.
+ *
+ * @param dev  Returns a configuration of TPM device
+ * @return 0 if ok, -1 on error
+ */
+static int tpm_tis_i2c_decode_config(struct tpm_chip *chip)
+{
+       const void *blob = gd->fdt_blob;
+       struct udevice *bus;
+       int chip_addr;
+       int parent;
+       int node;
+       int ret;
+
+       node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
+       if (node < 0) {
+               node = fdtdec_next_compatible(blob, 0,
+                               COMPAT_INFINEON_SLB9645_TPM);
+       }
+       if (node < 0) {
+               debug("%s: Node not found\n", __func__);
+               return -1;
+       }
+       parent = fdt_parent_offset(blob, node);
+       if (parent < 0) {
+               debug("%s: Cannot find node parent\n", __func__);
+               return -1;
+       }
+
+       /*
+        * TODO(sjg@chromium.org): Remove this when driver model supports
+        * TPMs
+        */
+       ret = uclass_get_device_by_of_offset(UCLASS_I2C, parent, &bus);
+       if (ret) {
+               debug("Cannot find bus for node '%s: ret=%d'\n",
+                     fdt_get_name(blob, parent, NULL), ret);
+               return ret;
+       }
+
+       chip_addr = fdtdec_get_int(blob, node, "reg", -1);
+       if (chip_addr == -1) {
+               debug("Cannot find reg property for node '%s: ret=%d'\n",
+                     fdt_get_name(blob, node, NULL), ret);
+               return ret;
+       }
+       /*
+        * TODO(sjg@chromium.org): Older TPMs will need to use the older method
+        * in tpm_tis_i2c_read() so the offset length needs to be 0 here.
+        */
+       ret = i2c_get_chip(bus, chip_addr, 1, &chip->dev);
+       if (ret) {
+               debug("Cannot find device for node '%s: ret=%d'\n",
+                     fdt_get_name(blob, node, NULL), ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int tis_init(void)
 {
-       release_locality(chip, chip->vendor.locality, 1);
+       if (g_chip.inited)
+               return 0;
+
+       if (tpm_tis_i2c_decode_config(&g_chip))
+               return -1;
+
+       debug("%s: done\n", __func__);
+
+       g_chip.inited = 1;
+
+       return 0;
+}
+
+int tis_open(void)
+{
+       int rc;
+
+       if (!g_chip.inited)
+               return -1;
+
+       debug("%s: start\n", __func__);
+       if (g_chip.is_open)
+               return -EBUSY;
+       rc = tpm_tis_i2c_init(g_chip.dev);
+       if (rc < 0)
+               g_chip.is_open = 0;
+
+       return rc;
+}
+
+int tis_close(void)
+{
+       if (!g_chip.inited)
+               return -1;
+
+       if (g_chip.is_open) {
+               tpm_tis_i2c_release_locality(&g_chip, g_chip.locality, 1);
+               g_chip.is_open = 0;
+       }
+
+       return 0;
+}
+
+int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
+               uint8_t *recvbuf, size_t *rbuf_len)
+{
+       int len;
+       uint8_t buf[4096];
+
+       if (!g_chip.inited)
+               return -1;
+
+       if (sizeof(buf) < sbuf_size)
+               return -1;
+
+       memcpy(buf, sendbuf, sbuf_size);
+
+       len = tpm_tis_i2c_transmit(buf, sbuf_size);
+
+       if (len < 10) {
+               *rbuf_len = 0;
+               return -1;
+       }
+
+       memcpy(recvbuf, buf, len);
+       *rbuf_len = len;
+
+       return 0;
 }