Exemple #1
0
/**

Routine Description:

  Sets the state of a GPIO pin

Arguments:

  This  - pointer to protocol
  Gpio  - which pin to modify
  Mode  - mode to set

Returns:

  EFI_SUCCESS           - GPIO set as requested
  EFI_UNSUPPORTED       - Mode is not supported
  EFI_INVALID_PARAMETER - Gpio pin is out of range
**/
EFI_STATUS
EFIAPI
Set (
  IN  EMBEDDED_GPIO       *This,
  IN  EMBEDDED_GPIO_PIN   Gpio,
  IN  EMBEDDED_GPIO_MODE  Mode
  )
{
  EFI_STATUS    Status = EFI_SUCCESS;
  UINTN         Index, Offset, RegisterBase;

  Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);
  if (EFI_ERROR (Status))
    goto EXIT;

  // Initialize the hardware if not already done
  if (!mPL061Initialized) {
    Status = PL061Initialize();
    if (EFI_ERROR(Status)) {
      goto EXIT;
    }
  }

  switch (Mode)
  {
    case GPIO_MODE_INPUT:
      // Set the corresponding direction bit to LOW for input
      MmioAnd8 (RegisterBase + PL061_GPIO_DIR_REG, ~GPIO_PIN_MASK(Gpio));
      break;

    case GPIO_MODE_OUTPUT_0:
      // Set the corresponding data bit to LOW for 0
      MmioWrite8 (RegisterBase + PL061_GPIO_DATA_REG + (GPIO_PIN_MASK(Offset) << 2), 0);
      // Set the corresponding direction bit to HIGH for output
      MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Offset));
      break;

    case GPIO_MODE_OUTPUT_1:
      // Set the corresponding data bit to HIGH for 1
      MmioWrite8 (RegisterBase + PL061_GPIO_DATA_REG + (GPIO_PIN_MASK(Offset) << 2), 0xff);
      // Set the corresponding direction bit to HIGH for output
      MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Offset));
      break;

    default:
      // Other modes are not supported
      return EFI_UNSUPPORTED;
  }

EXIT:
  return Status;
}
Exemple #2
0
/**
  Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE 
  to ACCESS Register in the time of default TIS_TIMEOUT_A.

  @param[in] TisReg                Pointer to TIS register.

  @retval    EFI_SUCCESS           Get the control of TPM chip.
  @retval    EFI_INVALID_PARAMETER TisReg is NULL.
  @retval    EFI_NOT_FOUND         TPM chip doesn't exit.
  @retval    EFI_TIMEOUT           Can't get the TPM control in time.
**/
EFI_STATUS
EFIAPI
TisPcRequestUseTpm (
  IN      TIS_PC_REGISTERS_PTR      TisReg
  )
{
  EFI_STATUS                        Status;
  
  if (TisReg == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  
  if (!TisPcPresenceCheck (TisReg)) {
    return EFI_NOT_FOUND;
  }

  MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
  //
  // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A
  //
  Status = TisPcWaitRegisterBits (
             &TisReg->Access,
             (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
             0,
             TIS_TIMEOUT_A
             );
  return Status;
}
Exemple #3
0
VOID
ClearP2PBusMaster(
  )
{
  UINT8             Command;
  UINT8             Index;

  for (Index = 0; Index < sizeof(mPciBm)/sizeof(EFI_PCI_BUS_MASTER); Index++) {
    Command = MmioRead8 (
                MmPciAddress (0,
                  DEFAULT_PCI_BUS_NUMBER_PCH,
                  mPciBm[Index].Device,
                  mPciBm[Index].Function,
                  PCI_COMMAND_OFFSET
                )
              );
    Command &= ~EFI_PCI_COMMAND_BUS_MASTER;
    MmioWrite8 (
      MmPciAddress (0,
        DEFAULT_PCI_BUS_NUMBER_PCH,
        mPciBm[Index].Device,
        mPciBm[Index].Function,
        PCI_COMMAND_OFFSET
      ),
      Command
    );
  }
}
Exemple #4
0
STATIC
EFI_STATUS
I2CWriteOneByte (
  UINT8 Data    
  )
{
  EFI_STATUS Status;

  //I2C bus status checking
  Status = WaitForBusBusy();
  if (EFI_ERROR(Status)) {
    return Status;
  }

  //Data transfer
  //Poll till Transmit ready bit is set
  Status = PollForStatus(XRDY);
  if (EFI_ERROR(Status)) {
    return Status;
  }

  MmioWrite8(I2C_DATA, Data);

  //Wait and check if the NACK is not set.
  gBS->Stall(1000);
  if (MmioRead16(I2C_STAT) & NACK) {
    return EFI_DEVICE_ERROR;
  }

  return EFI_SUCCESS;
}
Exemple #5
0
/**
  Writes an 8-bit PCI configuration register.

  Writes the 8-bit PCI configuration register specified by Address with the
  value specified by Value. Value is returned. This function must guarantee
  that all PCI read and write operations are serialized.

  If Address > 0x0FFFFFFF, then ASSERT().

  @param  Address Address that encodes the PCI Bus, Device, Function and
                  Register.
  @param  Value   The value to write.

  @return The value written to the PCI configuration register.

**/
UINT8
EFIAPI
PciExpressWrite8 (
  IN      UINTN                     Address,
  IN      UINT8                     Value
  )
{
  ASSERT_INVALID_PCI_ADDRESS (Address);
  return MmioWrite8 ((UINTN) GetPciExpressBaseAddress () + Address, Value);
}
Exemple #6
0
/**
  Read a 32-bit I/O APIC register.

  If Index is >= 0x100, then ASSERT().
  
  @param  Index  Specifies the I/O APIC register to read.

  @return  The 32-bit value read from the I/O APIC register specified by Index.
**/
UINT32
EFIAPI
IoApicRead (
  IN UINTN  Index
  )
{
  ASSERT (Index < 0x100);
  MmioWrite8 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_INDEX_OFFSET, (UINT8)Index);
  return MmioRead32 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_DATA_OFFSET);
}
Exemple #7
0
/**
  Writes memory-mapped registers.

  @param[in]  PeiServices  An indirect pointer to the PEI Services Table
                           published by the PEI Foundation.
  @param[in]  This         Pointer to local data for the interface.
  @param[in]  Width        The width of the access. Enumerated in bytes.
  @param[in]  Address      The physical address of the access.
  @param[in]  Count        The number of accesses to perform.
  @param[in]  Buffer       A pointer to the buffer of data.

  @retval EFI_SUCCESS            The function completed successfully.
  @retval EFI_INVALID_PARAMETER  Width is invalid for this EFI system.
  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
                                 and Count is not valid for this EFI system.

**/
EFI_STATUS
EFIAPI
CpuMemoryServiceWrite (
  IN CONST EFI_PEI_SERVICES    **PeiServices,
  IN CONST EFI_PEI_CPU_IO_PPI  *This,
  IN EFI_PEI_CPU_IO_PPI_WIDTH  Width,
  IN UINT64                    Address,
  IN UINTN                     Count,
  IN VOID                      *Buffer
  )
{
  EFI_STATUS                Status;
  UINT8                     InStride;
  UINT8                     OutStride;
  EFI_PEI_CPU_IO_PPI_WIDTH  OperationWidth;
  BOOLEAN                   Aligned;
  UINT8                     *Uint8Buffer;

  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Select loop based on the width of the transfer
  //
  InStride = mInStride[Width];
  OutStride = mOutStride[Width];
  OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03);
  Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00);
  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
    if (OperationWidth == EfiPeiCpuIoWidthUint8) {
      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
    } else if (OperationWidth == EfiPeiCpuIoWidthUint16) {
      if (Aligned) {
        MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
      } else {
        MmioWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer));
      }
    } else if (OperationWidth == EfiPeiCpuIoWidthUint32) {
      if (Aligned) {
        MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
      } else {
        MmioWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer));
      }
    } else if (OperationWidth == EfiPeiCpuIoWidthUint64) {
      if (Aligned) {
        MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
      } else {
        MmioWrite64 ((UINTN)Address, ReadUnaligned64 ((UINT64 *)Uint8Buffer));
      }
    }
  }
  return EFI_SUCCESS;
}
Exemple #8
0
/**
  8-bit memory write operations.

  @param[in] PeiServices  An indirect pointer to the PEI Services Table published
                          by the PEI Foundation.
  @param[in] This         Pointer to local data for the interface.
  @param[in] Address      The physical address of the access.
  @param[in] Data         The data to write.

**/
VOID
EFIAPI
CpuMemWrite8 (
  IN CONST EFI_PEI_SERVICES    **PeiServices,
  IN CONST EFI_PEI_CPU_IO_PPI  *This,
  IN UINT64                    Address,
  IN  UINT8                    Data
  )
{
  MmioWrite8 ((UINTN)Address, Data);
}
Exemple #9
0
/**
  Write a 32-bit I/O APIC register.

  If Index is >= 0x100, then ASSERT().
  
  @param  Index  Specifies the I/O APIC register to write.
  @param  Value  Specifies the value to write to the I/O APIC register specified by Index.

  @return  The 32-bit value written to I/O APIC register specified by Index.
**/
UINT32
EFIAPI
IoApicWrite (
  IN UINTN   Index,
  IN UINT32  Value
  )
{
  ASSERT (Index < 0x100);
  MmioWrite8 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_INDEX_OFFSET, (UINT8)Index);
  return MmioWrite32 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_DATA_OFFSET, Value);
}
Exemple #10
0
STATIC
VOID
EFIAPI
PL061SetPins (
  IN UINTN Address,
  IN UINTN Mask,
  IN UINTN Value
  )
{
  MmioWrite8 (PL061EffectiveAddress (Address, Mask), Value);
}
Exemple #11
0
VOID
EFIAPI
GdbPutChar (
  IN  CHAR8   Char
  )
{
  UINT32  LSR = UartBase(PcdGet32(PcdOmap35xxConsoleUart)) + UART_LSR_REG;
  UINT32  THR = UartBase(PcdGet32(PcdOmap35xxConsoleUart)) + UART_THR_REG;

  while ((MmioRead8(LSR) & UART_LSR_TX_FIFO_E_MASK) == UART_LSR_TX_FIFO_E_NOT_EMPTY);
  MmioWrite8(THR, Char);
}
/**
  Write I/O registers.

  The I/O operations are carried out exactly as requested. The caller is responsible
  for satisfying any alignment and I/O width restrictions that a PI System on a
  platform might require. For example on some platforms, width requests of
  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
  be handled by the driver.

  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
  each of the Count operations that is performed.

  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
  incremented for each of the Count operations that is performed. The read or
  write operation is performed Count times on the same Address.

  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
  incremented for each of the Count operations that is performed. The read or
  write operation is performed Count times from the first element of Buffer.

  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
  @param[in]  Width    Signifies the width of the I/O or Memory operation.
  @param[in]  Address  The base address of the I/O operation.
  @param[in]  Count    The number of I/O operations to perform. The number of
                       bytes moved is Width size * Count, starting at Address.
  @param[in]  Buffer   For read operations, the destination buffer to store the results.
                       For write operations, the source buffer from which to write data.

  @retval EFI_SUCCESS            The data was read from or written to the PI system.
  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
                                 and Count is not valid for this PI system.

**/
STATIC
EFI_STATUS
EFIAPI
CpuIoServiceWrite (
  IN EFI_CPU_IO2_PROTOCOL       *This,
  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
  IN UINT64                     Address,
  IN UINTN                      Count,
  IN VOID                       *Buffer
  )
{
  EFI_STATUS                 Status;
  UINT8                      InStride;
  UINT8                      OutStride;
  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
  UINT8                      *Uint8Buffer;

  //
  // Make sure the parameters are valid
  //
  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Address += PcdGet64 (PcdPciIoTranslation);

  //
  // Select loop based on the width of the transfer
  //
  InStride = mInStride[Width];
  OutStride = mOutStride[Width];
  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);

  for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
    if (OperationWidth == EfiCpuIoWidthUint8) {
      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
    } else if (OperationWidth == EfiCpuIoWidthUint16) {
      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
    } else if (OperationWidth == EfiCpuIoWidthUint32) {
      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
    }
  }

  return EFI_SUCCESS;
}
Exemple #13
0
/**
  Writes a 8-bit I/O port.

  Writes the 8-bit I/O port specified by Port with the value specified by Value
  and returns Value. This function must guarantee that all I/O read and write
  operations are serialized.

  @param  Port  The I/O port to write.
  @param  Value The value to write to the I/O port.

  @return The value written the I/O port.

**/
UINT8
EFIAPI
IoWrite8 (
  IN  UINT64                 Port,
  IN  UINT8                  Data
  )
{
  UINT64           Address;

  //
  // Add the 64MB aligned IO Port space to the IO address
  //
  Address = MAP_PORT_BASE_TO_MEM (Port);
  Address += PcdGet64(PcdIoBlockBaseAddressForIpf);

  return MmioWrite8 (Address, Data);
}
Exemple #14
0
/**
  Write data to serial device.

  @param  Buffer           Point of data buffer which need to be writed.
  @param  NumberOfBytes    Number of output bytes which are cached in Buffer.

  @retval 0                Write data failed.
  @retval !0               Actual number of bytes writed to serial device.

**/
UINTN
EFIAPI
SerialPortWrite (
  IN UINT8     *Buffer,
  IN UINTN     NumberOfBytes
)
{
  UINT32  LSR = UartBase(PcdGet32(PcdOmap35xxConsoleUart)) + UART_LSR_REG;
  UINT32  THR = UartBase(PcdGet32(PcdOmap35xxConsoleUart)) + UART_THR_REG;
  UINTN   Count;
    
  for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
    while ((MmioRead8(LSR) & UART_LSR_TX_FIFO_E_MASK) == UART_LSR_TX_FIFO_E_NOT_EMPTY);
    MmioWrite8(THR, *Buffer);
  }

  return NumberOfBytes;
}
Exemple #15
0
VOID
SetAfterG3On (
  BOOLEAN Enable
  )
{
  UINT8             PmCon1;

  //
  // ICH handling portion
  //
  PmCon1 = MmioRead8 ( PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1 );
  PmCon1 &= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
  if (Enable) {
    PmCon1 |= B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
  }
  MmioWrite8 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1, PmCon1);

}
Exemple #16
0
EFIAPI
MmioWriteBuffer8 (
  IN  UINTN         StartAddress,
  IN  UINTN         Length,
  IN  CONST UINT8   *Buffer
  )
{
  VOID* ReturnBuffer;

  ASSERT ((Length - 1) <=  (MAX_ADDRESS - StartAddress));
  ASSERT ((Length - 1) <=  (MAX_ADDRESS - (UINTN) Buffer));

  ReturnBuffer = (UINT8 *) Buffer;

  while (Length-- > 0) {
     MmioWrite8 (StartAddress++, *(Buffer++));
  }

  return ReturnBuffer;

}
Exemple #17
0
/**
  Set TPM chip to ready state by sending ready command TIS_PC_STS_READY 
  to Status Register in time.

  @param[in] TisReg                Pointer to TIS register.

  @retval    EFI_SUCCESS           TPM chip enters into ready state.
  @retval    EFI_INVALID_PARAMETER TisReg is NULL.
  @retval    EFI_TIMEOUT           TPM chip can't be set to ready state in time.
**/
EFI_STATUS
EFIAPI
TisPcPrepareCommand (
  IN      TIS_PC_REGISTERS_PTR      TisReg
  )
{
  EFI_STATUS                        Status;

  if (TisReg == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
  Status = TisPcWaitRegisterBits (
             &TisReg->Status,
             TIS_PC_STS_READY,
             0,
             TIS_TIMEOUT_B
             );
  return Status;
}
Exemple #18
0
/**
  Writes memory-mapped registers.

  The I/O operations are carried out exactly as requested. The caller is responsible 
  for satisfying any alignment and I/O width restrictions that a PI System on a 
  platform might require. For example on some platforms, width requests of 
  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will 
  be handled by the driver.
  
  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, 
  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for 
  each of the Count operations that is performed.
  
  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, 
  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is 
  incremented for each of the Count operations that is performed. The read or 
  write operation is performed Count times on the same Address.
  
  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, 
  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is 
  incremented for each of the Count operations that is performed. The read or 
  write operation is performed Count times from the first element of Buffer.
  
  @param[in]  This     A pointer to the EFI_CPU_IO_PROTOCOL instance.
  @param[in]  Width    Signifies the width of the I/O or Memory operation.
  @param[in]  Address  The base address of the I/O operation. 
  @param[in]  Count    The number of I/O operations to perform. The number of 
                       bytes moved is Width size * Count, starting at Address.
  @param[in]  Buffer   For read operations, the destination buffer to store the results.
                       For write operations, the source buffer from which to write data.

  @retval EFI_SUCCESS            The data was read from or written to the PI system.
  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
  @retval EFI_UNSUPPORTED        The address range specified by Address, Width, 
                                 and Count is not valid for this PI system.

**/
EFI_STATUS
EFIAPI
CpuMemoryServiceWrite (
  IN EFI_CPU_IO_PROTOCOL        *This,
  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
  IN UINT64                     Address,
  IN UINTN                      Count,
  IN VOID                       *Buffer
  )
{
  EFI_STATUS  Status;
  UINT8                      InStride;
  UINT8                      OutStride;
  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
  UINT8       *Uint8Buffer;

  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Select loop based on the width of the transfer
  //
  InStride = mInStride[Width];
  OutStride = mOutStride[Width];
  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
    if (OperationWidth == EfiCpuIoWidthUint8) {
      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
    } else if (OperationWidth == EfiCpuIoWidthUint16) {
      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
    } else if (OperationWidth == EfiCpuIoWidthUint32) {
      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
    } else if (OperationWidth == EfiCpuIoWidthUint64) {
      MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
    }
  }
  return EFI_SUCCESS;
}
Exemple #19
0
/**
  Writes memory-mapped registers.

  The I/O operations are carried out exactly as requested.  The caller is 
  responsible for any alignment and I/O width issues that the bus, device, 
  platform, or type of I/O might require.

  @param[in]  This     The EFI_SMM_CPU_IO2_PROTOCOL instance.
  @param[in]  Width    Signifies the width of the I/O operations.
  @param[in]  Address  The base address of the I/O operations.  The caller is 
                       responsible for aligning the Address if required. 
  @param[in]  Count    The number of I/O operations to perform.
  @param[in]  Buffer   For read operations, the destination buffer to store 
                       the results.  For write operations, the source buffer 
                       from which to write data.

  @retval EFI_SUCCESS            The data was read from or written to the device.
  @retval EFI_UNSUPPORTED        The Address is not valid for this system.
  @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
  @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a 
                                 lack of resources

**/
EFI_STATUS
EFIAPI
CpuMemoryServiceWrite (
  IN CONST EFI_SMM_CPU_IO2_PROTOCOL  *This,
  IN EFI_SMM_IO_WIDTH                Width,
  IN UINT64                          Address,
  IN UINTN                           Count,
  IN VOID                            *Buffer
  )
{
  EFI_STATUS  Status;
  UINT8       Stride;
  UINT8       *Uint8Buffer;

  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Select loop based on the width of the transfer
  //
  Stride = mStride[Width];
  for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {
    if (Width == SMM_IO_UINT8) {
      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
    } else if (Width == SMM_IO_UINT16) {
      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
    } else if (Width == SMM_IO_UINT32) {
      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
    } else if (Width == SMM_IO_UINT64) {
      MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
    }
  }
  return EFI_SUCCESS;
}
/**
  Perform flash write operation with progress indicator.  The start and end
  completion percentage values are passed into this function.  If the requested
  flash write operation is broken up, then completion percentage between the
  start and end values may be passed to the provided Progress function.  The
  caller of this function is required to call the Progress function for the
  start and end completion percentage values.  This allows the Progress,
  StartPercentage, and EndPercentage parameters to be ignored if the requested
  flash write operation can not be broken up

  @param[in] FirmwareType      The type of firmware.
  @param[in] FlashAddress      The address of flash device to be accessed.
  @param[in] FlashAddressType  The type of flash device address.
  @param[in] Buffer            The pointer to the data buffer.
  @param[in] Length            The length of data buffer in bytes.
  @param[in] Progress          A function used report the progress of the
                               firmware update.  This is an optional parameter
                               that may be NULL.
  @param[in] StartPercentage   The start completion percentage value that may
                               be used to report progress during the flash
                               write operation.
  @param[in] EndPercentage     The end completion percentage value that may
                               be used to report progress during the flash
                               write operation.

  @retval EFI_SUCCESS           The operation returns successfully.
  @retval EFI_WRITE_PROTECTED   The flash device is read only.
  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
**/
EFI_STATUS
EFIAPI
PerformFlashWriteWithProgress (
  IN PLATFORM_FIRMWARE_TYPE                         FirmwareType,
  IN EFI_PHYSICAL_ADDRESS                           FlashAddress,
  IN FLASH_ADDRESS_TYPE                             FlashAddressType,
  IN VOID                                           *Buffer,
  IN UINTN                                          Length,
  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,        OPTIONAL
  IN UINTN                                          StartPercentage,
  IN UINTN                                          EndPercentage
  )
{
  EFI_STATUS            Status = EFI_SUCCESS;
  UINTN               Index;
  EFI_PHYSICAL_ADDRESS  Address;
  UINTN                 CountOfBlocks;
  EFI_TPL               OldTpl;
  BOOLEAN               FlashError;
  UINT8                 *Buf;
  UINTN                 LpcBaseAddress;
  UINT8                 Data8Or;
  UINT8                 Data8And;
  UINT8                 BiosCntl;

  Index             = 0;
  Address           = 0;
  CountOfBlocks     = 0;
  FlashError        = FALSE;
  Buf               = Buffer;

  DEBUG((DEBUG_INFO | DEBUG_ERROR, "PerformFlashWrite - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));
  if (FlashAddressType == FlashAddressTypeRelativeAddress) {
    FlashAddress = FlashAddress + mInternalFdAddress;
  }

  CountOfBlocks = (UINTN) (Length / BLOCK_SIZE);
  Address = FlashAddress;

  LpcBaseAddress = MmPciAddress (0,
                    DEFAULT_PCI_BUS_NUMBER_PCH,
                    PCI_DEVICE_NUMBER_PCH_LPC,
                    PCI_FUNCTION_NUMBER_PCH_LPC,
                    0
                    );
  BiosCntl = MmioRead8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL);
  if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {
    ///
    /// Clear SMM_BWP bit (D31:F0:RegDCh[5])
    ///
    Data8And  = (UINT8) ~B_PCH_LPC_BIOS_CNTL_SMM_BWP;
    Data8Or   = 0x00;

    MmioAndThenOr8 (
      LpcBaseAddress + R_PCH_LPC_BIOS_CNTL,
      Data8And,
      Data8Or
      );
    DEBUG((DEBUG_INFO, "PerformFlashWrite Clear SMM_BWP bit\n"));
  }

    //
    // Raise TPL to TPL_NOTIFY to block any event handler,
    // while still allowing RaiseTPL(TPL_NOTIFY) within
    // output driver during Print()
    //
    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    for (Index = 0; Index < CountOfBlocks; Index++) {
      if (Progress != NULL) {
        Progress (StartPercentage + ((Index * (EndPercentage - StartPercentage)) / CountOfBlocks));
      }
      //
      // Handle block based on address and contents.
      //
      if (!EFI_ERROR (InternalCompareBlock (Address, Buf))) {
        DEBUG((DEBUG_INFO, "Skipping block at 0x%lx (already programmed)\n", Address));
      } else {
        //
        // Make updating process uninterruptable,
        // so that the flash memory area is not accessed by other entities
        // which may interfere with the updating process
        //
        Status  = InternalEraseBlock (Address);
        if (EFI_ERROR(Status)) {
          gBS->RestoreTPL (OldTpl);
          FlashError = TRUE;
          goto Done;
        }
        Status = InternalWriteBlock (
                  Address,
                  Buf,
                  (UINT32)(Length > BLOCK_SIZE ? BLOCK_SIZE : Length)
                  );
        if (EFI_ERROR(Status)) {
          gBS->RestoreTPL (OldTpl);
          FlashError = TRUE;
          goto Done;
        }
      }

      //
      // Move to next block to update.
      //
      Address += BLOCK_SIZE;
      Buf += BLOCK_SIZE;
      if (Length > BLOCK_SIZE) {
        Length -= BLOCK_SIZE;
      } else {
        Length = 0;
      }
    }
    gBS->RestoreTPL (OldTpl);

Done:
  if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {
    //
    // Restore original control setting
    //
    MmioWrite8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL, BiosCntl);
  }

  if (Progress != NULL) {
    Progress (EndPercentage);
  }

  return EFI_SUCCESS;
}
Exemple #21
0
EFI_STATUS
EFIAPI
SpiProtocolInit (
  IN EFI_SPI_PROTOCOL       *This,
  IN SPI_INIT_TABLE         *InitTable
  )
/*++

Routine Description:

  Initialize the host controller to execute SPI command.

Arguments:

  This                    Pointer to the EFI_SPI_PROTOCOL instance.
  InitTable               Initialization data to be programmed into the SPI host controller.

Returns:

  EFI_SUCCESS             Initialization completed.
  EFI_ACCESS_DENIED       The SPI static configuration interface has been locked-down.
  EFI_INVALID_PARAMETER   Bad input parameters.
  EFI_UNSUPPORTED         Can't get Descriptor mode VSCC values
--*/
{
  EFI_STATUS    Status;
  UINT8         Index;
  UINT16        OpcodeType;
  SPI_INSTANCE  *SpiInstance;
  BOOLEAN       MultiPartitionIsSupported;
  UINTN         PchRootComplexBar;
  UINT8         SFDPCmdOpcodeIndex;
  UINT8         UnlockCmdOpcodeIndex;
  UINT8         ReadDataCmdOpcodeIndex;
  UINT8         FlashPartId[3];

  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
  PchRootComplexBar = SpiInstance->PchRootComplexBar;

  if (InitTable != NULL) {
    //
    // Copy table into SPI driver Private data structure
    //
    CopyMem (
      &SpiInstance->SpiInitTable,
      InitTable,
      sizeof (SPI_INIT_TABLE)
      );
  } else {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Check if the SPI interface has been locked-down.
  //
  if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
    ASSERT_EFI_ERROR (EFI_ACCESS_DENIED);
    return EFI_ACCESS_DENIED;
  }
  //
  // Clear all the status bits for status regs.
  //
  MmioOr16 (
    (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),
    (UINT16) ((B_QNC_RCRB_SPIS_CDS | B_QNC_RCRB_SPIS_BAS))
    );
  MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);

  //
  // Set the Prefix Opcode registers.
  //
  MmioWrite16 (
    PchRootComplexBar + R_QNC_RCRB_SPIPREOP,
    (SpiInstance->SpiInitTable.PrefixOpcode[1] << 8) | InitTable->PrefixOpcode[0]
    );
  MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIPREOP);

  //
  // Set Opcode Type Configuration registers.
  //
  for (Index = 0, OpcodeType = 0; Index < SPI_NUM_OPCODE; Index++) {
    switch (SpiInstance->SpiInitTable.OpcodeMenu[Index].Type) {
    case EnumSpiOpcodeRead:
      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_READ << (Index * 2));
      break;
    case EnumSpiOpcodeWrite:
      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_WRITE << (Index * 2));
      break;
    case EnumSpiOpcodeWriteNoAddr:
      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE << (Index * 2));
      break;
    default:
      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_READ << (Index * 2));
      break;
    }
  }
  MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE, OpcodeType);
  MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE);

  //
  // Setup the Opcode Menu registers.
  //
  ReadDataCmdOpcodeIndex = SPI_NUM_OPCODE;
  SFDPCmdOpcodeIndex = SPI_NUM_OPCODE;
  UnlockCmdOpcodeIndex = SPI_NUM_OPCODE;
  for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {
    MmioWrite8 (
      PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index,
      SpiInstance->SpiInitTable.OpcodeMenu[Index].Code
      );
    MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index);
    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {
      Status = SpiProtocolExecute (
                This,
                Index,
                0,
                TRUE,
                TRUE,
                FALSE,
                (UINTN) 0,
                3,
                FlashPartId,
                EnumSpiRegionDescriptor
                );
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (FlashPartId[0] != SpiInstance->SpiInitTable.VendorId  ||
          FlashPartId[1] != SpiInstance->SpiInitTable.DeviceId0 ||
          FlashPartId[2] != SpiInstance->SpiInitTable.DeviceId1) {
        return EFI_INVALID_PARAMETER;
      }
    }

    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData ||
        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead ||
        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) {
      ReadDataCmdOpcodeIndex = Index;
    }

    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDiscoveryParameters) {
      SFDPCmdOpcodeIndex = Index;
    }

    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {
      UnlockCmdOpcodeIndex = Index;
    }
  }

  MultiPartitionIsSupported = FALSE;

  Status = UnlockFlashComponents (
            This,
            UnlockCmdOpcodeIndex
            );
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "Unlock flash components fail!\n"));
  }

  SpiPhaseInit ();
  FillOutPublicInfoStruct (SpiInstance);
  SpiInstance->InitDone = TRUE;
  return EFI_SUCCESS;
}
Exemple #22
0
EFI_STATUS
SendSpiCmd (
  IN     EFI_SPI_PROTOCOL   *This,
  IN     UINT8              OpcodeIndex,
  IN     UINT8              PrefixOpcodeIndex,
  IN     BOOLEAN            DataCycle,
  IN     BOOLEAN            Atomic,
  IN     BOOLEAN            ShiftOut,
  IN     UINTN              Address,
  IN     UINT32             DataByteCount,
  IN OUT UINT8              *Buffer,
  IN     SPI_REGION_TYPE    SpiRegionType
  )
/*++

Routine Description:

  This function sends the programmed SPI command to the slave device.

Arguments:

  OpcodeIndex       Index of the command in the OpCode Menu.
  PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
  DataCycle         TRUE if the SPI cycle contains data
  Atomic            TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
  ShiftOut          If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
  Address           In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
                    Region, this value specifies the offset from the Region Base; for BIOS Region,
                    this value specifies the offset from the start of the BIOS Image. In Non
                    Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
                    Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
                    Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
                    supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
                    the flash (in Non Descriptor Mode)
  DataByteCount     Number of bytes in the data portion of the SPI cycle. This function may break the
                    data transfer into multiple operations. This function ensures each operation does
                    not cross 256 byte flash address boundary.
                    *NOTE: if there is some SPI chip that has a stricter address boundary requirement
                    (e.g., its write page size is < 256 byte), then the caller cannot rely on this
                    function to cut the data transfer at proper address boundaries, and it's the
                    caller's reponsibility to pass in a properly cut DataByteCount parameter.
  Buffer            Data received or sent during the SPI cycle.
  SpiRegionType     SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
                    EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
                    Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
                    and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
                    to base of the 1st flash device (i.e., it is a Flash Linear Address).

Returns:

  EFI_SUCCESS             SPI command completes successfully.
  EFI_DEVICE_ERROR        Device error, the command aborts abnormally.
  EFI_ACCESS_DENIED       Some unrecognized command encountered in hardware sequencing mode
  EFI_INVALID_PARAMETER   The parameters specified are not valid.

--*/
{
  UINT32        Index;
  SPI_INSTANCE  *SpiInstance;
  UINTN         HardwareSpiAddr;
  UINTN         SpiBiosSize;
  UINTN         BaseAddress;
  UINTN         LimitAddress;
  UINT32        SpiDataCount;
  UINT8         OpCode;
  SPI_OPERATION Operation;
  UINTN         PchRootComplexBar;

  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
  PchRootComplexBar = SpiInstance->PchRootComplexBar;
  SpiBiosSize       = SpiInstance->SpiInitTable.BiosSize;
  Operation         = SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Operation;
  OpCode            = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + OpcodeIndex);

  //
  // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0
  //
  if (OpCode == 0 || SpiBiosSize == 0) {
    ASSERT (FALSE);
    return EFI_INVALID_PARAMETER;
  }

  SpiOffset2Physical (This, Address, SpiRegionType, &HardwareSpiAddr, &BaseAddress, &LimitAddress);
  //
  // Have direct access to BIOS region in Descriptor mode,
  //
  if (SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Type == EnumSpiOpcodeRead &&
      SpiRegionType == EnumSpiRegionBios) {
    CopyMem (
      Buffer,
      (UINT8 *) ((HardwareSpiAddr - BaseAddress) + (UINT32) (~(SpiBiosSize - 1))),
      DataByteCount
      );
    return EFI_SUCCESS;
  }
  //
  // DEBUG((EFI_D_ERROR, "SPIADDR %x, %x, %x, %x\n", Address, HardwareSpiAddr, BaseAddress,
  // LimitAddress));
  //
  if ((DataCycle == FALSE) && (DataByteCount > 0)) {
    DataByteCount = 0;
  }

  do {
    //
    // Trim at 256 byte boundary per operation,
    // - PCH SPI controller requires trimming at 4KB boundary
    // - Some SPI chips require trimming at 256 byte boundary for write operation
    // - Trimming has limited performance impact as we can read / write atmost 64 byte
    //   per operation
    //
    if (HardwareSpiAddr + DataByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) {
      SpiDataCount = (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32) (HardwareSpiAddr);
    } else {
      SpiDataCount = DataByteCount;
    }
    //
    // Calculate the number of bytes to shift in/out during the SPI data cycle.
    // Valid settings for the number of bytes duing each data portion of the
    // PCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64
    //
    if (SpiDataCount >= 64) {
      SpiDataCount = 64;
    } else if ((SpiDataCount &~0x07) != 0) {
      SpiDataCount = SpiDataCount &~0x07;
    }
    //
    // If shifts data out, load data into the SPI data buffer.
    //
    if (ShiftOut) {
      for (Index = 0; Index < SpiDataCount; Index++) {
        MmioWrite8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index, Buffer[Index]);
        MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);
      }
    }

    MmioWrite32 (
      (PchRootComplexBar + R_QNC_RCRB_SPIA),
      (UINT32) (HardwareSpiAddr & B_QNC_RCRB_SPIA_MASK)
      );
    MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIA);

    //
    // Execute the command on the SPI compatible mode
    //

    //
    // Clear error flags
    //
    MmioOr16 ((PchRootComplexBar + R_QNC_RCRB_SPIS), B_QNC_RCRB_SPIS_BAS);

    //
    // Initialte the SPI cycle
    //
    if (DataCycle) {
      MmioWrite16 (
        (PchRootComplexBar + R_QNC_RCRB_SPIC),
        ( (UINT16) (B_QNC_RCRB_SPIC_DC) | (UINT16) (((SpiDataCount - 1) << 8) & B_QNC_RCRB_SPIC_DBC) |
          (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |
          (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |
          (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |
          (UINT16) (B_QNC_RCRB_SPIC_SCGO)));
    } else {
      MmioWrite16 (
        (PchRootComplexBar + R_QNC_RCRB_SPIC),
        ( (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |
          (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |
          (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |
          (UINT16) (B_QNC_RCRB_SPIC_SCGO)));
    }

    MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIC);

    //
    // end of command execution
    //
    // Wait the SPI cycle to complete.
    //
    if (!WaitForSpiCycleComplete (This, TRUE)) {
      return EFI_DEVICE_ERROR;
    }
    //
    // If shifts data in, get data from the SPI data buffer.
    //
    if (!ShiftOut) {
      for (Index = 0; Index < SpiDataCount; Index++) {
        Buffer[Index] = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);
      }
    }

    HardwareSpiAddr += SpiDataCount;
    Buffer += SpiDataCount;
    DataByteCount -= SpiDataCount;
  } while (DataByteCount > 0);

  return EFI_SUCCESS;
}
Exemple #23
0
/**
  Send a command to TPM for execution and return response data.

  @param[in]      PeiServices   Describes the list of possible PEI Services.
  @param[in]      TisReg        TPM register space base address.  
  @param[in]      BufferIn      Buffer for command data.  
  @param[in]      SizeIn        Size of command data.  
  @param[in, out] BufferOut     Buffer for response data.  
  @param[in, out] SizeOut       Size of response data.  
 
  @retval EFI_SUCCESS           Operation completed successfully.
  @retval EFI_TIMEOUT           The register can't run into the expected status in time.
  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.
  @retval EFI_DEVICE_ERROR      Unexpected device behavior.

**/
EFI_STATUS
TisTpmCommand (
  IN     EFI_PEI_SERVICES           **PeiServices,
  IN     TIS_PC_REGISTERS_PTR       TisReg,
  IN     UINT8                      *BufferIn,
  IN     UINT32                     SizeIn,
  IN OUT UINT8                      *BufferOut,
  IN OUT UINT32                     *SizeOut
  )
{
  EFI_STATUS                        Status;
  UINT16                            BurstCount;
  UINT32                            Index;
  UINT32                            TpmOutSize;
  UINT16                            Data16;
  UINT32                            Data32;

  Status = TisPcPrepareCommand (TisReg);
  if (EFI_ERROR (Status)){
    DEBUG ((DEBUG_ERROR, "Tpm is not ready for command!\n"));
    return Status;
  }
  //
  // Send the command data to Tpm
  //
  Index = 0;
  while (Index < SizeIn) {
    Status = TisPcReadBurstCount (TisReg, &BurstCount);
    if (EFI_ERROR (Status)) {
      Status = EFI_TIMEOUT;
      goto Exit;
    }
    for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
      MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
      Index++;
    }
  }
  //
  // Check the Tpm status STS_EXPECT change from 1 to 0
  //
  Status = TisPcWaitRegisterBits (
             &TisReg->Status,
             (UINT8) TIS_PC_VALID,
             TIS_PC_STS_EXPECT,
             TIS_TIMEOUT_C
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "The send buffer too small!\n"));
    Status = EFI_BUFFER_TOO_SMALL;
    goto Exit;
  }
  //
  // Executed the TPM command and waiting for the response data ready
  //
  MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
  Status = TisPcWaitRegisterBits (
             &TisReg->Status,
             (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
             0,
             TIS_TIMEOUT_B
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Wait for Tpm response data time out!!\n"));
    Status = EFI_TIMEOUT;
    goto Exit;
  }
  //
  // Get response data header
  //
  Index = 0;
  BurstCount = 0;
  while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
    Status = TisPcReadBurstCount (TisReg, &BurstCount);
    if (EFI_ERROR (Status)) {
      Status = EFI_TIMEOUT;
      goto Exit;
    }
    for (; BurstCount > 0; BurstCount--) {
      *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
      Index++;
      if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break;
    }
  }
  //
  // Check the reponse data header (tag,parasize and returncode )
  //
  CopyMem (&Data16, BufferOut, sizeof (UINT16));
  if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND ) {
    Status = EFI_DEVICE_ERROR;
    goto Exit;
  }
  
  CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
  TpmOutSize  = SwapBytes32 (Data32);
  if (*SizeOut < TpmOutSize) {
    Status = EFI_BUFFER_TOO_SMALL;
    goto Exit;
  }
  *SizeOut = TpmOutSize;
  //
  // Continue reading the remaining data
  //
  while ( Index < TpmOutSize ) {
    for (; BurstCount > 0; BurstCount--) {
      *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
      Index++;
      if (Index == TpmOutSize) {
        Status = EFI_SUCCESS;
        goto Exit;
      }
    }
    Status = TisPcReadBurstCount (TisReg, &BurstCount);
    if (EFI_ERROR (Status)) {
      Status = EFI_TIMEOUT;
      goto Exit;
    }
  }
Exit:
  MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
  return Status;
}