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