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