Home | History | Annotate | Download | only in SdMmcPciHcPei
      1 /** @file
      2   SdMmcPciHcPei driver is used to provide platform-dependent info, mainly SD/MMC
      3   host controller MMIO base, to upper layer SD/MMC drivers.
      4 
      5   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "SdMmcPciHcPei.h"
     17 
     18 EDKII_SD_MMC_HOST_CONTROLLER_PPI  mSdMmcHostControllerPpi = { GetSdMmcHcMmioBar };
     19 
     20 EFI_PEI_PPI_DESCRIPTOR   mPpiList = {
     21   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     22   &gEdkiiPeiSdMmcHostControllerPpiGuid,
     23   &mSdMmcHostControllerPpi
     24 };
     25 
     26 /**
     27   Get the MMIO base address of SD/MMC host controller.
     28 
     29   @param[in]     This            The protocol instance pointer.
     30   @param[in]     ControllerId    The ID of the SD/MMC host controller.
     31   @param[in,out] MmioBar         The pointer to store the array of available
     32                                  SD/MMC host controller slot MMIO base addresses.
     33                                  The entry number of the array is specified by BarNum.
     34   @param[out]    BarNum          The pointer to store the supported bar number.
     35 
     36   @retval EFI_SUCCESS            The operation succeeds.
     37   @retval EFI_INVALID_PARAMETER  The parameters are invalid.
     38 
     39 **/
     40 EFI_STATUS
     41 EFIAPI
     42 GetSdMmcHcMmioBar (
     43   IN     EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,
     44   IN     UINT8                            ControllerId,
     45   IN OUT UINTN                            **MmioBar,
     46      OUT UINT8                            *BarNum
     47   )
     48 {
     49   SD_MMC_HC_PEI_PRIVATE_DATA  *Private;
     50 
     51   if ((This == NULL) || (MmioBar == NULL) || (BarNum == NULL)) {
     52     return EFI_INVALID_PARAMETER;
     53   }
     54 
     55   Private = SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS (This);
     56 
     57   if (ControllerId >= Private->TotalSdMmcHcs) {
     58     return EFI_INVALID_PARAMETER;
     59   }
     60 
     61   *MmioBar = &Private->MmioBar[ControllerId].MmioBarAddr[0];
     62   *BarNum  = (UINT8)Private->MmioBar[ControllerId].SlotNum;
     63   return EFI_SUCCESS;
     64 }
     65 
     66 /**
     67   The user code starts with this function.
     68 
     69   @param  FileHandle             Handle of the file being invoked.
     70   @param  PeiServices            Describes the list of possible PEI Services.
     71 
     72   @retval EFI_SUCCESS            The driver is successfully initialized.
     73   @retval Others                 Can't initialize the driver.
     74 
     75 **/
     76 EFI_STATUS
     77 EFIAPI
     78 InitializeSdMmcHcPeim (
     79   IN EFI_PEI_FILE_HANDLE       FileHandle,
     80   IN CONST EFI_PEI_SERVICES    **PeiServices
     81   )
     82 {
     83   EFI_BOOT_MODE                BootMode;
     84   EFI_STATUS                   Status;
     85   UINT16                       Bus;
     86   UINT16                       Device;
     87   UINT16                       Function;
     88   UINT32                       Size;
     89   UINT64                       MmioSize;
     90   UINT8                        SubClass;
     91   UINT8                        BaseClass;
     92   UINT8                        SlotInfo;
     93   UINT8                        SlotNum;
     94   UINT8                        FirstBar;
     95   UINT8                        Index;
     96   UINT8                        Slot;
     97   UINT32                       BarAddr;
     98   SD_MMC_HC_PEI_PRIVATE_DATA   *Private;
     99 
    100   //
    101   // Shadow this PEIM to run from memory
    102   //
    103   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
    104     return EFI_SUCCESS;
    105   }
    106 
    107   Status = PeiServicesGetBootMode (&BootMode);
    108   ///
    109   /// We do not expose this in S3 boot path, because it is only for recovery.
    110   ///
    111   if (BootMode == BOOT_ON_S3_RESUME) {
    112     return EFI_SUCCESS;
    113   }
    114 
    115   Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA));
    116   if (Private == NULL) {
    117     DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n"));
    118     return EFI_OUT_OF_RESOURCES;
    119   }
    120 
    121   Private->Signature              = SD_MMC_HC_PEI_SIGNATURE;
    122   Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi;
    123   Private->PpiList                = mPpiList;
    124   Private->PpiList.Ppi            = &Private->SdMmcHostControllerPpi;
    125 
    126   BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase);
    127   for (Bus = 0; Bus < 256; Bus++) {
    128     for (Device = 0; Device < 32; Device++) {
    129       for (Function = 0; Function < 8; Function++) {
    130         SubClass  = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
    131         BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
    132 
    133         if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) {
    134           //
    135           // Get the SD/MMC Pci host controller's Slot Info.
    136           //
    137           SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET));
    138           FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar;
    139           SlotNum  = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1;
    140           ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS);
    141 
    142           for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) {
    143             //
    144             // Get the SD/MMC Pci host controller's MMIO region size.
    145             //
    146             PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
    147             PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF);
    148             Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot));
    149 
    150             switch (Size & 0x07) {
    151               case 0x0:
    152                 //
    153                 // Memory space: anywhere in 32 bit address space
    154                 //
    155                 MmioSize = (~(Size & 0xFFFFFFF0)) + 1;
    156                 break;
    157               case 0x4:
    158                 //
    159                 // Memory space: anywhere in 64 bit address space
    160                 //
    161                 MmioSize = Size & 0xFFFFFFF0;
    162                 PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);
    163                 Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
    164                 //
    165                 // Fix the length to support some spefic 64 bit BAR
    166                 //
    167                 Size |= ((UINT32)(-1) << HighBitSet32 (Size));
    168                 //
    169                 // Calculate the size of 64bit bar
    170                 //
    171                 MmioSize  |= LShiftU64 ((UINT64) Size, 32);
    172                 MmioSize  = (~(MmioSize)) + 1;
    173                 //
    174                 // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR.
    175                 //
    176                 PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0);
    177                 break;
    178               default:
    179                 //
    180                 // Unknown BAR type
    181                 //
    182                 ASSERT (FALSE);
    183                 continue;
    184             };
    185             //
    186             // Assign resource to the SdMmc Pci host controller's MMIO BAR.
    187             // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register.
    188             //
    189             PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr);
    190             PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
    191             //
    192             // Record the allocated Mmio base address.
    193             //
    194             Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++;
    195             Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr;
    196             BarAddr += (UINT32)MmioSize;
    197           }
    198           Private->TotalSdMmcHcs++;
    199           ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS);
    200         }
    201       }
    202     }
    203   }
    204 
    205   ///
    206   /// Install SdMmc Host Controller PPI
    207   ///
    208   Status = PeiServicesInstallPpi (&Private->PpiList);
    209 
    210   ASSERT_EFI_ERROR (Status);
    211   return Status;
    212 }
    213