3 Copyright (c) 2014, 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
== 0) {
336 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
338 RemainingLen
= BufferSize
;
340 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
342 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
343 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
344 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
346 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
349 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
350 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
351 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
352 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
359 Initialize QUERY REQUEST UPIU.
361 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
362 @param[in] TaskTag The task tag of request.
363 @param[in] Opcode The opcode of request.
364 @param[in] DescId The descriptor ID of request.
365 @param[in] Index The index of request.
366 @param[in] Selector The selector of request.
367 @param[in] DataSize The data size to be read or written.
368 @param[in] Data The buffer to be read or written.
370 @retval EFI_SUCCESS The initialization succeed.
374 UfsInitQueryRequestUpiu (
375 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
381 IN UINTN DataSize OPTIONAL
,
382 IN UINT8
*Data OPTIONAL
385 ASSERT (QueryReq
!= NULL
);
387 QueryReq
->TransCode
= 0x16;
388 QueryReq
->TaskTag
= TaskTag
;
389 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
390 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
392 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
395 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
396 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
397 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
398 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
400 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
403 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
404 CopyMem (QueryReq
+ 1, Data
, DataSize
);
411 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
413 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
414 @param[in] Lun The Lun on which the SCSI command is executed.
415 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
416 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
418 @retval EFI_SUCCESS The creation succeed.
419 @retval EFI_DEVICE_ERROR The creation failed.
420 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
424 UfsCreateScsiCommandDesc (
425 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
427 IN UFS_SCSI_REQUEST_PACKET
*Packet
,
436 UTP_COMMAND_UPIU
*CommandUpiu
;
437 UTP_TR_PRD
*PrdtBase
;
438 UFS_DATA_DIRECTION DataDirection
;
440 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
442 if (Packet
->DataDirection
== UfsDataIn
) {
443 Buffer
= Packet
->InDataBuffer
;
444 Length
= Packet
->InTransferLength
;
445 DataDirection
= UfsDataIn
;
447 Buffer
= Packet
->OutDataBuffer
;
448 Length
= Packet
->OutTransferLength
;
449 DataDirection
= UfsDataOut
;
453 DataDirection
= UfsNoData
;
456 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)Length
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
458 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
459 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
460 if (CommandDesc
== NULL
) {
461 return EFI_OUT_OF_RESOURCES
;
464 CommandUpiu
= (UTP_COMMAND_UPIU
*)CommandDesc
;
465 PrdtBase
= (UTP_TR_PRD
*)(CommandDesc
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
467 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, Length
);
468 UfsInitUtpPrdt (PrdtBase
, Buffer
, Length
);
471 // Fill UTP_TRD associated fields
472 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
473 // *MUST* be located at a 64-bit aligned boundary.
475 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
476 Trd
->Dd
= DataDirection
;
477 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
478 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 7);
479 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 32);
480 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
481 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
482 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
483 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
488 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
490 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
491 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
492 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
494 @retval EFI_SUCCESS The creation succeed.
495 @retval EFI_DEVICE_ERROR The creation failed.
496 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
497 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
501 UfsCreateDMCommandDesc (
502 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
503 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
509 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
515 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
517 Opcode
= Packet
->Opcode
;
518 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
519 return EFI_INVALID_PARAMETER
;
522 DataDirection
= Packet
->DataDirection
;
523 if (DataDirection
== UfsDataIn
) {
524 DataSize
= Packet
->InTransferLength
;
525 Data
= Packet
->InDataBuffer
;
526 } else if (DataDirection
== UfsDataOut
) {
527 DataSize
= Packet
->OutTransferLength
;
528 Data
= Packet
->OutDataBuffer
;
534 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
535 && ((DataSize
== 0) || (Data
== NULL
))) {
536 return EFI_INVALID_PARAMETER
;
539 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
540 && ((DataSize
!= 0) || (Data
!= NULL
))) {
541 return EFI_INVALID_PARAMETER
;
544 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
545 return EFI_INVALID_PARAMETER
;
548 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
549 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
551 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
554 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
555 if (CommandDesc
== NULL
) {
556 return EFI_OUT_OF_RESOURCES
;
560 // Initialize UTP QUERY REQUEST UPIU
562 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)CommandDesc
;
563 UfsInitQueryRequestUpiu (
575 // Fill UTP_TRD associated fields
576 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
578 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
579 Trd
->Dd
= DataDirection
;
580 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
582 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 7);
583 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 32);
584 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
585 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
586 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
588 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
589 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
596 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
598 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
599 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
601 @retval EFI_SUCCESS The creation succeed.
602 @retval EFI_DEVICE_ERROR The creation failed.
603 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
607 UfsCreateNopCommandDesc (
608 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
614 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
616 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
618 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
619 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
620 if (CommandDesc
== NULL
) {
621 return EFI_OUT_OF_RESOURCES
;
624 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)CommandDesc
;
626 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
629 // Fill UTP_TRD associated fields
630 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
632 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
634 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
635 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 7);
636 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 32);
637 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
638 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
644 Find out available slot in transfer list of a UFS device.
646 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
647 @param[out] Slot The available slot.
649 @retval EFI_SUCCESS The available slot was found successfully.
653 UfsFindAvailableSlotInTrl (
654 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
658 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
661 // The simplest algo to always use slot 0.
662 // TODO: enhance it to support async transfer with multiple slot.
670 Find out available slot in task management transfer list of a UFS device.
672 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
673 @param[out] Slot The available slot.
675 @retval EFI_SUCCESS The available slot was found successfully.
679 UfsFindAvailableSlotInTmrl (
680 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
684 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
687 // The simplest algo to always use slot 0.
688 // TODO: enhance it to support async transfer with multiple slot.
696 Start specified slot in transfer list of a UFS device.
698 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
699 @param[in] Slot The slot to be started.
704 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
712 UfsHcBase
= Private
->UfsHcBase
;
714 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
715 Data
= MmioRead32 (Address
);
716 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
717 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
720 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
721 MmioWrite32 (Address
, BIT0
<< Slot
);
725 Stop specified slot in transfer list of a UFS device.
727 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
728 @param[in] Slot The slot to be stop.
733 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
741 UfsHcBase
= Private
->UfsHcBase
;
743 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
744 Data
= MmioRead32 (Address
);
745 if ((Data
& (BIT0
<< Slot
)) != 0) {
746 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
747 Data
= MmioRead32 (Address
);
748 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
753 Read or write specified device descriptor of a UFS device.
755 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
756 @param[in] Read The boolean variable to show r/w direction.
757 @param[in] DescId The ID of device descriptor.
758 @param[in] Index The Index of device descriptor.
759 @param[in] Selector The Selector of device descriptor.
760 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
761 @param[in] DescSize The size of device descriptor buffer.
763 @retval EFI_SUCCESS The device descriptor was read/written successfully.
764 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
765 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
770 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
775 IN OUT VOID
*Descriptor
,
780 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
784 UTP_QUERY_RESP_UPIU
*QueryResp
;
787 UINT16 ReturnDataSize
;
789 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
792 Packet
.DataDirection
= UfsDataIn
;
793 Packet
.InDataBuffer
= Descriptor
;
794 Packet
.InTransferLength
= DescSize
;
795 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
797 Packet
.DataDirection
= UfsDataOut
;
798 Packet
.OutDataBuffer
= Descriptor
;
799 Packet
.OutTransferLength
= DescSize
;
800 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
802 Packet
.DescId
= DescId
;
803 Packet
.Index
= Index
;
804 Packet
.Selector
= Selector
;
805 Packet
.Timeout
= UFS_TIMEOUT
;
808 // Find out which slot of transfer request list is available.
810 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
811 if (EFI_ERROR (Status
)) {
815 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
817 // Fill transfer request descriptor to this slot.
819 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
820 if (EFI_ERROR (Status
)) {
825 // Check the transfer request result.
827 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
828 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
829 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
832 // Start to execute the transfer request.
834 UfsStartExecCmd (Private
, Slot
);
837 // Wait for the completion of the transfer request.
839 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
840 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
.Timeout
);
841 if (EFI_ERROR (Status
)) {
845 if (QueryResp
->QueryResp
!= 0) {
846 DumpQueryResponseResult (QueryResp
->QueryResp
);
847 Status
= EFI_DEVICE_ERROR
;
852 ReturnDataSize
= QueryResp
->Tsf
.Length
;
853 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
856 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
857 Packet
.InTransferLength
= ReturnDataSize
;
859 Packet
.OutTransferLength
= ReturnDataSize
;
862 Status
= EFI_DEVICE_ERROR
;
866 UfsStopExecCmd (Private
, Slot
);
867 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
873 Read or write specified attribute of a UFS device.
875 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
876 @param[in] Read The boolean variable to show r/w direction.
877 @param[in] AttrId The ID of Attribute.
878 @param[in] Index The Index of Attribute.
879 @param[in] Selector The Selector of Attribute.
880 @param[in, out] Attributes The value of Attribute to be read or written.
882 @retval EFI_SUCCESS The Attribute was read/written successfully.
883 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
884 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
889 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
894 IN OUT UINT32
*Attributes
898 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
902 UTP_QUERY_RESP_UPIU
*QueryResp
;
907 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
910 Packet
.DataDirection
= UfsDataIn
;
911 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
913 Packet
.DataDirection
= UfsDataOut
;
914 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
916 Packet
.DescId
= AttrId
;
917 Packet
.Index
= Index
;
918 Packet
.Selector
= Selector
;
919 Packet
.Timeout
= UFS_TIMEOUT
;
922 // Find out which slot of transfer request list is available.
924 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
925 if (EFI_ERROR (Status
)) {
929 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
931 // Fill transfer request descriptor to this slot.
933 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
934 if (EFI_ERROR (Status
)) {
939 // Check the transfer request result.
941 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
942 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
943 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
946 // Start to execute the transfer request.
948 UfsStartExecCmd (Private
, Slot
);
951 // Wait for the completion of the transfer request.
953 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
954 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
.Timeout
);
955 if (EFI_ERROR (Status
)) {
959 if (QueryResp
->QueryResp
!= 0) {
960 DumpQueryResponseResult (QueryResp
->QueryResp
);
961 Status
= EFI_DEVICE_ERROR
;
966 ReturnData
= QueryResp
->Tsf
.Value
;
967 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
968 *Attributes
= ReturnData
;
970 Status
= EFI_DEVICE_ERROR
;
974 UfsStopExecCmd (Private
, Slot
);
975 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
981 Read or write specified flag of a UFS device.
983 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
984 @param[in] Read The boolean variable to show r/w direction.
985 @param[in] FlagId The ID of flag to be read or written.
986 @param[in, out] Value The value to set or clear flag.
988 @retval EFI_SUCCESS The flag was read/written successfully.
989 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
990 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
995 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1002 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1006 UTP_QUERY_RESP_UPIU
*QueryResp
;
1010 if (Value
== NULL
) {
1011 return EFI_INVALID_PARAMETER
;
1014 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1017 ASSERT (Value
!= NULL
);
1018 Packet
.DataDirection
= UfsDataIn
;
1019 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1021 Packet
.DataDirection
= UfsDataOut
;
1023 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1024 } else if (*Value
== 0) {
1025 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1027 return EFI_INVALID_PARAMETER
;
1030 Packet
.DescId
= FlagId
;
1032 Packet
.Selector
= 0;
1033 Packet
.Timeout
= UFS_TIMEOUT
;
1036 // Find out which slot of transfer request list is available.
1038 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1039 if (EFI_ERROR (Status
)) {
1044 // Fill transfer request descriptor to this slot.
1046 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1047 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
1048 if (EFI_ERROR (Status
)) {
1053 // Check the transfer request result.
1055 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1056 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1057 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1060 // Start to execute the transfer request.
1062 UfsStartExecCmd (Private
, Slot
);
1065 // Wait for the completion of the transfer request.
1067 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1068 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
.Timeout
);
1069 if (EFI_ERROR (Status
)) {
1073 if (QueryResp
->QueryResp
!= 0) {
1074 DumpQueryResponseResult (QueryResp
->QueryResp
);
1075 Status
= EFI_DEVICE_ERROR
;
1079 if (Trd
->Ocs
== 0) {
1080 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
1082 Status
= EFI_DEVICE_ERROR
;
1086 UfsStopExecCmd (Private
, Slot
);
1087 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1093 Set specified flag to 1 on a UFS device.
1095 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1096 @param[in] FlagId The ID of flag to be set.
1098 @retval EFI_SUCCESS The flag was set successfully.
1099 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1100 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1105 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1113 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1119 Clear specified flag to 0 on a UFS device.
1121 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1122 @param[in] FlagId The ID of flag to be cleared.
1124 @retval EFI_SUCCESS The flag was cleared successfully.
1125 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1126 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1131 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1139 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1145 Read specified flag from a UFS device.
1147 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1148 @param[in] FlagId The ID of flag to be read.
1149 @param[out] Value The flag's value.
1151 @retval EFI_SUCCESS The flag was read successfully.
1152 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1153 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1158 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1165 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1171 Sends NOP IN cmd to a UFS device for initialization process request.
1172 For more details, please refer to UFS 2.0 spec Figure 13.3.
1174 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1176 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1177 received successfully.
1178 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1179 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1180 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1185 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1191 UTP_NOP_IN_UPIU
*NopInUpiu
;
1197 // Find out which slot of transfer request list is available.
1199 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1200 if (EFI_ERROR (Status
)) {
1204 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1205 Status
= UfsCreateNopCommandDesc (Private
, Trd
);
1206 if (EFI_ERROR (Status
)) {
1211 // Check the transfer request result.
1213 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1214 NopInUpiu
= (UTP_NOP_IN_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1215 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1218 // Start to execute the transfer request.
1220 UfsStartExecCmd (Private
, Slot
);
1223 // Wait for the completion of the transfer request.
1225 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1226 Status
= UfsWaitMemSet (Address
, BIT0
, 0, UFS_TIMEOUT
);
1227 if (EFI_ERROR (Status
)) {
1231 if (NopInUpiu
->Resp
!= 0) {
1232 Status
= EFI_DEVICE_ERROR
;
1234 Status
= EFI_SUCCESS
;
1238 UfsStopExecCmd (Private
, Slot
);
1239 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1245 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1247 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1248 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1249 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1252 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1253 commands, InTransferLength bytes were transferred from
1254 InDataBuffer. For write and bi-directional commands,
1255 OutTransferLength bytes were transferred by
1257 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1259 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1260 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1265 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1267 IN OUT UFS_SCSI_REQUEST_PACKET
*Packet
1276 UTP_RESPONSE_UPIU
*Response
;
1277 UINT16 SenseDataLen
;
1278 UINT32 ResTranCount
;
1281 // Find out which slot of transfer request list is available.
1283 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1284 if (EFI_ERROR (Status
)) {
1288 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1291 // Fill transfer request descriptor to this slot.
1293 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
);
1294 if (EFI_ERROR (Status
)) {
1298 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1299 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1302 // Start to execute the transfer request.
1304 UfsStartExecCmd (Private
, Slot
);
1307 // Wait for the completion of the transfer request.
1309 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1310 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
->Timeout
);
1311 if (EFI_ERROR (Status
)) {
1316 // Get sense data if exists
1318 Response
= (UTP_RESPONSE_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1319 SenseDataLen
= Response
->SenseDataLen
;
1320 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1322 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1323 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1324 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1328 // Check the transfer request result.
1330 if (Response
->Response
!= 0) {
1331 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1332 Status
= EFI_DEVICE_ERROR
;
1336 if (Trd
->Ocs
== 0) {
1337 if (Packet
->DataDirection
== UfsDataIn
) {
1338 if ((Response
->Flags
& BIT5
) == BIT5
) {
1339 ResTranCount
= Response
->ResTranCount
;
1340 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1341 Packet
->InTransferLength
-= ResTranCount
;
1343 } else if (Packet
->DataDirection
== UfsDataOut
) {
1344 if ((Response
->Flags
& BIT5
) == BIT5
) {
1345 ResTranCount
= Response
->ResTranCount
;
1346 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1347 Packet
->OutTransferLength
-= ResTranCount
;
1351 Status
= EFI_DEVICE_ERROR
;
1355 UfsStopExecCmd (Private
, Slot
);
1356 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1363 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1365 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1366 @param[in] UicOpcode The opcode of the UIC command.
1367 @param[in] Arg1 The value for 1st argument of the UIC command.
1368 @param[in] Arg2 The value for 2nd argument of the UIC command.
1369 @param[in] Arg3 The value for 3rd argument of the UIC command.
1371 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1372 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1373 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1377 UfsExecUicCommands (
1378 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1390 UfsHcBase
= Private
->UfsHcBase
;
1391 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1392 Data
= MmioRead32 (Address
);
1393 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1395 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1397 MmioWrite32 (Address
, Data
);
1401 // When programming UIC command registers, host software shall set the register UICCMD
1402 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1405 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1406 MmioWrite32 (Address
, Arg1
);
1408 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1409 MmioWrite32 (Address
, Arg2
);
1411 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1412 MmioWrite32 (Address
, Arg3
);
1415 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1417 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1418 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1419 if (EFI_ERROR (Status
)) {
1423 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1424 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1427 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1428 // This bit is set to '1' by the host controller upon completion of a UIC command.
1430 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1431 Data
= MmioRead32 (Address
);
1432 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1433 if (EFI_ERROR (Status
)) {
1437 if (UicOpcode
!= UfsUicDmeReset
) {
1438 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1439 Data
= MmioRead32 (Address
);
1440 if ((Data
& 0xFF) != 0) {
1442 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1444 return EFI_DEVICE_ERROR
;
1449 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1451 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1452 Data
= MmioRead32 (Address
);
1453 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1454 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1455 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1456 if (EFI_ERROR (Status
)) {
1457 return EFI_DEVICE_ERROR
;
1459 return EFI_NOT_FOUND
;
1462 DEBUG ((EFI_D_INFO
, "UfsblockioPei: found a attached UFS device\n"));
1468 Enable the UFS host controller for accessing.
1470 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1472 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1473 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1477 UfsEnableHostController (
1478 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1486 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1488 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1490 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1491 Data
= MmioRead32 (Address
);
1492 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1494 // Write a 0 to the HCE register at first to disable the host controller.
1496 MmioWrite32 (Address
, 0);
1498 // Wait until HCE is read as '0' before continuing.
1500 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1501 if (EFI_ERROR (Status
)) {
1502 return EFI_DEVICE_ERROR
;
1507 // Write a 1 to the HCE register to enable the UFS host controller.
1509 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1511 // Wait until HCE is read as '1' before continuing.
1513 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1514 if (EFI_ERROR (Status
)) {
1515 return EFI_DEVICE_ERROR
;
1522 Detect if a UFS device attached.
1524 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1526 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1527 @retval EFI_NOT_FOUND Not found a UFS device attached.
1528 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1532 UfsDeviceDetection (
1533 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1540 // Start UFS device detection.
1541 // Try up to 3 times for establishing data link with device.
1543 for (Retry
= 0; Retry
< 3; Retry
++) {
1544 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1545 if (!EFI_ERROR (Status
)) {
1549 if (Status
== EFI_NOT_FOUND
) {
1553 return EFI_DEVICE_ERROR
;
1557 return EFI_NOT_FOUND
;
1564 Initialize UFS task management request list related h/w context.
1566 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1568 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1569 @retval EFI_DEVICE_ERROR The initialization fails.
1573 UfsInitTaskManagementRequestList (
1574 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1580 EFI_PHYSICAL_ADDRESS Buffer
;
1584 // Initial h/w and s/w context for future operations.
1586 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1587 Data
= MmioRead32 (Address
);
1588 Private
->Capabilities
= Data
;
1591 // Allocate and initialize UTP Task Management Request List.
1593 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1594 Status
= PeiServicesAllocatePages (
1595 EfiBootServicesCode
,
1596 EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
)),
1600 if (EFI_ERROR (Status
)) {
1601 return EFI_DEVICE_ERROR
;
1604 ZeroMem ((VOID
*)(UINTN
)Buffer
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
))));
1607 // Program the UTP Task Management Request List Base Address and UTP Task Management
1608 // Request List Base Address with a 64-bit address allocated at step 6.
1610 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1611 MmioWrite32 (Address
, (UINT32
)(UINTN
)Buffer
);
1612 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1613 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)Buffer
, 32));
1614 Private
->UtpTmrlBase
= (VOID
*)(UINTN
)Buffer
;
1615 Private
->Nutmrs
= Nutmrs
;
1618 // Enable the UTP Task Management Request List by setting the UTP Task Management
1619 // Request List RunStop Register (UTMRLRSR) to '1'.
1621 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1622 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1628 Initialize UFS transfer request list related h/w context.
1630 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1632 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1633 @retval EFI_DEVICE_ERROR The initialization fails.
1637 UfsInitTransferRequestList (
1638 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1644 EFI_PHYSICAL_ADDRESS Buffer
;
1648 // Initial h/w and s/w context for future operations.
1650 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1651 Data
= MmioRead32 (Address
);
1652 Private
->Capabilities
= Data
;
1655 // Allocate and initialize UTP Transfer Request List.
1657 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1658 Status
= PeiServicesAllocatePages (
1659 EfiBootServicesCode
,
1660 EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
)),
1664 if (EFI_ERROR (Status
)) {
1665 return EFI_DEVICE_ERROR
;
1668 ZeroMem ((VOID
*)(UINTN
)Buffer
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
))));
1671 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1672 // Base Address with a 64-bit address allocated at step 8.
1674 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1675 MmioWrite32 (Address
, (UINT32
)(UINTN
)Buffer
);
1676 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1677 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)Buffer
, 32));
1678 Private
->UtpTrlBase
= (VOID
*)(UINTN
)Buffer
;
1679 Private
->Nutrs
= Nutrs
;
1682 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1683 // RunStop Register (UTRLRSR) to '1'.
1685 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1686 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1692 Initialize the UFS host controller.
1694 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1696 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1697 @retval Others A device error occurred while initializing the controller.
1702 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1707 Status
= UfsEnableHostController (Private
);
1708 if (EFI_ERROR (Status
)) {
1709 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status
));
1713 Status
= UfsDeviceDetection (Private
);
1714 if (EFI_ERROR (Status
)) {
1715 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status
));
1719 Status
= UfsInitTaskManagementRequestList (Private
);
1720 if (EFI_ERROR (Status
)) {
1721 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status
));
1725 Status
= UfsInitTransferRequestList (Private
);
1726 if (EFI_ERROR (Status
)) {
1727 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status
));
1731 DEBUG ((EFI_D_INFO
, "UfsDevicePei Finished\n"));
1736 Stop the UFS host controller.
1738 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1740 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1741 @retval Others A device error occurred while stopping the controller.
1746 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1754 // Enable the UTP Task Management Request List by setting the UTP Task Management
1755 // Request List RunStop Register (UTMRLRSR) to '1'.
1757 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1758 MmioWrite32 (Address
, 0);
1761 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1762 // RunStop Register (UTRLRSR) to '1'.
1764 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1765 MmioWrite32 (Address
, 0);
1768 // Write a 0 to the HCE register in order to disable the host controller.
1770 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1771 Data
= MmioRead32 (Address
);
1772 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1773 MmioWrite32 (Address
, 0);
1776 // Wait until HCE is read as '0' before continuing.
1778 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1779 if (EFI_ERROR (Status
)) {
1780 return EFI_DEVICE_ERROR
;
1783 DEBUG ((EFI_D_INFO
, "UfsDevicePei: Stop the UFS Host Controller\n"));