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