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