1 /** @file
2 *
3 * Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
4 * Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.
5 *
6 * This program and the accompanying materials
7 * are licensed and made available under the terms and conditions of the BSD License
8 * which accompanies this distribution. The full text of the license may be found at
9 * http://opensource.org/licenses/bsd-license.php
10 *
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15
16 #include "MmcHostDxe.h"
17
18 EMBEDDED_EXTERNAL_DEVICE *gTPS65950;
19 UINT8 mMaxDataTransferRate = 0;
20 UINT32 mRca = 0;
21 BOOLEAN mBitModeSet = FALSE;
22
23
24 typedef struct {
25 VENDOR_DEVICE_PATH Mmc;
26 EFI_DEVICE_PATH End;
27 } MMCHS_DEVICE_PATH;
28
29 MMCHS_DEVICE_PATH gMMCDevicePath = {
30 {
31 {
32 HARDWARE_DEVICE_PATH,
33 HW_VENDOR_DP,
34 { (UINT8)(sizeof(VENDOR_DEVICE_PATH)), (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) },
35 },
36 { 0xb615f1f5, 0x5088, 0x43cd, { 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 } }
37 },
38 {
39 END_DEVICE_PATH_TYPE,
40 END_ENTIRE_DEVICE_PATH_SUBTYPE,
41 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
42 }
43 };
44
45 BOOLEAN
IgnoreCommand(UINT32 Command)46 IgnoreCommand (
47 UINT32 Command
48 )
49 {
50 switch(Command) {
51 case MMC_CMD12:
52 return TRUE;
53 case MMC_CMD13:
54 return TRUE;
55 default:
56 return FALSE;
57 }
58 }
59
60 UINT32
TranslateCommand(UINT32 Command)61 TranslateCommand (
62 UINT32 Command
63 )
64 {
65 UINT32 Translation;
66
67 switch(Command) {
68 case MMC_CMD2:
69 Translation = CMD2;
70 break;
71 case MMC_CMD3:
72 Translation = CMD3;
73 break;
74 /*case MMC_CMD6:
75 Translation = CMD6;
76 break;*/
77 case MMC_CMD7:
78 Translation = CMD7;
79 break;
80 case MMC_CMD8:
81 Translation = CMD8;
82 break;
83 case MMC_CMD9:
84 Translation = CMD9;
85 break;
86 /*case MMC_CMD12:
87 Translation = CMD12;
88 break;
89 case MMC_CMD13:
90 Translation = CMD13;
91 break;*/
92 case MMC_CMD16:
93 Translation = CMD16;
94 break;
95 case MMC_CMD17:
96 Translation = 0x113A0014;//CMD17;
97 break;
98 case MMC_CMD24:
99 Translation = CMD24 | 4;
100 break;
101 case MMC_CMD55:
102 Translation = CMD55;
103 break;
104 case MMC_ACMD41:
105 Translation = ACMD41;
106 break;
107 default:
108 Translation = Command;
109 }
110
111 return Translation;
112 }
113
114 VOID
CalculateCardCLKD(UINTN * ClockFrequencySelect)115 CalculateCardCLKD (
116 UINTN *ClockFrequencySelect
117 )
118 {
119 UINTN TransferRateValue = 0;
120 UINTN TimeValue = 0 ;
121 UINTN Frequency = 0;
122
123 DEBUG ((DEBUG_BLKIO, "CalculateCardCLKD()\n"));
124
125 // For SD Cards we would need to send CMD6 to set
126 // speeds abouve 25MHz. High Speed mode 50 MHz and up
127
128 // Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
129 switch (mMaxDataTransferRate & 0x7) { // 2
130 case 0:
131 TransferRateValue = 100 * 1000;
132 break;
133
134 case 1:
135 TransferRateValue = 1 * 1000 * 1000;
136 break;
137
138 case 2:
139 TransferRateValue = 10 * 1000 * 1000;
140 break;
141
142 case 3:
143 TransferRateValue = 100 * 1000 * 1000;
144 break;
145
146 default:
147 DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));
148 ASSERT(FALSE);
149 return;
150 }
151
152 //Calculate Time value (Bits 6:3 of TRAN_SPEED)
153 switch ((mMaxDataTransferRate >> 3) & 0xF) { // 6
154 case 1:
155 TimeValue = 10;
156 break;
157
158 case 2:
159 TimeValue = 12;
160 break;
161
162 case 3:
163 TimeValue = 13;
164 break;
165
166 case 4:
167 TimeValue = 15;
168 break;
169
170 case 5:
171 TimeValue = 20;
172 break;
173
174 case 6:
175 TimeValue = 25;
176 break;
177
178 case 7:
179 TimeValue = 30;
180 break;
181
182 case 8:
183 TimeValue = 35;
184 break;
185
186 case 9:
187 TimeValue = 40;
188 break;
189
190 case 10:
191 TimeValue = 45;
192 break;
193
194 case 11:
195 TimeValue = 50;
196 break;
197
198 case 12:
199 TimeValue = 55;
200 break;
201
202 case 13:
203 TimeValue = 60;
204 break;
205
206 case 14:
207 TimeValue = 70;
208 break;
209
210 case 15:
211 TimeValue = 80;
212 break;
213
214 default:
215 DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));
216 ASSERT(FALSE);
217 return;
218 }
219
220 Frequency = TransferRateValue * TimeValue/10;
221
222 // Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.
223 *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);
224
225 DEBUG ((DEBUG_BLKIO, "mMaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", mMaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));
226 }
227
228 VOID
UpdateMMCHSClkFrequency(UINTN NewCLKD)229 UpdateMMCHSClkFrequency (
230 UINTN NewCLKD
231 )
232 {
233 DEBUG ((DEBUG_BLKIO, "UpdateMMCHSClkFrequency()\n"));
234
235 // Set Clock enable to 0x0 to not provide the clock to the card
236 MmioAnd32 (MMCHS_SYSCTL, ~CEN);
237
238 // Set new clock frequency.
239 MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6);
240
241 // Poll till Internal Clock Stable
242 while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);
243
244 // Set Clock enable to 0x1 to provide the clock to the card
245 MmioOr32 (MMCHS_SYSCTL, CEN);
246 }
247
248 EFI_STATUS
InitializeMMCHS(VOID)249 InitializeMMCHS (
250 VOID
251 )
252 {
253 UINT8 Data;
254 EFI_STATUS Status;
255
256 DEBUG ((DEBUG_BLKIO, "InitializeMMCHS()\n"));
257
258 // Select Device group to belong to P1 device group in Power IC.
259 Data = DEV_GRP_P1;
260 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);
261 ASSERT_EFI_ERROR(Status);
262
263 // Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.
264 Data = VSEL_3_00V;
265 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);
266 ASSERT_EFI_ERROR(Status);
267
268 // After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.
269 MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));
270
271 // Enable WP GPIO
272 MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);
273
274 // Enable Card Detect
275 Data = CARD_DETECT_ENABLE;
276 gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);
277
278 return Status;
279 }
280
281 BOOLEAN
MMCIsCardPresent(IN EFI_MMC_HOST_PROTOCOL * This)282 MMCIsCardPresent (
283 IN EFI_MMC_HOST_PROTOCOL *This
284 )
285 {
286 EFI_STATUS Status;
287 UINT8 Data;
288
289 //
290 // Card detect is a GPIO0 on the TPS65950
291 //
292 Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);
293 if (EFI_ERROR (Status)) {
294 return FALSE;
295 }
296
297 return !(Data & CARD_DETECT_BIT);
298 }
299
300 BOOLEAN
MMCIsReadOnly(IN EFI_MMC_HOST_PROTOCOL * This)301 MMCIsReadOnly (
302 IN EFI_MMC_HOST_PROTOCOL *This
303 )
304 {
305 /* Note:
306 * On our BeagleBoard the SD card WP pin is always read as TRUE.
307 * Probably something wrong with GPIO configuration.
308 * BeagleBoard-xM uses microSD cards so there is no write protect at all.
309 * Hence commenting out SD card WP pin read status.
310 */
311 //return (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;
312 return 0;
313
314 }
315
316 // TODO
317 EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
318
319 EFI_STATUS
MMCBuildDevicePath(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL ** DevicePath)320 MMCBuildDevicePath (
321 IN EFI_MMC_HOST_PROTOCOL *This,
322 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
323 )
324 {
325 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
326
327 NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH));
328 CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid);
329 *DevicePath = NewDevicePathNode;
330 return EFI_SUCCESS;
331 }
332
333 EFI_STATUS
MMCSendCommand(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_CMD MmcCmd,IN UINT32 Argument)334 MMCSendCommand (
335 IN EFI_MMC_HOST_PROTOCOL *This,
336 IN MMC_CMD MmcCmd,
337 IN UINT32 Argument
338 )
339 {
340 UINTN MmcStatus;
341 UINTN RetryCount = 0;
342
343 if (IgnoreCommand(MmcCmd))
344 return EFI_SUCCESS;
345
346 MmcCmd = TranslateCommand(MmcCmd);
347
348 //DEBUG ((EFI_D_ERROR, "MMCSendCommand(%d)\n", MmcCmd));
349
350 // Check if command line is in use or not. Poll till command line is available.
351 while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);
352
353 // Provide the block size.
354 MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);
355
356 // Setting Data timeout counter value to max value.
357 MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);
358
359 // Clear Status register.
360 MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);
361
362 // Set command argument register
363 MmioWrite32 (MMCHS_ARG, Argument);
364
365 //TODO: fix this
366 //Enable interrupt enable events to occur
367 //MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);
368
369 // Send a command
370 MmioWrite32 (MMCHS_CMD, MmcCmd);
371
372 // Check for the command status.
373 while (RetryCount < MAX_RETRY_COUNT) {
374 do {
375 MmcStatus = MmioRead32 (MMCHS_STAT);
376 } while (MmcStatus == 0);
377
378 // Read status of command response
379 if ((MmcStatus & ERRI) != 0) {
380
381 // Perform soft-reset for mmci_cmd line.
382 MmioOr32 (MMCHS_SYSCTL, SRC);
383 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
384
385 //DEBUG ((EFI_D_INFO, "MmcStatus: 0x%x\n", MmcStatus));
386 return EFI_DEVICE_ERROR;
387 }
388
389 // Check if command is completed.
390 if ((MmcStatus & CC) == CC) {
391 MmioWrite32 (MMCHS_STAT, CC);
392 break;
393 }
394
395 RetryCount++;
396 }
397
398 if (RetryCount == MAX_RETRY_COUNT) {
399 DEBUG ((DEBUG_BLKIO, "MMCSendCommand: Timeout\n"));
400 return EFI_TIMEOUT;
401 }
402
403 return EFI_SUCCESS;
404 }
405
406 EFI_STATUS
MMCNotifyState(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_STATE State)407 MMCNotifyState (
408 IN EFI_MMC_HOST_PROTOCOL *This,
409 IN MMC_STATE State
410 )
411 {
412 EFI_STATUS Status;
413 UINTN FreqSel;
414
415 switch(State) {
416 case MmcInvalidState:
417 ASSERT(0);
418 break;
419 case MmcHwInitializationState:
420 mBitModeSet = FALSE;
421
422 DEBUG ((DEBUG_BLKIO, "MMCHwInitializationState()\n"));
423 Status = InitializeMMCHS ();
424 if (EFI_ERROR(Status)) {
425 DEBUG ((DEBUG_BLKIO, "Initialize MMC host controller fails. Status: %x\n", Status));
426 return Status;
427 }
428
429 // Software reset of the MMCHS host controller.
430 MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);
431 gBS->Stall(1000);
432 while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);
433
434 // Soft reset for all.
435 MmioWrite32 (MMCHS_SYSCTL, SRA);
436 gBS->Stall(1000);
437 while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);
438
439 //Voltage capabilities initialization. Activate VS18 and VS30.
440 MmioOr32 (MMCHS_CAPA, (VS30 | VS18));
441
442 // Wakeup configuration
443 MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);
444 MmioOr32 (MMCHS_HCTL, IWE);
445
446 // MMCHS Controller default initialization
447 MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));
448
449 MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));
450
451 // Enable internal clock
452 MmioOr32 (MMCHS_SYSCTL, ICE);
453
454 // Set the clock frequency to 80KHz.
455 UpdateMMCHSClkFrequency (CLKD_80KHZ);
456
457 // Enable SD bus power.
458 MmioOr32 (MMCHS_HCTL, (SDBP_ON));
459
460 // Poll till SD bus power bit is set.
461 while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);
462
463 // Enable interrupts.
464 MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |
465 CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));
466
467 // Controller INIT procedure start.
468 MmioOr32 (MMCHS_CON, INIT);
469 MmioWrite32 (MMCHS_CMD, 0x00000000);
470 while (!(MmioRead32 (MMCHS_STAT) & CC));
471
472 // Wait for 1 ms
473 gBS->Stall (1000);
474
475 // Set CC bit to 0x1 to clear the flag
476 MmioOr32 (MMCHS_STAT, CC);
477
478 // Retry INIT procedure.
479 MmioWrite32 (MMCHS_CMD, 0x00000000);
480 while (!(MmioRead32 (MMCHS_STAT) & CC));
481
482 // End initialization sequence
483 MmioAnd32 (MMCHS_CON, ~INIT);
484
485 MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));
486
487 // Change clock frequency to 400KHz to fit protocol
488 UpdateMMCHSClkFrequency(CLKD_400KHZ);
489
490 MmioOr32 (MMCHS_CON, OD);
491 break;
492 case MmcIdleState:
493 break;
494 case MmcReadyState:
495 break;
496 case MmcIdentificationState:
497 break;
498 case MmcStandByState:
499 CalculateCardCLKD (&FreqSel);
500 UpdateMMCHSClkFrequency (FreqSel);
501 break;
502 case MmcTransferState:
503 if (!mBitModeSet) {
504 Status = MMCSendCommand (This, CMD55, mRca << 16);
505 if (!EFI_ERROR (Status)) {
506 // Set device into 4-bit data bus mode
507 Status = MMCSendCommand (This, ACMD6, 0x2);
508 if (!EFI_ERROR (Status)) {
509 // Set host controler into 4-bit mode
510 MmioOr32 (MMCHS_HCTL, DTW_4_BIT);
511 DEBUG ((DEBUG_BLKIO, "SD Memory Card set to 4-bit mode\n"));
512 mBitModeSet = TRUE;
513 }
514 }
515 }
516 break;
517 case MmcSendingDataState:
518 break;
519 case MmcReceiveDataState:
520 break;
521 case MmcProgrammingState:
522 break;
523 case MmcDisconnectState:
524 default:
525 ASSERT(0);
526 }
527 return EFI_SUCCESS;
528 }
529
530 EFI_STATUS
MMCReceiveResponse(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_RESPONSE_TYPE Type,IN UINT32 * Buffer)531 MMCReceiveResponse (
532 IN EFI_MMC_HOST_PROTOCOL *This,
533 IN MMC_RESPONSE_TYPE Type,
534 IN UINT32* Buffer
535 )
536 {
537 if (Buffer == NULL) {
538 return EFI_INVALID_PARAMETER;
539 }
540
541 if (Type == MMC_RESPONSE_TYPE_R2) {
542 Buffer[0] = MmioRead32 (MMCHS_RSP10);
543 Buffer[1] = MmioRead32 (MMCHS_RSP32);
544 Buffer[2] = MmioRead32 (MMCHS_RSP54);
545 Buffer[3] = MmioRead32 (MMCHS_RSP76);
546 } else {
547 Buffer[0] = MmioRead32 (MMCHS_RSP10);
548 }
549
550 if (Type == MMC_RESPONSE_TYPE_CSD) {
551 mMaxDataTransferRate = Buffer[3] & 0xFF;
552 } else if (Type == MMC_RESPONSE_TYPE_RCA) {
553 mRca = Buffer[0] >> 16;
554 }
555
556 return EFI_SUCCESS;
557 }
558
559 EFI_STATUS
MMCReadBlockData(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Length,IN UINT32 * Buffer)560 MMCReadBlockData (
561 IN EFI_MMC_HOST_PROTOCOL *This,
562 IN EFI_LBA Lba,
563 IN UINTN Length,
564 IN UINT32* Buffer
565 )
566 {
567 UINTN MmcStatus;
568 UINTN Count;
569 UINTN RetryCount = 0;
570
571 DEBUG ((DEBUG_BLKIO, "MMCReadBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n", Lba, Length, Buffer));
572
573 // Check controller status to make sure there is no error.
574 while (RetryCount < MAX_RETRY_COUNT) {
575 do {
576 // Read Status.
577 MmcStatus = MmioRead32 (MMCHS_STAT);
578 } while(MmcStatus == 0);
579
580 // Check if Buffer read ready (BRR) bit is set?
581 if (MmcStatus & BRR) {
582
583 // Clear BRR bit
584 MmioOr32 (MMCHS_STAT, BRR);
585
586 for (Count = 0; Count < Length / 4; Count++) {
587 *Buffer++ = MmioRead32(MMCHS_DATA);
588 }
589 break;
590 }
591 RetryCount++;
592 }
593
594 if (RetryCount == MAX_RETRY_COUNT) {
595 return EFI_TIMEOUT;
596 }
597
598 return EFI_SUCCESS;
599 }
600
601 EFI_STATUS
MMCWriteBlockData(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Length,IN UINT32 * Buffer)602 MMCWriteBlockData (
603 IN EFI_MMC_HOST_PROTOCOL *This,
604 IN EFI_LBA Lba,
605 IN UINTN Length,
606 IN UINT32* Buffer
607 )
608 {
609 UINTN MmcStatus;
610 UINTN Count;
611 UINTN RetryCount = 0;
612
613 // Check controller status to make sure there is no error.
614 while (RetryCount < MAX_RETRY_COUNT) {
615 do {
616 // Read Status.
617 MmcStatus = MmioRead32 (MMCHS_STAT);
618 } while(MmcStatus == 0);
619
620 // Check if Buffer write ready (BWR) bit is set?
621 if (MmcStatus & BWR) {
622
623 // Clear BWR bit
624 MmioOr32 (MMCHS_STAT, BWR);
625
626 // Write block worth of data.
627 for (Count = 0; Count < Length / 4; Count++) {
628 MmioWrite32 (MMCHS_DATA, *Buffer++);
629 }
630
631 break;
632 }
633 RetryCount++;
634 }
635
636 if (RetryCount == MAX_RETRY_COUNT) {
637 return EFI_TIMEOUT;
638 }
639
640 return EFI_SUCCESS;
641 }
642
643 EFI_MMC_HOST_PROTOCOL gMMCHost = {
644 MMC_HOST_PROTOCOL_REVISION,
645 MMCIsCardPresent,
646 MMCIsReadOnly,
647 MMCBuildDevicePath,
648 MMCNotifyState,
649 MMCSendCommand,
650 MMCReceiveResponse,
651 MMCReadBlockData,
652 MMCWriteBlockData
653 };
654
655 EFI_STATUS
MMCInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)656 MMCInitialize (
657 IN EFI_HANDLE ImageHandle,
658 IN EFI_SYSTEM_TABLE *SystemTable
659 )
660 {
661 EFI_STATUS Status;
662 EFI_HANDLE Handle = NULL;
663
664 DEBUG ((DEBUG_BLKIO, "MMCInitialize()\n"));
665
666 Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
667 ASSERT_EFI_ERROR(Status);
668
669 Status = gBS->InstallMultipleProtocolInterfaces (
670 &Handle,
671 &gEfiMmcHostProtocolGuid, &gMMCHost,
672 NULL
673 );
674 ASSERT_EFI_ERROR (Status);
675
676 return Status;
677 }
678