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