]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Universal/MmcDxe/Mmc.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / Universal / MmcDxe / Mmc.c
... / ...
CommitLineData
1/** @file\r
2 Main file of the MMC Dxe driver. The driver entrypoint is defined into this file.\r
3\r
4 Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include <Protocol/DevicePath.h>\r
11\r
12#include <Library/BaseLib.h>\r
13#include <Library/BaseMemoryLib.h>\r
14#include <Library/MemoryAllocationLib.h>\r
15#include <Library/UefiBootServicesTableLib.h>\r
16#include <Library/DevicePathLib.h>\r
17\r
18#include "Mmc.h"\r
19\r
20EFI_BLOCK_IO_MEDIA mMmcMediaTemplate = {\r
21 SIGNATURE_32('m','m','c','o'), // MediaId\r
22 TRUE, // RemovableMedia\r
23 FALSE, // MediaPresent\r
24 FALSE, // LogicalPartition\r
25 FALSE, // ReadOnly\r
26 FALSE, // WriteCaching\r
27 512, // BlockSize\r
28 4, // IoAlign\r
29 0, // Pad\r
30 0 // LastBlock\r
31};\r
32\r
33//\r
34// This device structure is serviced as a header.\r
35// Its next field points to the first root bridge device node.\r
36//\r
37LIST_ENTRY mMmcHostPool;\r
38\r
39/**\r
40 Event triggered by the timer to check if any cards have been removed\r
41 or if new ones have been plugged in\r
42**/\r
43\r
44EFI_EVENT gCheckCardsEvent;\r
45\r
46/**\r
47 Initialize the MMC Host Pool to support multiple MMC devices\r
48**/\r
49VOID\r
50InitializeMmcHostPool (\r
51 VOID\r
52 )\r
53{\r
54 InitializeListHead (&mMmcHostPool);\r
55}\r
56\r
57/**\r
58 Insert a new Mmc Host controller to the pool\r
59**/\r
60VOID\r
61InsertMmcHost (\r
62 IN MMC_HOST_INSTANCE *MmcHostInstance\r
63 )\r
64{\r
65 InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link));\r
66}\r
67\r
68/*\r
69 Remove a new Mmc Host controller to the pool\r
70*/\r
71VOID\r
72RemoveMmcHost (\r
73 IN MMC_HOST_INSTANCE *MmcHostInstance\r
74 )\r
75{\r
76 RemoveEntryList (&(MmcHostInstance->Link));\r
77}\r
78\r
79MMC_HOST_INSTANCE* CreateMmcHostInstance (\r
80 IN EFI_MMC_HOST_PROTOCOL* MmcHost\r
81 )\r
82{\r
83 EFI_STATUS Status;\r
84 MMC_HOST_INSTANCE* MmcHostInstance;\r
85 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
86 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
87\r
88 MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE));\r
89 if (MmcHostInstance == NULL) {\r
90 return NULL;\r
91 }\r
92\r
93 MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE;\r
94\r
95 MmcHostInstance->State = MmcHwInitializationState;\r
96\r
97 MmcHostInstance->BlockIo.Media = AllocateCopyPool (sizeof(EFI_BLOCK_IO_MEDIA), &mMmcMediaTemplate);\r
98 if (MmcHostInstance->BlockIo.Media == NULL) {\r
99 goto FREE_INSTANCE;\r
100 }\r
101\r
102 MmcHostInstance->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION;\r
103 MmcHostInstance->BlockIo.Reset = MmcReset;\r
104 MmcHostInstance->BlockIo.ReadBlocks = MmcReadBlocks;\r
105 MmcHostInstance->BlockIo.WriteBlocks = MmcWriteBlocks;\r
106 MmcHostInstance->BlockIo.FlushBlocks = MmcFlushBlocks;\r
107\r
108 MmcHostInstance->MmcHost = MmcHost;\r
109\r
110 // Create DevicePath for the new MMC Host\r
111 Status = MmcHost->BuildDevicePath (MmcHost, &NewDevicePathNode);\r
112 if (EFI_ERROR (Status)) {\r
113 goto FREE_MEDIA;\r
114 }\r
115\r
116 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);\r
117 if (DevicePath == NULL) {\r
118 goto FREE_MEDIA;\r
119 }\r
120\r
121 SetDevicePathEndNode (DevicePath);\r
122 MmcHostInstance->DevicePath = AppendDevicePathNode (DevicePath, NewDevicePathNode);\r
123\r
124 // Publish BlockIO protocol interface\r
125 Status = gBS->InstallMultipleProtocolInterfaces (\r
126 &MmcHostInstance->MmcHandle,\r
127 &gEfiBlockIoProtocolGuid,&MmcHostInstance->BlockIo,\r
128 &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,\r
129 NULL\r
130 );\r
131 if (EFI_ERROR(Status)) {\r
132 goto FREE_DEVICE_PATH;\r
133 }\r
134\r
135 return MmcHostInstance;\r
136\r
137FREE_DEVICE_PATH:\r
138 FreePool(DevicePath);\r
139\r
140FREE_MEDIA:\r
141 FreePool(MmcHostInstance->BlockIo.Media);\r
142\r
143FREE_INSTANCE:\r
144 FreePool(MmcHostInstance);\r
145\r
146 return NULL;\r
147}\r
148\r
149EFI_STATUS DestroyMmcHostInstance (\r
150 IN MMC_HOST_INSTANCE* MmcHostInstance\r
151 )\r
152{\r
153 EFI_STATUS Status;\r
154\r
155 // Uninstall Protocol Interfaces\r
156 Status = gBS->UninstallMultipleProtocolInterfaces (\r
157 MmcHostInstance->MmcHandle,\r
158 &gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo),\r
159 &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,\r
160 NULL\r
161 );\r
162 ASSERT_EFI_ERROR (Status);\r
163\r
164 // Free Memory allocated for the instance\r
165 if (MmcHostInstance->BlockIo.Media) {\r
166 FreePool(MmcHostInstance->BlockIo.Media);\r
167 }\r
168 if (MmcHostInstance->CardInfo.ECSDData) {\r
169 FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD)));\r
170 }\r
171 FreePool (MmcHostInstance);\r
172\r
173 return Status;\r
174}\r
175\r
176/**\r
177 This function checks if the controller implement the Mmc Host and the Device Path Protocols\r
178**/\r
179EFI_STATUS\r
180EFIAPI\r
181MmcDriverBindingSupported (\r
182 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
183 IN EFI_HANDLE Controller,\r
184 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
185 )\r
186{\r
187 EFI_STATUS Status;\r
188 //EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
189 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
190 EFI_DEV_PATH_PTR Node;\r
191\r
192 //\r
193 // Check RemainingDevicePath validation\r
194 //\r
195 if (RemainingDevicePath != NULL) {\r
196 //\r
197 // Check if RemainingDevicePath is the End of Device Path Node,\r
198 // if yes, go on checking other conditions\r
199 //\r
200 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
201 //\r
202 // If RemainingDevicePath isn't the End of Device Path Node,\r
203 // check its validation\r
204 //\r
205 Node.DevPath = RemainingDevicePath;\r
206 if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||\r
207 Node.DevPath->SubType != HW_VENDOR_DP ||\r
208 DevicePathNodeLength(Node.DevPath) != sizeof(VENDOR_DEVICE_PATH)) {\r
209 return EFI_UNSUPPORTED;\r
210 }\r
211 }\r
212 }\r
213\r
214 //\r
215 // Check if Mmc Host protocol is installed by platform\r
216 //\r
217 Status = gBS->OpenProtocol (\r
218 Controller,\r
219 &gEmbeddedMmcHostProtocolGuid,\r
220 (VOID **) &MmcHost,\r
221 This->DriverBindingHandle,\r
222 Controller,\r
223 EFI_OPEN_PROTOCOL_BY_DRIVER\r
224 );\r
225 if (Status == EFI_ALREADY_STARTED) {\r
226 return EFI_SUCCESS;\r
227 }\r
228 if (EFI_ERROR (Status)) {\r
229 return Status;\r
230 }\r
231\r
232 //\r
233 // Close the Mmc Host used to perform the supported test\r
234 //\r
235 gBS->CloseProtocol (\r
236 Controller,\r
237 &gEmbeddedMmcHostProtocolGuid,\r
238 This->DriverBindingHandle,\r
239 Controller\r
240 );\r
241\r
242 return EFI_SUCCESS;\r
243}\r
244\r
245/**\r
246\r
247**/\r
248EFI_STATUS\r
249EFIAPI\r
250MmcDriverBindingStart (\r
251 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
252 IN EFI_HANDLE Controller,\r
253 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
254 )\r
255{\r
256 EFI_STATUS Status;\r
257 MMC_HOST_INSTANCE *MmcHostInstance;\r
258 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
259\r
260 //\r
261 // Check RemainingDevicePath validation\r
262 //\r
263 if (RemainingDevicePath != NULL) {\r
264 //\r
265 // Check if RemainingDevicePath is the End of Device Path Node,\r
266 // if yes, return EFI_SUCCESS\r
267 //\r
268 if (IsDevicePathEnd (RemainingDevicePath)) {\r
269 return EFI_SUCCESS;\r
270 }\r
271 }\r
272\r
273 //\r
274 // Get the Mmc Host protocol\r
275 //\r
276 Status = gBS->OpenProtocol (\r
277 Controller,\r
278 &gEmbeddedMmcHostProtocolGuid,\r
279 (VOID **) &MmcHost,\r
280 This->DriverBindingHandle,\r
281 Controller,\r
282 EFI_OPEN_PROTOCOL_BY_DRIVER\r
283 );\r
284 if (EFI_ERROR (Status)) {\r
285 if (Status == EFI_ALREADY_STARTED) {\r
286 return EFI_SUCCESS;\r
287 }\r
288 return Status;\r
289 }\r
290\r
291 MmcHostInstance = CreateMmcHostInstance(MmcHost);\r
292 if (MmcHostInstance != NULL) {\r
293 // Add the handle to the pool\r
294 InsertMmcHost (MmcHostInstance);\r
295\r
296 MmcHostInstance->Initialized = FALSE;\r
297\r
298 // Detect card presence now\r
299 CheckCardsCallback (NULL, NULL);\r
300 }\r
301\r
302 return EFI_SUCCESS;\r
303}\r
304\r
305/**\r
306\r
307**/\r
308EFI_STATUS\r
309EFIAPI\r
310MmcDriverBindingStop (\r
311 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
312 IN EFI_HANDLE Controller,\r
313 IN UINTN NumberOfChildren,\r
314 IN EFI_HANDLE *ChildHandleBuffer\r
315 )\r
316{\r
317 EFI_STATUS Status = EFI_SUCCESS;\r
318 LIST_ENTRY *CurrentLink;\r
319 MMC_HOST_INSTANCE *MmcHostInstance;\r
320\r
321 MMC_TRACE("MmcDriverBindingStop()");\r
322\r
323 // For each MMC instance\r
324 CurrentLink = mMmcHostPool.ForwardLink;\r
325 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {\r
326 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);\r
327 ASSERT(MmcHostInstance != NULL);\r
328\r
329 // Close gEmbeddedMmcHostProtocolGuid\r
330 Status = gBS->CloseProtocol (\r
331 Controller,\r
332 &gEmbeddedMmcHostProtocolGuid,\r
333 This->DriverBindingHandle,\r
334 Controller\r
335 );\r
336\r
337 // Remove MMC Host Instance from the pool\r
338 RemoveMmcHost (MmcHostInstance);\r
339\r
340 // Destroy MmcHostInstance\r
341 DestroyMmcHostInstance (MmcHostInstance);\r
342 }\r
343\r
344 return Status;\r
345}\r
346\r
347VOID\r
348EFIAPI\r
349CheckCardsCallback (\r
350 IN EFI_EVENT Event,\r
351 IN VOID *Context\r
352 )\r
353{\r
354 LIST_ENTRY *CurrentLink;\r
355 MMC_HOST_INSTANCE *MmcHostInstance;\r
356 EFI_STATUS Status;\r
357\r
358 CurrentLink = mMmcHostPool.ForwardLink;\r
359 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) {\r
360 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);\r
361 ASSERT(MmcHostInstance != NULL);\r
362\r
363 if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) {\r
364 MmcHostInstance->State = MmcHwInitializationState;\r
365 MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;\r
366 MmcHostInstance->Initialized = !MmcHostInstance->Initialized;\r
367\r
368 if (MmcHostInstance->BlockIo.Media->MediaPresent) {\r
369 InitializeMmcDevice (MmcHostInstance);\r
370 }\r
371\r
372 Status = gBS->ReinstallProtocolInterface (\r
373 (MmcHostInstance->MmcHandle),\r
374 &gEfiBlockIoProtocolGuid,\r
375 &(MmcHostInstance->BlockIo),\r
376 &(MmcHostInstance->BlockIo)\r
377 );\r
378\r
379 if (EFI_ERROR(Status)) {\r
380 Print(L"MMC Card: Error reinstalling BlockIo interface\n");\r
381 }\r
382 }\r
383\r
384 CurrentLink = CurrentLink->ForwardLink;\r
385 }\r
386}\r
387\r
388\r
389EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = {\r
390 MmcDriverBindingSupported,\r
391 MmcDriverBindingStart,\r
392 MmcDriverBindingStop,\r
393 0xa,\r
394 NULL,\r
395 NULL\r
396};\r
397\r
398/**\r
399\r
400**/\r
401EFI_STATUS\r
402EFIAPI\r
403MmcDxeInitialize (\r
404 IN EFI_HANDLE ImageHandle,\r
405 IN EFI_SYSTEM_TABLE *SystemTable\r
406 )\r
407{\r
408 EFI_STATUS Status;\r
409\r
410 //\r
411 // Initializes MMC Host pool\r
412 //\r
413 InitializeMmcHostPool ();\r
414\r
415 //\r
416 // Install driver model protocol(s).\r
417 //\r
418 Status = EfiLibInstallDriverBindingComponentName2 (\r
419 ImageHandle,\r
420 SystemTable,\r
421 &gMmcDriverBinding,\r
422 ImageHandle,\r
423 &gMmcComponentName,\r
424 &gMmcComponentName2\r
425 );\r
426 ASSERT_EFI_ERROR (Status);\r
427\r
428 // Install driver diagnostics\r
429 Status = gBS->InstallMultipleProtocolInterfaces (\r
430 &ImageHandle,\r
431 &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2,\r
432 NULL\r
433 );\r
434 ASSERT_EFI_ERROR (Status);\r
435\r
436 // Use a timer to detect if a card has been plugged in or removed\r
437 Status = gBS->CreateEvent (\r
438 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
439 TPL_CALLBACK,\r
440 CheckCardsCallback,\r
441 NULL,\r
442 &gCheckCardsEvent);\r
443 ASSERT_EFI_ERROR (Status);\r
444\r
445 Status = gBS->SetTimer(\r
446 gCheckCardsEvent,\r
447 TimerPeriodic,\r
448 (UINT64)(10*1000*200)); // 200 ms\r
449 ASSERT_EFI_ERROR (Status);\r
450\r
451 return Status;\r
452}\r