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