mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
tpm: add support for TPMv2.x I2C chips
Add the tpm2_tis_i2c driver that should support any TPMv2 compliant I2C chips, such as the NPCT75X chip. [Ilias rename priv_auto_alloc_size to priv_auto] Signed-off-by: Eddie James <eajames@linux.ibm.com> Reviewed-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
This commit is contained in:
parent
8d7199da3f
commit
9f971dac93
3 changed files with 181 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
171
drivers/tpm/tpm2_tis_i2c.c
Normal file
171
drivers/tpm/tpm2_tis_i2c.c
Normal file
|
@ -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,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
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 = sizeof(struct tpm_chip),
|
||||
};
|
Loading…
Reference in a new issue