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