summaryrefslogtreecommitdiff
path: root/drivers/tpm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tpm')
-rw-r--r--drivers/tpm/Kconfig69
-rw-r--r--drivers/tpm/Makefile4
-rw-r--r--drivers/tpm/tpm-uclass.c133
-rw-r--r--drivers/tpm/tpm.c694
-rw-r--r--drivers/tpm/tpm_atmel_twi.c15
-rw-r--r--drivers/tpm/tpm_internal.h287
-rw-r--r--drivers/tpm/tpm_tis_i2c.c572
-rw-r--r--drivers/tpm/tpm_tis_i2c.h (renamed from drivers/tpm/tpm_private.h)88
-rw-r--r--drivers/tpm/tpm_tis_lpc.c290
-rw-r--r--drivers/tpm/tpm_tis_sandbox.c57
10 files changed, 974 insertions, 1235 deletions
diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
index f408b8a81d1..6bc8fddbd16 100644
--- a/drivers/tpm/Kconfig
+++ b/drivers/tpm/Kconfig
@@ -1,7 +1,76 @@
+#
+# TPM subsystem configuration
+#
+
+menu "TPM support"
+
+config DM_TPM
+ bool "Enable driver model for Trusted Platform Module drivers"
+ depends on DM && TPM
+ help
+ Enable driver model for TPMs. The TIS interface (tis_open(),
+ tis_sendrecv(), etc.) is then implemented by the TPM uclass. Note
+ that even with driver model only a single TPM is currently
+ supported, since the tpm library assumes this.
+
config TPM_TIS_SANDBOX
bool "Enable sandbox TPM driver"
+ depends on SANDBOX
help
This driver emulates a TPM, providing access to base functions
such as reading and writing TPM private data. This is enough to
support Chrome OS verified boot. Extend functionality is not
implemented.
+
+config TPM_ATMEL_TWI
+ bool "Enable Atmel TWI TPM device driver"
+ depends on TPM
+ help
+ This driver supports an Atmel TPM device connected on the I2C bus.
+ The usual tpm operations and the 'tpm' command can be used to talk
+ to the device using the standard TPM Interface Specification (TIS)
+ protocol
+
+config TPM_TIS_I2C
+ bool "Enable support for Infineon SLB9635/45 TPMs on I2C"
+ depends on TPM && DM_I2C
+ help
+ This driver supports Infineon TPM devices connected on the I2C bus.
+ The usual tpm operations and the 'tpm' command can be used to talk
+ to the device using the standard TPM Interface Specification (TIS)
+ protocol
+
+config TPM_TIS_I2C_BURST_LIMITATION
+ bool "Enable I2C burst length limitation"
+ depends on TPM_TIS_I2C
+ help
+ Some broken TPMs have a limitation on the number of bytes they can
+ receive in one message. Enable this option to allow you to set this
+ option. The can allow a broken TPM to be used by splitting messages
+ into separate pieces.
+
+config TPM_TIS_I2C_BURST_LIMITATION_LEN
+ int "Length"
+ depends on TPM_TIS_I2C_BURST_LIMITATION
+ help
+ Use this to set the burst limitation length
+
+config TPM_TIS_LPC
+ bool "Enable support for Infineon SLB9635/45 TPMs on LPC"
+ depends on TPM && X86
+ help
+ This driver supports Infineon TPM devices connected on the I2C bus.
+ The usual tpm operations and the 'tpm' command can be used to talk
+ to the device using the standard TPM Interface Specification (TIS)
+ protocol
+
+config TPM_AUTH_SESSIONS
+ bool "Enable TPM authentication session support"
+ depends on TPM
+ help
+ Enable support for authorised (AUTH1) commands as specified in the
+ TCG Main Specification 1.2. OIAP-authorised versions of the commands
+ TPM_LoadKey2 and TPM_GetPubKey are provided. Both features are
+ available using the 'tpm' command, too.
+
+endmenu
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 150570ee7e4..0d328f8d9d3 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# TODO: Merge tpm_tis_lpc.c with tpm.c
+obj-$(CONFIG_DM_TPM) += tpm-uclass.o
+
obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
-obj-$(CONFIG_TPM_TIS_I2C) += tpm.o
obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o
obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
new file mode 100644
index 00000000000..b6e1fc5e628
--- /dev/null
+++ b/drivers/tpm/tpm-uclass.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <tpm.h>
+#include <linux/unaligned/be_byteshift.h>
+#include "tpm_internal.h"
+
+int tpm_open(struct udevice *dev)
+{
+ struct tpm_ops *ops = tpm_get_ops(dev);
+
+ if (!ops->open)
+ return -ENOSYS;
+
+ return ops->open(dev);
+}
+
+int tpm_close(struct udevice *dev)
+{
+ struct tpm_ops *ops = tpm_get_ops(dev);
+
+ if (!ops->close)
+ return -ENOSYS;
+
+ return ops->close(dev);
+}
+
+int tpm_get_desc(struct udevice *dev, char *buf, int size)
+{
+ struct tpm_ops *ops = tpm_get_ops(dev);
+
+ if (!ops->get_desc)
+ return -ENOSYS;
+
+ return ops->get_desc(dev, buf, size);
+}
+
+/* Returns max number of milliseconds to wait */
+static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv,
+ 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];
+ }
+
+ if (duration_idx != TPM_UNDEFINED)
+ duration = priv->duration_ms[duration_idx];
+
+ if (duration <= 0)
+ return 2 * 60 * 1000; /* Two minutes timeout */
+ else
+ return duration;
+}
+
+int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
+ uint8_t *recvbuf, size_t *recv_size)
+{
+ struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+ struct tpm_ops *ops = tpm_get_ops(dev);
+ ulong start, stop;
+ uint count, ordinal;
+ int ret, ret2;
+
+ if (ops->xfer)
+ return ops->xfer(dev, sendbuf, send_size, recvbuf, recv_size);
+
+ if (!ops->send || !ops->recv)
+ return -ENOSYS;
+
+ /* switch endianess: big->little */
+ count = get_unaligned_be32(sendbuf + TPM_CMD_COUNT_BYTE);
+ ordinal = get_unaligned_be32(sendbuf + TPM_CMD_ORDINAL_BYTE);
+
+ if (count == 0) {
+ debug("no data\n");
+ return -ENODATA;
+ }
+ if (count > send_size) {
+ debug("invalid count value %x %zx\n", count, send_size);
+ return -E2BIG;
+ }
+
+ debug("%s: Calling send\n", __func__);
+ ret = ops->send(dev, sendbuf, send_size);
+ if (ret < 0)
+ return ret;
+
+ start = get_timer(0);
+ stop = tpm_tis_i2c_calc_ordinal_duration(priv, ordinal);
+ do {
+ ret = ops->recv(dev, priv->buf, sizeof(priv->buf));
+ if (ret >= 0) {
+ if (ret > *recv_size)
+ return -ENOSPC;
+ memcpy(recvbuf, priv->buf, ret);
+ *recv_size = ret;
+ ret = 0;
+ break;
+ } else if (ret != -EAGAIN) {
+ return ret;
+ }
+
+ mdelay(priv->retry_time_ms);
+ if (get_timer(start) > stop) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ } while (ret);
+
+ ret2 = ops->cleanup ? ops->cleanup(dev) : 0;
+
+ return ret2 ? ret2 : ret;
+}
+
+UCLASS_DRIVER(tpm) = {
+ .id = UCLASS_TPM,
+ .name = "tpm",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .per_device_auto_alloc_size = sizeof(struct tpm_chip_priv),
+};
diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c
deleted file mode 100644
index a650892f09a..00000000000
--- a/drivers/tpm/tpm.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * 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
- *
- * 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
- *
- * 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
- */
-
-#include <config.h>
-#include <common.h>
-#include <dm.h>
-#include <linux/compiler.h>
-#include <fdtdec.h>
-#include <i2c.h>
-#include <tpm.h>
-#include <asm-generic/errno.h>
-#include <linux/types.h>
-#include <linux/unaligned/be_byteshift.h>
-
-#include "tpm_private.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-/* TPM configuration */
-struct tpm {
-#ifdef CONFIG_DM_I2C
- struct udevice *dev;
-#else
- int i2c_bus;
- int slave_addr;
- int old_bus;
-#endif
- char inited;
-} tpm;
-
-/* Global structure for tpm chip data */
-static struct tpm_chip g_chip;
-
-enum tpm_duration {
- TPM_SHORT = 0,
- TPM_MEDIUM = 1,
- TPM_LONG = 2,
- TPM_UNDEFINED,
-};
-
-/* Extended error numbers from linux (see errno.h) */
-#define ECANCELED 125 /* Operation Canceled */
-
-/* Timer frequency. Corresponds to msec timer resolution*/
-#define HZ 1000
-
-#define TPM_MAX_ORDINAL 243
-#define TPM_MAX_PROTECTED_ORDINAL 12
-#define TPM_PROTECTED_ORDINAL_MASK 0xFF
-
-#define TPM_CMD_COUNT_BYTE 2
-#define TPM_CMD_ORDINAL_BYTE 6
-
-/*
- * Array with one entry per ordinal defining the maximum amount
- * of time the chip could take to return the result. The ordinal
- * designation of short, medium or long is defined in a table in
- * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
- * values of the SHORT, MEDIUM, and LONG durations are retrieved
- * from the chip during initialization with a call to tpm_get_timeouts.
- */
-static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
- TPM_UNDEFINED, /* 0 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 5 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 10 */
- TPM_SHORT,
-};
-
-static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
- TPM_UNDEFINED, /* 0 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 5 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 10 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_LONG,
- TPM_LONG,
- TPM_MEDIUM, /* 15 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_LONG,
- TPM_SHORT, /* 20 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_SHORT, /* 25 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM, /* 30 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 35 */
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 40 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 45 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_LONG,
- TPM_MEDIUM, /* 50 */
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 55 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 60 */
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM, /* 65 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 70 */
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 75 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_LONG, /* 80 */
- TPM_UNDEFINED,
- TPM_MEDIUM,
- TPM_LONG,
- TPM_SHORT,
- TPM_UNDEFINED, /* 85 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 90 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED, /* 95 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 100 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 105 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 110 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 115 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_LONG, /* 120 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_SHORT, /* 125 */
- TPM_SHORT,
- TPM_LONG,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 130 */
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_UNDEFINED, /* 135 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 140 */
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 145 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 150 */
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED, /* 155 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 160 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 165 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_LONG, /* 170 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 175 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 180 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM, /* 185 */
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 190 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 195 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 200 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_SHORT, /* 205 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM, /* 210 */
- TPM_UNDEFINED,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_UNDEFINED, /* 215 */
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_SHORT, /* 220 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED, /* 225 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 230 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 235 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 240 */
- TPM_UNDEFINED,
- TPM_MEDIUM,
-};
-
-/* Returns max number of milliseconds to wait */
-static unsigned long tpm_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];
- }
-
- if (duration_idx != TPM_UNDEFINED)
- duration = chip->vendor.duration[duration_idx];
-
- if (duration <= 0)
- return 2 * 60 * HZ; /* Two minutes timeout */
- else
- return duration;
-}
-
-static ssize_t tpm_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 = chip->vendor.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->vendor.irq)
- goto out_recv;
-
- start = get_timer(0);
- stop = tpm_calc_ordinal_duration(chip, ordinal);
- do {
- debug("waiting for status... %ld %ld\n", start, stop);
- u8 status = chip->vendor.status(chip);
- if ((status & chip->vendor.req_complete_mask) ==
- chip->vendor.req_complete_val) {
- debug("...got it;\n");
- goto out_recv;
- }
-
- if (status == chip->vendor.req_canceled) {
- error("Operation Canceled\n");
- rc = -ECANCELED;
- goto out;
- }
- udelay(TPM_TIMEOUT * 1000);
- } while (get_timer(start) < stop);
-
- chip->vendor.cancel(chip);
- error("Operation Timed out\n");
- rc = -ETIME;
- goto out;
-
-out_recv:
- debug("out_recv: reading response...\n");
- rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE);
- if (rc < 0)
- error("tpm_transmit: tpm_recv: error %d\n", rc);
-
-out:
- return rc;
-}
-
-#ifdef CONFIG_DM_I2C
-static int tpm_open_dev(struct udevice *dev)
-{
- int rc;
-
- debug("%s: start\n", __func__);
- if (g_chip.is_open)
- return -EBUSY;
- rc = tpm_vendor_init_dev(dev);
- if (rc < 0)
- g_chip.is_open = 0;
- return rc;
-}
-#else
-static int tpm_open(uint32_t dev_addr)
-{
- int rc;
-
- if (g_chip.is_open)
- return -EBUSY;
- rc = tpm_vendor_init(dev_addr);
- if (rc < 0)
- g_chip.is_open = 0;
- return rc;
-}
-#endif
-static void tpm_close(void)
-{
- if (g_chip.is_open) {
- tpm_vendor_cleanup(&g_chip);
- g_chip.is_open = 0;
- }
-}
-
-static int tpm_select(void)
-{
-#ifndef CONFIG_DM_I2C
- int ret;
-
- tpm.old_bus = i2c_get_bus_num();
- if (tpm.old_bus != tpm.i2c_bus) {
- ret = i2c_set_bus_num(tpm.i2c_bus);
- if (ret) {
- debug("%s: Fail to set i2c bus %d\n", __func__,
- tpm.i2c_bus);
- return -1;
- }
- }
-#endif
- return 0;
-}
-
-static int tpm_deselect(void)
-{
-#ifndef CONFIG_DM_I2C
- int ret;
-
- if (tpm.old_bus != i2c_get_bus_num()) {
- ret = i2c_set_bus_num(tpm.old_bus);
- if (ret) {
- debug("%s: Fail to restore i2c bus %d\n",
- __func__, tpm.old_bus);
- return -1;
- }
- }
- tpm.old_bus = -1;
-#endif
- return 0;
-}
-
-/**
- * Decode TPM configuration.
- *
- * @param dev Returns a configuration of TPM device
- * @return 0 if ok, -1 on error
- */
-static int tpm_decode_config(struct tpm *dev)
-{
- const void *blob = gd->fdt_blob;
- int parent;
- int node;
-
- 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;
- }
-#ifdef CONFIG_DM_I2C
- struct udevice *bus;
- int chip_addr;
- int ret;
-
- /*
- * 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 iic_tpm_read() so the offset length needs to be 0 here.
- */
- ret = i2c_get_chip(bus, chip_addr, 1, &dev->dev);
- if (ret) {
- debug("Cannot find device for node '%s: ret=%d'\n",
- fdt_get_name(blob, node, NULL), ret);
- return ret;
- }
-#else
- int i2c_bus;
-
- i2c_bus = i2c_get_bus_num_fdt(parent);
- if (i2c_bus < 0)
- return -1;
- dev->i2c_bus = i2c_bus;
- dev->slave_addr = fdtdec_get_addr(blob, node, "reg");
-#endif
-
- return 0;
-}
-
-struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry)
-{
- struct tpm_chip *chip;
-
- /* Driver specific per-device data */
- chip = &g_chip;
- memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
- chip->is_open = 1;
-
- return chip;
-}
-
-int tis_init(void)
-{
- if (tpm.inited)
- return 0;
-
- if (tpm_decode_config(&tpm))
- return -1;
-
- if (tpm_select())
- return -1;
-
-#ifndef CONFIG_DM_I2C
- /*
- * Probe TPM twice; the first probing might fail because TPM is asleep,
- * and the probing can wake up TPM.
- */
- if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) {
- debug("%s: fail to probe i2c addr 0x%x\n", __func__,
- tpm.slave_addr);
- return -1;
- }
-#endif
-
- tpm_deselect();
- debug("%s: done\n", __func__);
-
- tpm.inited = 1;
-
- return 0;
-}
-
-int tis_open(void)
-{
- int rc;
-
- if (!tpm.inited)
- return -1;
-
- if (tpm_select())
- return -1;
-
-#ifdef CONFIG_DM_I2C
- rc = tpm_open_dev(tpm.dev);
-#else
- rc = tpm_open(tpm.slave_addr);
-#endif
-
- tpm_deselect();
-
- return rc;
-}
-
-int tis_close(void)
-{
- if (!tpm.inited)
- return -1;
-
- if (tpm_select())
- return -1;
-
- tpm_close();
-
- tpm_deselect();
-
- 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 (!tpm.inited)
- return -1;
-
- if (sizeof(buf) < sbuf_size)
- return -1;
-
- memcpy(buf, sendbuf, sbuf_size);
-
- if (tpm_select())
- return -1;
-
- len = tpm_transmit(buf, sbuf_size);
-
- tpm_deselect();
-
- if (len < 10) {
- *rbuf_len = 0;
- return -1;
- }
-
- memcpy(recvbuf, buf, len);
- *rbuf_len = len;
-
- return 0;
-}
diff --git a/drivers/tpm/tpm_atmel_twi.c b/drivers/tpm/tpm_atmel_twi.c
index 361a7720fa5..205d7a5d97d 100644
--- a/drivers/tpm/tpm_atmel_twi.c
+++ b/drivers/tpm/tpm_atmel_twi.c
@@ -1,18 +1,9 @@
/*
- * 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; either version 2 of
- * the License, or (at your option) any later version.
+ * Copyright (C) 2013 Guntermann & Drunck, GmbH
*
- * 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.
+ * Written by Dirk Eibach <eibach@gdsys.de>
*
- * 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>
diff --git a/drivers/tpm/tpm_internal.h b/drivers/tpm/tpm_internal.h
new file mode 100644
index 00000000000..cd29dba0b68
--- /dev/null
+++ b/drivers/tpm/tpm_internal.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __tpm_internal_h
+#define __tpm_internal_h
+
+enum {
+ TPM_MAX_ORDINAL = 243,
+ TPM_MAX_PROTECTED_ORDINAL = 12,
+ TPM_PROTECTED_ORDINAL_MASK = 0xff,
+ TPM_CMD_COUNT_BYTE = 2,
+ TPM_CMD_ORDINAL_BYTE = 6,
+};
+
+/*
+ * Array with one entry per ordinal defining the maximum amount
+ * of time the chip could take to return the result. The ordinal
+ * designation of short, medium or long is defined in a table in
+ * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
+ * values of the SHORT, MEDIUM, and LONG durations are retrieved
+ * from the chip during initialization with a call to tpm_get_timeouts.
+ */
+static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
+ TPM_UNDEFINED, /* 0 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 5 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 10 */
+ TPM_SHORT,
+};
+
+static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
+ TPM_UNDEFINED, /* 0 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 5 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 10 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_LONG,
+ TPM_MEDIUM, /* 15 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_SHORT, /* 20 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT, /* 25 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 30 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 35 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 40 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 45 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_LONG,
+ TPM_MEDIUM, /* 50 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 55 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 60 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 65 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 70 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 75 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 80 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 85 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 90 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 95 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 100 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 105 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 110 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 115 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 120 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 125 */
+ TPM_SHORT,
+ TPM_LONG,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 130 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_UNDEFINED, /* 135 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 140 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 145 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 150 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 155 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 160 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 165 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 170 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 175 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 180 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM, /* 185 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 190 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 195 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 200 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 205 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 210 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_UNDEFINED, /* 215 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 220 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 225 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 230 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 235 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 240 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+};
+
+#endif
diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c
index cc740e9c21b..9afe46c1e90 100644
--- a/drivers/tpm/tpm_tis_i2c.c
+++ b/drivers/tpm/tpm_tis_i2c.c
@@ -17,131 +17,33 @@
*
* 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 <tis.h>
#include <tpm.h>
#include <asm-generic/errno.h>
+#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/unaligned/be_byteshift.h>
-#include "tpm_private.h"
+#include "tpm_tis_i2c.h"
+#include "tpm_internal.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 {
-#ifdef CONFIG_DM_I2C
- struct udevice *dev;
-#else
- uint addr;
-#endif
- u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */
- enum i2c_chip_type chip_type;
-};
-
-static struct tpm_dev tpm_dev = {
-#ifndef CONFIG_DM_I2C
- .addr = TPM_I2C_ADDR
-#endif
-};
-
-static struct tpm_dev tpm_dev;
-
/*
- * 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
@@ -154,39 +56,32 @@ 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(struct udevice *dev, u8 addr, u8 *buffer,
+ size_t len)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc;
int count;
uint32_t addrbuf = addr;
- if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) {
+ if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) {
/* slb9635 protocol should work in both cases */
for (count = 0; count < MAX_COUNT; count++) {
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_write(tpm_dev.dev, 0, (uchar *)&addrbuf, 1);
-#else
- rc = i2c_write(tpm_dev.addr, 0, 0,
- (uchar *)&addrbuf, 1);
-#endif
+ rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1);
if (rc == 0)
break; /* Success, break to skip sleep */
- udelay(SLEEP_DURATION);
+ udelay(SLEEP_DURATION_US);
}
if (rc)
- return -rc;
+ return rc;
/* 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(SLEEP_DURATION);
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_read(tpm_dev.dev, 0, buffer, len);
-#else
- rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len);
-#endif
+ udelay(SLEEP_DURATION_US);
+ rc = dm_i2c_read(dev, 0, buffer, len);
if (rc == 0)
break; /* success, break to skip sleep */
}
@@ -199,60 +94,56 @@ 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++) {
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_read(tpm_dev.dev, addr, buffer, len);
-#else
- rc = i2c_read(tpm_dev.addr, addr, 1, buffer, len);
-#endif
+ rc = dm_i2c_read(dev, addr, buffer, len);
if (rc == 0)
break; /* break here to skip sleep */
- udelay(SLEEP_DURATION);
+ udelay(SLEEP_DURATION_US);
}
}
/* Take care of 'guard time' */
- udelay(SLEEP_DURATION);
+ udelay(SLEEP_DURATION_US);
if (rc)
- return -rc;
+ return rc;
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(struct udevice *dev, u8 addr,
+ const u8 *buffer, size_t len,
+ unsigned int sleep_time_us, u8 max_count)
{
+ struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc = 0;
int count;
- /* Prepare send buffer */
-#ifndef CONFIG_DM_I2C
- tpm_dev.buf[0] = addr;
- memcpy(&(tpm_dev.buf[1]), buffer, len);
- buffer = tpm_dev.buf;
- len++;
-#endif
+ if (chip->chip_type == SLB9635) {
+ /* Prepare send buffer to include the address */
+ priv->buf[0] = addr;
+ memcpy(&(priv->buf[1]), buffer, len);
+ buffer = priv->buf;
+ len++;
+ addr = 0;
+ }
for (count = 0; count < max_count; count++) {
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_write(tpm_dev.dev, addr, buffer, len);
-#else
- rc = i2c_write(tpm_dev.addr, 0, 0, buffer, len);
-#endif
+ rc = dm_i2c_write(dev, addr, buffer, len);
if (rc == 0)
break; /* Success, break to skip sleep */
- udelay(sleep_time);
+ udelay(sleep_time_us);
}
/* take care of 'guard time' */
- udelay(sleep_time);
+ udelay(sleep_time_us);
if (rc)
- return -rc;
+ return rc;
return 0;
}
/*
- * 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
@@ -263,109 +154,135 @@ 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(struct udevice *dev, u8 addr, const u8 *buffer,
+ size_t len)
{
- return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION,
- MAX_COUNT);
+ return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
+ SLEEP_DURATION_US, MAX_COUNT);
}
/*
* 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(struct udevice *dev, u8 addr, u8 *buffer,
+ size_t len)
{
- return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG,
- MAX_COUNT_LONG);
+ return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
+ SLEEP_DURATION_LONG_US,
+ MAX_COUNT_LONG);
}
-static int check_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_check_locality(struct udevice *dev, int loc)
{
const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID;
+ struct tpm_chip *chip = dev_get_priv(dev);
u8 buf;
int rc;
- rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1);
+ rc = tpm_tis_i2c_read(dev, 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;
+ return -ENOENT;
}
-static void release_locality(struct tpm_chip *chip, int loc, int force)
+static void tpm_tis_i2c_release_locality(struct udevice *dev, 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(dev, 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(dev, TPM_ACCESS(loc), &buf, 1);
}
}
-static int request_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_request_locality(struct udevice *dev, int loc)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
unsigned long start, stop;
u8 buf = TPM_ACCESS_REQUEST_USE;
int rc;
- if (check_locality(chip, loc) >= 0)
+ rc = tpm_tis_i2c_check_locality(dev, loc);
+ if (rc >= 0) {
+ debug("%s: Already have locality\n", __func__);
return loc; /* We already have the locality */
+ } else if (rc != -ENOENT) {
+ debug("%s: Failed to get locality: %d\n", __func__, rc);
+ return rc;
+ }
- rc = iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
- if (rc)
+ rc = tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
+ if (rc) {
+ debug("%s: Failed to write to TPM: %d\n", __func__, 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)
+ rc = tpm_tis_i2c_check_locality(dev, loc);
+ if (rc >= 0) {
+ debug("%s: Have locality\n", __func__);
return loc;
- udelay(TPM_TIMEOUT * 1000);
+ } else if (rc != -ENOENT) {
+ debug("%s: Failed to get locality: %d\n", __func__, rc);
+ return rc;
+ }
+ mdelay(TPM_TIMEOUT_MS);
} while (get_timer(start) < stop);
+ debug("%s: Timeout getting locality: %d\n", __func__, rc);
- return -1;
+ return rc;
}
-static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
+static u8 tpm_tis_i2c_status(struct udevice *dev)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
/* 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(dev, TPM_STS(chip->locality), &buf, 1) < 0)
return 0;
else
return buf;
}
-static void tpm_tis_i2c_ready(struct tpm_chip *chip)
+static int tpm_tis_i2c_ready(struct udevice *dev)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc;
/* This causes the current command to be aborted */
u8 buf = TPM_STS_COMMAND_READY;
debug("%s\n", __func__);
- rc = iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1);
+ rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1);
if (rc)
debug("%s: rc=%d\n", __func__, rc);
+
+ return rc;
}
-static ssize_t get_burstcount(struct tpm_chip *chip)
+static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
unsigned long start, stop;
ssize_t burstcnt;
u8 addr, buf[3];
@@ -373,53 +290,54 @@ 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(dev, addr, buf, 3) < 0)
burstcnt = 0;
else
burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
if (burstcnt)
return burstcnt;
- udelay(TPM_TIMEOUT * 1000);
+ mdelay(TPM_TIMEOUT_MS);
} while (get_timer(start) < stop);
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 udevice *dev, u8 mask,
+ unsigned long timeout, int *status)
{
unsigned long start, stop;
/* Check current status */
- *status = tpm_tis_i2c_status(chip);
+ *status = tpm_tis_i2c_status(dev);
if ((*status & mask) == mask)
return 0;
start = get_timer(0);
stop = timeout;
do {
- udelay(TPM_TIMEOUT * 1000);
- *status = tpm_tis_i2c_status(chip);
+ mdelay(TPM_TIMEOUT_MS);
+ *status = tpm_tis_i2c_status(dev);
if ((*status & mask) == mask)
return 0;
} while (get_timer(start) < stop);
- return -ETIME;
+ return -ETIMEDOUT;
}
-static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
size_t size = 0;
ssize_t burstcnt;
int rc;
while (size < count) {
- burstcnt = get_burstcount(chip);
+ burstcnt = tpm_tis_i2c_get_burstcount(dev);
/* burstcount < 0 -> tpm is busy */
if (burstcnt < 0)
@@ -429,8 +347,8 @@ 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),
- &(buf[size]), burstcnt);
+ rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality),
+ &(buf[size]), burstcnt);
if (rc == 0)
size += burstcnt;
}
@@ -438,60 +356,58 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
return size;
}
-static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int size = 0;
int expected, status;
+ int rc;
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ status = tpm_tis_i2c_status(dev);
+ if (status == TPM_STS_COMMAND_READY)
+ return -EINTR;
+ if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) !=
+ (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
+ return -EAGAIN;
+
+ debug("...got it;\n");
/* Read first 10 bytes, including tag, paramsize, and result */
- size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE);
if (size < TPM_HEADER_SIZE) {
- error("Unable to read header\n");
- goto out;
+ debug("Unable to read header\n");
+ return size < 0 ? size : -EIO;
}
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,
+ debug("Error size=%x, expected=%x, count=%x\n", size, expected,
count);
- size = -EIO;
- goto out;
+ return -ENOSPC;
}
- size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
+ size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
if (size < expected) {
- error("Unable to read remainder of result\n");
- size = -ETIME;
- goto out;
+ debug("Unable to read remainder of result\n");
+ return -ETIMEDOUT;
}
- wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
+ rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c,
+ &status);
+ if (rc)
+ return rc;
if (status & TPM_STS_DATA_AVAIL) { /* Retry? */
- error("Error left over data\n");
- size = -EIO;
- goto out;
+ debug("Error left over data\n");
+ return -EIO;
}
-out:
- 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);
-
return size;
}
-static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
+static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc, status;
size_t burstcnt;
size_t count = 0;
@@ -502,20 +418,21 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t 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(dev, 0) < 0)
return -EBUSY;
- status = tpm_tis_i2c_status(chip);
+ status = tpm_tis_i2c_status(dev);
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) {
- rc = -ETIME;
- goto out_err;
- }
+ rc = tpm_tis_i2c_ready(dev);
+ if (rc)
+ return rc;
+ rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY,
+ chip->timeout_b, &status);
+ if (rc)
+ return rc;
}
- burstcnt = get_burstcount(chip);
+ burstcnt = tpm_tis_i2c_get_burstcount(dev);
/* burstcount < 0 -> tpm is busy */
if (burstcnt < 0)
@@ -527,107 +444,79 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
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;
+ if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN)
+ burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN;
#endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */
- rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality),
- &(buf[count]), burstcnt);
+ rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality),
+ &(buf[count]), burstcnt);
if (rc == 0)
count += burstcnt;
else {
debug("%s: error\n", __func__);
- if (retry++ > 10) {
- rc = -EIO;
- goto out_err;
- }
- rc = wait_for_stat(chip, TPM_STS_VALID,
- chip->vendor.timeout_c, &status);
+ if (retry++ > 10)
+ return -EIO;
+ rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID,
+ chip->timeout_c,
+ &status);
if (rc)
- goto out_err;
+ return rc;
- if ((status & TPM_STS_DATA_EXPECT) == 0) {
- rc = -EIO;
- goto out_err;
- }
+ if ((status & TPM_STS_DATA_EXPECT) == 0)
+ return -EIO;
}
}
/* Go and do it */
- iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1);
- debug("done\n");
+ rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1);
+ if (rc < 0)
+ return rc;
+ debug("%s: done, rc=%d\n", __func__, rc);
return len;
+}
+
+static int tpm_tis_i2c_cleanup(struct udevice *dev)
+{
+ struct tpm_chip *chip = dev_get_priv(dev);
-out_err:
- debug("%s: out_err\n", __func__);
- tpm_tis_i2c_ready(chip);
+ tpm_tis_i2c_ready(dev);
/*
* 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);
-
- return rc;
-}
+ mdelay(2);
+ tpm_tis_i2c_release_locality(dev, chip->locality, 0);
-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)
-{
-#if CONFIG_IS_ENABLED(OF_CONTROL)
- const void *blob = gd->fdt_blob;
-
- if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9645_TPM) >= 0)
- return SLB9645;
-
- if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM) >= 0)
- return SLB9635;
-#endif
- return UNKNOWN;
+ return 0;
}
-static int tpm_vendor_init_common(void)
+static int tpm_tis_i2c_init(struct udevice *dev)
{
- struct tpm_chip *chip;
+ struct tpm_chip *chip = dev_get_priv(dev);
u32 vendor;
u32 expected_did_vid;
+ int rc;
- tpm_dev.chip_type = tpm_vendor_chip_type();
-
- chip = tpm_register_hardware(&tpm_tis_i2c);
- if (chip < 0)
- return -ENODEV;
-
- /* Disable interrupts (not supported) */
- chip->vendor.irq = 0;
+ chip->is_open = 1;
- /* 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_MS;
+ chip->timeout_b = TIS_LONG_TIMEOUT_MS;
+ chip->timeout_c = TIS_SHORT_TIMEOUT_MS;
+ chip->timeout_d = TIS_SHORT_TIMEOUT_MS;
- if (request_locality(chip, 0) < 0)
- return -ENODEV;
+ rc = tpm_tis_i2c_request_locality(dev, 0);
+ if (rc < 0)
+ return rc;
/* Read four bytes from DID_VID register */
- if (iic_tpm_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
- release_locality(chip, 0, 1);
+ if (tpm_tis_i2c_read(dev, TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
+ tpm_tis_i2c_release_locality(dev, 0, 1);
return -EIO;
}
- if (tpm_dev.chip_type == SLB9635) {
+ if (chip->chip_type == SLB9635) {
vendor = be32_to_cpu(vendor);
expected_did_vid = TPM_TIS_I2C_DID_VID_9635;
} else {
@@ -635,13 +524,14 @@ static int tpm_vendor_init_common(void)
expected_did_vid = TPM_TIS_I2C_DID_VID_9645;
}
- if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) {
+ if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) {
error("Vendor id did not match! ID was %08x\n", vendor);
return -ENODEV;
}
+ chip->vend_dev = vendor;
debug("1.2 TPM (chip type %s device-id 0x%X)\n",
- chip_name[tpm_dev.chip_type], vendor >> 16);
+ chip_name[chip->chip_type], vendor >> 16);
/*
* A timeout query to TPM can be placed here.
@@ -651,33 +541,83 @@ static int tpm_vendor_init_common(void)
return 0;
}
-#ifdef CONFIG_DM_I2C
-/* Initialisation of i2c tpm */
-int tpm_vendor_init_dev(struct udevice *dev)
+static int tpm_tis_i2c_open(struct udevice *dev)
{
- tpm_dev.dev = dev;
- return tpm_vendor_init_common();
+ struct tpm_chip *chip = dev_get_priv(dev);
+ int rc;
+
+ debug("%s: start\n", __func__);
+ if (chip->is_open)
+ return -EBUSY;
+ rc = tpm_tis_i2c_init(dev);
+ if (rc < 0)
+ chip->is_open = 0;
+
+ return rc;
}
-#else
-/* Initialisation of i2c tpm */
-int tpm_vendor_init(uint32_t dev_addr)
+
+static int tpm_tis_i2c_close(struct udevice *dev)
{
- uint old_addr;
- int rc = 0;
+ struct tpm_chip *chip = dev_get_priv(dev);
- old_addr = tpm_dev.addr;
- if (dev_addr != 0)
- tpm_dev.addr = dev_addr;
+ if (chip->is_open) {
+ tpm_tis_i2c_release_locality(dev, chip->locality, 1);
+ chip->is_open = 0;
+ chip->vend_dev = 0;
+ }
- rc = tpm_vendor_init_common();
- if (rc)
- tpm_dev.addr = old_addr;
+ return 0;
+}
- return rc;
+static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
+{
+ struct tpm_chip *chip = dev_get_priv(dev);
+
+ if (size < 50)
+ return -ENOSPC;
+
+ return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)",
+ chip->is_open ? "open" : "closed",
+ chip_name[chip->chip_type],
+ chip->vend_dev >> 16);
}
-#endif
-void tpm_vendor_cleanup(struct tpm_chip *chip)
+static int tpm_tis_i2c_probe(struct udevice *dev)
{
- release_locality(chip, chip->vendor.locality, 1);
+ struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct tpm_chip *chip = dev_get_priv(dev);
+
+ chip->chip_type = dev_get_driver_data(dev);
+
+ /* TODO: These need to be checked and tuned */
+ uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS;
+ uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS;
+ uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS;
+ uc_priv->retry_time_ms = TPM_TIMEOUT_MS;
+
+ return 0;
}
+
+static const struct tpm_ops tpm_tis_i2c_ops = {
+ .open = tpm_tis_i2c_open,
+ .close = tpm_tis_i2c_close,
+ .get_desc = tpm_tis_get_desc,
+ .send = tpm_tis_i2c_send,
+ .recv = tpm_tis_i2c_recv,
+ .cleanup = tpm_tis_i2c_cleanup,
+};
+
+static const struct udevice_id tpm_tis_i2c_ids[] = {
+ { .compatible = "infineon,slb9635tt", .data = SLB9635 },
+ { .compatible = "infineon,slb9645tt", .data = SLB9645 },
+ { }
+};
+
+U_BOOT_DRIVER(tpm_tis_i2c) = {
+ .name = "tpm_tis_i2c",
+ .id = UCLASS_TPM,
+ .of_match = tpm_tis_i2c_ids,
+ .ops = &tpm_tis_i2c_ops,
+ .probe = tpm_tis_i2c_probe,
+ .priv_auto_alloc_size = sizeof(struct tpm_chip),
+};
diff --git a/drivers/tpm/tpm_private.h b/drivers/tpm/tpm_tis_i2c.h
index 8894c98e6a8..3b510d101e7 100644
--- a/drivers/tpm/tpm_private.h
+++ b/drivers/tpm/tpm_tis_i2c.h
@@ -13,34 +13,21 @@
* It is based on the Linux kernel driver tpm.c from Leendert van
* Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
*
- *
- * 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
*/
-#ifndef _TPM_PRIVATE_H_
-#define _TPM_PRIVATE_H_
+#ifndef _TPM_TIS_I2C_H
+#define _TPM_TIS_I2C_H
#include <linux/compiler.h>
#include <linux/types.h>
enum tpm_timeout {
- TPM_TIMEOUT = 5, /* msecs */
+ TPM_TIMEOUT_MS = 5,
+ TIS_SHORT_TIMEOUT_MS = 750,
+ TIS_LONG_TIMEOUT_MS = 2000,
+ SLEEP_DURATION_US = 60,
+ SLEEP_DURATION_LONG_US = 210,
};
/* Size of external transmit buffer (used in tpm_transmit)*/
@@ -50,25 +37,18 @@ enum tpm_timeout {
#define TPM_RSP_SIZE_BYTE 2
#define TPM_RSP_RC_BYTE 6
-struct tpm_chip;
-
-struct tpm_vendor_specific {
- const u8 req_complete_mask;
- const u8 req_complete_val;
- const u8 req_canceled;
- int irq;
- int (*recv) (struct tpm_chip *, u8 *, size_t);
- int (*send) (struct tpm_chip *, u8 *, size_t);
- void (*cancel) (struct tpm_chip *);
- u8(*status) (struct tpm_chip *);
- int locality;
- unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */
- unsigned long duration[3]; /* msec */
+enum i2c_chip_type {
+ SLB9635,
+ SLB9645,
+ UNKNOWN,
};
struct tpm_chip {
int is_open;
- struct tpm_vendor_specific vendor;
+ int locality;
+ u32 vend_dev;
+ unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */
+ enum i2c_chip_type chip_type;
};
struct tpm_input_header {
@@ -127,14 +107,40 @@ struct tpm_cmd_t {
union tpm_cmd_params params;
} __packed;
-struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *);
+/* Max number of iterations after i2c NAK */
+#define MAX_COUNT 3
-int tpm_vendor_init(uint32_t dev_addr);
+/*
+ * 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
-struct udevice;
-int tpm_vendor_init_dev(struct udevice *dev);
+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,
+};
-void tpm_vendor_cleanup(struct tpm_chip *chip);
+/* expected value for DIDVID register */
+#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
+#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
+#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))
#endif
diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c
index d09f8cee05b..b41c3cec375 100644
--- a/drivers/tpm/tpm_tis_lpc.c
+++ b/drivers/tpm/tpm_tis_lpc.c
@@ -14,8 +14,11 @@
*/
#include <common.h>
-#include <asm/io.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <tis.h>
#include <tpm.h>
+#include <asm/io.h>
#define PREFIX "lpc_tpm: "
@@ -36,13 +39,15 @@ struct tpm_locality {
u8 padding4[251];
};
+struct tpm_tis_lpc_priv {
+ struct tpm_locality *regs;
+};
+
/*
* This pointer refers to the TPM chip, 5 of its localities are mapped as an
* array.
*/
#define TPM_TOTAL_LOCALITIES 5
-static struct tpm_locality *lpc_tpm_dev =
- (struct tpm_locality *)CONFIG_TPM_TIS_BASE_ADDRESS;
/* Some registers' bit field definitions */
#define TIS_STS_VALID (1 << 7) /* 0x80 */
@@ -63,85 +68,45 @@ static struct tpm_locality *lpc_tpm_dev =
#define TIS_STS_BURST_COUNT_MASK (0xffff)
#define TIS_STS_BURST_COUNT_SHIFT (8)
-/*
- * Error value returned if a tpm register does not enter the expected state
- * after continuous polling. No actual TPM register reading ever returns -1,
- * so this value is a safe error indication to be mixed with possible status
- * register values.
- */
-#define TPM_TIMEOUT_ERR (-1)
-
-/* Error value returned on various TPM driver errors. */
-#define TPM_DRIVER_ERR (1)
-
/* 1 second is plenty for anything TPM does. */
#define MAX_DELAY_US (1000 * 1000)
/* Retrieve burst count value out of the status register contents. */
static u16 burst_count(u32 status)
{
- return (status >> TIS_STS_BURST_COUNT_SHIFT) & TIS_STS_BURST_COUNT_MASK;
+ return (status >> TIS_STS_BURST_COUNT_SHIFT) &
+ TIS_STS_BURST_COUNT_MASK;
}
-/*
- * Structures defined below allow creating descriptions of TPM vendor/device
- * ID information for run time discovery. The only device the system knows
- * about at this time is Infineon slb9635.
- */
-struct device_name {
- u16 dev_id;
- const char * const dev_name;
-};
-
-struct vendor_name {
- u16 vendor_id;
- const char *vendor_name;
- const struct device_name *dev_names;
-};
-
-static const struct device_name infineon_devices[] = {
- {0xb, "SLB9635 TT 1.2"},
- {0}
-};
-
-static const struct vendor_name vendor_names[] = {
- {0x15d1, "Infineon", infineon_devices},
-};
-
-/*
- * Cached vendor/device ID pair to indicate that the device has been already
- * discovered.
- */
-static u32 vendor_dev_id;
-
/* TPM access wrappers to support tracing */
-static u8 tpm_read_byte(const u8 *ptr)
+static u8 tpm_read_byte(struct tpm_tis_lpc_priv *priv, const u8 *ptr)
{
u8 ret = readb(ptr);
debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
return ret;
}
-static u32 tpm_read_word(const u32 *ptr)
+static u32 tpm_read_word(struct tpm_tis_lpc_priv *priv, const u32 *ptr)
{
u32 ret = readl(ptr);
debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
return ret;
}
-static void tpm_write_byte(u8 value, u8 *ptr)
+static void tpm_write_byte(struct tpm_tis_lpc_priv *priv, u8 value, u8 *ptr)
{
debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
writeb(value, ptr);
}
-static void tpm_write_word(u32 value, u32 *ptr)
+static void tpm_write_word(struct tpm_tis_lpc_priv *priv, u32 value,
+ u32 *ptr)
{
debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
writel(value, ptr);
}
@@ -156,67 +121,51 @@ static void tpm_write_word(u32 value, u32 *ptr)
* @expected - value the field(s) are supposed to be set to
*
* Returns the register contents in case the expected value was found in the
- * appropriate register bits, or TPM_TIMEOUT_ERR on timeout.
+ * appropriate register bits, or -ETIMEDOUT on timeout.
*/
-static u32 tis_wait_reg(u32 *reg, u8 mask, u8 expected)
+static int tis_wait_reg(struct tpm_tis_lpc_priv *priv, u32 *reg, u8 mask,
+ u8 expected)
{
u32 time_us = MAX_DELAY_US;
while (time_us > 0) {
- u32 value = tpm_read_word(reg);
+ u32 value = tpm_read_word(priv, reg);
if ((value & mask) == expected)
return value;
udelay(1); /* 1 us */
time_us--;
}
- return TPM_TIMEOUT_ERR;
+
+ return -ETIMEDOUT;
}
/*
* Probe the TPM device and try determining its manufacturer/device name.
*
- * Returns 0 on success (the device is found or was found during an earlier
- * invocation) or TPM_DRIVER_ERR if the device is not found.
+ * Returns 0 on success, -ve on error
*/
-int tis_init(void)
+static int tpm_tis_lpc_probe(struct udevice *dev)
{
- u32 didvid = tpm_read_word(&lpc_tpm_dev[0].did_vid);
- int i;
- const char *device_name = "unknown";
- const char *vendor_name = device_name;
- u16 vid, did;
-
- if (vendor_dev_id)
- return 0; /* Already probed. */
-
- if (!didvid || (didvid == 0xffffffff)) {
- printf("%s: No TPM device found\n", __func__);
- return TPM_DRIVER_ERR;
- }
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ u32 vid, did;
+ fdt_addr_t addr;
+ u32 didvid;
- vendor_dev_id = didvid;
+ addr = dev_get_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ priv->regs = map_sysmem(addr, 0);
+ didvid = tpm_read_word(priv, &priv->regs[0].did_vid);
vid = didvid & 0xffff;
did = (didvid >> 16) & 0xffff;
- for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
- int j = 0;
- u16 known_did;
-
- if (vid == vendor_names[i].vendor_id)
- vendor_name = vendor_names[i].vendor_name;
-
- while ((known_did = vendor_names[i].dev_names[j].dev_id) != 0) {
- if (known_did == did) {
- device_name =
- vendor_names[i].dev_names[j].dev_name;
- break;
- }
- j++;
- }
- break;
+ if (vid != 0x15d1 || did != 0xb) {
+ debug("Invalid vendor/device ID %04x/%04x\n", vid, did);
+ return -ENOSYS;
}
- printf("Found TPM %s by %s\n", device_name, vendor_name);
+ debug("Found TPM %s by %s\n", "SLB9635 TT 1.2", "Infineon");
+
return 0;
}
@@ -228,23 +177,25 @@ int tis_init(void)
* @data - address of the data to send, byte by byte
* @len - length of the data to send
*
- * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
- * not accept the entire command).
+ * Returns 0 on success, -ve on error (in case the device does not accept
+ * the entire command).
*/
-static u32 tis_senddata(const u8 * const data, u32 len)
+static int tis_senddata(struct udevice *dev, const u8 *data, size_t len)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u32 offset = 0;
u16 burst = 0;
u32 max_cycles = 0;
u8 locality = 0;
u32 value;
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
- if (value == TPM_TIMEOUT_ERR) {
+ if (value == -ETIMEDOUT) {
printf("%s:%d - failed to get 'command_ready' status\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value;
}
burst = burst_count(value);
@@ -256,11 +207,11 @@ static u32 tis_senddata(const u8 * const data, u32 len)
if (max_cycles++ == MAX_DELAY_US) {
printf("%s:%d failed to feed %d bytes of %d\n",
__FILE__, __LINE__, len - offset, len);
- return TPM_DRIVER_ERR;
+ return -ETIMEDOUT;
}
udelay(1);
- burst = burst_count(tpm_read_word(&lpc_tpm_dev
- [locality].tpm_status));
+ burst = burst_count(tpm_read_word(priv,
+ &regs[locality].tpm_status));
}
max_cycles = 0;
@@ -276,16 +227,16 @@ static u32 tis_senddata(const u8 * const data, u32 len)
*/
count = min((u32)burst, len - offset - 1);
while (count--)
- tpm_write_byte(data[offset++],
- &lpc_tpm_dev[locality].data);
+ tpm_write_byte(priv, data[offset++],
+ &regs[locality].data);
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_VALID, TIS_STS_VALID);
- if ((value == TPM_TIMEOUT_ERR) || !(value & TIS_STS_EXPECT)) {
+ if ((value == -ETIMEDOUT) || !(value & TIS_STS_EXPECT)) {
printf("%s:%d TPM command feed overflow\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value == -ETIMEDOUT ? value : -EIO;
}
burst = burst_count(value);
@@ -300,21 +251,21 @@ static u32 tis_senddata(const u8 * const data, u32 len)
}
/* Send the last byte. */
- tpm_write_byte(data[offset++], &lpc_tpm_dev[locality].data);
+ tpm_write_byte(priv, data[offset++], &regs[locality].data);
/*
* Verify that TPM does not expect any more data as part of this
* command.
*/
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_VALID, TIS_STS_VALID);
- if ((value == TPM_TIMEOUT_ERR) || (value & TIS_STS_EXPECT)) {
+ if ((value == -ETIMEDOUT) || (value & TIS_STS_EXPECT)) {
printf("%s:%d unexpected TPM status 0x%x\n",
__FILE__, __LINE__, value);
- return TPM_DRIVER_ERR;
+ return value == -ETIMEDOUT ? value : -EIO;
}
/* OK, sitting pretty, let's start the command execution. */
- tpm_write_word(TIS_STS_TPM_GO, &lpc_tpm_dev[locality].tpm_status);
+ tpm_write_word(priv, TIS_STS_TPM_GO, &regs[locality].tpm_status);
return 0;
}
@@ -328,25 +279,27 @@ static u32 tis_senddata(const u8 * const data, u32 len)
*
* On success stores the number of received bytes to len and returns 0. On
* errors (misformatted TPM data or synchronization problems) returns
- * TPM_DRIVER_ERR.
+ * -ve value.
*/
-static u32 tis_readresponse(u8 *buffer, u32 *len)
+static int tis_readresponse(struct udevice *dev, u8 *buffer, size_t len)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u16 burst;
u32 value;
u32 offset = 0;
u8 locality = 0;
const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
- u32 expected_count = *len;
+ u32 expected_count = len;
int max_cycles = 0;
/* Wait for the TPM to process the command. */
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
has_data, has_data);
- if (value == TPM_TIMEOUT_ERR) {
+ if (value == -ETIMEDOUT) {
printf("%s:%d failed processing command\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value;
}
do {
@@ -354,18 +307,17 @@ static u32 tis_readresponse(u8 *buffer, u32 *len)
if (max_cycles++ == MAX_DELAY_US) {
printf("%s:%d TPM stuck on read\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return -EIO;
}
udelay(1);
- value = tpm_read_word(&lpc_tpm_dev
- [locality].tpm_status);
+ value = tpm_read_word(priv, &regs[locality].tpm_status);
}
max_cycles = 0;
while (burst-- && (offset < expected_count)) {
- buffer[offset++] = tpm_read_byte(&lpc_tpm_dev
- [locality].data);
+ buffer[offset++] = tpm_read_byte(priv,
+ &regs[locality].data);
if (offset == 6) {
/*
@@ -382,22 +334,22 @@ static u32 tis_readresponse(u8 *buffer, u32 *len)
expected_count = be32_to_cpu(real_length);
if ((expected_count < offset) ||
- (expected_count > *len)) {
+ (expected_count > len)) {
printf("%s:%d bad response size %d\n",
__FILE__, __LINE__,
expected_count);
- return TPM_DRIVER_ERR;
+ return -ENOSPC;
}
}
}
/* Wait for the next portion. */
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_VALID, TIS_STS_VALID);
- if (value == TPM_TIMEOUT_ERR) {
+ if (value == -ETIMEDOUT) {
printf("%s:%d failed to read response\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value;
}
if (offset == expected_count)
@@ -412,68 +364,90 @@ static u32 tis_readresponse(u8 *buffer, u32 *len)
if (value & TIS_STS_DATA_AVAILABLE) {
printf("%s:%d wrong receive status %x\n",
__FILE__, __LINE__, value);
- return TPM_DRIVER_ERR;
+ return -EBADMSG;
}
/* Tell the TPM that we are done. */
- tpm_write_word(TIS_STS_COMMAND_READY, &lpc_tpm_dev
- [locality].tpm_status);
- *len = offset;
- return 0;
+ tpm_write_word(priv, TIS_STS_COMMAND_READY,
+ &regs[locality].tpm_status);
+
+ return offset;
}
-int tis_open(void)
+static int tpm_tis_lpc_open(struct udevice *dev)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u8 locality = 0; /* we use locality zero for everything. */
-
- if (tis_close())
- return TPM_DRIVER_ERR;
+ int ret;
/* now request access to locality. */
- tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access);
+ tpm_write_word(priv, TIS_ACCESS_REQUEST_USE, &regs[locality].access);
/* did we get a lock? */
- if (tis_wait_reg(&lpc_tpm_dev[locality].access,
+ ret = tis_wait_reg(priv, &regs[locality].access,
TIS_ACCESS_ACTIVE_LOCALITY,
- TIS_ACCESS_ACTIVE_LOCALITY) == TPM_TIMEOUT_ERR) {
+ TIS_ACCESS_ACTIVE_LOCALITY);
+ if (ret == -ETIMEDOUT) {
printf("%s:%d - failed to lock locality %d\n",
__FILE__, __LINE__, locality);
- return TPM_DRIVER_ERR;
+ return ret;
}
- tpm_write_word(TIS_STS_COMMAND_READY,
- &lpc_tpm_dev[locality].tpm_status);
+ tpm_write_word(priv, TIS_STS_COMMAND_READY,
+ &regs[locality].tpm_status);
return 0;
}
-int tis_close(void)
+static int tpm_tis_lpc_close(struct udevice *dev)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u8 locality = 0;
- if (tpm_read_word(&lpc_tpm_dev[locality].access) &
+ if (tpm_read_word(priv, &regs[locality].access) &
TIS_ACCESS_ACTIVE_LOCALITY) {
- tpm_write_word(TIS_ACCESS_ACTIVE_LOCALITY,
- &lpc_tpm_dev[locality].access);
+ tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY,
+ &regs[locality].access);
- if (tis_wait_reg(&lpc_tpm_dev[locality].access,
- TIS_ACCESS_ACTIVE_LOCALITY, 0) ==
- TPM_TIMEOUT_ERR) {
+ if (tis_wait_reg(priv, &regs[locality].access,
+ TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) {
printf("%s:%d - failed to release locality %d\n",
__FILE__, __LINE__, locality);
- return TPM_DRIVER_ERR;
+ return -ETIMEDOUT;
}
}
return 0;
}
-int tis_sendrecv(const u8 *sendbuf, size_t send_size,
- u8 *recvbuf, size_t *recv_len)
+static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
{
- if (tis_senddata(sendbuf, send_size)) {
- printf("%s:%d failed sending data to TPM\n",
- __FILE__, __LINE__);
- return TPM_DRIVER_ERR;
- }
+ if (size < 50)
+ return -ENOSPC;
- return tis_readresponse(recvbuf, (u32 *)recv_len);
+ return snprintf(buf, size, "1.2 TPM (vendor %s, chip %s)",
+ "Infineon", "SLB9635 TT 1.2");
}
+
+
+static const struct tpm_ops tpm_tis_lpc_ops = {
+ .open = tpm_tis_lpc_open,
+ .close = tpm_tis_lpc_close,
+ .get_desc = tpm_tis_get_desc,
+ .send = tis_senddata,
+ .recv = tis_readresponse,
+};
+
+static const struct udevice_id tpm_tis_lpc_ids[] = {
+ { .compatible = "infineon,slb9635lpc" },
+ { }
+};
+
+U_BOOT_DRIVER(tpm_tis_lpc) = {
+ .name = "tpm_tis_lpc",
+ .id = UCLASS_TPM,
+ .of_match = tpm_tis_lpc_ids,
+ .ops = &tpm_tis_lpc_ops,
+ .probe = tpm_tis_lpc_probe,
+ .priv_auto_alloc_size = sizeof(struct tpm_tis_lpc_priv),
+};
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c
index ed4b0391278..9ea98075b30 100644
--- a/drivers/tpm/tpm_tis_sandbox.c
+++ b/drivers/tpm/tpm_tis_sandbox.c
@@ -5,6 +5,8 @@
*/
#include <common.h>
+#include <dm.h>
+#include <tpm.h>
#include <asm/state.h>
#include <asm/unaligned.h>
#include <linux/crc8.h>
@@ -56,7 +58,7 @@ enum {
*/
static struct tpm_state {
uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
-} state;
+} g_state;
/**
* sandbox_tpm_read_state() - read the sandbox EC state from the state file
@@ -82,7 +84,7 @@ static int sandbox_tpm_read_state(const void *blob, int node)
sprintf(prop_name, "nvdata%d", i);
prop = fdt_getprop(blob, node, prop_name, &len);
if (prop && len == NV_DATA_SIZE)
- memcpy(state.nvdata[i], prop, NV_DATA_SIZE);
+ memcpy(g_state.nvdata[i], prop, NV_DATA_SIZE);
}
return 0;
@@ -110,7 +112,7 @@ static int sandbox_tpm_write_state(void *blob, int node)
char prop_name[20];
sprintf(prop_name, "nvdata%d", i);
- fdt_setprop(blob, node, prop_name, state.nvdata[i],
+ fdt_setprop(blob, node, prop_name, g_state.nvdata[i],
NV_DATA_SIZE);
}
@@ -135,10 +137,11 @@ static int index_to_seq(uint32_t index)
return -1;
}
-int tis_sendrecv(const u8 *sendbuf, size_t send_size,
- u8 *recvbuf, size_t *recv_len)
+static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
+ size_t send_size, uint8_t *recvbuf,
+ size_t *recv_len)
{
- struct tpm_state *tpm = &state;
+ struct tpm_state *tpm = dev_get_priv(dev);
uint32_t code, index, length, type;
uint8_t *data;
int seq;
@@ -241,20 +244,50 @@ int tis_sendrecv(const u8 *sendbuf, size_t send_size,
return 0;
}
-int tis_open(void)
+static int sandbox_tpm_get_desc(struct udevice *dev, char *buf, int size)
{
- printf("%s\n", __func__);
+ if (size < 15)
+ return -ENOSPC;
+
+ return snprintf(buf, size, "sandbox TPM");
+}
+
+static int sandbox_tpm_probe(struct udevice *dev)
+{
+ struct tpm_state *tpm = dev_get_priv(dev);
+
+ memcpy(tpm, &g_state, sizeof(*tpm));
+
return 0;
}
-int tis_close(void)
+static int sandbox_tpm_open(struct udevice *dev)
{
- printf("%s\n", __func__);
return 0;
}
-int tis_init(void)
+static int sandbox_tpm_close(struct udevice *dev)
{
- printf("%s\n", __func__);
return 0;
}
+
+static const struct tpm_ops sandbox_tpm_ops = {
+ .open = sandbox_tpm_open,
+ .close = sandbox_tpm_close,
+ .get_desc = sandbox_tpm_get_desc,
+ .xfer = sandbox_tpm_xfer,
+};
+
+static const struct udevice_id sandbox_tpm_ids[] = {
+ { .compatible = "google,sandbox-tpm" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_tpm) = {
+ .name = "sandbox_tpm",
+ .id = UCLASS_TPM,
+ .of_match = sandbox_tpm_ids,
+ .ops = &sandbox_tpm_ops,
+ .probe = sandbox_tpm_probe,
+ .priv_auto_alloc_size = sizeof(struct tpm_state),
+};