summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/spi/tpm/tpm.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/src/drivers/spi/tpm/tpm.c b/src/drivers/spi/tpm/tpm.c
index 0b5a835837..58bf842267 100644
--- a/src/drivers/spi/tpm/tpm.c
+++ b/src/drivers/spi/tpm/tpm.c
@@ -280,7 +280,8 @@ static int tpm2_write_reg(unsigned reg_number, const void *buffer, size_t bytes)
* To read a register, start transaction, transfer data from the TPM, deassert
* CS when done.
*
- * Returns one to indicate success, zero to indicate failure.
+ * Returns one to indicate success, zero to indicate failure. In case of
+ * failure zero out the user buffer.
*/
static int tpm2_read_reg(unsigned reg_number, void *buffer, size_t bytes)
{
@@ -368,21 +369,52 @@ static int tpm2_claim_locality(void)
return 1;
}
+/* Device/vendor ID values of the TPM devices this driver supports. */
+static const uint32_t supported_did_vids[] = {
+ 0x00281ae0 /* H1 based Cr50 security chip. */
+};
+
int tpm2_init(struct spi_slave *spi_if)
{
uint32_t did_vid, status;
uint8_t cmd;
+ int retries;
struct tpm2_info *tpm_info = car_get_var_ptr(&g_tpm_info);
struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave);
memcpy(spi_slave, spi_if, sizeof(*spi_if));
/*
- * It is enough to check the first register read error status to bail
- * out in case of malfunctioning TPM.
+ * 150 ms should be enough to synchronize with the TPM even under the
+ * worst nested reset request conditions. In vast majority of cases
+ * there would be no wait at all.
*/
- if (!tpm2_read_reg(TPM_DID_VID_REG, &did_vid, sizeof(did_vid)))
+ printk(BIOS_INFO, "Probing TPM: ");
+ for (retries = 15; retries > 0; retries--) {
+ int i;
+
+ /* In case of falure to read div_vid is set to zero. */
+ tpm2_read_reg(TPM_DID_VID_REG, &did_vid, sizeof(did_vid));
+
+ for (i = 0; i < ARRAY_SIZE(supported_did_vids); i++)
+ if (did_vid == supported_did_vids[i])
+ break; /* Tpm is up and ready. */
+
+ if (i < ARRAY_SIZE(supported_did_vids))
+ break;
+
+ /* TPM might be resetting, let's retry in a bit. */
+ mdelay(10);
+ printk(BIOS_INFO, ".");
+ }
+
+ if (!retries) {
+ printk(BIOS_ERR, "\n%s: Failed to connect to the TPM\n",
+ __func__);
return -1;
+ }
+
+ printk(BIOS_INFO, " done!\n");
/* Claim locality 0. */
if (!tpm2_claim_locality())