Home | History | Annotate | Download | only in EmmcBlockIoPei
      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