]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
MdeModulePkg: Add UFS (Universal Flash Storage) Stack
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsBlockIoPei / UfsHci.c
1 /** @file
2
3 Copyright (c) 2014, 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 == 0) {
333 return EFI_SUCCESS;
334 }
335
336 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
337
338 RemainingLen = BufferSize;
339 Remaining = Buffer;
340 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
341
342 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
343 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
344 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
345 } else {
346 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
347 }
348
349 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
350 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
351 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
352 Remaining += UFS_MAX_DATA_LEN_PER_PRD;
353 }
354
355 return EFI_SUCCESS;
356 }
357
358 /**
359 Initialize QUERY REQUEST UPIU.
360
361 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
362 @param[in] TaskTag The task tag of request.
363 @param[in] Opcode The opcode of request.
364 @param[in] DescId The descriptor ID of request.
365 @param[in] Index The index of request.
366 @param[in] Selector The selector of request.
367 @param[in] DataSize The data size to be read or written.
368 @param[in] Data The buffer to be read or written.
369
370 @retval EFI_SUCCESS The initialization succeed.
371
372 **/
373 EFI_STATUS
374 UfsInitQueryRequestUpiu (
375 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,
376 IN UINT8 TaskTag,
377 IN UINT8 Opcode,
378 IN UINT8 DescId,
379 IN UINT8 Index,
380 IN UINT8 Selector,
381 IN UINTN DataSize OPTIONAL,
382 IN UINT8 *Data OPTIONAL
383 )
384 {
385 ASSERT (QueryReq != NULL);
386
387 QueryReq->TransCode = 0x16;
388 QueryReq->TaskTag = TaskTag;
389 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
390 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
391 } else {
392 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
393 }
394
395 if (Opcode == UtpQueryFuncOpcodeWrAttr) {
396 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);
397 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
398 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
399 } else {
400 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
401 }
402
403 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
404 CopyMem (QueryReq + 1, Data, DataSize);
405 }
406
407 return EFI_SUCCESS;
408 }
409
410 /**
411 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
412
413 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
414 @param[in] Lun The Lun on which the SCSI command is executed.
415 @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
416 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
417
418 @retval EFI_SUCCESS The creation succeed.
419 @retval EFI_DEVICE_ERROR The creation failed.
420 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
421
422 **/
423 EFI_STATUS
424 UfsCreateScsiCommandDesc (
425 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
426 IN UINT8 Lun,
427 IN UFS_SCSI_REQUEST_PACKET *Packet,
428 IN UTP_TRD *Trd
429 )
430 {
431 UINT8 *CommandDesc;
432 UINTN TotalLen;
433 UINTN PrdtNumber;
434 VOID *Buffer;
435 UINT32 Length;
436 UTP_COMMAND_UPIU *CommandUpiu;
437 UTP_TR_PRD *PrdtBase;
438 UFS_DATA_DIRECTION DataDirection;
439
440 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
441
442 if (Packet->DataDirection == UfsDataIn) {
443 Buffer = Packet->InDataBuffer;
444 Length = Packet->InTransferLength;
445 DataDirection = UfsDataIn;
446 } else {
447 Buffer = Packet->OutDataBuffer;
448 Length = Packet->OutTransferLength;
449 DataDirection = UfsDataOut;
450 }
451
452 if (Length == 0) {
453 DataDirection = UfsNoData;
454 }
455
456 PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
457
458 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
459 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
460 if (CommandDesc == NULL) {
461 return EFI_OUT_OF_RESOURCES;
462 }
463
464 CommandUpiu = (UTP_COMMAND_UPIU*)CommandDesc;
465 PrdtBase = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
466
467 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
468 UfsInitUtpPrdt (PrdtBase, Buffer, Length);
469
470 //
471 // Fill UTP_TRD associated fields
472 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
473 // *MUST* be located at a 64-bit aligned boundary.
474 //
475 Trd->Int = UFS_INTERRUPT_COMMAND;
476 Trd->Dd = DataDirection;
477 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
478 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);
479 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);
480 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
481 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
482 Trd->PrdtL = (UINT16)PrdtNumber;
483 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
484 return EFI_SUCCESS;
485 }
486
487 /**
488 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
489
490 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
491 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
492 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
493
494 @retval EFI_SUCCESS The creation succeed.
495 @retval EFI_DEVICE_ERROR The creation failed.
496 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
497 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
498
499 **/
500 EFI_STATUS
501 UfsCreateDMCommandDesc (
502 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
503 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
504 IN UTP_TRD *Trd
505 )
506 {
507 UINT8 *CommandDesc;
508 UINTN TotalLen;
509 UTP_QUERY_REQ_UPIU *QueryReqUpiu;
510 UINT8 Opcode;
511 UINT32 DataSize;
512 UINT8 *Data;
513 UINT8 DataDirection;
514
515 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
516
517 Opcode = Packet->Opcode;
518 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
519 return EFI_INVALID_PARAMETER;
520 }
521
522 DataDirection = Packet->DataDirection;
523 if (DataDirection == UfsDataIn) {
524 DataSize = Packet->InTransferLength;
525 Data = Packet->InDataBuffer;
526 } else if (DataDirection == UfsDataOut) {
527 DataSize = Packet->OutTransferLength;
528 Data = Packet->OutDataBuffer;
529 } else {
530 DataSize = 0;
531 Data = NULL;
532 }
533
534 if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))
535 && ((DataSize == 0) || (Data == NULL))) {
536 return EFI_INVALID_PARAMETER;
537 }
538
539 if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))
540 && ((DataSize != 0) || (Data != NULL))) {
541 return EFI_INVALID_PARAMETER;
542 }
543
544 if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {
545 return EFI_INVALID_PARAMETER;
546 }
547
548 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
549 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
550 } else {
551 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
552 }
553
554 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
555 if (CommandDesc == NULL) {
556 return EFI_OUT_OF_RESOURCES;
557 }
558
559 //
560 // Initialize UTP QUERY REQUEST UPIU
561 //
562 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;
563 UfsInitQueryRequestUpiu (
564 QueryReqUpiu,
565 Private->TaskTag++,
566 Opcode,
567 Packet->DescId,
568 Packet->Index,
569 Packet->Selector,
570 DataSize,
571 Data
572 );
573
574 //
575 // Fill UTP_TRD associated fields
576 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
577 //
578 Trd->Int = UFS_INTERRUPT_COMMAND;
579 Trd->Dd = DataDirection;
580 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
581 Trd->Ocs = 0x0F;
582 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);
583 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);
584 if (Opcode == UtpQueryFuncOpcodeWrDesc) {
585 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
586 Trd->RuO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));
587 } else {
588 Trd->RuL = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));
589 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
590 }
591
592 return EFI_SUCCESS;
593 }
594
595 /**
596 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
597
598 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
599 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
600
601 @retval EFI_SUCCESS The creation succeed.
602 @retval EFI_DEVICE_ERROR The creation failed.
603 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
604
605 **/
606 EFI_STATUS
607 UfsCreateNopCommandDesc (
608 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
609 IN UTP_TRD *Trd
610 )
611 {
612 UINT8 *CommandDesc;
613 UINTN TotalLen;
614 UTP_NOP_OUT_UPIU *NopOutUpiu;
615
616 ASSERT ((Private != NULL) && (Trd != NULL));
617
618 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
619 CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
620 if (CommandDesc == NULL) {
621 return EFI_OUT_OF_RESOURCES;
622 }
623
624 NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;
625
626 NopOutUpiu->TaskTag = Private->TaskTag++;
627
628 //
629 // Fill UTP_TRD associated fields
630 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
631 //
632 Trd->Int = UFS_INTERRUPT_COMMAND;
633 Trd->Dd = 0x00;
634 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
635 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);
636 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);
637 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
638 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
639
640 return EFI_SUCCESS;
641 }
642
643 /**
644 Find out available slot in transfer list of a UFS device.
645
646 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
647 @param[out] Slot The available slot.
648
649 @retval EFI_SUCCESS The available slot was found successfully.
650
651 **/
652 EFI_STATUS
653 UfsFindAvailableSlotInTrl (
654 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
655 OUT UINT8 *Slot
656 )
657 {
658 ASSERT ((Private != NULL) && (Slot != NULL));
659
660 //
661 // The simplest algo to always use slot 0.
662 // TODO: enhance it to support async transfer with multiple slot.
663 //
664 *Slot = 0;
665
666 return EFI_SUCCESS;
667 }
668
669 /**
670 Find out available slot in task management transfer list of a UFS device.
671
672 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
673 @param[out] Slot The available slot.
674
675 @retval EFI_SUCCESS The available slot was found successfully.
676
677 **/
678 EFI_STATUS
679 UfsFindAvailableSlotInTmrl (
680 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
681 OUT UINT8 *Slot
682 )
683 {
684 ASSERT ((Private != NULL) && (Slot != NULL));
685
686 //
687 // The simplest algo to always use slot 0.
688 // TODO: enhance it to support async transfer with multiple slot.
689 //
690 *Slot = 0;
691
692 return EFI_SUCCESS;
693 }
694
695 /**
696 Start specified slot in transfer list of a UFS device.
697
698 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
699 @param[in] Slot The slot to be started.
700
701 **/
702 VOID
703 UfsStartExecCmd (
704 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
705 IN UINT8 Slot
706 )
707 {
708 UINTN UfsHcBase;
709 UINTN Address;
710 UINT32 Data;
711
712 UfsHcBase = Private->UfsHcBase;
713
714 Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
715 Data = MmioRead32 (Address);
716 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
717 MmioWrite32 (Address, UFS_HC_UTRLRSR);
718 }
719
720 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
721 MmioWrite32 (Address, BIT0 << Slot);
722 }
723
724 /**
725 Stop specified slot in transfer list of a UFS device.
726
727 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
728 @param[in] Slot The slot to be stop.
729
730 **/
731 VOID
732 UfsStopExecCmd (
733 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
734 IN UINT8 Slot
735 )
736 {
737 UINTN UfsHcBase;
738 UINTN Address;
739 UINT32 Data;
740
741 UfsHcBase = Private->UfsHcBase;
742
743 Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
744 Data = MmioRead32 (Address);
745 if ((Data & (BIT0 << Slot)) != 0) {
746 Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;
747 Data = MmioRead32 (Address);
748 MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));
749 }
750 }
751
752 /**
753 Read or write specified device descriptor of a UFS device.
754
755 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
756 @param[in] Read The boolean variable to show r/w direction.
757 @param[in] DescId The ID of device descriptor.
758 @param[in] Index The Index of device descriptor.
759 @param[in] Selector The Selector of device descriptor.
760 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
761 @param[in] DescSize The size of device descriptor buffer.
762
763 @retval EFI_SUCCESS The device descriptor was read/written successfully.
764 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
765 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
766
767 **/
768 EFI_STATUS
769 UfsRwDeviceDesc (
770 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
771 IN BOOLEAN Read,
772 IN UINT8 DescId,
773 IN UINT8 Index,
774 IN UINT8 Selector,
775 IN OUT VOID *Descriptor,
776 IN UINT32 DescSize
777 )
778 {
779 EFI_STATUS Status;
780 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
781 UINT8 Slot;
782 UTP_TRD *Trd;
783 UINTN Address;
784 UTP_QUERY_RESP_UPIU *QueryResp;
785 UINT8 *CmdDescBase;
786 UINT32 CmdDescSize;
787 UINT16 ReturnDataSize;
788
789 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
790
791 if (Read) {
792 Packet.DataDirection = UfsDataIn;
793 Packet.InDataBuffer = Descriptor;
794 Packet.InTransferLength = DescSize;
795 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
796 } else {
797 Packet.DataDirection = UfsDataOut;
798 Packet.OutDataBuffer = Descriptor;
799 Packet.OutTransferLength = DescSize;
800 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
801 }
802 Packet.DescId = DescId;
803 Packet.Index = Index;
804 Packet.Selector = Selector;
805 Packet.Timeout = UFS_TIMEOUT;
806
807 //
808 // Find out which slot of transfer request list is available.
809 //
810 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
811 if (EFI_ERROR (Status)) {
812 return Status;
813 }
814
815 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
816 //
817 // Fill transfer request descriptor to this slot.
818 //
819 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
820 if (EFI_ERROR (Status)) {
821 return Status;
822 }
823
824 //
825 // Check the transfer request result.
826 //
827 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
828 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
829 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
830
831 //
832 // Start to execute the transfer request.
833 //
834 UfsStartExecCmd (Private, Slot);
835
836 //
837 // Wait for the completion of the transfer request.
838 //
839 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
840 Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);
841 if (EFI_ERROR (Status)) {
842 goto Exit;
843 }
844
845 if (QueryResp->QueryResp != 0) {
846 DumpQueryResponseResult (QueryResp->QueryResp);
847 Status = EFI_DEVICE_ERROR;
848 goto Exit;
849 }
850
851 if (Trd->Ocs == 0) {
852 ReturnDataSize = QueryResp->Tsf.Length;
853 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
854
855 if (Read) {
856 CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);
857 Packet.InTransferLength = ReturnDataSize;
858 } else {
859 Packet.OutTransferLength = ReturnDataSize;
860 }
861 } else {
862 Status = EFI_DEVICE_ERROR;
863 }
864
865 Exit:
866 UfsStopExecCmd (Private, Slot);
867 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
868
869 return Status;
870 }
871
872 /**
873 Read or write specified attribute of a UFS device.
874
875 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
876 @param[in] Read The boolean variable to show r/w direction.
877 @param[in] AttrId The ID of Attribute.
878 @param[in] Index The Index of Attribute.
879 @param[in] Selector The Selector of Attribute.
880 @param[in, out] Attributes The value of Attribute to be read or written.
881
882 @retval EFI_SUCCESS The Attribute was read/written successfully.
883 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
884 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
885
886 **/
887 EFI_STATUS
888 UfsRwAttributes (
889 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
890 IN BOOLEAN Read,
891 IN UINT8 AttrId,
892 IN UINT8 Index,
893 IN UINT8 Selector,
894 IN OUT UINT32 *Attributes
895 )
896 {
897 EFI_STATUS Status;
898 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
899 UINT8 Slot;
900 UTP_TRD *Trd;
901 UINTN Address;
902 UTP_QUERY_RESP_UPIU *QueryResp;
903 UINT8 *CmdDescBase;
904 UINT32 CmdDescSize;
905 UINT32 ReturnData;
906
907 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
908
909 if (Read) {
910 Packet.DataDirection = UfsDataIn;
911 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
912 } else {
913 Packet.DataDirection = UfsDataOut;
914 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
915 }
916 Packet.DescId = AttrId;
917 Packet.Index = Index;
918 Packet.Selector = Selector;
919 Packet.Timeout = UFS_TIMEOUT;
920
921 //
922 // Find out which slot of transfer request list is available.
923 //
924 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
925 if (EFI_ERROR (Status)) {
926 return Status;
927 }
928
929 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
930 //
931 // Fill transfer request descriptor to this slot.
932 //
933 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
934 if (EFI_ERROR (Status)) {
935 return Status;
936 }
937
938 //
939 // Check the transfer request result.
940 //
941 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
942 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
943 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
944
945 //
946 // Start to execute the transfer request.
947 //
948 UfsStartExecCmd (Private, Slot);
949
950 //
951 // Wait for the completion of the transfer request.
952 //
953 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
954 Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);
955 if (EFI_ERROR (Status)) {
956 goto Exit;
957 }
958
959 if (QueryResp->QueryResp != 0) {
960 DumpQueryResponseResult (QueryResp->QueryResp);
961 Status = EFI_DEVICE_ERROR;
962 goto Exit;
963 }
964
965 if (Trd->Ocs == 0) {
966 ReturnData = QueryResp->Tsf.Value;
967 SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));
968 *Attributes = ReturnData;
969 } else {
970 Status = EFI_DEVICE_ERROR;
971 }
972
973 Exit:
974 UfsStopExecCmd (Private, Slot);
975 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
976
977 return Status;
978 }
979
980 /**
981 Read or write specified flag of a UFS device.
982
983 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
984 @param[in] Read The boolean variable to show r/w direction.
985 @param[in] FlagId The ID of flag to be read or written.
986 @param[in, out] Value The value to set or clear flag.
987
988 @retval EFI_SUCCESS The flag was read/written successfully.
989 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
990 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
991
992 **/
993 EFI_STATUS
994 UfsRwFlags (
995 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
996 IN BOOLEAN Read,
997 IN UINT8 FlagId,
998 IN OUT UINT8 *Value
999 )
1000 {
1001 EFI_STATUS Status;
1002 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
1003 UINT8 Slot;
1004 UTP_TRD *Trd;
1005 UINTN Address;
1006 UTP_QUERY_RESP_UPIU *QueryResp;
1007 UINT8 *CmdDescBase;
1008 UINT32 CmdDescSize;
1009
1010 if (Value == NULL) {
1011 return EFI_INVALID_PARAMETER;
1012 }
1013
1014 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
1015
1016 if (Read) {
1017 ASSERT (Value != NULL);
1018 Packet.DataDirection = UfsDataIn;
1019 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
1020 } else {
1021 Packet.DataDirection = UfsDataOut;
1022 if (*Value == 1) {
1023 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
1024 } else if (*Value == 0) {
1025 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
1026 } else {
1027 return EFI_INVALID_PARAMETER;
1028 }
1029 }
1030 Packet.DescId = FlagId;
1031 Packet.Index = 0;
1032 Packet.Selector = 0;
1033 Packet.Timeout = UFS_TIMEOUT;
1034
1035 //
1036 // Find out which slot of transfer request list is available.
1037 //
1038 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1039 if (EFI_ERROR (Status)) {
1040 return Status;
1041 }
1042
1043 //
1044 // Fill transfer request descriptor to this slot.
1045 //
1046 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1047 Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
1048 if (EFI_ERROR (Status)) {
1049 return Status;
1050 }
1051
1052 //
1053 // Check the transfer request result.
1054 //
1055 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1056 QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1057 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1058
1059 //
1060 // Start to execute the transfer request.
1061 //
1062 UfsStartExecCmd (Private, Slot);
1063
1064 //
1065 // Wait for the completion of the transfer request.
1066 //
1067 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1068 Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);
1069 if (EFI_ERROR (Status)) {
1070 goto Exit;
1071 }
1072
1073 if (QueryResp->QueryResp != 0) {
1074 DumpQueryResponseResult (QueryResp->QueryResp);
1075 Status = EFI_DEVICE_ERROR;
1076 goto Exit;
1077 }
1078
1079 if (Trd->Ocs == 0) {
1080 *Value = (UINT8)QueryResp->Tsf.Value;
1081 } else {
1082 Status = EFI_DEVICE_ERROR;
1083 }
1084
1085 Exit:
1086 UfsStopExecCmd (Private, Slot);
1087 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1088
1089 return Status;
1090 }
1091
1092 /**
1093 Set specified flag to 1 on a UFS device.
1094
1095 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1096 @param[in] FlagId The ID of flag to be set.
1097
1098 @retval EFI_SUCCESS The flag was set successfully.
1099 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1100 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1101
1102 **/
1103 EFI_STATUS
1104 UfsSetFlag (
1105 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1106 IN UINT8 FlagId
1107 )
1108 {
1109 EFI_STATUS Status;
1110 UINT8 Value;
1111
1112 Value = 1;
1113 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1114
1115 return Status;
1116 }
1117
1118 /**
1119 Clear specified flag to 0 on a UFS device.
1120
1121 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1122 @param[in] FlagId The ID of flag to be cleared.
1123
1124 @retval EFI_SUCCESS The flag was cleared successfully.
1125 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1126 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1127
1128 **/
1129 EFI_STATUS
1130 UfsClearFlag (
1131 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1132 IN UINT8 FlagId
1133 )
1134 {
1135 EFI_STATUS Status;
1136 UINT8 Value;
1137
1138 Value = 0;
1139 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
1140
1141 return Status;
1142 }
1143
1144 /**
1145 Read specified flag from a UFS device.
1146
1147 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1148 @param[in] FlagId The ID of flag to be read.
1149 @param[out] Value The flag's value.
1150
1151 @retval EFI_SUCCESS The flag was read successfully.
1152 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1153 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1154
1155 **/
1156 EFI_STATUS
1157 UfsReadFlag (
1158 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1159 IN UINT8 FlagId,
1160 OUT UINT8 *Value
1161 )
1162 {
1163 EFI_STATUS Status;
1164
1165 Status = UfsRwFlags (Private, TRUE, FlagId, Value);
1166
1167 return Status;
1168 }
1169
1170 /**
1171 Sends NOP IN cmd to a UFS device for initialization process request.
1172 For more details, please refer to UFS 2.0 spec Figure 13.3.
1173
1174 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1175
1176 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1177 received successfully.
1178 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1179 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1180 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1181
1182 **/
1183 EFI_STATUS
1184 UfsExecNopCmds (
1185 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1186 )
1187 {
1188 EFI_STATUS Status;
1189 UINT8 Slot;
1190 UTP_TRD *Trd;
1191 UTP_NOP_IN_UPIU *NopInUpiu;
1192 UINT8 *CmdDescBase;
1193 UINT32 CmdDescSize;
1194 UINTN Address;
1195
1196 //
1197 // Find out which slot of transfer request list is available.
1198 //
1199 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1200 if (EFI_ERROR (Status)) {
1201 return Status;
1202 }
1203
1204 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1205 Status = UfsCreateNopCommandDesc (Private, Trd);
1206 if (EFI_ERROR (Status)) {
1207 return Status;
1208 }
1209
1210 //
1211 // Check the transfer request result.
1212 //
1213 CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1214 NopInUpiu = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1215 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
1216
1217 //
1218 // Start to execute the transfer request.
1219 //
1220 UfsStartExecCmd (Private, Slot);
1221
1222 //
1223 // Wait for the completion of the transfer request.
1224 //
1225 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1226 Status = UfsWaitMemSet (Address, BIT0, 0, UFS_TIMEOUT);
1227 if (EFI_ERROR (Status)) {
1228 goto Exit;
1229 }
1230
1231 if (NopInUpiu->Resp != 0) {
1232 Status = EFI_DEVICE_ERROR;
1233 } else {
1234 Status = EFI_SUCCESS;
1235 }
1236
1237 Exit:
1238 UfsStopExecCmd (Private, Slot);
1239 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1240
1241 return Status;
1242 }
1243
1244 /**
1245 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1246
1247 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1248 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1249 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1250 UFS device.
1251
1252 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1253 commands, InTransferLength bytes were transferred from
1254 InDataBuffer. For write and bi-directional commands,
1255 OutTransferLength bytes were transferred by
1256 OutDataBuffer.
1257 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1258 Packet.
1259 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1260 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1261
1262 **/
1263 EFI_STATUS
1264 UfsExecScsiCmds (
1265 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1266 IN UINT8 Lun,
1267 IN OUT UFS_SCSI_REQUEST_PACKET *Packet
1268 )
1269 {
1270 EFI_STATUS Status;
1271 UINT8 Slot;
1272 UTP_TRD *Trd;
1273 UINTN Address;
1274 UINT8 *CmdDescBase;
1275 UINT32 CmdDescSize;
1276 UTP_RESPONSE_UPIU *Response;
1277 UINT16 SenseDataLen;
1278 UINT32 ResTranCount;
1279
1280 //
1281 // Find out which slot of transfer request list is available.
1282 //
1283 Status = UfsFindAvailableSlotInTrl (Private, &Slot);
1284 if (EFI_ERROR (Status)) {
1285 return Status;
1286 }
1287
1288 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
1289
1290 //
1291 // Fill transfer request descriptor to this slot.
1292 //
1293 Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd);
1294 if (EFI_ERROR (Status)) {
1295 return Status;
1296 }
1297
1298 CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
1299 CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);
1300
1301 //
1302 // Start to execute the transfer request.
1303 //
1304 UfsStartExecCmd (Private, Slot);
1305
1306 //
1307 // Wait for the completion of the transfer request.
1308 //
1309 Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
1310 Status = UfsWaitMemSet (Address, BIT0, 0, Packet->Timeout);
1311 if (EFI_ERROR (Status)) {
1312 goto Exit;
1313 }
1314
1315 //
1316 // Get sense data if exists
1317 //
1318 Response = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
1319 SenseDataLen = Response->SenseDataLen;
1320 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
1321
1322 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
1323 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
1324 Packet->SenseDataLength = (UINT8)SenseDataLen;
1325 }
1326
1327 //
1328 // Check the transfer request result.
1329 //
1330 if (Response->Response != 0) {
1331 DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
1332 Status = EFI_DEVICE_ERROR;
1333 goto Exit;
1334 }
1335
1336 if (Trd->Ocs == 0) {
1337 if (Packet->DataDirection == UfsDataIn) {
1338 if ((Response->Flags & BIT5) == BIT5) {
1339 ResTranCount = Response->ResTranCount;
1340 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1341 Packet->InTransferLength -= ResTranCount;
1342 }
1343 } else if (Packet->DataDirection == UfsDataOut) {
1344 if ((Response->Flags & BIT5) == BIT5) {
1345 ResTranCount = Response->ResTranCount;
1346 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
1347 Packet->OutTransferLength -= ResTranCount;
1348 }
1349 }
1350 } else {
1351 Status = EFI_DEVICE_ERROR;
1352 }
1353
1354 Exit:
1355 UfsStopExecCmd (Private, Slot);
1356 UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
1357
1358 return Status;
1359 }
1360
1361
1362 /**
1363 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1364
1365 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1366 @param[in] UicOpcode The opcode of the UIC command.
1367 @param[in] Arg1 The value for 1st argument of the UIC command.
1368 @param[in] Arg2 The value for 2nd argument of the UIC command.
1369 @param[in] Arg3 The value for 3rd argument of the UIC command.
1370
1371 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1372 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1373 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1374
1375 **/
1376 EFI_STATUS
1377 UfsExecUicCommands (
1378 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
1379 IN UINT8 UicOpcode,
1380 IN UINT32 Arg1,
1381 IN UINT32 Arg2,
1382 IN UINT32 Arg3
1383 )
1384 {
1385 EFI_STATUS Status;
1386 UINTN Address;
1387 UINT32 Data;
1388 UINTN UfsHcBase;
1389
1390 UfsHcBase = Private->UfsHcBase;
1391 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1392 Data = MmioRead32 (Address);
1393 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
1394 //
1395 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1396 //
1397 MmioWrite32 (Address, Data);
1398 }
1399
1400 //
1401 // When programming UIC command registers, host software shall set the register UICCMD
1402 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1403 // are set.
1404 //
1405 Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;
1406 MmioWrite32 (Address, Arg1);
1407
1408 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1409 MmioWrite32 (Address, Arg2);
1410
1411 Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;
1412 MmioWrite32 (Address, Arg3);
1413
1414 //
1415 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1416 //
1417 Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
1418 Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
1419 if (EFI_ERROR (Status)) {
1420 return Status;
1421 }
1422
1423 Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;
1424 MmioWrite32 (Address, (UINT32)UicOpcode);
1425
1426 //
1427 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1428 // This bit is set to '1' by the host controller upon completion of a UIC command.
1429 //
1430 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1431 Data = MmioRead32 (Address);
1432 Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
1433 if (EFI_ERROR (Status)) {
1434 return Status;
1435 }
1436
1437 if (UicOpcode != UfsUicDmeReset) {
1438 Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
1439 Data = MmioRead32 (Address);
1440 if ((Data & 0xFF) != 0) {
1441 DEBUG_CODE_BEGIN();
1442 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
1443 DEBUG_CODE_END();
1444 return EFI_DEVICE_ERROR;
1445 }
1446 }
1447
1448 //
1449 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1450 //
1451 Address = UfsHcBase + UFS_HC_STATUS_OFFSET;
1452 Data = MmioRead32 (Address);
1453 if ((Data & UFS_HC_HCS_DP) == 0) {
1454 Address = UfsHcBase + UFS_HC_IS_OFFSET;
1455 Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
1456 if (EFI_ERROR (Status)) {
1457 return EFI_DEVICE_ERROR;
1458 }
1459 return EFI_NOT_FOUND;
1460 }
1461
1462 DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));
1463
1464 return EFI_SUCCESS;
1465 }
1466
1467 /**
1468 Enable the UFS host controller for accessing.
1469
1470 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1471
1472 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1473 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1474
1475 **/
1476 EFI_STATUS
1477 UfsEnableHostController (
1478 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1479 )
1480 {
1481 EFI_STATUS Status;
1482 UINTN Address;
1483 UINT32 Data;
1484
1485 //
1486 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1487 //
1488 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1489 //
1490 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1491 Data = MmioRead32 (Address);
1492 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
1493 //
1494 // Write a 0 to the HCE register at first to disable the host controller.
1495 //
1496 MmioWrite32 (Address, 0);
1497 //
1498 // Wait until HCE is read as '0' before continuing.
1499 //
1500 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1501 if (EFI_ERROR (Status)) {
1502 return EFI_DEVICE_ERROR;
1503 }
1504 }
1505
1506 //
1507 // Write a 1 to the HCE register to enable the UFS host controller.
1508 //
1509 MmioWrite32 (Address, UFS_HC_HCE_EN);
1510 //
1511 // Wait until HCE is read as '1' before continuing.
1512 //
1513 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
1514 if (EFI_ERROR (Status)) {
1515 return EFI_DEVICE_ERROR;
1516 }
1517
1518 return EFI_SUCCESS;
1519 }
1520
1521 /**
1522 Detect if a UFS device attached.
1523
1524 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1525
1526 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1527 @retval EFI_NOT_FOUND Not found a UFS device attached.
1528 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1529
1530 **/
1531 EFI_STATUS
1532 UfsDeviceDetection (
1533 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1534 )
1535 {
1536 UINTN Retry;
1537 EFI_STATUS Status;
1538
1539 //
1540 // Start UFS device detection.
1541 // Try up to 3 times for establishing data link with device.
1542 //
1543 for (Retry = 0; Retry < 3; Retry++) {
1544 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
1545 if (!EFI_ERROR (Status)) {
1546 break;
1547 }
1548
1549 if (Status == EFI_NOT_FOUND) {
1550 continue;
1551 }
1552
1553 return EFI_DEVICE_ERROR;
1554 }
1555
1556 if (Retry == 3) {
1557 return EFI_NOT_FOUND;
1558 }
1559
1560 return EFI_SUCCESS;
1561 }
1562
1563 /**
1564 Initialize UFS task management request list related h/w context.
1565
1566 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1567
1568 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1569 @retval EFI_DEVICE_ERROR The initialization fails.
1570
1571 **/
1572 EFI_STATUS
1573 UfsInitTaskManagementRequestList (
1574 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1575 )
1576 {
1577 UINTN Address;
1578 UINT32 Data;
1579 UINT8 Nutmrs;
1580 EFI_PHYSICAL_ADDRESS Buffer;
1581 EFI_STATUS Status;
1582
1583 //
1584 // Initial h/w and s/w context for future operations.
1585 //
1586 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1587 Data = MmioRead32 (Address);
1588 Private->Capabilities = Data;
1589
1590 //
1591 // Allocate and initialize UTP Task Management Request List.
1592 //
1593 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
1594 Status = PeiServicesAllocatePages (
1595 EfiBootServicesCode,
1596 EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
1597 &Buffer
1598 );
1599
1600 if (EFI_ERROR (Status)) {
1601 return EFI_DEVICE_ERROR;
1602 }
1603
1604 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
1605
1606 //
1607 // Program the UTP Task Management Request List Base Address and UTP Task Management
1608 // Request List Base Address with a 64-bit address allocated at step 6.
1609 //
1610 Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;
1611 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
1612 Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;
1613 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
1614 Private->UtpTmrlBase = (VOID*)(UINTN)Buffer;
1615 Private->Nutmrs = Nutmrs;
1616
1617 //
1618 // Enable the UTP Task Management Request List by setting the UTP Task Management
1619 // Request List RunStop Register (UTMRLRSR) to '1'.
1620 //
1621 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1622 MmioWrite32 (Address, UFS_HC_UTMRLRSR);
1623
1624 return EFI_SUCCESS;
1625 }
1626
1627 /**
1628 Initialize UFS transfer request list related h/w context.
1629
1630 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1631
1632 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1633 @retval EFI_DEVICE_ERROR The initialization fails.
1634
1635 **/
1636 EFI_STATUS
1637 UfsInitTransferRequestList (
1638 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1639 )
1640 {
1641 UINTN Address;
1642 UINT32 Data;
1643 UINT8 Nutrs;
1644 EFI_PHYSICAL_ADDRESS Buffer;
1645 EFI_STATUS Status;
1646
1647 //
1648 // Initial h/w and s/w context for future operations.
1649 //
1650 Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
1651 Data = MmioRead32 (Address);
1652 Private->Capabilities = Data;
1653
1654 //
1655 // Allocate and initialize UTP Transfer Request List.
1656 //
1657 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
1658 Status = PeiServicesAllocatePages (
1659 EfiBootServicesCode,
1660 EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
1661 &Buffer
1662 );
1663
1664 if (EFI_ERROR (Status)) {
1665 return EFI_DEVICE_ERROR;
1666 }
1667
1668 ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
1669
1670 //
1671 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1672 // Base Address with a 64-bit address allocated at step 8.
1673 //
1674 Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;
1675 MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
1676 Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;
1677 MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
1678 Private->UtpTrlBase = (VOID*)(UINTN)Buffer;
1679 Private->Nutrs = Nutrs;
1680
1681 //
1682 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1683 // RunStop Register (UTRLRSR) to '1'.
1684 //
1685 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1686 MmioWrite32 (Address, UFS_HC_UTRLRSR);
1687
1688 return EFI_SUCCESS;
1689 }
1690
1691 /**
1692 Initialize the UFS host controller.
1693
1694 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1695
1696 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1697 @retval Others A device error occurred while initializing the controller.
1698
1699 **/
1700 EFI_STATUS
1701 UfsControllerInit (
1702 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1703 )
1704 {
1705 EFI_STATUS Status;
1706
1707 Status = UfsEnableHostController (Private);
1708 if (EFI_ERROR (Status)) {
1709 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));
1710 return Status;
1711 }
1712
1713 Status = UfsDeviceDetection (Private);
1714 if (EFI_ERROR (Status)) {
1715 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));
1716 return Status;
1717 }
1718
1719 Status = UfsInitTaskManagementRequestList (Private);
1720 if (EFI_ERROR (Status)) {
1721 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));
1722 return Status;
1723 }
1724
1725 Status = UfsInitTransferRequestList (Private);
1726 if (EFI_ERROR (Status)) {
1727 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
1728 return Status;
1729 }
1730
1731 DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));
1732 return EFI_SUCCESS;
1733 }
1734
1735 /**
1736 Stop the UFS host controller.
1737
1738 @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
1739
1740 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1741 @retval Others A device error occurred while stopping the controller.
1742
1743 **/
1744 EFI_STATUS
1745 UfsControllerStop (
1746 IN UFS_PEIM_HC_PRIVATE_DATA *Private
1747 )
1748 {
1749 EFI_STATUS Status;
1750 UINTN Address;
1751 UINT32 Data;
1752
1753 //
1754 // Enable the UTP Task Management Request List by setting the UTP Task Management
1755 // Request List RunStop Register (UTMRLRSR) to '1'.
1756 //
1757 Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
1758 MmioWrite32 (Address, 0);
1759
1760 //
1761 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1762 // RunStop Register (UTRLRSR) to '1'.
1763 //
1764 Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
1765 MmioWrite32 (Address, 0);
1766
1767 //
1768 // Write a 0 to the HCE register in order to disable the host controller.
1769 //
1770 Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
1771 Data = MmioRead32 (Address);
1772 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
1773 MmioWrite32 (Address, 0);
1774
1775 //
1776 // Wait until HCE is read as '0' before continuing.
1777 //
1778 Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
1779 if (EFI_ERROR (Status)) {
1780 return EFI_DEVICE_ERROR;
1781 }
1782
1783 DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));
1784
1785 return EFI_SUCCESS;
1786 }
1787