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