[PATCH 2/2] tpm: add support for TPMv2.x I2C chips

Joel Stanley joel at jms.id.au
Thu May 19 02:26:26 CEST 2022


On Fri, 13 May 2022 at 18:30, Eddie James <eajames at linux.ibm.com> wrote:
>
> Add the tpm2_tis_i2c driver that should support any TPMv2 compliant
> I2C chips, such as the NPCT75X chip.
>
> Signed-off-by: Eddie James <eajames at linux.ibm.com>
> ---
>  drivers/tpm/Kconfig        |   9 ++
>  drivers/tpm/Makefile       |   1 +
>  drivers/tpm/tpm2_tis_i2c.c | 171 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 181 insertions(+)
>  create mode 100644 drivers/tpm/tpm2_tis_i2c.c
>
> diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
> index eceff27d5f..d59102d9a6 100644
> --- a/drivers/tpm/Kconfig
> +++ b/drivers/tpm/Kconfig
> @@ -185,6 +185,15 @@ config TPM2_TIS_SPI
>           to the device using the standard TPM Interface Specification (TIS)
>           protocol.
>
> +config TPM2_TIS_I2C
> +       bool "Enable support for TPMv2.x I2C chips"
> +       depends on TPM_V2 && DM_I2C
> +       help
> +         This driver supports TPMv2.x 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 TPM2_FTPM_TEE
>         bool "TEE based fTPM Interface"
>         depends on TEE && OPTEE && TPM_V2
> diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
> index 51725230c7..9540fd7fe7 100644
> --- a/drivers/tpm/Makefile
> +++ b/drivers/tpm/Makefile
> @@ -13,5 +13,6 @@ obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
>  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_core.o tpm2_tis_spi.o
> +obj-$(CONFIG_TPM2_TIS_I2C) += tpm2_tis_core.o tpm2_tis_i2c.o
>  obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
>  obj-$(CONFIG_TPM2_MMIO) += tpm2_tis_core.o tpm2_tis_mmio.o
> diff --git a/drivers/tpm/tpm2_tis_i2c.c b/drivers/tpm/tpm2_tis_i2c.c
> new file mode 100644
> index 0000000000..33cd5bb84b
> --- /dev/null
> +++ b/drivers/tpm/tpm2_tis_i2c.c
> @@ -0,0 +1,171 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2022 IBM Corp.
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <fdtdec.h>
> +#include <i2c.h>
> +#include <log.h>
> +#include <tpm-v2.h>
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/compiler.h>
> +#include <linux/types.h>
> +#include <linux/unaligned/be_byteshift.h>
> +#include <asm-generic/gpio.h>
> +
> +#include "tpm_tis.h"
> +#include "tpm_internal.h"
> +
> +struct tpm_tis_chip_data {
> +       unsigned int pcr_count;
> +       unsigned int pcr_select_min;
> +};
> +
> +static uint tpm_tis_i2c_address_to_register(u32 addr)
> +{
> +       addr &= 0xFFF;
> +
> +       /*
> +        * Adapt register addresses that have changed compared to older TIS
> +        * version.
> +        */
> +       switch (addr) {
> +       case TPM_ACCESS(0):
> +               return 0x04;
> +       case TPM_DID_VID(0):
> +               return 0x48;
> +       case TPM_RID(0):
> +               return 0x4C;
> +       default:
> +               return addr;
> +       }
> +}
> +
> +static int tpm_tis_i2c_read(struct udevice *dev, u32 addr, u16 len, u8 *in)
> +{
> +       int rc;
> +       int count = 0;
> +       uint reg = tpm_tis_i2c_address_to_register(addr);
> +
> +       do {
> +               rc = dm_i2c_read(dev, reg, in, len);
> +               udelay(SLEEP_DURATION_US);
> +       } while (rc && count++ < MAX_COUNT);
> +
> +       return rc;
> +}
> +
> +static int tpm_tis_i2c_write(struct udevice *dev, u32 addr, u16 len,
> +                            const u8 *out)
> +{
> +       int rc;
> +       int count = 0;
> +       uint reg = tpm_tis_i2c_address_to_register(addr);
> +
> +       do {
> +               rc = dm_i2c_write(dev, reg, out, len);
> +               udelay(SLEEP_DURATION_US);
> +       } while (rc && count++ < MAX_COUNT);
> +
> +       return rc;
> +}
> +
> +static int tpm_tis_i2c_read32(struct udevice *dev, u32 addr, u32 *result)
> +{
> +       __le32 result_le;
> +       int rc;
> +
> +       rc = tpm_tis_i2c_read(dev, addr, sizeof(u32), (u8 *)&result_le);
> +       if (!rc)
> +               *result = le32_to_cpu(result_le);
> +
> +       return rc;
> +}
> +
> +static int tpm_tis_i2c_write32(struct udevice *dev, u32 addr, u32 value)
> +{
> +       __le32 value_le = cpu_to_le32(value);
> +
> +       return tpm_tis_i2c_write(dev, addr, sizeof(value), (u8 *)&value_le);
> +}
> +
> +static struct tpm_tis_phy_ops phy_ops = {
> +       .read_bytes = tpm_tis_i2c_read,
> +       .write_bytes = tpm_tis_i2c_write,
> +       .read32 = tpm_tis_i2c_read32,
> +       .write32 = tpm_tis_i2c_write32,
> +};
> +
> +static int tpm_tis_i2c_probe(struct udevice *udev)
> +{
> +       struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev);
> +       struct tpm_chip_priv *priv = dev_get_uclass_priv(udev);
> +       int rc;
> +       u8 loc = 0;
> +
> +       tpm_tis_ops_register(udev, &phy_ops);
> +
> +       /*
> +        * Force locality 0. The core driver doesn't actually write the
> +        * locality register and instead just reads/writes various access
> +        * bits of the selected locality.
> +        */
> +       rc = dm_i2c_write(udev, 0, &loc, 1);
> +       if (rc)
> +               return rc;
> +
> +       rc = tpm_tis_init(udev);
> +       if (rc)
> +               return rc;
> +
> +       priv->pcr_count = drv_data->pcr_count;
> +       priv->pcr_select_min = drv_data->pcr_select_min;
> +       priv->version = TPM_V2;
> +
> +       return 0;
> +}
> +
> +static int tpm_tis_i2c_remove(struct udevice *udev)
 > +{
> +       return tpm_tis_cleanup(udev);
> +}
> +
> +static const struct tpm_ops tpm_tis_i2c_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_i2c_ids[] = {
> +       {
> +               .compatible = "nuvoton,npct75x",
> +               .data = (ulong)&tpm_tis_std_chip_data,
> +       },
> +       {
> +               .compatible = "tcg,tpm-tis-i2c",
> +               .data = (ulong)&tpm_tis_std_chip_data,

The .data pointers are the same, so could we do away with it all
together and just have

#define TPM_TIS_I2C_PCR_COUNT 24
#define TPM_TIS_I2C_PCR_SELECT_MIN 3

Aside from that small cleanup:

Reviewed-by: Joel Stanley <joel at jms.id.au>


> +       },
> +       { }
> +};
> +
> +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,
> +       .remove = tpm_tis_i2c_remove,
> +       .priv_auto_alloc_size = sizeof(struct tpm_chip),
> +};
> --
> 2.27.0
>


More information about the U-Boot mailing list