]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
MdeModulePkg UfsPassThruDxe: Remove redundant functions
[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
0591696e
FT
756\r
757/**\r
758 Start specified slot in transfer list of a UFS device.\r
759\r
760 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
761 @param[in] Slot The slot to be started.\r
762\r
763**/\r
095f0779 764EFI_STATUS\r
0591696e
FT
765UfsStartExecCmd (\r
766 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
767 IN UINT8 Slot\r
d1102dba 768 )\r
0591696e 769{\r
0591696e 770 UINT32 Data;\r
095f0779 771 EFI_STATUS Status;\r
0591696e 772\r
095f0779
FT
773 Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);\r
774 if (EFI_ERROR (Status)) {\r
775 return Status;\r
776 }\r
0591696e 777\r
0591696e 778 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
095f0779
FT
779 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
780 if (EFI_ERROR (Status)) {\r
781 return Status;\r
782 }\r
783 }\r
784\r
785 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);\r
786 if (EFI_ERROR (Status)) {\r
787 return Status;\r
0591696e
FT
788 }\r
789\r
095f0779 790 return EFI_SUCCESS;\r
0591696e
FT
791}\r
792\r
793/**\r
794 Stop specified slot in transfer list of a UFS device.\r
795\r
796 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
797 @param[in] Slot The slot to be stop.\r
798\r
799**/\r
095f0779 800EFI_STATUS\r
0591696e
FT
801UfsStopExecCmd (\r
802 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
803 IN UINT8 Slot\r
d1102dba 804 )\r
0591696e 805{\r
0591696e 806 UINT32 Data;\r
095f0779 807 EFI_STATUS Status;\r
0591696e 808\r
095f0779
FT
809 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);\r
810 if (EFI_ERROR (Status)) {\r
811 return Status;\r
812 }\r
0591696e 813\r
0591696e 814 if ((Data & (BIT0 << Slot)) != 0) {\r
095f0779
FT
815 Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);\r
816 if (EFI_ERROR (Status)) {\r
817 return Status;\r
818 }\r
819\r
820 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));\r
821 if (EFI_ERROR (Status)) {\r
822 return Status;\r
823 }\r
0591696e 824 }\r
095f0779
FT
825\r
826 return EFI_SUCCESS;\r
0591696e
FT
827}\r
828\r
829/**\r
95ad8f7f 830 Extracts return data from query response upiu.\r
0591696e 831\r
95ad8f7f
HW
832 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
833 @param[in] QueryResp Pointer to the query response.\r
0591696e 834\r
95ad8f7f
HW
835 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.\r
836 @retval EFI_SUCCESS Data extracted.\r
0591696e
FT
837\r
838**/\r
839EFI_STATUS\r
95ad8f7f
HW
840UfsGetReturnDataFromQueryResponse (\r
841 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
842 IN UTP_QUERY_RESP_UPIU *QueryResp\r
0591696e
FT
843 )\r
844{\r
95ad8f7f
HW
845 UINT16 ReturnDataSize;\r
846 UINT32 ReturnData;\r
0591696e 847\r
95ad8f7f
HW
848 if (Packet == NULL || QueryResp == NULL) {\r
849 return EFI_INVALID_PARAMETER;\r
850 }\r
0591696e 851\r
95ad8f7f
HW
852 switch (Packet->Opcode) {\r
853 case UtpQueryFuncOpcodeRdDesc:\r
854 ReturnDataSize = QueryResp->Tsf.Length;\r
855 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
856 CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);\r
857 Packet->TransferLength = ReturnDataSize;\r
858 break;\r
859 case UtpQueryFuncOpcodeWrDesc:\r
860 ReturnDataSize = QueryResp->Tsf.Length;\r
861 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
862 Packet->TransferLength = ReturnDataSize;\r
863 break;\r
864 case UtpQueryFuncOpcodeRdFlag:\r
865 case UtpQueryFuncOpcodeSetFlag:\r
866 case UtpQueryFuncOpcodeClrFlag:\r
867 case UtpQueryFuncOpcodeTogFlag:\r
868 CopyMem (Packet->DataBuffer, &QueryResp->Tsf.Value, sizeof (UINT8));\r
869 break;\r
870 case UtpQueryFuncOpcodeRdAttr:\r
871 case UtpQueryFuncOpcodeWrAttr:\r
872 ReturnData = QueryResp->Tsf.Value;\r
873 SwapLittleEndianToBigEndian ((UINT8*) &ReturnData, sizeof (UINT32));\r
874 CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));\r
875 break;\r
876 default:\r
877 return EFI_INVALID_PARAMETER;\r
0591696e 878 }\r
95ad8f7f
HW
879\r
880 return EFI_SUCCESS;\r
881}\r
882\r
883/**\r
884 Creates Transfer Request descriptor and sends Query Request to the device.\r
885\r
886 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
887 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
888\r
889 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
32c9049d
HW
890 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
891 combination to point to a type of UFS device descriptor.\r
95ad8f7f
HW
892 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
893 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
894\r
895**/\r
896EFI_STATUS\r
897UfsSendDmRequestRetry (\r
898 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
899 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
900 )\r
901{\r
902 UINT8 Slot;\r
903 UTP_TRD *Trd;\r
904 VOID *CmdDescHost;\r
905 VOID *CmdDescMapping;\r
906 UINT32 CmdDescSize;\r
907 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
908 UTP_QUERY_RESP_UPIU *QueryResp;\r
909 EFI_STATUS Status;\r
0591696e
FT
910\r
911 //\r
912 // Find out which slot of transfer request list is available.\r
913 //\r
914 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
915 if (EFI_ERROR (Status)) {\r
916 return Status;\r
917 }\r
d1102dba 918\r
0591696e
FT
919 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
920 //\r
921 // Fill transfer request descriptor to this slot.\r
922 //\r
95ad8f7f 923 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
0591696e 924 if (EFI_ERROR (Status)) {\r
95ad8f7f 925 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));\r
0591696e
FT
926 return Status;\r
927 }\r
928\r
0591696e
FT
929 UfsHc = Private->UfsHostController;\r
930 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
931 ASSERT (QueryResp != NULL);\r
932 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
933\r
934 //\r
935 // Start to execute the transfer request.\r
936 //\r
937 UfsStartExecCmd (Private, Slot);\r
938\r
939 //\r
940 // Wait for the completion of the transfer request.\r
95ad8f7f
HW
941 //\r
942 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);\r
0591696e
FT
943 if (EFI_ERROR (Status)) {\r
944 goto Exit;\r
945 }\r
946\r
95ad8f7f
HW
947 if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {\r
948 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));\r
0591696e 949 DumpQueryResponseResult (QueryResp->QueryResp);\r
32c9049d
HW
950\r
951 if ((QueryResp->QueryResp == UfsUtpQueryResponseInvalidSelector) ||\r
952 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIndex) ||\r
953 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIdn)) {\r
954 Status = EFI_INVALID_PARAMETER;\r
955 } else {\r
956 Status = EFI_DEVICE_ERROR;\r
957 }\r
0591696e
FT
958 goto Exit;\r
959 }\r
960\r
95ad8f7f
HW
961 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);\r
962 if (EFI_ERROR (Status)) {\r
963 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));\r
964 goto Exit;\r
0591696e
FT
965 }\r
966\r
967Exit:\r
968 UfsHc->Flush (UfsHc);\r
969\r
970 UfsStopExecCmd (Private, Slot);\r
971\r
972 if (CmdDescMapping != NULL) {\r
973 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
974 }\r
975 if (CmdDescHost != NULL) {\r
976 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
977 }\r
978\r
979 return Status;\r
980}\r
981\r
95ad8f7f
HW
982/**\r
983 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.\r
984\r
985 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
986 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.\r
987\r
988 @retval EFI_SUCCESS The device responded correctly to the Query request.\r
32c9049d
HW
989 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
990 combination to point to a type of UFS device descriptor.\r
95ad8f7f
HW
991 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.\r
992 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.\r
993\r
994**/\r
995EFI_STATUS\r
996UfsSendDmRequest (\r
997 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
998 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
999 )\r
1000{\r
1001 EFI_STATUS Status;\r
1002 UINT8 Retry;\r
1003\r
1004 Status = EFI_SUCCESS;\r
1005\r
1006 for (Retry = 0; Retry < 5; Retry ++) {\r
1007 Status = UfsSendDmRequestRetry (Private, Packet);\r
1008 if (!EFI_ERROR (Status)) {\r
1009 return EFI_SUCCESS;\r
1010 }\r
1011 }\r
1012\r
1013 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));\r
1014 return Status;\r
1015}\r
1016\r
1017/**\r
1018 Read or write specified device descriptor of a UFS device.\r
1019\r
1020 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1021 @param[in] Read The boolean variable to show r/w direction.\r
1022 @param[in] DescId The ID of device descriptor.\r
1023 @param[in] Index The Index of device descriptor.\r
1024 @param[in] Selector The Selector of device descriptor.\r
1025 @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
32c9049d
HW
1026 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,\r
1027 of the data buffer specified by Descriptor. On output, the number\r
1028 of bytes that were actually transferred.\r
95ad8f7f
HW
1029\r
1030 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
32c9049d
HW
1031 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a\r
1032 type of UFS device descriptor.\r
95ad8f7f
HW
1033 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
1034 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
1035\r
1036**/\r
1037EFI_STATUS\r
1038UfsRwDeviceDesc (\r
1039 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1040 IN BOOLEAN Read,\r
1041 IN UINT8 DescId,\r
1042 IN UINT8 Index,\r
1043 IN UINT8 Selector,\r
1044 IN OUT VOID *Descriptor,\r
32c9049d 1045 IN OUT UINT32 *DescSize\r
95ad8f7f
HW
1046 )\r
1047{\r
1048 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
32c9049d
HW
1049 EFI_STATUS Status;\r
1050\r
1051 if (DescSize == NULL) {\r
1052 return EFI_INVALID_PARAMETER;\r
1053 }\r
95ad8f7f
HW
1054\r
1055 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1056\r
1057 if (Read) {\r
1058 Packet.DataDirection = UfsDataIn;\r
1059 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
1060 } else {\r
1061 Packet.DataDirection = UfsDataOut;\r
1062 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
1063 }\r
1064 Packet.DataBuffer = Descriptor;\r
32c9049d 1065 Packet.TransferLength = *DescSize;\r
95ad8f7f
HW
1066 Packet.DescId = DescId;\r
1067 Packet.Index = Index;\r
1068 Packet.Selector = Selector;\r
1069 Packet.Timeout = UFS_TIMEOUT;\r
1070\r
32c9049d
HW
1071 Status = UfsSendDmRequest (Private, &Packet);\r
1072 if (EFI_ERROR (Status)) {\r
1073 *DescSize = 0;\r
1074 } else {\r
1075 *DescSize = Packet.TransferLength;\r
1076 }\r
1077\r
1078 return Status;\r
95ad8f7f
HW
1079}\r
1080\r
0591696e
FT
1081/**\r
1082 Read or write specified attribute of a UFS device.\r
1083\r
1084 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1085 @param[in] Read The boolean variable to show r/w direction.\r
1086 @param[in] AttrId The ID of Attribute.\r
1087 @param[in] Index The Index of Attribute.\r
1088 @param[in] Selector The Selector of Attribute.\r
1089 @param[in, out] Attributes The value of Attribute to be read or written.\r
1090\r
1091 @retval EFI_SUCCESS The Attribute was read/written successfully.\r
32c9049d
HW
1092 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a\r
1093 type of UFS device descriptor.\r
0591696e
FT
1094 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.\r
1095 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.\r
1096\r
1097**/\r
1098EFI_STATUS\r
1099UfsRwAttributes (\r
1100 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1101 IN BOOLEAN Read,\r
1102 IN UINT8 AttrId,\r
1103 IN UINT8 Index,\r
1104 IN UINT8 Selector,\r
1105 IN OUT UINT32 *Attributes\r
1106 )\r
1107{\r
0591696e 1108 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1109\r
1110 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1111\r
1112 if (Read) {\r
1113 Packet.DataDirection = UfsDataIn;\r
1114 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;\r
1115 } else {\r
1116 Packet.DataDirection = UfsDataOut;\r
1117 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;\r
1118 }\r
95ad8f7f 1119 Packet.DataBuffer = Attributes;\r
0591696e
FT
1120 Packet.DescId = AttrId;\r
1121 Packet.Index = Index;\r
1122 Packet.Selector = Selector;\r
1123 Packet.Timeout = UFS_TIMEOUT;\r
1124\r
95ad8f7f 1125 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1126}\r
1127\r
1128/**\r
1129 Read or write specified flag of a UFS device.\r
1130\r
1131 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1132 @param[in] Read The boolean variable to show r/w direction.\r
1133 @param[in] FlagId The ID of flag to be read or written.\r
1134 @param[in, out] Value The value to set or clear flag.\r
1135\r
1136 @retval EFI_SUCCESS The flag was read/written successfully.\r
32c9049d 1137 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.\r
0591696e
FT
1138 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.\r
1139 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.\r
1140\r
1141**/\r
1142EFI_STATUS\r
1143UfsRwFlags (\r
1144 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1145 IN BOOLEAN Read,\r
1146 IN UINT8 FlagId,\r
1147 IN OUT UINT8 *Value\r
1148 )\r
1149{\r
0591696e 1150 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1151\r
1152 if (Value == NULL) {\r
1153 return EFI_INVALID_PARAMETER;\r
1154 }\r
1155\r
1156 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1157\r
1158 if (Read) {\r
1159 ASSERT (Value != NULL);\r
1160 Packet.DataDirection = UfsDataIn;\r
1161 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
1162 } else {\r
1163 Packet.DataDirection = UfsDataOut;\r
1164 if (*Value == 1) {\r
1165 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
1166 } else if (*Value == 0) {\r
1167 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;\r
1168 } else {\r
1169 return EFI_INVALID_PARAMETER;\r
1170 }\r
1171 }\r
95ad8f7f 1172 Packet.DataBuffer = Value;\r
0591696e
FT
1173 Packet.DescId = FlagId;\r
1174 Packet.Index = 0;\r
1175 Packet.Selector = 0;\r
1176 Packet.Timeout = UFS_TIMEOUT;\r
1177\r
95ad8f7f 1178 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1179}\r
1180\r
1181/**\r
1182 Set specified flag to 1 on a UFS device.\r
1183\r
1184 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1185 @param[in] FlagId The ID of flag to be set.\r
1186\r
1187 @retval EFI_SUCCESS The flag was set successfully.\r
1188 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.\r
1189 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.\r
1190\r
1191**/\r
1192EFI_STATUS\r
1193UfsSetFlag (\r
1194 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1195 IN UINT8 FlagId\r
1196 )\r
1197{\r
1198 EFI_STATUS Status;\r
1199 UINT8 Value;\r
1200\r
1201 Value = 1;\r
1202 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1203\r
1204 return Status;\r
1205}\r
1206\r
0591696e 1207\r
0591696e
FT
1208\r
1209/**\r
1210 Read specified flag from a UFS device.\r
1211\r
1212 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1213 @param[in] FlagId The ID of flag to be read.\r
1214 @param[out] Value The flag's value.\r
1215\r
1216 @retval EFI_SUCCESS The flag was read successfully.\r
1217 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.\r
1218 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.\r
1219\r
1220**/\r
1221EFI_STATUS\r
1222UfsReadFlag (\r
1223 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1224 IN UINT8 FlagId,\r
1225 OUT UINT8 *Value\r
1226 )\r
1227{\r
1228 EFI_STATUS Status;\r
1229\r
1230 Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
1231\r
1232 return Status;\r
1233}\r
1234\r
1235/**\r
1236 Sends NOP IN cmd to a UFS device for initialization process request.\r
1237 For more details, please refer to UFS 2.0 spec Figure 13.3.\r
1238\r
1239 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1240\r
1241 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was\r
1242 received successfully.\r
1243 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.\r
1244 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1245 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.\r
1246\r
1247**/\r
1248EFI_STATUS\r
1249UfsExecNopCmds (\r
1250 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1251 )\r
1252{\r
1253 EFI_STATUS Status;\r
1254 UINT8 Slot;\r
1255 UTP_TRD *Trd;\r
1256 UTP_NOP_IN_UPIU *NopInUpiu;\r
1257 UINT32 CmdDescSize;\r
0591696e
FT
1258 VOID *CmdDescHost;\r
1259 VOID *CmdDescMapping;\r
1260 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1261\r
1262 //\r
1263 // Find out which slot of transfer request list is available.\r
1264 //\r
1265 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1266 if (EFI_ERROR (Status)) {\r
1267 return Status;\r
1268 }\r
1269\r
1270 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1271 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);\r
1272 if (EFI_ERROR (Status)) {\r
1273 return Status;\r
1274 }\r
1275\r
1276 //\r
1277 // Check the transfer request result.\r
1278 //\r
1279 UfsHc = Private->UfsHostController;\r
1280 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
1281 ASSERT (NopInUpiu != NULL);\r
1282 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1283\r
1284 //\r
1285 // Start to execute the transfer request.\r
1286 //\r
1287 UfsStartExecCmd (Private, Slot);\r
1288\r
1289 //\r
1290 // Wait for the completion of the transfer request.\r
d1102dba 1291 //\r
13fca387 1292 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);\r
0591696e
FT
1293 if (EFI_ERROR (Status)) {\r
1294 goto Exit;\r
1295 }\r
1296\r
1297 if (NopInUpiu->Resp != 0) {\r
1298 Status = EFI_DEVICE_ERROR;\r
1299 } else {\r
1300 Status = EFI_SUCCESS;\r
1301 }\r
1302\r
1303Exit:\r
1304 UfsHc->Flush (UfsHc);\r
1305\r
1306 UfsStopExecCmd (Private, Slot);\r
1307\r
1308 if (CmdDescMapping != NULL) {\r
1309 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1310 }\r
1311 if (CmdDescHost != NULL) {\r
1312 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1313 }\r
1314\r
1315 return Status;\r
1316}\r
1317\r
1318/**\r
1319 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
1320\r
1321 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1322 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.\r
1323 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the\r
1324 UFS device.\r
0350b57c
HW
1325 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking\r
1326 I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
1327 Event is not NULL and non blocking I/O is supported, then\r
1328 nonblocking I/O is performed, and Event will be signaled when the\r
1329 SCSI Request Packet completes.\r
0591696e
FT
1330\r
1331 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional\r
1332 commands, InTransferLength bytes were transferred from\r
1333 InDataBuffer. For write and bi-directional commands,\r
1334 OutTransferLength bytes were transferred by\r
1335 OutDataBuffer.\r
1336 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request\r
1337 Packet.\r
1338 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1339 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
1340\r
1341**/\r
1342EFI_STATUS\r
1343UfsExecScsiCmds (\r
1344 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1345 IN UINT8 Lun,\r
0350b57c
HW
1346 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
1347 IN EFI_EVENT Event OPTIONAL\r
0591696e
FT
1348 )\r
1349{\r
1350 EFI_STATUS Status;\r
0591696e
FT
1351 UTP_RESPONSE_UPIU *Response;\r
1352 UINT16 SenseDataLen;\r
1353 UINT32 ResTranCount;\r
0591696e
FT
1354 VOID *DataBuf;\r
1355 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;\r
1356 UINT32 DataLen;\r
1357 UINTN MapLength;\r
1358 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1359 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;\r
0591696e 1360 UTP_TR_PRD *PrdtBase;\r
0350b57c
HW
1361 EFI_TPL OldTpl;\r
1362 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
0591696e 1363\r
0350b57c
HW
1364 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));\r
1365 if (TransReq == NULL) {\r
1366 return EFI_OUT_OF_RESOURCES;\r
1367 }\r
1368\r
1369 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;\r
1370 TransReq->TimeoutRemain = Packet->Timeout;\r
0591696e
FT
1371 DataBufPhyAddr = 0;\r
1372 UfsHc = Private->UfsHostController;\r
1373 //\r
1374 // Find out which slot of transfer request list is available.\r
1375 //\r
0350b57c 1376 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);\r
0591696e
FT
1377 if (EFI_ERROR (Status)) {\r
1378 return Status;\r
1379 }\r
1380\r
0350b57c 1381 TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;\r
0591696e
FT
1382\r
1383 //\r
1384 // Fill transfer request descriptor to this slot.\r
1385 //\r
0350b57c
HW
1386 Status = UfsCreateScsiCommandDesc (\r
1387 Private,\r
1388 Lun,\r
1389 Packet,\r
1390 TransReq->Trd,\r
1391 &TransReq->CmdDescHost,\r
1392 &TransReq->CmdDescMapping\r
1393 );\r
0591696e
FT
1394 if (EFI_ERROR (Status)) {\r
1395 return Status;\r
1396 }\r
1397\r
0350b57c 1398 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);\r
0591696e
FT
1399\r
1400 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1401 DataBuf = Packet->InDataBuffer;\r
1402 DataLen = Packet->InTransferLength;\r
0591696e
FT
1403 Flag = EdkiiUfsHcOperationBusMasterWrite;\r
1404 } else {\r
1405 DataBuf = Packet->OutDataBuffer;\r
1406 DataLen = Packet->OutTransferLength;\r
0591696e
FT
1407 Flag = EdkiiUfsHcOperationBusMasterRead;\r
1408 }\r
1409\r
59ddab7e 1410 if (DataLen != 0) {\r
0591696e
FT
1411 MapLength = DataLen;\r
1412 Status = UfsHc->Map (\r
1413 UfsHc,\r
1414 Flag,\r
1415 DataBuf,\r
1416 &MapLength,\r
1417 &DataBufPhyAddr,\r
0350b57c 1418 &TransReq->DataBufMapping\r
0591696e
FT
1419 );\r
1420\r
1421 if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
1422 goto Exit1;\r
1423 }\r
1424 }\r
1425 //\r
1426 // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
1427 //\r
0350b57c 1428 PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
0591696e
FT
1429 ASSERT (PrdtBase != NULL);\r
1430 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);\r
1431\r
0350b57c
HW
1432 //\r
1433 // Insert the async SCSI cmd to the Async I/O list\r
1434 //\r
1435 if (Event != NULL) {\r
7e4632a3 1436 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
0350b57c
HW
1437 TransReq->Packet = Packet;\r
1438 TransReq->CallerEvent = Event;\r
1439 InsertTailList (&Private->Queue, &TransReq->TransferList);\r
1440 gBS->RestoreTPL (OldTpl);\r
1441 }\r
1442\r
0591696e
FT
1443 //\r
1444 // Start to execute the transfer request.\r
1445 //\r
0350b57c
HW
1446 UfsStartExecCmd (Private, TransReq->Slot);\r
1447\r
1448 //\r
1449 // Immediately return for async I/O.\r
1450 //\r
1451 if (Event != NULL) {\r
1452 return EFI_SUCCESS;\r
1453 }\r
0591696e
FT
1454\r
1455 //\r
1456 // Wait for the completion of the transfer request.\r
d1102dba 1457 //\r
13fca387 1458 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);\r
0591696e
FT
1459 if (EFI_ERROR (Status)) {\r
1460 goto Exit;\r
1461 }\r
1462\r
1463 //\r
1464 // Get sense data if exists\r
1465 //\r
0350b57c 1466 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
0591696e
FT
1467 ASSERT (Response != NULL);\r
1468 SenseDataLen = Response->SenseDataLen;\r
1469 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
d1102dba 1470\r
0591696e
FT
1471 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
1472 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
1473 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
1474 }\r
1475\r
1476 //\r
1477 // Check the transfer request result.\r
1478 //\r
1479 Packet->TargetStatus = Response->Status;\r
1480 if (Response->Response != 0) {\r
edd94e74 1481 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
0591696e
FT
1482 Status = EFI_DEVICE_ERROR;\r
1483 goto Exit;\r
1484 }\r
1485\r
0350b57c 1486 if (TransReq->Trd->Ocs == 0) {\r
0591696e
FT
1487 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1488 if ((Response->Flags & BIT5) == BIT5) {\r
1489 ResTranCount = Response->ResTranCount;\r
1490 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1491 Packet->InTransferLength -= ResTranCount;\r
1492 }\r
1493 } else {\r
1494 if ((Response->Flags & BIT5) == BIT5) {\r
1495 ResTranCount = Response->ResTranCount;\r
1496 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1497 Packet->OutTransferLength -= ResTranCount;\r
1498 }\r
1499 }\r
1500 } else {\r
1501 Status = EFI_DEVICE_ERROR;\r
1502 }\r
1503\r
1504Exit:\r
1505 UfsHc->Flush (UfsHc);\r
1506\r
0350b57c 1507 UfsStopExecCmd (Private, TransReq->Slot);\r
0591696e 1508\r
0350b57c
HW
1509 if (TransReq->DataBufMapping != NULL) {\r
1510 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);\r
0591696e
FT
1511 }\r
1512\r
1513Exit1:\r
0350b57c
HW
1514 if (TransReq->CmdDescMapping != NULL) {\r
1515 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
0591696e 1516 }\r
0350b57c
HW
1517 if (TransReq->CmdDescHost != NULL) {\r
1518 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);\r
1519 }\r
1520 if (TransReq != NULL) {\r
1521 FreePool (TransReq);\r
0591696e
FT
1522 }\r
1523 return Status;\r
1524}\r
1525\r
1526\r
1527/**\r
1528 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
1529\r
1530 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1531 @param[in] UicOpcode The opcode of the UIC command.\r
1532 @param[in] Arg1 The value for 1st argument of the UIC command.\r
1533 @param[in] Arg2 The value for 2nd argument of the UIC command.\r
1534 @param[in] Arg3 The value for 3rd argument of the UIC command.\r
1535\r
1536 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.\r
1537 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
1538 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.\r
1539\r
1540**/\r
1541EFI_STATUS\r
1542UfsExecUicCommands (\r
1543 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1544 IN UINT8 UicOpcode,\r
1545 IN UINT32 Arg1,\r
1546 IN UINT32 Arg2,\r
1547 IN UINT32 Arg3\r
1548 )\r
1549{\r
1550 EFI_STATUS Status;\r
0591696e 1551 UINT32 Data;\r
0591696e 1552\r
095f0779
FT
1553 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);\r
1554 if (EFI_ERROR (Status)) {\r
1555 return Status;\r
1556 }\r
1557\r
0591696e
FT
1558 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
1559 //\r
1560 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
1561 //\r
095f0779
FT
1562 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);\r
1563 if (EFI_ERROR (Status)) {\r
1564 return Status;\r
1565 }\r
0591696e
FT
1566 }\r
1567\r
1568 //\r
1569 // When programming UIC command registers, host software shall set the register UICCMD\r
1570 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
1571 // are set.\r
1572 //\r
095f0779
FT
1573 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, Arg1);\r
1574 if (EFI_ERROR (Status)) {\r
1575 return Status;\r
1576 }\r
0591696e 1577\r
095f0779
FT
1578 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, Arg2);\r
1579 if (EFI_ERROR (Status)) {\r
1580 return Status;\r
1581 }\r
0591696e 1582\r
095f0779
FT
1583 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, Arg3);\r
1584 if (EFI_ERROR (Status)) {\r
1585 return Status;\r
1586 }\r
0591696e
FT
1587\r
1588 //\r
1589 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
1590 //\r
095f0779 1591 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
0591696e
FT
1592 if (EFI_ERROR (Status)) {\r
1593 return Status;\r
1594 }\r
1595\r
095f0779
FT
1596 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, (UINT32)UicOpcode);\r
1597 if (EFI_ERROR (Status)) {\r
1598 return Status;\r
1599 }\r
0591696e
FT
1600\r
1601 //\r
1602 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
d1102dba 1603 // This bit is set to '1' by the host controller upon completion of a UIC command.\r
0591696e 1604 //\r
095f0779 1605 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
0591696e
FT
1606 if (EFI_ERROR (Status)) {\r
1607 return Status;\r
1608 }\r
1609\r
1610 if (UicOpcode != UfsUicDmeReset) {\r
095f0779
FT
1611 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &Data);\r
1612 if (EFI_ERROR (Status)) {\r
1613 return Status;\r
1614 }\r
0591696e
FT
1615 if ((Data & 0xFF) != 0) {\r
1616 DEBUG_CODE_BEGIN();\r
1617 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
1618 DEBUG_CODE_END();\r
1619 return EFI_DEVICE_ERROR;\r
1620 }\r
1621 }\r
1622\r
1623 //\r
1624 // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
1625 //\r
095f0779
FT
1626 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);\r
1627 if (EFI_ERROR (Status)) {\r
1628 return Status;\r
1629 }\r
1630\r
0591696e 1631 if ((Data & UFS_HC_HCS_DP) == 0) {\r
095f0779 1632 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
0591696e
FT
1633 if (EFI_ERROR (Status)) {\r
1634 return EFI_DEVICE_ERROR;\r
1635 }\r
1636 return EFI_NOT_FOUND;\r
1637 }\r
1638\r
edd94e74 1639 DEBUG ((DEBUG_INFO, "UfsPassThruDxe: found a attached UFS device\n"));\r
0591696e
FT
1640\r
1641 return EFI_SUCCESS;\r
1642}\r
1643\r
1644/**\r
1645 Allocate common buffer for host and UFS bus master access simultaneously.\r
1646\r
1647 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1648 @param[in] Size The length of buffer to be allocated.\r
1649 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
1650 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.\r
1651 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
1652\r
1653 @retval EFI_SUCCESS The common buffer was allocated successfully.\r
1654 @retval EFI_DEVICE_ERROR The allocation fails.\r
1655 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
1656\r
1657**/\r
1658EFI_STATUS\r
1659UfsAllocateAlignCommonBuffer (\r
1660 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1661 IN UINTN Size,\r
1662 OUT VOID **CmdDescHost,\r
1663 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,\r
1664 OUT VOID **CmdDescMapping\r
1665 )\r
1666{\r
1667 EFI_STATUS Status;\r
1668 UINTN Bytes;\r
1669 BOOLEAN Is32BitAddr;\r
1670 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1671\r
1672 if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
0591696e 1673 Is32BitAddr = FALSE;\r
a2e3feb6
HZ
1674 } else {\r
1675 Is32BitAddr = TRUE;\r
0591696e
FT
1676 }\r
1677\r
1678 UfsHc = Private->UfsHostController;\r
1679 Status = UfsHc->AllocateBuffer (\r
1680 UfsHc,\r
1681 AllocateAnyPages,\r
1682 EfiBootServicesData,\r
1683 EFI_SIZE_TO_PAGES (Size),\r
1684 CmdDescHost,\r
1685 0\r
1686 );\r
1687 if (EFI_ERROR (Status)) {\r
1688 *CmdDescMapping = NULL;\r
1689 *CmdDescHost = NULL;\r
1690 *CmdDescPhyAddr = 0;\r
1691 return EFI_OUT_OF_RESOURCES;\r
1692 }\r
1693\r
1694 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));\r
1695 Status = UfsHc->Map (\r
1696 UfsHc,\r
1697 EdkiiUfsHcOperationBusMasterCommonBuffer,\r
1698 *CmdDescHost,\r
1699 &Bytes,\r
1700 CmdDescPhyAddr,\r
1701 CmdDescMapping\r
1702 );\r
1703\r
1704 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {\r
1705 UfsHc->FreeBuffer (\r
1706 UfsHc,\r
1707 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1708 *CmdDescHost\r
1709 );\r
1710 *CmdDescHost = NULL;\r
1711 return EFI_OUT_OF_RESOURCES;\r
1712 }\r
1713\r
1714 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {\r
1715 //\r
1716 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.\r
1717 //\r
1718 UfsHc->Unmap (\r
1719 UfsHc,\r
1720 *CmdDescMapping\r
1721 );\r
1722 UfsHc->FreeBuffer (\r
1723 UfsHc,\r
1724 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1725 *CmdDescHost\r
1726 );\r
1727 *CmdDescMapping = NULL;\r
1728 *CmdDescHost = NULL;\r
1729 return EFI_DEVICE_ERROR;\r
1730 }\r
1731\r
1732 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));\r
1733 return EFI_SUCCESS;\r
1734}\r
1735\r
1736/**\r
1737 Enable the UFS host controller for accessing.\r
1738\r
1739 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1740\r
1741 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1742 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1743\r
1744**/\r
1745EFI_STATUS\r
1746UfsEnableHostController (\r
1747 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1748 )\r
1749{\r
1750 EFI_STATUS Status;\r
0591696e
FT
1751 UINT32 Data;\r
1752\r
1753 //\r
1754 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1755 //\r
1756 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1757 //\r
095f0779
FT
1758 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
1759 if (EFI_ERROR (Status)) {\r
1760 return Status;\r
1761 }\r
1762\r
0591696e
FT
1763 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1764 //\r
1765 // Write a 0 to the HCE register at first to disable the host controller.\r
1766 //\r
095f0779
FT
1767 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
1768 if (EFI_ERROR (Status)) {\r
1769 return Status;\r
1770 }\r
0591696e
FT
1771 //\r
1772 // Wait until HCE is read as '0' before continuing.\r
1773 //\r
095f0779 1774 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
1775 if (EFI_ERROR (Status)) {\r
1776 return EFI_DEVICE_ERROR;\r
1777 }\r
1778 }\r
1779\r
1780 //\r
1781 // Write a 1 to the HCE register to enable the UFS host controller.\r
1782 //\r
095f0779
FT
1783 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);\r
1784 if (EFI_ERROR (Status)) {\r
1785 return Status;\r
1786 }\r
1787\r
0591696e
FT
1788 //\r
1789 // Wait until HCE is read as '1' before continuing.\r
1790 //\r
095f0779 1791 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
0591696e
FT
1792 if (EFI_ERROR (Status)) {\r
1793 return EFI_DEVICE_ERROR;\r
1794 }\r
1795\r
1796 return EFI_SUCCESS;\r
1797}\r
1798\r
1799/**\r
1800 Detect if a UFS device attached.\r
1801\r
1802 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1803\r
1804 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1805 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1806 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1807\r
1808**/\r
1809EFI_STATUS\r
1810UfsDeviceDetection (\r
1811 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1812 )\r
1813{\r
1814 UINTN Retry;\r
1815 EFI_STATUS Status;\r
1816\r
1817 //\r
1818 // Start UFS device detection.\r
1819 // Try up to 3 times for establishing data link with device.\r
1820 //\r
1821 for (Retry = 0; Retry < 3; Retry++) {\r
1822 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
1823 if (!EFI_ERROR (Status)) {\r
1824 break;\r
1825 }\r
1826\r
1827 if (Status == EFI_NOT_FOUND) {\r
1828 continue;\r
1829 }\r
1830\r
1831 return EFI_DEVICE_ERROR;\r
1832 }\r
1833\r
1834 if (Retry == 3) {\r
1835 return EFI_NOT_FOUND;\r
1836 }\r
1837\r
1838 return EFI_SUCCESS;\r
1839}\r
1840\r
1841/**\r
1842 Initialize UFS task management request list related h/w context.\r
1843\r
1844 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1845\r
1846 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1847 @retval EFI_DEVICE_ERROR The initialization fails.\r
1848\r
1849**/\r
1850EFI_STATUS\r
1851UfsInitTaskManagementRequestList (\r
1852 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1853 )\r
1854{\r
0591696e
FT
1855 UINT32 Data;\r
1856 UINT8 Nutmrs;\r
1857 VOID *CmdDescHost;\r
1858 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1859 VOID *CmdDescMapping;\r
1860 EFI_STATUS Status;\r
d1102dba 1861\r
0591696e
FT
1862 //\r
1863 // Initial h/w and s/w context for future operations.\r
1864 //\r
1865 CmdDescHost = NULL;\r
1866 CmdDescMapping = NULL;\r
1867 CmdDescPhyAddr = 0;\r
095f0779
FT
1868\r
1869 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
1870 if (EFI_ERROR (Status)) {\r
1871 return Status;\r
1872 }\r
1873\r
0591696e
FT
1874 Private->Capabilities = Data;\r
1875\r
1876 //\r
1877 // Allocate and initialize UTP Task Management Request List.\r
1878 //\r
1879 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
1880 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
1881 if (EFI_ERROR (Status)) {\r
1882 return Status;\r
1883 }\r
1884\r
1885 //\r
1886 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
1887 // Request List Base Address with a 64-bit address allocated at step 6.\r
1888 //\r
095f0779
FT
1889 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
1890 if (EFI_ERROR (Status)) {\r
1891 return Status;\r
1892 }\r
1893\r
1894 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1895 if (EFI_ERROR (Status)) {\r
1896 return Status;\r
1897 }\r
0591696e
FT
1898 Private->UtpTmrlBase = CmdDescHost;\r
1899 Private->Nutmrs = Nutmrs;\r
1900 Private->TmrlMapping = CmdDescMapping;\r
1901\r
1902 //\r
1903 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1904 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1905 //\r
095f0779
FT
1906 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);\r
1907 if (EFI_ERROR (Status)) {\r
1908 return Status;\r
1909 }\r
0591696e
FT
1910\r
1911 return EFI_SUCCESS;\r
1912}\r
1913\r
1914/**\r
1915 Initialize UFS transfer request list related h/w context.\r
1916\r
1917 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1918\r
1919 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
1920 @retval EFI_DEVICE_ERROR The initialization fails.\r
1921\r
1922**/\r
1923EFI_STATUS\r
1924UfsInitTransferRequestList (\r
1925 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1926 )\r
1927{\r
0591696e
FT
1928 UINT32 Data;\r
1929 UINT8 Nutrs;\r
1930 VOID *CmdDescHost;\r
1931 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
d1102dba 1932 VOID *CmdDescMapping;\r
0591696e
FT
1933 EFI_STATUS Status;\r
1934\r
1935 //\r
1936 // Initial h/w and s/w context for future operations.\r
1937 //\r
1938 CmdDescHost = NULL;\r
1939 CmdDescMapping = NULL;\r
1940 CmdDescPhyAddr = 0;\r
095f0779
FT
1941\r
1942 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
1943 if (EFI_ERROR (Status)) {\r
1944 return Status;\r
1945 }\r
1946\r
0591696e
FT
1947 Private->Capabilities = Data;\r
1948\r
1949 //\r
1950 // Allocate and initialize UTP Transfer Request List.\r
1951 //\r
1952 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
1953 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
1954 if (EFI_ERROR (Status)) {\r
1955 return Status;\r
1956 }\r
1957\r
1958 //\r
1959 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
1960 // Base Address with a 64-bit address allocated at step 8.\r
1961 //\r
095f0779
FT
1962 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
1963 if (EFI_ERROR (Status)) {\r
1964 return Status;\r
1965 }\r
1966\r
1967 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1968 if (EFI_ERROR (Status)) {\r
1969 return Status;\r
1970 }\r
1971\r
0591696e 1972 Private->UtpTrlBase = CmdDescHost;\r
d1102dba 1973 Private->Nutrs = Nutrs;\r
0591696e
FT
1974 Private->TrlMapping = CmdDescMapping;\r
1975\r
1976 //\r
1977 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1978 // RunStop Register (UTRLRSR) to '1'.\r
1979 //\r
095f0779
FT
1980 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
1981 if (EFI_ERROR (Status)) {\r
1982 return Status;\r
1983 }\r
0591696e
FT
1984\r
1985 return EFI_SUCCESS;\r
1986}\r
1987\r
1988/**\r
1989 Initialize the UFS host controller.\r
1990\r
1991 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1992\r
1993 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
1994 @retval Others A device error occurred while initializing the controller.\r
1995\r
1996**/\r
1997EFI_STATUS\r
1998UfsControllerInit (\r
1999 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2000 )\r
2001{\r
2002 EFI_STATUS Status;\r
2003\r
2004 Status = UfsEnableHostController (Private);\r
2005 if (EFI_ERROR (Status)) {\r
edd94e74 2006 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));\r
0591696e
FT
2007 return Status;\r
2008 }\r
2009\r
2010 Status = UfsDeviceDetection (Private);\r
2011 if (EFI_ERROR (Status)) {\r
edd94e74 2012 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));\r
0591696e
FT
2013 return Status;\r
2014 }\r
2015\r
2016 Status = UfsInitTaskManagementRequestList (Private);\r
2017 if (EFI_ERROR (Status)) {\r
edd94e74 2018 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2019 return Status;\r
2020 }\r
2021\r
2022 Status = UfsInitTransferRequestList (Private);\r
2023 if (EFI_ERROR (Status)) {\r
edd94e74 2024 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2025 return Status;\r
2026 }\r
2027\r
edd94e74 2028 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));\r
0591696e
FT
2029 return EFI_SUCCESS;\r
2030}\r
2031\r
2032/**\r
2033 Stop the UFS host controller.\r
2034\r
2035 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2036\r
2037 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
2038 @retval Others A device error occurred while stopping the controller.\r
2039\r
2040**/\r
2041EFI_STATUS\r
2042UfsControllerStop (\r
2043 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2044 )\r
2045{\r
2046 EFI_STATUS Status;\r
0591696e
FT
2047 UINT32 Data;\r
2048\r
2049 //\r
2050 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
2051 // Request List RunStop Register (UTMRLRSR) to '1'.\r
2052 //\r
095f0779
FT
2053 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);\r
2054 if (EFI_ERROR (Status)) {\r
2055 return Status;\r
2056 }\r
0591696e
FT
2057\r
2058 //\r
2059 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
2060 // RunStop Register (UTRLRSR) to '1'.\r
2061 //\r
095f0779
FT
2062 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);\r
2063 if (EFI_ERROR (Status)) {\r
2064 return Status;\r
2065 }\r
0591696e
FT
2066\r
2067 //\r
2068 // Write a 0 to the HCE register in order to disable the host controller.\r
2069 //\r
095f0779
FT
2070 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
2071 if (EFI_ERROR (Status)) {\r
2072 return Status;\r
2073 }\r
0591696e 2074 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
095f0779
FT
2075\r
2076 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
2077 if (EFI_ERROR (Status)) {\r
2078 return Status;\r
2079 }\r
0591696e
FT
2080\r
2081 //\r
2082 // Wait until HCE is read as '0' before continuing.\r
2083 //\r
095f0779 2084 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
2085 if (EFI_ERROR (Status)) {\r
2086 return EFI_DEVICE_ERROR;\r
2087 }\r
2088\r
edd94e74 2089 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));\r
0591696e
FT
2090\r
2091 return EFI_SUCCESS;\r
2092}\r
2093\r
0350b57c
HW
2094\r
2095/**\r
2096 Internal helper function which will signal the caller event and clean up\r
2097 resources.\r
2098\r
2099 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data\r
2100 structure.\r
2101 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data\r
2102 structure.\r
2103\r
2104**/\r
2105VOID\r
2106EFIAPI\r
2107SignalCallerEvent (\r
2108 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
2109 IN UFS_PASS_THRU_TRANS_REQ *TransReq\r
2110 )\r
2111{\r
2112 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
2113 EFI_EVENT CallerEvent;\r
2114\r
33e2ba78
HW
2115 ASSERT ((Private != NULL) && (TransReq != NULL));\r
2116\r
0350b57c
HW
2117 UfsHc = Private->UfsHostController;\r
2118 CallerEvent = TransReq->CallerEvent;\r
2119\r
2120 RemoveEntryList (&TransReq->TransferList);\r
2121\r
2122 UfsHc->Flush (UfsHc);\r
2123\r
2124 UfsStopExecCmd (Private, TransReq->Slot);\r
2125\r
2126 if (TransReq->DataBufMapping != NULL) {\r
2127 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);\r
2128 }\r
2129\r
2130 if (TransReq->CmdDescMapping != NULL) {\r
2131 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
2132 }\r
2133 if (TransReq->CmdDescHost != NULL) {\r
2134 UfsHc->FreeBuffer (\r
2135 UfsHc,\r
2136 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),\r
2137 TransReq->CmdDescHost\r
2138 );\r
2139 }\r
33e2ba78
HW
2140\r
2141 FreePool (TransReq);\r
0350b57c
HW
2142\r
2143 gBS->SignalEvent (CallerEvent);\r
2144 return;\r
2145}\r
2146\r
2147/**\r
2148 Call back function when the timer event is signaled.\r
2149\r
2150 @param[in] Event The Event this notify function registered to.\r
2151 @param[in] Context Pointer to the context data registered to the Event.\r
2152\r
2153**/\r
2154VOID\r
2155EFIAPI\r
2156ProcessAsyncTaskList (\r
2157 IN EFI_EVENT Event,\r
2158 IN VOID *Context\r
2159 )\r
2160{\r
2161 UFS_PASS_THRU_PRIVATE_DATA *Private;\r
2162 LIST_ENTRY *Entry;\r
2163 LIST_ENTRY *NextEntry;\r
2164 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
2165 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;\r
2166 UTP_RESPONSE_UPIU *Response;\r
2167 UINT16 SenseDataLen;\r
2168 UINT32 ResTranCount;\r
2169 UINT32 SlotsMap;\r
2170 UINT32 Value;\r
2171 EFI_STATUS Status;\r
2172\r
2173 Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;\r
2174 SlotsMap = 0;\r
2175\r
2176 //\r
2177 // Check the entries in the async I/O queue are done or not.\r
2178 //\r
2179 if (!IsListEmpty(&Private->Queue)) {\r
2180 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {\r
2181 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);\r
2182 Packet = TransReq->Packet;\r
2183\r
2184 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {\r
2185 return;\r
2186 }\r
2187 SlotsMap |= BIT0 << TransReq->Slot;\r
2188\r
2189 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);\r
2190 if (EFI_ERROR (Status)) {\r
2191 //\r
2192 // TODO: Should find/add a proper host adapter return status for this\r
2193 // case.\r
2194 //\r
2195 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;\r
edd94e74 2196 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2197 SignalCallerEvent (Private, TransReq);\r
2198 continue;\r
2199 }\r
2200\r
2201 if ((Value & (BIT0 << TransReq->Slot)) != 0) {\r
2202 //\r
2203 // Scsi cmd not finished yet.\r
2204 //\r
2205 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {\r
2206 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;\r
2207 continue;\r
2208 } else {\r
2209 //\r
2210 // Timeout occurs.\r
2211 //\r
2212 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;\r
edd94e74 2213 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));\r
0350b57c
HW
2214 SignalCallerEvent (Private, TransReq);\r
2215 continue;\r
2216 }\r
2217 } else {\r
2218 //\r
2219 // Scsi cmd finished.\r
2220 //\r
2221 // Get sense data if exists\r
2222 //\r
2223 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
2224 ASSERT (Response != NULL);\r
2225 SenseDataLen = Response->SenseDataLen;\r
2226 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
2227\r
2228 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
2229 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
2230 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
2231 }\r
2232\r
2233 //\r
2234 // Check the transfer request result.\r
2235 //\r
2236 Packet->TargetStatus = Response->Status;\r
2237 if (Response->Response != 0) {\r
edd94e74 2238 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));\r
0350b57c
HW
2239 SignalCallerEvent (Private, TransReq);\r
2240 continue;\r
2241 }\r
2242\r
2243 if (TransReq->Trd->Ocs == 0) {\r
2244 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
2245 if ((Response->Flags & BIT5) == BIT5) {\r
2246 ResTranCount = Response->ResTranCount;\r
2247 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
2248 Packet->InTransferLength -= ResTranCount;\r
2249 }\r
2250 } else {\r
2251 if ((Response->Flags & BIT5) == BIT5) {\r
2252 ResTranCount = Response->ResTranCount;\r
2253 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
2254 Packet->OutTransferLength -= ResTranCount;\r
2255 }\r
2256 }\r
2257 } else {\r
edd94e74 2258 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2259 SignalCallerEvent (Private, TransReq);\r
2260 continue;\r
2261 }\r
2262\r
edd94e74 2263 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));\r
0350b57c
HW
2264 SignalCallerEvent (Private, TransReq);\r
2265 }\r
2266 }\r
2267 }\r
2268}\r
2269\r