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