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