]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
5fa635523aeb02c4f2c33ca60cdc3c7d0dd84c4c
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsPassThruDxe / UfsPassThruHci.c
1 /** @file
2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
3 for upper layer application to execute UFS-supported SCSI cmds.
4
5 Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "UfsPassThru.h"
17
18 /**
19 Read 32bits data from specified UFS MMIO register.
20
21 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
22 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
23 the memory operation.
24 @param[out] Value The data buffer to store.
25
26 @retval EFI_TIMEOUT The operation is time out.
27 @retval EFI_SUCCESS The operation succeeds.
28 @retval Others The operation fails.
29
30 **/
31 EFI_STATUS
32 UfsMmioRead32 (
33 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
34 IN UINTN Offset,
35 OUT UINT32 *Value
36 )
37 {
38 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
39 EFI_STATUS Status;
40
41 UfsHc = Private->UfsHostController;
42
43 Status = UfsHc->Read (UfsHc, EfiUfsHcWidthUint32, Offset, 1, Value);
44
45 return Status;
46 }
47
48 /**
49 Write 32bits data to specified UFS MMIO register.
50
51 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
52 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
53 the memory operation.
54 @param[in] Value The data to write.
55
56 @retval EFI_TIMEOUT The operation is time out.
57 @retval EFI_SUCCESS The operation succeeds.
58 @retval Others The operation fails.
59
60 **/
61 EFI_STATUS
62 UfsMmioWrite32 (
63 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
64 IN UINTN Offset,
65 IN UINT32 Value
66 )
67 {
68 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
69 EFI_STATUS Status;
70
71 UfsHc = Private->UfsHostController;
72
73 Status = UfsHc->Write (UfsHc, EfiUfsHcWidthUint32, Offset, 1, &Value);
74
75 return Status;
76 }
77
78 /**
79 Wait for the value of the specified system memory set to the test value.
80
81 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
82 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
83 the memory operation.
84 @param[in] MaskValue The mask value of memory.
85 @param[in] TestValue The test value of memory.
86 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
87
88 @retval EFI_TIMEOUT The system memory setting is time out.
89 @retval EFI_SUCCESS The system memory is correct set.
90 @retval Others The operation fails.
91
92 **/
93 EFI_STATUS
94 UfsWaitMemSet (
95 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
96 IN UINTN Offset,
97 IN UINT32 MaskValue,
98 IN UINT32 TestValue,
99 IN UINT64 Timeout
100 )
101 {
102 UINT32 Value;
103 UINT64 Delay;
104 BOOLEAN InfiniteWait;
105 EFI_STATUS Status;
106
107 if (Timeout == 0) {
108 InfiniteWait = TRUE;
109 } else {
110 InfiniteWait = FALSE;
111 }
112
113 Delay = DivU64x32 (Timeout, 10) + 1;
114
115 do {
116 //
117 // Access PCI MMIO space to see if the value is the tested one.
118 //
119 Status = UfsMmioRead32 (Private, Offset, &Value);
120 if (EFI_ERROR (Status)) {
121 return Status;
122 }
123
124 Value &= MaskValue;
125
126 if (Value == TestValue) {
127 return EFI_SUCCESS;
128 }
129
130 //
131 // Stall for 1 microseconds.
132 //
133 MicroSecondDelay (1);
134
135 Delay--;
136
137 } while (InfiniteWait || (Delay > 0));
138
139 return EFI_TIMEOUT;
140 }
141
142 /**
143 Dump UIC command execution result for debugging.
144
145 @param[in] UicOpcode The executed UIC opcode.
146 @param[in] Result The result to be parsed.
147
148 **/
149 VOID
150 DumpUicCmdExecResult (
151 IN UINT8 UicOpcode,
152 IN UINT8 Result
153 )
154 {
155 if (UicOpcode <= UfsUicDmePeerSet) {
156 switch (Result) {
157 case 0x00:
158 break;
159 case 0x01:
160 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
161 break;
162 case 0x02:
163 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
164 break;
165 case 0x03:
166 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
167 break;
168 case 0x04:
169 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
170 break;
171 case 0x05:
172 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
173 break;
174 case 0x06:
175 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
176 break;
177 case 0x07:
178 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
179 break;
180 case 0x08:
181 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
182 break;
183 case 0x09:
184 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));
185 break;
186 case 0x0A:
187 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
188 break;
189 default :
190 ASSERT (FALSE);
191 break;
192 }
193 } else {
194 switch (Result) {
195 case 0x00:
196 break;
197 case 0x01:
198 DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));
199 break;
200 default :
201 ASSERT (FALSE);
202 break;
203 }
204 }
205 }
206
207 /**
208 Dump QUERY RESPONSE UPIU result for debugging.
209
210 @param[in] Result The result to be parsed.
211
212 **/
213 VOID
214 DumpQueryResponseResult (
215 IN UINT8 Result
216 )
217 {
218 switch (Result) {
219 case 0xF6:
220 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));
221 break;
222 case 0xF7:
223 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));
224 break;
225 case 0xF8:
226 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));
227 break;
228 case 0xF9:
229 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));
230 break;
231 case 0xFA:
232 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));
233 break;
234 case 0xFB:
235 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));
236 break;
237 case 0xFC:
238 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));
239 break;
240 case 0xFD:
241 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));
242 break;
243 case 0xFE:
244 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));
245 break;
246 case 0xFF:
247 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));
248 break;
249 default :
250 ASSERT (FALSE);
251 break;
252 }
253 }
254
255 /**
256 Swap little endian to big endian.
257
258 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
259 In output, it will become big endian.
260 @param[in] BufferSize The length of converted data.
261
262 **/
263 VOID
264 SwapLittleEndianToBigEndian (
265 IN OUT UINT8 *Buffer,
266 IN UINT32 BufferSize
267 )
268 {
269 UINT32 Index;
270 UINT8 Temp;
271 UINT32 SwapCount;
272
273 SwapCount = BufferSize / 2;
274 for (Index = 0; Index < SwapCount; Index++) {
275 Temp = Buffer[Index];
276 Buffer[Index] = Buffer[BufferSize - 1 - Index];
277 Buffer[BufferSize - 1 - Index] = Temp;
278 }
279 }
280
281 /**
282 Fill TSF field of QUERY REQUEST UPIU.
283
284 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
285 @param[in] Opcode The opcode of request.
286 @param[in] DescId The descriptor ID of request.
287 @param[in] Index The index of request.
288 @param[in] Selector The selector of request.
289 @param[in] Length The length of transferred data. The maximum is 4.
290 @param[in] Value The value of transferred data.
291
292 **/
293 VOID
294 UfsFillTsfOfQueryReqUpiu (
295 IN OUT UTP_UPIU_TSF *TsfBase,
296 IN UINT8 Opcode,
297 IN UINT8 DescId OPTIONAL,
298 IN UINT8 Index OPTIONAL,
299 IN UINT8 Selector OPTIONAL,
300 IN UINT16 Length OPTIONAL,
301 IN UINT32 Value OPTIONAL
302 )
303 {
304 ASSERT (TsfBase != NULL);
305 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
306
307 TsfBase->Opcode = Opcode;
308 if (Opcode != UtpQueryFuncOpcodeNop) {
309 TsfBase->DescId = DescId;
310 TsfBase->Index = Index;
311 TsfBase->Selector = Selector;
312
313 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
314 SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));
315 TsfBase->Length = Length;
316 }
317
318 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
319 SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));
320 TsfBase->Value = Value;
321 }
322 }
323 }
324
325 /**
326 Initialize COMMAND UPIU.
327
328 @param[in, out] Command The base address of COMMAND UPIU.
329 @param[in] Lun The Lun on which the SCSI command is executed.
330 @param[in] TaskTag The task tag of request.
331 @param[in] Cdb The cdb buffer containing SCSI command.
332 @param[in] CdbLength The cdb length.
333 @param[in] DataDirection The direction of data transfer.
334 @param[in] ExpDataTranLen The expected transfer data length.
335
336 @retval EFI_SUCCESS The initialization succeed.
337
338 **/
339 EFI_STATUS
340 UfsInitCommandUpiu (
341 IN OUT UTP_COMMAND_UPIU *Command,
342 IN UINT8 Lun,
343 IN UINT8 TaskTag,
344 IN UINT8 *Cdb,
345 IN UINT8 CdbLength,
346 IN UFS_DATA_DIRECTION DataDirection,
347 IN UINT32 ExpDataTranLen
348 )
349 {
350 UINT8 Flags;
351
352 ASSERT ((Command != NULL) && (Cdb != NULL));
353
354 //
355 // Task attribute is hard-coded to Ordered.
356 //
357 if (DataDirection == UfsDataIn) {
358 Flags = BIT0 | BIT6;
359 } else if (DataDirection == UfsDataOut) {
360 Flags = BIT0 | BIT5;
361 } else {
362 Flags = BIT0;
363 }
364
365 //
366 // Fill UTP COMMAND UPIU associated fields.
367 //
368 Command->TransCode = 0x01;
369 Command->Flags = Flags;
370 Command->Lun = Lun;
371 Command->TaskTag = TaskTag;
372 Command->CmdSet = 0x00;
373 SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));
374 Command->ExpDataTranLen = ExpDataTranLen;
375
376 CopyMem (Command->Cdb, Cdb, CdbLength);
377
378 return EFI_SUCCESS;
379 }
380
381 /**
382 Initialize UTP PRDT for data transfer.
383
384 @param[in] Prdt The base address of PRDT.
385 @param[in] Buffer The buffer to be read or written.
386 @param[in] BufferSize The data size to be read or written.
387
388 @retval EFI_SUCCESS The initialization succeed.
389
390 **/
391 EFI_STATUS
392 UfsInitUtpPrdt (
393 IN UTP_TR_PRD *Prdt,
394 IN VOID *Buffer,
395 IN UINT32 BufferSize
396 )
397 {
398 UINT32 PrdtIndex;
399 UINT32 RemainingLen;
400 UINT8 *Remaining;
401 UINTN PrdtNumber;
402
403 if ((BufferSize & (BIT0 | BIT1)) != 0) {
404 BufferSize &= ~(BIT0 | BIT1);
405 DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));
406 }
407
408 if (BufferSize == 0) {
409 return EFI_SUCCESS;
410 }
411
412 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
413
414 RemainingLen = BufferSize;
415 Remaining = Buffer;
416 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
417
418 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
419 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
420 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
421 } else {
422 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
423 }
424
425 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
426 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
427 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
428 Remaining += UFS_MAX_DATA_LEN_PER_PRD;
429 }
430
431 return EFI_SUCCESS;
432 }
433
434 /**
435 Initialize QUERY REQUEST UPIU.
436
437 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
438 @param[in] TaskTag The task tag of request.
439 @param[in] Opcode The opcode of request.
440 @param[in] DescId The descriptor ID of request.
441 @param[in] Index The index of request.
442 @param[in] Selector The selector of request.
443 @param[in] DataSize The data size to be read or written.
444 @param[in] Data The buffer to be read or written.
445
446 @retval EFI_SUCCESS The initialization succeed.
447
448 **/
449 EFI_STATUS
450 UfsInitQueryRequestUpiu (
451 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,
452 IN UINT8 TaskTag,
453 IN UINT8 Opcode,
454 IN UINT8 DescId,
455 IN UINT8 Index,
456 IN UINT8 Selector,
457 IN UINTN DataSize OPTIONAL,
458 IN UINT8 *Data OPTIONAL
459 )
460 {
461 ASSERT (QueryReq != NULL);
462
463 QueryReq->TransCode = 0x16;
464 QueryReq->TaskTag = TaskTag;
465 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
466 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
467 } else {
468 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
469 }
470
471 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
472 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);
473 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
474 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
475 } else {
476 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
477 }
478
479 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
480 CopyMem (QueryReq + 1, Data, DataSize);
481 }
482
483 return EFI_SUCCESS;
484 }
485
486 /**
487 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
488
489 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
490 @param[in] Lun The Lun on which the SCSI command is executed.
491 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
492 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
493 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
494 @param[out] CmdDescMapping A resulting value to pass to Unmap().
495
496 @retval EFI_SUCCESS The creation succeed.
497 @retval EFI_DEVICE_ERROR The creation failed.
498 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
499
500 **/
501 EFI_STATUS
502 UfsCreateScsiCommandDesc (
503 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
504 IN UINT8 Lun,
505 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
506 IN UTP_TRD *Trd,
507 OUT VOID **CmdDescHost,
508 OUT VOID **CmdDescMapping
509 )
510 {
511 UINTN TotalLen;
512 UINTN PrdtNumber;
513 UTP_COMMAND_UPIU *CommandUpiu;
514 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
515 EFI_STATUS Status;
516 UINT32 DataLen;
517 UFS_DATA_DIRECTION DataDirection;
518
519 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
520
521 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
522 DataLen = Packet->InTransferLength;
523 DataDirection = UfsDataIn;
524 } else {
525 DataLen = Packet->OutTransferLength;
526 DataDirection = UfsDataOut;
527 }
528
529 if (DataLen == 0) {
530 DataDirection = UfsNoData;
531 }
532
533 PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
534
535 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
536
537 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
538 if (EFI_ERROR (Status)) {
539 return Status;
540 }
541
542 CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;
543
544 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);
545
546 //
547 // Fill UTP_TRD associated fields
548 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
549 // *MUST* be located at a 64-bit aligned boundary.
550 //
551 Trd->Int = UFS_INTERRUPT_COMMAND;
552 Trd->Dd = DataDirection;
553 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
554 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
555 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
556 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
557 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
558 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
559 Trd->PrdtL = (UINT16)PrdtNumber;
560 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
561 return EFI_SUCCESS;
562 }
563
564 /**
565 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
566
567 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
568 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
569 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
570 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
571 @param[out] CmdDescMapping A resulting value to pass to Unmap().
572
573 @retval EFI_SUCCESS The creation succeed.
574 @retval EFI_DEVICE_ERROR The creation failed.
575 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
576 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
577
578 **/
579 EFI_STATUS
580 UfsCreateDMCommandDesc (
581 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
582 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
583 IN UTP_TRD *Trd,
584 OUT VOID **CmdDescHost,
585 OUT VOID **CmdDescMapping
586 )
587 {
588 UINTN TotalLen;
589 UTP_QUERY_REQ_UPIU *QueryReqUpiu;
590 UINT8 Opcode;
591 UINT32 DataSize;
592 UINT8 *Data;
593 UINT8 DataDirection;
594 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
595 EFI_STATUS Status;
596
597 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
598
599 Opcode = Packet->Opcode;
600 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
601 return EFI_INVALID_PARAMETER;
602 }
603
604 DataDirection = Packet->DataDirection;
605 DataSize = Packet->TransferLength;
606 Data = Packet->DataBuffer;
607
608 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
609 if (DataSize == 0 || Data == NULL) {
610 return EFI_INVALID_PARAMETER;
611 }
612 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
613 } else {
614 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
615 }
616
617 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
618 if (EFI_ERROR (Status)) {
619 return Status;
620 }
621
622 //
623 // Initialize UTP QUERY REQUEST UPIU
624 //
625 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;
626 ASSERT (QueryReqUpiu != NULL);
627 UfsInitQueryRequestUpiu (
628 QueryReqUpiu,
629 Private->TaskTag++,
630 Opcode,
631 Packet->DescId,
632 Packet->Index,
633 Packet->Selector,
634 DataSize,
635 Data
636 );
637
638 //
639 // Fill UTP_TRD associated fields
640 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
641 //
642 Trd->Int = UFS_INTERRUPT_COMMAND;
643 Trd->Dd = DataDirection;
644 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
645 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
646 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
647 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
648 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
649 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
650 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
651 } else {
652 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
653 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
654 }
655
656 return EFI_SUCCESS;
657 }
658
659 /**
660 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
661
662 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
663 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
664 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
665 @param[out] CmdDescMapping A resulting value to pass to Unmap().
666
667 @retval EFI_SUCCESS The creation succeed.
668 @retval EFI_DEVICE_ERROR The creation failed.
669 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
670
671 **/
672 EFI_STATUS
673 UfsCreateNopCommandDesc (
674 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
675 IN UTP_TRD *Trd,
676 OUT VOID **CmdDescHost,
677 OUT VOID **CmdDescMapping
678 )
679 {
680 UINTN TotalLen;
681 UTP_NOP_OUT_UPIU *NopOutUpiu;
682 EFI_STATUS Status;
683 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
684
685 ASSERT ((Private != NULL) && (Trd != NULL));
686
687 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
688 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
689 if (EFI_ERROR (Status)) {
690 return Status;
691 }
692
693 NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;
694 ASSERT (NopOutUpiu != NULL);
695 NopOutUpiu->TaskTag = Private->TaskTag++;
696
697 //
698 // Fill UTP_TRD associated fields
699 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
700 //
701 Trd->Int = UFS_INTERRUPT_COMMAND;
702 Trd->Dd = 0x00;
703 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
704 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
705 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
706 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
707 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
708 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
709
710 return EFI_SUCCESS;
711 }
712
713 /**
714 Find out available slot in transfer list of a UFS device.
715
716 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
717 @param[out] Slot The available slot.
718
719 @retval EFI_SUCCESS The available slot was found successfully.
720 @retval EFI_NOT_READY No slot is available at this moment.
721
722 **/
723 EFI_STATUS
724 UfsFindAvailableSlotInTrl (
725 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
726 OUT UINT8 *Slot
727 )
728 {
729 UINT8 Nutrs;
730 UINT8 Index;
731 UINT32 Data;
732 EFI_STATUS Status;
733
734 ASSERT ((Private != NULL) && (Slot != NULL));
735
736 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
737 if (EFI_ERROR (Status)) {
738 return Status;
739 }
740
741 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
742
743 for (Index = 0; Index < Nutrs; Index++) {
744 if ((Data & (BIT0 << Index)) == 0) {
745 *Slot = Index;
746 return EFI_SUCCESS;
747 }
748 }
749
750 return EFI_NOT_READY;
751 }
752
753 /**
754 Find out available slot in task management transfer list of a UFS device.
755
756 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
757 @param[out] Slot The available slot.
758
759 @retval EFI_SUCCESS The available slot was found successfully.
760
761 **/
762 EFI_STATUS
763 UfsFindAvailableSlotInTmrl (
764 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
765 OUT UINT8 *Slot
766 )
767 {
768 ASSERT ((Private != NULL) && (Slot != NULL));
769
770 //
771 // The simplest algo to always use slot 0.
772 // TODO: enhance it to support async transfer with multiple slot.
773 //
774 *Slot = 0;
775
776 return EFI_SUCCESS;
777 }
778
779 /**
780 Start specified slot in transfer list of a UFS device.
781
782 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
783 @param[in] Slot The slot to be started.
784
785 **/
786 EFI_STATUS
787 UfsStartExecCmd (
788 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
789 IN UINT8 Slot
790 )
791 {
792 UINT32 Data;
793 EFI_STATUS Status;
794
795 Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);
796 if (EFI_ERROR (Status)) {
797 return Status;
798 }
799
800 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
801 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
802 if (EFI_ERROR (Status)) {
803 return Status;
804 }
805 }
806
807 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);
808 if (EFI_ERROR (Status)) {
809 return Status;
810 }
811
812 return EFI_SUCCESS;
813 }
814
815 /**
816 Stop specified slot in transfer list of a UFS device.
817
818 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
819 @param[in] Slot The slot to be stop.
820
821 **/
822 EFI_STATUS
823 UfsStopExecCmd (
824 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
825 IN UINT8 Slot
826 )
827 {
828 UINT32 Data;
829 EFI_STATUS Status;
830
831 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
832 if (EFI_ERROR (Status)) {
833 return Status;
834 }
835
836 if ((Data & (BIT0 << Slot)) != 0) {
837 Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);
838 if (EFI_ERROR (Status)) {
839 return Status;
840 }
841
842 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));
843 if (EFI_ERROR (Status)) {
844 return Status;
845 }
846 }
847
848 return EFI_SUCCESS;
849 }
850
851 /**
852 Extracts return data from query response upiu.
853
854 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
855 @param[in] QueryResp Pointer to the query response.
856
857 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
858 @retval EFI_SUCCESS Data extracted.
859
860 **/
861 EFI_STATUS
862 UfsGetReturnDataFromQueryResponse (
863 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
864 IN UTP_QUERY_RESP_UPIU *QueryResp
865 )
866 {
867 UINT16 ReturnDataSize;
868 UINT32 ReturnData;
869
870 if (Packet == NULL || QueryResp == NULL) {
871 return EFI_INVALID_PARAMETER;
872 }
873
874 switch (Packet->Opcode) {
875 case UtpQueryFuncOpcodeRdDesc:
876 ReturnDataSize = QueryResp->Tsf.Length;
877 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
878 CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);
879 Packet->TransferLength = ReturnDataSize;
880 break;
881 case UtpQueryFuncOpcodeWrDesc:
882 ReturnDataSize = QueryResp->Tsf.Length;
883 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
884 Packet->TransferLength = ReturnDataSize;
885 break;
886 case UtpQueryFuncOpcodeRdFlag:
887 case UtpQueryFuncOpcodeSetFlag:
888 case UtpQueryFuncOpcodeClrFlag:
889 case UtpQueryFuncOpcodeTogFlag:
890 CopyMem (Packet->DataBuffer, &QueryResp->Tsf.Value, sizeof (UINT8));
891 break;
892 case UtpQueryFuncOpcodeRdAttr:
893 case UtpQueryFuncOpcodeWrAttr:
894 ReturnData = QueryResp->Tsf.Value;
895 SwapLittleEndianToBigEndian ((UINT8*) &ReturnData, sizeof (UINT32));
896 CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));
897 break;
898 default:
899 return EFI_INVALID_PARAMETER;
900 }
901
902 return EFI_SUCCESS;
903 }
904
905 /**
906 Creates Transfer Request descriptor and sends Query Request to the device.
907
908 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
909 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
910
911 @retval EFI_SUCCESS The device descriptor was read/written successfully.
912 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
913 combination to point to a type of UFS device descriptor.
914 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
915 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
916
917 **/
918 EFI_STATUS
919 UfsSendDmRequestRetry (
920 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
921 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
922 )
923 {
924 UINT8 Slot;
925 UTP_TRD *Trd;
926 VOID *CmdDescHost;
927 VOID *CmdDescMapping;
928 UINT32 CmdDescSize;
929 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
930 UTP_QUERY_RESP_UPIU *QueryResp;
931 EFI_STATUS Status;
932
933 //
934 // Find out which slot of transfer request list is available.
935 //
936 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
937 if (EFI_ERROR (Status)) {
938 return Status;
939 }
940
941 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
942 //
943 // Fill transfer request descriptor to this slot.
944 //
945 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);
946 if (EFI_ERROR (Status)) {
947 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));
948 return Status;
949 }
950
951 UfsHc = Private->UfsHostController;
952 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
953 ASSERT (QueryResp != NULL);
954 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
955
956 //
957 // Start to execute the transfer request.
958 //
959 UfsStartExecCmd (Private, Slot);
960
961 //
962 // Wait for the completion of the transfer request.
963 //
964 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);
965 if (EFI_ERROR (Status)) {
966 goto Exit;
967 }
968
969 if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {
970 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));
971 DumpQueryResponseResult (QueryResp->QueryResp);
972
973 if ((QueryResp->QueryResp == UfsUtpQueryResponseInvalidSelector) ||
974 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIndex) ||
975 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIdn)) {
976 Status = EFI_INVALID_PARAMETER;
977 } else {
978 Status = EFI_DEVICE_ERROR;
979 }
980 goto Exit;
981 }
982
983 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);
984 if (EFI_ERROR (Status)) {
985 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));
986 goto Exit;
987 }
988
989 Exit:
990 UfsHc->Flush (UfsHc);
991
992 UfsStopExecCmd (Private, Slot);
993
994 if (CmdDescMapping != NULL) {
995 UfsHc->Unmap (UfsHc, CmdDescMapping);
996 }
997 if (CmdDescHost != NULL) {
998 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
999 }
1000
1001 return Status;
1002 }
1003
1004 /**
1005 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
1006
1007 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
1008 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
1009
1010 @retval EFI_SUCCESS The device responded correctly to the Query request.
1011 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
1012 combination to point to a type of UFS device descriptor.
1013 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
1014 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
1015
1016 **/
1017 EFI_STATUS
1018 UfsSendDmRequest (
1019 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1020 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
1021 )
1022 {
1023 EFI_STATUS Status;
1024 UINT8 Retry;
1025
1026 Status = EFI_SUCCESS;
1027
1028 for (Retry = 0; Retry < 5; Retry ++) {
1029 Status = UfsSendDmRequestRetry (Private, Packet);
1030 if (!EFI_ERROR (Status)) {
1031 return EFI_SUCCESS;
1032 }
1033 }
1034
1035 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));
1036 return Status;
1037 }
1038
1039 /**
1040 Read or write specified device descriptor of a UFS device.
1041
1042 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1043 @param[in] Read The boolean variable to show r/w direction.
1044 @param[in] DescId The ID of device descriptor.
1045 @param[in] Index The Index of device descriptor.
1046 @param[in] Selector The Selector of device descriptor.
1047 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1048 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1049 of the data buffer specified by Descriptor. On output, the number
1050 of bytes that were actually transferred.
1051
1052 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1053 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1054 type of UFS device descriptor.
1055 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1056 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1057
1058 **/
1059 EFI_STATUS
1060 UfsRwDeviceDesc (
1061 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1062 IN BOOLEAN Read,
1063 IN UINT8 DescId,
1064 IN UINT8 Index,
1065 IN UINT8 Selector,
1066 IN OUT VOID *Descriptor,
1067 IN OUT UINT32 *DescSize
1068 )
1069 {
1070 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1071 EFI_STATUS Status;
1072
1073 if (DescSize == NULL) {
1074 return EFI_INVALID_PARAMETER;
1075 }
1076
1077 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1078
1079 if (Read) {
1080 Packet.DataDirection = UfsDataIn;
1081 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
1082 } else {
1083 Packet.DataDirection = UfsDataOut;
1084 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
1085 }
1086 Packet.DataBuffer = Descriptor;
1087 Packet.TransferLength = *DescSize;
1088 Packet.DescId = DescId;
1089 Packet.Index = Index;
1090 Packet.Selector = Selector;
1091 Packet.Timeout = UFS_TIMEOUT;
1092
1093 Status = UfsSendDmRequest (Private, &Packet);
1094 if (EFI_ERROR (Status)) {
1095 *DescSize = 0;
1096 } else {
1097 *DescSize = Packet.TransferLength;
1098 }
1099
1100 return Status;
1101 }
1102
1103 /**
1104 Read or write specified attribute of a UFS device.
1105
1106 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1107 @param[in] Read The boolean variable to show r/w direction.
1108 @param[in] AttrId The ID of Attribute.
1109 @param[in] Index The Index of Attribute.
1110 @param[in] Selector The Selector of Attribute.
1111 @param[in, out] Attributes The value of Attribute to be read or written.
1112
1113 @retval EFI_SUCCESS The Attribute was read/written successfully.
1114 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1115 type of UFS device descriptor.
1116 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1117 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1118
1119 **/
1120 EFI_STATUS
1121 UfsRwAttributes (
1122 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1123 IN BOOLEAN Read,
1124 IN UINT8 AttrId,
1125 IN UINT8 Index,
1126 IN UINT8 Selector,
1127 IN OUT UINT32 *Attributes
1128 )
1129 {
1130 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1131
1132 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1133
1134 if (Read) {
1135 Packet.DataDirection = UfsDataIn;
1136 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
1137 } else {
1138 Packet.DataDirection = UfsDataOut;
1139 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
1140 }
1141 Packet.DataBuffer = Attributes;
1142 Packet.DescId = AttrId;
1143 Packet.Index = Index;
1144 Packet.Selector = Selector;
1145 Packet.Timeout = UFS_TIMEOUT;
1146
1147 return UfsSendDmRequest (Private, &Packet);
1148 }
1149
1150 /**
1151 Read or write specified flag of a UFS device.
1152
1153 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1154 @param[in] Read The boolean variable to show r/w direction.
1155 @param[in] FlagId The ID of flag to be read or written.
1156 @param[in, out] Value The value to set or clear flag.
1157
1158 @retval EFI_SUCCESS The flag was read/written successfully.
1159 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1160 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1161 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1162
1163 **/
1164 EFI_STATUS
1165 UfsRwFlags (
1166 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1167 IN BOOLEAN Read,
1168 IN UINT8 FlagId,
1169 IN OUT UINT8 *Value
1170 )
1171 {
1172 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1173
1174 if (Value == NULL) {
1175 return EFI_INVALID_PARAMETER;
1176 }
1177
1178 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1179
1180 if (Read) {
1181 ASSERT (Value != NULL);
1182 Packet.DataDirection = UfsDataIn;
1183 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1184 } else {
1185 Packet.DataDirection = UfsDataOut;
1186 if (*Value == 1) {
1187 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1188 } else if (*Value == 0) {
1189 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1190 } else {
1191 return EFI_INVALID_PARAMETER;
1192 }
1193 }
1194 Packet.DataBuffer = Value;
1195 Packet.DescId = FlagId;
1196 Packet.Index = 0;
1197 Packet.Selector = 0;
1198 Packet.Timeout = UFS_TIMEOUT;
1199
1200 return UfsSendDmRequest (Private, &Packet);
1201 }
1202
1203 /**
1204 Set specified flag to 1 on a UFS device.
1205
1206 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1207 @param[in] FlagId The ID of flag to be set.
1208
1209 @retval EFI_SUCCESS The flag was set successfully.
1210 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1211 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1212
1213 **/
1214 EFI_STATUS
1215 UfsSetFlag (
1216 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1217 IN UINT8 FlagId
1218 )
1219 {
1220 EFI_STATUS Status;
1221 UINT8 Value;
1222
1223 Value = 1;
1224 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1225
1226 return Status;
1227 }
1228
1229 /**
1230 Clear specified flag to 0 on a UFS device.
1231
1232 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1233 @param[in] FlagId The ID of flag to be cleared.
1234
1235 @retval EFI_SUCCESS The flag was cleared successfully.
1236 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1237 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1238
1239 **/
1240 EFI_STATUS
1241 UfsClearFlag (
1242 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1243 IN UINT8 FlagId
1244 )
1245 {
1246 EFI_STATUS Status;
1247 UINT8 Value;
1248
1249 Value = 0;
1250 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1251
1252 return Status;
1253 }
1254
1255 /**
1256 Read specified flag from a UFS device.
1257
1258 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1259 @param[in] FlagId The ID of flag to be read.
1260 @param[out] Value The flag's value.
1261
1262 @retval EFI_SUCCESS The flag was read successfully.
1263 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1264 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1265
1266 **/
1267 EFI_STATUS
1268 UfsReadFlag (
1269 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1270 IN UINT8 FlagId,
1271 OUT UINT8 *Value
1272 )
1273 {
1274 EFI_STATUS Status;
1275
1276 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1277
1278 return Status;
1279 }
1280
1281 /**
1282 Sends NOP IN cmd to a UFS device for initialization process request.
1283 For more details, please refer to UFS 2.0 spec Figure 13.3.
1284
1285 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1286
1287 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1288 received successfully.
1289 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1290 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1291 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1292
1293 **/
1294 EFI_STATUS
1295 UfsExecNopCmds (
1296 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1297 )
1298 {
1299 EFI_STATUS Status;
1300 UINT8 Slot;
1301 UTP_TRD *Trd;
1302 UTP_NOP_IN_UPIU *NopInUpiu;
1303 UINT32 CmdDescSize;
1304 VOID *CmdDescHost;
1305 VOID *CmdDescMapping;
1306 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1307
1308 //
1309 // Find out which slot of transfer request list is available.
1310 //
1311 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1312 if (EFI_ERROR (Status)) {
1313 return Status;
1314 }
1315
1316 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1317 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);
1318 if (EFI_ERROR (Status)) {
1319 return Status;
1320 }
1321
1322 //
1323 // Check the transfer request result.
1324 //
1325 UfsHc = Private->UfsHostController;
1326 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
1327 ASSERT (NopInUpiu != NULL);
1328 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1329
1330 //
1331 // Start to execute the transfer request.
1332 //
1333 UfsStartExecCmd (Private, Slot);
1334
1335 //
1336 // Wait for the completion of the transfer request.
1337 //
1338 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);
1339 if (EFI_ERROR (Status)) {
1340 goto Exit;
1341 }
1342
1343 if (NopInUpiu->Resp != 0) {
1344 Status = EFI_DEVICE_ERROR;
1345 } else {
1346 Status = EFI_SUCCESS;
1347 }
1348
1349 Exit:
1350 UfsHc->Flush (UfsHc);
1351
1352 UfsStopExecCmd (Private, Slot);
1353
1354 if (CmdDescMapping != NULL) {
1355 UfsHc->Unmap (UfsHc, CmdDescMapping);
1356 }
1357 if (CmdDescHost != NULL) {
1358 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
1359 }
1360
1361 return Status;
1362 }
1363
1364 /**
1365 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1366
1367 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1368 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1369 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1370 UFS device.
1371 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1372 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1373 Event is not NULL and non blocking I/O is supported, then
1374 nonblocking I/O is performed, and Event will be signaled when the
1375 SCSI Request Packet completes.
1376
1377 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1378 commands, InTransferLength bytes were transferred from
1379 InDataBuffer. For write and bi-directional commands,
1380 OutTransferLength bytes were transferred by
1381 OutDataBuffer.
1382 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1383 Packet.
1384 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1385 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1386
1387 **/
1388 EFI_STATUS
1389 UfsExecScsiCmds (
1390 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1391 IN UINT8 Lun,
1392 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
1393 IN EFI_EVENT Event OPTIONAL
1394 )
1395 {
1396 EFI_STATUS Status;
1397 UTP_RESPONSE_UPIU *Response;
1398 UINT16 SenseDataLen;
1399 UINT32 ResTranCount;
1400 VOID *DataBuf;
1401 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;
1402 UINT32 DataLen;
1403 UINTN MapLength;
1404 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1405 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;
1406 UTP_TR_PRD *PrdtBase;
1407 EFI_TPL OldTpl;
1408 UFS_PASS_THRU_TRANS_REQ *TransReq;
1409
1410 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));
1411 if (TransReq == NULL) {
1412 return EFI_OUT_OF_RESOURCES;
1413 }
1414
1415 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;
1416 TransReq->TimeoutRemain = Packet->Timeout;
1417 DataBufPhyAddr = 0;
1418 UfsHc = Private->UfsHostController;
1419 //
1420 // Find out which slot of transfer request list is available.
1421 //
1422 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);
1423 if (EFI_ERROR (Status)) {
1424 return Status;
1425 }
1426
1427 TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;
1428
1429 //
1430 // Fill transfer request descriptor to this slot.
1431 //
1432 Status = UfsCreateScsiCommandDesc (
1433 Private,
1434 Lun,
1435 Packet,
1436 TransReq->Trd,
1437 &TransReq->CmdDescHost,
1438 &TransReq->CmdDescMapping
1439 );
1440 if (EFI_ERROR (Status)) {
1441 return Status;
1442 }
1443
1444 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);
1445
1446 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1447 DataBuf = Packet->InDataBuffer;
1448 DataLen = Packet->InTransferLength;
1449 Flag = EdkiiUfsHcOperationBusMasterWrite;
1450 } else {
1451 DataBuf = Packet->OutDataBuffer;
1452 DataLen = Packet->OutTransferLength;
1453 Flag = EdkiiUfsHcOperationBusMasterRead;
1454 }
1455
1456 if (DataLen != 0) {
1457 MapLength = DataLen;
1458 Status = UfsHc->Map (
1459 UfsHc,
1460 Flag,
1461 DataBuf,
1462 &MapLength,
1463 &DataBufPhyAddr,
1464 &TransReq->DataBufMapping
1465 );
1466
1467 if (EFI_ERROR (Status) || (DataLen != MapLength)) {
1468 goto Exit1;
1469 }
1470 }
1471 //
1472 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1473 //
1474 PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
1475 ASSERT (PrdtBase != NULL);
1476 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);
1477
1478 //
1479 // Insert the async SCSI cmd to the Async I/O list
1480 //
1481 if (Event != NULL) {
1482 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1483 TransReq->Packet = Packet;
1484 TransReq->CallerEvent = Event;
1485 InsertTailList (&Private->Queue, &TransReq->TransferList);
1486 gBS->RestoreTPL (OldTpl);
1487 }
1488
1489 //
1490 // Start to execute the transfer request.
1491 //
1492 UfsStartExecCmd (Private, TransReq->Slot);
1493
1494 //
1495 // Immediately return for async I/O.
1496 //
1497 if (Event != NULL) {
1498 return EFI_SUCCESS;
1499 }
1500
1501 //
1502 // Wait for the completion of the transfer request.
1503 //
1504 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);
1505 if (EFI_ERROR (Status)) {
1506 goto Exit;
1507 }
1508
1509 //
1510 // Get sense data if exists
1511 //
1512 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
1513 ASSERT (Response != NULL);
1514 SenseDataLen = Response->SenseDataLen;
1515 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
1516
1517 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1518 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1519 Packet->SenseDataLength = (UINT8)SenseDataLen;
1520 }
1521
1522 //
1523 // Check the transfer request result.
1524 //
1525 Packet->TargetStatus = Response->Status;
1526 if (Response->Response != 0) {
1527 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1528 Status = EFI_DEVICE_ERROR;
1529 goto Exit;
1530 }
1531
1532 if (TransReq->Trd->Ocs == 0) {
1533 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1534 if ((Response->Flags & BIT5) == BIT5) {
1535 ResTranCount = Response->ResTranCount;
1536 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1537 Packet->InTransferLength -= ResTranCount;
1538 }
1539 } else {
1540 if ((Response->Flags & BIT5) == BIT5) {
1541 ResTranCount = Response->ResTranCount;
1542 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1543 Packet->OutTransferLength -= ResTranCount;
1544 }
1545 }
1546 } else {
1547 Status = EFI_DEVICE_ERROR;
1548 }
1549
1550 Exit:
1551 UfsHc->Flush (UfsHc);
1552
1553 UfsStopExecCmd (Private, TransReq->Slot);
1554
1555 if (TransReq->DataBufMapping != NULL) {
1556 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
1557 }
1558
1559 Exit1:
1560 if (TransReq->CmdDescMapping != NULL) {
1561 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
1562 }
1563 if (TransReq->CmdDescHost != NULL) {
1564 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);
1565 }
1566 if (TransReq != NULL) {
1567 FreePool (TransReq);
1568 }
1569 return Status;
1570 }
1571
1572
1573 /**
1574 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1575
1576 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1577 @param[in] UicOpcode The opcode of the UIC command.
1578 @param[in] Arg1 The value for 1st argument of the UIC command.
1579 @param[in] Arg2 The value for 2nd argument of the UIC command.
1580 @param[in] Arg3 The value for 3rd argument of the UIC command.
1581
1582 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1583 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1584 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1585
1586 **/
1587 EFI_STATUS
1588 UfsExecUicCommands (
1589 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1590 IN UINT8 UicOpcode,
1591 IN UINT32 Arg1,
1592 IN UINT32 Arg2,
1593 IN UINT32 Arg3
1594 )
1595 {
1596 EFI_STATUS Status;
1597 UINT32 Data;
1598
1599 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);
1600 if (EFI_ERROR (Status)) {
1601 return Status;
1602 }
1603
1604 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1605 //
1606 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1607 //
1608 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);
1609 if (EFI_ERROR (Status)) {
1610 return Status;
1611 }
1612 }
1613
1614 //
1615 // When programming UIC command registers, host software shall set the register UICCMD
1616 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1617 // are set.
1618 //
1619 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, Arg1);
1620 if (EFI_ERROR (Status)) {
1621 return Status;
1622 }
1623
1624 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, Arg2);
1625 if (EFI_ERROR (Status)) {
1626 return Status;
1627 }
1628
1629 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, Arg3);
1630 if (EFI_ERROR (Status)) {
1631 return Status;
1632 }
1633
1634 //
1635 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1636 //
1637 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1638 if (EFI_ERROR (Status)) {
1639 return Status;
1640 }
1641
1642 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, (UINT32)UicOpcode);
1643 if (EFI_ERROR (Status)) {
1644 return Status;
1645 }
1646
1647 //
1648 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1649 // This bit is set to '1' by the host controller upon completion of a UIC command.
1650 //
1651 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1652 if (EFI_ERROR (Status)) {
1653 return Status;
1654 }
1655
1656 if (UicOpcode != UfsUicDmeReset) {
1657 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &Data);
1658 if (EFI_ERROR (Status)) {
1659 return Status;
1660 }
1661 if ((Data & 0xFF) != 0) {
1662 DEBUG_CODE_BEGIN();
1663 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
1664 DEBUG_CODE_END();
1665 return EFI_DEVICE_ERROR;
1666 }
1667 }
1668
1669 //
1670 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1671 //
1672 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);
1673 if (EFI_ERROR (Status)) {
1674 return Status;
1675 }
1676
1677 if ((Data & UFS_HC_HCS_DP) == 0) {
1678 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1679 if (EFI_ERROR (Status)) {
1680 return EFI_DEVICE_ERROR;
1681 }
1682 return EFI_NOT_FOUND;
1683 }
1684
1685 DEBUG ((DEBUG_INFO, "UfsPassThruDxe: found a attached UFS device\n"));
1686
1687 return EFI_SUCCESS;
1688 }
1689
1690 /**
1691 Allocate common buffer for host and UFS bus master access simultaneously.
1692
1693 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1694 @param[in] Size The length of buffer to be allocated.
1695 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1696 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1697 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1698
1699 @retval EFI_SUCCESS The common buffer was allocated successfully.
1700 @retval EFI_DEVICE_ERROR The allocation fails.
1701 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1702
1703 **/
1704 EFI_STATUS
1705 UfsAllocateAlignCommonBuffer (
1706 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1707 IN UINTN Size,
1708 OUT VOID **CmdDescHost,
1709 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,
1710 OUT VOID **CmdDescMapping
1711 )
1712 {
1713 EFI_STATUS Status;
1714 UINTN Bytes;
1715 BOOLEAN Is32BitAddr;
1716 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1717
1718 if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {
1719 Is32BitAddr = FALSE;
1720 } else {
1721 Is32BitAddr = TRUE;
1722 }
1723
1724 UfsHc = Private->UfsHostController;
1725 Status = UfsHc->AllocateBuffer (
1726 UfsHc,
1727 AllocateAnyPages,
1728 EfiBootServicesData,
1729 EFI_SIZE_TO_PAGES (Size),
1730 CmdDescHost,
1731 0
1732 );
1733 if (EFI_ERROR (Status)) {
1734 *CmdDescMapping = NULL;
1735 *CmdDescHost = NULL;
1736 *CmdDescPhyAddr = 0;
1737 return EFI_OUT_OF_RESOURCES;
1738 }
1739
1740 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));
1741 Status = UfsHc->Map (
1742 UfsHc,
1743 EdkiiUfsHcOperationBusMasterCommonBuffer,
1744 *CmdDescHost,
1745 &Bytes,
1746 CmdDescPhyAddr,
1747 CmdDescMapping
1748 );
1749
1750 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {
1751 UfsHc->FreeBuffer (
1752 UfsHc,
1753 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1754 *CmdDescHost
1755 );
1756 *CmdDescHost = NULL;
1757 return EFI_OUT_OF_RESOURCES;
1758 }
1759
1760 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {
1761 //
1762 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1763 //
1764 UfsHc->Unmap (
1765 UfsHc,
1766 *CmdDescMapping
1767 );
1768 UfsHc->FreeBuffer (
1769 UfsHc,
1770 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1771 *CmdDescHost
1772 );
1773 *CmdDescMapping = NULL;
1774 *CmdDescHost = NULL;
1775 return EFI_DEVICE_ERROR;
1776 }
1777
1778 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));
1779 return EFI_SUCCESS;
1780 }
1781
1782 /**
1783 Enable the UFS host controller for accessing.
1784
1785 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1786
1787 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1788 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1789
1790 **/
1791 EFI_STATUS
1792 UfsEnableHostController (
1793 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1794 )
1795 {
1796 EFI_STATUS Status;
1797 UINT32 Data;
1798
1799 //
1800 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1801 //
1802 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1803 //
1804 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
1805 if (EFI_ERROR (Status)) {
1806 return Status;
1807 }
1808
1809 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1810 //
1811 // Write a 0 to the HCE register at first to disable the host controller.
1812 //
1813 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
1814 if (EFI_ERROR (Status)) {
1815 return Status;
1816 }
1817 //
1818 // Wait until HCE is read as '0' before continuing.
1819 //
1820 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1821 if (EFI_ERROR (Status)) {
1822 return EFI_DEVICE_ERROR;
1823 }
1824 }
1825
1826 //
1827 // Write a 1 to the HCE register to enable the UFS host controller.
1828 //
1829 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);
1830 if (EFI_ERROR (Status)) {
1831 return Status;
1832 }
1833
1834 //
1835 // Wait until HCE is read as '1' before continuing.
1836 //
1837 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1838 if (EFI_ERROR (Status)) {
1839 return EFI_DEVICE_ERROR;
1840 }
1841
1842 return EFI_SUCCESS;
1843 }
1844
1845 /**
1846 Detect if a UFS device attached.
1847
1848 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1849
1850 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1851 @retval EFI_NOT_FOUND Not found a UFS device attached.
1852 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1853
1854 **/
1855 EFI_STATUS
1856 UfsDeviceDetection (
1857 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1858 )
1859 {
1860 UINTN Retry;
1861 EFI_STATUS Status;
1862
1863 //
1864 // Start UFS device detection.
1865 // Try up to 3 times for establishing data link with device.
1866 //
1867 for (Retry = 0; Retry < 3; Retry++) {
1868 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
1869 if (!EFI_ERROR (Status)) {
1870 break;
1871 }
1872
1873 if (Status == EFI_NOT_FOUND) {
1874 continue;
1875 }
1876
1877 return EFI_DEVICE_ERROR;
1878 }
1879
1880 if (Retry == 3) {
1881 return EFI_NOT_FOUND;
1882 }
1883
1884 return EFI_SUCCESS;
1885 }
1886
1887 /**
1888 Initialize UFS task management request list related h/w context.
1889
1890 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1891
1892 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1893 @retval EFI_DEVICE_ERROR The initialization fails.
1894
1895 **/
1896 EFI_STATUS
1897 UfsInitTaskManagementRequestList (
1898 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1899 )
1900 {
1901 UINT32 Data;
1902 UINT8 Nutmrs;
1903 VOID *CmdDescHost;
1904 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1905 VOID *CmdDescMapping;
1906 EFI_STATUS Status;
1907
1908 //
1909 // Initial h/w and s/w context for future operations.
1910 //
1911 CmdDescHost = NULL;
1912 CmdDescMapping = NULL;
1913 CmdDescPhyAddr = 0;
1914
1915 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
1916 if (EFI_ERROR (Status)) {
1917 return Status;
1918 }
1919
1920 Private->Capabilities = Data;
1921
1922 //
1923 // Allocate and initialize UTP Task Management Request List.
1924 //
1925 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1926 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
1927 if (EFI_ERROR (Status)) {
1928 return Status;
1929 }
1930
1931 //
1932 // Program the UTP Task Management Request List Base Address and UTP Task Management
1933 // Request List Base Address with a 64-bit address allocated at step 6.
1934 //
1935 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
1936 if (EFI_ERROR (Status)) {
1937 return Status;
1938 }
1939
1940 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
1941 if (EFI_ERROR (Status)) {
1942 return Status;
1943 }
1944 Private->UtpTmrlBase = CmdDescHost;
1945 Private->Nutmrs = Nutmrs;
1946 Private->TmrlMapping = CmdDescMapping;
1947
1948 //
1949 // Enable the UTP Task Management Request List by setting the UTP Task Management
1950 // Request List RunStop Register (UTMRLRSR) to '1'.
1951 //
1952 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);
1953 if (EFI_ERROR (Status)) {
1954 return Status;
1955 }
1956
1957 return EFI_SUCCESS;
1958 }
1959
1960 /**
1961 Initialize UFS transfer request list related h/w context.
1962
1963 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1964
1965 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1966 @retval EFI_DEVICE_ERROR The initialization fails.
1967
1968 **/
1969 EFI_STATUS
1970 UfsInitTransferRequestList (
1971 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1972 )
1973 {
1974 UINT32 Data;
1975 UINT8 Nutrs;
1976 VOID *CmdDescHost;
1977 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1978 VOID *CmdDescMapping;
1979 EFI_STATUS Status;
1980
1981 //
1982 // Initial h/w and s/w context for future operations.
1983 //
1984 CmdDescHost = NULL;
1985 CmdDescMapping = NULL;
1986 CmdDescPhyAddr = 0;
1987
1988 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
1989 if (EFI_ERROR (Status)) {
1990 return Status;
1991 }
1992
1993 Private->Capabilities = Data;
1994
1995 //
1996 // Allocate and initialize UTP Transfer Request List.
1997 //
1998 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
1999 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
2000 if (EFI_ERROR (Status)) {
2001 return Status;
2002 }
2003
2004 //
2005 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2006 // Base Address with a 64-bit address allocated at step 8.
2007 //
2008 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
2009 if (EFI_ERROR (Status)) {
2010 return Status;
2011 }
2012
2013 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
2014 if (EFI_ERROR (Status)) {
2015 return Status;
2016 }
2017
2018 Private->UtpTrlBase = CmdDescHost;
2019 Private->Nutrs = Nutrs;
2020 Private->TrlMapping = CmdDescMapping;
2021
2022 //
2023 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2024 // RunStop Register (UTRLRSR) to '1'.
2025 //
2026 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
2027 if (EFI_ERROR (Status)) {
2028 return Status;
2029 }
2030
2031 return EFI_SUCCESS;
2032 }
2033
2034 /**
2035 Initialize the UFS host controller.
2036
2037 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2038
2039 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2040 @retval Others A device error occurred while initializing the controller.
2041
2042 **/
2043 EFI_STATUS
2044 UfsControllerInit (
2045 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2046 )
2047 {
2048 EFI_STATUS Status;
2049
2050 Status = UfsEnableHostController (Private);
2051 if (EFI_ERROR (Status)) {
2052 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));
2053 return Status;
2054 }
2055
2056 Status = UfsDeviceDetection (Private);
2057 if (EFI_ERROR (Status)) {
2058 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));
2059 return Status;
2060 }
2061
2062 Status = UfsInitTaskManagementRequestList (Private);
2063 if (EFI_ERROR (Status)) {
2064 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));
2065 return Status;
2066 }
2067
2068 Status = UfsInitTransferRequestList (Private);
2069 if (EFI_ERROR (Status)) {
2070 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));
2071 return Status;
2072 }
2073
2074 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));
2075 return EFI_SUCCESS;
2076 }
2077
2078 /**
2079 Stop the UFS host controller.
2080
2081 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2082
2083 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2084 @retval Others A device error occurred while stopping the controller.
2085
2086 **/
2087 EFI_STATUS
2088 UfsControllerStop (
2089 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2090 )
2091 {
2092 EFI_STATUS Status;
2093 UINT32 Data;
2094
2095 //
2096 // Enable the UTP Task Management Request List by setting the UTP Task Management
2097 // Request List RunStop Register (UTMRLRSR) to '1'.
2098 //
2099 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);
2100 if (EFI_ERROR (Status)) {
2101 return Status;
2102 }
2103
2104 //
2105 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2106 // RunStop Register (UTRLRSR) to '1'.
2107 //
2108 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);
2109 if (EFI_ERROR (Status)) {
2110 return Status;
2111 }
2112
2113 //
2114 // Write a 0 to the HCE register in order to disable the host controller.
2115 //
2116 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
2117 if (EFI_ERROR (Status)) {
2118 return Status;
2119 }
2120 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
2121
2122 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
2123 if (EFI_ERROR (Status)) {
2124 return Status;
2125 }
2126
2127 //
2128 // Wait until HCE is read as '0' before continuing.
2129 //
2130 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
2131 if (EFI_ERROR (Status)) {
2132 return EFI_DEVICE_ERROR;
2133 }
2134
2135 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));
2136
2137 return EFI_SUCCESS;
2138 }
2139
2140
2141 /**
2142 Internal helper function which will signal the caller event and clean up
2143 resources.
2144
2145 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2146 structure.
2147 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2148 structure.
2149
2150 **/
2151 VOID
2152 EFIAPI
2153 SignalCallerEvent (
2154 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
2155 IN UFS_PASS_THRU_TRANS_REQ *TransReq
2156 )
2157 {
2158 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
2159 EFI_EVENT CallerEvent;
2160
2161 ASSERT ((Private != NULL) && (TransReq != NULL));
2162
2163 UfsHc = Private->UfsHostController;
2164 CallerEvent = TransReq->CallerEvent;
2165
2166 RemoveEntryList (&TransReq->TransferList);
2167
2168 UfsHc->Flush (UfsHc);
2169
2170 UfsStopExecCmd (Private, TransReq->Slot);
2171
2172 if (TransReq->DataBufMapping != NULL) {
2173 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
2174 }
2175
2176 if (TransReq->CmdDescMapping != NULL) {
2177 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
2178 }
2179 if (TransReq->CmdDescHost != NULL) {
2180 UfsHc->FreeBuffer (
2181 UfsHc,
2182 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),
2183 TransReq->CmdDescHost
2184 );
2185 }
2186
2187 FreePool (TransReq);
2188
2189 gBS->SignalEvent (CallerEvent);
2190 return;
2191 }
2192
2193 /**
2194 Call back function when the timer event is signaled.
2195
2196 @param[in] Event The Event this notify function registered to.
2197 @param[in] Context Pointer to the context data registered to the Event.
2198
2199 **/
2200 VOID
2201 EFIAPI
2202 ProcessAsyncTaskList (
2203 IN EFI_EVENT Event,
2204 IN VOID *Context
2205 )
2206 {
2207 UFS_PASS_THRU_PRIVATE_DATA *Private;
2208 LIST_ENTRY *Entry;
2209 LIST_ENTRY *NextEntry;
2210 UFS_PASS_THRU_TRANS_REQ *TransReq;
2211 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;
2212 UTP_RESPONSE_UPIU *Response;
2213 UINT16 SenseDataLen;
2214 UINT32 ResTranCount;
2215 UINT32 SlotsMap;
2216 UINT32 Value;
2217 EFI_STATUS Status;
2218
2219 Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;
2220 SlotsMap = 0;
2221
2222 //
2223 // Check the entries in the async I/O queue are done or not.
2224 //
2225 if (!IsListEmpty(&Private->Queue)) {
2226 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
2227 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
2228 Packet = TransReq->Packet;
2229
2230 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {
2231 return;
2232 }
2233 SlotsMap |= BIT0 << TransReq->Slot;
2234
2235 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);
2236 if (EFI_ERROR (Status)) {
2237 //
2238 // TODO: Should find/add a proper host adapter return status for this
2239 // case.
2240 //
2241 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
2242 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));
2243 SignalCallerEvent (Private, TransReq);
2244 continue;
2245 }
2246
2247 if ((Value & (BIT0 << TransReq->Slot)) != 0) {
2248 //
2249 // Scsi cmd not finished yet.
2250 //
2251 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {
2252 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;
2253 continue;
2254 } else {
2255 //
2256 // Timeout occurs.
2257 //
2258 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
2259 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));
2260 SignalCallerEvent (Private, TransReq);
2261 continue;
2262 }
2263 } else {
2264 //
2265 // Scsi cmd finished.
2266 //
2267 // Get sense data if exists
2268 //
2269 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
2270 ASSERT (Response != NULL);
2271 SenseDataLen = Response->SenseDataLen;
2272 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
2273
2274 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
2275 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
2276 Packet->SenseDataLength = (UINT8)SenseDataLen;
2277 }
2278
2279 //
2280 // Check the transfer request result.
2281 //
2282 Packet->TargetStatus = Response->Status;
2283 if (Response->Response != 0) {
2284 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));
2285 SignalCallerEvent (Private, TransReq);
2286 continue;
2287 }
2288
2289 if (TransReq->Trd->Ocs == 0) {
2290 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
2291 if ((Response->Flags & BIT5) == BIT5) {
2292 ResTranCount = Response->ResTranCount;
2293 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2294 Packet->InTransferLength -= ResTranCount;
2295 }
2296 } else {
2297 if ((Response->Flags & BIT5) == BIT5) {
2298 ResTranCount = Response->ResTranCount;
2299 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2300 Packet->OutTransferLength -= ResTranCount;
2301 }
2302 }
2303 } else {
2304 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));
2305 SignalCallerEvent (Private, TransReq);
2306 continue;
2307 }
2308
2309 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));
2310 SignalCallerEvent (Private, TransReq);
2311 }
2312 }
2313 }
2314 }
2315