TianoCore EDK2 master
Loading...
Searching...
No Matches
UfsHci.c
Go to the documentation of this file.
1
8#include "UfsBlockIoPei.h"
9
23EFIAPI
25 IN UINTN Address,
26 IN UINT32 MaskValue,
27 IN UINT32 TestValue,
28 IN UINT64 Timeout
29 )
30{
31 UINT32 Value;
32 UINT64 Delay;
33 BOOLEAN InfiniteWait;
34
35 if (Timeout == 0) {
36 InfiniteWait = TRUE;
37 } else {
38 InfiniteWait = FALSE;
39 }
40
41 Delay = DivU64x32 (Timeout, 10) + 1;
42
43 do {
44 //
45 // Access PCI MMIO space to see if the value is the tested one.
46 //
47 Value = MmioRead32 (Address) & MaskValue;
48
49 if (Value == TestValue) {
50 return EFI_SUCCESS;
51 }
52
53 //
54 // Stall for 1 microseconds.
55 //
57
58 Delay--;
59 } while (InfiniteWait || (Delay > 0));
60
61 return EFI_TIMEOUT;
62}
63
71VOID
73 IN UINT8 UicOpcode,
74 IN UINT8 Result
75 )
76{
77 if (UicOpcode <= UfsUicDmePeerSet) {
78 switch (Result) {
79 case 0x00:
80 break;
81 case 0x01:
82 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
83 break;
84 case 0x02:
85 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
86 break;
87 case 0x03:
88 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
89 break;
90 case 0x04:
91 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
92 break;
93 case 0x05:
94 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
95 break;
96 case 0x06:
97 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
98 break;
99 case 0x07:
100 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
101 break;
102 case 0x08:
103 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
104 break;
105 case 0x09:
106 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));
107 break;
108 case 0x0A:
109 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
110 break;
111 default:
112 ASSERT (FALSE);
113 break;
114 }
115 } else {
116 switch (Result) {
117 case 0x00:
118 break;
119 case 0x01:
120 DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));
121 break;
122 default:
123 ASSERT (FALSE);
124 break;
125 }
126 }
127}
128
135VOID
137 IN UINT8 Result
138 )
139{
140 switch (Result) {
141 case 0xF6:
142 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));
143 break;
144 case 0xF7:
145 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));
146 break;
147 case 0xF8:
148 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));
149 break;
150 case 0xF9:
151 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));
152 break;
153 case 0xFA:
154 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));
155 break;
156 case 0xFB:
157 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));
158 break;
159 case 0xFC:
160 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));
161 break;
162 case 0xFD:
163 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));
164 break;
165 case 0xFE:
166 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));
167 break;
168 case 0xFF:
169 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));
170 break;
171 default:
172 ASSERT (FALSE);
173 break;
174 }
175}
176
185VOID
187 IN OUT UINT8 *Buffer,
188 IN UINT32 BufferSize
189 )
190{
191 UINT32 Index;
192 UINT8 Temp;
193 UINT32 SwapCount;
194
195 SwapCount = BufferSize / 2;
196 for (Index = 0; Index < SwapCount; Index++) {
197 Temp = Buffer[Index];
198 Buffer[Index] = Buffer[BufferSize - 1 - Index];
199 Buffer[BufferSize - 1 - Index] = Temp;
200 }
201}
202
215VOID
217 IN OUT UTP_UPIU_TSF *TsfBase,
218 IN UINT8 Opcode,
219 IN UINT8 DescId OPTIONAL,
220 IN UINT8 Index OPTIONAL,
221 IN UINT8 Selector OPTIONAL,
222 IN UINT16 Length OPTIONAL,
223 IN UINT32 Value OPTIONAL
224 )
225{
226 ASSERT (TsfBase != NULL);
227 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
228
229 TsfBase->Opcode = Opcode;
230 if (Opcode != UtpQueryFuncOpcodeNop) {
231 TsfBase->DescId = DescId;
232 TsfBase->Index = Index;
233 TsfBase->Selector = Selector;
234
235 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
236 SwapLittleEndianToBigEndian ((UINT8 *)&Length, sizeof (Length));
237 TsfBase->Length = Length;
238 }
239
240 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
241 SwapLittleEndianToBigEndian ((UINT8 *)&Value, sizeof (Value));
242 TsfBase->Value = Value;
243 }
244 }
245}
246
263 IN OUT UTP_COMMAND_UPIU *Command,
264 IN UINT8 Lun,
265 IN UINT8 TaskTag,
266 IN UINT8 *Cdb,
267 IN UINT8 CdbLength,
268 IN UFS_DATA_DIRECTION DataDirection,
269 IN UINT32 ExpDataTranLen
270 )
271{
272 UINT8 Flags;
273
274 ASSERT ((Command != NULL) && (Cdb != NULL));
275
276 //
277 // Task attribute is hard-coded to Ordered.
278 //
279 if (DataDirection == UfsDataIn) {
280 Flags = BIT0 | BIT6;
281 } else if (DataDirection == UfsDataOut) {
282 Flags = BIT0 | BIT5;
283 } else {
284 Flags = BIT0;
285 }
286
287 //
288 // Fill UTP COMMAND UPIU associated fields.
289 //
290 Command->TransCode = 0x01;
291 Command->Flags = Flags;
292 Command->Lun = Lun;
293 Command->TaskTag = TaskTag;
294 Command->CmdSet = 0x00;
295 SwapLittleEndianToBigEndian ((UINT8 *)&ExpDataTranLen, sizeof (ExpDataTranLen));
296 Command->ExpDataTranLen = ExpDataTranLen;
297
298 CopyMem (Command->Cdb, Cdb, CdbLength);
299
300 return EFI_SUCCESS;
301}
302
315 IN UTP_TR_PRD *Prdt,
316 IN VOID *Buffer,
317 IN UINT32 BufferSize
318 )
319{
320 UINT32 PrdtIndex;
321 UINT32 RemainingLen;
322 UINT8 *Remaining;
323 UINTN PrdtNumber;
324
325 if ((BufferSize & (BIT0 | BIT1)) != 0) {
326 BufferSize &= ~(BIT0 | BIT1);
327 DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));
328 }
329
330 if (BufferSize == 0) {
331 return EFI_SUCCESS;
332 }
333
334 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
335
336 RemainingLen = BufferSize;
337 Remaining = Buffer;
338 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
339
340 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
341 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
342 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
343 } else {
344 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
345 }
346
347 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
348 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
349 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
350 Remaining += UFS_MAX_DATA_LEN_PER_PRD;
351 }
352
353 return EFI_SUCCESS;
354}
355
373 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,
374 IN UINT8 TaskTag,
375 IN UINT8 Opcode,
376 IN UINT8 DescId,
377 IN UINT8 Index,
378 IN UINT8 Selector,
379 IN UINTN DataSize OPTIONAL,
380 IN UINT8 *Data OPTIONAL
381 )
382{
383 ASSERT (QueryReq != NULL);
384
385 QueryReq->TransCode = 0x16;
386 QueryReq->TaskTag = TaskTag;
387 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
388 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
389 } else {
390 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
391 }
392
393 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
394 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32 *)Data);
395 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
396 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
397 } else {
398 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
399 }
400
401 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
402 CopyMem (QueryReq + 1, Data, DataSize);
403
404 SwapLittleEndianToBigEndian ((UINT8 *)&DataSize, sizeof (UINT16));
405 QueryReq->DataSegLen = (UINT16)DataSize;
406 }
407
408 return EFI_SUCCESS;
409}
410
428 IN UINT8 Lun,
430 IN UTP_TRD *Trd,
431 OUT VOID **BufferMap
432 )
433{
434 UINT8 *CommandDesc;
435 UINTN TotalLen;
436 UINTN PrdtNumber;
437 VOID *Buffer;
438 UINT32 Length;
439 UTP_COMMAND_UPIU *CommandUpiu;
440 UTP_TR_PRD *PrdtBase;
441 UFS_DATA_DIRECTION DataDirection;
442 EFI_STATUS Status;
444 UINTN MapLength;
445 EFI_PHYSICAL_ADDRESS BufferPhyAddr;
446
447 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
448
449 BufferPhyAddr = 0;
450
451 if (Packet->DataDirection == UfsDataIn) {
452 Buffer = Packet->InDataBuffer;
453 Length = Packet->InTransferLength;
454 DataDirection = UfsDataIn;
456 } else {
457 Buffer = Packet->OutDataBuffer;
458 Length = Packet->OutTransferLength;
459 DataDirection = UfsDataOut;
461 }
462
463 if (Length == 0) {
464 DataDirection = UfsNoData;
465 } else {
466 MapLength = Length;
467 Status = IoMmuMap (MapOp, Buffer, &MapLength, &BufferPhyAddr, BufferMap);
468
469 if (EFI_ERROR (Status) || (MapLength != Length)) {
470 DEBUG ((DEBUG_ERROR, "UfsCreateScsiCommandDesc: Fail to map data buffer.\n"));
471 return EFI_OUT_OF_RESOURCES;
472 }
473 }
474
475 PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
476
477 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
478 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
479 if (CommandDesc == NULL) {
480 return EFI_OUT_OF_RESOURCES;
481 }
482
483 CommandUpiu = (UTP_COMMAND_UPIU *)CommandDesc;
484 PrdtBase = (UTP_TR_PRD *)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
485
486 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
487 UfsInitUtpPrdt (PrdtBase, (VOID *)(UINTN)BufferPhyAddr, Length);
488
489 //
490 // Fill UTP_TRD associated fields
491 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
492 // *MUST* be located at a 64-bit aligned boundary.
493 //
494 Trd->Int = UFS_INTERRUPT_COMMAND;
495 Trd->Dd = DataDirection;
496 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
497 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
498 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);
499 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);
500 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
501 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
502 Trd->PrdtL = (UINT16)PrdtNumber;
503 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
504 return EFI_SUCCESS;
505}
506
524 IN UTP_TRD *Trd
525 )
526{
527 UINT8 *CommandDesc;
528 UINTN TotalLen;
529 UTP_QUERY_REQ_UPIU *QueryReqUpiu;
530 UINT8 Opcode;
531 UINT32 DataSize;
532 UINT8 *Data;
533 UINT8 DataDirection;
534
535 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
536
537 Opcode = Packet->Opcode;
538 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
539 return EFI_INVALID_PARAMETER;
540 }
541
542 DataDirection = Packet->DataDirection;
543 if (DataDirection == UfsDataIn) {
544 DataSize = Packet->InTransferLength;
545 Data = Packet->InDataBuffer;
546 } else if (DataDirection == UfsDataOut) {
547 DataSize = Packet->OutTransferLength;
548 Data = Packet->OutDataBuffer;
549 } else {
550 DataSize = 0;
551 Data = NULL;
552 }
553
554 if (((Opcode != UtpQueryFuncOpcodeRdFlag) && (Opcode != UtpQueryFuncOpcodeSetFlag) &&
555 (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag) &&
556 (Opcode != UtpQueryFuncOpcodeRdAttr)) && ((DataSize == 0) || (Data == NULL)))
557 {
558 return EFI_INVALID_PARAMETER;
559 }
560
561 if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {
562 return EFI_INVALID_PARAMETER;
563 }
564
565 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
566 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
567 } else {
568 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
569 }
570
571 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
572 if (CommandDesc == NULL) {
573 return EFI_OUT_OF_RESOURCES;
574 }
575
576 //
577 // Initialize UTP QUERY REQUEST UPIU
578 //
579 QueryReqUpiu = (UTP_QUERY_REQ_UPIU *)CommandDesc;
581 QueryReqUpiu,
582 Private->TaskTag++,
583 Opcode,
584 Packet->DescId,
585 Packet->Index,
586 Packet->Selector,
587 DataSize,
588 Data
589 );
590
591 //
592 // Fill UTP_TRD associated fields
593 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
594 //
595 Trd->Int = UFS_INTERRUPT_COMMAND;
596 Trd->Dd = DataDirection;
597 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
598 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
599 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);
600 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);
601 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
602 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
603 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
604 } else {
605 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
606 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
607 }
608
609 return EFI_SUCCESS;
610}
611
626 IN UTP_TRD *Trd
627 )
628{
629 UINT8 *CommandDesc;
630 UINTN TotalLen;
631 UTP_NOP_OUT_UPIU *NopOutUpiu;
632
633 ASSERT ((Private != NULL) && (Trd != NULL));
634
635 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
636 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
637 if (CommandDesc == NULL) {
638 return EFI_OUT_OF_RESOURCES;
639 }
640
641 NopOutUpiu = (UTP_NOP_OUT_UPIU *)CommandDesc;
642
643 NopOutUpiu->TaskTag = Private->TaskTag++;
644
645 //
646 // Fill UTP_TRD associated fields
647 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
648 //
649 Trd->Int = UFS_INTERRUPT_COMMAND;
650 Trd->Dd = 0x00;
651 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
652 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
653 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);
654 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);
655 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
656 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
657
658 return EFI_SUCCESS;
659}
660
673 OUT UINT8 *Slot
674 )
675{
676 ASSERT ((Private != NULL) && (Slot != NULL));
677
678 //
679 // The simplest algo to always use slot 0.
680 // TODO: enhance it to support async transfer with multiple slot.
681 //
682 *Slot = 0;
683
684 return EFI_SUCCESS;
685}
686
694VOID
697 IN UINT8 Slot
698 )
699{
700 UINTN UfsHcBase;
701 UINTN Address;
702 UINT32 Data;
703
704 UfsHcBase = Private->UfsHcBase;
705
706 Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
707 Data = MmioRead32 (Address);
708 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
709 MmioWrite32 (Address, UFS_HC_UTRLRSR);
710 }
711
712 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
713 MmioWrite32 (Address, BIT0 << Slot);
714}
715
723VOID
726 IN UINT8 Slot
727 )
728{
729 UINTN UfsHcBase;
730 UINTN Address;
731 UINT32 Data;
732
733 UfsHcBase = Private->UfsHcBase;
734
735 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
736 Data = MmioRead32 (Address);
737 if ((Data & (BIT0 << Slot)) != 0) {
738 Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;
739 Data = MmioRead32 (Address);
740 MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));
741 }
742}
743
758 IN UTP_QUERY_RESP_UPIU *QueryResp
759 )
760{
761 UINT16 ReturnDataSize;
762 UINT32 ReturnData;
763
764 ReturnDataSize = 0;
765
766 if ((Packet == NULL) || (QueryResp == NULL)) {
767 return EFI_INVALID_PARAMETER;
768 }
769
770 switch (Packet->Opcode) {
771 case UtpQueryFuncOpcodeRdDesc:
772 ReturnDataSize = QueryResp->Tsf.Length;
773 SwapLittleEndianToBigEndian ((UINT8 *)&ReturnDataSize, sizeof (UINT16));
774 //
775 // Make sure the hardware device does not return more data than expected.
776 //
777 if (ReturnDataSize > Packet->InTransferLength) {
778 return EFI_DEVICE_ERROR;
779 }
780
781 CopyMem (Packet->InDataBuffer, (QueryResp + 1), ReturnDataSize);
782 Packet->InTransferLength = ReturnDataSize;
783 break;
784 case UtpQueryFuncOpcodeWrDesc:
785 ReturnDataSize = QueryResp->Tsf.Length;
786 SwapLittleEndianToBigEndian ((UINT8 *)&ReturnDataSize, sizeof (UINT16));
787 Packet->OutTransferLength = ReturnDataSize;
788 break;
789 case UtpQueryFuncOpcodeRdFlag:
790 //
791 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
792 //
793 *((UINT8 *)(Packet->InDataBuffer)) = *((UINT8 *)&(QueryResp->Tsf.Value) + 3);
794 break;
795 case UtpQueryFuncOpcodeSetFlag:
796 case UtpQueryFuncOpcodeClrFlag:
797 case UtpQueryFuncOpcodeTogFlag:
798 //
799 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
800 //
801 *((UINT8 *)(Packet->OutDataBuffer)) = *((UINT8 *)&(QueryResp->Tsf.Value) + 3);
802 break;
803 case UtpQueryFuncOpcodeRdAttr:
804 ReturnData = QueryResp->Tsf.Value;
805 SwapLittleEndianToBigEndian ((UINT8 *)&ReturnData, sizeof (UINT32));
806 CopyMem (Packet->InDataBuffer, &ReturnData, sizeof (UINT32));
807 break;
808 case UtpQueryFuncOpcodeWrAttr:
809 ReturnData = QueryResp->Tsf.Value;
810 SwapLittleEndianToBigEndian ((UINT8 *)&ReturnData, sizeof (UINT32));
811 CopyMem (Packet->OutDataBuffer, &ReturnData, sizeof (UINT32));
812 break;
813 default:
814 return EFI_INVALID_PARAMETER;
815 }
816
817 return EFI_SUCCESS;
818}
819
837 )
838{
839 UINT8 Slot;
840 EFI_STATUS Status;
841 UTP_TRD *Trd;
842 UINTN Address;
843 UTP_QUERY_RESP_UPIU *QueryResp;
844 UINT8 *CmdDescBase;
845 UINT32 CmdDescSize;
846
847 // Workaround: Adding this one second for reading descriptor
848 MicroSecondDelay (1 * 1000 * 1000); // delay 1 seconds
849
850 // Find out which slot of transfer request list is available.
851 //
852 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
853 if (EFI_ERROR (Status)) {
854 return Status;
855 }
856
857 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;
858 //
859 // Fill transfer request descriptor to this slot.
860 //
861 Status = UfsCreateDMCommandDesc (Private, Packet, Trd);
862 if (EFI_ERROR (Status)) {
863 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));
864 return Status;
865 }
866
867 //
868 // Check the transfer request result.
869 //
870 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
871 QueryResp = (UTP_QUERY_RESP_UPIU *)(CmdDescBase + Trd->RuO * sizeof (UINT32));
872 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
873
874 //
875 // Start to execute the transfer request.
876 //
877 UfsStartExecCmd (Private, Slot);
878
879 //
880 // Wait for the completion of the transfer request.
881 //
882 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
883 Status = UfsWaitMemSet (Address, (BIT0 << Slot), 0, Packet->Timeout);
884 if (EFI_ERROR (Status)) {
885 goto Exit;
886 }
887
888 if ((Trd->Ocs != 0) || (QueryResp->QueryResp != UfsUtpQueryResponseSuccess)) {
889 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));
890 DumpQueryResponseResult (QueryResp->QueryResp);
891 Status = EFI_DEVICE_ERROR;
892 goto Exit;
893 }
894
895 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);
896 if (EFI_ERROR (Status)) {
897 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));
898 goto Exit;
899 }
900
901Exit:
902 UfsStopExecCmd (Private, Slot);
903 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
904
905 return Status;
906}
907
925 )
926{
927 EFI_STATUS Status;
928 UINT8 Retry;
929
930 Status = EFI_SUCCESS;
931
932 for (Retry = 0; Retry < 5; Retry++) {
933 Status = UfsSendDmRequestRetry (Private, Packet);
934 if (!EFI_ERROR (Status)) {
935 return EFI_SUCCESS;
936 }
937 }
938
939 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));
940 return Status;
941}
942
962 IN BOOLEAN Read,
963 IN UINT8 DescId,
964 IN UINT8 Index,
965 IN UINT8 Selector,
966 IN OUT VOID *Descriptor,
967 IN UINT32 DescSize
968 )
969{
970 EFI_STATUS Status;
972
974
975 if (Read) {
976 Packet.DataDirection = UfsDataIn;
977 Packet.InDataBuffer = Descriptor;
978 Packet.InTransferLength = DescSize;
979 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
980 } else {
981 Packet.DataDirection = UfsDataOut;
982 Packet.OutDataBuffer = Descriptor;
983 Packet.OutTransferLength = DescSize;
984 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
985 }
986
987 Packet.DescId = DescId;
988 Packet.Index = Index;
989 Packet.Selector = Selector;
990 Packet.Timeout = UFS_TIMEOUT;
991
992 Status = UfsSendDmRequest (Private, &Packet);
993 return Status;
994}
995
1016 IN BOOLEAN Read,
1017 IN UINT8 AttrId,
1018 IN UINT8 Index,
1019 IN UINT8 Selector,
1020 IN OUT UINT32 *Attributes
1021 )
1022{
1024
1026
1027 if (Read) {
1028 Packet.DataDirection = UfsDataIn;
1029 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
1030 Packet.InDataBuffer = Attributes;
1031 } else {
1032 Packet.DataDirection = UfsDataOut;
1033 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
1034 Packet.OutDataBuffer = Attributes;
1035 Packet.OutTransferLength = sizeof (UINT32);
1036 }
1037
1038 Packet.DescId = AttrId;
1039 Packet.Index = Index;
1040 Packet.Selector = Selector;
1041 Packet.Timeout = UFS_TIMEOUT;
1042
1043 return UfsSendDmRequest (Private, &Packet);
1044}
1045
1062 IN BOOLEAN Read,
1063 IN UINT8 FlagId,
1064 IN OUT UINT8 *Value
1065 )
1066{
1067 EFI_STATUS Status;
1069
1070 if (Value == NULL) {
1071 return EFI_INVALID_PARAMETER;
1072 }
1073
1075
1076 if (Read) {
1077 ASSERT (Value != NULL);
1078 Packet.DataDirection = UfsDataIn;
1079 Packet.InDataBuffer = (VOID *)Value;
1080 Packet.InTransferLength = 0;
1081 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1082 } else {
1083 Packet.DataDirection = UfsDataOut;
1084 Packet.OutDataBuffer = (VOID *)Value;
1085 Packet.OutTransferLength = 0;
1086 if (*Value == 1) {
1087 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1088 } else if (*Value == 0) {
1089 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1090 } else {
1091 return EFI_INVALID_PARAMETER;
1092 }
1093 }
1094
1095 Packet.DescId = FlagId;
1096 Packet.Index = 0;
1097 Packet.Selector = 0;
1098 Packet.Timeout = UFS_TIMEOUT;
1099
1100 Status = UfsSendDmRequest (Private, &Packet);
1101
1102 return Status;
1103}
1104
1119 IN UINT8 FlagId
1120 )
1121{
1122 EFI_STATUS Status;
1123 UINT8 Value;
1124
1125 Value = 1;
1126 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1127
1128 return Status;
1129}
1130
1146 IN UINT8 FlagId,
1147 OUT UINT8 *Value
1148 )
1149{
1150 EFI_STATUS Status;
1151
1152 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1153
1154 return Status;
1155}
1156
1173 )
1174{
1175 EFI_STATUS Status;
1176 UINT8 Slot;
1177 UTP_TRD *Trd;
1178 UTP_NOP_IN_UPIU *NopInUpiu;
1179 UINT8 *CmdDescBase;
1180 UINT32 CmdDescSize;
1181 UINTN Address;
1182
1183 //
1184 // Find out which slot of transfer request list is available.
1185 //
1186 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1187 if (EFI_ERROR (Status)) {
1188 return Status;
1189 }
1190
1191 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;
1192 Status = UfsCreateNopCommandDesc (Private, Trd);
1193 if (EFI_ERROR (Status)) {
1194 return Status;
1195 }
1196
1197 //
1198 // Check the transfer request result.
1199 //
1200 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1201 NopInUpiu = (UTP_NOP_IN_UPIU *)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1202 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1203
1204 //
1205 // Start to execute the transfer request.
1206 //
1207 UfsStartExecCmd (Private, Slot);
1208
1209 //
1210 // Wait for the completion of the transfer request.
1211 //
1212 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1213 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);
1214 if (EFI_ERROR (Status)) {
1215 goto Exit;
1216 }
1217
1218 if (NopInUpiu->Resp != 0) {
1219 Status = EFI_DEVICE_ERROR;
1220 } else {
1221 Status = EFI_SUCCESS;
1222 }
1223
1224Exit:
1225 UfsStopExecCmd (Private, Slot);
1226 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1227
1228 return Status;
1229}
1230
1253 IN UINT8 Lun,
1255 )
1256{
1257 EFI_STATUS Status;
1258 UINT8 Slot;
1259 UTP_TRD *Trd;
1260 UINTN Address;
1261 UINT8 *CmdDescBase;
1262 UINT32 CmdDescSize;
1263 UTP_RESPONSE_UPIU *Response;
1264 UINT16 SenseDataLen;
1265 UINT32 ResTranCount;
1266 VOID *PacketBufferMap;
1267
1268 //
1269 // Find out which slot of transfer request list is available.
1270 //
1271 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1272 if (EFI_ERROR (Status)) {
1273 return Status;
1274 }
1275
1276 Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;
1277 PacketBufferMap = NULL;
1278
1279 //
1280 // Fill transfer request descriptor to this slot.
1281 //
1282 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &PacketBufferMap);
1283 if (EFI_ERROR (Status)) {
1284 return Status;
1285 }
1286
1287 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1288 CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);
1289
1290 //
1291 // Start to execute the transfer request.
1292 //
1293 UfsStartExecCmd (Private, Slot);
1294
1295 //
1296 // Wait for the completion of the transfer request.
1297 //
1298 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1299 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);
1300 if (EFI_ERROR (Status)) {
1301 goto Exit;
1302 }
1303
1304 //
1305 // Get sense data if exists
1306 //
1307 Response = (UTP_RESPONSE_UPIU *)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1308 SenseDataLen = Response->SenseDataLen;
1309 SwapLittleEndianToBigEndian ((UINT8 *)&SenseDataLen, sizeof (UINT16));
1310
1311 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1312 //
1313 // Make sure the hardware device does not return more data than expected.
1314 //
1315 if (SenseDataLen <= Packet->SenseDataLength) {
1316 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1317 Packet->SenseDataLength = (UINT8)SenseDataLen;
1318 } else {
1319 Packet->SenseDataLength = 0;
1320 }
1321 }
1322
1323 //
1324 // Check the transfer request result.
1325 //
1326 if (Response->Response != 0) {
1327 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1328 Status = EFI_DEVICE_ERROR;
1329 goto Exit;
1330 }
1331
1332 if (Trd->Ocs == 0) {
1333 if (Packet->DataDirection == UfsDataIn) {
1334 if ((Response->Flags & BIT5) == BIT5) {
1335 ResTranCount = Response->ResTranCount;
1336 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));
1337 Packet->InTransferLength -= ResTranCount;
1338 }
1339 } else if (Packet->DataDirection == UfsDataOut) {
1340 if ((Response->Flags & BIT5) == BIT5) {
1341 ResTranCount = Response->ResTranCount;
1342 SwapLittleEndianToBigEndian ((UINT8 *)&ResTranCount, sizeof (UINT32));
1343 Packet->OutTransferLength -= ResTranCount;
1344 }
1345 }
1346 } else {
1347 Status = EFI_DEVICE_ERROR;
1348 }
1349
1350Exit:
1351 if (PacketBufferMap != NULL) {
1352 IoMmuUnmap (PacketBufferMap);
1353 }
1354
1355 UfsStopExecCmd (Private, Slot);
1356 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1357
1358 return Status;
1359}
1360
1378 IN UINT8 UicOpcode,
1379 IN UINT32 Arg1,
1380 IN UINT32 Arg2,
1381 IN UINT32 Arg3
1382 )
1383{
1384 EFI_STATUS Status;
1385 UINTN Address;
1386 UINT32 Data;
1387 UINTN UfsHcBase;
1388
1389 UfsHcBase = Private->UfsHcBase;
1390 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1391 Data = MmioRead32 (Address);
1392 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1393 //
1394 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1395 //
1396 MmioWrite32 (Address, Data);
1397 }
1398
1399 //
1400 // When programming UIC command registers, host software shall set the register UICCMD
1401 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1402 // are set.
1403 //
1404 Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;
1405 MmioWrite32 (Address, Arg1);
1406
1407 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1408 MmioWrite32 (Address, Arg2);
1409
1410 Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;
1411 MmioWrite32 (Address, Arg3);
1412
1413 //
1414 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1415 //
1416 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
1417 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1418 if (EFI_ERROR (Status)) {
1419 return Status;
1420 }
1421
1422 Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;
1423 MmioWrite32 (Address, (UINT32)UicOpcode);
1424
1425 //
1426 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1427 // This bit is set to '1' by the host controller upon completion of a UIC command.
1428 //
1429 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1430 Data = MmioRead32 (Address);
1431 Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1432 if (EFI_ERROR (Status)) {
1433 return Status;
1434 }
1435
1436 if (UicOpcode != UfsUicDmeReset) {
1437 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1438 Data = MmioRead32 (Address);
1439 if ((Data & 0xFF) != 0) {
1441 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
1442 DEBUG_CODE_END ();
1443 return EFI_DEVICE_ERROR;
1444 }
1445 }
1446
1447 return EFI_SUCCESS;
1448}
1449
1462 IN EDKII_UFS_HC_PLATFORM_PPI *UfsHcPlatformPpi,
1464 )
1465{
1466 EFI_STATUS Status;
1467 UINTN Address;
1468 UINT32 Data;
1469
1470 if ((UfsHcPlatformPpi != NULL) && (UfsHcPlatformPpi->Callback != NULL)) {
1471 Status = UfsHcPlatformPpi->Callback (&Private->UfsHcBase, EdkiiUfsHcPreHce);
1472 if (EFI_ERROR (Status)) {
1473 DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPreHce, Status = %r\n", Status));
1474 return Status;
1475 }
1476 }
1477
1478 //
1479 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1480 //
1481 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1482 //
1483 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1484 Data = MmioRead32 (Address);
1485 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1486 //
1487 // Write a 0 to the HCE register at first to disable the host controller.
1488 //
1489 MmioWrite32 (Address, 0);
1490 //
1491 // Wait until HCE is read as '0' before continuing.
1492 //
1493 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1494 if (EFI_ERROR (Status)) {
1495 return EFI_DEVICE_ERROR;
1496 }
1497 }
1498
1499 //
1500 // Write a 1 to the HCE register to enable the UFS host controller.
1501 //
1502 MmioWrite32 (Address, UFS_HC_HCE_EN);
1503 //
1504 // Wait until HCE is read as '1' before continuing.
1505 //
1506 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1507 if (EFI_ERROR (Status)) {
1508 return EFI_DEVICE_ERROR;
1509 }
1510
1511 if ((UfsHcPlatformPpi != NULL) && (UfsHcPlatformPpi->Callback != NULL)) {
1512 Status = UfsHcPlatformPpi->Callback (&Private->UfsHcBase, EdkiiUfsHcPostHce);
1513 if (EFI_ERROR (Status)) {
1514 DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPostHce, Status = %r\n", Status));
1515 return Status;
1516 }
1517 }
1518
1519 return EFI_SUCCESS;
1520}
1521
1534 IN EDKII_UFS_HC_PLATFORM_PPI *UfsHcPlatformPpi,
1536 )
1537{
1538 UINTN Retry;
1539 UINTN Address;
1540 UINT32 Data;
1541 EFI_STATUS Status;
1542
1543 if ((UfsHcPlatformPpi != NULL) && (UfsHcPlatformPpi->Callback != NULL)) {
1544 Status = UfsHcPlatformPpi->Callback (&Private->UfsHcBase, EdkiiUfsHcPreLinkStartup);
1545 if (EFI_ERROR (Status)) {
1546 DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPreLinkStartup, Status = %r\n", Status));
1547 return Status;
1548 }
1549 }
1550
1551 //
1552 // Start UFS device detection.
1553 // Try up to 3 times for establishing data link with device.
1554 //
1555 for (Retry = 0; Retry < 3; Retry++) {
1556 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
1557 if (EFI_ERROR (Status)) {
1558 return EFI_DEVICE_ERROR;
1559 }
1560
1561 //
1562 // Check value of HCS.DP and make sure that there is a device attached to the Link
1563 //
1564 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
1565 Data = MmioRead32 (Address);
1566 if ((Data & UFS_HC_HCS_DP) == 0) {
1567 Address = Private->UfsHcBase + UFS_HC_IS_OFFSET;
1568 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1569 if (EFI_ERROR (Status)) {
1570 return EFI_DEVICE_ERROR;
1571 }
1572 } else {
1573 DEBUG ((DEBUG_INFO, "UfsblockioPei: found a attached UFS device\n"));
1574 return EFI_SUCCESS;
1575 }
1576 }
1577
1578 return EFI_NOT_FOUND;
1579}
1580
1593 )
1594{
1595 UINTN Address;
1596 UINT32 Data;
1597 UINT8 Nutmrs;
1598 VOID *CmdDescHost;
1599 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1600 VOID *CmdDescMapping;
1601 EFI_STATUS Status;
1602
1603 //
1604 // Initial h/w and s/w context for future operations.
1605 //
1606 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1607 Data = MmioRead32 (Address);
1608 Private->Capabilities = Data;
1609
1610 //
1611 // Allocate and initialize UTP Task Management Request List.
1612 //
1613 Nutmrs = (UINT8)(RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1614 Status = IoMmuAllocateBuffer (
1615 EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
1616 &CmdDescHost,
1617 &CmdDescPhyAddr,
1618 &CmdDescMapping
1619 );
1620 if (EFI_ERROR (Status)) {
1621 return EFI_DEVICE_ERROR;
1622 }
1623
1624 ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
1625
1626 //
1627 // Program the UTP Task Management Request List Base Address and UTP Task Management
1628 // Request List Base Address with a 64-bit address allocated at step 6.
1629 //
1630 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;
1631 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
1632 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;
1633 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
1634 Private->UtpTmrlBase = (VOID *)(UINTN)CmdDescHost;
1635 Private->Nutmrs = Nutmrs;
1636 Private->TmrlMapping = CmdDescMapping;
1637
1638 //
1639 // Enable the UTP Task Management Request List by setting the UTP Task Management
1640 // Request List RunStop Register (UTMRLRSR) to '1'.
1641 //
1642 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1643 MmioWrite32 (Address, UFS_HC_UTMRLRSR);
1644
1645 return EFI_SUCCESS;
1646}
1647
1660 )
1661{
1662 UINTN Address;
1663 UINT32 Data;
1664 UINT8 Nutrs;
1665 VOID *CmdDescHost;
1666 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1667 VOID *CmdDescMapping;
1668 EFI_STATUS Status;
1669
1670 //
1671 // Initial h/w and s/w context for future operations.
1672 //
1673 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1674 Data = MmioRead32 (Address);
1675 Private->Capabilities = Data;
1676
1677 //
1678 // Allocate and initialize UTP Transfer Request List.
1679 //
1680 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
1681 Status = IoMmuAllocateBuffer (
1682 EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
1683 &CmdDescHost,
1684 &CmdDescPhyAddr,
1685 &CmdDescMapping
1686 );
1687 if (EFI_ERROR (Status)) {
1688 return EFI_DEVICE_ERROR;
1689 }
1690
1691 ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
1692
1693 //
1694 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1695 // Base Address with a 64-bit address allocated at step 8.
1696 //
1697 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;
1698 MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
1699 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;
1700 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
1701 Private->UtpTrlBase = (VOID *)(UINTN)CmdDescHost;
1702 Private->Nutrs = Nutrs;
1703 Private->TrlMapping = CmdDescMapping;
1704
1705 //
1706 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1707 // RunStop Register (UTRLRSR) to '1'.
1708 //
1709 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1710 MmioWrite32 (Address, UFS_HC_UTRLRSR);
1711
1712 return EFI_SUCCESS;
1713}
1714
1727 IN EDKII_UFS_HC_PLATFORM_PPI *UfsHcPlatformPpi,
1729 )
1730{
1731 EFI_STATUS Status;
1732
1733 Status = UfsEnableHostController (UfsHcPlatformPpi, Private);
1734 if (EFI_ERROR (Status)) {
1735 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));
1736 return Status;
1737 }
1738
1739 Status = UfsDeviceDetection (UfsHcPlatformPpi, Private);
1740 if (EFI_ERROR (Status)) {
1741 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));
1742 return Status;
1743 }
1744
1745 Status = UfsInitTaskManagementRequestList (Private);
1746 if (EFI_ERROR (Status)) {
1747 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));
1748 return Status;
1749 }
1750
1751 Status = UfsInitTransferRequestList (Private);
1752 if (EFI_ERROR (Status)) {
1753 DEBUG ((DEBUG_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
1754
1755 if (Private->TmrlMapping != NULL) {
1757 EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),
1758 Private->UtpTmrlBase,
1759 Private->TmrlMapping
1760 );
1761 Private->TmrlMapping = NULL;
1762 }
1763
1764 return Status;
1765 }
1766
1767 DEBUG ((DEBUG_INFO, "UfsDevicePei Finished\n"));
1768 return EFI_SUCCESS;
1769}
1770
1783 )
1784{
1785 EFI_STATUS Status;
1786 UINTN Address;
1787 UINT32 Data;
1788
1789 //
1790 // Enable the UTP Task Management Request List by setting the UTP Task Management
1791 // Request List RunStop Register (UTMRLRSR) to '1'.
1792 //
1793 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1794 MmioWrite32 (Address, 0);
1795
1796 //
1797 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1798 // RunStop Register (UTRLRSR) to '1'.
1799 //
1800 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1801 MmioWrite32 (Address, 0);
1802
1803 //
1804 // Write a 0 to the HCE register in order to disable the host controller.
1805 //
1806 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1807 Data = MmioRead32 (Address);
1808 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
1809 MmioWrite32 (Address, 0);
1810
1811 //
1812 // Wait until HCE is read as '0' before continuing.
1813 //
1814 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1815 if (EFI_ERROR (Status)) {
1816 return EFI_DEVICE_ERROR;
1817 }
1818
1819 DEBUG ((DEBUG_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));
1820
1821 return EFI_SUCCESS;
1822}
UINT64 UINTN
EFI_STATUS IoMmuUnmap(IN VOID *Mapping)
Definition: DmaMem.c:132
EFI_STATUS IoMmuAllocateBuffer(IN UINTN Pages, OUT VOID **HostAddress, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: DmaMem.c:170
EFI_STATUS IoMmuMap(IN EDKII_IOMMU_OPERATION Operation, IN VOID *HostAddress, IN OUT UINTN *NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: DmaMem.c:60
EFI_STATUS IoMmuFreeBuffer(IN UINTN Pages, IN VOID *HostAddress, IN VOID *Mapping)
Definition: DmaMem.c:251
UINTN EFIAPI MicroSecondDelay(IN UINTN MicroSeconds)
UINT64 EFIAPI DivU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
Definition: DivU64x32.c:29
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition: IoLib.c:262
UINT32 EFIAPI MmioWrite32(IN UINTN Address, IN UINT32 Value)
Definition: IoLib.c:309
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG_CODE_BEGIN()
Definition: DebugLib.h:564
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define DEBUG_CODE_END()
Definition: DebugLib.h:578
EDKII_IOMMU_OPERATION
Definition: IoMmu.h:44
@ EdkiiIoMmuOperationBusMasterWrite
Definition: IoMmu.h:54
@ EdkiiIoMmuOperationBusMasterRead
Definition: IoMmu.h:49
VOID EFIAPI Exit(IN EFI_STATUS Status)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
VOID * UfsPeimAllocateMem(IN UFS_PEIM_MEM_POOL *Pool, IN UINTN Size)
Definition: UfsHcMem.c:295
VOID UfsPeimFreeMem(IN UFS_PEIM_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UfsHcMem.c:367
EFI_STATUS UfsCreateNopCommandDesc(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UTP_TRD *Trd)
Definition: UfsHci.c:624
EFI_STATUS UfsGetReturnDataFromQueryResponse(IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet, IN UTP_QUERY_RESP_UPIU *QueryResp)
Definition: UfsHci.c:756
VOID UfsStopExecCmd(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UINT8 Slot)
Definition: UfsHci.c:724
EFI_STATUS EFIAPI UfsWaitMemSet(IN UINTN Address, IN UINT32 MaskValue, IN UINT32 TestValue, IN UINT64 Timeout)
Definition: UfsHci.c:24
EFI_STATUS UfsRwDeviceDesc(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN BOOLEAN Read, IN UINT8 DescId, IN UINT8 Index, IN UINT8 Selector, IN OUT VOID *Descriptor, IN UINT32 DescSize)
Definition: UfsHci.c:960
EFI_STATUS UfsInitTransferRequestList(IN UFS_PEIM_HC_PRIVATE_DATA *Private)
Definition: UfsHci.c:1658
EFI_STATUS UfsRwAttributes(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN BOOLEAN Read, IN UINT8 AttrId, IN UINT8 Index, IN UINT8 Selector, IN OUT UINT32 *Attributes)
Definition: UfsHci.c:1014
EFI_STATUS UfsFindAvailableSlotInTrl(IN UFS_PEIM_HC_PRIVATE_DATA *Private, OUT UINT8 *Slot)
Definition: UfsHci.c:671
VOID SwapLittleEndianToBigEndian(IN OUT UINT8 *Buffer, IN UINT32 BufferSize)
Definition: UfsHci.c:186
EFI_STATUS UfsReadFlag(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UINT8 FlagId, OUT UINT8 *Value)
Definition: UfsHci.c:1144
EFI_STATUS UfsCreateScsiCommandDesc(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UINT8 Lun, IN UFS_SCSI_REQUEST_PACKET *Packet, IN UTP_TRD *Trd, OUT VOID **BufferMap)
Definition: UfsHci.c:426
EFI_STATUS UfsExecNopCmds(IN UFS_PEIM_HC_PRIVATE_DATA *Private)
Definition: UfsHci.c:1171
EFI_STATUS UfsSendDmRequest(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet)
Definition: UfsHci.c:922
VOID UfsFillTsfOfQueryReqUpiu(IN OUT UTP_UPIU_TSF *TsfBase, IN UINT8 Opcode, IN UINT8 DescId OPTIONAL, IN UINT8 Index OPTIONAL, IN UINT8 Selector OPTIONAL, IN UINT16 Length OPTIONAL, IN UINT32 Value OPTIONAL)
Definition: UfsHci.c:216
VOID DumpUicCmdExecResult(IN UINT8 UicOpcode, IN UINT8 Result)
Definition: UfsHci.c:72
EFI_STATUS UfsInitUtpPrdt(IN UTP_TR_PRD *Prdt, IN VOID *Buffer, IN UINT32 BufferSize)
Definition: UfsHci.c:314
EFI_STATUS UfsControllerInit(IN EDKII_UFS_HC_PLATFORM_PPI *UfsHcPlatformPpi, IN UFS_PEIM_HC_PRIVATE_DATA *Private)
Definition: UfsHci.c:1726
EFI_STATUS UfsSendDmRequestRetry(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet)
Definition: UfsHci.c:834
EFI_STATUS UfsRwFlags(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN BOOLEAN Read, IN UINT8 FlagId, IN OUT UINT8 *Value)
Definition: UfsHci.c:1060
EFI_STATUS UfsInitCommandUpiu(IN OUT UTP_COMMAND_UPIU *Command, IN UINT8 Lun, IN UINT8 TaskTag, IN UINT8 *Cdb, IN UINT8 CdbLength, IN UFS_DATA_DIRECTION DataDirection, IN UINT32 ExpDataTranLen)
Definition: UfsHci.c:262
EFI_STATUS UfsDeviceDetection(IN EDKII_UFS_HC_PLATFORM_PPI *UfsHcPlatformPpi, IN UFS_PEIM_HC_PRIVATE_DATA *Private)
Definition: UfsHci.c:1533
EFI_STATUS UfsControllerStop(IN UFS_PEIM_HC_PRIVATE_DATA *Private)
Definition: UfsHci.c:1781
EFI_STATUS UfsEnableHostController(IN EDKII_UFS_HC_PLATFORM_PPI *UfsHcPlatformPpi, IN UFS_PEIM_HC_PRIVATE_DATA *Private)
Definition: UfsHci.c:1461
VOID UfsStartExecCmd(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UINT8 Slot)
Definition: UfsHci.c:695
EFI_STATUS UfsInitTaskManagementRequestList(IN UFS_PEIM_HC_PRIVATE_DATA *Private)
Definition: UfsHci.c:1591
EFI_STATUS UfsSetFlag(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UINT8 FlagId)
Definition: UfsHci.c:1117
EFI_STATUS UfsExecUicCommands(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UINT8 UicOpcode, IN UINT32 Arg1, IN UINT32 Arg2, IN UINT32 Arg3)
Definition: UfsHci.c:1376
VOID DumpQueryResponseResult(IN UINT8 Result)
Definition: UfsHci.c:136
EFI_STATUS UfsCreateDMCommandDesc(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet, IN UTP_TRD *Trd)
Definition: UfsHci.c:521
EFI_STATUS UfsExecScsiCmds(IN UFS_PEIM_HC_PRIVATE_DATA *Private, IN UINT8 Lun, IN OUT UFS_SCSI_REQUEST_PACKET *Packet)
Definition: UfsHci.c:1251
EFI_STATUS UfsInitQueryRequestUpiu(IN OUT UTP_QUERY_REQ_UPIU *QueryReq, IN UINT8 TaskTag, IN UINT8 Opcode, IN UINT8 DescId, IN UINT8 Index, IN UINT8 Selector, IN UINTN DataSize OPTIONAL, IN UINT8 *Data OPTIONAL)
Definition: UfsHci.c:372