1 /** @file 2 3 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 **/ 13 14 #include "EmmcBlockIoPei.h" 15 16 // 17 // Template for EMMC HC Slot Data. 18 // 19 EMMC_PEIM_HC_SLOT gEmmcHcSlotTemplate = { 20 EMMC_PEIM_SLOT_SIG, // Signature 21 { // Media 22 { 23 MSG_EMMC_DP, 24 FALSE, 25 TRUE, 26 FALSE, 27 0x200, 28 0 29 }, 30 { 31 MSG_EMMC_DP, 32 FALSE, 33 TRUE, 34 FALSE, 35 0x200, 36 0 37 }, 38 { 39 MSG_EMMC_DP, 40 FALSE, 41 TRUE, 42 FALSE, 43 0x200, 44 0 45 }, 46 { 47 MSG_EMMC_DP, 48 FALSE, 49 TRUE, 50 FALSE, 51 0x200, 52 0 53 }, 54 { 55 MSG_EMMC_DP, 56 FALSE, 57 TRUE, 58 FALSE, 59 0x200, 60 0 61 }, 62 { 63 MSG_EMMC_DP, 64 FALSE, 65 TRUE, 66 FALSE, 67 0x200, 68 0 69 }, 70 { 71 MSG_EMMC_DP, 72 FALSE, 73 TRUE, 74 FALSE, 75 0x200, 76 0 77 }, 78 { 79 MSG_EMMC_DP, 80 FALSE, 81 TRUE, 82 FALSE, 83 0x200, 84 0 85 } 86 }, 87 0, // MediaNum 88 { // PartitionType 89 EmmcPartitionUnknown, 90 EmmcPartitionUnknown, 91 EmmcPartitionUnknown, 92 EmmcPartitionUnknown, 93 EmmcPartitionUnknown, 94 EmmcPartitionUnknown, 95 EmmcPartitionUnknown, 96 EmmcPartitionUnknown 97 }, 98 0, // EmmcHcBase 99 { // Capability 100 0, 101 }, 102 { // Csd 103 0, 104 }, 105 { // ExtCsd 106 {0}, 107 }, 108 TRUE, // SectorAddressing 109 NULL // Private 110 }; 111 112 // 113 // Template for EMMC HC Private Data. 114 // 115 EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = { 116 EMMC_PEIM_SIG, // Signature 117 NULL, // Pool 118 { // BlkIoPpi 119 EmmcBlockIoPeimGetDeviceNo, 120 EmmcBlockIoPeimGetMediaInfo, 121 EmmcBlockIoPeimReadBlocks 122 }, 123 { // BlkIo2Ppi 124 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION, 125 EmmcBlockIoPeimGetDeviceNo2, 126 EmmcBlockIoPeimGetMediaInfo2, 127 EmmcBlockIoPeimReadBlocks2 128 }, 129 { // BlkIoPpiList 130 EFI_PEI_PPI_DESCRIPTOR_PPI, 131 &gEfiPeiVirtualBlockIoPpiGuid, 132 NULL 133 }, 134 { // BlkIo2PpiList 135 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, 136 &gEfiPeiVirtualBlockIo2PpiGuid, 137 NULL 138 }, 139 { // Slot 140 { 141 0, 142 }, 143 { 144 0, 145 }, 146 { 147 0, 148 }, 149 { 150 0, 151 }, 152 { 153 0, 154 }, 155 { 156 0, 157 } 158 }, 159 0, // SlotNum 160 0 // TotalBlkIoDevices 161 }; 162 /** 163 Gets the count of block I/O devices that one specific block driver detects. 164 165 This function is used for getting the count of block I/O devices that one 166 specific block driver detects. To the PEI ATAPI driver, it returns the number 167 of all the detected ATAPI devices it detects during the enumeration process. 168 To the PEI legacy floppy driver, it returns the number of all the legacy 169 devices it finds during its enumeration process. If no device is detected, 170 then the function will return zero. 171 172 @param[in] PeiServices General-purpose services that are available 173 to every PEIM. 174 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI 175 instance. 176 @param[out] NumberBlockDevices The number of block I/O devices discovered. 177 178 @retval EFI_SUCCESS The operation performed successfully. 179 180 **/ 181 EFI_STATUS 182 EFIAPI 183 EmmcBlockIoPeimGetDeviceNo ( 184 IN EFI_PEI_SERVICES **PeiServices, 185 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 186 OUT UINTN *NumberBlockDevices 187 ) 188 { 189 EMMC_PEIM_HC_PRIVATE_DATA *Private; 190 191 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 192 *NumberBlockDevices = Private->TotalBlkIoDevices; 193 return EFI_SUCCESS; 194 } 195 196 /** 197 Gets a block device's media information. 198 199 This function will provide the caller with the specified block device's media 200 information. If the media changes, calling this function will update the media 201 information accordingly. 202 203 @param[in] PeiServices General-purpose services that are available to every 204 PEIM 205 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 206 @param[in] DeviceIndex Specifies the block device to which the function wants 207 to talk. Because the driver that implements Block I/O 208 PPIs will manage multiple block devices, the PPIs that 209 want to talk to a single device must specify the 210 device index that was assigned during the enumeration 211 process. This index is a number from one to 212 NumberBlockDevices. 213 @param[out] MediaInfo The media information of the specified block media. 214 The caller is responsible for the ownership of this 215 data structure. 216 217 @par Note: 218 The MediaInfo structure describes an enumeration of possible block device 219 types. This enumeration exists because no device paths are actually passed 220 across interfaces that describe the type or class of hardware that is publishing 221 the block I/O interface. This enumeration will allow for policy decisions 222 in the Recovery PEIM, such as "Try to recover from legacy floppy first, 223 LS-120 second, CD-ROM third." If there are multiple partitions abstracted 224 by a given device type, they should be reported in ascending order; this 225 order also applies to nested partitions, such as legacy MBR, where the 226 outermost partitions would have precedence in the reporting order. The 227 same logic applies to systems such as IDE that have precedence relationships 228 like "Master/Slave" or "Primary/Secondary". The master device should be 229 reported first, the slave second. 230 231 @retval EFI_SUCCESS Media information about the specified block device 232 was obtained successfully. 233 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 234 error. 235 236 **/ 237 EFI_STATUS 238 EFIAPI 239 EmmcBlockIoPeimGetMediaInfo ( 240 IN EFI_PEI_SERVICES **PeiServices, 241 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 242 IN UINTN DeviceIndex, 243 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo 244 ) 245 { 246 EMMC_PEIM_HC_PRIVATE_DATA *Private; 247 UINT8 SlotNum; 248 UINT8 MediaNum; 249 UINT8 Location; 250 BOOLEAN Found; 251 252 Found = FALSE; 253 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 254 255 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { 256 return EFI_INVALID_PARAMETER; 257 } 258 259 Location = 0; 260 MediaNum = 0; 261 for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) { 262 for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) { 263 Location ++; 264 if (Location == DeviceIndex) { 265 Found = TRUE; 266 break; 267 } 268 } 269 if (Found) { 270 break; 271 } 272 } 273 274 MediaInfo->DeviceType = EMMC; 275 MediaInfo->MediaPresent = TRUE; 276 MediaInfo->LastBlock = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock; 277 MediaInfo->BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize; 278 279 return EFI_SUCCESS; 280 } 281 282 /** 283 Reads the requested number of blocks from the specified block device. 284 285 The function reads the requested number of blocks from the device. All the 286 blocks are read, or an error is returned. If there is no media in the device, 287 the function returns EFI_NO_MEDIA. 288 289 @param[in] PeiServices General-purpose services that are available to 290 every PEIM. 291 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 292 @param[in] DeviceIndex Specifies the block device to which the function wants 293 to talk. Because the driver that implements Block I/O 294 PPIs will manage multiple block devices, PPIs that 295 want to talk to a single device must specify the device 296 index that was assigned during the enumeration process. 297 This index is a number from one to NumberBlockDevices. 298 @param[in] StartLBA The starting logical block address (LBA) to read from 299 on the device 300 @param[in] BufferSize The size of the Buffer in bytes. This number must be 301 a multiple of the intrinsic block size of the device. 302 @param[out] Buffer A pointer to the destination buffer for the data. 303 The caller is responsible for the ownership of the 304 buffer. 305 306 @retval EFI_SUCCESS The data was read correctly from the device. 307 @retval EFI_DEVICE_ERROR The device reported an error while attempting 308 to perform the read operation. 309 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 310 valid, or the buffer is not properly aligned. 311 @retval EFI_NO_MEDIA There is no media in the device. 312 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 313 the intrinsic block size of the device. 314 315 **/ 316 EFI_STATUS 317 EFIAPI 318 EmmcBlockIoPeimReadBlocks ( 319 IN EFI_PEI_SERVICES **PeiServices, 320 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 321 IN UINTN DeviceIndex, 322 IN EFI_PEI_LBA StartLBA, 323 IN UINTN BufferSize, 324 OUT VOID *Buffer 325 ) 326 { 327 EFI_STATUS Status; 328 UINT32 BlockSize; 329 UINTN NumberOfBlocks; 330 EMMC_PEIM_HC_PRIVATE_DATA *Private; 331 UINT8 SlotNum; 332 UINT8 MediaNum; 333 UINT8 Location; 334 UINT8 PartitionConfig; 335 UINTN Remaining; 336 UINT32 MaxBlock; 337 BOOLEAN Found; 338 339 Status = EFI_SUCCESS; 340 Found = FALSE; 341 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 342 343 // 344 // Check parameters 345 // 346 if (Buffer == NULL) { 347 return EFI_INVALID_PARAMETER; 348 } 349 350 if (BufferSize == 0) { 351 return EFI_SUCCESS; 352 } 353 354 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { 355 return EFI_INVALID_PARAMETER; 356 } 357 358 Location = 0; 359 MediaNum = 0; 360 for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) { 361 for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) { 362 Location ++; 363 if (Location == DeviceIndex) { 364 Found = TRUE; 365 break; 366 } 367 } 368 if (Found) { 369 break; 370 } 371 } 372 373 BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize; 374 if (BufferSize % BlockSize != 0) { 375 return EFI_BAD_BUFFER_SIZE; 376 } 377 378 if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) { 379 return EFI_INVALID_PARAMETER; 380 } 381 382 NumberOfBlocks = BufferSize / BlockSize; 383 384 // 385 // Check if needs to switch partition access. 386 // 387 PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig; 388 if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) { 389 PartitionConfig &= (UINT8)~0x7; 390 PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum]; 391 Status = EmmcPeimSwitch ( 392 &Private->Slot[SlotNum], 393 0x3, 394 OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), 395 PartitionConfig, 396 0x0 397 ); 398 if (EFI_ERROR (Status)) { 399 return Status; 400 } 401 Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig; 402 } 403 // 404 // Start to execute data transfer. The max block number in single cmd is 65535 blocks. 405 // 406 Remaining = NumberOfBlocks; 407 MaxBlock = 0xFFFF; 408 409 while (Remaining > 0) { 410 if (Remaining <= MaxBlock) { 411 NumberOfBlocks = Remaining; 412 } else { 413 NumberOfBlocks = MaxBlock; 414 } 415 416 Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks); 417 if (EFI_ERROR (Status)) { 418 return Status; 419 } 420 421 BufferSize = NumberOfBlocks * BlockSize; 422 Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE); 423 if (EFI_ERROR (Status)) { 424 return Status; 425 } 426 427 StartLBA += NumberOfBlocks; 428 Buffer = (UINT8*)Buffer + BufferSize; 429 Remaining -= NumberOfBlocks; 430 } 431 return Status; 432 } 433 434 /** 435 Gets the count of block I/O devices that one specific block driver detects. 436 437 This function is used for getting the count of block I/O devices that one 438 specific block driver detects. To the PEI ATAPI driver, it returns the number 439 of all the detected ATAPI devices it detects during the enumeration process. 440 To the PEI legacy floppy driver, it returns the number of all the legacy 441 devices it finds during its enumeration process. If no device is detected, 442 then the function will return zero. 443 444 @param[in] PeiServices General-purpose services that are available 445 to every PEIM. 446 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI 447 instance. 448 @param[out] NumberBlockDevices The number of block I/O devices discovered. 449 450 @retval EFI_SUCCESS The operation performed successfully. 451 452 **/ 453 EFI_STATUS 454 EFIAPI 455 EmmcBlockIoPeimGetDeviceNo2 ( 456 IN EFI_PEI_SERVICES **PeiServices, 457 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 458 OUT UINTN *NumberBlockDevices 459 ) 460 { 461 EMMC_PEIM_HC_PRIVATE_DATA *Private; 462 463 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 464 *NumberBlockDevices = Private->TotalBlkIoDevices; 465 466 return EFI_SUCCESS; 467 } 468 469 /** 470 Gets a block device's media information. 471 472 This function will provide the caller with the specified block device's media 473 information. If the media changes, calling this function will update the media 474 information accordingly. 475 476 @param[in] PeiServices General-purpose services that are available to every 477 PEIM 478 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 479 @param[in] DeviceIndex Specifies the block device to which the function wants 480 to talk. Because the driver that implements Block I/O 481 PPIs will manage multiple block devices, the PPIs that 482 want to talk to a single device must specify the 483 device index that was assigned during the enumeration 484 process. This index is a number from one to 485 NumberBlockDevices. 486 @param[out] MediaInfo The media information of the specified block media. 487 The caller is responsible for the ownership of this 488 data structure. 489 490 @par Note: 491 The MediaInfo structure describes an enumeration of possible block device 492 types. This enumeration exists because no device paths are actually passed 493 across interfaces that describe the type or class of hardware that is publishing 494 the block I/O interface. This enumeration will allow for policy decisions 495 in the Recovery PEIM, such as "Try to recover from legacy floppy first, 496 LS-120 second, CD-ROM third." If there are multiple partitions abstracted 497 by a given device type, they should be reported in ascending order; this 498 order also applies to nested partitions, such as legacy MBR, where the 499 outermost partitions would have precedence in the reporting order. The 500 same logic applies to systems such as IDE that have precedence relationships 501 like "Master/Slave" or "Primary/Secondary". The master device should be 502 reported first, the slave second. 503 504 @retval EFI_SUCCESS Media information about the specified block device 505 was obtained successfully. 506 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 507 error. 508 509 **/ 510 EFI_STATUS 511 EFIAPI 512 EmmcBlockIoPeimGetMediaInfo2 ( 513 IN EFI_PEI_SERVICES **PeiServices, 514 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 515 IN UINTN DeviceIndex, 516 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo 517 ) 518 { 519 EFI_STATUS Status; 520 EMMC_PEIM_HC_PRIVATE_DATA *Private; 521 EFI_PEI_BLOCK_IO_MEDIA Media; 522 UINT8 SlotNum; 523 UINT8 MediaNum; 524 UINT8 Location; 525 BOOLEAN Found; 526 527 Found = FALSE; 528 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 529 530 Status = EmmcBlockIoPeimGetMediaInfo ( 531 PeiServices, 532 &Private->BlkIoPpi, 533 DeviceIndex, 534 &Media 535 ); 536 if (EFI_ERROR (Status)) { 537 return Status; 538 } 539 540 Location = 0; 541 MediaNum = 0; 542 for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) { 543 for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) { 544 Location ++; 545 if (Location == DeviceIndex) { 546 Found = TRUE; 547 break; 548 } 549 } 550 if (Found) { 551 break; 552 } 553 } 554 555 CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA)); 556 return EFI_SUCCESS; 557 } 558 559 /** 560 Reads the requested number of blocks from the specified block device. 561 562 The function reads the requested number of blocks from the device. All the 563 blocks are read, or an error is returned. If there is no media in the device, 564 the function returns EFI_NO_MEDIA. 565 566 @param[in] PeiServices General-purpose services that are available to 567 every PEIM. 568 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 569 @param[in] DeviceIndex Specifies the block device to which the function wants 570 to talk. Because the driver that implements Block I/O 571 PPIs will manage multiple block devices, PPIs that 572 want to talk to a single device must specify the device 573 index that was assigned during the enumeration process. 574 This index is a number from one to NumberBlockDevices. 575 @param[in] StartLBA The starting logical block address (LBA) to read from 576 on the device 577 @param[in] BufferSize The size of the Buffer in bytes. This number must be 578 a multiple of the intrinsic block size of the device. 579 @param[out] Buffer A pointer to the destination buffer for the data. 580 The caller is responsible for the ownership of the 581 buffer. 582 583 @retval EFI_SUCCESS The data was read correctly from the device. 584 @retval EFI_DEVICE_ERROR The device reported an error while attempting 585 to perform the read operation. 586 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 587 valid, or the buffer is not properly aligned. 588 @retval EFI_NO_MEDIA There is no media in the device. 589 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 590 the intrinsic block size of the device. 591 592 **/ 593 EFI_STATUS 594 EFIAPI 595 EmmcBlockIoPeimReadBlocks2 ( 596 IN EFI_PEI_SERVICES **PeiServices, 597 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 598 IN UINTN DeviceIndex, 599 IN EFI_PEI_LBA StartLBA, 600 IN UINTN BufferSize, 601 OUT VOID *Buffer 602 ) 603 { 604 EFI_STATUS Status; 605 EMMC_PEIM_HC_PRIVATE_DATA *Private; 606 607 Status = EFI_SUCCESS; 608 Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 609 610 Status = EmmcBlockIoPeimReadBlocks ( 611 PeiServices, 612 &Private->BlkIoPpi, 613 DeviceIndex, 614 StartLBA, 615 BufferSize, 616 Buffer 617 ); 618 return Status; 619 } 620 621 /** 622 The user code starts with this function. 623 624 @param FileHandle Handle of the file being invoked. 625 @param PeiServices Describes the list of possible PEI Services. 626 627 @retval EFI_SUCCESS The driver is successfully initialized. 628 @retval Others Can't initialize the driver. 629 630 **/ 631 EFI_STATUS 632 EFIAPI 633 InitializeEmmcBlockIoPeim ( 634 IN EFI_PEI_FILE_HANDLE FileHandle, 635 IN CONST EFI_PEI_SERVICES **PeiServices 636 ) 637 { 638 EFI_STATUS Status; 639 EMMC_PEIM_HC_PRIVATE_DATA *Private; 640 EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi; 641 UINT32 Index; 642 UINT32 PartitionIndex; 643 UINTN *MmioBase; 644 UINT8 BarNum; 645 UINT8 SlotNum; 646 UINT8 MediaNum; 647 UINT8 Controller; 648 UINT64 Capacity; 649 EMMC_EXT_CSD *ExtCsd; 650 EMMC_HC_SLOT_CAP Capability; 651 EMMC_PEIM_HC_SLOT *Slot; 652 UINT32 SecCount; 653 UINT32 GpSizeMult; 654 655 // 656 // Shadow this PEIM to run from memory 657 // 658 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { 659 return EFI_SUCCESS; 660 } 661 662 // 663 // locate Emmc host controller PPI 664 // 665 Status = PeiServicesLocatePpi ( 666 &gEdkiiPeiSdMmcHostControllerPpiGuid, 667 0, 668 NULL, 669 (VOID **) &SdMmcHcPpi 670 ); 671 if (EFI_ERROR (Status)) { 672 return EFI_DEVICE_ERROR; 673 } 674 675 Controller = 0; 676 MmioBase = NULL; 677 while (TRUE) { 678 Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum); 679 // 680 // When status is error, meant no controller is found 681 // 682 if (EFI_ERROR (Status)) { 683 break; 684 } 685 686 if (BarNum == 0) { 687 Controller++; 688 continue; 689 } 690 691 Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate); 692 if (Private == NULL) { 693 Status = EFI_OUT_OF_RESOURCES; 694 break; 695 } 696 Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi; 697 Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi; 698 // 699 // Initialize the memory pool which will be used in all transactions. 700 // 701 Status = EmmcPeimInitMemPool (Private); 702 if (EFI_ERROR (Status)) { 703 Status = EFI_OUT_OF_RESOURCES; 704 break; 705 } 706 707 for (Index = 0; Index < BarNum; Index++) { 708 Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability); 709 if (EFI_ERROR (Status)) { 710 continue; 711 } 712 if (Capability.SlotType != 0x1) { 713 DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index])); 714 Status = EFI_UNSUPPORTED; 715 continue; 716 } 717 718 Status = EmmcPeimHcReset (MmioBase[Index]); 719 if (EFI_ERROR (Status)) { 720 continue; 721 } 722 Status = EmmcPeimHcCardDetect (MmioBase[Index]); 723 if (EFI_ERROR (Status)) { 724 continue; 725 } 726 Status = EmmcPeimHcInitHost (MmioBase[Index]); 727 if (EFI_ERROR (Status)) { 728 continue; 729 } 730 731 SlotNum = Private->SlotNum; 732 Slot = &Private->Slot[SlotNum]; 733 CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT)); 734 Slot->Private = Private; 735 Slot->EmmcHcBase = MmioBase[Index]; 736 CopyMem (&Slot->Capability, &Capability, sizeof (Capability)); 737 738 Status = EmmcPeimIdentification (Slot); 739 if (EFI_ERROR (Status)) { 740 continue; 741 } 742 743 ExtCsd = &Slot->ExtCsd; 744 if (ExtCsd->ExtCsdRev < 5) { 745 DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n")); 746 Status = EFI_UNSUPPORTED; 747 continue; 748 } 749 if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) { 750 DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n")); 751 Status = EFI_UNSUPPORTED; 752 continue; 753 } 754 755 for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) { 756 switch (PartitionIndex) { 757 case EmmcPartitionUserData: 758 SecCount = *(UINT32*)&ExtCsd->SecCount; 759 Capacity = MultU64x32 ((UINT64)SecCount, 0x200); 760 break; 761 case EmmcPartitionBoot1: 762 case EmmcPartitionBoot2: 763 Capacity = ExtCsd->BootSizeMult * SIZE_128KB; 764 break; 765 case EmmcPartitionRPMB: 766 Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB; 767 break; 768 case EmmcPartitionGP1: 769 GpSizeMult = (ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16)); 770 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); 771 break; 772 case EmmcPartitionGP2: 773 GpSizeMult = (ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16)); 774 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); 775 break; 776 case EmmcPartitionGP3: 777 GpSizeMult = (ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16)); 778 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); 779 break; 780 case EmmcPartitionGP4: 781 GpSizeMult = (ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16)); 782 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB); 783 break; 784 default: 785 ASSERT (FALSE); 786 continue; 787 } 788 789 MediaNum = Slot->MediaNum; 790 if (Capacity != 0) { 791 Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1; 792 Slot->PartitionType[MediaNum] = PartitionIndex; 793 Private->TotalBlkIoDevices++; 794 Slot->MediaNum++; 795 } 796 } 797 Private->SlotNum++; 798 } 799 Controller++; 800 801 if (!EFI_ERROR (Status)) { 802 PeiServicesInstallPpi (&Private->BlkIoPpiList); 803 } 804 } 805 806 return EFI_SUCCESS; 807 } 808