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