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