]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
MdeModulePkg/Ufs: Set 'Data Segment Length' field for Write Descriptor
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsBlockIoPei / UfsHci.c
1 /** @file
2
3 Copyright (c) 2014 - 2017, 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 SwapLittleEndianToBigEndian ((UINT8*)&DataSize, sizeof (UINT16));
412 QueryReq->DataSegLen = (UINT16)DataSize;
413 }
414
415 return EFI_SUCCESS;
416 }
417
418 /**
419 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
420
421 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
422 @param[in] Lun The Lun on which the SCSI command is executed.
423 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
424 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
425
426 @retval EFI_SUCCESS The creation succeed.
427 @retval EFI_DEVICE_ERROR The creation failed.
428 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
429
430 **/
431 EFI_STATUS
432 UfsCreateScsiCommandDesc (
433 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
434 IN UINT8 Lun,
435 IN UFS_SCSI_REQUEST_PACKET *Packet,
436 IN UTP_TRD *Trd
437 )
438 {
439 UINT8 *CommandDesc;
440 UINTN TotalLen;
441 UINTN PrdtNumber;
442 VOID *Buffer;
443 UINT32 Length;
444 UTP_COMMAND_UPIU *CommandUpiu;
445 UTP_TR_PRD *PrdtBase;
446 UFS_DATA_DIRECTION DataDirection;
447
448 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
449
450 if (Packet->DataDirection == UfsDataIn) {
451 Buffer = Packet->InDataBuffer;
452 Length = Packet->InTransferLength;
453 DataDirection = UfsDataIn;
454 } else {
455 Buffer = Packet->OutDataBuffer;
456 Length = Packet->OutTransferLength;
457 DataDirection = UfsDataOut;
458 }
459
460 if (Length == 0) {
461 DataDirection = UfsNoData;
462 }
463
464 PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
465
466 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
467 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
468 if (CommandDesc == NULL) {
469 return EFI_OUT_OF_RESOURCES;
470 }
471
472 CommandUpiu = (UTP_COMMAND_UPIU*)CommandDesc;
473 PrdtBase = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
474
475 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
476 UfsInitUtpPrdt (PrdtBase, Buffer, Length);
477
478 //
479 // Fill UTP_TRD associated fields
480 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
481 // *MUST* be located at a 64-bit aligned boundary.
482 //
483 Trd->Int = UFS_INTERRUPT_COMMAND;
484 Trd->Dd = DataDirection;
485 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
486 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
487 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);
488 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);
489 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
490 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
491 Trd->PrdtL = (UINT16)PrdtNumber;
492 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
493 return EFI_SUCCESS;
494 }
495
496 /**
497 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
498
499 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
500 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
501 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
502
503 @retval EFI_SUCCESS The creation succeed.
504 @retval EFI_DEVICE_ERROR The creation failed.
505 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
506 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
507
508 **/
509 EFI_STATUS
510 UfsCreateDMCommandDesc (
511 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
512 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
513 IN UTP_TRD *Trd
514 )
515 {
516 UINT8 *CommandDesc;
517 UINTN TotalLen;
518 UTP_QUERY_REQ_UPIU *QueryReqUpiu;
519 UINT8 Opcode;
520 UINT32 DataSize;
521 UINT8 *Data;
522 UINT8 DataDirection;
523
524 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
525
526 Opcode = Packet->Opcode;
527 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
528 return EFI_INVALID_PARAMETER;
529 }
530
531 DataDirection = Packet->DataDirection;
532 if (DataDirection == UfsDataIn) {
533 DataSize = Packet->InTransferLength;
534 Data = Packet->InDataBuffer;
535 } else if (DataDirection == UfsDataOut) {
536 DataSize = Packet->OutTransferLength;
537 Data = Packet->OutDataBuffer;
538 } else {
539 DataSize = 0;
540 Data = NULL;
541 }
542
543 if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))
544 && ((DataSize == 0) || (Data == NULL))) {
545 return EFI_INVALID_PARAMETER;
546 }
547
548 if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))
549 && ((DataSize != 0) || (Data != NULL))) {
550 return EFI_INVALID_PARAMETER;
551 }
552
553 if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {
554 return EFI_INVALID_PARAMETER;
555 }
556
557 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
558 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
559 } else {
560 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
561 }
562
563 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
564 if (CommandDesc == NULL) {
565 return EFI_OUT_OF_RESOURCES;
566 }
567
568 //
569 // Initialize UTP QUERY REQUEST UPIU
570 //
571 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;
572 UfsInitQueryRequestUpiu (
573 QueryReqUpiu,
574 Private->TaskTag++,
575 Opcode,
576 Packet->DescId,
577 Packet->Index,
578 Packet->Selector,
579 DataSize,
580 Data
581 );
582
583 //
584 // Fill UTP_TRD associated fields
585 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
586 //
587 Trd->Int = UFS_INTERRUPT_COMMAND;
588 Trd->Dd = DataDirection;
589 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
590 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
591 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);
592 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);
593 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
594 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
595 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
596 } else {
597 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
598 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
599 }
600
601 return EFI_SUCCESS;
602 }
603
604 /**
605 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
606
607 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
608 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
609
610 @retval EFI_SUCCESS The creation succeed.
611 @retval EFI_DEVICE_ERROR The creation failed.
612 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
613
614 **/
615 EFI_STATUS
616 UfsCreateNopCommandDesc (
617 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
618 IN UTP_TRD *Trd
619 )
620 {
621 UINT8 *CommandDesc;
622 UINTN TotalLen;
623 UTP_NOP_OUT_UPIU *NopOutUpiu;
624
625 ASSERT ((Private != NULL) && (Trd != NULL));
626
627 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
628 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
629 if (CommandDesc == NULL) {
630 return EFI_OUT_OF_RESOURCES;
631 }
632
633 NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;
634
635 NopOutUpiu->TaskTag = Private->TaskTag++;
636
637 //
638 // Fill UTP_TRD associated fields
639 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
640 //
641 Trd->Int = UFS_INTERRUPT_COMMAND;
642 Trd->Dd = 0x00;
643 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
644 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
645 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);
646 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);
647 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
648 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
649
650 return EFI_SUCCESS;
651 }
652
653 /**
654 Find out available slot in transfer list of a UFS device.
655
656 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
657 @param[out] Slot The available slot.
658
659 @retval EFI_SUCCESS The available slot was found successfully.
660
661 **/
662 EFI_STATUS
663 UfsFindAvailableSlotInTrl (
664 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
665 OUT UINT8 *Slot
666 )
667 {
668 ASSERT ((Private != NULL) && (Slot != NULL));
669
670 //
671 // The simplest algo to always use slot 0.
672 // TODO: enhance it to support async transfer with multiple slot.
673 //
674 *Slot = 0;
675
676 return EFI_SUCCESS;
677 }
678
679 /**
680 Find out available slot in task management transfer list of a UFS device.
681
682 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
683 @param[out] Slot The available slot.
684
685 @retval EFI_SUCCESS The available slot was found successfully.
686
687 **/
688 EFI_STATUS
689 UfsFindAvailableSlotInTmrl (
690 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
691 OUT UINT8 *Slot
692 )
693 {
694 ASSERT ((Private != NULL) && (Slot != NULL));
695
696 //
697 // The simplest algo to always use slot 0.
698 // TODO: enhance it to support async transfer with multiple slot.
699 //
700 *Slot = 0;
701
702 return EFI_SUCCESS;
703 }
704
705 /**
706 Start specified slot in transfer list of a UFS device.
707
708 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
709 @param[in] Slot The slot to be started.
710
711 **/
712 VOID
713 UfsStartExecCmd (
714 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
715 IN UINT8 Slot
716 )
717 {
718 UINTN UfsHcBase;
719 UINTN Address;
720 UINT32 Data;
721
722 UfsHcBase = Private->UfsHcBase;
723
724 Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
725 Data = MmioRead32 (Address);
726 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
727 MmioWrite32 (Address, UFS_HC_UTRLRSR);
728 }
729
730 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
731 MmioWrite32 (Address, BIT0 << Slot);
732 }
733
734 /**
735 Stop specified slot in transfer list of a UFS device.
736
737 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
738 @param[in] Slot The slot to be stop.
739
740 **/
741 VOID
742 UfsStopExecCmd (
743 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
744 IN UINT8 Slot
745 )
746 {
747 UINTN UfsHcBase;
748 UINTN Address;
749 UINT32 Data;
750
751 UfsHcBase = Private->UfsHcBase;
752
753 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
754 Data = MmioRead32 (Address);
755 if ((Data & (BIT0 << Slot)) != 0) {
756 Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;
757 Data = MmioRead32 (Address);
758 MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));
759 }
760 }
761
762 /**
763 Read or write specified device descriptor of a UFS device.
764
765 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
766 @param[in] Read The boolean variable to show r/w direction.
767 @param[in] DescId The ID of device descriptor.
768 @param[in] Index The Index of device descriptor.
769 @param[in] Selector The Selector of device descriptor.
770 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
771 @param[in] DescSize The size of device descriptor buffer.
772
773 @retval EFI_SUCCESS The device descriptor was read/written successfully.
774 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
775 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
776
777 **/
778 EFI_STATUS
779 UfsRwDeviceDesc (
780 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
781 IN BOOLEAN Read,
782 IN UINT8 DescId,
783 IN UINT8 Index,
784 IN UINT8 Selector,
785 IN OUT VOID *Descriptor,
786 IN UINT32 DescSize
787 )
788 {
789 EFI_STATUS Status;
790 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
791 UINT8 Slot;
792 UTP_TRD *Trd;
793 UINTN Address;
794 UTP_QUERY_RESP_UPIU *QueryResp;
795 UINT8 *CmdDescBase;
796 UINT32 CmdDescSize;
797 UINT16 ReturnDataSize;
798
799 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
800
801 if (Read) {
802 Packet.DataDirection = UfsDataIn;
803 Packet.InDataBuffer = Descriptor;
804 Packet.InTransferLength = DescSize;
805 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
806 } else {
807 Packet.DataDirection = UfsDataOut;
808 Packet.OutDataBuffer = Descriptor;
809 Packet.OutTransferLength = DescSize;
810 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
811 }
812 Packet.DescId = DescId;
813 Packet.Index = Index;
814 Packet.Selector = Selector;
815 Packet.Timeout = UFS_TIMEOUT;
816
817 //
818 // Find out which slot of transfer request list is available.
819 //
820 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
821 if (EFI_ERROR (Status)) {
822 return Status;
823 }
824
825 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
826 //
827 // Fill transfer request descriptor to this slot.
828 //
829 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
830 if (EFI_ERROR (Status)) {
831 return Status;
832 }
833
834 //
835 // Check the transfer request result.
836 //
837 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
838 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
839 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
840
841 //
842 // Start to execute the transfer request.
843 //
844 UfsStartExecCmd (Private, Slot);
845
846 //
847 // Wait for the completion of the transfer request.
848 //
849 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
850 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
851 if (EFI_ERROR (Status)) {
852 goto Exit;
853 }
854
855 if (QueryResp->QueryResp != 0) {
856 DumpQueryResponseResult (QueryResp->QueryResp);
857 Status = EFI_DEVICE_ERROR;
858 goto Exit;
859 }
860
861 if (Trd->Ocs == 0) {
862 ReturnDataSize = QueryResp->Tsf.Length;
863 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
864
865 if (Read) {
866 CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);
867 Packet.InTransferLength = ReturnDataSize;
868 } else {
869 Packet.OutTransferLength = ReturnDataSize;
870 }
871 } else {
872 Status = EFI_DEVICE_ERROR;
873 }
874
875 Exit:
876 UfsStopExecCmd (Private, Slot);
877 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
878
879 return Status;
880 }
881
882 /**
883 Read or write specified attribute of a UFS device.
884
885 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
886 @param[in] Read The boolean variable to show r/w direction.
887 @param[in] AttrId The ID of Attribute.
888 @param[in] Index The Index of Attribute.
889 @param[in] Selector The Selector of Attribute.
890 @param[in, out] Attributes The value of Attribute to be read or written.
891
892 @retval EFI_SUCCESS The Attribute was read/written successfully.
893 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
894 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
895
896 **/
897 EFI_STATUS
898 UfsRwAttributes (
899 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
900 IN BOOLEAN Read,
901 IN UINT8 AttrId,
902 IN UINT8 Index,
903 IN UINT8 Selector,
904 IN OUT UINT32 *Attributes
905 )
906 {
907 EFI_STATUS Status;
908 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
909 UINT8 Slot;
910 UTP_TRD *Trd;
911 UINTN Address;
912 UTP_QUERY_RESP_UPIU *QueryResp;
913 UINT8 *CmdDescBase;
914 UINT32 CmdDescSize;
915 UINT32 ReturnData;
916
917 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
918
919 if (Read) {
920 Packet.DataDirection = UfsDataIn;
921 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
922 } else {
923 Packet.DataDirection = UfsDataOut;
924 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
925 }
926 Packet.DescId = AttrId;
927 Packet.Index = Index;
928 Packet.Selector = Selector;
929 Packet.Timeout = UFS_TIMEOUT;
930
931 //
932 // Find out which slot of transfer request list is available.
933 //
934 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
935 if (EFI_ERROR (Status)) {
936 return Status;
937 }
938
939 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
940 //
941 // Fill transfer request descriptor to this slot.
942 //
943 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
944 if (EFI_ERROR (Status)) {
945 return Status;
946 }
947
948 //
949 // Check the transfer request result.
950 //
951 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
952 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
953 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
954
955 //
956 // Start to execute the transfer request.
957 //
958 UfsStartExecCmd (Private, Slot);
959
960 //
961 // Wait for the completion of the transfer request.
962 //
963 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
964 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
965 if (EFI_ERROR (Status)) {
966 goto Exit;
967 }
968
969 if (QueryResp->QueryResp != 0) {
970 DumpQueryResponseResult (QueryResp->QueryResp);
971 Status = EFI_DEVICE_ERROR;
972 goto Exit;
973 }
974
975 if (Trd->Ocs == 0) {
976 ReturnData = QueryResp->Tsf.Value;
977 SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));
978 *Attributes = ReturnData;
979 } else {
980 Status = EFI_DEVICE_ERROR;
981 }
982
983 Exit:
984 UfsStopExecCmd (Private, Slot);
985 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
986
987 return Status;
988 }
989
990 /**
991 Read or write specified flag of a UFS device.
992
993 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
994 @param[in] Read The boolean variable to show r/w direction.
995 @param[in] FlagId The ID of flag to be read or written.
996 @param[in, out] Value The value to set or clear flag.
997
998 @retval EFI_SUCCESS The flag was read/written successfully.
999 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1000 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1001
1002 **/
1003 EFI_STATUS
1004 UfsRwFlags (
1005 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1006 IN BOOLEAN Read,
1007 IN UINT8 FlagId,
1008 IN OUT UINT8 *Value
1009 )
1010 {
1011 EFI_STATUS Status;
1012 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1013 UINT8 Slot;
1014 UTP_TRD *Trd;
1015 UINTN Address;
1016 UTP_QUERY_RESP_UPIU *QueryResp;
1017 UINT8 *CmdDescBase;
1018 UINT32 CmdDescSize;
1019
1020 if (Value == NULL) {
1021 return EFI_INVALID_PARAMETER;
1022 }
1023
1024 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1025
1026 if (Read) {
1027 ASSERT (Value != NULL);
1028 Packet.DataDirection = UfsDataIn;
1029 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1030 } else {
1031 Packet.DataDirection = UfsDataOut;
1032 if (*Value == 1) {
1033 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1034 } else if (*Value == 0) {
1035 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1036 } else {
1037 return EFI_INVALID_PARAMETER;
1038 }
1039 }
1040 Packet.DescId = FlagId;
1041 Packet.Index = 0;
1042 Packet.Selector = 0;
1043 Packet.Timeout = UFS_TIMEOUT;
1044
1045 //
1046 // Find out which slot of transfer request list is available.
1047 //
1048 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1049 if (EFI_ERROR (Status)) {
1050 return Status;
1051 }
1052
1053 //
1054 // Fill transfer request descriptor to this slot.
1055 //
1056 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1057 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
1058 if (EFI_ERROR (Status)) {
1059 return Status;
1060 }
1061
1062 //
1063 // Check the transfer request result.
1064 //
1065 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1066 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1067 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1068
1069 //
1070 // Start to execute the transfer request.
1071 //
1072 UfsStartExecCmd (Private, Slot);
1073
1074 //
1075 // Wait for the completion of the transfer request.
1076 //
1077 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1078 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
1079 if (EFI_ERROR (Status)) {
1080 goto Exit;
1081 }
1082
1083 if (QueryResp->QueryResp != 0) {
1084 DumpQueryResponseResult (QueryResp->QueryResp);
1085 Status = EFI_DEVICE_ERROR;
1086 goto Exit;
1087 }
1088
1089 if (Trd->Ocs == 0) {
1090 *Value = (UINT8)QueryResp->Tsf.Value;
1091 } else {
1092 Status = EFI_DEVICE_ERROR;
1093 }
1094
1095 Exit:
1096 UfsStopExecCmd (Private, Slot);
1097 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1098
1099 return Status;
1100 }
1101
1102 /**
1103 Set specified flag to 1 on a UFS device.
1104
1105 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1106 @param[in] FlagId The ID of flag to be set.
1107
1108 @retval EFI_SUCCESS The flag was set successfully.
1109 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1110 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1111
1112 **/
1113 EFI_STATUS
1114 UfsSetFlag (
1115 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1116 IN UINT8 FlagId
1117 )
1118 {
1119 EFI_STATUS Status;
1120 UINT8 Value;
1121
1122 Value = 1;
1123 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1124
1125 return Status;
1126 }
1127
1128 /**
1129 Clear specified flag to 0 on a UFS device.
1130
1131 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1132 @param[in] FlagId The ID of flag to be cleared.
1133
1134 @retval EFI_SUCCESS The flag was cleared successfully.
1135 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1136 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1137
1138 **/
1139 EFI_STATUS
1140 UfsClearFlag (
1141 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1142 IN UINT8 FlagId
1143 )
1144 {
1145 EFI_STATUS Status;
1146 UINT8 Value;
1147
1148 Value = 0;
1149 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1150
1151 return Status;
1152 }
1153
1154 /**
1155 Read specified flag from a UFS device.
1156
1157 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1158 @param[in] FlagId The ID of flag to be read.
1159 @param[out] Value The flag's value.
1160
1161 @retval EFI_SUCCESS The flag was read successfully.
1162 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1163 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1164
1165 **/
1166 EFI_STATUS
1167 UfsReadFlag (
1168 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1169 IN UINT8 FlagId,
1170 OUT UINT8 *Value
1171 )
1172 {
1173 EFI_STATUS Status;
1174
1175 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1176
1177 return Status;
1178 }
1179
1180 /**
1181 Sends NOP IN cmd to a UFS device for initialization process request.
1182 For more details, please refer to UFS 2.0 spec Figure 13.3.
1183
1184 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1185
1186 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1187 received successfully.
1188 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1189 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1190 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1191
1192 **/
1193 EFI_STATUS
1194 UfsExecNopCmds (
1195 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1196 )
1197 {
1198 EFI_STATUS Status;
1199 UINT8 Slot;
1200 UTP_TRD *Trd;
1201 UTP_NOP_IN_UPIU *NopInUpiu;
1202 UINT8 *CmdDescBase;
1203 UINT32 CmdDescSize;
1204 UINTN Address;
1205
1206 //
1207 // Find out which slot of transfer request list is available.
1208 //
1209 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1210 if (EFI_ERROR (Status)) {
1211 return Status;
1212 }
1213
1214 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1215 Status = UfsCreateNopCommandDesc (Private, Trd);
1216 if (EFI_ERROR (Status)) {
1217 return Status;
1218 }
1219
1220 //
1221 // Check the transfer request result.
1222 //
1223 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1224 NopInUpiu = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1225 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1226
1227 //
1228 // Start to execute the transfer request.
1229 //
1230 UfsStartExecCmd (Private, Slot);
1231
1232 //
1233 // Wait for the completion of the transfer request.
1234 //
1235 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1236 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);
1237 if (EFI_ERROR (Status)) {
1238 goto Exit;
1239 }
1240
1241 if (NopInUpiu->Resp != 0) {
1242 Status = EFI_DEVICE_ERROR;
1243 } else {
1244 Status = EFI_SUCCESS;
1245 }
1246
1247 Exit:
1248 UfsStopExecCmd (Private, Slot);
1249 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1250
1251 return Status;
1252 }
1253
1254 /**
1255 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1256
1257 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1258 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1259 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1260 UFS device.
1261
1262 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1263 commands, InTransferLength bytes were transferred from
1264 InDataBuffer. For write and bi-directional commands,
1265 OutTransferLength bytes were transferred by
1266 OutDataBuffer.
1267 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1268 Packet.
1269 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1270 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1271
1272 **/
1273 EFI_STATUS
1274 UfsExecScsiCmds (
1275 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1276 IN UINT8 Lun,
1277 IN OUT UFS_SCSI_REQUEST_PACKET *Packet
1278 )
1279 {
1280 EFI_STATUS Status;
1281 UINT8 Slot;
1282 UTP_TRD *Trd;
1283 UINTN Address;
1284 UINT8 *CmdDescBase;
1285 UINT32 CmdDescSize;
1286 UTP_RESPONSE_UPIU *Response;
1287 UINT16 SenseDataLen;
1288 UINT32 ResTranCount;
1289
1290 //
1291 // Find out which slot of transfer request list is available.
1292 //
1293 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1294 if (EFI_ERROR (Status)) {
1295 return Status;
1296 }
1297
1298 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1299
1300 //
1301 // Fill transfer request descriptor to this slot.
1302 //
1303 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd);
1304 if (EFI_ERROR (Status)) {
1305 return Status;
1306 }
1307
1308 CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1309 CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);
1310
1311 //
1312 // Start to execute the transfer request.
1313 //
1314 UfsStartExecCmd (Private, Slot);
1315
1316 //
1317 // Wait for the completion of the transfer request.
1318 //
1319 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1320 Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);
1321 if (EFI_ERROR (Status)) {
1322 goto Exit;
1323 }
1324
1325 //
1326 // Get sense data if exists
1327 //
1328 Response = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1329 SenseDataLen = Response->SenseDataLen;
1330 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
1331
1332 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1333 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1334 Packet->SenseDataLength = (UINT8)SenseDataLen;
1335 }
1336
1337 //
1338 // Check the transfer request result.
1339 //
1340 if (Response->Response != 0) {
1341 DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1342 Status = EFI_DEVICE_ERROR;
1343 goto Exit;
1344 }
1345
1346 if (Trd->Ocs == 0) {
1347 if (Packet->DataDirection == UfsDataIn) {
1348 if ((Response->Flags & BIT5) == BIT5) {
1349 ResTranCount = Response->ResTranCount;
1350 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1351 Packet->InTransferLength -= ResTranCount;
1352 }
1353 } else if (Packet->DataDirection == UfsDataOut) {
1354 if ((Response->Flags & BIT5) == BIT5) {
1355 ResTranCount = Response->ResTranCount;
1356 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1357 Packet->OutTransferLength -= ResTranCount;
1358 }
1359 }
1360 } else {
1361 Status = EFI_DEVICE_ERROR;
1362 }
1363
1364 Exit:
1365 UfsStopExecCmd (Private, Slot);
1366 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1367
1368 return Status;
1369 }
1370
1371
1372 /**
1373 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1374
1375 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1376 @param[in] UicOpcode The opcode of the UIC command.
1377 @param[in] Arg1 The value for 1st argument of the UIC command.
1378 @param[in] Arg2 The value for 2nd argument of the UIC command.
1379 @param[in] Arg3 The value for 3rd argument of the UIC command.
1380
1381 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1382 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1383 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1384
1385 **/
1386 EFI_STATUS
1387 UfsExecUicCommands (
1388 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1389 IN UINT8 UicOpcode,
1390 IN UINT32 Arg1,
1391 IN UINT32 Arg2,
1392 IN UINT32 Arg3
1393 )
1394 {
1395 EFI_STATUS Status;
1396 UINTN Address;
1397 UINT32 Data;
1398 UINTN UfsHcBase;
1399
1400 UfsHcBase = Private->UfsHcBase;
1401 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1402 Data = MmioRead32 (Address);
1403 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1404 //
1405 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1406 //
1407 MmioWrite32 (Address, Data);
1408 }
1409
1410 //
1411 // When programming UIC command registers, host software shall set the register UICCMD
1412 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1413 // are set.
1414 //
1415 Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;
1416 MmioWrite32 (Address, Arg1);
1417
1418 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1419 MmioWrite32 (Address, Arg2);
1420
1421 Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;
1422 MmioWrite32 (Address, Arg3);
1423
1424 //
1425 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1426 //
1427 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
1428 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1429 if (EFI_ERROR (Status)) {
1430 return Status;
1431 }
1432
1433 Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;
1434 MmioWrite32 (Address, (UINT32)UicOpcode);
1435
1436 //
1437 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1438 // This bit is set to '1' by the host controller upon completion of a UIC command.
1439 //
1440 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1441 Data = MmioRead32 (Address);
1442 Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1443 if (EFI_ERROR (Status)) {
1444 return Status;
1445 }
1446
1447 if (UicOpcode != UfsUicDmeReset) {
1448 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1449 Data = MmioRead32 (Address);
1450 if ((Data & 0xFF) != 0) {
1451 DEBUG_CODE_BEGIN();
1452 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
1453 DEBUG_CODE_END();
1454 return EFI_DEVICE_ERROR;
1455 }
1456 }
1457
1458 //
1459 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1460 //
1461 Address = UfsHcBase + UFS_HC_STATUS_OFFSET;
1462 Data = MmioRead32 (Address);
1463 if ((Data & UFS_HC_HCS_DP) == 0) {
1464 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1465 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1466 if (EFI_ERROR (Status)) {
1467 return EFI_DEVICE_ERROR;
1468 }
1469 return EFI_NOT_FOUND;
1470 }
1471
1472 DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));
1473
1474 return EFI_SUCCESS;
1475 }
1476
1477 /**
1478 Enable the UFS host controller for accessing.
1479
1480 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1481
1482 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1483 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1484
1485 **/
1486 EFI_STATUS
1487 UfsEnableHostController (
1488 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1489 )
1490 {
1491 EFI_STATUS Status;
1492 UINTN Address;
1493 UINT32 Data;
1494
1495 //
1496 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1497 //
1498 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1499 //
1500 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1501 Data = MmioRead32 (Address);
1502 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1503 //
1504 // Write a 0 to the HCE register at first to disable the host controller.
1505 //
1506 MmioWrite32 (Address, 0);
1507 //
1508 // Wait until HCE is read as '0' before continuing.
1509 //
1510 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1511 if (EFI_ERROR (Status)) {
1512 return EFI_DEVICE_ERROR;
1513 }
1514 }
1515
1516 //
1517 // Write a 1 to the HCE register to enable the UFS host controller.
1518 //
1519 MmioWrite32 (Address, UFS_HC_HCE_EN);
1520 //
1521 // Wait until HCE is read as '1' before continuing.
1522 //
1523 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1524 if (EFI_ERROR (Status)) {
1525 return EFI_DEVICE_ERROR;
1526 }
1527
1528 return EFI_SUCCESS;
1529 }
1530
1531 /**
1532 Detect if a UFS device attached.
1533
1534 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1535
1536 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1537 @retval EFI_NOT_FOUND Not found a UFS device attached.
1538 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1539
1540 **/
1541 EFI_STATUS
1542 UfsDeviceDetection (
1543 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1544 )
1545 {
1546 UINTN Retry;
1547 EFI_STATUS Status;
1548
1549 //
1550 // Start UFS device detection.
1551 // Try up to 3 times for establishing data link with device.
1552 //
1553 for (Retry = 0; Retry < 3; Retry++) {
1554 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
1555 if (!EFI_ERROR (Status)) {
1556 break;
1557 }
1558
1559 if (Status == EFI_NOT_FOUND) {
1560 continue;
1561 }
1562
1563 return EFI_DEVICE_ERROR;
1564 }
1565
1566 if (Retry == 3) {
1567 return EFI_NOT_FOUND;
1568 }
1569
1570 return EFI_SUCCESS;
1571 }
1572
1573 /**
1574 Initialize UFS task management request list related h/w context.
1575
1576 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1577
1578 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1579 @retval EFI_DEVICE_ERROR The initialization fails.
1580
1581 **/
1582 EFI_STATUS
1583 UfsInitTaskManagementRequestList (
1584 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1585 )
1586 {
1587 UINTN Address;
1588 UINT32 Data;
1589 UINT8 Nutmrs;
1590 EFI_PHYSICAL_ADDRESS Buffer;
1591 EFI_STATUS Status;
1592
1593 //
1594 // Initial h/w and s/w context for future operations.
1595 //
1596 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1597 Data = MmioRead32 (Address);
1598 Private->Capabilities = Data;
1599
1600 //
1601 // Allocate and initialize UTP Task Management Request List.
1602 //
1603 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1604 Status = PeiServicesAllocatePages (
1605 EfiBootServicesCode,
1606 EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
1607 &Buffer
1608 );
1609
1610 if (EFI_ERROR (Status)) {
1611 return EFI_DEVICE_ERROR;
1612 }
1613
1614 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
1615
1616 //
1617 // Program the UTP Task Management Request List Base Address and UTP Task Management
1618 // Request List Base Address with a 64-bit address allocated at step 6.
1619 //
1620 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;
1621 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
1622 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;
1623 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
1624 Private->UtpTmrlBase = (VOID*)(UINTN)Buffer;
1625 Private->Nutmrs = Nutmrs;
1626
1627 //
1628 // Enable the UTP Task Management Request List by setting the UTP Task Management
1629 // Request List RunStop Register (UTMRLRSR) to '1'.
1630 //
1631 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1632 MmioWrite32 (Address, UFS_HC_UTMRLRSR);
1633
1634 return EFI_SUCCESS;
1635 }
1636
1637 /**
1638 Initialize UFS transfer request list related h/w context.
1639
1640 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1641
1642 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1643 @retval EFI_DEVICE_ERROR The initialization fails.
1644
1645 **/
1646 EFI_STATUS
1647 UfsInitTransferRequestList (
1648 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1649 )
1650 {
1651 UINTN Address;
1652 UINT32 Data;
1653 UINT8 Nutrs;
1654 EFI_PHYSICAL_ADDRESS Buffer;
1655 EFI_STATUS Status;
1656
1657 //
1658 // Initial h/w and s/w context for future operations.
1659 //
1660 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1661 Data = MmioRead32 (Address);
1662 Private->Capabilities = Data;
1663
1664 //
1665 // Allocate and initialize UTP Transfer Request List.
1666 //
1667 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
1668 Status = PeiServicesAllocatePages (
1669 EfiBootServicesCode,
1670 EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
1671 &Buffer
1672 );
1673
1674 if (EFI_ERROR (Status)) {
1675 return EFI_DEVICE_ERROR;
1676 }
1677
1678 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
1679
1680 //
1681 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1682 // Base Address with a 64-bit address allocated at step 8.
1683 //
1684 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;
1685 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
1686 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;
1687 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
1688 Private->UtpTrlBase = (VOID*)(UINTN)Buffer;
1689 Private->Nutrs = Nutrs;
1690
1691 //
1692 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1693 // RunStop Register (UTRLRSR) to '1'.
1694 //
1695 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1696 MmioWrite32 (Address, UFS_HC_UTRLRSR);
1697
1698 return EFI_SUCCESS;
1699 }
1700
1701 /**
1702 Initialize the UFS host controller.
1703
1704 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1705
1706 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1707 @retval Others A device error occurred while initializing the controller.
1708
1709 **/
1710 EFI_STATUS
1711 UfsControllerInit (
1712 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1713 )
1714 {
1715 EFI_STATUS Status;
1716
1717 Status = UfsEnableHostController (Private);
1718 if (EFI_ERROR (Status)) {
1719 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));
1720 return Status;
1721 }
1722
1723 Status = UfsDeviceDetection (Private);
1724 if (EFI_ERROR (Status)) {
1725 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));
1726 return Status;
1727 }
1728
1729 Status = UfsInitTaskManagementRequestList (Private);
1730 if (EFI_ERROR (Status)) {
1731 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));
1732 return Status;
1733 }
1734
1735 Status = UfsInitTransferRequestList (Private);
1736 if (EFI_ERROR (Status)) {
1737 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
1738 return Status;
1739 }
1740
1741 DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));
1742 return EFI_SUCCESS;
1743 }
1744
1745 /**
1746 Stop the UFS host controller.
1747
1748 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1749
1750 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1751 @retval Others A device error occurred while stopping the controller.
1752
1753 **/
1754 EFI_STATUS
1755 UfsControllerStop (
1756 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1757 )
1758 {
1759 EFI_STATUS Status;
1760 UINTN Address;
1761 UINT32 Data;
1762
1763 //
1764 // Enable the UTP Task Management Request List by setting the UTP Task Management
1765 // Request List RunStop Register (UTMRLRSR) to '1'.
1766 //
1767 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1768 MmioWrite32 (Address, 0);
1769
1770 //
1771 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1772 // RunStop Register (UTRLRSR) to '1'.
1773 //
1774 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1775 MmioWrite32 (Address, 0);
1776
1777 //
1778 // Write a 0 to the HCE register in order to disable the host controller.
1779 //
1780 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1781 Data = MmioRead32 (Address);
1782 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
1783 MmioWrite32 (Address, 0);
1784
1785 //
1786 // Wait until HCE is read as '0' before continuing.
1787 //
1788 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1789 if (EFI_ERROR (Status)) {
1790 return EFI_DEVICE_ERROR;
1791 }
1792
1793 DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));
1794
1795 return EFI_SUCCESS;
1796 }
1797