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