Add the tpm_tis_spi driver that should support any TPMv2 compliant (SPI)
module.
Signed-off-by: Miquel Raynal
---
drivers/tpm/Kconfig | 9 +
drivers/tpm/Makefile | 1 +
drivers/tpm/tpm_tis.h | 3 +
drivers/tpm/tpm_tis_spi.c | 656 ++
4 files changed, 669 insertions(+)
create mode 100644 drivers/tpm/tpm_tis_spi.c
diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
index a98570ee77..cc57008b6a 100644
--- a/drivers/tpm/Kconfig
+++ b/drivers/tpm/Kconfig
@@ -46,6 +46,15 @@ config TPM_TIS_I2C_BURST_LIMITATION_LEN
help
Use this to set the burst limitation length
+config TPM_TIS_SPI
+ bool "Enable support for TPMv2 SPI chips"
+ depends on TPM && DM_SPI
+ help
+ This driver supports TPMv2 devices connected on the SPI 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_LPC
bool "Enable support for Infineon SLB9635/45 TPMs on LPC"
depends on TPM && X86
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 5a19a58f43..a753b24230 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_TPM) += tpm-uclass.o
obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
obj-$(CONFIG_TPM_TIS_INFINEON_I2C) += tpm_tis_infineon_i2c.o
+obj-$(CONFIG_TPM_TIS_SPI) += tpm_tis_spi.o
obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o
diff --git a/drivers/tpm/tpm_tis.h b/drivers/tpm/tpm_tis.h
index 2b81f3be50..1f4b0c24bd 100644
--- a/drivers/tpm/tpm_tis.h
+++ b/drivers/tpm/tpm_tis.h
@@ -37,6 +37,9 @@ enum tpm_timeout {
#define TPM_RSP_SIZE_BYTE 2
#define TPM_RSP_RC_BYTE6
+/* Number of xfer retries */
+#define TPM_XFER_RETRY 10
+
struct tpm_chip {
int is_open;
int locality;
diff --git a/drivers/tpm/tpm_tis_spi.c b/drivers/tpm/tpm_tis_spi.c
new file mode 100644
index 00..17f6cfa85c
--- /dev/null
+++ b/drivers/tpm/tpm_tis_spi.c
@@ -0,0 +1,656 @@
+/*
+ * Author:
+ * Miquel Raynal
+ *
+ * Description:
+ * SPI-level driver for TCG/TIS TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This device driver implements the TPM interface as defined in
+ * the TCG SPI protocol stack version 2.0.
+ *
+ * It is based on the U-Boot driver tpm_tis_infineon_i2c.c.
+ *
+ * SPDX-License-Identifier:GPL-2.0
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "tpm_tis.h"
+#include "tpm_internal.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TPM_ACCESS(l) (0x | ((l) << 12))
+#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
+#define TPM_STS(l) (0x0018 | ((l) << 12))
+#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
+#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
+#define TPM_RID(l) (0x0F04 | ((l) << 12))
+
+#define MAX_SPI_FRAMESIZE 64
+
+/*
+ * tpm_tis_spi_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 -EIO on error, 0 on success.
+ */
+static int tpm_tis_spi_xfer(struct udevice *dev, u32 addr, const u8 *out,
+ u8 *in, u16 len)
+{
+ struct spi_slave *slave = dev_get_parent_priv(dev);
+ int transfer_len, ret;
+ u8 tx_buf[MAX_SPI_FRAMESIZE];
+ u8 rx_buf[MAX_SPI_FRAMESIZE];
+
+ if (in && out) {
+ debug("%s: cannot do full duplex\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = spi_claim_bus(slave);
+ if (ret < 0) {
+ debug("%s: could not claim bus\n", __func__);
+ return ret;
+ }
+
+ while (len) {
+ /* Request */
+ transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);
+ tx_buf[0] = (in ? BIT(7) : 0) | (transfer_len - 1);
+ tx_buf[1] = 0xD4;
+ tx_buf[2] = addr >> 8;
+ tx_buf[3] = addr;
+
+ ret = spi_xfer(slave, 4 * 8, tx_buf, rx_buf, SPI_XFER_BEGIN);
+ if (ret < 0) {
+ debug("%s: spi request transfer failed (err: %d)\n",
+ __func__, ret);
+ goto release_bus;
+ }
+
+ /* Wait state */
+ if (!(rx_buf[3] & 0x1)) {
+ int i;
+
+