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