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