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