Home | History | Annotate | Download | only in UfsBlockIoPei
      1 /** @file
      2 
      3   Copyright (c) 2014, 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 "UfsBlockIoPei.h"
     15 
     16 /**
     17   Wait for the value of the specified system memory set to the test value.
     18 
     19   @param  Address           The system memory address to test.
     20   @param  MaskValue         The mask value of memory.
     21   @param  TestValue         The test value of memory.
     22   @param  Timeout           The time out value for wait memory set, uses 100ns as a unit.
     23 
     24   @retval EFI_TIMEOUT       The system memory setting is time out.
     25   @retval EFI_SUCCESS       The system memory is correct set.
     26 
     27 **/
     28 EFI_STATUS
     29 EFIAPI
     30 UfsWaitMemSet (
     31   IN  UINTN                     Address,
     32   IN  UINT32                    MaskValue,
     33   IN  UINT32                    TestValue,
     34   IN  UINT64                    Timeout
     35   )
     36 {
     37   UINT32     Value;
     38   UINT64     Delay;
     39   BOOLEAN    InfiniteWait;
     40 
     41   if (Timeout == 0) {
     42     InfiniteWait = TRUE;
     43   } else {
     44     InfiniteWait = FALSE;
     45   }
     46 
     47   Delay = DivU64x32 (Timeout, 10) + 1;
     48 
     49   do {
     50     //
     51     // Access PCI MMIO space to see if the value is the tested one.
     52     //
     53     Value = MmioRead32 (Address) & MaskValue;
     54 
     55     if (Value == TestValue) {
     56       return EFI_SUCCESS;
     57     }
     58 
     59     //
     60     // Stall for 1 microseconds.
     61     //
     62     MicroSecondDelay (1);
     63 
     64     Delay--;
     65 
     66   } while (InfiniteWait || (Delay > 0));
     67 
     68   return EFI_TIMEOUT;
     69 }
     70 
     71 /**
     72   Dump UIC command execution result for debugging.
     73 
     74   @param[in]   UicOpcode  The executed UIC opcode.
     75   @param[in]   Result     The result to be parsed.
     76 
     77 **/
     78 VOID
     79 DumpUicCmdExecResult (
     80   IN  UINT8     UicOpcode,
     81   IN  UINT8     Result
     82   )
     83 {
     84   if (UicOpcode <= UfsUicDmePeerSet) {
     85     switch (Result) {
     86       case 0x00:
     87         break;
     88       case 0x01:
     89         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
     90         break;
     91       case 0x02:
     92         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
     93         break;
     94       case 0x03:
     95         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
     96         break;
     97       case 0x04:
     98         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
     99         break;
    100       case 0x05:
    101         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
    102         break;
    103       case 0x06:
    104         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
    105         break;
    106       case 0x07:
    107         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
    108         break;
    109       case 0x08:
    110         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
    111         break;
    112       case 0x09:
    113         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BUSY\n"));
    114         break;
    115       case 0x0A:
    116         DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
    117         break;
    118       default :
    119         ASSERT (FALSE);
    120         break;
    121     }
    122   } else {
    123     switch (Result) {
    124       case 0x00:
    125         break;
    126       case 0x01:
    127         DEBUG ((EFI_D_VERBOSE, "UIC control command fails - FAILURE\n"));
    128         break;
    129       default :
    130         ASSERT (FALSE);
    131         break;
    132     }
    133   }
    134 }
    135 
    136 /**
    137   Dump QUERY RESPONSE UPIU result for debugging.
    138 
    139   @param[in]   Result  The result to be parsed.
    140 
    141 **/
    142 VOID
    143 DumpQueryResponseResult (
    144   IN  UINT8     Result
    145   )
    146 {
    147   switch (Result) {
    148     case 0xF6:
    149       DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Readable\n"));
    150       break;
    151     case 0xF7:
    152       DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Writeable\n"));
    153       break;
    154     case 0xF8:
    155       DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Already Written\n"));
    156       break;
    157     case 0xF9:
    158       DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Length\n"));
    159       break;
    160     case 0xFA:
    161       DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Value\n"));
    162       break;
    163     case 0xFB:
    164       DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Selector\n"));
    165       break;
    166     case 0xFC:
    167       DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Index\n"));
    168       break;
    169     case 0xFD:
    170       DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Idn\n"));
    171       break;
    172     case 0xFE:
    173       DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Opcode\n"));
    174       break;
    175     case 0xFF:
    176       DEBUG ((EFI_D_VERBOSE, "Query Response with General Failure\n"));
    177       break;
    178     default :
    179       ASSERT (FALSE);
    180       break;
    181   }
    182 }
    183 
    184 /**
    185   Swap little endian to big endian.
    186 
    187   @param[in, out] Buffer      The data buffer. In input, it contains little endian data.
    188                               In output, it will become big endian.
    189   @param[in]      BufferSize  The length of converted data.
    190 
    191 **/
    192 VOID
    193 SwapLittleEndianToBigEndian (
    194   IN OUT UINT8         *Buffer,
    195   IN     UINT32        BufferSize
    196   )
    197 {
    198   UINT32 Index;
    199   UINT8  Temp;
    200   UINT32 SwapCount;
    201 
    202   SwapCount = BufferSize / 2;
    203   for (Index = 0; Index < SwapCount; Index++) {
    204     Temp = Buffer[Index];
    205     Buffer[Index] = Buffer[BufferSize - 1 - Index];
    206     Buffer[BufferSize - 1 - Index] = Temp;
    207   }
    208 }
    209 
    210 /**
    211   Fill TSF field of QUERY REQUEST UPIU.
    212 
    213   @param[in, out] TsfBase      The base address of TSF field of QUERY REQUEST UPIU.
    214   @param[in]      Opcode       The opcode of request.
    215   @param[in]      DescId       The descriptor ID of request.
    216   @param[in]      Index        The index of request.
    217   @param[in]      Selector     The selector of request.
    218   @param[in]      Length       The length of transferred data. The maximum is 4.
    219   @param[in]      Value        The value of transferred data.
    220 
    221 **/
    222 VOID
    223 UfsFillTsfOfQueryReqUpiu (
    224   IN OUT UTP_UPIU_TSF        *TsfBase,
    225   IN     UINT8               Opcode,
    226   IN     UINT8               DescId    OPTIONAL,
    227   IN     UINT8               Index     OPTIONAL,
    228   IN     UINT8               Selector  OPTIONAL,
    229   IN     UINT16              Length    OPTIONAL,
    230   IN     UINT32              Value     OPTIONAL
    231   )
    232 {
    233   ASSERT (TsfBase != NULL);
    234   ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
    235 
    236   TsfBase->Opcode   = Opcode;
    237   if (Opcode != UtpQueryFuncOpcodeNop) {
    238     TsfBase->DescId   = DescId;
    239     TsfBase->Index    = Index;
    240     TsfBase->Selector = Selector;
    241 
    242     if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
    243       SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));
    244       TsfBase->Length = Length;
    245     }
    246 
    247     if (Opcode == UtpQueryFuncOpcodeWrAttr) {
    248       SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));
    249       TsfBase->Value  = Value;
    250     }
    251   }
    252 }
    253 
    254 /**
    255   Initialize COMMAND UPIU.
    256 
    257   @param[in, out] Command         The base address of COMMAND UPIU.
    258   @param[in]      Lun             The Lun on which the SCSI command is executed.
    259   @param[in]      TaskTag         The task tag of request.
    260   @param[in]      Cdb             The cdb buffer containing SCSI command.
    261   @param[in]      CdbLength       The cdb length.
    262   @param[in]      DataDirection   The direction of data transfer.
    263   @param[in]      ExpDataTranLen  The expected transfer data length.
    264 
    265   @retval EFI_SUCCESS     The initialization succeed.
    266 
    267 **/
    268 EFI_STATUS
    269 UfsInitCommandUpiu (
    270   IN OUT UTP_COMMAND_UPIU              *Command,
    271   IN     UINT8                         Lun,
    272   IN     UINT8                         TaskTag,
    273   IN     UINT8                         *Cdb,
    274   IN     UINT8                         CdbLength,
    275   IN     UFS_DATA_DIRECTION            DataDirection,
    276   IN     UINT32                        ExpDataTranLen
    277   )
    278 {
    279   UINT8                   Flags;
    280 
    281   ASSERT ((Command != NULL) && (Cdb != NULL));
    282 
    283   //
    284   // Task attribute is hard-coded to Ordered.
    285   //
    286   if (DataDirection == UfsDataIn) {
    287     Flags = BIT0 | BIT6;
    288   } else if (DataDirection == UfsDataOut) {
    289     Flags = BIT0 | BIT5;
    290   } else {
    291     Flags = BIT0;
    292   }
    293 
    294   //
    295   // Fill UTP COMMAND UPIU associated fields.
    296   //
    297   Command->TransCode = 0x01;
    298   Command->Flags     = Flags;
    299   Command->Lun       = Lun;
    300   Command->TaskTag   = TaskTag;
    301   Command->CmdSet    = 0x00;
    302   SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));
    303   Command->ExpDataTranLen = ExpDataTranLen;
    304 
    305   CopyMem (Command->Cdb, Cdb, CdbLength);
    306 
    307   return EFI_SUCCESS;
    308 }
    309 
    310 /**
    311   Initialize UTP PRDT for data transfer.
    312 
    313   @param[in] Prdt         The base address of PRDT.
    314   @param[in] Buffer       The buffer to be read or written.
    315   @param[in] BufferSize   The data size to be read or written.
    316 
    317   @retval EFI_SUCCESS     The initialization succeed.
    318 
    319 **/
    320 EFI_STATUS
    321 UfsInitUtpPrdt (
    322   IN  UTP_TR_PRD                       *Prdt,
    323   IN  VOID                             *Buffer,
    324   IN  UINT32                           BufferSize
    325   )
    326 {
    327   UINT32     PrdtIndex;
    328   UINT32     RemainingLen;
    329   UINT8      *Remaining;
    330   UINTN      PrdtNumber;
    331 
    332   if (BufferSize == 0) {
    333     return EFI_SUCCESS;
    334   }
    335 
    336   ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
    337 
    338   RemainingLen = BufferSize;
    339   Remaining    = Buffer;
    340   PrdtNumber   = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
    341 
    342   for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
    343     if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
    344       Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
    345     } else {
    346       Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
    347     }
    348 
    349     Prdt[PrdtIndex].DbAddr  = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
    350     Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
    351     RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
    352     Remaining    += UFS_MAX_DATA_LEN_PER_PRD;
    353   }
    354 
    355   return EFI_SUCCESS;
    356 }
    357 
    358 /**
    359   Initialize QUERY REQUEST UPIU.
    360 
    361   @param[in, out] QueryReq      The base address of QUERY REQUEST UPIU.
    362   @param[in]      TaskTag       The task tag of request.
    363   @param[in]      Opcode        The opcode of request.
    364   @param[in]      DescId        The descriptor ID of request.
    365   @param[in]      Index         The index of request.
    366   @param[in]      Selector      The selector of request.
    367   @param[in]      DataSize      The data size to be read or written.
    368   @param[in]      Data          The buffer to be read or written.
    369 
    370   @retval EFI_SUCCESS           The initialization succeed.
    371 
    372 **/
    373 EFI_STATUS
    374 UfsInitQueryRequestUpiu (
    375   IN OUT UTP_QUERY_REQ_UPIU            *QueryReq,
    376   IN     UINT8                         TaskTag,
    377   IN     UINT8                         Opcode,
    378   IN     UINT8                         DescId,
    379   IN     UINT8                         Index,
    380   IN     UINT8                         Selector,
    381   IN     UINTN                         DataSize   OPTIONAL,
    382   IN     UINT8                         *Data      OPTIONAL
    383   )
    384 {
    385   ASSERT (QueryReq != NULL);
    386 
    387   QueryReq->TransCode = 0x16;
    388   QueryReq->TaskTag   = TaskTag;
    389   if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
    390     QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
    391   } else {
    392     QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
    393   }
    394 
    395   if (Opcode == UtpQueryFuncOpcodeWrAttr) {
    396     UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);
    397   } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
    398     UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
    399   } else {
    400     UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
    401   }
    402 
    403   if (Opcode == UtpQueryFuncOpcodeWrDesc) {
    404     CopyMem (QueryReq + 1, Data, DataSize);
    405   }
    406 
    407   return EFI_SUCCESS;
    408 }
    409 
    410 /**
    411   Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
    412 
    413   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    414   @param[in]  Lun               The Lun on which the SCSI command is executed.
    415   @param[in]  Packet            The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
    416   @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.
    417 
    418   @retval EFI_SUCCESS           The creation succeed.
    419   @retval EFI_DEVICE_ERROR      The creation failed.
    420   @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.
    421 
    422 **/
    423 EFI_STATUS
    424 UfsCreateScsiCommandDesc (
    425   IN  UFS_PEIM_HC_PRIVATE_DATA            *Private,
    426   IN  UINT8                               Lun,
    427   IN  UFS_SCSI_REQUEST_PACKET             *Packet,
    428   IN  UTP_TRD                             *Trd
    429   )
    430 {
    431   UINT8                    *CommandDesc;
    432   UINTN                    TotalLen;
    433   UINTN                    PrdtNumber;
    434   VOID                     *Buffer;
    435   UINT32                   Length;
    436   UTP_COMMAND_UPIU         *CommandUpiu;
    437   UTP_TR_PRD               *PrdtBase;
    438   UFS_DATA_DIRECTION       DataDirection;
    439 
    440   ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
    441 
    442   if (Packet->DataDirection == UfsDataIn) {
    443     Buffer = Packet->InDataBuffer;
    444     Length = Packet->InTransferLength;
    445     DataDirection = UfsDataIn;
    446   } else {
    447     Buffer = Packet->OutDataBuffer;
    448     Length = Packet->OutTransferLength;
    449     DataDirection = UfsDataOut;
    450   }
    451 
    452   if (Length == 0) {
    453     DataDirection = UfsNoData;
    454   }
    455 
    456   PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
    457 
    458   TotalLen    = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
    459   CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
    460   if (CommandDesc == NULL) {
    461     return EFI_OUT_OF_RESOURCES;
    462   }
    463 
    464   CommandUpiu  = (UTP_COMMAND_UPIU*)CommandDesc;
    465   PrdtBase     = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
    466 
    467   UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
    468   UfsInitUtpPrdt (PrdtBase, Buffer, Length);
    469 
    470   //
    471   // Fill UTP_TRD associated fields
    472   // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
    473   // *MUST* be located at a 64-bit aligned boundary.
    474   //
    475   Trd->Int    = UFS_INTERRUPT_COMMAND;
    476   Trd->Dd     = DataDirection;
    477   Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;
    478   Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);
    479   Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);
    480   Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
    481   Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
    482   Trd->PrdtL  = (UINT16)PrdtNumber;
    483   Trd->PrdtO  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
    484   return EFI_SUCCESS;
    485 }
    486 
    487 /**
    488   Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
    489 
    490   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    491   @param[in]  Packet            The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
    492   @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.
    493 
    494   @retval EFI_SUCCESS           The creation succeed.
    495   @retval EFI_DEVICE_ERROR      The creation failed.
    496   @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.
    497   @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
    498 
    499 **/
    500 EFI_STATUS
    501 UfsCreateDMCommandDesc (
    502   IN  UFS_PEIM_HC_PRIVATE_DATA              *Private,
    503   IN  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET  *Packet,
    504   IN  UTP_TRD                               *Trd
    505   )
    506 {
    507   UINT8                         *CommandDesc;
    508   UINTN                         TotalLen;
    509   UTP_QUERY_REQ_UPIU            *QueryReqUpiu;
    510   UINT8                         Opcode;
    511   UINT32                        DataSize;
    512   UINT8                         *Data;
    513   UINT8                         DataDirection;
    514 
    515   ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
    516 
    517   Opcode = Packet->Opcode;
    518   if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
    519     return EFI_INVALID_PARAMETER;
    520   }
    521 
    522   DataDirection = Packet->DataDirection;
    523   if (DataDirection == UfsDataIn) {
    524     DataSize = Packet->InTransferLength;
    525     Data     = Packet->InDataBuffer;
    526   } else if (DataDirection == UfsDataOut) {
    527     DataSize = Packet->OutTransferLength;
    528     Data     = Packet->OutDataBuffer;
    529   } else {
    530     DataSize = 0;
    531     Data     = NULL;
    532   }
    533 
    534   if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))
    535     && ((DataSize == 0) || (Data == NULL))) {
    536     return EFI_INVALID_PARAMETER;
    537   }
    538 
    539   if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))
    540     && ((DataSize != 0) || (Data != NULL))) {
    541     return EFI_INVALID_PARAMETER;
    542   }
    543 
    544   if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {
    545     return EFI_INVALID_PARAMETER;
    546   }
    547 
    548   if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
    549     TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
    550   } else {
    551     TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
    552   }
    553 
    554   CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
    555   if (CommandDesc == NULL) {
    556     return EFI_OUT_OF_RESOURCES;
    557   }
    558 
    559   //
    560   // Initialize UTP QUERY REQUEST UPIU
    561   //
    562   QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;
    563   UfsInitQueryRequestUpiu (
    564     QueryReqUpiu,
    565     Private->TaskTag++,
    566     Opcode,
    567     Packet->DescId,
    568     Packet->Index,
    569     Packet->Selector,
    570     DataSize,
    571     Data
    572     );
    573 
    574   //
    575   // Fill UTP_TRD associated fields
    576   // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
    577   //
    578   Trd->Int    = UFS_INTERRUPT_COMMAND;
    579   Trd->Dd     = DataDirection;
    580   Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;
    581   Trd->Ocs    = 0x0F;
    582   Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);
    583   Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);
    584   if (Opcode == UtpQueryFuncOpcodeWrDesc) {
    585     Trd->RuL  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
    586     Trd->RuO  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));
    587   } else {
    588     Trd->RuL  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));
    589     Trd->RuO  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
    590   }
    591 
    592   return EFI_SUCCESS;
    593 }
    594 
    595 /**
    596   Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
    597 
    598   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    599   @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.
    600 
    601   @retval EFI_SUCCESS           The creation succeed.
    602   @retval EFI_DEVICE_ERROR      The creation failed.
    603   @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.
    604 
    605 **/
    606 EFI_STATUS
    607 UfsCreateNopCommandDesc (
    608   IN  UFS_PEIM_HC_PRIVATE_DATA                    *Private,
    609   IN  UTP_TRD                                     *Trd
    610   )
    611 {
    612   UINT8                    *CommandDesc;
    613   UINTN                    TotalLen;
    614   UTP_NOP_OUT_UPIU         *NopOutUpiu;
    615 
    616   ASSERT ((Private != NULL) && (Trd != NULL));
    617 
    618   TotalLen    = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
    619   CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
    620   if (CommandDesc == NULL) {
    621     return EFI_OUT_OF_RESOURCES;
    622   }
    623 
    624   NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;
    625 
    626   NopOutUpiu->TaskTag = Private->TaskTag++;
    627 
    628   //
    629   // Fill UTP_TRD associated fields
    630   // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
    631   //
    632   Trd->Int    = UFS_INTERRUPT_COMMAND;
    633   Trd->Dd     = 0x00;
    634   Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;
    635   Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);
    636   Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);
    637   Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
    638   Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
    639 
    640   return EFI_SUCCESS;
    641 }
    642 
    643 /**
    644   Find out available slot in transfer list of a UFS device.
    645 
    646   @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    647   @param[out] Slot          The available slot.
    648 
    649   @retval EFI_SUCCESS       The available slot was found successfully.
    650 
    651 **/
    652 EFI_STATUS
    653 UfsFindAvailableSlotInTrl (
    654   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    655      OUT UINT8                        *Slot
    656   )
    657 {
    658   ASSERT ((Private != NULL) && (Slot != NULL));
    659 
    660   //
    661   // The simplest algo to always use slot 0.
    662   // TODO: enhance it to support async transfer with multiple slot.
    663   //
    664   *Slot = 0;
    665 
    666   return EFI_SUCCESS;
    667 }
    668 
    669 /**
    670   Find out available slot in task management transfer list of a UFS device.
    671 
    672   @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    673   @param[out] Slot          The available slot.
    674 
    675   @retval EFI_SUCCESS       The available slot was found successfully.
    676 
    677 **/
    678 EFI_STATUS
    679 UfsFindAvailableSlotInTmrl (
    680   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    681      OUT UINT8                        *Slot
    682   )
    683 {
    684   ASSERT ((Private != NULL) && (Slot != NULL));
    685 
    686   //
    687   // The simplest algo to always use slot 0.
    688   // TODO: enhance it to support async transfer with multiple slot.
    689   //
    690   *Slot = 0;
    691 
    692   return EFI_SUCCESS;
    693 }
    694 
    695 /**
    696   Start specified slot in transfer list of a UFS device.
    697 
    698   @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    699   @param[in]  Slot          The slot to be started.
    700 
    701 **/
    702 VOID
    703 UfsStartExecCmd (
    704   IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
    705   IN  UINT8                        Slot
    706   )
    707 {
    708   UINTN         UfsHcBase;
    709   UINTN         Address;
    710   UINT32        Data;
    711 
    712   UfsHcBase = Private->UfsHcBase;
    713 
    714   Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
    715   Data    = MmioRead32 (Address);
    716   if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
    717     MmioWrite32 (Address, UFS_HC_UTRLRSR);
    718   }
    719 
    720   Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
    721   MmioWrite32 (Address, BIT0 << Slot);
    722 }
    723 
    724 /**
    725   Stop specified slot in transfer list of a UFS device.
    726 
    727   @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    728   @param[in]  Slot          The slot to be stop.
    729 
    730 **/
    731 VOID
    732 UfsStopExecCmd (
    733   IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
    734   IN  UINT8                        Slot
    735   )
    736 {
    737   UINTN         UfsHcBase;
    738   UINTN         Address;
    739   UINT32        Data;
    740 
    741   UfsHcBase = Private->UfsHcBase;
    742 
    743   Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
    744   Data    = MmioRead32 (Address);
    745   if ((Data & (BIT0 << Slot)) != 0) {
    746     Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;
    747     Data    = MmioRead32 (Address);
    748     MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));
    749   }
    750 }
    751 
    752 /**
    753   Read or write specified device descriptor of a UFS device.
    754 
    755   @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    756   @param[in]      Read          The boolean variable to show r/w direction.
    757   @param[in]      DescId        The ID of device descriptor.
    758   @param[in]      Index         The Index of device descriptor.
    759   @param[in]      Selector      The Selector of device descriptor.
    760   @param[in, out] Descriptor    The buffer of device descriptor to be read or written.
    761   @param[in]      DescSize      The size of device descriptor buffer.
    762 
    763   @retval EFI_SUCCESS           The device descriptor was read/written successfully.
    764   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the device descriptor.
    765   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the device descriptor.
    766 
    767 **/
    768 EFI_STATUS
    769 UfsRwDeviceDesc (
    770   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    771   IN     BOOLEAN                      Read,
    772   IN     UINT8                        DescId,
    773   IN     UINT8                        Index,
    774   IN     UINT8                        Selector,
    775   IN OUT VOID                         *Descriptor,
    776   IN     UINT32                       DescSize
    777   )
    778 {
    779   EFI_STATUS                           Status;
    780   UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
    781   UINT8                                Slot;
    782   UTP_TRD                              *Trd;
    783   UINTN                                Address;
    784   UTP_QUERY_RESP_UPIU                  *QueryResp;
    785   UINT8                                *CmdDescBase;
    786   UINT32                               CmdDescSize;
    787   UINT16                               ReturnDataSize;
    788 
    789   ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
    790 
    791   if (Read) {
    792     Packet.DataDirection     = UfsDataIn;
    793     Packet.InDataBuffer      = Descriptor;
    794     Packet.InTransferLength  = DescSize;
    795     Packet.Opcode            = UtpQueryFuncOpcodeRdDesc;
    796   } else {
    797     Packet.DataDirection     = UfsDataOut;
    798     Packet.OutDataBuffer     = Descriptor;
    799     Packet.OutTransferLength = DescSize;
    800     Packet.Opcode            = UtpQueryFuncOpcodeWrDesc;
    801   }
    802   Packet.DescId              = DescId;
    803   Packet.Index               = Index;
    804   Packet.Selector            = Selector;
    805   Packet.Timeout             = UFS_TIMEOUT;
    806 
    807   //
    808   // Find out which slot of transfer request list is available.
    809   //
    810   Status = UfsFindAvailableSlotInTrl (Private, &Slot);
    811   if (EFI_ERROR (Status)) {
    812     return Status;
    813   }
    814 
    815   Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
    816   //
    817   // Fill transfer request descriptor to this slot.
    818   //
    819   Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
    820   if (EFI_ERROR (Status)) {
    821     return Status;
    822   }
    823 
    824   //
    825   // Check the transfer request result.
    826   //
    827   CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
    828   QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
    829   CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
    830 
    831   //
    832   // Start to execute the transfer request.
    833   //
    834   UfsStartExecCmd (Private, Slot);
    835 
    836   //
    837   // Wait for the completion of the transfer request.
    838   //
    839   Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
    840   Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);
    841   if (EFI_ERROR (Status)) {
    842     goto Exit;
    843   }
    844 
    845   if (QueryResp->QueryResp != 0) {
    846     DumpQueryResponseResult (QueryResp->QueryResp);
    847     Status = EFI_DEVICE_ERROR;
    848     goto Exit;
    849   }
    850 
    851   if (Trd->Ocs == 0) {
    852     ReturnDataSize = QueryResp->Tsf.Length;
    853     SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
    854 
    855     if (Read) {
    856       CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);
    857       Packet.InTransferLength = ReturnDataSize;
    858     } else {
    859       Packet.OutTransferLength = ReturnDataSize;
    860     }
    861   } else {
    862     Status = EFI_DEVICE_ERROR;
    863   }
    864 
    865 Exit:
    866   UfsStopExecCmd (Private, Slot);
    867   UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
    868 
    869   return Status;
    870 }
    871 
    872 /**
    873   Read or write specified attribute of a UFS device.
    874 
    875   @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    876   @param[in]      Read          The boolean variable to show r/w direction.
    877   @param[in]      AttrId        The ID of Attribute.
    878   @param[in]      Index         The Index of Attribute.
    879   @param[in]      Selector      The Selector of Attribute.
    880   @param[in, out] Attributes    The value of Attribute to be read or written.
    881 
    882   @retval EFI_SUCCESS           The Attribute was read/written successfully.
    883   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the Attribute.
    884   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the Attribute.
    885 
    886 **/
    887 EFI_STATUS
    888 UfsRwAttributes (
    889   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    890   IN     BOOLEAN                      Read,
    891   IN     UINT8                        AttrId,
    892   IN     UINT8                        Index,
    893   IN     UINT8                        Selector,
    894   IN OUT UINT32                       *Attributes
    895   )
    896 {
    897   EFI_STATUS                           Status;
    898   UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
    899   UINT8                                Slot;
    900   UTP_TRD                              *Trd;
    901   UINTN                                Address;
    902   UTP_QUERY_RESP_UPIU                  *QueryResp;
    903   UINT8                                *CmdDescBase;
    904   UINT32                               CmdDescSize;
    905   UINT32                               ReturnData;
    906 
    907   ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
    908 
    909   if (Read) {
    910     Packet.DataDirection     = UfsDataIn;
    911     Packet.Opcode            = UtpQueryFuncOpcodeRdAttr;
    912   } else {
    913     Packet.DataDirection     = UfsDataOut;
    914     Packet.Opcode            = UtpQueryFuncOpcodeWrAttr;
    915   }
    916   Packet.DescId              = AttrId;
    917   Packet.Index               = Index;
    918   Packet.Selector            = Selector;
    919   Packet.Timeout             = UFS_TIMEOUT;
    920 
    921   //
    922   // Find out which slot of transfer request list is available.
    923   //
    924   Status = UfsFindAvailableSlotInTrl (Private, &Slot);
    925   if (EFI_ERROR (Status)) {
    926     return Status;
    927   }
    928 
    929   Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
    930   //
    931   // Fill transfer request descriptor to this slot.
    932   //
    933   Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
    934   if (EFI_ERROR (Status)) {
    935     return Status;
    936   }
    937 
    938   //
    939   // Check the transfer request result.
    940   //
    941   CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
    942   QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
    943   CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
    944 
    945   //
    946   // Start to execute the transfer request.
    947   //
    948   UfsStartExecCmd (Private, Slot);
    949 
    950   //
    951   // Wait for the completion of the transfer request.
    952   //
    953   Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
    954   Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);
    955   if (EFI_ERROR (Status)) {
    956     goto Exit;
    957   }
    958 
    959   if (QueryResp->QueryResp != 0) {
    960     DumpQueryResponseResult (QueryResp->QueryResp);
    961     Status = EFI_DEVICE_ERROR;
    962     goto Exit;
    963   }
    964 
    965   if (Trd->Ocs == 0) {
    966     ReturnData = QueryResp->Tsf.Value;
    967     SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));
    968     *Attributes = ReturnData;
    969   } else {
    970     Status = EFI_DEVICE_ERROR;
    971   }
    972 
    973 Exit:
    974   UfsStopExecCmd (Private, Slot);
    975   UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
    976 
    977   return Status;
    978 }
    979 
    980 /**
    981   Read or write specified flag of a UFS device.
    982 
    983   @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
    984   @param[in]      Read          The boolean variable to show r/w direction.
    985   @param[in]      FlagId        The ID of flag to be read or written.
    986   @param[in, out] Value         The value to set or clear flag.
    987 
    988   @retval EFI_SUCCESS           The flag was read/written successfully.
    989   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the flag.
    990   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the flag.
    991 
    992 **/
    993 EFI_STATUS
    994 UfsRwFlags (
    995   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    996   IN     BOOLEAN                      Read,
    997   IN     UINT8                        FlagId,
    998   IN OUT UINT8                        *Value
    999   )
   1000 {
   1001   EFI_STATUS                           Status;
   1002   UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
   1003   UINT8                                Slot;
   1004   UTP_TRD                              *Trd;
   1005   UINTN                                Address;
   1006   UTP_QUERY_RESP_UPIU                  *QueryResp;
   1007   UINT8                                *CmdDescBase;
   1008   UINT32                               CmdDescSize;
   1009 
   1010   if (Value == NULL) {
   1011     return EFI_INVALID_PARAMETER;
   1012   }
   1013 
   1014   ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
   1015 
   1016   if (Read) {
   1017     ASSERT (Value != NULL);
   1018     Packet.DataDirection     = UfsDataIn;
   1019     Packet.Opcode            = UtpQueryFuncOpcodeRdFlag;
   1020   } else {
   1021     Packet.DataDirection     = UfsDataOut;
   1022     if (*Value == 1) {
   1023       Packet.Opcode          = UtpQueryFuncOpcodeSetFlag;
   1024     } else if (*Value == 0) {
   1025       Packet.Opcode          = UtpQueryFuncOpcodeClrFlag;
   1026     } else {
   1027       return EFI_INVALID_PARAMETER;
   1028     }
   1029   }
   1030   Packet.DescId              = FlagId;
   1031   Packet.Index               = 0;
   1032   Packet.Selector            = 0;
   1033   Packet.Timeout             = UFS_TIMEOUT;
   1034 
   1035   //
   1036   // Find out which slot of transfer request list is available.
   1037   //
   1038   Status = UfsFindAvailableSlotInTrl (Private, &Slot);
   1039   if (EFI_ERROR (Status)) {
   1040     return Status;
   1041   }
   1042 
   1043   //
   1044   // Fill transfer request descriptor to this slot.
   1045   //
   1046   Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
   1047   Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
   1048   if (EFI_ERROR (Status)) {
   1049     return Status;
   1050   }
   1051 
   1052   //
   1053   // Check the transfer request result.
   1054   //
   1055   CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
   1056   QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
   1057   CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
   1058 
   1059   //
   1060   // Start to execute the transfer request.
   1061   //
   1062   UfsStartExecCmd (Private, Slot);
   1063 
   1064   //
   1065   // Wait for the completion of the transfer request.
   1066   //
   1067   Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
   1068   Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);
   1069   if (EFI_ERROR (Status)) {
   1070     goto Exit;
   1071   }
   1072 
   1073   if (QueryResp->QueryResp != 0) {
   1074     DumpQueryResponseResult (QueryResp->QueryResp);
   1075     Status = EFI_DEVICE_ERROR;
   1076     goto Exit;
   1077   }
   1078 
   1079   if (Trd->Ocs == 0) {
   1080     *Value = (UINT8)QueryResp->Tsf.Value;
   1081   } else {
   1082     Status = EFI_DEVICE_ERROR;
   1083   }
   1084 
   1085 Exit:
   1086   UfsStopExecCmd (Private, Slot);
   1087   UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
   1088 
   1089   return Status;
   1090 }
   1091 
   1092 /**
   1093   Set specified flag to 1 on a UFS device.
   1094 
   1095   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1096   @param[in]  FlagId            The ID of flag to be set.
   1097 
   1098   @retval EFI_SUCCESS           The flag was set successfully.
   1099   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to set the flag.
   1100   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of setting the flag.
   1101 
   1102 **/
   1103 EFI_STATUS
   1104 UfsSetFlag (
   1105   IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
   1106   IN  UINT8                        FlagId
   1107   )
   1108 {
   1109   EFI_STATUS             Status;
   1110   UINT8                  Value;
   1111 
   1112   Value  = 1;
   1113   Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
   1114 
   1115   return Status;
   1116 }
   1117 
   1118 /**
   1119   Clear specified flag to 0 on a UFS device.
   1120 
   1121   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1122   @param[in]  FlagId            The ID of flag to be cleared.
   1123 
   1124   @retval EFI_SUCCESS           The flag was cleared successfully.
   1125   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to clear the flag.
   1126   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of clearing the flag.
   1127 
   1128 **/
   1129 EFI_STATUS
   1130 UfsClearFlag (
   1131   IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
   1132   IN  UINT8                        FlagId
   1133   )
   1134 {
   1135   EFI_STATUS             Status;
   1136   UINT8                  Value;
   1137 
   1138   Value  = 0;
   1139   Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
   1140 
   1141   return Status;
   1142 }
   1143 
   1144 /**
   1145   Read specified flag from a UFS device.
   1146 
   1147   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1148   @param[in]  FlagId            The ID of flag to be read.
   1149   @param[out] Value             The flag's value.
   1150 
   1151   @retval EFI_SUCCESS           The flag was read successfully.
   1152   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to read the flag.
   1153   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of reading the flag.
   1154 
   1155 **/
   1156 EFI_STATUS
   1157 UfsReadFlag (
   1158   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
   1159   IN     UINT8                        FlagId,
   1160      OUT UINT8                        *Value
   1161   )
   1162 {
   1163   EFI_STATUS                           Status;
   1164 
   1165   Status = UfsRwFlags (Private, TRUE, FlagId, Value);
   1166 
   1167   return Status;
   1168 }
   1169 
   1170 /**
   1171   Sends NOP IN cmd to a UFS device for initialization process request.
   1172   For more details, please refer to UFS 2.0 spec Figure 13.3.
   1173 
   1174   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1175 
   1176   @retval EFI_SUCCESS           The NOP IN command was sent by the host. The NOP OUT response was
   1177                                 received successfully.
   1178   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to execute NOP IN command.
   1179   @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.
   1180   @retval EFI_TIMEOUT           A timeout occurred while waiting for the NOP IN command to execute.
   1181 
   1182 **/
   1183 EFI_STATUS
   1184 UfsExecNopCmds (
   1185   IN  UFS_PEIM_HC_PRIVATE_DATA         *Private
   1186   )
   1187 {
   1188   EFI_STATUS                           Status;
   1189   UINT8                                Slot;
   1190   UTP_TRD                              *Trd;
   1191   UTP_NOP_IN_UPIU                      *NopInUpiu;
   1192   UINT8                                *CmdDescBase;
   1193   UINT32                               CmdDescSize;
   1194   UINTN                                Address;
   1195 
   1196   //
   1197   // Find out which slot of transfer request list is available.
   1198   //
   1199   Status = UfsFindAvailableSlotInTrl (Private, &Slot);
   1200   if (EFI_ERROR (Status)) {
   1201     return Status;
   1202   }
   1203 
   1204   Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
   1205   Status = UfsCreateNopCommandDesc (Private, Trd);
   1206   if (EFI_ERROR (Status)) {
   1207     return Status;
   1208   }
   1209 
   1210   //
   1211   // Check the transfer request result.
   1212   //
   1213   CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
   1214   NopInUpiu   = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
   1215   CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
   1216 
   1217   //
   1218   // Start to execute the transfer request.
   1219   //
   1220   UfsStartExecCmd (Private, Slot);
   1221 
   1222   //
   1223   // Wait for the completion of the transfer request.
   1224   //
   1225   Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
   1226   Status = UfsWaitMemSet (Address, BIT0, 0, UFS_TIMEOUT);
   1227   if (EFI_ERROR (Status)) {
   1228     goto Exit;
   1229   }
   1230 
   1231   if (NopInUpiu->Resp != 0) {
   1232     Status = EFI_DEVICE_ERROR;
   1233   } else {
   1234     Status = EFI_SUCCESS;
   1235   }
   1236 
   1237 Exit:
   1238   UfsStopExecCmd (Private, Slot);
   1239   UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
   1240 
   1241   return Status;
   1242 }
   1243 
   1244 /**
   1245   Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
   1246 
   1247   @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1248   @param[in]      Lun           The LUN of the UFS device to send the SCSI Request Packet.
   1249   @param[in, out] Packet        A pointer to the SCSI Request Packet to send to a specified Lun of the
   1250                                 UFS device.
   1251 
   1252   @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional
   1253                                 commands, InTransferLength bytes were transferred from
   1254                                 InDataBuffer. For write and bi-directional commands,
   1255                                 OutTransferLength bytes were transferred by
   1256                                 OutDataBuffer.
   1257   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request
   1258                                 Packet.
   1259   @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.
   1260   @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.
   1261 
   1262 **/
   1263 EFI_STATUS
   1264 UfsExecScsiCmds (
   1265   IN     UFS_PEIM_HC_PRIVATE_DATA      *Private,
   1266   IN     UINT8                         Lun,
   1267   IN OUT UFS_SCSI_REQUEST_PACKET       *Packet
   1268   )
   1269 {
   1270   EFI_STATUS                           Status;
   1271   UINT8                                Slot;
   1272   UTP_TRD                              *Trd;
   1273   UINTN                                Address;
   1274   UINT8                                *CmdDescBase;
   1275   UINT32                               CmdDescSize;
   1276   UTP_RESPONSE_UPIU                    *Response;
   1277   UINT16                               SenseDataLen;
   1278   UINT32                               ResTranCount;
   1279 
   1280   //
   1281   // Find out which slot of transfer request list is available.
   1282   //
   1283   Status = UfsFindAvailableSlotInTrl (Private, &Slot);
   1284   if (EFI_ERROR (Status)) {
   1285     return Status;
   1286   }
   1287 
   1288   Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
   1289 
   1290   //
   1291   // Fill transfer request descriptor to this slot.
   1292   //
   1293   Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd);
   1294   if (EFI_ERROR (Status)) {
   1295     return Status;
   1296   }
   1297 
   1298   CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
   1299   CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);
   1300 
   1301   //
   1302   // Start to execute the transfer request.
   1303   //
   1304   UfsStartExecCmd (Private, Slot);
   1305 
   1306   //
   1307   // Wait for the completion of the transfer request.
   1308   //
   1309   Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
   1310   Status = UfsWaitMemSet (Address, BIT0, 0, Packet->Timeout);
   1311   if (EFI_ERROR (Status)) {
   1312     goto Exit;
   1313   }
   1314 
   1315   //
   1316   // Get sense data if exists
   1317   //
   1318   Response     = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
   1319   SenseDataLen = Response->SenseDataLen;
   1320   SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
   1321 
   1322   if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
   1323     CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
   1324     Packet->SenseDataLength = (UINT8)SenseDataLen;
   1325   }
   1326 
   1327   //
   1328   // Check the transfer request result.
   1329   //
   1330   if (Response->Response != 0) {
   1331     DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
   1332     Status = EFI_DEVICE_ERROR;
   1333     goto Exit;
   1334   }
   1335 
   1336   if (Trd->Ocs == 0) {
   1337     if (Packet->DataDirection == UfsDataIn) {
   1338       if ((Response->Flags & BIT5) == BIT5) {
   1339         ResTranCount = Response->ResTranCount;
   1340         SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
   1341         Packet->InTransferLength -= ResTranCount;
   1342       }
   1343     } else if (Packet->DataDirection == UfsDataOut) {
   1344       if ((Response->Flags & BIT5) == BIT5) {
   1345         ResTranCount = Response->ResTranCount;
   1346         SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
   1347         Packet->OutTransferLength -= ResTranCount;
   1348       }
   1349     }
   1350   } else {
   1351     Status = EFI_DEVICE_ERROR;
   1352   }
   1353 
   1354 Exit:
   1355   UfsStopExecCmd (Private, Slot);
   1356   UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
   1357 
   1358   return Status;
   1359 }
   1360 
   1361 
   1362 /**
   1363   Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
   1364 
   1365   @param[in] Private          The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1366   @param[in] UicOpcode        The opcode of the UIC command.
   1367   @param[in] Arg1             The value for 1st argument of the UIC command.
   1368   @param[in] Arg2             The value for 2nd argument of the UIC command.
   1369   @param[in] Arg3             The value for 3rd argument of the UIC command.
   1370 
   1371   @return EFI_SUCCESS      Successfully execute this UIC command and detect attached UFS device.
   1372   @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
   1373   @return EFI_NOT_FOUND    The presence of the UFS device isn't detected.
   1374 
   1375 **/
   1376 EFI_STATUS
   1377 UfsExecUicCommands (
   1378   IN  UFS_PEIM_HC_PRIVATE_DATA      *Private,
   1379   IN  UINT8                         UicOpcode,
   1380   IN  UINT32                        Arg1,
   1381   IN  UINT32                        Arg2,
   1382   IN  UINT32                        Arg3
   1383   )
   1384 {
   1385   EFI_STATUS  Status;
   1386   UINTN       Address;
   1387   UINT32      Data;
   1388   UINTN       UfsHcBase;
   1389 
   1390   UfsHcBase = Private->UfsHcBase;
   1391   Address   = UfsHcBase + UFS_HC_IS_OFFSET;
   1392   Data      = MmioRead32 (Address);
   1393   if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
   1394     //
   1395     // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
   1396     //
   1397     MmioWrite32 (Address, Data);
   1398   }
   1399 
   1400   //
   1401   // When programming UIC command registers, host software shall set the register UICCMD
   1402   // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
   1403   // are set.
   1404   //
   1405   Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;
   1406   MmioWrite32 (Address, Arg1);
   1407 
   1408   Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
   1409   MmioWrite32 (Address, Arg2);
   1410 
   1411   Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;
   1412   MmioWrite32 (Address, Arg3);
   1413 
   1414   //
   1415   // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
   1416   //
   1417   Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
   1418   Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
   1419   if (EFI_ERROR (Status)) {
   1420     return Status;
   1421   }
   1422 
   1423   Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;
   1424   MmioWrite32 (Address, (UINT32)UicOpcode);
   1425 
   1426   //
   1427   // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
   1428   // This bit is set to '1' by the host controller upon completion of a UIC command.
   1429   //
   1430   Address = UfsHcBase + UFS_HC_IS_OFFSET;
   1431   Data    = MmioRead32 (Address);
   1432   Status  = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
   1433   if (EFI_ERROR (Status)) {
   1434     return Status;
   1435   }
   1436 
   1437   if (UicOpcode != UfsUicDmeReset) {
   1438     Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
   1439     Data    = MmioRead32 (Address);
   1440     if ((Data & 0xFF) != 0) {
   1441       DEBUG_CODE_BEGIN();
   1442         DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
   1443       DEBUG_CODE_END();
   1444       return EFI_DEVICE_ERROR;
   1445     }
   1446   }
   1447 
   1448   //
   1449   // Check value of HCS.DP and make sure that there is a device attached to the Link.
   1450   //
   1451   Address = UfsHcBase + UFS_HC_STATUS_OFFSET;
   1452   Data    = MmioRead32 (Address);
   1453   if ((Data & UFS_HC_HCS_DP) == 0) {
   1454     Address = UfsHcBase + UFS_HC_IS_OFFSET;
   1455     Status  = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
   1456     if (EFI_ERROR (Status)) {
   1457       return EFI_DEVICE_ERROR;
   1458     }
   1459     return EFI_NOT_FOUND;
   1460   }
   1461 
   1462   DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));
   1463 
   1464   return EFI_SUCCESS;
   1465 }
   1466 
   1467 /**
   1468   Enable the UFS host controller for accessing.
   1469 
   1470   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1471 
   1472   @retval EFI_SUCCESS                The UFS host controller enabling was executed successfully.
   1473   @retval EFI_DEVICE_ERROR           A device error occurred while enabling the UFS host controller.
   1474 
   1475 **/
   1476 EFI_STATUS
   1477 UfsEnableHostController (
   1478   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
   1479   )
   1480 {
   1481   EFI_STATUS             Status;
   1482   UINTN                  Address;
   1483   UINT32                 Data;
   1484 
   1485   //
   1486   // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
   1487   //
   1488   // Reinitialize the UFS host controller if HCE bit of HC register is set.
   1489   //
   1490   Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
   1491   Data    = MmioRead32 (Address);
   1492   if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
   1493     //
   1494     // Write a 0 to the HCE register at first to disable the host controller.
   1495     //
   1496     MmioWrite32 (Address, 0);
   1497     //
   1498     // Wait until HCE is read as '0' before continuing.
   1499     //
   1500     Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
   1501     if (EFI_ERROR (Status)) {
   1502       return EFI_DEVICE_ERROR;
   1503     }
   1504   }
   1505 
   1506   //
   1507   // Write a 1 to the HCE register to enable the UFS host controller.
   1508   //
   1509   MmioWrite32 (Address, UFS_HC_HCE_EN);
   1510   //
   1511   // Wait until HCE is read as '1' before continuing.
   1512   //
   1513   Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
   1514   if (EFI_ERROR (Status)) {
   1515     return EFI_DEVICE_ERROR;
   1516   }
   1517 
   1518   return EFI_SUCCESS;
   1519 }
   1520 
   1521 /**
   1522   Detect if a UFS device attached.
   1523 
   1524   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1525 
   1526   @retval EFI_SUCCESS                The UFS device detection was executed successfully.
   1527   @retval EFI_NOT_FOUND              Not found a UFS device attached.
   1528   @retval EFI_DEVICE_ERROR           A device error occurred while detecting the UFS device.
   1529 
   1530 **/
   1531 EFI_STATUS
   1532 UfsDeviceDetection (
   1533   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
   1534   )
   1535 {
   1536   UINTN                  Retry;
   1537   EFI_STATUS             Status;
   1538 
   1539   //
   1540   // Start UFS device detection.
   1541   // Try up to 3 times for establishing data link with device.
   1542   //
   1543   for (Retry = 0; Retry < 3; Retry++) {
   1544     Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
   1545     if (!EFI_ERROR (Status)) {
   1546       break;
   1547     }
   1548 
   1549     if (Status == EFI_NOT_FOUND) {
   1550       continue;
   1551     }
   1552 
   1553     return EFI_DEVICE_ERROR;
   1554   }
   1555 
   1556   if (Retry == 3) {
   1557     return EFI_NOT_FOUND;
   1558   }
   1559 
   1560   return EFI_SUCCESS;
   1561 }
   1562 
   1563 /**
   1564   Initialize UFS task management request list related h/w context.
   1565 
   1566   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1567 
   1568   @retval EFI_SUCCESS                The UFS task management list was initialzed successfully.
   1569   @retval EFI_DEVICE_ERROR           The initialization fails.
   1570 
   1571 **/
   1572 EFI_STATUS
   1573 UfsInitTaskManagementRequestList (
   1574   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
   1575   )
   1576 {
   1577   UINTN                  Address;
   1578   UINT32                 Data;
   1579   UINT8                  Nutmrs;
   1580   EFI_PHYSICAL_ADDRESS   Buffer;
   1581   EFI_STATUS             Status;
   1582 
   1583   //
   1584   // Initial h/w and s/w context for future operations.
   1585   //
   1586   Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
   1587   Data    = MmioRead32 (Address);
   1588   Private->Capabilities = Data;
   1589 
   1590   //
   1591   // Allocate and initialize UTP Task Management Request List.
   1592   //
   1593   Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
   1594   Status = PeiServicesAllocatePages (
   1595              EfiBootServicesCode,
   1596              EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
   1597              &Buffer
   1598              );
   1599 
   1600   if (EFI_ERROR (Status)) {
   1601     return EFI_DEVICE_ERROR;
   1602   }
   1603 
   1604   ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
   1605 
   1606   //
   1607   // Program the UTP Task Management Request List Base Address and UTP Task Management
   1608   // Request List Base Address with a 64-bit address allocated at step 6.
   1609   //
   1610   Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;
   1611   MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
   1612   Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;
   1613   MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
   1614   Private->UtpTmrlBase = (VOID*)(UINTN)Buffer;
   1615   Private->Nutmrs      = Nutmrs;
   1616 
   1617   //
   1618   // Enable the UTP Task Management Request List by setting the UTP Task Management
   1619   // Request List RunStop Register (UTMRLRSR) to '1'.
   1620   //
   1621   Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
   1622   MmioWrite32 (Address, UFS_HC_UTMRLRSR);
   1623 
   1624   return EFI_SUCCESS;
   1625 }
   1626 
   1627 /**
   1628   Initialize UFS transfer request list related h/w context.
   1629 
   1630   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1631 
   1632   @retval EFI_SUCCESS                The UFS transfer list was initialzed successfully.
   1633   @retval EFI_DEVICE_ERROR           The initialization fails.
   1634 
   1635 **/
   1636 EFI_STATUS
   1637 UfsInitTransferRequestList (
   1638   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
   1639   )
   1640 {
   1641   UINTN                  Address;
   1642   UINT32                 Data;
   1643   UINT8                  Nutrs;
   1644   EFI_PHYSICAL_ADDRESS   Buffer;
   1645   EFI_STATUS             Status;
   1646 
   1647   //
   1648   // Initial h/w and s/w context for future operations.
   1649   //
   1650   Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
   1651   Data    = MmioRead32 (Address);
   1652   Private->Capabilities = Data;
   1653 
   1654   //
   1655   // Allocate and initialize UTP Transfer Request List.
   1656   //
   1657   Nutrs  = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
   1658   Status = PeiServicesAllocatePages (
   1659              EfiBootServicesCode,
   1660              EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
   1661              &Buffer
   1662              );
   1663 
   1664   if (EFI_ERROR (Status)) {
   1665     return EFI_DEVICE_ERROR;
   1666   }
   1667 
   1668   ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
   1669 
   1670   //
   1671   // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
   1672   // Base Address with a 64-bit address allocated at step 8.
   1673   //
   1674   Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;
   1675   MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
   1676   Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;
   1677   MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
   1678   Private->UtpTrlBase = (VOID*)(UINTN)Buffer;
   1679   Private->Nutrs      = Nutrs;
   1680 
   1681   //
   1682   // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
   1683   // RunStop Register (UTRLRSR) to '1'.
   1684   //
   1685   Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
   1686   MmioWrite32 (Address, UFS_HC_UTRLRSR);
   1687 
   1688   return EFI_SUCCESS;
   1689 }
   1690 
   1691 /**
   1692   Initialize the UFS host controller.
   1693 
   1694   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1695 
   1696   @retval EFI_SUCCESS                The Ufs Host Controller is initialized successfully.
   1697   @retval Others                     A device error occurred while initializing the controller.
   1698 
   1699 **/
   1700 EFI_STATUS
   1701 UfsControllerInit (
   1702   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
   1703   )
   1704 {
   1705   EFI_STATUS             Status;
   1706 
   1707   Status = UfsEnableHostController (Private);
   1708   if (EFI_ERROR (Status)) {
   1709     DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));
   1710     return Status;
   1711   }
   1712 
   1713   Status = UfsDeviceDetection (Private);
   1714   if (EFI_ERROR (Status)) {
   1715     DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));
   1716     return Status;
   1717   }
   1718 
   1719   Status = UfsInitTaskManagementRequestList (Private);
   1720   if (EFI_ERROR (Status)) {
   1721     DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));
   1722     return Status;
   1723   }
   1724 
   1725   Status = UfsInitTransferRequestList (Private);
   1726   if (EFI_ERROR (Status)) {
   1727     DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
   1728     return Status;
   1729   }
   1730 
   1731   DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));
   1732   return EFI_SUCCESS;
   1733 }
   1734 
   1735 /**
   1736   Stop the UFS host controller.
   1737 
   1738   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
   1739 
   1740   @retval EFI_SUCCESS                The Ufs Host Controller is stopped successfully.
   1741   @retval Others                     A device error occurred while stopping the controller.
   1742 
   1743 **/
   1744 EFI_STATUS
   1745 UfsControllerStop (
   1746   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
   1747   )
   1748 {
   1749   EFI_STATUS             Status;
   1750   UINTN                  Address;
   1751   UINT32                 Data;
   1752 
   1753   //
   1754   // Enable the UTP Task Management Request List by setting the UTP Task Management
   1755   // Request List RunStop Register (UTMRLRSR) to '1'.
   1756   //
   1757   Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
   1758   MmioWrite32 (Address, 0);
   1759 
   1760   //
   1761   // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
   1762   // RunStop Register (UTRLRSR) to '1'.
   1763   //
   1764   Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
   1765   MmioWrite32 (Address, 0);
   1766 
   1767   //
   1768   // Write a 0 to the HCE register in order to disable the host controller.
   1769   //
   1770   Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
   1771   Data    = MmioRead32 (Address);
   1772   ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
   1773   MmioWrite32 (Address, 0);
   1774 
   1775   //
   1776   // Wait until HCE is read as '0' before continuing.
   1777   //
   1778   Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
   1779   if (EFI_ERROR (Status)) {
   1780     return EFI_DEVICE_ERROR;
   1781   }
   1782 
   1783   DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));
   1784 
   1785   return EFI_SUCCESS;
   1786 }
   1787 
   1788