]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.c
EmbeddedPkg/DwEmmcDxe: limit max clock for platform
[mirror_edk2.git] / EmbeddedPkg / Drivers / DwEmmcDxe / DwEmmcDxe.c
1 /** @file
2 This file implement the MMC Host Protocol for the DesignWare eMMC.
3
4 Copyright (c) 2014-2017, Linaro 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 <Library/BaseMemoryLib.h>
17 #include <Library/CacheMaintenanceLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/DevicePathLib.h>
20 #include <Library/IoLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/PcdLib.h>
23 #include <Library/TimerLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/UefiLib.h>
26
27 #include <Protocol/MmcHost.h>
28
29 #include "DwEmmc.h"
30
31 #define DWEMMC_DESC_PAGE 1
32 #define DWEMMC_BLOCK_SIZE 512
33 #define DWEMMC_DMA_BUF_SIZE (512 * 8)
34 #define DWEMMC_MAX_DESC_PAGES 512
35
36 typedef struct {
37 UINT32 Des0;
38 UINT32 Des1;
39 UINT32 Des2;
40 UINT32 Des3;
41 } DWEMMC_IDMAC_DESCRIPTOR;
42
43 EFI_MMC_HOST_PROTOCOL *gpMmcHost;
44 DWEMMC_IDMAC_DESCRIPTOR *gpIdmacDesc;
45 EFI_GUID mDwEmmcDevicePathGuid = EFI_CALLER_ID_GUID;
46 STATIC UINT32 mDwEmmcCommand;
47 STATIC UINT32 mDwEmmcArgument;
48
49 EFI_STATUS
50 DwEmmcReadBlockData (
51 IN EFI_MMC_HOST_PROTOCOL *This,
52 IN EFI_LBA Lba,
53 IN UINTN Length,
54 IN UINT32* Buffer
55 );
56
57 BOOLEAN
58 DwEmmcIsPowerOn (
59 VOID
60 )
61 {
62 return TRUE;
63 }
64
65 EFI_STATUS
66 DwEmmcInitialize (
67 VOID
68 )
69 {
70 DEBUG ((DEBUG_BLKIO, "DwEmmcInitialize()"));
71 return EFI_SUCCESS;
72 }
73
74 BOOLEAN
75 DwEmmcIsCardPresent (
76 IN EFI_MMC_HOST_PROTOCOL *This
77 )
78 {
79 return TRUE;
80 }
81
82 BOOLEAN
83 DwEmmcIsReadOnly (
84 IN EFI_MMC_HOST_PROTOCOL *This
85 )
86 {
87 return FALSE;
88 }
89
90 BOOLEAN
91 DwEmmcIsDmaSupported (
92 IN EFI_MMC_HOST_PROTOCOL *This
93 )
94 {
95 return TRUE;
96 }
97
98 EFI_STATUS
99 DwEmmcBuildDevicePath (
100 IN EFI_MMC_HOST_PROTOCOL *This,
101 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
102 )
103 {
104 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
105
106 NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
107 CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mDwEmmcDevicePathGuid);
108
109 *DevicePath = NewDevicePathNode;
110 return EFI_SUCCESS;
111 }
112
113 EFI_STATUS
114 DwEmmcUpdateClock (
115 VOID
116 )
117 {
118 UINT32 Data;
119
120 /* CMD_UPDATE_CLK */
121 Data = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |
122 BIT_CMD_START;
123 MmioWrite32 (DWEMMC_CMD, Data);
124 while (1) {
125 Data = MmioRead32 (DWEMMC_CMD);
126 if (!(Data & CMD_START_BIT)) {
127 break;
128 }
129 Data = MmioRead32 (DWEMMC_RINTSTS);
130 if (Data & DWEMMC_INT_HLE) {
131 Print (L"failed to update mmc clock frequency\n");
132 return EFI_DEVICE_ERROR;
133 }
134 }
135 return EFI_SUCCESS;
136 }
137
138 EFI_STATUS
139 DwEmmcSetClock (
140 IN UINTN ClockFreq
141 )
142 {
143 UINT32 Divider, Rate, Data;
144 EFI_STATUS Status;
145 BOOLEAN Found = FALSE;
146
147 for (Divider = 1; Divider < 256; Divider++) {
148 Rate = PcdGet32 (PcdDwEmmcDxeClockFrequencyInHz);
149 if ((Rate / (2 * Divider)) <= ClockFreq) {
150 Found = TRUE;
151 break;
152 }
153 }
154 if (Found == FALSE) {
155 return EFI_NOT_FOUND;
156 }
157
158 // Wait until MMC is idle
159 do {
160 Data = MmioRead32 (DWEMMC_STATUS);
161 } while (Data & DWEMMC_STS_DATA_BUSY);
162
163 // Disable MMC clock first
164 MmioWrite32 (DWEMMC_CLKENA, 0);
165 Status = DwEmmcUpdateClock ();
166 ASSERT (!EFI_ERROR (Status));
167
168 MmioWrite32 (DWEMMC_CLKDIV, Divider);
169 Status = DwEmmcUpdateClock ();
170 ASSERT (!EFI_ERROR (Status));
171
172 // Enable MMC clock
173 MmioWrite32 (DWEMMC_CLKENA, 1);
174 MmioWrite32 (DWEMMC_CLKSRC, 0);
175 Status = DwEmmcUpdateClock ();
176 ASSERT (!EFI_ERROR (Status));
177 return EFI_SUCCESS;
178 }
179
180 EFI_STATUS
181 DwEmmcNotifyState (
182 IN EFI_MMC_HOST_PROTOCOL *This,
183 IN MMC_STATE State
184 )
185 {
186 UINT32 Data;
187 EFI_STATUS Status;
188
189 switch (State) {
190 case MmcInvalidState:
191 return EFI_INVALID_PARAMETER;
192 case MmcHwInitializationState:
193 MmioWrite32 (DWEMMC_PWREN, 1);
194
195 // If device already turn on then restart it
196 Data = DWEMMC_CTRL_RESET_ALL;
197 MmioWrite32 (DWEMMC_CTRL, Data);
198 do {
199 // Wait until reset operation finished
200 Data = MmioRead32 (DWEMMC_CTRL);
201 } while (Data & DWEMMC_CTRL_RESET_ALL);
202
203 // Setup clock that could not be higher than 400KHz.
204 Status = DwEmmcSetClock (400000);
205 ASSERT (!EFI_ERROR (Status));
206 // Wait clock stable
207 MicroSecondDelay (100);
208
209 MmioWrite32 (DWEMMC_RINTSTS, ~0);
210 MmioWrite32 (DWEMMC_INTMASK, 0);
211 MmioWrite32 (DWEMMC_TMOUT, ~0);
212 MmioWrite32 (DWEMMC_IDINTEN, 0);
213 MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET);
214
215 MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
216 do {
217 Data = MmioRead32 (DWEMMC_BMOD);
218 } while (Data & DWEMMC_IDMAC_SWRESET);
219 break;
220 case MmcIdleState:
221 break;
222 case MmcReadyState:
223 break;
224 case MmcIdentificationState:
225 break;
226 case MmcStandByState:
227 break;
228 case MmcTransferState:
229 break;
230 case MmcSendingDataState:
231 break;
232 case MmcReceiveDataState:
233 break;
234 case MmcProgrammingState:
235 break;
236 case MmcDisconnectState:
237 break;
238 default:
239 return EFI_INVALID_PARAMETER;
240 }
241 return EFI_SUCCESS;
242 }
243
244 // Need to prepare DMA buffer first before sending commands to MMC card
245 BOOLEAN
246 IsPendingReadCommand (
247 IN MMC_CMD MmcCmd
248 )
249 {
250 UINTN Mask;
251
252 Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_READ;
253 if ((MmcCmd & Mask) == Mask) {
254 return TRUE;
255 }
256 return FALSE;
257 }
258
259 BOOLEAN
260 IsPendingWriteCommand (
261 IN MMC_CMD MmcCmd
262 )
263 {
264 UINTN Mask;
265
266 Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE;
267 if ((MmcCmd & Mask) == Mask) {
268 return TRUE;
269 }
270 return FALSE;
271 }
272
273 EFI_STATUS
274 SendCommand (
275 IN MMC_CMD MmcCmd,
276 IN UINT32 Argument
277 )
278 {
279 UINT32 Data, ErrMask;
280
281 // Wait until MMC is idle
282 do {
283 Data = MmioRead32 (DWEMMC_STATUS);
284 } while (Data & DWEMMC_STS_DATA_BUSY);
285
286 MmioWrite32 (DWEMMC_RINTSTS, ~0);
287 MmioWrite32 (DWEMMC_CMDARG, Argument);
288 MmioWrite32 (DWEMMC_CMD, MmcCmd);
289
290 ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO |
291 DWEMMC_INT_RCRC | DWEMMC_INT_RE;
292 ErrMask |= DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE;
293 do {
294 MicroSecondDelay(500);
295 Data = MmioRead32 (DWEMMC_RINTSTS);
296
297 if (Data & ErrMask) {
298 return EFI_DEVICE_ERROR;
299 }
300 if (Data & DWEMMC_INT_DTO) { // Transfer Done
301 break;
302 }
303 } while (!(Data & DWEMMC_INT_CMD_DONE));
304 return EFI_SUCCESS;
305 }
306
307 EFI_STATUS
308 DwEmmcSendCommand (
309 IN EFI_MMC_HOST_PROTOCOL *This,
310 IN MMC_CMD MmcCmd,
311 IN UINT32 Argument
312 )
313 {
314 UINT32 Cmd = 0;
315 EFI_STATUS Status = EFI_SUCCESS;
316
317 switch (MMC_GET_INDX(MmcCmd)) {
318 case MMC_INDX(0):
319 Cmd = BIT_CMD_SEND_INIT;
320 break;
321 case MMC_INDX(1):
322 Cmd = BIT_CMD_RESPONSE_EXPECT;
323 break;
324 case MMC_INDX(2):
325 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
326 BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;
327 break;
328 case MMC_INDX(3):
329 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
330 BIT_CMD_SEND_INIT;
331 break;
332 case MMC_INDX(7):
333 if (Argument)
334 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
335 else
336 Cmd = 0;
337 break;
338 case MMC_INDX(8):
339 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
340 BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
341 BIT_CMD_WAIT_PRVDATA_COMPLETE;
342 break;
343 case MMC_INDX(9):
344 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
345 BIT_CMD_LONG_RESPONSE;
346 break;
347 case MMC_INDX(12):
348 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
349 BIT_CMD_STOP_ABORT_CMD;
350 break;
351 case MMC_INDX(13):
352 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
353 BIT_CMD_WAIT_PRVDATA_COMPLETE;
354 break;
355 case MMC_INDX(16):
356 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
357 BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
358 BIT_CMD_WAIT_PRVDATA_COMPLETE;
359 break;
360 case MMC_INDX(17):
361 case MMC_INDX(18):
362 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
363 BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
364 BIT_CMD_WAIT_PRVDATA_COMPLETE;
365 break;
366 case MMC_INDX(24):
367 case MMC_INDX(25):
368 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
369 BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE |
370 BIT_CMD_WAIT_PRVDATA_COMPLETE;
371 break;
372 case MMC_INDX(30):
373 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
374 BIT_CMD_DATA_EXPECTED;
375 break;
376 default:
377 Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
378 break;
379 }
380
381 Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
382 if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) {
383 mDwEmmcCommand = Cmd;
384 mDwEmmcArgument = Argument;
385 } else {
386 Status = SendCommand (Cmd, Argument);
387 }
388 return Status;
389 }
390
391 EFI_STATUS
392 DwEmmcReceiveResponse (
393 IN EFI_MMC_HOST_PROTOCOL *This,
394 IN MMC_RESPONSE_TYPE Type,
395 IN UINT32* Buffer
396 )
397 {
398 if (Buffer == NULL) {
399 return EFI_INVALID_PARAMETER;
400 }
401
402 if ( (Type == MMC_RESPONSE_TYPE_R1)
403 || (Type == MMC_RESPONSE_TYPE_R1b)
404 || (Type == MMC_RESPONSE_TYPE_R3)
405 || (Type == MMC_RESPONSE_TYPE_R6)
406 || (Type == MMC_RESPONSE_TYPE_R7))
407 {
408 Buffer[0] = MmioRead32 (DWEMMC_RESP0);
409 } else if (Type == MMC_RESPONSE_TYPE_R2) {
410 Buffer[0] = MmioRead32 (DWEMMC_RESP0);
411 Buffer[1] = MmioRead32 (DWEMMC_RESP1);
412 Buffer[2] = MmioRead32 (DWEMMC_RESP2);
413 Buffer[3] = MmioRead32 (DWEMMC_RESP3);
414 }
415 return EFI_SUCCESS;
416 }
417
418 EFI_STATUS
419 PrepareDmaData (
420 IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc,
421 IN UINTN Length,
422 IN UINT32* Buffer
423 )
424 {
425 UINTN Cnt, Blks, Idx, LastIdx;
426
427 Cnt = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
428 Blks = (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE;
429 Length = DWEMMC_BLOCK_SIZE * Blks;
430
431 for (Idx = 0; Idx < Cnt; Idx++) {
432 (IdmacDesc + Idx)->Des0 = DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_CH |
433 DWEMMC_IDMAC_DES0_DIC;
434 (IdmacDesc + Idx)->Des1 = DWEMMC_IDMAC_DES1_BS1(DWEMMC_DMA_BUF_SIZE);
435 /* Buffer Address */
436 (IdmacDesc + Idx)->Des2 = (UINT32)((UINTN)Buffer + DWEMMC_DMA_BUF_SIZE * Idx);
437 /* Next Descriptor Address */
438 (IdmacDesc + Idx)->Des3 = (UINT32)((UINTN)IdmacDesc +
439 (sizeof(DWEMMC_IDMAC_DESCRIPTOR) * (Idx + 1)));
440 }
441 /* First Descriptor */
442 IdmacDesc->Des0 |= DWEMMC_IDMAC_DES0_FS;
443 /* Last Descriptor */
444 LastIdx = Cnt - 1;
445 (IdmacDesc + LastIdx)->Des0 |= DWEMMC_IDMAC_DES0_LD;
446 (IdmacDesc + LastIdx)->Des0 &= ~(DWEMMC_IDMAC_DES0_DIC | DWEMMC_IDMAC_DES0_CH);
447 (IdmacDesc + LastIdx)->Des1 = DWEMMC_IDMAC_DES1_BS1(Length -
448 (LastIdx * DWEMMC_DMA_BUF_SIZE));
449 /* Set the Next field of Last Descriptor */
450 (IdmacDesc + LastIdx)->Des3 = 0;
451 MmioWrite32 (DWEMMC_DBADDR, (UINT32)((UINTN)IdmacDesc));
452
453 return EFI_SUCCESS;
454 }
455
456 VOID
457 StartDma (
458 UINTN Length
459 )
460 {
461 UINT32 Data;
462
463 Data = MmioRead32 (DWEMMC_CTRL);
464 Data |= DWEMMC_CTRL_INT_EN | DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN;
465 MmioWrite32 (DWEMMC_CTRL, Data);
466 Data = MmioRead32 (DWEMMC_BMOD);
467 Data |= DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB;
468 MmioWrite32 (DWEMMC_BMOD, Data);
469
470 MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
471 MmioWrite32 (DWEMMC_BYTCNT, Length);
472 }
473
474 EFI_STATUS
475 DwEmmcReadBlockData (
476 IN EFI_MMC_HOST_PROTOCOL *This,
477 IN EFI_LBA Lba,
478 IN UINTN Length,
479 IN UINT32* Buffer
480 )
481 {
482 EFI_STATUS Status;
483 UINT32 DescPages, CountPerPage, Count;
484 EFI_TPL Tpl;
485
486 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
487
488 CountPerPage = EFI_PAGE_SIZE / 16;
489 Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
490 DescPages = (Count + CountPerPage - 1) / CountPerPage;
491
492 InvalidateDataCacheRange (Buffer, Length);
493
494 Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
495 if (EFI_ERROR (Status)) {
496 goto out;
497 }
498
499 WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
500 StartDma (Length);
501
502 Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);
503 if (EFI_ERROR (Status)) {
504 DEBUG ((DEBUG_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
505 goto out;
506 }
507 out:
508 // Restore Tpl
509 gBS->RestoreTPL (Tpl);
510 return Status;
511 }
512
513 EFI_STATUS
514 DwEmmcWriteBlockData (
515 IN EFI_MMC_HOST_PROTOCOL *This,
516 IN EFI_LBA Lba,
517 IN UINTN Length,
518 IN UINT32* Buffer
519 )
520 {
521 EFI_STATUS Status;
522 UINT32 DescPages, CountPerPage, Count;
523 EFI_TPL Tpl;
524
525 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
526
527 CountPerPage = EFI_PAGE_SIZE / 16;
528 Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
529 DescPages = (Count + CountPerPage - 1) / CountPerPage;
530
531 WriteBackDataCacheRange (Buffer, Length);
532
533 Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
534 if (EFI_ERROR (Status)) {
535 goto out;
536 }
537
538 WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
539 StartDma (Length);
540
541 Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);
542 if (EFI_ERROR (Status)) {
543 DEBUG ((DEBUG_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
544 goto out;
545 }
546 out:
547 // Restore Tpl
548 gBS->RestoreTPL (Tpl);
549 return Status;
550 }
551
552 EFI_STATUS
553 DwEmmcSetIos (
554 IN EFI_MMC_HOST_PROTOCOL *This,
555 IN UINT32 BusClockFreq,
556 IN UINT32 BusWidth,
557 IN UINT32 TimingMode
558 )
559 {
560 EFI_STATUS Status = EFI_SUCCESS;
561 UINT32 Data;
562
563 if ((PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz) != 0) &&
564 (BusClockFreq > PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz))) {
565 return EFI_UNSUPPORTED;
566 }
567 if (TimingMode != EMMCBACKWARD) {
568 Data = MmioRead32 (DWEMMC_UHSREG);
569 switch (TimingMode) {
570 case EMMCHS52DDR1V2:
571 case EMMCHS52DDR1V8:
572 Data |= 1 << 16;
573 break;
574 case EMMCHS52:
575 case EMMCHS26:
576 Data &= ~(1 << 16);
577 break;
578 default:
579 return EFI_UNSUPPORTED;
580 }
581 MmioWrite32 (DWEMMC_UHSREG, Data);
582 }
583
584 switch (BusWidth) {
585 case 1:
586 MmioWrite32 (DWEMMC_CTYPE, 0);
587 break;
588 case 4:
589 MmioWrite32 (DWEMMC_CTYPE, 1);
590 break;
591 case 8:
592 MmioWrite32 (DWEMMC_CTYPE, 1 << 16);
593 break;
594 default:
595 return EFI_UNSUPPORTED;
596 }
597 if (BusClockFreq) {
598 Status = DwEmmcSetClock (BusClockFreq);
599 }
600 return Status;
601 }
602
603 BOOLEAN
604 DwEmmcIsMultiBlock (
605 IN EFI_MMC_HOST_PROTOCOL *This
606 )
607 {
608 return TRUE;
609 }
610
611 EFI_MMC_HOST_PROTOCOL gMciHost = {
612 MMC_HOST_PROTOCOL_REVISION,
613 DwEmmcIsCardPresent,
614 DwEmmcIsReadOnly,
615 DwEmmcBuildDevicePath,
616 DwEmmcNotifyState,
617 DwEmmcSendCommand,
618 DwEmmcReceiveResponse,
619 DwEmmcReadBlockData,
620 DwEmmcWriteBlockData,
621 DwEmmcSetIos,
622 DwEmmcIsMultiBlock
623 };
624
625 EFI_STATUS
626 DwEmmcDxeInitialize (
627 IN EFI_HANDLE ImageHandle,
628 IN EFI_SYSTEM_TABLE *SystemTable
629 )
630 {
631 EFI_STATUS Status;
632 EFI_HANDLE Handle;
633
634 Handle = NULL;
635
636 gpIdmacDesc = (DWEMMC_IDMAC_DESCRIPTOR *)AllocatePages (DWEMMC_MAX_DESC_PAGES);
637 if (gpIdmacDesc == NULL) {
638 return EFI_BUFFER_TOO_SMALL;
639 }
640
641 DEBUG ((DEBUG_BLKIO, "DwEmmcDxeInitialize()\n"));
642
643 //Publish Component Name, BlockIO protocol interfaces
644 Status = gBS->InstallMultipleProtocolInterfaces (
645 &Handle,
646 &gEfiMmcHostProtocolGuid, &gMciHost,
647 NULL
648 );
649 ASSERT_EFI_ERROR (Status);
650
651 return EFI_SUCCESS;
652 }