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
GetSdMmcHcMmioBar(IN EDKII_SD_MMC_HOST_CONTROLLER_PPI * This,IN UINT8 ControllerId,IN OUT UINTN ** MmioBar,OUT UINT8 * BarNum)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
InitializeSdMmcHcPeim(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)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