]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
a19bdcc3cc397fdd36ab07aebbd58775b7870b6d
[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_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
913 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
914
915 **/
916 EFI_STATUS
917 UfsSendDmRequestRetry (
918 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
919 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
920 )
921 {
922 UINT8 Slot;
923 UTP_TRD *Trd;
924 VOID *CmdDescHost;
925 VOID *CmdDescMapping;
926 UINT32 CmdDescSize;
927 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
928 UTP_QUERY_RESP_UPIU *QueryResp;
929 EFI_STATUS Status;
930
931 //
932 // Find out which slot of transfer request list is available.
933 //
934 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
935 if (EFI_ERROR (Status)) {
936 return Status;
937 }
938
939 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
940 //
941 // Fill transfer request descriptor to this slot.
942 //
943 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);
944 if (EFI_ERROR (Status)) {
945 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));
946 return Status;
947 }
948
949 UfsHc = Private->UfsHostController;
950 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
951 ASSERT (QueryResp != NULL);
952 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
953
954 //
955 // Start to execute the transfer request.
956 //
957 UfsStartExecCmd (Private, Slot);
958
959 //
960 // Wait for the completion of the transfer request.
961 //
962 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);
963 if (EFI_ERROR (Status)) {
964 goto Exit;
965 }
966
967 if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {
968 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));
969 DumpQueryResponseResult (QueryResp->QueryResp);
970 Status = EFI_DEVICE_ERROR;
971 goto Exit;
972 }
973
974 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);
975 if (EFI_ERROR (Status)) {
976 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));
977 goto Exit;
978 }
979
980 Exit:
981 UfsHc->Flush (UfsHc);
982
983 UfsStopExecCmd (Private, Slot);
984
985 if (CmdDescMapping != NULL) {
986 UfsHc->Unmap (UfsHc, CmdDescMapping);
987 }
988 if (CmdDescHost != NULL) {
989 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
990 }
991
992 return Status;
993 }
994
995 /**
996 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
997
998 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
999 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
1000
1001 @retval EFI_SUCCESS The device responded correctly to the Query request.
1002 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
1003 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
1004
1005 **/
1006 EFI_STATUS
1007 UfsSendDmRequest (
1008 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1009 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
1010 )
1011 {
1012 EFI_STATUS Status;
1013 UINT8 Retry;
1014
1015 Status = EFI_SUCCESS;
1016
1017 for (Retry = 0; Retry < 5; Retry ++) {
1018 Status = UfsSendDmRequestRetry (Private, Packet);
1019 if (!EFI_ERROR (Status)) {
1020 return EFI_SUCCESS;
1021 }
1022 }
1023
1024 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));
1025 return Status;
1026 }
1027
1028 /**
1029 Read or write specified device descriptor of a UFS device.
1030
1031 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1032 @param[in] Read The boolean variable to show r/w direction.
1033 @param[in] DescId The ID of device descriptor.
1034 @param[in] Index The Index of device descriptor.
1035 @param[in] Selector The Selector of device descriptor.
1036 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1037 @param[in] DescSize The size of device descriptor buffer.
1038
1039 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1040 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1041 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1042
1043 **/
1044 EFI_STATUS
1045 UfsRwDeviceDesc (
1046 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1047 IN BOOLEAN Read,
1048 IN UINT8 DescId,
1049 IN UINT8 Index,
1050 IN UINT8 Selector,
1051 IN OUT VOID *Descriptor,
1052 IN UINT32 DescSize
1053 )
1054 {
1055 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1056
1057 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1058
1059 if (Read) {
1060 Packet.DataDirection = UfsDataIn;
1061 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
1062 } else {
1063 Packet.DataDirection = UfsDataOut;
1064 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
1065 }
1066 Packet.DataBuffer = Descriptor;
1067 Packet.TransferLength = DescSize;
1068 Packet.DescId = DescId;
1069 Packet.Index = Index;
1070 Packet.Selector = Selector;
1071 Packet.Timeout = UFS_TIMEOUT;
1072
1073 return UfsSendDmRequest (Private, &Packet);
1074 }
1075
1076 /**
1077 Read or write specified attribute of a UFS device.
1078
1079 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1080 @param[in] Read The boolean variable to show r/w direction.
1081 @param[in] AttrId The ID of Attribute.
1082 @param[in] Index The Index of Attribute.
1083 @param[in] Selector The Selector of Attribute.
1084 @param[in, out] Attributes The value of Attribute to be read or written.
1085
1086 @retval EFI_SUCCESS The Attribute was read/written successfully.
1087 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1088 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1089
1090 **/
1091 EFI_STATUS
1092 UfsRwAttributes (
1093 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1094 IN BOOLEAN Read,
1095 IN UINT8 AttrId,
1096 IN UINT8 Index,
1097 IN UINT8 Selector,
1098 IN OUT UINT32 *Attributes
1099 )
1100 {
1101 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1102
1103 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1104
1105 if (Read) {
1106 Packet.DataDirection = UfsDataIn;
1107 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
1108 } else {
1109 Packet.DataDirection = UfsDataOut;
1110 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
1111 }
1112 Packet.DataBuffer = Attributes;
1113 Packet.DescId = AttrId;
1114 Packet.Index = Index;
1115 Packet.Selector = Selector;
1116 Packet.Timeout = UFS_TIMEOUT;
1117
1118 return UfsSendDmRequest (Private, &Packet);
1119 }
1120
1121 /**
1122 Read or write specified flag of a UFS device.
1123
1124 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1125 @param[in] Read The boolean variable to show r/w direction.
1126 @param[in] FlagId The ID of flag to be read or written.
1127 @param[in, out] Value The value to set or clear flag.
1128
1129 @retval EFI_SUCCESS The flag was read/written successfully.
1130 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1131 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1132
1133 **/
1134 EFI_STATUS
1135 UfsRwFlags (
1136 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1137 IN BOOLEAN Read,
1138 IN UINT8 FlagId,
1139 IN OUT UINT8 *Value
1140 )
1141 {
1142 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1143
1144 if (Value == NULL) {
1145 return EFI_INVALID_PARAMETER;
1146 }
1147
1148 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1149
1150 if (Read) {
1151 ASSERT (Value != NULL);
1152 Packet.DataDirection = UfsDataIn;
1153 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1154 } else {
1155 Packet.DataDirection = UfsDataOut;
1156 if (*Value == 1) {
1157 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1158 } else if (*Value == 0) {
1159 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1160 } else {
1161 return EFI_INVALID_PARAMETER;
1162 }
1163 }
1164 Packet.DataBuffer = Value;
1165 Packet.DescId = FlagId;
1166 Packet.Index = 0;
1167 Packet.Selector = 0;
1168 Packet.Timeout = UFS_TIMEOUT;
1169
1170 return UfsSendDmRequest (Private, &Packet);
1171 }
1172
1173 /**
1174 Set specified flag to 1 on a UFS device.
1175
1176 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1177 @param[in] FlagId The ID of flag to be set.
1178
1179 @retval EFI_SUCCESS The flag was set successfully.
1180 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1181 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1182
1183 **/
1184 EFI_STATUS
1185 UfsSetFlag (
1186 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1187 IN UINT8 FlagId
1188 )
1189 {
1190 EFI_STATUS Status;
1191 UINT8 Value;
1192
1193 Value = 1;
1194 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1195
1196 return Status;
1197 }
1198
1199 /**
1200 Clear specified flag to 0 on a UFS device.
1201
1202 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1203 @param[in] FlagId The ID of flag to be cleared.
1204
1205 @retval EFI_SUCCESS The flag was cleared successfully.
1206 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1207 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1208
1209 **/
1210 EFI_STATUS
1211 UfsClearFlag (
1212 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1213 IN UINT8 FlagId
1214 )
1215 {
1216 EFI_STATUS Status;
1217 UINT8 Value;
1218
1219 Value = 0;
1220 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1221
1222 return Status;
1223 }
1224
1225 /**
1226 Read specified flag from a UFS device.
1227
1228 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1229 @param[in] FlagId The ID of flag to be read.
1230 @param[out] Value The flag's value.
1231
1232 @retval EFI_SUCCESS The flag was read successfully.
1233 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1234 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1235
1236 **/
1237 EFI_STATUS
1238 UfsReadFlag (
1239 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1240 IN UINT8 FlagId,
1241 OUT UINT8 *Value
1242 )
1243 {
1244 EFI_STATUS Status;
1245
1246 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1247
1248 return Status;
1249 }
1250
1251 /**
1252 Sends NOP IN cmd to a UFS device for initialization process request.
1253 For more details, please refer to UFS 2.0 spec Figure 13.3.
1254
1255 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1256
1257 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1258 received successfully.
1259 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1260 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1261 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1262
1263 **/
1264 EFI_STATUS
1265 UfsExecNopCmds (
1266 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1267 )
1268 {
1269 EFI_STATUS Status;
1270 UINT8 Slot;
1271 UTP_TRD *Trd;
1272 UTP_NOP_IN_UPIU *NopInUpiu;
1273 UINT32 CmdDescSize;
1274 VOID *CmdDescHost;
1275 VOID *CmdDescMapping;
1276 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1277
1278 //
1279 // Find out which slot of transfer request list is available.
1280 //
1281 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1282 if (EFI_ERROR (Status)) {
1283 return Status;
1284 }
1285
1286 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1287 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);
1288 if (EFI_ERROR (Status)) {
1289 return Status;
1290 }
1291
1292 //
1293 // Check the transfer request result.
1294 //
1295 UfsHc = Private->UfsHostController;
1296 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
1297 ASSERT (NopInUpiu != NULL);
1298 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1299
1300 //
1301 // Start to execute the transfer request.
1302 //
1303 UfsStartExecCmd (Private, Slot);
1304
1305 //
1306 // Wait for the completion of the transfer request.
1307 //
1308 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);
1309 if (EFI_ERROR (Status)) {
1310 goto Exit;
1311 }
1312
1313 if (NopInUpiu->Resp != 0) {
1314 Status = EFI_DEVICE_ERROR;
1315 } else {
1316 Status = EFI_SUCCESS;
1317 }
1318
1319 Exit:
1320 UfsHc->Flush (UfsHc);
1321
1322 UfsStopExecCmd (Private, Slot);
1323
1324 if (CmdDescMapping != NULL) {
1325 UfsHc->Unmap (UfsHc, CmdDescMapping);
1326 }
1327 if (CmdDescHost != NULL) {
1328 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
1329 }
1330
1331 return Status;
1332 }
1333
1334 /**
1335 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1336
1337 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1338 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1339 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1340 UFS device.
1341 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1342 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1343 Event is not NULL and non blocking I/O is supported, then
1344 nonblocking I/O is performed, and Event will be signaled when the
1345 SCSI Request Packet completes.
1346
1347 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1348 commands, InTransferLength bytes were transferred from
1349 InDataBuffer. For write and bi-directional commands,
1350 OutTransferLength bytes were transferred by
1351 OutDataBuffer.
1352 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1353 Packet.
1354 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1355 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1356
1357 **/
1358 EFI_STATUS
1359 UfsExecScsiCmds (
1360 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1361 IN UINT8 Lun,
1362 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
1363 IN EFI_EVENT Event OPTIONAL
1364 )
1365 {
1366 EFI_STATUS Status;
1367 UTP_RESPONSE_UPIU *Response;
1368 UINT16 SenseDataLen;
1369 UINT32 ResTranCount;
1370 VOID *DataBuf;
1371 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;
1372 UINT32 DataLen;
1373 UINTN MapLength;
1374 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1375 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;
1376 UTP_TR_PRD *PrdtBase;
1377 EFI_TPL OldTpl;
1378 UFS_PASS_THRU_TRANS_REQ *TransReq;
1379
1380 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));
1381 if (TransReq == NULL) {
1382 return EFI_OUT_OF_RESOURCES;
1383 }
1384
1385 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;
1386 TransReq->TimeoutRemain = Packet->Timeout;
1387 DataBufPhyAddr = 0;
1388 UfsHc = Private->UfsHostController;
1389 //
1390 // Find out which slot of transfer request list is available.
1391 //
1392 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);
1393 if (EFI_ERROR (Status)) {
1394 return Status;
1395 }
1396
1397 TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;
1398
1399 //
1400 // Fill transfer request descriptor to this slot.
1401 //
1402 Status = UfsCreateScsiCommandDesc (
1403 Private,
1404 Lun,
1405 Packet,
1406 TransReq->Trd,
1407 &TransReq->CmdDescHost,
1408 &TransReq->CmdDescMapping
1409 );
1410 if (EFI_ERROR (Status)) {
1411 return Status;
1412 }
1413
1414 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);
1415
1416 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1417 DataBuf = Packet->InDataBuffer;
1418 DataLen = Packet->InTransferLength;
1419 Flag = EdkiiUfsHcOperationBusMasterWrite;
1420 } else {
1421 DataBuf = Packet->OutDataBuffer;
1422 DataLen = Packet->OutTransferLength;
1423 Flag = EdkiiUfsHcOperationBusMasterRead;
1424 }
1425
1426 if (DataLen != 0) {
1427 MapLength = DataLen;
1428 Status = UfsHc->Map (
1429 UfsHc,
1430 Flag,
1431 DataBuf,
1432 &MapLength,
1433 &DataBufPhyAddr,
1434 &TransReq->DataBufMapping
1435 );
1436
1437 if (EFI_ERROR (Status) || (DataLen != MapLength)) {
1438 goto Exit1;
1439 }
1440 }
1441 //
1442 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1443 //
1444 PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
1445 ASSERT (PrdtBase != NULL);
1446 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);
1447
1448 //
1449 // Insert the async SCSI cmd to the Async I/O list
1450 //
1451 if (Event != NULL) {
1452 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1453 TransReq->Packet = Packet;
1454 TransReq->CallerEvent = Event;
1455 InsertTailList (&Private->Queue, &TransReq->TransferList);
1456 gBS->RestoreTPL (OldTpl);
1457 }
1458
1459 //
1460 // Start to execute the transfer request.
1461 //
1462 UfsStartExecCmd (Private, TransReq->Slot);
1463
1464 //
1465 // Immediately return for async I/O.
1466 //
1467 if (Event != NULL) {
1468 return EFI_SUCCESS;
1469 }
1470
1471 //
1472 // Wait for the completion of the transfer request.
1473 //
1474 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);
1475 if (EFI_ERROR (Status)) {
1476 goto Exit;
1477 }
1478
1479 //
1480 // Get sense data if exists
1481 //
1482 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
1483 ASSERT (Response != NULL);
1484 SenseDataLen = Response->SenseDataLen;
1485 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
1486
1487 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1488 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1489 Packet->SenseDataLength = (UINT8)SenseDataLen;
1490 }
1491
1492 //
1493 // Check the transfer request result.
1494 //
1495 Packet->TargetStatus = Response->Status;
1496 if (Response->Response != 0) {
1497 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1498 Status = EFI_DEVICE_ERROR;
1499 goto Exit;
1500 }
1501
1502 if (TransReq->Trd->Ocs == 0) {
1503 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1504 if ((Response->Flags & BIT5) == BIT5) {
1505 ResTranCount = Response->ResTranCount;
1506 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1507 Packet->InTransferLength -= ResTranCount;
1508 }
1509 } else {
1510 if ((Response->Flags & BIT5) == BIT5) {
1511 ResTranCount = Response->ResTranCount;
1512 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1513 Packet->OutTransferLength -= ResTranCount;
1514 }
1515 }
1516 } else {
1517 Status = EFI_DEVICE_ERROR;
1518 }
1519
1520 Exit:
1521 UfsHc->Flush (UfsHc);
1522
1523 UfsStopExecCmd (Private, TransReq->Slot);
1524
1525 if (TransReq->DataBufMapping != NULL) {
1526 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
1527 }
1528
1529 Exit1:
1530 if (TransReq->CmdDescMapping != NULL) {
1531 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
1532 }
1533 if (TransReq->CmdDescHost != NULL) {
1534 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);
1535 }
1536 if (TransReq != NULL) {
1537 FreePool (TransReq);
1538 }
1539 return Status;
1540 }
1541
1542
1543 /**
1544 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1545
1546 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1547 @param[in] UicOpcode The opcode of the UIC command.
1548 @param[in] Arg1 The value for 1st argument of the UIC command.
1549 @param[in] Arg2 The value for 2nd argument of the UIC command.
1550 @param[in] Arg3 The value for 3rd argument of the UIC command.
1551
1552 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1553 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1554 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1555
1556 **/
1557 EFI_STATUS
1558 UfsExecUicCommands (
1559 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1560 IN UINT8 UicOpcode,
1561 IN UINT32 Arg1,
1562 IN UINT32 Arg2,
1563 IN UINT32 Arg3
1564 )
1565 {
1566 EFI_STATUS Status;
1567 UINT32 Data;
1568
1569 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);
1570 if (EFI_ERROR (Status)) {
1571 return Status;
1572 }
1573
1574 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1575 //
1576 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1577 //
1578 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);
1579 if (EFI_ERROR (Status)) {
1580 return Status;
1581 }
1582 }
1583
1584 //
1585 // When programming UIC command registers, host software shall set the register UICCMD
1586 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1587 // are set.
1588 //
1589 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, Arg1);
1590 if (EFI_ERROR (Status)) {
1591 return Status;
1592 }
1593
1594 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, Arg2);
1595 if (EFI_ERROR (Status)) {
1596 return Status;
1597 }
1598
1599 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, Arg3);
1600 if (EFI_ERROR (Status)) {
1601 return Status;
1602 }
1603
1604 //
1605 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1606 //
1607 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1608 if (EFI_ERROR (Status)) {
1609 return Status;
1610 }
1611
1612 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, (UINT32)UicOpcode);
1613 if (EFI_ERROR (Status)) {
1614 return Status;
1615 }
1616
1617 //
1618 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1619 // This bit is set to '1' by the host controller upon completion of a UIC command.
1620 //
1621 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1622 if (EFI_ERROR (Status)) {
1623 return Status;
1624 }
1625
1626 if (UicOpcode != UfsUicDmeReset) {
1627 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &Data);
1628 if (EFI_ERROR (Status)) {
1629 return Status;
1630 }
1631 if ((Data & 0xFF) != 0) {
1632 DEBUG_CODE_BEGIN();
1633 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
1634 DEBUG_CODE_END();
1635 return EFI_DEVICE_ERROR;
1636 }
1637 }
1638
1639 //
1640 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1641 //
1642 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);
1643 if (EFI_ERROR (Status)) {
1644 return Status;
1645 }
1646
1647 if ((Data & UFS_HC_HCS_DP) == 0) {
1648 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1649 if (EFI_ERROR (Status)) {
1650 return EFI_DEVICE_ERROR;
1651 }
1652 return EFI_NOT_FOUND;
1653 }
1654
1655 DEBUG ((DEBUG_INFO, "UfsPassThruDxe: found a attached UFS device\n"));
1656
1657 return EFI_SUCCESS;
1658 }
1659
1660 /**
1661 Allocate common buffer for host and UFS bus master access simultaneously.
1662
1663 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1664 @param[in] Size The length of buffer to be allocated.
1665 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1666 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1667 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1668
1669 @retval EFI_SUCCESS The common buffer was allocated successfully.
1670 @retval EFI_DEVICE_ERROR The allocation fails.
1671 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1672
1673 **/
1674 EFI_STATUS
1675 UfsAllocateAlignCommonBuffer (
1676 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1677 IN UINTN Size,
1678 OUT VOID **CmdDescHost,
1679 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,
1680 OUT VOID **CmdDescMapping
1681 )
1682 {
1683 EFI_STATUS Status;
1684 UINTN Bytes;
1685 BOOLEAN Is32BitAddr;
1686 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1687
1688 if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {
1689 Is32BitAddr = FALSE;
1690 } else {
1691 Is32BitAddr = TRUE;
1692 }
1693
1694 UfsHc = Private->UfsHostController;
1695 Status = UfsHc->AllocateBuffer (
1696 UfsHc,
1697 AllocateAnyPages,
1698 EfiBootServicesData,
1699 EFI_SIZE_TO_PAGES (Size),
1700 CmdDescHost,
1701 0
1702 );
1703 if (EFI_ERROR (Status)) {
1704 *CmdDescMapping = NULL;
1705 *CmdDescHost = NULL;
1706 *CmdDescPhyAddr = 0;
1707 return EFI_OUT_OF_RESOURCES;
1708 }
1709
1710 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));
1711 Status = UfsHc->Map (
1712 UfsHc,
1713 EdkiiUfsHcOperationBusMasterCommonBuffer,
1714 *CmdDescHost,
1715 &Bytes,
1716 CmdDescPhyAddr,
1717 CmdDescMapping
1718 );
1719
1720 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {
1721 UfsHc->FreeBuffer (
1722 UfsHc,
1723 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1724 *CmdDescHost
1725 );
1726 *CmdDescHost = NULL;
1727 return EFI_OUT_OF_RESOURCES;
1728 }
1729
1730 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {
1731 //
1732 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1733 //
1734 UfsHc->Unmap (
1735 UfsHc,
1736 *CmdDescMapping
1737 );
1738 UfsHc->FreeBuffer (
1739 UfsHc,
1740 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1741 *CmdDescHost
1742 );
1743 *CmdDescMapping = NULL;
1744 *CmdDescHost = NULL;
1745 return EFI_DEVICE_ERROR;
1746 }
1747
1748 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));
1749 return EFI_SUCCESS;
1750 }
1751
1752 /**
1753 Enable the UFS host controller for accessing.
1754
1755 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1756
1757 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1758 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1759
1760 **/
1761 EFI_STATUS
1762 UfsEnableHostController (
1763 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1764 )
1765 {
1766 EFI_STATUS Status;
1767 UINT32 Data;
1768
1769 //
1770 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1771 //
1772 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1773 //
1774 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
1775 if (EFI_ERROR (Status)) {
1776 return Status;
1777 }
1778
1779 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1780 //
1781 // Write a 0 to the HCE register at first to disable the host controller.
1782 //
1783 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
1784 if (EFI_ERROR (Status)) {
1785 return Status;
1786 }
1787 //
1788 // Wait until HCE is read as '0' before continuing.
1789 //
1790 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1791 if (EFI_ERROR (Status)) {
1792 return EFI_DEVICE_ERROR;
1793 }
1794 }
1795
1796 //
1797 // Write a 1 to the HCE register to enable the UFS host controller.
1798 //
1799 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);
1800 if (EFI_ERROR (Status)) {
1801 return Status;
1802 }
1803
1804 //
1805 // Wait until HCE is read as '1' before continuing.
1806 //
1807 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1808 if (EFI_ERROR (Status)) {
1809 return EFI_DEVICE_ERROR;
1810 }
1811
1812 return EFI_SUCCESS;
1813 }
1814
1815 /**
1816 Detect if a UFS device attached.
1817
1818 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1819
1820 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1821 @retval EFI_NOT_FOUND Not found a UFS device attached.
1822 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1823
1824 **/
1825 EFI_STATUS
1826 UfsDeviceDetection (
1827 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1828 )
1829 {
1830 UINTN Retry;
1831 EFI_STATUS Status;
1832
1833 //
1834 // Start UFS device detection.
1835 // Try up to 3 times for establishing data link with device.
1836 //
1837 for (Retry = 0; Retry < 3; Retry++) {
1838 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
1839 if (!EFI_ERROR (Status)) {
1840 break;
1841 }
1842
1843 if (Status == EFI_NOT_FOUND) {
1844 continue;
1845 }
1846
1847 return EFI_DEVICE_ERROR;
1848 }
1849
1850 if (Retry == 3) {
1851 return EFI_NOT_FOUND;
1852 }
1853
1854 return EFI_SUCCESS;
1855 }
1856
1857 /**
1858 Initialize UFS task management request list related h/w context.
1859
1860 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1861
1862 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1863 @retval EFI_DEVICE_ERROR The initialization fails.
1864
1865 **/
1866 EFI_STATUS
1867 UfsInitTaskManagementRequestList (
1868 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1869 )
1870 {
1871 UINT32 Data;
1872 UINT8 Nutmrs;
1873 VOID *CmdDescHost;
1874 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1875 VOID *CmdDescMapping;
1876 EFI_STATUS Status;
1877
1878 //
1879 // Initial h/w and s/w context for future operations.
1880 //
1881 CmdDescHost = NULL;
1882 CmdDescMapping = NULL;
1883 CmdDescPhyAddr = 0;
1884
1885 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
1886 if (EFI_ERROR (Status)) {
1887 return Status;
1888 }
1889
1890 Private->Capabilities = Data;
1891
1892 //
1893 // Allocate and initialize UTP Task Management Request List.
1894 //
1895 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1896 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
1897 if (EFI_ERROR (Status)) {
1898 return Status;
1899 }
1900
1901 //
1902 // Program the UTP Task Management Request List Base Address and UTP Task Management
1903 // Request List Base Address with a 64-bit address allocated at step 6.
1904 //
1905 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
1906 if (EFI_ERROR (Status)) {
1907 return Status;
1908 }
1909
1910 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
1911 if (EFI_ERROR (Status)) {
1912 return Status;
1913 }
1914 Private->UtpTmrlBase = CmdDescHost;
1915 Private->Nutmrs = Nutmrs;
1916 Private->TmrlMapping = CmdDescMapping;
1917
1918 //
1919 // Enable the UTP Task Management Request List by setting the UTP Task Management
1920 // Request List RunStop Register (UTMRLRSR) to '1'.
1921 //
1922 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);
1923 if (EFI_ERROR (Status)) {
1924 return Status;
1925 }
1926
1927 return EFI_SUCCESS;
1928 }
1929
1930 /**
1931 Initialize UFS transfer request list related h/w context.
1932
1933 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1934
1935 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1936 @retval EFI_DEVICE_ERROR The initialization fails.
1937
1938 **/
1939 EFI_STATUS
1940 UfsInitTransferRequestList (
1941 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1942 )
1943 {
1944 UINT32 Data;
1945 UINT8 Nutrs;
1946 VOID *CmdDescHost;
1947 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1948 VOID *CmdDescMapping;
1949 EFI_STATUS Status;
1950
1951 //
1952 // Initial h/w and s/w context for future operations.
1953 //
1954 CmdDescHost = NULL;
1955 CmdDescMapping = NULL;
1956 CmdDescPhyAddr = 0;
1957
1958 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
1959 if (EFI_ERROR (Status)) {
1960 return Status;
1961 }
1962
1963 Private->Capabilities = Data;
1964
1965 //
1966 // Allocate and initialize UTP Transfer Request List.
1967 //
1968 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
1969 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
1970 if (EFI_ERROR (Status)) {
1971 return Status;
1972 }
1973
1974 //
1975 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1976 // Base Address with a 64-bit address allocated at step 8.
1977 //
1978 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
1979 if (EFI_ERROR (Status)) {
1980 return Status;
1981 }
1982
1983 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
1984 if (EFI_ERROR (Status)) {
1985 return Status;
1986 }
1987
1988 Private->UtpTrlBase = CmdDescHost;
1989 Private->Nutrs = Nutrs;
1990 Private->TrlMapping = CmdDescMapping;
1991
1992 //
1993 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1994 // RunStop Register (UTRLRSR) to '1'.
1995 //
1996 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
1997 if (EFI_ERROR (Status)) {
1998 return Status;
1999 }
2000
2001 return EFI_SUCCESS;
2002 }
2003
2004 /**
2005 Initialize the UFS host controller.
2006
2007 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2008
2009 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2010 @retval Others A device error occurred while initializing the controller.
2011
2012 **/
2013 EFI_STATUS
2014 UfsControllerInit (
2015 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2016 )
2017 {
2018 EFI_STATUS Status;
2019
2020 Status = UfsEnableHostController (Private);
2021 if (EFI_ERROR (Status)) {
2022 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));
2023 return Status;
2024 }
2025
2026 Status = UfsDeviceDetection (Private);
2027 if (EFI_ERROR (Status)) {
2028 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));
2029 return Status;
2030 }
2031
2032 Status = UfsInitTaskManagementRequestList (Private);
2033 if (EFI_ERROR (Status)) {
2034 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));
2035 return Status;
2036 }
2037
2038 Status = UfsInitTransferRequestList (Private);
2039 if (EFI_ERROR (Status)) {
2040 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));
2041 return Status;
2042 }
2043
2044 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));
2045 return EFI_SUCCESS;
2046 }
2047
2048 /**
2049 Stop the UFS host controller.
2050
2051 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2052
2053 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2054 @retval Others A device error occurred while stopping the controller.
2055
2056 **/
2057 EFI_STATUS
2058 UfsControllerStop (
2059 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2060 )
2061 {
2062 EFI_STATUS Status;
2063 UINT32 Data;
2064
2065 //
2066 // Enable the UTP Task Management Request List by setting the UTP Task Management
2067 // Request List RunStop Register (UTMRLRSR) to '1'.
2068 //
2069 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);
2070 if (EFI_ERROR (Status)) {
2071 return Status;
2072 }
2073
2074 //
2075 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2076 // RunStop Register (UTRLRSR) to '1'.
2077 //
2078 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);
2079 if (EFI_ERROR (Status)) {
2080 return Status;
2081 }
2082
2083 //
2084 // Write a 0 to the HCE register in order to disable the host controller.
2085 //
2086 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
2087 if (EFI_ERROR (Status)) {
2088 return Status;
2089 }
2090 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
2091
2092 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
2093 if (EFI_ERROR (Status)) {
2094 return Status;
2095 }
2096
2097 //
2098 // Wait until HCE is read as '0' before continuing.
2099 //
2100 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
2101 if (EFI_ERROR (Status)) {
2102 return EFI_DEVICE_ERROR;
2103 }
2104
2105 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));
2106
2107 return EFI_SUCCESS;
2108 }
2109
2110
2111 /**
2112 Internal helper function which will signal the caller event and clean up
2113 resources.
2114
2115 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2116 structure.
2117 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2118 structure.
2119
2120 **/
2121 VOID
2122 EFIAPI
2123 SignalCallerEvent (
2124 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
2125 IN UFS_PASS_THRU_TRANS_REQ *TransReq
2126 )
2127 {
2128 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
2129 EFI_EVENT CallerEvent;
2130
2131 ASSERT ((Private != NULL) && (TransReq != NULL));
2132
2133 UfsHc = Private->UfsHostController;
2134 CallerEvent = TransReq->CallerEvent;
2135
2136 RemoveEntryList (&TransReq->TransferList);
2137
2138 UfsHc->Flush (UfsHc);
2139
2140 UfsStopExecCmd (Private, TransReq->Slot);
2141
2142 if (TransReq->DataBufMapping != NULL) {
2143 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
2144 }
2145
2146 if (TransReq->CmdDescMapping != NULL) {
2147 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
2148 }
2149 if (TransReq->CmdDescHost != NULL) {
2150 UfsHc->FreeBuffer (
2151 UfsHc,
2152 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),
2153 TransReq->CmdDescHost
2154 );
2155 }
2156
2157 FreePool (TransReq);
2158
2159 gBS->SignalEvent (CallerEvent);
2160 return;
2161 }
2162
2163 /**
2164 Call back function when the timer event is signaled.
2165
2166 @param[in] Event The Event this notify function registered to.
2167 @param[in] Context Pointer to the context data registered to the Event.
2168
2169 **/
2170 VOID
2171 EFIAPI
2172 ProcessAsyncTaskList (
2173 IN EFI_EVENT Event,
2174 IN VOID *Context
2175 )
2176 {
2177 UFS_PASS_THRU_PRIVATE_DATA *Private;
2178 LIST_ENTRY *Entry;
2179 LIST_ENTRY *NextEntry;
2180 UFS_PASS_THRU_TRANS_REQ *TransReq;
2181 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;
2182 UTP_RESPONSE_UPIU *Response;
2183 UINT16 SenseDataLen;
2184 UINT32 ResTranCount;
2185 UINT32 SlotsMap;
2186 UINT32 Value;
2187 EFI_STATUS Status;
2188
2189 Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;
2190 SlotsMap = 0;
2191
2192 //
2193 // Check the entries in the async I/O queue are done or not.
2194 //
2195 if (!IsListEmpty(&Private->Queue)) {
2196 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
2197 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
2198 Packet = TransReq->Packet;
2199
2200 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {
2201 return;
2202 }
2203 SlotsMap |= BIT0 << TransReq->Slot;
2204
2205 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);
2206 if (EFI_ERROR (Status)) {
2207 //
2208 // TODO: Should find/add a proper host adapter return status for this
2209 // case.
2210 //
2211 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
2212 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));
2213 SignalCallerEvent (Private, TransReq);
2214 continue;
2215 }
2216
2217 if ((Value & (BIT0 << TransReq->Slot)) != 0) {
2218 //
2219 // Scsi cmd not finished yet.
2220 //
2221 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {
2222 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;
2223 continue;
2224 } else {
2225 //
2226 // Timeout occurs.
2227 //
2228 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
2229 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));
2230 SignalCallerEvent (Private, TransReq);
2231 continue;
2232 }
2233 } else {
2234 //
2235 // Scsi cmd finished.
2236 //
2237 // Get sense data if exists
2238 //
2239 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
2240 ASSERT (Response != NULL);
2241 SenseDataLen = Response->SenseDataLen;
2242 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
2243
2244 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
2245 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
2246 Packet->SenseDataLength = (UINT8)SenseDataLen;
2247 }
2248
2249 //
2250 // Check the transfer request result.
2251 //
2252 Packet->TargetStatus = Response->Status;
2253 if (Response->Response != 0) {
2254 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));
2255 SignalCallerEvent (Private, TransReq);
2256 continue;
2257 }
2258
2259 if (TransReq->Trd->Ocs == 0) {
2260 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
2261 if ((Response->Flags & BIT5) == BIT5) {
2262 ResTranCount = Response->ResTranCount;
2263 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2264 Packet->InTransferLength -= ResTranCount;
2265 }
2266 } else {
2267 if ((Response->Flags & BIT5) == BIT5) {
2268 ResTranCount = Response->ResTranCount;
2269 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2270 Packet->OutTransferLength -= ResTranCount;
2271 }
2272 }
2273 } else {
2274 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));
2275 SignalCallerEvent (Private, TransReq);
2276 continue;
2277 }
2278
2279 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));
2280 SignalCallerEvent (Private, TransReq);
2281 }
2282 }
2283 }
2284 }
2285