switch-coreboot/src/drivers/i2c/tpm/tpm.c
Duncan Laurie 36c775ce26 UPSTREAM: drivers/i2c/tpm: Clean up handling of command ready
The TPM driver was largely ignoring the meaning of the command
ready bit in the status register, instead just arbitrarily
sending it at the end of every receive transaction.

Instead of doing this have the command ready bit be set at the
start of a transaction, and only clear it at the end of a
transaction if it is still set, in case of failure.

Also the cr50 function to wait for status and burst count was
not waiting the full 2s that the existing driver does so that
value is increased.  Also, during the probe routine a delay is
inserted after each status register read to ensure the TPM has
time to actually start up.

BUG=None
BRANCH=None
TEST=None

Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://review.coreboot.org/16591
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@googlemail.com>

Change-Id: I1c66ea9849e6be537c7be06d57258f27c563c1c2
Reviewed-on: https://chromium-review.googlesource.com/385897
Commit-Ready: Furquan Shaikh <furquan@chromium.org>
Tested-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
2016-09-15 13:41:16 -07:00

827 lines
21 KiB
C

/*
* Copyright (C) 2011 Infineon Technologies
*
* Authors:
* Peter Huewe <huewe.external@infineon.com>
*
* Description:
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*
* This device driver implements the TPM interface as defined in
* the TCG TPM Interface Spec version 1.2, revision 1.0 and the
* Infineon I2C Protocol Stack Specification v0.20.
*
* It is based on the Linux kernel driver tpm.c from Leendert van
* Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
*
* Version: 2.1.1
*
* 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.
*/
#include <arch/early_variables.h>
#include <commonlib/endian.h>
#include <stdint.h>
#include <string.h>
#include <types.h>
#include <delay.h>
#include <console/console.h>
#include <device/i2c.h>
#include <endian.h>
#include <timer.h>
#include "tpm.h"
/* max. number of iterations after I2C NAK */
#define MAX_COUNT 3
#define SLEEP_DURATION 60 /* in usec */
#define SLEEP_DURATION_LONG 210 /* in usec */
#define SLEEP_DURATION_SAFE 750 /* in usec */
#define SLEEP_DURATION_PROBE_MS 1000 /* in msec */
/* 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
/* expected value for DIDVID register */
#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
#define TPM_TIS_I2C_DID_VID_CR50 0x00281ae0L
enum i2c_chip_type {
SLB9635,
SLB9645,
CR50,
UNKNOWN,
};
static const char * const chip_name[] = {
[SLB9635] = "slb9635tt",
[SLB9645] = "slb9645tt",
[CR50] = "cr50",
[UNKNOWN] = "unknown/fallback to slb9635",
};
/* Structure to store I2C TPM specific stuff */
struct tpm_inf_dev {
int bus;
unsigned int addr;
unsigned int sleep_short; /* Short sleep duration in usec */
unsigned int sleep_long; /* Long sleep duration in usec */
uint8_t buf[TPM_BUFSIZE + sizeof(uint8_t)]; // max. buffer size + addr
enum i2c_chip_type chip_type;
};
static struct tpm_inf_dev g_tpm_dev CAR_GLOBAL;
/*
* iic_tpm_read() - read from TPM register
* @addr: register address to read from
* @buffer: provided by caller
* @len: number of bytes to read
*
* Read len bytes from TPM register and put them into
* buffer (little-endian format, i.e. first byte is put into buffer[0]).
*
* NOTE: TPM is big-endian for multi-byte values. Multi-byte
* values have to be swapped.
*
* Return -1 on error, 0 on success.
*/
static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len)
{
struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);
int rc;
int count;
if (tpm_dev->addr == 0)
return -1;
switch (tpm_dev->chip_type) {
case SLB9635:
case CR50:
case UNKNOWN:
/* slb9635 protocol should work in both cases */
for (count = 0; count < MAX_COUNT; count++) {
rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr,
&addr, 1);
if (rc == 0)
break; /* success, break to skip sleep */
udelay(tpm_dev->sleep_short);
}
if (rc)
return -1;
/* After the TPM has successfully received the register address
* it needs some time, thus we're sleeping here again, before
* retrieving the data
*/
for (count = 0; count < MAX_COUNT; count++) {
udelay(tpm_dev->sleep_short);
rc = i2c_read_raw(tpm_dev->bus, tpm_dev->addr,
buffer, len);
if (rc == 0)
break; /* success, break to skip sleep */
}
break;
default:
{
/* use a combined read for newer chips
* unfortunately the smbus functions are not suitable due to
* the 32 byte limit of the smbus.
* retries should usually not be needed, but are kept just to
* be safe on the safe side.
*/
struct i2c_seg aseg = { .read = 0, .chip = tpm_dev->addr,
.buf = &addr, .len = 1 };
struct i2c_seg dseg = { .read = 1, .chip = tpm_dev->addr,
.buf = buffer, .len = len };
for (count = 0; count < MAX_COUNT; count++) {
rc = i2c_transfer(tpm_dev->bus, &aseg, 1) ||
i2c_transfer(tpm_dev->bus, &dseg, 1);
if (rc == 0)
break; /* break here to skip sleep */
udelay(tpm_dev->sleep_short);
}
}
}
/* take care of 'guard time' */
udelay(tpm_dev->sleep_short);
if (rc)
return -1;
return 0;
}
static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len,
unsigned int sleep_time,
uint8_t max_count)
{
struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);
int rc = 0;
int count;
if (len > TPM_BUFSIZE) {
printk(BIOS_DEBUG, "%s: Length %zd is too large\n", __func__, len);
return -1;
}
/* prepare send buffer */
tpm_dev->buf[0] = addr;
memcpy(&(tpm_dev->buf[1]), buffer, len);
if (tpm_dev->addr == 0)
return -1;
for (count = 0; count < max_count; count++) {
rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr,
tpm_dev->buf, len + 1);
if (rc == 0)
break; /* success, break to skip sleep */
udelay(sleep_time);
}
/* take care of 'guard time' */
udelay(tpm_dev->sleep_short);
if (rc)
return -1;
return 0;
}
/*
* iic_tpm_write() - write to TPM register
* @addr: register address to write to
* @buffer: containing data to be written
* @len: number of bytes to write
*
* Write len bytes from provided buffer to TPM register (little
* endian format, i.e. buffer[0] is written as first byte).
*
* 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.
*
* Return -EIO on error, 0 on success
*/
static int iic_tpm_write(uint8_t addr, uint8_t *buffer, size_t len)
{
struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);
return iic_tpm_write_generic(addr, buffer, len, tpm_dev->sleep_short,
MAX_COUNT);
}
/*
* This function is needed especially for the cleanup situation after
* sending TPM_READY
* */
static int iic_tpm_write_long(uint8_t addr, uint8_t *buffer, size_t len)
{
struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);
return iic_tpm_write_generic(addr, buffer, len, tpm_dev->sleep_long,
MAX_COUNT_LONG);
}
#define TPM_HEADER_SIZE 10
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,
};
#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))
static int check_locality(struct tpm_chip *chip, int loc)
{
uint8_t buf;
if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0)
return -1;
if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
chip->vendor.locality = loc;
return loc;
}
return -1;
}
static void release_locality(struct tpm_chip *chip, int loc, int force)
{
uint8_t buf;
if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0)
return;
if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
(TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
buf = TPM_ACCESS_ACTIVE_LOCALITY;
iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
}
}
static int request_locality(struct tpm_chip *chip, int loc)
{
uint8_t buf = TPM_ACCESS_REQUEST_USE;
if (check_locality(chip, loc) >= 0)
return loc; /* we already have the locality */
iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
/* wait for burstcount */
int timeout = 2 * 1000; /* 2s timeout */
while (timeout) {
if (check_locality(chip, loc) >= 0)
return loc;
mdelay(TPM_TIMEOUT);
timeout--;
}
return -1;
}
static uint8_t tpm_tis_i2c_status(struct tpm_chip *chip)
{
/* NOTE: Since I2C read may fail, return 0 in this case --> time-out */
uint8_t buf;
if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
return 0;
else
return buf;
}
static void tpm_tis_i2c_ready(struct tpm_chip *chip)
{
/* this causes the current command to be aborted */
uint8_t buf = TPM_STS_COMMAND_READY;
iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1);
}
static ssize_t get_burstcount(struct tpm_chip *chip)
{
ssize_t burstcnt;
uint8_t buf[3];
/* wait for burstcount */
int timeout = 2 * 1000; /* 2s timeout */
while (timeout) {
/* Note: STS is little endian */
if (iic_tpm_read(TPM_STS(chip->vendor.locality) + 1, buf, 3) < 0)
burstcnt = 0;
else
burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
if (burstcnt)
return burstcnt;
mdelay(TPM_TIMEOUT);
timeout--;
}
return -1;
}
static int wait_for_stat(struct tpm_chip *chip, uint8_t mask, int *status)
{
unsigned long timeout = 2 * 1024;
while (timeout) {
*status = tpm_tis_i2c_status(chip);
if ((*status & mask) == mask)
return 0;
mdelay(TPM_TIMEOUT);
timeout--;
}
return -1;
}
static int recv_data(struct tpm_chip *chip, uint8_t *buf, size_t count)
{
size_t size = 0;
while (size < count) {
ssize_t burstcnt = get_burstcount(chip);
int rc;
/* burstcount < 0 = TPM is busy */
if (burstcnt < 0)
return burstcnt;
/* limit received data to max. left */
if (burstcnt > (count - size))
burstcnt = count - size;
rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality),
&(buf[size]),
burstcnt);
if (rc == 0)
size += burstcnt;
}
return size;
}
static int tpm_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf, size_t count)
{
int size = 0;
uint32_t expected;
int status;
if (count < TPM_HEADER_SIZE) {
size = -1;
goto out;
}
/* read first 10 bytes, including tag, paramsize, and result */
size = recv_data(chip, buf, TPM_HEADER_SIZE);
if (size < TPM_HEADER_SIZE) {
printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Unable to read header\n");
goto out;
}
memcpy(&expected, buf + TPM_RSP_SIZE_BYTE, sizeof(expected));
expected = be32_to_cpu(expected);
if ((size_t)expected > count) {
size = -1;
goto out;
}
size += recv_data(chip, &buf[TPM_HEADER_SIZE],
expected - TPM_HEADER_SIZE);
if (size < expected) {
printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Unable to "
"read remainder of result\n");
size = -1;
goto out;
}
wait_for_stat(chip, TPM_STS_VALID, &status);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Error left over data\n");
size = -1;
goto out;
}
out:
tpm_tis_i2c_ready(chip);
return size;
}
static int tpm_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len)
{
int status;
size_t count = 0;
uint8_t sts = TPM_STS_GO;
if (len > TPM_BUFSIZE)
return -1; /* command is too long for our TPM, sorry */
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, &status) < 0)
goto out_err;
}
while (count < len - 1) {
ssize_t burstcnt = get_burstcount(chip);
/* burstcount < 0 = TPM is busy */
if (burstcnt < 0)
return burstcnt;
if (burstcnt > (len-1-count))
burstcnt = len-1-count;
#ifdef CONFIG_TPM_I2C_BURST_LIMITATION
if (burstcnt > CONFIG_TPM_I2C_BURST_LIMITATION)
burstcnt = CONFIG_TPM_I2C_BURST_LIMITATION;
#endif /* CONFIG_TPM_I2C_BURST_LIMITATION */
if (iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality),
&(buf[count]), burstcnt) == 0)
count += burstcnt;
wait_for_stat(chip, TPM_STS_VALID, &status);
if ((status & TPM_STS_DATA_EXPECT) == 0)
goto out_err;
}
/* write last byte */
iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1);
wait_for_stat(chip, TPM_STS_VALID, &status);
if ((status & TPM_STS_DATA_EXPECT) != 0)
goto out_err;
/* go and do it */
iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1);
return len;
out_err:
tpm_tis_i2c_ready(chip);
return -1;
}
/*
* cr50 is a TPM 2.0 capable device that requries special
* handling for the I2C interface.
*
* - Timeouts need to be longer
* - Must use the older SLB9635 style write+wait+read read protocol
* - All 4 bytes of status register must be read at once
* - Burst count max is 63 bytes, and burst count behaves
* slightly differently than other I2C TPMs
* - When reading from FIFO the full burstcnt must be read
* instead of just reading header and determining the remainder
*/
/* cr50 max burst count */
#define CR50_MAX_BURSTCOUNT 63
/* cr50 requires all 4 bytes of status register to be read */
static uint8_t cr50_tis_i2c_status(struct tpm_chip *chip)
{
uint8_t buf[4];
if (iic_tpm_read(TPM_STS(chip->vendor.locality),
buf, sizeof(buf)) < 0) {
printk(BIOS_ERR, "%s: Failed to read status\n", __func__);
return 0;
}
return buf[0];
}
/* cr50 requires all 4 bytes of status register to be written */
static void cr50_tis_i2c_ready(struct tpm_chip *chip)
{
uint8_t buf[4] = { TPM_STS_COMMAND_READY };
iic_tpm_write_long(TPM_STS(chip->vendor.locality), buf, sizeof(buf));
}
/* cr50 uses bytes 3:2 of status register for burst count and
* all 4 bytes must be read */
static int cr50_wait_burst_status(struct tpm_chip *chip, uint8_t mask,
size_t *burst, int *status)
{
uint8_t buf[4];
struct stopwatch sw;
stopwatch_init_msecs_expire(&sw, 2000);
while (!stopwatch_expired(&sw)) {
if (iic_tpm_read(TPM_STS(chip->vendor.locality),
buf, sizeof(buf)) != 0) {
printk(BIOS_WARNING, "%s: Read failed\n", __func__);
udelay(SLEEP_DURATION_SAFE);
continue;
}
*status = buf[0];
*burst = read_le16(&buf[1]);
/* Check if mask matches and burst is valid */
if ((*status & mask) == mask &&
*burst > 0 && *burst <= CR50_MAX_BURSTCOUNT)
return 0;
udelay(SLEEP_DURATION_SAFE);
}
printk(BIOS_ERR, "%s: Timeout reading burst and status\n", __func__);
return -1;
}
static int cr50_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf,
size_t buf_len)
{
size_t burstcnt, current, len, expected;
uint8_t addr = TPM_DATA_FIFO(chip->vendor.locality);
int status;
int ret = -1;
if (buf_len < TPM_HEADER_SIZE)
goto out;
if (cr50_wait_burst_status(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
goto out;
if (!(status & TPM_STS_DATA_AVAIL)) {
printk(BIOS_ERR, "%s: First chunk not available\n", __func__);
goto out;
}
/* Read first chunk of burstcnt bytes */
if (iic_tpm_read(addr, buf, burstcnt) != 0) {
printk(BIOS_ERR, "%s: Read failed\n", __func__);
goto out;
}
/* Determine expected data in the return buffer */
expected = read_be32(buf + TPM_RSP_SIZE_BYTE);
if (expected > buf_len) {
printk(BIOS_ERR, "%s: Too much data: %zu > %zu\n",
__func__, expected, buf_len);
goto out;
}
/* Now read the rest of the data */
current = burstcnt;
while (current < expected) {
/* Read updated burst count and check status */
if (cr50_wait_burst_status(chip, TPM_STS_VALID,
&burstcnt, &status) < 0)
goto out;
if (!(status & TPM_STS_DATA_AVAIL)) {
printk(BIOS_ERR, "%s: Data not available\n", __func__);
goto out;
}
len = min(burstcnt, expected - current);
if (iic_tpm_read(addr, buf + current, len) != 0) {
printk(BIOS_ERR, "%s: Read failed\n", __func__);
goto out;
}
current += len;
}
/* Ensure TPM is done reading data */
if (cr50_wait_burst_status(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
goto out;
if (status & TPM_STS_DATA_AVAIL) {
printk(BIOS_ERR, "%s: Data still available\n", __func__);
goto out;
}
ret = current;
out:
return ret;
}
static int cr50_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len)
{
int status;
size_t burstcnt, limit, sent = 0;
uint8_t tpm_go[4] = { TPM_STS_GO };
struct stopwatch sw;
if (len > TPM_BUFSIZE)
return -1;
stopwatch_init_msecs_expire(&sw, 2000);
/* Wait until TPM is ready for a command */
while (!(cr50_tis_i2c_status(chip) & TPM_STS_COMMAND_READY)) {
if (stopwatch_expired(&sw)) {
printk(BIOS_ERR, "%s: Command ready timeout\n",
__func__);
return -1;
}
cr50_tis_i2c_ready(chip);
udelay(SLEEP_DURATION_SAFE);
}
while (len > 0) {
/* Read burst count and check status */
if (cr50_wait_burst_status(chip, TPM_STS_VALID,
&burstcnt, &status) < 0)
goto out;
if (sent > 0 && !(status & TPM_STS_DATA_EXPECT)) {
printk(BIOS_ERR, "%s: Data not expected\n", __func__);
goto out;
}
/* Use burstcnt - 1 to account for the address byte
* that is inserted by iic_tpm_write() */
limit = min(burstcnt - 1, len);
if (iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality),
&buf[sent], limit) != 0) {
printk(BIOS_ERR, "%s: Write failed\n", __func__);
goto out;
}
sent += limit;
len -= limit;
}
/* Ensure TPM is not expecting more data */
if (cr50_wait_burst_status(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
goto out;
if (status & TPM_STS_DATA_EXPECT) {
printk(BIOS_ERR, "%s: Data still expected\n", __func__);
goto out;
}
/* Start the TPM command */
if (iic_tpm_write(TPM_STS(chip->vendor.locality), tpm_go,
sizeof(tpm_go)) < 0) {
printk(BIOS_ERR, "%s: Start command failed\n", __func__);
goto out;
}
return sent;
out:
/* Abort current transaction if still pending */
if (cr50_tis_i2c_status(chip) & TPM_STS_COMMAND_READY)
cr50_tis_i2c_ready(chip);
return -1;
}
/* Initialization of I2C TPM */
int tpm_vendor_probe(unsigned bus, uint32_t addr)
{
struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);
struct stopwatch sw;
uint8_t buf = 0;
int ret;
long sw_run_duration = SLEEP_DURATION_PROBE_MS;
tpm_dev->chip_type = UNKNOWN;
tpm_dev->bus = bus;
tpm_dev->addr = addr;
tpm_dev->sleep_short = SLEEP_DURATION_SAFE;
tpm_dev->sleep_long = SLEEP_DURATION_SAFE * 2;
/*
* Probe TPM. Check if the TPM_ACCESS register's ValidSts bit is set(1)
* If the bit remains clear(0) then claim that init has failed.
*/
stopwatch_init_msecs_expire(&sw, sw_run_duration);
do {
ret = iic_tpm_read(TPM_ACCESS(0), &buf, 1);
if (!ret && (buf & TPM_STS_VALID)) {
sw_run_duration = stopwatch_duration_msecs(&sw);
break;
}
udelay(SLEEP_DURATION_SAFE);
} while (!stopwatch_expired(&sw));
printk(BIOS_INFO,
"%s: ValidSts bit %s(%d) in TPM_ACCESS register after %ld ms\n",
__func__, (buf & TPM_STS_VALID) ? "set" : "clear",
(buf & TPM_STS_VALID) >> 7, sw_run_duration);
/*
* Claim failure if the ValidSts (bit 7) is clear.
*/
if (!(buf & TPM_STS_VALID))
return -1;
return 0;
}
int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr)
{
struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);
uint32_t vendor;
if (dev_addr == 0) {
printk(BIOS_ERR, "%s: missing device address\n", __func__);
return -1;
}
tpm_dev->chip_type = UNKNOWN;
tpm_dev->bus = bus;
tpm_dev->addr = dev_addr;
/* Use conservative values to read chip id */
tpm_dev->sleep_short = SLEEP_DURATION_SAFE;
tpm_dev->sleep_long = SLEEP_DURATION_SAFE * 2;
memset(&chip->vendor, 0, sizeof(struct tpm_vendor_specific));
chip->is_open = 1;
chip->vendor.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID;
chip->vendor.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID;
chip->vendor.req_canceled = TPM_STS_COMMAND_READY;
/* Disable interrupts (not supported) */
chip->vendor.irq = 0;
if (request_locality(chip, 0) != 0)
return -1;
/* Read four bytes from DID_VID register */
if (iic_tpm_read(TPM_DID_VID(0), (uint8_t *)&vendor, 4) < 0)
goto out_err;
if (vendor == TPM_TIS_I2C_DID_VID_9645) {
tpm_dev->chip_type = SLB9645;
} else if (be32_to_cpu(vendor) == TPM_TIS_I2C_DID_VID_9635) {
tpm_dev->chip_type = SLB9635;
} else if (vendor == TPM_TIS_I2C_DID_VID_CR50) {
tpm_dev->chip_type = CR50;
} else {
printk(BIOS_DEBUG, "Vendor ID 0x%08x not recognized.\n", vendor);
goto out_err;
}
if (tpm_dev->chip_type == CR50) {
chip->vendor.status = &cr50_tis_i2c_status;
chip->vendor.recv = &cr50_tis_i2c_recv;
chip->vendor.send = &cr50_tis_i2c_send;
chip->vendor.cancel = &cr50_tis_i2c_ready;
} else {
tpm_dev->sleep_short = SLEEP_DURATION;
tpm_dev->sleep_long = SLEEP_DURATION_LONG;
chip->vendor.status = &tpm_tis_i2c_status;
chip->vendor.recv = &tpm_tis_i2c_recv;
chip->vendor.send = &tpm_tis_i2c_send;
chip->vendor.cancel = &tpm_tis_i2c_ready;
}
printk(BIOS_DEBUG, "I2C TPM %u:%02x (chip type %s device-id 0x%X)\n",
tpm_dev->bus, tpm_dev->addr,
chip_name[tpm_dev->chip_type], vendor >> 16);
/*
* A timeout query to TPM can be placed here.
* Standard timeout values are used so far
*/
return 0;
out_err:
release_locality(chip, 0, 1);
return -1;
}
void tpm_vendor_cleanup(struct tpm_chip *chip)
{
release_locality(chip, chip->vendor.locality, 1);
}