3 Copyright (c) 2014 - 2021, 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.
59 } while (InfiniteWait
|| (Delay
> 0));
65 Dump UIC command execution result for debugging.
67 @param[in] UicOpcode The executed UIC opcode.
68 @param[in] Result The result to be parsed.
72 DumpUicCmdExecResult (
77 if (UicOpcode
<= UfsUicDmePeerSet
) {
82 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
85 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
88 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
91 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
94 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
97 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
100 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
103 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
106 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BUSY\n"));
109 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
120 DEBUG ((DEBUG_VERBOSE
, "UIC control command fails - FAILURE\n"));
130 Dump QUERY RESPONSE UPIU result for debugging.
132 @param[in] Result The result to be parsed.
136 DumpQueryResponseResult (
142 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Readable\n"));
145 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
148 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Already Written\n"));
151 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Length\n"));
154 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Value\n"));
157 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Selector\n"));
160 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Index\n"));
163 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Idn\n"));
166 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Opcode\n"));
169 DEBUG ((DEBUG_VERBOSE
, "Query Response with General Failure\n"));
178 Swap little endian to big endian.
180 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
181 In output, it will become big endian.
182 @param[in] BufferSize The length of converted data.
186 SwapLittleEndianToBigEndian (
187 IN OUT UINT8
*Buffer
,
195 SwapCount
= BufferSize
/ 2;
196 for (Index
= 0; Index
< SwapCount
; Index
++) {
197 Temp
= Buffer
[Index
];
198 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
199 Buffer
[BufferSize
- 1 - Index
] = Temp
;
204 Fill TSF field of QUERY REQUEST UPIU.
206 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
207 @param[in] Opcode The opcode of request.
208 @param[in] DescId The descriptor ID of request.
209 @param[in] Index The index of request.
210 @param[in] Selector The selector of request.
211 @param[in] Length The length of transferred data. The maximum is 4.
212 @param[in] Value The value of transferred data.
216 UfsFillTsfOfQueryReqUpiu (
217 IN OUT UTP_UPIU_TSF
*TsfBase
,
219 IN UINT8 DescId OPTIONAL
,
220 IN UINT8 Index OPTIONAL
,
221 IN UINT8 Selector OPTIONAL
,
222 IN UINT16 Length OPTIONAL
,
223 IN UINT32 Value OPTIONAL
226 ASSERT (TsfBase
!= NULL
);
227 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
229 TsfBase
->Opcode
= Opcode
;
230 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
231 TsfBase
->DescId
= DescId
;
232 TsfBase
->Index
= Index
;
233 TsfBase
->Selector
= Selector
;
235 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
236 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
237 TsfBase
->Length
= Length
;
240 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
241 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
242 TsfBase
->Value
= Value
;
248 Initialize COMMAND UPIU.
250 @param[in, out] Command The base address of COMMAND UPIU.
251 @param[in] Lun The Lun on which the SCSI command is executed.
252 @param[in] TaskTag The task tag of request.
253 @param[in] Cdb The cdb buffer containing SCSI command.
254 @param[in] CdbLength The cdb length.
255 @param[in] DataDirection The direction of data transfer.
256 @param[in] ExpDataTranLen The expected transfer data length.
258 @retval EFI_SUCCESS The initialization succeed.
263 IN OUT UTP_COMMAND_UPIU
*Command
,
268 IN UFS_DATA_DIRECTION DataDirection
,
269 IN UINT32 ExpDataTranLen
274 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
277 // Task attribute is hard-coded to Ordered.
279 if (DataDirection
== UfsDataIn
) {
281 } else if (DataDirection
== UfsDataOut
) {
288 // Fill UTP COMMAND UPIU associated fields.
290 Command
->TransCode
= 0x01;
291 Command
->Flags
= Flags
;
293 Command
->TaskTag
= TaskTag
;
294 Command
->CmdSet
= 0x00;
295 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
296 Command
->ExpDataTranLen
= ExpDataTranLen
;
298 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
304 Initialize UTP PRDT for data transfer.
306 @param[in] Prdt The base address of PRDT.
307 @param[in] Buffer The buffer to be read or written.
308 @param[in] BufferSize The data size to be read or written.
310 @retval EFI_SUCCESS The initialization succeed.
325 if ((BufferSize
& (BIT0
| BIT1
)) != 0) {
326 BufferSize
&= ~(BIT0
| BIT1
);
327 DEBUG ((DEBUG_WARN
, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize
));
330 if (BufferSize
== 0) {
334 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
336 RemainingLen
= BufferSize
;
338 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
340 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
341 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
342 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
344 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
347 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
348 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
349 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
350 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
357 Initialize QUERY REQUEST UPIU.
359 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
360 @param[in] TaskTag The task tag of request.
361 @param[in] Opcode The opcode of request.
362 @param[in] DescId The descriptor ID of request.
363 @param[in] Index The index of request.
364 @param[in] Selector The selector of request.
365 @param[in] DataSize The data size to be read or written.
366 @param[in] Data The buffer to be read or written.
368 @retval EFI_SUCCESS The initialization succeed.
372 UfsInitQueryRequestUpiu (
373 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
379 IN UINTN DataSize OPTIONAL
,
380 IN UINT8
*Data OPTIONAL
383 ASSERT (QueryReq
!= NULL
);
385 QueryReq
->TransCode
= 0x16;
386 QueryReq
->TaskTag
= TaskTag
;
387 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
388 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
390 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
393 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
394 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
395 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
396 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
398 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
401 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
402 CopyMem (QueryReq
+ 1, Data
, DataSize
);
404 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
405 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
412 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
414 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
415 @param[in] Lun The Lun on which the SCSI command is executed.
416 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
417 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
418 @param[out] BufferMap A resulting value, if not NULL, to pass to IoMmuUnmap().
420 @retval EFI_SUCCESS The creation succeed.
421 @retval EFI_DEVICE_ERROR The creation failed.
422 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
426 UfsCreateScsiCommandDesc (
427 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
429 IN UFS_SCSI_REQUEST_PACKET
*Packet
,
439 UTP_COMMAND_UPIU
*CommandUpiu
;
440 UTP_TR_PRD
*PrdtBase
;
441 UFS_DATA_DIRECTION DataDirection
;
443 EDKII_IOMMU_OPERATION MapOp
;
445 EFI_PHYSICAL_ADDRESS BufferPhyAddr
;
447 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
451 if (Packet
->DataDirection
== UfsDataIn
) {
452 Buffer
= Packet
->InDataBuffer
;
453 Length
= Packet
->InTransferLength
;
454 DataDirection
= UfsDataIn
;
455 MapOp
= EdkiiIoMmuOperationBusMasterWrite
;
457 Buffer
= Packet
->OutDataBuffer
;
458 Length
= Packet
->OutTransferLength
;
459 DataDirection
= UfsDataOut
;
460 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
464 DataDirection
= UfsNoData
;
467 Status
= IoMmuMap (MapOp
, Buffer
, &MapLength
, &BufferPhyAddr
, BufferMap
);
469 if (EFI_ERROR (Status
) || (MapLength
!= Length
)) {
470 DEBUG ((DEBUG_ERROR
, "UfsCreateScsiCommandDesc: Fail to map data buffer.\n"));
471 return EFI_OUT_OF_RESOURCES
;
475 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)Length
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
477 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
478 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
479 if (CommandDesc
== NULL
) {
480 return EFI_OUT_OF_RESOURCES
;
483 CommandUpiu
= (UTP_COMMAND_UPIU
*)CommandDesc
;
484 PrdtBase
= (UTP_TR_PRD
*)(CommandDesc
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
486 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, Length
);
487 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)BufferPhyAddr
, Length
);
490 // Fill UTP_TRD associated fields
491 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
492 // *MUST* be located at a 64-bit aligned boundary.
494 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
495 Trd
->Dd
= DataDirection
;
496 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
497 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
498 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 7);
499 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 32);
500 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
501 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
502 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
503 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
508 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
510 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
511 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
512 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
514 @retval EFI_SUCCESS The creation succeed.
515 @retval EFI_DEVICE_ERROR The creation failed.
516 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
517 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
521 UfsCreateDMCommandDesc (
522 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
523 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
529 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
535 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
537 Opcode
= Packet
->Opcode
;
538 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
539 return EFI_INVALID_PARAMETER
;
542 DataDirection
= Packet
->DataDirection
;
543 if (DataDirection
== UfsDataIn
) {
544 DataSize
= Packet
->InTransferLength
;
545 Data
= Packet
->InDataBuffer
;
546 } else if (DataDirection
== UfsDataOut
) {
547 DataSize
= Packet
->OutTransferLength
;
548 Data
= Packet
->OutDataBuffer
;
554 if (((Opcode
!= UtpQueryFuncOpcodeRdFlag
) && (Opcode
!= UtpQueryFuncOpcodeSetFlag
) &&
555 (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
)) &&
556 ((DataSize
== 0) || (Data
== NULL
)))
558 return EFI_INVALID_PARAMETER
;
561 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
562 return EFI_INVALID_PARAMETER
;
565 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
566 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
568 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
571 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
572 if (CommandDesc
== NULL
) {
573 return EFI_OUT_OF_RESOURCES
;
577 // Initialize UTP QUERY REQUEST UPIU
579 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)CommandDesc
;
580 UfsInitQueryRequestUpiu (
592 // Fill UTP_TRD associated fields
593 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
595 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
596 Trd
->Dd
= DataDirection
;
597 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
598 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
599 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 7);
600 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 32);
601 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
602 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
603 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
605 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
606 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
613 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
615 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
616 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
618 @retval EFI_SUCCESS The creation succeed.
619 @retval EFI_DEVICE_ERROR The creation failed.
620 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
624 UfsCreateNopCommandDesc (
625 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
631 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
633 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
635 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
636 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
637 if (CommandDesc
== NULL
) {
638 return EFI_OUT_OF_RESOURCES
;
641 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)CommandDesc
;
643 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
646 // Fill UTP_TRD associated fields
647 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
649 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
651 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
652 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
653 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 7);
654 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 32);
655 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
656 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
662 Find out available slot in transfer list of a UFS device.
664 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
665 @param[out] Slot The available slot.
667 @retval EFI_SUCCESS The available slot was found successfully.
671 UfsFindAvailableSlotInTrl (
672 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
676 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
679 // The simplest algo to always use slot 0.
680 // TODO: enhance it to support async transfer with multiple slot.
688 Start specified slot in transfer list of a UFS device.
690 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
691 @param[in] Slot The slot to be started.
696 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
704 UfsHcBase
= Private
->UfsHcBase
;
706 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
707 Data
= MmioRead32 (Address
);
708 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
709 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
712 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
713 MmioWrite32 (Address
, BIT0
<< Slot
);
717 Stop specified slot in transfer list of a UFS device.
719 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
720 @param[in] Slot The slot to be stop.
725 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
733 UfsHcBase
= Private
->UfsHcBase
;
735 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
736 Data
= MmioRead32 (Address
);
737 if ((Data
& (BIT0
<< Slot
)) != 0) {
738 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
739 Data
= MmioRead32 (Address
);
740 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
745 Extracts return data from query response upiu.
747 @param[in, out] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
748 @param[in] QueryResp Pointer to the query response.
750 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
751 @retval EFI_DEVICE_ERROR Data returned from device is invalid.
752 @retval EFI_SUCCESS Data extracted.
756 UfsGetReturnDataFromQueryResponse (
757 IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
758 IN UTP_QUERY_RESP_UPIU
*QueryResp
761 UINT16 ReturnDataSize
;
765 if ((Packet
== NULL
) || (QueryResp
== NULL
)) {
766 return EFI_INVALID_PARAMETER
;
769 switch (Packet
->Opcode
) {
770 case UtpQueryFuncOpcodeRdDesc
:
771 ReturnDataSize
= QueryResp
->Tsf
.Length
;
772 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
774 // Make sure the hardware device does not return more data than expected.
776 if (ReturnDataSize
> Packet
->InTransferLength
) {
777 return EFI_DEVICE_ERROR
;
780 CopyMem (Packet
->InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
781 Packet
->InTransferLength
= ReturnDataSize
;
783 case UtpQueryFuncOpcodeWrDesc
:
784 ReturnDataSize
= QueryResp
->Tsf
.Length
;
785 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
786 Packet
->OutTransferLength
= ReturnDataSize
;
788 case UtpQueryFuncOpcodeRdFlag
:
790 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
792 *((UINT8
*)(Packet
->InDataBuffer
)) = *((UINT8
*)&(QueryResp
->Tsf
.Value
) + 3);
794 case UtpQueryFuncOpcodeSetFlag
:
795 case UtpQueryFuncOpcodeClrFlag
:
796 case UtpQueryFuncOpcodeTogFlag
:
798 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
800 *((UINT8
*)(Packet
->OutDataBuffer
)) = *((UINT8
*)&(QueryResp
->Tsf
.Value
) + 3);
803 return EFI_INVALID_PARAMETER
;
810 Creates Transfer Request descriptor and sends Query Request to the device.
812 @param[in] Private Pointer to the UFS_PEIM_HC_PRIVATE_DATA.
813 @param[in, out] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
815 @retval EFI_SUCCESS The device descriptor was read/written successfully.
816 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
817 combination to point to a type of UFS device descriptor.
818 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
819 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
823 UfsSendDmRequestRetry (
824 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
825 IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
832 UTP_QUERY_RESP_UPIU
*QueryResp
;
837 // Find out which slot of transfer request list is available.
839 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
840 if (EFI_ERROR (Status
)) {
844 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
846 // Fill transfer request descriptor to this slot.
848 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
);
849 if (EFI_ERROR (Status
)) {
850 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
855 // Check the transfer request result.
857 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
858 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
859 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
862 // Start to execute the transfer request.
864 UfsStartExecCmd (Private
, Slot
);
867 // Wait for the completion of the transfer request.
869 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
870 Status
= UfsWaitMemSet (Address
, (BIT0
<< Slot
), 0, Packet
->Timeout
);
871 if (EFI_ERROR (Status
)) {
875 if ((Trd
->Ocs
!= 0) || (QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
)) {
876 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
877 DumpQueryResponseResult (QueryResp
->QueryResp
);
878 Status
= EFI_DEVICE_ERROR
;
882 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
883 if (EFI_ERROR (Status
)) {
884 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
889 UfsStopExecCmd (Private
, Slot
);
890 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
896 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
898 @param[in] Private Pointer to the UFS_PEIM_HC_PRIVATE_DATA.
899 @param[in, out] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
901 @retval EFI_SUCCESS The device responded correctly to the Query request.
902 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
903 combination to point to a type of UFS device descriptor.
904 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
905 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
910 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
911 IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
917 Status
= EFI_SUCCESS
;
919 for (Retry
= 0; Retry
< 5; Retry
++) {
920 Status
= UfsSendDmRequestRetry (Private
, Packet
);
921 if (!EFI_ERROR (Status
)) {
926 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
931 Read or write specified device descriptor of a UFS device.
933 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
934 @param[in] Read The boolean variable to show r/w direction.
935 @param[in] DescId The ID of device descriptor.
936 @param[in] Index The Index of device descriptor.
937 @param[in] Selector The Selector of device descriptor.
938 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
939 @param[in] DescSize The size of device descriptor buffer.
941 @retval EFI_SUCCESS The device descriptor was read/written successfully.
942 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
943 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
948 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
953 IN OUT VOID
*Descriptor
,
958 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
960 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
963 Packet
.DataDirection
= UfsDataIn
;
964 Packet
.InDataBuffer
= Descriptor
;
965 Packet
.InTransferLength
= DescSize
;
966 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
968 Packet
.DataDirection
= UfsDataOut
;
969 Packet
.OutDataBuffer
= Descriptor
;
970 Packet
.OutTransferLength
= DescSize
;
971 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
974 Packet
.DescId
= DescId
;
975 Packet
.Index
= Index
;
976 Packet
.Selector
= Selector
;
977 Packet
.Timeout
= UFS_TIMEOUT
;
979 Status
= UfsSendDmRequest (Private
, &Packet
);
984 Read or write specified flag of a UFS device.
986 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
987 @param[in] Read The boolean variable to show r/w direction.
988 @param[in] FlagId The ID of flag to be read or written.
989 @param[in, out] Value The value to set or clear flag.
991 @retval EFI_SUCCESS The flag was read/written successfully.
992 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
993 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
998 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1005 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1007 if (Value
== NULL
) {
1008 return EFI_INVALID_PARAMETER
;
1011 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1014 ASSERT (Value
!= NULL
);
1015 Packet
.DataDirection
= UfsDataIn
;
1016 Packet
.InDataBuffer
= (VOID
*)Value
;
1017 Packet
.InTransferLength
= 0;
1018 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1020 Packet
.DataDirection
= UfsDataOut
;
1021 Packet
.OutDataBuffer
= (VOID
*)Value
;
1022 Packet
.OutTransferLength
= 0;
1024 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1025 } else if (*Value
== 0) {
1026 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1028 return EFI_INVALID_PARAMETER
;
1032 Packet
.DescId
= FlagId
;
1034 Packet
.Selector
= 0;
1035 Packet
.Timeout
= UFS_TIMEOUT
;
1037 Status
= UfsSendDmRequest (Private
, &Packet
);
1043 Set specified flag to 1 on a UFS device.
1045 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1046 @param[in] FlagId The ID of flag to be set.
1048 @retval EFI_SUCCESS The flag was set successfully.
1049 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1050 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1055 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1063 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1069 Sends NOP IN cmd to a UFS device for initialization process request.
1070 For more details, please refer to UFS 2.0 spec Figure 13.3.
1072 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1074 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1075 received successfully.
1076 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1077 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1078 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1083 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1089 UTP_NOP_IN_UPIU
*NopInUpiu
;
1095 // Find out which slot of transfer request list is available.
1097 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1098 if (EFI_ERROR (Status
)) {
1102 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1103 Status
= UfsCreateNopCommandDesc (Private
, Trd
);
1104 if (EFI_ERROR (Status
)) {
1109 // Check the transfer request result.
1111 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1112 NopInUpiu
= (UTP_NOP_IN_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1113 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1116 // Start to execute the transfer request.
1118 UfsStartExecCmd (Private
, Slot
);
1121 // Wait for the completion of the transfer request.
1123 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1124 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1125 if (EFI_ERROR (Status
)) {
1129 if (NopInUpiu
->Resp
!= 0) {
1130 Status
= EFI_DEVICE_ERROR
;
1132 Status
= EFI_SUCCESS
;
1136 UfsStopExecCmd (Private
, Slot
);
1137 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1143 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1145 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1146 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1147 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1150 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1151 commands, InTransferLength bytes were transferred from
1152 InDataBuffer. For write and bi-directional commands,
1153 OutTransferLength bytes were transferred by
1155 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1157 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1158 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1163 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1165 IN OUT UFS_SCSI_REQUEST_PACKET
*Packet
1174 UTP_RESPONSE_UPIU
*Response
;
1175 UINT16 SenseDataLen
;
1176 UINT32 ResTranCount
;
1177 VOID
*PacketBufferMap
;
1180 // Find out which slot of transfer request list is available.
1182 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1183 if (EFI_ERROR (Status
)) {
1187 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1188 PacketBufferMap
= NULL
;
1191 // Fill transfer request descriptor to this slot.
1193 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
, &PacketBufferMap
);
1194 if (EFI_ERROR (Status
)) {
1198 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1199 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1202 // Start to execute the transfer request.
1204 UfsStartExecCmd (Private
, Slot
);
1207 // Wait for the completion of the transfer request.
1209 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1210 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
->Timeout
);
1211 if (EFI_ERROR (Status
)) {
1216 // Get sense data if exists
1218 Response
= (UTP_RESPONSE_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1219 SenseDataLen
= Response
->SenseDataLen
;
1220 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1222 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1224 // Make sure the hardware device does not return more data than expected.
1226 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1227 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1228 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1230 Packet
->SenseDataLength
= 0;
1235 // Check the transfer request result.
1237 if (Response
->Response
!= 0) {
1238 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1239 Status
= EFI_DEVICE_ERROR
;
1243 if (Trd
->Ocs
== 0) {
1244 if (Packet
->DataDirection
== UfsDataIn
) {
1245 if ((Response
->Flags
& BIT5
) == BIT5
) {
1246 ResTranCount
= Response
->ResTranCount
;
1247 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1248 Packet
->InTransferLength
-= ResTranCount
;
1250 } else if (Packet
->DataDirection
== UfsDataOut
) {
1251 if ((Response
->Flags
& BIT5
) == BIT5
) {
1252 ResTranCount
= Response
->ResTranCount
;
1253 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1254 Packet
->OutTransferLength
-= ResTranCount
;
1258 Status
= EFI_DEVICE_ERROR
;
1262 if (PacketBufferMap
!= NULL
) {
1263 IoMmuUnmap (PacketBufferMap
);
1266 UfsStopExecCmd (Private
, Slot
);
1267 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1273 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1275 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1276 @param[in] UicOpcode The opcode of the UIC command.
1277 @param[in] Arg1 The value for 1st argument of the UIC command.
1278 @param[in] Arg2 The value for 2nd argument of the UIC command.
1279 @param[in] Arg3 The value for 3rd argument of the UIC command.
1281 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1282 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1283 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1287 UfsExecUicCommands (
1288 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1300 UfsHcBase
= Private
->UfsHcBase
;
1301 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1302 Data
= MmioRead32 (Address
);
1303 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1305 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1307 MmioWrite32 (Address
, Data
);
1311 // When programming UIC command registers, host software shall set the register UICCMD
1312 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1315 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1316 MmioWrite32 (Address
, Arg1
);
1318 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1319 MmioWrite32 (Address
, Arg2
);
1321 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1322 MmioWrite32 (Address
, Arg3
);
1325 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1327 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1328 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1329 if (EFI_ERROR (Status
)) {
1333 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1334 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1337 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1338 // This bit is set to '1' by the host controller upon completion of a UIC command.
1340 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1341 Data
= MmioRead32 (Address
);
1342 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1343 if (EFI_ERROR (Status
)) {
1347 if (UicOpcode
!= UfsUicDmeReset
) {
1348 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1349 Data
= MmioRead32 (Address
);
1350 if ((Data
& 0xFF) != 0) {
1351 DEBUG_CODE_BEGIN ();
1352 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1354 return EFI_DEVICE_ERROR
;
1359 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1361 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1362 Data
= MmioRead32 (Address
);
1363 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1364 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1365 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1366 if (EFI_ERROR (Status
)) {
1367 return EFI_DEVICE_ERROR
;
1370 return EFI_NOT_FOUND
;
1373 DEBUG ((DEBUG_INFO
, "UfsblockioPei: found a attached UFS device\n"));
1379 Enable the UFS host controller for accessing.
1381 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1383 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1384 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1388 UfsEnableHostController (
1389 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1397 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1399 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1401 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1402 Data
= MmioRead32 (Address
);
1403 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1405 // Write a 0 to the HCE register at first to disable the host controller.
1407 MmioWrite32 (Address
, 0);
1409 // Wait until HCE is read as '0' before continuing.
1411 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1412 if (EFI_ERROR (Status
)) {
1413 return EFI_DEVICE_ERROR
;
1418 // Write a 1 to the HCE register to enable the UFS host controller.
1420 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1422 // Wait until HCE is read as '1' before continuing.
1424 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1425 if (EFI_ERROR (Status
)) {
1426 return EFI_DEVICE_ERROR
;
1433 Detect if a UFS device attached.
1435 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1437 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1438 @retval EFI_NOT_FOUND Not found a UFS device attached.
1439 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1443 UfsDeviceDetection (
1444 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1451 // Start UFS device detection.
1452 // Try up to 3 times for establishing data link with device.
1454 for (Retry
= 0; Retry
< 3; Retry
++) {
1455 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1456 if (!EFI_ERROR (Status
)) {
1460 if (Status
== EFI_NOT_FOUND
) {
1464 return EFI_DEVICE_ERROR
;
1468 return EFI_NOT_FOUND
;
1475 Initialize UFS task management request list related h/w context.
1477 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1479 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1480 @retval EFI_DEVICE_ERROR The initialization fails.
1484 UfsInitTaskManagementRequestList (
1485 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1492 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1493 VOID
*CmdDescMapping
;
1497 // Initial h/w and s/w context for future operations.
1499 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1500 Data
= MmioRead32 (Address
);
1501 Private
->Capabilities
= Data
;
1504 // Allocate and initialize UTP Task Management Request List.
1506 Nutmrs
= (UINT8
)(RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1507 Status
= IoMmuAllocateBuffer (
1508 EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
)),
1513 if (EFI_ERROR (Status
)) {
1514 return EFI_DEVICE_ERROR
;
1517 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
))));
1520 // Program the UTP Task Management Request List Base Address and UTP Task Management
1521 // Request List Base Address with a 64-bit address allocated at step 6.
1523 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1524 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1525 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1526 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1527 Private
->UtpTmrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1528 Private
->Nutmrs
= Nutmrs
;
1529 Private
->TmrlMapping
= CmdDescMapping
;
1532 // Enable the UTP Task Management Request List by setting the UTP Task Management
1533 // Request List RunStop Register (UTMRLRSR) to '1'.
1535 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1536 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1542 Initialize UFS transfer request list related h/w context.
1544 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1546 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1547 @retval EFI_DEVICE_ERROR The initialization fails.
1551 UfsInitTransferRequestList (
1552 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1559 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1560 VOID
*CmdDescMapping
;
1564 // Initial h/w and s/w context for future operations.
1566 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1567 Data
= MmioRead32 (Address
);
1568 Private
->Capabilities
= Data
;
1571 // Allocate and initialize UTP Transfer Request List.
1573 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1574 Status
= IoMmuAllocateBuffer (
1575 EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
)),
1580 if (EFI_ERROR (Status
)) {
1581 return EFI_DEVICE_ERROR
;
1584 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
))));
1587 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1588 // Base Address with a 64-bit address allocated at step 8.
1590 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1591 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1592 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1593 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1594 Private
->UtpTrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1595 Private
->Nutrs
= Nutrs
;
1596 Private
->TrlMapping
= CmdDescMapping
;
1599 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1600 // RunStop Register (UTRLRSR) to '1'.
1602 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1603 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1609 Initialize the UFS host controller.
1611 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1613 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1614 @retval Others A device error occurred while initializing the controller.
1619 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1624 Status
= UfsEnableHostController (Private
);
1625 if (EFI_ERROR (Status
)) {
1626 DEBUG ((DEBUG_ERROR
, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status
));
1630 Status
= UfsDeviceDetection (Private
);
1631 if (EFI_ERROR (Status
)) {
1632 DEBUG ((DEBUG_ERROR
, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status
));
1636 Status
= UfsInitTaskManagementRequestList (Private
);
1637 if (EFI_ERROR (Status
)) {
1638 DEBUG ((DEBUG_ERROR
, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status
));
1642 Status
= UfsInitTransferRequestList (Private
);
1643 if (EFI_ERROR (Status
)) {
1644 DEBUG ((DEBUG_ERROR
, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status
));
1646 if (Private
->TmrlMapping
!= NULL
) {
1648 EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)),
1649 Private
->UtpTmrlBase
,
1650 Private
->TmrlMapping
1652 Private
->TmrlMapping
= NULL
;
1658 DEBUG ((DEBUG_INFO
, "UfsDevicePei Finished\n"));
1663 Stop the UFS host controller.
1665 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1667 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1668 @retval Others A device error occurred while stopping the controller.
1673 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1681 // Enable the UTP Task Management Request List by setting the UTP Task Management
1682 // Request List RunStop Register (UTMRLRSR) to '1'.
1684 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1685 MmioWrite32 (Address
, 0);
1688 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1689 // RunStop Register (UTRLRSR) to '1'.
1691 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1692 MmioWrite32 (Address
, 0);
1695 // Write a 0 to the HCE register in order to disable the host controller.
1697 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1698 Data
= MmioRead32 (Address
);
1699 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1700 MmioWrite32 (Address
, 0);
1703 // Wait until HCE is read as '0' before continuing.
1705 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1706 if (EFI_ERROR (Status
)) {
1707 return EFI_DEVICE_ERROR
;
1710 DEBUG ((DEBUG_INFO
, "UfsDevicePei: Stop the UFS Host Controller\n"));