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