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