xref: /rk3399_ARM-atf/drivers/tpm/tpm2_fifo.c (revision 07282860f491eaa95bf7d29790bfdd906c6018d0)
136e3d877SAbhi.Singh /*
236e3d877SAbhi.Singh  * Copyright (c) 2025, Arm Limited. All rights reserved.
336e3d877SAbhi.Singh  *
436e3d877SAbhi.Singh  * SPDX-License-Identifier: BSD-3-Clause
536e3d877SAbhi.Singh  */
636e3d877SAbhi.Singh #include <lib/libc/endian.h>
736e3d877SAbhi.Singh 
836e3d877SAbhi.Singh #include <drivers/delay_timer.h>
936e3d877SAbhi.Singh #include <drivers/tpm/tpm2.h>
1036e3d877SAbhi.Singh #include <drivers/tpm/tpm2_chip.h>
1136e3d877SAbhi.Singh #include <drivers/tpm/tpm2_interface.h>
1236e3d877SAbhi.Singh 
1336e3d877SAbhi.Singh #define LOCALITY_START_ADDRESS(x, y) \
1436e3d877SAbhi.Singh 	((uint16_t)(x->address + (0x1000 * y)))
1536e3d877SAbhi.Singh 
tpm2_get_info(struct tpm_chip_data * chip_data,uint8_t locality)1636e3d877SAbhi.Singh static int tpm2_get_info(struct tpm_chip_data *chip_data, uint8_t locality)
1736e3d877SAbhi.Singh {
1836e3d877SAbhi.Singh 	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
1936e3d877SAbhi.Singh 	uint32_t vid_did;
2036e3d877SAbhi.Singh 	uint8_t revision;
2136e3d877SAbhi.Singh 	int err;
2236e3d877SAbhi.Singh 
2336e3d877SAbhi.Singh 	err = tpm2_fifo_read_chunk(tpm_base_addr + TPM_FIFO_REG_VENDID, DWORD, &vid_did);
2436e3d877SAbhi.Singh 	if (err < 0) {
2536e3d877SAbhi.Singh 		return err;
2636e3d877SAbhi.Singh 	}
2736e3d877SAbhi.Singh 
2836e3d877SAbhi.Singh 	err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_REVID, &revision);
2936e3d877SAbhi.Singh 	if (err < 0) {
3036e3d877SAbhi.Singh 		return err;
3136e3d877SAbhi.Singh 	}
3236e3d877SAbhi.Singh 
3336e3d877SAbhi.Singh 	INFO("TPM Chip: vendor-id 0x%x, device-id 0x%x, revision-id: 0x%x\n",
3436e3d877SAbhi.Singh 		0xFFFF & vid_did, vid_did >> 16, revision);
3536e3d877SAbhi.Singh 
3636e3d877SAbhi.Singh 	return TPM_SUCCESS;
3736e3d877SAbhi.Singh }
3836e3d877SAbhi.Singh 
tpm2_wait_reg_bits(uint16_t reg,uint8_t set,unsigned long timeout,uint8_t * status)3936e3d877SAbhi.Singh static int tpm2_wait_reg_bits(uint16_t reg, uint8_t set, unsigned long timeout, uint8_t *status)
4036e3d877SAbhi.Singh {
4136e3d877SAbhi.Singh 	int err;
4236e3d877SAbhi.Singh 	uint64_t timeout_delay = timeout_init_us(timeout * 1000);
4336e3d877SAbhi.Singh 
4436e3d877SAbhi.Singh 	do {
4536e3d877SAbhi.Singh 		err = tpm2_fifo_read_byte(reg, status);
4636e3d877SAbhi.Singh 		if (err < 0) {
4736e3d877SAbhi.Singh 			return err;
4836e3d877SAbhi.Singh 		}
4936e3d877SAbhi.Singh 		if ((*status & set) == set) {
5036e3d877SAbhi.Singh 			return TPM_SUCCESS;
5136e3d877SAbhi.Singh 		}
5236e3d877SAbhi.Singh 	} while (!timeout_elapsed(timeout_delay));
5336e3d877SAbhi.Singh 
5436e3d877SAbhi.Singh 	return TPM_ERR_TIMEOUT;
5536e3d877SAbhi.Singh }
5636e3d877SAbhi.Singh 
tpm2_fifo_request_access(struct tpm_chip_data * chip_data,uint8_t locality)5736e3d877SAbhi.Singh static int tpm2_fifo_request_access(struct tpm_chip_data *chip_data, uint8_t locality)
5836e3d877SAbhi.Singh {
5936e3d877SAbhi.Singh 	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
6036e3d877SAbhi.Singh 	uint8_t status;
6136e3d877SAbhi.Singh 	int err;
6236e3d877SAbhi.Singh 
6336e3d877SAbhi.Singh 	err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, TPM_ACCESS_REQUEST_USE);
6436e3d877SAbhi.Singh 	if (err < 0) {
6536e3d877SAbhi.Singh 		return err;
6636e3d877SAbhi.Singh 	}
6736e3d877SAbhi.Singh 
6836e3d877SAbhi.Singh 	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_ACCESS,
6936e3d877SAbhi.Singh 				TPM_ACCESS_ACTIVE_LOCALITY,
7036e3d877SAbhi.Singh 				chip_data->timeout_msec_a, &status);
7136e3d877SAbhi.Singh 	if (err == 0) {
7236e3d877SAbhi.Singh 		chip_data->locality = locality;
7336e3d877SAbhi.Singh 		return TPM_SUCCESS;
7436e3d877SAbhi.Singh 	}
7536e3d877SAbhi.Singh 
7636e3d877SAbhi.Singh 	return err;
7736e3d877SAbhi.Singh }
7836e3d877SAbhi.Singh 
tpm2_fifo_release_locality(struct tpm_chip_data * chip_data,uint8_t locality)7936e3d877SAbhi.Singh static int tpm2_fifo_release_locality(struct tpm_chip_data *chip_data, uint8_t locality)
8036e3d877SAbhi.Singh {
8136e3d877SAbhi.Singh 	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
8236e3d877SAbhi.Singh 	uint8_t buf;
8336e3d877SAbhi.Singh 	int err;
8436e3d877SAbhi.Singh 
8536e3d877SAbhi.Singh 	err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, &buf);
8636e3d877SAbhi.Singh 	if (err < 0) {
8736e3d877SAbhi.Singh 		return err;
8836e3d877SAbhi.Singh 	}
8936e3d877SAbhi.Singh 
9036e3d877SAbhi.Singh 	if (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
9136e3d877SAbhi.Singh 		return tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS,
9236e3d877SAbhi.Singh 				TPM_ACCESS_RELINQUISH_LOCALITY);
9336e3d877SAbhi.Singh 	}
9436e3d877SAbhi.Singh 
9536e3d877SAbhi.Singh 	ERROR("%s: Unable to release locality\n", __func__);
9636e3d877SAbhi.Singh 	return TPM_ERR_RESPONSE;
9736e3d877SAbhi.Singh }
9836e3d877SAbhi.Singh 
tpm2_fifo_prepare(struct tpm_chip_data * chip_data)9936e3d877SAbhi.Singh static int tpm2_fifo_prepare(struct tpm_chip_data *chip_data)
10036e3d877SAbhi.Singh {
10136e3d877SAbhi.Singh 	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
10236e3d877SAbhi.Singh 	uint8_t status;
10336e3d877SAbhi.Singh 	int err;
10436e3d877SAbhi.Singh 
10536e3d877SAbhi.Singh 	err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_COMMAND_READY);
10636e3d877SAbhi.Singh 	if (err < 0) {
10736e3d877SAbhi.Singh 		return err;
10836e3d877SAbhi.Singh 	}
10936e3d877SAbhi.Singh 
11036e3d877SAbhi.Singh 	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
11136e3d877SAbhi.Singh 				TPM_STAT_COMMAND_READY,
11236e3d877SAbhi.Singh 				chip_data->timeout_msec_b, &status);
11336e3d877SAbhi.Singh 	if (err < 0) {
11436e3d877SAbhi.Singh 		ERROR("%s: TPM Status Busy\n", __func__);
11536e3d877SAbhi.Singh 		return err;
11636e3d877SAbhi.Singh 	}
11736e3d877SAbhi.Singh 
11836e3d877SAbhi.Singh 	return TPM_SUCCESS;
11936e3d877SAbhi.Singh }
12036e3d877SAbhi.Singh 
tpm2_fifo_get_burstcount(struct tpm_chip_data * chip_data,uint16_t * burstcount)12136e3d877SAbhi.Singh static int tpm2_fifo_get_burstcount(struct tpm_chip_data *chip_data, uint16_t *burstcount)
12236e3d877SAbhi.Singh {
12336e3d877SAbhi.Singh 	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
12436e3d877SAbhi.Singh 	uint64_t timeout_delay = timeout_init_us(chip_data->timeout_msec_a * 1000);
12536e3d877SAbhi.Singh 	int err;
12636e3d877SAbhi.Singh 
12736e3d877SAbhi.Singh 	if (burstcount == NULL) {
12836e3d877SAbhi.Singh 		return TPM_INVALID_PARAM;
12936e3d877SAbhi.Singh 	}
13036e3d877SAbhi.Singh 
13136e3d877SAbhi.Singh 	do {
13236e3d877SAbhi.Singh 		uint8_t byte0, byte1;
13336e3d877SAbhi.Singh 
13436e3d877SAbhi.Singh 		err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_LO, &byte0);
13536e3d877SAbhi.Singh 		if (err < 0) {
13636e3d877SAbhi.Singh 			return err;
13736e3d877SAbhi.Singh 		}
13836e3d877SAbhi.Singh 
13936e3d877SAbhi.Singh 		err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_HI, &byte1);
14036e3d877SAbhi.Singh 		if (err < 0) {
14136e3d877SAbhi.Singh 			return err;
14236e3d877SAbhi.Singh 		}
14336e3d877SAbhi.Singh 
14436e3d877SAbhi.Singh 		*burstcount = (uint16_t)((byte1 << 8) + byte0);
14536e3d877SAbhi.Singh 		if (*burstcount != 0U) {
14636e3d877SAbhi.Singh 			return TPM_SUCCESS;
14736e3d877SAbhi.Singh 		}
14836e3d877SAbhi.Singh 	} while (!timeout_elapsed(timeout_delay));
14936e3d877SAbhi.Singh 
15036e3d877SAbhi.Singh 	return TPM_ERR_TIMEOUT;
15136e3d877SAbhi.Singh }
15236e3d877SAbhi.Singh 
tpm2_fifo_send(struct tpm_chip_data * chip_data,const tpm_cmd * buf)15336e3d877SAbhi.Singh static int tpm2_fifo_send(struct tpm_chip_data *chip_data, const tpm_cmd *buf)
15436e3d877SAbhi.Singh {
15536e3d877SAbhi.Singh 	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
15636e3d877SAbhi.Singh 	uint8_t status;
15736e3d877SAbhi.Singh 	uint16_t burstcnt;
15836e3d877SAbhi.Singh 	int err;
15936e3d877SAbhi.Singh 	uint32_t len, index;
16036e3d877SAbhi.Singh 
16136e3d877SAbhi.Singh 	if (sizeof(buf->header) != TPM_HEADER_SIZE) {
16236e3d877SAbhi.Singh 		ERROR("%s: invalid command header size.\n", __func__);
16336e3d877SAbhi.Singh 		return TPM_INVALID_PARAM;
16436e3d877SAbhi.Singh 	}
16536e3d877SAbhi.Singh 
16636e3d877SAbhi.Singh 	err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, &status);
16736e3d877SAbhi.Singh 	if (err < 0) {
16836e3d877SAbhi.Singh 		return err;
16936e3d877SAbhi.Singh 	}
17036e3d877SAbhi.Singh 
17136e3d877SAbhi.Singh 	if (!(status & TPM_STAT_COMMAND_READY)) {
17236e3d877SAbhi.Singh 		err = tpm2_fifo_prepare(chip_data);
17336e3d877SAbhi.Singh 		if (err < 0) {
17436e3d877SAbhi.Singh 			return err;
17536e3d877SAbhi.Singh 		}
17636e3d877SAbhi.Singh 	}
17736e3d877SAbhi.Singh 
17836e3d877SAbhi.Singh 	/* write the command header to the TPM first */
17936e3d877SAbhi.Singh 	const uint8_t *header_data = (const uint8_t *)&buf->header;
18036e3d877SAbhi.Singh 
18136e3d877SAbhi.Singh 	for (index = 0; index < TPM_HEADER_SIZE; index++) {
18236e3d877SAbhi.Singh 		err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
18336e3d877SAbhi.Singh 				header_data[index]);
18436e3d877SAbhi.Singh 		if (err < 0) {
18536e3d877SAbhi.Singh 			return err;
18636e3d877SAbhi.Singh 		}
18736e3d877SAbhi.Singh 	}
18836e3d877SAbhi.Singh 
18936e3d877SAbhi.Singh 	len =  be32toh(buf->header.cmd_size);
19036e3d877SAbhi.Singh 
19136e3d877SAbhi.Singh 	while (index < len) {
19236e3d877SAbhi.Singh 		err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
19336e3d877SAbhi.Singh 		if (err < 0) {
19436e3d877SAbhi.Singh 			return err;
19536e3d877SAbhi.Singh 		}
19636e3d877SAbhi.Singh 
19736e3d877SAbhi.Singh 		for (; burstcnt > 0U && index < len; burstcnt--) {
19836e3d877SAbhi.Singh 			err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
19936e3d877SAbhi.Singh 					buf->data[index - TPM_HEADER_SIZE]);
20036e3d877SAbhi.Singh 			if (err < 0) {
20136e3d877SAbhi.Singh 				return err;
20236e3d877SAbhi.Singh 			}
20336e3d877SAbhi.Singh 			index++;
20436e3d877SAbhi.Singh 		}
20536e3d877SAbhi.Singh 	}
20636e3d877SAbhi.Singh 
20736e3d877SAbhi.Singh 	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
20836e3d877SAbhi.Singh 				TPM_STAT_VALID,
20936e3d877SAbhi.Singh 				chip_data->timeout_msec_c,
21036e3d877SAbhi.Singh 				&status);
21136e3d877SAbhi.Singh 	if (err < 0) {
21236e3d877SAbhi.Singh 		return err;
21336e3d877SAbhi.Singh 	}
21436e3d877SAbhi.Singh 
21536e3d877SAbhi.Singh 	if (status & TPM_STAT_EXPECT) {
21636e3d877SAbhi.Singh 		ERROR("%s: TPM is still expecting data after command buffer is sent\n", __func__);
21736e3d877SAbhi.Singh 		return TPM_ERR_TRANSFER;
21836e3d877SAbhi.Singh 	}
21936e3d877SAbhi.Singh 
22036e3d877SAbhi.Singh 	err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_GO);
22136e3d877SAbhi.Singh 	if (err < 0) {
22236e3d877SAbhi.Singh 		return err;
22336e3d877SAbhi.Singh 	}
22436e3d877SAbhi.Singh 
22536e3d877SAbhi.Singh 	return TPM_SUCCESS;
22636e3d877SAbhi.Singh }
22736e3d877SAbhi.Singh 
tpm2_fifo_read_data(struct tpm_chip_data * chip_data,tpm_cmd * buf,uint16_t tpm_base_addr,uint8_t * status,int * size,int bytes_expected)22836e3d877SAbhi.Singh static int tpm2_fifo_read_data(struct tpm_chip_data *chip_data, tpm_cmd *buf,
22936e3d877SAbhi.Singh 			uint16_t tpm_base_addr, uint8_t *status, int *size, int bytes_expected)
23036e3d877SAbhi.Singh {
23136e3d877SAbhi.Singh 	int err, read_size, loop_index;
23236e3d877SAbhi.Singh 	uint16_t burstcnt;
23336e3d877SAbhi.Singh 	uint8_t *read_data;
23436e3d877SAbhi.Singh 
23536e3d877SAbhi.Singh 	if (bytes_expected == TPM_READ_HEADER) {
23636e3d877SAbhi.Singh 		/* read the response header from the TPM first */
23736e3d877SAbhi.Singh 		read_data = (uint8_t *)&buf->header;
23836e3d877SAbhi.Singh 		read_size = TPM_HEADER_SIZE;
23936e3d877SAbhi.Singh 		loop_index = *size;
24036e3d877SAbhi.Singh 	} else {
24136e3d877SAbhi.Singh 		/* process the rest of the mssg with bytes_expected */
24236e3d877SAbhi.Singh 		read_data = buf->data;
24336e3d877SAbhi.Singh 		read_size = bytes_expected;
24436e3d877SAbhi.Singh 		loop_index = *size - TPM_HEADER_SIZE;
24536e3d877SAbhi.Singh 	}
24636e3d877SAbhi.Singh 
24736e3d877SAbhi.Singh 	err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
24836e3d877SAbhi.Singh 				TPM_STAT_AVAIL,
249*6053ca4cSJenna May 				chip_data->timeout_msec_a,
25036e3d877SAbhi.Singh 				status);
25136e3d877SAbhi.Singh 	if (err < 0) {
25236e3d877SAbhi.Singh 		return err;
25336e3d877SAbhi.Singh 	}
25436e3d877SAbhi.Singh 
25536e3d877SAbhi.Singh 	while (*size < read_size) {
25636e3d877SAbhi.Singh 		err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
25736e3d877SAbhi.Singh 		if (err < 0) {
25836e3d877SAbhi.Singh 			ERROR("%s: TPM burst count error\n", __func__);
25936e3d877SAbhi.Singh 			return err;
26036e3d877SAbhi.Singh 		}
26136e3d877SAbhi.Singh 
26236e3d877SAbhi.Singh 		for (; burstcnt > 0U && loop_index < read_size;
26336e3d877SAbhi.Singh 		    burstcnt--, loop_index++, (*size)++) {
26436e3d877SAbhi.Singh 			err = tpm2_fifo_read_byte(
26536e3d877SAbhi.Singh 				tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
26636e3d877SAbhi.Singh 				(void *)&read_data[loop_index]);
26736e3d877SAbhi.Singh 			if (err < 0) {
26836e3d877SAbhi.Singh 				return err;
26936e3d877SAbhi.Singh 			}
27036e3d877SAbhi.Singh 		}
27136e3d877SAbhi.Singh 	}
27236e3d877SAbhi.Singh 
27336e3d877SAbhi.Singh 	return TPM_SUCCESS;
27436e3d877SAbhi.Singh }
27536e3d877SAbhi.Singh 
tpm2_fifo_receive(struct tpm_chip_data * chip_data,tpm_cmd * buf)27636e3d877SAbhi.Singh static int tpm2_fifo_receive(struct tpm_chip_data *chip_data, tpm_cmd *buf)
27736e3d877SAbhi.Singh {
27836e3d877SAbhi.Singh 	uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
27936e3d877SAbhi.Singh 	int size = 0, bytes_expected, err;
28036e3d877SAbhi.Singh 	uint8_t status;
28136e3d877SAbhi.Singh 
28236e3d877SAbhi.Singh 	err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, TPM_READ_HEADER);
28336e3d877SAbhi.Singh 	if (err < 0) {
28436e3d877SAbhi.Singh 		return err;
28536e3d877SAbhi.Singh 	}
28636e3d877SAbhi.Singh 
28736e3d877SAbhi.Singh 	bytes_expected = be32toh(buf->header.cmd_size);
28836e3d877SAbhi.Singh 	if (bytes_expected > sizeof(*buf)) {
28936e3d877SAbhi.Singh 		ERROR("%s: tpm response buffer cannot store expected response\n", __func__);
29036e3d877SAbhi.Singh 		return TPM_INVALID_PARAM;
29136e3d877SAbhi.Singh 	}
29236e3d877SAbhi.Singh 
29336e3d877SAbhi.Singh 	if (size == bytes_expected) {
29436e3d877SAbhi.Singh 		return size;
29536e3d877SAbhi.Singh 	}
29636e3d877SAbhi.Singh 
29736e3d877SAbhi.Singh 	err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, bytes_expected);
29836e3d877SAbhi.Singh 	if (err < 0) {
29936e3d877SAbhi.Singh 		return err;
30036e3d877SAbhi.Singh 	}
30136e3d877SAbhi.Singh 
30236e3d877SAbhi.Singh 	if (size < bytes_expected) {
30336e3d877SAbhi.Singh 		ERROR("%s: response buffer size is less than expected\n", __func__);
30436e3d877SAbhi.Singh 		return TPM_ERR_RESPONSE;
30536e3d877SAbhi.Singh 	}
30636e3d877SAbhi.Singh 
30736e3d877SAbhi.Singh 	return TPM_SUCCESS;
30836e3d877SAbhi.Singh }
30936e3d877SAbhi.Singh 
31036e3d877SAbhi.Singh static interface_ops_t fifo_ops = {
31136e3d877SAbhi.Singh 	.get_info = tpm2_get_info,
31236e3d877SAbhi.Singh 	.send = tpm2_fifo_send,
31336e3d877SAbhi.Singh 	.receive = tpm2_fifo_receive,
31436e3d877SAbhi.Singh 	.request_access = tpm2_fifo_request_access,
31536e3d877SAbhi.Singh 	.release_locality = tpm2_fifo_release_locality,
31636e3d877SAbhi.Singh };
31736e3d877SAbhi.Singh 
31836e3d877SAbhi.Singh struct interface_ops *
tpm_interface_getops(struct tpm_chip_data * chip_data,uint8_t locality)31936e3d877SAbhi.Singh tpm_interface_getops(struct tpm_chip_data *chip_data,  uint8_t locality)
32036e3d877SAbhi.Singh {
32136e3d877SAbhi.Singh 	return &fifo_ops;
32236e3d877SAbhi.Singh }
323