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