]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
MdeModulePkg: Clean up source files
[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 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 SwapLittleEndianToBigEndian ((UINT8*)&DataSize, sizeof (UINT16));
483 QueryReq->DataSegLen = (UINT16)DataSize;
484 }
485
486 return EFI_SUCCESS;
487 }
488
489 /**
490 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
491
492 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
493 @param[in] Lun The Lun on which the SCSI command is executed.
494 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
495 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
496 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
497 @param[out] CmdDescMapping A resulting value to pass to Unmap().
498
499 @retval EFI_SUCCESS The creation succeed.
500 @retval EFI_DEVICE_ERROR The creation failed.
501 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
502
503 **/
504 EFI_STATUS
505 UfsCreateScsiCommandDesc (
506 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
507 IN UINT8 Lun,
508 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
509 IN UTP_TRD *Trd,
510 OUT VOID **CmdDescHost,
511 OUT VOID **CmdDescMapping
512 )
513 {
514 UINTN TotalLen;
515 UINTN PrdtNumber;
516 UTP_COMMAND_UPIU *CommandUpiu;
517 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
518 EFI_STATUS Status;
519 UINT32 DataLen;
520 UFS_DATA_DIRECTION DataDirection;
521
522 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
523
524 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
525 DataLen = Packet->InTransferLength;
526 DataDirection = UfsDataIn;
527 } else {
528 DataLen = Packet->OutTransferLength;
529 DataDirection = UfsDataOut;
530 }
531
532 if (DataLen == 0) {
533 DataDirection = UfsNoData;
534 }
535
536 PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
537
538 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
539
540 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
541 if (EFI_ERROR (Status)) {
542 return Status;
543 }
544
545 CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;
546
547 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);
548
549 //
550 // Fill UTP_TRD associated fields
551 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
552 // *MUST* be located at a 64-bit aligned boundary.
553 //
554 Trd->Int = UFS_INTERRUPT_COMMAND;
555 Trd->Dd = DataDirection;
556 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
557 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
558 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
559 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
560 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
561 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
562 Trd->PrdtL = (UINT16)PrdtNumber;
563 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
564 return EFI_SUCCESS;
565 }
566
567 /**
568 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
569
570 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
571 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
572 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
573 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
574 @param[out] CmdDescMapping A resulting value to pass to Unmap().
575
576 @retval EFI_SUCCESS The creation succeed.
577 @retval EFI_DEVICE_ERROR The creation failed.
578 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
579 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
580
581 **/
582 EFI_STATUS
583 UfsCreateDMCommandDesc (
584 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
585 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
586 IN UTP_TRD *Trd,
587 OUT VOID **CmdDescHost,
588 OUT VOID **CmdDescMapping
589 )
590 {
591 UINTN TotalLen;
592 UTP_QUERY_REQ_UPIU *QueryReqUpiu;
593 UINT8 Opcode;
594 UINT32 DataSize;
595 UINT8 *Data;
596 UINT8 DataDirection;
597 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
598 EFI_STATUS Status;
599
600 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
601
602 Opcode = Packet->Opcode;
603 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
604 return EFI_INVALID_PARAMETER;
605 }
606
607 DataDirection = Packet->DataDirection;
608 DataSize = Packet->TransferLength;
609 Data = Packet->DataBuffer;
610
611 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
612 if (DataSize == 0 || Data == NULL) {
613 return EFI_INVALID_PARAMETER;
614 }
615 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
616 } else {
617 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
618 }
619
620 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
621 if (EFI_ERROR (Status)) {
622 return Status;
623 }
624
625 //
626 // Initialize UTP QUERY REQUEST UPIU
627 //
628 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;
629 ASSERT (QueryReqUpiu != NULL);
630 UfsInitQueryRequestUpiu (
631 QueryReqUpiu,
632 Private->TaskTag++,
633 Opcode,
634 Packet->DescId,
635 Packet->Index,
636 Packet->Selector,
637 DataSize,
638 Data
639 );
640
641 //
642 // Fill UTP_TRD associated fields
643 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
644 //
645 Trd->Int = UFS_INTERRUPT_COMMAND;
646 Trd->Dd = DataDirection;
647 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
648 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
649 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
650 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
651 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
652 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
653 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
654 } else {
655 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
656 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
657 }
658
659 return EFI_SUCCESS;
660 }
661
662 /**
663 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
664
665 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
666 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
667 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
668 @param[out] CmdDescMapping A resulting value to pass to Unmap().
669
670 @retval EFI_SUCCESS The creation succeed.
671 @retval EFI_DEVICE_ERROR The creation failed.
672 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
673
674 **/
675 EFI_STATUS
676 UfsCreateNopCommandDesc (
677 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
678 IN UTP_TRD *Trd,
679 OUT VOID **CmdDescHost,
680 OUT VOID **CmdDescMapping
681 )
682 {
683 UINTN TotalLen;
684 UTP_NOP_OUT_UPIU *NopOutUpiu;
685 EFI_STATUS Status;
686 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
687
688 ASSERT ((Private != NULL) && (Trd != NULL));
689
690 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
691 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
692 if (EFI_ERROR (Status)) {
693 return Status;
694 }
695
696 NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;
697 ASSERT (NopOutUpiu != NULL);
698 NopOutUpiu->TaskTag = Private->TaskTag++;
699
700 //
701 // Fill UTP_TRD associated fields
702 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
703 //
704 Trd->Int = UFS_INTERRUPT_COMMAND;
705 Trd->Dd = 0x00;
706 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
707 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
708 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
709 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
710 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
711 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
712
713 return EFI_SUCCESS;
714 }
715
716 /**
717 Find out available slot in transfer list of a UFS device.
718
719 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
720 @param[out] Slot The available slot.
721
722 @retval EFI_SUCCESS The available slot was found successfully.
723 @retval EFI_NOT_READY No slot is available at this moment.
724
725 **/
726 EFI_STATUS
727 UfsFindAvailableSlotInTrl (
728 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
729 OUT UINT8 *Slot
730 )
731 {
732 UINT8 Nutrs;
733 UINT8 Index;
734 UINT32 Data;
735 EFI_STATUS Status;
736
737 ASSERT ((Private != NULL) && (Slot != NULL));
738
739 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
740 if (EFI_ERROR (Status)) {
741 return Status;
742 }
743
744 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
745
746 for (Index = 0; Index < Nutrs; Index++) {
747 if ((Data & (BIT0 << Index)) == 0) {
748 *Slot = Index;
749 return EFI_SUCCESS;
750 }
751 }
752
753 return EFI_NOT_READY;
754 }
755
756 /**
757 Find out available slot in task management transfer list of a UFS device.
758
759 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
760 @param[out] Slot The available slot.
761
762 @retval EFI_SUCCESS The available slot was found successfully.
763
764 **/
765 EFI_STATUS
766 UfsFindAvailableSlotInTmrl (
767 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
768 OUT UINT8 *Slot
769 )
770 {
771 ASSERT ((Private != NULL) && (Slot != NULL));
772
773 //
774 // The simplest algo to always use slot 0.
775 // TODO: enhance it to support async transfer with multiple slot.
776 //
777 *Slot = 0;
778
779 return EFI_SUCCESS;
780 }
781
782 /**
783 Start specified slot in transfer list of a UFS device.
784
785 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
786 @param[in] Slot The slot to be started.
787
788 **/
789 EFI_STATUS
790 UfsStartExecCmd (
791 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
792 IN UINT8 Slot
793 )
794 {
795 UINT32 Data;
796 EFI_STATUS Status;
797
798 Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);
799 if (EFI_ERROR (Status)) {
800 return Status;
801 }
802
803 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
804 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
805 if (EFI_ERROR (Status)) {
806 return Status;
807 }
808 }
809
810 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);
811 if (EFI_ERROR (Status)) {
812 return Status;
813 }
814
815 return EFI_SUCCESS;
816 }
817
818 /**
819 Stop specified slot in transfer list of a UFS device.
820
821 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
822 @param[in] Slot The slot to be stop.
823
824 **/
825 EFI_STATUS
826 UfsStopExecCmd (
827 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
828 IN UINT8 Slot
829 )
830 {
831 UINT32 Data;
832 EFI_STATUS Status;
833
834 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
835 if (EFI_ERROR (Status)) {
836 return Status;
837 }
838
839 if ((Data & (BIT0 << Slot)) != 0) {
840 Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);
841 if (EFI_ERROR (Status)) {
842 return Status;
843 }
844
845 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));
846 if (EFI_ERROR (Status)) {
847 return Status;
848 }
849 }
850
851 return EFI_SUCCESS;
852 }
853
854 /**
855 Extracts return data from query response upiu.
856
857 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
858 @param[in] QueryResp Pointer to the query response.
859
860 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
861 @retval EFI_SUCCESS Data extracted.
862
863 **/
864 EFI_STATUS
865 UfsGetReturnDataFromQueryResponse (
866 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
867 IN UTP_QUERY_RESP_UPIU *QueryResp
868 )
869 {
870 UINT16 ReturnDataSize;
871 UINT32 ReturnData;
872
873 if (Packet == NULL || QueryResp == NULL) {
874 return EFI_INVALID_PARAMETER;
875 }
876
877 switch (Packet->Opcode) {
878 case UtpQueryFuncOpcodeRdDesc:
879 ReturnDataSize = QueryResp->Tsf.Length;
880 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
881 CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);
882 Packet->TransferLength = ReturnDataSize;
883 break;
884 case UtpQueryFuncOpcodeWrDesc:
885 ReturnDataSize = QueryResp->Tsf.Length;
886 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
887 Packet->TransferLength = ReturnDataSize;
888 break;
889 case UtpQueryFuncOpcodeRdFlag:
890 case UtpQueryFuncOpcodeSetFlag:
891 case UtpQueryFuncOpcodeClrFlag:
892 case UtpQueryFuncOpcodeTogFlag:
893 CopyMem (Packet->DataBuffer, &QueryResp->Tsf.Value, sizeof (UINT8));
894 break;
895 case UtpQueryFuncOpcodeRdAttr:
896 case UtpQueryFuncOpcodeWrAttr:
897 ReturnData = QueryResp->Tsf.Value;
898 SwapLittleEndianToBigEndian ((UINT8*) &ReturnData, sizeof (UINT32));
899 CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));
900 break;
901 default:
902 return EFI_INVALID_PARAMETER;
903 }
904
905 return EFI_SUCCESS;
906 }
907
908 /**
909 Creates Transfer Request descriptor and sends Query Request to the device.
910
911 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
912 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
913
914 @retval EFI_SUCCESS The device descriptor was read/written successfully.
915 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
916 combination to point to a type of UFS device descriptor.
917 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
918 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
919
920 **/
921 EFI_STATUS
922 UfsSendDmRequestRetry (
923 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
924 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
925 )
926 {
927 UINT8 Slot;
928 UTP_TRD *Trd;
929 VOID *CmdDescHost;
930 VOID *CmdDescMapping;
931 UINT32 CmdDescSize;
932 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
933 UTP_QUERY_RESP_UPIU *QueryResp;
934 EFI_STATUS Status;
935
936 //
937 // Find out which slot of transfer request list is available.
938 //
939 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
940 if (EFI_ERROR (Status)) {
941 return Status;
942 }
943
944 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
945 //
946 // Fill transfer request descriptor to this slot.
947 //
948 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);
949 if (EFI_ERROR (Status)) {
950 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));
951 return Status;
952 }
953
954 UfsHc = Private->UfsHostController;
955 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
956 ASSERT (QueryResp != NULL);
957 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
958
959 //
960 // Start to execute the transfer request.
961 //
962 UfsStartExecCmd (Private, Slot);
963
964 //
965 // Wait for the completion of the transfer request.
966 //
967 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);
968 if (EFI_ERROR (Status)) {
969 goto Exit;
970 }
971
972 if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {
973 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));
974 DumpQueryResponseResult (QueryResp->QueryResp);
975
976 if ((QueryResp->QueryResp == UfsUtpQueryResponseInvalidSelector) ||
977 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIndex) ||
978 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIdn)) {
979 Status = EFI_INVALID_PARAMETER;
980 } else {
981 Status = EFI_DEVICE_ERROR;
982 }
983 goto Exit;
984 }
985
986 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);
987 if (EFI_ERROR (Status)) {
988 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));
989 goto Exit;
990 }
991
992 Exit:
993 UfsHc->Flush (UfsHc);
994
995 UfsStopExecCmd (Private, Slot);
996
997 if (CmdDescMapping != NULL) {
998 UfsHc->Unmap (UfsHc, CmdDescMapping);
999 }
1000 if (CmdDescHost != NULL) {
1001 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
1002 }
1003
1004 return Status;
1005 }
1006
1007 /**
1008 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
1009
1010 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
1011 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
1012
1013 @retval EFI_SUCCESS The device responded correctly to the Query request.
1014 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
1015 combination to point to a type of UFS device descriptor.
1016 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
1017 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
1018
1019 **/
1020 EFI_STATUS
1021 UfsSendDmRequest (
1022 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1023 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
1024 )
1025 {
1026 EFI_STATUS Status;
1027 UINT8 Retry;
1028
1029 Status = EFI_SUCCESS;
1030
1031 for (Retry = 0; Retry < 5; Retry ++) {
1032 Status = UfsSendDmRequestRetry (Private, Packet);
1033 if (!EFI_ERROR (Status)) {
1034 return EFI_SUCCESS;
1035 }
1036 }
1037
1038 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));
1039 return Status;
1040 }
1041
1042 /**
1043 Read or write specified device descriptor of a UFS device.
1044
1045 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1046 @param[in] Read The boolean variable to show r/w direction.
1047 @param[in] DescId The ID of device descriptor.
1048 @param[in] Index The Index of device descriptor.
1049 @param[in] Selector The Selector of device descriptor.
1050 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1051 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1052 of the data buffer specified by Descriptor. On output, the number
1053 of bytes that were actually transferred.
1054
1055 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1056 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1057 type of UFS device descriptor.
1058 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1059 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1060
1061 **/
1062 EFI_STATUS
1063 UfsRwDeviceDesc (
1064 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1065 IN BOOLEAN Read,
1066 IN UINT8 DescId,
1067 IN UINT8 Index,
1068 IN UINT8 Selector,
1069 IN OUT VOID *Descriptor,
1070 IN OUT UINT32 *DescSize
1071 )
1072 {
1073 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1074 EFI_STATUS Status;
1075
1076 if (DescSize == NULL) {
1077 return EFI_INVALID_PARAMETER;
1078 }
1079
1080 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1081
1082 if (Read) {
1083 Packet.DataDirection = UfsDataIn;
1084 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
1085 } else {
1086 Packet.DataDirection = UfsDataOut;
1087 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
1088 }
1089 Packet.DataBuffer = Descriptor;
1090 Packet.TransferLength = *DescSize;
1091 Packet.DescId = DescId;
1092 Packet.Index = Index;
1093 Packet.Selector = Selector;
1094 Packet.Timeout = UFS_TIMEOUT;
1095
1096 Status = UfsSendDmRequest (Private, &Packet);
1097 if (EFI_ERROR (Status)) {
1098 *DescSize = 0;
1099 } else {
1100 *DescSize = Packet.TransferLength;
1101 }
1102
1103 return Status;
1104 }
1105
1106 /**
1107 Read or write specified attribute of a UFS device.
1108
1109 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1110 @param[in] Read The boolean variable to show r/w direction.
1111 @param[in] AttrId The ID of Attribute.
1112 @param[in] Index The Index of Attribute.
1113 @param[in] Selector The Selector of Attribute.
1114 @param[in, out] Attributes The value of Attribute to be read or written.
1115
1116 @retval EFI_SUCCESS The Attribute was read/written successfully.
1117 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1118 type of UFS device descriptor.
1119 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1120 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1121
1122 **/
1123 EFI_STATUS
1124 UfsRwAttributes (
1125 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1126 IN BOOLEAN Read,
1127 IN UINT8 AttrId,
1128 IN UINT8 Index,
1129 IN UINT8 Selector,
1130 IN OUT UINT32 *Attributes
1131 )
1132 {
1133 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1134
1135 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1136
1137 if (Read) {
1138 Packet.DataDirection = UfsDataIn;
1139 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
1140 } else {
1141 Packet.DataDirection = UfsDataOut;
1142 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
1143 }
1144 Packet.DataBuffer = Attributes;
1145 Packet.DescId = AttrId;
1146 Packet.Index = Index;
1147 Packet.Selector = Selector;
1148 Packet.Timeout = UFS_TIMEOUT;
1149
1150 return UfsSendDmRequest (Private, &Packet);
1151 }
1152
1153 /**
1154 Read or write specified flag of a UFS device.
1155
1156 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1157 @param[in] Read The boolean variable to show r/w direction.
1158 @param[in] FlagId The ID of flag to be read or written.
1159 @param[in, out] Value The value to set or clear flag.
1160
1161 @retval EFI_SUCCESS The flag was read/written successfully.
1162 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1163 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1164 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1165
1166 **/
1167 EFI_STATUS
1168 UfsRwFlags (
1169 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1170 IN BOOLEAN Read,
1171 IN UINT8 FlagId,
1172 IN OUT UINT8 *Value
1173 )
1174 {
1175 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1176
1177 if (Value == NULL) {
1178 return EFI_INVALID_PARAMETER;
1179 }
1180
1181 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1182
1183 if (Read) {
1184 ASSERT (Value != NULL);
1185 Packet.DataDirection = UfsDataIn;
1186 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1187 } else {
1188 Packet.DataDirection = UfsDataOut;
1189 if (*Value == 1) {
1190 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1191 } else if (*Value == 0) {
1192 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1193 } else {
1194 return EFI_INVALID_PARAMETER;
1195 }
1196 }
1197 Packet.DataBuffer = Value;
1198 Packet.DescId = FlagId;
1199 Packet.Index = 0;
1200 Packet.Selector = 0;
1201 Packet.Timeout = UFS_TIMEOUT;
1202
1203 return UfsSendDmRequest (Private, &Packet);
1204 }
1205
1206 /**
1207 Set specified flag to 1 on a UFS device.
1208
1209 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1210 @param[in] FlagId The ID of flag to be set.
1211
1212 @retval EFI_SUCCESS The flag was set successfully.
1213 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1214 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1215
1216 **/
1217 EFI_STATUS
1218 UfsSetFlag (
1219 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1220 IN UINT8 FlagId
1221 )
1222 {
1223 EFI_STATUS Status;
1224 UINT8 Value;
1225
1226 Value = 1;
1227 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1228
1229 return Status;
1230 }
1231
1232 /**
1233 Clear specified flag to 0 on a UFS device.
1234
1235 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1236 @param[in] FlagId The ID of flag to be cleared.
1237
1238 @retval EFI_SUCCESS The flag was cleared successfully.
1239 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1240 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1241
1242 **/
1243 EFI_STATUS
1244 UfsClearFlag (
1245 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1246 IN UINT8 FlagId
1247 )
1248 {
1249 EFI_STATUS Status;
1250 UINT8 Value;
1251
1252 Value = 0;
1253 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1254
1255 return Status;
1256 }
1257
1258 /**
1259 Read specified flag from a UFS device.
1260
1261 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1262 @param[in] FlagId The ID of flag to be read.
1263 @param[out] Value The flag's value.
1264
1265 @retval EFI_SUCCESS The flag was read successfully.
1266 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1267 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1268
1269 **/
1270 EFI_STATUS
1271 UfsReadFlag (
1272 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1273 IN UINT8 FlagId,
1274 OUT UINT8 *Value
1275 )
1276 {
1277 EFI_STATUS Status;
1278
1279 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1280
1281 return Status;
1282 }
1283
1284 /**
1285 Sends NOP IN cmd to a UFS device for initialization process request.
1286 For more details, please refer to UFS 2.0 spec Figure 13.3.
1287
1288 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1289
1290 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1291 received successfully.
1292 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1293 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1294 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1295
1296 **/
1297 EFI_STATUS
1298 UfsExecNopCmds (
1299 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1300 )
1301 {
1302 EFI_STATUS Status;
1303 UINT8 Slot;
1304 UTP_TRD *Trd;
1305 UTP_NOP_IN_UPIU *NopInUpiu;
1306 UINT32 CmdDescSize;
1307 VOID *CmdDescHost;
1308 VOID *CmdDescMapping;
1309 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1310
1311 //
1312 // Find out which slot of transfer request list is available.
1313 //
1314 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1315 if (EFI_ERROR (Status)) {
1316 return Status;
1317 }
1318
1319 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1320 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);
1321 if (EFI_ERROR (Status)) {
1322 return Status;
1323 }
1324
1325 //
1326 // Check the transfer request result.
1327 //
1328 UfsHc = Private->UfsHostController;
1329 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
1330 ASSERT (NopInUpiu != NULL);
1331 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1332
1333 //
1334 // Start to execute the transfer request.
1335 //
1336 UfsStartExecCmd (Private, Slot);
1337
1338 //
1339 // Wait for the completion of the transfer request.
1340 //
1341 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);
1342 if (EFI_ERROR (Status)) {
1343 goto Exit;
1344 }
1345
1346 if (NopInUpiu->Resp != 0) {
1347 Status = EFI_DEVICE_ERROR;
1348 } else {
1349 Status = EFI_SUCCESS;
1350 }
1351
1352 Exit:
1353 UfsHc->Flush (UfsHc);
1354
1355 UfsStopExecCmd (Private, Slot);
1356
1357 if (CmdDescMapping != NULL) {
1358 UfsHc->Unmap (UfsHc, CmdDescMapping);
1359 }
1360 if (CmdDescHost != NULL) {
1361 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
1362 }
1363
1364 return Status;
1365 }
1366
1367 /**
1368 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1369
1370 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1371 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1372 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1373 UFS device.
1374 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1375 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1376 Event is not NULL and non blocking I/O is supported, then
1377 nonblocking I/O is performed, and Event will be signaled when the
1378 SCSI Request Packet completes.
1379
1380 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1381 commands, InTransferLength bytes were transferred from
1382 InDataBuffer. For write and bi-directional commands,
1383 OutTransferLength bytes were transferred by
1384 OutDataBuffer.
1385 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1386 Packet.
1387 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1388 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1389
1390 **/
1391 EFI_STATUS
1392 UfsExecScsiCmds (
1393 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1394 IN UINT8 Lun,
1395 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
1396 IN EFI_EVENT Event OPTIONAL
1397 )
1398 {
1399 EFI_STATUS Status;
1400 UTP_RESPONSE_UPIU *Response;
1401 UINT16 SenseDataLen;
1402 UINT32 ResTranCount;
1403 VOID *DataBuf;
1404 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;
1405 UINT32 DataLen;
1406 UINTN MapLength;
1407 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1408 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;
1409 UTP_TR_PRD *PrdtBase;
1410 EFI_TPL OldTpl;
1411 UFS_PASS_THRU_TRANS_REQ *TransReq;
1412
1413 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));
1414 if (TransReq == NULL) {
1415 return EFI_OUT_OF_RESOURCES;
1416 }
1417
1418 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;
1419 TransReq->TimeoutRemain = Packet->Timeout;
1420 DataBufPhyAddr = 0;
1421 UfsHc = Private->UfsHostController;
1422 //
1423 // Find out which slot of transfer request list is available.
1424 //
1425 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);
1426 if (EFI_ERROR (Status)) {
1427 return Status;
1428 }
1429
1430 TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;
1431
1432 //
1433 // Fill transfer request descriptor to this slot.
1434 //
1435 Status = UfsCreateScsiCommandDesc (
1436 Private,
1437 Lun,
1438 Packet,
1439 TransReq->Trd,
1440 &TransReq->CmdDescHost,
1441 &TransReq->CmdDescMapping
1442 );
1443 if (EFI_ERROR (Status)) {
1444 return Status;
1445 }
1446
1447 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);
1448
1449 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1450 DataBuf = Packet->InDataBuffer;
1451 DataLen = Packet->InTransferLength;
1452 Flag = EdkiiUfsHcOperationBusMasterWrite;
1453 } else {
1454 DataBuf = Packet->OutDataBuffer;
1455 DataLen = Packet->OutTransferLength;
1456 Flag = EdkiiUfsHcOperationBusMasterRead;
1457 }
1458
1459 if (DataLen != 0) {
1460 MapLength = DataLen;
1461 Status = UfsHc->Map (
1462 UfsHc,
1463 Flag,
1464 DataBuf,
1465 &MapLength,
1466 &DataBufPhyAddr,
1467 &TransReq->DataBufMapping
1468 );
1469
1470 if (EFI_ERROR (Status) || (DataLen != MapLength)) {
1471 goto Exit1;
1472 }
1473 }
1474 //
1475 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1476 //
1477 PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
1478 ASSERT (PrdtBase != NULL);
1479 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);
1480
1481 //
1482 // Insert the async SCSI cmd to the Async I/O list
1483 //
1484 if (Event != NULL) {
1485 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1486 TransReq->Packet = Packet;
1487 TransReq->CallerEvent = Event;
1488 InsertTailList (&Private->Queue, &TransReq->TransferList);
1489 gBS->RestoreTPL (OldTpl);
1490 }
1491
1492 //
1493 // Start to execute the transfer request.
1494 //
1495 UfsStartExecCmd (Private, TransReq->Slot);
1496
1497 //
1498 // Immediately return for async I/O.
1499 //
1500 if (Event != NULL) {
1501 return EFI_SUCCESS;
1502 }
1503
1504 //
1505 // Wait for the completion of the transfer request.
1506 //
1507 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);
1508 if (EFI_ERROR (Status)) {
1509 goto Exit;
1510 }
1511
1512 //
1513 // Get sense data if exists
1514 //
1515 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
1516 ASSERT (Response != NULL);
1517 SenseDataLen = Response->SenseDataLen;
1518 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
1519
1520 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1521 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1522 Packet->SenseDataLength = (UINT8)SenseDataLen;
1523 }
1524
1525 //
1526 // Check the transfer request result.
1527 //
1528 Packet->TargetStatus = Response->Status;
1529 if (Response->Response != 0) {
1530 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1531 Status = EFI_DEVICE_ERROR;
1532 goto Exit;
1533 }
1534
1535 if (TransReq->Trd->Ocs == 0) {
1536 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
1537 if ((Response->Flags & BIT5) == BIT5) {
1538 ResTranCount = Response->ResTranCount;
1539 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1540 Packet->InTransferLength -= ResTranCount;
1541 }
1542 } else {
1543 if ((Response->Flags & BIT5) == BIT5) {
1544 ResTranCount = Response->ResTranCount;
1545 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1546 Packet->OutTransferLength -= ResTranCount;
1547 }
1548 }
1549 } else {
1550 Status = EFI_DEVICE_ERROR;
1551 }
1552
1553 Exit:
1554 UfsHc->Flush (UfsHc);
1555
1556 UfsStopExecCmd (Private, TransReq->Slot);
1557
1558 if (TransReq->DataBufMapping != NULL) {
1559 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
1560 }
1561
1562 Exit1:
1563 if (TransReq->CmdDescMapping != NULL) {
1564 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
1565 }
1566 if (TransReq->CmdDescHost != NULL) {
1567 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);
1568 }
1569 if (TransReq != NULL) {
1570 FreePool (TransReq);
1571 }
1572 return Status;
1573 }
1574
1575
1576 /**
1577 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1578
1579 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1580 @param[in] UicOpcode The opcode of the UIC command.
1581 @param[in] Arg1 The value for 1st argument of the UIC command.
1582 @param[in] Arg2 The value for 2nd argument of the UIC command.
1583 @param[in] Arg3 The value for 3rd argument of the UIC command.
1584
1585 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1586 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1587 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1588
1589 **/
1590 EFI_STATUS
1591 UfsExecUicCommands (
1592 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1593 IN UINT8 UicOpcode,
1594 IN UINT32 Arg1,
1595 IN UINT32 Arg2,
1596 IN UINT32 Arg3
1597 )
1598 {
1599 EFI_STATUS Status;
1600 UINT32 Data;
1601
1602 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);
1603 if (EFI_ERROR (Status)) {
1604 return Status;
1605 }
1606
1607 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1608 //
1609 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1610 //
1611 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);
1612 if (EFI_ERROR (Status)) {
1613 return Status;
1614 }
1615 }
1616
1617 //
1618 // When programming UIC command registers, host software shall set the register UICCMD
1619 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1620 // are set.
1621 //
1622 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, Arg1);
1623 if (EFI_ERROR (Status)) {
1624 return Status;
1625 }
1626
1627 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, Arg2);
1628 if (EFI_ERROR (Status)) {
1629 return Status;
1630 }
1631
1632 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, Arg3);
1633 if (EFI_ERROR (Status)) {
1634 return Status;
1635 }
1636
1637 //
1638 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1639 //
1640 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1641 if (EFI_ERROR (Status)) {
1642 return Status;
1643 }
1644
1645 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, (UINT32)UicOpcode);
1646 if (EFI_ERROR (Status)) {
1647 return Status;
1648 }
1649
1650 //
1651 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1652 // This bit is set to '1' by the host controller upon completion of a UIC command.
1653 //
1654 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1655 if (EFI_ERROR (Status)) {
1656 return Status;
1657 }
1658
1659 if (UicOpcode != UfsUicDmeReset) {
1660 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &Data);
1661 if (EFI_ERROR (Status)) {
1662 return Status;
1663 }
1664 if ((Data & 0xFF) != 0) {
1665 DEBUG_CODE_BEGIN();
1666 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
1667 DEBUG_CODE_END();
1668 return EFI_DEVICE_ERROR;
1669 }
1670 }
1671
1672 //
1673 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1674 //
1675 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);
1676 if (EFI_ERROR (Status)) {
1677 return Status;
1678 }
1679
1680 if ((Data & UFS_HC_HCS_DP) == 0) {
1681 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1682 if (EFI_ERROR (Status)) {
1683 return EFI_DEVICE_ERROR;
1684 }
1685 return EFI_NOT_FOUND;
1686 }
1687
1688 DEBUG ((DEBUG_INFO, "UfsPassThruDxe: found a attached UFS device\n"));
1689
1690 return EFI_SUCCESS;
1691 }
1692
1693 /**
1694 Allocate common buffer for host and UFS bus master access simultaneously.
1695
1696 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1697 @param[in] Size The length of buffer to be allocated.
1698 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1699 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1700 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1701
1702 @retval EFI_SUCCESS The common buffer was allocated successfully.
1703 @retval EFI_DEVICE_ERROR The allocation fails.
1704 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1705
1706 **/
1707 EFI_STATUS
1708 UfsAllocateAlignCommonBuffer (
1709 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
1710 IN UINTN Size,
1711 OUT VOID **CmdDescHost,
1712 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,
1713 OUT VOID **CmdDescMapping
1714 )
1715 {
1716 EFI_STATUS Status;
1717 UINTN Bytes;
1718 BOOLEAN Is32BitAddr;
1719 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
1720
1721 if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {
1722 Is32BitAddr = FALSE;
1723 } else {
1724 Is32BitAddr = TRUE;
1725 }
1726
1727 UfsHc = Private->UfsHostController;
1728 Status = UfsHc->AllocateBuffer (
1729 UfsHc,
1730 AllocateAnyPages,
1731 EfiBootServicesData,
1732 EFI_SIZE_TO_PAGES (Size),
1733 CmdDescHost,
1734 0
1735 );
1736 if (EFI_ERROR (Status)) {
1737 *CmdDescMapping = NULL;
1738 *CmdDescHost = NULL;
1739 *CmdDescPhyAddr = 0;
1740 return EFI_OUT_OF_RESOURCES;
1741 }
1742
1743 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));
1744 Status = UfsHc->Map (
1745 UfsHc,
1746 EdkiiUfsHcOperationBusMasterCommonBuffer,
1747 *CmdDescHost,
1748 &Bytes,
1749 CmdDescPhyAddr,
1750 CmdDescMapping
1751 );
1752
1753 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {
1754 UfsHc->FreeBuffer (
1755 UfsHc,
1756 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1757 *CmdDescHost
1758 );
1759 *CmdDescHost = NULL;
1760 return EFI_OUT_OF_RESOURCES;
1761 }
1762
1763 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {
1764 //
1765 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1766 //
1767 UfsHc->Unmap (
1768 UfsHc,
1769 *CmdDescMapping
1770 );
1771 UfsHc->FreeBuffer (
1772 UfsHc,
1773 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
1774 *CmdDescHost
1775 );
1776 *CmdDescMapping = NULL;
1777 *CmdDescHost = NULL;
1778 return EFI_DEVICE_ERROR;
1779 }
1780
1781 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));
1782 return EFI_SUCCESS;
1783 }
1784
1785 /**
1786 Enable the UFS host controller for accessing.
1787
1788 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1789
1790 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1791 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1792
1793 **/
1794 EFI_STATUS
1795 UfsEnableHostController (
1796 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1797 )
1798 {
1799 EFI_STATUS Status;
1800 UINT32 Data;
1801
1802 //
1803 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1804 //
1805 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1806 //
1807 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
1808 if (EFI_ERROR (Status)) {
1809 return Status;
1810 }
1811
1812 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1813 //
1814 // Write a 0 to the HCE register at first to disable the host controller.
1815 //
1816 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
1817 if (EFI_ERROR (Status)) {
1818 return Status;
1819 }
1820 //
1821 // Wait until HCE is read as '0' before continuing.
1822 //
1823 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1824 if (EFI_ERROR (Status)) {
1825 return EFI_DEVICE_ERROR;
1826 }
1827 }
1828
1829 //
1830 // Write a 1 to the HCE register to enable the UFS host controller.
1831 //
1832 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);
1833 if (EFI_ERROR (Status)) {
1834 return Status;
1835 }
1836
1837 //
1838 // Wait until HCE is read as '1' before continuing.
1839 //
1840 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1841 if (EFI_ERROR (Status)) {
1842 return EFI_DEVICE_ERROR;
1843 }
1844
1845 return EFI_SUCCESS;
1846 }
1847
1848 /**
1849 Detect if a UFS device attached.
1850
1851 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1852
1853 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1854 @retval EFI_NOT_FOUND Not found a UFS device attached.
1855 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1856
1857 **/
1858 EFI_STATUS
1859 UfsDeviceDetection (
1860 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1861 )
1862 {
1863 UINTN Retry;
1864 EFI_STATUS Status;
1865
1866 //
1867 // Start UFS device detection.
1868 // Try up to 3 times for establishing data link with device.
1869 //
1870 for (Retry = 0; Retry < 3; Retry++) {
1871 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
1872 if (!EFI_ERROR (Status)) {
1873 break;
1874 }
1875
1876 if (Status == EFI_NOT_FOUND) {
1877 continue;
1878 }
1879
1880 return EFI_DEVICE_ERROR;
1881 }
1882
1883 if (Retry == 3) {
1884 return EFI_NOT_FOUND;
1885 }
1886
1887 return EFI_SUCCESS;
1888 }
1889
1890 /**
1891 Initialize UFS task management request list related h/w context.
1892
1893 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1894
1895 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1896 @retval EFI_DEVICE_ERROR The initialization fails.
1897
1898 **/
1899 EFI_STATUS
1900 UfsInitTaskManagementRequestList (
1901 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1902 )
1903 {
1904 UINT32 Data;
1905 UINT8 Nutmrs;
1906 VOID *CmdDescHost;
1907 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1908 VOID *CmdDescMapping;
1909 EFI_STATUS Status;
1910
1911 //
1912 // Initial h/w and s/w context for future operations.
1913 //
1914 CmdDescHost = NULL;
1915 CmdDescMapping = NULL;
1916 CmdDescPhyAddr = 0;
1917
1918 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
1919 if (EFI_ERROR (Status)) {
1920 return Status;
1921 }
1922
1923 Private->Capabilities = Data;
1924
1925 //
1926 // Allocate and initialize UTP Task Management Request List.
1927 //
1928 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1929 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
1930 if (EFI_ERROR (Status)) {
1931 return Status;
1932 }
1933
1934 //
1935 // Program the UTP Task Management Request List Base Address and UTP Task Management
1936 // Request List Base Address with a 64-bit address allocated at step 6.
1937 //
1938 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
1939 if (EFI_ERROR (Status)) {
1940 return Status;
1941 }
1942
1943 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
1944 if (EFI_ERROR (Status)) {
1945 return Status;
1946 }
1947 Private->UtpTmrlBase = CmdDescHost;
1948 Private->Nutmrs = Nutmrs;
1949 Private->TmrlMapping = CmdDescMapping;
1950
1951 //
1952 // Enable the UTP Task Management Request List by setting the UTP Task Management
1953 // Request List RunStop Register (UTMRLRSR) to '1'.
1954 //
1955 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);
1956 if (EFI_ERROR (Status)) {
1957 return Status;
1958 }
1959
1960 return EFI_SUCCESS;
1961 }
1962
1963 /**
1964 Initialize UFS transfer request list related h/w context.
1965
1966 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1967
1968 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1969 @retval EFI_DEVICE_ERROR The initialization fails.
1970
1971 **/
1972 EFI_STATUS
1973 UfsInitTransferRequestList (
1974 IN UFS_PASS_THRU_PRIVATE_DATA *Private
1975 )
1976 {
1977 UINT32 Data;
1978 UINT8 Nutrs;
1979 VOID *CmdDescHost;
1980 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
1981 VOID *CmdDescMapping;
1982 EFI_STATUS Status;
1983
1984 //
1985 // Initial h/w and s/w context for future operations.
1986 //
1987 CmdDescHost = NULL;
1988 CmdDescMapping = NULL;
1989 CmdDescPhyAddr = 0;
1990
1991 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
1992 if (EFI_ERROR (Status)) {
1993 return Status;
1994 }
1995
1996 Private->Capabilities = Data;
1997
1998 //
1999 // Allocate and initialize UTP Transfer Request List.
2000 //
2001 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
2002 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
2003 if (EFI_ERROR (Status)) {
2004 return Status;
2005 }
2006
2007 //
2008 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2009 // Base Address with a 64-bit address allocated at step 8.
2010 //
2011 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
2012 if (EFI_ERROR (Status)) {
2013 return Status;
2014 }
2015
2016 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
2017 if (EFI_ERROR (Status)) {
2018 return Status;
2019 }
2020
2021 Private->UtpTrlBase = CmdDescHost;
2022 Private->Nutrs = Nutrs;
2023 Private->TrlMapping = CmdDescMapping;
2024
2025 //
2026 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2027 // RunStop Register (UTRLRSR) to '1'.
2028 //
2029 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
2030 if (EFI_ERROR (Status)) {
2031 return Status;
2032 }
2033
2034 return EFI_SUCCESS;
2035 }
2036
2037 /**
2038 Initialize the UFS host controller.
2039
2040 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2041
2042 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2043 @retval Others A device error occurred while initializing the controller.
2044
2045 **/
2046 EFI_STATUS
2047 UfsControllerInit (
2048 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2049 )
2050 {
2051 EFI_STATUS Status;
2052
2053 Status = UfsEnableHostController (Private);
2054 if (EFI_ERROR (Status)) {
2055 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));
2056 return Status;
2057 }
2058
2059 Status = UfsDeviceDetection (Private);
2060 if (EFI_ERROR (Status)) {
2061 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));
2062 return Status;
2063 }
2064
2065 Status = UfsInitTaskManagementRequestList (Private);
2066 if (EFI_ERROR (Status)) {
2067 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));
2068 return Status;
2069 }
2070
2071 Status = UfsInitTransferRequestList (Private);
2072 if (EFI_ERROR (Status)) {
2073 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));
2074 return Status;
2075 }
2076
2077 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));
2078 return EFI_SUCCESS;
2079 }
2080
2081 /**
2082 Stop the UFS host controller.
2083
2084 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2085
2086 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2087 @retval Others A device error occurred while stopping the controller.
2088
2089 **/
2090 EFI_STATUS
2091 UfsControllerStop (
2092 IN UFS_PASS_THRU_PRIVATE_DATA *Private
2093 )
2094 {
2095 EFI_STATUS Status;
2096 UINT32 Data;
2097
2098 //
2099 // Enable the UTP Task Management Request List by setting the UTP Task Management
2100 // Request List RunStop Register (UTMRLRSR) to '1'.
2101 //
2102 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);
2103 if (EFI_ERROR (Status)) {
2104 return Status;
2105 }
2106
2107 //
2108 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2109 // RunStop Register (UTRLRSR) to '1'.
2110 //
2111 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);
2112 if (EFI_ERROR (Status)) {
2113 return Status;
2114 }
2115
2116 //
2117 // Write a 0 to the HCE register in order to disable the host controller.
2118 //
2119 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
2120 if (EFI_ERROR (Status)) {
2121 return Status;
2122 }
2123 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
2124
2125 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
2126 if (EFI_ERROR (Status)) {
2127 return Status;
2128 }
2129
2130 //
2131 // Wait until HCE is read as '0' before continuing.
2132 //
2133 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
2134 if (EFI_ERROR (Status)) {
2135 return EFI_DEVICE_ERROR;
2136 }
2137
2138 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));
2139
2140 return EFI_SUCCESS;
2141 }
2142
2143
2144 /**
2145 Internal helper function which will signal the caller event and clean up
2146 resources.
2147
2148 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2149 structure.
2150 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2151 structure.
2152
2153 **/
2154 VOID
2155 EFIAPI
2156 SignalCallerEvent (
2157 IN UFS_PASS_THRU_PRIVATE_DATA *Private,
2158 IN UFS_PASS_THRU_TRANS_REQ *TransReq
2159 )
2160 {
2161 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
2162 EFI_EVENT CallerEvent;
2163
2164 ASSERT ((Private != NULL) && (TransReq != NULL));
2165
2166 UfsHc = Private->UfsHostController;
2167 CallerEvent = TransReq->CallerEvent;
2168
2169 RemoveEntryList (&TransReq->TransferList);
2170
2171 UfsHc->Flush (UfsHc);
2172
2173 UfsStopExecCmd (Private, TransReq->Slot);
2174
2175 if (TransReq->DataBufMapping != NULL) {
2176 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
2177 }
2178
2179 if (TransReq->CmdDescMapping != NULL) {
2180 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
2181 }
2182 if (TransReq->CmdDescHost != NULL) {
2183 UfsHc->FreeBuffer (
2184 UfsHc,
2185 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),
2186 TransReq->CmdDescHost
2187 );
2188 }
2189
2190 FreePool (TransReq);
2191
2192 gBS->SignalEvent (CallerEvent);
2193 return;
2194 }
2195
2196 /**
2197 Call back function when the timer event is signaled.
2198
2199 @param[in] Event The Event this notify function registered to.
2200 @param[in] Context Pointer to the context data registered to the Event.
2201
2202 **/
2203 VOID
2204 EFIAPI
2205 ProcessAsyncTaskList (
2206 IN EFI_EVENT Event,
2207 IN VOID *Context
2208 )
2209 {
2210 UFS_PASS_THRU_PRIVATE_DATA *Private;
2211 LIST_ENTRY *Entry;
2212 LIST_ENTRY *NextEntry;
2213 UFS_PASS_THRU_TRANS_REQ *TransReq;
2214 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;
2215 UTP_RESPONSE_UPIU *Response;
2216 UINT16 SenseDataLen;
2217 UINT32 ResTranCount;
2218 UINT32 SlotsMap;
2219 UINT32 Value;
2220 EFI_STATUS Status;
2221
2222 Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;
2223 SlotsMap = 0;
2224
2225 //
2226 // Check the entries in the async I/O queue are done or not.
2227 //
2228 if (!IsListEmpty(&Private->Queue)) {
2229 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
2230 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
2231 Packet = TransReq->Packet;
2232
2233 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {
2234 return;
2235 }
2236 SlotsMap |= BIT0 << TransReq->Slot;
2237
2238 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);
2239 if (EFI_ERROR (Status)) {
2240 //
2241 // TODO: Should find/add a proper host adapter return status for this
2242 // case.
2243 //
2244 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
2245 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));
2246 SignalCallerEvent (Private, TransReq);
2247 continue;
2248 }
2249
2250 if ((Value & (BIT0 << TransReq->Slot)) != 0) {
2251 //
2252 // Scsi cmd not finished yet.
2253 //
2254 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {
2255 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;
2256 continue;
2257 } else {
2258 //
2259 // Timeout occurs.
2260 //
2261 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
2262 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));
2263 SignalCallerEvent (Private, TransReq);
2264 continue;
2265 }
2266 } else {
2267 //
2268 // Scsi cmd finished.
2269 //
2270 // Get sense data if exists
2271 //
2272 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
2273 ASSERT (Response != NULL);
2274 SenseDataLen = Response->SenseDataLen;
2275 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
2276
2277 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
2278 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
2279 Packet->SenseDataLength = (UINT8)SenseDataLen;
2280 }
2281
2282 //
2283 // Check the transfer request result.
2284 //
2285 Packet->TargetStatus = Response->Status;
2286 if (Response->Response != 0) {
2287 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));
2288 SignalCallerEvent (Private, TransReq);
2289 continue;
2290 }
2291
2292 if (TransReq->Trd->Ocs == 0) {
2293 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
2294 if ((Response->Flags & BIT5) == BIT5) {
2295 ResTranCount = Response->ResTranCount;
2296 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2297 Packet->InTransferLength -= ResTranCount;
2298 }
2299 } else {
2300 if ((Response->Flags & BIT5) == BIT5) {
2301 ResTranCount = Response->ResTranCount;
2302 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
2303 Packet->OutTransferLength -= ResTranCount;
2304 }
2305 }
2306 } else {
2307 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));
2308 SignalCallerEvent (Private, TransReq);
2309 continue;
2310 }
2311
2312 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));
2313 SignalCallerEvent (Private, TransReq);
2314 }
2315 }
2316 }
2317 }
2318