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