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