/** 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; }
/** 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; }
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 ); } }
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; }
/** 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); }
/** 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); }
/** 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; }
/** 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); }
/** 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); }
STATIC VOID EFIAPI PL061SetPins ( IN UINTN Address, IN UINTN Mask, IN UINTN Value ) { MmioWrite8 (PL061EffectiveAddress (Address, Mask), Value); }
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; }
/** 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); }
/** 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; }
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); }
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; }
/** 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; }
/** 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; }
/** 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; }
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; }
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; }
/** 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; }