blob: 7c4b9d8b40caf2dc4de0402998004db8aeeb25fe [file] [log] [blame]
Abhi.Singhc8c5faf2024-08-28 14:17:52 -05001/*
2 * Copyright (c) 2025, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <lib/libc/endian.h>
7
8#include <drivers/delay_timer.h>
9#include <drivers/tpm/tpm2.h>
10#include <drivers/tpm/tpm2_chip.h>
11#include <drivers/tpm/tpm2_interface.h>
12
13#define LOCALITY_START_ADDRESS(x, y) \
14 ((uint16_t)(x->address + (0x1000 * y)))
15
16static int tpm2_get_info(struct tpm_chip_data *chip_data, uint8_t locality)
17{
18 uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
19 uint32_t vid_did;
20 uint8_t revision;
21 int err;
22
23 err = tpm2_fifo_read_chunk(tpm_base_addr + TPM_FIFO_REG_VENDID, DWORD, &vid_did);
24 if (err < 0) {
25 return err;
26 }
27
28 err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_REVID, &revision);
29 if (err < 0) {
30 return err;
31 }
32
33 INFO("TPM Chip: vendor-id 0x%x, device-id 0x%x, revision-id: 0x%x\n",
34 0xFFFF & vid_did, vid_did >> 16, revision);
35
36 return TPM_SUCCESS;
37}
38
39static int tpm2_wait_reg_bits(uint16_t reg, uint8_t set, unsigned long timeout, uint8_t *status)
40{
41 int err;
42 uint64_t timeout_delay = timeout_init_us(timeout * 1000);
43
44 do {
45 err = tpm2_fifo_read_byte(reg, status);
46 if (err < 0) {
47 return err;
48 }
49 if ((*status & set) == set) {
50 return TPM_SUCCESS;
51 }
52 } while (!timeout_elapsed(timeout_delay));
53
54 return TPM_ERR_TIMEOUT;
55}
56
57static int tpm2_fifo_request_access(struct tpm_chip_data *chip_data, uint8_t locality)
58{
59 uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
60 uint8_t status;
61 int err;
62
63 err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, TPM_ACCESS_REQUEST_USE);
64 if (err < 0) {
65 return err;
66 }
67
68 err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_ACCESS,
69 TPM_ACCESS_ACTIVE_LOCALITY,
70 chip_data->timeout_msec_a, &status);
71 if (err == 0) {
72 chip_data->locality = locality;
73 return TPM_SUCCESS;
74 }
75
76 return err;
77}
78
79static int tpm2_fifo_release_locality(struct tpm_chip_data *chip_data, uint8_t locality)
80{
81 uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
82 uint8_t buf;
83 int err;
84
85 err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, &buf);
86 if (err < 0) {
87 return err;
88 }
89
90 if (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
91 return tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS,
92 TPM_ACCESS_RELINQUISH_LOCALITY);
93 }
94
95 ERROR("%s: Unable to release locality\n", __func__);
96 return TPM_ERR_RESPONSE;
97}
98
99static int tpm2_fifo_prepare(struct tpm_chip_data *chip_data)
100{
101 uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
102 uint8_t status;
103 int err;
104
105 err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_COMMAND_READY);
106 if (err < 0) {
107 return err;
108 }
109
110 err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
111 TPM_STAT_COMMAND_READY,
112 chip_data->timeout_msec_b, &status);
113 if (err < 0) {
114 ERROR("%s: TPM Status Busy\n", __func__);
115 return err;
116 }
117
118 return TPM_SUCCESS;
119}
120
121static int tpm2_fifo_get_burstcount(struct tpm_chip_data *chip_data, uint16_t *burstcount)
122{
123 uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
124 uint64_t timeout_delay = timeout_init_us(chip_data->timeout_msec_a * 1000);
125 int err;
126
127 if (burstcount == NULL) {
128 return TPM_INVALID_PARAM;
129 }
130
131 do {
132 uint8_t byte0, byte1;
133
134 err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_LO, &byte0);
135 if (err < 0) {
136 return err;
137 }
138
139 err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_HI, &byte1);
140 if (err < 0) {
141 return err;
142 }
143
144 *burstcount = (uint16_t)((byte1 << 8) + byte0);
145 if (*burstcount != 0U) {
146 return TPM_SUCCESS;
147 }
148 } while (!timeout_elapsed(timeout_delay));
149
150 return TPM_ERR_TIMEOUT;
151}
152
153static int tpm2_fifo_send(struct tpm_chip_data *chip_data, const tpm_cmd *buf)
154{
155 uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
156 uint8_t status;
157 uint16_t burstcnt;
158 int err;
159 uint32_t len, index;
160
161 if (sizeof(buf->header) != TPM_HEADER_SIZE) {
162 ERROR("%s: invalid command header size.\n", __func__);
163 return TPM_INVALID_PARAM;
164 }
165
166 err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, &status);
167 if (err < 0) {
168 return err;
169 }
170
171 if (!(status & TPM_STAT_COMMAND_READY)) {
172 err = tpm2_fifo_prepare(chip_data);
173 if (err < 0) {
174 return err;
175 }
176 }
177
178 /* write the command header to the TPM first */
179 const uint8_t *header_data = (const uint8_t *)&buf->header;
180
181 for (index = 0; index < TPM_HEADER_SIZE; index++) {
182 err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
183 header_data[index]);
184 if (err < 0) {
185 return err;
186 }
187 }
188
189 len = be32toh(buf->header.cmd_size);
190
191 while (index < len) {
192 err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
193 if (err < 0) {
194 return err;
195 }
196
197 for (; burstcnt > 0U && index < len; burstcnt--) {
198 err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
199 buf->data[index - TPM_HEADER_SIZE]);
200 if (err < 0) {
201 return err;
202 }
203 index++;
204 }
205 }
206
207 err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
208 TPM_STAT_VALID,
209 chip_data->timeout_msec_c,
210 &status);
211 if (err < 0) {
212 return err;
213 }
214
215 if (status & TPM_STAT_EXPECT) {
216 ERROR("%s: TPM is still expecting data after command buffer is sent\n", __func__);
217 return TPM_ERR_TRANSFER;
218 }
219
220 err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_GO);
221 if (err < 0) {
222 return err;
223 }
224
225 return TPM_SUCCESS;
226}
227
228static int tpm2_fifo_read_data(struct tpm_chip_data *chip_data, tpm_cmd *buf,
229 uint16_t tpm_base_addr, uint8_t *status, int *size, int bytes_expected)
230{
231 int err, read_size, loop_index;
232 uint16_t burstcnt;
233 uint8_t *read_data;
234
235 if (bytes_expected == TPM_READ_HEADER) {
236 /* read the response header from the TPM first */
237 read_data = (uint8_t *)&buf->header;
238 read_size = TPM_HEADER_SIZE;
239 loop_index = *size;
240 } else {
241 /* process the rest of the mssg with bytes_expected */
242 read_data = buf->data;
243 read_size = bytes_expected;
244 loop_index = *size - TPM_HEADER_SIZE;
245 }
246
247 err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
248 TPM_STAT_AVAIL,
249 chip_data->timeout_msec_c,
250 status);
251 if (err < 0) {
252 return err;
253 }
254
255 while (*size < read_size) {
256 err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
257 if (err < 0) {
258 ERROR("%s: TPM burst count error\n", __func__);
259 return err;
260 }
261
262 for (; burstcnt > 0U && loop_index < read_size;
263 burstcnt--, loop_index++, (*size)++) {
264 err = tpm2_fifo_read_byte(
265 tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
266 (void *)&read_data[loop_index]);
267 if (err < 0) {
268 return err;
269 }
270 }
271 }
272
273 return TPM_SUCCESS;
274}
275
276static int tpm2_fifo_receive(struct tpm_chip_data *chip_data, tpm_cmd *buf)
277{
278 uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
279 int size = 0, bytes_expected, err;
280 uint8_t status;
281
282 err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, TPM_READ_HEADER);
283 if (err < 0) {
284 return err;
285 }
286
287 bytes_expected = be32toh(buf->header.cmd_size);
288 if (bytes_expected > sizeof(*buf)) {
289 ERROR("%s: tpm response buffer cannot store expected response\n", __func__);
290 return TPM_INVALID_PARAM;
291 }
292
293 if (size == bytes_expected) {
294 return size;
295 }
296
297 err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, bytes_expected);
298 if (err < 0) {
299 return err;
300 }
301
302 if (size < bytes_expected) {
303 ERROR("%s: response buffer size is less than expected\n", __func__);
304 return TPM_ERR_RESPONSE;
305 }
306
307 return TPM_SUCCESS;
308}
309
310static interface_ops_t fifo_ops = {
311 .get_info = tpm2_get_info,
312 .send = tpm2_fifo_send,
313 .receive = tpm2_fifo_receive,
314 .request_access = tpm2_fifo_request_access,
315 .release_locality = tpm2_fifo_release_locality,
316};
317
318struct interface_ops *
319tpm_interface_getops(struct tpm_chip_data *chip_data, uint8_t locality)
320{
321 return &fifo_ops;
322}