]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
IntelFsp2WrapperPkg: Apply uncrustify changes
[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
87000d77 83 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
0591696e
FT
84 break;\r
85 case 0x02:\r
87000d77 86 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
0591696e
FT
87 break;\r
88 case 0x03:\r
87000d77 89 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
90 break;\r
91 case 0x04:\r
87000d77 92 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
93 break;\r
94 case 0x05:\r
87000d77 95 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
0591696e
FT
96 break;\r
97 case 0x06:\r
87000d77 98 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
0591696e
FT
99 break;\r
100 case 0x07:\r
87000d77 101 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
0591696e
FT
102 break;\r
103 case 0x08:\r
87000d77 104 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
d1102dba 105 break;\r
0591696e 106 case 0x09:\r
87000d77 107 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
0591696e
FT
108 break;\r
109 case 0x0A:\r
87000d77 110 DEBUG ((DEBUG_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
87000d77 121 DEBUG ((DEBUG_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
87000d77 143 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
0591696e
FT
144 break;\r
145 case 0xF7:\r
87000d77 146 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
0591696e
FT
147 break;\r
148 case 0xF8:\r
87000d77 149 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));\r
0591696e
FT
150 break;\r
151 case 0xF9:\r
87000d77 152 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));\r
0591696e
FT
153 break;\r
154 case 0xFA:\r
87000d77 155 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));\r
0591696e
FT
156 break;\r
157 case 0xFB:\r
87000d77 158 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));\r
0591696e
FT
159 break;\r
160 case 0xFC:\r
87000d77 161 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));\r
0591696e
FT
162 break;\r
163 case 0xFD:\r
87000d77 164 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));\r
0591696e
FT
165 break;\r
166 case 0xFE:\r
87000d77 167 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));\r
d1102dba 168 break;\r
0591696e 169 case 0xFF:\r
87000d77 170 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));\r
0591696e
FT
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
87000d77 328 DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));\r
d945390d
FT
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
cd70b1a7
AS
980 //\r
981 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value\r
982 //\r
983 *Value = *((UINT8*)&(QueryResp->Tsf.Value) + 3);\r
0591696e
FT
984 } else {\r
985 Status = EFI_DEVICE_ERROR;\r
986 }\r
987\r
988Exit:\r
989 UfsStopExecCmd (Private, Slot);\r
990 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
991\r
992 return Status;\r
993}\r
994\r
995/**\r
996 Set specified flag to 1 on a UFS device.\r
997\r
998 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
999 @param[in] FlagId The ID of flag to be set.\r
1000\r
1001 @retval EFI_SUCCESS The flag was set successfully.\r
1002 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.\r
1003 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.\r
1004\r
1005**/\r
1006EFI_STATUS\r
1007UfsSetFlag (\r
1008 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1009 IN UINT8 FlagId\r
1010 )\r
1011{\r
1012 EFI_STATUS Status;\r
1013 UINT8 Value;\r
1014\r
1015 Value = 1;\r
1016 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1017\r
1018 return Status;\r
1019}\r
1020\r
0591696e 1021\r
0591696e
FT
1022\r
1023/**\r
1024 Sends NOP IN cmd to a UFS device for initialization process request.\r
1025 For more details, please refer to UFS 2.0 spec Figure 13.3.\r
1026\r
1027 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1028\r
1029 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was\r
1030 received successfully.\r
1031 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.\r
1032 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1033 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.\r
1034\r
1035**/\r
1036EFI_STATUS\r
1037UfsExecNopCmds (\r
1038 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1039 )\r
1040{\r
1041 EFI_STATUS Status;\r
1042 UINT8 Slot;\r
1043 UTP_TRD *Trd;\r
1044 UTP_NOP_IN_UPIU *NopInUpiu;\r
1045 UINT8 *CmdDescBase;\r
1046 UINT32 CmdDescSize;\r
1047 UINTN Address;\r
1048\r
1049 //\r
1050 // Find out which slot of transfer request list is available.\r
1051 //\r
1052 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1053 if (EFI_ERROR (Status)) {\r
1054 return Status;\r
1055 }\r
1056\r
1057 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1058 Status = UfsCreateNopCommandDesc (Private, Trd);\r
1059 if (EFI_ERROR (Status)) {\r
1060 return Status;\r
1061 }\r
1062\r
1063 //\r
1064 // Check the transfer request result.\r
1065 //\r
1066 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
1067 NopInUpiu = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
1068 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1069\r
1070 //\r
1071 // Start to execute the transfer request.\r
1072 //\r
1073 UfsStartExecCmd (Private, Slot);\r
1074\r
1075 //\r
1076 // Wait for the completion of the transfer request.\r
d1102dba
LG
1077 //\r
1078 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
a68093d5 1079 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);\r
0591696e
FT
1080 if (EFI_ERROR (Status)) {\r
1081 goto Exit;\r
1082 }\r
1083\r
1084 if (NopInUpiu->Resp != 0) {\r
1085 Status = EFI_DEVICE_ERROR;\r
1086 } else {\r
1087 Status = EFI_SUCCESS;\r
1088 }\r
1089\r
1090Exit:\r
1091 UfsStopExecCmd (Private, Slot);\r
1092 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
1093\r
1094 return Status;\r
1095}\r
1096\r
1097/**\r
1098 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
1099\r
1100 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1101 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.\r
1102 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the\r
1103 UFS device.\r
1104\r
1105 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional\r
1106 commands, InTransferLength bytes were transferred from\r
1107 InDataBuffer. For write and bi-directional commands,\r
1108 OutTransferLength bytes were transferred by\r
1109 OutDataBuffer.\r
1110 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request\r
1111 Packet.\r
1112 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1113 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
1114\r
1115**/\r
1116EFI_STATUS\r
1117UfsExecScsiCmds (\r
1118 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1119 IN UINT8 Lun,\r
1120 IN OUT UFS_SCSI_REQUEST_PACKET *Packet\r
1121 )\r
1122{\r
1123 EFI_STATUS Status;\r
1124 UINT8 Slot;\r
1125 UTP_TRD *Trd;\r
1126 UINTN Address;\r
1127 UINT8 *CmdDescBase;\r
1128 UINT32 CmdDescSize;\r
1129 UTP_RESPONSE_UPIU *Response;\r
1130 UINT16 SenseDataLen;\r
1131 UINT32 ResTranCount;\r
44a0857e 1132 VOID *PacketBufferMap;\r
0591696e
FT
1133\r
1134 //\r
1135 // Find out which slot of transfer request list is available.\r
1136 //\r
1137 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1138 if (EFI_ERROR (Status)) {\r
1139 return Status;\r
1140 }\r
1141\r
1142 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
44a0857e 1143 PacketBufferMap = NULL;\r
0591696e
FT
1144\r
1145 //\r
1146 // Fill transfer request descriptor to this slot.\r
1147 //\r
44a0857e 1148 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &PacketBufferMap);\r
0591696e
FT
1149 if (EFI_ERROR (Status)) {\r
1150 return Status;\r
1151 }\r
1152\r
1153 CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
1154 CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);\r
1155\r
1156 //\r
1157 // Start to execute the transfer request.\r
1158 //\r
1159 UfsStartExecCmd (Private, Slot);\r
1160\r
1161 //\r
1162 // Wait for the completion of the transfer request.\r
d1102dba
LG
1163 //\r
1164 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
a68093d5 1165 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);\r
0591696e
FT
1166 if (EFI_ERROR (Status)) {\r
1167 goto Exit;\r
1168 }\r
1169\r
1170 //\r
1171 // Get sense data if exists\r
1172 //\r
1173 Response = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
1174 SenseDataLen = Response->SenseDataLen;\r
1175 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
d1102dba 1176\r
0591696e 1177 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
8894c90d
HW
1178 //\r
1179 // Make sure the hardware device does not return more data than expected.\r
1180 //\r
1181 if (SenseDataLen <= Packet->SenseDataLength) {\r
1182 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
1183 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
1184 } else {\r
1185 Packet->SenseDataLength = 0;\r
1186 }\r
0591696e
FT
1187 }\r
1188\r
1189 //\r
1190 // Check the transfer request result.\r
1191 //\r
1192 if (Response->Response != 0) {\r
87000d77 1193 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
0591696e
FT
1194 Status = EFI_DEVICE_ERROR;\r
1195 goto Exit;\r
1196 }\r
1197\r
1198 if (Trd->Ocs == 0) {\r
1199 if (Packet->DataDirection == UfsDataIn) {\r
1200 if ((Response->Flags & BIT5) == BIT5) {\r
1201 ResTranCount = Response->ResTranCount;\r
1202 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1203 Packet->InTransferLength -= ResTranCount;\r
1204 }\r
1205 } else if (Packet->DataDirection == UfsDataOut) {\r
1206 if ((Response->Flags & BIT5) == BIT5) {\r
1207 ResTranCount = Response->ResTranCount;\r
1208 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1209 Packet->OutTransferLength -= ResTranCount;\r
1210 }\r
1211 }\r
1212 } else {\r
1213 Status = EFI_DEVICE_ERROR;\r
1214 }\r
1215\r
1216Exit:\r
44a0857e
HW
1217 if (PacketBufferMap != NULL) {\r
1218 IoMmuUnmap (PacketBufferMap);\r
1219 }\r
0591696e
FT
1220 UfsStopExecCmd (Private, Slot);\r
1221 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
1222\r
1223 return Status;\r
1224}\r
1225\r
1226\r
1227/**\r
1228 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
1229\r
1230 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1231 @param[in] UicOpcode The opcode of the UIC command.\r
1232 @param[in] Arg1 The value for 1st argument of the UIC command.\r
1233 @param[in] Arg2 The value for 2nd argument of the UIC command.\r
1234 @param[in] Arg3 The value for 3rd argument of the UIC command.\r
1235\r
1236 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.\r
1237 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
1238 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.\r
1239\r
1240**/\r
1241EFI_STATUS\r
1242UfsExecUicCommands (\r
1243 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1244 IN UINT8 UicOpcode,\r
1245 IN UINT32 Arg1,\r
1246 IN UINT32 Arg2,\r
1247 IN UINT32 Arg3\r
1248 )\r
1249{\r
1250 EFI_STATUS Status;\r
1251 UINTN Address;\r
1252 UINT32 Data;\r
1253 UINTN UfsHcBase;\r
1254\r
1255 UfsHcBase = Private->UfsHcBase;\r
1256 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1257 Data = MmioRead32 (Address);\r
1258 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
1259 //\r
1260 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
1261 //\r
1262 MmioWrite32 (Address, Data);\r
1263 }\r
1264\r
1265 //\r
1266 // When programming UIC command registers, host software shall set the register UICCMD\r
1267 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
1268 // are set.\r
1269 //\r
1270 Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;\r
1271 MmioWrite32 (Address, Arg1);\r
1272\r
1273 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
1274 MmioWrite32 (Address, Arg2);\r
1275\r
1276 Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;\r
1277 MmioWrite32 (Address, Arg3);\r
1278\r
1279 //\r
1280 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
1281 //\r
1282 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;\r
1283 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
1284 if (EFI_ERROR (Status)) {\r
1285 return Status;\r
1286 }\r
1287\r
1288 Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;\r
1289 MmioWrite32 (Address, (UINT32)UicOpcode);\r
1290\r
1291 //\r
1292 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
d1102dba 1293 // This bit is set to '1' by the host controller upon completion of a UIC command.\r
0591696e
FT
1294 //\r
1295 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1296 Data = MmioRead32 (Address);\r
1297 Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
1298 if (EFI_ERROR (Status)) {\r
1299 return Status;\r
1300 }\r
1301\r
1302 if (UicOpcode != UfsUicDmeReset) {\r
1303 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
1304 Data = MmioRead32 (Address);\r
1305 if ((Data & 0xFF) != 0) {\r
1306 DEBUG_CODE_BEGIN();\r
1307 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
1308 DEBUG_CODE_END();\r
1309 return EFI_DEVICE_ERROR;\r
1310 }\r
1311 }\r
1312\r
1313 //\r
1314 // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
1315 //\r
d1102dba 1316 Address = UfsHcBase + UFS_HC_STATUS_OFFSET;\r
0591696e
FT
1317 Data = MmioRead32 (Address);\r
1318 if ((Data & UFS_HC_HCS_DP) == 0) {\r
1319 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1320 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
1321 if (EFI_ERROR (Status)) {\r
1322 return EFI_DEVICE_ERROR;\r
1323 }\r
1324 return EFI_NOT_FOUND;\r
1325 }\r
1326\r
87000d77 1327 DEBUG ((DEBUG_INFO, "UfsblockioPei: found a attached UFS device\n"));\r
0591696e
FT
1328\r
1329 return EFI_SUCCESS;\r
1330}\r
1331\r
1332/**\r
1333 Enable the UFS host controller for accessing.\r
1334\r
1335 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1336\r
1337 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1338 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1339\r
1340**/\r
1341EFI_STATUS\r
1342UfsEnableHostController (\r
1343 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1344 )\r
1345{\r
1346 EFI_STATUS Status;\r
1347 UINTN Address;\r
1348 UINT32 Data;\r
1349\r
1350 //\r
1351 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1352 //\r
1353 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1354 //\r
1355 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1356 Data = MmioRead32 (Address);\r
1357 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1358 //\r
1359 // Write a 0 to the HCE register at first to disable the host controller.\r
1360 //\r
1361 MmioWrite32 (Address, 0);\r
1362 //\r
1363 // Wait until HCE is read as '0' before continuing.\r
1364 //\r
1365 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1366 if (EFI_ERROR (Status)) {\r
1367 return EFI_DEVICE_ERROR;\r
1368 }\r
1369 }\r
1370\r
1371 //\r
1372 // Write a 1 to the HCE register to enable the UFS host controller.\r
1373 //\r
1374 MmioWrite32 (Address, UFS_HC_HCE_EN);\r
1375 //\r
1376 // Wait until HCE is read as '1' before continuing.\r
1377 //\r
1378 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
1379 if (EFI_ERROR (Status)) {\r
1380 return EFI_DEVICE_ERROR;\r
1381 }\r
1382\r
1383 return EFI_SUCCESS;\r
1384}\r
1385\r
1386/**\r
1387 Detect if a UFS device attached.\r
1388\r
1389 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1390\r
1391 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1392 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1393 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1394\r
1395**/\r
1396EFI_STATUS\r
1397UfsDeviceDetection (\r
1398 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1399 )\r
1400{\r
1401 UINTN Retry;\r
1402 EFI_STATUS Status;\r
1403\r
1404 //\r
1405 // Start UFS device detection.\r
1406 // Try up to 3 times for establishing data link with device.\r
1407 //\r
1408 for (Retry = 0; Retry < 3; Retry++) {\r
1409 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
1410 if (!EFI_ERROR (Status)) {\r
1411 break;\r
1412 }\r
1413\r
1414 if (Status == EFI_NOT_FOUND) {\r
1415 continue;\r
1416 }\r
1417\r
1418 return EFI_DEVICE_ERROR;\r
1419 }\r
1420\r
1421 if (Retry == 3) {\r
1422 return EFI_NOT_FOUND;\r
1423 }\r
1424\r
1425 return EFI_SUCCESS;\r
1426}\r
1427\r
1428/**\r
1429 Initialize UFS task management request list related h/w context.\r
1430\r
1431 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1432\r
1433 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1434 @retval EFI_DEVICE_ERROR The initialization fails.\r
1435\r
1436**/\r
1437EFI_STATUS\r
1438UfsInitTaskManagementRequestList (\r
1439 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1440 )\r
1441{\r
1442 UINTN Address;\r
1443 UINT32 Data;\r
1444 UINT8 Nutmrs;\r
44a0857e
HW
1445 VOID *CmdDescHost;\r
1446 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1447 VOID *CmdDescMapping;\r
0591696e 1448 EFI_STATUS Status;\r
d1102dba 1449\r
0591696e
FT
1450 //\r
1451 // Initial h/w and s/w context for future operations.\r
1452 //\r
d1102dba 1453 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;\r
0591696e
FT
1454 Data = MmioRead32 (Address);\r
1455 Private->Capabilities = Data;\r
1456\r
1457 //\r
1458 // Allocate and initialize UTP Task Management Request List.\r
1459 //\r
1460 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
44a0857e 1461 Status = IoMmuAllocateBuffer (\r
0591696e 1462 EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),\r
44a0857e
HW
1463 &CmdDescHost,\r
1464 &CmdDescPhyAddr,\r
1465 &CmdDescMapping\r
0591696e 1466 );\r
0591696e
FT
1467 if (EFI_ERROR (Status)) {\r
1468 return EFI_DEVICE_ERROR;\r
1469 }\r
1470\r
44a0857e 1471 ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));\r
0591696e
FT
1472\r
1473 //\r
1474 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
1475 // Request List Base Address with a 64-bit address allocated at step 6.\r
1476 //\r
d1102dba 1477 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;\r
44a0857e 1478 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
d1102dba 1479 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;\r
44a0857e
HW
1480 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1481 Private->UtpTmrlBase = (VOID*)(UINTN)CmdDescHost;\r
0591696e 1482 Private->Nutmrs = Nutmrs;\r
44a0857e 1483 Private->TmrlMapping = CmdDescMapping;\r
0591696e
FT
1484\r
1485 //\r
1486 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1487 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1488 //\r
d1102dba 1489 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;\r
0591696e
FT
1490 MmioWrite32 (Address, UFS_HC_UTMRLRSR);\r
1491\r
1492 return EFI_SUCCESS;\r
1493}\r
1494\r
1495/**\r
1496 Initialize UFS transfer request list related h/w context.\r
1497\r
1498 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1499\r
1500 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
1501 @retval EFI_DEVICE_ERROR The initialization fails.\r
1502\r
1503**/\r
1504EFI_STATUS\r
1505UfsInitTransferRequestList (\r
1506 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1507 )\r
1508{\r
1509 UINTN Address;\r
1510 UINT32 Data;\r
1511 UINT8 Nutrs;\r
44a0857e
HW
1512 VOID *CmdDescHost;\r
1513 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1514 VOID *CmdDescMapping;\r
0591696e 1515 EFI_STATUS Status;\r
d1102dba 1516\r
0591696e
FT
1517 //\r
1518 // Initial h/w and s/w context for future operations.\r
1519 //\r
d1102dba 1520 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;\r
0591696e
FT
1521 Data = MmioRead32 (Address);\r
1522 Private->Capabilities = Data;\r
1523\r
1524 //\r
1525 // Allocate and initialize UTP Transfer Request List.\r
1526 //\r
1527 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
44a0857e 1528 Status = IoMmuAllocateBuffer (\r
0591696e 1529 EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),\r
44a0857e
HW
1530 &CmdDescHost,\r
1531 &CmdDescPhyAddr,\r
1532 &CmdDescMapping\r
0591696e 1533 );\r
0591696e
FT
1534 if (EFI_ERROR (Status)) {\r
1535 return EFI_DEVICE_ERROR;\r
1536 }\r
1537\r
44a0857e 1538 ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));\r
0591696e
FT
1539\r
1540 //\r
1541 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
1542 // Base Address with a 64-bit address allocated at step 8.\r
1543 //\r
d1102dba 1544 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;\r
44a0857e 1545 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
d1102dba 1546 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;\r
44a0857e
HW
1547 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1548 Private->UtpTrlBase = (VOID*)(UINTN)CmdDescHost;\r
0591696e 1549 Private->Nutrs = Nutrs;\r
44a0857e 1550 Private->TrlMapping = CmdDescMapping;\r
d1102dba 1551\r
0591696e
FT
1552 //\r
1553 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1554 // RunStop Register (UTRLRSR) to '1'.\r
1555 //\r
d1102dba 1556 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;\r
0591696e
FT
1557 MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
1558\r
1559 return EFI_SUCCESS;\r
1560}\r
1561\r
1562/**\r
1563 Initialize the UFS host controller.\r
1564\r
1565 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1566\r
1567 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
1568 @retval Others A device error occurred while initializing the controller.\r
1569\r
1570**/\r
1571EFI_STATUS\r
1572UfsControllerInit (\r
1573 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1574 )\r
1575{\r
1576 EFI_STATUS Status;\r
1577\r
1578 Status = UfsEnableHostController (Private);\r
1579 if (EFI_ERROR (Status)) {\r
87000d77 1580 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));\r
0591696e
FT
1581 return Status;\r
1582 }\r
1583\r
1584 Status = UfsDeviceDetection (Private);\r
1585 if (EFI_ERROR (Status)) {\r
87000d77 1586 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));\r
0591696e
FT
1587 return Status;\r
1588 }\r
1589\r
1590 Status = UfsInitTaskManagementRequestList (Private);\r
1591 if (EFI_ERROR (Status)) {\r
87000d77 1592 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
1593 return Status;\r
1594 }\r
1595\r
1596 Status = UfsInitTransferRequestList (Private);\r
1597 if (EFI_ERROR (Status)) {\r
87000d77 1598 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));\r
44a0857e
HW
1599\r
1600 if (Private->TmrlMapping != NULL) {\r
1601 IoMmuFreeBuffer (\r
1602 EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),\r
1603 Private->UtpTmrlBase,\r
1604 Private->TmrlMapping\r
1605 );\r
1606 Private->TmrlMapping = NULL;\r
1607 }\r
1608\r
0591696e
FT
1609 return Status;\r
1610 }\r
1611\r
87000d77 1612 DEBUG ((DEBUG_INFO, "UfsDevicePei Finished\n"));\r
0591696e
FT
1613 return EFI_SUCCESS;\r
1614}\r
1615\r
1616/**\r
1617 Stop the UFS host controller.\r
1618\r
1619 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1620\r
1621 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
1622 @retval Others A device error occurred while stopping the controller.\r
1623\r
1624**/\r
1625EFI_STATUS\r
1626UfsControllerStop (\r
1627 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1628 )\r
1629{\r
1630 EFI_STATUS Status;\r
1631 UINTN Address;\r
1632 UINT32 Data;\r
1633\r
1634 //\r
1635 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1636 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1637 //\r
d1102dba 1638 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;\r
0591696e
FT
1639 MmioWrite32 (Address, 0);\r
1640\r
1641 //\r
1642 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1643 // RunStop Register (UTRLRSR) to '1'.\r
1644 //\r
d1102dba 1645 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;\r
0591696e
FT
1646 MmioWrite32 (Address, 0);\r
1647\r
1648 //\r
1649 // Write a 0 to the HCE register in order to disable the host controller.\r
1650 //\r
1651 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1652 Data = MmioRead32 (Address);\r
1653 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
1654 MmioWrite32 (Address, 0);\r
1655\r
1656 //\r
1657 // Wait until HCE is read as '0' before continuing.\r
1658 //\r
1659 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1660 if (EFI_ERROR (Status)) {\r
1661 return EFI_DEVICE_ERROR;\r
1662 }\r
1663\r
87000d77 1664 DEBUG ((DEBUG_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));\r
0591696e
FT
1665\r
1666 return EFI_SUCCESS;\r
1667}\r