]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
MdeModulePkg: Add bRefClkFreq card attribute programming support
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsPassThruDxe / UfsPassThruHci.c
CommitLineData
0591696e
FT
1/** @file\r
2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface\r
3 for upper layer application to execute UFS-supported SCSI cmds.\r
4\r
f06941cc 5 Copyright (c) 2014 - 2022, Intel Corporation. All rights reserved.<BR>\r
d189a3f9 6 Copyright (c) Microsoft Corporation.<BR>\r
9d510e61 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
0591696e
FT
8\r
9**/\r
10\r
11#include "UfsPassThru.h"\r
12\r
095f0779
FT
13/**\r
14 Read 32bits data from specified UFS MMIO register.\r
15\r
16 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
17 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
18 the memory operation.\r
19 @param[out] Value The data buffer to store.\r
20\r
21 @retval EFI_TIMEOUT The operation is time out.\r
22 @retval EFI_SUCCESS The operation succeeds.\r
23 @retval Others The operation fails.\r
24\r
25**/\r
26EFI_STATUS\r
27UfsMmioRead32 (\r
1436aea4
MK
28 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
29 IN UINTN Offset,\r
30 OUT UINT32 *Value\r
095f0779
FT
31 )\r
32{\r
33 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
34 EFI_STATUS Status;\r
35\r
36 UfsHc = Private->UfsHostController;\r
37\r
38 Status = UfsHc->Read (UfsHc, EfiUfsHcWidthUint32, Offset, 1, Value);\r
39\r
40 return Status;\r
41}\r
42\r
43/**\r
44 Write 32bits data to specified UFS MMIO register.\r
45\r
46 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
47 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
48 the memory operation.\r
49 @param[in] Value The data to write.\r
50\r
51 @retval EFI_TIMEOUT The operation is time out.\r
52 @retval EFI_SUCCESS The operation succeeds.\r
53 @retval Others The operation fails.\r
54\r
55**/\r
56EFI_STATUS\r
57UfsMmioWrite32 (\r
1436aea4
MK
58 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
59 IN UINTN Offset,\r
60 IN UINT32 Value\r
095f0779
FT
61 )\r
62{\r
63 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
64 EFI_STATUS Status;\r
65\r
66 UfsHc = Private->UfsHostController;\r
67\r
68 Status = UfsHc->Write (UfsHc, EfiUfsHcWidthUint32, Offset, 1, &Value);\r
69\r
70 return Status;\r
71}\r
72\r
0591696e
FT
73/**\r
74 Wait for the value of the specified system memory set to the test value.\r
75\r
095f0779
FT
76 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
77 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
78 the memory operation.\r
79 @param[in] MaskValue The mask value of memory.\r
80 @param[in] TestValue The test value of memory.\r
81 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.\r
0591696e
FT
82\r
83 @retval EFI_TIMEOUT The system memory setting is time out.\r
84 @retval EFI_SUCCESS The system memory is correct set.\r
095f0779 85 @retval Others The operation fails.\r
0591696e
FT
86\r
87**/\r
88EFI_STATUS\r
0591696e 89UfsWaitMemSet (\r
1436aea4
MK
90 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
91 IN UINTN Offset,\r
92 IN UINT32 MaskValue,\r
93 IN UINT32 TestValue,\r
94 IN UINT64 Timeout\r
0591696e
FT
95 )\r
96{\r
1436aea4
MK
97 UINT32 Value;\r
98 UINT64 Delay;\r
99 BOOLEAN InfiniteWait;\r
100 EFI_STATUS Status;\r
0591696e
FT
101\r
102 if (Timeout == 0) {\r
103 InfiniteWait = TRUE;\r
104 } else {\r
105 InfiniteWait = FALSE;\r
106 }\r
107\r
108 Delay = DivU64x32 (Timeout, 10) + 1;\r
109\r
110 do {\r
111 //\r
112 // Access PCI MMIO space to see if the value is the tested one.\r
113 //\r
095f0779
FT
114 Status = UfsMmioRead32 (Private, Offset, &Value);\r
115 if (EFI_ERROR (Status)) {\r
116 return Status;\r
117 }\r
118\r
119 Value &= MaskValue;\r
0591696e
FT
120\r
121 if (Value == TestValue) {\r
122 return EFI_SUCCESS;\r
123 }\r
124\r
125 //\r
126 // Stall for 1 microseconds.\r
127 //\r
128 MicroSecondDelay (1);\r
129\r
130 Delay--;\r
0591696e
FT
131 } while (InfiniteWait || (Delay > 0));\r
132\r
133 return EFI_TIMEOUT;\r
134}\r
135\r
136/**\r
137 Dump UIC command execution result for debugging.\r
138\r
139 @param[in] UicOpcode The executed UIC opcode.\r
140 @param[in] Result The result to be parsed.\r
141\r
142**/\r
143VOID\r
144DumpUicCmdExecResult (\r
1436aea4
MK
145 IN UINT8 UicOpcode,\r
146 IN UINT8 Result\r
0591696e
FT
147 )\r
148{\r
149 if (UicOpcode <= UfsUicDmePeerSet) {\r
150 switch (Result) {\r
151 case 0x00:\r
152 break;\r
153 case 0x01:\r
edd94e74 154 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
0591696e
FT
155 break;\r
156 case 0x02:\r
edd94e74 157 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
0591696e
FT
158 break;\r
159 case 0x03:\r
edd94e74 160 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
161 break;\r
162 case 0x04:\r
edd94e74 163 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
164 break;\r
165 case 0x05:\r
edd94e74 166 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
0591696e
FT
167 break;\r
168 case 0x06:\r
edd94e74 169 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
0591696e
FT
170 break;\r
171 case 0x07:\r
edd94e74 172 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
0591696e
FT
173 break;\r
174 case 0x08:\r
edd94e74 175 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
d1102dba 176 break;\r
0591696e 177 case 0x09:\r
edd94e74 178 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
0591696e
FT
179 break;\r
180 case 0x0A:\r
edd94e74 181 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));\r
d1102dba 182 break;\r
1436aea4 183 default:\r
0591696e
FT
184 ASSERT (FALSE);\r
185 break;\r
186 }\r
187 } else {\r
188 switch (Result) {\r
189 case 0x00:\r
190 break;\r
191 case 0x01:\r
edd94e74 192 DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));\r
d1102dba 193 break;\r
1436aea4 194 default:\r
0591696e
FT
195 ASSERT (FALSE);\r
196 break;\r
197 }\r
198 }\r
199}\r
200\r
201/**\r
202 Dump QUERY RESPONSE UPIU result for debugging.\r
203\r
204 @param[in] Result The result to be parsed.\r
205\r
206**/\r
207VOID\r
208DumpQueryResponseResult (\r
1436aea4 209 IN UINT8 Result\r
0591696e
FT
210 )\r
211{\r
212 switch (Result) {\r
213 case 0xF6:\r
edd94e74 214 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
0591696e
FT
215 break;\r
216 case 0xF7:\r
edd94e74 217 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
0591696e
FT
218 break;\r
219 case 0xF8:\r
edd94e74 220 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));\r
0591696e
FT
221 break;\r
222 case 0xF9:\r
edd94e74 223 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));\r
0591696e
FT
224 break;\r
225 case 0xFA:\r
edd94e74 226 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));\r
0591696e
FT
227 break;\r
228 case 0xFB:\r
edd94e74 229 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));\r
0591696e
FT
230 break;\r
231 case 0xFC:\r
edd94e74 232 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));\r
0591696e
FT
233 break;\r
234 case 0xFD:\r
edd94e74 235 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));\r
0591696e
FT
236 break;\r
237 case 0xFE:\r
edd94e74 238 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));\r
d1102dba 239 break;\r
0591696e 240 case 0xFF:\r
edd94e74 241 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));\r
0591696e 242 break;\r
1436aea4 243 default:\r
0591696e
FT
244 ASSERT (FALSE);\r
245 break;\r
246 }\r
247}\r
248\r
249/**\r
250 Swap little endian to big endian.\r
251\r
252 @param[in, out] Buffer The data buffer. In input, it contains little endian data.\r
253 In output, it will become big endian.\r
254 @param[in] BufferSize The length of converted data.\r
255\r
256**/\r
257VOID\r
258SwapLittleEndianToBigEndian (\r
1436aea4
MK
259 IN OUT UINT8 *Buffer,\r
260 IN UINT32 BufferSize\r
0591696e
FT
261 )\r
262{\r
1436aea4
MK
263 UINT32 Index;\r
264 UINT8 Temp;\r
265 UINT32 SwapCount;\r
0591696e
FT
266\r
267 SwapCount = BufferSize / 2;\r
268 for (Index = 0; Index < SwapCount; Index++) {\r
1436aea4
MK
269 Temp = Buffer[Index];\r
270 Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
0591696e
FT
271 Buffer[BufferSize - 1 - Index] = Temp;\r
272 }\r
273}\r
274\r
275/**\r
276 Fill TSF field of QUERY REQUEST UPIU.\r
277\r
278 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.\r
279 @param[in] Opcode The opcode of request.\r
280 @param[in] DescId The descriptor ID of request.\r
281 @param[in] Index The index of request.\r
282 @param[in] Selector The selector of request.\r
283 @param[in] Length The length of transferred data. The maximum is 4.\r
284 @param[in] Value The value of transferred data.\r
285\r
286**/\r
287VOID\r
288UfsFillTsfOfQueryReqUpiu (\r
1436aea4
MK
289 IN OUT UTP_UPIU_TSF *TsfBase,\r
290 IN UINT8 Opcode,\r
291 IN UINT8 DescId OPTIONAL,\r
292 IN UINT8 Index OPTIONAL,\r
293 IN UINT8 Selector OPTIONAL,\r
294 IN UINT16 Length OPTIONAL,\r
295 IN UINT32 Value OPTIONAL\r
0591696e
FT
296 )\r
297{\r
298 ASSERT (TsfBase != NULL);\r
299 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);\r
300\r
1436aea4 301 TsfBase->Opcode = Opcode;\r
0591696e
FT
302 if (Opcode != UtpQueryFuncOpcodeNop) {\r
303 TsfBase->DescId = DescId;\r
304 TsfBase->Index = Index;\r
305 TsfBase->Selector = Selector;\r
306\r
307 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
1436aea4 308 SwapLittleEndianToBigEndian ((UINT8 *)&Length, sizeof (Length));\r
0591696e
FT
309 TsfBase->Length = Length;\r
310 }\r
d1102dba 311\r
0591696e 312 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
1436aea4
MK
313 SwapLittleEndianToBigEndian ((UINT8 *)&Value, sizeof (Value));\r
314 TsfBase->Value = Value;\r
0591696e
FT
315 }\r
316 }\r
317}\r
318\r
319/**\r
320 Initialize COMMAND UPIU.\r
321\r
322 @param[in, out] Command The base address of COMMAND UPIU.\r
323 @param[in] Lun The Lun on which the SCSI command is executed.\r
324 @param[in] TaskTag The task tag of request.\r
325 @param[in] Cdb The cdb buffer containing SCSI command.\r
326 @param[in] CdbLength The cdb length.\r
327 @param[in] DataDirection The direction of data transfer.\r
328 @param[in] ExpDataTranLen The expected transfer data length.\r
329\r
330 @retval EFI_SUCCESS The initialization succeed.\r
331\r
332**/\r
333EFI_STATUS\r
334UfsInitCommandUpiu (\r
1436aea4
MK
335 IN OUT UTP_COMMAND_UPIU *Command,\r
336 IN UINT8 Lun,\r
337 IN UINT8 TaskTag,\r
338 IN UINT8 *Cdb,\r
339 IN UINT8 CdbLength,\r
340 IN UFS_DATA_DIRECTION DataDirection,\r
341 IN UINT32 ExpDataTranLen\r
0591696e
FT
342 )\r
343{\r
1436aea4 344 UINT8 Flags;\r
0591696e
FT
345\r
346 ASSERT ((Command != NULL) && (Cdb != NULL));\r
347\r
348 //\r
349 // Task attribute is hard-coded to Ordered.\r
350 //\r
351 if (DataDirection == UfsDataIn) {\r
352 Flags = BIT0 | BIT6;\r
353 } else if (DataDirection == UfsDataOut) {\r
354 Flags = BIT0 | BIT5;\r
355 } else {\r
356 Flags = BIT0;\r
357 }\r
358\r
359 //\r
360 // Fill UTP COMMAND UPIU associated fields.\r
361 //\r
362 Command->TransCode = 0x01;\r
363 Command->Flags = Flags;\r
364 Command->Lun = Lun;\r
365 Command->TaskTag = TaskTag;\r
366 Command->CmdSet = 0x00;\r
1436aea4 367 SwapLittleEndianToBigEndian ((UINT8 *)&ExpDataTranLen, sizeof (ExpDataTranLen));\r
0591696e
FT
368 Command->ExpDataTranLen = ExpDataTranLen;\r
369\r
370 CopyMem (Command->Cdb, Cdb, CdbLength);\r
371\r
372 return EFI_SUCCESS;\r
373}\r
374\r
375/**\r
376 Initialize UTP PRDT for data transfer.\r
377\r
378 @param[in] Prdt The base address of PRDT.\r
379 @param[in] Buffer The buffer to be read or written.\r
380 @param[in] BufferSize The data size to be read or written.\r
381\r
382 @retval EFI_SUCCESS The initialization succeed.\r
383\r
384**/\r
385EFI_STATUS\r
386UfsInitUtpPrdt (\r
1436aea4
MK
387 IN UTP_TR_PRD *Prdt,\r
388 IN VOID *Buffer,\r
389 IN UINT32 BufferSize\r
0591696e
FT
390 )\r
391{\r
1436aea4
MK
392 UINT32 PrdtIndex;\r
393 UINT32 RemainingLen;\r
394 UINT8 *Remaining;\r
395 UINTN PrdtNumber;\r
0591696e 396\r
a37e18f6
AM
397 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
398 ASSERT ((BufferSize & (BIT1 | BIT0)) == 0);\r
d945390d 399\r
0591696e
FT
400 if (BufferSize == 0) {\r
401 return EFI_SUCCESS;\r
402 }\r
403\r
0591696e
FT
404 RemainingLen = BufferSize;\r
405 Remaining = Buffer;\r
406 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
407\r
408 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
409 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {\r
410 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;\r
411 } else {\r
412 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;\r
413 }\r
414\r
415 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);\r
416 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);\r
1436aea4
MK
417 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;\r
418 Remaining += UFS_MAX_DATA_LEN_PER_PRD;\r
0591696e
FT
419 }\r
420\r
421 return EFI_SUCCESS;\r
422}\r
423\r
424/**\r
425 Initialize QUERY REQUEST UPIU.\r
426\r
427 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.\r
428 @param[in] TaskTag The task tag of request.\r
429 @param[in] Opcode The opcode of request.\r
430 @param[in] DescId The descriptor ID of request.\r
431 @param[in] Index The index of request.\r
432 @param[in] Selector The selector of request.\r
433 @param[in] DataSize The data size to be read or written.\r
434 @param[in] Data The buffer to be read or written.\r
435\r
436 @retval EFI_SUCCESS The initialization succeed.\r
437\r
438**/\r
439EFI_STATUS\r
440UfsInitQueryRequestUpiu (\r
1436aea4
MK
441 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,\r
442 IN UINT8 TaskTag,\r
443 IN UINT8 Opcode,\r
444 IN UINT8 DescId,\r
445 IN UINT8 Index,\r
446 IN UINT8 Selector,\r
447 IN UINTN DataSize OPTIONAL,\r
448 IN UINT8 *Data OPTIONAL\r
0591696e
FT
449 )\r
450{\r
451 ASSERT (QueryReq != NULL);\r
452\r
453 QueryReq->TransCode = 0x16;\r
454 QueryReq->TaskTag = TaskTag;\r
455 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {\r
456 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;\r
457 } else {\r
458 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;\r
459 }\r
460\r
461 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
1436aea4 462 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32 *)Data);\r
0591696e
FT
463 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
464 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);\r
465 } else {\r
466 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);\r
467 }\r
468\r
469 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
470 CopyMem (QueryReq + 1, Data, DataSize);\r
c16eee92 471\r
1436aea4 472 SwapLittleEndianToBigEndian ((UINT8 *)&DataSize, sizeof (UINT16));\r
c16eee92 473 QueryReq->DataSegLen = (UINT16)DataSize;\r
0591696e
FT
474 }\r
475\r
476 return EFI_SUCCESS;\r
477}\r
478\r
479/**\r
480 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
481\r
482 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
483 @param[in] Lun The Lun on which the SCSI command is executed.\r
484 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
485 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
486 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
487 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
488\r
489 @retval EFI_SUCCESS The creation succeed.\r
490 @retval EFI_DEVICE_ERROR The creation failed.\r
491 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
492\r
493**/\r
494EFI_STATUS\r
495UfsCreateScsiCommandDesc (\r
496 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
497 IN UINT8 Lun,\r
498 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
499 IN UTP_TRD *Trd,\r
1436aea4
MK
500 OUT VOID **CmdDescHost,\r
501 OUT VOID **CmdDescMapping\r
0591696e
FT
502 )\r
503{\r
1436aea4
MK
504 UINTN TotalLen;\r
505 UINTN PrdtNumber;\r
506 UTP_COMMAND_UPIU *CommandUpiu;\r
507 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
508 EFI_STATUS Status;\r
509 UINT32 DataLen;\r
510 UFS_DATA_DIRECTION DataDirection;\r
0591696e
FT
511\r
512 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
513\r
514 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
515 DataLen = Packet->InTransferLength;\r
516 DataDirection = UfsDataIn;\r
517 } else {\r
518 DataLen = Packet->OutTransferLength;\r
519 DataDirection = UfsDataOut;\r
520 }\r
521\r
522 if (DataLen == 0) {\r
523 DataDirection = UfsNoData;\r
524 }\r
525\r
526 PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
527\r
1436aea4 528 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);\r
0591696e
FT
529\r
530 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
531 if (EFI_ERROR (Status)) {\r
532 return Status;\r
533 }\r
534\r
1436aea4 535 CommandUpiu = (UTP_COMMAND_UPIU *)*CmdDescHost;\r
0591696e
FT
536\r
537 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);\r
538\r
539 //\r
540 // Fill UTP_TRD associated fields\r
541 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table\r
542 // *MUST* be located at a 64-bit aligned boundary.\r
543 //\r
544 Trd->Int = UFS_INTERRUPT_COMMAND;\r
545 Trd->Dd = DataDirection;\r
546 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 547 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
548 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
549 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
550 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));\r
551 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));\r
552 Trd->PrdtL = (UINT16)PrdtNumber;\r
553 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));\r
554 return EFI_SUCCESS;\r
555}\r
556\r
557/**\r
558 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
559\r
560 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
561 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.\r
562 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
563 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
564 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
565\r
566 @retval EFI_SUCCESS The creation succeed.\r
567 @retval EFI_DEVICE_ERROR The creation failed.\r
568 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
569 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.\r
570\r
571**/\r
572EFI_STATUS\r
573UfsCreateDMCommandDesc (\r
574 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
575 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
576 IN UTP_TRD *Trd,\r
1436aea4
MK
577 OUT VOID **CmdDescHost,\r
578 OUT VOID **CmdDescMapping\r
0591696e
FT
579 )\r
580{\r
1436aea4
MK
581 UINTN TotalLen;\r
582 UTP_QUERY_REQ_UPIU *QueryReqUpiu;\r
583 UINT8 Opcode;\r
584 UINT32 DataSize;\r
585 UINT8 *Data;\r
586 UINT8 DataDirection;\r
587 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
588 EFI_STATUS Status;\r
0591696e
FT
589\r
590 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
591\r
592 Opcode = Packet->Opcode;\r
593 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {\r
594 return EFI_INVALID_PARAMETER;\r
595 }\r
596\r
597 DataDirection = Packet->DataDirection;\r
95ad8f7f
HW
598 DataSize = Packet->TransferLength;\r
599 Data = Packet->DataBuffer;\r
0591696e
FT
600\r
601 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {\r
1436aea4 602 if ((DataSize == 0) || (Data == NULL)) {\r
95ad8f7f
HW
603 return EFI_INVALID_PARAMETER;\r
604 }\r
1436aea4 605\r
0591696e
FT
606 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);\r
607 } else {\r
608 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));\r
609 }\r
610\r
611 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
612 if (EFI_ERROR (Status)) {\r
613 return Status;\r
614 }\r
615\r
616 //\r
617 // Initialize UTP QUERY REQUEST UPIU\r
618 //\r
1436aea4 619 QueryReqUpiu = (UTP_QUERY_REQ_UPIU *)*CmdDescHost;\r
0591696e
FT
620 ASSERT (QueryReqUpiu != NULL);\r
621 UfsInitQueryRequestUpiu (\r
622 QueryReqUpiu,\r
623 Private->TaskTag++,\r
624 Opcode,\r
625 Packet->DescId,\r
626 Packet->Index,\r
627 Packet->Selector,\r
628 DataSize,\r
629 Data\r
630 );\r
631\r
632 //\r
633 // Fill UTP_TRD associated fields\r
634 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.\r
635 //\r
636 Trd->Int = UFS_INTERRUPT_COMMAND;\r
637 Trd->Dd = DataDirection;\r
638 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 639 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
640 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
641 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
642 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
1436aea4
MK
643 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));\r
644 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));\r
0591696e 645 } else {\r
1436aea4
MK
646 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));\r
647 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));\r
0591696e
FT
648 }\r
649\r
650 return EFI_SUCCESS;\r
651}\r
652\r
653/**\r
654 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.\r
655\r
656 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
657 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
658 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
659 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
660\r
661 @retval EFI_SUCCESS The creation succeed.\r
662 @retval EFI_DEVICE_ERROR The creation failed.\r
663 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
664\r
665**/\r
666EFI_STATUS\r
667UfsCreateNopCommandDesc (\r
1436aea4
MK
668 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
669 IN UTP_TRD *Trd,\r
670 OUT VOID **CmdDescHost,\r
671 OUT VOID **CmdDescMapping\r
0591696e
FT
672 )\r
673{\r
1436aea4
MK
674 UINTN TotalLen;\r
675 UTP_NOP_OUT_UPIU *NopOutUpiu;\r
676 EFI_STATUS Status;\r
677 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
0591696e
FT
678\r
679 ASSERT ((Private != NULL) && (Trd != NULL));\r
680\r
681 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));\r
682 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
683 if (EFI_ERROR (Status)) {\r
684 return Status;\r
685 }\r
686\r
1436aea4 687 NopOutUpiu = (UTP_NOP_OUT_UPIU *)*CmdDescHost;\r
0591696e
FT
688 ASSERT (NopOutUpiu != NULL);\r
689 NopOutUpiu->TaskTag = Private->TaskTag++;\r
690\r
691 //\r
692 // Fill UTP_TRD associated fields\r
693 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.\r
694 //\r
695 Trd->Int = UFS_INTERRUPT_COMMAND;\r
696 Trd->Dd = 0x00;\r
697 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 698 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
699 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
700 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
701 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));\r
702 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));\r
703\r
704 return EFI_SUCCESS;\r
705}\r
706\r
707/**\r
708 Find out available slot in transfer list of a UFS device.\r
709\r
710 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
711 @param[out] Slot The available slot.\r
712\r
713 @retval EFI_SUCCESS The available slot was found successfully.\r
0350b57c 714 @retval EFI_NOT_READY No slot is available at this moment.\r
0591696e
FT
715\r
716**/\r
717EFI_STATUS\r
718UfsFindAvailableSlotInTrl (\r
1436aea4
MK
719 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
720 OUT UINT8 *Slot\r
0591696e
FT
721 )\r
722{\r
1436aea4
MK
723 UINT8 Nutrs;\r
724 UINT8 Index;\r
725 UINT32 Data;\r
726 EFI_STATUS Status;\r
0350b57c 727\r
0591696e
FT
728 ASSERT ((Private != NULL) && (Slot != NULL));\r
729\r
1436aea4 730 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);\r
0350b57c
HW
731 if (EFI_ERROR (Status)) {\r
732 return Status;\r
733 }\r
0591696e 734\r
1436aea4 735 Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
0350b57c
HW
736\r
737 for (Index = 0; Index < Nutrs; Index++) {\r
738 if ((Data & (BIT0 << Index)) == 0) {\r
739 *Slot = Index;\r
740 return EFI_SUCCESS;\r
741 }\r
742 }\r
743\r
744 return EFI_NOT_READY;\r
0591696e
FT
745}\r
746\r
0591696e
FT
747/**\r
748 Start specified slot in transfer list of a UFS device.\r
749\r
750 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
751 @param[in] Slot The slot to be started.\r
752\r
753**/\r
095f0779 754EFI_STATUS\r
0591696e 755UfsStartExecCmd (\r
1436aea4
MK
756 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
757 IN UINT8 Slot\r
d1102dba 758 )\r
0591696e 759{\r
1436aea4
MK
760 UINT32 Data;\r
761 EFI_STATUS Status;\r
0591696e 762\r
095f0779
FT
763 Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);\r
764 if (EFI_ERROR (Status)) {\r
765 return Status;\r
766 }\r
0591696e 767\r
0591696e 768 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
095f0779
FT
769 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
770 if (EFI_ERROR (Status)) {\r
771 return Status;\r
772 }\r
773 }\r
774\r
775 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);\r
776 if (EFI_ERROR (Status)) {\r
777 return Status;\r
0591696e
FT
778 }\r
779\r
095f0779 780 return EFI_SUCCESS;\r
0591696e
FT
781}\r
782\r
783/**\r
784 Stop specified slot in transfer list of a UFS device.\r
785\r
786 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
787 @param[in] Slot The slot to be stop.\r
788\r
789**/\r
095f0779 790EFI_STATUS\r
0591696e 791UfsStopExecCmd (\r
1436aea4
MK
792 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
793 IN UINT8 Slot\r
d1102dba 794 )\r
0591696e 795{\r
1436aea4
MK
796 UINT32 Data;\r
797 EFI_STATUS Status;\r
0591696e 798\r
095f0779
FT
799 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);\r
800 if (EFI_ERROR (Status)) {\r
801 return Status;\r
802 }\r
0591696e 803\r
0591696e 804 if ((Data & (BIT0 << Slot)) != 0) {\r
095f0779
FT
805 Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);\r
806 if (EFI_ERROR (Status)) {\r
807 return Status;\r
808 }\r
809\r
810 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));\r
811 if (EFI_ERROR (Status)) {\r
812 return Status;\r
813 }\r
0591696e 814 }\r
095f0779
FT
815\r
816 return EFI_SUCCESS;\r
0591696e
FT
817}\r
818\r
819/**\r
95ad8f7f 820 Extracts return data from query response upiu.\r
0591696e 821\r
95ad8f7f
HW
822 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
823 @param[in] QueryResp Pointer to the query response.\r
0591696e 824\r
95ad8f7f 825 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.\r
8894c90d 826 @retval EFI_DEVICE_ERROR Data returned from device is invalid.\r
95ad8f7f 827 @retval EFI_SUCCESS Data extracted.\r
0591696e
FT
828\r
829**/\r
830EFI_STATUS\r
95ad8f7f
HW
831UfsGetReturnDataFromQueryResponse (\r
832 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
833 IN UTP_QUERY_RESP_UPIU *QueryResp\r
0591696e
FT
834 )\r
835{\r
95ad8f7f
HW
836 UINT16 ReturnDataSize;\r
837 UINT32 ReturnData;\r
0591696e 838\r
1436aea4 839 if ((Packet == NULL) || (QueryResp == NULL)) {\r
95ad8f7f
HW
840 return EFI_INVALID_PARAMETER;\r
841 }\r
0591696e 842\r
95ad8f7f
HW
843 switch (Packet->Opcode) {\r
844 case UtpQueryFuncOpcodeRdDesc:\r
845 ReturnDataSize = QueryResp->Tsf.Length;\r
1436aea4 846 SwapLittleEndianToBigEndian ((UINT8 *)&ReturnDataSize, sizeof (UINT16));\r
8894c90d
HW
847 //\r
848 // Make sure the hardware device does not return more data than expected.\r
849 //\r
850 if (ReturnDataSize > Packet->TransferLength) {\r
851 return EFI_DEVICE_ERROR;\r
852 }\r
853\r
95ad8f7f
HW
854 CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);\r
855 Packet->TransferLength = ReturnDataSize;\r
856 break;\r
857 case UtpQueryFuncOpcodeWrDesc:\r
858 ReturnDataSize = QueryResp->Tsf.Length;\r
1436aea4 859 SwapLittleEndianToBigEndian ((UINT8 *)&ReturnDataSize, sizeof (UINT16));\r
95ad8f7f
HW
860 Packet->TransferLength = ReturnDataSize;\r
861 break;\r
862 case UtpQueryFuncOpcodeRdFlag:\r
863 case UtpQueryFuncOpcodeSetFlag:\r
864 case UtpQueryFuncOpcodeClrFlag:\r
865 case UtpQueryFuncOpcodeTogFlag:\r
cd70b1a7
AS
866 //\r
867 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value\r
868 //\r
1436aea4 869 *((UINT8 *)(Packet->DataBuffer)) = *((UINT8 *)&(QueryResp->Tsf.Value) + 3);\r
95ad8f7f
HW
870 break;\r
871 case UtpQueryFuncOpcodeRdAttr:\r
872 case UtpQueryFuncOpcodeWrAttr:\r
873 ReturnData = QueryResp->Tsf.Value;\r
1436aea4 874 SwapLittleEndianToBigEndian ((UINT8 *)&ReturnData, sizeof (UINT32));\r
95ad8f7f
HW
875 CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));\r
876 break;\r
877 default:\r
878 return EFI_INVALID_PARAMETER;\r
0591696e 879 }\r
95ad8f7f
HW
880\r
881 return EFI_SUCCESS;\r
882}\r
883\r
884/**\r
885 Creates Transfer Request descriptor and sends Query Request to the device.\r
886\r
887 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
888 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
889\r
890 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
32c9049d
HW
891 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
892 combination to point to a type of UFS device descriptor.\r
95ad8f7f
HW
893 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
894 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
895\r
896**/\r
897EFI_STATUS\r
898UfsSendDmRequestRetry (\r
899 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
900 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
901 )\r
902{\r
903 UINT8 Slot;\r
904 UTP_TRD *Trd;\r
905 VOID *CmdDescHost;\r
906 VOID *CmdDescMapping;\r
907 UINT32 CmdDescSize;\r
908 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
909 UTP_QUERY_RESP_UPIU *QueryResp;\r
910 EFI_STATUS Status;\r
0591696e
FT
911\r
912 //\r
913 // Find out which slot of transfer request list is available.\r
914 //\r
915 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
916 if (EFI_ERROR (Status)) {\r
917 return Status;\r
918 }\r
d1102dba 919\r
1436aea4 920 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;\r
0591696e
FT
921 //\r
922 // Fill transfer request descriptor to this slot.\r
923 //\r
95ad8f7f 924 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
0591696e 925 if (EFI_ERROR (Status)) {\r
95ad8f7f 926 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));\r
0591696e
FT
927 return Status;\r
928 }\r
929\r
1436aea4
MK
930 UfsHc = Private->UfsHostController;\r
931 QueryResp = (UTP_QUERY_RESP_UPIU *)((UINT8 *)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
0591696e
FT
932 ASSERT (QueryResp != NULL);\r
933 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
934\r
935 //\r
936 // Start to execute the transfer request.\r
937 //\r
938 UfsStartExecCmd (Private, Slot);\r
939\r
940 //\r
941 // Wait for the completion of the transfer request.\r
95ad8f7f
HW
942 //\r
943 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);\r
0591696e
FT
944 if (EFI_ERROR (Status)) {\r
945 goto Exit;\r
946 }\r
947\r
1436aea4 948 if ((Trd->Ocs != 0) || (QueryResp->QueryResp != UfsUtpQueryResponseSuccess)) {\r
95ad8f7f 949 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));\r
0591696e 950 DumpQueryResponseResult (QueryResp->QueryResp);\r
32c9049d
HW
951\r
952 if ((QueryResp->QueryResp == UfsUtpQueryResponseInvalidSelector) ||\r
953 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIndex) ||\r
1436aea4
MK
954 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIdn))\r
955 {\r
32c9049d
HW
956 Status = EFI_INVALID_PARAMETER;\r
957 } else {\r
958 Status = EFI_DEVICE_ERROR;\r
959 }\r
1436aea4 960\r
0591696e
FT
961 goto Exit;\r
962 }\r
963\r
95ad8f7f
HW
964 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);\r
965 if (EFI_ERROR (Status)) {\r
966 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));\r
967 goto Exit;\r
0591696e
FT
968 }\r
969\r
970Exit:\r
971 UfsHc->Flush (UfsHc);\r
972\r
973 UfsStopExecCmd (Private, Slot);\r
974\r
975 if (CmdDescMapping != NULL) {\r
976 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
977 }\r
1436aea4 978\r
0591696e
FT
979 if (CmdDescHost != NULL) {\r
980 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
981 }\r
982\r
983 return Status;\r
984}\r
985\r
95ad8f7f
HW
986/**\r
987 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.\r
988\r
989 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
990 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.\r
991\r
992 @retval EFI_SUCCESS The device responded correctly to the Query request.\r
32c9049d
HW
993 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
994 combination to point to a type of UFS device descriptor.\r
95ad8f7f
HW
995 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.\r
996 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.\r
997\r
998**/\r
999EFI_STATUS\r
1000UfsSendDmRequest (\r
1001 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1002 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
1003 )\r
1004{\r
1005 EFI_STATUS Status;\r
1006 UINT8 Retry;\r
1007\r
1008 Status = EFI_SUCCESS;\r
1009\r
1436aea4 1010 for (Retry = 0; Retry < 5; Retry++) {\r
95ad8f7f
HW
1011 Status = UfsSendDmRequestRetry (Private, Packet);\r
1012 if (!EFI_ERROR (Status)) {\r
1013 return EFI_SUCCESS;\r
1014 }\r
1015 }\r
1016\r
1017 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));\r
1018 return Status;\r
1019}\r
1020\r
1021/**\r
1022 Read or write specified device descriptor of a UFS device.\r
1023\r
1024 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1025 @param[in] Read The boolean variable to show r/w direction.\r
1026 @param[in] DescId The ID of device descriptor.\r
1027 @param[in] Index The Index of device descriptor.\r
1028 @param[in] Selector The Selector of device descriptor.\r
1029 @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
32c9049d
HW
1030 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,\r
1031 of the data buffer specified by Descriptor. On output, the number\r
1032 of bytes that were actually transferred.\r
95ad8f7f
HW
1033\r
1034 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
32c9049d
HW
1035 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a\r
1036 type of UFS device descriptor.\r
95ad8f7f
HW
1037 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
1038 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
1039\r
1040**/\r
1041EFI_STATUS\r
1042UfsRwDeviceDesc (\r
1436aea4
MK
1043 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1044 IN BOOLEAN Read,\r
1045 IN UINT8 DescId,\r
1046 IN UINT8 Index,\r
1047 IN UINT8 Selector,\r
1048 IN OUT VOID *Descriptor,\r
1049 IN OUT UINT32 *DescSize\r
95ad8f7f
HW
1050 )\r
1051{\r
1436aea4
MK
1052 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
1053 EFI_STATUS Status;\r
32c9049d
HW
1054\r
1055 if (DescSize == NULL) {\r
1056 return EFI_INVALID_PARAMETER;\r
1057 }\r
95ad8f7f
HW
1058\r
1059 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1060\r
1061 if (Read) {\r
1436aea4
MK
1062 Packet.DataDirection = UfsDataIn;\r
1063 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
95ad8f7f 1064 } else {\r
1436aea4
MK
1065 Packet.DataDirection = UfsDataOut;\r
1066 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
95ad8f7f 1067 }\r
1436aea4
MK
1068\r
1069 Packet.DataBuffer = Descriptor;\r
1070 Packet.TransferLength = *DescSize;\r
1071 Packet.DescId = DescId;\r
1072 Packet.Index = Index;\r
1073 Packet.Selector = Selector;\r
1074 Packet.Timeout = UFS_TIMEOUT;\r
95ad8f7f 1075\r
32c9049d
HW
1076 Status = UfsSendDmRequest (Private, &Packet);\r
1077 if (EFI_ERROR (Status)) {\r
1078 *DescSize = 0;\r
1079 } else {\r
1080 *DescSize = Packet.TransferLength;\r
1081 }\r
1082\r
1083 return Status;\r
95ad8f7f
HW
1084}\r
1085\r
0591696e
FT
1086/**\r
1087 Read or write specified attribute of a UFS device.\r
1088\r
1089 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1090 @param[in] Read The boolean variable to show r/w direction.\r
1091 @param[in] AttrId The ID of Attribute.\r
1092 @param[in] Index The Index of Attribute.\r
1093 @param[in] Selector The Selector of Attribute.\r
1094 @param[in, out] Attributes The value of Attribute to be read or written.\r
1095\r
1096 @retval EFI_SUCCESS The Attribute was read/written successfully.\r
32c9049d
HW
1097 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a\r
1098 type of UFS device descriptor.\r
0591696e
FT
1099 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.\r
1100 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.\r
1101\r
1102**/\r
1103EFI_STATUS\r
1104UfsRwAttributes (\r
1436aea4
MK
1105 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1106 IN BOOLEAN Read,\r
1107 IN UINT8 AttrId,\r
1108 IN UINT8 Index,\r
1109 IN UINT8 Selector,\r
1110 IN OUT UINT32 *Attributes\r
0591696e
FT
1111 )\r
1112{\r
1436aea4 1113 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1114\r
1115 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1116\r
1117 if (Read) {\r
1436aea4
MK
1118 Packet.DataDirection = UfsDataIn;\r
1119 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;\r
0591696e 1120 } else {\r
1436aea4
MK
1121 Packet.DataDirection = UfsDataOut;\r
1122 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;\r
0591696e 1123 }\r
1436aea4
MK
1124\r
1125 Packet.DataBuffer = Attributes;\r
1126 Packet.DescId = AttrId;\r
1127 Packet.Index = Index;\r
1128 Packet.Selector = Selector;\r
1129 Packet.Timeout = UFS_TIMEOUT;\r
0591696e 1130\r
95ad8f7f 1131 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1132}\r
1133\r
1134/**\r
1135 Read or write specified flag of a UFS device.\r
1136\r
1137 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1138 @param[in] Read The boolean variable to show r/w direction.\r
1139 @param[in] FlagId The ID of flag to be read or written.\r
1140 @param[in, out] Value The value to set or clear flag.\r
1141\r
1142 @retval EFI_SUCCESS The flag was read/written successfully.\r
32c9049d 1143 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.\r
0591696e
FT
1144 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.\r
1145 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.\r
1146\r
1147**/\r
1148EFI_STATUS\r
1149UfsRwFlags (\r
1436aea4
MK
1150 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1151 IN BOOLEAN Read,\r
1152 IN UINT8 FlagId,\r
1153 IN OUT UINT8 *Value\r
0591696e
FT
1154 )\r
1155{\r
1436aea4 1156 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1157\r
1158 if (Value == NULL) {\r
1159 return EFI_INVALID_PARAMETER;\r
1160 }\r
1161\r
1162 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1163\r
1164 if (Read) {\r
1165 ASSERT (Value != NULL);\r
1436aea4
MK
1166 Packet.DataDirection = UfsDataIn;\r
1167 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
0591696e 1168 } else {\r
1436aea4 1169 Packet.DataDirection = UfsDataOut;\r
0591696e 1170 if (*Value == 1) {\r
1436aea4 1171 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
0591696e 1172 } else if (*Value == 0) {\r
1436aea4 1173 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;\r
0591696e
FT
1174 } else {\r
1175 return EFI_INVALID_PARAMETER;\r
1176 }\r
1177 }\r
1436aea4
MK
1178\r
1179 Packet.DataBuffer = Value;\r
1180 Packet.DescId = FlagId;\r
1181 Packet.Index = 0;\r
1182 Packet.Selector = 0;\r
1183 Packet.Timeout = UFS_TIMEOUT;\r
0591696e 1184\r
95ad8f7f 1185 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1186}\r
1187\r
1188/**\r
1189 Set specified flag to 1 on a UFS device.\r
1190\r
1191 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1192 @param[in] FlagId The ID of flag to be set.\r
1193\r
1194 @retval EFI_SUCCESS The flag was set successfully.\r
1195 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.\r
1196 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.\r
1197\r
1198**/\r
1199EFI_STATUS\r
1200UfsSetFlag (\r
1436aea4
MK
1201 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1202 IN UINT8 FlagId\r
0591696e
FT
1203 )\r
1204{\r
1436aea4
MK
1205 EFI_STATUS Status;\r
1206 UINT8 Value;\r
0591696e
FT
1207\r
1208 Value = 1;\r
1209 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1210\r
1211 return Status;\r
1212}\r
1213\r
0591696e
FT
1214/**\r
1215 Read specified flag from a UFS device.\r
1216\r
1217 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1218 @param[in] FlagId The ID of flag to be read.\r
1219 @param[out] Value The flag's value.\r
1220\r
1221 @retval EFI_SUCCESS The flag was read successfully.\r
1222 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.\r
1223 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.\r
1224\r
1225**/\r
1226EFI_STATUS\r
1227UfsReadFlag (\r
1436aea4
MK
1228 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1229 IN UINT8 FlagId,\r
1230 OUT UINT8 *Value\r
0591696e
FT
1231 )\r
1232{\r
1436aea4 1233 EFI_STATUS Status;\r
0591696e
FT
1234\r
1235 Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
1236\r
1237 return Status;\r
1238}\r
1239\r
1240/**\r
1241 Sends NOP IN cmd to a UFS device for initialization process request.\r
1242 For more details, please refer to UFS 2.0 spec Figure 13.3.\r
1243\r
1244 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1245\r
1246 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was\r
1247 received successfully.\r
1248 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.\r
1249 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1250 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.\r
1251\r
1252**/\r
1253EFI_STATUS\r
1254UfsExecNopCmds (\r
1436aea4 1255 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
0591696e
FT
1256 )\r
1257{\r
1436aea4
MK
1258 EFI_STATUS Status;\r
1259 UINT8 Slot;\r
1260 UTP_TRD *Trd;\r
1261 UTP_NOP_IN_UPIU *NopInUpiu;\r
1262 UINT32 CmdDescSize;\r
1263 VOID *CmdDescHost;\r
1264 VOID *CmdDescMapping;\r
1265 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
0591696e
FT
1266\r
1267 //\r
1268 // Find out which slot of transfer request list is available.\r
1269 //\r
1270 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1271 if (EFI_ERROR (Status)) {\r
1272 return Status;\r
1273 }\r
1274\r
1436aea4 1275 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;\r
0591696e
FT
1276 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);\r
1277 if (EFI_ERROR (Status)) {\r
1278 return Status;\r
1279 }\r
1280\r
1281 //\r
1282 // Check the transfer request result.\r
1283 //\r
1436aea4
MK
1284 UfsHc = Private->UfsHostController;\r
1285 NopInUpiu = (UTP_NOP_IN_UPIU *)((UINT8 *)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
0591696e
FT
1286 ASSERT (NopInUpiu != NULL);\r
1287 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1288\r
1289 //\r
1290 // Start to execute the transfer request.\r
1291 //\r
1292 UfsStartExecCmd (Private, Slot);\r
1293\r
1294 //\r
1295 // Wait for the completion of the transfer request.\r
d1102dba 1296 //\r
13fca387 1297 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);\r
0591696e
FT
1298 if (EFI_ERROR (Status)) {\r
1299 goto Exit;\r
1300 }\r
1301\r
1302 if (NopInUpiu->Resp != 0) {\r
1303 Status = EFI_DEVICE_ERROR;\r
1304 } else {\r
1305 Status = EFI_SUCCESS;\r
1306 }\r
1307\r
1308Exit:\r
1309 UfsHc->Flush (UfsHc);\r
1310\r
1311 UfsStopExecCmd (Private, Slot);\r
1312\r
1313 if (CmdDescMapping != NULL) {\r
1314 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1315 }\r
1436aea4 1316\r
0591696e
FT
1317 if (CmdDescHost != NULL) {\r
1318 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1319 }\r
1320\r
1321 return Status;\r
1322}\r
1323\r
a37e18f6
AM
1324/**\r
1325 Cleanup data buffers after data transfer. This function\r
1326 also takes care to copy all data to user memory pool for\r
1327 unaligned data transfers.\r
1328\r
1329 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA\r
1330 @param[in] TransReq Pointer to the transfer request\r
1331**/\r
1332VOID\r
1333UfsReconcileDataTransferBuffer (\r
1334 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1335 IN UFS_PASS_THRU_TRANS_REQ *TransReq\r
1336 )\r
1337{\r
1338 if (TransReq->DataBufMapping != NULL) {\r
1339 Private->UfsHostController->Unmap (\r
1340 Private->UfsHostController,\r
1341 TransReq->DataBufMapping\r
1342 );\r
1343 }\r
1344\r
1345 //\r
1346 // Check if unaligned transfer was performed. If it was and we read\r
1347 // data from device copy memory to user data buffers before cleanup.\r
1348 // The assumption is if auxiliary aligned data buffer is not NULL then\r
1349 // unaligned transfer has been performed.\r
1350 //\r
1351 if (TransReq->AlignedDataBuf != NULL) {\r
1352 if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1353 CopyMem (TransReq->Packet->InDataBuffer, TransReq->AlignedDataBuf, TransReq->Packet->InTransferLength);\r
1354 }\r
1436aea4 1355\r
a37e18f6
AM
1356 //\r
1357 // Wipe out the transfer buffer in case it contains sensitive data.\r
1358 //\r
1359 ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);\r
1360 FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));\r
1361 TransReq->AlignedDataBuf = NULL;\r
1362 }\r
1363}\r
1364\r
1365/**\r
1366 Prepare data buffer for transfer.\r
1367\r
1368 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA\r
1369 @param[in, out] TransReq Pointer to the transfer request\r
1370\r
1371 @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer\r
1372 @retval EFI_SUCCESS Buffer ready for transfer\r
1373**/\r
1374EFI_STATUS\r
1375UfsPrepareDataTransferBuffer (\r
1376 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1377 IN OUT UFS_PASS_THRU_TRANS_REQ *TransReq\r
1378 )\r
1379{\r
1380 EFI_STATUS Status;\r
1381 VOID *DataBuf;\r
1382 UINT32 DataLen;\r
1383 UINTN MapLength;\r
1384 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;\r
1385 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;\r
1386 UTP_TR_PRD *PrdtBase;\r
1387\r
1388 DataBufPhyAddr = 0;\r
1389 DataBuf = NULL;\r
1390\r
1391 //\r
1392 // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.\r
1393 // When command is finished auxiliary memory pool is copied into actual user memory.\r
1394 // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)\r
1395 //\r
1396 if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1397 if (((UINTN)TransReq->Packet->InDataBuffer % 4 != 0) || (TransReq->Packet->InTransferLength % 4 != 0)) {\r
1398 DataLen = TransReq->Packet->InTransferLength + (4 - (TransReq->Packet->InTransferLength % 4));\r
1399 DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);\r
1400 if (DataBuf == NULL) {\r
1401 return EFI_DEVICE_ERROR;\r
1402 }\r
1436aea4 1403\r
a37e18f6 1404 ZeroMem (DataBuf, DataLen);\r
1436aea4 1405 TransReq->AlignedDataBuf = DataBuf;\r
a37e18f6
AM
1406 TransReq->AlignedDataBufSize = DataLen;\r
1407 } else {\r
1436aea4
MK
1408 DataLen = TransReq->Packet->InTransferLength;\r
1409 DataBuf = TransReq->Packet->InDataBuffer;\r
a37e18f6 1410 }\r
1436aea4
MK
1411\r
1412 Flag = EdkiiUfsHcOperationBusMasterWrite;\r
a37e18f6
AM
1413 } else {\r
1414 if (((UINTN)TransReq->Packet->OutDataBuffer % 4 != 0) || (TransReq->Packet->OutTransferLength % 4 != 0)) {\r
1415 DataLen = TransReq->Packet->OutTransferLength + (4 - (TransReq->Packet->OutTransferLength % 4));\r
1416 DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);\r
1417 if (DataBuf == NULL) {\r
1418 return EFI_DEVICE_ERROR;\r
1419 }\r
1436aea4 1420\r
a37e18f6 1421 CopyMem (DataBuf, TransReq->Packet->OutDataBuffer, TransReq->Packet->OutTransferLength);\r
1436aea4 1422 TransReq->AlignedDataBuf = DataBuf;\r
a37e18f6
AM
1423 TransReq->AlignedDataBufSize = DataLen;\r
1424 } else {\r
1436aea4
MK
1425 DataLen = TransReq->Packet->OutTransferLength;\r
1426 DataBuf = TransReq->Packet->OutDataBuffer;\r
a37e18f6 1427 }\r
1436aea4
MK
1428\r
1429 Flag = EdkiiUfsHcOperationBusMasterRead;\r
a37e18f6
AM
1430 }\r
1431\r
1432 if (DataLen != 0) {\r
1433 MapLength = DataLen;\r
1434 Status = Private->UfsHostController->Map (\r
1435 Private->UfsHostController,\r
1436 Flag,\r
1437 DataBuf,\r
1438 &MapLength,\r
1439 &DataBufPhyAddr,\r
1440 &TransReq->DataBufMapping\r
1441 );\r
1442\r
1443 if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
1444 if (TransReq->AlignedDataBuf != NULL) {\r
1445 //\r
1446 // Wipe out the transfer buffer in case it contains sensitive data.\r
1447 //\r
1448 ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);\r
1449 FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));\r
1450 TransReq->AlignedDataBuf = NULL;\r
1451 }\r
1436aea4 1452\r
a37e18f6
AM
1453 return EFI_DEVICE_ERROR;\r
1454 }\r
1455 }\r
1456\r
1457 //\r
1458 // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
1459 //\r
1436aea4 1460 PrdtBase = (UTP_TR_PRD *)((UINT8 *)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
a37e18f6 1461 ASSERT (PrdtBase != NULL);\r
1436aea4 1462 UfsInitUtpPrdt (PrdtBase, (VOID *)(UINTN)DataBufPhyAddr, DataLen);\r
a37e18f6
AM
1463\r
1464 return EFI_SUCCESS;\r
1465}\r
1466\r
0591696e
FT
1467/**\r
1468 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
1469\r
1470 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1471 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.\r
1472 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the\r
1473 UFS device.\r
0350b57c
HW
1474 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking\r
1475 I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
1476 Event is not NULL and non blocking I/O is supported, then\r
1477 nonblocking I/O is performed, and Event will be signaled when the\r
1478 SCSI Request Packet completes.\r
0591696e
FT
1479\r
1480 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional\r
1481 commands, InTransferLength bytes were transferred from\r
1482 InDataBuffer. For write and bi-directional commands,\r
1483 OutTransferLength bytes were transferred by\r
1484 OutDataBuffer.\r
1485 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request\r
1486 Packet.\r
1487 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1488 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
1489\r
1490**/\r
1491EFI_STATUS\r
1492UfsExecScsiCmds (\r
1493 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1494 IN UINT8 Lun,\r
0350b57c
HW
1495 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
1496 IN EFI_EVENT Event OPTIONAL\r
0591696e
FT
1497 )\r
1498{\r
1436aea4
MK
1499 EFI_STATUS Status;\r
1500 UTP_RESPONSE_UPIU *Response;\r
1501 UINT16 SenseDataLen;\r
1502 UINT32 ResTranCount;\r
1503 EFI_TPL OldTpl;\r
1504 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
1505 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
0591696e 1506\r
a37e18f6 1507 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));\r
0350b57c
HW
1508 if (TransReq == NULL) {\r
1509 return EFI_OUT_OF_RESOURCES;\r
1510 }\r
1511\r
1512 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;\r
1513 TransReq->TimeoutRemain = Packet->Timeout;\r
a37e18f6
AM
1514 TransReq->Packet = Packet;\r
1515\r
1436aea4 1516 UfsHc = Private->UfsHostController;\r
0591696e
FT
1517 //\r
1518 // Find out which slot of transfer request list is available.\r
1519 //\r
0350b57c 1520 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);\r
0591696e
FT
1521 if (EFI_ERROR (Status)) {\r
1522 return Status;\r
1523 }\r
1524\r
1436aea4 1525 TransReq->Trd = ((UTP_TRD *)Private->UtpTrlBase) + TransReq->Slot;\r
0591696e
FT
1526\r
1527 //\r
1528 // Fill transfer request descriptor to this slot.\r
1529 //\r
0350b57c
HW
1530 Status = UfsCreateScsiCommandDesc (\r
1531 Private,\r
1532 Lun,\r
1533 Packet,\r
1534 TransReq->Trd,\r
1535 &TransReq->CmdDescHost,\r
1536 &TransReq->CmdDescMapping\r
1537 );\r
0591696e
FT
1538 if (EFI_ERROR (Status)) {\r
1539 return Status;\r
1540 }\r
1541\r
0350b57c 1542 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);\r
0591696e 1543\r
a37e18f6
AM
1544 Status = UfsPrepareDataTransferBuffer (Private, TransReq);\r
1545 if (EFI_ERROR (Status)) {\r
1546 goto Exit1;\r
0591696e 1547 }\r
0591696e 1548\r
0350b57c
HW
1549 //\r
1550 // Insert the async SCSI cmd to the Async I/O list\r
1551 //\r
1552 if (Event != NULL) {\r
1436aea4 1553 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
0350b57c
HW
1554 TransReq->CallerEvent = Event;\r
1555 InsertTailList (&Private->Queue, &TransReq->TransferList);\r
1556 gBS->RestoreTPL (OldTpl);\r
1557 }\r
1558\r
0591696e
FT
1559 //\r
1560 // Start to execute the transfer request.\r
1561 //\r
0350b57c
HW
1562 UfsStartExecCmd (Private, TransReq->Slot);\r
1563\r
1564 //\r
1565 // Immediately return for async I/O.\r
1566 //\r
1567 if (Event != NULL) {\r
1568 return EFI_SUCCESS;\r
1569 }\r
0591696e
FT
1570\r
1571 //\r
1572 // Wait for the completion of the transfer request.\r
d1102dba 1573 //\r
13fca387 1574 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);\r
0591696e
FT
1575 if (EFI_ERROR (Status)) {\r
1576 goto Exit;\r
1577 }\r
1578\r
1579 //\r
1580 // Get sense data if exists\r
1581 //\r
1436aea4 1582 Response = (UTP_RESPONSE_UPIU *)((UINT8 *)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
0591696e
FT
1583 ASSERT (Response != NULL);\r
1584 SenseDataLen = Response->SenseDataLen;\r
1436aea4 1585 SwapLittleEndianToBigEndian ((UINT8 *)&SenseDataLen, sizeof (UINT16));\r
d1102dba 1586\r
0591696e 1587 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
8894c90d
HW
1588 //\r
1589 // Make sure the hardware device does not return more data than expected.\r
1590 //\r
1591 if (SenseDataLen <= Packet->SenseDataLength) {\r
1592 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
1593 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
1594 } else {\r
1595 Packet->SenseDataLength = 0;\r
1596 }\r
0591696e
FT
1597 }\r
1598\r
1599 //\r
1600 // Check the transfer request result.\r
1601 //\r
1602 Packet->TargetStatus = Response->Status;\r
1603 if (Response->Response != 0) {\r
edd94e74 1604 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
0591696e
FT
1605 Status = EFI_DEVICE_ERROR;\r
1606 goto Exit;\r
1607 }\r
1608\r
0350b57c 1609 if (TransReq->Trd->Ocs == 0) {\r
0591696e
FT
1610 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1611 if ((Response->Flags & BIT5) == BIT5) {\r
1612 ResTranCount = Response->ResTranCount;\r
1436aea4 1613 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));\r
0591696e
FT
1614 Packet->InTransferLength -= ResTranCount;\r
1615 }\r
1616 } else {\r
1617 if ((Response->Flags & BIT5) == BIT5) {\r
1618 ResTranCount = Response->ResTranCount;\r
1436aea4 1619 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));\r
0591696e
FT
1620 Packet->OutTransferLength -= ResTranCount;\r
1621 }\r
1622 }\r
1623 } else {\r
1624 Status = EFI_DEVICE_ERROR;\r
1625 }\r
1626\r
1627Exit:\r
1628 UfsHc->Flush (UfsHc);\r
1629\r
0350b57c 1630 UfsStopExecCmd (Private, TransReq->Slot);\r
0591696e 1631\r
a37e18f6 1632 UfsReconcileDataTransferBuffer (Private, TransReq);\r
0591696e
FT
1633\r
1634Exit1:\r
0350b57c
HW
1635 if (TransReq->CmdDescMapping != NULL) {\r
1636 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
0591696e 1637 }\r
1436aea4 1638\r
0350b57c
HW
1639 if (TransReq->CmdDescHost != NULL) {\r
1640 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);\r
1641 }\r
1436aea4 1642\r
0350b57c
HW
1643 if (TransReq != NULL) {\r
1644 FreePool (TransReq);\r
0591696e 1645 }\r
1436aea4 1646\r
0591696e
FT
1647 return Status;\r
1648}\r
1649\r
0591696e 1650/**\r
f426d874 1651 Send UIC command.\r
0591696e 1652\r
90952ad7
AM
1653 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1654 @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.\r
0591696e
FT
1655\r
1656 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.\r
1657 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
0591696e
FT
1658\r
1659**/\r
1660EFI_STATUS\r
1661UfsExecUicCommands (\r
1436aea4
MK
1662 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1663 IN OUT EDKII_UIC_COMMAND *UicCommand\r
0591696e
FT
1664 )\r
1665{\r
1666 EFI_STATUS Status;\r
0591696e 1667 UINT32 Data;\r
0591696e 1668\r
095f0779
FT
1669 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);\r
1670 if (EFI_ERROR (Status)) {\r
1671 return Status;\r
1672 }\r
1673\r
0591696e
FT
1674 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
1675 //\r
1676 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
1677 //\r
095f0779
FT
1678 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);\r
1679 if (EFI_ERROR (Status)) {\r
1680 return Status;\r
1681 }\r
0591696e
FT
1682 }\r
1683\r
1684 //\r
1685 // When programming UIC command registers, host software shall set the register UICCMD\r
1686 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
1687 // are set.\r
1688 //\r
90952ad7 1689 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, UicCommand->Arg1);\r
095f0779
FT
1690 if (EFI_ERROR (Status)) {\r
1691 return Status;\r
1692 }\r
0591696e 1693\r
90952ad7 1694 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, UicCommand->Arg2);\r
095f0779
FT
1695 if (EFI_ERROR (Status)) {\r
1696 return Status;\r
1697 }\r
0591696e 1698\r
90952ad7 1699 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, UicCommand->Arg3);\r
095f0779
FT
1700 if (EFI_ERROR (Status)) {\r
1701 return Status;\r
1702 }\r
0591696e
FT
1703\r
1704 //\r
1705 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
1706 //\r
095f0779 1707 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
0591696e
FT
1708 if (EFI_ERROR (Status)) {\r
1709 return Status;\r
1710 }\r
1711\r
90952ad7 1712 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, UicCommand->Opcode);\r
095f0779
FT
1713 if (EFI_ERROR (Status)) {\r
1714 return Status;\r
1715 }\r
0591696e
FT
1716\r
1717 //\r
1718 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
d1102dba 1719 // This bit is set to '1' by the host controller upon completion of a UIC command.\r
0591696e 1720 //\r
1436aea4 1721 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
0591696e
FT
1722 if (EFI_ERROR (Status)) {\r
1723 return Status;\r
1724 }\r
1725\r
90952ad7
AM
1726 if (UicCommand->Opcode != UfsUicDmeReset) {\r
1727 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &UicCommand->Arg2);\r
095f0779
FT
1728 if (EFI_ERROR (Status)) {\r
1729 return Status;\r
1730 }\r
1436aea4 1731\r
90952ad7
AM
1732 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG3_OFFSET, &UicCommand->Arg3);\r
1733 if (EFI_ERROR (Status)) {\r
1734 return Status;\r
1735 }\r
1436aea4 1736\r
90952ad7 1737 if ((UicCommand->Arg2 & 0xFF) != 0) {\r
1436aea4
MK
1738 DEBUG_CODE_BEGIN ();\r
1739 DumpUicCmdExecResult ((UINT8)UicCommand->Opcode, (UINT8)(UicCommand->Arg2 & 0xFF));\r
1740 DEBUG_CODE_END ();\r
0591696e
FT
1741 return EFI_DEVICE_ERROR;\r
1742 }\r
1743 }\r
1744\r
0591696e
FT
1745 return EFI_SUCCESS;\r
1746}\r
1747\r
1748/**\r
1749 Allocate common buffer for host and UFS bus master access simultaneously.\r
1750\r
1751 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1752 @param[in] Size The length of buffer to be allocated.\r
1753 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
1754 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.\r
1755 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
1756\r
1757 @retval EFI_SUCCESS The common buffer was allocated successfully.\r
1758 @retval EFI_DEVICE_ERROR The allocation fails.\r
1759 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
1760\r
1761**/\r
1762EFI_STATUS\r
1763UfsAllocateAlignCommonBuffer (\r
1436aea4
MK
1764 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1765 IN UINTN Size,\r
1766 OUT VOID **CmdDescHost,\r
1767 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,\r
1768 OUT VOID **CmdDescMapping\r
0591696e
FT
1769 )\r
1770{\r
1436aea4
MK
1771 EFI_STATUS Status;\r
1772 UINTN Bytes;\r
1773 BOOLEAN Is32BitAddr;\r
1774 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
0591696e 1775\r
a71272ed 1776 if ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
0591696e 1777 Is32BitAddr = FALSE;\r
a2e3feb6
HZ
1778 } else {\r
1779 Is32BitAddr = TRUE;\r
0591696e
FT
1780 }\r
1781\r
1782 UfsHc = Private->UfsHostController;\r
1783 Status = UfsHc->AllocateBuffer (\r
1784 UfsHc,\r
1785 AllocateAnyPages,\r
1786 EfiBootServicesData,\r
1787 EFI_SIZE_TO_PAGES (Size),\r
1788 CmdDescHost,\r
1789 0\r
1790 );\r
1791 if (EFI_ERROR (Status)) {\r
1792 *CmdDescMapping = NULL;\r
1793 *CmdDescHost = NULL;\r
1794 *CmdDescPhyAddr = 0;\r
1795 return EFI_OUT_OF_RESOURCES;\r
1796 }\r
1797\r
1798 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));\r
1799 Status = UfsHc->Map (\r
1800 UfsHc,\r
1801 EdkiiUfsHcOperationBusMasterCommonBuffer,\r
1802 *CmdDescHost,\r
1803 &Bytes,\r
1804 CmdDescPhyAddr,\r
1805 CmdDescMapping\r
1806 );\r
1807\r
1808 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {\r
1809 UfsHc->FreeBuffer (\r
1810 UfsHc,\r
1811 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1812 *CmdDescHost\r
1813 );\r
1814 *CmdDescHost = NULL;\r
1815 return EFI_OUT_OF_RESOURCES;\r
1816 }\r
1817\r
1818 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {\r
1819 //\r
1820 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.\r
1821 //\r
1822 UfsHc->Unmap (\r
1823 UfsHc,\r
1824 *CmdDescMapping\r
1825 );\r
1826 UfsHc->FreeBuffer (\r
1827 UfsHc,\r
1828 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1829 *CmdDescHost\r
1830 );\r
1831 *CmdDescMapping = NULL;\r
1832 *CmdDescHost = NULL;\r
1833 return EFI_DEVICE_ERROR;\r
1834 }\r
1835\r
1836 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));\r
1837 return EFI_SUCCESS;\r
1838}\r
1839\r
1840/**\r
1841 Enable the UFS host controller for accessing.\r
1842\r
1843 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1844\r
1845 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1846 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1847\r
1848**/\r
1849EFI_STATUS\r
1850UfsEnableHostController (\r
1436aea4 1851 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
0591696e
FT
1852 )\r
1853{\r
1436aea4
MK
1854 EFI_STATUS Status;\r
1855 UINT32 Data;\r
0591696e 1856\r
1436aea4 1857 if ((mUfsHcPlatform != NULL) && (mUfsHcPlatform->Callback != NULL)) {\r
ecc32c90
AM
1858 Status = mUfsHcPlatform->Callback (Private->Handle, EdkiiUfsHcPreHce, &Private->UfsHcDriverInterface);\r
1859 if (EFI_ERROR (Status)) {\r
1860 DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPreHce, Status = %r\n", Status));\r
1861 return Status;\r
1862 }\r
1863 }\r
1864\r
0591696e
FT
1865 //\r
1866 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1867 //\r
1868 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1869 //\r
095f0779
FT
1870 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
1871 if (EFI_ERROR (Status)) {\r
1872 return Status;\r
1873 }\r
1874\r
0591696e
FT
1875 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1876 //\r
1877 // Write a 0 to the HCE register at first to disable the host controller.\r
1878 //\r
095f0779
FT
1879 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
1880 if (EFI_ERROR (Status)) {\r
1881 return Status;\r
1882 }\r
1436aea4 1883\r
0591696e
FT
1884 //\r
1885 // Wait until HCE is read as '0' before continuing.\r
1886 //\r
095f0779 1887 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
1888 if (EFI_ERROR (Status)) {\r
1889 return EFI_DEVICE_ERROR;\r
1890 }\r
1891 }\r
1892\r
1893 //\r
1894 // Write a 1 to the HCE register to enable the UFS host controller.\r
1895 //\r
095f0779
FT
1896 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);\r
1897 if (EFI_ERROR (Status)) {\r
1898 return Status;\r
1899 }\r
1900\r
0591696e
FT
1901 //\r
1902 // Wait until HCE is read as '1' before continuing.\r
1903 //\r
095f0779 1904 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
0591696e
FT
1905 if (EFI_ERROR (Status)) {\r
1906 return EFI_DEVICE_ERROR;\r
1907 }\r
1908\r
1436aea4 1909 if ((mUfsHcPlatform != NULL) && (mUfsHcPlatform->Callback != NULL)) {\r
ecc32c90
AM
1910 Status = mUfsHcPlatform->Callback (Private->Handle, EdkiiUfsHcPostHce, &Private->UfsHcDriverInterface);\r
1911 if (EFI_ERROR (Status)) {\r
1912 DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPostHce, Status = %r\n", Status));\r
1913 return Status;\r
1914 }\r
1915 }\r
1916\r
0591696e
FT
1917 return EFI_SUCCESS;\r
1918}\r
1919\r
1920/**\r
1921 Detect if a UFS device attached.\r
1922\r
1923 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1924\r
1925 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1926 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1927 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1928\r
1929**/\r
1930EFI_STATUS\r
1931UfsDeviceDetection (\r
1436aea4 1932 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
0591696e
FT
1933 )\r
1934{\r
90952ad7
AM
1935 UINTN Retry;\r
1936 EFI_STATUS Status;\r
1937 UINT32 Data;\r
1938 EDKII_UIC_COMMAND LinkStartupCommand;\r
0591696e 1939\r
1436aea4 1940 if ((mUfsHcPlatform != NULL) && (mUfsHcPlatform->Callback != NULL)) {\r
ecc32c90
AM
1941 Status = mUfsHcPlatform->Callback (Private->Handle, EdkiiUfsHcPreLinkStartup, &Private->UfsHcDriverInterface);\r
1942 if (EFI_ERROR (Status)) {\r
1943 DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPreLinkStartup, Status = %r\n", Status));\r
1944 return Status;\r
1945 }\r
1946 }\r
1947\r
0591696e
FT
1948 //\r
1949 // Start UFS device detection.\r
1950 // Try up to 3 times for establishing data link with device.\r
1951 //\r
1952 for (Retry = 0; Retry < 3; Retry++) {\r
90952ad7 1953 LinkStartupCommand.Opcode = UfsUicDmeLinkStartup;\r
1436aea4
MK
1954 LinkStartupCommand.Arg1 = 0;\r
1955 LinkStartupCommand.Arg2 = 0;\r
1956 LinkStartupCommand.Arg3 = 0;\r
1957 Status = UfsExecUicCommands (Private, &LinkStartupCommand);\r
f426d874
AM
1958 if (EFI_ERROR (Status)) {\r
1959 return EFI_DEVICE_ERROR;\r
0591696e
FT
1960 }\r
1961\r
f426d874
AM
1962 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);\r
1963 if (EFI_ERROR (Status)) {\r
1964 return EFI_DEVICE_ERROR;\r
0591696e
FT
1965 }\r
1966\r
f426d874
AM
1967 if ((Data & UFS_HC_HCS_DP) == 0) {\r
1968 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
1969 if (EFI_ERROR (Status)) {\r
1970 return EFI_DEVICE_ERROR;\r
1971 }\r
1972 } else {\r
1973 return EFI_SUCCESS;\r
1974 }\r
0591696e
FT
1975 }\r
1976\r
f426d874 1977 return EFI_NOT_FOUND;\r
0591696e
FT
1978}\r
1979\r
1980/**\r
1981 Initialize UFS task management request list related h/w context.\r
1982\r
1983 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1984\r
1985 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1986 @retval EFI_DEVICE_ERROR The initialization fails.\r
1987\r
1988**/\r
1989EFI_STATUS\r
1990UfsInitTaskManagementRequestList (\r
1436aea4 1991 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
0591696e
FT
1992 )\r
1993{\r
1436aea4
MK
1994 UINT8 Nutmrs;\r
1995 VOID *CmdDescHost;\r
1996 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1997 VOID *CmdDescMapping;\r
1998 EFI_STATUS Status;\r
d1102dba 1999\r
0591696e
FT
2000 //\r
2001 // Initial h/w and s/w context for future operations.\r
2002 //\r
2003 CmdDescHost = NULL;\r
2004 CmdDescMapping = NULL;\r
2005 CmdDescPhyAddr = 0;\r
095f0779 2006\r
0591696e
FT
2007 //\r
2008 // Allocate and initialize UTP Task Management Request List.\r
2009 //\r
1436aea4 2010 Nutmrs = (UINT8)(RShiftU64 ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
0591696e
FT
2011 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
2012 if (EFI_ERROR (Status)) {\r
2013 return Status;\r
2014 }\r
2015\r
2016 //\r
2017 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
2018 // Request List Base Address with a 64-bit address allocated at step 6.\r
2019 //\r
095f0779
FT
2020 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
2021 if (EFI_ERROR (Status)) {\r
2022 return Status;\r
2023 }\r
2024\r
2025 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
2026 if (EFI_ERROR (Status)) {\r
2027 return Status;\r
2028 }\r
1436aea4 2029\r
0591696e
FT
2030 Private->UtpTmrlBase = CmdDescHost;\r
2031 Private->Nutmrs = Nutmrs;\r
2032 Private->TmrlMapping = CmdDescMapping;\r
2033\r
2034 //\r
2035 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
2036 // Request List RunStop Register (UTMRLRSR) to '1'.\r
2037 //\r
095f0779
FT
2038 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);\r
2039 if (EFI_ERROR (Status)) {\r
2040 return Status;\r
2041 }\r
0591696e
FT
2042\r
2043 return EFI_SUCCESS;\r
2044}\r
2045\r
2046/**\r
2047 Initialize UFS transfer request list related h/w context.\r
2048\r
2049 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2050\r
2051 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
2052 @retval EFI_DEVICE_ERROR The initialization fails.\r
2053\r
2054**/\r
2055EFI_STATUS\r
2056UfsInitTransferRequestList (\r
1436aea4 2057 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
0591696e
FT
2058 )\r
2059{\r
1436aea4
MK
2060 UINT8 Nutrs;\r
2061 VOID *CmdDescHost;\r
2062 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
2063 VOID *CmdDescMapping;\r
2064 EFI_STATUS Status;\r
0591696e
FT
2065\r
2066 //\r
2067 // Initial h/w and s/w context for future operations.\r
2068 //\r
2069 CmdDescHost = NULL;\r
2070 CmdDescMapping = NULL;\r
2071 CmdDescPhyAddr = 0;\r
095f0779 2072\r
0591696e
FT
2073 //\r
2074 // Allocate and initialize UTP Transfer Request List.\r
2075 //\r
a71272ed 2076 Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
0591696e
FT
2077 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
2078 if (EFI_ERROR (Status)) {\r
2079 return Status;\r
2080 }\r
2081\r
2082 //\r
2083 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
2084 // Base Address with a 64-bit address allocated at step 8.\r
2085 //\r
095f0779
FT
2086 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
2087 if (EFI_ERROR (Status)) {\r
2088 return Status;\r
2089 }\r
2090\r
2091 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
2092 if (EFI_ERROR (Status)) {\r
2093 return Status;\r
2094 }\r
2095\r
0591696e 2096 Private->UtpTrlBase = CmdDescHost;\r
d1102dba 2097 Private->Nutrs = Nutrs;\r
0591696e
FT
2098 Private->TrlMapping = CmdDescMapping;\r
2099\r
2100 //\r
2101 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
2102 // RunStop Register (UTRLRSR) to '1'.\r
2103 //\r
095f0779
FT
2104 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
2105 if (EFI_ERROR (Status)) {\r
2106 return Status;\r
2107 }\r
0591696e
FT
2108\r
2109 return EFI_SUCCESS;\r
2110}\r
2111\r
2112/**\r
2113 Initialize the UFS host controller.\r
2114\r
2115 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2116\r
2117 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
2118 @retval Others A device error occurred while initializing the controller.\r
2119\r
2120**/\r
2121EFI_STATUS\r
2122UfsControllerInit (\r
1436aea4 2123 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
0591696e
FT
2124 )\r
2125{\r
1436aea4 2126 EFI_STATUS Status;\r
0591696e
FT
2127\r
2128 Status = UfsEnableHostController (Private);\r
2129 if (EFI_ERROR (Status)) {\r
edd94e74 2130 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));\r
0591696e
FT
2131 return Status;\r
2132 }\r
2133\r
2134 Status = UfsDeviceDetection (Private);\r
2135 if (EFI_ERROR (Status)) {\r
edd94e74 2136 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));\r
0591696e
FT
2137 return Status;\r
2138 }\r
2139\r
2140 Status = UfsInitTaskManagementRequestList (Private);\r
2141 if (EFI_ERROR (Status)) {\r
edd94e74 2142 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2143 return Status;\r
2144 }\r
2145\r
2146 Status = UfsInitTransferRequestList (Private);\r
2147 if (EFI_ERROR (Status)) {\r
edd94e74 2148 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2149 return Status;\r
2150 }\r
2151\r
edd94e74 2152 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));\r
0591696e
FT
2153 return EFI_SUCCESS;\r
2154}\r
2155\r
2156/**\r
2157 Stop the UFS host controller.\r
2158\r
2159 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2160\r
2161 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
2162 @retval Others A device error occurred while stopping the controller.\r
2163\r
2164**/\r
2165EFI_STATUS\r
2166UfsControllerStop (\r
1436aea4 2167 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
0591696e
FT
2168 )\r
2169{\r
1436aea4
MK
2170 EFI_STATUS Status;\r
2171 UINT32 Data;\r
0591696e
FT
2172\r
2173 //\r
2174 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
2175 // Request List RunStop Register (UTMRLRSR) to '1'.\r
2176 //\r
095f0779
FT
2177 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);\r
2178 if (EFI_ERROR (Status)) {\r
2179 return Status;\r
2180 }\r
0591696e
FT
2181\r
2182 //\r
2183 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
2184 // RunStop Register (UTRLRSR) to '1'.\r
2185 //\r
095f0779
FT
2186 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);\r
2187 if (EFI_ERROR (Status)) {\r
2188 return Status;\r
2189 }\r
0591696e
FT
2190\r
2191 //\r
2192 // Write a 0 to the HCE register in order to disable the host controller.\r
2193 //\r
095f0779
FT
2194 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
2195 if (EFI_ERROR (Status)) {\r
2196 return Status;\r
2197 }\r
1436aea4 2198\r
0591696e 2199 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
095f0779
FT
2200\r
2201 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
2202 if (EFI_ERROR (Status)) {\r
2203 return Status;\r
2204 }\r
0591696e
FT
2205\r
2206 //\r
2207 // Wait until HCE is read as '0' before continuing.\r
2208 //\r
095f0779 2209 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
2210 if (EFI_ERROR (Status)) {\r
2211 return EFI_DEVICE_ERROR;\r
2212 }\r
2213\r
edd94e74 2214 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));\r
0591696e
FT
2215\r
2216 return EFI_SUCCESS;\r
2217}\r
2218\r
0350b57c
HW
2219/**\r
2220 Internal helper function which will signal the caller event and clean up\r
2221 resources.\r
2222\r
2223 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data\r
2224 structure.\r
2225 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data\r
2226 structure.\r
2227\r
2228**/\r
2229VOID\r
2230EFIAPI\r
2231SignalCallerEvent (\r
1436aea4
MK
2232 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
2233 IN UFS_PASS_THRU_TRANS_REQ *TransReq\r
0350b57c
HW
2234 )\r
2235{\r
1436aea4
MK
2236 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
2237 EFI_EVENT CallerEvent;\r
0350b57c 2238\r
33e2ba78
HW
2239 ASSERT ((Private != NULL) && (TransReq != NULL));\r
2240\r
1436aea4
MK
2241 UfsHc = Private->UfsHostController;\r
2242 CallerEvent = TransReq->CallerEvent;\r
0350b57c
HW
2243\r
2244 RemoveEntryList (&TransReq->TransferList);\r
2245\r
2246 UfsHc->Flush (UfsHc);\r
2247\r
2248 UfsStopExecCmd (Private, TransReq->Slot);\r
2249\r
a37e18f6 2250 UfsReconcileDataTransferBuffer (Private, TransReq);\r
0350b57c
HW
2251\r
2252 if (TransReq->CmdDescMapping != NULL) {\r
2253 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
2254 }\r
1436aea4 2255\r
0350b57c
HW
2256 if (TransReq->CmdDescHost != NULL) {\r
2257 UfsHc->FreeBuffer (\r
2258 UfsHc,\r
2259 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),\r
2260 TransReq->CmdDescHost\r
2261 );\r
2262 }\r
33e2ba78
HW
2263\r
2264 FreePool (TransReq);\r
0350b57c
HW
2265\r
2266 gBS->SignalEvent (CallerEvent);\r
2267 return;\r
2268}\r
2269\r
2270/**\r
2271 Call back function when the timer event is signaled.\r
2272\r
2273 @param[in] Event The Event this notify function registered to.\r
2274 @param[in] Context Pointer to the context data registered to the Event.\r
2275\r
2276**/\r
2277VOID\r
2278EFIAPI\r
2279ProcessAsyncTaskList (\r
1436aea4
MK
2280 IN EFI_EVENT Event,\r
2281 IN VOID *Context\r
0350b57c
HW
2282 )\r
2283{\r
1436aea4
MK
2284 UFS_PASS_THRU_PRIVATE_DATA *Private;\r
2285 LIST_ENTRY *Entry;\r
2286 LIST_ENTRY *NextEntry;\r
2287 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
2288 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;\r
2289 UTP_RESPONSE_UPIU *Response;\r
2290 UINT16 SenseDataLen;\r
2291 UINT32 ResTranCount;\r
2292 UINT32 SlotsMap;\r
2293 UINT32 Value;\r
2294 EFI_STATUS Status;\r
2295\r
2296 Private = (UFS_PASS_THRU_PRIVATE_DATA *)Context;\r
2297 SlotsMap = 0;\r
0350b57c
HW
2298\r
2299 //\r
2300 // Check the entries in the async I/O queue are done or not.\r
2301 //\r
1436aea4 2302 if (!IsListEmpty (&Private->Queue)) {\r
d189a3f9 2303 BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {\r
1436aea4
MK
2304 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);\r
2305 Packet = TransReq->Packet;\r
0350b57c
HW
2306\r
2307 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {\r
2308 return;\r
2309 }\r
1436aea4 2310\r
0350b57c
HW
2311 SlotsMap |= BIT0 << TransReq->Slot;\r
2312\r
2313 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);\r
2314 if (EFI_ERROR (Status)) {\r
2315 //\r
2316 // TODO: Should find/add a proper host adapter return status for this\r
2317 // case.\r
2318 //\r
2319 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;\r
edd94e74 2320 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2321 SignalCallerEvent (Private, TransReq);\r
2322 continue;\r
2323 }\r
2324\r
2325 if ((Value & (BIT0 << TransReq->Slot)) != 0) {\r
2326 //\r
2327 // Scsi cmd not finished yet.\r
2328 //\r
2329 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {\r
2330 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;\r
2331 continue;\r
2332 } else {\r
2333 //\r
2334 // Timeout occurs.\r
2335 //\r
2336 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;\r
edd94e74 2337 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));\r
0350b57c
HW
2338 SignalCallerEvent (Private, TransReq);\r
2339 continue;\r
2340 }\r
2341 } else {\r
2342 //\r
2343 // Scsi cmd finished.\r
2344 //\r
2345 // Get sense data if exists\r
2346 //\r
1436aea4 2347 Response = (UTP_RESPONSE_UPIU *)((UINT8 *)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
0350b57c
HW
2348 ASSERT (Response != NULL);\r
2349 SenseDataLen = Response->SenseDataLen;\r
1436aea4 2350 SwapLittleEndianToBigEndian ((UINT8 *)&SenseDataLen, sizeof (UINT16));\r
0350b57c
HW
2351\r
2352 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
8894c90d
HW
2353 //\r
2354 // Make sure the hardware device does not return more data than expected.\r
2355 //\r
2356 if (SenseDataLen <= Packet->SenseDataLength) {\r
2357 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
2358 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
2359 } else {\r
2360 Packet->SenseDataLength = 0;\r
2361 }\r
0350b57c
HW
2362 }\r
2363\r
2364 //\r
2365 // Check the transfer request result.\r
2366 //\r
2367 Packet->TargetStatus = Response->Status;\r
2368 if (Response->Response != 0) {\r
edd94e74 2369 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));\r
0350b57c
HW
2370 SignalCallerEvent (Private, TransReq);\r
2371 continue;\r
2372 }\r
2373\r
2374 if (TransReq->Trd->Ocs == 0) {\r
2375 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
2376 if ((Response->Flags & BIT5) == BIT5) {\r
2377 ResTranCount = Response->ResTranCount;\r
1436aea4 2378 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));\r
0350b57c
HW
2379 Packet->InTransferLength -= ResTranCount;\r
2380 }\r
2381 } else {\r
2382 if ((Response->Flags & BIT5) == BIT5) {\r
2383 ResTranCount = Response->ResTranCount;\r
1436aea4 2384 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));\r
0350b57c
HW
2385 Packet->OutTransferLength -= ResTranCount;\r
2386 }\r
2387 }\r
2388 } else {\r
edd94e74 2389 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2390 SignalCallerEvent (Private, TransReq);\r
2391 continue;\r
2392 }\r
2393\r
edd94e74 2394 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));\r
0350b57c
HW
2395 SignalCallerEvent (Private, TransReq);\r
2396 }\r
2397 }\r
2398 }\r
2399}\r
2400\r
ecc32c90
AM
2401/**\r
2402 Execute UIC command.\r
2403\r
2404 @param[in] This Pointer to driver interface produced by the UFS controller.\r
2405 @param[in, out] UicCommand Descriptor of the command that will be executed.\r
2406\r
2407 @retval EFI_SUCCESS Command executed successfully.\r
2408 @retval EFI_INVALID_PARAMETER This or UicCommand is NULL.\r
2409 @retval Others Command failed to execute.\r
2410**/\r
2411EFI_STATUS\r
2412EFIAPI\r
2413UfsHcDriverInterfaceExecUicCommand (\r
2414 IN EDKII_UFS_HC_DRIVER_INTERFACE *This,\r
2415 IN OUT EDKII_UIC_COMMAND *UicCommand\r
2416 )\r
2417{\r
1436aea4 2418 UFS_PASS_THRU_PRIVATE_DATA *Private;\r
ecc32c90 2419\r
1436aea4 2420 if ((This == NULL) || (UicCommand == NULL)) {\r
ecc32c90
AM
2421 return EFI_INVALID_PARAMETER;\r
2422 }\r
2423\r
2424 Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_DRIVER_INTF (This);\r
2425\r
2426 return UfsExecUicCommands (Private, UicCommand);\r
2427}\r
2428\r
a71272ed
AM
2429/**\r
2430 Initializes UfsHcInfo field in private data.\r
2431\r
2432 @param[in] Private Pointer to host controller private data.\r
2433\r
2434 @retval EFI_SUCCESS UfsHcInfo initialized successfully.\r
2435 @retval Others Failed to initalize UfsHcInfo.\r
2436**/\r
2437EFI_STATUS\r
2438GetUfsHcInfo (\r
2439 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2440 )\r
2441{\r
2442 UINT32 Data;\r
2443 EFI_STATUS Status;\r
2444\r
2445 Status = UfsMmioRead32 (Private, UFS_HC_VER_OFFSET, &Data);\r
2446 if (EFI_ERROR (Status)) {\r
2447 return Status;\r
2448 }\r
2449\r
2450 Private->UfsHcInfo.Version = Data;\r
2451\r
2452 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
2453 if (EFI_ERROR (Status)) {\r
2454 return Status;\r
2455 }\r
2456\r
2457 Private->UfsHcInfo.Capabilities = Data;\r
2458\r
1436aea4 2459 if ((mUfsHcPlatform != NULL) && (mUfsHcPlatform->OverrideHcInfo != NULL)) {\r
ecc32c90
AM
2460 Status = mUfsHcPlatform->OverrideHcInfo (Private->Handle, &Private->UfsHcInfo);\r
2461 if (EFI_ERROR (Status)) {\r
2462 DEBUG ((DEBUG_ERROR, "Failure from platform on OverrideHcInfo, Status = %r\n", Status));\r
2463 return Status;\r
2464 }\r
2465 }\r
2466\r
a71272ed
AM
2467 return EFI_SUCCESS;\r
2468}\r