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