]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
MdePkg: Refine casting expression result to bigger size
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsBlockIoPei / UfsHci.c
CommitLineData
0591696e
FT
1/** @file\r
2\r
d945390d 3 Copyright (c) 2014 - 2016, 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
111 break; \r
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
117 break; \r
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
128 break; \r
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
174 break; \r
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
246 \r
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
410 }\r
411\r
412 return EFI_SUCCESS;\r
413}\r
414\r
415/**\r
416 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
417\r
418 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
419 @param[in] Lun The Lun on which the SCSI command is executed.\r
420 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.\r
421 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
422\r
423 @retval EFI_SUCCESS The creation succeed.\r
424 @retval EFI_DEVICE_ERROR The creation failed.\r
425 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
426\r
427**/\r
428EFI_STATUS\r
429UfsCreateScsiCommandDesc (\r
430 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
431 IN UINT8 Lun,\r
432 IN UFS_SCSI_REQUEST_PACKET *Packet,\r
433 IN UTP_TRD *Trd\r
434 )\r
435{\r
436 UINT8 *CommandDesc;\r
437 UINTN TotalLen;\r
438 UINTN PrdtNumber;\r
439 VOID *Buffer;\r
440 UINT32 Length;\r
441 UTP_COMMAND_UPIU *CommandUpiu;\r
442 UTP_TR_PRD *PrdtBase;\r
443 UFS_DATA_DIRECTION DataDirection;\r
444\r
445 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
446\r
447 if (Packet->DataDirection == UfsDataIn) {\r
448 Buffer = Packet->InDataBuffer;\r
449 Length = Packet->InTransferLength;\r
450 DataDirection = UfsDataIn;\r
451 } else {\r
452 Buffer = Packet->OutDataBuffer;\r
453 Length = Packet->OutTransferLength;\r
454 DataDirection = UfsDataOut;\r
455 }\r
456\r
457 if (Length == 0) {\r
458 DataDirection = UfsNoData;\r
459 }\r
460\r
461 PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
462\r
463 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);\r
464 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);\r
465 if (CommandDesc == NULL) {\r
466 return EFI_OUT_OF_RESOURCES;\r
467 }\r
468\r
469 CommandUpiu = (UTP_COMMAND_UPIU*)CommandDesc;\r
470 PrdtBase = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
471\r
472 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);\r
473 UfsInitUtpPrdt (PrdtBase, Buffer, Length);\r
474\r
475 //\r
476 // Fill UTP_TRD associated fields\r
477 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table\r
478 // *MUST* be located at a 64-bit aligned boundary.\r
479 //\r
480 Trd->Int = UFS_INTERRUPT_COMMAND;\r
481 Trd->Dd = DataDirection;\r
482 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
4d580428 483 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
484 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);\r
485 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);\r
486 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));\r
487 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));\r
488 Trd->PrdtL = (UINT16)PrdtNumber;\r
489 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));\r
490 return EFI_SUCCESS;\r
491}\r
492\r
493/**\r
494 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
495\r
496 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
497 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.\r
498 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
499\r
500 @retval EFI_SUCCESS The creation succeed.\r
501 @retval EFI_DEVICE_ERROR The creation failed.\r
502 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
503 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.\r
504\r
505**/\r
506EFI_STATUS\r
507UfsCreateDMCommandDesc (\r
508 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
509 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
510 IN UTP_TRD *Trd\r
511 )\r
512{\r
513 UINT8 *CommandDesc;\r
514 UINTN TotalLen;\r
515 UTP_QUERY_REQ_UPIU *QueryReqUpiu;\r
516 UINT8 Opcode;\r
517 UINT32 DataSize;\r
518 UINT8 *Data;\r
519 UINT8 DataDirection;\r
520\r
521 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
522\r
523 Opcode = Packet->Opcode;\r
524 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {\r
525 return EFI_INVALID_PARAMETER;\r
526 }\r
527\r
528 DataDirection = Packet->DataDirection;\r
529 if (DataDirection == UfsDataIn) {\r
530 DataSize = Packet->InTransferLength;\r
531 Data = Packet->InDataBuffer;\r
532 } else if (DataDirection == UfsDataOut) {\r
533 DataSize = Packet->OutTransferLength;\r
534 Data = Packet->OutDataBuffer;\r
535 } else {\r
536 DataSize = 0;\r
537 Data = NULL;\r
538 }\r
539\r
540 if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))\r
541 && ((DataSize == 0) || (Data == NULL))) {\r
542 return EFI_INVALID_PARAMETER;\r
543 }\r
544\r
545 if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))\r
546 && ((DataSize != 0) || (Data != NULL))) {\r
547 return EFI_INVALID_PARAMETER;\r
548 }\r
549\r
550 if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {\r
551 return EFI_INVALID_PARAMETER;\r
552 }\r
553\r
554 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {\r
555 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);\r
556 } else {\r
557 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));\r
558 }\r
559\r
560 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);\r
561 if (CommandDesc == NULL) {\r
562 return EFI_OUT_OF_RESOURCES;\r
563 }\r
564\r
565 //\r
566 // Initialize UTP QUERY REQUEST UPIU\r
567 //\r
568 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;\r
569 UfsInitQueryRequestUpiu (\r
570 QueryReqUpiu,\r
571 Private->TaskTag++,\r
572 Opcode,\r
573 Packet->DescId,\r
574 Packet->Index,\r
575 Packet->Selector,\r
576 DataSize,\r
577 Data\r
578 );\r
579\r
580 //\r
581 // Fill UTP_TRD associated fields\r
582 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.\r
583 //\r
584 Trd->Int = UFS_INTERRUPT_COMMAND;\r
585 Trd->Dd = DataDirection;\r
586 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
4d580428 587 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
588 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);\r
589 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);\r
590 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
591 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));\r
592 Trd->RuO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
593 } else {\r
594 Trd->RuL = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
595 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));\r
596 }\r
597\r
598 return EFI_SUCCESS;\r
599}\r
600\r
601/**\r
602 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.\r
603\r
604 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
605 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
606\r
607 @retval EFI_SUCCESS The creation succeed.\r
608 @retval EFI_DEVICE_ERROR The creation failed.\r
609 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
610\r
611**/\r
612EFI_STATUS\r
613UfsCreateNopCommandDesc (\r
614 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
615 IN UTP_TRD *Trd\r
616 )\r
617{\r
618 UINT8 *CommandDesc;\r
619 UINTN TotalLen;\r
620 UTP_NOP_OUT_UPIU *NopOutUpiu;\r
621\r
622 ASSERT ((Private != NULL) && (Trd != NULL));\r
623\r
624 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));\r
625 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);\r
626 if (CommandDesc == NULL) {\r
627 return EFI_OUT_OF_RESOURCES;\r
628 }\r
629\r
630 NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;\r
631\r
632 NopOutUpiu->TaskTag = Private->TaskTag++;\r
633\r
634 //\r
635 // Fill UTP_TRD associated fields\r
636 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.\r
637 //\r
638 Trd->Int = UFS_INTERRUPT_COMMAND;\r
639 Trd->Dd = 0x00;\r
640 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
4d580428 641 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
642 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);\r
643 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);\r
644 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));\r
645 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));\r
646\r
647 return EFI_SUCCESS;\r
648}\r
649\r
650/**\r
651 Find out available slot in transfer list of a UFS device.\r
652\r
653 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
654 @param[out] Slot The available slot.\r
655\r
656 @retval EFI_SUCCESS The available slot was found successfully.\r
657\r
658**/\r
659EFI_STATUS\r
660UfsFindAvailableSlotInTrl (\r
661 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
662 OUT UINT8 *Slot\r
663 )\r
664{\r
665 ASSERT ((Private != NULL) && (Slot != NULL));\r
666\r
667 //\r
668 // The simplest algo to always use slot 0.\r
669 // TODO: enhance it to support async transfer with multiple slot.\r
670 //\r
671 *Slot = 0;\r
672\r
673 return EFI_SUCCESS;\r
674}\r
675\r
676/**\r
677 Find out available slot in task management transfer list of a UFS device.\r
678\r
679 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
680 @param[out] Slot The available slot.\r
681\r
682 @retval EFI_SUCCESS The available slot was found successfully.\r
683\r
684**/\r
685EFI_STATUS\r
686UfsFindAvailableSlotInTmrl (\r
687 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
688 OUT UINT8 *Slot\r
689 )\r
690{\r
691 ASSERT ((Private != NULL) && (Slot != NULL));\r
692\r
693 //\r
694 // The simplest algo to always use slot 0.\r
695 // TODO: enhance it to support async transfer with multiple slot.\r
696 //\r
697 *Slot = 0;\r
698\r
699 return EFI_SUCCESS;\r
700}\r
701\r
702/**\r
703 Start specified slot in transfer list of a UFS device.\r
704\r
705 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
706 @param[in] Slot The slot to be started.\r
707\r
708**/\r
709VOID\r
710UfsStartExecCmd (\r
711 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
712 IN UINT8 Slot\r
713 ) \r
714{\r
715 UINTN UfsHcBase;\r
716 UINTN Address;\r
717 UINT32 Data;\r
718\r
719 UfsHcBase = Private->UfsHcBase;\r
720\r
721 Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET; \r
722 Data = MmioRead32 (Address);\r
723 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
724 MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
725 }\r
726\r
727 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
728 MmioWrite32 (Address, BIT0 << Slot);\r
729}\r
730\r
731/**\r
732 Stop specified slot in transfer list of a UFS device.\r
733\r
734 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
735 @param[in] Slot The slot to be stop.\r
736\r
737**/\r
738VOID\r
739UfsStopExecCmd (\r
740 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
741 IN UINT8 Slot\r
742 ) \r
743{\r
744 UINTN UfsHcBase;\r
745 UINTN Address;\r
746 UINT32 Data;\r
747\r
748 UfsHcBase = Private->UfsHcBase;\r
749\r
750 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
751 Data = MmioRead32 (Address);\r
752 if ((Data & (BIT0 << Slot)) != 0) {\r
753 Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET; \r
754 Data = MmioRead32 (Address);\r
755 MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));\r
756 }\r
757}\r
758\r
759/**\r
760 Read or write specified device descriptor of a UFS device.\r
761\r
762 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
763 @param[in] Read The boolean variable to show r/w direction.\r
764 @param[in] DescId The ID of device descriptor.\r
765 @param[in] Index The Index of device descriptor.\r
766 @param[in] Selector The Selector of device descriptor.\r
767 @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
768 @param[in] DescSize The size of device descriptor buffer.\r
769\r
770 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
771 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
772 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
773\r
774**/\r
775EFI_STATUS\r
776UfsRwDeviceDesc (\r
777 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
778 IN BOOLEAN Read,\r
779 IN UINT8 DescId,\r
780 IN UINT8 Index,\r
781 IN UINT8 Selector,\r
782 IN OUT VOID *Descriptor,\r
783 IN UINT32 DescSize\r
784 )\r
785{\r
786 EFI_STATUS Status;\r
787 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
788 UINT8 Slot;\r
789 UTP_TRD *Trd;\r
790 UINTN Address;\r
791 UTP_QUERY_RESP_UPIU *QueryResp;\r
792 UINT8 *CmdDescBase;\r
793 UINT32 CmdDescSize;\r
794 UINT16 ReturnDataSize;\r
795\r
796 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
797\r
798 if (Read) {\r
799 Packet.DataDirection = UfsDataIn;\r
800 Packet.InDataBuffer = Descriptor;\r
801 Packet.InTransferLength = DescSize;\r
802 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
803 } else {\r
804 Packet.DataDirection = UfsDataOut;\r
805 Packet.OutDataBuffer = Descriptor;\r
806 Packet.OutTransferLength = DescSize;\r
807 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
808 }\r
809 Packet.DescId = DescId;\r
810 Packet.Index = Index;\r
811 Packet.Selector = Selector;\r
812 Packet.Timeout = UFS_TIMEOUT;\r
813\r
814 //\r
815 // Find out which slot of transfer request list is available.\r
816 //\r
817 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
818 if (EFI_ERROR (Status)) {\r
819 return Status;\r
820 }\r
821 \r
822 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
823 //\r
824 // Fill transfer request descriptor to this slot.\r
825 //\r
826 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
827 if (EFI_ERROR (Status)) {\r
828 return Status;\r
829 }\r
830\r
831 //\r
832 // Check the transfer request result.\r
833 //\r
834 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
835 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
836 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
837\r
838 //\r
839 // Start to execute the transfer request.\r
840 //\r
841 UfsStartExecCmd (Private, Slot);\r
842\r
843 //\r
844 // Wait for the completion of the transfer request.\r
845 // \r
846 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
a68093d5 847 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);\r
0591696e
FT
848 if (EFI_ERROR (Status)) {\r
849 goto Exit;\r
850 }\r
851\r
852 if (QueryResp->QueryResp != 0) {\r
853 DumpQueryResponseResult (QueryResp->QueryResp);\r
854 Status = EFI_DEVICE_ERROR;\r
855 goto Exit;\r
856 }\r
857\r
858 if (Trd->Ocs == 0) {\r
859 ReturnDataSize = QueryResp->Tsf.Length;\r
860 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
861\r
862 if (Read) {\r
863 CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);\r
864 Packet.InTransferLength = ReturnDataSize;\r
865 } else {\r
866 Packet.OutTransferLength = ReturnDataSize;\r
867 }\r
868 } else {\r
869 Status = EFI_DEVICE_ERROR;\r
870 }\r
871\r
872Exit:\r
873 UfsStopExecCmd (Private, Slot);\r
874 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
875\r
876 return Status;\r
877}\r
878\r
879/**\r
880 Read or write specified attribute of a UFS device.\r
881\r
882 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
883 @param[in] Read The boolean variable to show r/w direction.\r
884 @param[in] AttrId The ID of Attribute.\r
885 @param[in] Index The Index of Attribute.\r
886 @param[in] Selector The Selector of Attribute.\r
887 @param[in, out] Attributes The value of Attribute to be read or written.\r
888\r
889 @retval EFI_SUCCESS The Attribute was read/written successfully.\r
890 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.\r
891 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.\r
892\r
893**/\r
894EFI_STATUS\r
895UfsRwAttributes (\r
896 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
897 IN BOOLEAN Read,\r
898 IN UINT8 AttrId,\r
899 IN UINT8 Index,\r
900 IN UINT8 Selector,\r
901 IN OUT UINT32 *Attributes\r
902 )\r
903{\r
904 EFI_STATUS Status;\r
905 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
906 UINT8 Slot;\r
907 UTP_TRD *Trd;\r
908 UINTN Address;\r
909 UTP_QUERY_RESP_UPIU *QueryResp;\r
910 UINT8 *CmdDescBase;\r
911 UINT32 CmdDescSize;\r
912 UINT32 ReturnData;\r
913\r
914 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
915\r
916 if (Read) {\r
917 Packet.DataDirection = UfsDataIn;\r
918 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;\r
919 } else {\r
920 Packet.DataDirection = UfsDataOut;\r
921 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;\r
922 }\r
923 Packet.DescId = AttrId;\r
924 Packet.Index = Index;\r
925 Packet.Selector = Selector;\r
926 Packet.Timeout = UFS_TIMEOUT;\r
927\r
928 //\r
929 // Find out which slot of transfer request list is available.\r
930 //\r
931 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
932 if (EFI_ERROR (Status)) {\r
933 return Status;\r
934 }\r
935 \r
936 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
937 //\r
938 // Fill transfer request descriptor to this slot.\r
939 //\r
940 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
941 if (EFI_ERROR (Status)) {\r
942 return Status;\r
943 }\r
944\r
945 //\r
946 // Check the transfer request result.\r
947 //\r
948 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
949 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
950 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
951\r
952 //\r
953 // Start to execute the transfer request.\r
954 //\r
955 UfsStartExecCmd (Private, Slot);\r
956\r
957 //\r
958 // Wait for the completion of the transfer request.\r
959 // \r
960 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
a68093d5 961 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);\r
0591696e
FT
962 if (EFI_ERROR (Status)) {\r
963 goto Exit;\r
964 }\r
965\r
966 if (QueryResp->QueryResp != 0) {\r
967 DumpQueryResponseResult (QueryResp->QueryResp);\r
968 Status = EFI_DEVICE_ERROR;\r
969 goto Exit;\r
970 }\r
971\r
972 if (Trd->Ocs == 0) {\r
973 ReturnData = QueryResp->Tsf.Value;\r
974 SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));\r
975 *Attributes = ReturnData;\r
976 } else {\r
977 Status = EFI_DEVICE_ERROR;\r
978 }\r
979\r
980Exit:\r
981 UfsStopExecCmd (Private, Slot);\r
982 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
983\r
984 return Status;\r
985}\r
986\r
987/**\r
988 Read or write specified flag of a UFS device.\r
989\r
990 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
991 @param[in] Read The boolean variable to show r/w direction.\r
992 @param[in] FlagId The ID of flag to be read or written.\r
993 @param[in, out] Value The value to set or clear flag.\r
994\r
995 @retval EFI_SUCCESS The flag was read/written successfully.\r
996 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.\r
997 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.\r
998\r
999**/\r
1000EFI_STATUS\r
1001UfsRwFlags (\r
1002 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1003 IN BOOLEAN Read,\r
1004 IN UINT8 FlagId,\r
1005 IN OUT UINT8 *Value\r
1006 )\r
1007{\r
1008 EFI_STATUS Status;\r
1009 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
1010 UINT8 Slot;\r
1011 UTP_TRD *Trd;\r
1012 UINTN Address;\r
1013 UTP_QUERY_RESP_UPIU *QueryResp;\r
1014 UINT8 *CmdDescBase;\r
1015 UINT32 CmdDescSize;\r
1016\r
1017 if (Value == NULL) {\r
1018 return EFI_INVALID_PARAMETER;\r
1019 }\r
1020\r
1021 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1022\r
1023 if (Read) {\r
1024 ASSERT (Value != NULL);\r
1025 Packet.DataDirection = UfsDataIn;\r
1026 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
1027 } else {\r
1028 Packet.DataDirection = UfsDataOut;\r
1029 if (*Value == 1) {\r
1030 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
1031 } else if (*Value == 0) {\r
1032 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;\r
1033 } else {\r
1034 return EFI_INVALID_PARAMETER;\r
1035 }\r
1036 }\r
1037 Packet.DescId = FlagId;\r
1038 Packet.Index = 0;\r
1039 Packet.Selector = 0;\r
1040 Packet.Timeout = UFS_TIMEOUT;\r
1041\r
1042 //\r
1043 // Find out which slot of transfer request list is available.\r
1044 //\r
1045 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1046 if (EFI_ERROR (Status)) {\r
1047 return Status;\r
1048 }\r
1049\r
1050 //\r
1051 // Fill transfer request descriptor to this slot.\r
1052 //\r
1053 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1054 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
1055 if (EFI_ERROR (Status)) {\r
1056 return Status;\r
1057 }\r
1058\r
1059 //\r
1060 // Check the transfer request result.\r
1061 //\r
1062 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
1063 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
1064 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1065\r
1066 //\r
1067 // Start to execute the transfer request.\r
1068 //\r
1069 UfsStartExecCmd (Private, Slot);\r
1070\r
1071 //\r
1072 // Wait for the completion of the transfer request.\r
1073 // \r
1074 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
a68093d5 1075 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);\r
0591696e
FT
1076 if (EFI_ERROR (Status)) {\r
1077 goto Exit;\r
1078 }\r
1079\r
1080 if (QueryResp->QueryResp != 0) {\r
1081 DumpQueryResponseResult (QueryResp->QueryResp);\r
1082 Status = EFI_DEVICE_ERROR;\r
1083 goto Exit;\r
1084 }\r
1085\r
1086 if (Trd->Ocs == 0) {\r
1087 *Value = (UINT8)QueryResp->Tsf.Value;\r
1088 } else {\r
1089 Status = EFI_DEVICE_ERROR;\r
1090 }\r
1091\r
1092Exit:\r
1093 UfsStopExecCmd (Private, Slot);\r
1094 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
1095\r
1096 return Status;\r
1097}\r
1098\r
1099/**\r
1100 Set specified flag to 1 on a UFS device.\r
1101\r
1102 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1103 @param[in] FlagId The ID of flag to be set.\r
1104\r
1105 @retval EFI_SUCCESS The flag was set successfully.\r
1106 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.\r
1107 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.\r
1108\r
1109**/\r
1110EFI_STATUS\r
1111UfsSetFlag (\r
1112 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1113 IN UINT8 FlagId\r
1114 )\r
1115{\r
1116 EFI_STATUS Status;\r
1117 UINT8 Value;\r
1118\r
1119 Value = 1;\r
1120 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1121\r
1122 return Status;\r
1123}\r
1124\r
1125/**\r
1126 Clear specified flag to 0 on a UFS device.\r
1127\r
1128 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1129 @param[in] FlagId The ID of flag to be cleared.\r
1130\r
1131 @retval EFI_SUCCESS The flag was cleared successfully.\r
1132 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.\r
1133 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.\r
1134\r
1135**/\r
1136EFI_STATUS\r
1137UfsClearFlag (\r
1138 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1139 IN UINT8 FlagId\r
1140 )\r
1141{\r
1142 EFI_STATUS Status;\r
1143 UINT8 Value;\r
1144\r
1145 Value = 0;\r
1146 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1147\r
1148 return Status;\r
1149}\r
1150\r
1151/**\r
1152 Read specified flag from a UFS device.\r
1153\r
1154 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1155 @param[in] FlagId The ID of flag to be read.\r
1156 @param[out] Value The flag's value.\r
1157\r
1158 @retval EFI_SUCCESS The flag was read successfully.\r
1159 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.\r
1160 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.\r
1161\r
1162**/\r
1163EFI_STATUS\r
1164UfsReadFlag (\r
1165 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1166 IN UINT8 FlagId,\r
1167 OUT UINT8 *Value\r
1168 )\r
1169{\r
1170 EFI_STATUS Status;\r
1171\r
1172 Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
1173\r
1174 return Status;\r
1175}\r
1176\r
1177/**\r
1178 Sends NOP IN cmd to a UFS device for initialization process request.\r
1179 For more details, please refer to UFS 2.0 spec Figure 13.3.\r
1180\r
1181 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1182\r
1183 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was\r
1184 received successfully.\r
1185 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.\r
1186 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1187 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.\r
1188\r
1189**/\r
1190EFI_STATUS\r
1191UfsExecNopCmds (\r
1192 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1193 )\r
1194{\r
1195 EFI_STATUS Status;\r
1196 UINT8 Slot;\r
1197 UTP_TRD *Trd;\r
1198 UTP_NOP_IN_UPIU *NopInUpiu;\r
1199 UINT8 *CmdDescBase;\r
1200 UINT32 CmdDescSize;\r
1201 UINTN Address;\r
1202\r
1203 //\r
1204 // Find out which slot of transfer request list is available.\r
1205 //\r
1206 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1207 if (EFI_ERROR (Status)) {\r
1208 return Status;\r
1209 }\r
1210\r
1211 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1212 Status = UfsCreateNopCommandDesc (Private, Trd);\r
1213 if (EFI_ERROR (Status)) {\r
1214 return Status;\r
1215 }\r
1216\r
1217 //\r
1218 // Check the transfer request result.\r
1219 //\r
1220 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
1221 NopInUpiu = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
1222 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1223\r
1224 //\r
1225 // Start to execute the transfer request.\r
1226 //\r
1227 UfsStartExecCmd (Private, Slot);\r
1228\r
1229 //\r
1230 // Wait for the completion of the transfer request.\r
1231 // \r
1232 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
a68093d5 1233 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);\r
0591696e
FT
1234 if (EFI_ERROR (Status)) {\r
1235 goto Exit;\r
1236 }\r
1237\r
1238 if (NopInUpiu->Resp != 0) {\r
1239 Status = EFI_DEVICE_ERROR;\r
1240 } else {\r
1241 Status = EFI_SUCCESS;\r
1242 }\r
1243\r
1244Exit:\r
1245 UfsStopExecCmd (Private, Slot);\r
1246 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
1247\r
1248 return Status;\r
1249}\r
1250\r
1251/**\r
1252 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
1253\r
1254 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1255 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.\r
1256 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the\r
1257 UFS device.\r
1258\r
1259 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional\r
1260 commands, InTransferLength bytes were transferred from\r
1261 InDataBuffer. For write and bi-directional commands,\r
1262 OutTransferLength bytes were transferred by\r
1263 OutDataBuffer.\r
1264 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request\r
1265 Packet.\r
1266 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1267 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
1268\r
1269**/\r
1270EFI_STATUS\r
1271UfsExecScsiCmds (\r
1272 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1273 IN UINT8 Lun,\r
1274 IN OUT UFS_SCSI_REQUEST_PACKET *Packet\r
1275 )\r
1276{\r
1277 EFI_STATUS Status;\r
1278 UINT8 Slot;\r
1279 UTP_TRD *Trd;\r
1280 UINTN Address;\r
1281 UINT8 *CmdDescBase;\r
1282 UINT32 CmdDescSize;\r
1283 UTP_RESPONSE_UPIU *Response;\r
1284 UINT16 SenseDataLen;\r
1285 UINT32 ResTranCount;\r
1286\r
1287 //\r
1288 // Find out which slot of transfer request list is available.\r
1289 //\r
1290 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1291 if (EFI_ERROR (Status)) {\r
1292 return Status;\r
1293 }\r
1294\r
1295 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1296\r
1297 //\r
1298 // Fill transfer request descriptor to this slot.\r
1299 //\r
1300 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd);\r
1301 if (EFI_ERROR (Status)) {\r
1302 return Status;\r
1303 }\r
1304\r
1305 CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
1306 CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);\r
1307\r
1308 //\r
1309 // Start to execute the transfer request.\r
1310 //\r
1311 UfsStartExecCmd (Private, Slot);\r
1312\r
1313 //\r
1314 // Wait for the completion of the transfer request.\r
1315 // \r
1316 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET; \r
a68093d5 1317 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);\r
0591696e
FT
1318 if (EFI_ERROR (Status)) {\r
1319 goto Exit;\r
1320 }\r
1321\r
1322 //\r
1323 // Get sense data if exists\r
1324 //\r
1325 Response = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
1326 SenseDataLen = Response->SenseDataLen;\r
1327 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
1328 \r
1329 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
1330 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
1331 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
1332 }\r
1333\r
1334 //\r
1335 // Check the transfer request result.\r
1336 //\r
1337 if (Response->Response != 0) {\r
1338 DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
1339 Status = EFI_DEVICE_ERROR;\r
1340 goto Exit;\r
1341 }\r
1342\r
1343 if (Trd->Ocs == 0) {\r
1344 if (Packet->DataDirection == UfsDataIn) {\r
1345 if ((Response->Flags & BIT5) == BIT5) {\r
1346 ResTranCount = Response->ResTranCount;\r
1347 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1348 Packet->InTransferLength -= ResTranCount;\r
1349 }\r
1350 } else if (Packet->DataDirection == UfsDataOut) {\r
1351 if ((Response->Flags & BIT5) == BIT5) {\r
1352 ResTranCount = Response->ResTranCount;\r
1353 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1354 Packet->OutTransferLength -= ResTranCount;\r
1355 }\r
1356 }\r
1357 } else {\r
1358 Status = EFI_DEVICE_ERROR;\r
1359 }\r
1360\r
1361Exit:\r
1362 UfsStopExecCmd (Private, Slot);\r
1363 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
1364\r
1365 return Status;\r
1366}\r
1367\r
1368\r
1369/**\r
1370 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
1371\r
1372 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1373 @param[in] UicOpcode The opcode of the UIC command.\r
1374 @param[in] Arg1 The value for 1st argument of the UIC command.\r
1375 @param[in] Arg2 The value for 2nd argument of the UIC command.\r
1376 @param[in] Arg3 The value for 3rd argument of the UIC command.\r
1377\r
1378 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.\r
1379 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
1380 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.\r
1381\r
1382**/\r
1383EFI_STATUS\r
1384UfsExecUicCommands (\r
1385 IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
1386 IN UINT8 UicOpcode,\r
1387 IN UINT32 Arg1,\r
1388 IN UINT32 Arg2,\r
1389 IN UINT32 Arg3\r
1390 )\r
1391{\r
1392 EFI_STATUS Status;\r
1393 UINTN Address;\r
1394 UINT32 Data;\r
1395 UINTN UfsHcBase;\r
1396\r
1397 UfsHcBase = Private->UfsHcBase;\r
1398 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1399 Data = MmioRead32 (Address);\r
1400 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
1401 //\r
1402 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
1403 //\r
1404 MmioWrite32 (Address, Data);\r
1405 }\r
1406\r
1407 //\r
1408 // When programming UIC command registers, host software shall set the register UICCMD\r
1409 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
1410 // are set.\r
1411 //\r
1412 Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;\r
1413 MmioWrite32 (Address, Arg1);\r
1414\r
1415 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
1416 MmioWrite32 (Address, Arg2);\r
1417\r
1418 Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;\r
1419 MmioWrite32 (Address, Arg3);\r
1420\r
1421 //\r
1422 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
1423 //\r
1424 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;\r
1425 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
1426 if (EFI_ERROR (Status)) {\r
1427 return Status;\r
1428 }\r
1429\r
1430 Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;\r
1431 MmioWrite32 (Address, (UINT32)UicOpcode);\r
1432\r
1433 //\r
1434 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
1435 // This bit is set to '1' by the host controller upon completion of a UIC command. \r
1436 //\r
1437 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1438 Data = MmioRead32 (Address);\r
1439 Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
1440 if (EFI_ERROR (Status)) {\r
1441 return Status;\r
1442 }\r
1443\r
1444 if (UicOpcode != UfsUicDmeReset) {\r
1445 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
1446 Data = MmioRead32 (Address);\r
1447 if ((Data & 0xFF) != 0) {\r
1448 DEBUG_CODE_BEGIN();\r
1449 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
1450 DEBUG_CODE_END();\r
1451 return EFI_DEVICE_ERROR;\r
1452 }\r
1453 }\r
1454\r
1455 //\r
1456 // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
1457 //\r
1458 Address = UfsHcBase + UFS_HC_STATUS_OFFSET; \r
1459 Data = MmioRead32 (Address);\r
1460 if ((Data & UFS_HC_HCS_DP) == 0) {\r
1461 Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
1462 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
1463 if (EFI_ERROR (Status)) {\r
1464 return EFI_DEVICE_ERROR;\r
1465 }\r
1466 return EFI_NOT_FOUND;\r
1467 }\r
1468\r
1469 DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));\r
1470\r
1471 return EFI_SUCCESS;\r
1472}\r
1473\r
1474/**\r
1475 Enable the UFS host controller for accessing.\r
1476\r
1477 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1478\r
1479 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1480 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1481\r
1482**/\r
1483EFI_STATUS\r
1484UfsEnableHostController (\r
1485 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1486 )\r
1487{\r
1488 EFI_STATUS Status;\r
1489 UINTN Address;\r
1490 UINT32 Data;\r
1491\r
1492 //\r
1493 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1494 //\r
1495 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1496 //\r
1497 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1498 Data = MmioRead32 (Address);\r
1499 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1500 //\r
1501 // Write a 0 to the HCE register at first to disable the host controller.\r
1502 //\r
1503 MmioWrite32 (Address, 0);\r
1504 //\r
1505 // Wait until HCE is read as '0' before continuing.\r
1506 //\r
1507 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1508 if (EFI_ERROR (Status)) {\r
1509 return EFI_DEVICE_ERROR;\r
1510 }\r
1511 }\r
1512\r
1513 //\r
1514 // Write a 1 to the HCE register to enable the UFS host controller.\r
1515 //\r
1516 MmioWrite32 (Address, UFS_HC_HCE_EN);\r
1517 //\r
1518 // Wait until HCE is read as '1' before continuing.\r
1519 //\r
1520 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
1521 if (EFI_ERROR (Status)) {\r
1522 return EFI_DEVICE_ERROR;\r
1523 }\r
1524\r
1525 return EFI_SUCCESS;\r
1526}\r
1527\r
1528/**\r
1529 Detect if a UFS device attached.\r
1530\r
1531 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1532\r
1533 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1534 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1535 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1536\r
1537**/\r
1538EFI_STATUS\r
1539UfsDeviceDetection (\r
1540 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1541 )\r
1542{\r
1543 UINTN Retry;\r
1544 EFI_STATUS Status;\r
1545\r
1546 //\r
1547 // Start UFS device detection.\r
1548 // Try up to 3 times for establishing data link with device.\r
1549 //\r
1550 for (Retry = 0; Retry < 3; Retry++) {\r
1551 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
1552 if (!EFI_ERROR (Status)) {\r
1553 break;\r
1554 }\r
1555\r
1556 if (Status == EFI_NOT_FOUND) {\r
1557 continue;\r
1558 }\r
1559\r
1560 return EFI_DEVICE_ERROR;\r
1561 }\r
1562\r
1563 if (Retry == 3) {\r
1564 return EFI_NOT_FOUND;\r
1565 }\r
1566\r
1567 return EFI_SUCCESS;\r
1568}\r
1569\r
1570/**\r
1571 Initialize UFS task management request list related h/w context.\r
1572\r
1573 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1574\r
1575 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1576 @retval EFI_DEVICE_ERROR The initialization fails.\r
1577\r
1578**/\r
1579EFI_STATUS\r
1580UfsInitTaskManagementRequestList (\r
1581 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1582 )\r
1583{\r
1584 UINTN Address;\r
1585 UINT32 Data;\r
1586 UINT8 Nutmrs;\r
1587 EFI_PHYSICAL_ADDRESS Buffer;\r
1588 EFI_STATUS Status;\r
1589 \r
1590 //\r
1591 // Initial h/w and s/w context for future operations.\r
1592 //\r
1593 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET; \r
1594 Data = MmioRead32 (Address);\r
1595 Private->Capabilities = Data;\r
1596\r
1597 //\r
1598 // Allocate and initialize UTP Task Management Request List.\r
1599 //\r
1600 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
1601 Status = PeiServicesAllocatePages (\r
1602 EfiBootServicesCode,\r
1603 EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),\r
1604 &Buffer\r
1605 );\r
1606\r
1607 if (EFI_ERROR (Status)) {\r
1608 return EFI_DEVICE_ERROR;\r
1609 }\r
1610\r
1611 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));\r
1612\r
1613 //\r
1614 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
1615 // Request List Base Address with a 64-bit address allocated at step 6.\r
1616 //\r
1617 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET; \r
1618 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);\r
1619 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET; \r
1620 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));\r
1621 Private->UtpTmrlBase = (VOID*)(UINTN)Buffer;\r
1622 Private->Nutmrs = Nutmrs;\r
1623\r
1624 //\r
1625 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1626 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1627 //\r
1628 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET; \r
1629 MmioWrite32 (Address, UFS_HC_UTMRLRSR);\r
1630\r
1631 return EFI_SUCCESS;\r
1632}\r
1633\r
1634/**\r
1635 Initialize UFS transfer request list related h/w context.\r
1636\r
1637 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1638\r
1639 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
1640 @retval EFI_DEVICE_ERROR The initialization fails.\r
1641\r
1642**/\r
1643EFI_STATUS\r
1644UfsInitTransferRequestList (\r
1645 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1646 )\r
1647{\r
1648 UINTN Address;\r
1649 UINT32 Data;\r
1650 UINT8 Nutrs;\r
1651 EFI_PHYSICAL_ADDRESS Buffer;\r
1652 EFI_STATUS Status;\r
1653 \r
1654 //\r
1655 // Initial h/w and s/w context for future operations.\r
1656 //\r
1657 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET; \r
1658 Data = MmioRead32 (Address);\r
1659 Private->Capabilities = Data;\r
1660\r
1661 //\r
1662 // Allocate and initialize UTP Transfer Request List.\r
1663 //\r
1664 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
1665 Status = PeiServicesAllocatePages (\r
1666 EfiBootServicesCode,\r
1667 EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),\r
1668 &Buffer\r
1669 );\r
1670\r
1671 if (EFI_ERROR (Status)) {\r
1672 return EFI_DEVICE_ERROR;\r
1673 }\r
1674\r
1675 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));\r
1676\r
1677 //\r
1678 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
1679 // Base Address with a 64-bit address allocated at step 8.\r
1680 //\r
1681 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET; \r
1682 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);\r
1683 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET; \r
1684 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));\r
1685 Private->UtpTrlBase = (VOID*)(UINTN)Buffer;\r
1686 Private->Nutrs = Nutrs;\r
1687 \r
1688 //\r
1689 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1690 // RunStop Register (UTRLRSR) to '1'.\r
1691 //\r
1692 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET; \r
1693 MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
1694\r
1695 return EFI_SUCCESS;\r
1696}\r
1697\r
1698/**\r
1699 Initialize the UFS host controller.\r
1700\r
1701 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1702\r
1703 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
1704 @retval Others A device error occurred while initializing the controller.\r
1705\r
1706**/\r
1707EFI_STATUS\r
1708UfsControllerInit (\r
1709 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1710 )\r
1711{\r
1712 EFI_STATUS Status;\r
1713\r
1714 Status = UfsEnableHostController (Private);\r
1715 if (EFI_ERROR (Status)) {\r
1716 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));\r
1717 return Status;\r
1718 }\r
1719\r
1720 Status = UfsDeviceDetection (Private);\r
1721 if (EFI_ERROR (Status)) {\r
1722 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));\r
1723 return Status;\r
1724 }\r
1725\r
1726 Status = UfsInitTaskManagementRequestList (Private);\r
1727 if (EFI_ERROR (Status)) {\r
1728 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));\r
1729 return Status;\r
1730 }\r
1731\r
1732 Status = UfsInitTransferRequestList (Private);\r
1733 if (EFI_ERROR (Status)) {\r
1734 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));\r
1735 return Status;\r
1736 }\r
1737\r
1738 DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));\r
1739 return EFI_SUCCESS;\r
1740}\r
1741\r
1742/**\r
1743 Stop the UFS host controller.\r
1744\r
1745 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
1746\r
1747 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
1748 @retval Others A device error occurred while stopping the controller.\r
1749\r
1750**/\r
1751EFI_STATUS\r
1752UfsControllerStop (\r
1753 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
1754 )\r
1755{\r
1756 EFI_STATUS Status;\r
1757 UINTN Address;\r
1758 UINT32 Data;\r
1759\r
1760 //\r
1761 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1762 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1763 //\r
1764 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET; \r
1765 MmioWrite32 (Address, 0);\r
1766\r
1767 //\r
1768 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1769 // RunStop Register (UTRLRSR) to '1'.\r
1770 //\r
1771 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET; \r
1772 MmioWrite32 (Address, 0);\r
1773\r
1774 //\r
1775 // Write a 0 to the HCE register in order to disable the host controller.\r
1776 //\r
1777 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
1778 Data = MmioRead32 (Address);\r
1779 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
1780 MmioWrite32 (Address, 0);\r
1781\r
1782 //\r
1783 // Wait until HCE is read as '0' before continuing.\r
1784 //\r
1785 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
1786 if (EFI_ERROR (Status)) {\r
1787 return EFI_DEVICE_ERROR;\r
1788 }\r
1789\r
1790 DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));\r
1791\r
1792 return EFI_SUCCESS;\r
1793}\r
1794\r