On Fri, 13 May 2022 at 18:30, Eddie James <eaja...@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 <eaja...@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 <j...@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 >