VOID PlatformSsaInit ( IN SYSTEM_CONFIGURATION *SystemConfiguration, IN CONST EFI_PEI_SERVICES **PeiServices ) { DEBUG ((EFI_D_ERROR, "PlatformSsaInit() - Start\n")); DEBUG ((EFI_D_ERROR, "PlatformSsaInit() - SystemConfiguration->ISPDevSel 0x%x\n",SystemConfiguration->ISPDevSel)); if(SystemConfiguration->ISPDevSel == 0x02) { // // Device 3 Interrupt Route // MmioWrite16 ( (ILB_BASE_ADDRESS + R_PCH_ILB_D3IR), V_PCH_ILB_DXXIR_IAR_PIRQH // For IUNIT ); MmioRead16(ILB_BASE_ADDRESS + R_PCH_ILB_D3IR); // Read Posted Writes Register DEBUG ((EFI_D_ERROR, "PlatformSsaInit() - Device 3 Interrupt Route Done\n")); } // // Device 2 Interrupt Route // MmioWrite16 ( (ILB_BASE_ADDRESS + R_PCH_ILB_D2IR), V_PCH_ILB_DXXIR_IAR_PIRQA // For IGD ); MmioRead16(ILB_BASE_ADDRESS + R_PCH_ILB_D2IR); // Read Posted Writes Register DEBUG ((EFI_D_ERROR, "PlatformSsaInit() - Device 2 Interrupt Route Done\n")); return; }
/** Reads 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[out] 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 CpuMemoryServiceRead ( 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, OUT 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) { *Uint8Buffer = MmioRead8 ((UINTN)Address); } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { if (Aligned) { *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); } else { WriteUnaligned16 ((UINT16 *)Uint8Buffer, MmioRead16 ((UINTN)Address)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { if (Aligned) { *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); } else { WriteUnaligned32 ((UINT32 *)Uint8Buffer, MmioRead32 ((UINTN)Address)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint64) { if (Aligned) { *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address); } else { WriteUnaligned64 ((UINT64 *)Uint8Buffer, MmioRead64 ((UINTN)Address)); } } } return EFI_SUCCESS; }
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; }
EFIAPI MmioReadBuffer16 ( IN UINTN StartAddress, IN UINTN Length, OUT UINT16 *Buffer ) { UINT16 *ReturnBuffer; ASSERT ((StartAddress & (sizeof (UINT16) - 1)) == 0); ASSERT ((Length - 1) <= (MAX_ADDRESS - StartAddress)); ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN) Buffer)); ASSERT ((Length & (sizeof (UINT16) - 1)) == 0); ASSERT (((UINTN) Buffer & (sizeof (UINT16) - 1)) == 0); ReturnBuffer = Buffer; while (Length > 0) { *(Buffer++) = MmioRead16 (StartAddress); StartAddress += sizeof (UINT16); Length -= sizeof (UINT16); } return ReturnBuffer; }
BOOLEAN WaitForSpiCycleComplete ( IN EFI_SPI_PROTOCOL *This, IN BOOLEAN ErrorCheck ) /*++ Routine Description: Wait execution cycle to complete on the SPI interface. Check both Hardware and Software Sequencing status registers Arguments: This - The SPI protocol instance UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation ErrorCheck - TRUE if the SpiCycle needs to do the error check Returns: TRUE SPI cycle completed on the interface. FALSE Time out while waiting the SPI cycle to complete. It's not safe to program the next command on the SPI interface. --*/ { UINT64 WaitTicks; UINT64 WaitCount; UINT16 Data16; SPI_INSTANCE *SpiInstance; UINTN PchRootComplexBar; SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); PchRootComplexBar = SpiInstance->PchRootComplexBar; // // Convert the wait period allowed into to tick count // WaitCount = WAIT_TIME / WAIT_PERIOD; // // Wait for the SPI cycle to complete. // for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) { Data16 = MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS); if ((Data16 & B_QNC_RCRB_SPIS_SCIP) == 0) { MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIS, (B_QNC_RCRB_SPIS_BAS | B_QNC_RCRB_SPIS_CDS)); if ((Data16 & B_QNC_RCRB_SPIS_BAS) && (ErrorCheck == TRUE)) { return FALSE; } else { return TRUE; } } MicroSecondDelay (WAIT_PERIOD); } return FALSE; }
/** Reads a 16-bit PCI configuration register. Reads and returns the 16-bit PCI configuration register specified by Address. 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. @return The read value from the PCI configuration register. **/ UINT16 EFIAPI PciExpressRead16 ( IN UINTN Address ) { ASSERT_INVALID_PCI_ADDRESS (Address); return MmioRead16 ((UINTN) GetPciExpressBaseAddress () + Address); }
/** 16-bit memory read 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. @return A 16-bit value returned from the memory space. **/ UINT16 EFIAPI CpuMemRead16 ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_CPU_IO_PPI *This, IN UINT64 Address ) { return MmioRead16 ((UINTN)Address); }
BOOLEAN GetSleepTypeAfterWakeup ( IN CONST EFI_PEI_SERVICES **PeiServices, OUT UINT16 *SleepType ) { UINT16 Pm1Sts; UINT16 Pm1Cnt; UINT16 GenPmCon1; // // VLV BIOS Specification 0.6.2 - Section 18.4, "Power Failure Consideration" // // When the SUS_PWR_FLR bit is set, it indicates the SUS well power is lost. // This bit is in the SUS Well and defaults to 1’b1 based on RSMRST# assertion (not cleared by any type of reset). // System BIOS should follow cold boot path if SUS_PWR_FLR (PBASE + 0x20[14]), // GEN_RST_STS (PBASE + 0x20[9]) or PWRBTNOR_STS (ABASE + 0x00[11]) is set to 1’b1 // regardless of the value in the SLP_TYP (ABASE + 0x04[12:10]) field. // GenPmCon1 = MmioRead16 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1); // // Read the ACPI registers // Pm1Sts = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS); Pm1Cnt = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT); if ((GenPmCon1 & (B_PCH_PMC_GEN_PMCON_SUS_PWR_FLR | B_PCH_PMC_GEN_PMCON_GEN_RST_STS)) || (Pm1Sts & B_PCH_ACPI_PM1_STS_PRBTNOR)) { // // If power failure indicator, then don't attempt s3 resume. // Clear PM1_CNT of S3 and set it to S5 as we just had a power failure, and memory has // lost already. This is to make sure no one will use PM1_CNT to check for S3 after // power failure. // if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { Pm1Cnt = ((Pm1Cnt & ~B_PCH_ACPI_PM1_CNT_SLP_TYP) | V_PCH_ACPI_PM1_CNT_S5); IoWrite16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT, Pm1Cnt); } // // Clear Wake Status (WAK_STS) // } // // Get sleep type if a wake event occurred and there is no power failure // if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; return TRUE; } else if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S4) { *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; return TRUE; } return FALSE; }
// // Internal Functions // STATIC EFI_STATUS WaitForBusBusy ( VOID ) { UINTN Retry = 0; while (++Retry < MAX_RETRY && (MmioRead16(I2C_STAT) & BB) == 0x1); if (Retry == MAX_RETRY) { return EFI_TIMEOUT; } return EFI_SUCCESS; }
/** Reads a 16-bit I/O port. Reads the 16-bit I/O port specified by Port. The 16-bit read value is returned. This function must guarantee that all I/O read and write operations are serialized. @param Port The I/O port to read. @return The value read. **/ UINT16 EFIAPI IoRead16 ( IN UINT64 Port ) { UINT64 Address; // // Add the 64MB aligned IO Port space to the IO address // Address = MAP_PORT_BASE_TO_MEM (Port); Address += PcdGet64(PcdIoBlockBaseAddressForIpf); return MmioRead16 (Address); }
BOOLEAN GetSleepTypeAfterWakeup ( IN CONST EFI_PEI_SERVICES **PeiServices, OUT UINT16 *SleepType ) { UINT16 Pm1Sts; UINT16 Pm1Cnt; UINT16 GenPmCon1; GenPmCon1 = MmioRead16 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1); // // Read the ACPI registers // Pm1Sts = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS); Pm1Cnt = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT); if ((GenPmCon1 & (B_PCH_PMC_GEN_PMCON_SUS_PWR_FLR | B_PCH_PMC_GEN_PMCON_GEN_RST_STS)) || (Pm1Sts & B_PCH_ACPI_PM1_STS_PRBTNOR)) { // // If power failure indicator, then don't attempt s3 resume. // Clear PM1_CNT of S3 and set it to S5 as we just had a power failure, and memory has // lost already. This is to make sure no one will use PM1_CNT to check for S3 after // power failure. // if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { Pm1Cnt = ((Pm1Cnt & ~B_PCH_ACPI_PM1_CNT_SLP_TYP) | V_PCH_ACPI_PM1_CNT_S5); IoWrite16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT, Pm1Cnt); } // // Clear Wake Status (WAK_STS) // IoWrite16 ((ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS), B_PCH_ACPI_PM1_STS_WAK); } // // Get sleep type if a wake event occurred and there is no power failure // if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; return TRUE; } else if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S4){ *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; return TRUE; } return FALSE; }
/** Reads 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[out] 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 CpuIoServiceRead ( IN EFI_CPU_IO2_PROTOCOL *This, IN EFI_CPU_IO_PROTOCOL_WIDTH Width, IN UINT64 Address, IN UINTN Count, OUT VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; UINT8 *Uint8Buffer; 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 = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiCpuIoWidthUint8) { *Uint8Buffer = MmioRead8 ((UINTN)Address); } else if (OperationWidth == EfiCpuIoWidthUint16) { *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); } else if (OperationWidth == EfiCpuIoWidthUint32) { *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); } } return EFI_SUCCESS; }
STATIC EFI_STATUS PollForStatus( UINT16 StatusBit ) { UINTN Retry = 0; while(Retry < MAX_RETRY) { if (MmioRead16(I2C_STAT) & StatusBit) { //Clear particular status bit from Status register. MmioOr16(I2C_STAT, StatusBit); break; } Retry++; } if (Retry == MAX_RETRY) { return EFI_TIMEOUT; } return EFI_SUCCESS; }
/** Reads 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[out] 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 CpuMemoryServiceRead ( IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, IN EFI_SMM_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, OUT 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) { *Uint8Buffer = MmioRead8 ((UINTN)Address); } else if (Width == SMM_IO_UINT16) { *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); } else if (Width == SMM_IO_UINT32) { *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); } else if (Width == SMM_IO_UINT64) { *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address); } } return EFI_SUCCESS; }
/** Writes a Byte to I2C Device. @param I2cControllerIndex I2C Bus no to which the I2C device has been connected @param SlaveAddress Device Address from which the byte value has to be written @param Offset Offset from which the data has to be read @param *Byte Address to which the value written is stored @param Start Whether a RESTART is issued before the byte is sent or received @param End Whether STOP is generated after a data byte is sent or received @return EFI_SUCCESS IF the byte value has been successfully written @return EFI_DEVICE_ERROR Operation Failed, Device Error **/ EFI_STATUS ByteWriteI2CBasic( IN UINT8 I2cControllerIndex, IN UINT8 SlaveAddress, IN UINTN WriteBytes, IN UINT8 *WriteBuffer, IN UINT8 Start, IN UINT8 End ) { EFI_STATUS Status; UINT32 I2cStatus; UINT8 *TransmitEnd; UINT16 RawIntrStat; UINT32 Count=0; Status = EFI_SUCCESS; Status=I2CInit(I2cControllerIndex, SlaveAddress); if(Status!=EFI_SUCCESS) return Status; TransmitEnd = &WriteBuffer[WriteBytes]; if( WriteBytes ) { DEBUG((EFI_D_INFO,"Write: --------------%d bytes to TX\r\n",TransmitEnd - WriteBuffer)); while (TransmitEnd > WriteBuffer) { I2cStatus = MmioRead32 (mI2CBaseAddress + R_IC_STATUS); RawIntrStat = (UINT16)MmioRead32 (mI2CBaseAddress + R_IC_RawIntrStat); if (0 != ( RawIntrStat & I2C_INTR_TX_ABRT)) { MmioRead32 ( mI2CBaseAddress + R_IC_CLR_TX_ABRT); Status = RETURN_DEVICE_ERROR; DEBUG((EFI_D_ERROR,"TX ABRT TransmitEnd:0x%x WriteBuffer:0x%x\r\n", TransmitEnd, WriteBuffer)); break; } if (0 == (I2cStatus & STAT_TFNF)) { // // If TX not full , will send cmd or continue to wait // MicroSecondDelay (FIFO_WRITE_DELAY); continue; } if(End && Start) { MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_RESTART|B_CMD_STOP); } else if (!End && Start) { MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_RESTART); } else if (End && !Start) { MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_STOP); } else if (!End && !Start ) { MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)); } // // Add a small delay to work around some odd behavior being seen. Without this delay bytes get dropped. // MicroSecondDelay ( FIFO_WRITE_DELAY );//wait after send cmd // // Time out // while(1) { RawIntrStat = MmioRead16 ( mI2CBaseAddress + R_IC_RawIntrStat ); if (0 != ( RawIntrStat & I2C_INTR_TX_ABRT)) { MmioRead16 (mI2CBaseAddress + R_IC_CLR_TX_ABRT); Status = RETURN_DEVICE_ERROR; DEBUG((EFI_D_ERROR,"TX ABRT TransmitEnd:0x%x WriteBuffer:0x%x\r\n", TransmitEnd, WriteBuffer)); } if(0 == MmioRead16(mI2CBaseAddress + R_IC_TXFLR)) break; MicroSecondDelay (FIFO_WRITE_DELAY); Count++; if(Count<1024) { // // to avoid sys hung without ul-pmc device on RVP. // Waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE. // continue; } else { break; } }//while( 1 ) } } return Status; }
EFI_STATUS EFIAPI SpiProtocolLock ( IN EFI_SPI_PROTOCOL *This ) /*++ Routine Description: Lock the SPI Static Configuration Interface. Once locked, the interface can not be changed and can only be clear by system reset. Arguments: This Pointer to the EFI_SPI_PROTOCOL instance. Returns: EFI_SUCCESS Lock operation succeed. EFI_DEVICE_ERROR Device error, operation failed. EFI_ACCESS_DENIED The interface has already been locked. --*/ { SPI_INSTANCE *SpiInstance; UINTN PchRootComplexBar; SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); PchRootComplexBar = SpiInstance->PchRootComplexBar; // // Check if the SPI interface has been locked-down. // if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) { return EFI_ACCESS_DENIED; } // // Lock-down the configuration interface. // MmioOr16 ((UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), (UINT16) (B_QNC_RCRB_SPIS_SCL)); // // Verify if it's really locked. // if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) == 0) { return EFI_DEVICE_ERROR; } else { // // Save updated register in S3 Boot script. // S3BootScriptSaveMemWrite ( S3BootScriptWidthUint16, (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), 1, (VOID *) (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS) ); } 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; }
EFI_STATUS RtcPowerFailureHandler ( IN CONST EFI_PEI_SERVICES **PeiServices ) { UINT16 DataUint16; UINT8 DataUint8; BOOLEAN RtcUipIsAlwaysSet; DataUint16 = MmioRead16 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1); RtcUipIsAlwaysSet = IsRtcUipAlwaysSet (PeiServices); if ((DataUint16 & B_PCH_PMC_GEN_PMCON_RTC_PWR_STS) || (RtcUipIsAlwaysSet)) { // // Execute the sequence below. This will ensure that the RTC state machine has been initialized. // // Step 1. // BIOS clears this bit by writing a '0' to it. // if (DataUint16 & B_PCH_PMC_GEN_PMCON_RTC_PWR_STS) { // // Set to invalid date in order to reset the time to // BIOS build time later in the boot (SBRUN.c file). // IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_YEAR); IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_MONTH); IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_DAYOFMONTH); IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_DAYOFWEEK); IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_SECONDSALARM); IoWrite8 (R_PCH_RTC_TARGET2, 0x00); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_MINUTESALARM); IoWrite8 (R_PCH_RTC_TARGET2, 0x00); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_HOURSALARM); IoWrite8 (R_PCH_RTC_TARGET2, 0x00); } // // Step 2. // Set RTC Register 0Ah[6:4] to '110' or '111'. // IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERA); IoWrite8 (R_PCH_RTC_TARGET2, (V_PCH_RTC_REGISTERA_DV_DIV_RST1 | V_PCH_RTC_REGISTERA_RS_976P5US)); // // Step 3. // Set RTC Register 0Bh[7]. // IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB); DataUint8 = (IoRead8 (R_PCH_RTC_TARGET2) | B_PCH_RTC_REGISTERB_SET); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB); IoWrite8 (R_PCH_RTC_TARGET2, DataUint8); // // Step 4. // Set RTC Register 0Ah[6:4] to '010'. // IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERA); IoWrite8 (R_PCH_RTC_TARGET2, (V_PCH_RTC_REGISTERA_DV_NORM_OP | V_PCH_RTC_REGISTERA_RS_976P5US)); // // Step 5. // Clear RTC Register 0Bh[7]. // IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB); DataUint8 = (IoRead8 (R_PCH_RTC_TARGET2) & (UINT8)~B_PCH_RTC_REGISTERB_SET); IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB); IoWrite8 (R_PCH_RTC_TARGET2, DataUint8); } 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 SaveRuntimeScriptTable ( VOID ) { SMM_PCI_IO_ADDRESS PciAddress; UINT32 Data32; UINT16 Data16; UINT8 Data8; UINT8 Mask; UINTN Index; UINTN Offset; UINT8 RegTable[] = { // //Bus , Dev, Func, DMI // 0x00 , 0x00, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x00 , 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0xa0, // //Bus , Dev, Func, LPC device // 0x00 , 0x1F, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x00 , 0x08, 0x00, 0x07, 0x00, 0x00, 0x90, 0x00, // //Bus , Dev, Func, PCIE device // 0x00 , 0x1C, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0xC0 , 0x83, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, PCIE device // 0x00 , 0x1C, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x03 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, SATA device // 0x00 , 0x13, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0xf4 , 0xab, 0x27, 0x10, 0xf1, 0x1d, 0x00, 0x40, // //Bus , Dev, Func, EHCI device // 0x00 , 0x1D, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x10 , 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // //Bus , Dev, Func, SMBUS device // 0x00 , 0x1f, 0x03, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x10 , 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, SMBUS device // 0x00 , 0x1f, 0x03, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x02 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, VGA bus1 // 0x01 , 0x00, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x58 , 0x81, 0x18, 0x01, 0xb0, 0x00, 0x00, 0x00, // //Bus , Dev, Func, VGA bus1 // 0x01 , 0x00, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x02 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, VGA bus1 function 1 // 0x01 , 0x00, 0x01, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x51 , 0x80, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, VGA bus1 function 1 // 0x01 , 0x00, 0x01, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x02 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, IGD bus0 function 0 // 0x00 , 0x02, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x42 , 0x81, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, // //Bus , Dev, Func, USB bus0 function 0 // 0x00 , 0x16, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x32 , 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // //Bus , Dev, Func, HD Audio bus0 function 0 // 0x00 , 0x1B, 0x00, // //00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF // 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, // //0xFF indicates the end of the table // 0xFF }; // // These registers have to set in byte order // UINT8 ExtReg[] = { 0x9E, 0x9D }; // SMRAM settings // // Save PCI-Host bridge settings (0, 0, 0). 0x90, 94 and 9c are changed by CSM // and vital to S3 resume. That's why we put save code here // PciAddress.Bus = 0; PciAddress.Device = 0; PciAddress.Function = 0; PciAddress.ExtendedRegister = 0; for (Index = 0; Index < 2; Index++) { // // Read SRAM setting from Pci(0, 0, 0) // PciAddress.Register = ExtReg[Index]; Data8 = MmioRead8 ( MmPciAddress (0, PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register ) ); // // Save latest settings to runtime script table // S3BootScriptSavePciCfgWrite( S3BootScriptWidthUint8, *(UINT64*)&PciAddress, 1, &Data8 ); } // // Save PCI-Host bridge settings (0, 0, 0). 0x90, 94 and 9c are changed by CSM // and vital to S3 resume. That's why we put save code here // Index = 0; while (RegTable[Index] != 0xFF) { PciAddress.Bus = RegTable[Index++]; PciAddress.Device = RegTable[Index++]; PciAddress.Function = RegTable[Index++]; PciAddress.Register = 0; PciAddress.ExtendedRegister = 0; Data16 = MmioRead16 ( MmPciAddress (0, PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register ) ); if (Data16 == 0xFFFF) { Index+=8; continue; } for (Offset = 0, Mask = 0x01; Offset < 256; Offset+=4, Mask<<=1) { if (Mask == 0x00) { Mask = 0x01; } if (RegTable[Index + Offset/32] & Mask ) { PciAddress.Register = (UINT8)Offset; Data32 = MmioRead32 (MmPciAddress (0, PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)); // // Save latest settings to runtime script table // S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, *(UINT64*)&PciAddress, 1, &Data32 ); } } Index += 8; } // // Save I/O ports to S3 script table // // // Selftest KBC // Data8 = 0xAA; S3BootScriptSaveIoWrite ( S3BootScriptWidthUint8, 0x64, (UINTN)1, &Data8 ); Data32 = IoRead32(mAcpiBaseAddr + R_PCH_SMI_EN); S3BootScriptSaveIoWrite ( S3BootScriptWidthUint32, (mAcpiBaseAddr + R_PCH_SMI_EN), 1, &Data32 ); // // Save B_ICH_TCO_CNT_LOCK so it will be done on S3 resume path. // Data16 = IoRead16(mAcpiBaseAddr + R_PCH_TCO_CNT); S3BootScriptSaveIoWrite ( S3BootScriptWidthUint16, mAcpiBaseAddr + R_PCH_TCO_CNT, 1, &Data16 ); return EFI_SUCCESS; }
/** Do any final initialization on SATA controller @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance @param[in] IsSetS3BootScript Is this function called for S3 boot script save @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS ConfigureSataAtBoot ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN BOOLEAN IsSetS3BootScript ) { UINT8 Index; UINT32 AhciBar; UINTN PciD19F0RegBase; UINT16 SataModeSelect; UINT32 PxSctlDet; UINT32 PxCmdSud; UINT32 OrgCmdWord; UINT32 Data32And; UINT32 Data32Or; DEBUG ((EFI_D_INFO, "ConfigureSataAtBoot() Start\n")); // // eSATA port support only up to Gen2 // PciD19F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_SATA, PCI_FUNCTION_NUMBER_PCH_SATA, 0); // // Make sure SATA device exists. // if (MmioRead16 (PciD19F0RegBase + R_PCH_SATA_ID) != 0xFFFF) { SataModeSelect = MmioRead16 (PciD19F0RegBase + R_PCH_SATA_MAP) & B_PCH_SATA_MAP_SMS_MASK; if ((SataModeSelect == V_PCH_SATA_MAP_SMS_AHCI) || (SataModeSelect == V_PCH_SATA_MAP_SMS_RAID)) { AhciBar = MmioRead32 (PciD19F0RegBase + R_PCH_SATA_ABAR) & B_PCH_SATA_ABAR_BA; // // Make sure the AhciBar is valid. // if ((AhciBar != 0x00000000) && (AhciBar != B_PCH_SATA_ABAR_BA)) { // // Keep original CMD word, and enable MSE // OrgCmdWord = MmioRead32 (PciD19F0RegBase + R_PCH_SATA_COMMAND); if ((OrgCmdWord & B_PCH_SATA_COMMAND_MSE) == 0) { Data32And = (UINT32) 0xFFFFFFFF; Data32Or = (UINT32) B_PCH_SATA_COMMAND_MSE; if (!IsSetS3BootScript) { MmioOr32 ((PciD19F0RegBase + R_PCH_SATA_COMMAND), Data32Or); } else { // // Set S3 Boot Script // S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (PciD19F0RegBase + R_PCH_SATA_COMMAND), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); } } for (Index = 0; Index < PCH_AHCI_MAX_PORTS; Index++) { if (PchPlatformPolicy->SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE) { PxSctlDet = MmioRead32(AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))) & B_PCH_SATA_AHCI_PXSCTL_DET; PxCmdSud = MmioRead32(AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))) & B_PCH_SATA_AHCI_PxCMD_SUD; // // Limit speed to Gen2 // Data32And = (UINT32)~(B_PCH_SATA_AHCI_PXSCTL_SPD); Data32Or = (UINT32) V_PCH_SATA_AHCI_PXSCTL_SPD_2; if (!IsSetS3BootScript) { MmioAndThenOr32 ( (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), Data32And, Data32Or ); } else { // // Set S3 Boot Script // S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); } // // If port is not offline, and it's spin up, need to port reset. // After port reset, clear the SERR. // - Set DET=1, and then set DET=0. // - Finally, set FRE=1. // if ((PxSctlDet == V_PCH_SATA_AHCI_PXSCTL_DET_0) && (PxCmdSud == B_PCH_SATA_AHCI_PxCMD_SUD)) { if (!IsSetS3BootScript) { MmioOr32 (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), V_PCH_SATA_AHCI_PXSCTL_DET_1); PchPmTimerStall (1000); MmioAnd32(AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), (UINT32) ~(B_PCH_SATA_AHCI_PXSCTL_DET)); MmioWrite32 (AhciBar + (R_PCH_SATA_AHCI_P0SERR + (0x80 * Index)), (UINT32)~0u); MmioOr32 (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index)), B_PCH_SATA_AHCI_PxCMD_FRE); } else { // // Set S3 Boot Script // Data32And = (UINT32) 0xFFFFFFFF; Data32Or = (UINT32) V_PCH_SATA_AHCI_PXSCTL_DET_1; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); S3BootScriptSaveStall (1000); Data32And = (UINT32) ~(B_PCH_SATA_AHCI_PXSCTL_DET); Data32Or = (UINT32) 0x00000000; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); Data32And = (UINT32) 0xFFFFFFFF; Data32Or = (UINT32) 0xFFFFFFFF; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SERR + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); Data32And = (UINT32) 0xFFFFFFFF; Data32Or = (UINT32) B_PCH_SATA_AHCI_PxCMD_FRE; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); } } // // If port is offline, and it's not spin up, meets the power bug. // Need to do the W/A to spin up the port and then spin down. // Then entering back to offline and listen. // - Set DET=0, SUD=1, and then set SUD=0, DET=4. // if ((PxSctlDet == V_PCH_SATA_AHCI_PXSCTL_DET_4) && (PxCmdSud == 0)) { if (!IsSetS3BootScript) { MmioAnd32(AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), (UINT32) ~(B_PCH_SATA_AHCI_PXSCTL_DET)); MmioOr32 (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index)), B_PCH_SATA_AHCI_PxCMD_SUD); PchPmTimerStall (1000); MmioAnd32(AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index)), (UINT32) ~(B_PCH_SATA_AHCI_PxCMD_SUD)); MmioOr32 (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), V_PCH_SATA_AHCI_PXSCTL_DET_4); } else { // // Set S3 Boot Script // Data32And = (UINT32) ~(B_PCH_SATA_AHCI_PXSCTL_DET); Data32Or = (UINT32) 0x00000000; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); Data32And = (UINT32) 0xFFFFFFFF; Data32Or = (UINT32) B_PCH_SATA_AHCI_PxCMD_SUD; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); S3BootScriptSaveStall (1000); Data32And = (UINT32) ~(B_PCH_SATA_AHCI_PxCMD_SUD); Data32Or = (UINT32) 0x00000000; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); Data32And = (UINT32) 0xFFFFFFFF; Data32Or = (UINT32) V_PCH_SATA_AHCI_PXSCTL_DET_4; S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); } } } } // // Restore original CMD word. // if ((OrgCmdWord & B_PCH_SATA_COMMAND_MSE) == 0) { Data32And = (UINT32) 0xFFFFFFFF; Data32Or = (UINT32) OrgCmdWord; if (!IsSetS3BootScript) { MmioWrite32 ((PciD19F0RegBase + R_PCH_SATA_COMMAND), Data32Or); } else { S3BootScriptSaveMemReadWrite ( EfiBootScriptWidthUint32, (UINTN) (PciD19F0RegBase + R_PCH_SATA_COMMAND), &Data32Or, /// Data to be ORed &Data32And /// Data to be ANDed ); } } } // AhciBar is vaild } // SATA mode is AHCI or RAID } // if D19F0 is existed DEBUG ((EFI_D_INFO, "ConfigureSataAtBoot() End\n")); return EFI_SUCCESS; }