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