xref: /rk3399_rockchip-uboot/drivers/tpm/tpm_atmel_twi.c (revision 0fcb9f07a1d086fc6951c08d2fc1cf6048bd54e2)
1c01939c7SDirk Eibach /*
207470d6fSSimon Glass  * Copyright (C) 2013 Guntermann & Drunck, GmbH
3c01939c7SDirk Eibach  *
407470d6fSSimon Glass  * Written by Dirk Eibach <eibach@gdsys.de>
5c01939c7SDirk Eibach  *
607470d6fSSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
7c01939c7SDirk Eibach  */
8c01939c7SDirk Eibach 
9c01939c7SDirk Eibach #include <common.h>
10302c5dbaSChristophe Ricard #include <dm.h>
11c01939c7SDirk Eibach #include <tpm.h>
12c01939c7SDirk Eibach #include <i2c.h>
13c01939c7SDirk Eibach #include <asm/unaligned.h>
14c01939c7SDirk Eibach 
15302c5dbaSChristophe Ricard #include "tpm_internal.h"
16302c5dbaSChristophe Ricard 
17c01939c7SDirk Eibach #define ATMEL_TPM_TIMEOUT_MS 5000 /* sufficient for anything but
18c01939c7SDirk Eibach 				     generating/exporting keys */
19c01939c7SDirk Eibach 
20c01939c7SDirk Eibach /*
21302c5dbaSChristophe Ricard  * tpm_atmel_twi_open()
22c01939c7SDirk Eibach  *
23c01939c7SDirk Eibach  * Requests access to locality 0 for the caller. After all commands have been
24c01939c7SDirk Eibach  * completed the caller is supposed to call tis_close().
25c01939c7SDirk Eibach  *
26c01939c7SDirk Eibach  * Returns 0 on success, -1 on failure.
27c01939c7SDirk Eibach  */
tpm_atmel_twi_open(struct udevice * dev)28302c5dbaSChristophe Ricard static int tpm_atmel_twi_open(struct udevice *dev)
29c01939c7SDirk Eibach {
30c01939c7SDirk Eibach 	return 0;
31c01939c7SDirk Eibach }
32c01939c7SDirk Eibach 
33c01939c7SDirk Eibach /*
34302c5dbaSChristophe Ricard  * tpm_atmel_twi_close()
35c01939c7SDirk Eibach  *
36c01939c7SDirk Eibach  * terminate the currect session with the TPM by releasing the locked
37c01939c7SDirk Eibach  * locality. Returns 0 on success of -1 on failure (in case lock
38c01939c7SDirk Eibach  * removal did not succeed).
39c01939c7SDirk Eibach  */
tpm_atmel_twi_close(struct udevice * dev)40302c5dbaSChristophe Ricard static int tpm_atmel_twi_close(struct udevice *dev)
41c01939c7SDirk Eibach {
42c01939c7SDirk Eibach 	return 0;
43c01939c7SDirk Eibach }
44c01939c7SDirk Eibach 
45c01939c7SDirk Eibach /*
46302c5dbaSChristophe Ricard  * tpm_atmel_twi_get_desc()
47302c5dbaSChristophe Ricard  *
48302c5dbaSChristophe Ricard  * @dev:        Device to check
49302c5dbaSChristophe Ricard  * @buf:        Buffer to put the string
50302c5dbaSChristophe Ricard  * @size:       Maximum size of buffer
51302c5dbaSChristophe Ricard  * @return length of string, or -ENOSPC it no space
52302c5dbaSChristophe Ricard  */
tpm_atmel_twi_get_desc(struct udevice * dev,char * buf,int size)53302c5dbaSChristophe Ricard static int tpm_atmel_twi_get_desc(struct udevice *dev, char *buf, int size)
54302c5dbaSChristophe Ricard {
55302c5dbaSChristophe Ricard 	return 0;
56302c5dbaSChristophe Ricard }
57302c5dbaSChristophe Ricard 
58302c5dbaSChristophe Ricard /*
59302c5dbaSChristophe Ricard  * tpm_atmel_twi_xfer()
60c01939c7SDirk Eibach  *
61c01939c7SDirk Eibach  * Send the requested data to the TPM and then try to get its response
62c01939c7SDirk Eibach  *
63c01939c7SDirk Eibach  * @sendbuf - buffer of the data to send
64c01939c7SDirk Eibach  * @send_size size of the data to send
65c01939c7SDirk Eibach  * @recvbuf - memory to save the response to
66c01939c7SDirk Eibach  * @recv_len - pointer to the size of the response buffer
67c01939c7SDirk Eibach  *
68c01939c7SDirk Eibach  * Returns 0 on success (and places the number of response bytes at recv_len)
69c01939c7SDirk Eibach  * or -1 on failure.
70c01939c7SDirk Eibach  */
tpm_atmel_twi_xfer(struct udevice * dev,const uint8_t * sendbuf,size_t send_size,uint8_t * recvbuf,size_t * recv_len)71302c5dbaSChristophe Ricard static int tpm_atmel_twi_xfer(struct udevice *dev,
72302c5dbaSChristophe Ricard 			      const uint8_t *sendbuf, size_t send_size,
73302c5dbaSChristophe Ricard 			      uint8_t *recvbuf, size_t *recv_len)
74c01939c7SDirk Eibach {
75c01939c7SDirk Eibach 	int res;
76c01939c7SDirk Eibach 	unsigned long start;
77c01939c7SDirk Eibach 
78c01939c7SDirk Eibach #ifdef DEBUG
79c01939c7SDirk Eibach 	memset(recvbuf, 0xcc, *recv_len);
80c01939c7SDirk Eibach 	printf("send to TPM (%d bytes, recv_len=%d):\n", send_size, *recv_len);
81c01939c7SDirk Eibach 	print_buffer(0, (void *)sendbuf, 1, send_size, 0);
82c01939c7SDirk Eibach #endif
83c01939c7SDirk Eibach 
84*03dcd410Smario.six@gdsys.cc #ifndef CONFIG_DM_I2C
85c01939c7SDirk Eibach 	res = i2c_write(0x29, 0, 0, (uchar *)sendbuf, send_size);
86*03dcd410Smario.six@gdsys.cc #else
87*03dcd410Smario.six@gdsys.cc 	res = dm_i2c_write(dev, 0, sendbuf, send_size);
88*03dcd410Smario.six@gdsys.cc #endif
89c01939c7SDirk Eibach 	if (res) {
90c01939c7SDirk Eibach 		printf("i2c_write returned %d\n", res);
91c01939c7SDirk Eibach 		return -1;
92c01939c7SDirk Eibach 	}
93c01939c7SDirk Eibach 
94c01939c7SDirk Eibach 	start = get_timer(0);
95*03dcd410Smario.six@gdsys.cc #ifndef CONFIG_DM_I2C
96*03dcd410Smario.six@gdsys.cc 	while ((res = i2c_read(0x29, 0, 0, recvbuf, 10)))
97*03dcd410Smario.six@gdsys.cc #else
98*03dcd410Smario.six@gdsys.cc 	while ((res = dm_i2c_read(dev, 0, recvbuf, 10)))
99*03dcd410Smario.six@gdsys.cc #endif
100*03dcd410Smario.six@gdsys.cc 	{
101302c5dbaSChristophe Ricard 		/* TODO Use TIS_TIMEOUT from tpm_tis_infineon.h */
102c01939c7SDirk Eibach 		if (get_timer(start) > ATMEL_TPM_TIMEOUT_MS) {
103c01939c7SDirk Eibach 			puts("tpm timed out\n");
104c01939c7SDirk Eibach 			return -1;
105c01939c7SDirk Eibach 		}
106c01939c7SDirk Eibach 		udelay(100);
107c01939c7SDirk Eibach 	}
108c01939c7SDirk Eibach 	if (!res) {
109c01939c7SDirk Eibach 		*recv_len = get_unaligned_be32(recvbuf + 2);
110c01939c7SDirk Eibach 		if (*recv_len > 10)
111*03dcd410Smario.six@gdsys.cc #ifndef CONFIG_DM_I2C
112c01939c7SDirk Eibach 			res = i2c_read(0x29, 0, 0, recvbuf, *recv_len);
113*03dcd410Smario.six@gdsys.cc #else
114*03dcd410Smario.six@gdsys.cc 			res = dm_i2c_read(dev, 0, recvbuf, *recv_len);
115*03dcd410Smario.six@gdsys.cc #endif
116c01939c7SDirk Eibach 	}
117c01939c7SDirk Eibach 	if (res) {
118c01939c7SDirk Eibach 		printf("i2c_read returned %d (rlen=%d)\n", res, *recv_len);
119c01939c7SDirk Eibach #ifdef DEBUG
120c01939c7SDirk Eibach 		print_buffer(0, recvbuf, 1, *recv_len, 0);
121c01939c7SDirk Eibach #endif
122c01939c7SDirk Eibach 	}
123c01939c7SDirk Eibach 
124c01939c7SDirk Eibach #ifdef DEBUG
125c01939c7SDirk Eibach 	if (!res) {
126c01939c7SDirk Eibach 		printf("read from TPM (%d bytes):\n", *recv_len);
127c01939c7SDirk Eibach 		print_buffer(0, recvbuf, 1, *recv_len, 0);
128c01939c7SDirk Eibach 	}
129c01939c7SDirk Eibach #endif
130c01939c7SDirk Eibach 
131c01939c7SDirk Eibach 	return res;
132c01939c7SDirk Eibach }
133302c5dbaSChristophe Ricard 
tpm_atmel_twi_probe(struct udevice * dev)134302c5dbaSChristophe Ricard static int tpm_atmel_twi_probe(struct udevice *dev)
135302c5dbaSChristophe Ricard {
136302c5dbaSChristophe Ricard 	return 0;
137302c5dbaSChristophe Ricard }
138302c5dbaSChristophe Ricard 
139302c5dbaSChristophe Ricard static const struct udevice_id tpm_atmel_twi_ids[] = {
140302c5dbaSChristophe Ricard 	{ .compatible = "atmel,at97sc3204t"},
141302c5dbaSChristophe Ricard 	{ }
142302c5dbaSChristophe Ricard };
143302c5dbaSChristophe Ricard 
144302c5dbaSChristophe Ricard static const struct tpm_ops tpm_atmel_twi_ops = {
145302c5dbaSChristophe Ricard 	.open = tpm_atmel_twi_open,
146302c5dbaSChristophe Ricard 	.close = tpm_atmel_twi_close,
147302c5dbaSChristophe Ricard 	.xfer = tpm_atmel_twi_xfer,
148302c5dbaSChristophe Ricard 	.get_desc = tpm_atmel_twi_get_desc,
149302c5dbaSChristophe Ricard };
150302c5dbaSChristophe Ricard 
151302c5dbaSChristophe Ricard U_BOOT_DRIVER(tpm_atmel_twi) = {
152302c5dbaSChristophe Ricard 	.name = "tpm_atmel_twi",
153302c5dbaSChristophe Ricard 	.id = UCLASS_TPM,
154302c5dbaSChristophe Ricard 	.of_match = tpm_atmel_twi_ids,
155302c5dbaSChristophe Ricard 	.ops = &tpm_atmel_twi_ops,
156302c5dbaSChristophe Ricard 	.probe = tpm_atmel_twi_probe,
157302c5dbaSChristophe Ricard };
158