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