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