mb/google/brya: Create rull variant
[coreboot2.git] / src / drivers / i2c / tpm / tis.c
blob1fba61a12fe353cac413059575a8e4370ed0d9ac
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <stdint.h>
4 #include <string.h>
5 #include <assert.h>
6 #include <commonlib/endian.h>
7 #include <console/console.h>
8 #include <delay.h>
9 #include <device/i2c_simple.h>
10 #include <endian.h>
11 #include <lib.h>
12 #include <security/tpm/tis.h>
14 #include "tpm.h"
16 /* global structure for tpm chip data */
17 static struct tpm_chip chip;
19 #define TPM_CMD_COUNT_BYTE 2
20 #define TPM_CMD_ORDINAL_BYTE 6
22 static ssize_t tpm_transmit(const uint8_t *sbuf, size_t sbufsiz, void *rbuf,
23 size_t rbufsiz)
25 int rc = -1;
26 uint32_t count;
28 memcpy(&count, sbuf + TPM_CMD_COUNT_BYTE, sizeof(count));
29 count = be32_to_cpu(count);
31 if (!chip.send || !chip.status || !chip.cancel)
32 goto out;
34 if (count == 0) {
35 printk(BIOS_DEBUG, "%s: no data\n", __func__);
36 goto out;
38 if (count > sbufsiz) {
39 printk(BIOS_DEBUG, "%s: invalid count value %#x %zx\n", __func__,
40 count, sbufsiz);
41 goto out;
44 ASSERT(chip.send);
45 rc = chip.send((uint8_t *)sbuf, count);
46 if (rc < 0) {
47 printk(BIOS_DEBUG, "%s: tpm_send error\n", __func__);
48 goto out;
51 int timeout = 2 * 60 * 1000; /* two minutes timeout */
52 while (timeout) {
53 ASSERT(chip.status);
54 uint8_t status = chip.status();
55 if ((status & chip.req_complete_mask) == chip.req_complete_val) {
56 goto out_recv;
59 if (status == chip.req_canceled) {
60 printk(BIOS_DEBUG,
61 "%s: Operation Canceled\n", __func__);
62 rc = -1;
63 goto out;
65 mdelay(TPM_TIMEOUT);
66 timeout--;
69 ASSERT(chip.cancel);
70 chip.cancel();
71 printk(BIOS_DEBUG, "%s: Operation Timed out\n", __func__);
72 rc = -1;
73 goto out;
75 out_recv:
76 rc = chip.recv((uint8_t *)rbuf, rbufsiz);
77 if (rc < 0)
78 printk(BIOS_DEBUG, "%s: tpm_recv: error %d\n", __func__, rc);
79 out:
80 return rc;
83 static tpm_result_t i2c_tpm_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
84 uint8_t *recvbuf, size_t *rbuf_len)
86 ASSERT(sbuf_size >= 10);
88 /* Display the TPM command */
89 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
90 printk(BIOS_DEBUG, "TPM Command: 0x%08x\n",
91 read_at_be32(sendbuf, sizeof(uint16_t)
92 + sizeof(uint32_t)));
93 hexdump(sendbuf, sbuf_size);
96 int len = tpm_transmit(sendbuf, sbuf_size, recvbuf, *rbuf_len);
98 if (len < 10) {
99 *rbuf_len = 0;
100 return TPM_CB_FAIL;
103 if (len > *rbuf_len) {
104 *rbuf_len = len;
105 return TPM_CB_FAIL;
108 *rbuf_len = len;
110 /* Display the TPM response */
111 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
112 printk(BIOS_DEBUG, "TPM Response: 0x%08x\n",
113 read_at_be32(recvbuf, sizeof(uint16_t)
114 + sizeof(uint32_t)));
115 hexdump(recvbuf, *rbuf_len);
118 return TPM_SUCCESS;
121 tis_sendrecv_fn i2c_tis_probe(enum tpm_family *family)
123 if (tpm_vendor_probe(CONFIG_DRIVER_TPM_I2C_BUS, CONFIG_DRIVER_TPM_I2C_ADDR, family))
124 return NULL;
126 if (tpm_vendor_init(&chip, CONFIG_DRIVER_TPM_I2C_BUS, CONFIG_DRIVER_TPM_I2C_ADDR))
127 return NULL;
129 return &i2c_tpm_sendrecv;