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