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