xref: /OK3568_Linux_fs/u-boot/drivers/tpm/tpm_atmel_twi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2013 Guntermann & Drunck, GmbH
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Written by Dirk Eibach <eibach@gdsys.de>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <tpm.h>
12*4882a593Smuzhiyun #include <i2c.h>
13*4882a593Smuzhiyun #include <asm/unaligned.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "tpm_internal.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define ATMEL_TPM_TIMEOUT_MS 5000 /* sufficient for anything but
18*4882a593Smuzhiyun 				     generating/exporting keys */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun  * tpm_atmel_twi_open()
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * Requests access to locality 0 for the caller. After all commands have been
24*4882a593Smuzhiyun  * completed the caller is supposed to call tis_close().
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * Returns 0 on success, -1 on failure.
27*4882a593Smuzhiyun  */
tpm_atmel_twi_open(struct udevice * dev)28*4882a593Smuzhiyun static int tpm_atmel_twi_open(struct udevice *dev)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun 	return 0;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun  * tpm_atmel_twi_close()
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * terminate the currect session with the TPM by releasing the locked
37*4882a593Smuzhiyun  * locality. Returns 0 on success of -1 on failure (in case lock
38*4882a593Smuzhiyun  * removal did not succeed).
39*4882a593Smuzhiyun  */
tpm_atmel_twi_close(struct udevice * dev)40*4882a593Smuzhiyun static int tpm_atmel_twi_close(struct udevice *dev)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	return 0;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun  * tpm_atmel_twi_get_desc()
47*4882a593Smuzhiyun  *
48*4882a593Smuzhiyun  * @dev:        Device to check
49*4882a593Smuzhiyun  * @buf:        Buffer to put the string
50*4882a593Smuzhiyun  * @size:       Maximum size of buffer
51*4882a593Smuzhiyun  * @return length of string, or -ENOSPC it no space
52*4882a593Smuzhiyun  */
tpm_atmel_twi_get_desc(struct udevice * dev,char * buf,int size)53*4882a593Smuzhiyun static int tpm_atmel_twi_get_desc(struct udevice *dev, char *buf, int size)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * tpm_atmel_twi_xfer()
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * Send the requested data to the TPM and then try to get its response
62*4882a593Smuzhiyun  *
63*4882a593Smuzhiyun  * @sendbuf - buffer of the data to send
64*4882a593Smuzhiyun  * @send_size size of the data to send
65*4882a593Smuzhiyun  * @recvbuf - memory to save the response to
66*4882a593Smuzhiyun  * @recv_len - pointer to the size of the response buffer
67*4882a593Smuzhiyun  *
68*4882a593Smuzhiyun  * Returns 0 on success (and places the number of response bytes at recv_len)
69*4882a593Smuzhiyun  * or -1 on failure.
70*4882a593Smuzhiyun  */
tpm_atmel_twi_xfer(struct udevice * dev,const uint8_t * sendbuf,size_t send_size,uint8_t * recvbuf,size_t * recv_len)71*4882a593Smuzhiyun static int tpm_atmel_twi_xfer(struct udevice *dev,
72*4882a593Smuzhiyun 			      const uint8_t *sendbuf, size_t send_size,
73*4882a593Smuzhiyun 			      uint8_t *recvbuf, size_t *recv_len)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	int res;
76*4882a593Smuzhiyun 	unsigned long start;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun #ifdef DEBUG
79*4882a593Smuzhiyun 	memset(recvbuf, 0xcc, *recv_len);
80*4882a593Smuzhiyun 	printf("send to TPM (%d bytes, recv_len=%d):\n", send_size, *recv_len);
81*4882a593Smuzhiyun 	print_buffer(0, (void *)sendbuf, 1, send_size, 0);
82*4882a593Smuzhiyun #endif
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #ifndef CONFIG_DM_I2C
85*4882a593Smuzhiyun 	res = i2c_write(0x29, 0, 0, (uchar *)sendbuf, send_size);
86*4882a593Smuzhiyun #else
87*4882a593Smuzhiyun 	res = dm_i2c_write(dev, 0, sendbuf, send_size);
88*4882a593Smuzhiyun #endif
89*4882a593Smuzhiyun 	if (res) {
90*4882a593Smuzhiyun 		printf("i2c_write returned %d\n", res);
91*4882a593Smuzhiyun 		return -1;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	start = get_timer(0);
95*4882a593Smuzhiyun #ifndef CONFIG_DM_I2C
96*4882a593Smuzhiyun 	while ((res = i2c_read(0x29, 0, 0, recvbuf, 10)))
97*4882a593Smuzhiyun #else
98*4882a593Smuzhiyun 	while ((res = dm_i2c_read(dev, 0, recvbuf, 10)))
99*4882a593Smuzhiyun #endif
100*4882a593Smuzhiyun 	{
101*4882a593Smuzhiyun 		/* TODO Use TIS_TIMEOUT from tpm_tis_infineon.h */
102*4882a593Smuzhiyun 		if (get_timer(start) > ATMEL_TPM_TIMEOUT_MS) {
103*4882a593Smuzhiyun 			puts("tpm timed out\n");
104*4882a593Smuzhiyun 			return -1;
105*4882a593Smuzhiyun 		}
106*4882a593Smuzhiyun 		udelay(100);
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 	if (!res) {
109*4882a593Smuzhiyun 		*recv_len = get_unaligned_be32(recvbuf + 2);
110*4882a593Smuzhiyun 		if (*recv_len > 10)
111*4882a593Smuzhiyun #ifndef CONFIG_DM_I2C
112*4882a593Smuzhiyun 			res = i2c_read(0x29, 0, 0, recvbuf, *recv_len);
113*4882a593Smuzhiyun #else
114*4882a593Smuzhiyun 			res = dm_i2c_read(dev, 0, recvbuf, *recv_len);
115*4882a593Smuzhiyun #endif
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 	if (res) {
118*4882a593Smuzhiyun 		printf("i2c_read returned %d (rlen=%d)\n", res, *recv_len);
119*4882a593Smuzhiyun #ifdef DEBUG
120*4882a593Smuzhiyun 		print_buffer(0, recvbuf, 1, *recv_len, 0);
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun #ifdef DEBUG
125*4882a593Smuzhiyun 	if (!res) {
126*4882a593Smuzhiyun 		printf("read from TPM (%d bytes):\n", *recv_len);
127*4882a593Smuzhiyun 		print_buffer(0, recvbuf, 1, *recv_len, 0);
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun #endif
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	return res;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
tpm_atmel_twi_probe(struct udevice * dev)134*4882a593Smuzhiyun static int tpm_atmel_twi_probe(struct udevice *dev)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun static const struct udevice_id tpm_atmel_twi_ids[] = {
140*4882a593Smuzhiyun 	{ .compatible = "atmel,at97sc3204t"},
141*4882a593Smuzhiyun 	{ }
142*4882a593Smuzhiyun };
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static const struct tpm_ops tpm_atmel_twi_ops = {
145*4882a593Smuzhiyun 	.open = tpm_atmel_twi_open,
146*4882a593Smuzhiyun 	.close = tpm_atmel_twi_close,
147*4882a593Smuzhiyun 	.xfer = tpm_atmel_twi_xfer,
148*4882a593Smuzhiyun 	.get_desc = tpm_atmel_twi_get_desc,
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun U_BOOT_DRIVER(tpm_atmel_twi) = {
152*4882a593Smuzhiyun 	.name = "tpm_atmel_twi",
153*4882a593Smuzhiyun 	.id = UCLASS_TPM,
154*4882a593Smuzhiyun 	.of_match = tpm_atmel_twi_ids,
155*4882a593Smuzhiyun 	.ops = &tpm_atmel_twi_ops,
156*4882a593Smuzhiyun 	.probe = tpm_atmel_twi_probe,
157*4882a593Smuzhiyun };
158