]>
Commit | Line | Data |
---|---|---|
f6267998 RC |
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 | * See file CREDITS for list of people who contributed to this | |
21 | * project. | |
22 | * | |
23 | * This program is free software; you can redistribute it and/or | |
24 | * modify it under the terms of the GNU General Public License as | |
25 | * published by the Free Software Foundation, version 2 of the | |
26 | * License. | |
27 | * | |
28 | * This program is distributed in the hope that it will be useful, | |
29 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
30 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
31 | * GNU General Public License for more details. | |
32 | * | |
33 | * You should have received a copy of the GNU General Public License | |
34 | * along with this program; if not, write to the Free Software | |
35 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
36 | * MA 02111-1307 USA | |
37 | */ | |
38 | ||
39 | #include <common.h> | |
ec34fa5e | 40 | #include <fdtdec.h> |
1b393db5 | 41 | #include <compiler.h> |
f6267998 | 42 | #include <i2c.h> |
1b393db5 TWHT |
43 | #include <tpm.h> |
44 | #include <asm-generic/errno.h> | |
f6267998 | 45 | #include <linux/types.h> |
1b393db5 | 46 | #include <linux/unaligned/be_byteshift.h> |
f6267998 | 47 | |
1b393db5 | 48 | #include "tpm_private.h" |
f6267998 | 49 | |
ec34fa5e VP |
50 | DECLARE_GLOBAL_DATA_PTR; |
51 | ||
f6267998 | 52 | /* Address of the TPM on the I2C bus */ |
1b393db5 TWHT |
53 | #define TPM_I2C_ADDR 0x20 |
54 | ||
55 | /* Max buffer size supported by our tpm */ | |
56 | #define TPM_DEV_BUFSIZE 1260 | |
f6267998 | 57 | |
1b393db5 TWHT |
58 | /* Max number of iterations after i2c NAK */ |
59 | #define MAX_COUNT 3 | |
f6267998 | 60 | |
1b393db5 TWHT |
61 | /* |
62 | * Max number of iterations after i2c NAK for 'long' commands | |
63 | * | |
64 | * We need this especially for sending TPM_READY, since the cleanup after the | |
f6267998 RC |
65 | * transtion to the ready state may take some time, but it is unpredictable |
66 | * how long it will take. | |
67 | */ | |
1b393db5 TWHT |
68 | #define MAX_COUNT_LONG 50 |
69 | ||
70 | #define SLEEP_DURATION 60 /* in usec */ | |
71 | #define SLEEP_DURATION_LONG 210 /* in usec */ | |
72 | ||
73 | #define TPM_HEADER_SIZE 10 | |
74 | ||
75 | /* | |
76 | * Expected value for DIDVID register | |
77 | * | |
78 | * The only device the system knows about at this moment is Infineon slb9635. | |
79 | */ | |
80 | #define TPM_TIS_I2C_DID_VID 0x000b15d1L | |
81 | ||
82 | enum tis_access { | |
83 | TPM_ACCESS_VALID = 0x80, | |
84 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | |
85 | TPM_ACCESS_REQUEST_PENDING = 0x04, | |
86 | TPM_ACCESS_REQUEST_USE = 0x02, | |
87 | }; | |
88 | ||
89 | enum tis_status { | |
90 | TPM_STS_VALID = 0x80, | |
91 | TPM_STS_COMMAND_READY = 0x40, | |
92 | TPM_STS_GO = 0x20, | |
93 | TPM_STS_DATA_AVAIL = 0x10, | |
94 | TPM_STS_DATA_EXPECT = 0x08, | |
95 | }; | |
f6267998 | 96 | |
1b393db5 TWHT |
97 | enum tis_defaults { |
98 | TIS_SHORT_TIMEOUT = 750, /* ms */ | |
99 | TIS_LONG_TIMEOUT = 2000, /* ms */ | |
100 | }; | |
f6267998 RC |
101 | |
102 | /* expected value for DIDVID register */ | |
ec34fa5e VP |
103 | #define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L |
104 | #define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L | |
105 | ||
106 | enum i2c_chip_type { | |
107 | SLB9635, | |
108 | SLB9645, | |
109 | UNKNOWN, | |
110 | }; | |
111 | ||
112 | static const char * const chip_name[] = { | |
113 | [SLB9635] = "slb9635tt", | |
114 | [SLB9645] = "slb9645tt", | |
115 | [UNKNOWN] = "unknown/fallback to slb9635", | |
116 | }; | |
f6267998 | 117 | |
1b393db5 TWHT |
118 | #define TPM_ACCESS(l) (0x0000 | ((l) << 4)) |
119 | #define TPM_STS(l) (0x0001 | ((l) << 4)) | |
120 | #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) | |
121 | #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) | |
122 | ||
f6267998 | 123 | /* Structure to store I2C TPM specific stuff */ |
1b393db5 | 124 | struct tpm_dev { |
f6267998 | 125 | uint addr; |
1b393db5 | 126 | u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ |
ec34fa5e | 127 | enum i2c_chip_type chip_type; |
f6267998 RC |
128 | }; |
129 | ||
1b393db5 | 130 | static struct tpm_dev tpm_dev = { |
f6267998 RC |
131 | .addr = TPM_I2C_ADDR |
132 | }; | |
133 | ||
1b393db5 TWHT |
134 | static struct tpm_dev tpm_dev; |
135 | ||
f6267998 RC |
136 | /* |
137 | * iic_tpm_read() - read from TPM register | |
138 | * @addr: register address to read from | |
139 | * @buffer: provided by caller | |
140 | * @len: number of bytes to read | |
141 | * | |
142 | * Read len bytes from TPM register and put them into | |
143 | * buffer (little-endian format, i.e. first byte is put into buffer[0]). | |
144 | * | |
145 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | |
146 | * values have to be swapped. | |
147 | * | |
148 | * Return -EIO on error, 0 on success. | |
149 | */ | |
1b393db5 | 150 | static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) |
f6267998 RC |
151 | { |
152 | int rc; | |
153 | int count; | |
1b393db5 | 154 | uint32_t addrbuf = addr; |
f6267998 | 155 | |
ec34fa5e VP |
156 | if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { |
157 | /* slb9635 protocol should work in both cases */ | |
158 | for (count = 0; count < MAX_COUNT; count++) { | |
159 | rc = i2c_write(tpm_dev.addr, 0, 0, | |
1b393db5 | 160 | (uchar *)&addrbuf, 1); |
ec34fa5e | 161 | if (rc == 0) |
1b393db5 | 162 | break; /* Success, break to skip sleep */ |
ec34fa5e VP |
163 | udelay(SLEEP_DURATION); |
164 | } | |
ec34fa5e VP |
165 | if (rc) |
166 | return -rc; | |
167 | ||
168 | /* After the TPM has successfully received the register address | |
169 | * it needs some time, thus we're sleeping here again, before | |
170 | * retrieving the data | |
171 | */ | |
172 | for (count = 0; count < MAX_COUNT; count++) { | |
173 | udelay(SLEEP_DURATION); | |
174 | rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len); | |
175 | if (rc == 0) | |
176 | break; /* success, break to skip sleep */ | |
177 | } | |
178 | } else { | |
1b393db5 TWHT |
179 | /* |
180 | * Use a combined read for newer chips. | |
181 | * Unfortunately the smbus functions are not suitable due to | |
ec34fa5e | 182 | * the 32 byte limit of the smbus. |
1b393db5 | 183 | * Retries should usually not be needed, but are kept just to |
ec34fa5e VP |
184 | * be safe on the safe side. |
185 | */ | |
186 | for (count = 0; count < MAX_COUNT; count++) { | |
187 | rc = i2c_read(tpm_dev.addr, addr, 1, buffer, len); | |
188 | if (rc == 0) | |
189 | break; /* break here to skip sleep */ | |
190 | udelay(SLEEP_DURATION); | |
191 | } | |
f6267998 RC |
192 | } |
193 | ||
1b393db5 | 194 | /* Take care of 'guard time' */ |
ec34fa5e | 195 | udelay(SLEEP_DURATION); |
f6267998 RC |
196 | if (rc) |
197 | return -rc; | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
202 | static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, | |
1b393db5 | 203 | unsigned int sleep_time, u8 max_count) |
f6267998 RC |
204 | { |
205 | int rc = 0; | |
206 | int count; | |
207 | ||
1b393db5 | 208 | /* Prepare send buffer */ |
f6267998 RC |
209 | tpm_dev.buf[0] = addr; |
210 | memcpy(&(tpm_dev.buf[1]), buffer, len); | |
211 | ||
212 | for (count = 0; count < max_count; count++) { | |
213 | rc = i2c_write(tpm_dev.addr, 0, 0, tpm_dev.buf, len + 1); | |
214 | if (rc == 0) | |
1b393db5 | 215 | break; /* Success, break to skip sleep */ |
f6267998 RC |
216 | udelay(sleep_time); |
217 | } | |
218 | ||
ec34fa5e VP |
219 | /* take care of 'guard time' */ |
220 | udelay(SLEEP_DURATION); | |
f6267998 RC |
221 | if (rc) |
222 | return -rc; | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
227 | /* | |
228 | * iic_tpm_write() - write to TPM register | |
229 | * @addr: register address to write to | |
230 | * @buffer: containing data to be written | |
231 | * @len: number of bytes to write | |
232 | * | |
233 | * Write len bytes from provided buffer to TPM register (little | |
234 | * endian format, i.e. buffer[0] is written as first byte). | |
235 | * | |
236 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | |
237 | * values have to be swapped. | |
238 | * | |
239 | * NOTE: use this function instead of the iic_tpm_write_generic function. | |
240 | * | |
241 | * Return -EIO on error, 0 on success | |
242 | */ | |
243 | static int iic_tpm_write(u8 addr, u8 *buffer, size_t len) | |
244 | { | |
245 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION, | |
246 | MAX_COUNT); | |
247 | } | |
248 | ||
249 | /* | |
250 | * This function is needed especially for the cleanup situation after | |
251 | * sending TPM_READY | |
1b393db5 | 252 | */ |
f6267998 RC |
253 | static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len) |
254 | { | |
255 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, | |
256 | MAX_COUNT_LONG); | |
257 | } | |
258 | ||
f6267998 RC |
259 | static int check_locality(struct tpm_chip *chip, int loc) |
260 | { | |
1b393db5 | 261 | const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID; |
f6267998 RC |
262 | u8 buf; |
263 | int rc; | |
264 | ||
265 | rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1); | |
266 | if (rc < 0) | |
267 | return rc; | |
268 | ||
1b393db5 | 269 | if ((buf & mask) == mask) { |
f6267998 RC |
270 | chip->vendor.locality = loc; |
271 | return loc; | |
272 | } | |
273 | ||
274 | return -1; | |
275 | } | |
276 | ||
277 | static void release_locality(struct tpm_chip *chip, int loc, int force) | |
278 | { | |
1b393db5 | 279 | const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID; |
f6267998 | 280 | u8 buf; |
1b393db5 | 281 | |
f6267998 RC |
282 | if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) |
283 | return; | |
284 | ||
1b393db5 | 285 | if (force || (buf & mask) == mask) { |
f6267998 RC |
286 | buf = TPM_ACCESS_ACTIVE_LOCALITY; |
287 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | |
288 | } | |
289 | } | |
290 | ||
291 | static int request_locality(struct tpm_chip *chip, int loc) | |
292 | { | |
293 | unsigned long start, stop; | |
294 | u8 buf = TPM_ACCESS_REQUEST_USE; | |
295 | ||
296 | if (check_locality(chip, loc) >= 0) | |
1b393db5 | 297 | return loc; /* We already have the locality */ |
f6267998 RC |
298 | |
299 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | |
300 | ||
1b393db5 | 301 | /* Wait for burstcount */ |
f6267998 RC |
302 | start = get_timer(0); |
303 | stop = chip->vendor.timeout_a; | |
304 | do { | |
305 | if (check_locality(chip, loc) >= 0) | |
306 | return loc; | |
1b393db5 | 307 | udelay(TPM_TIMEOUT * 1000); |
f6267998 RC |
308 | } while (get_timer(start) < stop); |
309 | ||
310 | return -1; | |
311 | } | |
312 | ||
313 | static u8 tpm_tis_i2c_status(struct tpm_chip *chip) | |
314 | { | |
1b393db5 | 315 | /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */ |
f6267998 | 316 | u8 buf; |
1b393db5 | 317 | |
f6267998 RC |
318 | if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) |
319 | return 0; | |
320 | else | |
321 | return buf; | |
322 | } | |
323 | ||
324 | static void tpm_tis_i2c_ready(struct tpm_chip *chip) | |
325 | { | |
1b393db5 | 326 | /* This causes the current command to be aborted */ |
f6267998 | 327 | u8 buf = TPM_STS_COMMAND_READY; |
1b393db5 | 328 | |
f6267998 RC |
329 | iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); |
330 | } | |
331 | ||
332 | static ssize_t get_burstcount(struct tpm_chip *chip) | |
333 | { | |
334 | unsigned long start, stop; | |
335 | ssize_t burstcnt; | |
1b393db5 | 336 | u8 addr, buf[3]; |
f6267998 | 337 | |
1b393db5 TWHT |
338 | /* Wait for burstcount */ |
339 | /* XXX: Which timeout value? Spec has 2 answers (c & d) */ | |
f6267998 RC |
340 | start = get_timer(0); |
341 | stop = chip->vendor.timeout_d; | |
342 | do { | |
343 | /* Note: STS is little endian */ | |
1b393db5 TWHT |
344 | addr = TPM_STS(chip->vendor.locality) + 1; |
345 | if (iic_tpm_read(addr, buf, 3) < 0) | |
f6267998 RC |
346 | burstcnt = 0; |
347 | else | |
348 | burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | |
349 | ||
350 | if (burstcnt) | |
351 | return burstcnt; | |
1b393db5 | 352 | udelay(TPM_TIMEOUT * 1000); |
f6267998 RC |
353 | } while (get_timer(start) < stop); |
354 | ||
355 | return -EBUSY; | |
356 | } | |
357 | ||
358 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | |
1b393db5 | 359 | int *status) |
f6267998 RC |
360 | { |
361 | unsigned long start, stop; | |
362 | ||
1b393db5 | 363 | /* Check current status */ |
f6267998 RC |
364 | *status = tpm_tis_i2c_status(chip); |
365 | if ((*status & mask) == mask) | |
366 | return 0; | |
367 | ||
368 | start = get_timer(0); | |
369 | stop = timeout; | |
370 | do { | |
1b393db5 | 371 | udelay(TPM_TIMEOUT * 1000); |
f6267998 RC |
372 | *status = tpm_tis_i2c_status(chip); |
373 | if ((*status & mask) == mask) | |
374 | return 0; | |
f6267998 RC |
375 | } while (get_timer(start) < stop); |
376 | ||
377 | return -ETIME; | |
378 | } | |
379 | ||
380 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | |
381 | { | |
382 | size_t size = 0; | |
383 | ssize_t burstcnt; | |
384 | int rc; | |
385 | ||
386 | while (size < count) { | |
387 | burstcnt = get_burstcount(chip); | |
388 | ||
1b393db5 | 389 | /* burstcount < 0 -> tpm is busy */ |
f6267998 RC |
390 | if (burstcnt < 0) |
391 | return burstcnt; | |
392 | ||
1b393db5 | 393 | /* Limit received data to max left */ |
f6267998 RC |
394 | if (burstcnt > (count - size)) |
395 | burstcnt = count - size; | |
396 | ||
397 | rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality), | |
1b393db5 | 398 | &(buf[size]), burstcnt); |
f6267998 RC |
399 | if (rc == 0) |
400 | size += burstcnt; | |
401 | } | |
402 | ||
403 | return size; | |
404 | } | |
405 | ||
406 | static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |
407 | { | |
408 | int size = 0; | |
409 | int expected, status; | |
410 | ||
411 | if (count < TPM_HEADER_SIZE) { | |
412 | size = -EIO; | |
413 | goto out; | |
414 | } | |
415 | ||
1b393db5 | 416 | /* Read first 10 bytes, including tag, paramsize, and result */ |
f6267998 RC |
417 | size = recv_data(chip, buf, TPM_HEADER_SIZE); |
418 | if (size < TPM_HEADER_SIZE) { | |
1b393db5 | 419 | error("Unable to read header\n"); |
f6267998 RC |
420 | goto out; |
421 | } | |
422 | ||
423 | expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); | |
424 | if ((size_t)expected > count) { | |
425 | size = -EIO; | |
426 | goto out; | |
427 | } | |
428 | ||
429 | size += recv_data(chip, &buf[TPM_HEADER_SIZE], | |
1b393db5 | 430 | expected - TPM_HEADER_SIZE); |
f6267998 | 431 | if (size < expected) { |
1b393db5 | 432 | error("Unable to read remainder of result\n"); |
f6267998 RC |
433 | size = -ETIME; |
434 | goto out; | |
435 | } | |
436 | ||
437 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | |
1b393db5 TWHT |
438 | if (status & TPM_STS_DATA_AVAIL) { /* Retry? */ |
439 | error("Error left over data\n"); | |
f6267998 RC |
440 | size = -EIO; |
441 | goto out; | |
442 | } | |
443 | ||
444 | out: | |
445 | tpm_tis_i2c_ready(chip); | |
1b393db5 TWHT |
446 | /* |
447 | * The TPM needs some time to clean up here, | |
f6267998 RC |
448 | * so we sleep rather than keeping the bus busy |
449 | */ | |
450 | udelay(2000); | |
451 | release_locality(chip, chip->vendor.locality, 0); | |
452 | ||
453 | return size; | |
454 | } | |
455 | ||
456 | static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) | |
457 | { | |
458 | int rc, status; | |
459 | ssize_t burstcnt; | |
460 | size_t count = 0; | |
1b393db5 | 461 | int retry = 0; |
f6267998 RC |
462 | u8 sts = TPM_STS_GO; |
463 | ||
1b393db5 TWHT |
464 | if (len > TPM_DEV_BUFSIZE) |
465 | return -E2BIG; /* Command is too long for our tpm, sorry */ | |
f6267998 RC |
466 | |
467 | if (request_locality(chip, 0) < 0) | |
468 | return -EBUSY; | |
469 | ||
470 | status = tpm_tis_i2c_status(chip); | |
471 | if ((status & TPM_STS_COMMAND_READY) == 0) { | |
472 | tpm_tis_i2c_ready(chip); | |
1b393db5 TWHT |
473 | if (wait_for_stat(chip, TPM_STS_COMMAND_READY, |
474 | chip->vendor.timeout_b, &status) < 0) { | |
f6267998 RC |
475 | rc = -ETIME; |
476 | goto out_err; | |
477 | } | |
478 | } | |
479 | ||
1b393db5 | 480 | burstcnt = get_burstcount(chip); |
f6267998 | 481 | |
1b393db5 TWHT |
482 | /* burstcount < 0 -> tpm is busy */ |
483 | if (burstcnt < 0) | |
484 | return burstcnt; | |
f6267998 | 485 | |
1b393db5 TWHT |
486 | while (count < len - 1) { |
487 | if (burstcnt > len - 1 - count) | |
488 | burstcnt = len - 1 - count; | |
f6267998 | 489 | |
1b393db5 TWHT |
490 | #ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION |
491 | if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION) | |
492 | burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION; | |
493 | #endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */ | |
f6267998 RC |
494 | |
495 | rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), | |
1b393db5 | 496 | &(buf[count]), burstcnt); |
f6267998 RC |
497 | if (rc == 0) |
498 | count += burstcnt; | |
1b393db5 TWHT |
499 | else { |
500 | retry++; | |
501 | wait_for_stat(chip, TPM_STS_VALID, | |
502 | chip->vendor.timeout_c, &status); | |
503 | ||
504 | if ((status & TPM_STS_DATA_EXPECT) == 0) { | |
505 | rc = -EIO; | |
506 | goto out_err; | |
507 | } | |
f6267998 RC |
508 | } |
509 | } | |
510 | ||
1b393db5 | 511 | /* Write last byte */ |
f6267998 RC |
512 | iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); |
513 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | |
514 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | |
515 | rc = -EIO; | |
516 | goto out_err; | |
517 | } | |
518 | ||
1b393db5 | 519 | /* Go and do it */ |
f6267998 RC |
520 | iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); |
521 | ||
522 | return len; | |
1b393db5 | 523 | |
f6267998 RC |
524 | out_err: |
525 | tpm_tis_i2c_ready(chip); | |
1b393db5 TWHT |
526 | /* |
527 | * The TPM needs some time to clean up here, | |
f6267998 RC |
528 | * so we sleep rather than keeping the bus busy |
529 | */ | |
530 | udelay(2000); | |
531 | release_locality(chip, chip->vendor.locality, 0); | |
532 | ||
533 | return rc; | |
534 | } | |
535 | ||
536 | static struct tpm_vendor_specific tpm_tis_i2c = { | |
537 | .status = tpm_tis_i2c_status, | |
538 | .recv = tpm_tis_i2c_recv, | |
539 | .send = tpm_tis_i2c_send, | |
540 | .cancel = tpm_tis_i2c_ready, | |
541 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
542 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
543 | .req_canceled = TPM_STS_COMMAND_READY, | |
544 | }; | |
545 | ||
1b393db5 | 546 | |
ec34fa5e VP |
547 | static enum i2c_chip_type tpm_vendor_chip_type(void) |
548 | { | |
549 | #ifdef CONFIG_OF_CONTROL | |
550 | const void *blob = gd->fdt_blob; | |
551 | ||
552 | if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9645_TPM) >= 0) | |
553 | return SLB9645; | |
554 | ||
555 | if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM) >= 0) | |
556 | return SLB9635; | |
557 | #endif | |
558 | return UNKNOWN; | |
559 | } | |
560 | ||
1b393db5 | 561 | /* Initialisation of i2c tpm */ |
f6267998 RC |
562 | int tpm_vendor_init(uint32_t dev_addr) |
563 | { | |
564 | u32 vendor; | |
ec34fa5e | 565 | u32 expected_did_vid; |
f6267998 RC |
566 | uint old_addr; |
567 | int rc = 0; | |
568 | struct tpm_chip *chip; | |
569 | ||
570 | old_addr = tpm_dev.addr; | |
571 | if (dev_addr != 0) | |
572 | tpm_dev.addr = dev_addr; | |
573 | ||
ec34fa5e VP |
574 | tpm_dev.chip_type = tpm_vendor_chip_type(); |
575 | ||
f6267998 RC |
576 | chip = tpm_register_hardware(&tpm_tis_i2c); |
577 | if (chip < 0) { | |
578 | rc = -ENODEV; | |
579 | goto out_err; | |
580 | } | |
581 | ||
582 | /* Disable interrupts (not supported) */ | |
583 | chip->vendor.irq = 0; | |
584 | ||
585 | /* Default timeouts */ | |
586 | chip->vendor.timeout_a = TIS_SHORT_TIMEOUT; | |
587 | chip->vendor.timeout_b = TIS_LONG_TIMEOUT; | |
588 | chip->vendor.timeout_c = TIS_SHORT_TIMEOUT; | |
589 | chip->vendor.timeout_d = TIS_SHORT_TIMEOUT; | |
590 | ||
1b393db5 | 591 | if (request_locality(chip, 0) < 0) { |
f6267998 RC |
592 | rc = -ENODEV; |
593 | goto out_err; | |
594 | } | |
595 | ||
1b393db5 | 596 | /* Read four bytes from DID_VID register */ |
f6267998 RC |
597 | if (iic_tpm_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) { |
598 | rc = -EIO; | |
599 | goto out_release; | |
600 | } | |
601 | ||
ec34fa5e VP |
602 | if (tpm_dev.chip_type == SLB9635) { |
603 | vendor = be32_to_cpu(vendor); | |
604 | expected_did_vid = TPM_TIS_I2C_DID_VID_9635; | |
605 | } else { | |
606 | /* device id and byte order has changed for newer i2c tpms */ | |
607 | expected_did_vid = TPM_TIS_I2C_DID_VID_9645; | |
608 | } | |
f6267998 | 609 | |
ec34fa5e | 610 | if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) { |
1b393db5 | 611 | error("Vendor id did not match! ID was %08x\n", vendor); |
f6267998 RC |
612 | rc = -ENODEV; |
613 | goto out_release; | |
614 | } | |
615 | ||
1b393db5 TWHT |
616 | debug("1.2 TPM (chip type %s device-id 0x%X)\n", |
617 | chip_name[tpm_dev.chip_type], vendor >> 16); | |
f6267998 RC |
618 | |
619 | /* | |
620 | * A timeout query to TPM can be placed here. | |
621 | * Standard timeout values are used so far | |
622 | */ | |
623 | ||
624 | return 0; | |
625 | ||
626 | out_release: | |
627 | release_locality(chip, 0, 1); | |
628 | ||
629 | out_err: | |
630 | tpm_dev.addr = old_addr; | |
631 | return rc; | |
632 | } | |
633 | ||
634 | void tpm_vendor_cleanup(struct tpm_chip *chip) | |
635 | { | |
636 | release_locality(chip, chip->vendor.locality, 1); | |
637 | } |