blob: 0a29049d95a15b866460cea16c2b2e4ce349feef [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Lee Leahy1b39f172017-01-05 17:59:38 -08002
Lee Leahy1b39f172017-01-05 17:59:38 -08003#include <assert.h>
4#include <commonlib/endian.h>
Elyes HAOUAS361a9352019-12-18 21:26:33 +01005#include <commonlib/helpers.h>
Lee Leahy1b39f172017-01-05 17:59:38 -08006#include <console/console.h>
7#include <delay.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02008#include <device/i2c_simple.h>
Lee Leahy1b39f172017-01-05 17:59:38 -08009#include <endian.h>
10#include <lib.h>
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020011#include <security/tpm/tis.h>
Lee Leahy1b39f172017-01-05 17:59:38 -080012#include <timer.h>
Elyes HAOUASede8dd02019-06-23 06:57:53 +020013#include <types.h>
Lee Leahy1b39f172017-01-05 17:59:38 -080014
15#define RECV_TIMEOUT (1 * 1000) /* 1 second */
16#define XMIT_TIMEOUT (1 * 1000) /* 1 second */
17#define SLEEP_DURATION 1000 /* microseconds */
18
19struct tpm_output_header {
20 uint16_t tag;
21 uint32_t length;
22 uint32_t return_code;
Stefan Reinauer6a001132017-07-13 02:20:27 +020023} __packed;
Lee Leahy1b39f172017-01-05 17:59:38 -080024
Sergii Dmytruk963f7b92022-10-29 20:42:28 +030025static tpm_result_t i2c_tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
26 uint8_t *recvbuf, size_t *rbuf_len)
Lee Leahy1b39f172017-01-05 17:59:38 -080027{
28 size_t hdr_bytes;
29 struct tpm_output_header *header;
30 size_t max_recv_bytes;
31 size_t recv_bytes;
32 int status;
33 struct stopwatch sw;
34
35 ASSERT(sbuf_size >= 10);
Julius Wernercd49cce2019-03-05 16:53:33 -080036 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
Lee Leahy1b39f172017-01-05 17:59:38 -080037 /* Display the TPM command */
38 if (sbuf_size >= 10)
39 printk(BIOS_DEBUG, "TPM Command: 0x%08x\n",
40 read_at_be32(sendbuf, sizeof(uint16_t)
41 + sizeof(uint32_t)));
42 hexdump(sendbuf, sbuf_size);
43 }
44
45 /* Send the command to the TPM */
46 stopwatch_init_msecs_expire(&sw, XMIT_TIMEOUT);
47 while (1) {
48 status = i2c_write_raw(CONFIG_DRIVER_TPM_I2C_BUS,
49 CONFIG_DRIVER_TPM_I2C_ADDR, (uint8_t *)sendbuf,
50 sbuf_size);
51 if ((status < 0) && (!stopwatch_expired(&sw)))
52 continue;
Jon Murphyd7b8dc92023-09-05 11:36:43 -060053 if (status < 0) {
54 printk(BIOS_ERR, "I2C write error: %d\n", status);
55 return TPM_CB_COMMUNICATION_ERROR;
56 }
Lee Leahy1b39f172017-01-05 17:59:38 -080057 break;
58 }
59
60 /* Read the TPM response header */
61 max_recv_bytes = *rbuf_len;
62 ASSERT(max_recv_bytes >= sizeof(*header));
63 hdr_bytes = sizeof(*header);
64 header = (struct tpm_output_header *)recvbuf;
65 stopwatch_init_msecs_expire(&sw, RECV_TIMEOUT);
66 do {
67 status = i2c_read_raw(CONFIG_DRIVER_TPM_I2C_BUS,
68 CONFIG_DRIVER_TPM_I2C_ADDR, recvbuf, hdr_bytes);
69 if (status > 0)
70 break;
71 udelay(SLEEP_DURATION);
72 } while (!stopwatch_expired(&sw));
73 if (status != sizeof(*header))
Jon Murphyd7b8dc92023-09-05 11:36:43 -060074 return TPM_CB_COMMUNICATION_ERROR;
Lee Leahy1b39f172017-01-05 17:59:38 -080075
76 /* Determine the number of bytes remaining */
Elyes HAOUAS361a9352019-12-18 21:26:33 +010077 recv_bytes = MIN(be32_to_cpu(*(uint32_t *)&header->length),
Lee Leahy1b39f172017-01-05 17:59:38 -080078 max_recv_bytes);
79
80 /* Determine if there is additional response data */
81 if (recv_bytes > hdr_bytes) {
82 /* Display the TPM response */
Julius Wernercd49cce2019-03-05 16:53:33 -080083 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES))
Lee Leahy1b39f172017-01-05 17:59:38 -080084 hexdump(recvbuf, hdr_bytes);
85
86 /* Read the full TPM response */
87 status = i2c_read_raw(CONFIG_DRIVER_TPM_I2C_BUS,
88 CONFIG_DRIVER_TPM_I2C_ADDR, recvbuf, recv_bytes);
Jon Murphyd7b8dc92023-09-05 11:36:43 -060089 if (status < 0) {
90 printk(BIOS_ERR, "I2C read error: %d\n", status);
91 return TPM_CB_COMMUNICATION_ERROR;
92 }
Lee Leahy1b39f172017-01-05 17:59:38 -080093 }
94
95 /* Return the number of bytes received */
96 *rbuf_len = status;
97
98 /* Display the TPM response */
Julius Wernercd49cce2019-03-05 16:53:33 -080099 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
Lee Leahy1b39f172017-01-05 17:59:38 -0800100 printk(BIOS_DEBUG, "TPM Response: 0x%08x\n",
101 read_at_be32(recvbuf, sizeof(uint16_t)
102 + sizeof(uint32_t)));
103 hexdump(recvbuf, *rbuf_len);
104 }
105
106 /* Successful transfer */
Jon Murphyd7b8dc92023-09-05 11:36:43 -0600107 return TPM_SUCCESS;
Lee Leahy1b39f172017-01-05 17:59:38 -0800108}
Sergii Dmytruk963f7b92022-10-29 20:42:28 +0300109
110tis_sendrecv_fn tis_probe(void)
111{
112 return &i2c_tis_sendrecv;
113}