3 Copyright (c) 2014 - 2018, 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.
425 @param[out] BufferMap A resulting value, if not NULL, to pass to IoMmuUnmap().
427 @retval EFI_SUCCESS The creation succeed.
428 @retval EFI_DEVICE_ERROR The creation failed.
429 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
433 UfsCreateScsiCommandDesc (
434 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
436 IN UFS_SCSI_REQUEST_PACKET
*Packet
,
446 UTP_COMMAND_UPIU
*CommandUpiu
;
447 UTP_TR_PRD
*PrdtBase
;
448 UFS_DATA_DIRECTION DataDirection
;
450 EDKII_IOMMU_OPERATION MapOp
;
452 EFI_PHYSICAL_ADDRESS BufferPhyAddr
;
454 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
458 if (Packet
->DataDirection
== UfsDataIn
) {
459 Buffer
= Packet
->InDataBuffer
;
460 Length
= Packet
->InTransferLength
;
461 DataDirection
= UfsDataIn
;
462 MapOp
= EdkiiIoMmuOperationBusMasterWrite
;
464 Buffer
= Packet
->OutDataBuffer
;
465 Length
= Packet
->OutTransferLength
;
466 DataDirection
= UfsDataOut
;
467 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
471 DataDirection
= UfsNoData
;
474 Status
= IoMmuMap (MapOp
, Buffer
, &MapLength
, &BufferPhyAddr
, BufferMap
);
476 if (EFI_ERROR (Status
) || (MapLength
!= Length
)) {
477 DEBUG ((DEBUG_ERROR
, "UfsCreateScsiCommandDesc: Fail to map data buffer.\n"));
478 return EFI_OUT_OF_RESOURCES
;
482 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)Length
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
484 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
485 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
486 if (CommandDesc
== NULL
) {
487 return EFI_OUT_OF_RESOURCES
;
490 CommandUpiu
= (UTP_COMMAND_UPIU
*)CommandDesc
;
491 PrdtBase
= (UTP_TR_PRD
*)(CommandDesc
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
493 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, Length
);
494 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)BufferPhyAddr
, Length
);
497 // Fill UTP_TRD associated fields
498 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
499 // *MUST* be located at a 64-bit aligned boundary.
501 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
502 Trd
->Dd
= DataDirection
;
503 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
504 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
505 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 7);
506 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)CommandUpiu
, 32);
507 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
508 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
509 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
510 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
515 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
517 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
518 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
519 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
521 @retval EFI_SUCCESS The creation succeed.
522 @retval EFI_DEVICE_ERROR The creation failed.
523 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
524 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
528 UfsCreateDMCommandDesc (
529 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
530 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
536 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
542 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
544 Opcode
= Packet
->Opcode
;
545 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
546 return EFI_INVALID_PARAMETER
;
549 DataDirection
= Packet
->DataDirection
;
550 if (DataDirection
== UfsDataIn
) {
551 DataSize
= Packet
->InTransferLength
;
552 Data
= Packet
->InDataBuffer
;
553 } else if (DataDirection
== UfsDataOut
) {
554 DataSize
= Packet
->OutTransferLength
;
555 Data
= Packet
->OutDataBuffer
;
561 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
562 && ((DataSize
== 0) || (Data
== NULL
))) {
563 return EFI_INVALID_PARAMETER
;
566 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
567 && ((DataSize
!= 0) || (Data
!= NULL
))) {
568 return EFI_INVALID_PARAMETER
;
571 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
572 return EFI_INVALID_PARAMETER
;
575 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
576 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
578 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
581 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
582 if (CommandDesc
== NULL
) {
583 return EFI_OUT_OF_RESOURCES
;
587 // Initialize UTP QUERY REQUEST UPIU
589 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)CommandDesc
;
590 UfsInitQueryRequestUpiu (
602 // Fill UTP_TRD associated fields
603 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
605 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
606 Trd
->Dd
= DataDirection
;
607 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
608 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
609 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 7);
610 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)QueryReqUpiu
, 32);
611 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
612 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
613 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
615 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
616 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
623 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
625 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
626 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
628 @retval EFI_SUCCESS The creation succeed.
629 @retval EFI_DEVICE_ERROR The creation failed.
630 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
634 UfsCreateNopCommandDesc (
635 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
641 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
643 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
645 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
646 CommandDesc
= UfsPeimAllocateMem (Private
->Pool
, TotalLen
);
647 if (CommandDesc
== NULL
) {
648 return EFI_OUT_OF_RESOURCES
;
651 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)CommandDesc
;
653 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
656 // Fill UTP_TRD associated fields
657 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
659 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
661 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
662 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
663 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 7);
664 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)NopOutUpiu
, 32);
665 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
666 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
672 Find out available slot in transfer list of a UFS device.
674 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
675 @param[out] Slot The available slot.
677 @retval EFI_SUCCESS The available slot was found successfully.
681 UfsFindAvailableSlotInTrl (
682 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
686 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
689 // The simplest algo to always use slot 0.
690 // TODO: enhance it to support async transfer with multiple slot.
698 Find out available slot in task management transfer list of a UFS device.
700 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
701 @param[out] Slot The available slot.
703 @retval EFI_SUCCESS The available slot was found successfully.
707 UfsFindAvailableSlotInTmrl (
708 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
712 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
715 // The simplest algo to always use slot 0.
716 // TODO: enhance it to support async transfer with multiple slot.
724 Start specified slot in transfer list of a UFS device.
726 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
727 @param[in] Slot The slot to be started.
732 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
740 UfsHcBase
= Private
->UfsHcBase
;
742 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
743 Data
= MmioRead32 (Address
);
744 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
745 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
748 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
749 MmioWrite32 (Address
, BIT0
<< Slot
);
753 Stop specified slot in transfer list of a UFS device.
755 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
756 @param[in] Slot The slot to be stop.
761 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
769 UfsHcBase
= Private
->UfsHcBase
;
771 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
772 Data
= MmioRead32 (Address
);
773 if ((Data
& (BIT0
<< Slot
)) != 0) {
774 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
775 Data
= MmioRead32 (Address
);
776 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
781 Read or write specified device descriptor of a UFS device.
783 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
784 @param[in] Read The boolean variable to show r/w direction.
785 @param[in] DescId The ID of device descriptor.
786 @param[in] Index The Index of device descriptor.
787 @param[in] Selector The Selector of device descriptor.
788 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
789 @param[in] DescSize The size of device descriptor buffer.
791 @retval EFI_SUCCESS The device descriptor was read/written successfully.
792 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
793 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
798 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
803 IN OUT VOID
*Descriptor
,
808 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
812 UTP_QUERY_RESP_UPIU
*QueryResp
;
815 UINT16 ReturnDataSize
;
817 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
820 Packet
.DataDirection
= UfsDataIn
;
821 Packet
.InDataBuffer
= Descriptor
;
822 Packet
.InTransferLength
= DescSize
;
823 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
825 Packet
.DataDirection
= UfsDataOut
;
826 Packet
.OutDataBuffer
= Descriptor
;
827 Packet
.OutTransferLength
= DescSize
;
828 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
830 Packet
.DescId
= DescId
;
831 Packet
.Index
= Index
;
832 Packet
.Selector
= Selector
;
833 Packet
.Timeout
= UFS_TIMEOUT
;
836 // Find out which slot of transfer request list is available.
838 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
839 if (EFI_ERROR (Status
)) {
843 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
845 // Fill transfer request descriptor to this slot.
847 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
848 if (EFI_ERROR (Status
)) {
853 // Check the transfer request result.
855 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
856 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
857 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
860 // Start to execute the transfer request.
862 UfsStartExecCmd (Private
, Slot
);
865 // Wait for the completion of the transfer request.
867 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
868 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
869 if (EFI_ERROR (Status
)) {
873 if (QueryResp
->QueryResp
!= 0) {
874 DumpQueryResponseResult (QueryResp
->QueryResp
);
875 Status
= EFI_DEVICE_ERROR
;
880 ReturnDataSize
= QueryResp
->Tsf
.Length
;
881 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
884 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
885 Packet
.InTransferLength
= ReturnDataSize
;
887 Packet
.OutTransferLength
= ReturnDataSize
;
890 Status
= EFI_DEVICE_ERROR
;
894 UfsStopExecCmd (Private
, Slot
);
895 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
901 Read or write specified attribute of a UFS device.
903 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
904 @param[in] Read The boolean variable to show r/w direction.
905 @param[in] AttrId The ID of Attribute.
906 @param[in] Index The Index of Attribute.
907 @param[in] Selector The Selector of Attribute.
908 @param[in, out] Attributes The value of Attribute to be read or written.
910 @retval EFI_SUCCESS The Attribute was read/written successfully.
911 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
912 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
917 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
922 IN OUT UINT32
*Attributes
926 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
930 UTP_QUERY_RESP_UPIU
*QueryResp
;
935 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
938 Packet
.DataDirection
= UfsDataIn
;
939 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
941 Packet
.DataDirection
= UfsDataOut
;
942 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
944 Packet
.DescId
= AttrId
;
945 Packet
.Index
= Index
;
946 Packet
.Selector
= Selector
;
947 Packet
.Timeout
= UFS_TIMEOUT
;
950 // Find out which slot of transfer request list is available.
952 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
953 if (EFI_ERROR (Status
)) {
957 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
959 // Fill transfer request descriptor to this slot.
961 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
962 if (EFI_ERROR (Status
)) {
967 // Check the transfer request result.
969 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
970 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
971 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
974 // Start to execute the transfer request.
976 UfsStartExecCmd (Private
, Slot
);
979 // Wait for the completion of the transfer request.
981 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
982 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
983 if (EFI_ERROR (Status
)) {
987 if (QueryResp
->QueryResp
!= 0) {
988 DumpQueryResponseResult (QueryResp
->QueryResp
);
989 Status
= EFI_DEVICE_ERROR
;
994 ReturnData
= QueryResp
->Tsf
.Value
;
995 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
996 *Attributes
= ReturnData
;
998 Status
= EFI_DEVICE_ERROR
;
1002 UfsStopExecCmd (Private
, Slot
);
1003 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1009 Read or write specified flag of a UFS device.
1011 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1012 @param[in] Read The boolean variable to show r/w direction.
1013 @param[in] FlagId The ID of flag to be read or written.
1014 @param[in, out] Value The value to set or clear flag.
1016 @retval EFI_SUCCESS The flag was read/written successfully.
1017 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1018 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1023 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1030 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1034 UTP_QUERY_RESP_UPIU
*QueryResp
;
1038 if (Value
== NULL
) {
1039 return EFI_INVALID_PARAMETER
;
1042 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1045 ASSERT (Value
!= NULL
);
1046 Packet
.DataDirection
= UfsDataIn
;
1047 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1049 Packet
.DataDirection
= UfsDataOut
;
1051 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1052 } else if (*Value
== 0) {
1053 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1055 return EFI_INVALID_PARAMETER
;
1058 Packet
.DescId
= FlagId
;
1060 Packet
.Selector
= 0;
1061 Packet
.Timeout
= UFS_TIMEOUT
;
1064 // Find out which slot of transfer request list is available.
1066 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1067 if (EFI_ERROR (Status
)) {
1072 // Fill transfer request descriptor to this slot.
1074 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1075 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
1076 if (EFI_ERROR (Status
)) {
1081 // Check the transfer request result.
1083 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1084 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1085 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1088 // Start to execute the transfer request.
1090 UfsStartExecCmd (Private
, Slot
);
1093 // Wait for the completion of the transfer request.
1095 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1096 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
1097 if (EFI_ERROR (Status
)) {
1101 if (QueryResp
->QueryResp
!= 0) {
1102 DumpQueryResponseResult (QueryResp
->QueryResp
);
1103 Status
= EFI_DEVICE_ERROR
;
1107 if (Trd
->Ocs
== 0) {
1108 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
1110 Status
= EFI_DEVICE_ERROR
;
1114 UfsStopExecCmd (Private
, Slot
);
1115 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1121 Set specified flag to 1 on a UFS device.
1123 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1124 @param[in] FlagId The ID of flag to be set.
1126 @retval EFI_SUCCESS The flag was set successfully.
1127 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1128 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1133 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1141 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1147 Clear specified flag to 0 on a UFS device.
1149 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1150 @param[in] FlagId The ID of flag to be cleared.
1152 @retval EFI_SUCCESS The flag was cleared successfully.
1153 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1154 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1159 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1167 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1173 Read specified flag from a UFS device.
1175 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1176 @param[in] FlagId The ID of flag to be read.
1177 @param[out] Value The flag's value.
1179 @retval EFI_SUCCESS The flag was read successfully.
1180 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1181 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1186 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1193 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1199 Sends NOP IN cmd to a UFS device for initialization process request.
1200 For more details, please refer to UFS 2.0 spec Figure 13.3.
1202 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1204 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1205 received successfully.
1206 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1207 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1208 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1213 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1219 UTP_NOP_IN_UPIU
*NopInUpiu
;
1225 // Find out which slot of transfer request list is available.
1227 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1228 if (EFI_ERROR (Status
)) {
1232 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1233 Status
= UfsCreateNopCommandDesc (Private
, Trd
);
1234 if (EFI_ERROR (Status
)) {
1239 // Check the transfer request result.
1241 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1242 NopInUpiu
= (UTP_NOP_IN_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1243 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1246 // Start to execute the transfer request.
1248 UfsStartExecCmd (Private
, Slot
);
1251 // Wait for the completion of the transfer request.
1253 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1254 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1255 if (EFI_ERROR (Status
)) {
1259 if (NopInUpiu
->Resp
!= 0) {
1260 Status
= EFI_DEVICE_ERROR
;
1262 Status
= EFI_SUCCESS
;
1266 UfsStopExecCmd (Private
, Slot
);
1267 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1273 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1275 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1276 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1277 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1280 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1281 commands, InTransferLength bytes were transferred from
1282 InDataBuffer. For write and bi-directional commands,
1283 OutTransferLength bytes were transferred by
1285 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1287 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1288 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1293 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1295 IN OUT UFS_SCSI_REQUEST_PACKET
*Packet
1304 UTP_RESPONSE_UPIU
*Response
;
1305 UINT16 SenseDataLen
;
1306 UINT32 ResTranCount
;
1307 VOID
*PacketBufferMap
;
1310 // Find out which slot of transfer request list is available.
1312 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1313 if (EFI_ERROR (Status
)) {
1317 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1318 PacketBufferMap
= NULL
;
1321 // Fill transfer request descriptor to this slot.
1323 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
, &PacketBufferMap
);
1324 if (EFI_ERROR (Status
)) {
1328 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1329 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1332 // Start to execute the transfer request.
1334 UfsStartExecCmd (Private
, Slot
);
1337 // Wait for the completion of the transfer request.
1339 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1340 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
->Timeout
);
1341 if (EFI_ERROR (Status
)) {
1346 // Get sense data if exists
1348 Response
= (UTP_RESPONSE_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1349 SenseDataLen
= Response
->SenseDataLen
;
1350 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1352 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1353 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1354 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1358 // Check the transfer request result.
1360 if (Response
->Response
!= 0) {
1361 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1362 Status
= EFI_DEVICE_ERROR
;
1366 if (Trd
->Ocs
== 0) {
1367 if (Packet
->DataDirection
== UfsDataIn
) {
1368 if ((Response
->Flags
& BIT5
) == BIT5
) {
1369 ResTranCount
= Response
->ResTranCount
;
1370 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1371 Packet
->InTransferLength
-= ResTranCount
;
1373 } else if (Packet
->DataDirection
== UfsDataOut
) {
1374 if ((Response
->Flags
& BIT5
) == BIT5
) {
1375 ResTranCount
= Response
->ResTranCount
;
1376 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1377 Packet
->OutTransferLength
-= ResTranCount
;
1381 Status
= EFI_DEVICE_ERROR
;
1385 if (PacketBufferMap
!= NULL
) {
1386 IoMmuUnmap (PacketBufferMap
);
1388 UfsStopExecCmd (Private
, Slot
);
1389 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1396 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1398 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1399 @param[in] UicOpcode The opcode of the UIC command.
1400 @param[in] Arg1 The value for 1st argument of the UIC command.
1401 @param[in] Arg2 The value for 2nd argument of the UIC command.
1402 @param[in] Arg3 The value for 3rd argument of the UIC command.
1404 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1405 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1406 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1410 UfsExecUicCommands (
1411 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1423 UfsHcBase
= Private
->UfsHcBase
;
1424 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1425 Data
= MmioRead32 (Address
);
1426 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1428 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1430 MmioWrite32 (Address
, Data
);
1434 // When programming UIC command registers, host software shall set the register UICCMD
1435 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1438 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1439 MmioWrite32 (Address
, Arg1
);
1441 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1442 MmioWrite32 (Address
, Arg2
);
1444 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1445 MmioWrite32 (Address
, Arg3
);
1448 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1450 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1451 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1452 if (EFI_ERROR (Status
)) {
1456 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1457 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1460 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1461 // This bit is set to '1' by the host controller upon completion of a UIC command.
1463 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1464 Data
= MmioRead32 (Address
);
1465 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1466 if (EFI_ERROR (Status
)) {
1470 if (UicOpcode
!= UfsUicDmeReset
) {
1471 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1472 Data
= MmioRead32 (Address
);
1473 if ((Data
& 0xFF) != 0) {
1475 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1477 return EFI_DEVICE_ERROR
;
1482 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1484 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1485 Data
= MmioRead32 (Address
);
1486 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1487 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1488 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1489 if (EFI_ERROR (Status
)) {
1490 return EFI_DEVICE_ERROR
;
1492 return EFI_NOT_FOUND
;
1495 DEBUG ((EFI_D_INFO
, "UfsblockioPei: found a attached UFS device\n"));
1501 Enable the UFS host controller for accessing.
1503 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1505 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1506 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1510 UfsEnableHostController (
1511 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1519 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1521 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1523 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1524 Data
= MmioRead32 (Address
);
1525 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1527 // Write a 0 to the HCE register at first to disable the host controller.
1529 MmioWrite32 (Address
, 0);
1531 // Wait until HCE is read as '0' before continuing.
1533 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1534 if (EFI_ERROR (Status
)) {
1535 return EFI_DEVICE_ERROR
;
1540 // Write a 1 to the HCE register to enable the UFS host controller.
1542 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1544 // Wait until HCE is read as '1' before continuing.
1546 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1547 if (EFI_ERROR (Status
)) {
1548 return EFI_DEVICE_ERROR
;
1555 Detect if a UFS device attached.
1557 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1559 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1560 @retval EFI_NOT_FOUND Not found a UFS device attached.
1561 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1565 UfsDeviceDetection (
1566 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1573 // Start UFS device detection.
1574 // Try up to 3 times for establishing data link with device.
1576 for (Retry
= 0; Retry
< 3; Retry
++) {
1577 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1578 if (!EFI_ERROR (Status
)) {
1582 if (Status
== EFI_NOT_FOUND
) {
1586 return EFI_DEVICE_ERROR
;
1590 return EFI_NOT_FOUND
;
1597 Initialize UFS task management request list related h/w context.
1599 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1601 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1602 @retval EFI_DEVICE_ERROR The initialization fails.
1606 UfsInitTaskManagementRequestList (
1607 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1614 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1615 VOID
*CmdDescMapping
;
1619 // Initial h/w and s/w context for future operations.
1621 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1622 Data
= MmioRead32 (Address
);
1623 Private
->Capabilities
= Data
;
1626 // Allocate and initialize UTP Task Management Request List.
1628 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1629 Status
= IoMmuAllocateBuffer (
1630 EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
)),
1635 if (EFI_ERROR (Status
)) {
1636 return EFI_DEVICE_ERROR
;
1639 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
))));
1642 // Program the UTP Task Management Request List Base Address and UTP Task Management
1643 // Request List Base Address with a 64-bit address allocated at step 6.
1645 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1646 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1647 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1648 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1649 Private
->UtpTmrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1650 Private
->Nutmrs
= Nutmrs
;
1651 Private
->TmrlMapping
= CmdDescMapping
;
1654 // Enable the UTP Task Management Request List by setting the UTP Task Management
1655 // Request List RunStop Register (UTMRLRSR) to '1'.
1657 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1658 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1664 Initialize UFS transfer request list related h/w context.
1666 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1668 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1669 @retval EFI_DEVICE_ERROR The initialization fails.
1673 UfsInitTransferRequestList (
1674 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1681 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1682 VOID
*CmdDescMapping
;
1686 // Initial h/w and s/w context for future operations.
1688 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1689 Data
= MmioRead32 (Address
);
1690 Private
->Capabilities
= Data
;
1693 // Allocate and initialize UTP Transfer Request List.
1695 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1696 Status
= IoMmuAllocateBuffer (
1697 EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
)),
1702 if (EFI_ERROR (Status
)) {
1703 return EFI_DEVICE_ERROR
;
1706 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
))));
1709 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1710 // Base Address with a 64-bit address allocated at step 8.
1712 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1713 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1714 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1715 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1716 Private
->UtpTrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1717 Private
->Nutrs
= Nutrs
;
1718 Private
->TrlMapping
= CmdDescMapping
;
1721 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1722 // RunStop Register (UTRLRSR) to '1'.
1724 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1725 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1731 Initialize the UFS host controller.
1733 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1735 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1736 @retval Others A device error occurred while initializing the controller.
1741 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1746 Status
= UfsEnableHostController (Private
);
1747 if (EFI_ERROR (Status
)) {
1748 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status
));
1752 Status
= UfsDeviceDetection (Private
);
1753 if (EFI_ERROR (Status
)) {
1754 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status
));
1758 Status
= UfsInitTaskManagementRequestList (Private
);
1759 if (EFI_ERROR (Status
)) {
1760 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status
));
1764 Status
= UfsInitTransferRequestList (Private
);
1765 if (EFI_ERROR (Status
)) {
1766 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status
));
1768 if (Private
->TmrlMapping
!= NULL
) {
1770 EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)),
1771 Private
->UtpTmrlBase
,
1772 Private
->TmrlMapping
1774 Private
->TmrlMapping
= NULL
;
1780 DEBUG ((EFI_D_INFO
, "UfsDevicePei Finished\n"));
1785 Stop the UFS host controller.
1787 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1789 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1790 @retval Others A device error occurred while stopping the controller.
1795 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1803 // Enable the UTP Task Management Request List by setting the UTP Task Management
1804 // Request List RunStop Register (UTMRLRSR) to '1'.
1806 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1807 MmioWrite32 (Address
, 0);
1810 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1811 // RunStop Register (UTRLRSR) to '1'.
1813 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1814 MmioWrite32 (Address
, 0);
1817 // Write a 0 to the HCE register in order to disable the host controller.
1819 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1820 Data
= MmioRead32 (Address
);
1821 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1822 MmioWrite32 (Address
, 0);
1825 // Wait until HCE is read as '0' before continuing.
1827 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1828 if (EFI_ERROR (Status
)) {
1829 return EFI_DEVICE_ERROR
;
1832 DEBUG ((EFI_D_INFO
, "UfsDevicePei: Stop the UFS Host Controller\n"));