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