2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
3 for upper layer application to execute UFS-supported SCSI cmds.
5 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UfsPassThru.h"
19 Read 32bits data from specified UFS MMIO register.
21 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
22 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
24 @param[out] Value The data buffer to store.
26 @retval EFI_TIMEOUT The operation is time out.
27 @retval EFI_SUCCESS The operation succeeds.
28 @retval Others The operation fails.
33 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
38 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
41 UfsHc
= Private
->UfsHostController
;
43 Status
= UfsHc
->Read (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, Value
);
49 Write 32bits data to specified UFS MMIO register.
51 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
52 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
54 @param[in] Value The data to write.
56 @retval EFI_TIMEOUT The operation is time out.
57 @retval EFI_SUCCESS The operation succeeds.
58 @retval Others The operation fails.
63 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
68 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
71 UfsHc
= Private
->UfsHostController
;
73 Status
= UfsHc
->Write (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, &Value
);
79 Wait for the value of the specified system memory set to the test value.
81 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
82 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
84 @param[in] MaskValue The mask value of memory.
85 @param[in] TestValue The test value of memory.
86 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
88 @retval EFI_TIMEOUT The system memory setting is time out.
89 @retval EFI_SUCCESS The system memory is correct set.
90 @retval Others The operation fails.
95 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
104 BOOLEAN InfiniteWait
;
110 InfiniteWait
= FALSE
;
113 Delay
= DivU64x32 (Timeout
, 10) + 1;
117 // Access PCI MMIO space to see if the value is the tested one.
119 Status
= UfsMmioRead32 (Private
, Offset
, &Value
);
120 if (EFI_ERROR (Status
)) {
126 if (Value
== TestValue
) {
131 // Stall for 1 microseconds.
133 MicroSecondDelay (1);
137 } while (InfiniteWait
|| (Delay
> 0));
143 Dump UIC command execution result for debugging.
145 @param[in] UicOpcode The executed UIC opcode.
146 @param[in] Result The result to be parsed.
150 DumpUicCmdExecResult (
155 if (UicOpcode
<= UfsUicDmePeerSet
) {
160 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
163 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
166 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
169 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
172 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
175 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
178 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
181 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
184 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BUSY\n"));
187 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
198 DEBUG ((EFI_D_VERBOSE
, "UIC control command fails - FAILURE\n"));
208 Dump QUERY RESPONSE UPIU result for debugging.
210 @param[in] Result The result to be parsed.
214 DumpQueryResponseResult (
220 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Readable\n"));
223 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
226 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Already Written\n"));
229 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Length\n"));
232 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Value\n"));
235 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Selector\n"));
238 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Index\n"));
241 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Idn\n"));
244 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Opcode\n"));
247 DEBUG ((EFI_D_VERBOSE
, "Query Response with General Failure\n"));
256 Swap little endian to big endian.
258 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
259 In output, it will become big endian.
260 @param[in] BufferSize The length of converted data.
264 SwapLittleEndianToBigEndian (
265 IN OUT UINT8
*Buffer
,
273 SwapCount
= BufferSize
/ 2;
274 for (Index
= 0; Index
< SwapCount
; Index
++) {
275 Temp
= Buffer
[Index
];
276 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
277 Buffer
[BufferSize
- 1 - Index
] = Temp
;
282 Fill TSF field of QUERY REQUEST UPIU.
284 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
285 @param[in] Opcode The opcode of request.
286 @param[in] DescId The descriptor ID of request.
287 @param[in] Index The index of request.
288 @param[in] Selector The selector of request.
289 @param[in] Length The length of transferred data. The maximum is 4.
290 @param[in] Value The value of transferred data.
294 UfsFillTsfOfQueryReqUpiu (
295 IN OUT UTP_UPIU_TSF
*TsfBase
,
297 IN UINT8 DescId OPTIONAL
,
298 IN UINT8 Index OPTIONAL
,
299 IN UINT8 Selector OPTIONAL
,
300 IN UINT16 Length OPTIONAL
,
301 IN UINT32 Value OPTIONAL
304 ASSERT (TsfBase
!= NULL
);
305 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
307 TsfBase
->Opcode
= Opcode
;
308 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
309 TsfBase
->DescId
= DescId
;
310 TsfBase
->Index
= Index
;
311 TsfBase
->Selector
= Selector
;
313 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
314 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
315 TsfBase
->Length
= Length
;
318 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
319 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
320 TsfBase
->Value
= Value
;
326 Initialize COMMAND UPIU.
328 @param[in, out] Command The base address of COMMAND UPIU.
329 @param[in] Lun The Lun on which the SCSI command is executed.
330 @param[in] TaskTag The task tag of request.
331 @param[in] Cdb The cdb buffer containing SCSI command.
332 @param[in] CdbLength The cdb length.
333 @param[in] DataDirection The direction of data transfer.
334 @param[in] ExpDataTranLen The expected transfer data length.
336 @retval EFI_SUCCESS The initialization succeed.
341 IN OUT UTP_COMMAND_UPIU
*Command
,
346 IN UFS_DATA_DIRECTION DataDirection
,
347 IN UINT32 ExpDataTranLen
352 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
355 // Task attribute is hard-coded to Ordered.
357 if (DataDirection
== UfsDataIn
) {
359 } else if (DataDirection
== UfsDataOut
) {
366 // Fill UTP COMMAND UPIU associated fields.
368 Command
->TransCode
= 0x01;
369 Command
->Flags
= Flags
;
371 Command
->TaskTag
= TaskTag
;
372 Command
->CmdSet
= 0x00;
373 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
374 Command
->ExpDataTranLen
= ExpDataTranLen
;
376 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
382 Initialize UTP PRDT for data transfer.
384 @param[in] Prdt The base address of PRDT.
385 @param[in] Buffer The buffer to be read or written.
386 @param[in] BufferSize The data size to be read or written.
388 @retval EFI_SUCCESS The initialization succeed.
403 if (BufferSize
== 0) {
407 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
409 RemainingLen
= BufferSize
;
411 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
413 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
414 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
415 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
417 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
420 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
421 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
422 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
423 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
430 Initialize QUERY REQUEST UPIU.
432 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
433 @param[in] TaskTag The task tag of request.
434 @param[in] Opcode The opcode of request.
435 @param[in] DescId The descriptor ID of request.
436 @param[in] Index The index of request.
437 @param[in] Selector The selector of request.
438 @param[in] DataSize The data size to be read or written.
439 @param[in] Data The buffer to be read or written.
441 @retval EFI_SUCCESS The initialization succeed.
445 UfsInitQueryRequestUpiu (
446 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
452 IN UINTN DataSize OPTIONAL
,
453 IN UINT8
*Data OPTIONAL
456 ASSERT (QueryReq
!= NULL
);
458 QueryReq
->TransCode
= 0x16;
459 QueryReq
->TaskTag
= TaskTag
;
460 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
461 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
463 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
466 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
467 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
468 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
469 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
471 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
474 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
475 CopyMem (QueryReq
+ 1, Data
, DataSize
);
482 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
484 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
485 @param[in] Lun The Lun on which the SCSI command is executed.
486 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
487 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
488 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
489 @param[out] CmdDescMapping A resulting value to pass to Unmap().
491 @retval EFI_SUCCESS The creation succeed.
492 @retval EFI_DEVICE_ERROR The creation failed.
493 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
497 UfsCreateScsiCommandDesc (
498 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
500 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
502 OUT VOID
**CmdDescHost
,
503 OUT VOID
**CmdDescMapping
508 UTP_COMMAND_UPIU
*CommandUpiu
;
509 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
512 UFS_DATA_DIRECTION DataDirection
;
514 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
516 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
517 DataLen
= Packet
->InTransferLength
;
518 DataDirection
= UfsDataIn
;
520 DataLen
= Packet
->OutTransferLength
;
521 DataDirection
= UfsDataOut
;
525 DataDirection
= UfsNoData
;
528 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
530 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
532 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
533 if (EFI_ERROR (Status
)) {
537 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
539 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
542 // Fill UTP_TRD associated fields
543 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
544 // *MUST* be located at a 64-bit aligned boundary.
546 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
547 Trd
->Dd
= DataDirection
;
548 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
549 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
550 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
551 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
552 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
553 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
554 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
559 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
561 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
562 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
563 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
564 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
565 @param[out] CmdDescMapping A resulting value to pass to Unmap().
567 @retval EFI_SUCCESS The creation succeed.
568 @retval EFI_DEVICE_ERROR The creation failed.
569 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
570 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
574 UfsCreateDMCommandDesc (
575 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
576 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
578 OUT VOID
**CmdDescHost
,
579 OUT VOID
**CmdDescMapping
583 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
588 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
591 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
593 Opcode
= Packet
->Opcode
;
594 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
595 return EFI_INVALID_PARAMETER
;
598 DataDirection
= Packet
->DataDirection
;
599 if (DataDirection
== UfsDataIn
) {
600 DataSize
= Packet
->InTransferLength
;
601 Data
= Packet
->InDataBuffer
;
602 } else if (DataDirection
== UfsDataOut
) {
603 DataSize
= Packet
->OutTransferLength
;
604 Data
= Packet
->OutDataBuffer
;
610 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
611 && ((DataSize
== 0) || (Data
== NULL
))) {
612 return EFI_INVALID_PARAMETER
;
615 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
616 && ((DataSize
!= 0) || (Data
!= NULL
))) {
617 return EFI_INVALID_PARAMETER
;
620 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
621 return EFI_INVALID_PARAMETER
;
624 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
625 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
627 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
630 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
631 if (EFI_ERROR (Status
)) {
636 // Initialize UTP QUERY REQUEST UPIU
638 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
639 ASSERT (QueryReqUpiu
!= NULL
);
640 UfsInitQueryRequestUpiu (
652 // Fill UTP_TRD associated fields
653 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
655 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
656 Trd
->Dd
= DataDirection
;
657 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
659 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
660 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
661 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
662 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
663 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
665 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
666 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
673 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
675 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
676 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
677 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
678 @param[out] CmdDescMapping A resulting value to pass to Unmap().
680 @retval EFI_SUCCESS The creation succeed.
681 @retval EFI_DEVICE_ERROR The creation failed.
682 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
686 UfsCreateNopCommandDesc (
687 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
689 OUT VOID
**CmdDescHost
,
690 OUT VOID
**CmdDescMapping
694 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
696 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
698 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
700 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
701 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
702 if (EFI_ERROR (Status
)) {
706 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
707 ASSERT (NopOutUpiu
!= NULL
);
708 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
711 // Fill UTP_TRD associated fields
712 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
714 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
716 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
717 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
718 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
719 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
720 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
726 Find out available slot in transfer list of a UFS device.
728 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
729 @param[out] Slot The available slot.
731 @retval EFI_SUCCESS The available slot was found successfully.
735 UfsFindAvailableSlotInTrl (
736 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
740 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
743 // The simplest algo to always use slot 0.
744 // TODO: enhance it to support async transfer with multiple slot.
752 Find out available slot in task management transfer list of a UFS device.
754 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
755 @param[out] Slot The available slot.
757 @retval EFI_SUCCESS The available slot was found successfully.
761 UfsFindAvailableSlotInTmrl (
762 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
766 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
769 // The simplest algo to always use slot 0.
770 // TODO: enhance it to support async transfer with multiple slot.
778 Start specified slot in transfer list of a UFS device.
780 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
781 @param[in] Slot The slot to be started.
786 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
793 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
794 if (EFI_ERROR (Status
)) {
798 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
799 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
800 if (EFI_ERROR (Status
)) {
805 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
806 if (EFI_ERROR (Status
)) {
814 Stop specified slot in transfer list of a UFS device.
816 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
817 @param[in] Slot The slot to be stop.
822 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
829 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
830 if (EFI_ERROR (Status
)) {
834 if ((Data
& (BIT0
<< Slot
)) != 0) {
835 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
836 if (EFI_ERROR (Status
)) {
840 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
841 if (EFI_ERROR (Status
)) {
850 Read or write specified device descriptor of a UFS device.
852 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
853 @param[in] Read The boolean variable to show r/w direction.
854 @param[in] DescId The ID of device descriptor.
855 @param[in] Index The Index of device descriptor.
856 @param[in] Selector The Selector of device descriptor.
857 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
858 @param[in] DescSize The size of device descriptor buffer.
860 @retval EFI_SUCCESS The device descriptor was read/written successfully.
861 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
862 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
867 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
872 IN OUT VOID
*Descriptor
,
877 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
880 UTP_QUERY_RESP_UPIU
*QueryResp
;
882 UINT16 ReturnDataSize
;
884 VOID
*CmdDescMapping
;
885 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
887 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
890 Packet
.DataDirection
= UfsDataIn
;
891 Packet
.InDataBuffer
= Descriptor
;
892 Packet
.InTransferLength
= DescSize
;
893 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
895 Packet
.DataDirection
= UfsDataOut
;
896 Packet
.OutDataBuffer
= Descriptor
;
897 Packet
.OutTransferLength
= DescSize
;
898 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
900 Packet
.DescId
= DescId
;
901 Packet
.Index
= Index
;
902 Packet
.Selector
= Selector
;
903 Packet
.Timeout
= UFS_TIMEOUT
;
906 // Find out which slot of transfer request list is available.
908 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
909 if (EFI_ERROR (Status
)) {
913 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
915 // Fill transfer request descriptor to this slot.
917 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
918 if (EFI_ERROR (Status
)) {
923 // Check the transfer request result.
925 UfsHc
= Private
->UfsHostController
;
926 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
927 ASSERT (QueryResp
!= NULL
);
928 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
931 // Start to execute the transfer request.
933 UfsStartExecCmd (Private
, Slot
);
936 // Wait for the completion of the transfer request.
938 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
.Timeout
);
939 if (EFI_ERROR (Status
)) {
943 if (QueryResp
->QueryResp
!= 0) {
944 DumpQueryResponseResult (QueryResp
->QueryResp
);
945 Status
= EFI_DEVICE_ERROR
;
950 ReturnDataSize
= QueryResp
->Tsf
.Length
;
951 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
954 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
955 Packet
.InTransferLength
= ReturnDataSize
;
957 Packet
.OutTransferLength
= ReturnDataSize
;
960 Status
= EFI_DEVICE_ERROR
;
964 UfsHc
->Flush (UfsHc
);
966 UfsStopExecCmd (Private
, Slot
);
968 if (CmdDescMapping
!= NULL
) {
969 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
971 if (CmdDescHost
!= NULL
) {
972 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
979 Read or write specified attribute of a UFS device.
981 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
982 @param[in] Read The boolean variable to show r/w direction.
983 @param[in] AttrId The ID of Attribute.
984 @param[in] Index The Index of Attribute.
985 @param[in] Selector The Selector of Attribute.
986 @param[in, out] Attributes The value of Attribute to be read or written.
988 @retval EFI_SUCCESS The Attribute was read/written successfully.
989 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
990 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
995 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1000 IN OUT UINT32
*Attributes
1004 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1007 UTP_QUERY_RESP_UPIU
*QueryResp
;
1011 VOID
*CmdDescMapping
;
1012 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1014 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1017 Packet
.DataDirection
= UfsDataIn
;
1018 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1020 Packet
.DataDirection
= UfsDataOut
;
1021 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1023 Packet
.DescId
= AttrId
;
1024 Packet
.Index
= Index
;
1025 Packet
.Selector
= Selector
;
1026 Packet
.Timeout
= UFS_TIMEOUT
;
1029 // Find out which slot of transfer request list is available.
1031 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1032 if (EFI_ERROR (Status
)) {
1036 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1038 // Fill transfer request descriptor to this slot.
1040 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1041 if (EFI_ERROR (Status
)) {
1046 // Check the transfer request result.
1048 UfsHc
= Private
->UfsHostController
;
1049 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1050 ASSERT (QueryResp
!= NULL
);
1051 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1054 // Start to execute the transfer request.
1056 UfsStartExecCmd (Private
, Slot
);
1059 // Wait for the completion of the transfer request.
1061 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
.Timeout
);
1062 if (EFI_ERROR (Status
)) {
1066 if (QueryResp
->QueryResp
!= 0) {
1067 DumpQueryResponseResult (QueryResp
->QueryResp
);
1068 Status
= EFI_DEVICE_ERROR
;
1072 if (Trd
->Ocs
== 0) {
1073 ReturnData
= QueryResp
->Tsf
.Value
;
1074 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
1075 *Attributes
= ReturnData
;
1077 Status
= EFI_DEVICE_ERROR
;
1081 UfsHc
->Flush (UfsHc
);
1083 UfsStopExecCmd (Private
, Slot
);
1085 if (CmdDescMapping
!= NULL
) {
1086 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1089 if (CmdDescHost
!= NULL
) {
1090 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1097 Read or write specified flag of a UFS device.
1099 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1100 @param[in] Read The boolean variable to show r/w direction.
1101 @param[in] FlagId The ID of flag to be read or written.
1102 @param[in, out] Value The value to set or clear flag.
1104 @retval EFI_SUCCESS The flag was read/written successfully.
1105 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1106 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1111 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1118 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1121 UTP_QUERY_RESP_UPIU
*QueryResp
;
1124 VOID
*CmdDescMapping
;
1125 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1127 if (Value
== NULL
) {
1128 return EFI_INVALID_PARAMETER
;
1131 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1134 ASSERT (Value
!= NULL
);
1135 Packet
.DataDirection
= UfsDataIn
;
1136 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1138 Packet
.DataDirection
= UfsDataOut
;
1140 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1141 } else if (*Value
== 0) {
1142 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1144 return EFI_INVALID_PARAMETER
;
1147 Packet
.DescId
= FlagId
;
1149 Packet
.Selector
= 0;
1150 Packet
.Timeout
= UFS_TIMEOUT
;
1153 // Find out which slot of transfer request list is available.
1155 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1156 if (EFI_ERROR (Status
)) {
1161 // Fill transfer request descriptor to this slot.
1163 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1164 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1165 if (EFI_ERROR (Status
)) {
1170 // Check the transfer request result.
1172 UfsHc
= Private
->UfsHostController
;
1173 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1174 ASSERT (QueryResp
!= NULL
);
1175 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1178 // Start to execute the transfer request.
1180 UfsStartExecCmd (Private
, Slot
);
1183 // Wait for the completion of the transfer request.
1185 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
.Timeout
);
1186 if (EFI_ERROR (Status
)) {
1190 if (QueryResp
->QueryResp
!= 0) {
1191 DumpQueryResponseResult (QueryResp
->QueryResp
);
1192 Status
= EFI_DEVICE_ERROR
;
1196 if (Trd
->Ocs
== 0) {
1197 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
1199 Status
= EFI_DEVICE_ERROR
;
1203 UfsHc
->Flush (UfsHc
);
1205 UfsStopExecCmd (Private
, Slot
);
1207 if (CmdDescMapping
!= NULL
) {
1208 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1210 if (CmdDescHost
!= NULL
) {
1211 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1218 Set specified flag to 1 on a UFS device.
1220 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1221 @param[in] FlagId The ID of flag to be set.
1223 @retval EFI_SUCCESS The flag was set successfully.
1224 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1225 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1230 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1238 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1244 Clear specified flag to 0 on a UFS device.
1246 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1247 @param[in] FlagId The ID of flag to be cleared.
1249 @retval EFI_SUCCESS The flag was cleared successfully.
1250 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1251 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1256 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1264 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1270 Read specified flag from a UFS device.
1272 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1273 @param[in] FlagId The ID of flag to be read.
1274 @param[out] Value The flag's value.
1276 @retval EFI_SUCCESS The flag was read successfully.
1277 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1278 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1283 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1290 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1296 Sends NOP IN cmd to a UFS device for initialization process request.
1297 For more details, please refer to UFS 2.0 spec Figure 13.3.
1299 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1301 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1302 received successfully.
1303 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1304 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1305 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1310 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1316 UTP_NOP_IN_UPIU
*NopInUpiu
;
1319 VOID
*CmdDescMapping
;
1320 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1323 // Find out which slot of transfer request list is available.
1325 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1326 if (EFI_ERROR (Status
)) {
1330 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1331 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1332 if (EFI_ERROR (Status
)) {
1337 // Check the transfer request result.
1339 UfsHc
= Private
->UfsHostController
;
1340 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1341 ASSERT (NopInUpiu
!= NULL
);
1342 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1345 // Start to execute the transfer request.
1347 UfsStartExecCmd (Private
, Slot
);
1350 // Wait for the completion of the transfer request.
1352 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, UFS_TIMEOUT
);
1353 if (EFI_ERROR (Status
)) {
1357 if (NopInUpiu
->Resp
!= 0) {
1358 Status
= EFI_DEVICE_ERROR
;
1360 Status
= EFI_SUCCESS
;
1364 UfsHc
->Flush (UfsHc
);
1366 UfsStopExecCmd (Private
, Slot
);
1368 if (CmdDescMapping
!= NULL
) {
1369 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1371 if (CmdDescHost
!= NULL
) {
1372 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1379 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1381 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1382 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1383 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1386 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1387 commands, InTransferLength bytes were transferred from
1388 InDataBuffer. For write and bi-directional commands,
1389 OutTransferLength bytes were transferred by
1391 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1393 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1394 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1399 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1401 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1408 UTP_RESPONSE_UPIU
*Response
;
1409 UINT16 SenseDataLen
;
1410 UINT32 ResTranCount
;
1412 VOID
*CmdDescMapping
;
1413 VOID
*DataBufMapping
;
1415 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1418 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1419 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1420 UFS_DATA_DIRECTION DataDirection
;
1421 UTP_TR_PRD
*PrdtBase
;
1425 CmdDescMapping
= NULL
;
1426 DataBufMapping
= NULL
;
1428 UfsHc
= Private
->UfsHostController
;
1430 // Find out which slot of transfer request list is available.
1432 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1433 if (EFI_ERROR (Status
)) {
1437 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1440 // Fill transfer request descriptor to this slot.
1442 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1443 if (EFI_ERROR (Status
)) {
1447 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1449 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1450 DataBuf
= Packet
->InDataBuffer
;
1451 DataLen
= Packet
->InTransferLength
;
1452 DataDirection
= UfsDataIn
;
1453 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1455 DataBuf
= Packet
->OutDataBuffer
;
1456 DataLen
= Packet
->OutTransferLength
;
1457 DataDirection
= UfsDataOut
;
1458 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1462 DataDirection
= UfsNoData
;
1464 MapLength
= DataLen
;
1465 Status
= UfsHc
->Map (
1474 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1479 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1481 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1482 ASSERT (PrdtBase
!= NULL
);
1483 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1486 // Start to execute the transfer request.
1488 UfsStartExecCmd (Private
, Slot
);
1491 // Wait for the completion of the transfer request.
1493 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
1494 if (EFI_ERROR (Status
)) {
1499 // Get sense data if exists
1501 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1502 ASSERT (Response
!= NULL
);
1503 SenseDataLen
= Response
->SenseDataLen
;
1504 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1506 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1507 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1508 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1512 // Check the transfer request result.
1514 Packet
->TargetStatus
= Response
->Status
;
1515 if (Response
->Response
!= 0) {
1516 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1517 Status
= EFI_DEVICE_ERROR
;
1521 if (Trd
->Ocs
== 0) {
1522 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1523 if ((Response
->Flags
& BIT5
) == BIT5
) {
1524 ResTranCount
= Response
->ResTranCount
;
1525 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1526 Packet
->InTransferLength
-= ResTranCount
;
1529 if ((Response
->Flags
& BIT5
) == BIT5
) {
1530 ResTranCount
= Response
->ResTranCount
;
1531 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1532 Packet
->OutTransferLength
-= ResTranCount
;
1536 Status
= EFI_DEVICE_ERROR
;
1540 UfsHc
->Flush (UfsHc
);
1542 UfsStopExecCmd (Private
, Slot
);
1544 if (DataBufMapping
!= NULL
) {
1545 UfsHc
->Unmap (UfsHc
, DataBufMapping
);
1549 if (CmdDescMapping
!= NULL
) {
1550 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1552 if (CmdDescHost
!= NULL
) {
1553 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1560 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1562 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1563 @param[in] UicOpcode The opcode of the UIC command.
1564 @param[in] Arg1 The value for 1st argument of the UIC command.
1565 @param[in] Arg2 The value for 2nd argument of the UIC command.
1566 @param[in] Arg3 The value for 3rd argument of the UIC command.
1568 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1569 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1570 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1574 UfsExecUicCommands (
1575 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1585 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1586 if (EFI_ERROR (Status
)) {
1590 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1592 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1594 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1595 if (EFI_ERROR (Status
)) {
1601 // When programming UIC command registers, host software shall set the register UICCMD
1602 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1605 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1606 if (EFI_ERROR (Status
)) {
1610 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1611 if (EFI_ERROR (Status
)) {
1615 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1616 if (EFI_ERROR (Status
)) {
1621 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1623 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1624 if (EFI_ERROR (Status
)) {
1628 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1629 if (EFI_ERROR (Status
)) {
1634 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1635 // This bit is set to '1' by the host controller upon completion of a UIC command.
1637 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1638 if (EFI_ERROR (Status
)) {
1642 if (UicOpcode
!= UfsUicDmeReset
) {
1643 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1644 if (EFI_ERROR (Status
)) {
1647 if ((Data
& 0xFF) != 0) {
1649 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1651 return EFI_DEVICE_ERROR
;
1656 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1658 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1659 if (EFI_ERROR (Status
)) {
1663 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1664 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1665 if (EFI_ERROR (Status
)) {
1666 return EFI_DEVICE_ERROR
;
1668 return EFI_NOT_FOUND
;
1671 DEBUG ((EFI_D_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1677 Allocate common buffer for host and UFS bus master access simultaneously.
1679 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1680 @param[in] Size The length of buffer to be allocated.
1681 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1682 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1683 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1685 @retval EFI_SUCCESS The common buffer was allocated successfully.
1686 @retval EFI_DEVICE_ERROR The allocation fails.
1687 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1691 UfsAllocateAlignCommonBuffer (
1692 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1694 OUT VOID
**CmdDescHost
,
1695 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1696 OUT VOID
**CmdDescMapping
1701 BOOLEAN Is32BitAddr
;
1702 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1704 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1707 Is32BitAddr
= FALSE
;
1710 UfsHc
= Private
->UfsHostController
;
1711 Status
= UfsHc
->AllocateBuffer (
1714 EfiBootServicesData
,
1715 EFI_SIZE_TO_PAGES (Size
),
1719 if (EFI_ERROR (Status
)) {
1720 *CmdDescMapping
= NULL
;
1721 *CmdDescHost
= NULL
;
1722 *CmdDescPhyAddr
= 0;
1723 return EFI_OUT_OF_RESOURCES
;
1726 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1727 Status
= UfsHc
->Map (
1729 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1736 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1739 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1742 *CmdDescHost
= NULL
;
1743 return EFI_OUT_OF_RESOURCES
;
1746 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1748 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1756 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1759 *CmdDescMapping
= NULL
;
1760 *CmdDescHost
= NULL
;
1761 return EFI_DEVICE_ERROR
;
1764 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1769 Enable the UFS host controller for accessing.
1771 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1773 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1774 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1778 UfsEnableHostController (
1779 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1786 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1788 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1790 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1791 if (EFI_ERROR (Status
)) {
1795 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1797 // Write a 0 to the HCE register at first to disable the host controller.
1799 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1800 if (EFI_ERROR (Status
)) {
1804 // Wait until HCE is read as '0' before continuing.
1806 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1807 if (EFI_ERROR (Status
)) {
1808 return EFI_DEVICE_ERROR
;
1813 // Write a 1 to the HCE register to enable the UFS host controller.
1815 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1816 if (EFI_ERROR (Status
)) {
1821 // Wait until HCE is read as '1' before continuing.
1823 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1824 if (EFI_ERROR (Status
)) {
1825 return EFI_DEVICE_ERROR
;
1832 Detect if a UFS device attached.
1834 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1836 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1837 @retval EFI_NOT_FOUND Not found a UFS device attached.
1838 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1842 UfsDeviceDetection (
1843 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1850 // Start UFS device detection.
1851 // Try up to 3 times for establishing data link with device.
1853 for (Retry
= 0; Retry
< 3; Retry
++) {
1854 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1855 if (!EFI_ERROR (Status
)) {
1859 if (Status
== EFI_NOT_FOUND
) {
1863 return EFI_DEVICE_ERROR
;
1867 return EFI_NOT_FOUND
;
1874 Initialize UFS task management request list related h/w context.
1876 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1878 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1879 @retval EFI_DEVICE_ERROR The initialization fails.
1883 UfsInitTaskManagementRequestList (
1884 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1890 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1891 VOID
*CmdDescMapping
;
1895 // Initial h/w and s/w context for future operations.
1898 CmdDescMapping
= NULL
;
1901 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1902 if (EFI_ERROR (Status
)) {
1906 Private
->Capabilities
= Data
;
1909 // Allocate and initialize UTP Task Management Request List.
1911 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1912 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1913 if (EFI_ERROR (Status
)) {
1918 // Program the UTP Task Management Request List Base Address and UTP Task Management
1919 // Request List Base Address with a 64-bit address allocated at step 6.
1921 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1922 if (EFI_ERROR (Status
)) {
1926 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1927 if (EFI_ERROR (Status
)) {
1930 Private
->UtpTmrlBase
= CmdDescHost
;
1931 Private
->Nutmrs
= Nutmrs
;
1932 Private
->TmrlMapping
= CmdDescMapping
;
1935 // Enable the UTP Task Management Request List by setting the UTP Task Management
1936 // Request List RunStop Register (UTMRLRSR) to '1'.
1938 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1939 if (EFI_ERROR (Status
)) {
1947 Initialize UFS transfer request list related h/w context.
1949 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1951 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1952 @retval EFI_DEVICE_ERROR The initialization fails.
1956 UfsInitTransferRequestList (
1957 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1963 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1964 VOID
*CmdDescMapping
;
1968 // Initial h/w and s/w context for future operations.
1971 CmdDescMapping
= NULL
;
1974 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1975 if (EFI_ERROR (Status
)) {
1979 Private
->Capabilities
= Data
;
1982 // Allocate and initialize UTP Transfer Request List.
1984 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1985 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1986 if (EFI_ERROR (Status
)) {
1991 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1992 // Base Address with a 64-bit address allocated at step 8.
1994 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1995 if (EFI_ERROR (Status
)) {
1999 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2000 if (EFI_ERROR (Status
)) {
2004 Private
->UtpTrlBase
= CmdDescHost
;
2005 Private
->Nutrs
= Nutrs
;
2006 Private
->TrlMapping
= CmdDescMapping
;
2009 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2010 // RunStop Register (UTRLRSR) to '1'.
2012 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2013 if (EFI_ERROR (Status
)) {
2021 Initialize the UFS host controller.
2023 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2025 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2026 @retval Others A device error occurred while initializing the controller.
2031 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2036 Status
= UfsEnableHostController (Private
);
2037 if (EFI_ERROR (Status
)) {
2038 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2042 Status
= UfsDeviceDetection (Private
);
2043 if (EFI_ERROR (Status
)) {
2044 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2048 Status
= UfsInitTaskManagementRequestList (Private
);
2049 if (EFI_ERROR (Status
)) {
2050 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2054 Status
= UfsInitTransferRequestList (Private
);
2055 if (EFI_ERROR (Status
)) {
2056 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2060 DEBUG ((EFI_D_INFO
, "UfsControllerInit Finished\n"));
2065 Stop the UFS host controller.
2067 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2069 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2070 @retval Others A device error occurred while stopping the controller.
2075 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2082 // Enable the UTP Task Management Request List by setting the UTP Task Management
2083 // Request List RunStop Register (UTMRLRSR) to '1'.
2085 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2086 if (EFI_ERROR (Status
)) {
2091 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2092 // RunStop Register (UTRLRSR) to '1'.
2094 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2095 if (EFI_ERROR (Status
)) {
2100 // Write a 0 to the HCE register in order to disable the host controller.
2102 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2103 if (EFI_ERROR (Status
)) {
2106 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2108 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2109 if (EFI_ERROR (Status
)) {
2114 // Wait until HCE is read as '0' before continuing.
2116 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2117 if (EFI_ERROR (Status
)) {
2118 return EFI_DEVICE_ERROR
;
2121 DEBUG ((EFI_D_INFO
, "UfsController is stopped\n"));