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