]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/PL180MciDxe/PL180Mci.c
313f2af9fdc568b083e7346a694370c74ed900a9
[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
122 RetVal = EFI_SUCCESS;
123
124 if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) {
125 MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT);
126 } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) {
127 MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD);
128 }
129
130 // Create Command for PL180
131 Cmd = (MMC_GET_INDX (MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLE;
132 if (MmcCmd & MMC_CMD_WAIT_RESPONSE) {
133 Cmd |= MCI_CPSM_WAIT_RESPONSE;
134 }
135
136 if (MmcCmd & MMC_CMD_LONG_RESPONSE) {
137 Cmd |= MCI_CPSM_LONG_RESPONSE;
138 }
139
140 // Clear Status register static flags
141 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
142
143 // Write to command argument register
144 MmioWrite32 (MCI_ARGUMENT_REG, Argument);
145
146 // Write to command register
147 MmioWrite32 (MCI_COMMAND_REG, Cmd);
148
149 if (Cmd & MCI_CPSM_WAIT_RESPONSE) {
150 Status = MmioRead32 (MCI_STATUS_REG);
151 while (!(Status & (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_CMDCRCFAIL | MCI_STATUS_CMD_CMDTIMEOUT | MCI_STATUS_CMD_START_BIT_ERROR))) {
152 Status = MmioRead32(MCI_STATUS_REG);
153 }
154
155 if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) {
156 DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
157 RetVal = EFI_NO_RESPONSE;
158 goto Exit;
159 } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) {
160 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
161 RetVal = EFI_TIMEOUT;
162 goto Exit;
163 } else if ((! (MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) {
164 // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
165 RetVal = EFI_CRC_ERROR;
166 goto Exit;
167 } else {
168 RetVal = EFI_SUCCESS;
169 goto Exit;
170 }
171 } else {
172 Status = MmioRead32(MCI_STATUS_REG);
173 while (!(Status & (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_CMDCRCFAIL | MCI_STATUS_CMD_CMDTIMEOUT| MCI_STATUS_CMD_START_BIT_ERROR))) {
174 Status = MmioRead32(MCI_STATUS_REG);
175 }
176
177 if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) {
178 DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
179 RetVal = EFI_NO_RESPONSE;
180 goto Exit;
181 } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) {
182 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
183 RetVal = EFI_TIMEOUT;
184 goto Exit;
185 } else
186 if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) {
187 // The CMD1 does not contain CRC. We should ignore the CRC failed Status.
188 RetVal = EFI_CRC_ERROR;
189 goto Exit;
190 } else {
191 RetVal = EFI_SUCCESS;
192 goto Exit;
193 }
194 }
195
196 Exit:
197 // Disable Command Path
198 CmdCtrlReg = MmioRead32 (MCI_COMMAND_REG);
199 MmioWrite32 (MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLE));
200 return RetVal;
201 }
202
203 EFI_STATUS
204 MciReceiveResponse (
205 IN EFI_MMC_HOST_PROTOCOL *This,
206 IN MMC_RESPONSE_TYPE Type,
207 IN UINT32* Buffer
208 )
209 {
210 if (Buffer == NULL) {
211 return EFI_INVALID_PARAMETER;
212 }
213
214 if ( (Type == MMC_RESPONSE_TYPE_R1)
215 || (Type == MMC_RESPONSE_TYPE_R1b)
216 || (Type == MMC_RESPONSE_TYPE_R3)
217 || (Type == MMC_RESPONSE_TYPE_R6)
218 || (Type == MMC_RESPONSE_TYPE_R7))
219 {
220 Buffer[0] = MmioRead32 (MCI_RESPONSE3_REG);
221 } else if (Type == MMC_RESPONSE_TYPE_R2) {
222 Buffer[0] = MmioRead32 (MCI_RESPONSE0_REG);
223 Buffer[1] = MmioRead32 (MCI_RESPONSE1_REG);
224 Buffer[2] = MmioRead32 (MCI_RESPONSE2_REG);
225 Buffer[3] = MmioRead32 (MCI_RESPONSE3_REG);
226 }
227
228 return EFI_SUCCESS;
229 }
230
231 EFI_STATUS
232 MciReadBlockData (
233 IN EFI_MMC_HOST_PROTOCOL *This,
234 IN EFI_LBA Lba,
235 IN UINTN Length,
236 IN UINT32* Buffer
237 )
238 {
239 UINTN Loop;
240 UINTN Finish;
241 UINTN Status;
242 EFI_STATUS RetVal;
243 UINTN DataCtrlReg;
244
245 RetVal = EFI_SUCCESS;
246
247 // Read data from the RX FIFO
248 Loop = 0;
249 Finish = MMCI0_BLOCKLEN / 4;
250 do {
251 // Read the Status flags
252 Status = MmioRead32 (MCI_STATUS_REG);
253
254 // Do eight reads if possible else a single read
255 if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) {
256 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
257 Loop++;
258 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
259 Loop++;
260 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
261 Loop++;
262 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
263 Loop++;
264 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
265 Loop++;
266 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
267 Loop++;
268 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
269 Loop++;
270 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
271 Loop++;
272 } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) {
273 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
274 Loop++;
275 } else {
276 //Check for error conditions and timeouts
277 if (Status & MCI_STATUS_CMD_DATATIMEOUT) {
278 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
279 RetVal = EFI_TIMEOUT;
280 break;
281 } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {
282 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
283 RetVal = EFI_CRC_ERROR;
284 break;
285 } else if (Status & MCI_STATUS_CMD_START_BIT_ERROR) {
286 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
287 RetVal = EFI_NO_RESPONSE;
288 break;
289 }
290 }
291 //clear RX over run flag
292 if(Status & MCI_STATUS_CMD_RXOVERRUN) {
293 MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN);
294 }
295 } while ((Loop < Finish));
296
297 // Clear Status flags
298 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
299
300 //Disable Data path
301 DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);
302 MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));
303
304 return RetVal;
305 }
306
307 EFI_STATUS
308 MciWriteBlockData (
309 IN EFI_MMC_HOST_PROTOCOL *This,
310 IN EFI_LBA Lba,
311 IN UINTN Length,
312 IN UINT32* Buffer
313 )
314 {
315 UINTN Loop;
316 UINTN Finish;
317 UINTN Timer;
318 UINTN Status;
319 EFI_STATUS RetVal;
320 UINTN DataCtrlReg;
321
322 RetVal = EFI_SUCCESS;
323
324 // Write the data to the TX FIFO
325 Loop = 0;
326 Finish = MMCI0_BLOCKLEN / 4;
327 Timer = MMCI0_TIMEOUT * 100;
328 do {
329 // Read the Status flags
330 Status = MmioRead32 (MCI_STATUS_REG);
331
332 // Do eight writes if possible else a single write
333 if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) {
334 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
335 Loop++;
336 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
337 Loop++;
338 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
339 Loop++;
340 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
341 Loop++;
342 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
343 Loop++;
344 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
345 Loop++;
346 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
347 Loop++;
348 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
349 Loop++;
350 } else if ((Status & MCI_STATUS_CMD_TXFIFOEMPTY)) {
351 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
352 Loop++;
353 } else {
354 // Check for error conditions and timeouts
355 if (Status & MCI_STATUS_CMD_DATATIMEOUT) {
356 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
357 RetVal = EFI_TIMEOUT;
358 goto Exit;
359 } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {
360 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
361 RetVal = EFI_CRC_ERROR;
362 goto Exit;
363 } else if (Status & MCI_STATUS_CMD_TX_UNDERRUN) {
364 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));
365 RetVal = EFI_BUFFER_TOO_SMALL;
366 ASSERT(0);
367 goto Exit;
368 }
369 }
370 } while (Loop < Finish);
371
372 // Wait for FIFO to drain
373 Timer = MMCI0_TIMEOUT * 60;
374 Status = MmioRead32 (MCI_STATUS_REG);
375 #ifndef USE_STREAM
376 // Single block
377 while (((Status & MCI_STATUS_TXDONE) != MCI_STATUS_TXDONE) && Timer) {
378 #else
379 // Stream
380 while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) {
381 #endif
382 NanoSecondDelay(10);
383 Status = MmioRead32 (MCI_STATUS_REG);
384 Timer--;
385 }
386
387 if (Timer == 0) {
388 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of bytes written 0x%x\n",Loop));
389 ASSERT (Timer > 0);
390 return EFI_TIMEOUT;
391 }
392
393 // Clear Status flags
394 MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
395 if (Timer == 0) {
396 RetVal = EFI_TIMEOUT;
397 }
398
399 Exit:
400 // Disable Data path
401 DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);
402 MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));
403 return RetVal;
404 }
405
406 EFI_STATUS
407 MciNotifyState (
408 IN EFI_MMC_HOST_PROTOCOL *This,
409 IN MMC_STATE State
410 )
411 {
412 UINT32 Data32;
413
414 switch (State) {
415 case MmcInvalidState:
416 ASSERT (0);
417 break;
418 case MmcHwInitializationState:
419 // If device already turn on then restart it
420 Data32 = MmioRead32 (MCI_POWER_CONTROL_REG);
421 if ((Data32 & 0x2) == MCI_POWER_UP) {
422 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI");
423
424 // Turn off
425 MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0);
426 MmioWrite32 (MCI_POWER_CONTROL_REG, 0);
427 MicroSecondDelay (100);
428 }
429
430 MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI");
431 // Setup clock
432 // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
433 MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
434 //MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE);
435
436 // Set the voltage
437 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_OPENDRAIN | (15<<2));
438 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP);
439 MicroSecondDelay (10);
440 MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON);
441 MicroSecondDelay (100);
442
443 // Set Data Length & Data Timer
444 MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFF);
445 MmioWrite32 (MCI_DATA_LENGTH_REG, 8);
446
447 ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON);
448 break;
449 case MmcIdleState:
450 MCI_TRACE ("MciNotifyState(MmcIdleState)");
451 break;
452 case MmcReadyState:
453 MCI_TRACE ("MciNotifyState(MmcReadyState)");
454 break;
455 case MmcIdentificationState:
456 MCI_TRACE ("MciNotifyState (MmcIdentificationState)");
457 break;
458 case MmcStandByState:{
459 volatile UINT32 PwrCtrlReg;
460 MCI_TRACE ("MciNotifyState (MmcStandByState)");
461
462 // Enable MCICMD push-pull drive
463 PwrCtrlReg = MmioRead32 (MCI_POWER_CONTROL_REG);
464 //Disable Open Drain output
465 PwrCtrlReg &= ~ (MCI_POWER_OPENDRAIN);
466 MmioWrite32 (MCI_POWER_CONTROL_REG, PwrCtrlReg);
467
468 // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)
469 //
470 // Note: Increasing clock speed causes TX FIFO under-run errors.
471 // So careful when optimising this driver for higher performance.
472 //
473 MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
474 // Set MMCI0 clock to 24MHz (by bypassing the divider)
475 //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);
476 break;
477 }
478 case MmcTransferState:
479 //MCI_TRACE ("MciNotifyState(MmcTransferState)");
480 break;
481 case MmcSendingDataState:
482 MCI_TRACE ("MciNotifyState(MmcSendingDataState)");
483 break;
484 case MmcReceiveDataState:
485 MCI_TRACE ("MciNotifyState(MmcReceiveDataState)");
486 break;
487 case MmcProgrammingState:
488 MCI_TRACE ("MciNotifyState(MmcProgrammingState)");
489 break;
490 case MmcDisconnectState:
491 MCI_TRACE ("MciNotifyState(MmcDisconnectState)");
492 break;
493 default:
494 ASSERT (0);
495 }
496 return EFI_SUCCESS;
497 }
498
499 EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
500
501 EFI_STATUS
502 MciBuildDevicePath (
503 IN EFI_MMC_HOST_PROTOCOL *This,
504 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
505 )
506 {
507 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
508
509 NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
510 CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mPL180MciDevicePathGuid);
511
512 *DevicePath = NewDevicePathNode;
513 return EFI_SUCCESS;
514 }
515
516 EFI_MMC_HOST_PROTOCOL gMciHost = {
517 MMC_HOST_PROTOCOL_REVISION,
518 MciIsCardPresent,
519 MciIsReadOnly,
520 MciBuildDevicePath,
521 MciNotifyState,
522 MciSendCommand,
523 MciReceiveResponse,
524 MciReadBlockData,
525 MciWriteBlockData
526 };
527
528 EFI_STATUS
529 PL180MciDxeInitialize (
530 IN EFI_HANDLE ImageHandle,
531 IN EFI_SYSTEM_TABLE *SystemTable
532 )
533 {
534 EFI_STATUS Status;
535 EFI_HANDLE Handle;
536
537 Handle = NULL;
538
539 MCI_TRACE ("PL180MciDxeInitialize()");
540
541 //Publish Component Name, BlockIO protocol interfaces
542 Status = gBS->InstallMultipleProtocolInterfaces (
543 &Handle,
544 &gEfiMmcHostProtocolGuid, &gMciHost,
545 NULL
546 );
547 ASSERT_EFI_ERROR (Status);
548
549 return EFI_SUCCESS;
550 }