3 Copyright (c) 2014 - 2016, 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
);
416 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
418 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
419 @param[in] Lun The Lun on which the SCSI command is executed.
420 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
421 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
423 @retval EFI_SUCCESS The creation succeed.
424 @retval EFI_DEVICE_ERROR The creation failed.
425 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
429 UfsCreateScsiCommandDesc (
430 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
432 IN UFS_SCSI_REQUEST_PACKET
*Packet
,
441 UTP_COMMAND_UPIU
*CommandUpiu
;
442 UTP_TR_PRD
*PrdtBase
;
443 UFS_DATA_DIRECTION DataDirection
;
445 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
447 if (Packet
->DataDirection
== UfsDataIn
) {
448 Buffer
= Packet
->InDataBuffer
;
449 Length
= Packet
->InTransferLength
;
450 DataDirection
= UfsDataIn
;
452 Buffer
= Packet
->OutDataBuffer
;
453 Length
= Packet
->OutTransferLength
;
454 DataDirection
= UfsDataOut
;
458 DataDirection
= UfsNoData
;
461 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)Length
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
463 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
464 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
465 if (CommandDesc
== NULL
) {
466 return EFI_OUT_OF_RESOURCES
;
469 CommandUpiu
= (UTP_COMMAND_UPIU
*)CommandDesc
;
470 PrdtBase
= (UTP_TR_PRD
*)(CommandDesc
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
472 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, Length
);
473 UfsInitUtpPrdt (PrdtBase
, Buffer
, Length
);
476 // Fill UTP_TRD associated fields
477 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
478 // *MUST* be located at a 64-bit aligned boundary.
480 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
481 Trd
->Dd
= DataDirection
;
482 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
483 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
484 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 7);
485 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 32);
486 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
487 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
488 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
489 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
494 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
496 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
497 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
498 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
500 @retval EFI_SUCCESS The creation succeed.
501 @retval EFI_DEVICE_ERROR The creation failed.
502 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
503 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
507 UfsCreateDMCommandDesc (
508 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
509 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
515 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
521 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
523 Opcode
= Packet
->Opcode
;
524 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
525 return EFI_INVALID_PARAMETER
;
528 DataDirection
= Packet
->DataDirection
;
529 if (DataDirection
== UfsDataIn
) {
530 DataSize
= Packet
->InTransferLength
;
531 Data
= Packet
->InDataBuffer
;
532 } else if (DataDirection
== UfsDataOut
) {
533 DataSize
= Packet
->OutTransferLength
;
534 Data
= Packet
->OutDataBuffer
;
540 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
541 && ((DataSize
== 0) || (Data
== NULL
))) {
542 return EFI_INVALID_PARAMETER
;
545 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
546 && ((DataSize
!= 0) || (Data
!= NULL
))) {
547 return EFI_INVALID_PARAMETER
;
550 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
551 return EFI_INVALID_PARAMETER
;
554 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
555 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
557 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
560 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
561 if (CommandDesc
== NULL
) {
562 return EFI_OUT_OF_RESOURCES
;
566 // Initialize UTP QUERY REQUEST UPIU
568 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)CommandDesc
;
569 UfsInitQueryRequestUpiu (
581 // Fill UTP_TRD associated fields
582 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
584 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
585 Trd
->Dd
= DataDirection
;
586 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
587 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
588 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 7);
589 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 32);
590 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
591 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
592 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
594 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
595 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
602 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
604 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
605 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
607 @retval EFI_SUCCESS The creation succeed.
608 @retval EFI_DEVICE_ERROR The creation failed.
609 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
613 UfsCreateNopCommandDesc (
614 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
620 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
622 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
624 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
625 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
626 if (CommandDesc
== NULL
) {
627 return EFI_OUT_OF_RESOURCES
;
630 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)CommandDesc
;
632 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
635 // Fill UTP_TRD associated fields
636 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
638 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
640 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
641 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
642 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 7);
643 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 32);
644 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
645 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
651 Find out available slot in transfer list of a UFS device.
653 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
654 @param[out] Slot The available slot.
656 @retval EFI_SUCCESS The available slot was found successfully.
660 UfsFindAvailableSlotInTrl (
661 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
665 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
668 // The simplest algo to always use slot 0.
669 // TODO: enhance it to support async transfer with multiple slot.
677 Find out available slot in task management transfer list of a UFS device.
679 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
680 @param[out] Slot The available slot.
682 @retval EFI_SUCCESS The available slot was found successfully.
686 UfsFindAvailableSlotInTmrl (
687 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
691 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
694 // The simplest algo to always use slot 0.
695 // TODO: enhance it to support async transfer with multiple slot.
703 Start specified slot in transfer list of a UFS device.
705 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
706 @param[in] Slot The slot to be started.
711 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
719 UfsHcBase
= Private
->UfsHcBase
;
721 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
722 Data
= MmioRead32 (Address
);
723 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
724 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
727 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
728 MmioWrite32 (Address
, BIT0
<< Slot
);
732 Stop specified slot in transfer list of a UFS device.
734 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
735 @param[in] Slot The slot to be stop.
740 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
748 UfsHcBase
= Private
->UfsHcBase
;
750 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
751 Data
= MmioRead32 (Address
);
752 if ((Data
& (BIT0
<< Slot
)) != 0) {
753 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
754 Data
= MmioRead32 (Address
);
755 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
760 Read or write specified device descriptor of a UFS device.
762 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
763 @param[in] Read The boolean variable to show r/w direction.
764 @param[in] DescId The ID of device descriptor.
765 @param[in] Index The Index of device descriptor.
766 @param[in] Selector The Selector of device descriptor.
767 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
768 @param[in] DescSize The size of device descriptor buffer.
770 @retval EFI_SUCCESS The device descriptor was read/written successfully.
771 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
772 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
777 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
782 IN OUT VOID
*Descriptor
,
787 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
791 UTP_QUERY_RESP_UPIU
*QueryResp
;
794 UINT16 ReturnDataSize
;
796 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
799 Packet
.DataDirection
= UfsDataIn
;
800 Packet
.InDataBuffer
= Descriptor
;
801 Packet
.InTransferLength
= DescSize
;
802 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
804 Packet
.DataDirection
= UfsDataOut
;
805 Packet
.OutDataBuffer
= Descriptor
;
806 Packet
.OutTransferLength
= DescSize
;
807 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
809 Packet
.DescId
= DescId
;
810 Packet
.Index
= Index
;
811 Packet
.Selector
= Selector
;
812 Packet
.Timeout
= UFS_TIMEOUT
;
815 // Find out which slot of transfer request list is available.
817 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
818 if (EFI_ERROR (Status
)) {
822 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
824 // Fill transfer request descriptor to this slot.
826 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
827 if (EFI_ERROR (Status
)) {
832 // Check the transfer request result.
834 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
835 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
836 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
839 // Start to execute the transfer request.
841 UfsStartExecCmd (Private
, Slot
);
844 // Wait for the completion of the transfer request.
846 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
847 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
848 if (EFI_ERROR (Status
)) {
852 if (QueryResp
->QueryResp
!= 0) {
853 DumpQueryResponseResult (QueryResp
->QueryResp
);
854 Status
= EFI_DEVICE_ERROR
;
859 ReturnDataSize
= QueryResp
->Tsf
.Length
;
860 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
863 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
864 Packet
.InTransferLength
= ReturnDataSize
;
866 Packet
.OutTransferLength
= ReturnDataSize
;
869 Status
= EFI_DEVICE_ERROR
;
873 UfsStopExecCmd (Private
, Slot
);
874 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
880 Read or write specified attribute of a UFS device.
882 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
883 @param[in] Read The boolean variable to show r/w direction.
884 @param[in] AttrId The ID of Attribute.
885 @param[in] Index The Index of Attribute.
886 @param[in] Selector The Selector of Attribute.
887 @param[in, out] Attributes The value of Attribute to be read or written.
889 @retval EFI_SUCCESS The Attribute was read/written successfully.
890 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
891 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
896 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
901 IN OUT UINT32
*Attributes
905 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
909 UTP_QUERY_RESP_UPIU
*QueryResp
;
914 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
917 Packet
.DataDirection
= UfsDataIn
;
918 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
920 Packet
.DataDirection
= UfsDataOut
;
921 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
923 Packet
.DescId
= AttrId
;
924 Packet
.Index
= Index
;
925 Packet
.Selector
= Selector
;
926 Packet
.Timeout
= UFS_TIMEOUT
;
929 // Find out which slot of transfer request list is available.
931 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
932 if (EFI_ERROR (Status
)) {
936 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
938 // Fill transfer request descriptor to this slot.
940 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
941 if (EFI_ERROR (Status
)) {
946 // Check the transfer request result.
948 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
949 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
950 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
953 // Start to execute the transfer request.
955 UfsStartExecCmd (Private
, Slot
);
958 // Wait for the completion of the transfer request.
960 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
961 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
962 if (EFI_ERROR (Status
)) {
966 if (QueryResp
->QueryResp
!= 0) {
967 DumpQueryResponseResult (QueryResp
->QueryResp
);
968 Status
= EFI_DEVICE_ERROR
;
973 ReturnData
= QueryResp
->Tsf
.Value
;
974 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
975 *Attributes
= ReturnData
;
977 Status
= EFI_DEVICE_ERROR
;
981 UfsStopExecCmd (Private
, Slot
);
982 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
988 Read or write specified flag of a UFS device.
990 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
991 @param[in] Read The boolean variable to show r/w direction.
992 @param[in] FlagId The ID of flag to be read or written.
993 @param[in, out] Value The value to set or clear flag.
995 @retval EFI_SUCCESS The flag was read/written successfully.
996 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
997 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1002 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1009 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1013 UTP_QUERY_RESP_UPIU
*QueryResp
;
1017 if (Value
== NULL
) {
1018 return EFI_INVALID_PARAMETER
;
1021 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1024 ASSERT (Value
!= NULL
);
1025 Packet
.DataDirection
= UfsDataIn
;
1026 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1028 Packet
.DataDirection
= UfsDataOut
;
1030 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1031 } else if (*Value
== 0) {
1032 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1034 return EFI_INVALID_PARAMETER
;
1037 Packet
.DescId
= FlagId
;
1039 Packet
.Selector
= 0;
1040 Packet
.Timeout
= UFS_TIMEOUT
;
1043 // Find out which slot of transfer request list is available.
1045 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1046 if (EFI_ERROR (Status
)) {
1051 // Fill transfer request descriptor to this slot.
1053 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1054 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
1055 if (EFI_ERROR (Status
)) {
1060 // Check the transfer request result.
1062 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1063 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1064 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1067 // Start to execute the transfer request.
1069 UfsStartExecCmd (Private
, Slot
);
1072 // Wait for the completion of the transfer request.
1074 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1075 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
1076 if (EFI_ERROR (Status
)) {
1080 if (QueryResp
->QueryResp
!= 0) {
1081 DumpQueryResponseResult (QueryResp
->QueryResp
);
1082 Status
= EFI_DEVICE_ERROR
;
1086 if (Trd
->Ocs
== 0) {
1087 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
1089 Status
= EFI_DEVICE_ERROR
;
1093 UfsStopExecCmd (Private
, Slot
);
1094 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1100 Set specified flag to 1 on a UFS device.
1102 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1103 @param[in] FlagId The ID of flag to be set.
1105 @retval EFI_SUCCESS The flag was set successfully.
1106 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1107 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1112 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1120 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1126 Clear specified flag to 0 on a UFS device.
1128 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1129 @param[in] FlagId The ID of flag to be cleared.
1131 @retval EFI_SUCCESS The flag was cleared successfully.
1132 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1133 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1138 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1146 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1152 Read specified flag from a UFS device.
1154 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1155 @param[in] FlagId The ID of flag to be read.
1156 @param[out] Value The flag's value.
1158 @retval EFI_SUCCESS The flag was read successfully.
1159 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1160 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1165 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1172 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1178 Sends NOP IN cmd to a UFS device for initialization process request.
1179 For more details, please refer to UFS 2.0 spec Figure 13.3.
1181 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1183 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1184 received successfully.
1185 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1186 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1187 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1192 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1198 UTP_NOP_IN_UPIU
*NopInUpiu
;
1204 // Find out which slot of transfer request list is available.
1206 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1207 if (EFI_ERROR (Status
)) {
1211 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1212 Status
= UfsCreateNopCommandDesc (Private
, Trd
);
1213 if (EFI_ERROR (Status
)) {
1218 // Check the transfer request result.
1220 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1221 NopInUpiu
= (UTP_NOP_IN_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1222 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1225 // Start to execute the transfer request.
1227 UfsStartExecCmd (Private
, Slot
);
1230 // Wait for the completion of the transfer request.
1232 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1233 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1234 if (EFI_ERROR (Status
)) {
1238 if (NopInUpiu
->Resp
!= 0) {
1239 Status
= EFI_DEVICE_ERROR
;
1241 Status
= EFI_SUCCESS
;
1245 UfsStopExecCmd (Private
, Slot
);
1246 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1252 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1254 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1255 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1256 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1259 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1260 commands, InTransferLength bytes were transferred from
1261 InDataBuffer. For write and bi-directional commands,
1262 OutTransferLength bytes were transferred by
1264 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1266 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1267 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1272 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1274 IN OUT UFS_SCSI_REQUEST_PACKET
*Packet
1283 UTP_RESPONSE_UPIU
*Response
;
1284 UINT16 SenseDataLen
;
1285 UINT32 ResTranCount
;
1288 // Find out which slot of transfer request list is available.
1290 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1291 if (EFI_ERROR (Status
)) {
1295 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1298 // Fill transfer request descriptor to this slot.
1300 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
);
1301 if (EFI_ERROR (Status
)) {
1305 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1306 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1309 // Start to execute the transfer request.
1311 UfsStartExecCmd (Private
, Slot
);
1314 // Wait for the completion of the transfer request.
1316 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1317 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
->Timeout
);
1318 if (EFI_ERROR (Status
)) {
1323 // Get sense data if exists
1325 Response
= (UTP_RESPONSE_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1326 SenseDataLen
= Response
->SenseDataLen
;
1327 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1329 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1330 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1331 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1335 // Check the transfer request result.
1337 if (Response
->Response
!= 0) {
1338 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1339 Status
= EFI_DEVICE_ERROR
;
1343 if (Trd
->Ocs
== 0) {
1344 if (Packet
->DataDirection
== UfsDataIn
) {
1345 if ((Response
->Flags
& BIT5
) == BIT5
) {
1346 ResTranCount
= Response
->ResTranCount
;
1347 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1348 Packet
->InTransferLength
-= ResTranCount
;
1350 } else if (Packet
->DataDirection
== UfsDataOut
) {
1351 if ((Response
->Flags
& BIT5
) == BIT5
) {
1352 ResTranCount
= Response
->ResTranCount
;
1353 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1354 Packet
->OutTransferLength
-= ResTranCount
;
1358 Status
= EFI_DEVICE_ERROR
;
1362 UfsStopExecCmd (Private
, Slot
);
1363 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1370 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1372 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1373 @param[in] UicOpcode The opcode of the UIC command.
1374 @param[in] Arg1 The value for 1st argument of the UIC command.
1375 @param[in] Arg2 The value for 2nd argument of the UIC command.
1376 @param[in] Arg3 The value for 3rd argument of the UIC command.
1378 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1379 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1380 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1384 UfsExecUicCommands (
1385 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1397 UfsHcBase
= Private
->UfsHcBase
;
1398 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1399 Data
= MmioRead32 (Address
);
1400 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1402 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1404 MmioWrite32 (Address
, Data
);
1408 // When programming UIC command registers, host software shall set the register UICCMD
1409 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1412 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1413 MmioWrite32 (Address
, Arg1
);
1415 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1416 MmioWrite32 (Address
, Arg2
);
1418 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1419 MmioWrite32 (Address
, Arg3
);
1422 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1424 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1425 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1426 if (EFI_ERROR (Status
)) {
1430 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1431 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1434 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1435 // This bit is set to '1' by the host controller upon completion of a UIC command.
1437 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1438 Data
= MmioRead32 (Address
);
1439 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1440 if (EFI_ERROR (Status
)) {
1444 if (UicOpcode
!= UfsUicDmeReset
) {
1445 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1446 Data
= MmioRead32 (Address
);
1447 if ((Data
& 0xFF) != 0) {
1449 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1451 return EFI_DEVICE_ERROR
;
1456 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1458 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1459 Data
= MmioRead32 (Address
);
1460 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1461 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1462 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1463 if (EFI_ERROR (Status
)) {
1464 return EFI_DEVICE_ERROR
;
1466 return EFI_NOT_FOUND
;
1469 DEBUG ((EFI_D_INFO
, "UfsblockioPei: found a attached UFS device\n"));
1475 Enable the UFS host controller for accessing.
1477 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1479 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1480 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1484 UfsEnableHostController (
1485 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1493 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1495 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1497 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1498 Data
= MmioRead32 (Address
);
1499 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1501 // Write a 0 to the HCE register at first to disable the host controller.
1503 MmioWrite32 (Address
, 0);
1505 // Wait until HCE is read as '0' before continuing.
1507 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1508 if (EFI_ERROR (Status
)) {
1509 return EFI_DEVICE_ERROR
;
1514 // Write a 1 to the HCE register to enable the UFS host controller.
1516 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1518 // Wait until HCE is read as '1' before continuing.
1520 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1521 if (EFI_ERROR (Status
)) {
1522 return EFI_DEVICE_ERROR
;
1529 Detect if a UFS device attached.
1531 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1533 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1534 @retval EFI_NOT_FOUND Not found a UFS device attached.
1535 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1539 UfsDeviceDetection (
1540 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1547 // Start UFS device detection.
1548 // Try up to 3 times for establishing data link with device.
1550 for (Retry
= 0; Retry
< 3; Retry
++) {
1551 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1552 if (!EFI_ERROR (Status
)) {
1556 if (Status
== EFI_NOT_FOUND
) {
1560 return EFI_DEVICE_ERROR
;
1564 return EFI_NOT_FOUND
;
1571 Initialize UFS task management request list related h/w context.
1573 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1575 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1576 @retval EFI_DEVICE_ERROR The initialization fails.
1580 UfsInitTaskManagementRequestList (
1581 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1587 EFI_PHYSICAL_ADDRESS Buffer
;
1591 // Initial h/w and s/w context for future operations.
1593 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1594 Data
= MmioRead32 (Address
);
1595 Private
->Capabilities
= Data
;
1598 // Allocate and initialize UTP Task Management Request List.
1600 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1601 Status
= PeiServicesAllocatePages (
1602 EfiBootServicesCode
,
1603 EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
)),
1607 if (EFI_ERROR (Status
)) {
1608 return EFI_DEVICE_ERROR
;
1611 ZeroMem ((VOID
*)(UINTN
)Buffer
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
))));
1614 // Program the UTP Task Management Request List Base Address and UTP Task Management
1615 // Request List Base Address with a 64-bit address allocated at step 6.
1617 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1618 MmioWrite32 (Address
, (UINT32
)(UINTN
)Buffer
);
1619 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1620 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)Buffer
, 32));
1621 Private
->UtpTmrlBase
= (VOID
*)(UINTN
)Buffer
;
1622 Private
->Nutmrs
= Nutmrs
;
1625 // Enable the UTP Task Management Request List by setting the UTP Task Management
1626 // Request List RunStop Register (UTMRLRSR) to '1'.
1628 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1629 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1635 Initialize UFS transfer request list related h/w context.
1637 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1639 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1640 @retval EFI_DEVICE_ERROR The initialization fails.
1644 UfsInitTransferRequestList (
1645 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1651 EFI_PHYSICAL_ADDRESS Buffer
;
1655 // Initial h/w and s/w context for future operations.
1657 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1658 Data
= MmioRead32 (Address
);
1659 Private
->Capabilities
= Data
;
1662 // Allocate and initialize UTP Transfer Request List.
1664 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1665 Status
= PeiServicesAllocatePages (
1666 EfiBootServicesCode
,
1667 EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
)),
1671 if (EFI_ERROR (Status
)) {
1672 return EFI_DEVICE_ERROR
;
1675 ZeroMem ((VOID
*)(UINTN
)Buffer
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
))));
1678 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1679 // Base Address with a 64-bit address allocated at step 8.
1681 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1682 MmioWrite32 (Address
, (UINT32
)(UINTN
)Buffer
);
1683 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1684 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)Buffer
, 32));
1685 Private
->UtpTrlBase
= (VOID
*)(UINTN
)Buffer
;
1686 Private
->Nutrs
= Nutrs
;
1689 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1690 // RunStop Register (UTRLRSR) to '1'.
1692 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1693 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1699 Initialize the UFS host controller.
1701 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1703 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1704 @retval Others A device error occurred while initializing the controller.
1709 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1714 Status
= UfsEnableHostController (Private
);
1715 if (EFI_ERROR (Status
)) {
1716 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status
));
1720 Status
= UfsDeviceDetection (Private
);
1721 if (EFI_ERROR (Status
)) {
1722 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status
));
1726 Status
= UfsInitTaskManagementRequestList (Private
);
1727 if (EFI_ERROR (Status
)) {
1728 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status
));
1732 Status
= UfsInitTransferRequestList (Private
);
1733 if (EFI_ERROR (Status
)) {
1734 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status
));
1738 DEBUG ((EFI_D_INFO
, "UfsDevicePei Finished\n"));
1743 Stop the UFS host controller.
1745 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1747 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1748 @retval Others A device error occurred while stopping the controller.
1753 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1761 // Enable the UTP Task Management Request List by setting the UTP Task Management
1762 // Request List RunStop Register (UTMRLRSR) to '1'.
1764 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1765 MmioWrite32 (Address
, 0);
1768 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1769 // RunStop Register (UTRLRSR) to '1'.
1771 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1772 MmioWrite32 (Address
, 0);
1775 // Write a 0 to the HCE register in order to disable the host controller.
1777 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1778 Data
= MmioRead32 (Address
);
1779 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1780 MmioWrite32 (Address
, 0);
1783 // Wait until HCE is read as '0' before continuing.
1785 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1786 if (EFI_ERROR (Status
)) {
1787 return EFI_DEVICE_ERROR
;
1790 DEBUG ((EFI_D_INFO
, "UfsDevicePei: Stop the UFS Host Controller\n"));