3 Copyright (c) 2014 - 2017, 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.
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.
14 #include "UfsBlockIoPei.h"
17 Wait for the value of the specified system memory set to the test value.
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.
24 @retval EFI_TIMEOUT The system memory setting is time out.
25 @retval EFI_SUCCESS The system memory is correct set.
47 Delay
= DivU64x32 (Timeout
, 10) + 1;
51 // Access PCI MMIO space to see if the value is the tested one.
53 Value
= MmioRead32 (Address
) & MaskValue
;
55 if (Value
== TestValue
) {
60 // Stall for 1 microseconds.
66 } while (InfiniteWait
|| (Delay
> 0));
72 Dump UIC command execution result for debugging.
74 @param[in] UicOpcode The executed UIC opcode.
75 @param[in] Result The result to be parsed.
79 DumpUicCmdExecResult (
84 if (UicOpcode
<= UfsUicDmePeerSet
) {
89 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
92 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
95 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
98 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
101 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
104 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
107 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
110 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
113 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BUSY\n"));
116 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
127 DEBUG ((EFI_D_VERBOSE
, "UIC control command fails - FAILURE\n"));
137 Dump QUERY RESPONSE UPIU result for debugging.
139 @param[in] Result The result to be parsed.
143 DumpQueryResponseResult (
149 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Readable\n"));
152 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
155 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Already Written\n"));
158 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Length\n"));
161 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Value\n"));
164 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Selector\n"));
167 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Index\n"));
170 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Idn\n"));
173 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Opcode\n"));
176 DEBUG ((EFI_D_VERBOSE
, "Query Response with General Failure\n"));
185 Swap little endian to big endian.
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.
193 SwapLittleEndianToBigEndian (
194 IN OUT UINT8
*Buffer
,
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
;
211 Fill TSF field of QUERY REQUEST UPIU.
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.
223 UfsFillTsfOfQueryReqUpiu (
224 IN OUT UTP_UPIU_TSF
*TsfBase
,
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
233 ASSERT (TsfBase
!= NULL
);
234 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
236 TsfBase
->Opcode
= Opcode
;
237 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
238 TsfBase
->DescId
= DescId
;
239 TsfBase
->Index
= Index
;
240 TsfBase
->Selector
= Selector
;
242 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
243 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
244 TsfBase
->Length
= Length
;
247 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
248 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
249 TsfBase
->Value
= Value
;
255 Initialize COMMAND UPIU.
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.
265 @retval EFI_SUCCESS The initialization succeed.
270 IN OUT UTP_COMMAND_UPIU
*Command
,
275 IN UFS_DATA_DIRECTION DataDirection
,
276 IN UINT32 ExpDataTranLen
281 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
284 // Task attribute is hard-coded to Ordered.
286 if (DataDirection
== UfsDataIn
) {
288 } else if (DataDirection
== UfsDataOut
) {
295 // Fill UTP COMMAND UPIU associated fields.
297 Command
->TransCode
= 0x01;
298 Command
->Flags
= Flags
;
300 Command
->TaskTag
= TaskTag
;
301 Command
->CmdSet
= 0x00;
302 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
303 Command
->ExpDataTranLen
= ExpDataTranLen
;
305 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
311 Initialize UTP PRDT for data transfer.
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.
317 @retval EFI_SUCCESS The initialization succeed.
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
));
337 if (BufferSize
== 0) {
341 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
343 RemainingLen
= BufferSize
;
345 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
347 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
348 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
349 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
351 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
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
;
364 Initialize QUERY REQUEST UPIU.
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.
375 @retval EFI_SUCCESS The initialization succeed.
379 UfsInitQueryRequestUpiu (
380 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
386 IN UINTN DataSize OPTIONAL
,
387 IN UINT8
*Data OPTIONAL
390 ASSERT (QueryReq
!= NULL
);
392 QueryReq
->TransCode
= 0x16;
393 QueryReq
->TaskTag
= TaskTag
;
394 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
395 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
397 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
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);
405 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
408 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
409 CopyMem (QueryReq
+ 1, Data
, DataSize
);
411 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
412 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
419 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
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.
426 @retval EFI_SUCCESS The creation succeed.
427 @retval EFI_DEVICE_ERROR The creation failed.
428 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
432 UfsCreateScsiCommandDesc (
433 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
435 IN UFS_SCSI_REQUEST_PACKET
*Packet
,
444 UTP_COMMAND_UPIU
*CommandUpiu
;
445 UTP_TR_PRD
*PrdtBase
;
446 UFS_DATA_DIRECTION DataDirection
;
448 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
450 if (Packet
->DataDirection
== UfsDataIn
) {
451 Buffer
= Packet
->InDataBuffer
;
452 Length
= Packet
->InTransferLength
;
453 DataDirection
= UfsDataIn
;
455 Buffer
= Packet
->OutDataBuffer
;
456 Length
= Packet
->OutTransferLength
;
457 DataDirection
= UfsDataOut
;
461 DataDirection
= UfsNoData
;
464 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)Length
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
466 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
467 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
468 if (CommandDesc
== NULL
) {
469 return EFI_OUT_OF_RESOURCES
;
472 CommandUpiu
= (UTP_COMMAND_UPIU
*)CommandDesc
;
473 PrdtBase
= (UTP_TR_PRD
*)(CommandDesc
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
475 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, Length
);
476 UfsInitUtpPrdt (PrdtBase
, Buffer
, Length
);
479 // Fill UTP_TRD associated fields
480 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
481 // *MUST* be located at a 64-bit aligned boundary.
483 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
484 Trd
->Dd
= DataDirection
;
485 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
486 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
487 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 7);
488 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 32);
489 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
490 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
491 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
492 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
497 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
499 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
500 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
501 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
503 @retval EFI_SUCCESS The creation succeed.
504 @retval EFI_DEVICE_ERROR The creation failed.
505 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
506 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
510 UfsCreateDMCommandDesc (
511 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
512 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
518 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
524 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
526 Opcode
= Packet
->Opcode
;
527 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
528 return EFI_INVALID_PARAMETER
;
531 DataDirection
= Packet
->DataDirection
;
532 if (DataDirection
== UfsDataIn
) {
533 DataSize
= Packet
->InTransferLength
;
534 Data
= Packet
->InDataBuffer
;
535 } else if (DataDirection
== UfsDataOut
) {
536 DataSize
= Packet
->OutTransferLength
;
537 Data
= Packet
->OutDataBuffer
;
543 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
544 && ((DataSize
== 0) || (Data
== NULL
))) {
545 return EFI_INVALID_PARAMETER
;
548 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
549 && ((DataSize
!= 0) || (Data
!= NULL
))) {
550 return EFI_INVALID_PARAMETER
;
553 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
554 return EFI_INVALID_PARAMETER
;
557 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
558 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
560 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
563 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
564 if (CommandDesc
== NULL
) {
565 return EFI_OUT_OF_RESOURCES
;
569 // Initialize UTP QUERY REQUEST UPIU
571 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)CommandDesc
;
572 UfsInitQueryRequestUpiu (
584 // Fill UTP_TRD associated fields
585 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
587 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
588 Trd
->Dd
= DataDirection
;
589 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
590 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
591 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 7);
592 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 32);
593 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
594 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
595 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
597 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
598 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
605 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
607 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
608 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
610 @retval EFI_SUCCESS The creation succeed.
611 @retval EFI_DEVICE_ERROR The creation failed.
612 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
616 UfsCreateNopCommandDesc (
617 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
623 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
625 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
627 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
628 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
629 if (CommandDesc
== NULL
) {
630 return EFI_OUT_OF_RESOURCES
;
633 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)CommandDesc
;
635 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
638 // Fill UTP_TRD associated fields
639 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
641 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
643 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
644 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
645 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 7);
646 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 32);
647 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
648 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
654 Find out available slot in transfer list of a UFS device.
656 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
657 @param[out] Slot The available slot.
659 @retval EFI_SUCCESS The available slot was found successfully.
663 UfsFindAvailableSlotInTrl (
664 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
668 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
671 // The simplest algo to always use slot 0.
672 // TODO: enhance it to support async transfer with multiple slot.
680 Find out available slot in task management transfer list of a UFS device.
682 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
683 @param[out] Slot The available slot.
685 @retval EFI_SUCCESS The available slot was found successfully.
689 UfsFindAvailableSlotInTmrl (
690 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
694 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
697 // The simplest algo to always use slot 0.
698 // TODO: enhance it to support async transfer with multiple slot.
706 Start specified slot in transfer list of a UFS device.
708 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
709 @param[in] Slot The slot to be started.
714 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
722 UfsHcBase
= Private
->UfsHcBase
;
724 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
725 Data
= MmioRead32 (Address
);
726 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
727 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
730 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
731 MmioWrite32 (Address
, BIT0
<< Slot
);
735 Stop specified slot in transfer list of a UFS device.
737 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
738 @param[in] Slot The slot to be stop.
743 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
751 UfsHcBase
= Private
->UfsHcBase
;
753 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
754 Data
= MmioRead32 (Address
);
755 if ((Data
& (BIT0
<< Slot
)) != 0) {
756 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
757 Data
= MmioRead32 (Address
);
758 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
763 Read or write specified device descriptor of a UFS device.
765 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
766 @param[in] Read The boolean variable to show r/w direction.
767 @param[in] DescId The ID of device descriptor.
768 @param[in] Index The Index of device descriptor.
769 @param[in] Selector The Selector of device descriptor.
770 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
771 @param[in] DescSize The size of device descriptor buffer.
773 @retval EFI_SUCCESS The device descriptor was read/written successfully.
774 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
775 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
780 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
785 IN OUT VOID
*Descriptor
,
790 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
794 UTP_QUERY_RESP_UPIU
*QueryResp
;
797 UINT16 ReturnDataSize
;
799 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
802 Packet
.DataDirection
= UfsDataIn
;
803 Packet
.InDataBuffer
= Descriptor
;
804 Packet
.InTransferLength
= DescSize
;
805 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
807 Packet
.DataDirection
= UfsDataOut
;
808 Packet
.OutDataBuffer
= Descriptor
;
809 Packet
.OutTransferLength
= DescSize
;
810 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
812 Packet
.DescId
= DescId
;
813 Packet
.Index
= Index
;
814 Packet
.Selector
= Selector
;
815 Packet
.Timeout
= UFS_TIMEOUT
;
818 // Find out which slot of transfer request list is available.
820 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
821 if (EFI_ERROR (Status
)) {
825 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
827 // Fill transfer request descriptor to this slot.
829 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
830 if (EFI_ERROR (Status
)) {
835 // Check the transfer request result.
837 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
838 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
839 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
842 // Start to execute the transfer request.
844 UfsStartExecCmd (Private
, Slot
);
847 // Wait for the completion of the transfer request.
849 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
850 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
851 if (EFI_ERROR (Status
)) {
855 if (QueryResp
->QueryResp
!= 0) {
856 DumpQueryResponseResult (QueryResp
->QueryResp
);
857 Status
= EFI_DEVICE_ERROR
;
862 ReturnDataSize
= QueryResp
->Tsf
.Length
;
863 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
866 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
867 Packet
.InTransferLength
= ReturnDataSize
;
869 Packet
.OutTransferLength
= ReturnDataSize
;
872 Status
= EFI_DEVICE_ERROR
;
876 UfsStopExecCmd (Private
, Slot
);
877 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
883 Read or write specified attribute of a UFS device.
885 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
886 @param[in] Read The boolean variable to show r/w direction.
887 @param[in] AttrId The ID of Attribute.
888 @param[in] Index The Index of Attribute.
889 @param[in] Selector The Selector of Attribute.
890 @param[in, out] Attributes The value of Attribute to be read or written.
892 @retval EFI_SUCCESS The Attribute was read/written successfully.
893 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
894 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
899 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
904 IN OUT UINT32
*Attributes
908 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
912 UTP_QUERY_RESP_UPIU
*QueryResp
;
917 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
920 Packet
.DataDirection
= UfsDataIn
;
921 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
923 Packet
.DataDirection
= UfsDataOut
;
924 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
926 Packet
.DescId
= AttrId
;
927 Packet
.Index
= Index
;
928 Packet
.Selector
= Selector
;
929 Packet
.Timeout
= UFS_TIMEOUT
;
932 // Find out which slot of transfer request list is available.
934 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
935 if (EFI_ERROR (Status
)) {
939 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
941 // Fill transfer request descriptor to this slot.
943 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
944 if (EFI_ERROR (Status
)) {
949 // Check the transfer request result.
951 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
952 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
953 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
956 // Start to execute the transfer request.
958 UfsStartExecCmd (Private
, Slot
);
961 // Wait for the completion of the transfer request.
963 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
964 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
965 if (EFI_ERROR (Status
)) {
969 if (QueryResp
->QueryResp
!= 0) {
970 DumpQueryResponseResult (QueryResp
->QueryResp
);
971 Status
= EFI_DEVICE_ERROR
;
976 ReturnData
= QueryResp
->Tsf
.Value
;
977 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
978 *Attributes
= ReturnData
;
980 Status
= EFI_DEVICE_ERROR
;
984 UfsStopExecCmd (Private
, Slot
);
985 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
991 Read or write specified flag of a UFS device.
993 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
994 @param[in] Read The boolean variable to show r/w direction.
995 @param[in] FlagId The ID of flag to be read or written.
996 @param[in, out] Value The value to set or clear flag.
998 @retval EFI_SUCCESS The flag was read/written successfully.
999 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1000 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1005 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1012 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1016 UTP_QUERY_RESP_UPIU
*QueryResp
;
1020 if (Value
== NULL
) {
1021 return EFI_INVALID_PARAMETER
;
1024 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1027 ASSERT (Value
!= NULL
);
1028 Packet
.DataDirection
= UfsDataIn
;
1029 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1031 Packet
.DataDirection
= UfsDataOut
;
1033 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1034 } else if (*Value
== 0) {
1035 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1037 return EFI_INVALID_PARAMETER
;
1040 Packet
.DescId
= FlagId
;
1042 Packet
.Selector
= 0;
1043 Packet
.Timeout
= UFS_TIMEOUT
;
1046 // Find out which slot of transfer request list is available.
1048 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1049 if (EFI_ERROR (Status
)) {
1054 // Fill transfer request descriptor to this slot.
1056 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1057 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
1058 if (EFI_ERROR (Status
)) {
1063 // Check the transfer request result.
1065 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1066 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1067 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1070 // Start to execute the transfer request.
1072 UfsStartExecCmd (Private
, Slot
);
1075 // Wait for the completion of the transfer request.
1077 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1078 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
1079 if (EFI_ERROR (Status
)) {
1083 if (QueryResp
->QueryResp
!= 0) {
1084 DumpQueryResponseResult (QueryResp
->QueryResp
);
1085 Status
= EFI_DEVICE_ERROR
;
1089 if (Trd
->Ocs
== 0) {
1090 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
1092 Status
= EFI_DEVICE_ERROR
;
1096 UfsStopExecCmd (Private
, Slot
);
1097 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1103 Set specified flag to 1 on a UFS device.
1105 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1106 @param[in] FlagId The ID of flag to be set.
1108 @retval EFI_SUCCESS The flag was set successfully.
1109 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1110 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1115 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1123 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1129 Clear specified flag to 0 on a UFS device.
1131 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1132 @param[in] FlagId The ID of flag to be cleared.
1134 @retval EFI_SUCCESS The flag was cleared successfully.
1135 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1136 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1141 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1149 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1155 Read specified flag from a UFS device.
1157 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1158 @param[in] FlagId The ID of flag to be read.
1159 @param[out] Value The flag's value.
1161 @retval EFI_SUCCESS The flag was read successfully.
1162 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1163 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1168 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1175 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1181 Sends NOP IN cmd to a UFS device for initialization process request.
1182 For more details, please refer to UFS 2.0 spec Figure 13.3.
1184 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1186 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1187 received successfully.
1188 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1189 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1190 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1195 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1201 UTP_NOP_IN_UPIU
*NopInUpiu
;
1207 // Find out which slot of transfer request list is available.
1209 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1210 if (EFI_ERROR (Status
)) {
1214 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1215 Status
= UfsCreateNopCommandDesc (Private
, Trd
);
1216 if (EFI_ERROR (Status
)) {
1221 // Check the transfer request result.
1223 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1224 NopInUpiu
= (UTP_NOP_IN_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1225 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1228 // Start to execute the transfer request.
1230 UfsStartExecCmd (Private
, Slot
);
1233 // Wait for the completion of the transfer request.
1235 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1236 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1237 if (EFI_ERROR (Status
)) {
1241 if (NopInUpiu
->Resp
!= 0) {
1242 Status
= EFI_DEVICE_ERROR
;
1244 Status
= EFI_SUCCESS
;
1248 UfsStopExecCmd (Private
, Slot
);
1249 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1255 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1257 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1258 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1259 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1262 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1263 commands, InTransferLength bytes were transferred from
1264 InDataBuffer. For write and bi-directional commands,
1265 OutTransferLength bytes were transferred by
1267 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1269 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1270 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1275 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1277 IN OUT UFS_SCSI_REQUEST_PACKET
*Packet
1286 UTP_RESPONSE_UPIU
*Response
;
1287 UINT16 SenseDataLen
;
1288 UINT32 ResTranCount
;
1291 // Find out which slot of transfer request list is available.
1293 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1294 if (EFI_ERROR (Status
)) {
1298 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1301 // Fill transfer request descriptor to this slot.
1303 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
);
1304 if (EFI_ERROR (Status
)) {
1308 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1309 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1312 // Start to execute the transfer request.
1314 UfsStartExecCmd (Private
, Slot
);
1317 // Wait for the completion of the transfer request.
1319 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1320 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
->Timeout
);
1321 if (EFI_ERROR (Status
)) {
1326 // Get sense data if exists
1328 Response
= (UTP_RESPONSE_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1329 SenseDataLen
= Response
->SenseDataLen
;
1330 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1332 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1333 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1334 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1338 // Check the transfer request result.
1340 if (Response
->Response
!= 0) {
1341 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1342 Status
= EFI_DEVICE_ERROR
;
1346 if (Trd
->Ocs
== 0) {
1347 if (Packet
->DataDirection
== UfsDataIn
) {
1348 if ((Response
->Flags
& BIT5
) == BIT5
) {
1349 ResTranCount
= Response
->ResTranCount
;
1350 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1351 Packet
->InTransferLength
-= ResTranCount
;
1353 } else if (Packet
->DataDirection
== UfsDataOut
) {
1354 if ((Response
->Flags
& BIT5
) == BIT5
) {
1355 ResTranCount
= Response
->ResTranCount
;
1356 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1357 Packet
->OutTransferLength
-= ResTranCount
;
1361 Status
= EFI_DEVICE_ERROR
;
1365 UfsStopExecCmd (Private
, Slot
);
1366 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1373 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1375 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1376 @param[in] UicOpcode The opcode of the UIC command.
1377 @param[in] Arg1 The value for 1st argument of the UIC command.
1378 @param[in] Arg2 The value for 2nd argument of the UIC command.
1379 @param[in] Arg3 The value for 3rd argument of the UIC command.
1381 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1382 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1383 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1387 UfsExecUicCommands (
1388 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1400 UfsHcBase
= Private
->UfsHcBase
;
1401 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1402 Data
= MmioRead32 (Address
);
1403 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1405 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1407 MmioWrite32 (Address
, Data
);
1411 // When programming UIC command registers, host software shall set the register UICCMD
1412 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1415 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1416 MmioWrite32 (Address
, Arg1
);
1418 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1419 MmioWrite32 (Address
, Arg2
);
1421 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1422 MmioWrite32 (Address
, Arg3
);
1425 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1427 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1428 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1429 if (EFI_ERROR (Status
)) {
1433 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1434 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1437 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1438 // This bit is set to '1' by the host controller upon completion of a UIC command.
1440 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1441 Data
= MmioRead32 (Address
);
1442 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1443 if (EFI_ERROR (Status
)) {
1447 if (UicOpcode
!= UfsUicDmeReset
) {
1448 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1449 Data
= MmioRead32 (Address
);
1450 if ((Data
& 0xFF) != 0) {
1452 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1454 return EFI_DEVICE_ERROR
;
1459 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1461 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1462 Data
= MmioRead32 (Address
);
1463 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1464 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1465 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1466 if (EFI_ERROR (Status
)) {
1467 return EFI_DEVICE_ERROR
;
1469 return EFI_NOT_FOUND
;
1472 DEBUG ((EFI_D_INFO
, "UfsblockioPei: found a attached UFS device\n"));
1478 Enable the UFS host controller for accessing.
1480 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1482 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1483 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1487 UfsEnableHostController (
1488 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1496 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1498 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1500 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1501 Data
= MmioRead32 (Address
);
1502 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1504 // Write a 0 to the HCE register at first to disable the host controller.
1506 MmioWrite32 (Address
, 0);
1508 // Wait until HCE is read as '0' before continuing.
1510 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1511 if (EFI_ERROR (Status
)) {
1512 return EFI_DEVICE_ERROR
;
1517 // Write a 1 to the HCE register to enable the UFS host controller.
1519 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1521 // Wait until HCE is read as '1' before continuing.
1523 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1524 if (EFI_ERROR (Status
)) {
1525 return EFI_DEVICE_ERROR
;
1532 Detect if a UFS device attached.
1534 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1536 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1537 @retval EFI_NOT_FOUND Not found a UFS device attached.
1538 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1542 UfsDeviceDetection (
1543 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1550 // Start UFS device detection.
1551 // Try up to 3 times for establishing data link with device.
1553 for (Retry
= 0; Retry
< 3; Retry
++) {
1554 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1555 if (!EFI_ERROR (Status
)) {
1559 if (Status
== EFI_NOT_FOUND
) {
1563 return EFI_DEVICE_ERROR
;
1567 return EFI_NOT_FOUND
;
1574 Initialize UFS task management request list related h/w context.
1576 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1578 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1579 @retval EFI_DEVICE_ERROR The initialization fails.
1583 UfsInitTaskManagementRequestList (
1584 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1590 EFI_PHYSICAL_ADDRESS Buffer
;
1594 // Initial h/w and s/w context for future operations.
1596 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1597 Data
= MmioRead32 (Address
);
1598 Private
->Capabilities
= Data
;
1601 // Allocate and initialize UTP Task Management Request List.
1603 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1604 Status
= PeiServicesAllocatePages (
1605 EfiBootServicesCode
,
1606 EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
)),
1610 if (EFI_ERROR (Status
)) {
1611 return EFI_DEVICE_ERROR
;
1614 ZeroMem ((VOID
*)(UINTN
)Buffer
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
))));
1617 // Program the UTP Task Management Request List Base Address and UTP Task Management
1618 // Request List Base Address with a 64-bit address allocated at step 6.
1620 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1621 MmioWrite32 (Address
, (UINT32
)(UINTN
)Buffer
);
1622 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1623 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)Buffer
, 32));
1624 Private
->UtpTmrlBase
= (VOID
*)(UINTN
)Buffer
;
1625 Private
->Nutmrs
= Nutmrs
;
1628 // Enable the UTP Task Management Request List by setting the UTP Task Management
1629 // Request List RunStop Register (UTMRLRSR) to '1'.
1631 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1632 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1638 Initialize UFS transfer request list related h/w context.
1640 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1642 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1643 @retval EFI_DEVICE_ERROR The initialization fails.
1647 UfsInitTransferRequestList (
1648 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1654 EFI_PHYSICAL_ADDRESS Buffer
;
1658 // Initial h/w and s/w context for future operations.
1660 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1661 Data
= MmioRead32 (Address
);
1662 Private
->Capabilities
= Data
;
1665 // Allocate and initialize UTP Transfer Request List.
1667 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1668 Status
= PeiServicesAllocatePages (
1669 EfiBootServicesCode
,
1670 EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
)),
1674 if (EFI_ERROR (Status
)) {
1675 return EFI_DEVICE_ERROR
;
1678 ZeroMem ((VOID
*)(UINTN
)Buffer
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
))));
1681 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1682 // Base Address with a 64-bit address allocated at step 8.
1684 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1685 MmioWrite32 (Address
, (UINT32
)(UINTN
)Buffer
);
1686 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1687 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)Buffer
, 32));
1688 Private
->UtpTrlBase
= (VOID
*)(UINTN
)Buffer
;
1689 Private
->Nutrs
= Nutrs
;
1692 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1693 // RunStop Register (UTRLRSR) to '1'.
1695 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1696 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1702 Initialize the UFS host controller.
1704 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1706 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1707 @retval Others A device error occurred while initializing the controller.
1712 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1717 Status
= UfsEnableHostController (Private
);
1718 if (EFI_ERROR (Status
)) {
1719 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status
));
1723 Status
= UfsDeviceDetection (Private
);
1724 if (EFI_ERROR (Status
)) {
1725 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status
));
1729 Status
= UfsInitTaskManagementRequestList (Private
);
1730 if (EFI_ERROR (Status
)) {
1731 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status
));
1735 Status
= UfsInitTransferRequestList (Private
);
1736 if (EFI_ERROR (Status
)) {
1737 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status
));
1741 DEBUG ((EFI_D_INFO
, "UfsDevicePei Finished\n"));
1746 Stop the UFS host controller.
1748 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1750 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1751 @retval Others A device error occurred while stopping the controller.
1756 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1764 // Enable the UTP Task Management Request List by setting the UTP Task Management
1765 // Request List RunStop Register (UTMRLRSR) to '1'.
1767 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1768 MmioWrite32 (Address
, 0);
1771 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1772 // RunStop Register (UTRLRSR) to '1'.
1774 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1775 MmioWrite32 (Address
, 0);
1778 // Write a 0 to the HCE register in order to disable the host controller.
1780 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1781 Data
= MmioRead32 (Address
);
1782 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1783 MmioWrite32 (Address
, 0);
1786 // Wait until HCE is read as '0' before continuing.
1788 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1789 if (EFI_ERROR (Status
)) {
1790 return EFI_DEVICE_ERROR
;
1793 DEBUG ((EFI_D_INFO
, "UfsDevicePei: Stop the UFS Host Controller\n"));