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