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