1 /* SPDX-License-Identifier: GPL-2.0-or-later */
4 #include <commonlib/endian.h>
5 #include <commonlib/helpers.h>
6 #include <console/console.h>
8 #include <device/i2c_simple.h>
11 #include <security/tpm/tis.h>
17 #define RECV_TIMEOUT (1 * 1000) /* 1 second */
18 #define XMIT_TIMEOUT (1 * 1000) /* 1 second */
19 #define SLEEP_DURATION 1000 /* microseconds */
21 struct tpm_output_header
{
27 static tpm_result_t
i2c_tis_sendrecv(const uint8_t *sendbuf
, size_t sbuf_size
,
28 uint8_t *recvbuf
, size_t *rbuf_len
)
31 struct tpm_output_header
*header
;
32 size_t max_recv_bytes
;
37 ASSERT(sbuf_size
>= 10);
38 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES
)) {
39 /* Display the TPM command */
41 printk(BIOS_DEBUG
, "TPM Command: 0x%08x\n",
42 read_at_be32(sendbuf
, sizeof(uint16_t)
44 hexdump(sendbuf
, sbuf_size
);
47 /* Send the command to the TPM */
48 stopwatch_init_msecs_expire(&sw
, XMIT_TIMEOUT
);
50 status
= i2c_write_raw(CONFIG_DRIVER_TPM_I2C_BUS
,
51 CONFIG_DRIVER_TPM_I2C_ADDR
, (uint8_t *)sendbuf
,
53 if ((status
< 0) && (!stopwatch_expired(&sw
)))
56 printk(BIOS_ERR
, "I2C write error: %d\n", status
);
57 return TPM_CB_COMMUNICATION_ERROR
;
62 /* Read the TPM response header */
63 max_recv_bytes
= *rbuf_len
;
64 ASSERT(max_recv_bytes
>= sizeof(*header
));
65 hdr_bytes
= sizeof(*header
);
66 header
= (struct tpm_output_header
*)recvbuf
;
67 stopwatch_init_msecs_expire(&sw
, RECV_TIMEOUT
);
69 status
= i2c_read_raw(CONFIG_DRIVER_TPM_I2C_BUS
,
70 CONFIG_DRIVER_TPM_I2C_ADDR
, recvbuf
, hdr_bytes
);
73 udelay(SLEEP_DURATION
);
74 } while (!stopwatch_expired(&sw
));
75 if (status
!= sizeof(*header
))
76 return TPM_CB_COMMUNICATION_ERROR
;
78 /* Determine the number of bytes remaining */
79 recv_bytes
= MIN(be32_to_cpu(*(uint32_t *)&header
->length
),
82 /* Determine if there is additional response data */
83 if (recv_bytes
> hdr_bytes
) {
84 /* Display the TPM response */
85 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES
))
86 hexdump(recvbuf
, hdr_bytes
);
88 /* Read the full TPM response */
89 status
= i2c_read_raw(CONFIG_DRIVER_TPM_I2C_BUS
,
90 CONFIG_DRIVER_TPM_I2C_ADDR
, recvbuf
, recv_bytes
);
92 printk(BIOS_ERR
, "I2C read error: %d\n", status
);
93 return TPM_CB_COMMUNICATION_ERROR
;
97 /* Return the number of bytes received */
100 /* Display the TPM response */
101 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES
)) {
102 printk(BIOS_DEBUG
, "TPM Response: 0x%08x\n",
103 read_at_be32(recvbuf
, sizeof(uint16_t)
104 + sizeof(uint32_t)));
105 hexdump(recvbuf
, *rbuf_len
);
108 /* Successful transfer */
112 tis_sendrecv_fn
i2c_tis_probe(enum tpm_family
*family
)
115 * Can't query version or really anything as the device doesn't support
116 * much through this interface (can't specify address on accesses).
118 * Hence the assumption is that whatever TPM version is enabled at
119 * compile-time defines what the device supports. The check is written
120 * in a way to give TPM 1 preference even if support for both versions
124 *family
= CONFIG(TPM1
) ? TPM_1
: TPM_2
;
126 return &i2c_tis_sendrecv
;