/** Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value, followed a bitwise OR with another 16-bit value and saves the value in the S3 script to be replayed on S3 resume. Reads the 16-bit PCI configuration register specified by Address, performs a bitwise AND between the read result and the value specified by AndData, performs a bitwise OR between the result of the AND operation and the value specified by OrData, and writes the result to the 16-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). @param Address Address that encodes the PCI Bus, Device, Function and Register. @param AndData The value to AND with the PCI configuration register. @param OrData The value to OR with the result of the AND operation. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI S3PciAndThenOr16 ( IN UINTN Address, IN UINT16 AndData, IN UINT16 OrData ) { return InternalSavePciWrite16ValueToBootScript (Address, PciAndThenOr16 (Address, AndData, OrData)); }
/** This function performs a read-modify-write operation on the contents from a given location in the PCI configuration space. @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param This Pointer to local data for the interface. @param Width The width of the access. Enumerated in bytes. Type EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read(). @param Address The physical address of the access. @param SetBits Points to value to bitwise-OR with the read configuration value. The size of the value is determined by Width. @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value. The size of the value is determined by Width. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER The invalid access width. **/ EFI_STATUS EFIAPI PciCfg2Modify ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_PCI_CFG2_PPI *This, IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, IN UINT64 Address, IN VOID *SetBits, IN VOID *ClearBits ) { UINTN PciLibAddress; UINT16 ClearValue16; UINT16 SetValue16; UINT32 ClearValue32; UINT32 SetValue32; PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); if (Width == EfiPeiPciCfgWidthUint8) { PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); } else if (Width == EfiPeiPciCfgWidthUint16) { if ((PciLibAddress & 0x01) == 0) { // // Aligned Pci address access // ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits)); SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits); PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1)); } } else if (Width == EfiPeiPciCfgWidthUint32) { if ((PciLibAddress & 0x03) == 0) { // // Aligned Pci address access // ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits)); SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits); PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32); } else if ((PciLibAddress & 0x01) == 0) { // // Unaligned Pci address access, break up the request into word by word. // ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits)); SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits); PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16); ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1)); SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1); PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1)); PciAndThenOr8 (PciLibAddress + 2, (UINT8) (~(*((UINT8 *) ClearBits + 2))), *((UINT8 *) SetBits + 2)); PciAndThenOr8 (PciLibAddress + 3, (UINT8) (~(*((UINT8 *) ClearBits + 3))), *((UINT8 *) SetBits + 3)); } } else { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; }
EFI_STATUS EFIAPI SpiProtocolExecute ( 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: Execute SPI commands from the host controller. This function would be called by runtime driver, please do not use any MMIO marco here Arguments: This Pointer to the EFI_SPI_PROTOCOL instance. 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 Pointer to caller-allocated buffer containing the dada 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 Command succeed. EFI_INVALID_PARAMETER The parameters specified are not valid. EFI_UNSUPPORTED Command not supported. EFI_DEVICE_ERROR Device error, command aborts abnormally. --*/ { EFI_STATUS Status; UINT16 BiosCtlSave; UINT32 SmiEnSave; BiosCtlSave = 0; SmiEnSave = 0; // // Check if the parameters are valid. // if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) { return EFI_INVALID_PARAMETER; } // // Make sure it's safe to program the command. // if (!WaitForSpiCycleComplete (This, FALSE)) { return EFI_DEVICE_ERROR; } // // Acquire access to the SPI interface is not required any more. // // // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI // whose SMI handler accesses flash (e.g. for error logging) // SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN)); // // Save BIOS Ctrl register // BiosCtlSave = PciRead16 ( PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_QNC_LPC_BIOS_CNTL) ) & (B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP); // // Enable flash writing // PciOr16 ( PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_QNC_LPC_BIOS_CNTL), (UINT16) (B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP) ); // // If shifts the data out, disable Prefetching and Caching. // if (ShiftOut) { PciAndThenOr16 ( PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_QNC_LPC_BIOS_CNTL), (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE)), (UINT16) ((B_QNC_LPC_BIOS_CNTL_BCD)) ); } // // Sends the command to the SPI interface to execute. // Status = SendSpiCmd ( This, OpcodeIndex, PrefixOpcodeIndex, DataCycle, Atomic, ShiftOut, Address, DataByteCount, Buffer, SpiRegionType ); // // Restore BIOS Ctrl register // PciAndThenOr16 ( PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_QNC_LPC_BIOS_CNTL), (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)), (UINT16) (BiosCtlSave) ); // // Restore SMIs. // QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, SmiEnSave); return Status; }