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