• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
MciIsPowerOn(VOID)34 MciIsPowerOn (
35   VOID
36   )
37 {
38   return ((MmioRead32 (MCI_POWER_CONTROL_REG) & MCI_POWER_ON) == MCI_POWER_ON);
39 }
40 
41 EFI_STATUS
MciInitialize(VOID)42 MciInitialize (
43   VOID
44   )
45 {
46   MCI_TRACE ("MciInitialize()");
47   return EFI_SUCCESS;
48 }
49 
50 BOOLEAN
MciIsCardPresent(IN EFI_MMC_HOST_PROTOCOL * This)51 MciIsCardPresent (
52   IN EFI_MMC_HOST_PROTOCOL     *This
53   )
54 {
55   return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_CARDIN);
56 }
57 
58 BOOLEAN
MciIsReadOnly(IN EFI_MMC_HOST_PROTOCOL * This)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
MciPrepareDataPath(IN UINTN TransferDirection)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
MciSendCommand(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_CMD MmcCmd,IN UINT32 Argument)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
MciReceiveResponse(IN EFI_MMC_HOST_PROTOCOL * This,IN MMC_RESPONSE_TYPE Type,IN UINT32 * Buffer)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
MciReadBlockData(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Length,IN UINT32 * Buffer)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
MciWriteBlockData(IN EFI_MMC_HOST_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Length,IN UINT32 * Buffer)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 }
554