@@ -161,6 +161,15 @@ config TPM2_FTPM_TEE
help
This driver supports firmware TPM running in TEE.
+config TPM2_MMIO
+ bool "MMIO based TPM2 Interface"
+ depends on TPM_V2
+ help
+ This driver supports firmware TPM2.0 MMIO interface.
+ The usual TPM operations and the 'tpm' command can be used to talk
+ to the device using the standard TPM Interface Specification (TIS)
+ protocol.
+
endif # TPM_V2
endmenu
@@ -14,3 +14,4 @@ obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o
obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o
obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o
obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
+obj-$(CONFIG_TPM2_MMIO) += tpm2_tis_core.o tpm2_tis_mmio.o
new file mode 100644
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * driver for mmio TCG/TIS TPM (trusted platform module).
+ *
+ * Specifications at www.trustedcomputinggroup.org
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <tpm-v2.h>
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/unaligned/be_byteshift.h>
+#include "tpm_tis.h"
+#include "tpm_internal.h"
+
+/**
+ * struct tpm_tis_chip_data - Information about an MMIO TPM
+ * @pcr_count: Number of PCR per bank
+ * @pcr_select_min: Minimum size in bytes of the pcrSelect array
+ * @iobase: Base address
+ */
+struct tpm_tis_chip_data {
+ unsigned int pcr_count;
+ unsigned int pcr_select_min;
+ void __iomem *iobase;
+};
+
+static int mmio_read_bytes(struct udevice *dev, u32 addr, u16 len,
+ u8 *result)
+{
+ struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev);
+
+ while (len--)
+ *result++ = ioread8(drv_data->iobase + addr);
+
+ return 0;
+}
+
+static int mmio_write_bytes(struct udevice *dev, u32 addr, u16 len,
+ const u8 *value)
+{
+ struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev);
+
+ while (len--)
+ iowrite8(*value++, drv_data->iobase + addr);
+
+ return 0;
+}
+
+static int mmio_read32(struct udevice *dev, u32 addr, u32 *result)
+{
+ struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev);
+
+ *result = ioread32(drv_data->iobase + addr);
+
+ return 0;
+}
+
+static int mmio_write32(struct udevice *dev, u32 addr, u32 value)
+{
+ struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev);
+
+ iowrite32(value, drv_data->iobase + addr);
+
+ return 0;
+}
+
+static struct tpm_tis_phy_ops phy_ops = {
+ .read_bytes = mmio_read_bytes,
+ .write_bytes = mmio_write_bytes,
+ .read32 = mmio_read32,
+ .write32 = mmio_write32,
+};
+
+static int tpm_tis_probe(struct udevice *dev)
+{
+ struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev);
+ struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+ int ret = 0;
+ fdt_addr_t ioaddr;
+ u64 sz;
+
+ ioaddr = dev_read_addr(dev);
+ if (ioaddr == FDT_ADDR_T_NONE)
+ return log_msg_ret("ioaddr", -EINVAL);
+
+ ret = dev_read_u64(dev, "reg", &sz);
+ if (ret)
+ return -EINVAL;
+
+ drv_data->iobase = ioremap(ioaddr, sz);
+ tpm_tis_ops_register(dev, &phy_ops);
+ ret = tpm_tis_init(dev);
+ if (ret)
+ goto iounmap;
+
+ priv->pcr_count = drv_data->pcr_count;
+ priv->pcr_select_min = drv_data->pcr_select_min;
+ /*
+ * Although the driver probably works with a TPMv1 our Kconfig
+ * limits the driver to TPMv2 only
+ */
+ priv->version = TPM_V2;
+
+ return ret;
+iounmap:
+ iounmap(drv_data->iobase);
+
+ return -EINVAL;
+}
+
+static int tpm_tis_remove(struct udevice *dev)
+{
+ struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev);
+
+ iounmap(drv_data->iobase);
+
+ return tpm_tis_cleanup(dev);
+}
+
+static const struct tpm_ops tpm_tis_ops = {
+ .open = tpm_tis_open,
+ .close = tpm_tis_close,
+ .get_desc = tpm_tis_get_desc,
+ .send = tpm_tis_send,
+ .recv = tpm_tis_recv,
+ .cleanup = tpm_tis_cleanup,
+};
+
+static const struct tpm_tis_chip_data tpm_tis_std_chip_data = {
+ .pcr_count = 24,
+ .pcr_select_min = 3,
+};
+
+static const struct udevice_id tpm_tis_ids[] = {
+ {
+ .compatible = "tcg,tpm-tis-mmio",
+ .data = (ulong)&tpm_tis_std_chip_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(tpm_tis_mmio) = {
+ .name = "tpm_tis_mmio",
+ .id = UCLASS_TPM,
+ .of_match = tpm_tis_ids,
+ .ops = &tpm_tis_ops,
+ .probe = tpm_tis_probe,
+ .remove = tpm_tis_remove,
+ .priv_auto = sizeof(struct tpm_chip),
+};