Commit 0766ad2f7fdae6d7482b8e1e3f5a49b3d9a3810b
Committed by
Simon Glass
1 parent
8d1f3a9daf
Exists in
v2017.01-smarct4x
and in
30 other branches
dm: tpm: Move tpm_tis_i2c to tpm_i2c_infineon
As there is no TCG specification or recommendation for i2c TPM 1.2, move tpm_tis_i2c driver to tpm_i2c_infineon. Other tpm vendors like Atmel or STMicroelectronics may have a different transport protocol for i2c. Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Reviewed-by: Tom Rini <trini@konsulko.com> Acked-by: Simon Glass <sjg@chromium.org>
Showing 12 changed files with 779 additions and 779 deletions Side-by-side Diff
README
... | ... | @@ -1472,8 +1472,8 @@ |
1472 | 1472 | CONFIG_TPM |
1473 | 1473 | Support TPM devices. |
1474 | 1474 | |
1475 | - CONFIG_TPM_TIS_I2C | |
1476 | - Support for i2c bus TPM devices. Only one device | |
1475 | + CONFIG_TPM_TIS_INFINEON | |
1476 | + Support for Infineon i2c bus TPM devices. Only one device | |
1477 | 1477 | per system is supported at this time. |
1478 | 1478 | |
1479 | 1479 | CONFIG_TPM_TIS_I2C_BURST_LIMITATION |
configs/nyan-big_defconfig
configs/peach-pi_defconfig
configs/peach-pit_defconfig
configs/snow_defconfig
configs/spring_defconfig
drivers/tpm/Kconfig
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | to the device using the standard TPM Interface Specification (TIS) |
32 | 32 | protocol |
33 | 33 | |
34 | -config TPM_TIS_I2C | |
34 | +config TPM_TIS_INFINEON | |
35 | 35 | bool "Enable support for Infineon SLB9635/45 TPMs on I2C" |
36 | 36 | depends on TPM && DM_I2C |
37 | 37 | help |
... | ... | @@ -42,7 +42,7 @@ |
42 | 42 | |
43 | 43 | config TPM_TIS_I2C_BURST_LIMITATION |
44 | 44 | bool "Enable I2C burst length limitation" |
45 | - depends on TPM_TIS_I2C | |
45 | + depends on TPM_TIS_INFINEON | |
46 | 46 | help |
47 | 47 | Some broken TPMs have a limitation on the number of bytes they can |
48 | 48 | receive in one message. Enable this option to allow you to set this |
drivers/tpm/Makefile
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | obj-$(CONFIG_DM_TPM) += tpm-uclass.o |
7 | 7 | |
8 | 8 | obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o |
9 | -obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o | |
9 | +obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o | |
10 | 10 | obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o |
11 | 11 | obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o |
drivers/tpm/tpm_tis_i2c.c
1 | -/* | |
2 | - * Copyright (C) 2011 Infineon Technologies | |
3 | - * | |
4 | - * Authors: | |
5 | - * Peter Huewe <huewe.external@infineon.com> | |
6 | - * | |
7 | - * Description: | |
8 | - * Device driver for TCG/TCPA TPM (trusted platform module). | |
9 | - * Specifications at www.trustedcomputinggroup.org | |
10 | - * | |
11 | - * This device driver implements the TPM interface as defined in | |
12 | - * the TCG TPM Interface Spec version 1.2, revision 1.0 and the | |
13 | - * Infineon I2C Protocol Stack Specification v0.20. | |
14 | - * | |
15 | - * It is based on the Linux kernel driver tpm.c from Leendert van | |
16 | - * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. | |
17 | - * | |
18 | - * Version: 2.1.1 | |
19 | - * | |
20 | - * SPDX-License-Identifier: GPL-2.0 | |
21 | - */ | |
22 | - | |
23 | -#include <common.h> | |
24 | -#include <dm.h> | |
25 | -#include <fdtdec.h> | |
26 | -#include <i2c.h> | |
27 | -#include <tis.h> | |
28 | -#include <tpm.h> | |
29 | -#include <asm-generic/errno.h> | |
30 | -#include <linux/compiler.h> | |
31 | -#include <linux/types.h> | |
32 | -#include <linux/unaligned/be_byteshift.h> | |
33 | - | |
34 | -#include "tpm_tis_i2c.h" | |
35 | -#include "tpm_internal.h" | |
36 | - | |
37 | -DECLARE_GLOBAL_DATA_PTR; | |
38 | - | |
39 | -static const char * const chip_name[] = { | |
40 | - [SLB9635] = "slb9635tt", | |
41 | - [SLB9645] = "slb9645tt", | |
42 | - [UNKNOWN] = "unknown/fallback to slb9635", | |
43 | -}; | |
44 | - | |
45 | -/* | |
46 | - * tpm_tis_i2c_read() - read from TPM register | |
47 | - * @addr: register address to read from | |
48 | - * @buffer: provided by caller | |
49 | - * @len: number of bytes to read | |
50 | - * | |
51 | - * Read len bytes from TPM register and put them into | |
52 | - * buffer (little-endian format, i.e. first byte is put into buffer[0]). | |
53 | - * | |
54 | - * NOTE: TPM is big-endian for multi-byte values. Multi-byte | |
55 | - * values have to be swapped. | |
56 | - * | |
57 | - * Return -EIO on error, 0 on success. | |
58 | - */ | |
59 | -static int tpm_tis_i2c_read(struct udevice *dev, u8 addr, u8 *buffer, | |
60 | - size_t len) | |
61 | -{ | |
62 | - struct tpm_chip *chip = dev_get_priv(dev); | |
63 | - int rc; | |
64 | - int count; | |
65 | - uint32_t addrbuf = addr; | |
66 | - | |
67 | - if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) { | |
68 | - /* slb9635 protocol should work in both cases */ | |
69 | - for (count = 0; count < MAX_COUNT; count++) { | |
70 | - rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1); | |
71 | - if (rc == 0) | |
72 | - break; /* Success, break to skip sleep */ | |
73 | - udelay(SLEEP_DURATION_US); | |
74 | - } | |
75 | - if (rc) | |
76 | - return rc; | |
77 | - | |
78 | - /* After the TPM has successfully received the register address | |
79 | - * it needs some time, thus we're sleeping here again, before | |
80 | - * retrieving the data | |
81 | - */ | |
82 | - for (count = 0; count < MAX_COUNT; count++) { | |
83 | - udelay(SLEEP_DURATION_US); | |
84 | - rc = dm_i2c_read(dev, 0, buffer, len); | |
85 | - if (rc == 0) | |
86 | - break; /* success, break to skip sleep */ | |
87 | - } | |
88 | - } else { | |
89 | - /* | |
90 | - * Use a combined read for newer chips. | |
91 | - * Unfortunately the smbus functions are not suitable due to | |
92 | - * the 32 byte limit of the smbus. | |
93 | - * Retries should usually not be needed, but are kept just to | |
94 | - * be safe on the safe side. | |
95 | - */ | |
96 | - for (count = 0; count < MAX_COUNT; count++) { | |
97 | - rc = dm_i2c_read(dev, addr, buffer, len); | |
98 | - if (rc == 0) | |
99 | - break; /* break here to skip sleep */ | |
100 | - udelay(SLEEP_DURATION_US); | |
101 | - } | |
102 | - } | |
103 | - | |
104 | - /* Take care of 'guard time' */ | |
105 | - udelay(SLEEP_DURATION_US); | |
106 | - if (rc) | |
107 | - return rc; | |
108 | - | |
109 | - return 0; | |
110 | -} | |
111 | - | |
112 | -static int tpm_tis_i2c_write_generic(struct udevice *dev, u8 addr, | |
113 | - const u8 *buffer, size_t len, | |
114 | - unsigned int sleep_time_us, u8 max_count) | |
115 | -{ | |
116 | - struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); | |
117 | - struct tpm_chip *chip = dev_get_priv(dev); | |
118 | - int rc = 0; | |
119 | - int count; | |
120 | - | |
121 | - if (chip->chip_type == SLB9635) { | |
122 | - /* Prepare send buffer to include the address */ | |
123 | - priv->buf[0] = addr; | |
124 | - memcpy(&(priv->buf[1]), buffer, len); | |
125 | - buffer = priv->buf; | |
126 | - len++; | |
127 | - addr = 0; | |
128 | - } | |
129 | - | |
130 | - for (count = 0; count < max_count; count++) { | |
131 | - rc = dm_i2c_write(dev, addr, buffer, len); | |
132 | - if (rc == 0) | |
133 | - break; /* Success, break to skip sleep */ | |
134 | - udelay(sleep_time_us); | |
135 | - } | |
136 | - | |
137 | - /* take care of 'guard time' */ | |
138 | - udelay(sleep_time_us); | |
139 | - if (rc) | |
140 | - return rc; | |
141 | - | |
142 | - return 0; | |
143 | -} | |
144 | - | |
145 | -/* | |
146 | - * tpm_tis_i2c_write() - write to TPM register | |
147 | - * @addr: register address to write to | |
148 | - * @buffer: containing data to be written | |
149 | - * @len: number of bytes to write | |
150 | - * | |
151 | - * Write len bytes from provided buffer to TPM register (little | |
152 | - * endian format, i.e. buffer[0] is written as first byte). | |
153 | - * | |
154 | - * NOTE: TPM is big-endian for multi-byte values. Multi-byte | |
155 | - * values have to be swapped. | |
156 | - * | |
157 | - * NOTE: use this function instead of the tpm_tis_i2c_write_generic function. | |
158 | - * | |
159 | - * Return -EIO on error, 0 on success | |
160 | - */ | |
161 | -static int tpm_tis_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer, | |
162 | - size_t len) | |
163 | -{ | |
164 | - return tpm_tis_i2c_write_generic(dev, addr, buffer, len, | |
165 | - SLEEP_DURATION_US, MAX_COUNT); | |
166 | -} | |
167 | - | |
168 | -/* | |
169 | - * This function is needed especially for the cleanup situation after | |
170 | - * sending TPM_READY | |
171 | - */ | |
172 | -static int tpm_tis_i2c_write_long(struct udevice *dev, u8 addr, u8 *buffer, | |
173 | - size_t len) | |
174 | -{ | |
175 | - return tpm_tis_i2c_write_generic(dev, addr, buffer, len, | |
176 | - SLEEP_DURATION_LONG_US, | |
177 | - MAX_COUNT_LONG); | |
178 | -} | |
179 | - | |
180 | -static int tpm_tis_i2c_check_locality(struct udevice *dev, int loc) | |
181 | -{ | |
182 | - const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID; | |
183 | - struct tpm_chip *chip = dev_get_priv(dev); | |
184 | - u8 buf; | |
185 | - int rc; | |
186 | - | |
187 | - rc = tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1); | |
188 | - if (rc < 0) | |
189 | - return rc; | |
190 | - | |
191 | - if ((buf & mask) == mask) { | |
192 | - chip->locality = loc; | |
193 | - return loc; | |
194 | - } | |
195 | - | |
196 | - return -ENOENT; | |
197 | -} | |
198 | - | |
199 | -static void tpm_tis_i2c_release_locality(struct udevice *dev, int loc, | |
200 | - int force) | |
201 | -{ | |
202 | - const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID; | |
203 | - u8 buf; | |
204 | - | |
205 | - if (tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1) < 0) | |
206 | - return; | |
207 | - | |
208 | - if (force || (buf & mask) == mask) { | |
209 | - buf = TPM_ACCESS_ACTIVE_LOCALITY; | |
210 | - tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1); | |
211 | - } | |
212 | -} | |
213 | - | |
214 | -static int tpm_tis_i2c_request_locality(struct udevice *dev, int loc) | |
215 | -{ | |
216 | - struct tpm_chip *chip = dev_get_priv(dev); | |
217 | - unsigned long start, stop; | |
218 | - u8 buf = TPM_ACCESS_REQUEST_USE; | |
219 | - int rc; | |
220 | - | |
221 | - rc = tpm_tis_i2c_check_locality(dev, loc); | |
222 | - if (rc >= 0) { | |
223 | - debug("%s: Already have locality\n", __func__); | |
224 | - return loc; /* We already have the locality */ | |
225 | - } else if (rc != -ENOENT) { | |
226 | - debug("%s: Failed to get locality: %d\n", __func__, rc); | |
227 | - return rc; | |
228 | - } | |
229 | - | |
230 | - rc = tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1); | |
231 | - if (rc) { | |
232 | - debug("%s: Failed to write to TPM: %d\n", __func__, rc); | |
233 | - return rc; | |
234 | - } | |
235 | - | |
236 | - /* Wait for burstcount */ | |
237 | - start = get_timer(0); | |
238 | - stop = chip->timeout_a; | |
239 | - do { | |
240 | - rc = tpm_tis_i2c_check_locality(dev, loc); | |
241 | - if (rc >= 0) { | |
242 | - debug("%s: Have locality\n", __func__); | |
243 | - return loc; | |
244 | - } else if (rc != -ENOENT) { | |
245 | - debug("%s: Failed to get locality: %d\n", __func__, rc); | |
246 | - return rc; | |
247 | - } | |
248 | - mdelay(TPM_TIMEOUT_MS); | |
249 | - } while (get_timer(start) < stop); | |
250 | - debug("%s: Timeout getting locality: %d\n", __func__, rc); | |
251 | - | |
252 | - return rc; | |
253 | -} | |
254 | - | |
255 | -static u8 tpm_tis_i2c_status(struct udevice *dev) | |
256 | -{ | |
257 | - struct tpm_chip *chip = dev_get_priv(dev); | |
258 | - /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */ | |
259 | - u8 buf; | |
260 | - | |
261 | - if (tpm_tis_i2c_read(dev, TPM_STS(chip->locality), &buf, 1) < 0) | |
262 | - return 0; | |
263 | - else | |
264 | - return buf; | |
265 | -} | |
266 | - | |
267 | -static int tpm_tis_i2c_ready(struct udevice *dev) | |
268 | -{ | |
269 | - struct tpm_chip *chip = dev_get_priv(dev); | |
270 | - int rc; | |
271 | - | |
272 | - /* This causes the current command to be aborted */ | |
273 | - u8 buf = TPM_STS_COMMAND_READY; | |
274 | - | |
275 | - debug("%s\n", __func__); | |
276 | - rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1); | |
277 | - if (rc) | |
278 | - debug("%s: rc=%d\n", __func__, rc); | |
279 | - | |
280 | - return rc; | |
281 | -} | |
282 | - | |
283 | -static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev) | |
284 | -{ | |
285 | - struct tpm_chip *chip = dev_get_priv(dev); | |
286 | - unsigned long start, stop; | |
287 | - ssize_t burstcnt; | |
288 | - u8 addr, buf[3]; | |
289 | - | |
290 | - /* Wait for burstcount */ | |
291 | - /* XXX: Which timeout value? Spec has 2 answers (c & d) */ | |
292 | - start = get_timer(0); | |
293 | - stop = chip->timeout_d; | |
294 | - do { | |
295 | - /* Note: STS is little endian */ | |
296 | - addr = TPM_STS(chip->locality) + 1; | |
297 | - if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0) | |
298 | - burstcnt = 0; | |
299 | - else | |
300 | - burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | |
301 | - | |
302 | - if (burstcnt) | |
303 | - return burstcnt; | |
304 | - mdelay(TPM_TIMEOUT_MS); | |
305 | - } while (get_timer(start) < stop); | |
306 | - | |
307 | - return -EBUSY; | |
308 | -} | |
309 | - | |
310 | -static int tpm_tis_i2c_wait_for_stat(struct udevice *dev, u8 mask, | |
311 | - unsigned long timeout, int *status) | |
312 | -{ | |
313 | - unsigned long start, stop; | |
314 | - | |
315 | - /* Check current status */ | |
316 | - *status = tpm_tis_i2c_status(dev); | |
317 | - if ((*status & mask) == mask) | |
318 | - return 0; | |
319 | - | |
320 | - start = get_timer(0); | |
321 | - stop = timeout; | |
322 | - do { | |
323 | - mdelay(TPM_TIMEOUT_MS); | |
324 | - *status = tpm_tis_i2c_status(dev); | |
325 | - if ((*status & mask) == mask) | |
326 | - return 0; | |
327 | - } while (get_timer(start) < stop); | |
328 | - | |
329 | - return -ETIMEDOUT; | |
330 | -} | |
331 | - | |
332 | -static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count) | |
333 | -{ | |
334 | - struct tpm_chip *chip = dev_get_priv(dev); | |
335 | - size_t size = 0; | |
336 | - ssize_t burstcnt; | |
337 | - int rc; | |
338 | - | |
339 | - while (size < count) { | |
340 | - burstcnt = tpm_tis_i2c_get_burstcount(dev); | |
341 | - | |
342 | - /* burstcount < 0 -> tpm is busy */ | |
343 | - if (burstcnt < 0) | |
344 | - return burstcnt; | |
345 | - | |
346 | - /* Limit received data to max left */ | |
347 | - if (burstcnt > (count - size)) | |
348 | - burstcnt = count - size; | |
349 | - | |
350 | - rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality), | |
351 | - &(buf[size]), burstcnt); | |
352 | - if (rc == 0) | |
353 | - size += burstcnt; | |
354 | - } | |
355 | - | |
356 | - return size; | |
357 | -} | |
358 | - | |
359 | -static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count) | |
360 | -{ | |
361 | - struct tpm_chip *chip = dev_get_priv(dev); | |
362 | - int size = 0; | |
363 | - int expected, status; | |
364 | - int rc; | |
365 | - | |
366 | - status = tpm_tis_i2c_status(dev); | |
367 | - if (status == TPM_STS_COMMAND_READY) | |
368 | - return -EINTR; | |
369 | - if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) != | |
370 | - (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) | |
371 | - return -EAGAIN; | |
372 | - | |
373 | - debug("...got it;\n"); | |
374 | - | |
375 | - /* Read first 10 bytes, including tag, paramsize, and result */ | |
376 | - size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE); | |
377 | - if (size < TPM_HEADER_SIZE) { | |
378 | - debug("Unable to read header\n"); | |
379 | - return size < 0 ? size : -EIO; | |
380 | - } | |
381 | - | |
382 | - expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); | |
383 | - if ((size_t)expected > count) { | |
384 | - debug("Error size=%x, expected=%x, count=%x\n", size, expected, | |
385 | - count); | |
386 | - return -ENOSPC; | |
387 | - } | |
388 | - | |
389 | - size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE], | |
390 | - expected - TPM_HEADER_SIZE); | |
391 | - if (size < expected) { | |
392 | - debug("Unable to read remainder of result\n"); | |
393 | - return -ETIMEDOUT; | |
394 | - } | |
395 | - | |
396 | - rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c, | |
397 | - &status); | |
398 | - if (rc) | |
399 | - return rc; | |
400 | - if (status & TPM_STS_DATA_AVAIL) { /* Retry? */ | |
401 | - debug("Error left over data\n"); | |
402 | - return -EIO; | |
403 | - } | |
404 | - | |
405 | - return size; | |
406 | -} | |
407 | - | |
408 | -static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len) | |
409 | -{ | |
410 | - struct tpm_chip *chip = dev_get_priv(dev); | |
411 | - int rc, status; | |
412 | - size_t burstcnt; | |
413 | - size_t count = 0; | |
414 | - int retry = 0; | |
415 | - u8 sts = TPM_STS_GO; | |
416 | - | |
417 | - debug("%s: len=%d\n", __func__, len); | |
418 | - if (len > TPM_DEV_BUFSIZE) | |
419 | - return -E2BIG; /* Command is too long for our tpm, sorry */ | |
420 | - | |
421 | - if (tpm_tis_i2c_request_locality(dev, 0) < 0) | |
422 | - return -EBUSY; | |
423 | - | |
424 | - status = tpm_tis_i2c_status(dev); | |
425 | - if ((status & TPM_STS_COMMAND_READY) == 0) { | |
426 | - rc = tpm_tis_i2c_ready(dev); | |
427 | - if (rc) | |
428 | - return rc; | |
429 | - rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY, | |
430 | - chip->timeout_b, &status); | |
431 | - if (rc) | |
432 | - return rc; | |
433 | - } | |
434 | - | |
435 | - burstcnt = tpm_tis_i2c_get_burstcount(dev); | |
436 | - | |
437 | - /* burstcount < 0 -> tpm is busy */ | |
438 | - if (burstcnt < 0) | |
439 | - return burstcnt; | |
440 | - | |
441 | - while (count < len) { | |
442 | - udelay(300); | |
443 | - if (burstcnt > len - count) | |
444 | - burstcnt = len - count; | |
445 | - | |
446 | -#ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION | |
447 | - if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN) | |
448 | - burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN; | |
449 | -#endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */ | |
450 | - | |
451 | - rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality), | |
452 | - &(buf[count]), burstcnt); | |
453 | - if (rc == 0) | |
454 | - count += burstcnt; | |
455 | - else { | |
456 | - debug("%s: error\n", __func__); | |
457 | - if (retry++ > 10) | |
458 | - return -EIO; | |
459 | - rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, | |
460 | - chip->timeout_c, | |
461 | - &status); | |
462 | - if (rc) | |
463 | - return rc; | |
464 | - | |
465 | - if ((status & TPM_STS_DATA_EXPECT) == 0) | |
466 | - return -EIO; | |
467 | - } | |
468 | - } | |
469 | - | |
470 | - /* Go and do it */ | |
471 | - rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1); | |
472 | - if (rc < 0) | |
473 | - return rc; | |
474 | - debug("%s: done, rc=%d\n", __func__, rc); | |
475 | - | |
476 | - return len; | |
477 | -} | |
478 | - | |
479 | -static int tpm_tis_i2c_cleanup(struct udevice *dev) | |
480 | -{ | |
481 | - struct tpm_chip *chip = dev_get_priv(dev); | |
482 | - | |
483 | - tpm_tis_i2c_ready(dev); | |
484 | - /* | |
485 | - * The TPM needs some time to clean up here, | |
486 | - * so we sleep rather than keeping the bus busy | |
487 | - */ | |
488 | - mdelay(2); | |
489 | - tpm_tis_i2c_release_locality(dev, chip->locality, 0); | |
490 | - | |
491 | - return 0; | |
492 | -} | |
493 | - | |
494 | -static int tpm_tis_i2c_init(struct udevice *dev) | |
495 | -{ | |
496 | - struct tpm_chip *chip = dev_get_priv(dev); | |
497 | - u32 vendor; | |
498 | - u32 expected_did_vid; | |
499 | - int rc; | |
500 | - | |
501 | - chip->is_open = 1; | |
502 | - | |
503 | - /* Default timeouts - these could move to the device tree */ | |
504 | - chip->timeout_a = TIS_SHORT_TIMEOUT_MS; | |
505 | - chip->timeout_b = TIS_LONG_TIMEOUT_MS; | |
506 | - chip->timeout_c = TIS_SHORT_TIMEOUT_MS; | |
507 | - chip->timeout_d = TIS_SHORT_TIMEOUT_MS; | |
508 | - | |
509 | - rc = tpm_tis_i2c_request_locality(dev, 0); | |
510 | - if (rc < 0) | |
511 | - return rc; | |
512 | - | |
513 | - /* Read four bytes from DID_VID register */ | |
514 | - if (tpm_tis_i2c_read(dev, TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) { | |
515 | - tpm_tis_i2c_release_locality(dev, 0, 1); | |
516 | - return -EIO; | |
517 | - } | |
518 | - | |
519 | - if (chip->chip_type == SLB9635) { | |
520 | - vendor = be32_to_cpu(vendor); | |
521 | - expected_did_vid = TPM_TIS_I2C_DID_VID_9635; | |
522 | - } else { | |
523 | - /* device id and byte order has changed for newer i2c tpms */ | |
524 | - expected_did_vid = TPM_TIS_I2C_DID_VID_9645; | |
525 | - } | |
526 | - | |
527 | - if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) { | |
528 | - error("Vendor id did not match! ID was %08x\n", vendor); | |
529 | - return -ENODEV; | |
530 | - } | |
531 | - | |
532 | - chip->vend_dev = vendor; | |
533 | - debug("1.2 TPM (chip type %s device-id 0x%X)\n", | |
534 | - chip_name[chip->chip_type], vendor >> 16); | |
535 | - | |
536 | - /* | |
537 | - * A timeout query to TPM can be placed here. | |
538 | - * Standard timeout values are used so far | |
539 | - */ | |
540 | - | |
541 | - return 0; | |
542 | -} | |
543 | - | |
544 | -static int tpm_tis_i2c_open(struct udevice *dev) | |
545 | -{ | |
546 | - struct tpm_chip *chip = dev_get_priv(dev); | |
547 | - int rc; | |
548 | - | |
549 | - debug("%s: start\n", __func__); | |
550 | - if (chip->is_open) | |
551 | - return -EBUSY; | |
552 | - rc = tpm_tis_i2c_init(dev); | |
553 | - if (rc < 0) | |
554 | - chip->is_open = 0; | |
555 | - | |
556 | - return rc; | |
557 | -} | |
558 | - | |
559 | -static int tpm_tis_i2c_close(struct udevice *dev) | |
560 | -{ | |
561 | - struct tpm_chip *chip = dev_get_priv(dev); | |
562 | - | |
563 | - if (chip->is_open) { | |
564 | - tpm_tis_i2c_release_locality(dev, chip->locality, 1); | |
565 | - chip->is_open = 0; | |
566 | - chip->vend_dev = 0; | |
567 | - } | |
568 | - | |
569 | - return 0; | |
570 | -} | |
571 | - | |
572 | -static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size) | |
573 | -{ | |
574 | - struct tpm_chip *chip = dev_get_priv(dev); | |
575 | - | |
576 | - if (size < 50) | |
577 | - return -ENOSPC; | |
578 | - | |
579 | - return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)", | |
580 | - chip->is_open ? "open" : "closed", | |
581 | - chip_name[chip->chip_type], | |
582 | - chip->vend_dev >> 16); | |
583 | -} | |
584 | - | |
585 | -static int tpm_tis_i2c_probe(struct udevice *dev) | |
586 | -{ | |
587 | - struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev); | |
588 | - struct tpm_chip *chip = dev_get_priv(dev); | |
589 | - | |
590 | - chip->chip_type = dev_get_driver_data(dev); | |
591 | - | |
592 | - /* TODO: These need to be checked and tuned */ | |
593 | - uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS; | |
594 | - uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS; | |
595 | - uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS; | |
596 | - uc_priv->retry_time_ms = TPM_TIMEOUT_MS; | |
597 | - | |
598 | - return 0; | |
599 | -} | |
600 | - | |
601 | -static const struct tpm_ops tpm_tis_i2c_ops = { | |
602 | - .open = tpm_tis_i2c_open, | |
603 | - .close = tpm_tis_i2c_close, | |
604 | - .get_desc = tpm_tis_get_desc, | |
605 | - .send = tpm_tis_i2c_send, | |
606 | - .recv = tpm_tis_i2c_recv, | |
607 | - .cleanup = tpm_tis_i2c_cleanup, | |
608 | -}; | |
609 | - | |
610 | -static const struct udevice_id tpm_tis_i2c_ids[] = { | |
611 | - { .compatible = "infineon,slb9635tt", .data = SLB9635 }, | |
612 | - { .compatible = "infineon,slb9645tt", .data = SLB9645 }, | |
613 | - { } | |
614 | -}; | |
615 | - | |
616 | -U_BOOT_DRIVER(tpm_tis_i2c) = { | |
617 | - .name = "tpm_tis_i2c", | |
618 | - .id = UCLASS_TPM, | |
619 | - .of_match = tpm_tis_i2c_ids, | |
620 | - .ops = &tpm_tis_i2c_ops, | |
621 | - .probe = tpm_tis_i2c_probe, | |
622 | - .priv_auto_alloc_size = sizeof(struct tpm_chip), | |
623 | -}; |
drivers/tpm/tpm_tis_i2c.h
1 | -/* | |
2 | - * Copyright (C) 2011 Infineon Technologies | |
3 | - * | |
4 | - * Authors: | |
5 | - * Peter Huewe <huewe.external@infineon.com> | |
6 | - * | |
7 | - * Version: 2.1.1 | |
8 | - * | |
9 | - * Description: | |
10 | - * Device driver for TCG/TCPA TPM (trusted platform module). | |
11 | - * Specifications at www.trustedcomputinggroup.org | |
12 | - * | |
13 | - * It is based on the Linux kernel driver tpm.c from Leendert van | |
14 | - * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. | |
15 | - * | |
16 | - * SPDX-License-Identifier: GPL-2.0 | |
17 | - */ | |
18 | - | |
19 | -#ifndef _TPM_TIS_I2C_H | |
20 | -#define _TPM_TIS_I2C_H | |
21 | - | |
22 | -#include <linux/compiler.h> | |
23 | -#include <linux/types.h> | |
24 | - | |
25 | -enum tpm_timeout { | |
26 | - TPM_TIMEOUT_MS = 5, | |
27 | - TIS_SHORT_TIMEOUT_MS = 750, | |
28 | - TIS_LONG_TIMEOUT_MS = 2000, | |
29 | - SLEEP_DURATION_US = 60, | |
30 | - SLEEP_DURATION_LONG_US = 210, | |
31 | -}; | |
32 | - | |
33 | -/* Size of external transmit buffer (used in tpm_transmit)*/ | |
34 | -#define TPM_BUFSIZE 4096 | |
35 | - | |
36 | -/* Index of Count field in TPM response buffer */ | |
37 | -#define TPM_RSP_SIZE_BYTE 2 | |
38 | -#define TPM_RSP_RC_BYTE 6 | |
39 | - | |
40 | -enum i2c_chip_type { | |
41 | - SLB9635, | |
42 | - SLB9645, | |
43 | - UNKNOWN, | |
44 | -}; | |
45 | - | |
46 | -struct tpm_chip { | |
47 | - int is_open; | |
48 | - int locality; | |
49 | - u32 vend_dev; | |
50 | - unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ | |
51 | - enum i2c_chip_type chip_type; | |
52 | -}; | |
53 | - | |
54 | -struct tpm_input_header { | |
55 | - __be16 tag; | |
56 | - __be32 length; | |
57 | - __be32 ordinal; | |
58 | -} __packed; | |
59 | - | |
60 | -struct tpm_output_header { | |
61 | - __be16 tag; | |
62 | - __be32 length; | |
63 | - __be32 return_code; | |
64 | -} __packed; | |
65 | - | |
66 | -struct timeout_t { | |
67 | - __be32 a; | |
68 | - __be32 b; | |
69 | - __be32 c; | |
70 | - __be32 d; | |
71 | -} __packed; | |
72 | - | |
73 | -struct duration_t { | |
74 | - __be32 tpm_short; | |
75 | - __be32 tpm_medium; | |
76 | - __be32 tpm_long; | |
77 | -} __packed; | |
78 | - | |
79 | -union cap_t { | |
80 | - struct timeout_t timeout; | |
81 | - struct duration_t duration; | |
82 | -}; | |
83 | - | |
84 | -struct tpm_getcap_params_in { | |
85 | - __be32 cap; | |
86 | - __be32 subcap_size; | |
87 | - __be32 subcap; | |
88 | -} __packed; | |
89 | - | |
90 | -struct tpm_getcap_params_out { | |
91 | - __be32 cap_size; | |
92 | - union cap_t cap; | |
93 | -} __packed; | |
94 | - | |
95 | -union tpm_cmd_header { | |
96 | - struct tpm_input_header in; | |
97 | - struct tpm_output_header out; | |
98 | -}; | |
99 | - | |
100 | -union tpm_cmd_params { | |
101 | - struct tpm_getcap_params_out getcap_out; | |
102 | - struct tpm_getcap_params_in getcap_in; | |
103 | -}; | |
104 | - | |
105 | -struct tpm_cmd_t { | |
106 | - union tpm_cmd_header header; | |
107 | - union tpm_cmd_params params; | |
108 | -} __packed; | |
109 | - | |
110 | -/* Max number of iterations after i2c NAK */ | |
111 | -#define MAX_COUNT 3 | |
112 | - | |
113 | -/* | |
114 | - * Max number of iterations after i2c NAK for 'long' commands | |
115 | - * | |
116 | - * We need this especially for sending TPM_READY, since the cleanup after the | |
117 | - * transtion to the ready state may take some time, but it is unpredictable | |
118 | - * how long it will take. | |
119 | - */ | |
120 | -#define MAX_COUNT_LONG 50 | |
121 | - | |
122 | -enum tis_access { | |
123 | - TPM_ACCESS_VALID = 0x80, | |
124 | - TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | |
125 | - TPM_ACCESS_REQUEST_PENDING = 0x04, | |
126 | - TPM_ACCESS_REQUEST_USE = 0x02, | |
127 | -}; | |
128 | - | |
129 | -enum tis_status { | |
130 | - TPM_STS_VALID = 0x80, | |
131 | - TPM_STS_COMMAND_READY = 0x40, | |
132 | - TPM_STS_GO = 0x20, | |
133 | - TPM_STS_DATA_AVAIL = 0x10, | |
134 | - TPM_STS_DATA_EXPECT = 0x08, | |
135 | -}; | |
136 | - | |
137 | -/* expected value for DIDVID register */ | |
138 | -#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L | |
139 | -#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L | |
140 | - | |
141 | -#define TPM_ACCESS(l) (0x0000 | ((l) << 4)) | |
142 | -#define TPM_STS(l) (0x0001 | ((l) << 4)) | |
143 | -#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) | |
144 | -#define TPM_DID_VID(l) (0x0006 | ((l) << 4)) | |
145 | - | |
146 | -#endif |
drivers/tpm/tpm_tis_infineon.c
1 | +/* | |
2 | + * Copyright (C) 2011 Infineon Technologies | |
3 | + * | |
4 | + * Authors: | |
5 | + * Peter Huewe <huewe.external@infineon.com> | |
6 | + * | |
7 | + * Description: | |
8 | + * Device driver for TCG/TCPA TPM (trusted platform module). | |
9 | + * Specifications at www.trustedcomputinggroup.org | |
10 | + * | |
11 | + * This device driver implements the TPM interface as defined in | |
12 | + * the TCG TPM Interface Spec version 1.2, revision 1.0 and the | |
13 | + * Infineon I2C Protocol Stack Specification v0.20. | |
14 | + * | |
15 | + * It is based on the Linux kernel driver tpm.c from Leendert van | |
16 | + * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. | |
17 | + * | |
18 | + * Version: 2.1.1 | |
19 | + * | |
20 | + * SPDX-License-Identifier: GPL-2.0 | |
21 | + */ | |
22 | + | |
23 | +#include <common.h> | |
24 | +#include <dm.h> | |
25 | +#include <fdtdec.h> | |
26 | +#include <i2c.h> | |
27 | +#include <tis.h> | |
28 | +#include <tpm.h> | |
29 | +#include <asm-generic/errno.h> | |
30 | +#include <linux/compiler.h> | |
31 | +#include <linux/types.h> | |
32 | +#include <linux/unaligned/be_byteshift.h> | |
33 | + | |
34 | +#include "tpm_tis_infineon.h" | |
35 | +#include "tpm_internal.h" | |
36 | + | |
37 | +DECLARE_GLOBAL_DATA_PTR; | |
38 | + | |
39 | +static const char * const chip_name[] = { | |
40 | + [SLB9635] = "slb9635tt", | |
41 | + [SLB9645] = "slb9645tt", | |
42 | + [UNKNOWN] = "unknown/fallback to slb9635", | |
43 | +}; | |
44 | + | |
45 | +/* | |
46 | + * tpm_tis_i2c_read() - read from TPM register | |
47 | + * @addr: register address to read from | |
48 | + * @buffer: provided by caller | |
49 | + * @len: number of bytes to read | |
50 | + * | |
51 | + * Read len bytes from TPM register and put them into | |
52 | + * buffer (little-endian format, i.e. first byte is put into buffer[0]). | |
53 | + * | |
54 | + * NOTE: TPM is big-endian for multi-byte values. Multi-byte | |
55 | + * values have to be swapped. | |
56 | + * | |
57 | + * Return -EIO on error, 0 on success. | |
58 | + */ | |
59 | +static int tpm_tis_i2c_read(struct udevice *dev, u8 addr, u8 *buffer, | |
60 | + size_t len) | |
61 | +{ | |
62 | + struct tpm_chip *chip = dev_get_priv(dev); | |
63 | + int rc; | |
64 | + int count; | |
65 | + uint32_t addrbuf = addr; | |
66 | + | |
67 | + if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) { | |
68 | + /* slb9635 protocol should work in both cases */ | |
69 | + for (count = 0; count < MAX_COUNT; count++) { | |
70 | + rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1); | |
71 | + if (rc == 0) | |
72 | + break; /* Success, break to skip sleep */ | |
73 | + udelay(SLEEP_DURATION_US); | |
74 | + } | |
75 | + if (rc) | |
76 | + return rc; | |
77 | + | |
78 | + /* After the TPM has successfully received the register address | |
79 | + * it needs some time, thus we're sleeping here again, before | |
80 | + * retrieving the data | |
81 | + */ | |
82 | + for (count = 0; count < MAX_COUNT; count++) { | |
83 | + udelay(SLEEP_DURATION_US); | |
84 | + rc = dm_i2c_read(dev, 0, buffer, len); | |
85 | + if (rc == 0) | |
86 | + break; /* success, break to skip sleep */ | |
87 | + } | |
88 | + } else { | |
89 | + /* | |
90 | + * Use a combined read for newer chips. | |
91 | + * Unfortunately the smbus functions are not suitable due to | |
92 | + * the 32 byte limit of the smbus. | |
93 | + * Retries should usually not be needed, but are kept just to | |
94 | + * be safe on the safe side. | |
95 | + */ | |
96 | + for (count = 0; count < MAX_COUNT; count++) { | |
97 | + rc = dm_i2c_read(dev, addr, buffer, len); | |
98 | + if (rc == 0) | |
99 | + break; /* break here to skip sleep */ | |
100 | + udelay(SLEEP_DURATION_US); | |
101 | + } | |
102 | + } | |
103 | + | |
104 | + /* Take care of 'guard time' */ | |
105 | + udelay(SLEEP_DURATION_US); | |
106 | + if (rc) | |
107 | + return rc; | |
108 | + | |
109 | + return 0; | |
110 | +} | |
111 | + | |
112 | +static int tpm_tis_i2c_write_generic(struct udevice *dev, u8 addr, | |
113 | + const u8 *buffer, size_t len, | |
114 | + unsigned int sleep_time_us, u8 max_count) | |
115 | +{ | |
116 | + struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); | |
117 | + struct tpm_chip *chip = dev_get_priv(dev); | |
118 | + int rc = 0; | |
119 | + int count; | |
120 | + | |
121 | + if (chip->chip_type == SLB9635) { | |
122 | + /* Prepare send buffer to include the address */ | |
123 | + priv->buf[0] = addr; | |
124 | + memcpy(&(priv->buf[1]), buffer, len); | |
125 | + buffer = priv->buf; | |
126 | + len++; | |
127 | + addr = 0; | |
128 | + } | |
129 | + | |
130 | + for (count = 0; count < max_count; count++) { | |
131 | + rc = dm_i2c_write(dev, addr, buffer, len); | |
132 | + if (rc == 0) | |
133 | + break; /* Success, break to skip sleep */ | |
134 | + udelay(sleep_time_us); | |
135 | + } | |
136 | + | |
137 | + /* take care of 'guard time' */ | |
138 | + udelay(sleep_time_us); | |
139 | + if (rc) | |
140 | + return rc; | |
141 | + | |
142 | + return 0; | |
143 | +} | |
144 | + | |
145 | +/* | |
146 | + * tpm_tis_i2c_write() - write to TPM register | |
147 | + * @addr: register address to write to | |
148 | + * @buffer: containing data to be written | |
149 | + * @len: number of bytes to write | |
150 | + * | |
151 | + * Write len bytes from provided buffer to TPM register (little | |
152 | + * endian format, i.e. buffer[0] is written as first byte). | |
153 | + * | |
154 | + * NOTE: TPM is big-endian for multi-byte values. Multi-byte | |
155 | + * values have to be swapped. | |
156 | + * | |
157 | + * NOTE: use this function instead of the tpm_tis_i2c_write_generic function. | |
158 | + * | |
159 | + * Return -EIO on error, 0 on success | |
160 | + */ | |
161 | +static int tpm_tis_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer, | |
162 | + size_t len) | |
163 | +{ | |
164 | + return tpm_tis_i2c_write_generic(dev, addr, buffer, len, | |
165 | + SLEEP_DURATION_US, MAX_COUNT); | |
166 | +} | |
167 | + | |
168 | +/* | |
169 | + * This function is needed especially for the cleanup situation after | |
170 | + * sending TPM_READY | |
171 | + */ | |
172 | +static int tpm_tis_i2c_write_long(struct udevice *dev, u8 addr, u8 *buffer, | |
173 | + size_t len) | |
174 | +{ | |
175 | + return tpm_tis_i2c_write_generic(dev, addr, buffer, len, | |
176 | + SLEEP_DURATION_LONG_US, | |
177 | + MAX_COUNT_LONG); | |
178 | +} | |
179 | + | |
180 | +static int tpm_tis_i2c_check_locality(struct udevice *dev, int loc) | |
181 | +{ | |
182 | + const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID; | |
183 | + struct tpm_chip *chip = dev_get_priv(dev); | |
184 | + u8 buf; | |
185 | + int rc; | |
186 | + | |
187 | + rc = tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1); | |
188 | + if (rc < 0) | |
189 | + return rc; | |
190 | + | |
191 | + if ((buf & mask) == mask) { | |
192 | + chip->locality = loc; | |
193 | + return loc; | |
194 | + } | |
195 | + | |
196 | + return -ENOENT; | |
197 | +} | |
198 | + | |
199 | +static void tpm_tis_i2c_release_locality(struct udevice *dev, int loc, | |
200 | + int force) | |
201 | +{ | |
202 | + const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID; | |
203 | + u8 buf; | |
204 | + | |
205 | + if (tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1) < 0) | |
206 | + return; | |
207 | + | |
208 | + if (force || (buf & mask) == mask) { | |
209 | + buf = TPM_ACCESS_ACTIVE_LOCALITY; | |
210 | + tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1); | |
211 | + } | |
212 | +} | |
213 | + | |
214 | +static int tpm_tis_i2c_request_locality(struct udevice *dev, int loc) | |
215 | +{ | |
216 | + struct tpm_chip *chip = dev_get_priv(dev); | |
217 | + unsigned long start, stop; | |
218 | + u8 buf = TPM_ACCESS_REQUEST_USE; | |
219 | + int rc; | |
220 | + | |
221 | + rc = tpm_tis_i2c_check_locality(dev, loc); | |
222 | + if (rc >= 0) { | |
223 | + debug("%s: Already have locality\n", __func__); | |
224 | + return loc; /* We already have the locality */ | |
225 | + } else if (rc != -ENOENT) { | |
226 | + debug("%s: Failed to get locality: %d\n", __func__, rc); | |
227 | + return rc; | |
228 | + } | |
229 | + | |
230 | + rc = tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1); | |
231 | + if (rc) { | |
232 | + debug("%s: Failed to write to TPM: %d\n", __func__, rc); | |
233 | + return rc; | |
234 | + } | |
235 | + | |
236 | + /* Wait for burstcount */ | |
237 | + start = get_timer(0); | |
238 | + stop = chip->timeout_a; | |
239 | + do { | |
240 | + rc = tpm_tis_i2c_check_locality(dev, loc); | |
241 | + if (rc >= 0) { | |
242 | + debug("%s: Have locality\n", __func__); | |
243 | + return loc; | |
244 | + } else if (rc != -ENOENT) { | |
245 | + debug("%s: Failed to get locality: %d\n", __func__, rc); | |
246 | + return rc; | |
247 | + } | |
248 | + mdelay(TPM_TIMEOUT_MS); | |
249 | + } while (get_timer(start) < stop); | |
250 | + debug("%s: Timeout getting locality: %d\n", __func__, rc); | |
251 | + | |
252 | + return rc; | |
253 | +} | |
254 | + | |
255 | +static u8 tpm_tis_i2c_status(struct udevice *dev) | |
256 | +{ | |
257 | + struct tpm_chip *chip = dev_get_priv(dev); | |
258 | + /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */ | |
259 | + u8 buf; | |
260 | + | |
261 | + if (tpm_tis_i2c_read(dev, TPM_STS(chip->locality), &buf, 1) < 0) | |
262 | + return 0; | |
263 | + else | |
264 | + return buf; | |
265 | +} | |
266 | + | |
267 | +static int tpm_tis_i2c_ready(struct udevice *dev) | |
268 | +{ | |
269 | + struct tpm_chip *chip = dev_get_priv(dev); | |
270 | + int rc; | |
271 | + | |
272 | + /* This causes the current command to be aborted */ | |
273 | + u8 buf = TPM_STS_COMMAND_READY; | |
274 | + | |
275 | + debug("%s\n", __func__); | |
276 | + rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1); | |
277 | + if (rc) | |
278 | + debug("%s: rc=%d\n", __func__, rc); | |
279 | + | |
280 | + return rc; | |
281 | +} | |
282 | + | |
283 | +static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev) | |
284 | +{ | |
285 | + struct tpm_chip *chip = dev_get_priv(dev); | |
286 | + unsigned long start, stop; | |
287 | + ssize_t burstcnt; | |
288 | + u8 addr, buf[3]; | |
289 | + | |
290 | + /* Wait for burstcount */ | |
291 | + /* XXX: Which timeout value? Spec has 2 answers (c & d) */ | |
292 | + start = get_timer(0); | |
293 | + stop = chip->timeout_d; | |
294 | + do { | |
295 | + /* Note: STS is little endian */ | |
296 | + addr = TPM_STS(chip->locality) + 1; | |
297 | + if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0) | |
298 | + burstcnt = 0; | |
299 | + else | |
300 | + burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | |
301 | + | |
302 | + if (burstcnt) | |
303 | + return burstcnt; | |
304 | + mdelay(TPM_TIMEOUT_MS); | |
305 | + } while (get_timer(start) < stop); | |
306 | + | |
307 | + return -EBUSY; | |
308 | +} | |
309 | + | |
310 | +static int tpm_tis_i2c_wait_for_stat(struct udevice *dev, u8 mask, | |
311 | + unsigned long timeout, int *status) | |
312 | +{ | |
313 | + unsigned long start, stop; | |
314 | + | |
315 | + /* Check current status */ | |
316 | + *status = tpm_tis_i2c_status(dev); | |
317 | + if ((*status & mask) == mask) | |
318 | + return 0; | |
319 | + | |
320 | + start = get_timer(0); | |
321 | + stop = timeout; | |
322 | + do { | |
323 | + mdelay(TPM_TIMEOUT_MS); | |
324 | + *status = tpm_tis_i2c_status(dev); | |
325 | + if ((*status & mask) == mask) | |
326 | + return 0; | |
327 | + } while (get_timer(start) < stop); | |
328 | + | |
329 | + return -ETIMEDOUT; | |
330 | +} | |
331 | + | |
332 | +static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count) | |
333 | +{ | |
334 | + struct tpm_chip *chip = dev_get_priv(dev); | |
335 | + size_t size = 0; | |
336 | + ssize_t burstcnt; | |
337 | + int rc; | |
338 | + | |
339 | + while (size < count) { | |
340 | + burstcnt = tpm_tis_i2c_get_burstcount(dev); | |
341 | + | |
342 | + /* burstcount < 0 -> tpm is busy */ | |
343 | + if (burstcnt < 0) | |
344 | + return burstcnt; | |
345 | + | |
346 | + /* Limit received data to max left */ | |
347 | + if (burstcnt > (count - size)) | |
348 | + burstcnt = count - size; | |
349 | + | |
350 | + rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality), | |
351 | + &(buf[size]), burstcnt); | |
352 | + if (rc == 0) | |
353 | + size += burstcnt; | |
354 | + } | |
355 | + | |
356 | + return size; | |
357 | +} | |
358 | + | |
359 | +static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count) | |
360 | +{ | |
361 | + struct tpm_chip *chip = dev_get_priv(dev); | |
362 | + int size = 0; | |
363 | + int expected, status; | |
364 | + int rc; | |
365 | + | |
366 | + status = tpm_tis_i2c_status(dev); | |
367 | + if (status == TPM_STS_COMMAND_READY) | |
368 | + return -EINTR; | |
369 | + if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) != | |
370 | + (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) | |
371 | + return -EAGAIN; | |
372 | + | |
373 | + debug("...got it;\n"); | |
374 | + | |
375 | + /* Read first 10 bytes, including tag, paramsize, and result */ | |
376 | + size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE); | |
377 | + if (size < TPM_HEADER_SIZE) { | |
378 | + debug("Unable to read header\n"); | |
379 | + return size < 0 ? size : -EIO; | |
380 | + } | |
381 | + | |
382 | + expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); | |
383 | + if ((size_t)expected > count) { | |
384 | + debug("Error size=%x, expected=%x, count=%x\n", size, expected, | |
385 | + count); | |
386 | + return -ENOSPC; | |
387 | + } | |
388 | + | |
389 | + size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE], | |
390 | + expected - TPM_HEADER_SIZE); | |
391 | + if (size < expected) { | |
392 | + debug("Unable to read remainder of result\n"); | |
393 | + return -ETIMEDOUT; | |
394 | + } | |
395 | + | |
396 | + rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c, | |
397 | + &status); | |
398 | + if (rc) | |
399 | + return rc; | |
400 | + if (status & TPM_STS_DATA_AVAIL) { /* Retry? */ | |
401 | + debug("Error left over data\n"); | |
402 | + return -EIO; | |
403 | + } | |
404 | + | |
405 | + return size; | |
406 | +} | |
407 | + | |
408 | +static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len) | |
409 | +{ | |
410 | + struct tpm_chip *chip = dev_get_priv(dev); | |
411 | + int rc, status; | |
412 | + size_t burstcnt; | |
413 | + size_t count = 0; | |
414 | + int retry = 0; | |
415 | + u8 sts = TPM_STS_GO; | |
416 | + | |
417 | + debug("%s: len=%d\n", __func__, len); | |
418 | + if (len > TPM_DEV_BUFSIZE) | |
419 | + return -E2BIG; /* Command is too long for our tpm, sorry */ | |
420 | + | |
421 | + if (tpm_tis_i2c_request_locality(dev, 0) < 0) | |
422 | + return -EBUSY; | |
423 | + | |
424 | + status = tpm_tis_i2c_status(dev); | |
425 | + if ((status & TPM_STS_COMMAND_READY) == 0) { | |
426 | + rc = tpm_tis_i2c_ready(dev); | |
427 | + if (rc) | |
428 | + return rc; | |
429 | + rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY, | |
430 | + chip->timeout_b, &status); | |
431 | + if (rc) | |
432 | + return rc; | |
433 | + } | |
434 | + | |
435 | + burstcnt = tpm_tis_i2c_get_burstcount(dev); | |
436 | + | |
437 | + /* burstcount < 0 -> tpm is busy */ | |
438 | + if (burstcnt < 0) | |
439 | + return burstcnt; | |
440 | + | |
441 | + while (count < len) { | |
442 | + udelay(300); | |
443 | + if (burstcnt > len - count) | |
444 | + burstcnt = len - count; | |
445 | + | |
446 | +#ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION | |
447 | + if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN) | |
448 | + burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN; | |
449 | +#endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */ | |
450 | + | |
451 | + rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality), | |
452 | + &(buf[count]), burstcnt); | |
453 | + if (rc == 0) | |
454 | + count += burstcnt; | |
455 | + else { | |
456 | + debug("%s: error\n", __func__); | |
457 | + if (retry++ > 10) | |
458 | + return -EIO; | |
459 | + rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, | |
460 | + chip->timeout_c, | |
461 | + &status); | |
462 | + if (rc) | |
463 | + return rc; | |
464 | + | |
465 | + if ((status & TPM_STS_DATA_EXPECT) == 0) | |
466 | + return -EIO; | |
467 | + } | |
468 | + } | |
469 | + | |
470 | + /* Go and do it */ | |
471 | + rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1); | |
472 | + if (rc < 0) | |
473 | + return rc; | |
474 | + debug("%s: done, rc=%d\n", __func__, rc); | |
475 | + | |
476 | + return len; | |
477 | +} | |
478 | + | |
479 | +static int tpm_tis_i2c_cleanup(struct udevice *dev) | |
480 | +{ | |
481 | + struct tpm_chip *chip = dev_get_priv(dev); | |
482 | + | |
483 | + tpm_tis_i2c_ready(dev); | |
484 | + /* | |
485 | + * The TPM needs some time to clean up here, | |
486 | + * so we sleep rather than keeping the bus busy | |
487 | + */ | |
488 | + mdelay(2); | |
489 | + tpm_tis_i2c_release_locality(dev, chip->locality, 0); | |
490 | + | |
491 | + return 0; | |
492 | +} | |
493 | + | |
494 | +static int tpm_tis_i2c_init(struct udevice *dev) | |
495 | +{ | |
496 | + struct tpm_chip *chip = dev_get_priv(dev); | |
497 | + u32 vendor; | |
498 | + u32 expected_did_vid; | |
499 | + int rc; | |
500 | + | |
501 | + chip->is_open = 1; | |
502 | + | |
503 | + /* Default timeouts - these could move to the device tree */ | |
504 | + chip->timeout_a = TIS_SHORT_TIMEOUT_MS; | |
505 | + chip->timeout_b = TIS_LONG_TIMEOUT_MS; | |
506 | + chip->timeout_c = TIS_SHORT_TIMEOUT_MS; | |
507 | + chip->timeout_d = TIS_SHORT_TIMEOUT_MS; | |
508 | + | |
509 | + rc = tpm_tis_i2c_request_locality(dev, 0); | |
510 | + if (rc < 0) | |
511 | + return rc; | |
512 | + | |
513 | + /* Read four bytes from DID_VID register */ | |
514 | + if (tpm_tis_i2c_read(dev, TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) { | |
515 | + tpm_tis_i2c_release_locality(dev, 0, 1); | |
516 | + return -EIO; | |
517 | + } | |
518 | + | |
519 | + if (chip->chip_type == SLB9635) { | |
520 | + vendor = be32_to_cpu(vendor); | |
521 | + expected_did_vid = TPM_TIS_I2C_DID_VID_9635; | |
522 | + } else { | |
523 | + /* device id and byte order has changed for newer i2c tpms */ | |
524 | + expected_did_vid = TPM_TIS_I2C_DID_VID_9645; | |
525 | + } | |
526 | + | |
527 | + if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) { | |
528 | + error("Vendor id did not match! ID was %08x\n", vendor); | |
529 | + return -ENODEV; | |
530 | + } | |
531 | + | |
532 | + chip->vend_dev = vendor; | |
533 | + debug("1.2 TPM (chip type %s device-id 0x%X)\n", | |
534 | + chip_name[chip->chip_type], vendor >> 16); | |
535 | + | |
536 | + /* | |
537 | + * A timeout query to TPM can be placed here. | |
538 | + * Standard timeout values are used so far | |
539 | + */ | |
540 | + | |
541 | + return 0; | |
542 | +} | |
543 | + | |
544 | +static int tpm_tis_i2c_open(struct udevice *dev) | |
545 | +{ | |
546 | + struct tpm_chip *chip = dev_get_priv(dev); | |
547 | + int rc; | |
548 | + | |
549 | + debug("%s: start\n", __func__); | |
550 | + if (chip->is_open) | |
551 | + return -EBUSY; | |
552 | + rc = tpm_tis_i2c_init(dev); | |
553 | + if (rc < 0) | |
554 | + chip->is_open = 0; | |
555 | + | |
556 | + return rc; | |
557 | +} | |
558 | + | |
559 | +static int tpm_tis_i2c_close(struct udevice *dev) | |
560 | +{ | |
561 | + struct tpm_chip *chip = dev_get_priv(dev); | |
562 | + | |
563 | + if (chip->is_open) { | |
564 | + tpm_tis_i2c_release_locality(dev, chip->locality, 1); | |
565 | + chip->is_open = 0; | |
566 | + chip->vend_dev = 0; | |
567 | + } | |
568 | + | |
569 | + return 0; | |
570 | +} | |
571 | + | |
572 | +static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size) | |
573 | +{ | |
574 | + struct tpm_chip *chip = dev_get_priv(dev); | |
575 | + | |
576 | + if (size < 50) | |
577 | + return -ENOSPC; | |
578 | + | |
579 | + return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)", | |
580 | + chip->is_open ? "open" : "closed", | |
581 | + chip_name[chip->chip_type], | |
582 | + chip->vend_dev >> 16); | |
583 | +} | |
584 | + | |
585 | +static int tpm_tis_i2c_probe(struct udevice *dev) | |
586 | +{ | |
587 | + struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev); | |
588 | + struct tpm_chip *chip = dev_get_priv(dev); | |
589 | + | |
590 | + chip->chip_type = dev_get_driver_data(dev); | |
591 | + | |
592 | + /* TODO: These need to be checked and tuned */ | |
593 | + uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS; | |
594 | + uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS; | |
595 | + uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS; | |
596 | + uc_priv->retry_time_ms = TPM_TIMEOUT_MS; | |
597 | + | |
598 | + return 0; | |
599 | +} | |
600 | + | |
601 | +static const struct tpm_ops tpm_tis_i2c_ops = { | |
602 | + .open = tpm_tis_i2c_open, | |
603 | + .close = tpm_tis_i2c_close, | |
604 | + .get_desc = tpm_tis_get_desc, | |
605 | + .send = tpm_tis_i2c_send, | |
606 | + .recv = tpm_tis_i2c_recv, | |
607 | + .cleanup = tpm_tis_i2c_cleanup, | |
608 | +}; | |
609 | + | |
610 | +static const struct udevice_id tpm_tis_i2c_ids[] = { | |
611 | + { .compatible = "infineon,slb9635tt", .data = SLB9635 }, | |
612 | + { .compatible = "infineon,slb9645tt", .data = SLB9645 }, | |
613 | + { } | |
614 | +}; | |
615 | + | |
616 | +U_BOOT_DRIVER(tpm_tis_i2c) = { | |
617 | + .name = "tpm_tis_infineon", | |
618 | + .id = UCLASS_TPM, | |
619 | + .of_match = tpm_tis_i2c_ids, | |
620 | + .ops = &tpm_tis_i2c_ops, | |
621 | + .probe = tpm_tis_i2c_probe, | |
622 | + .priv_auto_alloc_size = sizeof(struct tpm_chip), | |
623 | +}; |
drivers/tpm/tpm_tis_infineon.h
1 | +/* | |
2 | + * Copyright (C) 2011 Infineon Technologies | |
3 | + * | |
4 | + * Authors: | |
5 | + * Peter Huewe <huewe.external@infineon.com> | |
6 | + * | |
7 | + * Version: 2.1.1 | |
8 | + * | |
9 | + * Description: | |
10 | + * Device driver for TCG/TCPA TPM (trusted platform module). | |
11 | + * Specifications at www.trustedcomputinggroup.org | |
12 | + * | |
13 | + * It is based on the Linux kernel driver tpm.c from Leendert van | |
14 | + * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. | |
15 | + * | |
16 | + * SPDX-License-Identifier: GPL-2.0 | |
17 | + */ | |
18 | + | |
19 | +#ifndef _TPM_TIS_I2C_H | |
20 | +#define _TPM_TIS_I2C_H | |
21 | + | |
22 | +#include <linux/compiler.h> | |
23 | +#include <linux/types.h> | |
24 | + | |
25 | +enum tpm_timeout { | |
26 | + TPM_TIMEOUT_MS = 5, | |
27 | + TIS_SHORT_TIMEOUT_MS = 750, | |
28 | + TIS_LONG_TIMEOUT_MS = 2000, | |
29 | + SLEEP_DURATION_US = 60, | |
30 | + SLEEP_DURATION_LONG_US = 210, | |
31 | +}; | |
32 | + | |
33 | +/* Size of external transmit buffer (used in tpm_transmit)*/ | |
34 | +#define TPM_BUFSIZE 4096 | |
35 | + | |
36 | +/* Index of Count field in TPM response buffer */ | |
37 | +#define TPM_RSP_SIZE_BYTE 2 | |
38 | +#define TPM_RSP_RC_BYTE 6 | |
39 | + | |
40 | +enum i2c_chip_type { | |
41 | + SLB9635, | |
42 | + SLB9645, | |
43 | + UNKNOWN, | |
44 | +}; | |
45 | + | |
46 | +struct tpm_chip { | |
47 | + int is_open; | |
48 | + int locality; | |
49 | + u32 vend_dev; | |
50 | + unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ | |
51 | + enum i2c_chip_type chip_type; | |
52 | +}; | |
53 | + | |
54 | +struct tpm_input_header { | |
55 | + __be16 tag; | |
56 | + __be32 length; | |
57 | + __be32 ordinal; | |
58 | +} __packed; | |
59 | + | |
60 | +struct tpm_output_header { | |
61 | + __be16 tag; | |
62 | + __be32 length; | |
63 | + __be32 return_code; | |
64 | +} __packed; | |
65 | + | |
66 | +struct timeout_t { | |
67 | + __be32 a; | |
68 | + __be32 b; | |
69 | + __be32 c; | |
70 | + __be32 d; | |
71 | +} __packed; | |
72 | + | |
73 | +struct duration_t { | |
74 | + __be32 tpm_short; | |
75 | + __be32 tpm_medium; | |
76 | + __be32 tpm_long; | |
77 | +} __packed; | |
78 | + | |
79 | +union cap_t { | |
80 | + struct timeout_t timeout; | |
81 | + struct duration_t duration; | |
82 | +}; | |
83 | + | |
84 | +struct tpm_getcap_params_in { | |
85 | + __be32 cap; | |
86 | + __be32 subcap_size; | |
87 | + __be32 subcap; | |
88 | +} __packed; | |
89 | + | |
90 | +struct tpm_getcap_params_out { | |
91 | + __be32 cap_size; | |
92 | + union cap_t cap; | |
93 | +} __packed; | |
94 | + | |
95 | +union tpm_cmd_header { | |
96 | + struct tpm_input_header in; | |
97 | + struct tpm_output_header out; | |
98 | +}; | |
99 | + | |
100 | +union tpm_cmd_params { | |
101 | + struct tpm_getcap_params_out getcap_out; | |
102 | + struct tpm_getcap_params_in getcap_in; | |
103 | +}; | |
104 | + | |
105 | +struct tpm_cmd_t { | |
106 | + union tpm_cmd_header header; | |
107 | + union tpm_cmd_params params; | |
108 | +} __packed; | |
109 | + | |
110 | +/* Max number of iterations after i2c NAK */ | |
111 | +#define MAX_COUNT 3 | |
112 | + | |
113 | +/* | |
114 | + * Max number of iterations after i2c NAK for 'long' commands | |
115 | + * | |
116 | + * We need this especially for sending TPM_READY, since the cleanup after the | |
117 | + * transtion to the ready state may take some time, but it is unpredictable | |
118 | + * how long it will take. | |
119 | + */ | |
120 | +#define MAX_COUNT_LONG 50 | |
121 | + | |
122 | +enum tis_access { | |
123 | + TPM_ACCESS_VALID = 0x80, | |
124 | + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | |
125 | + TPM_ACCESS_REQUEST_PENDING = 0x04, | |
126 | + TPM_ACCESS_REQUEST_USE = 0x02, | |
127 | +}; | |
128 | + | |
129 | +enum tis_status { | |
130 | + TPM_STS_VALID = 0x80, | |
131 | + TPM_STS_COMMAND_READY = 0x40, | |
132 | + TPM_STS_GO = 0x20, | |
133 | + TPM_STS_DATA_AVAIL = 0x10, | |
134 | + TPM_STS_DATA_EXPECT = 0x08, | |
135 | +}; | |
136 | + | |
137 | +/* expected value for DIDVID register */ | |
138 | +#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L | |
139 | +#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L | |
140 | + | |
141 | +#define TPM_ACCESS(l) (0x0000 | ((l) << 4)) | |
142 | +#define TPM_STS(l) (0x0001 | ((l) << 4)) | |
143 | +#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) | |
144 | +#define TPM_DID_VID(l) (0x0006 | ((l) << 4)) | |
145 | + | |
146 | +#endif |