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.
700 Start specified slot in transfer list of a UFS device.
702 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
703 @param[in] Slot The slot to be started.
708 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
716 UfsHcBase
= Private
->UfsHcBase
;
718 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
719 Data
= MmioRead32 (Address
);
720 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
721 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
724 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
725 MmioWrite32 (Address
, BIT0
<< Slot
);
729 Stop specified slot in transfer list of a UFS device.
731 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
732 @param[in] Slot The slot to be stop.
737 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
745 UfsHcBase
= Private
->UfsHcBase
;
747 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
748 Data
= MmioRead32 (Address
);
749 if ((Data
& (BIT0
<< Slot
)) != 0) {
750 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
751 Data
= MmioRead32 (Address
);
752 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
757 Read or write specified device descriptor of a UFS device.
759 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
760 @param[in] Read The boolean variable to show r/w direction.
761 @param[in] DescId The ID of device descriptor.
762 @param[in] Index The Index of device descriptor.
763 @param[in] Selector The Selector of device descriptor.
764 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
765 @param[in] DescSize The size of device descriptor buffer.
767 @retval EFI_SUCCESS The device descriptor was read/written successfully.
768 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
769 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
774 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
779 IN OUT VOID
*Descriptor
,
784 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
788 UTP_QUERY_RESP_UPIU
*QueryResp
;
791 UINT16 ReturnDataSize
;
793 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
796 Packet
.DataDirection
= UfsDataIn
;
797 Packet
.InDataBuffer
= Descriptor
;
798 Packet
.InTransferLength
= DescSize
;
799 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
801 Packet
.DataDirection
= UfsDataOut
;
802 Packet
.OutDataBuffer
= Descriptor
;
803 Packet
.OutTransferLength
= DescSize
;
804 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
806 Packet
.DescId
= DescId
;
807 Packet
.Index
= Index
;
808 Packet
.Selector
= Selector
;
809 Packet
.Timeout
= UFS_TIMEOUT
;
812 // Find out which slot of transfer request list is available.
814 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
815 if (EFI_ERROR (Status
)) {
819 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
821 // Fill transfer request descriptor to this slot.
823 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
824 if (EFI_ERROR (Status
)) {
829 // Check the transfer request result.
831 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
832 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
833 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
836 // Start to execute the transfer request.
838 UfsStartExecCmd (Private
, Slot
);
841 // Wait for the completion of the transfer request.
843 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
844 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
845 if (EFI_ERROR (Status
)) {
849 if (QueryResp
->QueryResp
!= 0) {
850 DumpQueryResponseResult (QueryResp
->QueryResp
);
851 Status
= EFI_DEVICE_ERROR
;
856 ReturnDataSize
= QueryResp
->Tsf
.Length
;
857 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
860 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
861 Packet
.InTransferLength
= ReturnDataSize
;
863 Packet
.OutTransferLength
= ReturnDataSize
;
866 Status
= EFI_DEVICE_ERROR
;
870 UfsStopExecCmd (Private
, Slot
);
871 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
879 Read or write specified flag of a UFS device.
881 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
882 @param[in] Read The boolean variable to show r/w direction.
883 @param[in] FlagId The ID of flag to be read or written.
884 @param[in, out] Value The value to set or clear flag.
886 @retval EFI_SUCCESS The flag was read/written successfully.
887 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
888 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
893 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
900 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
904 UTP_QUERY_RESP_UPIU
*QueryResp
;
909 return EFI_INVALID_PARAMETER
;
912 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
915 ASSERT (Value
!= NULL
);
916 Packet
.DataDirection
= UfsDataIn
;
917 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
919 Packet
.DataDirection
= UfsDataOut
;
921 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
922 } else if (*Value
== 0) {
923 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
925 return EFI_INVALID_PARAMETER
;
928 Packet
.DescId
= FlagId
;
931 Packet
.Timeout
= UFS_TIMEOUT
;
934 // Find out which slot of transfer request list is available.
936 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
937 if (EFI_ERROR (Status
)) {
942 // Fill transfer request descriptor to this slot.
944 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
945 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
);
946 if (EFI_ERROR (Status
)) {
951 // Check the transfer request result.
953 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
954 QueryResp
= (UTP_QUERY_RESP_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
955 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
958 // Start to execute the transfer request.
960 UfsStartExecCmd (Private
, Slot
);
963 // Wait for the completion of the transfer request.
965 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
966 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
.Timeout
);
967 if (EFI_ERROR (Status
)) {
971 if (QueryResp
->QueryResp
!= 0) {
972 DumpQueryResponseResult (QueryResp
->QueryResp
);
973 Status
= EFI_DEVICE_ERROR
;
978 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
980 Status
= EFI_DEVICE_ERROR
;
984 UfsStopExecCmd (Private
, Slot
);
985 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
991 Set specified flag to 1 on a UFS device.
993 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
994 @param[in] FlagId The ID of flag to be set.
996 @retval EFI_SUCCESS The flag was set successfully.
997 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
998 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1003 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1011 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1019 Sends NOP IN cmd to a UFS device for initialization process request.
1020 For more details, please refer to UFS 2.0 spec Figure 13.3.
1022 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1024 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1025 received successfully.
1026 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1027 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1028 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1033 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1039 UTP_NOP_IN_UPIU
*NopInUpiu
;
1045 // Find out which slot of transfer request list is available.
1047 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1048 if (EFI_ERROR (Status
)) {
1052 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1053 Status
= UfsCreateNopCommandDesc (Private
, Trd
);
1054 if (EFI_ERROR (Status
)) {
1059 // Check the transfer request result.
1061 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1062 NopInUpiu
= (UTP_NOP_IN_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1063 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1066 // Start to execute the transfer request.
1068 UfsStartExecCmd (Private
, Slot
);
1071 // Wait for the completion of the transfer request.
1073 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1074 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1075 if (EFI_ERROR (Status
)) {
1079 if (NopInUpiu
->Resp
!= 0) {
1080 Status
= EFI_DEVICE_ERROR
;
1082 Status
= EFI_SUCCESS
;
1086 UfsStopExecCmd (Private
, Slot
);
1087 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1093 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1095 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1096 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1097 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1100 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1101 commands, InTransferLength bytes were transferred from
1102 InDataBuffer. For write and bi-directional commands,
1103 OutTransferLength bytes were transferred by
1105 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1107 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1108 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1113 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1115 IN OUT UFS_SCSI_REQUEST_PACKET
*Packet
1124 UTP_RESPONSE_UPIU
*Response
;
1125 UINT16 SenseDataLen
;
1126 UINT32 ResTranCount
;
1127 VOID
*PacketBufferMap
;
1130 // Find out which slot of transfer request list is available.
1132 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1133 if (EFI_ERROR (Status
)) {
1137 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1138 PacketBufferMap
= NULL
;
1141 // Fill transfer request descriptor to this slot.
1143 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
, &PacketBufferMap
);
1144 if (EFI_ERROR (Status
)) {
1148 CmdDescBase
= (UINT8
*)(UINTN
)(LShiftU64 ((UINT64
)Trd
->UcdBaU
, 32) | LShiftU64 ((UINT64
)Trd
->UcdBa
, 7));
1149 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1152 // Start to execute the transfer request.
1154 UfsStartExecCmd (Private
, Slot
);
1157 // Wait for the completion of the transfer request.
1159 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1160 Status
= UfsWaitMemSet (Address
, BIT0
<< Slot
, 0, Packet
->Timeout
);
1161 if (EFI_ERROR (Status
)) {
1166 // Get sense data if exists
1168 Response
= (UTP_RESPONSE_UPIU
*)(CmdDescBase
+ Trd
->RuO
* sizeof (UINT32
));
1169 SenseDataLen
= Response
->SenseDataLen
;
1170 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1172 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1173 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1174 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1178 // Check the transfer request result.
1180 if (Response
->Response
!= 0) {
1181 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1182 Status
= EFI_DEVICE_ERROR
;
1186 if (Trd
->Ocs
== 0) {
1187 if (Packet
->DataDirection
== UfsDataIn
) {
1188 if ((Response
->Flags
& BIT5
) == BIT5
) {
1189 ResTranCount
= Response
->ResTranCount
;
1190 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1191 Packet
->InTransferLength
-= ResTranCount
;
1193 } else if (Packet
->DataDirection
== UfsDataOut
) {
1194 if ((Response
->Flags
& BIT5
) == BIT5
) {
1195 ResTranCount
= Response
->ResTranCount
;
1196 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1197 Packet
->OutTransferLength
-= ResTranCount
;
1201 Status
= EFI_DEVICE_ERROR
;
1205 if (PacketBufferMap
!= NULL
) {
1206 IoMmuUnmap (PacketBufferMap
);
1208 UfsStopExecCmd (Private
, Slot
);
1209 UfsPeimFreeMem (Private
->Pool
, CmdDescBase
, CmdDescSize
);
1216 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1218 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1219 @param[in] UicOpcode The opcode of the UIC command.
1220 @param[in] Arg1 The value for 1st argument of the UIC command.
1221 @param[in] Arg2 The value for 2nd argument of the UIC command.
1222 @param[in] Arg3 The value for 3rd argument of the UIC command.
1224 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1225 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1226 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1230 UfsExecUicCommands (
1231 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
1243 UfsHcBase
= Private
->UfsHcBase
;
1244 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1245 Data
= MmioRead32 (Address
);
1246 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1248 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1250 MmioWrite32 (Address
, Data
);
1254 // When programming UIC command registers, host software shall set the register UICCMD
1255 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1258 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1259 MmioWrite32 (Address
, Arg1
);
1261 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1262 MmioWrite32 (Address
, Arg2
);
1264 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1265 MmioWrite32 (Address
, Arg3
);
1268 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1270 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1271 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1272 if (EFI_ERROR (Status
)) {
1276 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1277 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1280 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1281 // This bit is set to '1' by the host controller upon completion of a UIC command.
1283 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1284 Data
= MmioRead32 (Address
);
1285 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1286 if (EFI_ERROR (Status
)) {
1290 if (UicOpcode
!= UfsUicDmeReset
) {
1291 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1292 Data
= MmioRead32 (Address
);
1293 if ((Data
& 0xFF) != 0) {
1295 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1297 return EFI_DEVICE_ERROR
;
1302 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1304 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1305 Data
= MmioRead32 (Address
);
1306 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1307 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1308 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1309 if (EFI_ERROR (Status
)) {
1310 return EFI_DEVICE_ERROR
;
1312 return EFI_NOT_FOUND
;
1315 DEBUG ((EFI_D_INFO
, "UfsblockioPei: found a attached UFS device\n"));
1321 Enable the UFS host controller for accessing.
1323 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1325 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1326 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1330 UfsEnableHostController (
1331 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1339 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1341 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1343 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1344 Data
= MmioRead32 (Address
);
1345 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1347 // Write a 0 to the HCE register at first to disable the host controller.
1349 MmioWrite32 (Address
, 0);
1351 // Wait until HCE is read as '0' before continuing.
1353 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1354 if (EFI_ERROR (Status
)) {
1355 return EFI_DEVICE_ERROR
;
1360 // Write a 1 to the HCE register to enable the UFS host controller.
1362 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1364 // Wait until HCE is read as '1' before continuing.
1366 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1367 if (EFI_ERROR (Status
)) {
1368 return EFI_DEVICE_ERROR
;
1375 Detect if a UFS device attached.
1377 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1379 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1380 @retval EFI_NOT_FOUND Not found a UFS device attached.
1381 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1385 UfsDeviceDetection (
1386 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1393 // Start UFS device detection.
1394 // Try up to 3 times for establishing data link with device.
1396 for (Retry
= 0; Retry
< 3; Retry
++) {
1397 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1398 if (!EFI_ERROR (Status
)) {
1402 if (Status
== EFI_NOT_FOUND
) {
1406 return EFI_DEVICE_ERROR
;
1410 return EFI_NOT_FOUND
;
1417 Initialize UFS task management request list related h/w context.
1419 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1421 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1422 @retval EFI_DEVICE_ERROR The initialization fails.
1426 UfsInitTaskManagementRequestList (
1427 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1434 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1435 VOID
*CmdDescMapping
;
1439 // Initial h/w and s/w context for future operations.
1441 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1442 Data
= MmioRead32 (Address
);
1443 Private
->Capabilities
= Data
;
1446 // Allocate and initialize UTP Task Management Request List.
1448 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1449 Status
= IoMmuAllocateBuffer (
1450 EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
)),
1455 if (EFI_ERROR (Status
)) {
1456 return EFI_DEVICE_ERROR
;
1459 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs
* sizeof (UTP_TMRD
))));
1462 // Program the UTP Task Management Request List Base Address and UTP Task Management
1463 // Request List Base Address with a 64-bit address allocated at step 6.
1465 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1466 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1467 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1468 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1469 Private
->UtpTmrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1470 Private
->Nutmrs
= Nutmrs
;
1471 Private
->TmrlMapping
= CmdDescMapping
;
1474 // Enable the UTP Task Management Request List by setting the UTP Task Management
1475 // Request List RunStop Register (UTMRLRSR) to '1'.
1477 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1478 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1484 Initialize UFS transfer request list related h/w context.
1486 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1488 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1489 @retval EFI_DEVICE_ERROR The initialization fails.
1493 UfsInitTransferRequestList (
1494 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1501 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1502 VOID
*CmdDescMapping
;
1506 // Initial h/w and s/w context for future operations.
1508 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1509 Data
= MmioRead32 (Address
);
1510 Private
->Capabilities
= Data
;
1513 // Allocate and initialize UTP Transfer Request List.
1515 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1516 Status
= IoMmuAllocateBuffer (
1517 EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
)),
1522 if (EFI_ERROR (Status
)) {
1523 return EFI_DEVICE_ERROR
;
1526 ZeroMem (CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs
* sizeof (UTP_TRD
))));
1529 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1530 // Base Address with a 64-bit address allocated at step 8.
1532 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1533 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1534 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1535 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1536 Private
->UtpTrlBase
= (VOID
*)(UINTN
)CmdDescHost
;
1537 Private
->Nutrs
= Nutrs
;
1538 Private
->TrlMapping
= CmdDescMapping
;
1541 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1542 // RunStop Register (UTRLRSR) to '1'.
1544 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1545 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1551 Initialize the UFS host controller.
1553 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1555 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1556 @retval Others A device error occurred while initializing the controller.
1561 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1566 Status
= UfsEnableHostController (Private
);
1567 if (EFI_ERROR (Status
)) {
1568 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status
));
1572 Status
= UfsDeviceDetection (Private
);
1573 if (EFI_ERROR (Status
)) {
1574 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status
));
1578 Status
= UfsInitTaskManagementRequestList (Private
);
1579 if (EFI_ERROR (Status
)) {
1580 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status
));
1584 Status
= UfsInitTransferRequestList (Private
);
1585 if (EFI_ERROR (Status
)) {
1586 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status
));
1588 if (Private
->TmrlMapping
!= NULL
) {
1590 EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)),
1591 Private
->UtpTmrlBase
,
1592 Private
->TmrlMapping
1594 Private
->TmrlMapping
= NULL
;
1600 DEBUG ((EFI_D_INFO
, "UfsDevicePei Finished\n"));
1605 Stop the UFS host controller.
1607 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1609 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1610 @retval Others A device error occurred while stopping the controller.
1615 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
1623 // Enable the UTP Task Management Request List by setting the UTP Task Management
1624 // Request List RunStop Register (UTMRLRSR) to '1'.
1626 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1627 MmioWrite32 (Address
, 0);
1630 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1631 // RunStop Register (UTRLRSR) to '1'.
1633 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1634 MmioWrite32 (Address
, 0);
1637 // Write a 0 to the HCE register in order to disable the host controller.
1639 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1640 Data
= MmioRead32 (Address
);
1641 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1642 MmioWrite32 (Address
, 0);
1645 // Wait until HCE is read as '0' before continuing.
1647 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1648 if (EFI_ERROR (Status
)) {
1649 return EFI_DEVICE_ERROR
;
1652 DEBUG ((EFI_D_INFO
, "UfsDevicePei: Stop the UFS Host Controller\n"));