1 /** @file
2   This driver is used to manage Designware SD/MMC host controller.
3 
4   It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
5 
6   Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
7   Copyright (C) 2016 Marvell International Ltd. All rigths reserved.<BR>
8   Copyright (C) 2017, Linaro Ltd. All rigths reserved.<BR>
9 
10   This program and the accompanying materials
11   are licensed and made available under the terms and conditions of the BSD License
12   which accompanies this distribution.  The full text of the license may be found at
13   http://opensource.org/licenses/bsd-license.php
14 
15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 
18 **/
19 
20 #include "DwMmcHcDxe.h"
21 
22 //
23 // Driver Global Variables
24 //
25 EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding = {
26   DwMmcHcDriverBindingSupported,
27   DwMmcHcDriverBindingStart,
28   DwMmcHcDriverBindingStop,
29   0x10,
30   NULL,
31   NULL
32 };
33 
34 //
35 // Template for Designware SD/MMC host controller private data.
36 //
37 DW_MMC_HC_PRIVATE_DATA gDwMmcHcTemplate = {
38   DW_MMC_HC_PRIVATE_SIGNATURE,      // Signature
39   NULL,                             // ControllerHandle
40   NULL,                             // PciIo
41   {                                 // PassThru
42     sizeof (UINT32),
43     DwMmcPassThruPassThru,
44     DwMmcPassThruGetNextSlot,
45     DwMmcPassThruBuildDevicePath,
46     DwMmcPassThruGetSlotNumber,
47     DwMmcPassThruResetDevice
48   },
49   NULL,                             // PlatformDwMmc
50   0,                                // PciAttributes
51   0,                                // PreviousSlot
52   NULL,                             // TimerEvent
53   NULL,                             // ConnectEvent
54                                     // Queue
55   INITIALIZE_LIST_HEAD_VARIABLE (gDwMmcHcTemplate.Queue),
56   {                                 // Slot
57     {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0},
58     {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}
59   },
60   {                                 // Capability
61     {0},
62   },
63   {                                 // MaxCurrent
64     0,
65   },
66   0                                 // ControllerVersion
67 };
68 
69 SD_DEVICE_PATH    mSdDpTemplate = {
70   {
71     MESSAGING_DEVICE_PATH,
72     MSG_SD_DP,
73     {
74       (UINT8) (sizeof (SD_DEVICE_PATH)),
75       (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
76     }
77   },
78   0
79 };
80 
81 EMMC_DEVICE_PATH    mEmmcDpTemplate = {
82   {
83     MESSAGING_DEVICE_PATH,
84     MSG_EMMC_DP,
85     {
86       (UINT8) (sizeof (EMMC_DEVICE_PATH)),
87       (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
88     }
89   },
90   0
91 };
92 
93 //
94 // Prioritized function list to detect card type.
95 // User could add other card detection logic here.
96 //
97 CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {
98   EmmcIdentification,
99   SdCardIdentification,
100   NULL
101 };
102 
103 /**
104   The entry point for SD host controller driver, used to install this driver on the ImageHandle.
105 
106   @param[in]  ImageHandle   The firmware allocated handle for this driver image.
107   @param[in]  SystemTable   Pointer to the EFI system table.
108 
109   @retval EFI_SUCCESS   Driver loaded.
110   @retval other         Driver not loaded.
111 
112 **/
113 EFI_STATUS
114 EFIAPI
InitializeDwMmcHcDxe(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)115 InitializeDwMmcHcDxe (
116   IN EFI_HANDLE        ImageHandle,
117   IN EFI_SYSTEM_TABLE  *SystemTable
118   )
119 {
120   EFI_STATUS           Status;
121 
122   Status = EfiLibInstallDriverBindingComponentName2 (
123              ImageHandle,
124              SystemTable,
125              &gDwMmcHcDriverBinding,
126              ImageHandle,
127              &gDwMmcHcComponentName,
128              &gDwMmcHcComponentName2
129              );
130   ASSERT_EFI_ERROR (Status);
131 
132   return Status;
133 }
134 
135 /**
136   Call back function when the timer event is signaled.
137 
138   @param[in]  Event     The Event this notify function registered to.
139   @param[in]  Context   Pointer to the context data registered to the
140                         Event.
141 
142 **/
143 VOID
144 EFIAPI
ProcessAsyncTaskList(IN EFI_EVENT Event,IN VOID * Context)145 ProcessAsyncTaskList (
146   IN EFI_EVENT          Event,
147   IN VOID*              Context
148   )
149 {
150   DW_MMC_HC_PRIVATE_DATA              *Private;
151   LIST_ENTRY                          *Link;
152   DW_MMC_HC_TRB                       *Trb;
153   EFI_STATUS                          Status;
154   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
155   BOOLEAN                             InfiniteWait;
156   EFI_EVENT                           TrbEvent;
157 
158   Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
159 
160   //
161   // Check if the first entry in the async I/O queue is done or not.
162   //
163   Status = EFI_SUCCESS;
164   Trb    = NULL;
165   Link   = GetFirstNode (&Private->Queue);
166   if (!IsNull (&Private->Queue, Link)) {
167     Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
168     if (!Private->Slot[Trb->Slot].MediaPresent) {
169       Status = EFI_NO_MEDIA;
170       goto Done;
171     }
172     if (!Trb->Started) {
173       //
174       // Check whether the cmd/data line is ready for transfer.
175       //
176       Status = DwMmcCheckTrbEnv (Private, Trb);
177       if (!EFI_ERROR (Status)) {
178         Trb->Started = TRUE;
179         Status = DwMmcExecTrb (Private, Trb);
180         if (EFI_ERROR (Status)) {
181           goto Done;
182         }
183       } else {
184         goto Done;
185       }
186     }
187     Status = DwMmcCheckTrbResult (Private, Trb);
188   }
189 
190 Done:
191   if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
192     Packet = Trb->Packet;
193     if (Packet->Timeout == 0) {
194       InfiniteWait = TRUE;
195     } else {
196       InfiniteWait = FALSE;
197     }
198     if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
199       RemoveEntryList (Link);
200       Trb->Packet->TransactionStatus = EFI_TIMEOUT;
201       TrbEvent = Trb->Event;
202       DwMmcFreeTrb (Trb);
203       DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));
204       gBS->SignalEvent (TrbEvent);
205       return;
206     }
207   }
208   if ((Trb != NULL) && (Status != EFI_NOT_READY)) {
209     RemoveEntryList (Link);
210     Trb->Packet->TransactionStatus = Status;
211     TrbEvent = Trb->Event;
212     DwMmcFreeTrb (Trb);
213     DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));
214     gBS->SignalEvent (TrbEvent);
215   }
216   return;
217 }
218 
219 /**
220   Sd removable device enumeration callback function when the timer event is signaled.
221 
222   @param[in]  Event     The Event this notify function registered to.
223   @param[in]  Context   Pointer to the context data registered to the
224                         Event.
225 
226 **/
227 VOID
228 EFIAPI
DwMmcHcEnumerateDevice(IN EFI_EVENT Event,IN VOID * Context)229 DwMmcHcEnumerateDevice (
230   IN EFI_EVENT          Event,
231   IN VOID*              Context
232   )
233 {
234   DW_MMC_HC_PRIVATE_DATA              *Private;
235   EFI_STATUS                          Status;
236   UINT8                               Slot;
237   BOOLEAN                             MediaPresent;
238   UINT32                              RoutineNum;
239   CARD_TYPE_DETECT_ROUTINE            *Routine;
240   UINTN                               Index;
241   LIST_ENTRY                          *Link;
242   LIST_ENTRY                          *NextLink;
243   DW_MMC_HC_TRB                       *Trb;
244   EFI_TPL                             OldTpl;
245 
246 return;
247   Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
248 
249   for (Slot = 0; Slot < DW_MMC_HC_MAX_SLOT; Slot++) {
250     if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {
251       Status = DwMmcHcCardDetect (Private->PciIo, Private->ControllerHandle, Slot, &MediaPresent);
252       if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
253         DEBUG ((DEBUG_INFO, "DwMmcHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));
254         Private->Slot[Slot].MediaPresent = FALSE;
255         //
256         // Signal all async task events at the slot with EFI_NO_MEDIA status.
257         //
258         OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
259         for (Link = GetFirstNode (&Private->Queue);
260              !IsNull (&Private->Queue, Link);
261              Link = NextLink) {
262           NextLink = GetNextNode (&Private->Queue, Link);
263           Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
264           if (Trb->Slot == Slot) {
265             RemoveEntryList (Link);
266             Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
267             gBS->SignalEvent (Trb->Event);
268             DwMmcFreeTrb (Trb);
269           }
270         }
271         gBS->RestoreTPL (OldTpl);
272         //
273         // Notify the upper layer the connect state change through ReinstallProtocolInterface.
274         //
275         gBS->ReinstallProtocolInterface (
276               Private->ControllerHandle,
277               &gEfiSdMmcPassThruProtocolGuid,
278               &Private->PassThru,
279               &Private->PassThru
280               );
281       }
282       if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
283         DEBUG ((DEBUG_INFO, "DwMmcHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));
284         //
285         // Initialize slot and start identification process for the new attached device
286         //
287         Status = DwMmcHcInitHost (Private->PciIo, Slot, Private->Capability[Slot]);
288         if (EFI_ERROR (Status)) {
289           continue;
290         }
291         //
292         // Reset the specified slot of the SD/MMC Pci Host Controller
293         //
294         Status = DwMmcHcReset (Private->PciIo, Slot, Private->Capability[Slot]);
295         if (EFI_ERROR (Status)) {
296           continue;
297         }
298 
299         Private->Slot[Slot].MediaPresent = TRUE;
300         RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
301         for (Index = 0; Index < RoutineNum; Index++) {
302           Routine = &mCardTypeDetectRoutineTable[Index];
303           if (*Routine != NULL) {
304             Status = (*Routine) (Private, Slot);
305             if (!EFI_ERROR (Status)) {
306               break;
307             }
308           }
309         }
310         //
311         // This card doesn't get initialized correctly.
312         //
313         if (Index == RoutineNum) {
314         }
315 
316         //
317         // Notify the upper layer the connect state change through ReinstallProtocolInterface.
318         //
319         gBS->ReinstallProtocolInterface (
320                Private->ControllerHandle,
321                &gEfiSdMmcPassThruProtocolGuid,
322                &Private->PassThru,
323                &Private->PassThru
324                );
325       }
326     }
327   }
328 
329   return;
330 }
331 
332 /**
333   Reset the specified SD/MMC host controller and enable all interrupts.
334 
335   @param[in] PciIo          The PCI IO protocol instance.
336   @param[in] Slot           The slot number of the SD card to send the command to.
337 
338   @retval EFI_SUCCESS       The software reset executes successfully.
339   @retval Others            The software reset fails.
340 
341 **/
342 EFI_STATUS
DwMmcHcReset(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN DW_MMC_HC_SLOT_CAP Capability)343 DwMmcHcReset (
344   IN EFI_PCI_IO_PROTOCOL    *PciIo,
345   IN UINT8                  Slot,
346   IN DW_MMC_HC_SLOT_CAP     Capability
347   )
348 {
349   EFI_STATUS                Status;
350   UINT32                    BlkSize;
351 
352   //
353   // Enable all interrupt after reset all.
354   //
355   Status = DwMmcHcEnableInterrupt (PciIo, Slot);
356   if (EFI_ERROR (Status)) {
357     DEBUG ((DEBUG_ERROR, "DwMmcHcReset: enable interrupts fail: %r\n", Status));
358     return Status;
359   }
360   Status = DwMmcHcInitTimeoutCtrl (PciIo, Slot);
361   if (EFI_ERROR (Status)) {
362     return Status;
363   }
364 
365   BlkSize = DW_MMC_BLOCK_SIZE;
366   Status = DwMmcHcRwMmio (PciIo, Slot, DW_MMC_BLKSIZ, FALSE, sizeof (BlkSize), &BlkSize);
367   if (EFI_ERROR (Status)) {
368     DEBUG ((DEBUG_ERROR, "DwMmcHcReset: set block size fails: %r\n", Status));
369     return Status;
370   }
371 
372   Status = DwMmcHcInitClockFreq (PciIo, Slot, Capability);
373   if (EFI_ERROR (Status)) {
374     return Status;
375   }
376 
377   Status = DwMmcHcSetBusWidth (PciIo, Slot, FALSE, 1);
378 
379   return Status;
380 }
381 
382 /**
383   Tests to see if this driver supports a given controller. If a child device is provided,
384   it further tests to see if this driver supports creating a handle for the specified child device.
385 
386   This function checks to see if the driver specified by This supports the device specified by
387   ControllerHandle. Drivers will typically use the device path attached to
388   ControllerHandle and/or the services from the bus I/O abstraction attached to
389   ControllerHandle to determine if the driver supports ControllerHandle. This function
390   may be called many times during platform initialization. In order to reduce boot times, the tests
391   performed by this function must be very small, and take as little time as possible to execute. This
392   function must not change the state of any hardware devices, and this function must be aware that the
393   device specified by ControllerHandle may already be managed by the same driver or a
394   different driver. This function must match its calls to AllocatePages() with FreePages(),
395   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
396   Since ControllerHandle may have been previously started by the same driver, if a protocol is
397   already in the opened state, then it must not be closed with CloseProtocol(). This is required
398   to guarantee the state of ControllerHandle is not modified by this function.
399 
400   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
401   @param[in]  ControllerHandle     The handle of the controller to test. This handle
402                                    must support a protocol interface that supplies
403                                    an I/O abstraction to the driver.
404   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
405                                    parameter is ignored by device drivers, and is optional for bus
406                                    drivers. For bus drivers, if this parameter is not NULL, then
407                                    the bus driver must determine if the bus controller specified
408                                    by ControllerHandle and the child controller specified
409                                    by RemainingDevicePath are both supported by this
410                                    bus driver.
411 
412   @retval EFI_SUCCESS              The device specified by ControllerHandle and
413                                    RemainingDevicePath is supported by the driver specified by This.
414   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
415                                    RemainingDevicePath is already being managed by the driver
416                                    specified by This.
417   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
418                                    RemainingDevicePath is already being managed by a different
419                                    driver or an application that requires exclusive access.
420                                    Currently not implemented.
421   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
422                                    RemainingDevicePath is not supported by the driver specified by This.
423 **/
424 EFI_STATUS
425 EFIAPI
DwMmcHcDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)426 DwMmcHcDriverBindingSupported (
427   IN EFI_DRIVER_BINDING_PROTOCOL *This,
428   IN EFI_HANDLE                  Controller,
429   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
430   )
431 {
432   EFI_STATUS                Status;
433   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
434   EFI_PCI_IO_PROTOCOL       *PciIo;
435   PCI_TYPE00                PciData;
436   PLATFORM_DW_MMC_PROTOCOL  *PlatformDwMmc;
437 
438   PciIo            = NULL;
439   ParentDevicePath = NULL;
440 
441   Status = gBS->LocateProtocol (
442                   &gPlatformDwMmcProtocolGuid,
443                   NULL,
444                   (VOID **) &PlatformDwMmc
445                   );
446   if (EFI_ERROR (Status)) {
447     return Status;
448   }
449   //
450   // SdPciHcDxe is a device driver, and should ingore the
451   // "RemainingDevicePath" according to EFI spec.
452   //
453   Status = gBS->OpenProtocol (
454                   Controller,
455                   &gEfiDevicePathProtocolGuid,
456                   (VOID *) &ParentDevicePath,
457                   This->DriverBindingHandle,
458                   Controller,
459                   EFI_OPEN_PROTOCOL_BY_DRIVER
460                   );
461   if (EFI_ERROR (Status)) {
462     //
463     // EFI_ALREADY_STARTED is also an error.
464     //
465     return Status;
466   }
467   //
468   // Close the protocol because we don't use it here.
469   //
470   gBS->CloseProtocol (
471         Controller,
472         &gEfiDevicePathProtocolGuid,
473         This->DriverBindingHandle,
474         Controller
475         );
476 
477   //
478   // Now test the EfiPciIoProtocol.
479   //
480   Status = gBS->OpenProtocol (
481                   Controller,
482                   &gEfiPciIoProtocolGuid,
483                   (VOID **) &PciIo,
484                   This->DriverBindingHandle,
485                   Controller,
486                   EFI_OPEN_PROTOCOL_BY_DRIVER
487                   );
488   if (EFI_ERROR (Status)) {
489     return Status;
490   }
491 
492   //
493   // Now further check the PCI header: Base class (offset 0x08) and
494   // Sub Class (offset 0x05). This controller should be an SD/MMC PCI
495   // Host Controller.
496   //
497   Status = PciIo->Pci.Read (
498                         PciIo,
499                         EfiPciIoWidthUint8,
500                         0,
501                         sizeof (PciData),
502                         &PciData
503                         );
504   if (EFI_ERROR (Status)) {
505     gBS->CloseProtocol (
506           Controller,
507           &gEfiPciIoProtocolGuid,
508           This->DriverBindingHandle,
509           Controller
510           );
511     return EFI_UNSUPPORTED;
512   }
513   //
514   // Since we already got the PciData, we can close protocol to avoid to carry it
515   // on for multiple exit points.
516   //
517   gBS->CloseProtocol (
518         Controller,
519         &gEfiPciIoProtocolGuid,
520         This->DriverBindingHandle,
521         Controller
522         );
523 
524   //
525   // Examine SD PCI Host Controller PCI Configuration table fields.
526   //
527   if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) &&
528       (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) &&
529       ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) {
530     return EFI_SUCCESS;
531   }
532 
533   return EFI_UNSUPPORTED;
534 }
535 
536 /**
537   Starts a device controller or a bus controller.
538 
539   The Start() function is designed to be invoked from the EFI boot service ConnectController().
540   As a result, much of the error checking on the parameters to Start() has been moved into this
541   common boot service. It is legal to call Start() from other locations,
542   but the following calling restrictions must be followed or the system behavior will not be deterministic.
543   1. ControllerHandle must be a valid EFI_HANDLE.
544   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
545      EFI_DEVICE_PATH_PROTOCOL.
546   3. Prior to calling Start(), the Supported() function for the driver specified by This must
547      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
548 
549   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
550   @param[in]  ControllerHandle     The handle of the controller to start. This handle
551                                    must support a protocol interface that supplies
552                                    an I/O abstraction to the driver.
553   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
554                                    parameter is ignored by device drivers, and is optional for bus
555                                    drivers. For a bus driver, if this parameter is NULL, then handles
556                                    for all the children of Controller are created by this driver.
557                                    If this parameter is not NULL and the first Device Path Node is
558                                    not the End of Device Path Node, then only the handle for the
559                                    child device specified by the first Device Path Node of
560                                    RemainingDevicePath is created by this driver.
561                                    If the first Device Path Node of RemainingDevicePath is
562                                    the End of Device Path Node, no child handle is created by this
563                                    driver.
564 
565   @retval EFI_SUCCESS              The device was started.
566   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
567   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
568   @retval Others                   The driver failded to start the device.
569 
570 **/
571 EFI_STATUS
572 EFIAPI
DwMmcHcDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)573 DwMmcHcDriverBindingStart (
574   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
575   IN EFI_HANDLE                      Controller,
576   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
577   )
578 {
579   EFI_STATUS                      Status;
580   DW_MMC_HC_PRIVATE_DATA          *Private;
581   EFI_PCI_IO_PROTOCOL             *PciIo;
582   UINT64                          Supports;
583   UINT64                          PciAttributes;
584   UINT8                           Slot;
585   UINT8                           Index;
586   CARD_TYPE_DETECT_ROUTINE        *Routine;
587   UINT32                          RoutineNum;
588   BOOLEAN                         Support64BitDma;
589   BOOLEAN                         MediaPresent;
590   PLATFORM_DW_MMC_PROTOCOL        *PlatformDwMmc;
591 
592   Status = gBS->LocateProtocol (
593                   &gPlatformDwMmcProtocolGuid,
594                   NULL,
595                   (VOID **) &PlatformDwMmc
596                   );
597   if (EFI_ERROR (Status)) {
598     return Status;
599   }
600 
601   //
602   // Open PCI I/O Protocol and save pointer to open protocol
603   // in private data area.
604   //
605   PciIo  = NULL;
606   Status = gBS->OpenProtocol (
607                   Controller,
608                   &gEfiPciIoProtocolGuid,
609                   (VOID **) &PciIo,
610                   This->DriverBindingHandle,
611                   Controller,
612                   EFI_OPEN_PROTOCOL_BY_DRIVER
613                   );
614   if (EFI_ERROR (Status)) {
615     return Status;
616   }
617 
618   //
619   // Enable the SD Host Controller MMIO space
620   //
621   Private = NULL;
622   Status  = PciIo->Attributes (
623                      PciIo,
624                      EfiPciIoAttributeOperationGet,
625                      0,
626                      &PciAttributes
627                      );
628 
629   if (EFI_ERROR (Status)) {
630     goto Done;
631   }
632 
633   Status = PciIo->Attributes (
634                     PciIo,
635                     EfiPciIoAttributeOperationSupported,
636                     0,
637                     &Supports
638                     );
639 
640   if (!EFI_ERROR (Status)) {
641     Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
642     Status    = PciIo->Attributes (
643                          PciIo,
644                          EfiPciIoAttributeOperationEnable,
645                          Supports,
646                          NULL
647                          );
648   } else {
649     goto Done;
650   }
651 
652   Private = AllocateCopyPool (sizeof (DW_MMC_HC_PRIVATE_DATA), &gDwMmcHcTemplate);
653   if (Private == NULL) {
654     Status = EFI_OUT_OF_RESOURCES;
655     goto Done;
656   }
657 
658   Private->ControllerHandle = Controller;
659   Private->PciIo            = PciIo;
660   Private->PciAttributes    = PciAttributes;
661   Private->PlatformDwMmc    = PlatformDwMmc;
662   InitializeListHead (&Private->Queue);
663 
664   Support64BitDma = TRUE;
665 
666   //for (Slot = 0; Slot < DW_MMC_HC_MAX_SLOT; Slot++) {
667   for (Slot = 0; Slot < 1; Slot++) {
668     Status = DwMmcHcGetCapability (PciIo, Controller, Slot, &Private->Capability[Slot]);
669     if (EFI_ERROR (Status)) {
670       break;
671     }
672 
673     Support64BitDma &= Private->Capability[Slot].SysBus64;
674 
675     if (Private->Capability[Slot].BaseClkFreq == 0) {
676       continue;
677     }
678 
679     DumpCapabilityReg (Slot, &Private->Capability[Slot]);
680 
681     MediaPresent = FALSE;
682     Status = DwMmcHcCardDetect (Private->PciIo, Controller, Slot, &MediaPresent);
683     if (MediaPresent == FALSE) {
684       continue;
685     }
686 
687     //
688     // Initialize slot and start identification process for the new attached device
689     //
690     Status = DwMmcHcInitHost (PciIo, Slot, Private->Capability[Slot]);
691     if (EFI_ERROR (Status)) {
692       return Status;
693     }
694 
695     //
696     // Reset HC
697     //
698     Status = DwMmcHcReset (PciIo, Slot, Private->Capability[Slot]);
699     if (EFI_ERROR (Status)) {
700       return Status;
701     }
702 
703     Private->Slot[Slot].CardType = Private->Capability[Slot].CardType;
704     Private->Slot[Slot].Enable = TRUE;
705     Private->Slot[Slot].MediaPresent = TRUE;
706 
707     RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
708     for (Index = 0; Index < RoutineNum; Index++) {
709       Routine = &mCardTypeDetectRoutineTable[Index];
710       if (*Routine != NULL) {
711         Status = (*Routine) (Private, Slot);
712         if (!EFI_ERROR (Status)) {
713           break;
714         }
715       }
716     }
717   }
718 
719   //
720   // Enable 64-bit DMA support in the PCI layer if this controller
721   // supports it.
722   //
723   if (Support64BitDma) {
724     Status = PciIo->Attributes (
725                       PciIo,
726                       EfiPciIoAttributeOperationEnable,
727                       EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
728                       NULL
729                       );
730     if (EFI_ERROR (Status)) {
731       DEBUG ((DEBUG_WARN, "DwMmcHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status));
732     }
733   }
734 
735   //
736   // Start the asynchronous I/O monitor
737   //
738   Status = gBS->CreateEvent (
739                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
740                   TPL_NOTIFY,
741                   ProcessAsyncTaskList,
742                   Private,
743                   &Private->TimerEvent
744                   );
745   if (EFI_ERROR (Status)) {
746     goto Done;
747   }
748 
749   Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, DW_MMC_HC_ASYNC_TIMER);
750   if (EFI_ERROR (Status)) {
751     goto Done;
752   }
753 
754   //
755   // Start the Sd removable device connection enumeration
756   //
757   Status = gBS->CreateEvent (
758                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
759                   TPL_CALLBACK,
760                   DwMmcHcEnumerateDevice,
761                   Private,
762                   &Private->ConnectEvent
763                   );
764   if (EFI_ERROR (Status)) {
765     goto Done;
766   }
767 
768   Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, DW_MMC_HC_ENUM_TIMER);
769   if (EFI_ERROR (Status)) {
770     goto Done;
771   }
772 
773   Status = gBS->InstallMultipleProtocolInterfaces (
774                   &Controller,
775                   &gEfiSdMmcPassThruProtocolGuid,
776                   &(Private->PassThru),
777                   NULL
778                   );
779 
780   DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStart: %r End on %x\n", Status, Controller));
781 
782 Done:
783   if (EFI_ERROR (Status)) {
784     if ((Private != NULL) && (Private->PciAttributes != 0)) {
785       //
786       // Restore original PCI attributes
787       //
788       PciIo->Attributes (
789                PciIo,
790                EfiPciIoAttributeOperationSet,
791                Private->PciAttributes,
792                NULL
793                );
794     }
795     gBS->CloseProtocol (
796           Controller,
797           &gEfiPciIoProtocolGuid,
798           This->DriverBindingHandle,
799           Controller
800           );
801 
802     if ((Private != NULL) && (Private->TimerEvent != NULL)) {
803       gBS->CloseEvent (Private->TimerEvent);
804     }
805 
806     if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
807       gBS->CloseEvent (Private->ConnectEvent);
808     }
809 
810     if (Private != NULL) {
811       FreePool (Private);
812     }
813   }
814 
815   return Status;
816 }
817 
818 /**
819   Stops a device controller or a bus controller.
820 
821   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
822   As a result, much of the error checking on the parameters to Stop() has been moved
823   into this common boot service. It is legal to call Stop() from other locations,
824   but the following calling restrictions must be followed or the system behavior will not be deterministic.
825   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
826      same driver's Start() function.
827   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
828      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
829      Start() function, and the Start() function must have called OpenProtocol() on
830      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
831 
832   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
833   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
834                                 support a bus specific I/O protocol for the driver
835                                 to use to stop the device.
836   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
837   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
838                                 if NumberOfChildren is 0.
839 
840   @retval EFI_SUCCESS           The device was stopped.
841   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
842 
843 **/
844 EFI_STATUS
845 EFIAPI
DwMmcHcDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)846 DwMmcHcDriverBindingStop (
847   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
848   IN  EFI_HANDLE                      Controller,
849   IN  UINTN                           NumberOfChildren,
850   IN  EFI_HANDLE                      *ChildHandleBuffer
851   )
852 {
853   EFI_STATUS                          Status;
854   EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
855   DW_MMC_HC_PRIVATE_DATA              *Private;
856   EFI_PCI_IO_PROTOCOL                 *PciIo;
857   LIST_ENTRY                          *Link;
858   LIST_ENTRY                          *NextLink;
859   DW_MMC_HC_TRB                       *Trb;
860 
861   DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: Start\n"));
862 
863   Status = gBS->OpenProtocol (
864                   Controller,
865                   &gEfiSdMmcPassThruProtocolGuid,
866                   (VOID**) &PassThru,
867                   This->DriverBindingHandle,
868                   Controller,
869                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
870                   );
871   if (EFI_ERROR (Status)) {
872     return Status;
873   }
874 
875   Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
876   //
877   // Close Non-Blocking timer and free Task list.
878   //
879   if (Private->TimerEvent != NULL) {
880     gBS->CloseEvent (Private->TimerEvent);
881     Private->TimerEvent = NULL;
882   }
883   if (Private->ConnectEvent != NULL) {
884     gBS->CloseEvent (Private->ConnectEvent);
885     Private->ConnectEvent = NULL;
886   }
887   //
888   // As the timer is closed, there is no needs to use TPL lock to
889   // protect the critical region "queue".
890   //
891   for (Link = GetFirstNode (&Private->Queue);
892        !IsNull (&Private->Queue, Link);
893        Link = NextLink) {
894     NextLink = GetNextNode (&Private->Queue, Link);
895     RemoveEntryList (Link);
896     Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
897     Trb->Packet->TransactionStatus = EFI_ABORTED;
898     gBS->SignalEvent (Trb->Event);
899     DwMmcFreeTrb (Trb);
900   }
901 
902   //
903   // Uninstall Block I/O protocol from the device handle
904   //
905   Status = gBS->UninstallProtocolInterface (
906                   Controller,
907                   &gEfiSdMmcPassThruProtocolGuid,
908                   &(Private->PassThru)
909                   );
910 
911   if (EFI_ERROR (Status)) {
912     return Status;
913   }
914 
915   gBS->CloseProtocol (
916          Controller,
917          &gEfiPciIoProtocolGuid,
918          This->DriverBindingHandle,
919          Controller
920          );
921   //
922   // Restore original PCI attributes
923   //
924   PciIo  = Private->PciIo;
925   Status = PciIo->Attributes (
926                     PciIo,
927                     EfiPciIoAttributeOperationSet,
928                     Private->PciAttributes,
929                     NULL
930                     );
931   ASSERT_EFI_ERROR (Status);
932 
933   FreePool (Private);
934 
935   DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: End with %r\n", Status));
936 
937   return Status;
938 }
939 
940 /**
941   Sends SD command to an SD card that is attached to the SD controller.
942 
943   The PassThru() function sends the SD command specified by Packet to the SD card
944   specified by Slot.
945 
946   If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
947 
948   If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
949 
950   If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
951   is returned.
952 
953   If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
954   EFI_INVALID_PARAMETER is returned.
955 
956   @param[in]     This           A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
957   @param[in]     Slot           The slot number of the SD card to send the command to.
958   @param[in,out] Packet         A pointer to the SD command data structure.
959   @param[in]     Event          If Event is NULL, blocking I/O is performed. If Event is
960                                 not NULL, then nonblocking I/O is performed, and Event
961                                 will be signaled when the Packet completes.
962 
963   @retval EFI_SUCCESS           The SD Command Packet was sent by the host.
964   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SD
965                                 command Packet.
966   @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
967   @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
968                                 OutDataBuffer are NULL.
969   @retval EFI_NO_MEDIA          SD Device not present in the Slot.
970   @retval EFI_UNSUPPORTED       The command described by the SD Command Packet is not
971                                 supported by the host controller.
972   @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength exceeds the
973                                 limit supported by SD card ( i.e. if the number of bytes
974                                 exceed the Last LBA).
975 
976 **/
977 EFI_STATUS
978 EFIAPI
DwMmcPassThruPassThru(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN UINT8 Slot,IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET * Packet,IN EFI_EVENT Event OPTIONAL)979 DwMmcPassThruPassThru (
980   IN     EFI_SD_MMC_PASS_THRU_PROTOCOL         *This,
981   IN     UINT8                                 Slot,
982   IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   *Packet,
983   IN     EFI_EVENT                             Event    OPTIONAL
984   )
985 {
986   EFI_STATUS                      Status;
987   DW_MMC_HC_PRIVATE_DATA          *Private;
988   DW_MMC_HC_TRB                   *Trb;
989   EFI_TPL                         OldTpl;
990 
991   if ((This == NULL) || (Packet == NULL)) {
992     return EFI_INVALID_PARAMETER;
993   }
994 
995   if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {
996     return EFI_INVALID_PARAMETER;
997   }
998 
999   if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
1000     return EFI_INVALID_PARAMETER;
1001   }
1002 
1003   if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
1004     return EFI_INVALID_PARAMETER;
1005   }
1006 
1007   Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
1008 
1009   if (!Private->Slot[Slot].Enable) {
1010     return EFI_INVALID_PARAMETER;
1011   }
1012 
1013   if (!Private->Slot[Slot].MediaPresent) {
1014     return EFI_NO_MEDIA;
1015   }
1016 
1017   Trb = DwMmcCreateTrb (Private, Slot, Packet, Event);
1018   if (Trb == NULL) {
1019     return EFI_OUT_OF_RESOURCES;
1020   }
1021   //
1022   // Immediately return for async I/O.
1023   //
1024   if (Event != NULL) {
1025     return EFI_SUCCESS;
1026   }
1027 
1028   //
1029   // Wait async I/O list is empty before execute sync I/O operation.
1030   //
1031   while (TRUE) {
1032     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1033     if (IsListEmpty (&Private->Queue)) {
1034       gBS->RestoreTPL (OldTpl);
1035       break;
1036     }
1037     gBS->RestoreTPL (OldTpl);
1038   }
1039 
1040   Status = DwMmcWaitTrbEnv (Private, Trb);
1041   if (EFI_ERROR (Status)) {
1042     goto Done;
1043   }
1044 
1045   Status = DwMmcExecTrb (Private, Trb);
1046   if (EFI_ERROR (Status)) {
1047     goto Done;
1048   }
1049 
1050   Status = DwMmcWaitTrbResult (Private, Trb);
1051   if (EFI_ERROR (Status)) {
1052     goto Done;
1053   }
1054 
1055 Done:
1056 #if 0
1057   if ((Trb != NULL) && (Trb->DmaDesc != NULL)) {
1058     FreePages (Trb->DmaDesc, Trb->DmaDescPages);
1059   }
1060 
1061   if (Trb != NULL) {
1062     FreePool (Trb);
1063   }
1064 #else
1065   if (Trb != NULL) {
1066     DwMmcFreeTrb (Trb);
1067   }
1068 #endif
1069 
1070   return Status;
1071 }
1072 
1073 /**
1074   Used to retrieve next slot numbers supported by the SD controller. The function
1075   returns information about all available slots (populated or not-populated).
1076 
1077   The GetNextSlot() function retrieves the next slot number on an SD controller.
1078   If on input Slot is 0xFF, then the slot number of the first slot on the SD controller
1079   is returned.
1080 
1081   If Slot is a slot number that was returned on a previous call to GetNextSlot(), then
1082   the slot number of the next slot on the SD controller is returned.
1083 
1084   If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),
1085   EFI_INVALID_PARAMETER is returned.
1086 
1087   If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND
1088   is returned.
1089 
1090   @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
1091   @param[in,out] Slot           On input, a pointer to a slot number on the SD controller.
1092                                 On output, a pointer to the next slot number on the SD controller.
1093                                 An input value of 0xFF retrieves the first slot number on the SD
1094                                 controller.
1095 
1096   @retval EFI_SUCCESS           The next slot number on the SD controller was returned in Slot.
1097   @retval EFI_NOT_FOUND         There are no more slots on this SD controller.
1098   @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call
1099                                 to GetNextSlot().
1100 
1101 **/
1102 EFI_STATUS
1103 EFIAPI
DwMmcPassThruGetNextSlot(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN OUT UINT8 * Slot)1104 DwMmcPassThruGetNextSlot (
1105   IN     EFI_SD_MMC_PASS_THRU_PROTOCOL        *This,
1106   IN OUT UINT8                                *Slot
1107   )
1108 {
1109   DW_MMC_HC_PRIVATE_DATA          *Private;
1110   UINT8                           Index;
1111 
1112   if ((This == NULL) || (Slot == NULL)) {
1113     return EFI_INVALID_PARAMETER;
1114   }
1115 
1116   Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
1117 
1118   if (*Slot == 0xFF) {
1119     for (Index = 0; Index < DW_MMC_HC_MAX_SLOT; Index++) {
1120       if (Private->Slot[Index].Enable) {
1121         *Slot = Index;
1122         Private->PreviousSlot = Index;
1123         return EFI_SUCCESS;
1124       }
1125     }
1126     return EFI_NOT_FOUND;
1127   } else if (*Slot == Private->PreviousSlot) {
1128     for (Index = *Slot + 1; Index < DW_MMC_HC_MAX_SLOT; Index++) {
1129       if (Private->Slot[Index].Enable) {
1130         *Slot = Index;
1131         Private->PreviousSlot = Index;
1132         return EFI_SUCCESS;
1133       }
1134     }
1135     return EFI_NOT_FOUND;
1136   } else {
1137     return EFI_INVALID_PARAMETER;
1138   }
1139 }
1140 
1141 /**
1142   Used to allocate and build a device path node for an SD card on the SD controller.
1143 
1144   The BuildDevicePath() function allocates and builds a single device node for the SD
1145   card specified by Slot.
1146 
1147   If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND
1148   is returned.
1149 
1150   If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
1151 
1152   If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES
1153   is returned.
1154 
1155   Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
1156   DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is
1157   returned.
1158 
1159   @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
1160   @param[in]     Slot           Specifies the slot number of the SD card for which a device
1161                                 path node is to be allocated and built.
1162   @param[in,out] DevicePath     A pointer to a single device path node that describes the SD
1163                                 card specified by Slot. This function is responsible for
1164                                 allocating the buffer DevicePath with the boot service
1165                                 AllocatePool(). It is the caller's responsibility to free
1166                                 DevicePath when the caller is finished with DevicePath.
1167 
1168   @retval EFI_SUCCESS           The device path node that describes the SD card specified by
1169                                 Slot was allocated and returned in DevicePath.
1170   @retval EFI_NOT_FOUND         The SD card specified by Slot does not exist on the SD controller.
1171   @retval EFI_INVALID_PARAMETER DevicePath is NULL.
1172   @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.
1173 
1174 **/
1175 EFI_STATUS
1176 EFIAPI
DwMmcPassThruBuildDevicePath(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN UINT8 Slot,IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)1177 DwMmcPassThruBuildDevicePath (
1178   IN     EFI_SD_MMC_PASS_THRU_PROTOCOL       *This,
1179   IN     UINT8                               Slot,
1180   IN OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
1181   )
1182 {
1183   DW_MMC_HC_PRIVATE_DATA          *Private;
1184   SD_DEVICE_PATH                  *SdNode;
1185   EMMC_DEVICE_PATH                *EmmcNode;
1186 
1187   if ((This == NULL) || (DevicePath == NULL) || (Slot >= DW_MMC_HC_MAX_SLOT)) {
1188     return EFI_INVALID_PARAMETER;
1189   }
1190 
1191   Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
1192 
1193   if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
1194     return EFI_NOT_FOUND;
1195   }
1196 
1197   if (Private->Slot[Slot].CardType == SdCardType) {
1198     SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);
1199     if (SdNode == NULL) {
1200       return EFI_OUT_OF_RESOURCES;
1201     }
1202     SdNode->SlotNumber = Slot;
1203 
1204     *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
1205   } else if (Private->Slot[Slot].CardType == EmmcCardType) {
1206     EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);
1207     if (EmmcNode == NULL) {
1208       return EFI_OUT_OF_RESOURCES;
1209     }
1210     EmmcNode->SlotNumber = Slot;
1211 
1212     *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
1213   } else {
1214     //
1215     // Currently we only support SD and EMMC two device nodes.
1216     //
1217     return EFI_NOT_FOUND;
1218   }
1219 
1220   return EFI_SUCCESS;
1221 }
1222 
1223 /**
1224   This function retrieves an SD card slot number based on the input device path.
1225 
1226   The GetSlotNumber() function retrieves slot number for the SD card specified by
1227   the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.
1228 
1229   If DevicePath is not a device path node type that the SD Pass Thru driver supports,
1230   EFI_UNSUPPORTED is returned.
1231 
1232   @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
1233   @param[in]  DevicePath        A pointer to the device path node that describes a SD
1234                                 card on the SD controller.
1235   @param[out] Slot              On return, points to the slot number of an SD card on
1236                                 the SD controller.
1237 
1238   @retval EFI_SUCCESS           SD card slot number is returned in Slot.
1239   @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
1240   @retval EFI_UNSUPPORTED       DevicePath is not a device path node type that the SD
1241                                 Pass Thru driver supports.
1242 
1243 **/
1244 EFI_STATUS
1245 EFIAPI
DwMmcPassThruGetSlotNumber(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT UINT8 * Slot)1246 DwMmcPassThruGetSlotNumber (
1247   IN  EFI_SD_MMC_PASS_THRU_PROTOCOL          *This,
1248   IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath,
1249   OUT UINT8                                  *Slot
1250   )
1251 {
1252   DW_MMC_HC_PRIVATE_DATA          *Private;
1253   SD_DEVICE_PATH                  *SdNode;
1254   EMMC_DEVICE_PATH                *EmmcNode;
1255   UINT8                           SlotNumber;
1256 
1257   if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
1258     return EFI_INVALID_PARAMETER;
1259   }
1260 
1261   Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
1262 
1263   //
1264   // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH
1265   //
1266   if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
1267       ((DevicePath->SubType != MSG_SD_DP) &&
1268        (DevicePath->SubType != MSG_EMMC_DP)) ||
1269       (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
1270       (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {
1271     return EFI_UNSUPPORTED;
1272   }
1273 
1274   if (DevicePath->SubType == MSG_SD_DP) {
1275     SdNode = (SD_DEVICE_PATH *) DevicePath;
1276     SlotNumber = SdNode->SlotNumber;
1277   } else {
1278     EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
1279     SlotNumber = EmmcNode->SlotNumber;
1280   }
1281 
1282   if (SlotNumber >= DW_MMC_HC_MAX_SLOT) {
1283     return EFI_NOT_FOUND;
1284   }
1285 
1286   if (Private->Slot[SlotNumber].Enable) {
1287     *Slot = SlotNumber;
1288     return EFI_SUCCESS;
1289   } else {
1290     return EFI_NOT_FOUND;
1291   }
1292 }
1293 
1294 /**
1295   Resets an SD card that is connected to the SD controller.
1296 
1297   The ResetDevice() function resets the SD card specified by Slot.
1298 
1299   If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is
1300   returned.
1301 
1302   If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER
1303   is returned.
1304 
1305   If the device reset operation is completed, EFI_SUCCESS is returned.
1306 
1307   @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
1308   @param[in]  Slot              Specifies the slot number of the SD card to be reset.
1309 
1310   @retval EFI_SUCCESS           The SD card specified by Slot was reset.
1311   @retval EFI_UNSUPPORTED       The SD controller does not support a device reset operation.
1312   @retval EFI_INVALID_PARAMETER Slot number is invalid.
1313   @retval EFI_NO_MEDIA          SD Device not present in the Slot.
1314   @retval EFI_DEVICE_ERROR      The reset command failed due to a device error
1315 
1316 **/
1317 EFI_STATUS
1318 EFIAPI
DwMmcPassThruResetDevice(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN UINT8 Slot)1319 DwMmcPassThruResetDevice (
1320   IN EFI_SD_MMC_PASS_THRU_PROTOCOL           *This,
1321   IN UINT8                                   Slot
1322   )
1323 {
1324   DW_MMC_HC_PRIVATE_DATA          *Private;
1325   LIST_ENTRY                      *Link;
1326   LIST_ENTRY                      *NextLink;
1327   DW_MMC_HC_TRB                   *Trb;
1328   EFI_TPL                         OldTpl;
1329 
1330   if (This == NULL) {
1331     return EFI_INVALID_PARAMETER;
1332   }
1333 
1334   Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
1335 
1336   if (!Private->Slot[Slot].Enable) {
1337     return EFI_INVALID_PARAMETER;
1338   }
1339 
1340   if (!Private->Slot[Slot].MediaPresent) {
1341     return EFI_NO_MEDIA;
1342   }
1343 
1344   //
1345   // Free all async I/O requests in the queue
1346   //
1347   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1348 
1349   for (Link = GetFirstNode (&Private->Queue);
1350        !IsNull (&Private->Queue, Link);
1351        Link = NextLink) {
1352     NextLink = GetNextNode (&Private->Queue, Link);
1353     RemoveEntryList (Link);
1354     Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
1355     Trb->Packet->TransactionStatus = EFI_ABORTED;
1356     gBS->SignalEvent (Trb->Event);
1357     DwMmcFreeTrb (Trb);
1358   }
1359 
1360   gBS->RestoreTPL (OldTpl);
1361 
1362   return EFI_SUCCESS;
1363 }
1364