EFI_STATUS GetAllQncPmBase ( IN EFI_SMM_SYSTEM_TABLE2 *Smst ) /*++ Routine Description: Get QNC chipset LPC Power Management I/O Base at runtime. Arguments: Smst - The standard SMM system table. Returns: EFI_SUCCESS - Successfully init the device. Other - Error occured whening calling Dxe lib functions. --*/ { mAcpiSmm.QncPmBase = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_PM1BLK)) & B_QNC_LPC_PM1BLK_MASK; mAcpiSmm.QncGpe0Base = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_GPE0BLK)) & B_QNC_LPC_GPE0BLK_MASK; // // Quark does not support Changing Primary SoC IOBARs from what was // setup in SEC/PEI UEFI stages. // ASSERT (mAcpiSmm.QncPmBase == (UINT32) PcdGet16 (PcdPm1blkIoBaseAddress)); ASSERT (mAcpiSmm.QncGpe0Base == (UINT32) PcdGet16 (PcdGpe0blkIoBaseAddress)); return EFI_SUCCESS; }
VOID GetQncName ( VOID ) { DEBUG ((EFI_D_INFO, "QNC Name: ")); switch (PciRead16 (PCI_LIB_ADDRESS (MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET))) { case QUARK_MC_DEVICE_ID: DEBUG ((EFI_D_INFO, "Quark")); break; case QUARK2_MC_DEVICE_ID: DEBUG ((EFI_D_INFO, "Quark2")); break; default: DEBUG ((EFI_D_INFO, "Unknown")); } // // Revision // switch (PciRead8 (PCI_LIB_ADDRESS (MC_BUS, MC_DEV, MC_FUN, PCI_REVISION_ID_OFFSET))) { case QNC_MC_REV_ID_A0: DEBUG ((EFI_D_INFO, " - A0 stepping\n")); break; default: DEBUG ((EFI_D_INFO, " - xx\n")); } return; }
/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINTN Bus; UINTN Device; UINTN Function; UINTN EnableRegister; UINT8 EnableMask; // // ASSERT for the invalid PCD values. They must be configured to the real value. // ASSERT (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0xFFFF); ASSERT (PcdGet16 (PcdAcpiIoPortBaseAddress) != 0xFFFF); // // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then // no PCI register programming is required to enable access to the the ACPI registers // specified by PcdAcpiIoPortBaseAddress // if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) { return RETURN_SUCCESS; } // // ASSERT for the invalid PCD values. They must be configured to the real value. // ASSERT (PcdGet8 (PcdAcpiIoPciDeviceNumber) != 0xFF); ASSERT (PcdGet8 (PcdAcpiIoPciFunctionNumber) != 0xFF); ASSERT (PcdGet16 (PcdAcpiIoPciEnableRegisterOffset) != 0xFFFF); // // Retrieve the PCD values for the PCI configuration space required to program the ACPI I/O Port Base Address // Bus = PcdGet8 (PcdAcpiIoPciBusNumber); Device = PcdGet8 (PcdAcpiIoPciDeviceNumber); Function = PcdGet8 (PcdAcpiIoPciFunctionNumber); EnableRegister = PcdGet16 (PcdAcpiIoPciEnableRegisterOffset); EnableMask = PcdGet8 (PcdAcpiIoBarEnableMask); // // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. // if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister) & EnableMask) != EnableMask)) { PciWrite16 ( PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)), PcdGet16 (PcdAcpiIoPortBaseAddress) ); PciOr8 ( PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister), EnableMask ); } return RETURN_SUCCESS; }
EFI_STATUS EFIAPI PostPmInitCallBack ( IN EFI_EVENT Event, IN VOID *Context ) { UINT64 OriginalGTTMMADR; UINT32 LoGTBaseAddress; UINT32 HiGTBaseAddress; // // Enable Bus Master, I/O and Memory access on 0:2:0 // PciOr8 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_CMD), (BIT2 | BIT1)); // // only 32bit read/write is legal for device 0:2:0 // OriginalGTTMMADR = (UINT64) PciRead32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR)); OriginalGTTMMADR = LShiftU64 ((UINT64) PciRead32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR + 4)), 32) | (OriginalGTTMMADR); // // 64bit GTTMADR does not work for S3 save script table since it is executed in PEIM phase // Program temporarily 32bits GTTMMADR for POST and S3 resume // LoGTBaseAddress = (UINT32) (GTTMMADR & 0xFFFFFFFF); HiGTBaseAddress = (UINT32) RShiftU64 ((GTTMMADR & 0xFFFFFFFF00000000), 32); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR), LoGTBaseAddress); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR+4), HiGTBaseAddress); // // Restore original GTTMMADR // LoGTBaseAddress = (UINT32) (OriginalGTTMMADR & 0xFFFFFFFF); HiGTBaseAddress = (UINT32) RShiftU64 ((OriginalGTTMMADR & 0xFFFFFFFF00000000), 32); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR), LoGTBaseAddress); S3PciWrite32(PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_GTTMMADR+4), HiGTBaseAddress); // // Lock the following registers, GGC, BDSM, BGSM // PciOr32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_MGGC_OFFSET), LockBit); PciOr32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_BSM_OFFSET), LockBit); PciOr32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0,IGD_R_BGSM), LockBit); gBS->CloseEvent (Event); // // Return final status // return EFI_SUCCESS; }
/** Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS. @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format. @return PCI address with PCI_LIB_ADDRESS format. **/ UINTN PciCfgAddressConvert ( EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address ) { if (Address->ExtendedRegister == 0) { return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->Register); } return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->ExtendedRegister); }
/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI IntelQNCAcpiTimerLibConstructor ( VOID ) { if ((PciRead32 (PCI_LIB_ADDRESS (LPC_PCI_BUS, LPC_PCI_DEV, LPC_PCI_FUNC, R_LPC_PM1BLK)) & BIT31) == 0) { // // If ACPI I/O space is not enabled, program ACPI I/O base address and enable it. // PciWrite32 (PCI_LIB_ADDRESS (LPC_PCI_BUS, LPC_PCI_DEV, LPC_PCI_FUNC, R_LPC_PM1BLK), BIT31 | PcdGet16 (PcdPm1blkIoBaseAddress)); } return RETURN_SUCCESS; }
/** Internal function to retrieve the ACPI I/O Port Base Address. Internal function to retrieve the ACPI I/O Port Base Address. @return The 16-bit ACPI I/O Port Base Address. **/ UINT16 InternalAcpiGetAcpiTimerIoPort ( VOID ) { UINT16 Port; Port = PcdGet16 (PcdAcpiIoPortBaseAddress); // // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then // read the PCI register for the ACPI BAR value in case the BAR has been programmed to a // value other than PcdAcpiIoPortBaseAddress // if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0x0000) { Port = PciRead16 (PCI_LIB_ADDRESS ( PcdGet8 (PcdAcpiIoPciBusNumber), PcdGet8 (PcdAcpiIoPciDeviceNumber), PcdGet8 (PcdAcpiIoPciFunctionNumber), PcdGet16 (PcdAcpiIoPciBarRegisterOffset) )); } return (Port & PcdGet16 (PcdAcpiIoPortBaseAddressMask)) + PcdGet16 (PcdAcpiPm1TmrOffset); }
/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT8 u8Device = 7; UINT16 u16VendorID = 0; UINT16 u16DeviceID = 0; u16VendorID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 0)); u16DeviceID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 2)); if ( u16VendorID != 0x8086 || u16DeviceID != 0x7113) return RETURN_ABORTED; if (PciRead8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80)) & 1) { mPmba = PciRead32 (PCI_LIB_ADDRESS (0, u8Device, 0, 0x40)); ASSERT (mPmba & PCI_BAR_IO); DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); mPmba &= ~PCI_BAR_IO; DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); } else { PciAndThenOr32 (PCI_LIB_ADDRESS (0,u8Device,0,0x40), (UINT32) ~0xfc0, mPmba); PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x04), 0x01); DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); } // // ACPI Timer enable is in Bus 0, Device ?, Function 3 // PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80), 0x01); return RETURN_SUCCESS; }
VOID MiscInitialization ( VOID ) { // // Disable A20 Mask // IoOr8 (0x92, BIT1); // // Build the CPU hob with 36-bit addressing and 16-bits of IO space. // BuildCpuHob (36, 16); // // If PMREGMISC/PMIOSE is set, assume the ACPI PMBA has been configured (for // example by Xen) and skip the setup here. This matches the logic in // AcpiTimerLibConstructor (). // if ((PciRead8 (PCI_LIB_ADDRESS (0, 1, 3, 0x80)) & 0x01) == 0) { // // The PEI phase should be exited with fully accessibe PIIX4 IO space: // 1. set PMBA // PciAndThenOr32 ( PCI_LIB_ADDRESS (0, 1, 3, 0x40), (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress) ); // // 2. set PCICMD/IOSE // PciOr8 ( PCI_LIB_ADDRESS (0, 1, 3, PCI_COMMAND_OFFSET), EFI_PCI_COMMAND_IO_SPACE ); // // 3. set PMREGMISC/PMIOSE // PciOr8 (PCI_LIB_ADDRESS (0, 1, 3, 0x80), 0x01); } }
VOID AcpiInitialization ( VOID ) { // // Set ACPI SCI_EN bit in PMCNTRL // IoOr16 ((PciRead32 (PCI_LIB_ADDRESS (0, 1, 3, 0x40)) & ~BIT0) + 4, BIT0); }
VOID MiscInitialization () { // // Disable A20 Mask // IoOr8 (0x92, BIT1); // // Build the CPU hob with 36-bit addressing and 16-bits of IO space. // BuildCpuHob (36, 16); // // Set the PM I/O base address to 0x400 // PciAndThenOr32 (PCI_LIB_ADDRESS (0, 1, 3, 0x40), (UINT32) ~0xfc0, 0x400); }
/** This function scan PCI bus. @param VtdIndex VTd engine index @param Bus Pci bus @retval EFI_SUCCESS scan PCI bus successfully. **/ EFI_STATUS ScanPciBus ( IN UINTN VtdIndex, IN UINT8 Bus ) { UINT8 Device; UINT8 Function; UINT8 SecondaryBusNumber; UINT8 HeaderType; UINT8 BaseClass; UINT8 SubClass; UINT32 MaxFunction; UINT16 VendorID; UINT16 DeviceID; EFI_STATUS Status; // Scan the PCI bus for devices for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) { HeaderType = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, 0, PCI_HEADER_TYPE_OFFSET)); MaxFunction = PCI_MAX_FUNC + 1; if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) { MaxFunction = 1; } for (Function = 0; Function < MaxFunction; Function++) { VendorID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_VENDOR_ID_OFFSET)); DeviceID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_DEVICE_ID_OFFSET)); if (VendorID == 0xFFFF && DeviceID == 0xFFFF) { continue; } Status = RegisterPciDevice (VtdIndex, Bus, Device, Function, FALSE); if (EFI_ERROR (Status)) { return Status; } BaseClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2)); if (BaseClass == PCI_CLASS_BRIDGE) { SubClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1)); if (SubClass == PCI_CLASS_BRIDGE_P2P) { SecondaryBusNumber = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); DEBUG ((EFI_D_INFO," ScanPciBus: PCI bridge B%02x D%02x F%02x (SecondBus:%02x)\n", Bus, Device, Function, SecondaryBusNumber)); if (SecondaryBusNumber != 0) { ScanPciBus (VtdIndex, SecondaryBusNumber); } } } } } return EFI_SUCCESS; }
/** Save/Restore RootPort configuration space. @param[in] DeviceNode - The device node. @param[in] SaveAction - TRUE: Save, FALSE: Restore @param[in,out] PcieConfBufferList - Configuration space data buffer for save/restore @retval - PCIE base address of this RootPort **/ UINTN SaveRestoreRootportConfSpace ( IN OPAL_SMM_DEVICE *DeviceNode, IN BOOLEAN SaveAction, IN OUT UINT8 **PcieConfBufferList ) { UINTN RpBase; UINTN Length; PCI_DEVICE *DevNode; UINT8 *StorePcieConfData; UINTN Index; Length = 0; Index = 0; RpBase = 0; while (Length < DeviceNode->Length) { DevNode = (PCI_DEVICE *)((UINT8*)DeviceNode->PciBridgeNode + Length); RpBase = PCI_LIB_ADDRESS (DevNode->BusNum, DevNode->DevNum, DevNode->FuncNum, 0x0); if (PcieConfBufferList != NULL) { if (SaveAction) { StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE); ASSERT (StorePcieConfData != NULL); OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE); PcieConfBufferList[Index] = StorePcieConfData; } else { // Skip PCIe Command & Status registers StorePcieConfData = PcieConfBufferList[Index]; OpalPciWrite (RpBase, StorePcieConfData, 4); OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8); FreePool (StorePcieConfData); } } Length += sizeof (PCI_DEVICE); Index ++; } return RpBase; }
/** This notification function is invoked when an instance of the EFI_DEVICE_PATH_PROTOCOL is produced. @param Event The event that occured @param Context For EFI compatiblity. Not used. **/ VOID EFIAPI NotifyDevPath ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_HANDLE Handle; EFI_STATUS Status; UINTN BufferSize; EFI_DEVICE_PATH_PROTOCOL *DevPathNode; ATAPI_DEVICE_PATH *Atapi; // // Examine all new handles // for (;;) { // // Get the next handle // BufferSize = sizeof (Handle); Status = gBS->LocateHandle ( ByRegisterNotify, NULL, mEfiDevPathNotifyReg, &BufferSize, &Handle ); // // If not found, we're done // if (EFI_NOT_FOUND == Status) { break; } if (EFI_ERROR (Status)) { continue; } // // Get the DevicePath protocol on that handle // Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode); ASSERT_EFI_ERROR (Status); while (!IsDevicePathEnd (DevPathNode)) { // // Find the handler to dump this device path node // if ( (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP) ) { Atapi = (ATAPI_DEVICE_PATH*) DevPathNode; PciOr16 ( PCI_LIB_ADDRESS ( 0, 1, 1, (Atapi->PrimarySecondary == 1) ? 0x42: 0x40 ), BIT15 ); } // // Next device path node // DevPathNode = NextDevicePathNode (DevPathNode); } } return; }
/** Install the VBE Info and VBE Mode Info structures, and the VBE service handler routine in the C segment. Point the real-mode Int10h interrupt vector to the handler. The only advertised mode is 1024x768x32. @param[in] CardName Name of the video card to be exposed in the Product Name field of the VBE Info structure. The parameter must originate from a QEMU_VIDEO_CARD.Name field. @param[in] FrameBufferBase Guest-physical base address of the video card's frame buffer. **/ VOID InstallVbeShim ( IN CONST CHAR16 *CardName, IN EFI_PHYSICAL_ADDRESS FrameBufferBase ) { EFI_PHYSICAL_ADDRESS Segment0, SegmentC, SegmentF; UINTN Segment0Pages; IVT_ENTRY *Int0x10; EFI_STATUS Status; UINTN Pam1Address; UINT8 Pam1; UINTN SegmentCPages; VBE_INFO *VbeInfoFull; VBE_INFO_BASE *VbeInfo; UINT8 *Ptr; UINTN Printed; VBE_MODE_INFO *VbeModeInfo; Segment0 = 0x00000; SegmentC = 0xC0000; SegmentF = 0xF0000; // // Attempt to cover the real mode IVT with an allocation. This is a UEFI // driver, hence the arch protocols have been installed previously. Among // those, the CPU arch protocol has configured the IDT, so we can overwrite // the IVT used in real mode. // // The allocation request may fail, eg. if LegacyBiosDxe has already run. // Segment0Pages = 1; Int0x10 = (IVT_ENTRY *)(UINTN)Segment0 + 0x10; Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, Segment0Pages, &Segment0); if (EFI_ERROR (Status)) { EFI_PHYSICAL_ADDRESS Handler; // // Check if a video BIOS handler has been installed previously -- we // shouldn't override a real video BIOS with our shim, nor our own shim if // it's already present. // Handler = (Int0x10->Segment << 4) + Int0x10->Offset; if (Handler >= SegmentC && Handler < SegmentF) { DEBUG ((EFI_D_VERBOSE, "%a: Video BIOS handler found at %04x:%04x\n", __FUNCTION__, Int0x10->Segment, Int0x10->Offset)); return; } // // Otherwise we'll overwrite the Int10h vector, even though we may not own // the page at zero. // DEBUG ((EFI_D_VERBOSE, "%a: failed to allocate page at zero: %r\n", __FUNCTION__, Status)); } else { // // We managed to allocate the page at zero. SVN r14218 guarantees that it // is NUL-filled. // ASSERT (Int0x10->Segment == 0x0000); ASSERT (Int0x10->Offset == 0x0000); } // // Put the shim in place first. // Pam1Address = PCI_LIB_ADDRESS (0, 0, 0, 0x5A); // // low nibble covers 0xC0000 to 0xC3FFF // high nibble covers 0xC4000 to 0xC7FFF // bit1 in each nibble is Write Enable // bit0 in each nibble is Read Enable // Pam1 = PciRead8 (Pam1Address); PciWrite8 (Pam1Address, Pam1 | (BIT1 | BIT0)); // // We never added memory space durig PEI or DXE for the C segment, so we // don't need to (and can't) allocate from there. Also, guest operating // systems will see a hole in the UEFI memory map there. // SegmentCPages = 4; ASSERT (sizeof mVbeShim <= EFI_PAGES_TO_SIZE (SegmentCPages)); CopyMem ((VOID *)(UINTN)SegmentC, mVbeShim, sizeof mVbeShim); // // Fill in the VBE INFO structure. // VbeInfoFull = (VBE_INFO *)(UINTN)SegmentC; VbeInfo = &VbeInfoFull->Base; Ptr = VbeInfoFull->Buffer; CopyMem (VbeInfo->Signature, "VESA", 4); VbeInfo->VesaVersion = 0x0300; VbeInfo->OemNameAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); CopyMem (Ptr, "QEMU", 5); Ptr += 5; VbeInfo->Capabilities = BIT0; // DAC can be switched into 8-bit mode VbeInfo->ModeListAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); *(UINT16*)Ptr = 0x00f1; // mode number Ptr += 2; *(UINT16*)Ptr = 0xFFFF; // mode list terminator Ptr += 2; VbeInfo->VideoMem64K = (UINT16)((1024 * 768 * 4 + 65535) / 65536); VbeInfo->OemSoftwareVersion = 0x0000; VbeInfo->VendorNameAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); CopyMem (Ptr, "OVMF", 5); Ptr += 5; VbeInfo->ProductNameAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); Printed = AsciiSPrint ((CHAR8 *)Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer), "%s", CardName); Ptr += Printed + 1; VbeInfo->ProductRevAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr); CopyMem (Ptr, mProductRevision, sizeof mProductRevision); Ptr += sizeof mProductRevision; ASSERT (sizeof VbeInfoFull->Buffer >= Ptr - VbeInfoFull->Buffer); ZeroMem (Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer)); // // Fil in the VBE MODE INFO structure. // VbeModeInfo = (VBE_MODE_INFO *)(VbeInfoFull + 1); // // bit0: mode supported by present hardware configuration // bit1: optional information available (must be =1 for VBE v1.2+) // bit3: set if color, clear if monochrome // bit4: set if graphics mode, clear if text mode // bit5: mode is not VGA-compatible // bit7: linear framebuffer mode supported // VbeModeInfo->ModeAttr = BIT7 | BIT5 | BIT4 | BIT3 | BIT1 | BIT0; // // bit0: exists // bit1: bit1: readable // bit2: writeable // VbeModeInfo->WindowAAttr = BIT2 | BIT1 | BIT0; VbeModeInfo->WindowBAttr = 0x00; VbeModeInfo->WindowGranularityKB = 0x0040; VbeModeInfo->WindowSizeKB = 0x0040; VbeModeInfo->WindowAStartSegment = 0xA000; VbeModeInfo->WindowBStartSegment = 0x0000; VbeModeInfo->WindowPositioningAddress = 0x0000; VbeModeInfo->BytesPerScanLine = 1024 * 4; VbeModeInfo->Width = 1024; VbeModeInfo->Height = 768; VbeModeInfo->CharCellWidth = 8; VbeModeInfo->CharCellHeight = 16; VbeModeInfo->NumPlanes = 1; VbeModeInfo->BitsPerPixel = 32; VbeModeInfo->NumBanks = 1; VbeModeInfo->MemoryModel = 6; // direct color VbeModeInfo->BankSizeKB = 0; VbeModeInfo->NumImagePagesLessOne = 0; VbeModeInfo->Vbe3 = 0x01; VbeModeInfo->RedMaskSize = 8; VbeModeInfo->RedMaskPos = 16; VbeModeInfo->GreenMaskSize = 8; VbeModeInfo->GreenMaskPos = 8; VbeModeInfo->BlueMaskSize = 8; VbeModeInfo->BlueMaskPos = 0; VbeModeInfo->ReservedMaskSize = 8; VbeModeInfo->ReservedMaskPos = 24; // // bit1: Bytes in reserved field may be used by application // VbeModeInfo->DirectColorModeInfo = BIT1; VbeModeInfo->LfbAddress = (UINT32)FrameBufferBase; VbeModeInfo->OffScreenAddress = 0; VbeModeInfo->OffScreenSizeKB = 0; VbeModeInfo->BytesPerScanLineLinear = 1024 * 4; VbeModeInfo->NumImagesLessOneBanked = 0; VbeModeInfo->NumImagesLessOneLinear = 0; VbeModeInfo->RedMaskSizeLinear = 8; VbeModeInfo->RedMaskPosLinear = 16; VbeModeInfo->GreenMaskSizeLinear = 8; VbeModeInfo->GreenMaskPosLinear = 8; VbeModeInfo->BlueMaskSizeLinear = 8; VbeModeInfo->BlueMaskPosLinear = 0; VbeModeInfo->ReservedMaskSizeLinear = 8; VbeModeInfo->ReservedMaskPosLinear = 24; VbeModeInfo->MaxPixelClockHz = 0; ZeroMem (VbeModeInfo->Reserved, sizeof VbeModeInfo->Reserved); // // Clear Write Enable (bit1), keep Read Enable (bit0) set // PciWrite8 (Pam1Address, (Pam1 & ~BIT1) | BIT0); // // Second, point the Int10h vector at the shim. // Int0x10->Segment = SegmentC >> 4; Int0x10->Offset = (EFI_PHYSICAL_ADDRESS)(UINTN)(VbeModeInfo + 1) - SegmentC; DEBUG ((EFI_D_INFO, "%a: VBE shim installed\n", __FUNCTION__)); }
EFI_STATUS SaveRuntimeScriptTable ( IN EFI_SMM_SYSTEM_TABLE2 *Smst ) { EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; UINT32 Data32; UINT16 Data16; UINT8 Mask; UINTN Index; UINTN Offset; UINT16 DeviceId; // // Check what Soc we are running on (read Host bridge DeviceId) // DeviceId = QncGetSocDeviceId(); // // 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 (mPciCfgRegTable[Index] != PCI_DEVICE_END) { PciAddress.Bus = mPciCfgRegTable[Index++]; PciAddress.Device = mPciCfgRegTable[Index++]; PciAddress.Function = mPciCfgRegTable[Index++]; PciAddress.Register = 0; PciAddress.ExtendedRegister = 0; Data16 = PciRead16 (PCI_LIB_ADDRESS(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 (mPciCfgRegTable[Index + Offset / 32] & Mask) { PciAddress.Register = (UINT8) Offset; Data32 = PciRead32 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)); // // Save latest settings to runtime script table // S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)), 1, &Data32 ); } } Index += 8; } // // Save message bus registers // Index = 0; while (QNCS3SaveExtReg[Index] != 0xFF) { Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); // // Save IMR settings with IMR protection disabled initially // HMBOUND and IMRs will be locked just before jumping to the OS waking vector // if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) { if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) == QUARK_NC_MEMORY_MANAGER_IMRXL)) { Data32 &= ~IMR_LOCK; if (DeviceId == QUARK2_MC_DEVICE_ID) { Data32 &= ~IMR_EN; } } if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) >= QUARK_NC_MEMORY_MANAGER_IMRXRM)) { Data32 = (UINT32)IMRX_ALL_ACCESS; } } // // Save latest settings to runtime script table // S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), 1, &Data32 ); Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 1, &Data32 ); Index += 2; } Index = 0; while (QNCS3SaveExtReg[Index] != 0xFF) { // // Save IMR settings with IMR protection enabled (above script was to handle restoring all settings first - now we want to enable) // if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) { if (DeviceId == QUARK2_MC_DEVICE_ID) { if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) == QUARK_NC_MEMORY_MANAGER_IMRXL)) { Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); Data32 &= ~IMR_LOCK; // // Save latest settings to runtime script table // S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), 1, &Data32 ); Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 1, &Data32 ); } } else { if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) >= QUARK_NC_MEMORY_MANAGER_IMRXRM)) { Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); // // Save latest settings to runtime script table // S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), 1, &Data32 ); Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 1, &Data32 ); } } } Index += 2; } // Check if ECC scrub enabled and need re-enabling on resume // All scrub related configuration registers are saved on suspend // as part of QNCS3SaveExtReg configuration table script. // The code below extends the S3 resume script with scrub reactivation // message (if needed only) Data32 = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG); if( 0 != (Data32 & SCRUB_CFG_ACTIVE)) { Data32 = SCRUB_RESUME_MSG(); S3BootScriptSavePciCfgWrite ( S3BootScriptWidthUint32, PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), 1, &Data32 ); } // // Save I/O ports to S3 script table // // // Important to trap Sx for SMM // Data32 = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE); S3BootScriptSaveIoWrite(S3BootScriptWidthUint32, (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE), 1, &Data32); return EFI_SUCCESS; }
VOID PlatformInitQNCRegs ( VOID ) { // // All devices on bus 0. // Device 0: // FNC 0: Host Bridge // Device 20: // FNC 0: IOSF2AHB Bridge // Device 21: // FNC 0: IOSF2AHB Bridge // Device 23: // FNC 0: PCIe Port 0 // Device 24: // FNC 0: PCIe Port 1 // Device 31: // FNC 0: PCI-LPC Bridge // S3PciWrite32 (PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_QNC_LPC_FWH_BIOS_DEC), B_QNC_LPC_FWH_BIOS_DEC_F0 | B_QNC_LPC_FWH_BIOS_DEC_F8 | B_QNC_LPC_FWH_BIOS_DEC_E0 | B_QNC_LPC_FWH_BIOS_DEC_E8 | B_QNC_LPC_FWH_BIOS_DEC_D0 | B_QNC_LPC_FWH_BIOS_DEC_D8 | B_QNC_LPC_FWH_BIOS_DEC_C0 | B_QNC_LPC_FWH_BIOS_DEC_C8 ); // // Program SCI Interrupt for IRQ9 // S3PciWrite8 (PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_QNC_LPC_ACTL), V_QNC_LPC_ACTL_SCIS_IRQ9 ); // // Program Quark Interrupt Route Registers // S3MmioWrite16 ((UINTN)PcdGet64(PcdRcbaMmioBaseAddress) + R_QNC_RCRB_AGENT0IR, PcdGet16(PcdQuarkAgent0IR) ); S3MmioWrite16 ((UINTN)PcdGet64(PcdRcbaMmioBaseAddress) + R_QNC_RCRB_AGENT1IR, PcdGet16(PcdQuarkAgent1IR) ); S3MmioWrite16 ((UINTN)PcdGet64(PcdRcbaMmioBaseAddress) + R_QNC_RCRB_AGENT2IR, PcdGet16(PcdQuarkAgent2IR) ); S3MmioWrite16 ((UINTN)PcdGet64(PcdRcbaMmioBaseAddress) + R_QNC_RCRB_AGENT3IR, PcdGet16(PcdQuarkAgent3IR) ); // // Program SVID and SID for QNC PCI devices. In order to boost performance, we // combine two 16 bit PCI_WRITE into one 32 bit PCI_WRITE. The programmed LPC SVID // will reflect on all internal devices's SVID registers // S3PciWrite32 (PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_EFI_PCI_SVID), (UINT32)(V_INTEL_VENDOR_ID + (QUARK_V_LPC_DEVICE_ID_0 << 16)) ); // // Write once on Element Self Description Register before OS boot // QNCMmio32And (PcdGet64(PcdRcbaMmioBaseAddress), 0x04, 0xFF00FFFF); return; }
/** Finds the device path that should be used as the primary display adapter. @param VgaHandle - The handle of the video device **/ VOID GetSelectedVgaDeviceInfo ( OUT EFI_HANDLE *VgaHandle ) { EFI_STATUS Status; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE00 Pci; UINT8 MinBus; UINT8 MaxBus; UINTN Segment; UINTN Bus; UINTN Device; UINTN Function; UINTN SelectedAddress; UINTN CurrentAddress; // // Initialize return to 'not found' state // *VgaHandle = NULL; // // Initialize variable states. Ths is important for selecting the VGA device // if multiple devices exist behind a single bridge. // HandleCount = 0; HandleBuffer = NULL; SelectedAddress = PCI_LIB_ADDRESS(0xff, 0x1f, 0x7, 0); // // The bus range to search for a VGA device in. // MinBus = MaxBus = 0; // // Start to check all the pci io to find all possible VGA device // HandleCount = 0; HandleBuffer = NULL; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return; } for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID**)&PciIo); if (!EFI_ERROR (Status)) { // // Detemine if this is in the correct bus range. // Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function); if (EFI_ERROR(Status) || (Bus < MinBus || Bus > MaxBus)) { continue; } // // Read device information. // Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci ); if (EFI_ERROR (Status)) { continue; } // // Make sure the device is a VGA device. // if (!IS_PCI_VGA (&Pci)) { continue; } DEBUG ((EFI_D_INFO, "PCI VGA: 0x%04x:0x%04x\n", Pci.Hdr.VendorId, Pci.Hdr.DeviceId )); // // Currently we use the lowest numbered bus/device/function if multiple // devices are found in the target bus range. // CurrentAddress = PCI_LIB_ADDRESS(Bus, Device, Function, 0); if (CurrentAddress < SelectedAddress) { SelectedAddress = CurrentAddress; *VgaHandle = HandleBuffer[Index]; } } } FreePool (HandleBuffer); }
/** Performs any early platform specific GPIO Controller manipulation. **/ VOID EFIAPI EarlyPlatformGpioCtrlerManipulation ( VOID ) { UINT32 IohGpioBase; UINT32 Data32; UINT32 Addr; UINT32 DevPcieAddr; UINT16 SaveCmdReg; UINT32 SaveBarReg; UINT16 PciVid; UINT16 PciDid; IohGpioBase = (UINT32) PcdGet64 (PcdIohGpioMmioBase); DevPcieAddr = PCI_LIB_ADDRESS ( PcdGet8 (PcdIohGpioBusNumber), PcdGet8 (PcdIohGpioDevNumber), PcdGet8 (PcdIohGpioFunctionNumber), 0 ); // // Do nothing if not a supported device. // PciVid = PciRead16 (DevPcieAddr + PCI_VENDOR_ID_OFFSET); PciDid = PciRead16 (DevPcieAddr + PCI_DEVICE_ID_OFFSET); if((PciVid != V_IOH_I2C_GPIO_VENDOR_ID) || (PciDid != V_IOH_I2C_GPIO_DEVICE_ID)) { return; } // // Save current settings for PCI CMD/BAR registers. // SaveCmdReg = PciRead16 (DevPcieAddr + PCI_COMMAND_OFFSET); SaveBarReg = PciRead32 (DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister)); // // Use predefined tempory memory resource. // PciWrite32 ( DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister), IohGpioBase); PciWrite8 ( DevPcieAddr + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); // // Gpio Controller Manipulation Tasks. // // // Reset Cypress Expander on Galileo Platform // Addr = IohGpioBase + GPIO_SWPORTA_DR; Data32 = *((volatile UINT32 *) (UINTN)(Addr)); Data32 |= BIT4; // Cypress Reset line controlled by GPIO<4> *((volatile UINT32 *) (UINTN)(Addr)) = Data32; Data32 = *((volatile UINT32 *) (UINTN)(Addr)); Data32 &= ~BIT4; // Cypress Reset line controlled by GPIO<4> *((volatile UINT32 *) (UINTN)(Addr)) = Data32; // // Restore settings for PCI CMD/BAR registers // PciWrite32 ((DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister)), SaveBarReg); PciWrite16 (DevPcieAddr + PCI_COMMAND_OFFSET, SaveCmdReg); }
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; }
/** Extract device info from the input device path. @param[in] DevicePath Device path info for the device. @param[in,out] Dev The device which new inputed. **/ VOID ExtractDeviceInfoFromDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN OUT OPAL_SMM_DEVICE *Dev ) { EFI_DEVICE_PATH_PROTOCOL *TmpDevPath; EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2; PCI_DEVICE_PATH *PciDevPath; SATA_DEVICE_PATH *SataDevPath; NVME_NAMESPACE_DEVICE_PATH *NvmeDevPath; UINTN BusNum; TmpDevPath = DevicePath; Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN; while (!IsDevicePathEnd(TmpDevPath)) { if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) { // // SATA // SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath; Dev->SataPort = SataDevPath->HBAPortNumber; Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber; Dev->DeviceType = OPAL_DEVICE_TYPE_SATA; break; } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) { // // NVMe // NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath; Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId; Dev->DeviceType = OPAL_DEVICE_TYPE_NVME; break; } TmpDevPath = NextDevicePathNode (TmpDevPath); } // // Get bridge node info for the nvme device. // BusNum = 0; TmpDevPath = DevicePath; TmpDevPath2 = NextDevicePathNode (DevicePath); while (!IsDevicePathEnd(TmpDevPath2)) { if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) { PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath; if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)|| (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) { Dev->BusNum = (UINT32)BusNum; Dev->DevNum = PciDevPath->Device; Dev->FuncNum = PciDevPath->Function; } else { AddPciDeviceNode((UINT32)BusNum, PciDevPath->Device, PciDevPath->Function, Dev); if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) { BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, NVME_PCIE_SEC_BNUM)); } } } TmpDevPath = NextDevicePathNode (TmpDevPath); TmpDevPath2 = NextDevicePathNode (TmpDevPath2); } }
EFIAPI PciHostBridgeGetRootBridges ( UINTN *Count ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; UINT64 ExtraRootBridges; PCI_ROOT_BRIDGE *Bridges; UINTN Initialized; UINTN LastRootBridgeNumber; UINTN RootBridgeNumber; *Count = 0; // // QEMU provides the number of extra root buses, shortening the exhaustive // search below. If there is no hint, the feature is missing. // Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) { ExtraRootBridges = 0; } else { QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges); if (ExtraRootBridges > PCI_MAX_BUS) { DEBUG ((EFI_D_ERROR, "%a: invalid count of extra root buses (%Lu) " "reported by QEMU\n", __FUNCTION__, ExtraRootBridges)); return NULL; } DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n", __FUNCTION__, ExtraRootBridges)); } // // Allocate the "main" root bridge, and any extra root bridges. // Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges); if (Bridges == NULL) { DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES)); return NULL; } Initialized = 0; // // The "main" root bus is always there. // LastRootBridgeNumber = 0; // // Scan all other root buses. If function 0 of any device on a bus returns a // VendorId register value different from all-bits-one, then that bus is // alive. // for (RootBridgeNumber = 1; RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges; ++RootBridgeNumber) { UINTN Device; for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) { if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0, PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) { break; } } if (Device <= PCI_MAX_DEVICE) { // // Found the next root bus. We can now install the *previous* one, // because now we know how big a bus number range *that* one has, for any // subordinate buses that might exist behind PCI bridges hanging off it. // Status = InitRootBridge ((UINT8)LastRootBridgeNumber, (UINT8)(RootBridgeNumber - 1), &Bridges[Initialized]); if (EFI_ERROR (Status)) { goto FreeBridges; } ++Initialized; LastRootBridgeNumber = RootBridgeNumber; } } // // Install the last root bus (which might be the only, ie. main, root bus, if // we've found no extra root buses). // Status = InitRootBridge ((UINT8)LastRootBridgeNumber, PCI_MAX_BUS, &Bridges[Initialized]); if (EFI_ERROR (Status)) { goto FreeBridges; } ++Initialized; *Count = Initialized; return Bridges; FreeBridges: while (Initialized > 0) { --Initialized; UninitRootBridge (&Bridges[Initialized]); } FreePool (Bridges); return NULL; }
EFI_STATUS IgdPmHook ( IN EFI_HANDLE ImageHandle, IN DXE_VLV_PLATFORM_POLICY_PROTOCOL *DxePlatformSaPolicy ) { EFI_EVENT mConOutEvent; VOID *gConOutNotifyReg; EFI_STATUS Status; EFI_PHYSICAL_ADDRESS MemBaseAddress; UINT32 LoGTBaseAddress; UINT32 HiGTBaseAddress; GTTMMADR = 0; Status = EFI_SUCCESS; // // If device 0:2:0 (Internal Graphics Device, or GT) is enabled, then Program GTTMMADR, // if (PciRead16(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_VID)) != 0xFFFF) { ASSERT (gDS!=NULL); // // Enable Bus Master, I/O and Memory access on 0:2:0 // PciOr8(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_CMD), (BIT2 | BIT1 | BIT0)); // // Means Allocate 4MB for GTTMADDR // MemBaseAddress = 0x0ffffffff; Status = gDS->AllocateMemorySpace ( EfiGcdAllocateMaxAddressSearchBottomUp, EfiGcdMemoryTypeMemoryMappedIo, GTT_MEM_ALIGN, GTTMMADR_SIZE_4MB, &MemBaseAddress, ImageHandle, NULL ); ASSERT_EFI_ERROR (Status); // // Program GT PM Settings if GTTMMADR allocation is Successful // GTTMMADR = (UINTN) MemBaseAddress; LoGTBaseAddress = (UINT32) (MemBaseAddress & 0xFFFFFFFF); HiGTBaseAddress = (UINT32) RShiftU64 ((MemBaseAddress & 0xFFFFFFFF00000000), 32); PciWrite32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR), LoGTBaseAddress); PciWrite32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR+4), HiGTBaseAddress); S3PciRead32(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR)); S3MmioRead32(IGD_R_GTTMMADR + 4); S3PciRead8(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_CMD)); // // Do POST GT PM Init Steps after VBIOS Initialization in DoPostPmInitCallBack // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, (EFI_EVENT_NOTIFY)PostPmInitCallBack, NULL, &mConOutEvent ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } Status = gBS->RegisterProtocolNotify ( &gEfiGraphicsOutputProtocolGuid, mConOutEvent, &gConOutNotifyReg ); MmioWrite64 (IGD_R_GTTMMADR, 0); // // Free allocated resources // gDS->FreeMemorySpace ( MemBaseAddress, GTTMMADR_SIZE_4MB ); } return EFI_SUCCESS; }
/** Parse PCI bar and collect the assigned PCI resouce information. @param[in] Command Supported attributes. @param[in] Bus PCI bus number. @param[in] Device PCI device number. @param[in] Function PCI function number. @param[in] BarOffsetBase PCI bar start offset. @param[in] BarOffsetEnd PCI bar end offset. @param[in] Io IO aperture. @param[in] Mem MMIO aperture. @param[in] MemAbove4G MMIO aperture above 4G. @param[in] PMem Prefetchable MMIO aperture. @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. **/ STATIC VOID PcatPciRootBridgeParseBars ( IN UINT16 Command, IN UINTN Bus, IN UINTN Device, IN UINTN Function, IN UINTN BarOffsetBase, IN UINTN BarOffsetEnd, IN PCI_ROOT_BRIDGE_APERTURE *Io, IN PCI_ROOT_BRIDGE_APERTURE *Mem, IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, IN PCI_ROOT_BRIDGE_APERTURE *PMem, IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G ) { UINT32 OriginalValue; UINT32 Value; UINT32 OriginalUpperValue; UINT32 UpperValue; UINT64 Mask; UINTN Offset; UINTN LowBit; UINT64 Base; UINT64 Length; UINT64 Limit; PCI_ROOT_BRIDGE_APERTURE *MemAperture; for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) { PcatPciRootBridgeBarExisted ( PCI_LIB_ADDRESS (Bus, Device, Function, Offset), &OriginalValue, &Value ); if (Value == 0) { continue; } if ((Value & BIT0) == BIT0) { // // IO Bar // if (Command & EFI_PCI_COMMAND_IO_SPACE) { Mask = 0xfffffffc; Base = OriginalValue & Mask; Length = ((~(Value & Mask)) & Mask) + 0x04; if (!(Value & 0xFFFF0000)) { Length &= 0x0000FFFF; } Limit = Base + Length - 1; if ((Base > 0) && (Base < Limit)) { if (Io->Base > Base) { Io->Base = Base; } if (Io->Limit < Limit) { Io->Limit = Limit; } } } } else { // // Mem Bar // if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) { Mask = 0xfffffff0; Base = OriginalValue & Mask; Length = Value & Mask; if ((Value & (BIT1 | BIT2)) == 0) { // // 32bit // Length = ((~Length) + 1) & 0xffffffff; if ((Value & BIT3) == BIT3) { MemAperture = PMem; } else { MemAperture = Mem; } } else { // // 64bit // Offset += 4; PcatPciRootBridgeBarExisted ( PCI_LIB_ADDRESS (Bus, Device, Function, Offset), &OriginalUpperValue, &UpperValue ); Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32); Length = Length | LShiftU64 ((UINT64) UpperValue, 32); if (Length != 0) { LowBit = LowBitSet64 (Length); Length = LShiftU64 (1ULL, LowBit); } if ((Value & BIT3) == BIT3) { MemAperture = PMemAbove4G; } else { MemAperture = MemAbove4G; } } Limit = Base + Length - 1; if ((Base > 0) && (Base < Limit)) { if (MemAperture->Base > Base) { MemAperture->Base = Base; } if (MemAperture->Limit < Limit) { MemAperture->Limit = Limit; } } } } } }
/** Scan for all root bridges in platform. @param[out] NumberOfRootBridges Number of root bridges detected @retval Pointer to the allocated PCI_ROOT_BRIDGE structure array. **/ PCI_ROOT_BRIDGE * ScanForRootBridges ( OUT UINTN *NumberOfRootBridges ) { UINTN PrimaryBus; UINTN SubBus; UINT8 Device; UINT8 Function; UINTN NumberOfDevices; UINTN Address; PCI_TYPE01 Pci; UINT64 Attributes; UINT64 Base; UINT64 Limit; UINT64 Value; PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture; PCI_ROOT_BRIDGE *RootBridges; UINTN BarOffsetEnd; *NumberOfRootBridges = 0; RootBridges = NULL; // // After scanning all the PCI devices on the PCI root bridge's primary bus, // update the Primary Bus Number for the next PCI root bridge to be this PCI // root bridge's subordinate bus number + 1. // for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) { SubBus = PrimaryBus; Attributes = 0; Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64; Io.Limit = Mem.Limit = MemAbove4G.Limit = PMem.Limit = PMemAbove4G.Limit = 0; // // Scan all the PCI devices on the primary bus of the PCI root bridge // for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) { for (Function = 0; Function <= PCI_MAX_FUNC; Function++) { // // Compute the PCI configuration address of the PCI device to probe // Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0); // // Read the Vendor ID from the PCI Configuration Header // if (PciRead16 (Address) == MAX_UINT16) { if (Function == 0) { // // If the PCI Configuration Read fails, or a PCI device does not // exist, then skip this entire PCI device // break; } else { // // If PCI function != 0, VendorId == 0xFFFF, we continue to search // PCI function. // continue; } } // // Read the entire PCI Configuration Header // PciReadBuffer (Address, sizeof (Pci), &Pci); // // Increment the number of PCI device found on the primary bus of the // PCI root bridge // NumberOfDevices++; // // Look for devices with the VGA Palette Snoop enabled in the COMMAND // register of the PCI Config Header // if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) { Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; } BarOffsetEnd = 0; // // PCI-PCI Bridge // if (IS_PCI_BRIDGE (&Pci)) { // // Get the Bus range that the PPB is decoding // if (Pci.Bridge.SubordinateBus > SubBus) { // // If the suborinate bus number of the PCI-PCI bridge is greater // than the PCI root bridge's current subordinate bus number, // then update the PCI root bridge's subordinate bus number // SubBus = Pci.Bridge.SubordinateBus; } // // Get the I/O range that the PPB is decoding // Value = Pci.Bridge.IoBase & 0x0f; Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8; Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff; if (Value == BIT0) { Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16); Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16); } if ((Base > 0) && (Base < Limit)) { if (Io.Base > Base) { Io.Base = Base; } if (Io.Limit < Limit) { Io.Limit = Limit; } } // // Get the Memory range that the PPB is decoding // Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16; Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff; if ((Base > 0) && (Base < Limit)) { if (Mem.Base > Base) { Mem.Base = Base; } if (Mem.Limit < Limit) { Mem.Limit = Limit; } } // // Get the Prefetchable Memory range that the PPB is decoding // Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f; Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16; Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0) << 16) | 0xfffff; MemAperture = &PMem; if (Value == BIT0) { Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32); Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32); MemAperture = &PMemAbove4G; } if ((Base > 0) && (Base < Limit)) { if (MemAperture->Base > Base) { MemAperture->Base = Base; } if (MemAperture->Limit < Limit) { MemAperture->Limit = Limit; } } // // Look at the PPB Configuration for legacy decoding attributes // if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) == EFI_PCI_BRIDGE_CONTROL_ISA) { Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; } if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) == EFI_PCI_BRIDGE_CONTROL_VGA) { Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) { Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; } } BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]); } else { // // Parse the BARs of the PCI device to get what I/O Ranges, Memory // Ranges, and Prefetchable Memory Ranges the device is decoding // if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) { BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]); } } PcatPciRootBridgeParseBars ( Pci.Hdr.Command, PrimaryBus, Device, Function, OFFSET_OF (PCI_TYPE00, Device.Bar), BarOffsetEnd, &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G ); // // See if the PCI device is an IDE controller // if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_IDE)) { if (Pci.Hdr.ClassCode[0] & 0x80) { Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; } if (Pci.Hdr.ClassCode[0] & 0x01) { Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; } if (Pci.Hdr.ClassCode[0] & 0x04) { Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; } } // // See if the PCI device is a legacy VGA controller or // a standard VGA controller // if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) || IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA) ) { Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; } // // See if the PCI Device is a PCI - ISA or PCI - EISA // or ISA_POSITIVIE_DECODE Bridge device // if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) { if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA || Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA || Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) { Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; } } // // If this device is not a multi function device, then skip the rest // of this PCI device // if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { break; } } } // // If at least one PCI device was found on the primary bus of this PCI // root bridge, then the PCI root bridge exists. // if (NumberOfDevices > 0) { RootBridges = ReallocatePool ( (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE), (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE), RootBridges ); ASSERT (RootBridges != NULL); AdjustRootBridgeResource (&Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G); InitRootBridge ( Attributes, Attributes, 0, (UINT8) PrimaryBus, (UINT8) SubBus, &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G, &RootBridges[*NumberOfRootBridges] ); RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE; // // Increment the index for the next PCI Root Bridge // (*NumberOfRootBridges)++; } } return RootBridges; }
VOID PciInitialization ( ) { // // Bus 0, Device 0, Function 0 - Host to PCI Bridge // PciWrite8 (PCI_LIB_ADDRESS (0, 0, 0, 0x3c), 0x00); // // Bus 0, Device 1, Function 0 - PCI to ISA Bridge // PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x3c), 0x00); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // LNKA routing target PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // LNKB routing target PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // LNKC routing target PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // LNKD routing target // // Bus 0, Device 1, Function 1 - IDE Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x3c), 0x00); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x0d), 0x40); // // Bus 0, Device 1, Function 3 - Power Managment Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x09); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3d), 0x01); // INTA // // Bus 0, Device 2, Function 0 - Video Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x00); // // Bus 0, Device 3, Function 0 - Network Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0a); PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3d), 0x01); // INTA (-> LNKC) // // Bus 0, Device 5, Function 0 - RAM Memory // PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0b); PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3d), 0x01); // INTA (-> LNKA) }
/** Dispatch function for a Software SMI handler. @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). @param[in] RegisterContext Points to an optional handler context which was specified when the handler was registered. @param[in, out] CommBuffer A pointer to a collection of Data in memory that will be conveyed from a non-SMM environment into an SMM environment. @param[in, out] CommBufferSize The Size of the CommBuffer. @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers should still be called. @retval Others Other execution results. **/ EFI_STATUS EFIAPI SmmUnlockOpalPassword ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *RegisterContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize ) { EFI_STATUS Status; OPAL_SMM_DEVICE *OpalDev; LIST_ENTRY *Entry; UINT8 BaseClassCode; UINT8 SubClassCode; UINT8 ProgInt; TCG_RESULT Result; UINT8 SataCmdSt; UINT8 *StorePcieConfDataList[16]; UINTN RpBase; UINTN MemoryBase; UINTN MemoryLength; OPAL_SESSION Session; BOOLEAN BlockSidSupport; ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList)); Status = EFI_DEVICE_ERROR; // // try to unlock all locked hdd disks. // for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) { OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link); RpBase = 0; SataCmdSt = 0; /// /// Configure RootPort for PCIe AHCI/NVME devices. /// if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { /// /// Save original RootPort configuration space to heap /// RpBase = SaveRestoreRootportConfSpace ( OpalDev, TRUE, StorePcieConfDataList ); MemoryBase = mNvmeContext.Nbar; MemoryLength = 0; ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength); /// /// Enable PCIE decode for RootPort /// SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6); } else { SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD)); PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6); } BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B)); SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A)); ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09)); if (BaseClassCode != PCI_CLASS_MASS_STORAGE) { Status = EFI_INVALID_PARAMETER; break; } Status = EFI_DEVICE_ERROR; if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) { if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) { Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status)); goto done; } Status = AhciModeInitialize ((UINT8)OpalDev->SataPort); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status)); goto done; } } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n")); } } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { if (ProgInt != PCI_IF_NVMHCI) { DEBUG ((DEBUG_ERROR, "PI not support, skipped\n")); Status = EFI_NOT_FOUND; goto done; } mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0); mNvmeContext.NvmeInitWaitTime = 0; mNvmeContext.Nsid = OpalDev->NvmeNamespaceId; Status = NvmeControllerInit (&mNvmeContext); } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n")); } } else { DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n")); goto done; } Status = EFI_DEVICE_ERROR; BlockSidSupport = FALSE; if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) { ZeroMem(&Session, sizeof(Session)); Session.Sscp = &OpalDev->Sscp; Session.MediaId = 0; Session.OpalBaseComId = OpalDev->OpalBaseComId; Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL); if (Result == TcgResultSuccess) { Status = EFI_SUCCESS; } } if (mSendBlockSID && BlockSidSupport) { Result = OpalBlockSid (&Session, TRUE); if (Result != TcgResultSuccess) { break; } } if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { Status = NvmeControllerExit (&mNvmeContext); } } done: if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { ASSERT (RpBase != 0); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0); RpBase = SaveRestoreRootportConfSpace ( OpalDev, FALSE, // restore StorePcieConfDataList ); PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt); } else { PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt); } if (EFI_ERROR (Status)) { break; } } return Status; }
VOID PciInitialization ( ) { // // Bus 0, Device 0, Function 0 - Host to PCI Bridge // PciWrite8 (PCI_LIB_ADDRESS (0, 0, 0, 0x3c), 0x00); // // Bus 0, Device 1, Function 0 - PCI to ISA Bridge // PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x3c), 0x00); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x09); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0b); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x09); // // Bus 0, Device 1, Function 1 - IDE Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x3c), 0x00); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x0d), 0x40); // // Bus 0, Device 1, Function 3 - Power Managment Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x0b); PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3d), 0x01); // // Bus 0, Device 2, Function 0 - Video Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x00); // // Bus 0, Device 3, Function 0 - Network Controller // PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0b); PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3d), 0x01); // // Bus 0, Device 4, Function 0 - RAM Memory // PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3c), 0x09); PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3d), 0x01); }
// #define EHCI_OUT_THRESHOLD_VALUE (0x7f) #define EHCI_IN_THRESHOLD_VALUE (0x7f) // // Platform init USB device interrupt masks. // #define V_IOH_USBDEVICE_D_INTR_MSK_UDC_REG (0x0000007f) #define V_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG (B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_OUT_EP_MASK | B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_IN_EP_MASK) // // Global variables defined within this source module. // UINTN IohEhciPciReg[IOH_MAX_EHCI_USB_CONTROLLERS] = { PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, 0), }; UINTN IohUsbDevicePciReg[IOH_MAX_USBDEVICE_USB_CONTROLLERS] = { PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USBDEVICE_DEVICE_NUMBER, IOH_USBDEVICE_FUNCTION_NUMBER, 0), }; // // Routines local to this source module. // /** Perform USB erratas after MRC init. **/ VOID PlatformUsbErratasPostMrc (
/** The user code starts with this function. @param FileHandle Handle of the file being invoked. @param PeiServices Describes the list of possible PEI Services. @retval EFI_SUCCESS The driver is successfully initialized. @retval Others Can't initialize the driver. **/ EFI_STATUS EFIAPI InitializeSdMmcHcPeim ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_BOOT_MODE BootMode; EFI_STATUS Status; UINT16 Bus; UINT16 Device; UINT16 Function; UINT32 Size; UINT64 MmioSize; UINT8 SubClass; UINT8 BaseClass; UINT8 SlotInfo; UINT8 SlotNum; UINT8 FirstBar; UINT8 Index; UINT8 Slot; UINT32 BarAddr; SD_MMC_HC_PEI_PRIVATE_DATA *Private; // // Shadow this PEIM to run from memory // if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { return EFI_SUCCESS; } Status = PeiServicesGetBootMode (&BootMode); /// /// We do not expose this in S3 boot path, because it is only for recovery. /// if (BootMode == BOOT_ON_S3_RESUME) { return EFI_SUCCESS; } Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA)); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n")); return EFI_OUT_OF_RESOURCES; } Private->Signature = SD_MMC_HC_PEI_SIGNATURE; Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi; Private->PpiList = mPpiList; Private->PpiList.Ppi = &Private->SdMmcHostControllerPpi; BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase); for (Bus = 0; Bus < 256; Bus++) { for (Device = 0; Device < 32; Device++) { for (Function = 0; Function < 8; Function++) { SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A)); BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B)); if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) { // // Get the SD/MMC Pci host controller's Slot Info. // SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET)); FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar; SlotNum = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1; ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS); for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) { // // Get the SD/MMC Pci host controller's MMIO region size. // PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE)); PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF); Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot)); switch (Size & 0x07) { case 0x0: // // Memory space: anywhere in 32 bit address space // MmioSize = (~(Size & 0xFFFFFFF0)) + 1; break; case 0x4: // // Memory space: anywhere in 64 bit address space // MmioSize = Size & 0xFFFFFFF0; PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF); Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4)); // // Fix the length to support some spefic 64 bit BAR // Size |= ((UINT32)(-1) << HighBitSet32 (Size)); // // Calculate the size of 64bit bar // MmioSize |= LShiftU64 ((UINT64) Size, 32); MmioSize = (~(MmioSize)) + 1; // // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR. // PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0); break; default: // // Unknown BAR type // ASSERT (FALSE); continue; }; // // Assign resource to the SdMmc Pci host controller's MMIO BAR. // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register. // PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr); PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE)); // // Record the allocated Mmio base address. // Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++; Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr; BarAddr += (UINT32)MmioSize; } Private->TotalSdMmcHcs++; ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS); } } } } /// /// Install SdMmc Host Controller PPI /// Status = PeiServicesInstallPpi (&Private->PpiList); ASSERT_EFI_ERROR (Status); return Status; }