--- /dev/null
+/** @file\r
+ SdMmcPciHcPei driver is used to provide platform-dependent info, mainly SD/MMC\r
+ host controller MMIO base, to upper layer SD/MMC drivers.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcPei.h"\r
+\r
+EDKII_SD_MMC_HOST_CONTROLLER_PPI mSdMmcHostControllerPpi = { GetSdMmcHcMmioBar };\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEdkiiPeiSdMmcHostControllerPpiGuid,\r
+ &mSdMmcHostControllerPpi\r
+};\r
+\r
+/**\r
+ Get the MMIO base address of SD/MMC host controller.\r
+\r
+ @param[in] This The protocol instance pointer.\r
+ @param[in] ControllerId The ID of the SD/MMC host controller.\r
+ @param[in,out] MmioBar The pointer to store the array of available\r
+ SD/MMC host controller slot MMIO base addresses.\r
+ The entry number of the array is specified by BarNum.\r
+ @param[out] BarNum The pointer to store the supported bar number.\r
+\r
+ @retval EFI_SUCCESS The operation succeeds.\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetSdMmcHcMmioBar (\r
+ IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 ControllerId,\r
+ IN OUT UINTN **MmioBar,\r
+ OUT UINT8 *BarNum\r
+ )\r
+{\r
+ SD_MMC_HC_PEI_PRIVATE_DATA *Private;\r
+\r
+ if ((This == NULL) || (MmioBar == NULL) || (BarNum == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (ControllerId >= Private->TotalSdMmcHcs) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *MmioBar = &Private->MmioBar[ControllerId].MmioBarAddr[0];\r
+ *BarNum = (UINT8)Private->MmioBar[ControllerId].SlotNum;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The user code starts with this function.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS The driver is successfully initialized.\r
+ @retval Others Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdMmcHcPeim (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_BOOT_MODE BootMode;\r
+ EFI_STATUS Status;\r
+ UINT16 Bus;\r
+ UINT16 Device;\r
+ UINT16 Function;\r
+ UINT32 Size;\r
+ UINT64 MmioSize;\r
+ UINT8 SubClass;\r
+ UINT8 BaseClass;\r
+ UINT8 SlotInfo;\r
+ UINT8 SlotNum;\r
+ UINT8 FirstBar;\r
+ UINT8 Index;\r
+ UINT8 Slot;\r
+ UINT32 BarAddr;\r
+ SD_MMC_HC_PEI_PRIVATE_DATA *Private;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = PeiServicesGetBootMode (&BootMode);\r
+ ///\r
+ /// We do not expose this in S3 boot path, because it is only for recovery.\r
+ ///\r
+ if (BootMode == BOOT_ON_S3_RESUME) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Signature = SD_MMC_HC_PEI_SIGNATURE;\r
+ Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi;\r
+ Private->PpiList = mPpiList;\r
+ Private->PpiList.Ppi = &Private->SdMmcHostControllerPpi;\r
+\r
+ BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase);\r
+ for (Bus = 0; Bus < 256; Bus++) {\r
+ for (Device = 0; Device < 32; Device++) {\r
+ for (Function = 0; Function < 8; Function++) {\r
+ SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
+ BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
+\r
+ if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) {\r
+ //\r
+ // Get the SD/MMC Pci host controller's Slot Info.\r
+ //\r
+ SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET));\r
+ FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar;\r
+ SlotNum = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1;\r
+ ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS);\r
+\r
+ for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) {\r
+ //\r
+ // Get the SD/MMC Pci host controller's MMIO region size.\r
+ //\r
+ PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF);\r
+ Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot));\r
+\r
+ switch (Size & 0x07) {\r
+ case 0x0:\r
+ //\r
+ // Memory space: anywhere in 32 bit address space\r
+ //\r
+ MmioSize = (~(Size & 0xFFFFFFF0)) + 1;\r
+ break;\r
+ case 0x4:\r
+ //\r
+ // Memory space: anywhere in 64 bit address space\r
+ //\r
+ MmioSize = Size & 0xFFFFFFF0;\r
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);\r
+ Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4)); \r
+ //\r
+ // Fix the length to support some spefic 64 bit BAR\r
+ //\r
+ Size |= ((UINT32)(-1) << HighBitSet32 (Size));\r
+ //\r
+ // Calculate the size of 64bit bar\r
+ //\r
+ MmioSize |= LShiftU64 ((UINT64) Size, 32);\r
+ MmioSize = (~(MmioSize)) + 1;\r
+ //\r
+ // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR.\r
+ //\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0);\r
+ break;\r
+ default:\r
+ //\r
+ // Unknown BAR type\r
+ //\r
+ ASSERT (FALSE);\r
+ continue;\r
+ };\r
+ //\r
+ // Assign resource to the SdMmc Pci host controller's MMIO BAR.\r
+ // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register.\r
+ //\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr);\r
+ PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+ //\r
+ // Record the allocated Mmio base address.\r
+ //\r
+ Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++;\r
+ Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr;\r
+ BarAddr += (UINT32)MmioSize;\r
+ }\r
+ Private->TotalSdMmcHcs++;\r
+ ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ ///\r
+ /// Install SdMmc Host Controller PPI\r
+ ///\r
+ Status = PeiServicesInstallPpi (&Private->PpiList);\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r