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
InitializeMmcHostPool(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
InsertMmcHost(IN MMC_HOST_INSTANCE * MmcHostInstance)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
RemoveMmcHost(IN MMC_HOST_INSTANCE * MmcHostInstance)72 RemoveMmcHost (
73   IN MMC_HOST_INSTANCE      *MmcHostInstance
74   )
75 {
76   RemoveEntryList (&(MmcHostInstance->Link));
77 }
78 
CreateMmcHostInstance(IN EFI_MMC_HOST_PROTOCOL * MmcHost)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 
DestroyMmcHostInstance(IN MMC_HOST_INSTANCE * MmcHostInstance)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
MmcDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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                 &gEfiMmcHostProtocolGuid,
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       &gEfiMmcHostProtocolGuid,
238       This->DriverBindingHandle,
239       Controller
240       );
241 
242   return EFI_SUCCESS;
243 }
244 
245 /**
246 
247 **/
248 EFI_STATUS
249 EFIAPI
MmcDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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                 &gEfiMmcHostProtocolGuid,
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
MmcDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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 gEfiMmcHostProtocolGuid
330     Status = gBS->CloseProtocol (
331                 Controller,
332                 &gEfiMmcHostProtocolGuid,(VOID **) &MmcHostInstance->MmcHost,
333                 This->DriverBindingHandle
334                 );
335 
336     // Remove MMC Host Instance from the pool
337     RemoveMmcHost (MmcHostInstance);
338 
339     // Destroy MmcHostInstance
340     DestroyMmcHostInstance (MmcHostInstance);
341   }
342 
343   return Status;
344 }
345 
346 VOID
347 EFIAPI
CheckCardsCallback(IN EFI_EVENT Event,IN VOID * Context)348 CheckCardsCallback (
349   IN  EFI_EVENT   Event,
350   IN  VOID        *Context
351   )
352 {
353   LIST_ENTRY          *CurrentLink;
354   MMC_HOST_INSTANCE   *MmcHostInstance;
355   EFI_STATUS          Status;
356 
357   CurrentLink = mMmcHostPool.ForwardLink;
358   while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) {
359     MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
360     ASSERT(MmcHostInstance != NULL);
361 
362     if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) {
363       MmcHostInstance->State = MmcHwInitializationState;
364       MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;
365       MmcHostInstance->Initialized = !MmcHostInstance->Initialized;
366 
367       if (MmcHostInstance->BlockIo.Media->MediaPresent) {
368         InitializeMmcDevice (MmcHostInstance);
369       }
370 
371       Status = gBS->ReinstallProtocolInterface (
372                     (MmcHostInstance->MmcHandle),
373                     &gEfiBlockIoProtocolGuid,
374                     &(MmcHostInstance->BlockIo),
375                     &(MmcHostInstance->BlockIo)
376                     );
377 
378       if (EFI_ERROR(Status)) {
379         Print(L"MMC Card: Error reinstalling BlockIo interface\n");
380       }
381     }
382 
383     CurrentLink = CurrentLink->ForwardLink;
384   }
385 }
386 
387 
388 EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = {
389   MmcDriverBindingSupported,
390   MmcDriverBindingStart,
391   MmcDriverBindingStop,
392   0xa,
393   NULL,
394   NULL
395 };
396 
397 /**
398 
399 **/
400 EFI_STATUS
401 EFIAPI
MmcDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)402 MmcDxeInitialize (
403   IN EFI_HANDLE         ImageHandle,
404   IN EFI_SYSTEM_TABLE   *SystemTable
405   )
406 {
407   EFI_STATUS  Status;
408 
409   //
410   // Initializes MMC Host pool
411   //
412   InitializeMmcHostPool ();
413 
414   //
415   // Install driver model protocol(s).
416   //
417   Status = EfiLibInstallDriverBindingComponentName2 (
418            ImageHandle,
419            SystemTable,
420            &gMmcDriverBinding,
421            ImageHandle,
422            &gMmcComponentName,
423            &gMmcComponentName2
424            );
425   ASSERT_EFI_ERROR (Status);
426 
427   // Install driver diagnostics
428   Status = gBS->InstallMultipleProtocolInterfaces (
429                 &ImageHandle,
430                 &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2,
431                 NULL
432                 );
433   ASSERT_EFI_ERROR (Status);
434 
435   // Use a timer to detect if a card has been plugged in or removed
436   Status = gBS->CreateEvent (
437                 EVT_NOTIFY_SIGNAL | EVT_TIMER,
438                 TPL_CALLBACK,
439                 CheckCardsCallback,
440                 NULL,
441                 &gCheckCardsEvent);
442   ASSERT_EFI_ERROR (Status);
443 
444   Status = gBS->SetTimer(
445                 gCheckCardsEvent,
446                 TimerPeriodic,
447                 (UINT64)(10*1000*200)); // 200 ms
448   ASSERT_EFI_ERROR (Status);
449 
450   return Status;
451 }
452