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