2 Basic TIS (TPM Interface Specification) functions for Infineon I2C TPM.
4 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
17 // Default TPM (Infineon SLB9645) I2C Slave Device Address on Crosshill board.
19 #define TPM_I2C_SLAVE_DEVICE_ADDRESS 0x20
22 // Default Infineon SLB9645 TPM I2C mapped registers (SLB9645 I2C Comm. Protocol Application Note).
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
32 // Max. retry count for read transfers (as recommended by Infineon).
37 // Guard time of 250us between I2C read and next I2C write transfer (as recommended by Infineon).
39 #define GUARD_TIME 250
42 // Define bits of ACCESS and STATUS registers
46 /// This bit is a 1 to indicate that the other bits in this register are valid.
48 #define TIS_PC_VALID BIT7
50 /// Indicate that this locality is active.
52 #define TIS_PC_ACC_ACTIVE BIT5
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.
57 #define TIS_PC_ACC_SEIZED BIT4
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.
63 #define TIS_PC_ACC_SEIZE BIT3
65 /// When this bit is 1, another locality is requesting usage of the TPM.
67 #define TIS_PC_ACC_PENDIND BIT2
69 /// Set to 1 to indicate that this locality is requesting to use TPM.
71 #define TIS_PC_ACC_RQUUSE BIT1
73 /// A value of 1 indicates that a T/OS has not been established on the platform
75 #define TIS_PC_ACC_ESTABLISH BIT0
78 /// When this bit is 1, TPM is in the Ready state,
79 /// indicating it is ready to receive a new command.
81 #define TIS_PC_STS_READY BIT6
83 /// Write a 1 to this bit to cause the TPM to execute that command.
85 #define TIS_PC_STS_GO BIT5
87 /// This bit indicates that the TPM has data available as a response.
89 #define TIS_PC_STS_DATA BIT4
91 /// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.
93 #define TIS_PC_STS_EXPECT BIT3
95 /// Writes a 1 to this bit to force the TPM to re-send the response.
97 #define TIS_PC_STS_RETRY BIT1
100 // Default TimeOut values in microseconds
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
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
112 BOOLEAN mI2CPrevReadTransfer
= FALSE
;
115 Writes single byte data to TPM specified by I2C register address.
117 @param[in] TpmAddress The register to write.
118 @param[in] Data The data to write to the register.
130 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr
;
133 // Setup I2C Slave device address and address mode (7-bit).
135 I2CDeviceAddr
.I2CDeviceAddress
= TPM_I2C_SLAVE_DEVICE_ADDRESS
;
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.
141 if (mI2CPrevReadTransfer
) {
142 MicroSecondDelay (GUARD_TIME
);
146 // Write to TPM register.
149 WriteData
[0] = (UINT8
)TpmAddress
;
152 Status
= I2cWriteMultipleByte (
154 EfiI2CSevenBitAddrMode
,
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.
163 mI2CPrevReadTransfer
= FALSE
;
167 Reads single byte data from TPM specified by I2C register address.
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).
173 @param[in] TpmAddress Address of register to read.
175 @return The value register read.
187 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr
;
188 EFI_I2C_ADDR_MODE I2CAddrMode
;
192 Status
= EFI_SUCCESS
;
197 // Locate I2C protocol for TPM I2C access.
199 I2CDeviceAddr
.I2CDeviceAddress
= TPM_I2C_SLAVE_DEVICE_ADDRESS
;
200 I2CAddrMode
= EfiI2CSevenBitAddrMode
;
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.
207 while ((ReadData
== 0xFF) && (ReadCount
< READ_RETRY
)) {
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.
212 if (mI2CPrevReadTransfer
) {
213 MicroSecondDelay (GUARD_TIME
);
217 // Write address to TPM.
219 Data
[0] = (UINT8
)TpmAddress
;
220 Status
= I2cWriteByte (
226 if (EFI_ERROR(Status
)) {
227 DEBUG ((EFI_D_INFO
, "TpmReadByte(): write to TPM address %0x failed (%r)\n", TpmAddress
, Status
));
230 mI2CPrevReadTransfer
= FALSE
;
233 // Read data from TPM.
235 Data
[0] = (UINT8
)TpmAddress
;
236 Status
= I2cReadByte (
242 if (EFI_ERROR(Status
)) {
243 DEBUG ((EFI_D_INFO
, "TpmReadByte(): read from TPM address %0x failed (%r)\n", TpmAddress
, Status
));
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.
253 if (TpmAddress
== INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT
) {
254 ReadCount
= READ_RETRY
;
259 mI2CPrevReadTransfer
= TRUE
;
262 if (EFI_ERROR(Status
)) {
264 // Only reads to access register allowed to fail.
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
);
275 Check whether the value of a TPM chip register satisfies the input BIT setting.
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.
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.
286 TisPcWaitRegisterBits (
296 for (WaitTime
= 0; WaitTime
< TimeOut
; WaitTime
+= 30){
297 RegRead
= TpmReadByte (Register
);
298 if ((RegRead
& BitSet
) == BitSet
&& (RegRead
& BitClear
) == 0)
300 MicroSecondDelay (30);
306 Get BurstCount by reading the burstCount field of a TIS register
307 in the time of default TIS_TIMEOUT_D.
309 @param[out] BurstCount Pointer to a buffer to store the got BurstConut.
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.
316 TisPcReadBurstCount (
317 OUT UINT16
*BurstCount
324 if (BurstCount
== NULL
) {
325 return EFI_INVALID_PARAMETER
;
331 // BurstCount is UINT16, but it is not 2bytes aligned,
332 // so it needs to use TpmReadByte to read two times
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) {
340 MicroSecondDelay (30);
342 } while (WaitTime
< TIS_TIMEOUT_D
);
348 Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
349 to Status Register in time.
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.
355 TisPcPrepareCommand (
361 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT
, TIS_PC_STS_READY
);
362 Status
= TisPcWaitRegisterBits (
363 INFINEON_TPM_STS_0_ADDRESS_DEFAULT
,
372 This service requests use TPM12.
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.
387 // Check to see if TPM exists
389 if (TpmReadByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT
) == 0xFF) {
390 return EFI_NOT_FOUND
;
393 TpmWriteByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT
, TIS_PC_ACC_RQUUSE
);
396 // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A
398 Status
= TisPcWaitRegisterBits (
399 INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT
,
400 (UINT8
)(TIS_PC_ACC_ACTIVE
|TIS_PC_VALID
),
408 Send command to TPM for execution.
410 @param[in] TpmBuffer Buffer for TPM command data.
411 @param[in] DataLength TPM command data length.
413 @retval EFI_SUCCESS Operation completed successfully.
414 @retval EFI_TIMEOUT The register can't run into the expected status in time.
427 Status
= TisPcPrepareCommand ();
428 if (EFI_ERROR (Status
)){
429 DEBUG ((DEBUG_ERROR
, "The TPM is not ready!\n"));
433 while (Index
< DataLength
) {
434 Status
= TisPcReadBurstCount (&BurstCount
);
435 if (EFI_ERROR (Status
)) {
436 Status
= EFI_TIMEOUT
;
439 for (; BurstCount
> 0 && Index
< DataLength
; BurstCount
--) {
440 TpmWriteByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT
, *(TpmBuffer
+ Index
));
445 // Ensure the TPM status STS_EXPECT change from 1 to 0
447 Status
= TisPcWaitRegisterBits (
448 INFINEON_TPM_STS_0_ADDRESS_DEFAULT
,
449 (UINT8
) TIS_PC_VALID
,
453 if (EFI_ERROR (Status
)) {
460 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT
, TIS_PC_STS_GO
);
463 if (EFI_ERROR (Status
)) {
465 // Ensure the TPM state change from "Reception" to "Idle/Ready"
467 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT
, TIS_PC_STS_READY
);
474 Receive response data of last command from TPM.
476 @param[out] TpmBuffer Buffer for response data.
477 @param[out] RespSize Response data length.
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.
487 OUT UINT8
*TpmBuffer
,
495 TPM_RSP_COMMAND_HDR
*ResponseHeader
;
498 // Wait for the command completion
500 Status
= TisPcWaitRegisterBits (
501 INFINEON_TPM_STS_0_ADDRESS_DEFAULT
,
502 (UINT8
) (TIS_PC_VALID
| TIS_PC_STS_DATA
),
506 if (EFI_ERROR (Status
)) {
507 Status
= EFI_TIMEOUT
;
511 // Read the response data header and check it
515 while (Index
< sizeof (TPM_RSP_COMMAND_HDR
)) {
516 Status
= TisPcReadBurstCount (&BurstCount
);
517 if (EFI_ERROR (Status
)) {
518 Status
= EFI_TIMEOUT
;
521 for (; BurstCount
> 0 ; BurstCount
--) {
522 *(TpmBuffer
+ Index
) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT
);
524 if (Index
== sizeof (TPM_RSP_COMMAND_HDR
))
530 // Check the response data header (tag, parasize and returncode)
532 ResponseHeader
= (TPM_RSP_COMMAND_HDR
*)TpmBuffer
;
533 if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader
->tag
)) != TPM_TAG_RSP_COMMAND
) {
534 Status
= EFI_DEVICE_ERROR
;
538 ResponseSize
= SwapBytes32 (ReadUnaligned32 (&ResponseHeader
->paramSize
));
539 if (ResponseSize
== sizeof (TPM_RSP_COMMAND_HDR
)) {
540 Status
= EFI_SUCCESS
;
543 if (ResponseSize
< sizeof (TPM_RSP_COMMAND_HDR
)) {
544 Status
= EFI_DEVICE_ERROR
;
547 if (*RespSize
< ResponseSize
) {
548 Status
= EFI_BUFFER_TOO_SMALL
;
551 *RespSize
= ResponseSize
;
554 // Continue reading the remaining data
556 while (Index
< ResponseSize
) {
557 for (; BurstCount
> 0 ; BurstCount
--) {
558 *(TpmBuffer
+ Index
) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT
);
560 if (Index
== ResponseSize
) {
561 Status
= EFI_SUCCESS
;
565 Status
= TisPcReadBurstCount (&BurstCount
);
566 if (EFI_ERROR (Status
) && (Index
< ResponseSize
)) {
567 Status
= EFI_DEVICE_ERROR
;
574 // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
576 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT
, TIS_PC_STS_READY
);
582 This service enables the sending of commands to the TPM12.
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.
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
594 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
599 IN UINT32 InputParameterBlockSize
,
600 IN UINT8
*InputParameterBlock
,
601 IN OUT UINT32
*OutputParameterBlockSize
,
602 IN UINT8
*OutputParameterBlock
607 Status
= TisPcSend (InputParameterBlock
, InputParameterBlockSize
);
608 if (!EFI_ERROR (Status
)) {
609 Status
= TisPcReceive (OutputParameterBlock
, OutputParameterBlockSize
);