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 1788