]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkPlatformPkg/Library/Tpm12DeviceLibInfineonI2c/TisPc.c
QuarkPlatformPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / QuarkPlatformPkg / Library / Tpm12DeviceLibInfineonI2c / TisPc.c
1 /** @file
2 Basic TIS (TPM Interface Specification) functions for Infineon I2C TPM.
3
4 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <PiPei.h>
10 #include <Library/Tpm12DeviceLib.h>
11 #include <Library/BaseLib.h>
12 #include <Library/TimerLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/I2cLib.h>
15
16 //
17 // Default TPM (Infineon SLB9645) I2C Slave Device Address on Crosshill board.
18 //
19 #define TPM_I2C_SLAVE_DEVICE_ADDRESS 0x20
20
21 //
22 // Default Infineon SLB9645 TPM I2C mapped registers (SLB9645 I2C Comm. Protocol Application Note).
23 //
24 #define INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT 0x0
25 #define INFINEON_TPM_STS_0_ADDRESS_DEFAULT 0x01
26 #define INFINEON_TPM_BURST0_COUNT_0_DEFAULT 0x02
27 #define INFINEON_TPM_BURST1_COUNT_0_DEFAULT 0x03
28 #define INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT 0x05
29 #define INFINEON_TPM_DID_VID_0_DEFAULT 0x09
30
31 //
32 // Max. retry count for read transfers (as recommended by Infineon).
33 //
34 #define READ_RETRY 3
35
36 //
37 // Guard time of 250us between I2C read and next I2C write transfer (as recommended by Infineon).
38 //
39 #define GUARD_TIME 250
40
41 //
42 // Define bits of ACCESS and STATUS registers
43 //
44
45 ///
46 /// This bit is a 1 to indicate that the other bits in this register are valid.
47 ///
48 #define TIS_PC_VALID BIT7
49 ///
50 /// Indicate that this locality is active.
51 ///
52 #define TIS_PC_ACC_ACTIVE BIT5
53 ///
54 /// Set to 1 to indicate that this locality had the TPM taken away while
55 /// this locality had the TIS_PC_ACC_ACTIVE bit set.
56 ///
57 #define TIS_PC_ACC_SEIZED BIT4
58 ///
59 /// Set to 1 to indicate that TPM MUST reset the
60 /// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the
61 /// locality that is writing this bit.
62 ///
63 #define TIS_PC_ACC_SEIZE BIT3
64 ///
65 /// When this bit is 1, another locality is requesting usage of the TPM.
66 ///
67 #define TIS_PC_ACC_PENDIND BIT2
68 ///
69 /// Set to 1 to indicate that this locality is requesting to use TPM.
70 ///
71 #define TIS_PC_ACC_RQUUSE BIT1
72 ///
73 /// A value of 1 indicates that a T/OS has not been established on the platform
74 ///
75 #define TIS_PC_ACC_ESTABLISH BIT0
76
77 ///
78 /// When this bit is 1, TPM is in the Ready state,
79 /// indicating it is ready to receive a new command.
80 ///
81 #define TIS_PC_STS_READY BIT6
82 ///
83 /// Write a 1 to this bit to cause the TPM to execute that command.
84 ///
85 #define TIS_PC_STS_GO BIT5
86 ///
87 /// This bit indicates that the TPM has data available as a response.
88 ///
89 #define TIS_PC_STS_DATA BIT4
90 ///
91 /// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.
92 ///
93 #define TIS_PC_STS_EXPECT BIT3
94 ///
95 /// Writes a 1 to this bit to force the TPM to re-send the response.
96 ///
97 #define TIS_PC_STS_RETRY BIT1
98
99 //
100 // Default TimeOut values in microseconds
101 //
102 #define TIS_TIMEOUT_A (750 * 1000) // 750ms
103 #define TIS_TIMEOUT_B (2000 * 1000) // 2s
104 #define TIS_TIMEOUT_C (750 * 1000) // 750ms
105 #define TIS_TIMEOUT_D (750 * 1000) // 750ms
106
107 //
108 // Global variable to indicate if TPM I2C Read Transfer has previously occurred.
109 // NOTE: Given the GUARD_TIME requirement (TpmAccess.h), if this library loaded
110 // by PEI Drivers this global variable required to be resident in R/W memory
111 //
112 BOOLEAN mI2CPrevReadTransfer = FALSE;
113
114 /**
115 Writes single byte data to TPM specified by I2C register address.
116
117 @param[in] TpmAddress The register to write.
118 @param[in] Data The data to write to the register.
119
120 **/
121 VOID
122 TpmWriteByte (
123 IN UINTN TpmAddress,
124 IN UINT8 Data
125 )
126 {
127 EFI_STATUS Status;
128 UINTN WriteLength;
129 UINT8 WriteData[2];
130 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;
131
132 //
133 // Setup I2C Slave device address and address mode (7-bit).
134 //
135 I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;
136
137 //
138 // As recommended by Infineon (SLB9645 I2C Communication protocol application
139 // note revision 1.0) wait 250 microseconds between a read and a write transfer.
140 //
141 if (mI2CPrevReadTransfer) {
142 MicroSecondDelay (GUARD_TIME);
143 }
144
145 //
146 // Write to TPM register.
147 //
148 WriteLength = 2;
149 WriteData[0] = (UINT8)TpmAddress;
150 WriteData[1] = Data;
151
152 Status = I2cWriteMultipleByte (
153 I2CDeviceAddr,
154 EfiI2CSevenBitAddrMode,
155 &WriteLength,
156 &WriteData
157 );
158 if (EFI_ERROR(Status)) {
159 DEBUG ((EFI_D_ERROR, "TpmWriteByte(): I2C Write to TPM address %0x failed (%r)\n", TpmAddress, Status));
160 ASSERT (FALSE); // Writes to TPM should always succeed.
161 }
162
163 mI2CPrevReadTransfer = FALSE;
164 }
165
166 /**
167 Reads single byte data from TPM specified by I2C register address.
168
169 Due to stability issues when using I2C combined write/read transfers (with
170 RESTART) to TPM (specifically read from status register), a single write is
171 performed followed by single read (with STOP condition in between).
172
173 @param[in] TpmAddress Address of register to read.
174
175 @return The value register read.
176
177 **/
178 UINT8
179 TpmReadByte (
180 IN UINTN TpmAddress
181 )
182 {
183 UINT8 Data[1];
184 UINT8 ReadData;
185 UINT8 ReadCount;
186
187 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;
188 EFI_I2C_ADDR_MODE I2CAddrMode;
189
190 EFI_STATUS Status;
191
192 Status = EFI_SUCCESS;
193 ReadData = 0xFF;
194 ReadCount = 0;
195
196 //
197 // Locate I2C protocol for TPM I2C access.
198 //
199 I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;
200 I2CAddrMode = EfiI2CSevenBitAddrMode;
201
202 //
203 // As recommended by Infineon (SLB9645 I2C Communication protocol application
204 // note revision 1.0) retry up to 3 times if TPM status, access or burst count
205 // registers return 0xFF.
206 //
207 while ((ReadData == 0xFF) && (ReadCount < READ_RETRY)) {
208 //
209 // As recommended by Infineon (SLB9645 I2C Communication protocol application
210 // note revision 1.0) wait 250 microseconds between a read and a write transfer.
211 //
212 if (mI2CPrevReadTransfer) {
213 MicroSecondDelay (GUARD_TIME);
214 }
215
216 //
217 // Write address to TPM.
218 //
219 Data[0] = (UINT8)TpmAddress;
220 Status = I2cWriteByte (
221 I2CDeviceAddr,
222 I2CAddrMode,
223 &Data
224 );
225
226 if (EFI_ERROR(Status)) {
227 DEBUG ((EFI_D_INFO, "TpmReadByte(): write to TPM address %0x failed (%r)\n", TpmAddress, Status));
228 }
229
230 mI2CPrevReadTransfer = FALSE;
231
232 //
233 // Read data from TPM.
234 //
235 Data[0] = (UINT8)TpmAddress;
236 Status = I2cReadByte (
237 I2CDeviceAddr,
238 I2CAddrMode,
239 &Data
240 );
241
242 if (EFI_ERROR(Status)) {
243 DEBUG ((EFI_D_INFO, "TpmReadByte(): read from TPM address %0x failed (%r)\n", TpmAddress, Status));
244 ReadData = 0xFF;
245 } else {
246 ReadData = Data[0];
247 }
248
249 //
250 // Only need to retry 3 times for TPM status, access, and burst count registers.
251 // If read transfer is to TPM Data FIFO, do not retry, exit loop.
252 //
253 if (TpmAddress == INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT) {
254 ReadCount = READ_RETRY;
255 } else {
256 ReadCount++;
257 }
258
259 mI2CPrevReadTransfer = TRUE;
260 }
261
262 if (EFI_ERROR(Status)) {
263 //
264 // Only reads to access register allowed to fail.
265 //
266 if (TpmAddress != INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) {
267 DEBUG ((EFI_D_ERROR, "TpmReadByte(): read from TPM address %0x failed\n", TpmAddress));
268 ASSERT_EFI_ERROR (Status);
269 }
270 }
271 return ReadData;
272 }
273
274 /**
275 Check whether the value of a TPM chip register satisfies the input BIT setting.
276
277 @param[in] Register TPM register to be checked.
278 @param[in] BitSet Check these data bits are set.
279 @param[in] BitClear Check these data bits are clear.
280 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
281
282 @retval EFI_SUCCESS The register satisfies the check bit.
283 @retval EFI_TIMEOUT The register can't run into the expected status in time.
284 **/
285 EFI_STATUS
286 TisPcWaitRegisterBits (
287 IN UINTN Register,
288 IN UINT8 BitSet,
289 IN UINT8 BitClear,
290 IN UINT32 TimeOut
291 )
292 {
293 UINT8 RegRead;
294 UINT32 WaitTime;
295
296 for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
297 RegRead = TpmReadByte (Register);
298 if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
299 return EFI_SUCCESS;
300 MicroSecondDelay (30);
301 }
302 return EFI_TIMEOUT;
303 }
304
305 /**
306 Get BurstCount by reading the burstCount field of a TIS register
307 in the time of default TIS_TIMEOUT_D.
308
309 @param[out] BurstCount Pointer to a buffer to store the got BurstConut.
310
311 @retval EFI_SUCCESS Get BurstCount.
312 @retval EFI_INVALID_PARAMETER BurstCount is NULL.
313 @retval EFI_TIMEOUT BurstCount can't be got in time.
314 **/
315 EFI_STATUS
316 TisPcReadBurstCount (
317 OUT UINT16 *BurstCount
318 )
319 {
320 UINT32 WaitTime;
321 UINT8 DataByte0;
322 UINT8 DataByte1;
323
324 if (BurstCount == NULL) {
325 return EFI_INVALID_PARAMETER;
326 }
327
328 WaitTime = 0;
329 do {
330 //
331 // BurstCount is UINT16, but it is not 2bytes aligned,
332 // so it needs to use TpmReadByte to read two times
333 //
334 DataByte0 = TpmReadByte (INFINEON_TPM_BURST0_COUNT_0_DEFAULT);
335 DataByte1 = TpmReadByte (INFINEON_TPM_BURST1_COUNT_0_DEFAULT);
336 *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
337 if (*BurstCount != 0) {
338 return EFI_SUCCESS;
339 }
340 MicroSecondDelay (30);
341 WaitTime += 30;
342 } while (WaitTime < TIS_TIMEOUT_D);
343
344 return EFI_TIMEOUT;
345 }
346
347 /**
348 Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
349 to Status Register in time.
350
351 @retval EFI_SUCCESS TPM chip enters into ready state.
352 @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.
353 **/
354 EFI_STATUS
355 TisPcPrepareCommand (
356 VOID
357 )
358 {
359 EFI_STATUS Status;
360
361 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
362 Status = TisPcWaitRegisterBits (
363 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
364 TIS_PC_STS_READY,
365 0,
366 TIS_TIMEOUT_B
367 );
368 return Status;
369 }
370
371 /**
372 This service requests use TPM12.
373
374 @retval EFI_SUCCESS Get the control of TPM12 chip.
375 @retval EFI_NOT_FOUND TPM12 not found.
376 @retval EFI_DEVICE_ERROR Unexpected device behavior.
377 **/
378 EFI_STATUS
379 EFIAPI
380 Tpm12RequestUseTpm (
381 VOID
382 )
383 {
384 EFI_STATUS Status;
385
386 //
387 // Check to see if TPM exists
388 //
389 if (TpmReadByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) == 0xFF) {
390 return EFI_NOT_FOUND;
391 }
392
393 TpmWriteByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT, TIS_PC_ACC_RQUUSE);
394
395 //
396 // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A
397 //
398 Status = TisPcWaitRegisterBits (
399 INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT,
400 (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
401 0,
402 TIS_TIMEOUT_A
403 );
404 return Status;
405 }
406
407 /**
408 Send command to TPM for execution.
409
410 @param[in] TpmBuffer Buffer for TPM command data.
411 @param[in] DataLength TPM command data length.
412
413 @retval EFI_SUCCESS Operation completed successfully.
414 @retval EFI_TIMEOUT The register can't run into the expected status in time.
415
416 **/
417 EFI_STATUS
418 TisPcSend (
419 IN UINT8 *TpmBuffer,
420 IN UINT32 DataLength
421 )
422 {
423 UINT16 BurstCount;
424 UINT32 Index;
425 EFI_STATUS Status;
426
427 Status = TisPcPrepareCommand ();
428 if (EFI_ERROR (Status)){
429 DEBUG ((DEBUG_ERROR, "The TPM is not ready!\n"));
430 goto Done;
431 }
432 Index = 0;
433 while (Index < DataLength) {
434 Status = TisPcReadBurstCount (&BurstCount);
435 if (EFI_ERROR (Status)) {
436 Status = EFI_TIMEOUT;
437 goto Done;
438 }
439 for (; BurstCount > 0 && Index < DataLength; BurstCount--) {
440 TpmWriteByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT, *(TpmBuffer + Index));
441 Index++;
442 }
443 }
444 //
445 // Ensure the TPM status STS_EXPECT change from 1 to 0
446 //
447 Status = TisPcWaitRegisterBits (
448 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
449 (UINT8) TIS_PC_VALID,
450 TIS_PC_STS_EXPECT,
451 TIS_TIMEOUT_C
452 );
453 if (EFI_ERROR (Status)) {
454 goto Done;
455 }
456
457 //
458 // Start the command
459 //
460 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_GO);
461
462 Done:
463 if (EFI_ERROR (Status)) {
464 //
465 // Ensure the TPM state change from "Reception" to "Idle/Ready"
466 //
467 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
468 }
469
470 return Status;
471 }
472
473 /**
474 Receive response data of last command from TPM.
475
476 @param[out] TpmBuffer Buffer for response data.
477 @param[out] RespSize Response data length.
478
479 @retval EFI_SUCCESS Operation completed successfully.
480 @retval EFI_TIMEOUT The register can't run into the expected status in time.
481 @retval EFI_DEVICE_ERROR Unexpected device status.
482 @retval EFI_BUFFER_TOO_SMALL Response data is too long.
483
484 **/
485 EFI_STATUS
486 TisPcReceive (
487 OUT UINT8 *TpmBuffer,
488 OUT UINT32 *RespSize
489 )
490 {
491 EFI_STATUS Status;
492 UINT16 BurstCount;
493 UINT32 Index;
494 UINT32 ResponseSize;
495 TPM_RSP_COMMAND_HDR *ResponseHeader;
496
497 //
498 // Wait for the command completion
499 //
500 Status = TisPcWaitRegisterBits (
501 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
502 (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
503 0,
504 TIS_TIMEOUT_B
505 );
506 if (EFI_ERROR (Status)) {
507 Status = EFI_TIMEOUT;
508 goto Done;
509 }
510 //
511 // Read the response data header and check it
512 //
513 Index = 0;
514 BurstCount = 0;
515 while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
516 Status = TisPcReadBurstCount (&BurstCount);
517 if (EFI_ERROR (Status)) {
518 Status = EFI_TIMEOUT;
519 goto Done;
520 }
521 for (; BurstCount > 0 ; BurstCount--) {
522 *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);
523 Index++;
524 if (Index == sizeof (TPM_RSP_COMMAND_HDR))
525 break;
526 }
527 }
528
529 //
530 // Check the response data header (tag, parasize and returncode)
531 //
532 ResponseHeader = (TPM_RSP_COMMAND_HDR *)TpmBuffer;
533 if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) {
534 Status = EFI_DEVICE_ERROR;
535 goto Done;
536 }
537
538 ResponseSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize));
539 if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {
540 Status = EFI_SUCCESS;
541 goto Done;
542 }
543 if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {
544 Status = EFI_DEVICE_ERROR;
545 goto Done;
546 }
547 if (*RespSize < ResponseSize) {
548 Status = EFI_BUFFER_TOO_SMALL;
549 goto Done;
550 }
551 *RespSize = ResponseSize;
552
553 //
554 // Continue reading the remaining data
555 //
556 while (Index < ResponseSize) {
557 for (; BurstCount > 0 ; BurstCount--) {
558 *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);
559 Index++;
560 if (Index == ResponseSize) {
561 Status = EFI_SUCCESS;
562 goto Done;
563 }
564 }
565 Status = TisPcReadBurstCount (&BurstCount);
566 if (EFI_ERROR (Status) && (Index < ResponseSize)) {
567 Status = EFI_DEVICE_ERROR;
568 goto Done;
569 }
570 }
571
572 Done:
573 //
574 // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
575 //
576 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
577
578 return Status;
579 }
580
581 /**
582 This service enables the sending of commands to the TPM12.
583
584 @param[in] InputParameterBlockSize Size of the TPM12 input parameter block.
585 @param[in] InputParameterBlock Pointer to the TPM12 input parameter block.
586 @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block.
587 @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block.
588
589 @retval EFI_SUCCESS The command byte stream was successfully sent to
590 the device and a response was successfully received.
591 @retval EFI_DEVICE_ERROR The command was not successfully sent to the
592 device or a response was not successfully received
593 from the device.
594 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
595 **/
596 EFI_STATUS
597 EFIAPI
598 Tpm12SubmitCommand (
599 IN UINT32 InputParameterBlockSize,
600 IN UINT8 *InputParameterBlock,
601 IN OUT UINT32 *OutputParameterBlockSize,
602 IN UINT8 *OutputParameterBlock
603 )
604 {
605 EFI_STATUS Status;
606
607 Status = TisPcSend (InputParameterBlock, InputParameterBlockSize);
608 if (!EFI_ERROR (Status)) {
609 Status = TisPcReceive (OutputParameterBlock, OutputParameterBlockSize);
610 }
611 return Status;
612 }