xref: /rk3399_ARM-atf/drivers/tpm/tpm2_fifo_spi.c (revision 7e848540159ba8fbb0577c76e4dc0c5bbc542489)
1 /*
2  * Copyright (c) 2025, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdbool.h>
10 #include <string.h>
11 
12 #include <drivers/gpio_spi.h>
13 #include <drivers/tpm/tpm2.h>
14 #include <drivers/tpm/tpm2_chip.h>
15 #include <drivers/tpm/tpm2_interface.h>
16 
17 #define ENCODE_LIMIT		128
18 #define CS_ASSERT_OFFSET	0xD4
19 #define RETRY_COUNT		50
20 
21 #define TPM_READ	false
22 #define TPM_WRITE	true
23 
24 extern struct spi_plat *spidev;
25 
tpm2_spi_transfer(const void * data_out,void * data_in,uint8_t len)26 static int tpm2_spi_transfer(const void *data_out, void *data_in, uint8_t len)
27 {
28 	return spidev->ops->xfer(len, data_out, data_in);
29 }
30 
31 /*
32  * Reference: TCG PC Client Platform TPM Profile (PTP) Specification v1.05
33  */
tpm2_spi_start_transaction(uint16_t tpm_reg,bool write,uint8_t len)34 static int tpm2_spi_start_transaction(uint16_t tpm_reg, bool write, uint8_t len)
35 {
36 	int rc;
37 	uint8_t header[4];
38 	uint8_t header_response[4];
39 	uint8_t zero = 0, byte;
40 	int retries;
41 
42 	/* check to make sure len does not exceed the encoding limit */
43 	if (len > ENCODE_LIMIT) {
44 		return TPM_INVALID_PARAM;
45 	}
46 
47 	/*
48 	 * 7.4.6 TPM SPI Bit protocol calls for the following header
49 	 * to be sent to the TPM at the start of every attempted read/write.
50 	 */
51 
52 	/* header[0] contains the r/w and the xfer size, if the msb is not
53 	 * set, the operation is write, if it is set then it is read.
54 	 * The size of the transfer is encoded, and must not overwrite
55 	 * the msb, therefore an ENCODE LIMIT of 128 is present.
56 	 */
57 	header[0] = ((write) ? 0x00 : 0x80) | (len - 1);
58 
59 	/*
60 	 * header[1] contains the address offset 0xD4_xxxx as defined
61 	 * in the TPM spec, since the CS# is asserted.
62 	 */
63 	header[1] = CS_ASSERT_OFFSET;
64 
65 	/*
66 	 * header[2] and header[3] contain the address of the register
67 	 * to be read/written.
68 	 */
69 	header[2] = tpm_reg >> 8;
70 	header[3] = tpm_reg;
71 
72 	rc = tpm2_spi_transfer(header, header_response, 4);
73 	if (rc != 0) {
74 		return TPM_ERR_TRANSFER;
75 	}
76 
77 	/*
78 	 * 7.4.5 Flow Control defines a wait state in order to accommodate
79 	 * the TPM in case it needs to free its buffer.
80 	 */
81 	if ((header_response[3] & 0x01) != 0U) {
82 		return TPM_SUCCESS;
83 	}
84 
85 	/*
86 	 * if the wait state over bit is not set in the initial header_response,
87 	 * poll for the wait state over by sending a zeroed byte, if the
88 	 * RETRY_COUNT is exceeded the transfer fails.
89 	 */
90 	for (retries = RETRY_COUNT; retries > 0; retries--) {
91 		rc = tpm2_spi_transfer(&zero, &byte, 1);
92 		if (rc != 0) {
93 			return TPM_ERR_TRANSFER;
94 		}
95 		if ((byte & 0x01) != 0U) {
96 			return TPM_SUCCESS;
97 		}
98 	}
99 
100 	if (retries == 0) {
101 		ERROR("%s: TPM Timeout\n", __func__);
102 		return TPM_ERR_TIMEOUT;
103 	}
104 
105 	return TPM_SUCCESS;
106 }
107 
tpm2_spi_end_transaction(void)108 static void tpm2_spi_end_transaction(void)
109 {
110 	spidev->ops->stop();
111 }
112 
tpm2_spi_init(void)113 static void tpm2_spi_init(void)
114 {
115 	spidev->ops->get_access();
116 	spidev->ops->start();
117 }
118 
tpm2_fifo_io(uint16_t tpm_reg,bool is_write,uint8_t len,void * val)119 static int tpm2_fifo_io(uint16_t tpm_reg, bool is_write, uint8_t len, void *val)
120 {
121 	int rc;
122 
123 	tpm2_spi_init();
124 	rc = tpm2_spi_start_transaction(tpm_reg, is_write, len);
125 	if (rc != 0) {
126 		tpm2_spi_end_transaction();
127 		return rc;
128 	}
129 
130 	rc = tpm2_spi_transfer(
131 		is_write ? val : NULL,
132 		is_write ? NULL : val,
133 		len);
134 	if (rc != 0) {
135 		tpm2_spi_end_transaction();
136 		return rc;
137 	}
138 
139 	tpm2_spi_end_transaction();
140 
141 	return TPM_SUCCESS;
142 }
143 
tpm2_fifo_write_byte(uint16_t tpm_reg,uint8_t val)144 int tpm2_fifo_write_byte(uint16_t tpm_reg, uint8_t val)
145 {
146 	return tpm2_fifo_io(tpm_reg, TPM_WRITE, BYTE, &val);
147 }
148 
tpm2_fifo_read_byte(uint16_t tpm_reg,uint8_t * val)149 int tpm2_fifo_read_byte(uint16_t tpm_reg, uint8_t *val)
150 {
151 	return tpm2_fifo_io(tpm_reg, TPM_READ, BYTE, val);
152 }
153 
tpm2_fifo_read_chunk(uint16_t tpm_reg,uint8_t len,void * val)154 int tpm2_fifo_read_chunk(uint16_t tpm_reg, uint8_t len, void *val)
155 {
156 	if ((len != BYTE) && (len != WORD) && (len != DWORD)) {
157 		return TPM_INVALID_PARAM;
158 	}
159 
160 	return tpm2_fifo_io(tpm_reg, TPM_READ, len, val);
161 }
162