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