]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/PL180MciDxe/PL180Mci.c
688cd8a98ced2b540ced7c4c7c7bfd5174ef86c4
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL180MciDxe / PL180Mci.c
1 /** @file
2 This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
3
4 Copyright (c) 2011-2012, 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 "PL180Mci.h"
17
18 #include <Library/DevicePathLib.h>
19 #include <Library/BaseMemoryLib.h>
20
21 EFI_MMC_HOST_PROTOCOL *gpMmcHost;
22
23 // Untested ...
24 //#define USE_STREAM
25
26 #define MMCI0_BLOCKLEN 512
27 #define MMCI0_POW2_BLOCKLEN 9
28 #define MMCI0_TIMEOUT 1000
29
30 #define SYS_MCI_CARDIN BIT0
31 #define SYS_MCI_WPROT BIT1
32
33 BOOLEAN
34 MciIsPowerOn (
35 VOID
36 )
37 {
38 return ((MmioRead32 (MCI_POWER_CONTROL_REG) & MCI_POWER_ON) == MCI_POWER_ON);
39 }
40
41 EFI_STATUS
42 MciInitialize (
43 VOID
44 )
45 {
46 MCI_TRACE ("MciInitialize()");
47 return EFI_SUCCESS;
48 }
49
50 BOOLEAN
51 MciIsCardPresent (
52 IN EFI_MMC_HOST_PROTOCOL *This
53 )
54 {
55 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_CARDIN);
56 }
57
58 BOOLEAN
59 MciIsReadOnly (
60 IN EFI_MMC_HOST_PROTOCOL *This
61 )
62 {
63 return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_WPROT);
64 }
65
66 #if 0
67 //Note: This function has been commented out because it is not used yet.
68 // This function could be used to remove the hardcoded BlockLen used
69 // in MciPrepareDataPath
70
71 // Convert block size to 2^n
72 STATIC
73 UINT32
74 GetPow2BlockLen (
75 IN UINT32 BlockLen
76 )
77 {
78 UINTN Loop;
79 UINTN Pow2BlockLen;
80
81 Loop = 0x8000;
82 Pow2BlockLen = 15;
83 do {
84 Loop = (Loop >> 1) & 0xFFFF;
85 Pow2BlockLen--;
86 } while (Pow2BlockLen && (!(Loop & BlockLen)));
87
88 return Pow2BlockLen;
89 }
90 #endif
91
92 VOID
93 MciPrepareDataPath (
94 IN UINTN TransferDirection
95 )
96 {
97 // Set Data Length & Data Timer
98 MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);
99 MmioWrite32 (MCI_DATA_LENGTH_REG, MMCI0_BLOCKLEN);
100
101 #ifndef USE_STREAM
102 //Note: we are using a hardcoded BlockLen (==512). If we decide to use a variable size, we could
103 // compute the pow2 of BlockLen with the above function GetPow2BlockLen ()
104 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4));
105 #else
106 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS);
107 #endif
108 }
109
110 EFI_STATUS
111 MciSendCommand (
112 IN EFI_MMC_HOST_PROTOCOL *This,
113 IN MMC_CMD MmcCmd,
114 IN UINT32 Argument
115 )
116 {
117 UINT32 Status;
118 UINT32 Cmd;
119 UINTN RetVal;
120 UINTN CmdCtrlReg;
121 UINT32 DoneMask;
122
123 RetVal = EFI_SUCCESS;
124
125 if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) {
126 MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT);
127 } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) {
128 MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD);
129 }
130
131 // Create Command for PL180
132 Cmd = (MMC_GET_INDX (MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLE;
133 if (MmcCmd & MMC_CMD_WAIT_RESPONSE) {
134 Cmd |= MCI_CPSM_WAIT_RESPONSE;
135 }
136
137 if (MmcCmd & MMC_CMD_LONG_RESPONSE) {
138 Cmd |= MCI_CPSM_LONG_RESPONSE;
139 }
140
141 // Clear Status register static flags
142 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
143
144 // Write to command argument register
145 MmioWrite32 (MCI_ARGUMENT_REG, Argument);
146
147 // Write to command register
148 MmioWrite32 (MCI_COMMAND_REG, Cmd);
149
150 DoneMask = (Cmd & MCI_CPSM_WAIT_RESPONSE)
151 ? (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_ERROR)
152 : (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_ERROR);
153 do {
154 Status = MmioRead32 (MCI_STATUS_REG);
155 } while (! (Status & DoneMask));
156
157 if ((Status & MCI_STATUS_CMD_ERROR)) {
158 // Clear Status register error flags
159 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_ERROR);
160
161 if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) {
162 DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
163 RetVal = EFI_NO_RESPONSE;
164 } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) {
165 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
166 RetVal = EFI_TIMEOUT;
167 } else if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) {
168 // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
169 RetVal = EFI_CRC_ERROR;
170 }
171 }
172
173 // Disable Command Path
174 CmdCtrlReg = MmioRead32 (MCI_COMMAND_REG);
175 MmioWrite32 (MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLE));
176 return RetVal;
177 }
178
179 EFI_STATUS
180 MciReceiveResponse (
181 IN EFI_MMC_HOST_PROTOCOL *This,
182 IN MMC_RESPONSE_TYPE Type,
183 IN UINT32* Buffer
184 )
185 {
186 if (Buffer == NULL) {
187 return EFI_INVALID_PARAMETER;
188 }
189
190 if ( (Type == MMC_RESPONSE_TYPE_R1)
191 || (Type == MMC_RESPONSE_TYPE_R1b)
192 || (Type == MMC_RESPONSE_TYPE_R3)
193 || (Type == MMC_RESPONSE_TYPE_R6)
194 || (Type == MMC_RESPONSE_TYPE_R7))
195 {
196 Buffer[0] = MmioRead32 (MCI_RESPONSE3_REG);
197 } else if (Type == MMC_RESPONSE_TYPE_R2) {
198 Buffer[0] = MmioRead32 (MCI_RESPONSE0_REG);
199 Buffer[1] = MmioRead32 (MCI_RESPONSE1_REG);
200 Buffer[2] = MmioRead32 (MCI_RESPONSE2_REG);
201 Buffer[3] = MmioRead32 (MCI_RESPONSE3_REG);
202 }
203
204 return EFI_SUCCESS;
205 }
206
207 EFI_STATUS
208 MciReadBlockData (
209 IN EFI_MMC_HOST_PROTOCOL *This,
210 IN EFI_LBA Lba,
211 IN UINTN Length,
212 IN UINT32* Buffer
213 )
214 {
215 UINTN Loop;
216 UINTN Finish;
217 UINTN Status;
218 EFI_STATUS RetVal;
219 UINTN DataCtrlReg;
220 EFI_TPL Tpl;
221
222 RetVal = EFI_SUCCESS;
223
224 // Read data from the RX FIFO
225 Loop = 0;
226 Finish = MMCI0_BLOCKLEN / 4;
227
228 // Raise the TPL at the highest level to disable Interrupts.
229 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
230
231 do {
232 // Read the Status flags
233 Status = MmioRead32 (MCI_STATUS_REG);
234
235 // Do eight reads if possible else a single read
236 if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) {
237 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
238 Loop++;
239 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
240 Loop++;
241 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
242 Loop++;
243 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
244 Loop++;
245 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
246 Loop++;
247 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
248 Loop++;
249 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
250 Loop++;
251 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
252 Loop++;
253 } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) {
254 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
255 Loop++;
256 } else {
257 //Check for error conditions and timeouts
258 if (Status & MCI_STATUS_CMD_DATATIMEOUT) {
259 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
260 RetVal = EFI_TIMEOUT;
261 break;
262 } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {
263 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
264 RetVal = EFI_CRC_ERROR;
265 break;
266 } else if (Status & MCI_STATUS_CMD_START_BIT_ERROR) {
267 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
268 RetVal = EFI_NO_RESPONSE;
269 break;
270 }
271 }
272 //clear RX over run flag
273 if(Status & MCI_STATUS_CMD_RXOVERRUN) {
274 MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN);
275 }
276 } while ((Loop < Finish));
277
278 // Restore Tpl
279 gBS->RestoreTPL (Tpl);
280
281 // Clear Status flags
282 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
283
284 //Disable Data path
285 DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);
286 MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));
287
288 return RetVal;
289 }
290
291 EFI_STATUS
292 MciWriteBlockData (
293 IN EFI_MMC_HOST_PROTOCOL *This,
294 IN EFI_LBA Lba,
295 IN UINTN Length,
296 IN UINT32* Buffer
297 )
298 {
299 UINTN Loop;
300 UINTN Finish;
301 UINTN Timer;
302 UINTN Status;
303 EFI_STATUS RetVal;
304 UINTN DataCtrlReg;
305 EFI_TPL Tpl;
306
307 RetVal = EFI_SUCCESS;
308
309 // Write the data to the TX FIFO
310 Loop = 0;
311 Finish = MMCI0_BLOCKLEN / 4;
312 Timer = MMCI0_TIMEOUT * 100;
313
314 // Raise the TPL at the highest level to disable Interrupts.
315 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
316
317 do {
318 // Read the Status flags
319 Status = MmioRead32 (MCI_STATUS_REG);
320
321 // Do eight writes if possible else a single write
322 if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) {
323 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
324 Loop++;
325 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
326 Loop++;
327 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
328 Loop++;
329 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
330 Loop++;
331 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
332 Loop++;
333 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
334 Loop++;
335 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
336 Loop++;
337 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
338 Loop++;
339 } else if (!(Status & MCI_STATUS_CMD_TXFIFOFULL)) {
340 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
341 Loop++;
342 } else {
343 // Check for error conditions and timeouts
344 if (Status & MCI_STATUS_CMD_DATATIMEOUT) {
345 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
346 RetVal = EFI_TIMEOUT;
347 goto Exit;
348 } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {
349 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
350 RetVal = EFI_CRC_ERROR;
351 goto Exit;
352 } else if (Status & MCI_STATUS_CMD_TX_UNDERRUN) {
353 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TX buffer Underrun! Response:0x%X Status:0x%x, Number of bytes written 0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status, Loop));
354 RetVal = EFI_BUFFER_TOO_SMALL;
355 ASSERT(0);
356 goto Exit;
357 }
358 }
359 } while (Loop < Finish);
360
361 // Restore Tpl
362 gBS->RestoreTPL (Tpl);
363
364 // Wait for FIFO to drain
365 Timer = MMCI0_TIMEOUT * 60;
366 Status = MmioRead32 (MCI_STATUS_REG);
367 #ifndef USE_STREAM
368 // Single block
369 while (((Status & MCI_STATUS_TXDONE) != MCI_STATUS_TXDONE) && Timer) {
370 #else
371 // Stream
372 while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) {
373 #endif
374 NanoSecondDelay(10);
375 Status = MmioRead32 (MCI_STATUS_REG);
376 Timer--;
377 }
378
379 // Clear Status flags
380 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
381
382 if (Timer == 0) {
383 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of words written 0x%x\n", Loop));
384 RetVal = EFI_TIMEOUT;
385 }
386
387 Exit:
388 // Disable Data path
389 DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);
390 MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));
391 return RetVal;
392 }
393
394 EFI_STATUS
395 MciNotifyState (
396 IN EFI_MMC_HOST_PROTOCOL *This,
397 IN MMC_STATE State
398 )
399 {
400 UINT32 Data32;
401
402 switch (State) {
403 case MmcInvalidState:
404 ASSERT (0);
405 break;
406 case MmcHwInitializationState:
407 // If device already turn on then restart it
408 Data32 = MmioRead32 (MCI_POWER_CONTROL_REG);
409 if ((Data32 & 0x2) == MCI_POWER_UP) {
410 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI");
411
412 // Turn off
413 MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0);
414 MmioWrite32 (MCI_POWER_CONTROL_REG, 0);
415 MicroSecondDelay (100);
416 }
417
418 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI");
419 // Setup clock
420 // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
421 MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
422
423 // Set the voltage
424 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_OPENDRAIN | (15<<2));
425 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP);
426 MicroSecondDelay (10);
427 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON);
428 MicroSecondDelay (100);
429
430 // Set Data Length & Data Timer
431 MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFF);
432 MmioWrite32 (MCI_DATA_LENGTH_REG, 8);
433
434 ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON);
435 break;
436 case MmcIdleState:
437 MCI_TRACE ("MciNotifyState(MmcIdleState)");
438 break;
439 case MmcReadyState:
440 MCI_TRACE ("MciNotifyState(MmcReadyState)");
441 break;
442 case MmcIdentificationState:
443 MCI_TRACE ("MciNotifyState (MmcIdentificationState)");
444 break;
445 case MmcStandByState:{
446 volatile UINT32 PwrCtrlReg;
447 MCI_TRACE ("MciNotifyState (MmcStandByState)");
448
449 // Enable MCICMD push-pull drive
450 PwrCtrlReg = MmioRead32 (MCI_POWER_CONTROL_REG);
451 //Disable Open Drain output
452 PwrCtrlReg &= ~ (MCI_POWER_OPENDRAIN);
453 MmioWrite32 (MCI_POWER_CONTROL_REG, PwrCtrlReg);
454
455 // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)
456 //
457 // Note: Increasing clock speed causes TX FIFO under-run errors.
458 // So careful when optimising this driver for higher performance.
459 //
460 MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
461 // Set MMCI0 clock to 24MHz (by bypassing the divider)
462 //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);
463 break;
464 }
465 case MmcTransferState:
466 //MCI_TRACE ("MciNotifyState(MmcTransferState)");
467 break;
468 case MmcSendingDataState:
469 MCI_TRACE ("MciNotifyState(MmcSendingDataState)");
470 break;
471 case MmcReceiveDataState:
472 MCI_TRACE ("MciNotifyState(MmcReceiveDataState)");
473 break;
474 case MmcProgrammingState:
475 MCI_TRACE ("MciNotifyState(MmcProgrammingState)");
476 break;
477 case MmcDisconnectState:
478 MCI_TRACE ("MciNotifyState(MmcDisconnectState)");
479 break;
480 default:
481 ASSERT (0);
482 }
483 return EFI_SUCCESS;
484 }
485
486 EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
487
488 EFI_STATUS
489 MciBuildDevicePath (
490 IN EFI_MMC_HOST_PROTOCOL *This,
491 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
492 )
493 {
494 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
495
496 NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
497 CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mPL180MciDevicePathGuid);
498
499 *DevicePath = NewDevicePathNode;
500 return EFI_SUCCESS;
501 }
502
503 EFI_MMC_HOST_PROTOCOL gMciHost = {
504 MMC_HOST_PROTOCOL_REVISION,
505 MciIsCardPresent,
506 MciIsReadOnly,
507 MciBuildDevicePath,
508 MciNotifyState,
509 MciSendCommand,
510 MciReceiveResponse,
511 MciReadBlockData,
512 MciWriteBlockData
513 };
514
515 EFI_STATUS
516 PL180MciDxeInitialize (
517 IN EFI_HANDLE ImageHandle,
518 IN EFI_SYSTEM_TABLE *SystemTable
519 )
520 {
521 EFI_STATUS Status;
522 EFI_HANDLE Handle;
523
524 DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180\n",
525 MCI_PERIPH_ID_REG0));
526
527 // Check if this is a PL180
528 if (MmioRead8 (MCI_PERIPH_ID_REG0) != MCI_PERIPH_ID0 ||
529 MmioRead8 (MCI_PERIPH_ID_REG1) != MCI_PERIPH_ID1 ||
530 MmioRead8 (MCI_PERIPH_ID_REG2) != MCI_PERIPH_ID2 ||
531 MmioRead8 (MCI_PERIPH_ID_REG3) != MCI_PERIPH_ID3 ||
532 MmioRead8 (MCI_PCELL_ID_REG0) != MCI_PCELL_ID0 ||
533 MmioRead8 (MCI_PCELL_ID_REG1) != MCI_PCELL_ID1 ||
534 MmioRead8 (MCI_PCELL_ID_REG2) != MCI_PCELL_ID2 ||
535 MmioRead8 (MCI_PCELL_ID_REG3) != MCI_PCELL_ID3) {
536
537 return EFI_NOT_FOUND;
538 }
539
540 Handle = NULL;
541
542 MCI_TRACE ("PL180MciDxeInitialize()");
543
544 //Publish Component Name, BlockIO protocol interfaces
545 Status = gBS->InstallMultipleProtocolInterfaces (
546 &Handle,
547 &gEfiMmcHostProtocolGuid, &gMciHost,
548 NULL
549 );
550 ASSERT_EFI_ERROR (Status);
551
552 return EFI_SUCCESS;
553 }