Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 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 | * |
Simon Glass | 9457627 | 2015-08-22 18:31:22 -0600 | [diff] [blame] | 16 | * SPDX-License-Identifier: GPL-2.0 |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 17 | */ |
| 18 | |
Simon Glass | 9457627 | 2015-08-22 18:31:22 -0600 | [diff] [blame] | 19 | #ifndef _TPM_TIS_I2C_H |
| 20 | #define _TPM_TIS_I2C_H |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 21 | |
| 22 | #include <linux/compiler.h> |
Tom Wai-Hong Tam | e49fed5 | 2013-04-12 11:04:37 +0000 | [diff] [blame] | 23 | #include <linux/types.h> |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 24 | |
| 25 | enum tpm_timeout { |
Simon Glass | a57bcee | 2015-08-22 18:31:30 -0600 | [diff] [blame^] | 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, |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 31 | }; |
| 32 | |
| 33 | /* Size of external transmit buffer (used in tpm_transmit)*/ |
| 34 | #define TPM_BUFSIZE 4096 |
| 35 | |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 36 | /* Index of Count field in TPM response buffer */ |
Tom Wai-Hong Tam | e49fed5 | 2013-04-12 11:04:37 +0000 | [diff] [blame] | 37 | #define TPM_RSP_SIZE_BYTE 2 |
| 38 | #define TPM_RSP_RC_BYTE 6 |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 39 | |
Simon Glass | 1de4d58 | 2015-08-22 18:31:25 -0600 | [diff] [blame] | 40 | /* Max buffer size supported by our tpm */ |
| 41 | #define TPM_DEV_BUFSIZE 1260 |
| 42 | |
| 43 | enum i2c_chip_type { |
| 44 | SLB9635, |
| 45 | SLB9645, |
| 46 | UNKNOWN, |
| 47 | }; |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 48 | |
Simon Glass | ab79b00 | 2015-08-22 18:31:24 -0600 | [diff] [blame] | 49 | struct tpm_chip { |
Simon Glass | fbb120a | 2015-08-22 18:31:26 -0600 | [diff] [blame] | 50 | bool inited; |
Simon Glass | ab79b00 | 2015-08-22 18:31:24 -0600 | [diff] [blame] | 51 | int is_open; |
| 52 | u8 req_complete_mask; |
| 53 | u8 req_complete_val; |
| 54 | u8 req_canceled; |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 55 | int irq; |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 56 | int locality; |
Tom Wai-Hong Tam | e49fed5 | 2013-04-12 11:04:37 +0000 | [diff] [blame] | 57 | unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ |
| 58 | unsigned long duration[3]; /* msec */ |
Simon Glass | 1de4d58 | 2015-08-22 18:31:25 -0600 | [diff] [blame] | 59 | struct udevice *dev; |
| 60 | u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ |
| 61 | enum i2c_chip_type chip_type; |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 62 | }; |
| 63 | |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 64 | struct tpm_input_header { |
| 65 | __be16 tag; |
| 66 | __be32 length; |
| 67 | __be32 ordinal; |
| 68 | } __packed; |
| 69 | |
| 70 | struct tpm_output_header { |
| 71 | __be16 tag; |
| 72 | __be32 length; |
| 73 | __be32 return_code; |
| 74 | } __packed; |
| 75 | |
| 76 | struct timeout_t { |
| 77 | __be32 a; |
| 78 | __be32 b; |
| 79 | __be32 c; |
| 80 | __be32 d; |
| 81 | } __packed; |
| 82 | |
| 83 | struct duration_t { |
| 84 | __be32 tpm_short; |
| 85 | __be32 tpm_medium; |
| 86 | __be32 tpm_long; |
| 87 | } __packed; |
| 88 | |
| 89 | union cap_t { |
| 90 | struct timeout_t timeout; |
| 91 | struct duration_t duration; |
| 92 | }; |
| 93 | |
| 94 | struct tpm_getcap_params_in { |
| 95 | __be32 cap; |
| 96 | __be32 subcap_size; |
| 97 | __be32 subcap; |
| 98 | } __packed; |
| 99 | |
| 100 | struct tpm_getcap_params_out { |
| 101 | __be32 cap_size; |
| 102 | union cap_t cap; |
| 103 | } __packed; |
| 104 | |
| 105 | union tpm_cmd_header { |
| 106 | struct tpm_input_header in; |
| 107 | struct tpm_output_header out; |
| 108 | }; |
| 109 | |
| 110 | union tpm_cmd_params { |
| 111 | struct tpm_getcap_params_out getcap_out; |
| 112 | struct tpm_getcap_params_in getcap_in; |
| 113 | }; |
| 114 | |
| 115 | struct tpm_cmd_t { |
| 116 | union tpm_cmd_header header; |
| 117 | union tpm_cmd_params params; |
| 118 | } __packed; |
| 119 | |
Simon Glass | 6a7e7cc | 2015-08-22 18:31:27 -0600 | [diff] [blame] | 120 | /* Max number of iterations after i2c NAK */ |
| 121 | #define MAX_COUNT 3 |
| 122 | |
| 123 | /* |
| 124 | * Max number of iterations after i2c NAK for 'long' commands |
| 125 | * |
| 126 | * We need this especially for sending TPM_READY, since the cleanup after the |
| 127 | * transtion to the ready state may take some time, but it is unpredictable |
| 128 | * how long it will take. |
| 129 | */ |
| 130 | #define MAX_COUNT_LONG 50 |
| 131 | |
Simon Glass | 6a7e7cc | 2015-08-22 18:31:27 -0600 | [diff] [blame] | 132 | #define TPM_HEADER_SIZE 10 |
| 133 | |
| 134 | enum tis_access { |
| 135 | TPM_ACCESS_VALID = 0x80, |
| 136 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, |
| 137 | TPM_ACCESS_REQUEST_PENDING = 0x04, |
| 138 | TPM_ACCESS_REQUEST_USE = 0x02, |
| 139 | }; |
| 140 | |
| 141 | enum tis_status { |
| 142 | TPM_STS_VALID = 0x80, |
| 143 | TPM_STS_COMMAND_READY = 0x40, |
| 144 | TPM_STS_GO = 0x20, |
| 145 | TPM_STS_DATA_AVAIL = 0x10, |
| 146 | TPM_STS_DATA_EXPECT = 0x08, |
| 147 | }; |
| 148 | |
Simon Glass | 6a7e7cc | 2015-08-22 18:31:27 -0600 | [diff] [blame] | 149 | /* expected value for DIDVID register */ |
| 150 | #define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L |
| 151 | #define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L |
| 152 | |
| 153 | #define TPM_ACCESS(l) (0x0000 | ((l) << 4)) |
| 154 | #define TPM_STS(l) (0x0001 | ((l) << 4)) |
| 155 | #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) |
| 156 | #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) |
| 157 | |
| 158 | enum tpm_duration { |
| 159 | TPM_SHORT = 0, |
| 160 | TPM_MEDIUM = 1, |
| 161 | TPM_LONG = 2, |
| 162 | TPM_UNDEFINED, |
| 163 | }; |
| 164 | |
| 165 | /* Extended error numbers from linux (see errno.h) */ |
| 166 | #define ECANCELED 125 /* Operation Canceled */ |
| 167 | |
Simon Glass | a57bcee | 2015-08-22 18:31:30 -0600 | [diff] [blame^] | 168 | /* Timer frequency. Corresponds to msec timer resolution */ |
Simon Glass | 6a7e7cc | 2015-08-22 18:31:27 -0600 | [diff] [blame] | 169 | #define HZ 1000 |
| 170 | |
| 171 | #define TPM_MAX_ORDINAL 243 |
| 172 | #define TPM_MAX_PROTECTED_ORDINAL 12 |
| 173 | #define TPM_PROTECTED_ORDINAL_MASK 0xFF |
| 174 | |
| 175 | #define TPM_CMD_COUNT_BYTE 2 |
| 176 | #define TPM_CMD_ORDINAL_BYTE 6 |
| 177 | |
| 178 | /* |
| 179 | * Array with one entry per ordinal defining the maximum amount |
| 180 | * of time the chip could take to return the result. The ordinal |
| 181 | * designation of short, medium or long is defined in a table in |
| 182 | * TCG Specification TPM Main Part 2 TPM Structures Section 17. The |
| 183 | * values of the SHORT, MEDIUM, and LONG durations are retrieved |
| 184 | * from the chip during initialization with a call to tpm_get_timeouts. |
| 185 | */ |
| 186 | static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { |
| 187 | TPM_UNDEFINED, /* 0 */ |
| 188 | TPM_UNDEFINED, |
| 189 | TPM_UNDEFINED, |
| 190 | TPM_UNDEFINED, |
| 191 | TPM_UNDEFINED, |
| 192 | TPM_UNDEFINED, /* 5 */ |
| 193 | TPM_UNDEFINED, |
| 194 | TPM_UNDEFINED, |
| 195 | TPM_UNDEFINED, |
| 196 | TPM_UNDEFINED, |
| 197 | TPM_SHORT, /* 10 */ |
| 198 | TPM_SHORT, |
| 199 | }; |
| 200 | |
| 201 | static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { |
| 202 | TPM_UNDEFINED, /* 0 */ |
| 203 | TPM_UNDEFINED, |
| 204 | TPM_UNDEFINED, |
| 205 | TPM_UNDEFINED, |
| 206 | TPM_UNDEFINED, |
| 207 | TPM_UNDEFINED, /* 5 */ |
| 208 | TPM_UNDEFINED, |
| 209 | TPM_UNDEFINED, |
| 210 | TPM_UNDEFINED, |
| 211 | TPM_UNDEFINED, |
| 212 | TPM_SHORT, /* 10 */ |
| 213 | TPM_SHORT, |
| 214 | TPM_MEDIUM, |
| 215 | TPM_LONG, |
| 216 | TPM_LONG, |
| 217 | TPM_MEDIUM, /* 15 */ |
| 218 | TPM_SHORT, |
| 219 | TPM_SHORT, |
| 220 | TPM_MEDIUM, |
| 221 | TPM_LONG, |
| 222 | TPM_SHORT, /* 20 */ |
| 223 | TPM_SHORT, |
| 224 | TPM_MEDIUM, |
| 225 | TPM_MEDIUM, |
| 226 | TPM_MEDIUM, |
| 227 | TPM_SHORT, /* 25 */ |
| 228 | TPM_SHORT, |
| 229 | TPM_MEDIUM, |
| 230 | TPM_SHORT, |
| 231 | TPM_SHORT, |
| 232 | TPM_MEDIUM, /* 30 */ |
| 233 | TPM_LONG, |
| 234 | TPM_MEDIUM, |
| 235 | TPM_SHORT, |
| 236 | TPM_SHORT, |
| 237 | TPM_SHORT, /* 35 */ |
| 238 | TPM_MEDIUM, |
| 239 | TPM_MEDIUM, |
| 240 | TPM_UNDEFINED, |
| 241 | TPM_UNDEFINED, |
| 242 | TPM_MEDIUM, /* 40 */ |
| 243 | TPM_LONG, |
| 244 | TPM_MEDIUM, |
| 245 | TPM_SHORT, |
| 246 | TPM_SHORT, |
| 247 | TPM_SHORT, /* 45 */ |
| 248 | TPM_SHORT, |
| 249 | TPM_SHORT, |
| 250 | TPM_SHORT, |
| 251 | TPM_LONG, |
| 252 | TPM_MEDIUM, /* 50 */ |
| 253 | TPM_MEDIUM, |
| 254 | TPM_UNDEFINED, |
| 255 | TPM_UNDEFINED, |
| 256 | TPM_UNDEFINED, |
| 257 | TPM_UNDEFINED, /* 55 */ |
| 258 | TPM_UNDEFINED, |
| 259 | TPM_UNDEFINED, |
| 260 | TPM_UNDEFINED, |
| 261 | TPM_UNDEFINED, |
| 262 | TPM_MEDIUM, /* 60 */ |
| 263 | TPM_MEDIUM, |
| 264 | TPM_MEDIUM, |
| 265 | TPM_SHORT, |
| 266 | TPM_SHORT, |
| 267 | TPM_MEDIUM, /* 65 */ |
| 268 | TPM_UNDEFINED, |
| 269 | TPM_UNDEFINED, |
| 270 | TPM_UNDEFINED, |
| 271 | TPM_UNDEFINED, |
| 272 | TPM_SHORT, /* 70 */ |
| 273 | TPM_SHORT, |
| 274 | TPM_UNDEFINED, |
| 275 | TPM_UNDEFINED, |
| 276 | TPM_UNDEFINED, |
| 277 | TPM_UNDEFINED, /* 75 */ |
| 278 | TPM_UNDEFINED, |
| 279 | TPM_UNDEFINED, |
| 280 | TPM_UNDEFINED, |
| 281 | TPM_UNDEFINED, |
| 282 | TPM_LONG, /* 80 */ |
| 283 | TPM_UNDEFINED, |
| 284 | TPM_MEDIUM, |
| 285 | TPM_LONG, |
| 286 | TPM_SHORT, |
| 287 | TPM_UNDEFINED, /* 85 */ |
| 288 | TPM_UNDEFINED, |
| 289 | TPM_UNDEFINED, |
| 290 | TPM_UNDEFINED, |
| 291 | TPM_UNDEFINED, |
| 292 | TPM_SHORT, /* 90 */ |
| 293 | TPM_SHORT, |
| 294 | TPM_SHORT, |
| 295 | TPM_SHORT, |
| 296 | TPM_SHORT, |
| 297 | TPM_UNDEFINED, /* 95 */ |
| 298 | TPM_UNDEFINED, |
| 299 | TPM_UNDEFINED, |
| 300 | TPM_UNDEFINED, |
| 301 | TPM_UNDEFINED, |
| 302 | TPM_MEDIUM, /* 100 */ |
| 303 | TPM_SHORT, |
| 304 | TPM_SHORT, |
| 305 | TPM_UNDEFINED, |
| 306 | TPM_UNDEFINED, |
| 307 | TPM_UNDEFINED, /* 105 */ |
| 308 | TPM_UNDEFINED, |
| 309 | TPM_UNDEFINED, |
| 310 | TPM_UNDEFINED, |
| 311 | TPM_UNDEFINED, |
| 312 | TPM_SHORT, /* 110 */ |
| 313 | TPM_SHORT, |
| 314 | TPM_SHORT, |
| 315 | TPM_SHORT, |
| 316 | TPM_SHORT, |
| 317 | TPM_SHORT, /* 115 */ |
| 318 | TPM_SHORT, |
| 319 | TPM_SHORT, |
| 320 | TPM_UNDEFINED, |
| 321 | TPM_UNDEFINED, |
| 322 | TPM_LONG, /* 120 */ |
| 323 | TPM_LONG, |
| 324 | TPM_MEDIUM, |
| 325 | TPM_UNDEFINED, |
| 326 | TPM_SHORT, |
| 327 | TPM_SHORT, /* 125 */ |
| 328 | TPM_SHORT, |
| 329 | TPM_LONG, |
| 330 | TPM_SHORT, |
| 331 | TPM_SHORT, |
| 332 | TPM_SHORT, /* 130 */ |
| 333 | TPM_MEDIUM, |
| 334 | TPM_UNDEFINED, |
| 335 | TPM_SHORT, |
| 336 | TPM_MEDIUM, |
| 337 | TPM_UNDEFINED, /* 135 */ |
| 338 | TPM_UNDEFINED, |
| 339 | TPM_UNDEFINED, |
| 340 | TPM_UNDEFINED, |
| 341 | TPM_UNDEFINED, |
| 342 | TPM_SHORT, /* 140 */ |
| 343 | TPM_SHORT, |
| 344 | TPM_UNDEFINED, |
| 345 | TPM_UNDEFINED, |
| 346 | TPM_UNDEFINED, |
| 347 | TPM_UNDEFINED, /* 145 */ |
| 348 | TPM_UNDEFINED, |
| 349 | TPM_UNDEFINED, |
| 350 | TPM_UNDEFINED, |
| 351 | TPM_UNDEFINED, |
| 352 | TPM_SHORT, /* 150 */ |
| 353 | TPM_MEDIUM, |
| 354 | TPM_MEDIUM, |
| 355 | TPM_SHORT, |
| 356 | TPM_SHORT, |
| 357 | TPM_UNDEFINED, /* 155 */ |
| 358 | TPM_UNDEFINED, |
| 359 | TPM_UNDEFINED, |
| 360 | TPM_UNDEFINED, |
| 361 | TPM_UNDEFINED, |
| 362 | TPM_SHORT, /* 160 */ |
| 363 | TPM_SHORT, |
| 364 | TPM_SHORT, |
| 365 | TPM_SHORT, |
| 366 | TPM_UNDEFINED, |
| 367 | TPM_UNDEFINED, /* 165 */ |
| 368 | TPM_UNDEFINED, |
| 369 | TPM_UNDEFINED, |
| 370 | TPM_UNDEFINED, |
| 371 | TPM_UNDEFINED, |
| 372 | TPM_LONG, /* 170 */ |
| 373 | TPM_UNDEFINED, |
| 374 | TPM_UNDEFINED, |
| 375 | TPM_UNDEFINED, |
| 376 | TPM_UNDEFINED, |
| 377 | TPM_UNDEFINED, /* 175 */ |
| 378 | TPM_UNDEFINED, |
| 379 | TPM_UNDEFINED, |
| 380 | TPM_UNDEFINED, |
| 381 | TPM_UNDEFINED, |
| 382 | TPM_MEDIUM, /* 180 */ |
| 383 | TPM_SHORT, |
| 384 | TPM_MEDIUM, |
| 385 | TPM_MEDIUM, |
| 386 | TPM_MEDIUM, |
| 387 | TPM_MEDIUM, /* 185 */ |
| 388 | TPM_SHORT, |
| 389 | TPM_UNDEFINED, |
| 390 | TPM_UNDEFINED, |
| 391 | TPM_UNDEFINED, |
| 392 | TPM_UNDEFINED, /* 190 */ |
| 393 | TPM_UNDEFINED, |
| 394 | TPM_UNDEFINED, |
| 395 | TPM_UNDEFINED, |
| 396 | TPM_UNDEFINED, |
| 397 | TPM_UNDEFINED, /* 195 */ |
| 398 | TPM_UNDEFINED, |
| 399 | TPM_UNDEFINED, |
| 400 | TPM_UNDEFINED, |
| 401 | TPM_UNDEFINED, |
| 402 | TPM_SHORT, /* 200 */ |
| 403 | TPM_UNDEFINED, |
| 404 | TPM_UNDEFINED, |
| 405 | TPM_UNDEFINED, |
| 406 | TPM_SHORT, |
| 407 | TPM_SHORT, /* 205 */ |
| 408 | TPM_SHORT, |
| 409 | TPM_SHORT, |
| 410 | TPM_SHORT, |
| 411 | TPM_SHORT, |
| 412 | TPM_MEDIUM, /* 210 */ |
| 413 | TPM_UNDEFINED, |
| 414 | TPM_MEDIUM, |
| 415 | TPM_MEDIUM, |
| 416 | TPM_MEDIUM, |
| 417 | TPM_UNDEFINED, /* 215 */ |
| 418 | TPM_MEDIUM, |
| 419 | TPM_UNDEFINED, |
| 420 | TPM_UNDEFINED, |
| 421 | TPM_SHORT, |
| 422 | TPM_SHORT, /* 220 */ |
| 423 | TPM_SHORT, |
| 424 | TPM_SHORT, |
| 425 | TPM_SHORT, |
| 426 | TPM_SHORT, |
| 427 | TPM_UNDEFINED, /* 225 */ |
| 428 | TPM_UNDEFINED, |
| 429 | TPM_UNDEFINED, |
| 430 | TPM_UNDEFINED, |
| 431 | TPM_UNDEFINED, |
| 432 | TPM_SHORT, /* 230 */ |
| 433 | TPM_LONG, |
| 434 | TPM_MEDIUM, |
| 435 | TPM_UNDEFINED, |
| 436 | TPM_UNDEFINED, |
| 437 | TPM_UNDEFINED, /* 235 */ |
| 438 | TPM_UNDEFINED, |
| 439 | TPM_UNDEFINED, |
| 440 | TPM_UNDEFINED, |
| 441 | TPM_UNDEFINED, |
| 442 | TPM_SHORT, /* 240 */ |
| 443 | TPM_UNDEFINED, |
| 444 | TPM_MEDIUM, |
| 445 | }; |
| 446 | |
Rong Chang | 8faa945 | 2013-04-12 10:44:57 +0000 | [diff] [blame] | 447 | #endif |