treewide: replace GPLv2 long form headers with SPDX header
[coreboot.git] / src / drivers / i2c / tpm / tis.c
bloba7004a82e336e022809e885dd8dc8fe37d5c66dc
1 /* This file is part of the coreboot project. */
2 /* SPDX-License-Identifier: GPL-2.0-or-later */
4 #include <stdint.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <commonlib/endian.h>
8 #include <console/console.h>
9 #include <delay.h>
10 #include <device/i2c_simple.h>
11 #include <endian.h>
12 #include <lib.h>
13 #include <security/tpm/tis.h>
15 #include "tpm.h"
17 /* global structure for tpm chip data */
18 static struct tpm_chip chip;
20 #define TPM_CMD_COUNT_BYTE 2
21 #define TPM_CMD_ORDINAL_BYTE 6
23 int tis_open(void)
25 int rc;
27 if (chip.is_open) {
28 printk(BIOS_DEBUG, "tis_open() called twice.\n");
29 return -1;
32 rc = tpm_vendor_init(&chip, CONFIG_DRIVER_TPM_I2C_BUS,
33 CONFIG_DRIVER_TPM_I2C_ADDR);
34 if (rc < 0)
35 chip.is_open = 0;
37 if (rc)
38 return -1;
40 return 0;
43 int tis_close(void)
45 if (chip.is_open) {
46 tpm_vendor_cleanup(&chip);
47 chip.is_open = 0;
50 return 0;
53 int tis_init(void)
55 return tpm_vendor_probe(CONFIG_DRIVER_TPM_I2C_BUS,
56 CONFIG_DRIVER_TPM_I2C_ADDR);
59 static ssize_t tpm_transmit(const uint8_t *sbuf, size_t sbufsiz, void *rbuf,
60 size_t rbufsiz)
62 int rc;
63 uint32_t count;
65 memcpy(&count, sbuf + TPM_CMD_COUNT_BYTE, sizeof(count));
66 count = be32_to_cpu(count);
68 if (!chip.vendor.send || !chip.vendor.status || !chip.vendor.cancel)
69 return -1;
71 if (count == 0) {
72 printk(BIOS_DEBUG, "tpm_transmit: no data\n");
73 return -1;
75 if (count > sbufsiz) {
76 printk(BIOS_DEBUG, "tpm_transmit: invalid count value %x %zx\n",
77 count, sbufsiz);
78 return -1;
81 ASSERT(chip.vendor.send);
82 rc = chip.vendor.send(&chip, (uint8_t *) sbuf, count);
83 if (rc < 0) {
84 printk(BIOS_DEBUG, "tpm_transmit: tpm_send error\n");
85 goto out;
88 int timeout = 2 * 60 * 1000; /* two minutes timeout */
89 while (timeout) {
90 ASSERT(chip.vendor.status);
91 uint8_t status = chip.vendor.status(&chip);
92 if ((status & chip.vendor.req_complete_mask) ==
93 chip.vendor.req_complete_val) {
94 goto out_recv;
97 if (status == chip.vendor.req_canceled) {
98 printk(BIOS_DEBUG,
99 "tpm_transmit: Operation Canceled\n");
100 rc = -1;
101 goto out;
103 mdelay(TPM_TIMEOUT);
104 timeout--;
107 ASSERT(chip.vendor.cancel);
108 chip.vendor.cancel(&chip);
109 printk(BIOS_DEBUG, "tpm_transmit: Operation Timed out\n");
110 rc = -1; //ETIME;
111 goto out;
113 out_recv:
115 rc = chip.vendor.recv(&chip, (uint8_t *) rbuf, rbufsiz);
116 if (rc < 0)
117 printk(BIOS_DEBUG, "tpm_transmit: tpm_recv: error %d\n", rc);
118 out:
119 return rc;
122 int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
123 uint8_t *recvbuf, size_t *rbuf_len)
125 ASSERT(sbuf_size >= 10);
127 /* Display the TPM command */
128 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
129 printk(BIOS_DEBUG, "TPM Command: 0x%08x\n",
130 read_at_be32(sendbuf, sizeof(uint16_t)
131 + sizeof(uint32_t)));
132 hexdump(sendbuf, sbuf_size);
135 int len = tpm_transmit(sendbuf, sbuf_size, recvbuf, *rbuf_len);
137 if (len < 10) {
138 *rbuf_len = 0;
139 return -1;
142 if (len > *rbuf_len) {
143 *rbuf_len = len;
144 return -1;
147 *rbuf_len = len;
149 /* Display the TPM response */
150 if (CONFIG(DRIVER_TPM_DISPLAY_TIS_BYTES)) {
151 printk(BIOS_DEBUG, "TPM Response: 0x%08x\n",
152 read_at_be32(recvbuf, sizeof(uint16_t)
153 + sizeof(uint32_t)));
154 hexdump(recvbuf, *rbuf_len);
157 return 0;