]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
MdeModulePkg/UfsBlockIoPei: fix initialize OCS value to 0x0F
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsBlockIoPei / UfsHci.c
1 /** @file
2
3 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php.
8
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.
11
12 **/
13
14 #include "UfsBlockIoPei.h"
15
16 /**
17 Wait for the value of the specified system memory set to the test value.
18
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.
23
24 @retval EFI_TIMEOUT The system memory setting is time out.
25 @retval EFI_SUCCESS The system memory is correct set.
26
27 **/
28 EFI_STATUS
29 EFIAPI
30 UfsWaitMemSet (
31 IN UINTN Address,
32 IN UINT32 MaskValue,
33 IN UINT32 TestValue,
34 IN UINT64 Timeout
35 )
36 {
37 UINT32 Value;
38 UINT64 Delay;
39 BOOLEAN InfiniteWait;
40
41 if (Timeout == 0) {
42 InfiniteWait = TRUE;
43 } else {
44 InfiniteWait = FALSE;
45 }
46
47 Delay = DivU64x32 (Timeout, 10) + 1;
48
49 do {
50 //
51 // Access PCI MMIO space to see if the value is the tested one.
52 //
53 Value = MmioRead32 (Address) & MaskValue;
54
55 if (Value == TestValue) {
56 return EFI_SUCCESS;
57 }
58
59 //
60 // Stall for 1 microseconds.
61 //
62 MicroSecondDelay (1);
63
64 Delay--;
65
66 } while (InfiniteWait || (Delay > 0));
67
68 return EFI_TIMEOUT;
69 }
70
71 /**
72 Dump UIC command execution result for debugging.
73
74 @param[in] UicOpcode The executed UIC opcode.
75 @param[in] Result The result to be parsed.
76
77 **/
78 VOID
79 DumpUicCmdExecResult (
80 IN UINT8 UicOpcode,
81 IN UINT8 Result
82 )
83 {
84 if (UicOpcode <= UfsUicDmePeerSet) {
85 switch (Result) {
86 case 0x00:
87 break;
88 case 0x01:
89 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
90 break;
91 case 0x02:
92 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
93 break;
94 case 0x03:
95 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
96 break;
97 case 0x04:
98 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
99 break;
100 case 0x05:
101 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
102 break;
103 case 0x06:
104 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
105 break;
106 case 0x07:
107 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
108 break;
109 case 0x08:
110 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
111 break;
112 case 0x09:
113 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BUSY\n"));
114 break;
115 case 0x0A:
116 DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
117 break;
118 default :
119 ASSERT (FALSE);
120 break;
121 }
122 } else {
123 switch (Result) {
124 case 0x00:
125 break;
126 case 0x01:
127 DEBUG ((EFI_D_VERBOSE, "UIC control command fails - FAILURE\n"));
128 break;
129 default :
130 ASSERT (FALSE);
131 break;
132 }
133 }
134 }
135
136 /**
137 Dump QUERY RESPONSE UPIU result for debugging.
138
139 @param[in] Result The result to be parsed.
140
141 **/
142 VOID
143 DumpQueryResponseResult (
144 IN UINT8 Result
145 )
146 {
147 switch (Result) {
148 case 0xF6:
149 DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Readable\n"));
150 break;
151 case 0xF7:
152 DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Writeable\n"));
153 break;
154 case 0xF8:
155 DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Already Written\n"));
156 break;
157 case 0xF9:
158 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Length\n"));
159 break;
160 case 0xFA:
161 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Value\n"));
162 break;
163 case 0xFB:
164 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Selector\n"));
165 break;
166 case 0xFC:
167 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Index\n"));
168 break;
169 case 0xFD:
170 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Idn\n"));
171 break;
172 case 0xFE:
173 DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Opcode\n"));
174 break;
175 case 0xFF:
176 DEBUG ((EFI_D_VERBOSE, "Query Response with General Failure\n"));
177 break;
178 default :
179 ASSERT (FALSE);
180 break;
181 }
182 }
183
184 /**
185 Swap little endian to big endian.
186
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.
190
191 **/
192 VOID
193 SwapLittleEndianToBigEndian (
194 IN OUT UINT8 *Buffer,
195 IN UINT32 BufferSize
196 )
197 {
198 UINT32 Index;
199 UINT8 Temp;
200 UINT32 SwapCount;
201
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;
207 }
208 }
209
210 /**
211 Fill TSF field of QUERY REQUEST UPIU.
212
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.
220
221 **/
222 VOID
223 UfsFillTsfOfQueryReqUpiu (
224 IN OUT UTP_UPIU_TSF *TsfBase,
225 IN UINT8 Opcode,
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
231 )
232 {
233 ASSERT (TsfBase != NULL);
234 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
235
236 TsfBase->Opcode = Opcode;
237 if (Opcode != UtpQueryFuncOpcodeNop) {
238 TsfBase->DescId = DescId;
239 TsfBase->Index = Index;
240 TsfBase->Selector = Selector;
241
242 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
243 SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));
244 TsfBase->Length = Length;
245 }
246
247 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
248 SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));
249 TsfBase->Value = Value;
250 }
251 }
252 }
253
254 /**
255 Initialize COMMAND UPIU.
256
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.
264
265 @retval EFI_SUCCESS The initialization succeed.
266
267 **/
268 EFI_STATUS
269 UfsInitCommandUpiu (
270 IN OUT UTP_COMMAND_UPIU *Command,
271 IN UINT8 Lun,
272 IN UINT8 TaskTag,
273 IN UINT8 *Cdb,
274 IN UINT8 CdbLength,
275 IN UFS_DATA_DIRECTION DataDirection,
276 IN UINT32 ExpDataTranLen
277 )
278 {
279 UINT8 Flags;
280
281 ASSERT ((Command != NULL) && (Cdb != NULL));
282
283 //
284 // Task attribute is hard-coded to Ordered.
285 //
286 if (DataDirection == UfsDataIn) {
287 Flags = BIT0 | BIT6;
288 } else if (DataDirection == UfsDataOut) {
289 Flags = BIT0 | BIT5;
290 } else {
291 Flags = BIT0;
292 }
293
294 //
295 // Fill UTP COMMAND UPIU associated fields.
296 //
297 Command->TransCode = 0x01;
298 Command->Flags = Flags;
299 Command->Lun = Lun;
300 Command->TaskTag = TaskTag;
301 Command->CmdSet = 0x00;
302 SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));
303 Command->ExpDataTranLen = ExpDataTranLen;
304
305 CopyMem (Command->Cdb, Cdb, CdbLength);
306
307 return EFI_SUCCESS;
308 }
309
310 /**
311 Initialize UTP PRDT for data transfer.
312
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.
316
317 @retval EFI_SUCCESS The initialization succeed.
318
319 **/
320 EFI_STATUS
321 UfsInitUtpPrdt (
322 IN UTP_TR_PRD *Prdt,
323 IN VOID *Buffer,
324 IN UINT32 BufferSize
325 )
326 {
327 UINT32 PrdtIndex;
328 UINT32 RemainingLen;
329 UINT8 *Remaining;
330 UINTN PrdtNumber;
331
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));
335 }
336
337 if (BufferSize == 0) {
338 return EFI_SUCCESS;
339 }
340
341 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
342
343 RemainingLen = BufferSize;
344 Remaining = Buffer;
345 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
346
347 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
348 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
349 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
350 } else {
351 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
352 }
353
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;
358 }
359
360 return EFI_SUCCESS;
361 }
362
363 /**
364 Initialize QUERY REQUEST UPIU.
365
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.
374
375 @retval EFI_SUCCESS The initialization succeed.
376
377 **/
378 EFI_STATUS
379 UfsInitQueryRequestUpiu (
380 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,
381 IN UINT8 TaskTag,
382 IN UINT8 Opcode,
383 IN UINT8 DescId,
384 IN UINT8 Index,
385 IN UINT8 Selector,
386 IN UINTN DataSize OPTIONAL,
387 IN UINT8 *Data OPTIONAL
388 )
389 {
390 ASSERT (QueryReq != NULL);
391
392 QueryReq->TransCode = 0x16;
393 QueryReq->TaskTag = TaskTag;
394 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
395 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
396 } else {
397 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
398 }
399
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);
404 } else {
405 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
406 }
407
408 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
409 CopyMem (QueryReq + 1, Data, DataSize);
410 }
411
412 return EFI_SUCCESS;
413 }
414
415 /**
416 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
417
418 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
419 @param[in] Lun The Lun on which the SCSI command is executed.
420 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
421 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
422
423 @retval EFI_SUCCESS The creation succeed.
424 @retval EFI_DEVICE_ERROR The creation failed.
425 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
426
427 **/
428 EFI_STATUS
429 UfsCreateScsiCommandDesc (
430 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
431 IN UINT8 Lun,
432 IN UFS_SCSI_REQUEST_PACKET *Packet,
433 IN UTP_TRD *Trd
434 )
435 {
436 UINT8 *CommandDesc;
437 UINTN TotalLen;
438 UINTN PrdtNumber;
439 VOID *Buffer;
440 UINT32 Length;
441 UTP_COMMAND_UPIU *CommandUpiu;
442 UTP_TR_PRD *PrdtBase;
443 UFS_DATA_DIRECTION DataDirection;
444
445 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
446
447 if (Packet->DataDirection == UfsDataIn) {
448 Buffer = Packet->InDataBuffer;
449 Length = Packet->InTransferLength;
450 DataDirection = UfsDataIn;
451 } else {
452 Buffer = Packet->OutDataBuffer;
453 Length = Packet->OutTransferLength;
454 DataDirection = UfsDataOut;
455 }
456
457 if (Length == 0) {
458 DataDirection = UfsNoData;
459 }
460
461 PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
462
463 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
464 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
465 if (CommandDesc == NULL) {
466 return EFI_OUT_OF_RESOURCES;
467 }
468
469 CommandUpiu = (UTP_COMMAND_UPIU*)CommandDesc;
470 PrdtBase = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
471
472 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
473 UfsInitUtpPrdt (PrdtBase, Buffer, Length);
474
475 //
476 // Fill UTP_TRD associated fields
477 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
478 // *MUST* be located at a 64-bit aligned boundary.
479 //
480 Trd->Int = UFS_INTERRUPT_COMMAND;
481 Trd->Dd = DataDirection;
482 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
483 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
484 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);
485 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);
486 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
487 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
488 Trd->PrdtL = (UINT16)PrdtNumber;
489 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
490 return EFI_SUCCESS;
491 }
492
493 /**
494 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
495
496 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
497 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
498 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
499
500 @retval EFI_SUCCESS The creation succeed.
501 @retval EFI_DEVICE_ERROR The creation failed.
502 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
503 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
504
505 **/
506 EFI_STATUS
507 UfsCreateDMCommandDesc (
508 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
509 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
510 IN UTP_TRD *Trd
511 )
512 {
513 UINT8 *CommandDesc;
514 UINTN TotalLen;
515 UTP_QUERY_REQ_UPIU *QueryReqUpiu;
516 UINT8 Opcode;
517 UINT32 DataSize;
518 UINT8 *Data;
519 UINT8 DataDirection;
520
521 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
522
523 Opcode = Packet->Opcode;
524 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
525 return EFI_INVALID_PARAMETER;
526 }
527
528 DataDirection = Packet->DataDirection;
529 if (DataDirection == UfsDataIn) {
530 DataSize = Packet->InTransferLength;
531 Data = Packet->InDataBuffer;
532 } else if (DataDirection == UfsDataOut) {
533 DataSize = Packet->OutTransferLength;
534 Data = Packet->OutDataBuffer;
535 } else {
536 DataSize = 0;
537 Data = NULL;
538 }
539
540 if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))
541 && ((DataSize == 0) || (Data == NULL))) {
542 return EFI_INVALID_PARAMETER;
543 }
544
545 if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))
546 && ((DataSize != 0) || (Data != NULL))) {
547 return EFI_INVALID_PARAMETER;
548 }
549
550 if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {
551 return EFI_INVALID_PARAMETER;
552 }
553
554 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
555 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
556 } else {
557 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
558 }
559
560 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
561 if (CommandDesc == NULL) {
562 return EFI_OUT_OF_RESOURCES;
563 }
564
565 //
566 // Initialize UTP QUERY REQUEST UPIU
567 //
568 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;
569 UfsInitQueryRequestUpiu (
570 QueryReqUpiu,
571 Private->TaskTag++,
572 Opcode,
573 Packet->DescId,
574 Packet->Index,
575 Packet->Selector,
576 DataSize,
577 Data
578 );
579
580 //
581 // Fill UTP_TRD associated fields
582 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
583 //
584 Trd->Int = UFS_INTERRUPT_COMMAND;
585 Trd->Dd = DataDirection;
586 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
587 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
588 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);
589 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);
590 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
591 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
592 Trd->RuO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));
593 } else {
594 Trd->RuL = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));
595 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
596 }
597
598 return EFI_SUCCESS;
599 }
600
601 /**
602 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
603
604 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
605 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
606
607 @retval EFI_SUCCESS The creation succeed.
608 @retval EFI_DEVICE_ERROR The creation failed.
609 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
610
611 **/
612 EFI_STATUS
613 UfsCreateNopCommandDesc (
614 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
615 IN UTP_TRD *Trd
616 )
617 {
618 UINT8 *CommandDesc;
619 UINTN TotalLen;
620 UTP_NOP_OUT_UPIU *NopOutUpiu;
621
622 ASSERT ((Private != NULL) && (Trd != NULL));
623
624 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
625 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
626 if (CommandDesc == NULL) {
627 return EFI_OUT_OF_RESOURCES;
628 }
629
630 NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;
631
632 NopOutUpiu->TaskTag = Private->TaskTag++;
633
634 //
635 // Fill UTP_TRD associated fields
636 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
637 //
638 Trd->Int = UFS_INTERRUPT_COMMAND;
639 Trd->Dd = 0x00;
640 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
641 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
642 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);
643 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);
644 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
645 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
646
647 return EFI_SUCCESS;
648 }
649
650 /**
651 Find out available slot in transfer list of a UFS device.
652
653 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
654 @param[out] Slot The available slot.
655
656 @retval EFI_SUCCESS The available slot was found successfully.
657
658 **/
659 EFI_STATUS
660 UfsFindAvailableSlotInTrl (
661 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
662 OUT UINT8 *Slot
663 )
664 {
665 ASSERT ((Private != NULL) && (Slot != NULL));
666
667 //
668 // The simplest algo to always use slot 0.
669 // TODO: enhance it to support async transfer with multiple slot.
670 //
671 *Slot = 0;
672
673 return EFI_SUCCESS;
674 }
675
676 /**
677 Find out available slot in task management transfer list of a UFS device.
678
679 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
680 @param[out] Slot The available slot.
681
682 @retval EFI_SUCCESS The available slot was found successfully.
683
684 **/
685 EFI_STATUS
686 UfsFindAvailableSlotInTmrl (
687 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
688 OUT UINT8 *Slot
689 )
690 {
691 ASSERT ((Private != NULL) && (Slot != NULL));
692
693 //
694 // The simplest algo to always use slot 0.
695 // TODO: enhance it to support async transfer with multiple slot.
696 //
697 *Slot = 0;
698
699 return EFI_SUCCESS;
700 }
701
702 /**
703 Start specified slot in transfer list of a UFS device.
704
705 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
706 @param[in] Slot The slot to be started.
707
708 **/
709 VOID
710 UfsStartExecCmd (
711 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
712 IN UINT8 Slot
713 )
714 {
715 UINTN UfsHcBase;
716 UINTN Address;
717 UINT32 Data;
718
719 UfsHcBase = Private->UfsHcBase;
720
721 Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
722 Data = MmioRead32 (Address);
723 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
724 MmioWrite32 (Address, UFS_HC_UTRLRSR);
725 }
726
727 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
728 MmioWrite32 (Address, BIT0 << Slot);
729 }
730
731 /**
732 Stop specified slot in transfer list of a UFS device.
733
734 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
735 @param[in] Slot The slot to be stop.
736
737 **/
738 VOID
739 UfsStopExecCmd (
740 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
741 IN UINT8 Slot
742 )
743 {
744 UINTN UfsHcBase;
745 UINTN Address;
746 UINT32 Data;
747
748 UfsHcBase = Private->UfsHcBase;
749
750 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
751 Data = MmioRead32 (Address);
752 if ((Data & (BIT0 << Slot)) != 0) {
753 Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;
754 Data = MmioRead32 (Address);
755 MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));
756 }
757 }
758
759 /**
760 Read or write specified device descriptor of a UFS device.
761
762 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
763 @param[in] Read The boolean variable to show r/w direction.
764 @param[in] DescId The ID of device descriptor.
765 @param[in] Index The Index of device descriptor.
766 @param[in] Selector The Selector of device descriptor.
767 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
768 @param[in] DescSize The size of device descriptor buffer.
769
770 @retval EFI_SUCCESS The device descriptor was read/written successfully.
771 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
772 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
773
774 **/
775 EFI_STATUS
776 UfsRwDeviceDesc (
777 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
778 IN BOOLEAN Read,
779 IN UINT8 DescId,
780 IN UINT8 Index,
781 IN UINT8 Selector,
782 IN OUT VOID *Descriptor,
783 IN UINT32 DescSize
784 )
785 {
786 EFI_STATUS Status;
787 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
788 UINT8 Slot;
789 UTP_TRD *Trd;
790 UINTN Address;
791 UTP_QUERY_RESP_UPIU *QueryResp;
792 UINT8 *CmdDescBase;
793 UINT32 CmdDescSize;
794 UINT16 ReturnDataSize;
795
796 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
797
798 if (Read) {
799 Packet.DataDirection = UfsDataIn;
800 Packet.InDataBuffer = Descriptor;
801 Packet.InTransferLength = DescSize;
802 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
803 } else {
804 Packet.DataDirection = UfsDataOut;
805 Packet.OutDataBuffer = Descriptor;
806 Packet.OutTransferLength = DescSize;
807 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
808 }
809 Packet.DescId = DescId;
810 Packet.Index = Index;
811 Packet.Selector = Selector;
812 Packet.Timeout = UFS_TIMEOUT;
813
814 //
815 // Find out which slot of transfer request list is available.
816 //
817 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
818 if (EFI_ERROR (Status)) {
819 return Status;
820 }
821
822 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
823 //
824 // Fill transfer request descriptor to this slot.
825 //
826 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
827 if (EFI_ERROR (Status)) {
828 return Status;
829 }
830
831 //
832 // Check the transfer request result.
833 //
834 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
835 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
836 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
837
838 //
839 // Start to execute the transfer request.
840 //
841 UfsStartExecCmd (Private, Slot);
842
843 //
844 // Wait for the completion of the transfer request.
845 //
846 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
847 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
848 if (EFI_ERROR (Status)) {
849 goto Exit;
850 }
851
852 if (QueryResp->QueryResp != 0) {
853 DumpQueryResponseResult (QueryResp->QueryResp);
854 Status = EFI_DEVICE_ERROR;
855 goto Exit;
856 }
857
858 if (Trd->Ocs == 0) {
859 ReturnDataSize = QueryResp->Tsf.Length;
860 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
861
862 if (Read) {
863 CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);
864 Packet.InTransferLength = ReturnDataSize;
865 } else {
866 Packet.OutTransferLength = ReturnDataSize;
867 }
868 } else {
869 Status = EFI_DEVICE_ERROR;
870 }
871
872 Exit:
873 UfsStopExecCmd (Private, Slot);
874 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
875
876 return Status;
877 }
878
879 /**
880 Read or write specified attribute of a UFS device.
881
882 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
883 @param[in] Read The boolean variable to show r/w direction.
884 @param[in] AttrId The ID of Attribute.
885 @param[in] Index The Index of Attribute.
886 @param[in] Selector The Selector of Attribute.
887 @param[in, out] Attributes The value of Attribute to be read or written.
888
889 @retval EFI_SUCCESS The Attribute was read/written successfully.
890 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
891 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
892
893 **/
894 EFI_STATUS
895 UfsRwAttributes (
896 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
897 IN BOOLEAN Read,
898 IN UINT8 AttrId,
899 IN UINT8 Index,
900 IN UINT8 Selector,
901 IN OUT UINT32 *Attributes
902 )
903 {
904 EFI_STATUS Status;
905 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
906 UINT8 Slot;
907 UTP_TRD *Trd;
908 UINTN Address;
909 UTP_QUERY_RESP_UPIU *QueryResp;
910 UINT8 *CmdDescBase;
911 UINT32 CmdDescSize;
912 UINT32 ReturnData;
913
914 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
915
916 if (Read) {
917 Packet.DataDirection = UfsDataIn;
918 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
919 } else {
920 Packet.DataDirection = UfsDataOut;
921 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
922 }
923 Packet.DescId = AttrId;
924 Packet.Index = Index;
925 Packet.Selector = Selector;
926 Packet.Timeout = UFS_TIMEOUT;
927
928 //
929 // Find out which slot of transfer request list is available.
930 //
931 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
932 if (EFI_ERROR (Status)) {
933 return Status;
934 }
935
936 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
937 //
938 // Fill transfer request descriptor to this slot.
939 //
940 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
941 if (EFI_ERROR (Status)) {
942 return Status;
943 }
944
945 //
946 // Check the transfer request result.
947 //
948 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
949 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
950 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
951
952 //
953 // Start to execute the transfer request.
954 //
955 UfsStartExecCmd (Private, Slot);
956
957 //
958 // Wait for the completion of the transfer request.
959 //
960 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
961 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
962 if (EFI_ERROR (Status)) {
963 goto Exit;
964 }
965
966 if (QueryResp->QueryResp != 0) {
967 DumpQueryResponseResult (QueryResp->QueryResp);
968 Status = EFI_DEVICE_ERROR;
969 goto Exit;
970 }
971
972 if (Trd->Ocs == 0) {
973 ReturnData = QueryResp->Tsf.Value;
974 SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));
975 *Attributes = ReturnData;
976 } else {
977 Status = EFI_DEVICE_ERROR;
978 }
979
980 Exit:
981 UfsStopExecCmd (Private, Slot);
982 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
983
984 return Status;
985 }
986
987 /**
988 Read or write specified flag of a UFS device.
989
990 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
991 @param[in] Read The boolean variable to show r/w direction.
992 @param[in] FlagId The ID of flag to be read or written.
993 @param[in, out] Value The value to set or clear flag.
994
995 @retval EFI_SUCCESS The flag was read/written successfully.
996 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
997 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
998
999 **/
1000 EFI_STATUS
1001 UfsRwFlags (
1002 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1003 IN BOOLEAN Read,
1004 IN UINT8 FlagId,
1005 IN OUT UINT8 *Value
1006 )
1007 {
1008 EFI_STATUS Status;
1009 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1010 UINT8 Slot;
1011 UTP_TRD *Trd;
1012 UINTN Address;
1013 UTP_QUERY_RESP_UPIU *QueryResp;
1014 UINT8 *CmdDescBase;
1015 UINT32 CmdDescSize;
1016
1017 if (Value == NULL) {
1018 return EFI_INVALID_PARAMETER;
1019 }
1020
1021 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1022
1023 if (Read) {
1024 ASSERT (Value != NULL);
1025 Packet.DataDirection = UfsDataIn;
1026 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1027 } else {
1028 Packet.DataDirection = UfsDataOut;
1029 if (*Value == 1) {
1030 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1031 } else if (*Value == 0) {
1032 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1033 } else {
1034 return EFI_INVALID_PARAMETER;
1035 }
1036 }
1037 Packet.DescId = FlagId;
1038 Packet.Index = 0;
1039 Packet.Selector = 0;
1040 Packet.Timeout = UFS_TIMEOUT;
1041
1042 //
1043 // Find out which slot of transfer request list is available.
1044 //
1045 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1046 if (EFI_ERROR (Status)) {
1047 return Status;
1048 }
1049
1050 //
1051 // Fill transfer request descriptor to this slot.
1052 //
1053 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1054 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
1055 if (EFI_ERROR (Status)) {
1056 return Status;
1057 }
1058
1059 //
1060 // Check the transfer request result.
1061 //
1062 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1063 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1064 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1065
1066 //
1067 // Start to execute the transfer request.
1068 //
1069 UfsStartExecCmd (Private, Slot);
1070
1071 //
1072 // Wait for the completion of the transfer request.
1073 //
1074 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1075 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
1076 if (EFI_ERROR (Status)) {
1077 goto Exit;
1078 }
1079
1080 if (QueryResp->QueryResp != 0) {
1081 DumpQueryResponseResult (QueryResp->QueryResp);
1082 Status = EFI_DEVICE_ERROR;
1083 goto Exit;
1084 }
1085
1086 if (Trd->Ocs == 0) {
1087 *Value = (UINT8)QueryResp->Tsf.Value;
1088 } else {
1089 Status = EFI_DEVICE_ERROR;
1090 }
1091
1092 Exit:
1093 UfsStopExecCmd (Private, Slot);
1094 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1095
1096 return Status;
1097 }
1098
1099 /**
1100 Set specified flag to 1 on a UFS device.
1101
1102 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1103 @param[in] FlagId The ID of flag to be set.
1104
1105 @retval EFI_SUCCESS The flag was set successfully.
1106 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1107 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1108
1109 **/
1110 EFI_STATUS
1111 UfsSetFlag (
1112 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1113 IN UINT8 FlagId
1114 )
1115 {
1116 EFI_STATUS Status;
1117 UINT8 Value;
1118
1119 Value = 1;
1120 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1121
1122 return Status;
1123 }
1124
1125 /**
1126 Clear specified flag to 0 on a UFS device.
1127
1128 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1129 @param[in] FlagId The ID of flag to be cleared.
1130
1131 @retval EFI_SUCCESS The flag was cleared successfully.
1132 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1133 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1134
1135 **/
1136 EFI_STATUS
1137 UfsClearFlag (
1138 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1139 IN UINT8 FlagId
1140 )
1141 {
1142 EFI_STATUS Status;
1143 UINT8 Value;
1144
1145 Value = 0;
1146 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1147
1148 return Status;
1149 }
1150
1151 /**
1152 Read specified flag from a UFS device.
1153
1154 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1155 @param[in] FlagId The ID of flag to be read.
1156 @param[out] Value The flag's value.
1157
1158 @retval EFI_SUCCESS The flag was read successfully.
1159 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1160 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1161
1162 **/
1163 EFI_STATUS
1164 UfsReadFlag (
1165 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1166 IN UINT8 FlagId,
1167 OUT UINT8 *Value
1168 )
1169 {
1170 EFI_STATUS Status;
1171
1172 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1173
1174 return Status;
1175 }
1176
1177 /**
1178 Sends NOP IN cmd to a UFS device for initialization process request.
1179 For more details, please refer to UFS 2.0 spec Figure 13.3.
1180
1181 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1182
1183 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1184 received successfully.
1185 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1186 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1187 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1188
1189 **/
1190 EFI_STATUS
1191 UfsExecNopCmds (
1192 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1193 )
1194 {
1195 EFI_STATUS Status;
1196 UINT8 Slot;
1197 UTP_TRD *Trd;
1198 UTP_NOP_IN_UPIU *NopInUpiu;
1199 UINT8 *CmdDescBase;
1200 UINT32 CmdDescSize;
1201 UINTN Address;
1202
1203 //
1204 // Find out which slot of transfer request list is available.
1205 //
1206 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1207 if (EFI_ERROR (Status)) {
1208 return Status;
1209 }
1210
1211 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1212 Status = UfsCreateNopCommandDesc (Private, Trd);
1213 if (EFI_ERROR (Status)) {
1214 return Status;
1215 }
1216
1217 //
1218 // Check the transfer request result.
1219 //
1220 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1221 NopInUpiu = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1222 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1223
1224 //
1225 // Start to execute the transfer request.
1226 //
1227 UfsStartExecCmd (Private, Slot);
1228
1229 //
1230 // Wait for the completion of the transfer request.
1231 //
1232 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1233 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);
1234 if (EFI_ERROR (Status)) {
1235 goto Exit;
1236 }
1237
1238 if (NopInUpiu->Resp != 0) {
1239 Status = EFI_DEVICE_ERROR;
1240 } else {
1241 Status = EFI_SUCCESS;
1242 }
1243
1244 Exit:
1245 UfsStopExecCmd (Private, Slot);
1246 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1247
1248 return Status;
1249 }
1250
1251 /**
1252 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1253
1254 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1255 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1256 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1257 UFS device.
1258
1259 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1260 commands, InTransferLength bytes were transferred from
1261 InDataBuffer. For write and bi-directional commands,
1262 OutTransferLength bytes were transferred by
1263 OutDataBuffer.
1264 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1265 Packet.
1266 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1267 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1268
1269 **/
1270 EFI_STATUS
1271 UfsExecScsiCmds (
1272 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1273 IN UINT8 Lun,
1274 IN OUT UFS_SCSI_REQUEST_PACKET *Packet
1275 )
1276 {
1277 EFI_STATUS Status;
1278 UINT8 Slot;
1279 UTP_TRD *Trd;
1280 UINTN Address;
1281 UINT8 *CmdDescBase;
1282 UINT32 CmdDescSize;
1283 UTP_RESPONSE_UPIU *Response;
1284 UINT16 SenseDataLen;
1285 UINT32 ResTranCount;
1286
1287 //
1288 // Find out which slot of transfer request list is available.
1289 //
1290 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1291 if (EFI_ERROR (Status)) {
1292 return Status;
1293 }
1294
1295 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1296
1297 //
1298 // Fill transfer request descriptor to this slot.
1299 //
1300 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd);
1301 if (EFI_ERROR (Status)) {
1302 return Status;
1303 }
1304
1305 CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1306 CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);
1307
1308 //
1309 // Start to execute the transfer request.
1310 //
1311 UfsStartExecCmd (Private, Slot);
1312
1313 //
1314 // Wait for the completion of the transfer request.
1315 //
1316 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1317 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);
1318 if (EFI_ERROR (Status)) {
1319 goto Exit;
1320 }
1321
1322 //
1323 // Get sense data if exists
1324 //
1325 Response = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1326 SenseDataLen = Response->SenseDataLen;
1327 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
1328
1329 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1330 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1331 Packet->SenseDataLength = (UINT8)SenseDataLen;
1332 }
1333
1334 //
1335 // Check the transfer request result.
1336 //
1337 if (Response->Response != 0) {
1338 DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1339 Status = EFI_DEVICE_ERROR;
1340 goto Exit;
1341 }
1342
1343 if (Trd->Ocs == 0) {
1344 if (Packet->DataDirection == UfsDataIn) {
1345 if ((Response->Flags & BIT5) == BIT5) {
1346 ResTranCount = Response->ResTranCount;
1347 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1348 Packet->InTransferLength -= ResTranCount;
1349 }
1350 } else if (Packet->DataDirection == UfsDataOut) {
1351 if ((Response->Flags & BIT5) == BIT5) {
1352 ResTranCount = Response->ResTranCount;
1353 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1354 Packet->OutTransferLength -= ResTranCount;
1355 }
1356 }
1357 } else {
1358 Status = EFI_DEVICE_ERROR;
1359 }
1360
1361 Exit:
1362 UfsStopExecCmd (Private, Slot);
1363 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1364
1365 return Status;
1366 }
1367
1368
1369 /**
1370 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1371
1372 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1373 @param[in] UicOpcode The opcode of the UIC command.
1374 @param[in] Arg1 The value for 1st argument of the UIC command.
1375 @param[in] Arg2 The value for 2nd argument of the UIC command.
1376 @param[in] Arg3 The value for 3rd argument of the UIC command.
1377
1378 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1379 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1380 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1381
1382 **/
1383 EFI_STATUS
1384 UfsExecUicCommands (
1385 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1386 IN UINT8 UicOpcode,
1387 IN UINT32 Arg1,
1388 IN UINT32 Arg2,
1389 IN UINT32 Arg3
1390 )
1391 {
1392 EFI_STATUS Status;
1393 UINTN Address;
1394 UINT32 Data;
1395 UINTN UfsHcBase;
1396
1397 UfsHcBase = Private->UfsHcBase;
1398 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1399 Data = MmioRead32 (Address);
1400 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1401 //
1402 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1403 //
1404 MmioWrite32 (Address, Data);
1405 }
1406
1407 //
1408 // When programming UIC command registers, host software shall set the register UICCMD
1409 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1410 // are set.
1411 //
1412 Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;
1413 MmioWrite32 (Address, Arg1);
1414
1415 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1416 MmioWrite32 (Address, Arg2);
1417
1418 Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;
1419 MmioWrite32 (Address, Arg3);
1420
1421 //
1422 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1423 //
1424 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
1425 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1426 if (EFI_ERROR (Status)) {
1427 return Status;
1428 }
1429
1430 Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;
1431 MmioWrite32 (Address, (UINT32)UicOpcode);
1432
1433 //
1434 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1435 // This bit is set to '1' by the host controller upon completion of a UIC command.
1436 //
1437 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1438 Data = MmioRead32 (Address);
1439 Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1440 if (EFI_ERROR (Status)) {
1441 return Status;
1442 }
1443
1444 if (UicOpcode != UfsUicDmeReset) {
1445 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1446 Data = MmioRead32 (Address);
1447 if ((Data & 0xFF) != 0) {
1448 DEBUG_CODE_BEGIN();
1449 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
1450 DEBUG_CODE_END();
1451 return EFI_DEVICE_ERROR;
1452 }
1453 }
1454
1455 //
1456 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1457 //
1458 Address = UfsHcBase + UFS_HC_STATUS_OFFSET;
1459 Data = MmioRead32 (Address);
1460 if ((Data & UFS_HC_HCS_DP) == 0) {
1461 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1462 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1463 if (EFI_ERROR (Status)) {
1464 return EFI_DEVICE_ERROR;
1465 }
1466 return EFI_NOT_FOUND;
1467 }
1468
1469 DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));
1470
1471 return EFI_SUCCESS;
1472 }
1473
1474 /**
1475 Enable the UFS host controller for accessing.
1476
1477 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1478
1479 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1480 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1481
1482 **/
1483 EFI_STATUS
1484 UfsEnableHostController (
1485 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1486 )
1487 {
1488 EFI_STATUS Status;
1489 UINTN Address;
1490 UINT32 Data;
1491
1492 //
1493 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1494 //
1495 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1496 //
1497 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1498 Data = MmioRead32 (Address);
1499 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1500 //
1501 // Write a 0 to the HCE register at first to disable the host controller.
1502 //
1503 MmioWrite32 (Address, 0);
1504 //
1505 // Wait until HCE is read as '0' before continuing.
1506 //
1507 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1508 if (EFI_ERROR (Status)) {
1509 return EFI_DEVICE_ERROR;
1510 }
1511 }
1512
1513 //
1514 // Write a 1 to the HCE register to enable the UFS host controller.
1515 //
1516 MmioWrite32 (Address, UFS_HC_HCE_EN);
1517 //
1518 // Wait until HCE is read as '1' before continuing.
1519 //
1520 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1521 if (EFI_ERROR (Status)) {
1522 return EFI_DEVICE_ERROR;
1523 }
1524
1525 return EFI_SUCCESS;
1526 }
1527
1528 /**
1529 Detect if a UFS device attached.
1530
1531 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1532
1533 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1534 @retval EFI_NOT_FOUND Not found a UFS device attached.
1535 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1536
1537 **/
1538 EFI_STATUS
1539 UfsDeviceDetection (
1540 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1541 )
1542 {
1543 UINTN Retry;
1544 EFI_STATUS Status;
1545
1546 //
1547 // Start UFS device detection.
1548 // Try up to 3 times for establishing data link with device.
1549 //
1550 for (Retry = 0; Retry < 3; Retry++) {
1551 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
1552 if (!EFI_ERROR (Status)) {
1553 break;
1554 }
1555
1556 if (Status == EFI_NOT_FOUND) {
1557 continue;
1558 }
1559
1560 return EFI_DEVICE_ERROR;
1561 }
1562
1563 if (Retry == 3) {
1564 return EFI_NOT_FOUND;
1565 }
1566
1567 return EFI_SUCCESS;
1568 }
1569
1570 /**
1571 Initialize UFS task management request list related h/w context.
1572
1573 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1574
1575 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1576 @retval EFI_DEVICE_ERROR The initialization fails.
1577
1578 **/
1579 EFI_STATUS
1580 UfsInitTaskManagementRequestList (
1581 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1582 )
1583 {
1584 UINTN Address;
1585 UINT32 Data;
1586 UINT8 Nutmrs;
1587 EFI_PHYSICAL_ADDRESS Buffer;
1588 EFI_STATUS Status;
1589
1590 //
1591 // Initial h/w and s/w context for future operations.
1592 //
1593 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1594 Data = MmioRead32 (Address);
1595 Private->Capabilities = Data;
1596
1597 //
1598 // Allocate and initialize UTP Task Management Request List.
1599 //
1600 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1601 Status = PeiServicesAllocatePages (
1602 EfiBootServicesCode,
1603 EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
1604 &Buffer
1605 );
1606
1607 if (EFI_ERROR (Status)) {
1608 return EFI_DEVICE_ERROR;
1609 }
1610
1611 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
1612
1613 //
1614 // Program the UTP Task Management Request List Base Address and UTP Task Management
1615 // Request List Base Address with a 64-bit address allocated at step 6.
1616 //
1617 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;
1618 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
1619 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;
1620 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
1621 Private->UtpTmrlBase = (VOID*)(UINTN)Buffer;
1622 Private->Nutmrs = Nutmrs;
1623
1624 //
1625 // Enable the UTP Task Management Request List by setting the UTP Task Management
1626 // Request List RunStop Register (UTMRLRSR) to '1'.
1627 //
1628 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1629 MmioWrite32 (Address, UFS_HC_UTMRLRSR);
1630
1631 return EFI_SUCCESS;
1632 }
1633
1634 /**
1635 Initialize UFS transfer request list related h/w context.
1636
1637 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1638
1639 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1640 @retval EFI_DEVICE_ERROR The initialization fails.
1641
1642 **/
1643 EFI_STATUS
1644 UfsInitTransferRequestList (
1645 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1646 )
1647 {
1648 UINTN Address;
1649 UINT32 Data;
1650 UINT8 Nutrs;
1651 EFI_PHYSICAL_ADDRESS Buffer;
1652 EFI_STATUS Status;
1653
1654 //
1655 // Initial h/w and s/w context for future operations.
1656 //
1657 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1658 Data = MmioRead32 (Address);
1659 Private->Capabilities = Data;
1660
1661 //
1662 // Allocate and initialize UTP Transfer Request List.
1663 //
1664 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
1665 Status = PeiServicesAllocatePages (
1666 EfiBootServicesCode,
1667 EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
1668 &Buffer
1669 );
1670
1671 if (EFI_ERROR (Status)) {
1672 return EFI_DEVICE_ERROR;
1673 }
1674
1675 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
1676
1677 //
1678 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1679 // Base Address with a 64-bit address allocated at step 8.
1680 //
1681 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;
1682 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
1683 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;
1684 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
1685 Private->UtpTrlBase = (VOID*)(UINTN)Buffer;
1686 Private->Nutrs = Nutrs;
1687
1688 //
1689 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1690 // RunStop Register (UTRLRSR) to '1'.
1691 //
1692 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1693 MmioWrite32 (Address, UFS_HC_UTRLRSR);
1694
1695 return EFI_SUCCESS;
1696 }
1697
1698 /**
1699 Initialize the UFS host controller.
1700
1701 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1702
1703 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1704 @retval Others A device error occurred while initializing the controller.
1705
1706 **/
1707 EFI_STATUS
1708 UfsControllerInit (
1709 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1710 )
1711 {
1712 EFI_STATUS Status;
1713
1714 Status = UfsEnableHostController (Private);
1715 if (EFI_ERROR (Status)) {
1716 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));
1717 return Status;
1718 }
1719
1720 Status = UfsDeviceDetection (Private);
1721 if (EFI_ERROR (Status)) {
1722 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));
1723 return Status;
1724 }
1725
1726 Status = UfsInitTaskManagementRequestList (Private);
1727 if (EFI_ERROR (Status)) {
1728 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));
1729 return Status;
1730 }
1731
1732 Status = UfsInitTransferRequestList (Private);
1733 if (EFI_ERROR (Status)) {
1734 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
1735 return Status;
1736 }
1737
1738 DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));
1739 return EFI_SUCCESS;
1740 }
1741
1742 /**
1743 Stop the UFS host controller.
1744
1745 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1746
1747 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1748 @retval Others A device error occurred while stopping the controller.
1749
1750 **/
1751 EFI_STATUS
1752 UfsControllerStop (
1753 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1754 )
1755 {
1756 EFI_STATUS Status;
1757 UINTN Address;
1758 UINT32 Data;
1759
1760 //
1761 // Enable the UTP Task Management Request List by setting the UTP Task Management
1762 // Request List RunStop Register (UTMRLRSR) to '1'.
1763 //
1764 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1765 MmioWrite32 (Address, 0);
1766
1767 //
1768 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1769 // RunStop Register (UTRLRSR) to '1'.
1770 //
1771 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1772 MmioWrite32 (Address, 0);
1773
1774 //
1775 // Write a 0 to the HCE register in order to disable the host controller.
1776 //
1777 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1778 Data = MmioRead32 (Address);
1779 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
1780 MmioWrite32 (Address, 0);
1781
1782 //
1783 // Wait until HCE is read as '0' before continuing.
1784 //
1785 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1786 if (EFI_ERROR (Status)) {
1787 return EFI_DEVICE_ERROR;
1788 }
1789
1790 DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));
1791
1792 return EFI_SUCCESS;
1793 }
1794