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