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