Add TPM framework support
Ported from Coreboot:
https://chromium.googlesource.com/chromiumos/third_party/coreboot/+/chromeos-2013.04/src/drivers/i2c/tpm/
d5ab28b5d73c03adcdc0fd4e530b39a7a8989dae
Change-Id: I42501e659007332e3b1d36828d47759bacc2c0f7
diff --git a/drivers/Kconfig b/drivers/Kconfig
index db351f7..eb7d815 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -14,5 +14,6 @@
source "drivers/mfd/Kconfig"
source "drivers/led/Kconfig"
source "drivers/otp/Kconfig"
+source "drivers/tpm/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 7ee324e..a7cce32 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -13,4 +13,5 @@
obj-$(CONFIG_LED) += led/
obj-y += otp/
obj-$(CONFIG_COMCERTO_SATA) += sata/
+obj-y += tpm/
diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
new file mode 100644
index 0000000..ab98f2a
--- /dev/null
+++ b/drivers/tpm/Kconfig
@@ -0,0 +1,7 @@
+menu "TPM driver "
+
+config TPM
+ bool "Enable TPM driver support"
+ default n
+
+endmenu
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
new file mode 100644
index 0000000..443ce91
--- /dev/null
+++ b/drivers/tpm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_TPM) += tis.o
diff --git a/drivers/tpm/tis.c b/drivers/tpm/tis.c
new file mode 100644
index 0000000..7c9a89b
--- /dev/null
+++ b/drivers/tpm/tis.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 Infineon Technologies
+ * Copyright 2013 Google Inc.
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 <asm/byteorder.h>
+#include <common.h>
+#include <stdint.h>
+#include <string.h>
+#include <tpm.h>
+#include "tpm.h"
+
+#ifdef DEBUG
+#include <assert.h>
+#define ASSERT(x) assert(x)
+#else
+#define ASSERT(x) ((void)0)
+#endif
+
+#define BIOS_DEBUG KERN_DEBUG
+
+/* global structure for tpm chip data */
+struct tpm_chip g_chip;
+
+#define TPM_CMD_COUNT_BYTE 2
+#define TPM_CMD_ORDINAL_BYTE 6
+#define TPM_VALID_STATUS (1 << 7)
+
+int tis_open(void)
+{
+ if (!g_chip.is_open) {
+ printk(BIOS_DEBUG "TPM is not available.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int tis_close(void)
+{
+ return 0;
+}
+
+int tis_init(void)
+{
+ if (!g_chip.is_open) {
+ printk(BIOS_DEBUG "TPM is not available.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t tpm_transmit(const uint8_t *buf, size_t bufsiz)
+{
+ int rc;
+ uint32_t count, ordinal;
+
+ struct tpm_chip *chip = &g_chip;
+
+ memcpy(&count, buf + TPM_CMD_COUNT_BYTE, sizeof(count));
+ count = be32_to_cpu(count);
+ memcpy(&ordinal, buf + TPM_CMD_ORDINAL_BYTE, sizeof(ordinal));
+ ordinal = be32_to_cpu(ordinal);
+
+ if (count == 0) {
+ printk(BIOS_DEBUG "tpm_transmit: no data\n");
+ return -1;
+ }
+ if (count > bufsiz) {
+ printk(BIOS_DEBUG "tpm_transmit: invalid count value %x %zx\n",
+ count, bufsiz);
+ return -1;
+ }
+
+ ASSERT(chip->vendor.send);
+ rc = chip->vendor.send(chip, (uint8_t *) buf, count);
+ if (rc < 0) {
+ printk(BIOS_DEBUG "tpm_transmit: tpm_send error\n");
+ goto out;
+ }
+
+ if (chip->vendor.irq)
+ goto out_recv;
+
+ int timeout = 2 * 60 * 1000; /* two minutes timeout */
+ while (timeout) {
+ ASSERT(chip->vendor.status);
+ uint8_t status = chip->vendor.status(chip);
+ if ((status & chip->vendor.req_complete_mask) ==
+ chip->vendor.req_complete_val) {
+ goto out_recv;
+ }
+
+ if ((status == chip->vendor.req_canceled)) {
+ printk(BIOS_DEBUG "tpm_transmit: Operation Canceled\n");
+ rc = -1;
+ goto out;
+ }
+ mdelay(TPM_TIMEOUT);
+ timeout--;
+ }
+
+ ASSERT(chip->vendor.cancel);
+ chip->vendor.cancel(chip);
+ printk(BIOS_DEBUG "tpm_transmit: Operation Timed out\n");
+ rc = -1; //ETIME;
+ goto out;
+
+out_recv:
+
+ rc = chip->vendor.recv(chip, (uint8_t *) buf, TPM_BUFSIZE);
+ if (rc < 0)
+ printk(BIOS_DEBUG "tpm_transmit: tpm_recv: error %d\n", rc);
+out:
+ return rc;
+}
+
+int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
+ uint8_t *recvbuf, size_t *rbuf_len)
+{
+ uint8_t buf[TPM_BUFSIZE];
+
+ if (sizeof(buf) < sbuf_size)
+ return -1;
+
+ memcpy(buf, sendbuf, sbuf_size);
+
+ int len = tpm_transmit(buf, sbuf_size);
+
+ if (len < 10) {
+ *rbuf_len = 0;
+ return -1;
+ }
+
+ if (len > *rbuf_len) {
+ *rbuf_len = len;
+ return -1;
+ }
+
+ memcpy(recvbuf, buf, len);
+ *rbuf_len = len;
+
+ return 0;
+}
diff --git a/drivers/tpm/tpm.h b/drivers/tpm/tpm.h
new file mode 100644
index 0000000..a34a0d5
--- /dev/null
+++ b/drivers/tpm/tpm.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 Infineon Technologies
+ *
+ * Authors:
+ * Peter Huewe <huewe.external@infineon.com>
+ *
+ * Version: 2.1.1
+ *
+ * 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.
+ *
+ *
+ * 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
+ */
+
+#ifndef __DRIVERS_TPM_TPM_H__
+#define __DRIVERS_TPM_TPM_H__
+
+#include <stdint.h>
+
+enum tpm_timeout {
+ TPM_TIMEOUT = 1, /* msecs */
+};
+
+/* Size of external transmit buffer (used for stack buffer in tpm_sendrecv) */
+#define TPM_BUFSIZE 1260
+
+/* Index of fields in TPM command buffer */
+#define TPM_CMD_SIZE_BYTE 2
+#define TPM_CMD_ORDINAL_BYTE 6
+
+/* Index of Count field in TPM response buffer */
+#define TPM_RSP_SIZE_BYTE 2
+#define TPM_RSP_RC_BYTE 6
+
+struct tpm_chip;
+
+struct tpm_vendor_specific {
+ const uint8_t req_complete_mask;
+ const uint8_t req_complete_val;
+ const uint8_t req_canceled;
+ int irq;
+ int (*recv)(struct tpm_chip *, uint8_t *, size_t);
+ int (*send)(struct tpm_chip *, uint8_t *, size_t);
+ void (*cancel)(struct tpm_chip *);
+ uint8_t(*status)(struct tpm_chip *);
+ int locality;
+};
+
+struct tpm_chip {
+ int is_open;
+ struct tpm_vendor_specific vendor;
+};
+
+struct tpm_input_header {
+ uint16_t tag;
+ uint32_t length;
+ uint32_t ordinal;
+} __attribute__ ((packed));
+
+struct tpm_output_header {
+ uint16_t tag;
+ uint32_t length;
+ uint32_t return_code;
+} __attribute__ ((packed));
+
+struct timeout_t {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+} __attribute__ ((packed));
+
+struct duration_t {
+ uint32_t tpm_short;
+ uint32_t tpm_medium;
+ uint32_t tpm_long;
+} __attribute__ ((packed));
+
+typedef union {
+ struct timeout_t timeout;
+ struct duration_t duration;
+} cap_t;
+
+struct tpm_getcap_params_in {
+ uint32_t cap;
+ uint32_t subcap_size;
+ uint32_t subcap;
+} __attribute__ ((packed));
+
+struct tpm_getcap_params_out {
+ uint32_t cap_size;
+ cap_t cap;
+} __attribute__ ((packed));
+
+typedef union {
+ struct tpm_input_header in;
+ struct tpm_output_header out;
+} tpm_cmd_header;
+
+typedef union {
+ struct tpm_getcap_params_out getcap_out;
+ struct tpm_getcap_params_in getcap_in;
+} tpm_cmd_params;
+
+struct tpm_cmd_t {
+ tpm_cmd_header header;
+ tpm_cmd_params params;
+} __attribute__ ((packed));
+
+#endif /* __DRIVERS_TPM_H__ */
diff --git a/include/tpm.h b/include/tpm.h
new file mode 100644
index 0000000..e25ad6a
--- /dev/null
+++ b/include/tpm.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2011 Google Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TPM_H_
+#define TPM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * tis_init()
+ *
+ * Initialize the TPM device. Returns 0 on success or -1 on
+ * failure (in case device probing did not succeed).
+ */
+int tis_init(void);
+
+/*
+ * tis_open()
+ *
+ * Requests access to locality 0 for the caller. After all commands have been
+ * completed the caller is supposed to call tis_close().
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int tis_open(void);
+
+/*
+ * tis_close()
+ *
+ * terminate the currect session with the TPM by releasing the locked
+ * locality. Returns 0 on success of -1 on failure (in case lock
+ * removal did not succeed).
+ */
+int tis_close(void);
+
+/*
+ * tis_sendrecv()
+ *
+ * Send the requested data to the TPM and then try to get its response
+ *
+ * @sendbuf - buffer of the data to send
+ * @send_size size of the data to send
+ * @recvbuf - memory to save the response to
+ * @recv_len - pointer to the size of the response buffer
+ *
+ * Returns 0 on success (and places the number of response bytes at recv_len)
+ * or -1 on failure.
+ */
+int tis_sendrecv(const u8 *sendbuf, size_t send_size, u8 *recvbuf,
+ size_t *recv_len);
+
+#endif /* TPM_H_ */