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