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