3 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "UfsBlockIoPei.h"
11 Wait for the value of the specified system memory set to the test value.
13 @param Address The system memory address to test.
14 @param MaskValue The mask value of memory.
15 @param TestValue The test value of memory.
16 @param Timeout The time out value for wait memory set, uses 100ns as a unit.
18 @retval EFI_TIMEOUT The system memory setting is time out.
19 @retval EFI_SUCCESS The system memory is correct set.
41 Delay
= DivU64x32 (Timeout
, 10) + 1;
45 // Access PCI MMIO space to see if the value is the tested one.
47 Value
= MmioRead32 (Address
) & MaskValue
;
49 if (Value
== TestValue
) {
54 // Stall for 1 microseconds.
60 } while (InfiniteWait
|| (Delay
> 0));
66 Dump UIC command execution result for debugging.
68 @param[in] UicOpcode The executed UIC opcode.
69 @param[in] Result The result to be parsed.
73 DumpUicCmdExecResult (
78 if (UicOpcode
<= UfsUicDmePeerSet
) {
83 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
86 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
89 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
92 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
95 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
98 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
101 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
104 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
107 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BUSY\n"));
110 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
121 DEBUG ((EFI_D_VERBOSE
, "UIC control command fails - FAILURE\n"));
131 Dump QUERY RESPONSE UPIU result for debugging.
133 @param[in] Result The result to be parsed.
137 DumpQueryResponseResult (
143 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Readable\n"));
146 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
149 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Already Written\n"));
152 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Length\n"));
155 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Value\n"));
158 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Selector\n"));
161 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Index\n"));
164 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Idn\n"));
167 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Opcode\n"));
170 DEBUG ((EFI_D_VERBOSE
, "Query Response with General Failure\n"));
179 Swap little endian to big endian.
181 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
182 In output, it will become big endian.
183 @param[in] BufferSize The length of converted data.
187 SwapLittleEndianToBigEndian (
188 IN OUT UINT8
*Buffer
,
196 SwapCount
= BufferSize
/ 2;
197 for (Index
= 0; Index
< SwapCount
; Index
++) {
198 Temp
= Buffer
[Index
];
199 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
200 Buffer
[BufferSize
- 1 - Index
] = Temp
;
205 Fill TSF field of QUERY REQUEST UPIU.
207 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
208 @param[in] Opcode The opcode of request.
209 @param[in] DescId The descriptor ID of request.
210 @param[in] Index The index of request.
211 @param[in] Selector The selector of request.
212 @param[in] Length The length of transferred data. The maximum is 4.
213 @param[in] Value The value of transferred data.
217 UfsFillTsfOfQueryReqUpiu (
218 IN OUT UTP_UPIU_TSF
*TsfBase
,
220 IN UINT8 DescId OPTIONAL
,
221 IN UINT8 Index OPTIONAL
,
222 IN UINT8 Selector OPTIONAL
,
223 IN UINT16 Length OPTIONAL
,
224 IN UINT32 Value OPTIONAL
227 ASSERT (TsfBase
!= NULL
);
228 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
230 TsfBase
->Opcode
= Opcode
;
231 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
232 TsfBase
->DescId
= DescId
;
233 TsfBase
->Index
= Index
;
234 TsfBase
->Selector
= Selector
;
236 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
237 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
238 TsfBase
->Length
= Length
;
241 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
242 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
243 TsfBase
->Value
= Value
;
249 Initialize COMMAND UPIU.
251 @param[in, out] Command The base address of COMMAND UPIU.
252 @param[in] Lun The Lun on which the SCSI command is executed.
253 @param[in] TaskTag The task tag of request.
254 @param[in] Cdb The cdb buffer containing SCSI command.
255 @param[in] CdbLength The cdb length.
256 @param[in] DataDirection The direction of data transfer.
257 @param[in] ExpDataTranLen The expected transfer data length.
259 @retval EFI_SUCCESS The initialization succeed.
264 IN OUT UTP_COMMAND_UPIU
*Command
,
269 IN UFS_DATA_DIRECTION DataDirection
,
270 IN UINT32 ExpDataTranLen
275 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
278 // Task attribute is hard-coded to Ordered.
280 if (DataDirection
== UfsDataIn
) {
282 } else if (DataDirection
== UfsDataOut
) {
289 // Fill UTP COMMAND UPIU associated fields.
291 Command
->TransCode
= 0x01;
292 Command
->Flags
= Flags
;
294 Command
->TaskTag
= TaskTag
;
295 Command
->CmdSet
= 0x00;
296 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
297 Command
->ExpDataTranLen
= ExpDataTranLen
;
299 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
305 Initialize UTP PRDT for data transfer.
307 @param[in] Prdt The base address of PRDT.
308 @param[in] Buffer The buffer to be read or written.
309 @param[in] BufferSize The data size to be read or written.
311 @retval EFI_SUCCESS The initialization succeed.
326 if ((BufferSize
& (BIT0
| BIT1
)) != 0) {
327 BufferSize
&= ~(BIT0
| BIT1
);
328 DEBUG ((EFI_D_WARN
, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize
));
331 if (BufferSize
== 0) {
335 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
337 RemainingLen
= BufferSize
;
339 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
341 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
342 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
343 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
345 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
348 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
349 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
350 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
351 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
358 Initialize QUERY REQUEST UPIU.
360 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
361 @param[in] TaskTag The task tag of request.
362 @param[in] Opcode The opcode of request.
363 @param[in] DescId The descriptor ID of request.
364 @param[in] Index The index of request.
365 @param[in] Selector The selector of request.
366 @param[in] DataSize The data size to be read or written.
367 @param[in] Data The buffer to be read or written.
369 @retval EFI_SUCCESS The initialization succeed.
373 UfsInitQueryRequestUpiu (
374 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
380 IN UINTN DataSize OPTIONAL
,
381 IN UINT8
*Data OPTIONAL
384 ASSERT (QueryReq
!= NULL
);
386 QueryReq
->TransCode
= 0x16;
387 QueryReq
->TaskTag
= TaskTag
;
388 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
389 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
391 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
394 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
395 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
396 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
397 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
399 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
402 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
403 CopyMem (QueryReq
+ 1, Data
, DataSize
);
405 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
406 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
413 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
415 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
416 @param[in] Lun The Lun on which the SCSI command is executed.
417 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
418 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
419 @param[out] BufferMap A resulting value, if not NULL, to pass to IoMmuUnmap().
421 @retval EFI_SUCCESS The creation succeed.
422 @retval EFI_DEVICE_ERROR The creation failed.
423 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
427 UfsCreateScsiCommandDesc (
428 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
430 IN UFS_SCSI_REQUEST_PACKET
*Packet
,
440 UTP_COMMAND_UPIU
*CommandUpiu
;
441 UTP_TR_PRD
*PrdtBase
;
442 UFS_DATA_DIRECTION DataDirection
;
444 EDKII_IOMMU_OPERATION MapOp
;
446 EFI_PHYSICAL_ADDRESS BufferPhyAddr
;
448 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
452 if (Packet
->DataDirection
== UfsDataIn
) {
453 Buffer
= Packet
->InDataBuffer
;
454 Length
= Packet
->InTransferLength
;
455 DataDirection
= UfsDataIn
;
456 MapOp
= EdkiiIoMmuOperationBusMasterWrite
;
458 Buffer
= Packet
->OutDataBuffer
;
459 Length
= Packet
->OutTransferLength
;
460 DataDirection
= UfsDataOut
;
461 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
465 DataDirection
= UfsNoData
;
468 Status
= IoMmuMap (MapOp
, Buffer
, &MapLength
, &BufferPhyAddr
, BufferMap
);
470 if (EFI_ERROR (Status
) || (MapLength
!= Length
)) {
471 DEBUG ((DEBUG_ERROR
, "UfsCreateScsiCommandDesc: Fail to map data buffer.\n"));
472 return EFI_OUT_OF_RESOURCES
;
476 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)Length
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
478 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
479 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
480 if (CommandDesc
== NULL
) {
481 return EFI_OUT_OF_RESOURCES
;
484 CommandUpiu
= (UTP_COMMAND_UPIU
*)CommandDesc
;
485 PrdtBase
= (UTP_TR_PRD
*)(CommandDesc
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
487 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, Length
);
488 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)BufferPhyAddr
, Length
);
491 // Fill UTP_TRD associated fields
492 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
493 // *MUST* be located at a 64-bit aligned boundary.
495 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
496 Trd
->Dd
= DataDirection
;
497 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
498 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
499 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 7);
500 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 32);
501 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
502 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
503 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
504 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
509 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
511 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
512 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
513 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
515 @retval EFI_SUCCESS The creation succeed.
516 @retval EFI_DEVICE_ERROR The creation failed.
517 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
518 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
522 UfsCreateDMCommandDesc (
523 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
524 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
530 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
536 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
538 Opcode
= Packet
->Opcode
;
539 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
540 return EFI_INVALID_PARAMETER
;
543 DataDirection
= Packet
->DataDirection
;
544 if (DataDirection
== UfsDataIn
) {
545 DataSize
= Packet
->InTransferLength
;
546 Data
= Packet
->InDataBuffer
;
547 } else if (DataDirection
== UfsDataOut
) {
548 DataSize
= Packet
->OutTransferLength
;
549 Data
= Packet
->OutDataBuffer
;
555 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
556 && ((DataSize
== 0) || (Data
== NULL
))) {
557 return EFI_INVALID_PARAMETER
;
560 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
561 && ((DataSize
!= 0) || (Data
!= NULL
))) {
562 return EFI_INVALID_PARAMETER
;
565 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
566 return EFI_INVALID_PARAMETER
;
569 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
570 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
572 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
575 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
576 if (CommandDesc
== NULL
) {
577 return EFI_OUT_OF_RESOURCES
;
581 // Initialize UTP QUERY REQUEST UPIU
583 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)CommandDesc
;
584 UfsInitQueryRequestUpiu (
596 // Fill UTP_TRD associated fields
597 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
599 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
600 Trd
->Dd
= DataDirection
;
601 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
602 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
603 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 7);
604 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 32);
605 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
606 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
607 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
609 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
610 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
617 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
619 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
620 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
622 @retval EFI_SUCCESS The creation succeed.
623 @retval EFI_DEVICE_ERROR The creation failed.
624 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
628 UfsCreateNopCommandDesc (
629 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
635 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
637 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
639 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
640 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
641 if (CommandDesc
== NULL
) {
642 return EFI_OUT_OF_RESOURCES
;
645 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)CommandDesc
;
647 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
650 // Fill UTP_TRD associated fields
651 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
653 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
655 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
656 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
657 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 7);
658 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 32);
659 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
660 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
666 Find out available slot in transfer list of a UFS device.
668 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
669 @param[out] Slot The available slot.
671 @retval EFI_SUCCESS The available slot was found successfully.
675 UfsFindAvailableSlotInTrl (
676 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
680 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
683 // The simplest algo to always use slot 0.
684 // TODO: enhance it to support async transfer with multiple slot.
694 Start specified slot in transfer list of a UFS device.
696 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
697 @param[in] Slot The slot to be started.
702 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
710 UfsHcBase
= Private
->UfsHcBase
;
712 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
713 Data
= MmioRead32 (Address
);
714 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
715 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
718 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
719 MmioWrite32 (Address
, BIT0
<< Slot
);
723 Stop specified slot in transfer list of a UFS device.
725 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
726 @param[in] Slot The slot to be stop.
731 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
739 UfsHcBase
= Private
->UfsHcBase
;
741 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
742 Data
= MmioRead32 (Address
);
743 if ((Data
& (BIT0
<< Slot
)) != 0) {
744 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
745 Data
= MmioRead32 (Address
);
746 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
751 Read or write specified device descriptor of a UFS device.
753 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
754 @param[in] Read The boolean variable to show r/w direction.
755 @param[in] DescId The ID of device descriptor.
756 @param[in] Index The Index of device descriptor.
757 @param[in] Selector The Selector of device descriptor.
758 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
759 @param[in] DescSize The size of device descriptor buffer.
761 @retval EFI_SUCCESS The device descriptor was read/written successfully.
762 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
763 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
768 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
773 IN OUT VOID
*Descriptor
,
778 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
782 UTP_QUERY_RESP_UPIU
*QueryResp
;
785 UINT16 ReturnDataSize
;
787 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
790 Packet
.DataDirection
= UfsDataIn
;
791 Packet
.InDataBuffer
= Descriptor
;
792 Packet
.InTransferLength
= DescSize
;
793 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
795 Packet
.DataDirection
= UfsDataOut
;
796 Packet
.OutDataBuffer
= Descriptor
;
797 Packet
.OutTransferLength
= DescSize
;
798 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
800 Packet
.DescId
= DescId
;
801 Packet
.Index
= Index
;
802 Packet
.Selector
= Selector
;
803 Packet
.Timeout
= UFS_TIMEOUT
;
806 // Find out which slot of transfer request list is available.
808 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
809 if (EFI_ERROR (Status
)) {
813 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
815 // Fill transfer request descriptor to this slot.
817 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
818 if (EFI_ERROR (Status
)) {
823 // Check the transfer request result.
825 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
826 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
827 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
830 // Start to execute the transfer request.
832 UfsStartExecCmd (Private
, Slot
);
835 // Wait for the completion of the transfer request.
837 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
838 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
839 if (EFI_ERROR (Status
)) {
843 if (QueryResp
->QueryResp
!= 0) {
844 DumpQueryResponseResult (QueryResp
->QueryResp
);
845 Status
= EFI_DEVICE_ERROR
;
850 ReturnDataSize
= QueryResp
->Tsf
.Length
;
851 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
855 // Make sure the hardware device does not return more data than expected.
857 if (ReturnDataSize
> Packet
.InTransferLength
) {
858 Status
= EFI_DEVICE_ERROR
;
862 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
863 Packet
.InTransferLength
= ReturnDataSize
;
865 Packet
.OutTransferLength
= ReturnDataSize
;
868 Status
= EFI_DEVICE_ERROR
;
872 UfsStopExecCmd (Private
, Slot
);
873 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
881 Read or write specified flag of a UFS device.
883 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
884 @param[in] Read The boolean variable to show r/w direction.
885 @param[in] FlagId The ID of flag to be read or written.
886 @param[in, out] Value The value to set or clear flag.
888 @retval EFI_SUCCESS The flag was read/written successfully.
889 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
890 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
895 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
902 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
906 UTP_QUERY_RESP_UPIU
*QueryResp
;
911 return EFI_INVALID_PARAMETER
;
914 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
917 ASSERT (Value
!= NULL
);
918 Packet
.DataDirection
= UfsDataIn
;
919 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
921 Packet
.DataDirection
= UfsDataOut
;
923 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
924 } else if (*Value
== 0) {
925 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
927 return EFI_INVALID_PARAMETER
;
930 Packet
.DescId
= FlagId
;
933 Packet
.Timeout
= UFS_TIMEOUT
;
936 // Find out which slot of transfer request list is available.
938 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
939 if (EFI_ERROR (Status
)) {
944 // Fill transfer request descriptor to this slot.
946 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
947 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
948 if (EFI_ERROR (Status
)) {
953 // Check the transfer request result.
955 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
956 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
957 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
960 // Start to execute the transfer request.
962 UfsStartExecCmd (Private
, Slot
);
965 // Wait for the completion of the transfer request.
967 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
968 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
969 if (EFI_ERROR (Status
)) {
973 if (QueryResp
->QueryResp
!= 0) {
974 DumpQueryResponseResult (QueryResp
->QueryResp
);
975 Status
= EFI_DEVICE_ERROR
;
981 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
983 *Value
= *((UINT8
*)&(QueryResp
->Tsf
.Value
) + 3);
985 Status
= EFI_DEVICE_ERROR
;
989 UfsStopExecCmd (Private
, Slot
);
990 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
996 Set specified flag to 1 on a UFS device.
998 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
999 @param[in] FlagId The ID of flag to be set.
1001 @retval EFI_SUCCESS The flag was set successfully.
1002 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1003 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1008 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1016 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1024 Sends NOP IN cmd to a UFS device for initialization process request.
1025 For more details, please refer to UFS 2.0 spec Figure 13.3.
1027 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1029 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1030 received successfully.
1031 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1032 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1033 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1038 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1044 UTP_NOP_IN_UPIU
*NopInUpiu
;
1050 // Find out which slot of transfer request list is available.
1052 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1053 if (EFI_ERROR (Status
)) {
1057 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1058 Status
= UfsCreateNopCommandDesc (Private
, Trd
);
1059 if (EFI_ERROR (Status
)) {
1064 // Check the transfer request result.
1066 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1067 NopInUpiu
= (UTP_NOP_IN_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1068 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1071 // Start to execute the transfer request.
1073 UfsStartExecCmd (Private
, Slot
);
1076 // Wait for the completion of the transfer request.
1078 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1079 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1080 if (EFI_ERROR (Status
)) {
1084 if (NopInUpiu
->Resp
!= 0) {
1085 Status
= EFI_DEVICE_ERROR
;
1087 Status
= EFI_SUCCESS
;
1091 UfsStopExecCmd (Private
, Slot
);
1092 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1098 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1100 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1101 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1102 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1105 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1106 commands, InTransferLength bytes were transferred from
1107 InDataBuffer. For write and bi-directional commands,
1108 OutTransferLength bytes were transferred by
1110 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1112 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1113 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1118 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1120 IN OUT UFS_SCSI_REQUEST_PACKET
*Packet
1129 UTP_RESPONSE_UPIU
*Response
;
1130 UINT16 SenseDataLen
;
1131 UINT32 ResTranCount
;
1132 VOID
*PacketBufferMap
;
1135 // Find out which slot of transfer request list is available.
1137 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1138 if (EFI_ERROR (Status
)) {
1142 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1143 PacketBufferMap
= NULL
;
1146 // Fill transfer request descriptor to this slot.
1148 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
, &PacketBufferMap
);
1149 if (EFI_ERROR (Status
)) {
1153 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1154 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1157 // Start to execute the transfer request.
1159 UfsStartExecCmd (Private
, Slot
);
1162 // Wait for the completion of the transfer request.
1164 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1165 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
->Timeout
);
1166 if (EFI_ERROR (Status
)) {
1171 // Get sense data if exists
1173 Response
= (UTP_RESPONSE_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1174 SenseDataLen
= Response
->SenseDataLen
;
1175 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1177 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1179 // Make sure the hardware device does not return more data than expected.
1181 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1182 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1183 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1185 Packet
->SenseDataLength
= 0;
1190 // Check the transfer request result.
1192 if (Response
->Response
!= 0) {
1193 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1194 Status
= EFI_DEVICE_ERROR
;
1198 if (Trd
->Ocs
== 0) {
1199 if (Packet
->DataDirection
== UfsDataIn
) {
1200 if ((Response
->Flags
& BIT5
) == BIT5
) {
1201 ResTranCount
= Response
->ResTranCount
;
1202 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1203 Packet
->InTransferLength
-= ResTranCount
;
1205 } else if (Packet
->DataDirection
== UfsDataOut
) {
1206 if ((Response
->Flags
& BIT5
) == BIT5
) {
1207 ResTranCount
= Response
->ResTranCount
;
1208 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1209 Packet
->OutTransferLength
-= ResTranCount
;
1213 Status
= EFI_DEVICE_ERROR
;
1217 if (PacketBufferMap
!= NULL
) {
1218 IoMmuUnmap (PacketBufferMap
);
1220 UfsStopExecCmd (Private
, Slot
);
1221 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1228 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1230 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1231 @param[in] UicOpcode The opcode of the UIC command.
1232 @param[in] Arg1 The value for 1st argument of the UIC command.
1233 @param[in] Arg2 The value for 2nd argument of the UIC command.
1234 @param[in] Arg3 The value for 3rd argument of the UIC command.
1236 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1237 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1238 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1242 UfsExecUicCommands (
1243 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1255 UfsHcBase
= Private
->UfsHcBase
;
1256 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1257 Data
= MmioRead32 (Address
);
1258 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1260 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1262 MmioWrite32 (Address
, Data
);
1266 // When programming UIC command registers, host software shall set the register UICCMD
1267 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1270 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1271 MmioWrite32 (Address
, Arg1
);
1273 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1274 MmioWrite32 (Address
, Arg2
);
1276 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1277 MmioWrite32 (Address
, Arg3
);
1280 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1282 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1283 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1284 if (EFI_ERROR (Status
)) {
1288 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1289 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1292 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1293 // This bit is set to '1' by the host controller upon completion of a UIC command.
1295 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1296 Data
= MmioRead32 (Address
);
1297 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1298 if (EFI_ERROR (Status
)) {
1302 if (UicOpcode
!= UfsUicDmeReset
) {
1303 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1304 Data
= MmioRead32 (Address
);
1305 if ((Data
& 0xFF) != 0) {
1307 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1309 return EFI_DEVICE_ERROR
;
1314 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1316 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1317 Data
= MmioRead32 (Address
);
1318 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1319 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1320 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1321 if (EFI_ERROR (Status
)) {
1322 return EFI_DEVICE_ERROR
;
1324 return EFI_NOT_FOUND
;
1327 DEBUG ((EFI_D_INFO
, "UfsblockioPei: found a attached UFS device\n"));
1333 Enable the UFS host controller for accessing.
1335 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1337 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1338 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1342 UfsEnableHostController (
1343 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1351 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1353 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1355 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1356 Data
= MmioRead32 (Address
);
1357 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1359 // Write a 0 to the HCE register at first to disable the host controller.
1361 MmioWrite32 (Address
, 0);
1363 // Wait until HCE is read as '0' before continuing.
1365 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1366 if (EFI_ERROR (Status
)) {
1367 return EFI_DEVICE_ERROR
;
1372 // Write a 1 to the HCE register to enable the UFS host controller.
1374 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1376 // Wait until HCE is read as '1' before continuing.
1378 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1379 if (EFI_ERROR (Status
)) {
1380 return EFI_DEVICE_ERROR
;
1387 Detect if a UFS device attached.
1389 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1391 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1392 @retval EFI_NOT_FOUND Not found a UFS device attached.
1393 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1397 UfsDeviceDetection (
1398 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1405 // Start UFS device detection.
1406 // Try up to 3 times for establishing data link with device.
1408 for (Retry
= 0; Retry
< 3; Retry
++) {
1409 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1410 if (!EFI_ERROR (Status
)) {
1414 if (Status
== EFI_NOT_FOUND
) {
1418 return EFI_DEVICE_ERROR
;
1422 return EFI_NOT_FOUND
;
1429 Initialize UFS task management request list related h/w context.
1431 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1433 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1434 @retval EFI_DEVICE_ERROR The initialization fails.
1438 UfsInitTaskManagementRequestList (
1439 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1446 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1447 VOID
*CmdDescMapping
;
1451 // Initial h/w and s/w context for future operations.
1453 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1454 Data
= MmioRead32 (Address
);
1455 Private
->Capabilities
= Data
;
1458 // Allocate and initialize UTP Task Management Request List.
1460 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1461 Status
= IoMmuAllocateBuffer (
1462 EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
)),
1467 if (EFI_ERROR (Status
)) {
1468 return EFI_DEVICE_ERROR
;
1471 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
))));
1474 // Program the UTP Task Management Request List Base Address and UTP Task Management
1475 // Request List Base Address with a 64-bit address allocated at step 6.
1477 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1478 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1479 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1480 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1481 Private
->UtpTmrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1482 Private
->Nutmrs
= Nutmrs
;
1483 Private
->TmrlMapping
= CmdDescMapping
;
1486 // Enable the UTP Task Management Request List by setting the UTP Task Management
1487 // Request List RunStop Register (UTMRLRSR) to '1'.
1489 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1490 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1496 Initialize UFS transfer request list related h/w context.
1498 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1500 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1501 @retval EFI_DEVICE_ERROR The initialization fails.
1505 UfsInitTransferRequestList (
1506 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1513 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1514 VOID
*CmdDescMapping
;
1518 // Initial h/w and s/w context for future operations.
1520 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1521 Data
= MmioRead32 (Address
);
1522 Private
->Capabilities
= Data
;
1525 // Allocate and initialize UTP Transfer Request List.
1527 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1528 Status
= IoMmuAllocateBuffer (
1529 EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
)),
1534 if (EFI_ERROR (Status
)) {
1535 return EFI_DEVICE_ERROR
;
1538 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
))));
1541 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1542 // Base Address with a 64-bit address allocated at step 8.
1544 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1545 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1546 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1547 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1548 Private
->UtpTrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1549 Private
->Nutrs
= Nutrs
;
1550 Private
->TrlMapping
= CmdDescMapping
;
1553 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1554 // RunStop Register (UTRLRSR) to '1'.
1556 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1557 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1563 Initialize the UFS host controller.
1565 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1567 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1568 @retval Others A device error occurred while initializing the controller.
1573 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1578 Status
= UfsEnableHostController (Private
);
1579 if (EFI_ERROR (Status
)) {
1580 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status
));
1584 Status
= UfsDeviceDetection (Private
);
1585 if (EFI_ERROR (Status
)) {
1586 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status
));
1590 Status
= UfsInitTaskManagementRequestList (Private
);
1591 if (EFI_ERROR (Status
)) {
1592 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status
));
1596 Status
= UfsInitTransferRequestList (Private
);
1597 if (EFI_ERROR (Status
)) {
1598 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status
));
1600 if (Private
->TmrlMapping
!= NULL
) {
1602 EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)),
1603 Private
->UtpTmrlBase
,
1604 Private
->TmrlMapping
1606 Private
->TmrlMapping
= NULL
;
1612 DEBUG ((EFI_D_INFO
, "UfsDevicePei Finished\n"));
1617 Stop the UFS host controller.
1619 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1621 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1622 @retval Others A device error occurred while stopping the controller.
1627 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1635 // Enable the UTP Task Management Request List by setting the UTP Task Management
1636 // Request List RunStop Register (UTMRLRSR) to '1'.
1638 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1639 MmioWrite32 (Address
, 0);
1642 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1643 // RunStop Register (UTRLRSR) to '1'.
1645 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1646 MmioWrite32 (Address
, 0);
1649 // Write a 0 to the HCE register in order to disable the host controller.
1651 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1652 Data
= MmioRead32 (Address
);
1653 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1654 MmioWrite32 (Address
, 0);
1657 // Wait until HCE is read as '0' before continuing.
1659 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1660 if (EFI_ERROR (Status
)) {
1661 return EFI_DEVICE_ERROR
;
1664 DEBUG ((EFI_D_INFO
, "UfsDevicePei: Stop the UFS Host Controller\n"));