/** Performs a bitwise OR of a 16-bit PCI configuration register with a 16-bit value and saves the value in the S3 script to be replayed on S3 resume. Reads the 16-bit PCI configuration register specified by Address, performs a bitwise OR between the read result and the value specified by OrData, and writes the result to the 16-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). @param Address Address that encodes the PCI Bus, Device, Function and Register. @param OrData The value to OR with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI S3PciOr16 ( IN UINTN Address, IN UINT16 OrData ) { return InternalSavePciWrite16ValueToBootScript (Address, PciOr16 (Address, OrData)); }
/** 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; }
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; }
/** 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; }