V2 changes: Resource cleanup logic update in UfsEndOfPei(). V1 history: Update the UfsBlockIoPei driver to consume IOMMU_PPI to allocate DMA buffer. If no IOMMU_PPI exists, this driver still calls PEI service to allocate DMA buffer, with assumption that DRAM==DMA. This is a compatible change. Cc: Jiewen Yao <jiewen.yao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			1837 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1837 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php.
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "UfsBlockIoPei.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Wait for the value of the specified system memory set to the test value.
 | 
						|
 | 
						|
  @param  Address           The system memory address to test.
 | 
						|
  @param  MaskValue         The mask value of memory.
 | 
						|
  @param  TestValue         The test value of memory.
 | 
						|
  @param  Timeout           The time out value for wait memory set, uses 100ns as a unit.
 | 
						|
 | 
						|
  @retval EFI_TIMEOUT       The system memory setting is time out.
 | 
						|
  @retval EFI_SUCCESS       The system memory is correct set.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UfsWaitMemSet (
 | 
						|
  IN  UINTN                     Address,
 | 
						|
  IN  UINT32                    MaskValue,
 | 
						|
  IN  UINT32                    TestValue,
 | 
						|
  IN  UINT64                    Timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32     Value;
 | 
						|
  UINT64     Delay;
 | 
						|
  BOOLEAN    InfiniteWait;
 | 
						|
 | 
						|
  if (Timeout == 0) {
 | 
						|
    InfiniteWait = TRUE;
 | 
						|
  } else {
 | 
						|
    InfiniteWait = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Delay = DivU64x32 (Timeout, 10) + 1;
 | 
						|
 | 
						|
  do {
 | 
						|
    //
 | 
						|
    // Access PCI MMIO space to see if the value is the tested one.
 | 
						|
    //
 | 
						|
    Value = MmioRead32 (Address) & MaskValue;
 | 
						|
 | 
						|
    if (Value == TestValue) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Stall for 1 microseconds.
 | 
						|
    //
 | 
						|
    MicroSecondDelay (1);
 | 
						|
 | 
						|
    Delay--;
 | 
						|
 | 
						|
  } while (InfiniteWait || (Delay > 0));
 | 
						|
 | 
						|
  return EFI_TIMEOUT;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Dump UIC command execution result for debugging.
 | 
						|
 | 
						|
  @param[in]   UicOpcode  The executed UIC opcode.
 | 
						|
  @param[in]   Result     The result to be parsed.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DumpUicCmdExecResult (
 | 
						|
  IN  UINT8     UicOpcode,
 | 
						|
  IN  UINT8     Result
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (UicOpcode <= UfsUicDmePeerSet) {
 | 
						|
    switch (Result) {
 | 
						|
      case 0x00:
 | 
						|
        break;
 | 
						|
      case 0x01:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
 | 
						|
        break;
 | 
						|
      case 0x02:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
 | 
						|
        break;
 | 
						|
      case 0x03:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
 | 
						|
        break;
 | 
						|
      case 0x04:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
 | 
						|
        break;
 | 
						|
      case 0x05:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
 | 
						|
        break;
 | 
						|
      case 0x06:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
 | 
						|
        break;
 | 
						|
      case 0x07:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
 | 
						|
        break;
 | 
						|
      case 0x08:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
 | 
						|
        break; 
 | 
						|
      case 0x09:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BUSY\n"));
 | 
						|
        break;
 | 
						|
      case 0x0A:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
 | 
						|
        break;        
 | 
						|
      default :
 | 
						|
        ASSERT (FALSE);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    switch (Result) {
 | 
						|
      case 0x00:
 | 
						|
        break;
 | 
						|
      case 0x01:
 | 
						|
        DEBUG ((EFI_D_VERBOSE, "UIC control command fails - FAILURE\n"));
 | 
						|
        break;     
 | 
						|
      default :
 | 
						|
        ASSERT (FALSE);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Dump QUERY RESPONSE UPIU result for debugging.
 | 
						|
 | 
						|
  @param[in]   Result  The result to be parsed.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DumpQueryResponseResult (
 | 
						|
  IN  UINT8     Result
 | 
						|
  )
 | 
						|
{
 | 
						|
  switch (Result) {
 | 
						|
    case 0xF6:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Readable\n"));
 | 
						|
      break;
 | 
						|
    case 0xF7:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Writeable\n"));
 | 
						|
      break;
 | 
						|
    case 0xF8:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Already Written\n"));
 | 
						|
      break;
 | 
						|
    case 0xF9:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Length\n"));
 | 
						|
      break;
 | 
						|
    case 0xFA:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Value\n"));
 | 
						|
      break;
 | 
						|
    case 0xFB:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Selector\n"));
 | 
						|
      break;
 | 
						|
    case 0xFC:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Index\n"));
 | 
						|
      break;
 | 
						|
    case 0xFD:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Idn\n"));
 | 
						|
      break;
 | 
						|
    case 0xFE:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Opcode\n"));
 | 
						|
      break; 
 | 
						|
    case 0xFF:
 | 
						|
      DEBUG ((EFI_D_VERBOSE, "Query Response with General Failure\n"));
 | 
						|
      break;
 | 
						|
    default :
 | 
						|
      ASSERT (FALSE);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Swap little endian to big endian.
 | 
						|
 | 
						|
  @param[in, out] Buffer      The data buffer. In input, it contains little endian data.
 | 
						|
                              In output, it will become big endian.
 | 
						|
  @param[in]      BufferSize  The length of converted data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SwapLittleEndianToBigEndian (
 | 
						|
  IN OUT UINT8         *Buffer,
 | 
						|
  IN     UINT32        BufferSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32 Index;
 | 
						|
  UINT8  Temp;
 | 
						|
  UINT32 SwapCount;
 | 
						|
 | 
						|
  SwapCount = BufferSize / 2;
 | 
						|
  for (Index = 0; Index < SwapCount; Index++) {
 | 
						|
    Temp = Buffer[Index];
 | 
						|
    Buffer[Index] = Buffer[BufferSize - 1 - Index];
 | 
						|
    Buffer[BufferSize - 1 - Index] = Temp;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Fill TSF field of QUERY REQUEST UPIU.
 | 
						|
 | 
						|
  @param[in, out] TsfBase      The base address of TSF field of QUERY REQUEST UPIU.
 | 
						|
  @param[in]      Opcode       The opcode of request.
 | 
						|
  @param[in]      DescId       The descriptor ID of request.
 | 
						|
  @param[in]      Index        The index of request.
 | 
						|
  @param[in]      Selector     The selector of request.
 | 
						|
  @param[in]      Length       The length of transferred data. The maximum is 4.
 | 
						|
  @param[in]      Value        The value of transferred data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UfsFillTsfOfQueryReqUpiu (
 | 
						|
  IN OUT UTP_UPIU_TSF        *TsfBase,
 | 
						|
  IN     UINT8               Opcode,
 | 
						|
  IN     UINT8               DescId    OPTIONAL,
 | 
						|
  IN     UINT8               Index     OPTIONAL,
 | 
						|
  IN     UINT8               Selector  OPTIONAL,
 | 
						|
  IN     UINT16              Length    OPTIONAL,
 | 
						|
  IN     UINT32              Value     OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (TsfBase != NULL);
 | 
						|
  ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
 | 
						|
 | 
						|
  TsfBase->Opcode   = Opcode;
 | 
						|
  if (Opcode != UtpQueryFuncOpcodeNop) {
 | 
						|
    TsfBase->DescId   = DescId;
 | 
						|
    TsfBase->Index    = Index;
 | 
						|
    TsfBase->Selector = Selector;
 | 
						|
 | 
						|
    if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
 | 
						|
      SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));
 | 
						|
      TsfBase->Length = Length;
 | 
						|
    }
 | 
						|
  
 | 
						|
    if (Opcode == UtpQueryFuncOpcodeWrAttr) {
 | 
						|
      SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));
 | 
						|
      TsfBase->Value  = Value;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize COMMAND UPIU.
 | 
						|
 | 
						|
  @param[in, out] Command         The base address of COMMAND UPIU.
 | 
						|
  @param[in]      Lun             The Lun on which the SCSI command is executed.
 | 
						|
  @param[in]      TaskTag         The task tag of request.
 | 
						|
  @param[in]      Cdb             The cdb buffer containing SCSI command.
 | 
						|
  @param[in]      CdbLength       The cdb length.
 | 
						|
  @param[in]      DataDirection   The direction of data transfer.
 | 
						|
  @param[in]      ExpDataTranLen  The expected transfer data length.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The initialization succeed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsInitCommandUpiu (
 | 
						|
  IN OUT UTP_COMMAND_UPIU              *Command,
 | 
						|
  IN     UINT8                         Lun,
 | 
						|
  IN     UINT8                         TaskTag,
 | 
						|
  IN     UINT8                         *Cdb,
 | 
						|
  IN     UINT8                         CdbLength,
 | 
						|
  IN     UFS_DATA_DIRECTION            DataDirection,
 | 
						|
  IN     UINT32                        ExpDataTranLen
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                   Flags;
 | 
						|
 | 
						|
  ASSERT ((Command != NULL) && (Cdb != NULL));
 | 
						|
 | 
						|
  //
 | 
						|
  // Task attribute is hard-coded to Ordered.
 | 
						|
  //
 | 
						|
  if (DataDirection == UfsDataIn) {
 | 
						|
    Flags = BIT0 | BIT6;
 | 
						|
  } else if (DataDirection == UfsDataOut) {
 | 
						|
    Flags = BIT0 | BIT5;
 | 
						|
  } else {
 | 
						|
    Flags = BIT0;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill UTP COMMAND UPIU associated fields.
 | 
						|
  //
 | 
						|
  Command->TransCode = 0x01;
 | 
						|
  Command->Flags     = Flags;
 | 
						|
  Command->Lun       = Lun;
 | 
						|
  Command->TaskTag   = TaskTag;
 | 
						|
  Command->CmdSet    = 0x00;
 | 
						|
  SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));
 | 
						|
  Command->ExpDataTranLen = ExpDataTranLen;
 | 
						|
 | 
						|
  CopyMem (Command->Cdb, Cdb, CdbLength);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize UTP PRDT for data transfer.
 | 
						|
 | 
						|
  @param[in] Prdt         The base address of PRDT.
 | 
						|
  @param[in] Buffer       The buffer to be read or written.
 | 
						|
  @param[in] BufferSize   The data size to be read or written.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The initialization succeed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsInitUtpPrdt (
 | 
						|
  IN  UTP_TR_PRD                       *Prdt,
 | 
						|
  IN  VOID                             *Buffer,
 | 
						|
  IN  UINT32                           BufferSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32     PrdtIndex;
 | 
						|
  UINT32     RemainingLen;
 | 
						|
  UINT8      *Remaining;
 | 
						|
  UINTN      PrdtNumber;
 | 
						|
 | 
						|
  if ((BufferSize & (BIT0 | BIT1)) != 0) {
 | 
						|
    BufferSize &= ~(BIT0 | BIT1);
 | 
						|
    DEBUG ((EFI_D_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));
 | 
						|
  }
 | 
						|
 | 
						|
  if (BufferSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
 | 
						|
 | 
						|
  RemainingLen = BufferSize;
 | 
						|
  Remaining    = Buffer;
 | 
						|
  PrdtNumber   = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
 | 
						|
 | 
						|
  for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
 | 
						|
    if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
 | 
						|
      Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
 | 
						|
    } else {
 | 
						|
      Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
 | 
						|
    }
 | 
						|
 | 
						|
    Prdt[PrdtIndex].DbAddr  = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
 | 
						|
    Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
 | 
						|
    RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
 | 
						|
    Remaining    += UFS_MAX_DATA_LEN_PER_PRD;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize QUERY REQUEST UPIU.
 | 
						|
 | 
						|
  @param[in, out] QueryReq      The base address of QUERY REQUEST UPIU.
 | 
						|
  @param[in]      TaskTag       The task tag of request.
 | 
						|
  @param[in]      Opcode        The opcode of request.
 | 
						|
  @param[in]      DescId        The descriptor ID of request.
 | 
						|
  @param[in]      Index         The index of request.
 | 
						|
  @param[in]      Selector      The selector of request.
 | 
						|
  @param[in]      DataSize      The data size to be read or written.
 | 
						|
  @param[in]      Data          The buffer to be read or written.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The initialization succeed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsInitQueryRequestUpiu (
 | 
						|
  IN OUT UTP_QUERY_REQ_UPIU            *QueryReq,
 | 
						|
  IN     UINT8                         TaskTag,
 | 
						|
  IN     UINT8                         Opcode,
 | 
						|
  IN     UINT8                         DescId,
 | 
						|
  IN     UINT8                         Index,
 | 
						|
  IN     UINT8                         Selector,
 | 
						|
  IN     UINTN                         DataSize   OPTIONAL,
 | 
						|
  IN     UINT8                         *Data      OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (QueryReq != NULL);
 | 
						|
 | 
						|
  QueryReq->TransCode = 0x16;
 | 
						|
  QueryReq->TaskTag   = TaskTag;
 | 
						|
  if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
 | 
						|
    QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
 | 
						|
  } else {
 | 
						|
    QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Opcode == UtpQueryFuncOpcodeWrAttr) {
 | 
						|
    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);
 | 
						|
  } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
 | 
						|
    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
 | 
						|
  } else {
 | 
						|
    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Opcode == UtpQueryFuncOpcodeWrDesc) {
 | 
						|
    CopyMem (QueryReq + 1, Data, DataSize);
 | 
						|
 | 
						|
    SwapLittleEndianToBigEndian ((UINT8*)&DataSize, sizeof (UINT16));
 | 
						|
    QueryReq->DataSegLen = (UINT16)DataSize;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
 | 
						|
 | 
						|
  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun               The Lun on which the SCSI command is executed.
 | 
						|
  @param[in]  Packet            The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
 | 
						|
  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.
 | 
						|
  @param[out] BufferMap         A resulting value, if not NULL, to pass to IoMmuUnmap().
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The creation succeed.
 | 
						|
  @retval EFI_DEVICE_ERROR      The creation failed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsCreateScsiCommandDesc (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA         *Private,
 | 
						|
  IN     UINT8                            Lun,
 | 
						|
  IN     UFS_SCSI_REQUEST_PACKET          *Packet,
 | 
						|
  IN     UTP_TRD                          *Trd,
 | 
						|
     OUT VOID                             **BufferMap
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                    *CommandDesc;
 | 
						|
  UINTN                    TotalLen;
 | 
						|
  UINTN                    PrdtNumber;
 | 
						|
  VOID                     *Buffer;
 | 
						|
  UINT32                   Length;
 | 
						|
  UTP_COMMAND_UPIU         *CommandUpiu;
 | 
						|
  UTP_TR_PRD               *PrdtBase;
 | 
						|
  UFS_DATA_DIRECTION       DataDirection;
 | 
						|
  EFI_STATUS               Status;
 | 
						|
  EDKII_IOMMU_OPERATION    MapOp;
 | 
						|
  UINTN                    MapLength;
 | 
						|
  EFI_PHYSICAL_ADDRESS     BufferPhyAddr;
 | 
						|
 | 
						|
  ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
 | 
						|
 | 
						|
  BufferPhyAddr = 0;
 | 
						|
 | 
						|
  if (Packet->DataDirection == UfsDataIn) {
 | 
						|
    Buffer        = Packet->InDataBuffer;
 | 
						|
    Length        = Packet->InTransferLength;
 | 
						|
    DataDirection = UfsDataIn;
 | 
						|
    MapOp         = EdkiiIoMmuOperationBusMasterWrite;
 | 
						|
  } else {
 | 
						|
    Buffer = Packet->OutDataBuffer;
 | 
						|
    Length = Packet->OutTransferLength;
 | 
						|
    DataDirection = UfsDataOut;
 | 
						|
    MapOp         = EdkiiIoMmuOperationBusMasterRead;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Length == 0) {
 | 
						|
    DataDirection = UfsNoData;
 | 
						|
  } else {
 | 
						|
    MapLength = Length;
 | 
						|
    Status = IoMmuMap (MapOp, Buffer, &MapLength, &BufferPhyAddr, BufferMap);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status) || (MapLength != Length)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "UfsCreateScsiCommandDesc: Fail to map data buffer.\n"));
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
 | 
						|
 | 
						|
  TotalLen    = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
 | 
						|
  CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
 | 
						|
  if (CommandDesc == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  CommandUpiu  = (UTP_COMMAND_UPIU*)CommandDesc;
 | 
						|
  PrdtBase     = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
 | 
						|
 | 
						|
  UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
 | 
						|
  UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)BufferPhyAddr, Length);
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill UTP_TRD associated fields
 | 
						|
  // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
 | 
						|
  // *MUST* be located at a 64-bit aligned boundary.
 | 
						|
  //
 | 
						|
  Trd->Int    = UFS_INTERRUPT_COMMAND;
 | 
						|
  Trd->Dd     = DataDirection;
 | 
						|
  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;
 | 
						|
  Trd->Ocs    = UFS_HC_TRD_OCS_INIT_VALUE;
 | 
						|
  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);
 | 
						|
  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);
 | 
						|
  Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
 | 
						|
  Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
 | 
						|
  Trd->PrdtL  = (UINT16)PrdtNumber;
 | 
						|
  Trd->PrdtO  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
 | 
						|
 | 
						|
  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Packet            The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
 | 
						|
  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The creation succeed.
 | 
						|
  @retval EFI_DEVICE_ERROR      The creation failed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.
 | 
						|
  @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsCreateDMCommandDesc (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA              *Private,
 | 
						|
  IN  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET  *Packet,
 | 
						|
  IN  UTP_TRD                               *Trd
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                         *CommandDesc;
 | 
						|
  UINTN                         TotalLen;
 | 
						|
  UTP_QUERY_REQ_UPIU            *QueryReqUpiu;
 | 
						|
  UINT8                         Opcode;
 | 
						|
  UINT32                        DataSize;
 | 
						|
  UINT8                         *Data;
 | 
						|
  UINT8                         DataDirection;
 | 
						|
 | 
						|
  ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
 | 
						|
 | 
						|
  Opcode = Packet->Opcode;
 | 
						|
  if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  DataDirection = Packet->DataDirection;
 | 
						|
  if (DataDirection == UfsDataIn) {
 | 
						|
    DataSize = Packet->InTransferLength;
 | 
						|
    Data     = Packet->InDataBuffer;
 | 
						|
  } else if (DataDirection == UfsDataOut) {
 | 
						|
    DataSize = Packet->OutTransferLength;
 | 
						|
    Data     = Packet->OutDataBuffer;
 | 
						|
  } else {
 | 
						|
    DataSize = 0;
 | 
						|
    Data     = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))
 | 
						|
    && ((DataSize == 0) || (Data == NULL))) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))
 | 
						|
    && ((DataSize != 0) || (Data != NULL))) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
 | 
						|
    TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
 | 
						|
  } else {
 | 
						|
    TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
 | 
						|
  }
 | 
						|
 | 
						|
  CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
 | 
						|
  if (CommandDesc == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize UTP QUERY REQUEST UPIU
 | 
						|
  //
 | 
						|
  QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;
 | 
						|
  UfsInitQueryRequestUpiu (
 | 
						|
    QueryReqUpiu,
 | 
						|
    Private->TaskTag++,
 | 
						|
    Opcode,
 | 
						|
    Packet->DescId,
 | 
						|
    Packet->Index,
 | 
						|
    Packet->Selector,
 | 
						|
    DataSize,
 | 
						|
    Data
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill UTP_TRD associated fields
 | 
						|
  // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
 | 
						|
  //
 | 
						|
  Trd->Int    = UFS_INTERRUPT_COMMAND;
 | 
						|
  Trd->Dd     = DataDirection;
 | 
						|
  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;
 | 
						|
  Trd->Ocs    = UFS_HC_TRD_OCS_INIT_VALUE;
 | 
						|
  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);
 | 
						|
  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);
 | 
						|
  if (Opcode == UtpQueryFuncOpcodeWrDesc) {
 | 
						|
    Trd->RuL  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
 | 
						|
    Trd->RuO  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
 | 
						|
  } else {
 | 
						|
    Trd->RuL  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
 | 
						|
    Trd->RuO  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
 | 
						|
 | 
						|
  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The creation succeed.
 | 
						|
  @retval EFI_DEVICE_ERROR      The creation failed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsCreateNopCommandDesc (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA                    *Private,
 | 
						|
  IN  UTP_TRD                                     *Trd
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                    *CommandDesc;
 | 
						|
  UINTN                    TotalLen;
 | 
						|
  UTP_NOP_OUT_UPIU         *NopOutUpiu;
 | 
						|
 | 
						|
  ASSERT ((Private != NULL) && (Trd != NULL));
 | 
						|
 | 
						|
  TotalLen    = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
 | 
						|
  CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
 | 
						|
  if (CommandDesc == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;
 | 
						|
 | 
						|
  NopOutUpiu->TaskTag = Private->TaskTag++;
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill UTP_TRD associated fields
 | 
						|
  // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
 | 
						|
  //
 | 
						|
  Trd->Int    = UFS_INTERRUPT_COMMAND;
 | 
						|
  Trd->Dd     = 0x00;
 | 
						|
  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;
 | 
						|
  Trd->Ocs    = UFS_HC_TRD_OCS_INIT_VALUE;
 | 
						|
  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);
 | 
						|
  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);
 | 
						|
  Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
 | 
						|
  Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find out available slot in transfer list of a UFS device.
 | 
						|
 | 
						|
  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[out] Slot          The available slot.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       The available slot was found successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsFindAvailableSlotInTrl (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
     OUT UINT8                        *Slot
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT ((Private != NULL) && (Slot != NULL));
 | 
						|
 | 
						|
  //
 | 
						|
  // The simplest algo to always use slot 0.
 | 
						|
  // TODO: enhance it to support async transfer with multiple slot.
 | 
						|
  //
 | 
						|
  *Slot = 0;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find out available slot in task management transfer list of a UFS device.
 | 
						|
 | 
						|
  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[out] Slot          The available slot.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       The available slot was found successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsFindAvailableSlotInTmrl (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
     OUT UINT8                        *Slot
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT ((Private != NULL) && (Slot != NULL));
 | 
						|
 | 
						|
  //
 | 
						|
  // The simplest algo to always use slot 0.
 | 
						|
  // TODO: enhance it to support async transfer with multiple slot.
 | 
						|
  //
 | 
						|
  *Slot = 0;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Start specified slot in transfer list of a UFS device.
 | 
						|
 | 
						|
  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Slot          The slot to be started.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UfsStartExecCmd (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN  UINT8                        Slot
 | 
						|
  ) 
 | 
						|
{
 | 
						|
  UINTN         UfsHcBase;
 | 
						|
  UINTN         Address;
 | 
						|
  UINT32        Data;
 | 
						|
 | 
						|
  UfsHcBase = Private->UfsHcBase;
 | 
						|
 | 
						|
  Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
 | 
						|
    MmioWrite32 (Address, UFS_HC_UTRLRSR);
 | 
						|
  }
 | 
						|
 | 
						|
  Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
 | 
						|
  MmioWrite32 (Address, BIT0 << Slot);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop specified slot in transfer list of a UFS device.
 | 
						|
 | 
						|
  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Slot          The slot to be stop.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UfsStopExecCmd (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN  UINT8                        Slot
 | 
						|
  ) 
 | 
						|
{
 | 
						|
  UINTN         UfsHcBase;
 | 
						|
  UINTN         Address;
 | 
						|
  UINT32        Data;
 | 
						|
 | 
						|
  UfsHcBase = Private->UfsHcBase;
 | 
						|
 | 
						|
  Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  if ((Data & (BIT0 << Slot)) != 0) {
 | 
						|
    Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;  
 | 
						|
    Data    = MmioRead32 (Address);
 | 
						|
    MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read or write specified device descriptor of a UFS device.
 | 
						|
 | 
						|
  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]      Read          The boolean variable to show r/w direction.
 | 
						|
  @param[in]      DescId        The ID of device descriptor.
 | 
						|
  @param[in]      Index         The Index of device descriptor.
 | 
						|
  @param[in]      Selector      The Selector of device descriptor.
 | 
						|
  @param[in, out] Descriptor    The buffer of device descriptor to be read or written.
 | 
						|
  @param[in]      DescSize      The size of device descriptor buffer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The device descriptor was read/written successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the device descriptor.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the device descriptor.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsRwDeviceDesc (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     BOOLEAN                      Read,
 | 
						|
  IN     UINT8                        DescId,
 | 
						|
  IN     UINT8                        Index,
 | 
						|
  IN     UINT8                        Selector,
 | 
						|
  IN OUT VOID                         *Descriptor,
 | 
						|
  IN     UINT32                       DescSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
 | 
						|
  UINT8                                Slot;
 | 
						|
  UTP_TRD                              *Trd;
 | 
						|
  UINTN                                Address;
 | 
						|
  UTP_QUERY_RESP_UPIU                  *QueryResp;
 | 
						|
  UINT8                                *CmdDescBase;
 | 
						|
  UINT32                               CmdDescSize;
 | 
						|
  UINT16                               ReturnDataSize;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
 | 
						|
 | 
						|
  if (Read) {
 | 
						|
    Packet.DataDirection     = UfsDataIn;
 | 
						|
    Packet.InDataBuffer      = Descriptor;
 | 
						|
    Packet.InTransferLength  = DescSize;
 | 
						|
    Packet.Opcode            = UtpQueryFuncOpcodeRdDesc;
 | 
						|
  } else {
 | 
						|
    Packet.DataDirection     = UfsDataOut;
 | 
						|
    Packet.OutDataBuffer     = Descriptor;
 | 
						|
    Packet.OutTransferLength = DescSize;
 | 
						|
    Packet.Opcode            = UtpQueryFuncOpcodeWrDesc;
 | 
						|
  }
 | 
						|
  Packet.DescId              = DescId;
 | 
						|
  Packet.Index               = Index;
 | 
						|
  Packet.Selector            = Selector;
 | 
						|
  Packet.Timeout             = UFS_TIMEOUT;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out which slot of transfer request list is available.
 | 
						|
  //
 | 
						|
  Status = UfsFindAvailableSlotInTrl (Private, &Slot);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  
 | 
						|
  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
 | 
						|
  //
 | 
						|
  // Fill transfer request descriptor to this slot.
 | 
						|
  //
 | 
						|
  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the transfer request result.
 | 
						|
  //
 | 
						|
  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
 | 
						|
  QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
 | 
						|
  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Start to execute the transfer request.
 | 
						|
  //
 | 
						|
  UfsStartExecCmd (Private, Slot);
 | 
						|
 | 
						|
  //
 | 
						|
  // Wait for the completion of the transfer request.
 | 
						|
  //  
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  
 | 
						|
  Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (QueryResp->QueryResp != 0) {
 | 
						|
    DumpQueryResponseResult (QueryResp->QueryResp);
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Trd->Ocs == 0) {
 | 
						|
    ReturnDataSize = QueryResp->Tsf.Length;
 | 
						|
    SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
 | 
						|
 | 
						|
    if (Read) {
 | 
						|
      CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);
 | 
						|
      Packet.InTransferLength = ReturnDataSize;
 | 
						|
    } else {
 | 
						|
      Packet.OutTransferLength = ReturnDataSize;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
  UfsStopExecCmd (Private, Slot);
 | 
						|
  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read or write specified attribute of a UFS device.
 | 
						|
 | 
						|
  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]      Read          The boolean variable to show r/w direction.
 | 
						|
  @param[in]      AttrId        The ID of Attribute.
 | 
						|
  @param[in]      Index         The Index of Attribute.
 | 
						|
  @param[in]      Selector      The Selector of Attribute.
 | 
						|
  @param[in, out] Attributes    The value of Attribute to be read or written.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The Attribute was read/written successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the Attribute.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the Attribute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsRwAttributes (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     BOOLEAN                      Read,
 | 
						|
  IN     UINT8                        AttrId,
 | 
						|
  IN     UINT8                        Index,
 | 
						|
  IN     UINT8                        Selector,
 | 
						|
  IN OUT UINT32                       *Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
 | 
						|
  UINT8                                Slot;
 | 
						|
  UTP_TRD                              *Trd;
 | 
						|
  UINTN                                Address;
 | 
						|
  UTP_QUERY_RESP_UPIU                  *QueryResp;
 | 
						|
  UINT8                                *CmdDescBase;
 | 
						|
  UINT32                               CmdDescSize;
 | 
						|
  UINT32                               ReturnData;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
 | 
						|
 | 
						|
  if (Read) {
 | 
						|
    Packet.DataDirection     = UfsDataIn;
 | 
						|
    Packet.Opcode            = UtpQueryFuncOpcodeRdAttr;
 | 
						|
  } else {
 | 
						|
    Packet.DataDirection     = UfsDataOut;
 | 
						|
    Packet.Opcode            = UtpQueryFuncOpcodeWrAttr;
 | 
						|
  }
 | 
						|
  Packet.DescId              = AttrId;
 | 
						|
  Packet.Index               = Index;
 | 
						|
  Packet.Selector            = Selector;
 | 
						|
  Packet.Timeout             = UFS_TIMEOUT;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out which slot of transfer request list is available.
 | 
						|
  //
 | 
						|
  Status = UfsFindAvailableSlotInTrl (Private, &Slot);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  
 | 
						|
  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
 | 
						|
  //
 | 
						|
  // Fill transfer request descriptor to this slot.
 | 
						|
  //
 | 
						|
  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the transfer request result.
 | 
						|
  //
 | 
						|
  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
 | 
						|
  QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
 | 
						|
  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Start to execute the transfer request.
 | 
						|
  //
 | 
						|
  UfsStartExecCmd (Private, Slot);
 | 
						|
 | 
						|
  //
 | 
						|
  // Wait for the completion of the transfer request.
 | 
						|
  //  
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  
 | 
						|
  Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (QueryResp->QueryResp != 0) {
 | 
						|
    DumpQueryResponseResult (QueryResp->QueryResp);
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Trd->Ocs == 0) {
 | 
						|
    ReturnData = QueryResp->Tsf.Value;
 | 
						|
    SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));
 | 
						|
    *Attributes = ReturnData;
 | 
						|
  } else {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
  UfsStopExecCmd (Private, Slot);
 | 
						|
  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read or write specified flag of a UFS device.
 | 
						|
 | 
						|
  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]      Read          The boolean variable to show r/w direction.
 | 
						|
  @param[in]      FlagId        The ID of flag to be read or written.
 | 
						|
  @param[in, out] Value         The value to set or clear flag.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The flag was read/written successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the flag.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the flag.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsRwFlags (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     BOOLEAN                      Read,
 | 
						|
  IN     UINT8                        FlagId,
 | 
						|
  IN OUT UINT8                        *Value
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
 | 
						|
  UINT8                                Slot;
 | 
						|
  UTP_TRD                              *Trd;
 | 
						|
  UINTN                                Address;
 | 
						|
  UTP_QUERY_RESP_UPIU                  *QueryResp;
 | 
						|
  UINT8                                *CmdDescBase;
 | 
						|
  UINT32                               CmdDescSize;
 | 
						|
 | 
						|
  if (Value == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
 | 
						|
 | 
						|
  if (Read) {
 | 
						|
    ASSERT (Value != NULL);
 | 
						|
    Packet.DataDirection     = UfsDataIn;
 | 
						|
    Packet.Opcode            = UtpQueryFuncOpcodeRdFlag;
 | 
						|
  } else {
 | 
						|
    Packet.DataDirection     = UfsDataOut;
 | 
						|
    if (*Value == 1) {
 | 
						|
      Packet.Opcode          = UtpQueryFuncOpcodeSetFlag;
 | 
						|
    } else if (*Value == 0) {
 | 
						|
      Packet.Opcode          = UtpQueryFuncOpcodeClrFlag;
 | 
						|
    } else {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  Packet.DescId              = FlagId;
 | 
						|
  Packet.Index               = 0;
 | 
						|
  Packet.Selector            = 0;
 | 
						|
  Packet.Timeout             = UFS_TIMEOUT;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out which slot of transfer request list is available.
 | 
						|
  //
 | 
						|
  Status = UfsFindAvailableSlotInTrl (Private, &Slot);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill transfer request descriptor to this slot.
 | 
						|
  //
 | 
						|
  Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
 | 
						|
  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the transfer request result.
 | 
						|
  //
 | 
						|
  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
 | 
						|
  QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
 | 
						|
  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Start to execute the transfer request.
 | 
						|
  //
 | 
						|
  UfsStartExecCmd (Private, Slot);
 | 
						|
 | 
						|
  //
 | 
						|
  // Wait for the completion of the transfer request.
 | 
						|
  //  
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  
 | 
						|
  Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (QueryResp->QueryResp != 0) {
 | 
						|
    DumpQueryResponseResult (QueryResp->QueryResp);
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Trd->Ocs == 0) {
 | 
						|
    *Value = (UINT8)QueryResp->Tsf.Value;
 | 
						|
  } else {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
  UfsStopExecCmd (Private, Slot);
 | 
						|
  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set specified flag to 1 on a UFS device.
 | 
						|
 | 
						|
  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  FlagId            The ID of flag to be set.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The flag was set successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to set the flag.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of setting the flag.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsSetFlag (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN  UINT8                        FlagId
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  UINT8                  Value;
 | 
						|
 | 
						|
  Value  = 1;
 | 
						|
  Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clear specified flag to 0 on a UFS device.
 | 
						|
 | 
						|
  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  FlagId            The ID of flag to be cleared.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The flag was cleared successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to clear the flag.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of clearing the flag.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsClearFlag (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN  UINT8                        FlagId
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  UINT8                  Value;
 | 
						|
 | 
						|
  Value  = 0;
 | 
						|
  Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read specified flag from a UFS device.
 | 
						|
 | 
						|
  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  FlagId            The ID of flag to be read.
 | 
						|
  @param[out] Value             The flag's value.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The flag was read successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to read the flag.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of reading the flag.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsReadFlag (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     UINT8                        FlagId,
 | 
						|
     OUT UINT8                        *Value
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
 | 
						|
  Status = UfsRwFlags (Private, TRUE, FlagId, Value);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sends NOP IN cmd to a UFS device for initialization process request.
 | 
						|
  For more details, please refer to UFS 2.0 spec Figure 13.3.
 | 
						|
 | 
						|
  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The NOP IN command was sent by the host. The NOP OUT response was
 | 
						|
                                received successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to execute NOP IN command.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the NOP IN command to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsExecNopCmds (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA         *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  UINT8                                Slot;
 | 
						|
  UTP_TRD                              *Trd;
 | 
						|
  UTP_NOP_IN_UPIU                      *NopInUpiu;
 | 
						|
  UINT8                                *CmdDescBase;
 | 
						|
  UINT32                               CmdDescSize;
 | 
						|
  UINTN                                Address;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out which slot of transfer request list is available.
 | 
						|
  //
 | 
						|
  Status = UfsFindAvailableSlotInTrl (Private, &Slot);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
 | 
						|
  Status = UfsCreateNopCommandDesc (Private, Trd);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the transfer request result.
 | 
						|
  //
 | 
						|
  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
 | 
						|
  NopInUpiu   = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
 | 
						|
  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Start to execute the transfer request.
 | 
						|
  //
 | 
						|
  UfsStartExecCmd (Private, Slot);
 | 
						|
 | 
						|
  //
 | 
						|
  // Wait for the completion of the transfer request.
 | 
						|
  //  
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  
 | 
						|
  Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NopInUpiu->Resp != 0) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
  } else {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
  UfsStopExecCmd (Private, Slot);
 | 
						|
  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
 | 
						|
 | 
						|
  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]      Lun           The LUN of the UFS device to send the SCSI Request Packet.
 | 
						|
  @param[in, out] Packet        A pointer to the SCSI Request Packet to send to a specified Lun of the
 | 
						|
                                UFS device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional
 | 
						|
                                commands, InTransferLength bytes were transferred from
 | 
						|
                                InDataBuffer. For write and bi-directional commands,
 | 
						|
                                OutTransferLength bytes were transferred by
 | 
						|
                                OutDataBuffer.
 | 
						|
  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request
 | 
						|
                                Packet.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.
 | 
						|
  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsExecScsiCmds (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA      *Private,
 | 
						|
  IN     UINT8                         Lun,
 | 
						|
  IN OUT UFS_SCSI_REQUEST_PACKET       *Packet
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  UINT8                                Slot;
 | 
						|
  UTP_TRD                              *Trd;
 | 
						|
  UINTN                                Address;
 | 
						|
  UINT8                                *CmdDescBase;
 | 
						|
  UINT32                               CmdDescSize;
 | 
						|
  UTP_RESPONSE_UPIU                    *Response;
 | 
						|
  UINT16                               SenseDataLen;
 | 
						|
  UINT32                               ResTranCount;
 | 
						|
  VOID                                 *PacketBufferMap;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out which slot of transfer request list is available.
 | 
						|
  //
 | 
						|
  Status = UfsFindAvailableSlotInTrl (Private, &Slot);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
 | 
						|
  PacketBufferMap = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill transfer request descriptor to this slot.
 | 
						|
  //
 | 
						|
  Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &PacketBufferMap);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
 | 
						|
  CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);
 | 
						|
 | 
						|
  //
 | 
						|
  // Start to execute the transfer request.
 | 
						|
  //
 | 
						|
  UfsStartExecCmd (Private, Slot);
 | 
						|
 | 
						|
  //
 | 
						|
  // Wait for the completion of the transfer request.
 | 
						|
  //  
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  
 | 
						|
  Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get sense data if exists
 | 
						|
  //
 | 
						|
  Response     = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
 | 
						|
  SenseDataLen = Response->SenseDataLen;
 | 
						|
  SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
 | 
						|
  
 | 
						|
  if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
 | 
						|
    CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
 | 
						|
    Packet->SenseDataLength = (UINT8)SenseDataLen;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the transfer request result.
 | 
						|
  //
 | 
						|
  if (Response->Response != 0) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Trd->Ocs == 0) {
 | 
						|
    if (Packet->DataDirection == UfsDataIn) {
 | 
						|
      if ((Response->Flags & BIT5) == BIT5) {
 | 
						|
        ResTranCount = Response->ResTranCount;
 | 
						|
        SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
 | 
						|
        Packet->InTransferLength -= ResTranCount;
 | 
						|
      }
 | 
						|
    } else if (Packet->DataDirection == UfsDataOut) {
 | 
						|
      if ((Response->Flags & BIT5) == BIT5) {
 | 
						|
        ResTranCount = Response->ResTranCount;
 | 
						|
        SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
 | 
						|
        Packet->OutTransferLength -= ResTranCount;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
  if (PacketBufferMap != NULL) {
 | 
						|
    IoMmuUnmap (PacketBufferMap);
 | 
						|
  }
 | 
						|
  UfsStopExecCmd (Private, Slot);
 | 
						|
  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
 | 
						|
 | 
						|
  @param[in] Private          The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in] UicOpcode        The opcode of the UIC command.
 | 
						|
  @param[in] Arg1             The value for 1st argument of the UIC command.
 | 
						|
  @param[in] Arg2             The value for 2nd argument of the UIC command.
 | 
						|
  @param[in] Arg3             The value for 3rd argument of the UIC command.
 | 
						|
 | 
						|
  @return EFI_SUCCESS      Successfully execute this UIC command and detect attached UFS device.
 | 
						|
  @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
 | 
						|
  @return EFI_NOT_FOUND    The presence of the UFS device isn't detected.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsExecUicCommands (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA      *Private,
 | 
						|
  IN  UINT8                         UicOpcode,
 | 
						|
  IN  UINT32                        Arg1,
 | 
						|
  IN  UINT32                        Arg2,
 | 
						|
  IN  UINT32                        Arg3
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINTN       Address;
 | 
						|
  UINT32      Data;
 | 
						|
  UINTN       UfsHcBase;
 | 
						|
 | 
						|
  UfsHcBase = Private->UfsHcBase;
 | 
						|
  Address   = UfsHcBase + UFS_HC_IS_OFFSET;
 | 
						|
  Data      = MmioRead32 (Address);
 | 
						|
  if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
 | 
						|
    //
 | 
						|
    // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
 | 
						|
    //
 | 
						|
    MmioWrite32 (Address, Data);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // When programming UIC command registers, host software shall set the register UICCMD
 | 
						|
  // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
 | 
						|
  // are set.
 | 
						|
  //
 | 
						|
  Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;
 | 
						|
  MmioWrite32 (Address, Arg1);
 | 
						|
 | 
						|
  Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
 | 
						|
  MmioWrite32 (Address, Arg2);
 | 
						|
 | 
						|
  Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;
 | 
						|
  MmioWrite32 (Address, Arg3);
 | 
						|
 | 
						|
  //
 | 
						|
  // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
 | 
						|
  Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;
 | 
						|
  MmioWrite32 (Address, (UINT32)UicOpcode);
 | 
						|
 | 
						|
  //
 | 
						|
  // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
 | 
						|
  // This bit is set to '1' by the host controller upon completion of a UIC command. 
 | 
						|
  //
 | 
						|
  Address = UfsHcBase + UFS_HC_IS_OFFSET;
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  Status  = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (UicOpcode != UfsUicDmeReset) {
 | 
						|
    Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
 | 
						|
    Data    = MmioRead32 (Address);
 | 
						|
    if ((Data & 0xFF) != 0) {
 | 
						|
      DEBUG_CODE_BEGIN();
 | 
						|
        DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
 | 
						|
      DEBUG_CODE_END();
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check value of HCS.DP and make sure that there is a device attached to the Link.
 | 
						|
  //
 | 
						|
  Address = UfsHcBase + UFS_HC_STATUS_OFFSET;  
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  if ((Data & UFS_HC_HCS_DP) == 0) {
 | 
						|
    Address = UfsHcBase + UFS_HC_IS_OFFSET;
 | 
						|
    Status  = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable the UFS host controller for accessing.
 | 
						|
 | 
						|
  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                The UFS host controller enabling was executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR           A device error occurred while enabling the UFS host controller.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsEnableHostController (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  UINTN                  Address;
 | 
						|
  UINT32                 Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
 | 
						|
  //
 | 
						|
  // Reinitialize the UFS host controller if HCE bit of HC register is set.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
 | 
						|
    //
 | 
						|
    // Write a 0 to the HCE register at first to disable the host controller.
 | 
						|
    //
 | 
						|
    MmioWrite32 (Address, 0);
 | 
						|
    //
 | 
						|
    // Wait until HCE is read as '0' before continuing.
 | 
						|
    //
 | 
						|
    Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Write a 1 to the HCE register to enable the UFS host controller.
 | 
						|
  //
 | 
						|
  MmioWrite32 (Address, UFS_HC_HCE_EN);
 | 
						|
  //
 | 
						|
  // Wait until HCE is read as '1' before continuing.
 | 
						|
  //
 | 
						|
  Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Detect if a UFS device attached.
 | 
						|
 | 
						|
  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                The UFS device detection was executed successfully.
 | 
						|
  @retval EFI_NOT_FOUND              Not found a UFS device attached.
 | 
						|
  @retval EFI_DEVICE_ERROR           A device error occurred while detecting the UFS device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsDeviceDetection (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                  Retry;
 | 
						|
  EFI_STATUS             Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Start UFS device detection.
 | 
						|
  // Try up to 3 times for establishing data link with device.
 | 
						|
  //
 | 
						|
  for (Retry = 0; Retry < 3; Retry++) {
 | 
						|
    Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Status == EFI_NOT_FOUND) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Retry == 3) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize UFS task management request list related h/w context.
 | 
						|
 | 
						|
  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                The UFS task management list was initialzed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR           The initialization fails.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsInitTaskManagementRequestList (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                  Address;
 | 
						|
  UINT32                 Data;
 | 
						|
  UINT8                  Nutmrs;
 | 
						|
  VOID                   *CmdDescHost;
 | 
						|
  EFI_PHYSICAL_ADDRESS   CmdDescPhyAddr;
 | 
						|
  VOID                   *CmdDescMapping;
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Initial h/w and s/w context for future operations.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;  
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  Private->Capabilities = Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate and initialize UTP Task Management Request List.
 | 
						|
  //
 | 
						|
  Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
 | 
						|
  Status = IoMmuAllocateBuffer (
 | 
						|
             EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
 | 
						|
             &CmdDescHost,
 | 
						|
             &CmdDescPhyAddr,
 | 
						|
             &CmdDescMapping
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
 | 
						|
 | 
						|
  //
 | 
						|
  // Program the UTP Task Management Request List Base Address and UTP Task Management
 | 
						|
  // Request List Base Address with a 64-bit address allocated at step 6.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;  
 | 
						|
  MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;  
 | 
						|
  MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
 | 
						|
  Private->UtpTmrlBase = (VOID*)(UINTN)CmdDescHost;
 | 
						|
  Private->Nutmrs      = Nutmrs;
 | 
						|
  Private->TmrlMapping = CmdDescMapping;
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable the UTP Task Management Request List by setting the UTP Task Management
 | 
						|
  // Request List RunStop Register (UTMRLRSR) to '1'.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;  
 | 
						|
  MmioWrite32 (Address, UFS_HC_UTMRLRSR);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize UFS transfer request list related h/w context.
 | 
						|
 | 
						|
  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                The UFS transfer list was initialzed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR           The initialization fails.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsInitTransferRequestList (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                  Address;
 | 
						|
  UINT32                 Data;
 | 
						|
  UINT8                  Nutrs;
 | 
						|
  VOID                   *CmdDescHost;
 | 
						|
  EFI_PHYSICAL_ADDRESS   CmdDescPhyAddr;
 | 
						|
  VOID                   *CmdDescMapping;
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Initial h/w and s/w context for future operations.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;  
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  Private->Capabilities = Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate and initialize UTP Transfer Request List.
 | 
						|
  //
 | 
						|
  Nutrs  = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
 | 
						|
  Status = IoMmuAllocateBuffer (
 | 
						|
             EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
 | 
						|
             &CmdDescHost,
 | 
						|
             &CmdDescPhyAddr,
 | 
						|
             &CmdDescMapping
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
 | 
						|
 | 
						|
  //
 | 
						|
  // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
 | 
						|
  // Base Address with a 64-bit address allocated at step 8.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;  
 | 
						|
  MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;  
 | 
						|
  MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
 | 
						|
  Private->UtpTrlBase = (VOID*)(UINTN)CmdDescHost;
 | 
						|
  Private->Nutrs      = Nutrs;
 | 
						|
  Private->TrlMapping = CmdDescMapping;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
 | 
						|
  // RunStop Register (UTRLRSR) to '1'.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  
 | 
						|
  MmioWrite32 (Address, UFS_HC_UTRLRSR);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the UFS host controller.
 | 
						|
 | 
						|
  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                The Ufs Host Controller is initialized successfully.
 | 
						|
  @retval Others                     A device error occurred while initializing the controller.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsControllerInit (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS             Status;
 | 
						|
 | 
						|
  Status = UfsEnableHostController (Private);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = UfsDeviceDetection (Private);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = UfsInitTaskManagementRequestList (Private);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = UfsInitTransferRequestList (Private);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
 | 
						|
 | 
						|
    if (Private->TmrlMapping != NULL) {
 | 
						|
      IoMmuFreeBuffer (
 | 
						|
        EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),
 | 
						|
        Private->UtpTmrlBase,
 | 
						|
        Private->TmrlMapping
 | 
						|
        );
 | 
						|
      Private->TmrlMapping = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop the UFS host controller.
 | 
						|
 | 
						|
  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                The Ufs Host Controller is stopped successfully.
 | 
						|
  @retval Others                     A device error occurred while stopping the controller.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsControllerStop (
 | 
						|
  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  UINTN                  Address;
 | 
						|
  UINT32                 Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable the UTP Task Management Request List by setting the UTP Task Management
 | 
						|
  // Request List RunStop Register (UTMRLRSR) to '1'.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;  
 | 
						|
  MmioWrite32 (Address, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
 | 
						|
  // RunStop Register (UTRLRSR) to '1'.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  
 | 
						|
  MmioWrite32 (Address, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Write a 0 to the HCE register in order to disable the host controller.
 | 
						|
  //
 | 
						|
  Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
 | 
						|
  Data    = MmioRead32 (Address);
 | 
						|
  ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
 | 
						|
  MmioWrite32 (Address, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Wait until HCE is read as '0' before continuing.
 | 
						|
  //
 | 
						|
  Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 |