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