]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c
MdeModulePkg/SdMmc: Add EDKII SD/MMC stack
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SdMmcPciHcPei / SdMmcPciHcPei.c
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c
new file mode 100644 (file)
index 0000000..3f4ebc4
--- /dev/null
@@ -0,0 +1,212 @@
+/** @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