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