]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
MdeModulePkg/PciBusDxe: Remove unused variable assignment
[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
5 Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
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
18/**\r
19 Wait for the value of the specified system memory set to the test value.\r
20\r
21 @param Address The system memory address to test.\r
22 @param MaskValue The mask value of memory.\r
23 @param TestValue The test value of memory.\r
24 @param Timeout The time out value for wait memory set, uses 100ns as a unit.\r
25\r
26 @retval EFI_TIMEOUT The system memory setting is time out.\r
27 @retval EFI_SUCCESS The system memory is correct set.\r
28\r
29**/\r
30EFI_STATUS\r
31EFIAPI\r
32UfsWaitMemSet (\r
33 IN UINTN Address,\r
34 IN UINT32 MaskValue,\r
35 IN UINT32 TestValue,\r
36 IN UINT64 Timeout\r
37 )\r
38{\r
39 UINT32 Value;\r
40 UINT64 Delay;\r
41 BOOLEAN InfiniteWait;\r
42\r
43 if (Timeout == 0) {\r
44 InfiniteWait = TRUE;\r
45 } else {\r
46 InfiniteWait = FALSE;\r
47 }\r
48\r
49 Delay = DivU64x32 (Timeout, 10) + 1;\r
50\r
51 do {\r
52 //\r
53 // Access PCI MMIO space to see if the value is the tested one.\r
54 //\r
55 Value = MmioRead32 (Address) & MaskValue;\r
56\r
57 if (Value == TestValue) {\r
58 return EFI_SUCCESS;\r
59 }\r
60\r
61 //\r
62 // Stall for 1 microseconds.\r
63 //\r
64 MicroSecondDelay (1);\r
65\r
66 Delay--;\r
67\r
68 } while (InfiniteWait || (Delay > 0));\r
69\r
70 return EFI_TIMEOUT;\r
71}\r
72\r
73/**\r
74 Dump UIC command execution result for debugging.\r
75\r
76 @param[in] UicOpcode The executed UIC opcode.\r
77 @param[in] Result The result to be parsed.\r
78\r
79**/\r
80VOID\r
81DumpUicCmdExecResult (\r
82 IN UINT8 UicOpcode,\r
83 IN UINT8 Result\r
84 )\r
85{\r
86 if (UicOpcode <= UfsUicDmePeerSet) {\r
87 switch (Result) {\r
88 case 0x00:\r
89 break;\r
90 case 0x01:\r
91 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
92 break;\r
93 case 0x02:\r
94 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
95 break;\r
96 case 0x03:\r
97 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
98 break;\r
99 case 0x04:\r
100 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
101 break;\r
102 case 0x05:\r
103 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
104 break;\r
105 case 0x06:\r
106 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
107 break;\r
108 case 0x07:\r
109 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
110 break;\r
111 case 0x08:\r
112 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
113 break; \r
114 case 0x09:\r
115 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
116 break;\r
117 case 0x0A:\r
118 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));\r
119 break; \r
120 default :\r
121 ASSERT (FALSE);\r
122 break;\r
123 }\r
124 } else {\r
125 switch (Result) {\r
126 case 0x00:\r
127 break;\r
128 case 0x01:\r
129 DEBUG ((EFI_D_VERBOSE, "UIC control command fails - FAILURE\n"));\r
130 break; \r
131 default :\r
132 ASSERT (FALSE);\r
133 break;\r
134 }\r
135 }\r
136}\r
137\r
138/**\r
139 Dump QUERY RESPONSE UPIU result for debugging.\r
140\r
141 @param[in] Result The result to be parsed.\r
142\r
143**/\r
144VOID\r
145DumpQueryResponseResult (\r
146 IN UINT8 Result\r
147 )\r
148{\r
149 switch (Result) {\r
150 case 0xF6:\r
151 DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
152 break;\r
153 case 0xF7:\r
154 DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
155 break;\r
156 case 0xF8:\r
157 DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Already Written\n"));\r
158 break;\r
159 case 0xF9:\r
160 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Length\n"));\r
161 break;\r
162 case 0xFA:\r
163 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Value\n"));\r
164 break;\r
165 case 0xFB:\r
166 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Selector\n"));\r
167 break;\r
168 case 0xFC:\r
169 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Index\n"));\r
170 break;\r
171 case 0xFD:\r
172 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Idn\n"));\r
173 break;\r
174 case 0xFE:\r
175 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Opcode\n"));\r
176 break; \r
177 case 0xFF:\r
178 DEBUG ((EFI_D_VERBOSE, "Query Response with General Failure\n"));\r
179 break;\r
180 default :\r
181 ASSERT (FALSE);\r
182 break;\r
183 }\r
184}\r
185\r
186/**\r
187 Swap little endian to big endian.\r
188\r
189 @param[in, out] Buffer The data buffer. In input, it contains little endian data.\r
190 In output, it will become big endian.\r
191 @param[in] BufferSize The length of converted data.\r
192\r
193**/\r
194VOID\r
195SwapLittleEndianToBigEndian (\r
196 IN OUT UINT8 *Buffer,\r
197 IN UINT32 BufferSize\r
198 )\r
199{\r
200 UINT32 Index;\r
201 UINT8 Temp;\r
202 UINT32 SwapCount;\r
203\r
204 SwapCount = BufferSize / 2;\r
205 for (Index = 0; Index < SwapCount; Index++) {\r
206 Temp = Buffer[Index];\r
207 Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
208 Buffer[BufferSize - 1 - Index] = Temp;\r
209 }\r
210}\r
211\r
212/**\r
213 Fill TSF field of QUERY REQUEST UPIU.\r
214\r
215 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.\r
216 @param[in] Opcode The opcode of request.\r
217 @param[in] DescId The descriptor ID of request.\r
218 @param[in] Index The index of request.\r
219 @param[in] Selector The selector of request.\r
220 @param[in] Length The length of transferred data. The maximum is 4.\r
221 @param[in] Value The value of transferred data.\r
222\r
223**/\r
224VOID\r
225UfsFillTsfOfQueryReqUpiu (\r
226 IN OUT UTP_UPIU_TSF *TsfBase,\r
227 IN UINT8 Opcode,\r
228 IN UINT8 DescId OPTIONAL,\r
229 IN UINT8 Index OPTIONAL,\r
230 IN UINT8 Selector OPTIONAL,\r
231 IN UINT16 Length OPTIONAL,\r
232 IN UINT32 Value OPTIONAL\r
233 )\r
234{\r
235 ASSERT (TsfBase != NULL);\r
236 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);\r
237\r
238 TsfBase->Opcode = Opcode;\r
239 if (Opcode != UtpQueryFuncOpcodeNop) {\r
240 TsfBase->DescId = DescId;\r
241 TsfBase->Index = Index;\r
242 TsfBase->Selector = Selector;\r
243\r
244 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
245 SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));\r
246 TsfBase->Length = Length;\r
247 }\r
248 \r
249 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
250 SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));\r
251 TsfBase->Value = Value;\r
252 }\r
253 }\r
254}\r
255\r
256/**\r
257 Initialize COMMAND UPIU.\r
258\r
259 @param[in, out] Command The base address of COMMAND UPIU.\r
260 @param[in] Lun The Lun on which the SCSI command is executed.\r
261 @param[in] TaskTag The task tag of request.\r
262 @param[in] Cdb The cdb buffer containing SCSI command.\r
263 @param[in] CdbLength The cdb length.\r
264 @param[in] DataDirection The direction of data transfer.\r
265 @param[in] ExpDataTranLen The expected transfer data length.\r
266\r
267 @retval EFI_SUCCESS The initialization succeed.\r
268\r
269**/\r
270EFI_STATUS\r
271UfsInitCommandUpiu (\r
272 IN OUT UTP_COMMAND_UPIU *Command,\r
273 IN UINT8 Lun,\r
274 IN UINT8 TaskTag,\r
275 IN UINT8 *Cdb,\r
276 IN UINT8 CdbLength,\r
277 IN UFS_DATA_DIRECTION DataDirection,\r
278 IN UINT32 ExpDataTranLen\r
279 )\r
280{\r
281 UINT8 Flags;\r
282\r
283 ASSERT ((Command != NULL) && (Cdb != NULL));\r
284\r
285 //\r
286 // Task attribute is hard-coded to Ordered.\r
287 //\r
288 if (DataDirection == UfsDataIn) {\r
289 Flags = BIT0 | BIT6;\r
290 } else if (DataDirection == UfsDataOut) {\r
291 Flags = BIT0 | BIT5;\r
292 } else {\r
293 Flags = BIT0;\r
294 }\r
295\r
296 //\r
297 // Fill UTP COMMAND UPIU associated fields.\r
298 //\r
299 Command->TransCode = 0x01;\r
300 Command->Flags = Flags;\r
301 Command->Lun = Lun;\r
302 Command->TaskTag = TaskTag;\r
303 Command->CmdSet = 0x00;\r
304 SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));\r
305 Command->ExpDataTranLen = ExpDataTranLen;\r
306\r
307 CopyMem (Command->Cdb, Cdb, CdbLength);\r
308\r
309 return EFI_SUCCESS;\r
310}\r
311\r
312/**\r
313 Initialize UTP PRDT for data transfer.\r
314\r
315 @param[in] Prdt The base address of PRDT.\r
316 @param[in] Buffer The buffer to be read or written.\r
317 @param[in] BufferSize The data size to be read or written.\r
318\r
319 @retval EFI_SUCCESS The initialization succeed.\r
320\r
321**/\r
322EFI_STATUS\r
323UfsInitUtpPrdt (\r
324 IN UTP_TR_PRD *Prdt,\r
325 IN VOID *Buffer,\r
326 IN UINT32 BufferSize\r
327 )\r
328{\r
329 UINT32 PrdtIndex;\r
330 UINT32 RemainingLen;\r
331 UINT8 *Remaining;\r
332 UINTN PrdtNumber;\r
333\r
334 if (BufferSize == 0) {\r
335 return EFI_SUCCESS;\r
336 }\r
337\r
338 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
339\r
340 RemainingLen = BufferSize;\r
341 Remaining = Buffer;\r
342 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
343\r
344 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
345 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {\r
346 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;\r
347 } else {\r
348 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;\r
349 }\r
350\r
351 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);\r
352 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);\r
353 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;\r
354 Remaining += UFS_MAX_DATA_LEN_PER_PRD;\r
355 }\r
356\r
357 return EFI_SUCCESS;\r
358}\r
359\r
360/**\r
361 Initialize QUERY REQUEST UPIU.\r
362\r
363 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.\r
364 @param[in] TaskTag The task tag of request.\r
365 @param[in] Opcode The opcode of request.\r
366 @param[in] DescId The descriptor ID of request.\r
367 @param[in] Index The index of request.\r
368 @param[in] Selector The selector of request.\r
369 @param[in] DataSize The data size to be read or written.\r
370 @param[in] Data The buffer to be read or written.\r
371\r
372 @retval EFI_SUCCESS The initialization succeed.\r
373\r
374**/\r
375EFI_STATUS\r
376UfsInitQueryRequestUpiu (\r
377 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,\r
378 IN UINT8 TaskTag,\r
379 IN UINT8 Opcode,\r
380 IN UINT8 DescId,\r
381 IN UINT8 Index,\r
382 IN UINT8 Selector,\r
383 IN UINTN DataSize OPTIONAL,\r
384 IN UINT8 *Data OPTIONAL\r
385 )\r
386{\r
387 ASSERT (QueryReq != NULL);\r
388\r
389 QueryReq->TransCode = 0x16;\r
390 QueryReq->TaskTag = TaskTag;\r
391 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {\r
392 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;\r
393 } else {\r
394 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;\r
395 }\r
396\r
397 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
398 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);\r
399 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
400 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);\r
401 } else {\r
402 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);\r
403 }\r
404\r
405 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
406 CopyMem (QueryReq + 1, Data, DataSize);\r
407 }\r
408\r
409 return EFI_SUCCESS;\r
410}\r
411\r
412/**\r
413 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
414\r
415 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
416 @param[in] Lun The Lun on which the SCSI command is executed.\r
417 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
418 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
419 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
420 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
421\r
422 @retval EFI_SUCCESS The creation succeed.\r
423 @retval EFI_DEVICE_ERROR The creation failed.\r
424 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
425\r
426**/\r
427EFI_STATUS\r
428UfsCreateScsiCommandDesc (\r
429 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
430 IN UINT8 Lun,\r
431 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
432 IN UTP_TRD *Trd,\r
433 OUT VOID **CmdDescHost,\r
434 OUT VOID **CmdDescMapping\r
435 )\r
436{\r
437 UINTN TotalLen;\r
438 UINTN PrdtNumber;\r
439 UTP_COMMAND_UPIU *CommandUpiu;\r
440 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
441 EFI_STATUS Status;\r
442 UINT32 DataLen;\r
443 UFS_DATA_DIRECTION DataDirection;\r
444\r
445 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
446\r
447 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
448 DataLen = Packet->InTransferLength;\r
449 DataDirection = UfsDataIn;\r
450 } else {\r
451 DataLen = Packet->OutTransferLength;\r
452 DataDirection = UfsDataOut;\r
453 }\r
454\r
455 if (DataLen == 0) {\r
456 DataDirection = UfsNoData;\r
457 }\r
458\r
459 PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
460\r
461 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);\r
462\r
463 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
464 if (EFI_ERROR (Status)) {\r
465 return Status;\r
466 }\r
467\r
468 CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;\r
469\r
470 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);\r
471\r
472 //\r
473 // Fill UTP_TRD associated fields\r
474 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table\r
475 // *MUST* be located at a 64-bit aligned boundary.\r
476 //\r
477 Trd->Int = UFS_INTERRUPT_COMMAND;\r
478 Trd->Dd = DataDirection;\r
479 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
480 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
481 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
482 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));\r
483 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));\r
484 Trd->PrdtL = (UINT16)PrdtNumber;\r
485 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));\r
486 return EFI_SUCCESS;\r
487}\r
488\r
489/**\r
490 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
491\r
492 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
493 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.\r
494 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
495 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
496 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
497\r
498 @retval EFI_SUCCESS The creation succeed.\r
499 @retval EFI_DEVICE_ERROR The creation failed.\r
500 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
501 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.\r
502\r
503**/\r
504EFI_STATUS\r
505UfsCreateDMCommandDesc (\r
506 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
507 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
508 IN UTP_TRD *Trd,\r
509 OUT VOID **CmdDescHost,\r
510 OUT VOID **CmdDescMapping\r
511 )\r
512{\r
513 UINTN TotalLen;\r
514 UTP_QUERY_REQ_UPIU *QueryReqUpiu;\r
515 UINT8 Opcode;\r
516 UINT32 DataSize;\r
517 UINT8 *Data;\r
518 UINT8 DataDirection;\r
519 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
520 EFI_STATUS Status;\r
521\r
522 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
523\r
524 Opcode = Packet->Opcode;\r
525 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {\r
526 return EFI_INVALID_PARAMETER;\r
527 }\r
528\r
529 DataDirection = Packet->DataDirection;\r
530 if (DataDirection == UfsDataIn) {\r
531 DataSize = Packet->InTransferLength;\r
532 Data = Packet->InDataBuffer;\r
533 } else if (DataDirection == UfsDataOut) {\r
534 DataSize = Packet->OutTransferLength;\r
535 Data = Packet->OutDataBuffer;\r
536 } else {\r
537 DataSize = 0;\r
538 Data = NULL;\r
539 }\r
540\r
541 if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))\r
542 && ((DataSize == 0) || (Data == NULL))) {\r
543 return EFI_INVALID_PARAMETER;\r
544 }\r
545\r
546 if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))\r
547 && ((DataSize != 0) || (Data != NULL))) {\r
548 return EFI_INVALID_PARAMETER;\r
549 }\r
550\r
551 if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {\r
552 return EFI_INVALID_PARAMETER;\r
553 }\r
554\r
555 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {\r
556 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);\r
557 } else {\r
558 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));\r
559 }\r
560\r
561 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
562 if (EFI_ERROR (Status)) {\r
563 return Status;\r
564 }\r
565\r
566 //\r
567 // Initialize UTP QUERY REQUEST UPIU\r
568 //\r
569 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;\r
570 ASSERT (QueryReqUpiu != NULL);\r
571 UfsInitQueryRequestUpiu (\r
572 QueryReqUpiu,\r
573 Private->TaskTag++,\r
574 Opcode,\r
575 Packet->DescId,\r
576 Packet->Index,\r
577 Packet->Selector,\r
578 DataSize,\r
579 Data\r
580 );\r
581\r
582 //\r
583 // Fill UTP_TRD associated fields\r
584 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.\r
585 //\r
586 Trd->Int = UFS_INTERRUPT_COMMAND;\r
587 Trd->Dd = DataDirection;\r
588 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
589 Trd->Ocs = 0x0F;\r
590 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
591 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
592 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
593 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));\r
594 Trd->RuO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
595 } else {\r
596 Trd->RuL = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
597 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));\r
598 }\r
599\r
600 return EFI_SUCCESS;\r
601}\r
602\r
603/**\r
604 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.\r
605\r
606 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
607 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
608 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
609 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
610\r
611 @retval EFI_SUCCESS The creation succeed.\r
612 @retval EFI_DEVICE_ERROR The creation failed.\r
613 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
614\r
615**/\r
616EFI_STATUS\r
617UfsCreateNopCommandDesc (\r
618 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
619 IN UTP_TRD *Trd,\r
620 OUT VOID **CmdDescHost,\r
621 OUT VOID **CmdDescMapping\r
622 )\r
623{\r
624 UINTN TotalLen;\r
625 UTP_NOP_OUT_UPIU *NopOutUpiu;\r
626 EFI_STATUS Status;\r
627 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
628\r
629 ASSERT ((Private != NULL) && (Trd != NULL));\r
630\r
631 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));\r
632 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
633 if (EFI_ERROR (Status)) {\r
634 return Status;\r
635 }\r
636\r
637 NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;\r
638 ASSERT (NopOutUpiu != NULL);\r
639 NopOutUpiu->TaskTag = Private->TaskTag++;\r
640\r
641 //\r
642 // Fill UTP_TRD associated fields\r
643 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.\r
644 //\r
645 Trd->Int = UFS_INTERRUPT_COMMAND;\r
646 Trd->Dd = 0x00;\r
647 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
648 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
649 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
650 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));\r
651 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));\r
652\r
653 return EFI_SUCCESS;\r
654}\r
655\r
656/**\r
657 Find out available slot in transfer list of a UFS device.\r
658\r
659 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
660 @param[out] Slot The available slot.\r
661\r
662 @retval EFI_SUCCESS The available slot was found successfully.\r
663\r
664**/\r
665EFI_STATUS\r
666UfsFindAvailableSlotInTrl (\r
667 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
668 OUT UINT8 *Slot\r
669 )\r
670{\r
671 ASSERT ((Private != NULL) && (Slot != NULL));\r
672\r
673 //\r
674 // The simplest algo to always use slot 0.\r
675 // TODO: enhance it to support async transfer with multiple slot.\r
676 //\r
677 *Slot = 0;\r
678\r
679 return EFI_SUCCESS;\r
680}\r
681\r
682/**\r
683 Find out available slot in task management transfer list of a UFS device.\r
684\r
685 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
686 @param[out] Slot The available slot.\r
687\r
688 @retval EFI_SUCCESS The available slot was found successfully.\r
689\r
690**/\r
691EFI_STATUS\r
692UfsFindAvailableSlotInTmrl (\r
693 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
694 OUT UINT8 *Slot\r
695 )\r
696{\r
697 ASSERT ((Private != NULL) && (Slot != NULL));\r
698\r
699 //\r
700 // The simplest algo to always use slot 0.\r
701 // TODO: enhance it to support async transfer with multiple slot.\r
702 //\r
703 *Slot = 0;\r
704\r
705 return EFI_SUCCESS;\r
706}\r
707\r
708/**\r
709 Start specified slot in transfer list of a UFS device.\r
710\r
711 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
712 @param[in] Slot The slot to be started.\r
713\r
714**/\r
715VOID\r
716UfsStartExecCmd (\r
717 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
718 IN UINT8 Slot\r
719 ) \r
720{\r
721 UINTN UfsHcBase;\r
722 UINTN Address;\r
723 UINT32 Data;\r
724\r
725 UfsHcBase = Private->UfsHcBase;\r
726\r
727 Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET; \r
728 Data = MmioRead32 (Address);\r
729 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
730 MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
731 }\r
732\r
733 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
734 MmioWrite32 (Address, BIT0 << Slot);\r
735}\r
736\r
737/**\r
738 Stop specified slot in transfer list of a UFS device.\r
739\r
740 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
741 @param[in] Slot The slot to be stop.\r
742\r
743**/\r
744VOID\r
745UfsStopExecCmd (\r
746 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
747 IN UINT8 Slot\r
748 ) \r
749{\r
750 UINTN UfsHcBase;\r
751 UINTN Address;\r
752 UINT32 Data;\r
753\r
754 UfsHcBase = Private->UfsHcBase;\r
755\r
756 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
757 Data = MmioRead32 (Address);\r
758 if ((Data & (BIT0 << Slot)) != 0) {\r
759 Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET; \r
760 Data = MmioRead32 (Address);\r
761 MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));\r
762 }\r
763}\r
764\r
765/**\r
766 Read or write specified device descriptor of a UFS device.\r
767\r
768 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
769 @param[in] Read The boolean variable to show r/w direction.\r
770 @param[in] DescId The ID of device descriptor.\r
771 @param[in] Index The Index of device descriptor.\r
772 @param[in] Selector The Selector of device descriptor.\r
773 @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
774 @param[in] DescSize The size of device descriptor buffer.\r
775\r
776 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
777 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
778 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
779\r
780**/\r
781EFI_STATUS\r
782UfsRwDeviceDesc (\r
783 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
784 IN BOOLEAN Read,\r
785 IN UINT8 DescId,\r
786 IN UINT8 Index,\r
787 IN UINT8 Selector,\r
788 IN OUT VOID *Descriptor,\r
789 IN UINT32 DescSize\r
790 )\r
791{\r
792 EFI_STATUS Status;\r
793 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
794 UINT8 Slot;\r
795 UTP_TRD *Trd;\r
796 UINTN Address;\r
797 UTP_QUERY_RESP_UPIU *QueryResp;\r
798 UINT32 CmdDescSize;\r
799 UINT16 ReturnDataSize;\r
800 VOID *CmdDescHost;\r
801 VOID *CmdDescMapping;\r
802 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
803\r
804 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
805\r
806 if (Read) {\r
807 Packet.DataDirection = UfsDataIn;\r
808 Packet.InDataBuffer = Descriptor;\r
809 Packet.InTransferLength = DescSize;\r
810 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
811 } else {\r
812 Packet.DataDirection = UfsDataOut;\r
813 Packet.OutDataBuffer = Descriptor;\r
814 Packet.OutTransferLength = DescSize;\r
815 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
816 }\r
817 Packet.DescId = DescId;\r
818 Packet.Index = Index;\r
819 Packet.Selector = Selector;\r
820 Packet.Timeout = UFS_TIMEOUT;\r
821\r
822 //\r
823 // Find out which slot of transfer request list is available.\r
824 //\r
825 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
826 if (EFI_ERROR (Status)) {\r
827 return Status;\r
828 }\r
829 \r
830 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
831 //\r
832 // Fill transfer request descriptor to this slot.\r
833 //\r
834 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
835 if (EFI_ERROR (Status)) {\r
836 return Status;\r
837 }\r
838\r
839 //\r
840 // Check the transfer request result.\r
841 //\r
842 UfsHc = Private->UfsHostController;\r
843 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
844 ASSERT (QueryResp != NULL);\r
845 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
846\r
847 //\r
848 // Start to execute the transfer request.\r
849 //\r
850 UfsStartExecCmd (Private, Slot);\r
851\r
852 //\r
853 // Wait for the completion of the transfer request.\r
854 // \r
855 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
856 Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
857 if (EFI_ERROR (Status)) {\r
858 goto Exit;\r
859 }\r
860\r
861 if (QueryResp->QueryResp != 0) {\r
862 DumpQueryResponseResult (QueryResp->QueryResp);\r
863 Status = EFI_DEVICE_ERROR;\r
864 goto Exit;\r
865 }\r
866\r
867 if (Trd->Ocs == 0) {\r
868 ReturnDataSize = QueryResp->Tsf.Length;\r
869 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
870\r
871 if (Read) {\r
872 CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);\r
873 Packet.InTransferLength = ReturnDataSize;\r
874 } else {\r
875 Packet.OutTransferLength = ReturnDataSize;\r
876 }\r
877 } else {\r
878 Status = EFI_DEVICE_ERROR;\r
879 }\r
880\r
881Exit:\r
882 UfsHc->Flush (UfsHc);\r
883\r
884 UfsStopExecCmd (Private, Slot);\r
885\r
886 if (CmdDescMapping != NULL) {\r
887 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
888 }\r
889 if (CmdDescHost != NULL) {\r
890 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
891 }\r
892\r
893 return Status;\r
894}\r
895\r
896/**\r
897 Read or write specified attribute of a UFS device.\r
898\r
899 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
900 @param[in] Read The boolean variable to show r/w direction.\r
901 @param[in] AttrId The ID of Attribute.\r
902 @param[in] Index The Index of Attribute.\r
903 @param[in] Selector The Selector of Attribute.\r
904 @param[in, out] Attributes The value of Attribute to be read or written.\r
905\r
906 @retval EFI_SUCCESS The Attribute was read/written successfully.\r
907 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.\r
908 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.\r
909\r
910**/\r
911EFI_STATUS\r
912UfsRwAttributes (\r
913 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
914 IN BOOLEAN Read,\r
915 IN UINT8 AttrId,\r
916 IN UINT8 Index,\r
917 IN UINT8 Selector,\r
918 IN OUT UINT32 *Attributes\r
919 )\r
920{\r
921 EFI_STATUS Status;\r
922 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
923 UINT8 Slot;\r
924 UTP_TRD *Trd;\r
925 UINTN Address;\r
926 UTP_QUERY_RESP_UPIU *QueryResp;\r
927 UINT32 CmdDescSize;\r
928 UINT32 ReturnData;\r
929 VOID *CmdDescHost;\r
930 VOID *CmdDescMapping;\r
931 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
932\r
933 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
934\r
935 if (Read) {\r
936 Packet.DataDirection = UfsDataIn;\r
937 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;\r
938 } else {\r
939 Packet.DataDirection = UfsDataOut;\r
940 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;\r
941 }\r
942 Packet.DescId = AttrId;\r
943 Packet.Index = Index;\r
944 Packet.Selector = Selector;\r
945 Packet.Timeout = UFS_TIMEOUT;\r
946\r
947 //\r
948 // Find out which slot of transfer request list is available.\r
949 //\r
950 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
951 if (EFI_ERROR (Status)) {\r
952 return Status;\r
953 }\r
954 \r
955 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
956 //\r
957 // Fill transfer request descriptor to this slot.\r
958 //\r
959 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
960 if (EFI_ERROR (Status)) {\r
961 return Status;\r
962 }\r
963\r
964 //\r
965 // Check the transfer request result.\r
966 //\r
967 UfsHc = Private->UfsHostController;\r
968 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
969 ASSERT (QueryResp != NULL);\r
970 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
971\r
972 //\r
973 // Start to execute the transfer request.\r
974 //\r
975 UfsStartExecCmd (Private, Slot);\r
976\r
977 //\r
978 // Wait for the completion of the transfer request.\r
979 // \r
980 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
981 Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
982 if (EFI_ERROR (Status)) {\r
983 goto Exit;\r
984 }\r
985\r
986 if (QueryResp->QueryResp != 0) {\r
987 DumpQueryResponseResult (QueryResp->QueryResp);\r
988 Status = EFI_DEVICE_ERROR;\r
989 goto Exit;\r
990 }\r
991\r
992 if (Trd->Ocs == 0) {\r
993 ReturnData = QueryResp->Tsf.Value;\r
994 SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));\r
995 *Attributes = ReturnData;\r
996 } else {\r
997 Status = EFI_DEVICE_ERROR;\r
998 }\r
999\r
1000Exit:\r
1001 UfsHc->Flush (UfsHc);\r
1002\r
1003 UfsStopExecCmd (Private, Slot);\r
1004\r
1005 if (CmdDescMapping != NULL) {\r
1006 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1007 }\r
1008\r
1009 if (CmdDescHost != NULL) {\r
1010 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1011 }\r
1012\r
1013 return Status;\r
1014}\r
1015\r
1016/**\r
1017 Read or write specified flag of a UFS device.\r
1018\r
1019 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1020 @param[in] Read The boolean variable to show r/w direction.\r
1021 @param[in] FlagId The ID of flag to be read or written.\r
1022 @param[in, out] Value The value to set or clear flag.\r
1023\r
1024 @retval EFI_SUCCESS The flag was read/written successfully.\r
1025 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.\r
1026 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.\r
1027\r
1028**/\r
1029EFI_STATUS\r
1030UfsRwFlags (\r
1031 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1032 IN BOOLEAN Read,\r
1033 IN UINT8 FlagId,\r
1034 IN OUT UINT8 *Value\r
1035 )\r
1036{\r
1037 EFI_STATUS Status;\r
1038 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
1039 UINT8 Slot;\r
1040 UTP_TRD *Trd;\r
1041 UINTN Address;\r
1042 UTP_QUERY_RESP_UPIU *QueryResp;\r
1043 UINT32 CmdDescSize;\r
1044 VOID *CmdDescHost;\r
1045 VOID *CmdDescMapping;\r
1046 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1047\r
1048 if (Value == NULL) {\r
1049 return EFI_INVALID_PARAMETER;\r
1050 }\r
1051\r
1052 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1053\r
1054 if (Read) {\r
1055 ASSERT (Value != NULL);\r
1056 Packet.DataDirection = UfsDataIn;\r
1057 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
1058 } else {\r
1059 Packet.DataDirection = UfsDataOut;\r
1060 if (*Value == 1) {\r
1061 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
1062 } else if (*Value == 0) {\r
1063 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;\r
1064 } else {\r
1065 return EFI_INVALID_PARAMETER;\r
1066 }\r
1067 }\r
1068 Packet.DescId = FlagId;\r
1069 Packet.Index = 0;\r
1070 Packet.Selector = 0;\r
1071 Packet.Timeout = UFS_TIMEOUT;\r
1072\r
1073 //\r
1074 // Find out which slot of transfer request list is available.\r
1075 //\r
1076 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1077 if (EFI_ERROR (Status)) {\r
1078 return Status;\r
1079 }\r
1080\r
1081 //\r
1082 // Fill transfer request descriptor to this slot.\r
1083 //\r
1084 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1085 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
1086 if (EFI_ERROR (Status)) {\r
1087 return Status;\r
1088 }\r
1089\r
1090 //\r
1091 // Check the transfer request result.\r
1092 //\r
1093 UfsHc = Private->UfsHostController;\r
1094 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
1095 ASSERT (QueryResp != NULL);\r
1096 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1097\r
1098 //\r
1099 // Start to execute the transfer request.\r
1100 //\r
1101 UfsStartExecCmd (Private, Slot);\r
1102\r
1103 //\r
1104 // Wait for the completion of the transfer request.\r
1105 // \r
1106 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
1107 Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
1108 if (EFI_ERROR (Status)) {\r
1109 goto Exit;\r
1110 }\r
1111\r
1112 if (QueryResp->QueryResp != 0) {\r
1113 DumpQueryResponseResult (QueryResp->QueryResp);\r
1114 Status = EFI_DEVICE_ERROR;\r
1115 goto Exit;\r
1116 }\r
1117\r
1118 if (Trd->Ocs == 0) {\r
1119 *Value = (UINT8)QueryResp->Tsf.Value;\r
1120 } else {\r
1121 Status = EFI_DEVICE_ERROR;\r
1122 }\r
1123\r
1124Exit:\r
1125 UfsHc->Flush (UfsHc);\r
1126\r
1127 UfsStopExecCmd (Private, Slot);\r
1128\r
1129 if (CmdDescMapping != NULL) {\r
1130 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1131 }\r
1132 if (CmdDescHost != NULL) {\r
1133 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1134 }\r
1135\r
1136 return Status;\r
1137}\r
1138\r
1139/**\r
1140 Set specified flag to 1 on a UFS device.\r
1141\r
1142 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1143 @param[in] FlagId The ID of flag to be set.\r
1144\r
1145 @retval EFI_SUCCESS The flag was set successfully.\r
1146 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.\r
1147 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.\r
1148\r
1149**/\r
1150EFI_STATUS\r
1151UfsSetFlag (\r
1152 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1153 IN UINT8 FlagId\r
1154 )\r
1155{\r
1156 EFI_STATUS Status;\r
1157 UINT8 Value;\r
1158\r
1159 Value = 1;\r
1160 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1161\r
1162 return Status;\r
1163}\r
1164\r
1165/**\r
1166 Clear specified flag to 0 on a UFS device.\r
1167\r
1168 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1169 @param[in] FlagId The ID of flag to be cleared.\r
1170\r
1171 @retval EFI_SUCCESS The flag was cleared successfully.\r
1172 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.\r
1173 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.\r
1174\r
1175**/\r
1176EFI_STATUS\r
1177UfsClearFlag (\r
1178 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1179 IN UINT8 FlagId\r
1180 )\r
1181{\r
1182 EFI_STATUS Status;\r
1183 UINT8 Value;\r
1184\r
1185 Value = 0;\r
1186 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1187\r
1188 return Status;\r
1189}\r
1190\r
1191/**\r
1192 Read specified flag from a UFS device.\r
1193\r
1194 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1195 @param[in] FlagId The ID of flag to be read.\r
1196 @param[out] Value The flag's value.\r
1197\r
1198 @retval EFI_SUCCESS The flag was read successfully.\r
1199 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.\r
1200 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.\r
1201\r
1202**/\r
1203EFI_STATUS\r
1204UfsReadFlag (\r
1205 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1206 IN UINT8 FlagId,\r
1207 OUT UINT8 *Value\r
1208 )\r
1209{\r
1210 EFI_STATUS Status;\r
1211\r
1212 Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
1213\r
1214 return Status;\r
1215}\r
1216\r
1217/**\r
1218 Sends NOP IN cmd to a UFS device for initialization process request.\r
1219 For more details, please refer to UFS 2.0 spec Figure 13.3.\r
1220\r
1221 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1222\r
1223 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was\r
1224 received successfully.\r
1225 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.\r
1226 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1227 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.\r
1228\r
1229**/\r
1230EFI_STATUS\r
1231UfsExecNopCmds (\r
1232 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1233 )\r
1234{\r
1235 EFI_STATUS Status;\r
1236 UINT8 Slot;\r
1237 UTP_TRD *Trd;\r
1238 UTP_NOP_IN_UPIU *NopInUpiu;\r
1239 UINT32 CmdDescSize;\r
1240 UINTN Address;\r
1241 VOID *CmdDescHost;\r
1242 VOID *CmdDescMapping;\r
1243 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1244\r
1245 //\r
1246 // Find out which slot of transfer request list is available.\r
1247 //\r
1248 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1249 if (EFI_ERROR (Status)) {\r
1250 return Status;\r
1251 }\r
1252\r
1253 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1254 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);\r
1255 if (EFI_ERROR (Status)) {\r
1256 return Status;\r
1257 }\r
1258\r
1259 //\r
1260 // Check the transfer request result.\r
1261 //\r
1262 UfsHc = Private->UfsHostController;\r
1263 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
1264 ASSERT (NopInUpiu != NULL);\r
1265 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1266\r
1267 //\r
1268 // Start to execute the transfer request.\r
1269 //\r
1270 UfsStartExecCmd (Private, Slot);\r
1271\r
1272 //\r
1273 // Wait for the completion of the transfer request.\r
1274 // \r
1275 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
1276 Status = UfsWaitMemSet (Address, BIT0, 0, UFS_TIMEOUT);\r
1277 if (EFI_ERROR (Status)) {\r
1278 goto Exit;\r
1279 }\r
1280\r
1281 if (NopInUpiu->Resp != 0) {\r
1282 Status = EFI_DEVICE_ERROR;\r
1283 } else {\r
1284 Status = EFI_SUCCESS;\r
1285 }\r
1286\r
1287Exit:\r
1288 UfsHc->Flush (UfsHc);\r
1289\r
1290 UfsStopExecCmd (Private, Slot);\r
1291\r
1292 if (CmdDescMapping != NULL) {\r
1293 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1294 }\r
1295 if (CmdDescHost != NULL) {\r
1296 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1297 }\r
1298\r
1299 return Status;\r
1300}\r
1301\r
1302/**\r
1303 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
1304\r
1305 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1306 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.\r
1307 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the\r
1308 UFS device.\r
1309\r
1310 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional\r
1311 commands, InTransferLength bytes were transferred from\r
1312 InDataBuffer. For write and bi-directional commands,\r
1313 OutTransferLength bytes were transferred by\r
1314 OutDataBuffer.\r
1315 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request\r
1316 Packet.\r
1317 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1318 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
1319\r
1320**/\r
1321EFI_STATUS\r
1322UfsExecScsiCmds (\r
1323 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1324 IN UINT8 Lun,\r
1325 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
1326 )\r
1327{\r
1328 EFI_STATUS Status;\r
1329 UINT8 Slot;\r
1330 UTP_TRD *Trd;\r
1331 UINTN Address;\r
1332 UINT32 CmdDescSize;\r
1333 UTP_RESPONSE_UPIU *Response;\r
1334 UINT16 SenseDataLen;\r
1335 UINT32 ResTranCount;\r
1336 VOID *CmdDescHost;\r
1337 VOID *CmdDescMapping;\r
1338 VOID *DataBufMapping;\r
1339 VOID *DataBuf;\r
1340 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;\r
1341 UINT32 DataLen;\r
1342 UINTN MapLength;\r
1343 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1344 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;\r
1345 UFS_DATA_DIRECTION DataDirection;\r
1346 UTP_TR_PRD *PrdtBase;\r
1347\r
1348 Trd = NULL;\r
1349 CmdDescHost = NULL;\r
1350 CmdDescMapping = NULL;\r
1351 DataBufMapping = NULL;\r
1352 DataBufPhyAddr = 0;\r
1353 UfsHc = Private->UfsHostController;\r
1354 //\r
1355 // Find out which slot of transfer request list is available.\r
1356 //\r
1357 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1358 if (EFI_ERROR (Status)) {\r
1359 return Status;\r
1360 }\r
1361\r
1362 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1363\r
1364 //\r
1365 // Fill transfer request descriptor to this slot.\r
1366 //\r
1367 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
1368 if (EFI_ERROR (Status)) {\r
1369 return Status;\r
1370 }\r
1371\r
1372 CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);\r
1373\r
1374 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1375 DataBuf = Packet->InDataBuffer;\r
1376 DataLen = Packet->InTransferLength;\r
1377 DataDirection = UfsDataIn;\r
1378 Flag = EdkiiUfsHcOperationBusMasterWrite;\r
1379 } else {\r
1380 DataBuf = Packet->OutDataBuffer;\r
1381 DataLen = Packet->OutTransferLength;\r
1382 DataDirection = UfsDataOut;\r
1383 Flag = EdkiiUfsHcOperationBusMasterRead;\r
1384 }\r
1385\r
1386 if (DataLen == 0) {\r
1387 DataDirection = UfsNoData;\r
1388 } else {\r
1389 MapLength = DataLen;\r
1390 Status = UfsHc->Map (\r
1391 UfsHc,\r
1392 Flag,\r
1393 DataBuf,\r
1394 &MapLength,\r
1395 &DataBufPhyAddr,\r
1396 &DataBufMapping\r
1397 );\r
1398\r
1399 if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
1400 goto Exit1;\r
1401 }\r
1402 }\r
1403 //\r
1404 // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
1405 //\r
1406 PrdtBase = (UTP_TR_PRD*)((UINT8*)CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
1407 ASSERT (PrdtBase != NULL);\r
1408 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);\r
1409\r
1410 //\r
1411 // Start to execute the transfer request.\r
1412 //\r
1413 UfsStartExecCmd (Private, Slot);\r
1414\r
1415 //\r
1416 // Wait for the completion of the transfer request.\r
1417 // \r
1418 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
1419 Status = UfsWaitMemSet (Address, BIT0, 0, Packet->Timeout);\r
1420 if (EFI_ERROR (Status)) {\r
1421 goto Exit;\r
1422 }\r
1423\r
1424 //\r
1425 // Get sense data if exists\r
1426 //\r
1427 Response = (UTP_RESPONSE_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
1428 ASSERT (Response != NULL);\r
1429 SenseDataLen = Response->SenseDataLen;\r
1430 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
1431 \r
1432 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
1433 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
1434 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
1435 }\r
1436\r
1437 //\r
1438 // Check the transfer request result.\r
1439 //\r
1440 Packet->TargetStatus = Response->Status;\r
1441 if (Response->Response != 0) {\r
1442 DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
1443 Status = EFI_DEVICE_ERROR;\r
1444 goto Exit;\r
1445 }\r
1446\r
1447 if (Trd->Ocs == 0) {\r
1448 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1449 if ((Response->Flags & BIT5) == BIT5) {\r
1450 ResTranCount = Response->ResTranCount;\r
1451 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1452 Packet->InTransferLength -= ResTranCount;\r
1453 }\r
1454 } else {\r
1455 if ((Response->Flags & BIT5) == BIT5) {\r
1456 ResTranCount = Response->ResTranCount;\r
1457 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1458 Packet->OutTransferLength -= ResTranCount;\r
1459 }\r
1460 }\r
1461 } else {\r
1462 Status = EFI_DEVICE_ERROR;\r
1463 }\r
1464\r
1465Exit:\r
1466 UfsHc->Flush (UfsHc);\r
1467\r
1468 UfsStopExecCmd (Private, Slot);\r
1469\r
1470 if (DataBufMapping != NULL) {\r
1471 UfsHc->Unmap (UfsHc, DataBufMapping);\r
1472 }\r
1473\r
1474Exit1:\r
1475 if (CmdDescMapping != NULL) {\r
1476 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1477 }\r
1478 if (CmdDescHost != NULL) {\r
1479 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1480 }\r
1481 return Status;\r
1482}\r
1483\r
1484\r
1485/**\r
1486 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
1487\r
1488 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1489 @param[in] UicOpcode The opcode of the UIC command.\r
1490 @param[in] Arg1 The value for 1st argument of the UIC command.\r
1491 @param[in] Arg2 The value for 2nd argument of the UIC command.\r
1492 @param[in] Arg3 The value for 3rd argument of the UIC command.\r
1493\r
1494 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.\r
1495 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
1496 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.\r
1497\r
1498**/\r
1499EFI_STATUS\r
1500UfsExecUicCommands (\r
1501 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1502 IN UINT8 UicOpcode,\r
1503 IN UINT32 Arg1,\r
1504 IN UINT32 Arg2,\r
1505 IN UINT32 Arg3\r
1506 )\r
1507{\r
1508 EFI_STATUS Status;\r
1509 UINTN Address;\r
1510 UINT32 Data;\r
1511 UINTN UfsHcBase;\r
1512\r
1513 UfsHcBase = Private->UfsHcBase;\r
1514 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1515 Data = MmioRead32 (Address);\r
1516 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
1517 //\r
1518 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
1519 //\r
1520 MmioWrite32 (Address, Data);\r
1521 }\r
1522\r
1523 //\r
1524 // When programming UIC command registers, host software shall set the register UICCMD\r
1525 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
1526 // are set.\r
1527 //\r
1528 Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;\r
1529 MmioWrite32 (Address, Arg1);\r
1530\r
1531 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
1532 MmioWrite32 (Address, Arg2);\r
1533\r
1534 Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;\r
1535 MmioWrite32 (Address, Arg3);\r
1536\r
1537 //\r
1538 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
1539 //\r
1540 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;\r
1541 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
1542 if (EFI_ERROR (Status)) {\r
1543 return Status;\r
1544 }\r
1545\r
1546 Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;\r
1547 MmioWrite32 (Address, (UINT32)UicOpcode);\r
1548\r
1549 //\r
1550 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
1551 // This bit is set to '1' by the host controller upon completion of a UIC command. \r
1552 //\r
1553 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1554 Data = MmioRead32 (Address);\r
1555 Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
1556 if (EFI_ERROR (Status)) {\r
1557 return Status;\r
1558 }\r
1559\r
1560 if (UicOpcode != UfsUicDmeReset) {\r
1561 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
1562 Data = MmioRead32 (Address);\r
1563 if ((Data & 0xFF) != 0) {\r
1564 DEBUG_CODE_BEGIN();\r
1565 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
1566 DEBUG_CODE_END();\r
1567 return EFI_DEVICE_ERROR;\r
1568 }\r
1569 }\r
1570\r
1571 //\r
1572 // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
1573 //\r
1574 Address = UfsHcBase + UFS_HC_STATUS_OFFSET; \r
1575 Data = MmioRead32 (Address);\r
1576 if ((Data & UFS_HC_HCS_DP) == 0) {\r
1577 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1578 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
1579 if (EFI_ERROR (Status)) {\r
1580 return EFI_DEVICE_ERROR;\r
1581 }\r
1582 return EFI_NOT_FOUND;\r
1583 }\r
1584\r
1585 DEBUG ((EFI_D_INFO, "UfsPassThruDxe: found a attached UFS device\n"));\r
1586\r
1587 return EFI_SUCCESS;\r
1588}\r
1589\r
1590/**\r
1591 Allocate common buffer for host and UFS bus master access simultaneously.\r
1592\r
1593 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1594 @param[in] Size The length of buffer to be allocated.\r
1595 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
1596 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.\r
1597 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
1598\r
1599 @retval EFI_SUCCESS The common buffer was allocated successfully.\r
1600 @retval EFI_DEVICE_ERROR The allocation fails.\r
1601 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
1602\r
1603**/\r
1604EFI_STATUS\r
1605UfsAllocateAlignCommonBuffer (\r
1606 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1607 IN UINTN Size,\r
1608 OUT VOID **CmdDescHost,\r
1609 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,\r
1610 OUT VOID **CmdDescMapping\r
1611 )\r
1612{\r
1613 EFI_STATUS Status;\r
1614 UINTN Bytes;\r
1615 BOOLEAN Is32BitAddr;\r
1616 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1617\r
1618 if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
1619 Is32BitAddr = TRUE;\r
1620 } else {\r
1621 Is32BitAddr = FALSE;\r
1622 }\r
1623\r
1624 UfsHc = Private->UfsHostController;\r
1625 Status = UfsHc->AllocateBuffer (\r
1626 UfsHc,\r
1627 AllocateAnyPages,\r
1628 EfiBootServicesData,\r
1629 EFI_SIZE_TO_PAGES (Size),\r
1630 CmdDescHost,\r
1631 0\r
1632 );\r
1633 if (EFI_ERROR (Status)) {\r
1634 *CmdDescMapping = NULL;\r
1635 *CmdDescHost = NULL;\r
1636 *CmdDescPhyAddr = 0;\r
1637 return EFI_OUT_OF_RESOURCES;\r
1638 }\r
1639\r
1640 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));\r
1641 Status = UfsHc->Map (\r
1642 UfsHc,\r
1643 EdkiiUfsHcOperationBusMasterCommonBuffer,\r
1644 *CmdDescHost,\r
1645 &Bytes,\r
1646 CmdDescPhyAddr,\r
1647 CmdDescMapping\r
1648 );\r
1649\r
1650 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {\r
1651 UfsHc->FreeBuffer (\r
1652 UfsHc,\r
1653 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1654 *CmdDescHost\r
1655 );\r
1656 *CmdDescHost = NULL;\r
1657 return EFI_OUT_OF_RESOURCES;\r
1658 }\r
1659\r
1660 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {\r
1661 //\r
1662 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.\r
1663 //\r
1664 UfsHc->Unmap (\r
1665 UfsHc,\r
1666 *CmdDescMapping\r
1667 );\r
1668 UfsHc->FreeBuffer (\r
1669 UfsHc,\r
1670 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1671 *CmdDescHost\r
1672 );\r
1673 *CmdDescMapping = NULL;\r
1674 *CmdDescHost = NULL;\r
1675 return EFI_DEVICE_ERROR;\r
1676 }\r
1677\r
1678 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));\r
1679 return EFI_SUCCESS;\r
1680}\r
1681\r
1682/**\r
1683 Enable the UFS host controller for accessing.\r
1684\r
1685 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1686\r
1687 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1688 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1689\r
1690**/\r
1691EFI_STATUS\r
1692UfsEnableHostController (\r
1693 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1694 )\r
1695{\r
1696 EFI_STATUS Status;\r
1697 UINTN Address;\r
1698 UINT32 Data;\r
1699\r
1700 //\r
1701 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1702 //\r
1703 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1704 //\r
1705 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1706 Data = MmioRead32 (Address);\r
1707 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1708 //\r
1709 // Write a 0 to the HCE register at first to disable the host controller.\r
1710 //\r
1711 MmioWrite32 (Address, 0);\r
1712 //\r
1713 // Wait until HCE is read as '0' before continuing.\r
1714 //\r
1715 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1716 if (EFI_ERROR (Status)) {\r
1717 return EFI_DEVICE_ERROR;\r
1718 }\r
1719 }\r
1720\r
1721 //\r
1722 // Write a 1 to the HCE register to enable the UFS host controller.\r
1723 //\r
1724 MmioWrite32 (Address, UFS_HC_HCE_EN);\r
1725 //\r
1726 // Wait until HCE is read as '1' before continuing.\r
1727 //\r
1728 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
1729 if (EFI_ERROR (Status)) {\r
1730 return EFI_DEVICE_ERROR;\r
1731 }\r
1732\r
1733 return EFI_SUCCESS;\r
1734}\r
1735\r
1736/**\r
1737 Detect if a UFS device attached.\r
1738\r
1739 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1740\r
1741 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1742 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1743 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1744\r
1745**/\r
1746EFI_STATUS\r
1747UfsDeviceDetection (\r
1748 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1749 )\r
1750{\r
1751 UINTN Retry;\r
1752 EFI_STATUS Status;\r
1753\r
1754 //\r
1755 // Start UFS device detection.\r
1756 // Try up to 3 times for establishing data link with device.\r
1757 //\r
1758 for (Retry = 0; Retry < 3; Retry++) {\r
1759 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
1760 if (!EFI_ERROR (Status)) {\r
1761 break;\r
1762 }\r
1763\r
1764 if (Status == EFI_NOT_FOUND) {\r
1765 continue;\r
1766 }\r
1767\r
1768 return EFI_DEVICE_ERROR;\r
1769 }\r
1770\r
1771 if (Retry == 3) {\r
1772 return EFI_NOT_FOUND;\r
1773 }\r
1774\r
1775 return EFI_SUCCESS;\r
1776}\r
1777\r
1778/**\r
1779 Initialize UFS task management request list related h/w context.\r
1780\r
1781 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1782\r
1783 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1784 @retval EFI_DEVICE_ERROR The initialization fails.\r
1785\r
1786**/\r
1787EFI_STATUS\r
1788UfsInitTaskManagementRequestList (\r
1789 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1790 )\r
1791{\r
1792 UINTN Address;\r
1793 UINT32 Data;\r
1794 UINT8 Nutmrs;\r
1795 VOID *CmdDescHost;\r
1796 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1797 VOID *CmdDescMapping;\r
1798 EFI_STATUS Status;\r
1799 \r
1800 //\r
1801 // Initial h/w and s/w context for future operations.\r
1802 //\r
1803 CmdDescHost = NULL;\r
1804 CmdDescMapping = NULL;\r
1805 CmdDescPhyAddr = 0;\r
1806 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET; \r
1807 Data = MmioRead32 (Address);\r
1808 Private->Capabilities = Data;\r
1809\r
1810 //\r
1811 // Allocate and initialize UTP Task Management Request List.\r
1812 //\r
1813 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
1814 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
1815 if (EFI_ERROR (Status)) {\r
1816 return Status;\r
1817 }\r
1818\r
1819 //\r
1820 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
1821 // Request List Base Address with a 64-bit address allocated at step 6.\r
1822 //\r
1823 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET; \r
1824 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
1825 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET; \r
1826 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1827 Private->UtpTmrlBase = CmdDescHost;\r
1828 Private->Nutmrs = Nutmrs;\r
1829 Private->TmrlMapping = CmdDescMapping;\r
1830\r
1831 //\r
1832 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1833 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1834 //\r
1835 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET; \r
1836 MmioWrite32 (Address, UFS_HC_UTMRLRSR);\r
1837\r
1838 return EFI_SUCCESS;\r
1839}\r
1840\r
1841/**\r
1842 Initialize UFS transfer request list related h/w context.\r
1843\r
1844 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1845\r
1846 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
1847 @retval EFI_DEVICE_ERROR The initialization fails.\r
1848\r
1849**/\r
1850EFI_STATUS\r
1851UfsInitTransferRequestList (\r
1852 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1853 )\r
1854{\r
1855 UINTN Address;\r
1856 UINT32 Data;\r
1857 UINT8 Nutrs;\r
1858 VOID *CmdDescHost;\r
1859 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1860 VOID *CmdDescMapping; \r
1861 EFI_STATUS Status;\r
1862\r
1863 //\r
1864 // Initial h/w and s/w context for future operations.\r
1865 //\r
1866 CmdDescHost = NULL;\r
1867 CmdDescMapping = NULL;\r
1868 CmdDescPhyAddr = 0;\r
1869 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET; \r
1870 Data = MmioRead32 (Address);\r
1871 Private->Capabilities = Data;\r
1872\r
1873 //\r
1874 // Allocate and initialize UTP Transfer Request List.\r
1875 //\r
1876 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
1877 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
1878 if (EFI_ERROR (Status)) {\r
1879 return Status;\r
1880 }\r
1881\r
1882 //\r
1883 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
1884 // Base Address with a 64-bit address allocated at step 8.\r
1885 //\r
1886 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET; \r
1887 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
1888 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET; \r
1889 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1890 Private->UtpTrlBase = CmdDescHost;\r
1891 Private->Nutrs = Nutrs; \r
1892 Private->TrlMapping = CmdDescMapping;\r
1893\r
1894 //\r
1895 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1896 // RunStop Register (UTRLRSR) to '1'.\r
1897 //\r
1898 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET; \r
1899 MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
1900\r
1901 return EFI_SUCCESS;\r
1902}\r
1903\r
1904/**\r
1905 Initialize the UFS host controller.\r
1906\r
1907 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1908\r
1909 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
1910 @retval Others A device error occurred while initializing the controller.\r
1911\r
1912**/\r
1913EFI_STATUS\r
1914UfsControllerInit (\r
1915 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1916 )\r
1917{\r
1918 EFI_STATUS Status;\r
1919\r
1920 Status = UfsEnableHostController (Private);\r
1921 if (EFI_ERROR (Status)) {\r
1922 DEBUG ((EFI_D_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));\r
1923 return Status;\r
1924 }\r
1925\r
1926 Status = UfsDeviceDetection (Private);\r
1927 if (EFI_ERROR (Status)) {\r
1928 DEBUG ((EFI_D_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));\r
1929 return Status;\r
1930 }\r
1931\r
1932 Status = UfsInitTaskManagementRequestList (Private);\r
1933 if (EFI_ERROR (Status)) {\r
1934 DEBUG ((EFI_D_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));\r
1935 return Status;\r
1936 }\r
1937\r
1938 Status = UfsInitTransferRequestList (Private);\r
1939 if (EFI_ERROR (Status)) {\r
1940 DEBUG ((EFI_D_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));\r
1941 return Status;\r
1942 }\r
1943\r
1944 DEBUG ((EFI_D_INFO, "UfsControllerInit Finished\n"));\r
1945 return EFI_SUCCESS;\r
1946}\r
1947\r
1948/**\r
1949 Stop the UFS host controller.\r
1950\r
1951 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1952\r
1953 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
1954 @retval Others A device error occurred while stopping the controller.\r
1955\r
1956**/\r
1957EFI_STATUS\r
1958UfsControllerStop (\r
1959 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1960 )\r
1961{\r
1962 EFI_STATUS Status;\r
1963 UINTN Address;\r
1964 UINT32 Data;\r
1965\r
1966 //\r
1967 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1968 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1969 //\r
1970 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET; \r
1971 MmioWrite32 (Address, 0);\r
1972\r
1973 //\r
1974 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1975 // RunStop Register (UTRLRSR) to '1'.\r
1976 //\r
1977 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET; \r
1978 MmioWrite32 (Address, 0);\r
1979\r
1980 //\r
1981 // Write a 0 to the HCE register in order to disable the host controller.\r
1982 //\r
1983 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1984 Data = MmioRead32 (Address);\r
1985 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
1986 MmioWrite32 (Address, 0);\r
1987\r
1988 //\r
1989 // Wait until HCE is read as '0' before continuing.\r
1990 //\r
1991 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1992 if (EFI_ERROR (Status)) {\r
1993 return EFI_DEVICE_ERROR;\r
1994 }\r
1995\r
1996 DEBUG ((EFI_D_INFO, "UfsController is stopped\n"));\r
1997\r
1998 return EFI_SUCCESS;\r
1999}\r
2000\r