]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
MdeModulePkg: Refactoring UFS DME request and fix timing problem
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsBlockIoPei / UfsHci.c
CommitLineData
0591696e
FT
1/** @file\r
2\r
45920941 3 Copyright (c) 2014 - 2021, 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
1436aea4
MK
25 IN UINTN Address,\r
26 IN UINT32 MaskValue,\r
27 IN UINT32 TestValue,\r
28 IN UINT64 Timeout\r
0591696e
FT
29 )\r
30{\r
1436aea4
MK
31 UINT32 Value;\r
32 UINT64 Delay;\r
33 BOOLEAN InfiniteWait;\r
0591696e
FT
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
0591696e
FT
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
1436aea4
MK
73 IN UINT8 UicOpcode,\r
74 IN UINT8 Result\r
0591696e
FT
75 )\r
76{\r
77 if (UicOpcode <= UfsUicDmePeerSet) {\r
78 switch (Result) {\r
79 case 0x00:\r
80 break;\r
81 case 0x01:\r
87000d77 82 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
0591696e
FT
83 break;\r
84 case 0x02:\r
87000d77 85 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
0591696e
FT
86 break;\r
87 case 0x03:\r
87000d77 88 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
89 break;\r
90 case 0x04:\r
87000d77 91 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
92 break;\r
93 case 0x05:\r
87000d77 94 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
0591696e
FT
95 break;\r
96 case 0x06:\r
87000d77 97 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
0591696e
FT
98 break;\r
99 case 0x07:\r
87000d77 100 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
0591696e
FT
101 break;\r
102 case 0x08:\r
87000d77 103 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
d1102dba 104 break;\r
0591696e 105 case 0x09:\r
87000d77 106 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
0591696e
FT
107 break;\r
108 case 0x0A:\r
87000d77 109 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));\r
d1102dba 110 break;\r
1436aea4 111 default:\r
0591696e
FT
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
87000d77 120 DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));\r
d1102dba 121 break;\r
1436aea4 122 default:\r
0591696e
FT
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
1436aea4 137 IN UINT8 Result\r
0591696e
FT
138 )\r
139{\r
140 switch (Result) {\r
141 case 0xF6:\r
87000d77 142 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
0591696e
FT
143 break;\r
144 case 0xF7:\r
87000d77 145 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
0591696e
FT
146 break;\r
147 case 0xF8:\r
87000d77 148 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));\r
0591696e
FT
149 break;\r
150 case 0xF9:\r
87000d77 151 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));\r
0591696e
FT
152 break;\r
153 case 0xFA:\r
87000d77 154 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));\r
0591696e
FT
155 break;\r
156 case 0xFB:\r
87000d77 157 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));\r
0591696e
FT
158 break;\r
159 case 0xFC:\r
87000d77 160 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));\r
0591696e
FT
161 break;\r
162 case 0xFD:\r
87000d77 163 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));\r
0591696e
FT
164 break;\r
165 case 0xFE:\r
87000d77 166 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));\r
d1102dba 167 break;\r
0591696e 168 case 0xFF:\r
87000d77 169 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));\r
0591696e 170 break;\r
1436aea4 171 default:\r
0591696e
FT
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
1436aea4
MK
187 IN OUT UINT8 *Buffer,\r
188 IN UINT32 BufferSize\r
0591696e
FT
189 )\r
190{\r
1436aea4
MK
191 UINT32 Index;\r
192 UINT8 Temp;\r
193 UINT32 SwapCount;\r
0591696e
FT
194\r
195 SwapCount = BufferSize / 2;\r
196 for (Index = 0; Index < SwapCount; Index++) {\r
1436aea4
MK
197 Temp = Buffer[Index];\r
198 Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
0591696e
FT
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
1436aea4
MK
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
0591696e
FT
224 )\r
225{\r
226 ASSERT (TsfBase != NULL);\r
227 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);\r
228\r
1436aea4 229 TsfBase->Opcode = Opcode;\r
0591696e
FT
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
1436aea4 236 SwapLittleEndianToBigEndian ((UINT8 *)&Length, sizeof (Length));\r
0591696e
FT
237 TsfBase->Length = Length;\r
238 }\r
d1102dba 239\r
0591696e 240 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
1436aea4
MK
241 SwapLittleEndianToBigEndian ((UINT8 *)&Value, sizeof (Value));\r
242 TsfBase->Value = Value;\r
0591696e
FT
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
1436aea4
MK
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
0591696e
FT
270 )\r
271{\r
1436aea4 272 UINT8 Flags;\r
0591696e
FT
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
1436aea4 295 SwapLittleEndianToBigEndian ((UINT8 *)&ExpDataTranLen, sizeof (ExpDataTranLen));\r
0591696e
FT
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
1436aea4
MK
315 IN UTP_TR_PRD *Prdt,\r
316 IN VOID *Buffer,\r
317 IN UINT32 BufferSize\r
0591696e
FT
318 )\r
319{\r
1436aea4
MK
320 UINT32 PrdtIndex;\r
321 UINT32 RemainingLen;\r
322 UINT8 *Remaining;\r
323 UINTN PrdtNumber;\r
0591696e 324\r
d945390d
FT
325 if ((BufferSize & (BIT0 | BIT1)) != 0) {\r
326 BufferSize &= ~(BIT0 | BIT1);\r
87000d77 327 DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));\r
d945390d
FT
328 }\r
329\r
0591696e
FT
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
1436aea4
MK
349 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;\r
350 Remaining += UFS_MAX_DATA_LEN_PER_PRD;\r
0591696e
FT
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
1436aea4
MK
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
0591696e
FT
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
1436aea4 394 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32 *)Data);\r
0591696e
FT
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
c16eee92 403\r
1436aea4 404 SwapLittleEndianToBigEndian ((UINT8 *)&DataSize, sizeof (UINT16));\r
c16eee92 405 QueryReq->DataSegLen = (UINT16)DataSize;\r
0591696e
FT
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
44a0857e 418 @param[out] BufferMap A resulting value, if not NULL, to pass to IoMmuUnmap().\r
0591696e
FT
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
1436aea4
MK
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
0591696e
FT
432 )\r
433{\r
1436aea4
MK
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
0591696e
FT
446\r
447 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
448\r
44a0857e
HW
449 BufferPhyAddr = 0;\r
450\r
0591696e 451 if (Packet->DataDirection == UfsDataIn) {\r
44a0857e
HW
452 Buffer = Packet->InDataBuffer;\r
453 Length = Packet->InTransferLength;\r
0591696e 454 DataDirection = UfsDataIn;\r
44a0857e 455 MapOp = EdkiiIoMmuOperationBusMasterWrite;\r
0591696e 456 } else {\r
1436aea4
MK
457 Buffer = Packet->OutDataBuffer;\r
458 Length = Packet->OutTransferLength;\r
0591696e 459 DataDirection = UfsDataOut;\r
44a0857e 460 MapOp = EdkiiIoMmuOperationBusMasterRead;\r
0591696e
FT
461 }\r
462\r
463 if (Length == 0) {\r
464 DataDirection = UfsNoData;\r
44a0857e
HW
465 } else {\r
466 MapLength = Length;\r
1436aea4 467 Status = IoMmuMap (MapOp, Buffer, &MapLength, &BufferPhyAddr, BufferMap);\r
44a0857e
HW
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
0591696e
FT
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
1436aea4
MK
483 CommandUpiu = (UTP_COMMAND_UPIU *)CommandDesc;\r
484 PrdtBase = (UTP_TR_PRD *)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
0591696e
FT
485\r
486 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);\r
1436aea4 487 UfsInitUtpPrdt (PrdtBase, (VOID *)(UINTN)BufferPhyAddr, Length);\r
0591696e
FT
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
4d580428 497 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
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
1436aea4
MK
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
0591696e
FT
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
45920941
KV
554 if (((Opcode != UtpQueryFuncOpcodeRdFlag) && (Opcode != UtpQueryFuncOpcodeSetFlag) &&\r
555 (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag)) &&\r
556 ((DataSize == 0) || (Data == NULL)))\r
1436aea4 557 {\r
0591696e
FT
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
1436aea4 579 QueryReqUpiu = (UTP_QUERY_REQ_UPIU *)CommandDesc;\r
0591696e
FT
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
4d580428 598 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
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
1436aea4
MK
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
0591696e 604 } else {\r
1436aea4
MK
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
0591696e
FT
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
1436aea4
MK
625 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
626 IN UTP_TRD *Trd\r
0591696e
FT
627 )\r
628{\r
1436aea4
MK
629 UINT8 *CommandDesc;\r
630 UINTN TotalLen;\r
631 UTP_NOP_OUT_UPIU *NopOutUpiu;\r
0591696e
FT
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
1436aea4 641 NopOutUpiu = (UTP_NOP_OUT_UPIU *)CommandDesc;\r
0591696e
FT
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
4d580428 652 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
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
1436aea4
MK
672 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
673 OUT UINT8 *Slot\r
0591696e
FT
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
0591696e
FT
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
1436aea4
MK
696 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
697 IN UINT8 Slot\r
d1102dba 698 )\r
0591696e 699{\r
1436aea4
MK
700 UINTN UfsHcBase;\r
701 UINTN Address;\r
702 UINT32 Data;\r
0591696e
FT
703\r
704 UfsHcBase = Private->UfsHcBase;\r
705\r
d1102dba 706 Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;\r
0591696e
FT
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
1436aea4
MK
725 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
726 IN UINT8 Slot\r
d1102dba 727 )\r
0591696e 728{\r
1436aea4
MK
729 UINTN UfsHcBase;\r
730 UINTN Address;\r
731 UINT32 Data;\r
0591696e
FT
732\r
733 UfsHcBase = Private->UfsHcBase;\r
734\r
d1102dba 735 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
0591696e
FT
736 Data = MmioRead32 (Address);\r
737 if ((Data & (BIT0 << Slot)) != 0) {\r
d1102dba 738 Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;\r
0591696e
FT
739 Data = MmioRead32 (Address);\r
740 MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));\r
741 }\r
742}\r
743\r
744/**\r
45920941 745 Extracts return data from query response upiu.\r
0591696e 746\r
45920941
KV
747 @param[in, out] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
748 @param[in] QueryResp Pointer to the query response.\r
0591696e 749\r
45920941
KV
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
0591696e
FT
753\r
754**/\r
755EFI_STATUS\r
45920941
KV
756UfsGetReturnDataFromQueryResponse (\r
757 IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
758 IN UTP_QUERY_RESP_UPIU *QueryResp\r
0591696e
FT
759 )\r
760{\r
45920941 761 UINT16 ReturnDataSize;\r
0591696e 762\r
45920941 763 ReturnDataSize = 0;\r
0591696e 764\r
45920941
KV
765 if ((Packet == NULL) || (QueryResp == NULL)) {\r
766 return EFI_INVALID_PARAMETER;\r
0591696e 767 }\r
1436aea4 768\r
45920941
KV
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
0591696e
FT
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
d1102dba 843\r
1436aea4 844 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;\r
0591696e
FT
845 //\r
846 // Fill transfer request descriptor to this slot.\r
847 //\r
45920941 848 Status = UfsCreateDMCommandDesc (Private, Packet, Trd);\r
0591696e 849 if (EFI_ERROR (Status)) {\r
45920941 850 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));\r
0591696e
FT
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
1436aea4 858 QueryResp = (UTP_QUERY_RESP_UPIU *)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
0591696e
FT
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
d1102dba
LG
868 //\r
869 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
45920941 870 Status = UfsWaitMemSet (Address, (BIT0 << Slot), 0, Packet->Timeout);\r
0591696e
FT
871 if (EFI_ERROR (Status)) {\r
872 goto Exit;\r
873 }\r
874\r
45920941
KV
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
0591696e
FT
877 DumpQueryResponseResult (QueryResp->QueryResp);\r
878 Status = EFI_DEVICE_ERROR;\r
879 goto Exit;\r
880 }\r
881\r
45920941
KV
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
0591696e 887\r
45920941
KV
888Exit:\r
889 UfsStopExecCmd (Private, Slot);\r
890 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
8894c90d 891\r
45920941
KV
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
0591696e 923 }\r
45920941
KV
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
0591696e 967 } else {\r
45920941
KV
968 Packet.DataDirection = UfsDataOut;\r
969 Packet.OutDataBuffer = Descriptor;\r
970 Packet.OutTransferLength = DescSize;\r
971 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
0591696e
FT
972 }\r
973\r
45920941
KV
974 Packet.DescId = DescId;\r
975 Packet.Index = Index;\r
976 Packet.Selector = Selector;\r
977 Packet.Timeout = UFS_TIMEOUT;\r
0591696e 978\r
45920941 979 Status = UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
980 return Status;\r
981}\r
982\r
0591696e
FT
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
1436aea4
MK
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
0591696e
FT
1002 )\r
1003{\r
1436aea4
MK
1004 EFI_STATUS Status;\r
1005 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
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
45920941
KV
1015 Packet.DataDirection = UfsDataIn;\r
1016 Packet.InDataBuffer = (VOID *)Value;\r
1017 Packet.InTransferLength = 0;\r
1018 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
0591696e 1019 } else {\r
45920941
KV
1020 Packet.DataDirection = UfsDataOut;\r
1021 Packet.OutDataBuffer = (VOID *)Value;\r
1022 Packet.OutTransferLength = 0;\r
0591696e 1023 if (*Value == 1) {\r
1436aea4 1024 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
0591696e 1025 } else if (*Value == 0) {\r
1436aea4 1026 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;\r
0591696e
FT
1027 } else {\r
1028 return EFI_INVALID_PARAMETER;\r
1029 }\r
1030 }\r
1436aea4
MK
1031\r
1032 Packet.DescId = FlagId;\r
1033 Packet.Index = 0;\r
1034 Packet.Selector = 0;\r
1035 Packet.Timeout = UFS_TIMEOUT;\r
0591696e 1036\r
45920941 1037 Status = UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
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
1436aea4
MK
1055 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1056 IN UINT8 FlagId\r
0591696e
FT
1057 )\r
1058{\r
1436aea4
MK
1059 EFI_STATUS Status;\r
1060 UINT8 Value;\r
0591696e
FT
1061\r
1062 Value = 1;\r
1063 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1064\r
1065 return Status;\r
1066}\r
1067\r
0591696e
FT
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
1436aea4 1083 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
0591696e
FT
1084 )\r
1085{\r
1436aea4
MK
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
0591696e
FT
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
1436aea4 1102 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;\r
0591696e
FT
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
1436aea4 1112 NopInUpiu = (UTP_NOP_IN_UPIU *)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
0591696e
FT
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
d1102dba
LG
1122 //\r
1123 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
1436aea4 1124 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);\r
0591696e
FT
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
1436aea4
MK
1163 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1164 IN UINT8 Lun,\r
1165 IN OUT UFS_SCSI_REQUEST_PACKET *Packet\r
0591696e
FT
1166 )\r
1167{\r
1436aea4
MK
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
0591696e
FT
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
1436aea4 1187 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;\r
44a0857e 1188 PacketBufferMap = NULL;\r
0591696e
FT
1189\r
1190 //\r
1191 // Fill transfer request descriptor to this slot.\r
1192 //\r
44a0857e 1193 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &PacketBufferMap);\r
0591696e
FT
1194 if (EFI_ERROR (Status)) {\r
1195 return Status;\r
1196 }\r
1197\r
1436aea4 1198 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
0591696e
FT
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
d1102dba
LG
1208 //\r
1209 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
1436aea4 1210 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);\r
0591696e
FT
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
1436aea4 1218 Response = (UTP_RESPONSE_UPIU *)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
0591696e 1219 SenseDataLen = Response->SenseDataLen;\r
1436aea4 1220 SwapLittleEndianToBigEndian ((UINT8 *)&SenseDataLen, sizeof (UINT16));\r
d1102dba 1221\r
0591696e 1222 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
8894c90d
HW
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
0591696e
FT
1232 }\r
1233\r
1234 //\r
1235 // Check the transfer request result.\r
1236 //\r
1237 if (Response->Response != 0) {\r
87000d77 1238 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
0591696e
FT
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
1436aea4 1247 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));\r
0591696e
FT
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
1436aea4 1253 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));\r
0591696e
FT
1254 Packet->OutTransferLength -= ResTranCount;\r
1255 }\r
1256 }\r
1257 } else {\r
1258 Status = EFI_DEVICE_ERROR;\r
1259 }\r
1260\r
1261Exit:\r
44a0857e
HW
1262 if (PacketBufferMap != NULL) {\r
1263 IoMmuUnmap (PacketBufferMap);\r
1264 }\r
1436aea4 1265\r
0591696e
FT
1266 UfsStopExecCmd (Private, Slot);\r
1267 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
1268\r
1269 return Status;\r
1270}\r
1271\r
0591696e
FT
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
1436aea4
MK
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
0591696e
FT
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
1436aea4 1328 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
0591696e
FT
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
d1102dba 1338 // This bit is set to '1' by the host controller upon completion of a UIC command.\r
0591696e
FT
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
1436aea4
MK
1351 DEBUG_CODE_BEGIN ();\r
1352 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
1353 DEBUG_CODE_END ();\r
0591696e
FT
1354 return EFI_DEVICE_ERROR;\r
1355 }\r
1356 }\r
1357\r
1358 //\r
1359 // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
1360 //\r
d1102dba 1361 Address = UfsHcBase + UFS_HC_STATUS_OFFSET;\r
0591696e
FT
1362 Data = MmioRead32 (Address);\r
1363 if ((Data & UFS_HC_HCS_DP) == 0) {\r
1364 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1365 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
1366 if (EFI_ERROR (Status)) {\r
1367 return EFI_DEVICE_ERROR;\r
1368 }\r
1436aea4 1369\r
0591696e
FT
1370 return EFI_NOT_FOUND;\r
1371 }\r
1372\r
87000d77 1373 DEBUG ((DEBUG_INFO, "UfsblockioPei: found a attached UFS device\n"));\r
0591696e
FT
1374\r
1375 return EFI_SUCCESS;\r
1376}\r
1377\r
1378/**\r
1379 Enable the UFS host controller for accessing.\r
1380\r
1381 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1382\r
1383 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1384 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1385\r
1386**/\r
1387EFI_STATUS\r
1388UfsEnableHostController (\r
1436aea4 1389 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
0591696e
FT
1390 )\r
1391{\r
1436aea4
MK
1392 EFI_STATUS Status;\r
1393 UINTN Address;\r
1394 UINT32 Data;\r
0591696e
FT
1395\r
1396 //\r
1397 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1398 //\r
1399 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1400 //\r
1401 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1402 Data = MmioRead32 (Address);\r
1403 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1404 //\r
1405 // Write a 0 to the HCE register at first to disable the host controller.\r
1406 //\r
1407 MmioWrite32 (Address, 0);\r
1408 //\r
1409 // Wait until HCE is read as '0' before continuing.\r
1410 //\r
1411 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1412 if (EFI_ERROR (Status)) {\r
1413 return EFI_DEVICE_ERROR;\r
1414 }\r
1415 }\r
1416\r
1417 //\r
1418 // Write a 1 to the HCE register to enable the UFS host controller.\r
1419 //\r
1420 MmioWrite32 (Address, UFS_HC_HCE_EN);\r
1421 //\r
1422 // Wait until HCE is read as '1' before continuing.\r
1423 //\r
1424 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
1425 if (EFI_ERROR (Status)) {\r
1426 return EFI_DEVICE_ERROR;\r
1427 }\r
1428\r
1429 return EFI_SUCCESS;\r
1430}\r
1431\r
1432/**\r
1433 Detect if a UFS device attached.\r
1434\r
1435 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1436\r
1437 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1438 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1439 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1440\r
1441**/\r
1442EFI_STATUS\r
1443UfsDeviceDetection (\r
1436aea4 1444 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
0591696e
FT
1445 )\r
1446{\r
1436aea4
MK
1447 UINTN Retry;\r
1448 EFI_STATUS Status;\r
0591696e
FT
1449\r
1450 //\r
1451 // Start UFS device detection.\r
1452 // Try up to 3 times for establishing data link with device.\r
1453 //\r
1454 for (Retry = 0; Retry < 3; Retry++) {\r
1455 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
1456 if (!EFI_ERROR (Status)) {\r
1457 break;\r
1458 }\r
1459\r
1460 if (Status == EFI_NOT_FOUND) {\r
1461 continue;\r
1462 }\r
1463\r
1464 return EFI_DEVICE_ERROR;\r
1465 }\r
1466\r
1467 if (Retry == 3) {\r
1468 return EFI_NOT_FOUND;\r
1469 }\r
1470\r
1471 return EFI_SUCCESS;\r
1472}\r
1473\r
1474/**\r
1475 Initialize UFS task management request list related h/w context.\r
1476\r
1477 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1478\r
1479 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1480 @retval EFI_DEVICE_ERROR The initialization fails.\r
1481\r
1482**/\r
1483EFI_STATUS\r
1484UfsInitTaskManagementRequestList (\r
1436aea4 1485 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
0591696e
FT
1486 )\r
1487{\r
1436aea4
MK
1488 UINTN Address;\r
1489 UINT32 Data;\r
1490 UINT8 Nutmrs;\r
1491 VOID *CmdDescHost;\r
1492 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1493 VOID *CmdDescMapping;\r
1494 EFI_STATUS Status;\r
d1102dba 1495\r
0591696e
FT
1496 //\r
1497 // Initial h/w and s/w context for future operations.\r
1498 //\r
1436aea4
MK
1499 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;\r
1500 Data = MmioRead32 (Address);\r
0591696e
FT
1501 Private->Capabilities = Data;\r
1502\r
1503 //\r
1504 // Allocate and initialize UTP Task Management Request List.\r
1505 //\r
1436aea4 1506 Nutmrs = (UINT8)(RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
44a0857e 1507 Status = IoMmuAllocateBuffer (\r
0591696e 1508 EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),\r
44a0857e
HW
1509 &CmdDescHost,\r
1510 &CmdDescPhyAddr,\r
1511 &CmdDescMapping\r
0591696e 1512 );\r
0591696e
FT
1513 if (EFI_ERROR (Status)) {\r
1514 return EFI_DEVICE_ERROR;\r
1515 }\r
1516\r
44a0857e 1517 ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));\r
0591696e
FT
1518\r
1519 //\r
1520 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
1521 // Request List Base Address with a 64-bit address allocated at step 6.\r
1522 //\r
d1102dba 1523 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;\r
44a0857e 1524 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
d1102dba 1525 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;\r
44a0857e 1526 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1436aea4 1527 Private->UtpTmrlBase = (VOID *)(UINTN)CmdDescHost;\r
0591696e 1528 Private->Nutmrs = Nutmrs;\r
44a0857e 1529 Private->TmrlMapping = CmdDescMapping;\r
0591696e
FT
1530\r
1531 //\r
1532 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1533 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1534 //\r
d1102dba 1535 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;\r
0591696e
FT
1536 MmioWrite32 (Address, UFS_HC_UTMRLRSR);\r
1537\r
1538 return EFI_SUCCESS;\r
1539}\r
1540\r
1541/**\r
1542 Initialize UFS transfer request list related h/w context.\r
1543\r
1544 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1545\r
1546 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
1547 @retval EFI_DEVICE_ERROR The initialization fails.\r
1548\r
1549**/\r
1550EFI_STATUS\r
1551UfsInitTransferRequestList (\r
1436aea4 1552 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
0591696e
FT
1553 )\r
1554{\r
1436aea4
MK
1555 UINTN Address;\r
1556 UINT32 Data;\r
1557 UINT8 Nutrs;\r
1558 VOID *CmdDescHost;\r
1559 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1560 VOID *CmdDescMapping;\r
1561 EFI_STATUS Status;\r
d1102dba 1562\r
0591696e
FT
1563 //\r
1564 // Initial h/w and s/w context for future operations.\r
1565 //\r
1436aea4
MK
1566 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;\r
1567 Data = MmioRead32 (Address);\r
0591696e
FT
1568 Private->Capabilities = Data;\r
1569\r
1570 //\r
1571 // Allocate and initialize UTP Transfer Request List.\r
1572 //\r
1573 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
44a0857e 1574 Status = IoMmuAllocateBuffer (\r
0591696e 1575 EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),\r
44a0857e
HW
1576 &CmdDescHost,\r
1577 &CmdDescPhyAddr,\r
1578 &CmdDescMapping\r
0591696e 1579 );\r
0591696e
FT
1580 if (EFI_ERROR (Status)) {\r
1581 return EFI_DEVICE_ERROR;\r
1582 }\r
1583\r
44a0857e 1584 ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));\r
0591696e
FT
1585\r
1586 //\r
1587 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
1588 // Base Address with a 64-bit address allocated at step 8.\r
1589 //\r
d1102dba 1590 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;\r
44a0857e 1591 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
d1102dba 1592 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;\r
44a0857e 1593 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1436aea4 1594 Private->UtpTrlBase = (VOID *)(UINTN)CmdDescHost;\r
0591696e 1595 Private->Nutrs = Nutrs;\r
44a0857e 1596 Private->TrlMapping = CmdDescMapping;\r
d1102dba 1597\r
0591696e
FT
1598 //\r
1599 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1600 // RunStop Register (UTRLRSR) to '1'.\r
1601 //\r
d1102dba 1602 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;\r
0591696e
FT
1603 MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
1604\r
1605 return EFI_SUCCESS;\r
1606}\r
1607\r
1608/**\r
1609 Initialize the UFS host controller.\r
1610\r
1611 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1612\r
1613 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
1614 @retval Others A device error occurred while initializing the controller.\r
1615\r
1616**/\r
1617EFI_STATUS\r
1618UfsControllerInit (\r
1436aea4 1619 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
0591696e
FT
1620 )\r
1621{\r
1436aea4 1622 EFI_STATUS Status;\r
0591696e
FT
1623\r
1624 Status = UfsEnableHostController (Private);\r
1625 if (EFI_ERROR (Status)) {\r
87000d77 1626 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));\r
0591696e
FT
1627 return Status;\r
1628 }\r
1629\r
1630 Status = UfsDeviceDetection (Private);\r
1631 if (EFI_ERROR (Status)) {\r
87000d77 1632 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));\r
0591696e
FT
1633 return Status;\r
1634 }\r
1635\r
1636 Status = UfsInitTaskManagementRequestList (Private);\r
1637 if (EFI_ERROR (Status)) {\r
87000d77 1638 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
1639 return Status;\r
1640 }\r
1641\r
1642 Status = UfsInitTransferRequestList (Private);\r
1643 if (EFI_ERROR (Status)) {\r
87000d77 1644 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));\r
44a0857e
HW
1645\r
1646 if (Private->TmrlMapping != NULL) {\r
1647 IoMmuFreeBuffer (\r
1648 EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),\r
1649 Private->UtpTmrlBase,\r
1650 Private->TmrlMapping\r
1651 );\r
1652 Private->TmrlMapping = NULL;\r
1653 }\r
1654\r
0591696e
FT
1655 return Status;\r
1656 }\r
1657\r
87000d77 1658 DEBUG ((DEBUG_INFO, "UfsDevicePei Finished\n"));\r
0591696e
FT
1659 return EFI_SUCCESS;\r
1660}\r
1661\r
1662/**\r
1663 Stop the UFS host controller.\r
1664\r
1665 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1666\r
1667 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
1668 @retval Others A device error occurred while stopping the controller.\r
1669\r
1670**/\r
1671EFI_STATUS\r
1672UfsControllerStop (\r
1436aea4 1673 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
0591696e
FT
1674 )\r
1675{\r
1436aea4
MK
1676 EFI_STATUS Status;\r
1677 UINTN Address;\r
1678 UINT32 Data;\r
0591696e
FT
1679\r
1680 //\r
1681 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1682 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1683 //\r
d1102dba 1684 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;\r
0591696e
FT
1685 MmioWrite32 (Address, 0);\r
1686\r
1687 //\r
1688 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1689 // RunStop Register (UTRLRSR) to '1'.\r
1690 //\r
d1102dba 1691 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;\r
0591696e
FT
1692 MmioWrite32 (Address, 0);\r
1693\r
1694 //\r
1695 // Write a 0 to the HCE register in order to disable the host controller.\r
1696 //\r
1697 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1698 Data = MmioRead32 (Address);\r
1699 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
1700 MmioWrite32 (Address, 0);\r
1701\r
1702 //\r
1703 // Wait until HCE is read as '0' before continuing.\r
1704 //\r
1705 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1706 if (EFI_ERROR (Status)) {\r
1707 return EFI_DEVICE_ERROR;\r
1708 }\r
1709\r
87000d77 1710 DEBUG ((DEBUG_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));\r
0591696e
FT
1711\r
1712 return EFI_SUCCESS;\r
1713}\r