]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Add UFS (Universal Flash Storage) Stack
authorFeng Tian <feng.tian@intel.com>
Wed, 29 Apr 2015 02:42:58 +0000 (02:42 +0000)
committererictian <erictian@Edk2>
Wed, 29 Apr 2015 02:42:58 +0000 (02:42 +0000)
It includes 4 drivers:
1. UfsPassThruDxe, which is a UEFI driver and consumes EFI_UFS_HOST_CONTROLLER_PROTOCOL and produces EFI_EXT_SCSI_PASS_THRU_PROTOCOL
2. UfsPciHcDxe, which is specific for pci-based UFS HC implementation and is a UEFI driver to produce EFI_UFS_HOST_CONTROLLER_PROTOCOL.
3. UfsBlockIoPei, which is a PEI driver and consumes EFI_UFS_HOST_CONTROLLER_PPI and produces EFI_PEI_VIRTUAL_BLOCK_IO_PPI.
4. UfsPciHcPei, which is specific for pci-based UFS HC implementation and is a PEI driver to produce EFI_UFS_HOST_CONTROLLER_PPI.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17246 6f19259b-4bc3-4df7-8a09-765794883524

33 files changed:
MdeModulePkg/Bus/Pci/UfsPciHcDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.h [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.h [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c [new file with mode: 0644]
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.h [new file with mode: 0644]
MdeModulePkg/Include/Ppi/UfsHostController.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/UfsHostController.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/MdeModulePkg.uni

diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..1e2db1a
--- /dev/null
@@ -0,0 +1,225 @@
+/** @file\r
+  UfsHcDxe driver produces EFI_UFS_HOST_CONTROLLER_PROTOCOL. The upper layer module\r
+  uses it to query the MMIO base address of the UFS host controller.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsPciHcDxe.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUfsHcComponentName = {\r
+  UfsHcComponentNameGetDriverName,\r
+  UfsHcComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUfsHcComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UfsHcComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UfsHcComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsHcDriverNameTable[] = {\r
+  {\r
+    "eng;en",\r
+    L"Universal Flash Storage (UFS) Pci Host Controller Driver"\r
+  },\r
+  { \r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsHcControllerNameTable[] = {\r
+  {\r
+    "eng;en",\r
+    L"Universal Flash Storage (UFS) Pci Host Controller"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL       *This,\r
+  IN  CHAR8                             *Language,\r
+  OUT CHAR16                            **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mUfsHcDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gUfsHcComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+\r
+  if (Language == NULL || ControllerName == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // This is a device driver, so ChildHandle must be NULL.\r
+  //\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Make sure this driver is currently managing Controller Handle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gUfsHcDriverBinding.DriverBindingHandle,\r
+             &gEfiPciIoProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mUfsHcControllerNameTable,\r
+           ControllerName,\r
+           (BOOLEAN)(This == &gUfsHcComponentName)\r
+           );\r
+\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.c b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.c
new file mode 100644 (file)
index 0000000..586a52b
--- /dev/null
@@ -0,0 +1,699 @@
+/** @file\r
+  UfsHcDxe driver is used to provide platform-dependent info, mainly UFS host controller\r
+  MMIO base, to upper layer UFS drivers.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsPciHcDxe.h"\r
+\r
+//\r
+// NVM Express Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gUfsHcDriverBinding = {\r
+  UfsHcDriverBindingSupported,\r
+  UfsHcDriverBindingStart,\r
+  UfsHcDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Template for Ufs host controller private data.\r
+//\r
+UFS_HOST_CONTROLLER_PRIVATE_DATA gUfsHcTemplate = {\r
+  UFS_HC_PRIVATE_DATA_SIGNATURE,  // Signature\r
+  NULL,                           // Handle\r
+  {                               // UfsHcProtocol\r
+    UfsHcGetMmioBar,\r
+    UfsHcAllocateBuffer,\r
+    UfsHcFreeBuffer,\r
+    UfsHcMap,\r
+    UfsHcUnmap,\r
+    UfsHcFlush\r
+  },\r
+  NULL,                           // PciIo\r
+  0                               // PciAttributes\r
+};\r
+\r
+/**\r
+  Get the MMIO base of the UFS host controller.\r
+\r
+  @param[in]   This             A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param[out]  MmioBar          The MMIO base address of UFS host controller.\r
+\r
+  @retval EFI_SUCCESS           The operation succeeds.\r
+  @retval others                The operation fails.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcGetMmioBar (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,\r
+     OUT UINTN                              *MmioBar\r
+  )\r
+{\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_STATUS                        Status;\r
+\r
+  if ((This == NULL) || (MmioBar == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);\r
+  PciIo   = Private->PciIo;\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        PCI_BASE_ADDRESSREG_OFFSET,\r
+                        sizeof (UINT32),\r
+                        MmioBar\r
+                        );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *MmioBar &= (UINTN)~0xF;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**                                                                 \r
+  Provides the UFS controller-specific addresses needed to access system memory.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
+  @param  HostAddress           The system memory address to map to the UFS controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
+                                that were mapped.                                                 \r
+  @param  DeviceAddress         The resulting map address for the bus master UFS controller to use to\r
+                                access the hosts HostAddress.                                        \r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.                                \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
+                                   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcMap (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This,\r
+  IN     EDKII_UFS_HOST_CONTROLLER_OPERATION  Operation,\r
+  IN     VOID                                 *HostAddress,\r
+  IN OUT UINTN                                *NumberOfBytes,\r
+     OUT EFI_PHYSICAL_ADDRESS                 *DeviceAddress,\r
+     OUT VOID                                 **Mapping\r
+  )\r
+{\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_STATUS                        Status;\r
+\r
+  if ((This == NULL) || (HostAddress == NULL) || (NumberOfBytes == NULL) || (DeviceAddress == NULL) || (Mapping == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);\r
+  PciIo   = Private->PciIo;\r
+\r
+  Status  = PciIo->Map (PciIo, Operation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);\r
+  return Status;\r
+}\r
+\r
+/**                                                                 \r
+  Completes the Map() operation and releases any corresponding resources.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.                                      \r
+  @param  Mapping               The mapping value returned from Map().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+                                   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcUnmap (\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,\r
+  IN  VOID                               *Mapping\r
+  )\r
+{\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_STATUS                        Status;\r
+\r
+  if ((This == NULL) || (Mapping == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);\r
+  PciIo   = Private->PciIo;\r
+\r
+  Status  = PciIo->Unmap (PciIo, Mapping);\r
+  return Status;\r
+}\r
+\r
+/**                                                                 \r
+  Allocates pages that are suitable for an EfiUfsHcOperationBusMasterCommonBuffer\r
+  mapping.                                                                       \r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param  Type                  This parameter is not used and must be ignored.\r
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
+                                EfiRuntimeServicesData.                               \r
+  @param  Pages                 The number of pages to allocate.                                \r
+  @param  HostAddress           A pointer to store the base system memory address of the\r
+                                allocated range.                                        \r
+  @param  Attributes            The requested bit mask of attributes for the allocated range.\r
+                                  \r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.                     \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.  \r
+                                   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcAllocateBuffer (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,\r
+  IN     EFI_ALLOCATE_TYPE                  Type,\r
+  IN     EFI_MEMORY_TYPE                    MemoryType,\r
+  IN     UINTN                              Pages,\r
+     OUT VOID                               **HostAddress,\r
+  IN     UINT64                             Attributes\r
+  )\r
+{\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_STATUS                        Status;\r
+\r
+  if ((This == NULL) || (HostAddress == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);\r
+  PciIo   = Private->PciIo;\r
+\r
+  Status  = PciIo->AllocateBuffer (PciIo, Type, MemoryType, Pages, HostAddress, Attributes);\r
+  return Status;\r
+}\r
+\r
+/**                                                                 \r
+  Frees memory that was allocated with AllocateBuffer().\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.  \r
+  @param  Pages                 The number of pages to free.                                \r
+  @param  HostAddress           The base system memory address of the allocated range.                                    \r
+                                  \r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+                                was not allocated with AllocateBuffer().\r
+                                     \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcFreeBuffer (\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,\r
+  IN  UINTN                              Pages,\r
+  IN  VOID                               *HostAddress\r
+  )\r
+{\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_STATUS                        Status;\r
+\r
+  if ((This == NULL) || (HostAddress == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);\r
+  PciIo   = Private->PciIo;\r
+\r
+  Status  = PciIo->FreeBuffer (PciIo, Pages, HostAddress);\r
+  return Status;\r
+}\r
+\r
+/**                                                                 \r
+  Flushes all posted write transactions from the UFS bus to attached UFS device.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.  \r
+                                  \r
+  @retval EFI_SUCCESS           The posted write transactions were flushed from the UFS bus\r
+                                to attached UFS device.                                      \r
+  @retval EFI_DEVICE_ERROR      The posted write transactions were not flushed from the UFS\r
+                                bus to attached UFS device due to a hardware error.                           \r
+                                     \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcFlush (\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This\r
+  )\r
+{\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_STATUS                        Status;\r
+\r
+  Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);\r
+  PciIo   = Private->PciIo;\r
+\r
+  Status  = PciIo->Flush (PciIo);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  BOOLEAN                   UfsHcFound;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  PCI_TYPE00                PciData;\r
+\r
+  PciIo            = NULL;\r
+  ParentDevicePath = NULL;\r
+  UfsHcFound       = FALSE;\r
+\r
+  //\r
+  // UfsHcDxe is a device driver, and should ingore the\r
+  // "RemainingDevicePath" according to EFI spec\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID *) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EFI_ALREADY_STARTED is also an error\r
+    //\r
+    return Status;\r
+  }\r
+  //\r
+  // Close the protocol because we don't use it here\r
+  //\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiDevicePathProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  //\r
+  // Now test the EfiPciIoProtocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Now further check the PCI header: Base class (offset 0x0B) and\r
+  // Sub Class (offset 0x0A). This controller should be an UFS controller\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        0,\r
+                        sizeof (PciData),\r
+                        &PciData\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiPciIoProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Since we already got the PciData, we can close protocol to avoid to carry it on for multiple exit points.\r
+  //\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiPciIoProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  //\r
+  // Examine UFS Host Controller PCI Configuration table fields\r
+  //\r
+  if (PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE) {\r
+    if (PciData.Hdr.ClassCode[1] == 0x09 ) { //UFS Controller Subclass\r
+      UfsHcFound = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!UfsHcFound) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;\r
+  UINT64                            Supports;\r
+\r
+  PciIo    = NULL;\r
+  Private  = NULL;\r
+  Supports = 0;\r
+\r
+  //\r
+  // Now test and open the EfiPciIoProtocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  //\r
+  // Status == 0 - A normal execution flow, SUCCESS and the program proceeds.\r
+  // Status == ALREADY_STARTED - A non-zero Status code returned. It indicates\r
+  //           that the protocol has been opened and should be treated as a\r
+  //           normal condition and the program proceeds. The Protocol will not\r
+  //           opened 'again' by this call.\r
+  // Status != ALREADY_STARTED - Error status, terminate program execution\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EFI_ALREADY_STARTED is also an error\r
+    //\r
+    return Status;\r
+  }\r
+\r
+  Private = AllocateCopyPool (sizeof (UFS_HOST_CONTROLLER_PRIVATE_DATA), &gUfsHcTemplate);\r
+  if (Private == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  Private->PciIo = PciIo;\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationGet,\r
+                    0,\r
+                    &Private->PciAttributes\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
+    Status    = PciIo->Attributes (\r
+                         PciIo,\r
+                         EfiPciIoAttributeOperationEnable,\r
+                         Supports,\r
+                         NULL\r
+                         );\r
+  } else {\r
+    goto Done;\r
+  }\r
+\r
+  ///\r
+  /// Install UFS_HOST_CONTROLLER protocol\r
+  ///\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &gEdkiiUfsHostControllerProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  (VOID*)&(Private->UfsHc)\r
+                  );\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    if ((Private != NULL) && (Private->PciAttributes != 0)) {\r
+      //\r
+      // Restore original PCI attributes\r
+      //\r
+      Status = PciIo->Attributes (\r
+                        PciIo,\r
+                        EfiPciIoAttributeOperationSet,\r
+                        Private->PciAttributes,\r
+                        NULL\r
+                        );\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiPciIoProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+    if (Private != NULL) {\r
+      FreePool (Private);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  UFS_HOST_CONTROLLER_PRIVATE_DATA    *Private;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL  *UfsHc;\r
+\r
+  ///\r
+  /// Get private data\r
+  ///\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEdkiiUfsHostControllerProtocolGuid,\r
+                  (VOID **) &UfsHc,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (UfsHc);\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  Controller,\r
+                  &gEdkiiUfsHostControllerProtocolGuid,\r
+                  &(Private->UfsHc)\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Restore original PCI attributes\r
+    //\r
+    Status = Private->PciIo->Attributes (\r
+                               Private->PciIo,\r
+                               EfiPciIoAttributeOperationSet,\r
+                               Private->PciAttributes,\r
+                               NULL\r
+                               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Close protocols opened by UFS host controller driver\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+\r
+    FreePool (Private);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The entry point for UFS host controller driver, used to install this driver on the ImageHandle.\r
+\r
+  @param[in]  ImageHandle   The firmware allocated handle for this driver image.\r
+  @param[in]  SystemTable   Pointer to the EFI system table.\r
+\r
+  @retval EFI_SUCCESS   Driver loaded.\r
+  @retval other         Driver not loaded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcDriverEntry (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gUfsHcDriverBinding,\r
+             ImageHandle,\r
+             &gUfsHcComponentName,\r
+             &gUfsHcComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.h b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.h
new file mode 100644 (file)
index 0000000..f3b7eab
--- /dev/null
@@ -0,0 +1,453 @@
+/** @file\r
+  UfsHcDxe driver is used to provide platform-dependent info, mainly UFS host controller\r
+  MMIO base, to upper layer UFS drivers.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_UFS_HOST_CONTROLLER_H_\r
+#define _EFI_UFS_HOST_CONTROLLER_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Protocol/ComponentName.h>\r
+#include <Protocol/ComponentName2.h>\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/UfsHostController.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL                gUfsHcDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL                gUfsHcComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL               gUfsHcComponentName2;\r
+\r
+//\r
+// Unique signature for private data structure.\r
+//\r
+#define UFS_HC_PRIVATE_DATA_SIGNATURE             SIGNATURE_32 ('U','F','S','H')\r
+\r
+typedef struct _UFS_HOST_CONTROLLER_PRIVATE_DATA  UFS_HOST_CONTROLLER_PRIVATE_DATA;\r
+\r
+//\r
+// Nvme private data structure.\r
+//\r
+struct _UFS_HOST_CONTROLLER_PRIVATE_DATA {\r
+  UINT32                             Signature;\r
+  EFI_HANDLE                         Handle;\r
+\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL UfsHc;\r
+  EFI_PCI_IO_PROTOCOL                *PciIo;  \r
+  UINT64                             PciAttributes;\r
+};\r
+\r
+#define UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC(a) \\r
+  CR (a, \\r
+      UFS_HOST_CONTROLLER_PRIVATE_DATA, \\r
+      UfsHc, \\r
+      UFS_HC_PRIVATE_DATA_SIGNATURE \\r
+      )\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  );\r
+\r
+/**\r
+  Get the MMIO base of the UFS host controller.\r
+\r
+  @param[in]   This             A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param[out]  MmioBar          The MMIO base address of UFS host controller.\r
+\r
+  @retval EFI_SUCCESS           The operation succeeds.\r
+  @retval others                The operation fails.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcGetMmioBar (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,\r
+     OUT UINTN                              *MmioBar\r
+  );\r
+\r
+/**                                                                 \r
+  Provides the UFS controller-specific addresses needed to access system memory.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
+  @param  HostAddress           The system memory address to map to the UFS controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
+                                that were mapped.                                                 \r
+  @param  DeviceAddress         The resulting map address for the bus master UFS controller to use to\r
+                                access the hosts HostAddress.                                        \r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.                                \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
+                                   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcMap (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This,\r
+  IN     EDKII_UFS_HOST_CONTROLLER_OPERATION  Operation,\r
+  IN     VOID                                 *HostAddress,\r
+  IN OUT UINTN                                *NumberOfBytes,\r
+     OUT EFI_PHYSICAL_ADDRESS                 *DeviceAddress,\r
+     OUT VOID                                 **Mapping\r
+  );\r
+\r
+/**                                                                 \r
+  Completes the Map() operation and releases any corresponding resources.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.                                      \r
+  @param  Mapping               The mapping value returned from Map().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+                                   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcUnmap (\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This,\r
+  IN  VOID                                 *Mapping\r
+  );\r
+\r
+/**                                                                 \r
+  Allocates pages that are suitable for an EfiUfsHcOperationBusMasterCommonBuffer\r
+  mapping.                                                                       \r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param  Type                  This parameter is not used and must be ignored.\r
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
+                                EfiRuntimeServicesData.                               \r
+  @param  Pages                 The number of pages to allocate.                                \r
+  @param  HostAddress           A pointer to store the base system memory address of the\r
+                                allocated range.                                        \r
+  @param  Attributes            The requested bit mask of attributes for the allocated range.\r
+                                  \r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.                     \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.  \r
+                                   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcAllocateBuffer (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,\r
+  IN     EFI_ALLOCATE_TYPE                  Type,\r
+  IN     EFI_MEMORY_TYPE                    MemoryType,\r
+  IN     UINTN                              Pages,\r
+     OUT VOID                               **HostAddress,\r
+  IN     UINT64                             Attributes\r
+  );\r
+\r
+/**                                                                 \r
+  Frees memory that was allocated with AllocateBuffer().\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.  \r
+  @param  Pages                 The number of pages to free.                                \r
+  @param  HostAddress           The base system memory address of the allocated range.                                    \r
+                                  \r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+                                was not allocated with AllocateBuffer().\r
+                                     \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcFreeBuffer (\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL    *This,\r
+  IN  UINTN                                 Pages,\r
+  IN  VOID                                  *HostAddress\r
+  );\r
+\r
+/**                                                                 \r
+  Flushes all posted write transactions from the UFS bus to attached UFS device.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.  \r
+                                  \r
+  @retval EFI_SUCCESS           The posted write transactions were flushed from the UFS bus\r
+                                to attached UFS device.                                      \r
+  @retval EFI_DEVICE_ERROR      The posted write transactions were not flushed from the UFS\r
+                                bus to attached UFS device due to a hardware error.                           \r
+                                     \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsHcFlush (\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf
new file mode 100644 (file)
index 0000000..c1ce9ea
--- /dev/null
@@ -0,0 +1,56 @@
+## @file\r
+#  Component Description File For Universal Flash Storage Pci Host Controller Module.\r
+#\r
+#  Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php.\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UfsPciHcDxe\r
+  MODULE_UNI_FILE                = UfsPciHcDxe.uni\r
+  FILE_GUID                      = AF43E178-C2E9-4712-A7CD-08BFDAC7482C\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 0.9\r
+  ENTRY_POINT                    = UfsHcDriverEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gUfsHcDriverBinding\r
+#  COMPONENT_NAME                =  gUfsHcComponentName\r
+#  COMPONENT_NAME2               =  gUfsHcComponentName2\r
+\r
+[Sources]\r
+  ComponentName.c\r
+  UfsPciHcDxe.c\r
+  UfsPciHcDxe.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  DebugLib\r
+  DevicePathLib\r
+  UefiDriverEntryPoint\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+\r
+[Protocols]\r
+  gEfiPciIoProtocolGuid                       ## TO_START\r
+  gEfiDevicePathProtocolGuid                  ## TO_START\r
+  gEdkiiUfsHostControllerProtocolGuid         ## BY_START\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  UfsPciHcDxeExtra.uni
\ No newline at end of file
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni
new file mode 100644 (file)
index 0000000..5b3a137
Binary files /dev/null and b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni differ
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni
new file mode 100644 (file)
index 0000000..fb359fd
Binary files /dev/null and b/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni differ
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.c b/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.c
new file mode 100644 (file)
index 0000000..3632564
--- /dev/null
@@ -0,0 +1,152 @@
+/** @file\r
+  UfsPciHcPei driver is used to provide platform-dependent info, mainly UFS host controller\r
+  MMIO base, to upper layer UFS drivers.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsPciHcPei.h"\r
+\r
+EDKII_UFS_HOST_CONTROLLER_PPI  mUfsHostControllerPpi = { GetUfsHcMmioBar };\r
+\r
+EFI_PEI_PPI_DESCRIPTOR   mPpiList = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gEdkiiPeiUfsHostControllerPpiGuid,\r
+  &mUfsHostControllerPpi\r
+};\r
+\r
+/**\r
+  Get the MMIO base address of UFS host controller.\r
+\r
+  @param[in]  This               The protocol instance pointer.\r
+  @param[in]  ControllerId       The ID of the UFS host controller.\r
+  @param[out] MmioBar            Pointer to the UFS host controller MMIO base address.\r
+\r
+  @retval EFI_SUCCESS            The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetUfsHcMmioBar (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PPI *This,\r
+  IN     UINT8                         ControllerId,\r
+     OUT UINTN                         *MmioBar\r
+  )\r
+{\r
+  UFS_HC_PEI_PRIVATE_DATA  *Private;\r
+\r
+  if ((This == NULL) || (MmioBar == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = UFS_HC_PEI_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (ControllerId >= Private->TotalUfsHcs) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  *MmioBar = (UINTN)Private->UfsHcPciAddr[ControllerId];\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The user code starts with this function.\r
+  \r
+  @param  FileHandle             Handle of the file being invoked.\r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS            The driver is successfully initialized.\r
+  @retval Others                 Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeUfsHcPeim (\r
+  IN EFI_PEI_FILE_HANDLE       FileHandle,\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices\r
+  )\r
+{\r
+  EFI_BOOT_MODE            BootMode;\r
+  EFI_STATUS               Status;\r
+  UINT16                   Bus;\r
+  UINT16                   Device;\r
+  UINT16                   Function;\r
+  UINT32                   Size;\r
+  UINT8                    SubClass;\r
+  UINT8                    BaseClass;\r
+  UFS_HC_PEI_PRIVATE_DATA  *Private;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = PeiServicesGetBootMode (&BootMode);\r
+  ///\r
+  /// We do not export this in S3 boot path, because it is only for recovery.\r
+  ///\r
+  if (BootMode == BOOT_ON_S3_RESUME) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Private = (UFS_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (UFS_HC_PEI_PRIVATE_DATA));\r
+  if (Private == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "Failed to allocate memory for UFS_HC_PEI_PRIVATE_DATA! \n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Private->Signature            = UFS_HC_PEI_SIGNATURE;\r
+  Private->UfsHostControllerPpi = mUfsHostControllerPpi;\r
+  Private->PpiList              = mPpiList;\r
+  Private->PpiList.Ppi          = &Private->UfsHostControllerPpi;\r
+\r
+  for (Bus = 0; Bus < 256; Bus++) {\r
+    for (Device = 0; Device < 32; Device++) {\r
+      for (Function = 0; Function < 8; Function++) {\r
+        SubClass  = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
+        BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
+\r
+        if ((SubClass == 0x09) && (BaseClass == PCI_CLASS_MASS_STORAGE)) {\r
+          //\r
+          // Get the Ufs Pci host controller's MMIO region size.\r
+          //\r
+          PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+          PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), 0xFFFFFFFF);\r
+          Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));\r
+          //\r
+          // Assign resource to the Ufs Pci host controller's MMIO BAR.\r
+          // Enable the Ufs Pci host controller by setting BME and MSE bits of PCI_CMD register.\r
+          //\r
+          PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)(PcdGet32 (PcdUfsPciHostControllerMmioBase) + Size * Private->TotalUfsHcs));\r
+          PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+          //\r
+          // Record the allocated Mmio base address.\r
+          //\r
+          Private->UfsHcPciAddr[Private->TotalUfsHcs] = PcdGet32 (PcdUfsPciHostControllerMmioBase) + Size * Private->TotalUfsHcs;\r
+          Private->TotalUfsHcs++;\r
+          ASSERT (Private->TotalUfsHcs < MAX_UFS_HCS);\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  ///\r
+  /// Install Ufs Host Controller PPI\r
+  ///\r
+  Status = PeiServicesInstallPpi (&Private->PpiList);\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h b/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h
new file mode 100644 (file)
index 0000000..2405dd7
--- /dev/null
@@ -0,0 +1,62 @@
+/** @file\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _UFS_PCI_HOST_CONTROLLER_PEI_H_\r
+#define _UFS_PCI_HOST_CONTROLLER_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/MasterBootMode.h>\r
+#include <Ppi/UfsHostController.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#define UFS_HC_PEI_SIGNATURE    SIGNATURE_32 ('U', 'F', 'S', 'P')\r
+#define MAX_UFS_HCS             8\r
+\r
+typedef struct {\r
+  UINTN                         Signature;\r
+  EDKII_UFS_HOST_CONTROLLER_PPI UfsHostControllerPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR        PpiList;\r
+  UINTN                         TotalUfsHcs;\r
+  UINTN                         UfsHcPciAddr[MAX_UFS_HCS];\r
+} UFS_HC_PEI_PRIVATE_DATA;\r
+\r
+#define UFS_HC_PEI_PRIVATE_DATA_FROM_THIS(a)  CR (a, UFS_HC_PEI_PRIVATE_DATA, UfsHostControllerPpi, UFS_HC_PEI_SIGNATURE)\r
+\r
+/**\r
+  Get the MMIO base address of UFS host controller.\r
+\r
+  @param[in]  This               The protocol instance pointer.\r
+  @param[in]  ControllerId       The ID of the UFS host controller.\r
+  @param[out] MmioBar            Pointer to the UFS host controller MMIO base address.\r
+\r
+  @retval EFI_SUCCESS            The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetUfsHcMmioBar (\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PPI *This,\r
+  IN     UINT8                         ControllerId,\r
+     OUT UINTN                         *MmioBar\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf b/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf
new file mode 100644 (file)
index 0000000..b169356
--- /dev/null
@@ -0,0 +1,56 @@
+## @file\r
+#  Component Description File For Universal Flash Storage Pci Host Controller Pei Module.\r
+#\r
+#  Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php.\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UfsPciHcPei\r
+  MODULE_UNI_FILE                = UfsPciHcPei.uni\r
+  FILE_GUID                      = 905DC1AD-C44D-4965-98AC-B6B4444BFD65\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 0.9\r
+\r
+  ENTRY_POINT                    = InitializeUfsHcPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  UfsPciHcPei.c\r
+  UfsPciHcPei.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  PciLib\r
+  DebugLib\r
+  PeiServicesLib\r
+  MemoryAllocationLib\r
+  PeimEntryPoint\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUfsPciHostControllerMmioBase   ## CONSUMES\r
+\r
+[Ppis]\r
+  gEdkiiPeiUfsHostControllerPpiGuid         ## PRODUCES\r
+\r
+[Depex]\r
+  gEfiPeiMasterBootModePpiGuid AND gEfiPeiMemoryDiscoveredPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  UfsPciHcPeiExtra.uni
\ No newline at end of file
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni b/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni
new file mode 100644 (file)
index 0000000..7b7ea3a
Binary files /dev/null and b/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni differ
diff --git a/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni b/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni
new file mode 100644 (file)
index 0000000..4487eb9
Binary files /dev/null and b/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni differ
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c
new file mode 100644 (file)
index 0000000..05730ff
--- /dev/null
@@ -0,0 +1,995 @@
+/** @file\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsBlockIoPei.h"\r
+\r
+//\r
+// Template for UFS HC Peim Private Data.\r
+//\r
+UFS_PEIM_HC_PRIVATE_DATA   gUfsHcPeimTemplate = {\r
+  UFS_PEIM_HC_SIG,                // Signature\r
+  NULL,                           // Controller\r
+  NULL,                           // Pool\r
+  {                               // BlkIoPpi\r
+    UfsBlockIoPeimGetDeviceNo,\r
+    UfsBlockIoPeimGetMediaInfo,\r
+    UfsBlockIoPeimReadBlocks\r
+  },\r
+  {                               // BlkIoPpiList\r
+    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+    &gEfiPeiVirtualBlockIoPpiGuid,\r
+    NULL\r
+  },\r
+  {                               // Media\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    },\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    },\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    },\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    },\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    },\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    },\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    },\r
+    {\r
+      UfsDevice,\r
+      TRUE,\r
+      0,\r
+      0x1000\r
+    }\r
+  },\r
+  0,                              // UfsHcBase\r
+  0,                              // Capabilities\r
+  0,                              // TaskTag\r
+  0,                              // UtpTrlBase\r
+  0,                              // Nutrs\r
+  0,                              // UtpTmrlBase\r
+  0,                              // Nutmrs\r
+  {                               // Luns\r
+    {\r
+      UFS_LUN_0,                      // Ufs Common Lun 0\r
+      UFS_LUN_1,                      // Ufs Common Lun 1\r
+      UFS_LUN_2,                      // Ufs Common Lun 2\r
+      UFS_LUN_3,                      // Ufs Common Lun 3\r
+      UFS_LUN_4,                      // Ufs Common Lun 4\r
+      UFS_LUN_5,                      // Ufs Common Lun 5\r
+      UFS_LUN_6,                      // Ufs Common Lun 6\r
+      UFS_LUN_7,                      // Ufs Common Lun 7\r
+    },\r
+    0x0000,                           // By default exposing all Luns.\r
+    0x0\r
+  }\r
+};\r
+\r
+/**\r
+  Execute Request Sense SCSI command on a specific UFS device.\r
+\r
+  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun                  The lun on which the SCSI cmd executed.\r
+  @param[out] DataBuffer           A pointer to output sense data.\r
+  @param[out] DataBufferLength     The length of output sense data.\r
+\r
+  @retval EFI_SUCCESS              The command executed successfully.\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.\r
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimRequestSense (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA        *Private,\r
+  IN     UINTN                           Lun,  \r
+     OUT VOID                            *DataBuffer,\r
+     OUT UINT32                          *DataBufferLength\r
+  )  \r
+{\r
+  UFS_SCSI_REQUEST_PACKET                Packet;\r
+  UINT8                                  Cdb[UFS_SCSI_OP_LENGTH_SIX];\r
+  EFI_STATUS                             Status;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0]  = EFI_SCSI_OP_REQUEST_SENSE;\r
+\r
+  Packet.Timeout          = UFS_TIMEOUT;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = sizeof (Cdb);\r
+  Packet.DataDirection    = UfsDataIn;\r
+  Packet.InDataBuffer     = DataBuffer;\r
+  Packet.InTransferLength = *DataBufferLength;\r
+  Packet.SenseData        = NULL;\r
+  Packet.SenseDataLength  = 0;\r
+\r
+  Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *DataBufferLength = Packet.InTransferLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute TEST UNITY READY SCSI command on a specific UFS device.\r
+\r
+  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun                  The lun on which the SCSI cmd executed.\r
+  @param[out] SenseData            A pointer to output sense data.\r
+  @param[out] SenseDataLength      The length of output sense data.\r
+\r
+  @retval EFI_SUCCESS              The command executed successfully.\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.\r
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimTestUnitReady (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA        *Private,\r
+  IN     UINTN                           Lun,  \r
+     OUT VOID                            *SenseData,  OPTIONAL\r
+     OUT UINT8                           *SenseDataLength\r
+  )  \r
+{\r
+  UFS_SCSI_REQUEST_PACKET                Packet;\r
+  UINT8                                  Cdb[UFS_SCSI_OP_LENGTH_SIX];\r
+  EFI_STATUS                             Status;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0]  = EFI_SCSI_OP_TEST_UNIT_READY;\r
+\r
+  Packet.Timeout         = UFS_TIMEOUT;\r
+  Packet.Cdb             = Cdb;\r
+  Packet.CdbLength       = sizeof (Cdb);\r
+  Packet.DataDirection   = UfsNoData;\r
+  Packet.SenseData       = SenseData;\r
+  Packet.SenseDataLength = *SenseDataLength;\r
+\r
+  Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);\r
+\r
+  if (*SenseDataLength != 0) {\r
+    *SenseDataLength = Packet.SenseDataLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute INQUIRY SCSI command on a specific UFS device.\r
+\r
+  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun                  The lun on which the SCSI cmd executed.\r
+  @param[out] Inquiry              A pointer to Inquiry data buffer.\r
+  @param[out] InquiryLengths       The length of output Inquiry data.\r
+  @param[out] SenseData            A pointer to output sense data.\r
+  @param[out] SenseDataLength      The length of output sense data.\r
+\r
+  @retval EFI_SUCCESS              The command executed successfully.\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.\r
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimInquiry (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     UINTN                        Lun,\r
+     OUT VOID                         *Inquiry,\r
+     OUT UINT32                       *InquiryLength,\r
+     OUT VOID                         *SenseData,  OPTIONAL\r
+     OUT UINT8                        *SenseDataLength\r
+  )  \r
+{\r
+  UFS_SCSI_REQUEST_PACKET             Packet;\r
+  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIX];\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0]  = EFI_SCSI_OP_INQUIRY;\r
+  Cdb[4]  = sizeof (EFI_SCSI_INQUIRY_DATA);\r
+\r
+  Packet.Timeout          = UFS_TIMEOUT;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = sizeof (Cdb);\r
+  Packet.InDataBuffer     = Inquiry;\r
+  Packet.InTransferLength = *InquiryLength;\r
+  Packet.DataDirection    = UfsDataIn;\r
+  Packet.SenseData        = SenseData;\r
+  Packet.SenseDataLength  = *SenseDataLength;\r
+\r
+  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);\r
+\r
+  if (*SenseDataLength != 0) {\r
+    *SenseDataLength = Packet.SenseDataLength;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *InquiryLength = Packet.InTransferLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute READ CAPACITY(10) SCSI command on a specific UFS device.\r
+\r
+  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun                  The lun on which the SCSI cmd executed.\r
+  @param[out] DataBuffer           A pointer to READ_CAPACITY data buffer.\r
+  @param[out] DataLength           The length of output READ_CAPACITY data.\r
+  @param[out] SenseData            A pointer to output sense data.\r
+  @param[out] SenseDataLength      The length of output sense data.\r
+\r
+  @retval EFI_SUCCESS              The command executed successfully.\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.\r
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimReadCapacity (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     UINTN                        Lun,\r
+     OUT VOID                         *DataBuffer,\r
+     OUT UINT32                       *DataLength,\r
+     OUT VOID                         *SenseData,  OPTIONAL\r
+     OUT UINT8                        *SenseDataLength\r
+  )  \r
+{\r
+  UFS_SCSI_REQUEST_PACKET             Packet;\r
+  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;\r
+\r
+  Packet.Timeout          = UFS_TIMEOUT;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = sizeof (Cdb);\r
+  Packet.InDataBuffer     = DataBuffer;\r
+  Packet.InTransferLength = *DataLength;\r
+  Packet.DataDirection    = UfsDataIn;\r
+  Packet.SenseData        = SenseData;\r
+  Packet.SenseDataLength  = *SenseDataLength;\r
+\r
+  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);\r
+\r
+  if (*SenseDataLength != 0) {\r
+    *SenseDataLength = Packet.SenseDataLength;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *DataLength = Packet.InTransferLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute READ CAPACITY(16) SCSI command on a specific UFS device.\r
+\r
+  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun                  The lun on which the SCSI cmd executed.\r
+  @param[out] DataBuffer           A pointer to READ_CAPACITY data buffer.\r
+  @param[out] DataLength           The length of output READ_CAPACITY data.\r
+  @param[out] SenseData            A pointer to output sense data.\r
+  @param[out] SenseDataLength      The length of output sense data.\r
+\r
+  @retval EFI_SUCCESS              The command executed successfully.\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.\r
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimReadCapacity16 (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     UINTN                        Lun,\r
+     OUT VOID                         *DataBuffer,\r
+     OUT UINT32                       *DataLength,\r
+     OUT VOID                         *SenseData,  OPTIONAL\r
+     OUT UINT8                        *SenseDataLength\r
+  )  \r
+{\r
+  UFS_SCSI_REQUEST_PACKET             Packet;\r
+  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0]  = EFI_SCSI_OP_READ_CAPACITY16;\r
+  Cdb[1]  = 0x10;          // Service Action should be 0x10 for UFS device.\r
+  Cdb[13] = 0x20;          // The maximum number of bytes for returned data.\r
+\r
+  Packet.Timeout          = UFS_TIMEOUT;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = sizeof (Cdb);\r
+  Packet.InDataBuffer     = DataBuffer;\r
+  Packet.InTransferLength = *DataLength;\r
+  Packet.DataDirection    = UfsDataIn;\r
+  Packet.SenseData        = SenseData;\r
+  Packet.SenseDataLength  = *SenseDataLength;\r
+\r
+  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);\r
+\r
+  if (*SenseDataLength != 0) {\r
+    *SenseDataLength = Packet.SenseDataLength;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *DataLength = Packet.InTransferLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute READ (10) SCSI command on a specific UFS device.\r
+\r
+  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun                  The lun on which the SCSI cmd executed.\r
+  @param[in]  StartLba             The start LBA.\r
+  @param[in]  SectorNum            The sector number to be read.\r
+  @param[out] DataBuffer           A pointer to data buffer.\r
+  @param[out] DataLength           The length of output data.\r
+  @param[out] SenseData            A pointer to output sense data.\r
+  @param[out] SenseDataLength      The length of output sense data.\r
+\r
+  @retval EFI_SUCCESS              The command executed successfully.\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.\r
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimRead10 (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     UINTN                        Lun,\r
+  IN     UINTN                        StartLba,\r
+  IN     UINT32                       SectorNum,\r
+     OUT VOID                         *DataBuffer,\r
+     OUT UINT32                       *DataLength,\r
+     OUT VOID                         *SenseData,  OPTIONAL\r
+     OUT UINT8                        *SenseDataLength\r
+  )  \r
+{\r
+  UFS_SCSI_REQUEST_PACKET             Packet;\r
+  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0] = EFI_SCSI_OP_READ10;\r
+  WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 ((UINT32) StartLba));\r
+  WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorNum));\r
+\r
+  Packet.Timeout          = UFS_TIMEOUT;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = sizeof (Cdb);\r
+  Packet.InDataBuffer     = DataBuffer;\r
+  Packet.InTransferLength = *DataLength;\r
+  Packet.DataDirection    = UfsDataIn;\r
+  Packet.SenseData        = SenseData;\r
+  Packet.SenseDataLength  = *SenseDataLength;\r
+\r
+  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);\r
+\r
+  if (*SenseDataLength != 0) {\r
+    *SenseDataLength = Packet.SenseDataLength;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *DataLength = Packet.InTransferLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute READ (16) SCSI command on a specific UFS device.\r
+\r
+  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun                  The lun on which the SCSI cmd executed.\r
+  @param[in]  StartLba             The start LBA.\r
+  @param[in]  SectorNum            The sector number to be read.\r
+  @param[out] DataBuffer           A pointer to data buffer.\r
+  @param[out] DataLength           The length of output data.\r
+  @param[out] SenseData            A pointer to output sense data.\r
+  @param[out] SenseDataLength      The length of output sense data.\r
+\r
+  @retval EFI_SUCCESS              The command executed successfully.\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.\r
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimRead16 (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     UINTN                        Lun,\r
+  IN     UINTN                        StartLba,\r
+  IN     UINT32                       SectorNum,\r
+     OUT VOID                         *DataBuffer,\r
+     OUT UINT32                       *DataLength,\r
+     OUT VOID                         *SenseData,  OPTIONAL\r
+     OUT UINT8                        *SenseDataLength\r
+  )  \r
+{\r
+  UFS_SCSI_REQUEST_PACKET             Packet;\r
+  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0] = EFI_SCSI_OP_READ16;\r
+  WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));\r
+  WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorNum));\r
+\r
+  Packet.Timeout          = UFS_TIMEOUT;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = sizeof (Cdb);\r
+  Packet.InDataBuffer     = DataBuffer;\r
+  Packet.InTransferLength = *DataLength;\r
+  Packet.DataDirection    = UfsDataIn;\r
+  Packet.SenseData        = SenseData;\r
+  Packet.SenseDataLength  = *SenseDataLength;\r
+\r
+  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);\r
+\r
+  if (*SenseDataLength != 0) {\r
+    *SenseDataLength = Packet.SenseDataLength;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *DataLength = Packet.InTransferLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Parsing Sense Keys from sense data.\r
+\r
+  @param  Media              The pointer of EFI_PEI_BLOCK_IO_MEDIA\r
+  @param  SenseData          The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  NeedRetry          The pointer of action which indicates what is need to retry\r
+\r
+  @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
+  @retval EFI_SUCCESS        Successfully to complete the parsing\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimParsingSenseKeys (\r
+  IN     EFI_PEI_BLOCK_IO_MEDIA    *Media,\r
+  IN     EFI_SCSI_SENSE_DATA       *SenseData,\r
+     OUT BOOLEAN                   *NeedRetry\r
+  )\r
+{\r
+  if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&\r
+      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {\r
+    Media->MediaPresent = FALSE;\r
+    *NeedRetry = FALSE;\r
+    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is No Media\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
+      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {\r
+    *NeedRetry = TRUE;\r
+    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is Media Change\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
+      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {\r
+    *NeedRetry = TRUE;\r
+    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((SenseData->Sense_Key == EFI_SCSI_SK_MEDIUM_ERROR) ||\r
+      ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&\r
+      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN))) {\r
+    *NeedRetry = FALSE;\r
+    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Media Error\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (SenseData->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {\r
+    *NeedRetry = FALSE;\r
+    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Hardware Error\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&\r
+      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NOT_READY) &&\r
+      (SenseData->Addnl_Sense_Code_Qualifier == EFI_SCSI_ASCQ_IN_PROGRESS)) {\r
+    *NeedRetry = TRUE;\r
+    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  *NeedRetry = FALSE;\r
+  DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one \r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process. \r
+  To the PEI legacy floppy driver, it returns the number of all the legacy \r
+  devices it finds during its enumeration process. If no device is detected, \r
+  then the function will return zero.  \r
+  \r
+  @param[in]  PeiServices          General-purpose services that are available \r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI \r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsBlockIoPeimGetDeviceNo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  )\r
+{\r
+  //\r
+  // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.\r
+  // At PEI phase, we will only expose normal Luns to user.\r
+  // For those disabled Lun, when user try to access it, the operation would fail.\r
+  //\r
+  *NumberBlockDevices = UFS_PEIM_MAX_LUNS;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media \r
+  information. If the media changes, calling this function will update the media \r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, the PPIs that \r
+                            want to talk to a single device must specify the \r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to \r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.  \r
+                            The caller is responsible for the ownership of this \r
+                            data structure.\r
+\r
+  @par Note: \r
+      The MediaInfo structure describes an enumeration of possible block device \r
+      types.  This enumeration exists because no device paths are actually passed \r
+      across interfaces that describe the type or class of hardware that is publishing \r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first, \r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted \r
+      by a given device type, they should be reported in ascending order; this \r
+      order also applies to nested partitions, such as legacy MBR, where the \r
+      outermost partitions would have precedence in the reporting order. The \r
+      same logic applies to systems such as IDE that have precedence relationships \r
+      like "Master/Slave" or "Primary/Secondary". The master device should be \r
+      reported first, the slave second.\r
+  \r
+  @retval EFI_SUCCESS        Media information about the specified block device \r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware \r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsBlockIoPeimGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UFS_PEIM_HC_PRIVATE_DATA           *Private;\r
+  EFI_SCSI_SENSE_DATA                SenseData;\r
+  UINT8                              SenseDataLength;\r
+  EFI_SCSI_DISK_CAPACITY_DATA        Capacity;\r
+  EFI_SCSI_DISK_CAPACITY_DATA16      Capacity16;\r
+  UINTN                              DataLength;\r
+  BOOLEAN                            NeedRetry;  \r
+\r
+  Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+  NeedRetry = TRUE;\r
+\r
+  if (DeviceIndex >= UFS_PEIM_MAX_LUNS) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  ZeroMem (&SenseData, sizeof (SenseData));\r
+  ZeroMem (&Capacity, sizeof (Capacity));\r
+  ZeroMem (&Capacity16, sizeof (Capacity16));\r
+  SenseDataLength = sizeof (SenseData);\r
+  //\r
+  // First test unit ready\r
+  //\r
+  do {\r
+    Status = UfsPeimTestUnitReady (\r
+               Private,\r
+               DeviceIndex,\r
+               &SenseData,\r
+               &SenseDataLength\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  \r
+    if (SenseDataLength == 0) {\r
+      continue;\r
+    }\r
+\r
+    Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+  } while (NeedRetry);\r
+\r
+  DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
+  SenseDataLength = 0;\r
+  Status = UfsPeimReadCapacity (Private, DeviceIndex, &Capacity, (UINT32 *)&DataLength, NULL, &SenseDataLength);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((Capacity.LastLba3 == 0xff) && (Capacity.LastLba2 == 0xff) &&\r
+      (Capacity.LastLba1 == 0xff) && (Capacity.LastLba0 == 0xff)) {\r
+    DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
+    SenseDataLength = 0;\r
+    Status = UfsPeimReadCapacity16 (Private, DeviceIndex, &Capacity16, (UINT32 *)&DataLength, NULL, &SenseDataLength);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    MediaInfo->LastBlock  = (Capacity16.LastLba3 << 24) | (Capacity16.LastLba2 << 16) | (Capacity16.LastLba1 << 8) | Capacity16.LastLba0;\r
+    MediaInfo->LastBlock |= ((UINT64)Capacity16.LastLba7 << 56) | ((UINT64)Capacity16.LastLba6 << 48) | ((UINT64)Capacity16.LastLba5 << 40) | ((UINT64)Capacity16.LastLba4 << 32);\r
+    MediaInfo->BlockSize  = (Capacity16.BlockSize3 << 24) | (Capacity16.BlockSize2 << 16) | (Capacity16.BlockSize1 << 8) | Capacity16.BlockSize0;\r
+  } else {\r
+    MediaInfo->LastBlock  = (Capacity.LastLba3 << 24) | (Capacity.LastLba2 << 16) | (Capacity.LastLba1 << 8) | Capacity.LastLba0;\r
+    MediaInfo->BlockSize  = (Capacity.BlockSize3 << 24) | (Capacity.BlockSize2 << 16) | (Capacity.BlockSize1 << 8) | Capacity.BlockSize0;\r
+  }\r
+\r
+  MediaInfo->DeviceType   = UfsDevice;\r
+  MediaInfo->MediaPresent = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the \r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to \r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, PPIs that \r
+                            want to talk to a single device must specify the device \r
+                            index that was assigned during the enumeration process. \r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the \r
+                            buffer.\r
+                         \r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting \r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not \r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsBlockIoPeimReadBlocks (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UINTN                              BlockSize;\r
+  UINTN                              NumberOfBlocks;\r
+  UFS_PEIM_HC_PRIVATE_DATA           *Private;\r
+  EFI_SCSI_SENSE_DATA                SenseData;\r
+  UINT8                              SenseDataLength;\r
+  BOOLEAN                            NeedRetry;  \r
+\r
+  Status    = EFI_SUCCESS;\r
+  NeedRetry = TRUE;\r
+  Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  ZeroMem (&SenseData, sizeof (SenseData));\r
+  SenseDataLength = sizeof (SenseData);\r
+\r
+  //\r
+  // Check parameters\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (DeviceIndex >= UFS_PEIM_MAX_LUNS) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  BlockSize = Private->Media[DeviceIndex].BlockSize;\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    Status = EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (StartLBA > Private->Media[DeviceIndex].LastBlock) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+  do {\r
+    Status = UfsPeimTestUnitReady (\r
+               Private,\r
+               DeviceIndex,\r
+               &SenseData,\r
+               &SenseDataLength\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  \r
+    if (SenseDataLength == 0) {\r
+      continue;\r
+    }\r
+\r
+    Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+  } while (NeedRetry);\r
+\r
+  SenseDataLength = 0;\r
+  if (Private->Media[DeviceIndex].LastBlock != ~((UINTN)0)) {\r
+    Status = UfsPeimRead10 (\r
+               Private,\r
+               DeviceIndex,\r
+               (UINT32)StartLBA,\r
+               (UINT32)NumberOfBlocks,\r
+               Buffer,\r
+               (UINT32 *)&BufferSize,\r
+               NULL,\r
+               &SenseDataLength\r
+               );\r
+  } else {\r
+    Status = UfsPeimRead16 (\r
+               Private,\r
+               DeviceIndex,\r
+               (UINT32)StartLBA,\r
+               (UINT32)NumberOfBlocks,\r
+               Buffer,\r
+               (UINT32 *)&BufferSize,\r
+               NULL,\r
+               &SenseDataLength\r
+               );\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The user code starts with this function.\r
+  \r
+  @param  FileHandle             Handle of the file being invoked.\r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS            The driver is successfully initialized.\r
+  @retval Others                 Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeUfsBlockIoPeim (\r
+  IN EFI_PEI_FILE_HANDLE        FileHandle,\r
+  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UFS_PEIM_HC_PRIVATE_DATA      *Private;\r
+  EDKII_UFS_HOST_CONTROLLER_PPI *UfsHcPpi;\r
+  UINT32                        Index;\r
+  UFS_CONFIG_DESC               Config;\r
+  UINTN                         MmioBase;\r
+  UINT8                         Controller;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // locate ufs host controller PPI\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &gEdkiiPeiUfsHostControllerPpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **) &UfsHcPpi\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Controller = 0;\r
+  MmioBase   = 0;\r
+  while (TRUE) {\r
+    Status = UfsHcPpi->GetUfsHcMmioBar (UfsHcPpi, Controller, &MmioBase);\r
+    //\r
+    // When status is error, meant no controller is found\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    Private = AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA), &gUfsHcPeimTemplate);\r
+    if (Private == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+\r
+    Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;\r
+    Private->UfsHcBase        = MmioBase;\r
+\r
+    //\r
+    // Initialize the memory pool which will be used in all transactions.\r
+    //\r
+    Status = UfsPeimInitMemPool (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Initialize UFS Host Controller H/W.\r
+    //\r
+    Status = UfsControllerInit (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status));\r
+      Controller++;\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // UFS 2.0 spec Section 13.1.3.3:\r
+    // At the end of the UFS Interconnect Layer initialization on both host and device side, \r
+    // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready. \r
+    //\r
+    Status = UfsExecNopCmds (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));\r
+      Controller++;\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // The host enables the device initialization completion by setting fDeviceInit flag.\r
+    //\r
+    Status = UfsSetFlag (Private, UfsFlagDevInit);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));\r
+      Controller++;\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Get Ufs Device's Lun Info by reading Configuration Descriptor.\r
+    //\r
+    Status = UfsRwDeviceDesc (Private, TRUE, UfsConfigDesc, 0, 0, &Config, sizeof (UFS_CONFIG_DESC));\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status));\r
+      Controller++;\r
+      continue;\r
+    }\r
+\r
+    for (Index = 0; Index < UFS_PEIM_MAX_LUNS; Index++) {\r
+      if (Config.UnitDescConfParams[Index].LunEn != 0) {\r
+        Private->Luns.BitMask |= (BIT0 << Index);\r
+        DEBUG ((EFI_D_INFO, "Ufs %d Lun %d is enabled\n", Controller, Index));\r
+      }\r
+    }\r
+    \r
+    Status = PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
+    Controller++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
new file mode 100644 (file)
index 0000000..835b9c6
--- /dev/null
@@ -0,0 +1,434 @@
+/** @file\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _UFS_BLOCK_IO_PEI_H_\r
+#define _UFS_BLOCK_IO_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UfsHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <IndustryStandard/Scsi.h>\r
+\r
+#include "UfsHci.h"\r
+#include "UfsHcMem.h"\r
+\r
+#define UFS_PEIM_HC_SIG             SIGNATURE_32 ('U', 'F', 'S', 'H')\r
+\r
+#define UFS_PEIM_MAX_LUNS           8\r
+\r
+typedef struct {\r
+  UINT8    Lun[UFS_PEIM_MAX_LUNS];\r
+  UINT16   BitMask:12;              // Bit 0~7 is for common luns. Bit 8~11 is reserved for those well known luns\r
+  UINT16   Rsvd:4;\r
+} UFS_PEIM_EXPOSED_LUNS;\r
+\r
+typedef struct {\r
+  ///\r
+  /// The timeout, in 100 ns units, to use for the execution of this SCSI\r
+  /// Request Packet. A Timeout value of 0 means that this function\r
+  /// will wait indefinitely for the SCSI Request Packet to execute. If\r
+  /// Timeout is greater than zero, then this function will return\r
+  /// EFI_TIMEOUT if the time required to execute the SCSI\r
+  /// Request Packet is greater than Timeout.\r
+  ///\r
+  UINT64 Timeout;\r
+  ///\r
+  /// A pointer to the data buffer to transfer between the SCSI\r
+  /// controller and the SCSI device for read and bidirectional commands.\r
+  ///\r
+  VOID   *InDataBuffer;\r
+  ///\r
+  /// A pointer to the data buffer to transfer between the SCSI\r
+  /// controller and the SCSI device for write or bidirectional commands.\r
+  ///\r
+  VOID   *OutDataBuffer;\r
+  ///\r
+  /// A pointer to the sense data that was generated by the execution of\r
+  /// the SCSI Request Packet.\r
+  ///\r
+  VOID   *SenseData;\r
+  ///\r
+  /// A pointer to buffer that contains the Command Data Block to\r
+  /// send to the SCSI device specified by Target and Lun.\r
+  ///\r
+  VOID   *Cdb;\r
+  ///\r
+  /// On Input, the size, in bytes, of InDataBuffer. On output, the\r
+  /// number of bytes transferred between the SCSI controller and the SCSI device.\r
+  ///\r
+  UINT32 InTransferLength;\r
+  ///\r
+  /// On Input, the size, in bytes of OutDataBuffer. On Output, the\r
+  /// Number of bytes transferred between SCSI Controller and the SCSI device.\r
+  ///\r
+  UINT32 OutTransferLength;\r
+  ///\r
+  /// The length, in bytes, of the buffer Cdb. The standard values are 6,\r
+  /// 10, 12, and 16, but other values are possible if a variable length CDB is used.\r
+  ///\r
+  UINT8  CdbLength;\r
+  ///\r
+  /// The direction of the data transfer. 0 for reads, 1 for writes. A\r
+  /// value of 2 is Reserved for Bi-Directional SCSI commands.\r
+  ///\r
+  UINT8  DataDirection;\r
+  ///\r
+  /// On input, the length in bytes of the SenseData buffer. On\r
+  /// output, the number of bytes written to the SenseData buffer.\r
+  ///\r
+  UINT8  SenseDataLength;\r
+} UFS_SCSI_REQUEST_PACKET;\r
+\r
+typedef struct _UFS_PEIM_HC_PRIVATE_DATA {  \r
+  UINT32                            Signature;\r
+  EFI_HANDLE                        Controller;\r
+\r
+  UFS_PEIM_MEM_POOL                 *Pool;\r
+\r
+  EFI_PEI_RECOVERY_BLOCK_IO_PPI     BlkIoPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR            BlkIoPpiList;\r
+  EFI_PEI_BLOCK_IO_MEDIA            Media[UFS_PEIM_MAX_LUNS];\r
+\r
+  UINTN                             UfsHcBase;\r
+  UINT32                            Capabilities;\r
+\r
+  UINT8                             TaskTag;\r
+\r
+  VOID                              *UtpTrlBase;\r
+  UINT8                             Nutrs;\r
+  VOID                              *UtpTmrlBase;\r
+  UINT8                             Nutmrs;\r
+\r
+  UFS_PEIM_EXPOSED_LUNS             Luns;\r
+} UFS_PEIM_HC_PRIVATE_DATA;\r
+\r
+#define UFS_TIMEOUT                 MultU64x32((UINT64)(3), 10000000)\r
+\r
+#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)\r
+\r
+#define IS_ALIGNED(addr, size)      (((UINTN) (addr) & (size - 1)) == 0)\r
+\r
+#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIoPpi, UFS_PEIM_HC_SIG)\r
+\r
+#define UFS_SCSI_OP_LENGTH_SIX      0x6\r
+#define UFS_SCSI_OP_LENGTH_TEN      0xa\r
+#define UFS_SCSI_OP_LENGTH_SIXTEEN  0x10\r
+\r
+typedef struct _UFS_DEVICE_MANAGEMENT_REQUEST_PACKET {\r
+  UINT64                            Timeout;\r
+  VOID                              *InDataBuffer;\r
+  VOID                              *OutDataBuffer;\r
+  UINT8                             Opcode;\r
+  UINT8                             DescId;\r
+  UINT8                             Index;\r
+  UINT8                             Selector;\r
+  UINT32                            InTransferLength;\r
+  UINT32                            OutTransferLength;\r
+  UINT8                             DataDirection;\r
+  UINT8                             Ocs;\r
+} UFS_DEVICE_MANAGEMENT_REQUEST_PACKET;\r
+\r
+/**\r
+  Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]      Lun           The LUN of the UFS device to send the SCSI Request Packet.\r
+  @param[in, out] Packet        A pointer to the SCSI Request Packet to send to a specified Lun of the\r
+                                UFS device.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecScsiCmds (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA      *Private,\r
+  IN     UINT8                         Lun,\r
+  IN OUT UFS_SCSI_REQUEST_PACKET       *Packet\r
+  );\r
+\r
+/**\r
+  Initialize the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The Ufs Host Controller is initialized successfully.\r
+  @retval Others                     A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerInit (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  );\r
+\r
+/**\r
+  Stop the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The Ufs Host Controller is stopped successfully.\r
+  @retval Others                     A device error occurred while stopping the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerStop (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  );\r
+\r
+/**\r
+  Set specified flag to 1 on a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be set.\r
+\r
+  @retval EFI_SUCCESS           The flag was set successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to set the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of setting the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsSetFlag (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN  UINT8                        FlagId\r
+  );\r
+\r
+/**\r
+  Read or write specified device descriptor of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      DescId        The ID of device descriptor.\r
+  @param[in]      Index         The Index of device descriptor.\r
+  @param[in]      Selector      The Selector of device descriptor.\r
+  @param[in, out] Descriptor    The buffer of device descriptor to be read or written.\r
+  @param[in]      DescSize      The size of device descriptor buffer.\r
+\r
+  @retval EFI_SUCCESS           The device descriptor was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the device descriptor.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the device descriptor.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwDeviceDesc (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        DescId,\r
+  IN     UINT8                        Index,\r
+  IN     UINT8                        Selector,\r
+  IN OUT VOID                         *Descriptor,\r
+  IN     UINT32                       DescSize\r
+  );\r
+\r
+/**\r
+  Sends NOP IN cmd to a UFS device for initialization process request.\r
+  For more details, please refer to UFS 2.0 spec Figure 13.3.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS           The NOP IN command was sent by the host. The NOP OUT response was\r
+                                received successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to execute NOP IN command.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the NOP IN command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecNopCmds (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  );\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one \r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process. \r
+  To the PEI legacy floppy driver, it returns the number of all the legacy \r
+  devices it finds during its enumeration process. If no device is detected, \r
+  then the function will return zero.  \r
+  \r
+  @param[in]  PeiServices          General-purpose services that are available \r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI \r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsBlockIoPeimGetDeviceNo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  );\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media \r
+  information. If the media changes, calling this function will update the media \r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, the PPIs that \r
+                            want to talk to a single device must specify the \r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to \r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.  \r
+                            The caller is responsible for the ownership of this \r
+                            data structure.\r
+\r
+  @par Note: \r
+      The MediaInfo structure describes an enumeration of possible block device \r
+      types.  This enumeration exists because no device paths are actually passed \r
+      across interfaces that describe the type or class of hardware that is publishing \r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first, \r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted \r
+      by a given device type, they should be reported in ascending order; this \r
+      order also applies to nested partitions, such as legacy MBR, where the \r
+      outermost partitions would have precedence in the reporting order. The \r
+      same logic applies to systems such as IDE that have precedence relationships \r
+      like "Master/Slave" or "Primary/Secondary". The master device should be \r
+      reported first, the slave second.\r
+  \r
+  @retval EFI_SUCCESS        Media information about the specified block device \r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware \r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsBlockIoPeimGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo\r
+  );\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the \r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to \r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, PPIs that \r
+                            want to talk to a single device must specify the device \r
+                            index that was assigned during the enumeration process. \r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the \r
+                            buffer.\r
+                         \r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting \r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not \r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsBlockIoPeimReadBlocks (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  );\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+  \r
+  @param  Private               The Ufs Peim driver private data.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval Others                Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimInitMemPool (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA      *Private\r
+  );\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+  \r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UfsPeimAllocateMem (\r
+  IN  UFS_PEIM_MEM_POOL        *Pool,\r
+  IN  UINTN                    Size\r
+  );\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UfsPeimFreeMem (\r
+  IN UFS_PEIM_MEM_POOL    *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf
new file mode 100644 (file)
index 0000000..574e244
--- /dev/null
@@ -0,0 +1,61 @@
+## @file\r
+# Description file for the Universal Flash Storage (UFS) Peim driver.\r
+#\r
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UfsBlockIoPei\r
+  MODULE_UNI_FILE                = UfsBlockIoPei.uni\r
+  FILE_GUID                      = BE189D38-C963-41CF-B695-D90E9E545A13\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 0.9\r
+\r
+  ENTRY_POINT                    = InitializeUfsBlockIoPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  UfsBlockIoPei.c\r
+  UfsBlockIoPei.h\r
+  UfsHci.c\r
+  UfsHci.h\r
+  UfsHcMem.c\r
+  UfsHcMem.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  IoLib\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+  DebugLib\r
+\r
+[Ppis]\r
+  gEfiPeiVirtualBlockIoPpiGuid                  ## PRODUCES\r
+  gEdkiiPeiUfsHostControllerPpiGuid             ## CONSUMES\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiUfsHostControllerPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  UfsBlockIoPeiExtra.uni\r
+\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni
new file mode 100644 (file)
index 0000000..23b6e63
Binary files /dev/null and b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni differ
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni
new file mode 100644 (file)
index 0000000..706fcdc
Binary files /dev/null and b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni differ
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c
new file mode 100644 (file)
index 0000000..cc6c3d4
--- /dev/null
@@ -0,0 +1,455 @@
+/** @file\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsBlockIoPei.h"\r
+\r
+/**\r
+  Allocate a block of memory to be used by the buffer pool.\r
+\r
+  @param  Pages          How many pages to allocate.\r
+\r
+  @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+UFS_PEIM_MEM_BLOCK *\r
+UfsPeimAllocMemBlock (\r
+  IN  UINTN                    Pages\r
+  )\r
+{\r
+  UFS_PEIM_MEM_BLOCK           *Block;\r
+  EFI_STATUS                   Status;\r
+  VOID                         *TempPtr;\r
+  EFI_PHYSICAL_ADDRESS         Address;\r
+\r
+  TempPtr = NULL;\r
+  Block   = NULL;\r
+\r
+  Status = PeiServicesAllocatePool (sizeof(UFS_PEIM_MEM_BLOCK), &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(UFS_PEIM_MEM_BLOCK));\r
+  \r
+  //\r
+  // each bit in the bit array represents UFS_PEIM_MEM_UNIT\r
+  // bytes of memory in the memory block.\r
+  //\r
+  ASSERT (UFS_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+  \r
+  Block = (UFS_PEIM_MEM_BLOCK*)(UINTN)TempPtr;\r
+  Block->BufLen   = EFI_PAGES_TO_SIZE (Pages);\r
+  Block->BitsLen  = Block->BufLen / (UFS_PEIM_MEM_UNIT * 8);\r
+  \r
+  Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);\r
+\r
+  Block->Bits = (UINT8*)(UINTN)TempPtr;\r
+\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             Pages,\r
+             &Address\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)Address, EFI_PAGES_TO_SIZE (Pages));\r
+\r
+  Block->Buf  = (UINT8*)((UINTN)Address);\r
+  Block->Next = NULL;\r
+\r
+  return Block;\r
+}\r
+\r
+/**\r
+  Free the memory block from the memory pool.\r
+\r
+  @param  Pool           The memory pool to free the block from.\r
+  @param  Block          The memory block to free.\r
+\r
+**/\r
+VOID\r
+UfsPeimFreeMemBlock (\r
+  IN UFS_PEIM_MEM_POOL       *Pool,\r
+  IN UFS_PEIM_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+/**\r
+  Alloc some memory from the block.\r
+\r
+  @param  Block          The memory block to allocate memory from.\r
+  @param  Units          Number of memory units to allocate.\r
+\r
+  @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+          the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+UfsPeimAllocMemFromBlock (\r
+  IN  UFS_PEIM_MEM_BLOCK  *Block,\r
+  IN  UINTN               Units\r
+  )\r
+{\r
+  UINTN                   Byte;\r
+  UINT8                   Bit;\r
+  UINTN                   StartByte;\r
+  UINT8                   StartBit;\r
+  UINTN                   Available;\r
+  UINTN                   Count;\r
+\r
+  ASSERT ((Block != 0) && (Units != 0));\r
+\r
+  StartByte  = 0;\r
+  StartBit   = 0;\r
+  Available  = 0;\r
+\r
+  for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+    //\r
+    // If current bit is zero, the corresponding memory unit is\r
+    // available, otherwise we need to restart our searching.\r
+    // Available counts the consective number of zero bit.\r
+    //\r
+    if (!UFS_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+      Available++;\r
+\r
+      if (Available >= Units) {\r
+        break;\r
+      }\r
+\r
+      UFS_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+    } else {\r
+      UFS_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+      Available  = 0;\r
+      StartByte  = Byte;\r
+      StartBit   = Bit;\r
+    }\r
+  }\r
+\r
+  if (Available < Units) {\r
+    return NULL;\r
+  }\r
+  \r
+  //\r
+  // Mark the memory as allocated\r
+  //\r
+  Byte  = StartByte;\r
+  Bit   = StartBit;\r
+\r
+  for (Count = 0; Count < Units; Count++) {\r
+    ASSERT (!UFS_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+    Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) UFS_PEIM_MEM_BIT (Bit));\r
+    UFS_PEIM_NEXT_BIT (Byte, Bit);\r
+  }\r
+\r
+  return Block->Buf + (StartByte * 8 + StartBit) * UFS_PEIM_MEM_UNIT;\r
+}\r
+\r
+/**\r
+  Insert the memory block to the pool's list of the blocks.\r
+\r
+  @param  Head           The head of the memory pool's block list.\r
+  @param  Block          The memory block to insert.\r
+\r
+**/\r
+VOID\r
+UfsPeimInsertMemBlockToPool (\r
+  IN UFS_PEIM_MEM_BLOCK      *Head,\r
+  IN UFS_PEIM_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Head != NULL) && (Block != NULL));\r
+  Block->Next = Head->Next;\r
+  Head->Next  = Block;\r
+}\r
+\r
+/**\r
+  Is the memory block empty?\r
+\r
+  @param  Block   The memory block to check.\r
+\r
+  @retval TRUE    The memory block is empty.\r
+  @retval FALSE   The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+UfsPeimIsMemBlockEmpty (\r
+  IN UFS_PEIM_MEM_BLOCK     *Block\r
+  )\r
+{\r
+  UINTN                   Index;\r
+\r
+  \r
+  for (Index = 0; Index < Block->BitsLen; Index++) {\r
+    if (Block->Bits[Index] != 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Unlink the memory block from the pool's list.\r
+\r
+  @param  Head           The block list head of the memory's pool.\r
+  @param  BlockToUnlink  The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+UfsPeimUnlinkMemBlock (\r
+  IN UFS_PEIM_MEM_BLOCK      *Head,\r
+  IN UFS_PEIM_MEM_BLOCK      *BlockToUnlink\r
+  )\r
+{\r
+  UFS_PEIM_MEM_BLOCK         *Block;\r
+\r
+  ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    if (Block->Next == BlockToUnlink) {\r
+      Block->Next         = BlockToUnlink->Next;\r
+      BlockToUnlink->Next = NULL;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+  \r
+  @param  Private               The Ufs Peim driver private data.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval Others                Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimInitMemPool (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  UFS_PEIM_MEM_POOL          *Pool;\r
+  EFI_STATUS                 Status;\r
+  VOID                       *TempPtr;\r
+\r
+  TempPtr = NULL;\r
+  Pool    = NULL;\r
+  \r
+  Status = PeiServicesAllocatePool (sizeof (UFS_PEIM_MEM_POOL), &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (UFS_PEIM_MEM_POOL));\r
+\r
+  Pool = (UFS_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
+\r
+  Pool->Head = UfsPeimAllocMemBlock (UFS_PEIM_MEM_DEFAULT_PAGES);\r
+\r
+  if (Pool->Head == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Private->Pool = Pool;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Release the memory management pool.\r
+  \r
+  @param  Pool                  The memory pool to free.\r
+\r
+  @retval EFI_DEVICE_ERROR      Fail to free the memory pool.\r
+  @retval EFI_SUCCESS           The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsPeimFreeMemPool (\r
+  IN UFS_PEIM_MEM_POOL       *Pool\r
+  )\r
+{\r
+  UFS_PEIM_MEM_BLOCK         *Block;\r
+\r
+  ASSERT (Pool->Head != NULL);\r
+\r
+  //\r
+  // Unlink all the memory blocks from the pool, then free them.\r
+  // UfsPeimUnlinkMemBlock can't be used to unlink and free the\r
+  // first block.\r
+  //\r
+  for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+    UfsPeimFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  UfsPeimFreeMemBlock (Pool, Pool->Head);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+  \r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UfsPeimAllocateMem (\r
+  IN  UFS_PEIM_MEM_POOL        *Pool,\r
+  IN  UINTN                    Size\r
+  )\r
+{\r
+  UFS_PEIM_MEM_BLOCK         *Head;\r
+  UFS_PEIM_MEM_BLOCK         *Block;\r
+  UFS_PEIM_MEM_BLOCK         *NewBlock;\r
+  VOID                       *Mem;\r
+  UINTN                      AllocSize;\r
+  UINTN                      Pages;\r
+\r
+  Mem       = NULL;\r
+  AllocSize = UFS_PEIM_MEM_ROUND (Size);\r
+  Head      = Pool->Head;\r
+  ASSERT (Head != NULL);\r
+\r
+  //\r
+  // First check whether current memory blocks can satisfy the allocation.\r
+  //\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    Mem = UfsPeimAllocMemFromBlock (Block, AllocSize / UFS_PEIM_MEM_UNIT);\r
+\r
+    if (Mem != NULL) {\r
+      ZeroMem (Mem, Size);\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Mem != NULL) {\r
+    return Mem;\r
+  }\r
+\r
+  //\r
+  // Create a new memory block if there is not enough memory\r
+  // in the pool. If the allocation size is larger than the\r
+  // default page number, just allocate a large enough memory\r
+  // block. Otherwise allocate default pages.\r
+  //\r
+  if (AllocSize > EFI_PAGES_TO_SIZE (UFS_PEIM_MEM_DEFAULT_PAGES)) {\r
+    Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+  } else {\r
+    Pages = UFS_PEIM_MEM_DEFAULT_PAGES;\r
+  }\r
+\r
+  NewBlock = UfsPeimAllocMemBlock (Pages);\r
+  if (NewBlock == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  //\r
+  // Add the new memory block to the pool, then allocate memory from it\r
+  //\r
+  UfsPeimInsertMemBlockToPool (Head, NewBlock);\r
+  Mem = UfsPeimAllocMemFromBlock (NewBlock, AllocSize / UFS_PEIM_MEM_UNIT);\r
+\r
+  if (Mem != NULL) {\r
+    ZeroMem (Mem, Size);\r
+  }\r
+\r
+  return Mem;\r
+}\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UfsPeimFreeMem (\r
+  IN UFS_PEIM_MEM_POOL    *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  )\r
+{\r
+  UFS_PEIM_MEM_BLOCK      *Head;\r
+  UFS_PEIM_MEM_BLOCK      *Block;\r
+  UINT8                   *ToFree;\r
+  UINTN                   AllocSize;\r
+  UINTN                   Byte;\r
+  UINTN                   Bit;\r
+  UINTN                   Count;\r
+\r
+  Head      = Pool->Head;\r
+  AllocSize = UFS_PEIM_MEM_ROUND (Size);\r
+  ToFree    = (UINT8 *) Mem;\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    //\r
+    // scan the memory block list for the memory block that\r
+    // completely contains the memory to free.\r
+    //\r
+    if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+      //\r
+      // compute the start byte and bit in the bit array\r
+      //\r
+      Byte  = ((ToFree - Block->Buf) / UFS_PEIM_MEM_UNIT) / 8;\r
+      Bit   = ((ToFree - Block->Buf) / UFS_PEIM_MEM_UNIT) % 8;\r
+\r
+      //\r
+      // reset associated bits in bit arry\r
+      //\r
+      for (Count = 0; Count < (AllocSize / UFS_PEIM_MEM_UNIT); Count++) {\r
+        ASSERT (UFS_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+        Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ UFS_PEIM_MEM_BIT (Bit));\r
+        UFS_PEIM_NEXT_BIT (Byte, Bit);\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If Block == NULL, it means that the current memory isn't\r
+  // in the host controller's pool. This is critical because\r
+  // the caller has passed in a wrong memory point\r
+  //\r
+  ASSERT (Block != NULL);\r
+\r
+  //\r
+  // Release the current memory block if it is empty and not the head\r
+  //\r
+  if ((Block != Head) && UfsPeimIsMemBlockEmpty (Block)) {\r
+    UfsPeimFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.h b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.h
new file mode 100644 (file)
index 0000000..3c4b240
--- /dev/null
@@ -0,0 +1,61 @@
+/** @file\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _UFS_PEIM_MEM_H_\r
+#define _UFS_PEIM_MEM_H_\r
+\r
+#define UFS_PEIM_MEM_BIT(a)          ((UINTN)(1 << (a)))\r
+\r
+#define UFS_PEIM_MEM_BIT_IS_SET(Data, Bit)   \\r
+          ((BOOLEAN)(((Data) & UFS_PEIM_MEM_BIT(Bit)) == UFS_PEIM_MEM_BIT(Bit)))\r
+\r
+typedef struct _UFS_PEIM_MEM_BLOCK UFS_PEIM_MEM_BLOCK;\r
+\r
+struct _UFS_PEIM_MEM_BLOCK {\r
+  UINT8                   *Bits;    // Bit array to record which unit is allocated\r
+  UINTN                   BitsLen; \r
+  UINT8                   *Buf;\r
+  UINTN                   BufLen;   // Memory size in bytes\r
+  UFS_PEIM_MEM_BLOCK      *Next;\r
+};\r
+\r
+typedef struct _UFS_PEIM_MEM_POOL {\r
+  UFS_PEIM_MEM_BLOCK         *Head;\r
+} UFS_PEIM_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, note that the value must meet UFS spec alignment requirement.\r
+//\r
+#define UFS_PEIM_MEM_UNIT           128\r
+\r
+#define UFS_PEIM_MEM_UNIT_MASK      (UFS_PEIM_MEM_UNIT - 1)\r
+#define UFS_PEIM_MEM_DEFAULT_PAGES  16\r
+\r
+#define UFS_PEIM_MEM_ROUND(Len)  (((Len) + UFS_PEIM_MEM_UNIT_MASK) & (~UFS_PEIM_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define UFS_PEIM_NEXT_BIT(Byte, Bit)   \\r
+          do {                \\r
+            (Bit)++;          \\r
+            if ((Bit) > 7) {  \\r
+              (Byte)++;       \\r
+              (Bit) = 0;      \\r
+            }                 \\r
+          } while (0)\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
new file mode 100644 (file)
index 0000000..6880057
--- /dev/null
@@ -0,0 +1,1787 @@
+/** @file\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsBlockIoPei.h"\r
+\r
+/**\r
+  Wait for the value of the specified system memory set to the test value.\r
+\r
+  @param  Address           The system memory address to test.\r
+  @param  MaskValue         The mask value of memory.\r
+  @param  TestValue         The test value of memory.\r
+  @param  Timeout           The time out value for wait memory set, uses 100ns as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The system memory setting is time out.\r
+  @retval EFI_SUCCESS       The system memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsWaitMemSet (\r
+  IN  UINTN                     Address,\r
+  IN  UINT32                    MaskValue,\r
+  IN  UINT32                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32     Value;\r
+  UINT64     Delay;\r
+  BOOLEAN    InfiniteWait;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  Delay = DivU64x32 (Timeout, 10) + 1;\r
+\r
+  do {\r
+    //\r
+    // Access PCI MMIO space to see if the value is the tested one.\r
+    //\r
+    Value = MmioRead32 (Address) & MaskValue;\r
+\r
+    if (Value == TestValue) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Stall for 1 microseconds.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Delay--;\r
+\r
+  } while (InfiniteWait || (Delay > 0));\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Dump UIC command execution result for debugging.\r
+\r
+  @param[in]   UicOpcode  The executed UIC opcode.\r
+  @param[in]   Result     The result to be parsed.\r
+\r
+**/\r
+VOID\r
+DumpUicCmdExecResult (\r
+  IN  UINT8     UicOpcode,\r
+  IN  UINT8     Result\r
+  )\r
+{\r
+  if (UicOpcode <= UfsUicDmePeerSet) {\r
+    switch (Result) {\r
+      case 0x00:\r
+        break;\r
+      case 0x01:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x02:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
+        break;\r
+      case 0x03:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x04:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x05:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
+        break;\r
+      case 0x06:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x07:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
+        break;\r
+      case 0x08:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
+        break; \r
+      case 0x09:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
+        break;\r
+      case 0x0A:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));\r
+        break;        \r
+      default :\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+  } else {\r
+    switch (Result) {\r
+      case 0x00:\r
+        break;\r
+      case 0x01:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC control command fails - FAILURE\n"));\r
+        break;     \r
+      default :\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Dump QUERY RESPONSE UPIU result for debugging.\r
+\r
+  @param[in]   Result  The result to be parsed.\r
+\r
+**/\r
+VOID\r
+DumpQueryResponseResult (\r
+  IN  UINT8     Result\r
+  )\r
+{\r
+  switch (Result) {\r
+    case 0xF6:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
+      break;\r
+    case 0xF7:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
+      break;\r
+    case 0xF8:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Already Written\n"));\r
+      break;\r
+    case 0xF9:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Length\n"));\r
+      break;\r
+    case 0xFA:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Value\n"));\r
+      break;\r
+    case 0xFB:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Selector\n"));\r
+      break;\r
+    case 0xFC:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Index\n"));\r
+      break;\r
+    case 0xFD:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Idn\n"));\r
+      break;\r
+    case 0xFE:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Opcode\n"));\r
+      break; \r
+    case 0xFF:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with General Failure\n"));\r
+      break;\r
+    default :\r
+      ASSERT (FALSE);\r
+      break;\r
+  }\r
+}\r
+\r
+/**\r
+  Swap little endian to big endian.\r
+\r
+  @param[in, out] Buffer      The data buffer. In input, it contains little endian data.\r
+                              In output, it will become big endian.\r
+  @param[in]      BufferSize  The length of converted data.\r
+\r
+**/\r
+VOID\r
+SwapLittleEndianToBigEndian (\r
+  IN OUT UINT8         *Buffer,\r
+  IN     UINT32        BufferSize\r
+  )\r
+{\r
+  UINT32 Index;\r
+  UINT8  Temp;\r
+  UINT32 SwapCount;\r
+\r
+  SwapCount = BufferSize / 2;\r
+  for (Index = 0; Index < SwapCount; Index++) {\r
+    Temp = Buffer[Index];\r
+    Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
+    Buffer[BufferSize - 1 - Index] = Temp;\r
+  }\r
+}\r
+\r
+/**\r
+  Fill TSF field of QUERY REQUEST UPIU.\r
+\r
+  @param[in, out] TsfBase      The base address of TSF field of QUERY REQUEST UPIU.\r
+  @param[in]      Opcode       The opcode of request.\r
+  @param[in]      DescId       The descriptor ID of request.\r
+  @param[in]      Index        The index of request.\r
+  @param[in]      Selector     The selector of request.\r
+  @param[in]      Length       The length of transferred data. The maximum is 4.\r
+  @param[in]      Value        The value of transferred data.\r
+\r
+**/\r
+VOID\r
+UfsFillTsfOfQueryReqUpiu (\r
+  IN OUT UTP_UPIU_TSF        *TsfBase,\r
+  IN     UINT8               Opcode,\r
+  IN     UINT8               DescId    OPTIONAL,\r
+  IN     UINT8               Index     OPTIONAL,\r
+  IN     UINT8               Selector  OPTIONAL,\r
+  IN     UINT16              Length    OPTIONAL,\r
+  IN     UINT32              Value     OPTIONAL\r
+  )\r
+{\r
+  ASSERT (TsfBase != NULL);\r
+  ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);\r
+\r
+  TsfBase->Opcode   = Opcode;\r
+  if (Opcode != UtpQueryFuncOpcodeNop) {\r
+    TsfBase->DescId   = DescId;\r
+    TsfBase->Index    = Index;\r
+    TsfBase->Selector = Selector;\r
+\r
+    if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
+      SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));\r
+      TsfBase->Length = Length;\r
+    }\r
+  \r
+    if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
+      SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));\r
+      TsfBase->Value  = Value;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize COMMAND UPIU.\r
+\r
+  @param[in, out] Command         The base address of COMMAND UPIU.\r
+  @param[in]      Lun             The Lun on which the SCSI command is executed.\r
+  @param[in]      TaskTag         The task tag of request.\r
+  @param[in]      Cdb             The cdb buffer containing SCSI command.\r
+  @param[in]      CdbLength       The cdb length.\r
+  @param[in]      DataDirection   The direction of data transfer.\r
+  @param[in]      ExpDataTranLen  The expected transfer data length.\r
+\r
+  @retval EFI_SUCCESS     The initialization succeed.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitCommandUpiu (\r
+  IN OUT UTP_COMMAND_UPIU              *Command,\r
+  IN     UINT8                         Lun,\r
+  IN     UINT8                         TaskTag,\r
+  IN     UINT8                         *Cdb,\r
+  IN     UINT8                         CdbLength,\r
+  IN     UFS_DATA_DIRECTION            DataDirection,\r
+  IN     UINT32                        ExpDataTranLen\r
+  )\r
+{\r
+  UINT8                   Flags;\r
+\r
+  ASSERT ((Command != NULL) && (Cdb != NULL));\r
+\r
+  //\r
+  // Task attribute is hard-coded to Ordered.\r
+  //\r
+  if (DataDirection == UfsDataIn) {\r
+    Flags = BIT0 | BIT6;\r
+  } else if (DataDirection == UfsDataOut) {\r
+    Flags = BIT0 | BIT5;\r
+  } else {\r
+    Flags = BIT0;\r
+  }\r
+\r
+  //\r
+  // Fill UTP COMMAND UPIU associated fields.\r
+  //\r
+  Command->TransCode = 0x01;\r
+  Command->Flags     = Flags;\r
+  Command->Lun       = Lun;\r
+  Command->TaskTag   = TaskTag;\r
+  Command->CmdSet    = 0x00;\r
+  SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));\r
+  Command->ExpDataTranLen = ExpDataTranLen;\r
+\r
+  CopyMem (Command->Cdb, Cdb, CdbLength);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UTP PRDT for data transfer.\r
+\r
+  @param[in] Prdt         The base address of PRDT.\r
+  @param[in] Buffer       The buffer to be read or written.\r
+  @param[in] BufferSize   The data size to be read or written.\r
+\r
+  @retval EFI_SUCCESS     The initialization succeed.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitUtpPrdt (\r
+  IN  UTP_TR_PRD                       *Prdt,\r
+  IN  VOID                             *Buffer,\r
+  IN  UINT32                           BufferSize\r
+  )\r
+{\r
+  UINT32     PrdtIndex;\r
+  UINT32     RemainingLen;\r
+  UINT8      *Remaining;\r
+  UINTN      PrdtNumber;\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
+\r
+  RemainingLen = BufferSize;\r
+  Remaining    = Buffer;\r
+  PrdtNumber   = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
+\r
+  for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
+    if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {\r
+      Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;\r
+    } else {\r
+      Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;\r
+    }\r
+\r
+    Prdt[PrdtIndex].DbAddr  = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);\r
+    Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);\r
+    RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;\r
+    Remaining    += UFS_MAX_DATA_LEN_PER_PRD;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize QUERY REQUEST UPIU.\r
+\r
+  @param[in, out] QueryReq      The base address of QUERY REQUEST UPIU.\r
+  @param[in]      TaskTag       The task tag of request.\r
+  @param[in]      Opcode        The opcode of request.\r
+  @param[in]      DescId        The descriptor ID of request.\r
+  @param[in]      Index         The index of request.\r
+  @param[in]      Selector      The selector of request.\r
+  @param[in]      DataSize      The data size to be read or written.\r
+  @param[in]      Data          The buffer to be read or written.\r
+\r
+  @retval EFI_SUCCESS           The initialization succeed.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitQueryRequestUpiu (\r
+  IN OUT UTP_QUERY_REQ_UPIU            *QueryReq,\r
+  IN     UINT8                         TaskTag,\r
+  IN     UINT8                         Opcode,\r
+  IN     UINT8                         DescId,\r
+  IN     UINT8                         Index,\r
+  IN     UINT8                         Selector,\r
+  IN     UINTN                         DataSize   OPTIONAL,\r
+  IN     UINT8                         *Data      OPTIONAL\r
+  )\r
+{\r
+  ASSERT (QueryReq != NULL);\r
+\r
+  QueryReq->TransCode = 0x16;\r
+  QueryReq->TaskTag   = TaskTag;\r
+  if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {\r
+    QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;\r
+  } else {\r
+    QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;\r
+  }\r
+\r
+  if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
+    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);\r
+  } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
+    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);\r
+  } else {\r
+    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);\r
+  }\r
+\r
+  if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
+    CopyMem (QueryReq + 1, Data, DataSize);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Lun               The Lun on which the SCSI command is executed.\r
+  @param[in]  Packet            The pointer to the UFS_SCSI_REQUEST_PACKET data structure.\r
+  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.\r
+\r
+  @retval EFI_SUCCESS           The creation succeed.\r
+  @retval EFI_DEVICE_ERROR      The creation failed.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsCreateScsiCommandDesc (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA            *Private,\r
+  IN  UINT8                               Lun,\r
+  IN  UFS_SCSI_REQUEST_PACKET             *Packet,\r
+  IN  UTP_TRD                             *Trd\r
+  )\r
+{\r
+  UINT8                    *CommandDesc;\r
+  UINTN                    TotalLen;\r
+  UINTN                    PrdtNumber;\r
+  VOID                     *Buffer;\r
+  UINT32                   Length;\r
+  UTP_COMMAND_UPIU         *CommandUpiu;\r
+  UTP_TR_PRD               *PrdtBase;\r
+  UFS_DATA_DIRECTION       DataDirection;\r
+\r
+  ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
+\r
+  if (Packet->DataDirection == UfsDataIn) {\r
+    Buffer = Packet->InDataBuffer;\r
+    Length = Packet->InTransferLength;\r
+    DataDirection = UfsDataIn;\r
+  } else {\r
+    Buffer = Packet->OutDataBuffer;\r
+    Length = Packet->OutTransferLength;\r
+    DataDirection = UfsDataOut;\r
+  }\r
+\r
+  if (Length == 0) {\r
+    DataDirection = UfsNoData;\r
+  }\r
+\r
+  PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
+\r
+  TotalLen    = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);\r
+  CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);\r
+  if (CommandDesc == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CommandUpiu  = (UTP_COMMAND_UPIU*)CommandDesc;\r
+  PrdtBase     = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
+\r
+  UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);\r
+  UfsInitUtpPrdt (PrdtBase, Buffer, Length);\r
+\r
+  //\r
+  // Fill UTP_TRD associated fields\r
+  // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table\r
+  // *MUST* be located at a 64-bit aligned boundary.\r
+  //\r
+  Trd->Int    = UFS_INTERRUPT_COMMAND;\r
+  Trd->Dd     = DataDirection;\r
+  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;\r
+  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);\r
+  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);\r
+  Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));\r
+  Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));\r
+  Trd->PrdtL  = (UINT16)PrdtNumber;\r
+  Trd->PrdtO  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Packet            The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.\r
+  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.\r
+\r
+  @retval EFI_SUCCESS           The creation succeed.\r
+  @retval EFI_DEVICE_ERROR      The creation failed.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.\r
+  @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsCreateDMCommandDesc (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA              *Private,\r
+  IN  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET  *Packet,\r
+  IN  UTP_TRD                               *Trd\r
+  )\r
+{\r
+  UINT8                         *CommandDesc;\r
+  UINTN                         TotalLen;\r
+  UTP_QUERY_REQ_UPIU            *QueryReqUpiu;\r
+  UINT8                         Opcode;\r
+  UINT32                        DataSize;\r
+  UINT8                         *Data;\r
+  UINT8                         DataDirection;\r
+\r
+  ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
+\r
+  Opcode = Packet->Opcode;\r
+  if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DataDirection = Packet->DataDirection;\r
+  if (DataDirection == UfsDataIn) {\r
+    DataSize = Packet->InTransferLength;\r
+    Data     = Packet->InDataBuffer;\r
+  } else if (DataDirection == UfsDataOut) {\r
+    DataSize = Packet->OutTransferLength;\r
+    Data     = Packet->OutDataBuffer;\r
+  } else {\r
+    DataSize = 0;\r
+    Data     = NULL;\r
+  }\r
+\r
+  if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))\r
+    && ((DataSize == 0) || (Data == NULL))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))\r
+    && ((DataSize != 0) || (Data != NULL))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {\r
+    TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);\r
+  } else {\r
+    TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));\r
+  }\r
+\r
+  CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);\r
+  if (CommandDesc == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Initialize UTP QUERY REQUEST UPIU\r
+  //\r
+  QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;\r
+  UfsInitQueryRequestUpiu (\r
+    QueryReqUpiu,\r
+    Private->TaskTag++,\r
+    Opcode,\r
+    Packet->DescId,\r
+    Packet->Index,\r
+    Packet->Selector,\r
+    DataSize,\r
+    Data\r
+    );\r
+\r
+  //\r
+  // Fill UTP_TRD associated fields\r
+  // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.\r
+  //\r
+  Trd->Int    = UFS_INTERRUPT_COMMAND;\r
+  Trd->Dd     = DataDirection;\r
+  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;\r
+  Trd->Ocs    = 0x0F;\r
+  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);\r
+  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);\r
+  if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
+    Trd->RuL  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));\r
+    Trd->RuO  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
+  } else {\r
+    Trd->RuL  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
+    Trd->RuO  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.\r
+\r
+  @retval EFI_SUCCESS           The creation succeed.\r
+  @retval EFI_DEVICE_ERROR      The creation failed.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsCreateNopCommandDesc (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA                    *Private,\r
+  IN  UTP_TRD                                     *Trd\r
+  )\r
+{\r
+  UINT8                    *CommandDesc;\r
+  UINTN                    TotalLen;\r
+  UTP_NOP_OUT_UPIU         *NopOutUpiu;\r
+\r
+  ASSERT ((Private != NULL) && (Trd != NULL));\r
+\r
+  TotalLen    = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));\r
+  CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);\r
+  if (CommandDesc == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;\r
+\r
+  NopOutUpiu->TaskTag = Private->TaskTag++;\r
+\r
+  //\r
+  // Fill UTP_TRD associated fields\r
+  // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.\r
+  //\r
+  Trd->Int    = UFS_INTERRUPT_COMMAND;\r
+  Trd->Dd     = 0x00;\r
+  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;\r
+  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);\r
+  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);\r
+  Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));\r
+  Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find out available slot in transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[out] Slot          The available slot.\r
+\r
+  @retval EFI_SUCCESS       The available slot was found successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsFindAvailableSlotInTrl (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+     OUT UINT8                        *Slot\r
+  )\r
+{\r
+  ASSERT ((Private != NULL) && (Slot != NULL));\r
+\r
+  //\r
+  // The simplest algo to always use slot 0.\r
+  // TODO: enhance it to support async transfer with multiple slot.\r
+  //\r
+  *Slot = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find out available slot in task management transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[out] Slot          The available slot.\r
+\r
+  @retval EFI_SUCCESS       The available slot was found successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsFindAvailableSlotInTmrl (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+     OUT UINT8                        *Slot\r
+  )\r
+{\r
+  ASSERT ((Private != NULL) && (Slot != NULL));\r
+\r
+  //\r
+  // The simplest algo to always use slot 0.\r
+  // TODO: enhance it to support async transfer with multiple slot.\r
+  //\r
+  *Slot = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Start specified slot in transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Slot          The slot to be started.\r
+\r
+**/\r
+VOID\r
+UfsStartExecCmd (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN  UINT8                        Slot\r
+  ) \r
+{\r
+  UINTN         UfsHcBase;\r
+  UINTN         Address;\r
+  UINT32        Data;\r
+\r
+  UfsHcBase = Private->UfsHcBase;\r
+\r
+  Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
+    MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
+  }\r
+\r
+  Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
+  MmioWrite32 (Address, BIT0 << Slot);\r
+}\r
+\r
+/**\r
+  Stop specified slot in transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  Slot          The slot to be stop.\r
+\r
+**/\r
+VOID\r
+UfsStopExecCmd (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN  UINT8                        Slot\r
+  ) \r
+{\r
+  UINTN         UfsHcBase;\r
+  UINTN         Address;\r
+  UINT32        Data;\r
+\r
+  UfsHcBase = Private->UfsHcBase;\r
+\r
+  Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & (BIT0 << Slot)) != 0) {\r
+    Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;  \r
+    Data    = MmioRead32 (Address);\r
+    MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));\r
+  }\r
+}\r
+\r
+/**\r
+  Read or write specified device descriptor of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      DescId        The ID of device descriptor.\r
+  @param[in]      Index         The Index of device descriptor.\r
+  @param[in]      Selector      The Selector of device descriptor.\r
+  @param[in, out] Descriptor    The buffer of device descriptor to be read or written.\r
+  @param[in]      DescSize      The size of device descriptor buffer.\r
+\r
+  @retval EFI_SUCCESS           The device descriptor was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the device descriptor.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the device descriptor.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwDeviceDesc (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        DescId,\r
+  IN     UINT8                        Index,\r
+  IN     UINT8                        Selector,\r
+  IN OUT VOID                         *Descriptor,\r
+  IN     UINT32                       DescSize\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UTP_QUERY_RESP_UPIU                  *QueryResp;\r
+  UINT8                                *CmdDescBase;\r
+  UINT32                               CmdDescSize;\r
+  UINT16                               ReturnDataSize;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+\r
+  if (Read) {\r
+    Packet.DataDirection     = UfsDataIn;\r
+    Packet.InDataBuffer      = Descriptor;\r
+    Packet.InTransferLength  = DescSize;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeRdDesc;\r
+  } else {\r
+    Packet.DataDirection     = UfsDataOut;\r
+    Packet.OutDataBuffer     = Descriptor;\r
+    Packet.OutTransferLength = DescSize;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeWrDesc;\r
+  }\r
+  Packet.DescId              = DescId;\r
+  Packet.Index               = Index;\r
+  Packet.Selector            = Selector;\r
+  Packet.Timeout             = UFS_TIMEOUT;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
+  QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (QueryResp->QueryResp != 0) {\r
+    DumpQueryResponseResult (QueryResp->QueryResp);\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    ReturnDataSize = QueryResp->Tsf.Length;\r
+    SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
+\r
+    if (Read) {\r
+      CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);\r
+      Packet.InTransferLength = ReturnDataSize;\r
+    } else {\r
+      Packet.OutTransferLength = ReturnDataSize;\r
+    }\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsStopExecCmd (Private, Slot);\r
+  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read or write specified attribute of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      AttrId        The ID of Attribute.\r
+  @param[in]      Index         The Index of Attribute.\r
+  @param[in]      Selector      The Selector of Attribute.\r
+  @param[in, out] Attributes    The value of Attribute to be read or written.\r
+\r
+  @retval EFI_SUCCESS           The Attribute was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the Attribute.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the Attribute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwAttributes (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        AttrId,\r
+  IN     UINT8                        Index,\r
+  IN     UINT8                        Selector,\r
+  IN OUT UINT32                       *Attributes\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UTP_QUERY_RESP_UPIU                  *QueryResp;\r
+  UINT8                                *CmdDescBase;\r
+  UINT32                               CmdDescSize;\r
+  UINT32                               ReturnData;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+\r
+  if (Read) {\r
+    Packet.DataDirection     = UfsDataIn;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeRdAttr;\r
+  } else {\r
+    Packet.DataDirection     = UfsDataOut;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeWrAttr;\r
+  }\r
+  Packet.DescId              = AttrId;\r
+  Packet.Index               = Index;\r
+  Packet.Selector            = Selector;\r
+  Packet.Timeout             = UFS_TIMEOUT;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
+  QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (QueryResp->QueryResp != 0) {\r
+    DumpQueryResponseResult (QueryResp->QueryResp);\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    ReturnData = QueryResp->Tsf.Value;\r
+    SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));\r
+    *Attributes = ReturnData;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsStopExecCmd (Private, Slot);\r
+  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read or write specified flag of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      FlagId        The ID of flag to be read or written.\r
+  @param[in, out] Value         The value to set or clear flag.\r
+\r
+  @retval EFI_SUCCESS           The flag was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwFlags (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        FlagId,\r
+  IN OUT UINT8                        *Value\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UTP_QUERY_RESP_UPIU                  *QueryResp;\r
+  UINT8                                *CmdDescBase;\r
+  UINT32                               CmdDescSize;\r
+\r
+  if (Value == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+\r
+  if (Read) {\r
+    ASSERT (Value != NULL);\r
+    Packet.DataDirection     = UfsDataIn;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeRdFlag;\r
+  } else {\r
+    Packet.DataDirection     = UfsDataOut;\r
+    if (*Value == 1) {\r
+      Packet.Opcode          = UtpQueryFuncOpcodeSetFlag;\r
+    } else if (*Value == 0) {\r
+      Packet.Opcode          = UtpQueryFuncOpcodeClrFlag;\r
+    } else {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  Packet.DescId              = FlagId;\r
+  Packet.Index               = 0;\r
+  Packet.Selector            = 0;\r
+  Packet.Timeout             = UFS_TIMEOUT;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
+  QueryResp   = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (QueryResp->QueryResp != 0) {\r
+    DumpQueryResponseResult (QueryResp->QueryResp);\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    *Value = (UINT8)QueryResp->Tsf.Value;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsStopExecCmd (Private, Slot);\r
+  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set specified flag to 1 on a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be set.\r
+\r
+  @retval EFI_SUCCESS           The flag was set successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to set the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of setting the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsSetFlag (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN  UINT8                        FlagId\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINT8                  Value;\r
+\r
+  Value  = 1;\r
+  Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Clear specified flag to 0 on a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be cleared.\r
+\r
+  @retval EFI_SUCCESS           The flag was cleared successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to clear the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of clearing the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsClearFlag (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN  UINT8                        FlagId\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINT8                  Value;\r
+\r
+  Value  = 0;\r
+  Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read specified flag from a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be read.\r
+  @param[out] Value             The flag's value.\r
+\r
+  @retval EFI_SUCCESS           The flag was read successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to read the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of reading the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsReadFlag (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,\r
+  IN     UINT8                        FlagId,\r
+     OUT UINT8                        *Value\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+\r
+  Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends NOP IN cmd to a UFS device for initialization process request.\r
+  For more details, please refer to UFS 2.0 spec Figure 13.3.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS           The NOP IN command was sent by the host. The NOP OUT response was\r
+                                received successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to execute NOP IN command.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the NOP IN command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecNopCmds (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA         *Private\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UTP_NOP_IN_UPIU                      *NopInUpiu;\r
+  UINT8                                *CmdDescBase;\r
+  UINT32                               CmdDescSize;\r
+  UINTN                                Address;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  Status = UfsCreateNopCommandDesc (Private, Trd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
+  NopInUpiu   = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (NopInUpiu->Resp != 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Exit:\r
+  UfsStopExecCmd (Private, Slot);\r
+  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in]      Lun           The LUN of the UFS device to send the SCSI Request Packet.\r
+  @param[in, out] Packet        A pointer to the SCSI Request Packet to send to a specified Lun of the\r
+                                UFS device.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecScsiCmds (\r
+  IN     UFS_PEIM_HC_PRIVATE_DATA      *Private,\r
+  IN     UINT8                         Lun,\r
+  IN OUT UFS_SCSI_REQUEST_PACKET       *Packet\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UINT8                                *CmdDescBase;\r
+  UINT32                               CmdDescSize;\r
+  UTP_RESPONSE_UPIU                    *Response;\r
+  UINT16                               SenseDataLen;\r
+  UINT32                               ResTranCount;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
+  CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet->Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Get sense data if exists\r
+  //\r
+  Response     = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
+  SenseDataLen = Response->SenseDataLen;\r
+  SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
+  \r
+  if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
+    CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
+    Packet->SenseDataLength = (UINT8)SenseDataLen;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  if (Response->Response != 0) {\r
+    DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    if (Packet->DataDirection == UfsDataIn) {\r
+      if ((Response->Flags & BIT5) == BIT5) {\r
+        ResTranCount = Response->ResTranCount;\r
+        SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
+        Packet->InTransferLength -= ResTranCount;\r
+      }\r
+    } else if (Packet->DataDirection == UfsDataOut) {\r
+      if ((Response->Flags & BIT5) == BIT5) {\r
+        ResTranCount = Response->ResTranCount;\r
+        SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
+        Packet->OutTransferLength -= ResTranCount;\r
+      }\r
+    }\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsStopExecCmd (Private, Slot);\r
+  UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
+\r
+  @param[in] Private          The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+  @param[in] UicOpcode        The opcode of the UIC command.\r
+  @param[in] Arg1             The value for 1st argument of the UIC command.\r
+  @param[in] Arg2             The value for 2nd argument of the UIC command.\r
+  @param[in] Arg3             The value for 3rd argument of the UIC command.\r
+\r
+  @return EFI_SUCCESS      Successfully execute this UIC command and detect attached UFS device.\r
+  @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
+  @return EFI_NOT_FOUND    The presence of the UFS device isn't detected.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecUicCommands (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA      *Private,\r
+  IN  UINT8                         UicOpcode,\r
+  IN  UINT32                        Arg1,\r
+  IN  UINT32                        Arg2,\r
+  IN  UINT32                        Arg3\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Address;\r
+  UINT32      Data;\r
+  UINTN       UfsHcBase;\r
+\r
+  UfsHcBase = Private->UfsHcBase;\r
+  Address   = UfsHcBase + UFS_HC_IS_OFFSET;\r
+  Data      = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
+    //\r
+    // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
+    //\r
+    MmioWrite32 (Address, Data);\r
+  }\r
+\r
+  //\r
+  // When programming UIC command registers, host software shall set the register UICCMD\r
+  // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
+  // are set.\r
+  //\r
+  Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;\r
+  MmioWrite32 (Address, Arg1);\r
+\r
+  Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
+  MmioWrite32 (Address, Arg2);\r
+\r
+  Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;\r
+  MmioWrite32 (Address, Arg3);\r
+\r
+  //\r
+  // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;\r
+  Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;\r
+  MmioWrite32 (Address, (UINT32)UicOpcode);\r
+\r
+  //\r
+  // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
+  // This bit is set to '1' by the host controller upon completion of a UIC command. \r
+  //\r
+  Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
+  Data    = MmioRead32 (Address);\r
+  Status  = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (UicOpcode != UfsUicDmeReset) {\r
+    Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
+    Data    = MmioRead32 (Address);\r
+    if ((Data & 0xFF) != 0) {\r
+      DEBUG_CODE_BEGIN();\r
+        DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
+      DEBUG_CODE_END();\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
+  //\r
+  Address = UfsHcBase + UFS_HC_STATUS_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_HCS_DP) == 0) {\r
+    Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
+    Status  = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable the UFS host controller for accessing.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS host controller enabling was executed successfully.\r
+  @retval EFI_DEVICE_ERROR           A device error occurred while enabling the UFS host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsEnableHostController (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+\r
+  //\r
+  // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
+  //\r
+  // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
+    //\r
+    // Write a 0 to the HCE register at first to disable the host controller.\r
+    //\r
+    MmioWrite32 (Address, 0);\r
+    //\r
+    // Wait until HCE is read as '0' before continuing.\r
+    //\r
+    Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Write a 1 to the HCE register to enable the UFS host controller.\r
+  //\r
+  MmioWrite32 (Address, UFS_HC_HCE_EN);\r
+  //\r
+  // Wait until HCE is read as '1' before continuing.\r
+  //\r
+  Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Detect if a UFS device attached.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS device detection was executed successfully.\r
+  @retval EFI_NOT_FOUND              Not found a UFS device attached.\r
+  @retval EFI_DEVICE_ERROR           A device error occurred while detecting the UFS device.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsDeviceDetection (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  UINTN                  Retry;\r
+  EFI_STATUS             Status;\r
+\r
+  //\r
+  // Start UFS device detection.\r
+  // Try up to 3 times for establishing data link with device.\r
+  //\r
+  for (Retry = 0; Retry < 3; Retry++) {\r
+    Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (Status == EFI_NOT_FOUND) {\r
+      continue;\r
+    }\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (Retry == 3) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UFS task management request list related h/w context.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS task management list was initialzed successfully.\r
+  @retval EFI_DEVICE_ERROR           The initialization fails.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitTaskManagementRequestList (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+  UINT8                  Nutmrs;\r
+  EFI_PHYSICAL_ADDRESS   Buffer;\r
+  EFI_STATUS             Status;\r
+  \r
+  //\r
+  // Initial h/w and s/w context for future operations.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  Private->Capabilities = Data;\r
+\r
+  //\r
+  // Allocate and initialize UTP Task Management Request List.\r
+  //\r
+  Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),\r
+             &Buffer\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));\r
+\r
+  //\r
+  // Program the UTP Task Management Request List Base Address and UTP Task Management\r
+  // Request List Base Address with a 64-bit address allocated at step 6.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)(UINTN)Buffer);\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));\r
+  Private->UtpTmrlBase = (VOID*)(UINTN)Buffer;\r
+  Private->Nutmrs      = Nutmrs;\r
+\r
+  //\r
+  // Enable the UTP Task Management Request List by setting the UTP Task Management\r
+  // Request List RunStop Register (UTMRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, UFS_HC_UTMRLRSR);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UFS transfer request list related h/w context.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS transfer list was initialzed successfully.\r
+  @retval EFI_DEVICE_ERROR           The initialization fails.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitTransferRequestList (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+  UINT8                  Nutrs;\r
+  EFI_PHYSICAL_ADDRESS   Buffer;\r
+  EFI_STATUS             Status;\r
+  \r
+  //\r
+  // Initial h/w and s/w context for future operations.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  Private->Capabilities = Data;\r
+\r
+  //\r
+  // Allocate and initialize UTP Transfer Request List.\r
+  //\r
+  Nutrs  = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),\r
+             &Buffer\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));\r
+\r
+  //\r
+  // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
+  // Base Address with a 64-bit address allocated at step 8.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)(UINTN)Buffer);\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));\r
+  Private->UtpTrlBase = (VOID*)(UINTN)Buffer;\r
+  Private->Nutrs      = Nutrs;\r
+  \r
+  //\r
+  // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
+  // RunStop Register (UTRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The Ufs Host Controller is initialized successfully.\r
+  @retval Others                     A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerInit (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+\r
+  Status = UfsEnableHostController (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = UfsDeviceDetection (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = UfsInitTaskManagementRequestList (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = UfsInitTransferRequestList (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Stop the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The Ufs Host Controller is stopped successfully.\r
+  @retval Others                     A device error occurred while stopping the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerStop (\r
+  IN  UFS_PEIM_HC_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+\r
+  //\r
+  // Enable the UTP Task Management Request List by setting the UTP Task Management\r
+  // Request List RunStop Register (UTMRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, 0);\r
+\r
+  //\r
+  // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
+  // RunStop Register (UTRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, 0);\r
+\r
+  //\r
+  // Write a 0 to the HCE register in order to disable the host controller.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
+  Data    = MmioRead32 (Address);\r
+  ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
+  MmioWrite32 (Address, 0);\r
+\r
+  //\r
+  // Wait until HCE is read as '0' before continuing.\r
+  //\r
+  Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.h b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.h
new file mode 100644 (file)
index 0000000..a423a92
--- /dev/null
@@ -0,0 +1,1339 @@
+/** @file\r
+  UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface\r
+  for upper layer application to execute UFS-supported SCSI cmds.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _UFS_PASS_THRU_HCI_H_\r
+#define _UFS_PASS_THRU_HCI_H_\r
+\r
+//\r
+// Host Capabilities Register Offsets\r
+//\r
+#define UFS_HC_CAP_OFFSET          0x0000  // Controller Capabilities\r
+#define UFS_HC_VER_OFFSET          0x0008  // Version\r
+#define UFS_HC_DDID_OFFSET         0x0010  // Device ID and Device Class\r
+#define UFS_HC_PMID_OFFSET         0x0014  // Product ID and Manufacturer ID\r
+#define UFS_HC_AHIT_OFFSET         0x0018  // Auto-Hibernate Idle Timer\r
+//\r
+// Operation and Runtime Register Offsets\r
+//\r
+#define UFS_HC_IS_OFFSET           0x0020  // Interrupt Status\r
+#define UFS_HC_IE_OFFSET           0x0024  // Interrupt Enable\r
+#define UFS_HC_STATUS_OFFSET       0x0030  // Host Controller Status\r
+#define UFS_HC_ENABLE_OFFSET       0x0034  // Host Controller Enable\r
+#define UFS_HC_UECPA_OFFSET        0x0038  // Host UIC Error Code PHY Adapter Layer\r
+#define UFS_HC_UECDL_OFFSET        0x003c  // Host UIC Error Code Data Link Layer\r
+#define UFS_HC_UECN_OFFSET         0x0040  // Host UIC Error Code Network Layer\r
+#define UFS_HC_UECT_OFFSET         0x0044  // Host UIC Error Code Transport Layer\r
+#define UFS_HC_UECDME_OFFSET       0x0048  // Host UIC Error Code DME\r
+#define UFS_HC_UTRIACR_OFFSET      0x004c  // UTP Transfer Request Interrupt Aggregation Control Register\r
+//\r
+// UTP Transfer Register Offsets\r
+//\r
+#define UFS_HC_UTRLBA_OFFSET       0x0050  // UTP Transfer Request List Base Address\r
+#define UFS_HC_UTRLBAU_OFFSET      0x0054  // UTP Transfer Request List Base Address Upper 32-Bits\r
+#define UFS_HC_UTRLDBR_OFFSET      0x0058  // UTP Transfer Request List Door Bell Register\r
+#define UFS_HC_UTRLCLR_OFFSET      0x005c  // UTP Transfer Request List CLear Register\r
+#define UFS_HC_UTRLRSR_OFFSET      0x0060  // UTP Transfer Request Run-Stop Register\r
+//\r
+// UTP Task Management Register Offsets\r
+//\r
+#define UFS_HC_UTMRLBA_OFFSET      0x0070  // UTP Task Management Request List Base Address\r
+#define UFS_HC_UTMRLBAU_OFFSET     0x0074  // UTP Task Management Request List Base Address Upper 32-Bits\r
+#define UFS_HC_UTMRLDBR_OFFSET     0x0078  // UTP Task Management Request List Door Bell Register\r
+#define UFS_HC_UTMRLCLR_OFFSET     0x007c  // UTP Task Management Request List CLear Register\r
+#define UFS_HC_UTMRLRSR_OFFSET     0x0080  // UTP Task Management Run-Stop Register\r
+//\r
+// UIC Command Register Offsets\r
+//\r
+#define UFS_HC_UIC_CMD_OFFSET      0x0090  // UIC Command Register\r
+#define UFS_HC_UCMD_ARG1_OFFSET    0x0094  // UIC Command Argument 1\r
+#define UFS_HC_UCMD_ARG2_OFFSET    0x0098  // UIC Command Argument 2\r
+#define UFS_HC_UCMD_ARG3_OFFSET    0x009c  // UIC Command Argument 3\r
+//\r
+// UMA Register Offsets\r
+//\r
+#define UFS_HC_UMA_OFFSET          0x00b0  // Reserved for Unified Memory Extension\r
+\r
+#define UFS_HC_HCE_EN              BIT0\r
+#define UFS_HC_HCS_DP              BIT0\r
+#define UFS_HC_HCS_UCRDY           BIT3\r
+#define UFS_HC_IS_ULSS             BIT8\r
+#define UFS_HC_IS_UCCS             BIT10\r
+#define UFS_HC_CAP_64ADDR          BIT24\r
+#define UFS_HC_CAP_NUTMRS          (BIT16 | BIT17 | BIT18)\r
+#define UFS_HC_CAP_NUTRS           (BIT0 | BIT1 | BIT2 | BIT3 | BIT4)\r
+#define UFS_HC_UTMRLRSR            BIT0\r
+#define UFS_HC_UTRLRSR             BIT0\r
+\r
+//\r
+// A maximum of length of 256KB is supported by PRDT entry\r
+//\r
+#define UFS_MAX_DATA_LEN_PER_PRD   0x40000\r
+\r
+#define UFS_STORAGE_COMMAND_TYPE   0x01\r
+\r
+#define UFS_REGULAR_COMMAND        0x00\r
+#define UFS_INTERRUPT_COMMAND      0x01\r
+\r
+#define UFS_LUN_0                  0x00\r
+#define UFS_LUN_1                  0x01\r
+#define UFS_LUN_2                  0x02\r
+#define UFS_LUN_3                  0x03\r
+#define UFS_LUN_4                  0x04\r
+#define UFS_LUN_5                  0x05\r
+#define UFS_LUN_6                  0x06\r
+#define UFS_LUN_7                  0x07\r
+#define UFS_WLUN_REPORT_LUNS       0x81\r
+#define UFS_WLUN_UFS_DEV           0xD0\r
+#define UFS_WLUN_BOOT              0xB0\r
+#define UFS_WLUN_RPMB              0xC4\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.1 Offset 00h: CAP - Controller Capabilities\r
+//\r
+typedef struct {\r
+  UINT8  Nutrs:4;      // Number of UTP Transfer Request Slots\r
+  UINT8  Rsvd1:4;\r
+\r
+  UINT8  NoRtt;        // Number of outstanding READY TO TRANSFER (RTT) requests supported\r
+\r
+  UINT8  Nutmrs:3;     // Number of UTP Task Management Request Slots\r
+  UINT8  Rsvd2:4;\r
+  UINT8  AutoHs:1;     // Auto-Hibernation Support\r
+\r
+  UINT8  As64:1;       // 64-bit addressing supported\r
+  UINT8  Oodds:1;      // Out of order data delivery supported\r
+  UINT8  UicDmetms:1;  // UIC DME_TEST_MODE command supported\r
+  UINT8  Ume:1;        // Reserved for Unified Memory Extension\r
+  UINT8  Rsvd4:4;\r
+} UFS_HC_CAP;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.2 Offset 08h: VER - UFS Version\r
+//\r
+typedef struct {\r
+  UINT8  Vs:4;         // Version Suffix\r
+  UINT8  Mnr:4;        // Minor version number\r
+\r
+  UINT8  Mjr;          // Major version number\r
+\r
+  UINT16 Rsvd1;\r
+} UFS_HC_VER;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.3 Offset 10h: HCPID - Host Controller Product ID\r
+//\r
+#define UFS_HC_PID     UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.4 Offset 14h: HCMID - Host Controller Manufacturer ID\r
+//\r
+#define UFS_HC_MID     UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.5 Offset 18h: AHIT - Auto-Hibernate Idle Timer\r
+//\r
+typedef struct {\r
+  UINT32 Ahitv:10;     // Auto-Hibernate Idle Timer Value \r
+  UINT32 Ts:3;         // Timer scale\r
+  UINT32 Rsvd1:19;\r
+} UFS_HC_AHIT;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.1 Offset 20h: IS - Interrupt Status\r
+//\r
+typedef struct {\r
+  UINT16 Utrcs:1;      // UTP Transfer Request Completion Status\r
+  UINT16 Udepri:1;     // UIC DME_ENDPOINT_RESET Indication\r
+  UINT16 Ue:1;         // UIC Error\r
+  UINT16 Utms:1;       // UIC Test Mode Status \r
+\r
+  UINT16 Upms:1;       // UIC Power Mode Status \r
+  UINT16 Uhxs:1;       // UIC Hibernate Exit Status \r
+  UINT16 Uhes:1;       // UIC Hibernate Enter Status \r
+  UINT16 Ulls:1;       // UIC Link Lost Status \r
+\r
+  UINT16 Ulss:1;       // UIC Link Startup Status \r
+  UINT16 Utmrcs:1;     // UTP Task  Management Request Completion Status \r
+  UINT16 Uccs:1;       // UIC Command Completion Status \r
+  UINT16 Dfes:1;       // Device Fatal Error Status  \r
+\r
+  UINT16 Utpes:1;      // UTP Error Status  \r
+  UINT16 Rsvd1:3;\r
+\r
+  UINT16 Hcfes:1;      // Host Controller Fatal Error Status\r
+  UINT16 Sbfes:1;      // System Bus Fatal Error Status\r
+  UINT16 Rsvd2:14;\r
+} UFS_HC_IS;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.2 Offset 24h: IE - Interrupt Enable\r
+//\r
+typedef struct {\r
+  UINT16 Utrce:1;      // UTP Transfer Request Completion Enable\r
+  UINT16 Udeprie:1;    // UIC DME_ENDPOINT_RESET Enable\r
+  UINT16 Uee:1;        // UIC Error Enable\r
+  UINT16 Utmse:1;      // UIC Test Mode Status Enable\r
+\r
+  UINT16 Upmse:1;      // UIC Power Mode Status Enable \r
+  UINT16 Uhxse:1;      // UIC Hibernate Exit Status Enable\r
+  UINT16 Uhese:1;      // UIC Hibernate Enter Status Enable \r
+  UINT16 Ullse:1;      // UIC Link Lost Status Enable\r
+\r
+  UINT16 Ulsse:1;      // UIC Link Startup Status Enable\r
+  UINT16 Utmrce:1;     // UTP Task  Management Request Completion Enable\r
+  UINT16 Ucce:1;       // UIC Command Completion Enable\r
+  UINT16 Dfee:1;       // Device Fatal Error Enable\r
+\r
+  UINT16 Utpee:1;      // UTP Error Enable\r
+  UINT16 Rsvd1:3;\r
+\r
+  UINT16 Hcfee:1;      // Host Controller Fatal Error Enable\r
+  UINT16 Sbfee:1;      // System Bus Fatal Error Enable\r
+  UINT16 Rsvd2:14;\r
+} UFS_HC_IE;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.3 Offset 30h: HCS - Host Controller Status\r
+//\r
+typedef struct {\r
+  UINT8  Dp:1;         // Device Present\r
+  UINT8  UtrlRdy:1;    // UTP Transfer Request List Ready\r
+  UINT8  UtmrlRdy:1;   // UTP Task Management Request List Ready\r
+  UINT8  UcRdy:1;      // UIC COMMAND Ready\r
+  UINT8  Rsvd1:4;\r
+\r
+  UINT8  Upmcrs:3;     // UIC Power Mode Change Request Status\r
+  UINT8  Rsvd2:1;      // UIC Hibernate Exit Status Enable\r
+  UINT8  Utpec:4;      // UTP Error Code\r
+\r
+  UINT8  TtagUtpE;     // Task Tag of UTP error\r
+  UINT8  TlunUtpE;     // Target LUN of UTP error\r
+} UFS_HC_STATUS;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.4 Offset 34h: HCE - Host Controller Enable\r
+//\r
+typedef struct {\r
+  UINT32 Hce:1;        // Host Controller Enable\r
+  UINT32 Rsvd1:31;\r
+} UFS_HC_ENABLE;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.5 Offset 38h: UECPA - Host UIC Error Code PHY Adapter Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:5;         // UIC PHY Adapter Layer Error Code\r
+  UINT32 Rsvd1:26;\r
+  UINT32 Err:1;        // UIC PHY Adapter Layer Error\r
+} UFS_HC_UECPA;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.6 Offset 3ch: UECDL - Host UIC Error Code Data Link Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:15;        // UIC Data Link Layer Error Code\r
+  UINT32 Rsvd1:16;\r
+  UINT32 Err:1;        // UIC Data Link Layer Error\r
+} UFS_HC_UECDL;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.7 Offset 40h: UECN - Host UIC Error Code Network Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:3;         // UIC Network Layer Error Code\r
+  UINT32 Rsvd1:28;\r
+  UINT32 Err:1;        // UIC Network Layer Error\r
+} UFS_HC_UECN;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.8 Offset 44h: UECT - Host UIC Error Code Transport Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:7;         // UIC Transport Layer Error Code\r
+  UINT32 Rsvd1:24;\r
+  UINT32 Err:1;        // UIC Transport Layer Error\r
+} UFS_HC_UECT;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.9 Offset 48h: UECDME - Host UIC Error Code\r
+//\r
+typedef struct {\r
+  UINT32 Ec:1;         // UIC DME Error Code\r
+  UINT32 Rsvd1:30;\r
+  UINT32 Err:1;        // UIC DME Error\r
+} UFS_HC_UECDME;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.10 Offset 4Ch: UTRIACR - UTP Transfer Request Interrupt Aggregation Control Register\r
+//\r
+typedef struct {\r
+  UINT8  IaToVal;      // Interrupt aggregation timeout value\r
+\r
+  UINT8  IacTh:5;      // Interrupt aggregation counter threshold\r
+  UINT8  Rsvd1:3;\r
+\r
+  UINT8  Ctr:1;        // Counter and Timer Reset\r
+  UINT8  Rsvd2:3;\r
+  UINT8  Iasb:1;       // Interrupt aggregation status bit\r
+  UINT8  Rsvd3:3;\r
+\r
+  UINT8  IapwEn:1;     // Interrupt aggregation parameter write enable\r
+  UINT8  Rsvd4:6;\r
+  UINT8  IaEn:1;       // Interrupt Aggregation Enable/Disable\r
+} UFS_HC_UTRIACR;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.1 Offset 50h: UTRLBA - UTP Transfer Request List Base Address\r
+//\r
+typedef struct {\r
+  UINT32 Rsvd1:10;\r
+  UINT32 UtrlBa:22;    // UTP Transfer Request List Base Address\r
+} UFS_HC_UTRLBA;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.2 Offset 54h: UTRLBAU - UTP Transfer Request List Base Address Upper 32-bits\r
+//\r
+#define UFS_HC_UTRLBAU UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.3 Offset 58h: UTRLDBR - UTP Transfer Request List Door Bell Register\r
+//\r
+#define UFS_HC_UTRLDBR UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.4 Offset 5Ch: UTRLCLR - UTP Transfer Request List CLear Register\r
+//\r
+#define UFS_HC_UTRLCLR UINT32\r
+\r
+#if 0\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.5 Offset 60h: UTRLRSR - UTP Transfer Request List Run Stop Register\r
+//\r
+typedef struct {\r
+  UINT32 UtrlRsr:1;    // UTP Transfer Request List Run-Stop Register\r
+  UINT32 Rsvd1:31;\r
+} UFS_HC_UTRLRSR;\r
+#endif\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.1 Offset 70h: UTMRLBA - UTP Task Management Request List Base Address\r
+//\r
+typedef struct {\r
+  UINT32 Rsvd1:10;\r
+  UINT32 UtmrlBa:22;   // UTP Task Management Request List Base Address\r
+} UFS_HC_UTMRLBA;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.2 Offset 74h: UTMRLBAU - UTP Task Management Request List Base Address Upper 32-bits\r
+//\r
+#define UFS_HC_UTMRLBAU UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.3 Offset 78h: UTMRLDBR - UTP Task Management Request List Door Bell Register\r
+//\r
+typedef struct {\r
+  UINT32 UtmrlDbr:8;   // UTP Task Management Request List Door bell Register\r
+  UINT32 Rsvd1:24;\r
+} UFS_HC_UTMRLDBR;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.4 Offset 7Ch: UTMRLCLR - UTP Task Management Request List CLear Register\r
+//\r
+typedef struct {\r
+  UINT32 UtmrlClr:8;   // UTP Task Management List Clear Register\r
+  UINT32 Rsvd1:24;\r
+} UFS_HC_UTMRLCLR;\r
+\r
+#if 0\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.5 Offset 80h: UTMRLRSR - UTP Task Management Request List Run Stop Register\r
+//\r
+typedef struct {\r
+  UINT32 UtmrlRsr:1;   // UTP Task Management Request List Run-Stop Register\r
+  UINT32 Rsvd1:31;\r
+} UFS_HC_UTMRLRSR;\r
+#endif\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.1 Offset 90h: UICCMD - UIC Command\r
+//\r
+typedef struct {\r
+  UINT32 CmdOp:8;      // Command Opcode\r
+  UINT32 Rsvd1:24;\r
+} UFS_HC_UICCMD;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 94h: UICCMDARG1 - UIC Command Argument 1\r
+//\r
+#define UFS_HC_UICCMD_ARG1 UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 98h: UICCMDARG2 - UIC Command Argument 2\r
+//\r
+#define UFS_HC_UICCMD_ARG2 UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 9ch: UICCMDARG3 - UIC Command Argument 3\r
+//\r
+#define UFS_HC_UICCMD_ARG3 UINT32\r
+\r
+//\r
+// UIC command opcodes\r
+//\r
+typedef enum {\r
+  UfsUicDmeGet            = 0x01,\r
+  UfsUicDmeSet            = 0x02,\r
+  UfsUicDmePeerGet        = 0x03,\r
+  UfsUicDmePeerSet        = 0x04,\r
+  UfsUicDmePwrOn          = 0x10,\r
+  UfsUicDmePwrOff         = 0x11,\r
+  UfsUicDmeEnable         = 0x12,\r
+  UfsUicDmeReset          = 0x14,\r
+  UfsUicDmeEndpointReset  = 0x15,\r
+  UfsUicDmeLinkStartup    = 0x16,\r
+  UfsUicDmeHibernateEnter = 0x17,\r
+  UfsUicDmeHibernateExit  = 0x18,\r
+  UfsUicDmeTestMode       = 0x1A\r
+} UFS_UIC_OPCODE;\r
+\r
+//\r
+// UTP Transfer Request Descriptor\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT32 Rsvd1:24;\r
+  UINT32 Int:1;               /* Interrupt */\r
+  UINT32 Dd:2;                /* Data Direction */\r
+  UINT32 Rsvd2:1;\r
+  UINT32 Ct:4;                /* Command Type */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT32 Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT32 Ocs:8;               /* Overall Command Status */\r
+  UINT32 Rsvd4:24;\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 Rsvd5;\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 Rsvd6:7;\r
+  UINT32 UcdBa:25;            /* UTP Command Descriptor Base Address */\r
+  \r
+  //\r
+  // DW5\r
+  //\r
+  UINT32 UcdBaU;              /* UTP Command Descriptor Base Address Upper 32-bits */\r
\r
+  //\r
+  // DW6\r
+  //\r
+  UINT16 RuL;                 /* Response UPIU Length */  \r
+  UINT16 RuO;                 /* Response UPIU Offset */\r
+\r
+  //\r
+  // DW7\r
+  //\r
+  UINT16 PrdtL;               /* PRDT Length */  \r
+  UINT16 PrdtO;               /* PRDT Offset */\r
+} UTP_TRD;\r
+\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT32 Rsvd1:2;\r
+  UINT32 DbAddr:30;           /* Data Base Address */\r
+  \r
+  //\r
+  // DW1\r
+  //\r
+  UINT32 DbAddrU;             /* Data Base Address Upper 32-bits */\r
\r
+  //\r
+  // DW2\r
+  //\r
+  UINT32 Rsvd2;\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DbCount:18;          /* Data Byte Count */\r
+  UINT32 Rsvd3:14;\r
+} UTP_TR_PRD;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.3 - UTP Command UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x01*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  CmdSet:4;            /* Command Set Type */\r
+  UINT8  Rsvd1:4;\r
+  UINT8  Rsvd2;\r
+  UINT8  Rsvd3;\r
+  UINT8  Rsvd4;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd5;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 ExpDataTranLen;      /* Expected Data Transfer Length - Big Endian */\r
+\r
+  //\r
+  // DW4 - DW7\r
+  //\r
+  UINT8  Cdb[16];\r
+} UTP_COMMAND_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.4 - UTP Response UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x21*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  CmdSet:4;            /* Command Set Type */\r
+  UINT8  Rsvd1:4;\r
+  UINT8  Rsvd2;\r
+  UINT8  Response;            /* Response */\r
+  UINT8  Status;              /* Status */\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  DevInfo;             /* Device Information */\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 ResTranCount;        /* Residual Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW4 - DW7\r
+  //\r
+  UINT8  Rsvd3[16];\r
+\r
+  //\r
+  // Data Segment - Sense Data\r
+  //\r
+  UINT16 SenseDataLen;        /* Sense Data Length - Big Endian */\r
+  UINT8  SenseData[18];       /* Sense Data */\r
+} UTP_RESPONSE_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.5 - UTP Data-Out UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x02*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd2;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd3[12];\r
+\r
+  //\r
+  // Data Segment - Data to be sent out\r
+  //\r
+  //UINT8  Data[];            /* Data to be sent out, maximum is 65535 bytes */\r
+} UTP_DATA_OUT_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.6 - UTP Data-In UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x22*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd2;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd3[12];\r
+\r
+  //\r
+  // Data Segment - Data to be read\r
+  //\r
+  //UINT8  Data[];            /* Data to be read, maximum is 65535 bytes */\r
+} UTP_DATA_IN_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.7 - UTP Ready-To-Transfer UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x31*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd2;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd3[12];\r
+\r
+  //\r
+  // Data Segment - Data to be read\r
+  //\r
+  //UINT8  Data[];            /* Data to be read, maximum is 65535 bytes */\r
+} UTP_RDY_TO_TRAN_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.8 - UTP Task Management Request UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x04*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1;\r
+  UINT8  TskManFunc;          /* Task Management Function */\r
+  UINT8  Rsvd2[2];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd3;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 InputParam1;         /* Input Parameter 1 - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 InputParam2;         /* Input Parameter 2 - Big Endian */\r
+\r
+  //\r
+  // DW5\r
+  //\r
+  UINT32 InputParam3;         /* Input Parameter 3 - Big Endian */\r
+\r
+  //\r
+  // DW6 - DW7\r
+  //\r
+  UINT8  Rsvd4[8];\r
+} UTP_TM_REQ_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.9 - UTP Task Management Response UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x24*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[2];\r
+  UINT8  Resp;                /* Response */\r
+  UINT8  Rsvd2;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd3;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 OutputParam1;        /* Output Parameter 1 - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 OutputParam2;        /* Output Parameter 2 - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd4[12];\r
+} UTP_TM_RESP_UPIU;\r
+\r
+//\r
+// UTP Task Management Request Descriptor\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT32 Rsvd1:24;\r
+  UINT32 Int:1;               /* Interrupt */\r
+  UINT32 Rsvd2:7;\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT32 Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT32 Ocs:8;               /* Overall Command Status */\r
+  UINT32 Rsvd4:24;\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 Rsvd5;\r
+\r
+  //\r
+  // DW4 - DW11\r
+  //\r
+  UTP_TM_REQ_UPIU TmReq;      /* Task Management Request UPIU */\r
+  \r
+  //\r
+  // DW12 - DW19\r
+  //\r
+  UTP_TM_RESP_UPIU TmResp;    /* Task Management Response UPIU */\r
+} UTP_TMRD;\r
+\r
+\r
+typedef struct {\r
+  UINT8  Opcode;\r
+  UINT8  DescId;\r
+  UINT8  Index;\r
+  UINT8  Selector;\r
+  UINT16 Rsvd1;\r
+  UINT16 Length;\r
+  UINT32 Value;\r
+  UINT32 Rsvd2;\r
+} UTP_UPIU_TSF;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.10 - UTP Query Request UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8        TransCode:6;   /* Transaction Type - 0x16*/\r
+  UINT8        Dd:1;\r
+  UINT8        Hd:1;\r
+  UINT8        Flags;\r
+  UINT8        Rsvd1;\r
+  UINT8        TaskTag;       /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8        Rsvd2;\r
+  UINT8        QueryFunc;     /* Query Function */\r
+  UINT8        Rsvd3[2];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8        EhsLen;        /* Total EHS Length - 0x00 */\r
+  UINT8        Rsvd4;\r
+  UINT16       DataSegLen;    /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3 - 6\r
+  //\r
+  UTP_UPIU_TSF Tsf;           /* Transaction Specific Fields */\r
+\r
+  //\r
+  // DW7\r
+  //\r
+  UINT8        Rsvd5[4];\r
+\r
+  //\r
+  // Data Segment - Data to be transferred\r
+  //\r
+  //UINT8  Data[];            /* Data to be transferred, maximum is 65535 bytes */\r
+} UTP_QUERY_REQ_UPIU;\r
+\r
+#define QUERY_FUNC_STD_READ_REQ     0x01\r
+#define QUERY_FUNC_STD_WRITE_REQ    0x81\r
+\r
+typedef enum {\r
+  UtpQueryFuncOpcodeNop      = 0x00,\r
+  UtpQueryFuncOpcodeRdDesc   = 0x01,\r
+  UtpQueryFuncOpcodeWrDesc   = 0x02,\r
+  UtpQueryFuncOpcodeRdAttr   = 0x03,\r
+  UtpQueryFuncOpcodeWrAttr   = 0x04,\r
+  UtpQueryFuncOpcodeRdFlag   = 0x05,\r
+  UtpQueryFuncOpcodeSetFlag  = 0x06,\r
+  UtpQueryFuncOpcodeClrFlag  = 0x07,\r
+  UtpQueryFuncOpcodeTogFlag  = 0x08\r
+} UTP_QUERY_FUNC_OPCODE;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.11 - UTP Query Response UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8        TransCode:6;   /* Transaction Type - 0x36*/\r
+  UINT8        Dd:1;\r
+  UINT8        Hd:1;\r
+  UINT8        Flags;\r
+  UINT8        Rsvd1;\r
+  UINT8        TaskTag;       /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8        Rsvd2;\r
+  UINT8        QueryFunc;     /* Query Function */\r
+  UINT8        QueryResp;     /* Query Response */\r
+  UINT8        Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8        EhsLen;        /* Total EHS Length - 0x00 */\r
+  UINT8        DevInfo;       /* Device Information */\r
+  UINT16       DataSegLen;    /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3 - 6\r
+  //\r
+  UTP_UPIU_TSF Tsf;           /* Transaction Specific Fields */\r
+\r
+  //\r
+  // DW7\r
+  //\r
+  UINT8        Rsvd4[4];\r
+\r
+  //\r
+  // Data Segment - Data to be transferred\r
+  //\r
+  //UINT8      Data[];        /* Data to be transferred, maximum is 65535 bytes */\r
+} UTP_QUERY_RESP_UPIU;\r
+\r
+typedef enum {\r
+  UfsUtpQueryResponseSuccess             = 0x00,\r
+  UfsUtpQueryResponseParamNotReadable    = 0xF6,\r
+  UfsUtpQueryResponseParamNotWriteable   = 0xF7,  \r
+  UfsUtpQueryResponseParamAlreadyWritten = 0xF8,\r
+  UfsUtpQueryResponseInvalidLen          = 0xF9,\r
+  UfsUtpQueryResponseInvalidVal          = 0xFA,\r
+  UfsUtpQueryResponseInvalidSelector     = 0xFB,\r
+  UfsUtpQueryResponseInvalidIndex        = 0xFC,\r
+  UfsUtpQueryResponseInvalidIdn          = 0xFD,\r
+  UfsUtpQueryResponseInvalidOpc          = 0xFE,\r
+  UfsUtpQueryResponseGeneralFailure      = 0xFF\r
+} UTP_QUERY_RESP_CODE;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.12 - UTP Reject UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x3F*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[2];\r
+  UINT8  Response;            /* Response - 0x01 */\r
+  UINT8  Rsvd2;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  DevInfo;             /* Device Information - 0x00 */\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT8  HdrSts;              /* Basic Header Status */\r
+  UINT8  Rsvd3;\r
+  UINT8  E2ESts;              /* End-to-End Status */\r
+  UINT8  Rsvd4;\r
+\r
+  //\r
+  // DW4 - DW7\r
+  //\r
+  UINT8  Rsvd5[16];\r
+} UTP_REJ_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.13 - UTP NOP OUT UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x00*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Rsvd1;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd2[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd3;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3 - DW7\r
+  //\r
+  UINT8  Rsvd4[20];\r
+} UTP_NOP_OUT_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.14 - UTP NOP IN UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x20*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Rsvd1;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd2[2];\r
+  UINT8  Resp;                /* Response - 0x00 */\r
+  UINT8  Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  DevInfo;             /* Device Information - 0x00 */\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3 - DW7\r
+  //\r
+  UINT8  Rsvd4[20];\r
+} UTP_NOP_IN_UPIU;\r
+\r
+//\r
+// UFS Descriptors\r
+//\r
+typedef enum {\r
+  UfsDeviceDesc     = 0x00,\r
+  UfsConfigDesc     = 0x01,\r
+  UfsUnitDesc       = 0x02,\r
+  UfsInterConnDesc  = 0x04,\r
+  UfsStringDesc     = 0x05,\r
+  UfsGeometryDesc   = 0x07,\r
+  UfsPowerDesc      = 0x08\r
+} UFS_DESC_IDN;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.2 - Device Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  Device;\r
+  UINT8  DevClass;\r
+  UINT8  DevSubClass;\r
+  UINT8  Protocol;\r
+  UINT8  NumLun;\r
+  UINT8  NumWLun;\r
+  UINT8  BootEn;\r
+  UINT8  DescAccessEn;\r
+  UINT8  InitPowerMode;\r
+  UINT8  HighPriorityLun;\r
+  UINT8  SecureRemovalType;\r
+  UINT8  SecurityLun;\r
+  UINT8  BgOpsTermLat;\r
+  UINT8  InitActiveIccLevel;\r
+  UINT16 SpecVersion;\r
+  UINT16 ManufactureDate;\r
+  UINT8  ManufacturerName;\r
+  UINT8  ProductName;\r
+  UINT8  SerialName;\r
+  UINT8  OemId;\r
+  UINT16 ManufacturerId;\r
+  UINT8  Ud0BaseOffset;\r
+  UINT8  Ud0ConfParamLen;\r
+  UINT8  DevRttCap;\r
+  UINT16 PeriodicRtcUpdate;\r
+  UINT8  Rsvd1[17];\r
+  UINT8  Rsvd2[16];\r
+} UFS_DEV_DESC;\r
+\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  Rsvd1;\r
+  UINT8  BootEn;\r
+  UINT8  DescAccessEn;\r
+  UINT8  InitPowerMode;\r
+  UINT8  HighPriorityLun;\r
+  UINT8  SecureRemovalType;\r
+  UINT8  InitActiveIccLevel;\r
+  UINT16 PeriodicRtcUpdate;\r
+  UINT8  Rsvd2[5];\r
+} UFS_CONFIG_DESC_GEN_HEADER;\r
+\r
+typedef struct {\r
+  UINT8  LunEn;\r
+  UINT8  BootLunId;\r
+  UINT8  LunWriteProt;\r
+  UINT8  MemType;\r
+  UINT32 NumAllocUnits;\r
+  UINT8  DataReliability;\r
+  UINT8  LogicBlkSize;\r
+  UINT8  ProvisionType;\r
+  UINT16 CtxCap;\r
+  UINT8  Rsvd1[3];\r
+} UFS_UNIT_DESC_CONFIG_PARAMS;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.3 - Configuration Descriptor\r
+//\r
+typedef struct {\r
+  UFS_CONFIG_DESC_GEN_HEADER  Header;\r
+  UFS_UNIT_DESC_CONFIG_PARAMS UnitDescConfParams[8];\r
+} UFS_CONFIG_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.4 - Geometry Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  MediaTech;\r
+  UINT8  Rsvd1;\r
+  UINT64 TotalRawDevCapacity;\r
+  UINT8  Rsvd2;\r
+  UINT32 SegSize;\r
+  UINT8  AllocUnitSize;\r
+  UINT8  MinAddrBlkSize;\r
+  UINT8  OptReadBlkSize;\r
+  UINT8  OptWriteBlkSize;\r
+  UINT8  MaxInBufSize;\r
+  UINT8  MaxOutBufSize;\r
+  UINT8  RpmbRwSize;\r
+  UINT8  Rsvd3;\r
+  UINT8  DataOrder;\r
+  UINT8  MaxCtxIdNum;\r
+  UINT8  SysDataTagUnitSize;\r
+  UINT8  SysDataResUnitSize;\r
+  UINT8  SupSecRemovalTypes;\r
+  UINT16 SupMemTypes;\r
+  UINT32 SysCodeMaxNumAllocUnits;\r
+  UINT16 SupCodeCapAdjFac;\r
+  UINT32 NonPersMaxNumAllocUnits;\r
+  UINT16 NonPersCapAdjFac;\r
+  UINT32 Enhance1MaxNumAllocUnits;\r
+  UINT16 Enhance1CapAdjFac;\r
+  UINT32 Enhance2MaxNumAllocUnits;\r
+  UINT16 Enhance2CapAdjFac;\r
+  UINT32 Enhance3MaxNumAllocUnits;\r
+  UINT16 Enhance3CapAdjFac;\r
+  UINT32 Enhance4MaxNumAllocUnits;\r
+  UINT16 Enhance4CapAdjFac;\r
+} UFS_GEOMETRY_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.5 - Unit Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  UnitIdx;\r
+  UINT8  LunEn;\r
+  UINT8  BootLunId;\r
+  UINT8  LunWriteProt;\r
+  UINT8  LunQueueDep;\r
+  UINT8  Rsvd1;\r
+  UINT8  MemType;\r
+  UINT8  DataReliability;\r
+  UINT8  LogicBlkSize;\r
+  UINT64 LogicBlkCount;\r
+  UINT32 EraseBlkSize;\r
+  UINT8  ProvisionType;\r
+  UINT64 PhyMemResCount;\r
+  UINT16 CtxCap;\r
+  UINT8  LargeUnitGranularity;\r
+} UFS_UNIT_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.6 - RPMB Unit Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  UnitIdx;\r
+  UINT8  LunEn;\r
+  UINT8  BootLunId;\r
+  UINT8  LunWriteProt;\r
+  UINT8  LunQueueDep;\r
+  UINT8  Rsvd1;\r
+  UINT8  MemType;\r
+  UINT8  Rsvd2;\r
+  UINT8  LogicBlkSize;\r
+  UINT64 LogicBlkCount;\r
+  UINT32 EraseBlkSize;\r
+  UINT8  ProvisionType;\r
+  UINT64 PhyMemResCount;\r
+  UINT8  Rsvd3[3];\r
+} UFS_RPMB_UNIT_DESC;\r
+\r
+typedef struct {\r
+  UINT16 Value:10;\r
+  UINT16 Rsvd1:4;\r
+  UINT16 Unit:2;\r
+} UFS_POWER_PARAM_ELEMENT;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.7 - Power Parameter Descriptor\r
+//\r
+typedef struct {\r
+  UINT8                    Length;\r
+  UINT8                    DescType;\r
+  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVcc[16];\r
+  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVccQ[16];\r
+  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVccQ2[16];\r
+} UFS_POWER_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.8 - InterConnect Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT16 UniProVer;\r
+  UINT16 MphyVer;\r
+} UFS_INTER_CONNECT_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.9 - 14.1.6.12 - String Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  CHAR16 Unicode[126];\r
+} UFS_STRING_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.2 - Flags\r
+//\r
+typedef enum {\r
+  UfsFlagDevInit         = 0x01,\r
+  UfsFlagPermWpEn        = 0x02,\r
+  UfsFlagPowerOnWpEn     = 0x03,\r
+  UfsFlagBgOpsEn         = 0x04,\r
+  UfsFlagPurgeEn         = 0x06,\r
+  UfsFlagPhyResRemoval   = 0x08,\r
+  UfsFlagBusyRtc         = 0x09,\r
+  UfsFlagPermDisFwUpdate = 0x0B    \r
+} UFS_FLAGS_IDN;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.2 - Attributes\r
+//\r
+typedef enum {\r
+  UfsAttrBootLunEn         = 0x00,\r
+  UfsAttrCurPowerMode      = 0x02,\r
+  UfsAttrActiveIccLevel    = 0x03,\r
+  UfsAttrOutOfOrderDataEn  = 0x04,\r
+  UfsAttrBgOpStatus        = 0x05,\r
+  UfsAttrPurgeStatus       = 0x06,\r
+  UfsAttrMaxDataInSize     = 0x07,\r
+  UfsAttrMaxDataOutSize    = 0x08,\r
+  UfsAttrDynCapNeeded      = 0x09,\r
+  UfsAttrRefClkFreq        = 0x0a,\r
+  UfsAttrConfigDescLock    = 0x0b,\r
+  UfsAttrMaxNumOfRtt       = 0x0c,\r
+  UfsAttrExceptionEvtCtrl  = 0x0d,\r
+  UfsAttrExceptionEvtSts   = 0x0e,\r
+  UfsAttrSecondsPassed     = 0x0f,\r
+  UfsAttrContextConf       = 0x10,\r
+  UfsAttrCorrPrgBlkNum     = 0x11\r
+} UFS_ATTR_IDN;\r
+\r
+typedef enum {\r
+  UfsNoData                = 0,\r
+  UfsDataOut               = 1,\r
+  UfsDataIn                = 2,\r
+  UfsDdReserved\r
+} UFS_DATA_DIRECTION;\r
+\r
+\r
+#pragma pack()\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/ComponentName.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..7da2111
--- /dev/null
@@ -0,0 +1,222 @@
+/** @file\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+#include "UfsPassThru.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gUfsPassThruComponentName = {\r
+  UfsPassThruComponentNameGetDriverName,\r
+  UfsPassThruComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UfsPassThruComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UfsPassThruComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsPassThruDriverNameTable[] = {\r
+  { \r
+    "eng;en",\r
+    L"Universal Flash Storage (UFS) Pass Thru Driver"\r
+  },\r
+  { \r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsPassThruControllerNameTable[] = {\r
+  { \r
+    "eng;en",\r
+    L"Universal Flash Storage (UFS) Host Controller"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mUfsPassThruDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gUfsPassThruComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+\r
+  if (Language == NULL || ControllerName == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // This is a device driver, so ChildHandle must be NULL.\r
+  //\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Make sure this driver is currently managing Controller Handle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gUfsPassThruDriverBinding.DriverBindingHandle,\r
+             &gEdkiiUfsHostControllerProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mUfsPassThruControllerNameTable,\r
+           ControllerName,\r
+           (BOOLEAN)(This == &gUfsPassThruComponentName)\r
+           );\r
+}\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
new file mode 100644 (file)
index 0000000..306fd37
--- /dev/null
@@ -0,0 +1,1054 @@
+/** @file\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsPassThru.h"\r
+\r
+//\r
+// Template for Ufs Pass Thru private data.\r
+//\r
+UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate = {\r
+  UFS_PASS_THRU_SIG,              // Signature\r
+  NULL,                           // Handle  \r
+  {                               // ExtScsiPassThruMode\r
+    0xFFFFFFFF,\r
+    //\r
+    // Note that the driver doesn't support ExtScsiPassThru non blocking I/O.\r
+    //\r
+    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,\r
+    sizeof (UINTN)\r
+  },\r
+  {                               // ExtScsiPassThru\r
+    NULL,\r
+    UfsPassThruPassThru,\r
+    UfsPassThruGetNextTargetLun,\r
+    UfsPassThruBuildDevicePath,\r
+    UfsPassThruGetTargetLun,\r
+    UfsPassThruResetChannel,\r
+    UfsPassThruResetTargetLun,\r
+    UfsPassThruGetNextTarget\r
+  },\r
+  0,                              // UfsHostController\r
+  0,                              // UfsHcBase\r
+  0,                              // Capabilities\r
+  0,                              // TaskTag\r
+  0,                              // UtpTrlBase\r
+  0,                              // Nutrs\r
+  0,                              // TrlMapping\r
+  0,                              // UtpTmrlBase\r
+  0,                              // Nutmrs\r
+  0,                              // TmrlMapping\r
+  {                               // Luns\r
+    {\r
+      UFS_LUN_0,                      // Ufs Common Lun 0\r
+      UFS_LUN_1,                      // Ufs Common Lun 1\r
+      UFS_LUN_2,                      // Ufs Common Lun 2\r
+      UFS_LUN_3,                      // Ufs Common Lun 3\r
+      UFS_LUN_4,                      // Ufs Common Lun 4\r
+      UFS_LUN_5,                      // Ufs Common Lun 5\r
+      UFS_LUN_6,                      // Ufs Common Lun 6\r
+      UFS_LUN_7,                      // Ufs Common Lun 7\r
+      UFS_WLUN_REPORT_LUNS,           // Ufs Reports Luns Well Known Lun\r
+      UFS_WLUN_UFS_DEV,               // Ufs Device Well Known Lun\r
+      UFS_WLUN_BOOT,                  // Ufs Boot Well Known Lun\r
+      UFS_WLUN_RPMB                   // RPMB Well Known Lun\r
+    },\r
+    0x0000,                           // By default don't expose any Luns.\r
+    0x0\r
+  }\r
+};\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gUfsPassThruDriverBinding = {\r
+  UfsPassThruDriverBindingSupported,\r
+  UfsPassThruDriverBindingStart,\r
+  UfsPassThruDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+UFS_DEVICE_PATH    mUfsDevicePathTemplate = {\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_UFS_DP,\r
+    {\r
+      (UINT8) (sizeof (UFS_DEVICE_PATH)),\r
+      (UINT8) ((sizeof (UFS_DEVICE_PATH)) >> 8)\r
+    }\r
+  },\r
+  0,\r
+  0\r
+};\r
+\r
+UINT8 mUfsTargetId[TARGET_MAX_BYTES];\r
+\r
+/**\r
+  Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function\r
+  supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the\r
+  nonblocking I/O functionality is optional.\r
+\r
+  @param  This    A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target  The Target is an array of size TARGET_MAX_BYTES and it represents\r
+                  the id of the SCSI device to send the SCSI Request Packet. Each\r
+                  transport driver may choose to utilize a subset of this size to suit the needs\r
+                  of transport target representation. For example, a Fibre Channel driver\r
+                  may use only 8 bytes (WWN) to represent an FC target.\r
+  @param  Lun     The LUN of the SCSI device to send the SCSI Request Packet.\r
+  @param  Packet  A pointer to the SCSI Request Packet to send to the SCSI device\r
+                  specified by Target and Lun.\r
+  @param  Event   If nonblocking I/O is not supported then Event is ignored, and blocking\r
+                  I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
+                  Event is not NULL and non blocking I/O is supported, then\r
+                  nonblocking I/O is performed, and Event will be signaled when the\r
+                  SCSI Request Packet completes.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_BAD_BUFFER_SIZE   The SCSI Request Packet was not executed. The number of bytes that\r
+                                could be transferred is returned in InTransferLength. For write\r
+                                and bi-directional commands, OutTransferLength bytes were\r
+                                transferred by OutDataBuffer.\r
+  @retval EFI_NOT_READY         The SCSI Request Packet could not be sent because there are too many\r
+                                SCSI Request Packets already queued. The caller may retry again later.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.\r
+  @retval EFI_UNSUPPORTED       The command described by the SCSI Request Packet is not supported\r
+                                by the host adapter. This includes the case of Bi-directional SCSI\r
+                                commands not supported by the implementation. The SCSI Request\r
+                                Packet was not sent, so no additional status information is available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruPassThru (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,\r
+  IN UINT8                                              *Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UFS_PASS_THRU_PRIVATE_DATA      *Private;\r
+  UINT8                           UfsLun;\r
+  UINT16                          Index;\r
+\r
+  Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if ((Packet == NULL) || (Packet->Cdb == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Don't support variable length CDB\r
+  //\r
+  if ((Packet->CdbLength != 6) && (Packet->CdbLength != 10) &&\r
+      (Packet->CdbLength != 12) && (Packet->CdbLength != 16)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->SenseDataLength != 0) && (Packet->SenseData == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // For UFS 2.0 compatible device, 0 is always used to represent the location of the UFS device.\r
+  //\r
+  SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0x00);\r
+  if ((Target == NULL) || (CompareMem(Target, mUfsTargetId, TARGET_MAX_BYTES) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // UFS 2.0 spec Section 10.6.7 - Translation of 8-bit UFS LUN to 64-bit SCSI LUN Address\r
+  // 0xC1 in the first 8 bits of the 64-bit address indicates a well known LUN address in the SAM SCSI format.\r
+  // The second 8 bits of the 64-bit address saves the corresponding 8-bit UFS LUN.\r
+  //\r
+  if ((UINT8)Lun == UFS_WLUN_PREFIX) {\r
+    UfsLun = BIT7 | (((UINT8*)&Lun)[1] & 0xFF);\r
+  } else if ((UINT8)Lun == 0) {\r
+    UfsLun = ((UINT8*)&Lun)[1] & 0xFF;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (Index = 0; Index < UFS_MAX_LUNS; Index++) {\r
+    if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {\r
+      continue;\r
+    }\r
+  \r
+    if (Private->Luns.Lun[Index] == UfsLun) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == UFS_MAX_LUNS) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = UfsExecScsiCmds (Private, UfsLun, Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These\r
+  can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal\r
+  Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the\r
+  Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI\r
+  channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target On input, a pointer to the Target ID (an array of size\r
+                 TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+  @param  Lun    On input, a pointer to the LUN of a SCSI device present on the SCSI\r
+                 channel. On output, a pointer to the LUN of the next SCSI device present\r
+                 on a SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID and LUN of the next SCSI device on the SCSI\r
+                                channel was returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were\r
+                                not returned on a previous call to GetNextTargetLun().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruGetNextTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target,\r
+  IN OUT UINT64                          *Lun\r
+  )\r
+{\r
+  UFS_PASS_THRU_PRIVATE_DATA      *Private;\r
+  UINT8                           UfsLun;\r
+  UINT16                          Index;\r
+  UINT16                          Next;\r
+\r
+  Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*Target == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UfsLun = 0;\r
+  SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0xFF);\r
+  if (CompareMem (*Target, mUfsTargetId, TARGET_MAX_BYTES) == 0) {\r
+    //\r
+    // If the array is all 0xFF's, return the first exposed Lun to caller.\r
+    //\r
+    SetMem (*Target, TARGET_MAX_BYTES, 0x00);\r
+    for (Index = 0; Index < UFS_MAX_LUNS; Index++) {\r
+      if ((Private->Luns.BitMask & (BIT0 << Index)) != 0) {\r
+        UfsLun = Private->Luns.Lun[Index];\r
+        break;\r
+      }\r
+    }\r
+    if (Index != UFS_MAX_LUNS) {\r
+      *Lun = 0;\r
+      if ((UfsLun & BIT7) == BIT7) {\r
+        ((UINT8*)Lun)[0] = UFS_WLUN_PREFIX;\r
+        ((UINT8*)Lun)[1] = UfsLun & ~BIT7;\r
+      } else {\r
+        ((UINT8*)Lun)[1] = UfsLun;\r
+      }\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+\r
+  SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0x00);\r
+  if (CompareMem (*Target, mUfsTargetId, TARGET_MAX_BYTES) == 0) {\r
+    if (((UINT8*)Lun)[0] == UFS_WLUN_PREFIX) {\r
+      UfsLun = BIT7 | (((UINT8*)Lun)[1] & 0xFF);\r
+    } else if (((UINT8*)Lun)[0] == 0) {\r
+      UfsLun = ((UINT8*)Lun)[1] & 0xFF;\r
+    } else {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    for (Index = 0; Index < UFS_MAX_LUNS; Index++) {\r
+      if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {\r
+        continue;\r
+      }\r
+\r
+      if (Private->Luns.Lun[Index] != UfsLun) {\r
+        continue;\r
+      }\r
+\r
+      for (Next = Index + 1; Next < UFS_MAX_LUNS; Next++) {\r
+        if ((Private->Luns.BitMask & (BIT0 << Next)) != 0) {\r
+          UfsLun = Private->Luns.Lun[Next];\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (Next == UFS_MAX_LUNS) {\r
+        return EFI_NOT_FOUND;\r
+      } else {\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (Index != UFS_MAX_LUNS) {\r
+      *Lun = 0;\r
+      if ((UfsLun & BIT7) == BIT7) {\r
+        ((UINT8*)Lun)[0] = UFS_WLUN_PREFIX;\r
+        ((UINT8*)Lun)[1] = UfsLun & ~BIT7;\r
+      } else {\r
+        ((UINT8*)Lun)[1] = UfsLun;\r
+      }\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Used to allocate and build a device path node for a SCSI device on a SCSI channel.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target     The Target is an array of size TARGET_MAX_BYTES and it specifies the\r
+                     Target ID of the SCSI device for which a device path node is to be\r
+                     allocated and built. Transport drivers may chose to utilize a subset of\r
+                     this size to suit the representation of targets. For example, a Fibre\r
+                     Channel driver may use only 8 bytes (WWN) in the array to represent a\r
+                     FC target.\r
+  @param  Lun        The LUN of the SCSI device for which a device path node is to be\r
+                     allocated and built.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     specified by Target and Lun. This function is responsible for\r
+                     allocating the buffer DevicePath with the boot service\r
+                     AllocatePool(). It is the caller's responsibility to free\r
+                     DevicePath when the caller is finished with DevicePath.\r
+\r
+  @retval EFI_SUCCESS           The device path node that describes the SCSI device specified by\r
+                                Target and Lun was allocated and returned in\r
+                                DevicePath.\r
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+  @retval EFI_NOT_FOUND         The SCSI devices specified by Target and Lun does not exist\r
+                                on the SCSI channel.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruBuildDevicePath (\r
+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT8                              *Target,\r
+  IN     UINT64                             Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath\r
+  )\r
+{\r
+  UFS_PASS_THRU_PRIVATE_DATA      *Private;\r
+  EFI_DEV_PATH                    *DevicePathNode;\r
+  UINT8                           UfsLun;\r
+  UINT16                          Index;\r
+\r
+  Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0x00);\r
+  if (CompareMem (Target, mUfsTargetId, TARGET_MAX_BYTES) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((UINT8)Lun == UFS_WLUN_PREFIX) {\r
+    UfsLun = BIT7 | (((UINT8*)&Lun)[1] & 0xFF);\r
+  } else if ((UINT8)Lun == 0) {\r
+    UfsLun = ((UINT8*)&Lun)[1] & 0xFF;\r
+  } else {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  for (Index = 0; Index < UFS_MAX_LUNS; Index++) {\r
+    if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {\r
+      continue;\r
+    }\r
+  \r
+    if (Private->Luns.Lun[Index] == UfsLun) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == UFS_MAX_LUNS) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  DevicePathNode = AllocateCopyPool (sizeof (UFS_DEVICE_PATH), &mUfsDevicePathTemplate);\r
+  if (DevicePathNode == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DevicePathNode->Ufs.Pun = 0;\r
+  DevicePathNode->Ufs.Lun = UfsLun;\r
+\r
+  *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathNode;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     on the SCSI channel.\r
+  @param  Target     A pointer to the Target Array which represents the ID of a SCSI device\r
+                     on the SCSI channel.\r
+  @param  Lun        A pointer to the LUN of a SCSI device on the SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           DevicePath was successfully translated to a Target ID and\r
+                                LUN, and they were returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.\r
+  @retval EFI_NOT_FOUND         A valid translation from DevicePath to a Target ID and LUN\r
+                                does not exist.\r
+  @retval EFI_UNSUPPORTED       This driver does not support the device path node type in\r
+                                 DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruGetTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,\r
+  OUT UINT8                              **Target,\r
+  OUT UINT64                             *Lun\r
+  )\r
+{\r
+  UFS_PASS_THRU_PRIVATE_DATA      *Private;\r
+  EFI_DEV_PATH                    *DevicePathNode;\r
+  UINT8                           Pun;\r
+  UINT8                           UfsLun;\r
+  UINT16                          Index;\r
+\r
+  Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*Target == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
+  //\r
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) || (DevicePath->SubType != MSG_UFS_DP) ||\r
+      (DevicePathNodeLength(DevicePath) != sizeof(SCSI_DEVICE_PATH))) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  DevicePathNode = (EFI_DEV_PATH *) DevicePath;\r
+\r
+  Pun    = (UINT8) DevicePathNode->Ufs.Pun;\r
+  UfsLun = (UINT8) DevicePathNode->Ufs.Lun;\r
+\r
+  if (Pun != 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  for (Index = 0; Index < UFS_MAX_LUNS; Index++) {\r
+    if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {\r
+      continue;\r
+    }\r
+  \r
+    if (Private->Luns.Lun[Index] == UfsLun) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == UFS_MAX_LUNS) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  SetMem (*Target, TARGET_MAX_BYTES, 0x00);\r
+  *Lun = 0;\r
+  if ((UfsLun & BIT7) == BIT7) {\r
+    ((UINT8*)Lun)[0] = UFS_WLUN_PREFIX;\r
+    ((UINT8*)Lun)[1] = UfsLun & ~BIT7;\r
+  } else {\r
+    ((UINT8*)Lun)[1] = UfsLun;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.\r
+\r
+  @param  This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS      The SCSI channel was reset.\r
+  @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_TIMEOUT      A timeout occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_UNSUPPORTED  The SCSI channel does not support a channel reset operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruResetChannel (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This\r
+  )\r
+{\r
+  //\r
+  // Return success directly then upper layer driver could think reset channel operation is done.\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resets a SCSI logical unit that is connected to a SCSI channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target The Target is an array of size TARGET_MAX_BYTE and it represents the\r
+                 target port ID of the SCSI device containing the SCSI logical unit to\r
+                 reset. Transport drivers may chose to utilize a subset of this array to suit\r
+                 the representation of their targets.\r
+  @param  Lun    The LUN of the SCSI device to reset.\r
+\r
+  @retval EFI_SUCCESS           The SCSI device specified by Target and Lun was reset.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           A timeout occurred while attempting to reset the SCSI device\r
+                                specified by Target and Lun.\r
+  @retval EFI_UNSUPPORTED       The SCSI channel does not support a target reset operation.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to reset the SCSI device\r
+                                 specified by Target and Lun.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruResetTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT8                              *Target,\r
+  IN UINT64                             Lun\r
+  )\r
+{\r
+  //\r
+  // Return success directly then upper layer driver could think reset target LUN operation is done.\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either\r
+  be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs\r
+  for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to\r
+  see if a SCSI device is actually present at that location on the SCSI channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID of the next SCSI device on the SCSI\r
+                                channel was returned in Target.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           Target array is not all 0xF, and Target was not\r
+                                returned on a previous call to GetNextTarget().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruGetNextTarget (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target\r
+  )\r
+{\r
+  UFS_PASS_THRU_PRIVATE_DATA      *Private;\r
+\r
+  Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (Target == NULL || *Target == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0xFF);\r
+  if (CompareMem(*Target, mUfsTargetId, TARGET_MAX_BYTES) == 0) {\r
+    SetMem (*Target, TARGET_MAX_BYTES, 0x00);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL       *This,\r
+  IN EFI_HANDLE                        Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_DEVICE_PATH_PROTOCOL             *ParentDevicePath;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHostController;\r
+\r
+  //\r
+  // Ufs Pass Thru driver is a device driver, and should ingore the\r
+  // "RemainingDevicePath" according to UEFI spec\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID *) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EFI_ALREADY_STARTED is also an error\r
+    //\r
+    return Status;\r
+  }\r
+  //\r
+  // Close the protocol because we don't use it here\r
+  //\r
+  gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Controller\r
+                  );\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEdkiiUfsHostControllerProtocolGuid,\r
+                  (VOID **) &UfsHostController,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EFI_ALREADY_STARTED is also an error\r
+    //\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEdkiiUfsHostControllerProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+        \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL        *This,\r
+  IN EFI_HANDLE                         Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL    *UfsHc;\r
+  UFS_PASS_THRU_PRIVATE_DATA            *Private;\r
+  UINTN                                 UfsHcBase;\r
+  UINT32                                Index;\r
+  UFS_CONFIG_DESC                       Config;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  UfsHc     = NULL;\r
+  Private   = NULL;\r
+  UfsHcBase = 0;\r
+\r
+  DEBUG ((EFI_D_INFO, "==UfsPassThru Start== Controller = %x\n", Controller));\r
+\r
+  Status  = gBS->OpenProtocol (\r
+                   Controller,\r
+                   &gEdkiiUfsHostControllerProtocolGuid,\r
+                   (VOID **) &UfsHc,\r
+                   This->DriverBindingHandle,\r
+                   Controller,\r
+                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                   );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Open Ufs Host Controller Protocol Error, Status = %r\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Get the UFS Host Controller MMIO Bar Base Address.\r
+  //\r
+  Status = UfsHc->GetUfsHcMmioBar (UfsHc, &UfsHcBase);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Get Ufs Host Controller Mmio Bar Error, Status = %r\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Initialize Ufs Pass Thru private data for managed UFS Host Controller.\r
+  //\r
+  Private = AllocateCopyPool (sizeof (UFS_PASS_THRU_PRIVATE_DATA), &gUfsPassThruTemplate);\r
+  if (Private == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  Private->ExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;\r
+  Private->UfsHostController    = UfsHc;\r
+  Private->UfsHcBase            = UfsHcBase;\r
+\r
+  //\r
+  // Initialize UFS Host Controller H/W.\r
+  //\r
+  Status = UfsControllerInit (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Ufs Host Controller Initialization Error, Status = %r\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // UFS 2.0 spec Section 13.1.3.3:\r
+  // At the end of the UFS Interconnect Layer initialization on both host and device side, \r
+  // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready. \r
+  //\r
+  Status = UfsExecNopCmds (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // The host enables the device initialization completion by setting fDeviceInit flag.\r
+  //\r
+  Status = UfsSetFlag (Private, UfsFlagDevInit);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Get Ufs Device's Lun Info by reading Configuration Descriptor.\r
+  //\r
+  Status = UfsRwDeviceDesc (Private, TRUE, UfsConfigDesc, 0, 0, &Config, sizeof (UFS_CONFIG_DESC));\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Check if 8 common luns are active and set corresponding bit mask.\r
+  // TODO: Parse device descriptor to decide if exposing RPMB LUN to upper layer for authentication access.\r
+  //\r
+  for (Index = 0; Index < 8; Index++) {\r
+    if (Config.UnitDescConfParams[Index].LunEn != 0) {\r
+      Private->Luns.BitMask |= (BIT0 << Index);\r
+      DEBUG ((EFI_D_INFO, "Ufs Lun %d is enabled\n", Index));\r
+    }\r
+  }\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &gEfiExtScsiPassThruProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &(Private->ExtScsiPassThru)\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Error:\r
+  if (Private != NULL) {\r
+    if (Private->TmrlMapping != NULL) {\r
+      UfsHc->Unmap (UfsHc, Private->TmrlMapping);  \r
+    }\r
+    if (Private->UtpTmrlBase != NULL) {\r
+      UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)), Private->UtpTmrlBase);\r
+    }\r
+\r
+    if (Private->TrlMapping != NULL) {\r
+      UfsHc->Unmap (UfsHc, Private->TrlMapping);\r
+    }\r
+    if (Private->UtpTrlBase != NULL) {\r
+      UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);\r
+    }\r
+\r
+    FreePool (Private);\r
+  }\r
+\r
+  if (UfsHc != NULL) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEdkiiUfsHostControllerProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL       *This,\r
+  IN  EFI_HANDLE                        Controller,\r
+  IN  UINTN                             NumberOfChildren,\r
+  IN  EFI_HANDLE                        *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UFS_PASS_THRU_PRIVATE_DATA            *Private;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL       *ExtScsiPassThru;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL    *UfsHc;\r
+\r
+  DEBUG ((EFI_D_INFO, "==UfsPassThru Stop== Controller Controller = %x\n", Controller));\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiExtScsiPassThruProtocolGuid,\r
+                  (VOID **) &ExtScsiPassThru,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (ExtScsiPassThru);\r
+  UfsHc   = Private->UfsHostController;\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  Controller,\r
+                  &gEfiExtScsiPassThruProtocolGuid,\r
+                  &(Private->ExtScsiPassThru)\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Stop Ufs Host Controller\r
+  //\r
+  Status = UfsControllerStop (Private);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (Private->TmrlMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, Private->TmrlMapping);\r
+  }\r
+  if (Private->UtpTmrlBase != NULL) {\r
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)), Private->UtpTmrlBase);\r
+  }\r
+\r
+  if (Private->TrlMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, Private->TrlMapping);\r
+  }\r
+  if (Private->UtpTrlBase != NULL) {\r
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);\r
+  }\r
+\r
+  FreePool (Private);\r
+\r
+  //\r
+  // Close protocols opened by UfsPassThru controller driver\r
+  //\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEdkiiUfsHostControllerProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  The user Entry Point for module UfsPassThru. The user code starts with this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeUfsPassThru (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gUfsPassThruDriverBinding,\r
+             ImageHandle,\r
+             &gUfsPassThruComponentName,\r
+             &gUfsPassThruComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
new file mode 100644 (file)
index 0000000..c435fe1
--- /dev/null
@@ -0,0 +1,727 @@
+/** @file\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _UFS_PASS_THRU_H_\r
+#define _UFS_PASS_THRU_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/ScsiPassThruExt.h>\r
+#include <Protocol/UfsHostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+\r
+#include "UfsPassThruHci.h"\r
+\r
+#define UFS_PASS_THRU_SIG           SIGNATURE_32 ('U', 'F', 'S', 'P')\r
+\r
+//\r
+// Lun 0~7 is for 8 common luns. \r
+// Lun 8~11 is for those 4 well known luns (Refer to UFS 2.0 spec Table 10.58 for details):\r
+//  Lun 8:  REPORT LUNS\r
+//  Lun 9:  UFS DEVICE\r
+//  Lun 10: BOOT\r
+//  Lun 11: RPMB\r
+//\r
+#define UFS_MAX_LUNS                12\r
+#define UFS_WLUN_PREFIX             0xC1\r
+\r
+typedef struct {\r
+  UINT8    Lun[UFS_MAX_LUNS];\r
+  UINT16   BitMask:12;              // Bit 0~7 is 1/1 mapping to common luns. Bit 8~11 is 1/1 mapping to well-known luns.\r
+  UINT16   Rsvd:4;\r
+} UFS_EXPOSED_LUNS;\r
+\r
+typedef struct _UFS_PASS_THRU_PRIVATE_DATA {  \r
+  UINT32                              Signature;\r
+  EFI_HANDLE                          Handle;\r
+  EFI_EXT_SCSI_PASS_THRU_MODE         ExtScsiPassThruMode;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL     ExtScsiPassThru;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL  *UfsHostController;\r
+  UINTN                               UfsHcBase;\r
+  UINT32                              Capabilities;\r
+\r
+  UINT8                               TaskTag;\r
+\r
+  VOID                                *UtpTrlBase;\r
+  UINT8                               Nutrs;\r
+  VOID                                *TrlMapping;\r
+  VOID                                *UtpTmrlBase;\r
+  UINT8                               Nutmrs;\r
+  VOID                                *TmrlMapping;\r
+\r
+  UFS_EXPOSED_LUNS                    Luns;\r
+} UFS_PASS_THRU_PRIVATE_DATA;\r
+\r
+#define UFS_TIMEOUT                   EFI_TIMER_PERIOD_SECONDS(3)\r
+\r
+#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)\r
+\r
+#define IS_ALIGNED(addr, size)        (((UINTN) (addr) & (size - 1)) == 0)\r
+\r
+#define UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \\r
+  CR (a, \\r
+      UFS_PASS_THRU_PRIVATE_DATA, \\r
+      ExtScsiPassThru, \\r
+      UFS_PASS_THRU_SIG \\r
+      )\r
+\r
+typedef struct _UFS_DEVICE_MANAGEMENT_REQUEST_PACKET {\r
+  UINT64           Timeout;\r
+  VOID             *InDataBuffer;\r
+  VOID             *OutDataBuffer;\r
+  UINT8            Opcode;\r
+  UINT8            DescId;\r
+  UINT8            Index;\r
+  UINT8            Selector;\r
+  UINT32           InTransferLength;\r
+  UINT32           OutTransferLength;\r
+  UINT8            DataDirection;\r
+  UINT8            Ocs;\r
+} UFS_DEVICE_MANAGEMENT_REQUEST_PACKET;\r
+\r
+//\r
+// function prototype\r
+//\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+/**\r
+  Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function\r
+  supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the\r
+  nonblocking I/O functionality is optional.\r
+\r
+  @param  This    A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target  The Target is an array of size TARGET_MAX_BYTES and it represents\r
+                  the id of the SCSI device to send the SCSI Request Packet. Each\r
+                  transport driver may choose to utilize a subset of this size to suit the needs\r
+                  of transport target representation. For example, a Fibre Channel driver\r
+                  may use only 8 bytes (WWN) to represent an FC target.\r
+  @param  Lun     The LUN of the SCSI device to send the SCSI Request Packet.\r
+  @param  Packet  A pointer to the SCSI Request Packet to send to the SCSI device\r
+                  specified by Target and Lun.\r
+  @param  Event   If nonblocking I/O is not supported then Event is ignored, and blocking\r
+                  I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
+                  Event is not NULL and non blocking I/O is supported, then\r
+                  nonblocking I/O is performed, and Event will be signaled when the\r
+                  SCSI Request Packet completes.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_BAD_BUFFER_SIZE   The SCSI Request Packet was not executed. The number of bytes that\r
+                                could be transferred is returned in InTransferLength. For write\r
+                                and bi-directional commands, OutTransferLength bytes were\r
+                                transferred by OutDataBuffer.\r
+  @retval EFI_NOT_READY         The SCSI Request Packet could not be sent because there are too many\r
+                                SCSI Request Packets already queued. The caller may retry again later.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.\r
+  @retval EFI_UNSUPPORTED       The command described by the SCSI Request Packet is not supported\r
+                                by the host adapter. This includes the case of Bi-directional SCSI\r
+                                commands not supported by the implementation. The SCSI Request\r
+                                Packet was not sent, so no additional status information is available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruPassThru (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,\r
+  IN UINT8                                              *Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  );\r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These\r
+  can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal\r
+  Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the\r
+  Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI\r
+  channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target On input, a pointer to the Target ID (an array of size\r
+                 TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+  @param  Lun    On input, a pointer to the LUN of a SCSI device present on the SCSI\r
+                 channel. On output, a pointer to the LUN of the next SCSI device present\r
+                 on a SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID and LUN of the next SCSI device on the SCSI\r
+                                channel was returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were\r
+                                not returned on a previous call to GetNextTargetLun().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruGetNextTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target,\r
+  IN OUT UINT64                          *Lun\r
+  );\r
+\r
+/**\r
+  Used to allocate and build a device path node for a SCSI device on a SCSI channel.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target     The Target is an array of size TARGET_MAX_BYTES and it specifies the\r
+                     Target ID of the SCSI device for which a device path node is to be\r
+                     allocated and built. Transport drivers may chose to utilize a subset of\r
+                     this size to suit the representation of targets. For example, a Fibre\r
+                     Channel driver may use only 8 bytes (WWN) in the array to represent a\r
+                     FC target.\r
+  @param  Lun        The LUN of the SCSI device for which a device path node is to be\r
+                     allocated and built.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     specified by Target and Lun. This function is responsible for\r
+                     allocating the buffer DevicePath with the boot service\r
+                     AllocatePool(). It is the caller's responsibility to free\r
+                     DevicePath when the caller is finished with DevicePath.\r
+\r
+  @retval EFI_SUCCESS           The device path node that describes the SCSI device specified by\r
+                                Target and Lun was allocated and returned in\r
+                                DevicePath.\r
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+  @retval EFI_NOT_FOUND         The SCSI devices specified by Target and Lun does not exist\r
+                                on the SCSI channel.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruBuildDevicePath (\r
+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT8                              *Target,\r
+  IN     UINT64                             Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath\r
+  );\r
+\r
+/**\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     on the SCSI channel.\r
+  @param  Target     A pointer to the Target Array which represents the ID of a SCSI device\r
+                     on the SCSI channel.\r
+  @param  Lun        A pointer to the LUN of a SCSI device on the SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           DevicePath was successfully translated to a Target ID and\r
+                                LUN, and they were returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.\r
+  @retval EFI_NOT_FOUND         A valid translation from DevicePath to a Target ID and LUN\r
+                                does not exist.\r
+  @retval EFI_UNSUPPORTED       This driver does not support the device path node type in\r
+                                 DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruGetTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,\r
+  OUT UINT8                              **Target,\r
+  OUT UINT64                             *Lun\r
+  );\r
+\r
+/**\r
+  Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.\r
+\r
+  @param  This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS      The SCSI channel was reset.\r
+  @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_TIMEOUT      A timeout occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_UNSUPPORTED  The SCSI channel does not support a channel reset operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruResetChannel (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This\r
+  );\r
+\r
+/**\r
+  Resets a SCSI logical unit that is connected to a SCSI channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target The Target is an array of size TARGET_MAX_BYTE and it represents the\r
+                 target port ID of the SCSI device containing the SCSI logical unit to\r
+                 reset. Transport drivers may chose to utilize a subset of this array to suit\r
+                 the representation of their targets.\r
+  @param  Lun    The LUN of the SCSI device to reset.\r
+\r
+  @retval EFI_SUCCESS           The SCSI device specified by Target and Lun was reset.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           A timeout occurred while attempting to reset the SCSI device\r
+                                specified by Target and Lun.\r
+  @retval EFI_UNSUPPORTED       The SCSI channel does not support a target reset operation.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to reset the SCSI device\r
+                                 specified by Target and Lun.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruResetTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT8                              *Target,\r
+  IN UINT64                             Lun\r
+  );\r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either\r
+  be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs\r
+  for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to\r
+  see if a SCSI device is actually present at that location on the SCSI channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID of the next SCSI device on the SCSI\r
+                                channel was returned in Target.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           Target array is not all 0xF, and Target was not\r
+                                returned on a previous call to GetNextTarget().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsPassThruGetNextTarget (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target\r
+  );\r
+\r
+/**\r
+  Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]      Lun           The LUN of the UFS device to send the SCSI Request Packet.\r
+  @param[in, out] Packet        A pointer to the SCSI Request Packet to send to a specified Lun of the\r
+                                UFS device.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecScsiCmds (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA                  *Private,\r
+  IN     UINT8                                       Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  );\r
+\r
+/**\r
+  Initialize the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The NVM Express Controller is initialized successfully.\r
+  @retval Others                     A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerInit (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  );\r
+\r
+/**\r
+  Stop the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The Ufs Host Controller is stopped successfully.\r
+  @retval Others                     A device error occurred while stopping the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerStop (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  );\r
+\r
+/**\r
+  Allocate common buffer for host and UFS bus master access simultaneously.\r
+\r
+  @param[in]  Private                The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  Size                   The length of buffer to be allocated.\r
+  @param[out] CmdDescHost            A pointer to store the base system memory address of the allocated range.\r
+  @param[out] CmdDescPhyAddr         The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.\r
+  @param[out] CmdDescMapping         A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS                The common buffer was allocated successfully.\r
+  @retval EFI_DEVICE_ERROR           The allocation fails.\r
+  @retval EFI_OUT_OF_RESOURCES       The memory resource is insufficient.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsAllocateAlignCommonBuffer (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA    *Private,\r
+  IN     UINTN                         Size,\r
+     OUT VOID                          **CmdDescHost,\r
+     OUT EFI_PHYSICAL_ADDRESS          *CmdDescPhyAddr,\r
+     OUT VOID                          **CmdDescMapping\r
+  );\r
+\r
+/**\r
+  Set specified flag to 1 on a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be set.\r
+\r
+  @retval EFI_SUCCESS           The flag was set successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to set the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of setting the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsSetFlag (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN  UINT8                        FlagId\r
+  );\r
+\r
+/**\r
+  Read or write specified device descriptor of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      DescId        The ID of device descriptor.\r
+  @param[in]      Index         The Index of device descriptor.\r
+  @param[in]      Selector      The Selector of device descriptor.\r
+  @param[in, out] Descriptor    The buffer of device descriptor to be read or written.\r
+  @param[in]      DescSize      The size of device descriptor buffer.\r
+\r
+  @retval EFI_SUCCESS           The device descriptor was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the device descriptor.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the device descriptor.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwDeviceDesc (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        DescId,\r
+  IN     UINT8                        Index,\r
+  IN     UINT8                        Selector,\r
+  IN OUT VOID                         *Descriptor,\r
+  IN     UINT32                       DescSize\r
+  );\r
+\r
+/**\r
+  Sends NOP IN cmd to a UFS device for initialization process request.\r
+  For more details, please refer to UFS 2.0 spec Figure 13.3.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS           The NOP IN command was sent by the host. The NOP OUT response was\r
+                                received successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to execute NOP IN command.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the NOP IN command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecNopCmds (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA       *Private\r
+  );\r
+\r
+extern GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gUfsPassThruComponentName;\r
+extern GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2;\r
+extern EFI_DRIVER_BINDING_PROTOCOL   gUfsPassThruDriverBinding;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni
new file mode 100644 (file)
index 0000000..1e627bd
Binary files /dev/null and b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni differ
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
new file mode 100644 (file)
index 0000000..21b8e6c
--- /dev/null
@@ -0,0 +1,63 @@
+## @file\r
+# Description file for the Universal Flash Storage (UFS) Pass Thru driver.\r
+#\r
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UfsPassThruDxe\r
+  MODULE_UNI_FILE                = UfsPassThru.uni\r
+  FILE_GUID                      = E7F1DFF9-DAB6-498A-9ADF-57F344EDDF57\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = InitializeUfsPassThru\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gUfsPassThruDriverBinding              \r
+#  COMPONENT_NAME                =  gUfsPassThruComponentName              \r
+#\r
+\r
+[Sources]\r
+  ComponentName.c\r
+  UfsPassThru.c\r
+  UfsPassThru.h\r
+  UfsPassThruHci.c\r
+  UfsPassThruHci.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  BaseLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+  DevicePathLib\r
+  IoLib\r
+  TimerLib\r
+\r
+[Protocols]\r
+  gEfiExtScsiPassThruProtocolGuid               ## BY_START\r
+  gEdkiiUfsHostControllerProtocolGuid           ## TO_START\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  UfsPassThruExtra.uni\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni
new file mode 100644 (file)
index 0000000..771b7ba
Binary files /dev/null and b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni differ
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
new file mode 100644 (file)
index 0000000..4cc32f0
--- /dev/null
@@ -0,0 +1,2000 @@
+/** @file\r
+  UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface\r
+  for upper layer application to execute UFS-supported SCSI cmds.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UfsPassThru.h"\r
+\r
+/**\r
+  Wait for the value of the specified system memory set to the test value.\r
+\r
+  @param  Address           The system memory address to test.\r
+  @param  MaskValue         The mask value of memory.\r
+  @param  TestValue         The test value of memory.\r
+  @param  Timeout           The time out value for wait memory set, uses 100ns as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The system memory setting is time out.\r
+  @retval EFI_SUCCESS       The system memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UfsWaitMemSet (\r
+  IN  UINTN                     Address,\r
+  IN  UINT32                    MaskValue,\r
+  IN  UINT32                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32     Value;\r
+  UINT64     Delay;\r
+  BOOLEAN    InfiniteWait;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  Delay = DivU64x32 (Timeout, 10) + 1;\r
+\r
+  do {\r
+    //\r
+    // Access PCI MMIO space to see if the value is the tested one.\r
+    //\r
+    Value = MmioRead32 (Address) & MaskValue;\r
+\r
+    if (Value == TestValue) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Stall for 1 microseconds.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Delay--;\r
+\r
+  } while (InfiniteWait || (Delay > 0));\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Dump UIC command execution result for debugging.\r
+\r
+  @param[in]   UicOpcode  The executed UIC opcode.\r
+  @param[in]   Result     The result to be parsed.\r
+\r
+**/\r
+VOID\r
+DumpUicCmdExecResult (\r
+  IN  UINT8     UicOpcode,\r
+  IN  UINT8     Result\r
+  )\r
+{\r
+  if (UicOpcode <= UfsUicDmePeerSet) {\r
+    switch (Result) {\r
+      case 0x00:\r
+        break;\r
+      case 0x01:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x02:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
+        break;\r
+      case 0x03:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x04:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x05:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
+        break;\r
+      case 0x06:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
+        break;\r
+      case 0x07:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
+        break;\r
+      case 0x08:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
+        break; \r
+      case 0x09:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
+        break;\r
+      case 0x0A:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));\r
+        break;        \r
+      default :\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+  } else {\r
+    switch (Result) {\r
+      case 0x00:\r
+        break;\r
+      case 0x01:\r
+        DEBUG ((EFI_D_VERBOSE, "UIC control command fails - FAILURE\n"));\r
+        break;     \r
+      default :\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Dump QUERY RESPONSE UPIU result for debugging.\r
+\r
+  @param[in]   Result  The result to be parsed.\r
+\r
+**/\r
+VOID\r
+DumpQueryResponseResult (\r
+  IN  UINT8     Result\r
+  )\r
+{\r
+  switch (Result) {\r
+    case 0xF6:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
+      break;\r
+    case 0xF7:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
+      break;\r
+    case 0xF8:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Already Written\n"));\r
+      break;\r
+    case 0xF9:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Length\n"));\r
+      break;\r
+    case 0xFA:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Value\n"));\r
+      break;\r
+    case 0xFB:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Selector\n"));\r
+      break;\r
+    case 0xFC:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Index\n"));\r
+      break;\r
+    case 0xFD:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Idn\n"));\r
+      break;\r
+    case 0xFE:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Opcode\n"));\r
+      break; \r
+    case 0xFF:\r
+      DEBUG ((EFI_D_VERBOSE, "Query Response with General Failure\n"));\r
+      break;\r
+    default :\r
+      ASSERT (FALSE);\r
+      break;\r
+  }\r
+}\r
+\r
+/**\r
+  Swap little endian to big endian.\r
+\r
+  @param[in, out] Buffer      The data buffer. In input, it contains little endian data.\r
+                              In output, it will become big endian.\r
+  @param[in]      BufferSize  The length of converted data.\r
+\r
+**/\r
+VOID\r
+SwapLittleEndianToBigEndian (\r
+  IN OUT UINT8         *Buffer,\r
+  IN     UINT32        BufferSize\r
+  )\r
+{\r
+  UINT32 Index;\r
+  UINT8  Temp;\r
+  UINT32 SwapCount;\r
+\r
+  SwapCount = BufferSize / 2;\r
+  for (Index = 0; Index < SwapCount; Index++) {\r
+    Temp = Buffer[Index];\r
+    Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
+    Buffer[BufferSize - 1 - Index] = Temp;\r
+  }\r
+}\r
+\r
+/**\r
+  Fill TSF field of QUERY REQUEST UPIU.\r
+\r
+  @param[in, out] TsfBase      The base address of TSF field of QUERY REQUEST UPIU.\r
+  @param[in]      Opcode       The opcode of request.\r
+  @param[in]      DescId       The descriptor ID of request.\r
+  @param[in]      Index        The index of request.\r
+  @param[in]      Selector     The selector of request.\r
+  @param[in]      Length       The length of transferred data. The maximum is 4.\r
+  @param[in]      Value        The value of transferred data.\r
+\r
+**/\r
+VOID\r
+UfsFillTsfOfQueryReqUpiu (\r
+  IN OUT UTP_UPIU_TSF        *TsfBase,\r
+  IN     UINT8               Opcode,\r
+  IN     UINT8               DescId    OPTIONAL,\r
+  IN     UINT8               Index     OPTIONAL,\r
+  IN     UINT8               Selector  OPTIONAL,\r
+  IN     UINT16              Length    OPTIONAL,\r
+  IN     UINT32              Value     OPTIONAL\r
+  )\r
+{\r
+  ASSERT (TsfBase != NULL);\r
+  ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);\r
+\r
+  TsfBase->Opcode   = Opcode;\r
+  if (Opcode != UtpQueryFuncOpcodeNop) {\r
+    TsfBase->DescId   = DescId;\r
+    TsfBase->Index    = Index;\r
+    TsfBase->Selector = Selector;\r
+\r
+    if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
+      SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));\r
+      TsfBase->Length = Length;\r
+    }\r
+  \r
+    if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
+      SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));\r
+      TsfBase->Value  = Value;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize COMMAND UPIU.\r
+\r
+  @param[in, out] Command         The base address of COMMAND UPIU.\r
+  @param[in]      Lun             The Lun on which the SCSI command is executed.\r
+  @param[in]      TaskTag         The task tag of request.\r
+  @param[in]      Cdb             The cdb buffer containing SCSI command.\r
+  @param[in]      CdbLength       The cdb length.\r
+  @param[in]      DataDirection   The direction of data transfer.\r
+  @param[in]      ExpDataTranLen  The expected transfer data length.\r
+\r
+  @retval EFI_SUCCESS     The initialization succeed.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitCommandUpiu (\r
+  IN OUT UTP_COMMAND_UPIU              *Command,\r
+  IN     UINT8                         Lun,\r
+  IN     UINT8                         TaskTag,\r
+  IN     UINT8                         *Cdb,\r
+  IN     UINT8                         CdbLength,\r
+  IN     UFS_DATA_DIRECTION            DataDirection,\r
+  IN     UINT32                        ExpDataTranLen\r
+  )\r
+{\r
+  UINT8                   Flags;\r
+\r
+  ASSERT ((Command != NULL) && (Cdb != NULL));\r
+\r
+  //\r
+  // Task attribute is hard-coded to Ordered.\r
+  //\r
+  if (DataDirection == UfsDataIn) {\r
+    Flags = BIT0 | BIT6;\r
+  } else if (DataDirection == UfsDataOut) {\r
+    Flags = BIT0 | BIT5;\r
+  } else {\r
+    Flags = BIT0;\r
+  }\r
+\r
+  //\r
+  // Fill UTP COMMAND UPIU associated fields.\r
+  //\r
+  Command->TransCode = 0x01;\r
+  Command->Flags     = Flags;\r
+  Command->Lun       = Lun;\r
+  Command->TaskTag   = TaskTag;\r
+  Command->CmdSet    = 0x00;\r
+  SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));\r
+  Command->ExpDataTranLen = ExpDataTranLen;\r
+\r
+  CopyMem (Command->Cdb, Cdb, CdbLength);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UTP PRDT for data transfer.\r
+\r
+  @param[in] Prdt         The base address of PRDT.\r
+  @param[in] Buffer       The buffer to be read or written.\r
+  @param[in] BufferSize   The data size to be read or written.\r
+\r
+  @retval EFI_SUCCESS     The initialization succeed.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitUtpPrdt (\r
+  IN  UTP_TR_PRD                       *Prdt,\r
+  IN  VOID                             *Buffer,\r
+  IN  UINT32                           BufferSize\r
+  )\r
+{\r
+  UINT32     PrdtIndex;\r
+  UINT32     RemainingLen;\r
+  UINT8      *Remaining;\r
+  UINTN      PrdtNumber;\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
+\r
+  RemainingLen = BufferSize;\r
+  Remaining    = Buffer;\r
+  PrdtNumber   = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
+\r
+  for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
+    if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {\r
+      Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;\r
+    } else {\r
+      Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;\r
+    }\r
+\r
+    Prdt[PrdtIndex].DbAddr  = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);\r
+    Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);\r
+    RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;\r
+    Remaining    += UFS_MAX_DATA_LEN_PER_PRD;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize QUERY REQUEST UPIU.\r
+\r
+  @param[in, out] QueryReq      The base address of QUERY REQUEST UPIU.\r
+  @param[in]      TaskTag       The task tag of request.\r
+  @param[in]      Opcode        The opcode of request.\r
+  @param[in]      DescId        The descriptor ID of request.\r
+  @param[in]      Index         The index of request.\r
+  @param[in]      Selector      The selector of request.\r
+  @param[in]      DataSize      The data size to be read or written.\r
+  @param[in]      Data          The buffer to be read or written.\r
+\r
+  @retval EFI_SUCCESS           The initialization succeed.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitQueryRequestUpiu (\r
+  IN OUT UTP_QUERY_REQ_UPIU            *QueryReq,\r
+  IN     UINT8                         TaskTag,\r
+  IN     UINT8                         Opcode,\r
+  IN     UINT8                         DescId,\r
+  IN     UINT8                         Index,\r
+  IN     UINT8                         Selector,\r
+  IN     UINTN                         DataSize   OPTIONAL,\r
+  IN     UINT8                         *Data      OPTIONAL\r
+  )\r
+{\r
+  ASSERT (QueryReq != NULL);\r
+\r
+  QueryReq->TransCode = 0x16;\r
+  QueryReq->TaskTag   = TaskTag;\r
+  if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {\r
+    QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;\r
+  } else {\r
+    QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;\r
+  }\r
+\r
+  if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
+    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);\r
+  } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
+    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);\r
+  } else {\r
+    UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);\r
+  }\r
+\r
+  if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
+    CopyMem (QueryReq + 1, Data, DataSize);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  Lun               The Lun on which the SCSI command is executed.\r
+  @param[in]  Packet            The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
+  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.\r
+  @param[out] CmdDescHost       A pointer to store the base system memory address of the allocated range.\r
+  @param[out] CmdDescMapping    A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The creation succeed.\r
+  @retval EFI_DEVICE_ERROR      The creation failed.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsCreateScsiCommandDesc (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA                  *Private,\r
+  IN     UINT8                                       Lun,\r
+  IN     EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet,\r
+  IN     UTP_TRD                                     *Trd,\r
+     OUT VOID                                        **CmdDescHost,\r
+     OUT VOID                                        **CmdDescMapping\r
+  )\r
+{\r
+  UINTN                             TotalLen;\r
+  UINTN                             PrdtNumber;\r
+  UTP_COMMAND_UPIU                  *CommandUpiu;\r
+  EFI_PHYSICAL_ADDRESS              CmdDescPhyAddr;\r
+  EFI_STATUS                        Status;\r
+  UINT32                            DataLen;\r
+  UFS_DATA_DIRECTION                DataDirection;\r
+\r
+  ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
+\r
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+    DataLen       = Packet->InTransferLength;\r
+    DataDirection = UfsDataIn;\r
+  } else {\r
+    DataLen       = Packet->OutTransferLength;\r
+    DataDirection = UfsDataOut;\r
+  }\r
+\r
+  if (DataLen == 0) {\r
+    DataDirection = UfsNoData;\r
+  }\r
+\r
+  PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
+\r
+  TotalLen   = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);\r
+\r
+  Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;\r
+\r
+  UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);\r
+\r
+  //\r
+  // Fill UTP_TRD associated fields\r
+  // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table\r
+  // *MUST* be located at a 64-bit aligned boundary.\r
+  //\r
+  Trd->Int    = UFS_INTERRUPT_COMMAND;\r
+  Trd->Dd     = DataDirection;\r
+  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;\r
+  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
+  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
+  Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));\r
+  Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));\r
+  Trd->PrdtL  = (UINT16)PrdtNumber;\r
+  Trd->PrdtO  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  Packet            The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.\r
+  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.\r
+  @param[out] CmdDescHost       A pointer to store the base system memory address of the allocated range.\r
+  @param[out] CmdDescMapping    A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The creation succeed.\r
+  @retval EFI_DEVICE_ERROR      The creation failed.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.\r
+  @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsCreateDMCommandDesc (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA            *Private,\r
+  IN     UFS_DEVICE_MANAGEMENT_REQUEST_PACKET  *Packet,\r
+  IN     UTP_TRD                               *Trd,\r
+     OUT VOID                                  **CmdDescHost,\r
+     OUT VOID                                  **CmdDescMapping\r
+  )\r
+{\r
+  UINTN                         TotalLen;\r
+  UTP_QUERY_REQ_UPIU            *QueryReqUpiu;\r
+  UINT8                         Opcode;\r
+  UINT32                        DataSize;\r
+  UINT8                         *Data;\r
+  UINT8                         DataDirection;\r
+  EFI_PHYSICAL_ADDRESS          CmdDescPhyAddr;\r
+  EFI_STATUS                    Status;\r
+\r
+  ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
+\r
+  Opcode = Packet->Opcode;\r
+  if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DataDirection = Packet->DataDirection;\r
+  if (DataDirection == UfsDataIn) {\r
+    DataSize = Packet->InTransferLength;\r
+    Data     = Packet->InDataBuffer;\r
+  } else if (DataDirection == UfsDataOut) {\r
+    DataSize = Packet->OutTransferLength;\r
+    Data     = Packet->OutDataBuffer;\r
+  } else {\r
+    DataSize = 0;\r
+    Data     = NULL;\r
+  }\r
+\r
+  if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))\r
+    && ((DataSize == 0) || (Data == NULL))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))\r
+    && ((DataSize != 0) || (Data != NULL))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {\r
+    TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);\r
+  } else {\r
+    TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));\r
+  }\r
+\r
+  Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Initialize UTP QUERY REQUEST UPIU\r
+  //\r
+  QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;\r
+  ASSERT (QueryReqUpiu != NULL);\r
+  UfsInitQueryRequestUpiu (\r
+    QueryReqUpiu,\r
+    Private->TaskTag++,\r
+    Opcode,\r
+    Packet->DescId,\r
+    Packet->Index,\r
+    Packet->Selector,\r
+    DataSize,\r
+    Data\r
+    );\r
+\r
+  //\r
+  // Fill UTP_TRD associated fields\r
+  // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.\r
+  //\r
+  Trd->Int    = UFS_INTERRUPT_COMMAND;\r
+  Trd->Dd     = DataDirection;\r
+  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;\r
+  Trd->Ocs    = 0x0F;\r
+  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
+  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
+  if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
+    Trd->RuL  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));\r
+    Trd->RuO  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
+  } else {\r
+    Trd->RuL  = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize)), sizeof (UINT32));\r
+    Trd->RuO  = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  Trd               The pointer to the UTP Transfer Request Descriptor.\r
+  @param[out] CmdDescHost       A pointer to store the base system memory address of the allocated range.\r
+  @param[out] CmdDescMapping    A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The creation succeed.\r
+  @retval EFI_DEVICE_ERROR      The creation failed.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory resource is insufficient.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsCreateNopCommandDesc (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA        *Private,\r
+  IN     UTP_TRD                           *Trd,\r
+     OUT VOID                              **CmdDescHost,\r
+     OUT VOID                              **CmdDescMapping\r
+  )\r
+{\r
+  UINTN                    TotalLen;\r
+  UTP_NOP_OUT_UPIU         *NopOutUpiu;\r
+  EFI_STATUS               Status;\r
+  EFI_PHYSICAL_ADDRESS     CmdDescPhyAddr;\r
+\r
+  ASSERT ((Private != NULL) && (Trd != NULL));\r
+\r
+  TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));\r
+  Status   = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;\r
+  ASSERT (NopOutUpiu != NULL);\r
+  NopOutUpiu->TaskTag = Private->TaskTag++;\r
+\r
+  //\r
+  // Fill UTP_TRD associated fields\r
+  // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.\r
+  //\r
+  Trd->Int    = UFS_INTERRUPT_COMMAND;\r
+  Trd->Dd     = 0x00;\r
+  Trd->Ct     = UFS_STORAGE_COMMAND_TYPE;\r
+  Trd->UcdBa  = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
+  Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
+  Trd->RuL    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));\r
+  Trd->RuO    = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find out available slot in transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[out] Slot          The available slot.\r
+\r
+  @retval EFI_SUCCESS       The available slot was found successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsFindAvailableSlotInTrl (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+     OUT UINT8                        *Slot\r
+  )\r
+{\r
+  ASSERT ((Private != NULL) && (Slot != NULL));\r
+\r
+  //\r
+  // The simplest algo to always use slot 0.\r
+  // TODO: enhance it to support async transfer with multiple slot.\r
+  //\r
+  *Slot = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find out available slot in task management transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[out] Slot          The available slot.\r
+\r
+  @retval EFI_SUCCESS       The available slot was found successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsFindAvailableSlotInTmrl (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+     OUT UINT8                        *Slot\r
+  )\r
+{\r
+  ASSERT ((Private != NULL) && (Slot != NULL));\r
+\r
+  //\r
+  // The simplest algo to always use slot 0.\r
+  // TODO: enhance it to support async transfer with multiple slot.\r
+  //\r
+  *Slot = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Start specified slot in transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  Slot          The slot to be started.\r
+\r
+**/\r
+VOID\r
+UfsStartExecCmd (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN  UINT8                        Slot\r
+  ) \r
+{\r
+  UINTN         UfsHcBase;\r
+  UINTN         Address;\r
+  UINT32        Data;\r
+\r
+  UfsHcBase = Private->UfsHcBase;\r
+\r
+  Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
+    MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
+  }\r
+\r
+  Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
+  MmioWrite32 (Address, BIT0 << Slot);\r
+}\r
+\r
+/**\r
+  Stop specified slot in transfer list of a UFS device.\r
+\r
+  @param[in]  Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  Slot          The slot to be stop.\r
+\r
+**/\r
+VOID\r
+UfsStopExecCmd (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN  UINT8                        Slot\r
+  ) \r
+{\r
+  UINTN         UfsHcBase;\r
+  UINTN         Address;\r
+  UINT32        Data;\r
+\r
+  UfsHcBase = Private->UfsHcBase;\r
+\r
+  Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & (BIT0 << Slot)) != 0) {\r
+    Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;  \r
+    Data    = MmioRead32 (Address);\r
+    MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));\r
+  }\r
+}\r
+\r
+/**\r
+  Read or write specified device descriptor of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      DescId        The ID of device descriptor.\r
+  @param[in]      Index         The Index of device descriptor.\r
+  @param[in]      Selector      The Selector of device descriptor.\r
+  @param[in, out] Descriptor    The buffer of device descriptor to be read or written.\r
+  @param[in]      DescSize      The size of device descriptor buffer.\r
+\r
+  @retval EFI_SUCCESS           The device descriptor was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the device descriptor.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the device descriptor.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwDeviceDesc (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        DescId,\r
+  IN     UINT8                        Index,\r
+  IN     UINT8                        Selector,\r
+  IN OUT VOID                         *Descriptor,\r
+  IN     UINT32                       DescSize\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UTP_QUERY_RESP_UPIU                  *QueryResp;\r
+  UINT32                               CmdDescSize;\r
+  UINT16                               ReturnDataSize;\r
+  VOID                                 *CmdDescHost;\r
+  VOID                                 *CmdDescMapping;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+\r
+  if (Read) {\r
+    Packet.DataDirection     = UfsDataIn;\r
+    Packet.InDataBuffer      = Descriptor;\r
+    Packet.InTransferLength  = DescSize;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeRdDesc;\r
+  } else {\r
+    Packet.DataDirection     = UfsDataOut;\r
+    Packet.OutDataBuffer     = Descriptor;\r
+    Packet.OutTransferLength = DescSize;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeWrDesc;\r
+  }\r
+  Packet.DescId              = DescId;\r
+  Packet.Index               = Index;\r
+  Packet.Selector            = Selector;\r
+  Packet.Timeout             = UFS_TIMEOUT;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  UfsHc       = Private->UfsHostController;\r
+  QueryResp   = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
+  ASSERT (QueryResp != NULL);\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (QueryResp->QueryResp != 0) {\r
+    DumpQueryResponseResult (QueryResp->QueryResp);\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    ReturnDataSize = QueryResp->Tsf.Length;\r
+    SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
+\r
+    if (Read) {\r
+      CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);\r
+      Packet.InTransferLength = ReturnDataSize;\r
+    } else {\r
+      Packet.OutTransferLength = ReturnDataSize;\r
+    }\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsHc->Flush (UfsHc);\r
+\r
+  UfsStopExecCmd (Private, Slot);\r
+\r
+  if (CmdDescMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, CmdDescMapping);\r
+  }\r
+  if (CmdDescHost != NULL) {\r
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read or write specified attribute of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      AttrId        The ID of Attribute.\r
+  @param[in]      Index         The Index of Attribute.\r
+  @param[in]      Selector      The Selector of Attribute.\r
+  @param[in, out] Attributes    The value of Attribute to be read or written.\r
+\r
+  @retval EFI_SUCCESS           The Attribute was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the Attribute.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the Attribute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwAttributes (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        AttrId,\r
+  IN     UINT8                        Index,\r
+  IN     UINT8                        Selector,\r
+  IN OUT UINT32                       *Attributes\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UTP_QUERY_RESP_UPIU                  *QueryResp;\r
+  UINT32                               CmdDescSize;\r
+  UINT32                               ReturnData;\r
+  VOID                                 *CmdDescHost;\r
+  VOID                                 *CmdDescMapping;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+\r
+  if (Read) {\r
+    Packet.DataDirection     = UfsDataIn;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeRdAttr;\r
+  } else {\r
+    Packet.DataDirection     = UfsDataOut;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeWrAttr;\r
+  }\r
+  Packet.DescId              = AttrId;\r
+  Packet.Index               = Index;\r
+  Packet.Selector            = Selector;\r
+  Packet.Timeout             = UFS_TIMEOUT;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  UfsHc       = Private->UfsHostController;\r
+  QueryResp   = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
+  ASSERT (QueryResp != NULL);\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (QueryResp->QueryResp != 0) {\r
+    DumpQueryResponseResult (QueryResp->QueryResp);\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    ReturnData = QueryResp->Tsf.Value;\r
+    SwapLittleEndianToBigEndian ((UINT8*)&ReturnData, sizeof (UINT32));\r
+    *Attributes = ReturnData;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsHc->Flush (UfsHc);\r
+\r
+  UfsStopExecCmd (Private, Slot);\r
+\r
+  if (CmdDescMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, CmdDescMapping);\r
+  }\r
+\r
+  if (CmdDescHost != NULL) {\r
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read or write specified flag of a UFS device.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]      Read          The boolean variable to show r/w direction.\r
+  @param[in]      FlagId        The ID of flag to be read or written.\r
+  @param[in, out] Value         The value to set or clear flag.\r
+\r
+  @retval EFI_SUCCESS           The flag was read/written successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwFlags (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN     BOOLEAN                      Read,\r
+  IN     UINT8                        FlagId,\r
+  IN OUT UINT8                        *Value\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UTP_QUERY_RESP_UPIU                  *QueryResp;\r
+  UINT32                               CmdDescSize;\r
+  VOID                                 *CmdDescHost;\r
+  VOID                                 *CmdDescMapping;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
+\r
+  if (Value == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+\r
+  if (Read) {\r
+    ASSERT (Value != NULL);\r
+    Packet.DataDirection     = UfsDataIn;\r
+    Packet.Opcode            = UtpQueryFuncOpcodeRdFlag;\r
+  } else {\r
+    Packet.DataDirection     = UfsDataOut;\r
+    if (*Value == 1) {\r
+      Packet.Opcode          = UtpQueryFuncOpcodeSetFlag;\r
+    } else if (*Value == 0) {\r
+      Packet.Opcode          = UtpQueryFuncOpcodeClrFlag;\r
+    } else {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  Packet.DescId              = FlagId;\r
+  Packet.Index               = 0;\r
+  Packet.Selector            = 0;\r
+  Packet.Timeout             = UFS_TIMEOUT;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  Status = UfsCreateDMCommandDesc (Private, &Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  UfsHc       = Private->UfsHostController;\r
+  QueryResp   = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
+  ASSERT (QueryResp != NULL);\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet.Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (QueryResp->QueryResp != 0) {\r
+    DumpQueryResponseResult (QueryResp->QueryResp);\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    *Value = (UINT8)QueryResp->Tsf.Value;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsHc->Flush (UfsHc);\r
+\r
+  UfsStopExecCmd (Private, Slot);\r
+\r
+  if (CmdDescMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, CmdDescMapping);\r
+  }\r
+  if (CmdDescHost != NULL) {\r
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set specified flag to 1 on a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be set.\r
+\r
+  @retval EFI_SUCCESS           The flag was set successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to set the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of setting the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsSetFlag (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN  UINT8                        FlagId\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINT8                  Value;\r
+\r
+  Value  = 1;\r
+  Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Clear specified flag to 0 on a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be cleared.\r
+\r
+  @retval EFI_SUCCESS           The flag was cleared successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to clear the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of clearing the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsClearFlag (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN  UINT8                        FlagId\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINT8                  Value;\r
+\r
+  Value  = 0;\r
+  Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read specified flag from a UFS device.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  FlagId            The ID of flag to be read.\r
+  @param[out] Value             The flag's value.\r
+\r
+  @retval EFI_SUCCESS           The flag was read successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to read the flag.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of reading the flag.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsReadFlag (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA   *Private,\r
+  IN     UINT8                        FlagId,\r
+     OUT UINT8                        *Value\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+\r
+  Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends NOP IN cmd to a UFS device for initialization process request.\r
+  For more details, please refer to UFS 2.0 spec Figure 13.3.\r
+\r
+  @param[in]  Private           The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS           The NOP IN command was sent by the host. The NOP OUT response was\r
+                                received successfully.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to execute NOP IN command.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the NOP IN command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecNopCmds (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA       *Private\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UTP_NOP_IN_UPIU                      *NopInUpiu;\r
+  UINT32                               CmdDescSize;\r
+  UINTN                                Address;\r
+  VOID                                 *CmdDescHost;\r
+  VOID                                 *CmdDescMapping;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
+\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Trd    = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+  Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  UfsHc       = Private->UfsHostController;\r
+  NopInUpiu   = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
+  ASSERT (NopInUpiu != NULL);\r
+  CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (NopInUpiu->Resp != 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Exit:\r
+  UfsHc->Flush (UfsHc);\r
+\r
+  UfsStopExecCmd (Private, Slot);\r
+\r
+  if (CmdDescMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, CmdDescMapping);\r
+  }\r
+  if (CmdDescHost != NULL) {\r
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
+\r
+  @param[in]      Private       The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]      Lun           The LUN of the UFS device to send the SCSI Request Packet.\r
+  @param[in, out] Packet        A pointer to the SCSI Request Packet to send to a specified Lun of the\r
+                                UFS device.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecScsiCmds (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA                  *Private,\r
+  IN     UINT8                                       Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UINT8                                Slot;\r
+  UTP_TRD                              *Trd;\r
+  UINTN                                Address;\r
+  UINT32                               CmdDescSize;\r
+  UTP_RESPONSE_UPIU                    *Response;\r
+  UINT16                               SenseDataLen;\r
+  UINT32                               ResTranCount;\r
+  VOID                                 *CmdDescHost;\r
+  VOID                                 *CmdDescMapping;\r
+  VOID                                 *DataBufMapping;\r
+  VOID                                 *DataBuf;\r
+  EFI_PHYSICAL_ADDRESS                 DataBufPhyAddr;\r
+  UINT32                               DataLen;\r
+  UINTN                                MapLength;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
+  EDKII_UFS_HOST_CONTROLLER_OPERATION  Flag;\r
+  UFS_DATA_DIRECTION                   DataDirection;\r
+  UTP_TR_PRD                           *PrdtBase;\r
+\r
+  Trd            = NULL;\r
+  CmdDescHost    = NULL;\r
+  CmdDescMapping = NULL;\r
+  DataBufMapping = NULL;\r
+  DataBufPhyAddr = 0;\r
+  UfsHc          = Private->UfsHostController;\r
+  //\r
+  // Find out which slot of transfer request list is available.\r
+  //\r
+  Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
+\r
+  //\r
+  // Fill transfer request descriptor to this slot.\r
+  //\r
+  Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);\r
+\r
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+    DataBuf       = Packet->InDataBuffer;\r
+    DataLen       = Packet->InTransferLength;\r
+    DataDirection = UfsDataIn;\r
+    Flag          = EdkiiUfsHcOperationBusMasterWrite;\r
+  } else {\r
+    DataBuf       = Packet->OutDataBuffer;\r
+    DataLen       = Packet->OutTransferLength;\r
+    DataDirection = UfsDataOut;\r
+    Flag          = EdkiiUfsHcOperationBusMasterRead;\r
+  }\r
+\r
+  if (DataLen == 0) {\r
+    DataDirection = UfsNoData;\r
+  } else {\r
+    MapLength = DataLen;\r
+    Status    = UfsHc->Map (\r
+                         UfsHc,\r
+                         Flag,\r
+                         DataBuf,\r
+                         &MapLength,\r
+                         &DataBufPhyAddr,\r
+                         &DataBufMapping\r
+                         );\r
+\r
+    if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
+      goto Exit1;\r
+    }\r
+  }\r
+  //\r
+  // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
+  //\r
+  PrdtBase = (UTP_TR_PRD*)((UINT8*)CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
+  ASSERT (PrdtBase != NULL);\r
+  UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);\r
+\r
+  //\r
+  // Start to execute the transfer request.\r
+  //\r
+  UfsStartExecCmd (Private, Slot);\r
+\r
+  //\r
+  // Wait for the completion of the transfer request.\r
+  //  \r
+  Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;  \r
+  Status = UfsWaitMemSet (Address, BIT0, 0, Packet->Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Get sense data if exists\r
+  //\r
+  Response     = (UTP_RESPONSE_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
+  ASSERT (Response != NULL);\r
+  SenseDataLen = Response->SenseDataLen;\r
+  SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
+  \r
+  if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
+    CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
+    Packet->SenseDataLength = (UINT8)SenseDataLen;\r
+  }\r
+\r
+  //\r
+  // Check the transfer request result.\r
+  //\r
+  Packet->TargetStatus = Response->Status;\r
+  if (Response->Response != 0) {\r
+    DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  if (Trd->Ocs == 0) {\r
+    if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+      if ((Response->Flags & BIT5) == BIT5) {\r
+        ResTranCount = Response->ResTranCount;\r
+        SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
+        Packet->InTransferLength -= ResTranCount;\r
+      }\r
+    } else {\r
+      if ((Response->Flags & BIT5) == BIT5) {\r
+        ResTranCount = Response->ResTranCount;\r
+        SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
+        Packet->OutTransferLength -= ResTranCount;\r
+      }\r
+    }\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Exit:\r
+  UfsHc->Flush (UfsHc);\r
+\r
+  UfsStopExecCmd (Private, Slot);\r
+\r
+  if (DataBufMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, DataBufMapping);\r
+  }\r
+\r
+Exit1:\r
+  if (CmdDescMapping != NULL) {\r
+    UfsHc->Unmap (UfsHc, CmdDescMapping);\r
+  }\r
+  if (CmdDescHost != NULL) {\r
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
+\r
+  @param[in] Private          The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in] UicOpcode        The opcode of the UIC command.\r
+  @param[in] Arg1             The value for 1st argument of the UIC command.\r
+  @param[in] Arg2             The value for 2nd argument of the UIC command.\r
+  @param[in] Arg3             The value for 3rd argument of the UIC command.\r
+\r
+  @return EFI_SUCCESS      Successfully execute this UIC command and detect attached UFS device.\r
+  @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
+  @return EFI_NOT_FOUND    The presence of the UFS device isn't detected.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsExecUicCommands (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA    *Private,\r
+  IN  UINT8                         UicOpcode,\r
+  IN  UINT32                        Arg1,\r
+  IN  UINT32                        Arg2,\r
+  IN  UINT32                        Arg3\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Address;\r
+  UINT32      Data;\r
+  UINTN       UfsHcBase;\r
+\r
+  UfsHcBase = Private->UfsHcBase;\r
+  Address   = UfsHcBase + UFS_HC_IS_OFFSET;\r
+  Data      = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
+    //\r
+    // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
+    //\r
+    MmioWrite32 (Address, Data);\r
+  }\r
+\r
+  //\r
+  // When programming UIC command registers, host software shall set the register UICCMD\r
+  // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
+  // are set.\r
+  //\r
+  Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;\r
+  MmioWrite32 (Address, Arg1);\r
+\r
+  Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
+  MmioWrite32 (Address, Arg2);\r
+\r
+  Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;\r
+  MmioWrite32 (Address, Arg3);\r
+\r
+  //\r
+  // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;\r
+  Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;\r
+  MmioWrite32 (Address, (UINT32)UicOpcode);\r
+\r
+  //\r
+  // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
+  // This bit is set to '1' by the host controller upon completion of a UIC command. \r
+  //\r
+  Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
+  Data    = MmioRead32 (Address);\r
+  Status  = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (UicOpcode != UfsUicDmeReset) {\r
+    Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;\r
+    Data    = MmioRead32 (Address);\r
+    if ((Data & 0xFF) != 0) {\r
+      DEBUG_CODE_BEGIN();\r
+        DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
+      DEBUG_CODE_END();\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
+  //\r
+  Address = UfsHcBase + UFS_HC_STATUS_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_HCS_DP) == 0) {\r
+    Address = UfsHcBase + UFS_HC_IS_OFFSET;\r
+    Status  = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "UfsPassThruDxe: found a attached UFS device\n"));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate common buffer for host and UFS bus master access simultaneously.\r
+\r
+  @param[in]  Private                The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in]  Size                   The length of buffer to be allocated.\r
+  @param[out] CmdDescHost            A pointer to store the base system memory address of the allocated range.\r
+  @param[out] CmdDescPhyAddr         The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.\r
+  @param[out] CmdDescMapping         A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS                The common buffer was allocated successfully.\r
+  @retval EFI_DEVICE_ERROR           The allocation fails.\r
+  @retval EFI_OUT_OF_RESOURCES       The memory resource is insufficient.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsAllocateAlignCommonBuffer (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA    *Private,\r
+  IN     UINTN                         Size,\r
+     OUT VOID                          **CmdDescHost,\r
+     OUT EFI_PHYSICAL_ADDRESS          *CmdDescPhyAddr,\r
+     OUT VOID                          **CmdDescMapping\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UINTN                                Bytes;\r
+  BOOLEAN                              Is32BitAddr;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
+\r
+  if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
+    Is32BitAddr = TRUE;\r
+  } else {\r
+    Is32BitAddr = FALSE;\r
+  }\r
+\r
+  UfsHc  = Private->UfsHostController;\r
+  Status = UfsHc->AllocateBuffer (\r
+                    UfsHc,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    EFI_SIZE_TO_PAGES (Size),\r
+                    CmdDescHost,\r
+                    0\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    *CmdDescMapping = NULL;\r
+    *CmdDescHost    = NULL;\r
+    *CmdDescPhyAddr = 0;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Bytes  = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));\r
+  Status = UfsHc->Map (\r
+                    UfsHc,\r
+                    EdkiiUfsHcOperationBusMasterCommonBuffer,\r
+                    *CmdDescHost,\r
+                    &Bytes,\r
+                    CmdDescPhyAddr,\r
+                    CmdDescMapping\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {\r
+    UfsHc->FreeBuffer (\r
+             UfsHc,\r
+             EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
+             *CmdDescHost\r
+             );\r
+    *CmdDescHost = NULL;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {\r
+    //\r
+    // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.\r
+    //\r
+    UfsHc->Unmap (\r
+             UfsHc,\r
+             *CmdDescMapping\r
+             );\r
+    UfsHc->FreeBuffer (\r
+             UfsHc,\r
+             EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
+             *CmdDescHost\r
+             );\r
+    *CmdDescMapping = NULL;\r
+    *CmdDescHost    = NULL;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable the UFS host controller for accessing.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS host controller enabling was executed successfully.\r
+  @retval EFI_DEVICE_ERROR           A device error occurred while enabling the UFS host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsEnableHostController (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+\r
+  //\r
+  // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
+  //\r
+  // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
+  Data    = MmioRead32 (Address);\r
+  if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
+    //\r
+    // Write a 0 to the HCE register at first to disable the host controller.\r
+    //\r
+    MmioWrite32 (Address, 0);\r
+    //\r
+    // Wait until HCE is read as '0' before continuing.\r
+    //\r
+    Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Write a 1 to the HCE register to enable the UFS host controller.\r
+  //\r
+  MmioWrite32 (Address, UFS_HC_HCE_EN);\r
+  //\r
+  // Wait until HCE is read as '1' before continuing.\r
+  //\r
+  Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Detect if a UFS device attached.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS device detection was executed successfully.\r
+  @retval EFI_NOT_FOUND              Not found a UFS device attached.\r
+  @retval EFI_DEVICE_ERROR           A device error occurred while detecting the UFS device.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsDeviceDetection (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  )\r
+{\r
+  UINTN                  Retry;\r
+  EFI_STATUS             Status;\r
+\r
+  //\r
+  // Start UFS device detection.\r
+  // Try up to 3 times for establishing data link with device.\r
+  //\r
+  for (Retry = 0; Retry < 3; Retry++) {\r
+    Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (Status == EFI_NOT_FOUND) {\r
+      continue;\r
+    }\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (Retry == 3) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UFS task management request list related h/w context.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS task management list was initialzed successfully.\r
+  @retval EFI_DEVICE_ERROR           The initialization fails.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitTaskManagementRequestList (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  )\r
+{\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+  UINT8                  Nutmrs;\r
+  VOID                   *CmdDescHost;\r
+  EFI_PHYSICAL_ADDRESS   CmdDescPhyAddr;\r
+  VOID                   *CmdDescMapping;\r
+  EFI_STATUS             Status;\r
+  \r
+  //\r
+  // Initial h/w and s/w context for future operations.\r
+  //\r
+  CmdDescHost    = NULL;\r
+  CmdDescMapping = NULL;\r
+  CmdDescPhyAddr = 0;\r
+  Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  Private->Capabilities = Data;\r
+\r
+  //\r
+  // Allocate and initialize UTP Task Management Request List.\r
+  //\r
+  Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
+  Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Program the UTP Task Management Request List Base Address and UTP Task Management\r
+  // Request List Base Address with a 64-bit address allocated at step 6.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
+  Private->UtpTmrlBase = CmdDescHost;\r
+  Private->Nutmrs      = Nutmrs;\r
+  Private->TmrlMapping = CmdDescMapping;\r
+\r
+  //\r
+  // Enable the UTP Task Management Request List by setting the UTP Task Management\r
+  // Request List RunStop Register (UTMRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, UFS_HC_UTMRLRSR);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UFS transfer request list related h/w context.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The UFS transfer list was initialzed successfully.\r
+  @retval EFI_DEVICE_ERROR           The initialization fails.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsInitTransferRequestList (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  )\r
+{\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+  UINT8                  Nutrs;\r
+  VOID                   *CmdDescHost;\r
+  EFI_PHYSICAL_ADDRESS   CmdDescPhyAddr;\r
+  VOID                   *CmdDescMapping;  \r
+  EFI_STATUS             Status;\r
+\r
+  //\r
+  // Initial h/w and s/w context for future operations.\r
+  //\r
+  CmdDescHost    = NULL;\r
+  CmdDescMapping = NULL;\r
+  CmdDescPhyAddr = 0;\r
+  Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;  \r
+  Data    = MmioRead32 (Address);\r
+  Private->Capabilities = Data;\r
+\r
+  //\r
+  // Allocate and initialize UTP Transfer Request List.\r
+  //\r
+  Nutrs  = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
+  Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
+  // Base Address with a 64-bit address allocated at step 8.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;  \r
+  MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
+  Private->UtpTrlBase = CmdDescHost;\r
+  Private->Nutrs      = Nutrs;  \r
+  Private->TrlMapping = CmdDescMapping;\r
+\r
+  //\r
+  // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
+  // RunStop Register (UTRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, UFS_HC_UTRLRSR);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The Ufs Host Controller is initialized successfully.\r
+  @retval Others                     A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerInit (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+\r
+  Status = UfsEnableHostController (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = UfsDeviceDetection (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = UfsInitTaskManagementRequestList (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = UfsInitTransferRequestList (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "UfsControllerInit Finished\n"));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Stop the UFS host controller.\r
+\r
+  @param[in] Private                 The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+\r
+  @retval EFI_SUCCESS                The Ufs Host Controller is stopped successfully.\r
+  @retval Others                     A device error occurred while stopping the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsControllerStop (\r
+  IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  UINTN                  Address;\r
+  UINT32                 Data;\r
+\r
+  //\r
+  // Enable the UTP Task Management Request List by setting the UTP Task Management\r
+  // Request List RunStop Register (UTMRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, 0);\r
+\r
+  //\r
+  // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
+  // RunStop Register (UTRLRSR) to '1'.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;  \r
+  MmioWrite32 (Address, 0);\r
+\r
+  //\r
+  // Write a 0 to the HCE register in order to disable the host controller.\r
+  //\r
+  Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;\r
+  Data    = MmioRead32 (Address);\r
+  ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
+  MmioWrite32 (Address, 0);\r
+\r
+  //\r
+  // Wait until HCE is read as '0' before continuing.\r
+  //\r
+  Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "UfsController is stopped\n"));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.h b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.h
new file mode 100644 (file)
index 0000000..a423a92
--- /dev/null
@@ -0,0 +1,1339 @@
+/** @file\r
+  UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface\r
+  for upper layer application to execute UFS-supported SCSI cmds.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _UFS_PASS_THRU_HCI_H_\r
+#define _UFS_PASS_THRU_HCI_H_\r
+\r
+//\r
+// Host Capabilities Register Offsets\r
+//\r
+#define UFS_HC_CAP_OFFSET          0x0000  // Controller Capabilities\r
+#define UFS_HC_VER_OFFSET          0x0008  // Version\r
+#define UFS_HC_DDID_OFFSET         0x0010  // Device ID and Device Class\r
+#define UFS_HC_PMID_OFFSET         0x0014  // Product ID and Manufacturer ID\r
+#define UFS_HC_AHIT_OFFSET         0x0018  // Auto-Hibernate Idle Timer\r
+//\r
+// Operation and Runtime Register Offsets\r
+//\r
+#define UFS_HC_IS_OFFSET           0x0020  // Interrupt Status\r
+#define UFS_HC_IE_OFFSET           0x0024  // Interrupt Enable\r
+#define UFS_HC_STATUS_OFFSET       0x0030  // Host Controller Status\r
+#define UFS_HC_ENABLE_OFFSET       0x0034  // Host Controller Enable\r
+#define UFS_HC_UECPA_OFFSET        0x0038  // Host UIC Error Code PHY Adapter Layer\r
+#define UFS_HC_UECDL_OFFSET        0x003c  // Host UIC Error Code Data Link Layer\r
+#define UFS_HC_UECN_OFFSET         0x0040  // Host UIC Error Code Network Layer\r
+#define UFS_HC_UECT_OFFSET         0x0044  // Host UIC Error Code Transport Layer\r
+#define UFS_HC_UECDME_OFFSET       0x0048  // Host UIC Error Code DME\r
+#define UFS_HC_UTRIACR_OFFSET      0x004c  // UTP Transfer Request Interrupt Aggregation Control Register\r
+//\r
+// UTP Transfer Register Offsets\r
+//\r
+#define UFS_HC_UTRLBA_OFFSET       0x0050  // UTP Transfer Request List Base Address\r
+#define UFS_HC_UTRLBAU_OFFSET      0x0054  // UTP Transfer Request List Base Address Upper 32-Bits\r
+#define UFS_HC_UTRLDBR_OFFSET      0x0058  // UTP Transfer Request List Door Bell Register\r
+#define UFS_HC_UTRLCLR_OFFSET      0x005c  // UTP Transfer Request List CLear Register\r
+#define UFS_HC_UTRLRSR_OFFSET      0x0060  // UTP Transfer Request Run-Stop Register\r
+//\r
+// UTP Task Management Register Offsets\r
+//\r
+#define UFS_HC_UTMRLBA_OFFSET      0x0070  // UTP Task Management Request List Base Address\r
+#define UFS_HC_UTMRLBAU_OFFSET     0x0074  // UTP Task Management Request List Base Address Upper 32-Bits\r
+#define UFS_HC_UTMRLDBR_OFFSET     0x0078  // UTP Task Management Request List Door Bell Register\r
+#define UFS_HC_UTMRLCLR_OFFSET     0x007c  // UTP Task Management Request List CLear Register\r
+#define UFS_HC_UTMRLRSR_OFFSET     0x0080  // UTP Task Management Run-Stop Register\r
+//\r
+// UIC Command Register Offsets\r
+//\r
+#define UFS_HC_UIC_CMD_OFFSET      0x0090  // UIC Command Register\r
+#define UFS_HC_UCMD_ARG1_OFFSET    0x0094  // UIC Command Argument 1\r
+#define UFS_HC_UCMD_ARG2_OFFSET    0x0098  // UIC Command Argument 2\r
+#define UFS_HC_UCMD_ARG3_OFFSET    0x009c  // UIC Command Argument 3\r
+//\r
+// UMA Register Offsets\r
+//\r
+#define UFS_HC_UMA_OFFSET          0x00b0  // Reserved for Unified Memory Extension\r
+\r
+#define UFS_HC_HCE_EN              BIT0\r
+#define UFS_HC_HCS_DP              BIT0\r
+#define UFS_HC_HCS_UCRDY           BIT3\r
+#define UFS_HC_IS_ULSS             BIT8\r
+#define UFS_HC_IS_UCCS             BIT10\r
+#define UFS_HC_CAP_64ADDR          BIT24\r
+#define UFS_HC_CAP_NUTMRS          (BIT16 | BIT17 | BIT18)\r
+#define UFS_HC_CAP_NUTRS           (BIT0 | BIT1 | BIT2 | BIT3 | BIT4)\r
+#define UFS_HC_UTMRLRSR            BIT0\r
+#define UFS_HC_UTRLRSR             BIT0\r
+\r
+//\r
+// A maximum of length of 256KB is supported by PRDT entry\r
+//\r
+#define UFS_MAX_DATA_LEN_PER_PRD   0x40000\r
+\r
+#define UFS_STORAGE_COMMAND_TYPE   0x01\r
+\r
+#define UFS_REGULAR_COMMAND        0x00\r
+#define UFS_INTERRUPT_COMMAND      0x01\r
+\r
+#define UFS_LUN_0                  0x00\r
+#define UFS_LUN_1                  0x01\r
+#define UFS_LUN_2                  0x02\r
+#define UFS_LUN_3                  0x03\r
+#define UFS_LUN_4                  0x04\r
+#define UFS_LUN_5                  0x05\r
+#define UFS_LUN_6                  0x06\r
+#define UFS_LUN_7                  0x07\r
+#define UFS_WLUN_REPORT_LUNS       0x81\r
+#define UFS_WLUN_UFS_DEV           0xD0\r
+#define UFS_WLUN_BOOT              0xB0\r
+#define UFS_WLUN_RPMB              0xC4\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.1 Offset 00h: CAP - Controller Capabilities\r
+//\r
+typedef struct {\r
+  UINT8  Nutrs:4;      // Number of UTP Transfer Request Slots\r
+  UINT8  Rsvd1:4;\r
+\r
+  UINT8  NoRtt;        // Number of outstanding READY TO TRANSFER (RTT) requests supported\r
+\r
+  UINT8  Nutmrs:3;     // Number of UTP Task Management Request Slots\r
+  UINT8  Rsvd2:4;\r
+  UINT8  AutoHs:1;     // Auto-Hibernation Support\r
+\r
+  UINT8  As64:1;       // 64-bit addressing supported\r
+  UINT8  Oodds:1;      // Out of order data delivery supported\r
+  UINT8  UicDmetms:1;  // UIC DME_TEST_MODE command supported\r
+  UINT8  Ume:1;        // Reserved for Unified Memory Extension\r
+  UINT8  Rsvd4:4;\r
+} UFS_HC_CAP;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.2 Offset 08h: VER - UFS Version\r
+//\r
+typedef struct {\r
+  UINT8  Vs:4;         // Version Suffix\r
+  UINT8  Mnr:4;        // Minor version number\r
+\r
+  UINT8  Mjr;          // Major version number\r
+\r
+  UINT16 Rsvd1;\r
+} UFS_HC_VER;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.3 Offset 10h: HCPID - Host Controller Product ID\r
+//\r
+#define UFS_HC_PID     UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.4 Offset 14h: HCMID - Host Controller Manufacturer ID\r
+//\r
+#define UFS_HC_MID     UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.2.5 Offset 18h: AHIT - Auto-Hibernate Idle Timer\r
+//\r
+typedef struct {\r
+  UINT32 Ahitv:10;     // Auto-Hibernate Idle Timer Value \r
+  UINT32 Ts:3;         // Timer scale\r
+  UINT32 Rsvd1:19;\r
+} UFS_HC_AHIT;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.1 Offset 20h: IS - Interrupt Status\r
+//\r
+typedef struct {\r
+  UINT16 Utrcs:1;      // UTP Transfer Request Completion Status\r
+  UINT16 Udepri:1;     // UIC DME_ENDPOINT_RESET Indication\r
+  UINT16 Ue:1;         // UIC Error\r
+  UINT16 Utms:1;       // UIC Test Mode Status \r
+\r
+  UINT16 Upms:1;       // UIC Power Mode Status \r
+  UINT16 Uhxs:1;       // UIC Hibernate Exit Status \r
+  UINT16 Uhes:1;       // UIC Hibernate Enter Status \r
+  UINT16 Ulls:1;       // UIC Link Lost Status \r
+\r
+  UINT16 Ulss:1;       // UIC Link Startup Status \r
+  UINT16 Utmrcs:1;     // UTP Task  Management Request Completion Status \r
+  UINT16 Uccs:1;       // UIC Command Completion Status \r
+  UINT16 Dfes:1;       // Device Fatal Error Status  \r
+\r
+  UINT16 Utpes:1;      // UTP Error Status  \r
+  UINT16 Rsvd1:3;\r
+\r
+  UINT16 Hcfes:1;      // Host Controller Fatal Error Status\r
+  UINT16 Sbfes:1;      // System Bus Fatal Error Status\r
+  UINT16 Rsvd2:14;\r
+} UFS_HC_IS;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.2 Offset 24h: IE - Interrupt Enable\r
+//\r
+typedef struct {\r
+  UINT16 Utrce:1;      // UTP Transfer Request Completion Enable\r
+  UINT16 Udeprie:1;    // UIC DME_ENDPOINT_RESET Enable\r
+  UINT16 Uee:1;        // UIC Error Enable\r
+  UINT16 Utmse:1;      // UIC Test Mode Status Enable\r
+\r
+  UINT16 Upmse:1;      // UIC Power Mode Status Enable \r
+  UINT16 Uhxse:1;      // UIC Hibernate Exit Status Enable\r
+  UINT16 Uhese:1;      // UIC Hibernate Enter Status Enable \r
+  UINT16 Ullse:1;      // UIC Link Lost Status Enable\r
+\r
+  UINT16 Ulsse:1;      // UIC Link Startup Status Enable\r
+  UINT16 Utmrce:1;     // UTP Task  Management Request Completion Enable\r
+  UINT16 Ucce:1;       // UIC Command Completion Enable\r
+  UINT16 Dfee:1;       // Device Fatal Error Enable\r
+\r
+  UINT16 Utpee:1;      // UTP Error Enable\r
+  UINT16 Rsvd1:3;\r
+\r
+  UINT16 Hcfee:1;      // Host Controller Fatal Error Enable\r
+  UINT16 Sbfee:1;      // System Bus Fatal Error Enable\r
+  UINT16 Rsvd2:14;\r
+} UFS_HC_IE;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.3 Offset 30h: HCS - Host Controller Status\r
+//\r
+typedef struct {\r
+  UINT8  Dp:1;         // Device Present\r
+  UINT8  UtrlRdy:1;    // UTP Transfer Request List Ready\r
+  UINT8  UtmrlRdy:1;   // UTP Task Management Request List Ready\r
+  UINT8  UcRdy:1;      // UIC COMMAND Ready\r
+  UINT8  Rsvd1:4;\r
+\r
+  UINT8  Upmcrs:3;     // UIC Power Mode Change Request Status\r
+  UINT8  Rsvd2:1;      // UIC Hibernate Exit Status Enable\r
+  UINT8  Utpec:4;      // UTP Error Code\r
+\r
+  UINT8  TtagUtpE;     // Task Tag of UTP error\r
+  UINT8  TlunUtpE;     // Target LUN of UTP error\r
+} UFS_HC_STATUS;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.4 Offset 34h: HCE - Host Controller Enable\r
+//\r
+typedef struct {\r
+  UINT32 Hce:1;        // Host Controller Enable\r
+  UINT32 Rsvd1:31;\r
+} UFS_HC_ENABLE;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.5 Offset 38h: UECPA - Host UIC Error Code PHY Adapter Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:5;         // UIC PHY Adapter Layer Error Code\r
+  UINT32 Rsvd1:26;\r
+  UINT32 Err:1;        // UIC PHY Adapter Layer Error\r
+} UFS_HC_UECPA;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.6 Offset 3ch: UECDL - Host UIC Error Code Data Link Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:15;        // UIC Data Link Layer Error Code\r
+  UINT32 Rsvd1:16;\r
+  UINT32 Err:1;        // UIC Data Link Layer Error\r
+} UFS_HC_UECDL;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.7 Offset 40h: UECN - Host UIC Error Code Network Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:3;         // UIC Network Layer Error Code\r
+  UINT32 Rsvd1:28;\r
+  UINT32 Err:1;        // UIC Network Layer Error\r
+} UFS_HC_UECN;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.8 Offset 44h: UECT - Host UIC Error Code Transport Layer\r
+//\r
+typedef struct {\r
+  UINT32 Ec:7;         // UIC Transport Layer Error Code\r
+  UINT32 Rsvd1:24;\r
+  UINT32 Err:1;        // UIC Transport Layer Error\r
+} UFS_HC_UECT;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.9 Offset 48h: UECDME - Host UIC Error Code\r
+//\r
+typedef struct {\r
+  UINT32 Ec:1;         // UIC DME Error Code\r
+  UINT32 Rsvd1:30;\r
+  UINT32 Err:1;        // UIC DME Error\r
+} UFS_HC_UECDME;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.3.10 Offset 4Ch: UTRIACR - UTP Transfer Request Interrupt Aggregation Control Register\r
+//\r
+typedef struct {\r
+  UINT8  IaToVal;      // Interrupt aggregation timeout value\r
+\r
+  UINT8  IacTh:5;      // Interrupt aggregation counter threshold\r
+  UINT8  Rsvd1:3;\r
+\r
+  UINT8  Ctr:1;        // Counter and Timer Reset\r
+  UINT8  Rsvd2:3;\r
+  UINT8  Iasb:1;       // Interrupt aggregation status bit\r
+  UINT8  Rsvd3:3;\r
+\r
+  UINT8  IapwEn:1;     // Interrupt aggregation parameter write enable\r
+  UINT8  Rsvd4:6;\r
+  UINT8  IaEn:1;       // Interrupt Aggregation Enable/Disable\r
+} UFS_HC_UTRIACR;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.1 Offset 50h: UTRLBA - UTP Transfer Request List Base Address\r
+//\r
+typedef struct {\r
+  UINT32 Rsvd1:10;\r
+  UINT32 UtrlBa:22;    // UTP Transfer Request List Base Address\r
+} UFS_HC_UTRLBA;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.2 Offset 54h: UTRLBAU - UTP Transfer Request List Base Address Upper 32-bits\r
+//\r
+#define UFS_HC_UTRLBAU UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.3 Offset 58h: UTRLDBR - UTP Transfer Request List Door Bell Register\r
+//\r
+#define UFS_HC_UTRLDBR UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.4 Offset 5Ch: UTRLCLR - UTP Transfer Request List CLear Register\r
+//\r
+#define UFS_HC_UTRLCLR UINT32\r
+\r
+#if 0\r
+//\r
+// UFSHCI 2.0 Spec Section 5.4.5 Offset 60h: UTRLRSR - UTP Transfer Request List Run Stop Register\r
+//\r
+typedef struct {\r
+  UINT32 UtrlRsr:1;    // UTP Transfer Request List Run-Stop Register\r
+  UINT32 Rsvd1:31;\r
+} UFS_HC_UTRLRSR;\r
+#endif\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.1 Offset 70h: UTMRLBA - UTP Task Management Request List Base Address\r
+//\r
+typedef struct {\r
+  UINT32 Rsvd1:10;\r
+  UINT32 UtmrlBa:22;   // UTP Task Management Request List Base Address\r
+} UFS_HC_UTMRLBA;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.2 Offset 74h: UTMRLBAU - UTP Task Management Request List Base Address Upper 32-bits\r
+//\r
+#define UFS_HC_UTMRLBAU UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.3 Offset 78h: UTMRLDBR - UTP Task Management Request List Door Bell Register\r
+//\r
+typedef struct {\r
+  UINT32 UtmrlDbr:8;   // UTP Task Management Request List Door bell Register\r
+  UINT32 Rsvd1:24;\r
+} UFS_HC_UTMRLDBR;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.4 Offset 7Ch: UTMRLCLR - UTP Task Management Request List CLear Register\r
+//\r
+typedef struct {\r
+  UINT32 UtmrlClr:8;   // UTP Task Management List Clear Register\r
+  UINT32 Rsvd1:24;\r
+} UFS_HC_UTMRLCLR;\r
+\r
+#if 0\r
+//\r
+// UFSHCI 2.0 Spec Section 5.5.5 Offset 80h: UTMRLRSR - UTP Task Management Request List Run Stop Register\r
+//\r
+typedef struct {\r
+  UINT32 UtmrlRsr:1;   // UTP Task Management Request List Run-Stop Register\r
+  UINT32 Rsvd1:31;\r
+} UFS_HC_UTMRLRSR;\r
+#endif\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.1 Offset 90h: UICCMD - UIC Command\r
+//\r
+typedef struct {\r
+  UINT32 CmdOp:8;      // Command Opcode\r
+  UINT32 Rsvd1:24;\r
+} UFS_HC_UICCMD;\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 94h: UICCMDARG1 - UIC Command Argument 1\r
+//\r
+#define UFS_HC_UICCMD_ARG1 UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 98h: UICCMDARG2 - UIC Command Argument 2\r
+//\r
+#define UFS_HC_UICCMD_ARG2 UINT32\r
+\r
+//\r
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 9ch: UICCMDARG3 - UIC Command Argument 3\r
+//\r
+#define UFS_HC_UICCMD_ARG3 UINT32\r
+\r
+//\r
+// UIC command opcodes\r
+//\r
+typedef enum {\r
+  UfsUicDmeGet            = 0x01,\r
+  UfsUicDmeSet            = 0x02,\r
+  UfsUicDmePeerGet        = 0x03,\r
+  UfsUicDmePeerSet        = 0x04,\r
+  UfsUicDmePwrOn          = 0x10,\r
+  UfsUicDmePwrOff         = 0x11,\r
+  UfsUicDmeEnable         = 0x12,\r
+  UfsUicDmeReset          = 0x14,\r
+  UfsUicDmeEndpointReset  = 0x15,\r
+  UfsUicDmeLinkStartup    = 0x16,\r
+  UfsUicDmeHibernateEnter = 0x17,\r
+  UfsUicDmeHibernateExit  = 0x18,\r
+  UfsUicDmeTestMode       = 0x1A\r
+} UFS_UIC_OPCODE;\r
+\r
+//\r
+// UTP Transfer Request Descriptor\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT32 Rsvd1:24;\r
+  UINT32 Int:1;               /* Interrupt */\r
+  UINT32 Dd:2;                /* Data Direction */\r
+  UINT32 Rsvd2:1;\r
+  UINT32 Ct:4;                /* Command Type */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT32 Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT32 Ocs:8;               /* Overall Command Status */\r
+  UINT32 Rsvd4:24;\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 Rsvd5;\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 Rsvd6:7;\r
+  UINT32 UcdBa:25;            /* UTP Command Descriptor Base Address */\r
+  \r
+  //\r
+  // DW5\r
+  //\r
+  UINT32 UcdBaU;              /* UTP Command Descriptor Base Address Upper 32-bits */\r
\r
+  //\r
+  // DW6\r
+  //\r
+  UINT16 RuL;                 /* Response UPIU Length */  \r
+  UINT16 RuO;                 /* Response UPIU Offset */\r
+\r
+  //\r
+  // DW7\r
+  //\r
+  UINT16 PrdtL;               /* PRDT Length */  \r
+  UINT16 PrdtO;               /* PRDT Offset */\r
+} UTP_TRD;\r
+\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT32 Rsvd1:2;\r
+  UINT32 DbAddr:30;           /* Data Base Address */\r
+  \r
+  //\r
+  // DW1\r
+  //\r
+  UINT32 DbAddrU;             /* Data Base Address Upper 32-bits */\r
\r
+  //\r
+  // DW2\r
+  //\r
+  UINT32 Rsvd2;\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DbCount:18;          /* Data Byte Count */\r
+  UINT32 Rsvd3:14;\r
+} UTP_TR_PRD;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.3 - UTP Command UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x01*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  CmdSet:4;            /* Command Set Type */\r
+  UINT8  Rsvd1:4;\r
+  UINT8  Rsvd2;\r
+  UINT8  Rsvd3;\r
+  UINT8  Rsvd4;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd5;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 ExpDataTranLen;      /* Expected Data Transfer Length - Big Endian */\r
+\r
+  //\r
+  // DW4 - DW7\r
+  //\r
+  UINT8  Cdb[16];\r
+} UTP_COMMAND_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.4 - UTP Response UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x21*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  CmdSet:4;            /* Command Set Type */\r
+  UINT8  Rsvd1:4;\r
+  UINT8  Rsvd2;\r
+  UINT8  Response;            /* Response */\r
+  UINT8  Status;              /* Status */\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  DevInfo;             /* Device Information */\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 ResTranCount;        /* Residual Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW4 - DW7\r
+  //\r
+  UINT8  Rsvd3[16];\r
+\r
+  //\r
+  // Data Segment - Sense Data\r
+  //\r
+  UINT16 SenseDataLen;        /* Sense Data Length - Big Endian */\r
+  UINT8  SenseData[18];       /* Sense Data */\r
+} UTP_RESPONSE_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.5 - UTP Data-Out UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x02*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd2;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd3[12];\r
+\r
+  //\r
+  // Data Segment - Data to be sent out\r
+  //\r
+  //UINT8  Data[];            /* Data to be sent out, maximum is 65535 bytes */\r
+} UTP_DATA_OUT_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.6 - UTP Data-In UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x22*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd2;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd3[12];\r
+\r
+  //\r
+  // Data Segment - Data to be read\r
+  //\r
+  //UINT8  Data[];            /* Data to be read, maximum is 65535 bytes */\r
+} UTP_DATA_IN_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.7 - UTP Ready-To-Transfer UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x31*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd2;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd3[12];\r
+\r
+  //\r
+  // Data Segment - Data to be read\r
+  //\r
+  //UINT8  Data[];            /* Data to be read, maximum is 65535 bytes */\r
+} UTP_RDY_TO_TRAN_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.8 - UTP Task Management Request UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x04*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1;\r
+  UINT8  TskManFunc;          /* Task Management Function */\r
+  UINT8  Rsvd2[2];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd3;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 InputParam1;         /* Input Parameter 1 - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 InputParam2;         /* Input Parameter 2 - Big Endian */\r
+\r
+  //\r
+  // DW5\r
+  //\r
+  UINT32 InputParam3;         /* Input Parameter 3 - Big Endian */\r
+\r
+  //\r
+  // DW6 - DW7\r
+  //\r
+  UINT8  Rsvd4[8];\r
+} UTP_TM_REQ_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.9 - UTP Task Management Response UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x24*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[2];\r
+  UINT8  Resp;                /* Response */\r
+  UINT8  Rsvd2;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd3;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 OutputParam1;        /* Output Parameter 1 - Big Endian */\r
+\r
+  //\r
+  // DW4\r
+  //\r
+  UINT32 OutputParam2;        /* Output Parameter 2 - Big Endian */\r
+\r
+  //\r
+  // DW5 - DW7\r
+  //\r
+  UINT8  Rsvd4[12];\r
+} UTP_TM_RESP_UPIU;\r
+\r
+//\r
+// UTP Task Management Request Descriptor\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT32 Rsvd1:24;\r
+  UINT32 Int:1;               /* Interrupt */\r
+  UINT32 Rsvd2:7;\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT32 Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT32 Ocs:8;               /* Overall Command Status */\r
+  UINT32 Rsvd4:24;\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT32 Rsvd5;\r
+\r
+  //\r
+  // DW4 - DW11\r
+  //\r
+  UTP_TM_REQ_UPIU TmReq;      /* Task Management Request UPIU */\r
+  \r
+  //\r
+  // DW12 - DW19\r
+  //\r
+  UTP_TM_RESP_UPIU TmResp;    /* Task Management Response UPIU */\r
+} UTP_TMRD;\r
+\r
+\r
+typedef struct {\r
+  UINT8  Opcode;\r
+  UINT8  DescId;\r
+  UINT8  Index;\r
+  UINT8  Selector;\r
+  UINT16 Rsvd1;\r
+  UINT16 Length;\r
+  UINT32 Value;\r
+  UINT32 Rsvd2;\r
+} UTP_UPIU_TSF;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.10 - UTP Query Request UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8        TransCode:6;   /* Transaction Type - 0x16*/\r
+  UINT8        Dd:1;\r
+  UINT8        Hd:1;\r
+  UINT8        Flags;\r
+  UINT8        Rsvd1;\r
+  UINT8        TaskTag;       /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8        Rsvd2;\r
+  UINT8        QueryFunc;     /* Query Function */\r
+  UINT8        Rsvd3[2];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8        EhsLen;        /* Total EHS Length - 0x00 */\r
+  UINT8        Rsvd4;\r
+  UINT16       DataSegLen;    /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3 - 6\r
+  //\r
+  UTP_UPIU_TSF Tsf;           /* Transaction Specific Fields */\r
+\r
+  //\r
+  // DW7\r
+  //\r
+  UINT8        Rsvd5[4];\r
+\r
+  //\r
+  // Data Segment - Data to be transferred\r
+  //\r
+  //UINT8  Data[];            /* Data to be transferred, maximum is 65535 bytes */\r
+} UTP_QUERY_REQ_UPIU;\r
+\r
+#define QUERY_FUNC_STD_READ_REQ     0x01\r
+#define QUERY_FUNC_STD_WRITE_REQ    0x81\r
+\r
+typedef enum {\r
+  UtpQueryFuncOpcodeNop      = 0x00,\r
+  UtpQueryFuncOpcodeRdDesc   = 0x01,\r
+  UtpQueryFuncOpcodeWrDesc   = 0x02,\r
+  UtpQueryFuncOpcodeRdAttr   = 0x03,\r
+  UtpQueryFuncOpcodeWrAttr   = 0x04,\r
+  UtpQueryFuncOpcodeRdFlag   = 0x05,\r
+  UtpQueryFuncOpcodeSetFlag  = 0x06,\r
+  UtpQueryFuncOpcodeClrFlag  = 0x07,\r
+  UtpQueryFuncOpcodeTogFlag  = 0x08\r
+} UTP_QUERY_FUNC_OPCODE;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.11 - UTP Query Response UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8        TransCode:6;   /* Transaction Type - 0x36*/\r
+  UINT8        Dd:1;\r
+  UINT8        Hd:1;\r
+  UINT8        Flags;\r
+  UINT8        Rsvd1;\r
+  UINT8        TaskTag;       /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8        Rsvd2;\r
+  UINT8        QueryFunc;     /* Query Function */\r
+  UINT8        QueryResp;     /* Query Response */\r
+  UINT8        Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8        EhsLen;        /* Total EHS Length - 0x00 */\r
+  UINT8        DevInfo;       /* Device Information */\r
+  UINT16       DataSegLen;    /* Data Segment Length - Big Endian */\r
+\r
+  //\r
+  // DW3 - 6\r
+  //\r
+  UTP_UPIU_TSF Tsf;           /* Transaction Specific Fields */\r
+\r
+  //\r
+  // DW7\r
+  //\r
+  UINT8        Rsvd4[4];\r
+\r
+  //\r
+  // Data Segment - Data to be transferred\r
+  //\r
+  //UINT8      Data[];        /* Data to be transferred, maximum is 65535 bytes */\r
+} UTP_QUERY_RESP_UPIU;\r
+\r
+typedef enum {\r
+  UfsUtpQueryResponseSuccess             = 0x00,\r
+  UfsUtpQueryResponseParamNotReadable    = 0xF6,\r
+  UfsUtpQueryResponseParamNotWriteable   = 0xF7,  \r
+  UfsUtpQueryResponseParamAlreadyWritten = 0xF8,\r
+  UfsUtpQueryResponseInvalidLen          = 0xF9,\r
+  UfsUtpQueryResponseInvalidVal          = 0xFA,\r
+  UfsUtpQueryResponseInvalidSelector     = 0xFB,\r
+  UfsUtpQueryResponseInvalidIndex        = 0xFC,\r
+  UfsUtpQueryResponseInvalidIdn          = 0xFD,\r
+  UfsUtpQueryResponseInvalidOpc          = 0xFE,\r
+  UfsUtpQueryResponseGeneralFailure      = 0xFF\r
+} UTP_QUERY_RESP_CODE;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.12 - UTP Reject UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x3F*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Lun;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd1[2];\r
+  UINT8  Response;            /* Response - 0x01 */\r
+  UINT8  Rsvd2;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  DevInfo;             /* Device Information - 0x00 */\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3\r
+  //\r
+  UINT8  HdrSts;              /* Basic Header Status */\r
+  UINT8  Rsvd3;\r
+  UINT8  E2ESts;              /* End-to-End Status */\r
+  UINT8  Rsvd4;\r
+\r
+  //\r
+  // DW4 - DW7\r
+  //\r
+  UINT8  Rsvd5[16];\r
+} UTP_REJ_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.13 - UTP NOP OUT UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x00*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Rsvd1;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd2[4];\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  Rsvd3;\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3 - DW7\r
+  //\r
+  UINT8  Rsvd4[20];\r
+} UTP_NOP_OUT_UPIU;\r
+\r
+//\r
+// UFS 2.0 Spec Section 10.5.14 - UTP NOP IN UPIU\r
+//\r
+typedef struct {\r
+  //\r
+  // DW0\r
+  //\r
+  UINT8  TransCode:6;         /* Transaction Type - 0x20*/\r
+  UINT8  Dd:1;\r
+  UINT8  Hd:1;\r
+  UINT8  Flags;\r
+  UINT8  Rsvd1;\r
+  UINT8  TaskTag;             /* Task Tag */\r
+\r
+  //\r
+  // DW1\r
+  //\r
+  UINT8  Rsvd2[2];\r
+  UINT8  Resp;                /* Response - 0x00 */\r
+  UINT8  Rsvd3;\r
+\r
+  //\r
+  // DW2\r
+  //\r
+  UINT8  EhsLen;              /* Total EHS Length - 0x00 */\r
+  UINT8  DevInfo;             /* Device Information - 0x00 */\r
+  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */\r
+\r
+  //\r
+  // DW3 - DW7\r
+  //\r
+  UINT8  Rsvd4[20];\r
+} UTP_NOP_IN_UPIU;\r
+\r
+//\r
+// UFS Descriptors\r
+//\r
+typedef enum {\r
+  UfsDeviceDesc     = 0x00,\r
+  UfsConfigDesc     = 0x01,\r
+  UfsUnitDesc       = 0x02,\r
+  UfsInterConnDesc  = 0x04,\r
+  UfsStringDesc     = 0x05,\r
+  UfsGeometryDesc   = 0x07,\r
+  UfsPowerDesc      = 0x08\r
+} UFS_DESC_IDN;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.2 - Device Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  Device;\r
+  UINT8  DevClass;\r
+  UINT8  DevSubClass;\r
+  UINT8  Protocol;\r
+  UINT8  NumLun;\r
+  UINT8  NumWLun;\r
+  UINT8  BootEn;\r
+  UINT8  DescAccessEn;\r
+  UINT8  InitPowerMode;\r
+  UINT8  HighPriorityLun;\r
+  UINT8  SecureRemovalType;\r
+  UINT8  SecurityLun;\r
+  UINT8  BgOpsTermLat;\r
+  UINT8  InitActiveIccLevel;\r
+  UINT16 SpecVersion;\r
+  UINT16 ManufactureDate;\r
+  UINT8  ManufacturerName;\r
+  UINT8  ProductName;\r
+  UINT8  SerialName;\r
+  UINT8  OemId;\r
+  UINT16 ManufacturerId;\r
+  UINT8  Ud0BaseOffset;\r
+  UINT8  Ud0ConfParamLen;\r
+  UINT8  DevRttCap;\r
+  UINT16 PeriodicRtcUpdate;\r
+  UINT8  Rsvd1[17];\r
+  UINT8  Rsvd2[16];\r
+} UFS_DEV_DESC;\r
+\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  Rsvd1;\r
+  UINT8  BootEn;\r
+  UINT8  DescAccessEn;\r
+  UINT8  InitPowerMode;\r
+  UINT8  HighPriorityLun;\r
+  UINT8  SecureRemovalType;\r
+  UINT8  InitActiveIccLevel;\r
+  UINT16 PeriodicRtcUpdate;\r
+  UINT8  Rsvd2[5];\r
+} UFS_CONFIG_DESC_GEN_HEADER;\r
+\r
+typedef struct {\r
+  UINT8  LunEn;\r
+  UINT8  BootLunId;\r
+  UINT8  LunWriteProt;\r
+  UINT8  MemType;\r
+  UINT32 NumAllocUnits;\r
+  UINT8  DataReliability;\r
+  UINT8  LogicBlkSize;\r
+  UINT8  ProvisionType;\r
+  UINT16 CtxCap;\r
+  UINT8  Rsvd1[3];\r
+} UFS_UNIT_DESC_CONFIG_PARAMS;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.3 - Configuration Descriptor\r
+//\r
+typedef struct {\r
+  UFS_CONFIG_DESC_GEN_HEADER  Header;\r
+  UFS_UNIT_DESC_CONFIG_PARAMS UnitDescConfParams[8];\r
+} UFS_CONFIG_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.4 - Geometry Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  MediaTech;\r
+  UINT8  Rsvd1;\r
+  UINT64 TotalRawDevCapacity;\r
+  UINT8  Rsvd2;\r
+  UINT32 SegSize;\r
+  UINT8  AllocUnitSize;\r
+  UINT8  MinAddrBlkSize;\r
+  UINT8  OptReadBlkSize;\r
+  UINT8  OptWriteBlkSize;\r
+  UINT8  MaxInBufSize;\r
+  UINT8  MaxOutBufSize;\r
+  UINT8  RpmbRwSize;\r
+  UINT8  Rsvd3;\r
+  UINT8  DataOrder;\r
+  UINT8  MaxCtxIdNum;\r
+  UINT8  SysDataTagUnitSize;\r
+  UINT8  SysDataResUnitSize;\r
+  UINT8  SupSecRemovalTypes;\r
+  UINT16 SupMemTypes;\r
+  UINT32 SysCodeMaxNumAllocUnits;\r
+  UINT16 SupCodeCapAdjFac;\r
+  UINT32 NonPersMaxNumAllocUnits;\r
+  UINT16 NonPersCapAdjFac;\r
+  UINT32 Enhance1MaxNumAllocUnits;\r
+  UINT16 Enhance1CapAdjFac;\r
+  UINT32 Enhance2MaxNumAllocUnits;\r
+  UINT16 Enhance2CapAdjFac;\r
+  UINT32 Enhance3MaxNumAllocUnits;\r
+  UINT16 Enhance3CapAdjFac;\r
+  UINT32 Enhance4MaxNumAllocUnits;\r
+  UINT16 Enhance4CapAdjFac;\r
+} UFS_GEOMETRY_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.5 - Unit Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  UnitIdx;\r
+  UINT8  LunEn;\r
+  UINT8  BootLunId;\r
+  UINT8  LunWriteProt;\r
+  UINT8  LunQueueDep;\r
+  UINT8  Rsvd1;\r
+  UINT8  MemType;\r
+  UINT8  DataReliability;\r
+  UINT8  LogicBlkSize;\r
+  UINT64 LogicBlkCount;\r
+  UINT32 EraseBlkSize;\r
+  UINT8  ProvisionType;\r
+  UINT64 PhyMemResCount;\r
+  UINT16 CtxCap;\r
+  UINT8  LargeUnitGranularity;\r
+} UFS_UNIT_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.6 - RPMB Unit Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT8  UnitIdx;\r
+  UINT8  LunEn;\r
+  UINT8  BootLunId;\r
+  UINT8  LunWriteProt;\r
+  UINT8  LunQueueDep;\r
+  UINT8  Rsvd1;\r
+  UINT8  MemType;\r
+  UINT8  Rsvd2;\r
+  UINT8  LogicBlkSize;\r
+  UINT64 LogicBlkCount;\r
+  UINT32 EraseBlkSize;\r
+  UINT8  ProvisionType;\r
+  UINT64 PhyMemResCount;\r
+  UINT8  Rsvd3[3];\r
+} UFS_RPMB_UNIT_DESC;\r
+\r
+typedef struct {\r
+  UINT16 Value:10;\r
+  UINT16 Rsvd1:4;\r
+  UINT16 Unit:2;\r
+} UFS_POWER_PARAM_ELEMENT;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.7 - Power Parameter Descriptor\r
+//\r
+typedef struct {\r
+  UINT8                    Length;\r
+  UINT8                    DescType;\r
+  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVcc[16];\r
+  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVccQ[16];\r
+  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVccQ2[16];\r
+} UFS_POWER_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.8 - InterConnect Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  UINT16 UniProVer;\r
+  UINT16 MphyVer;\r
+} UFS_INTER_CONNECT_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.1.6.9 - 14.1.6.12 - String Descriptor\r
+//\r
+typedef struct {\r
+  UINT8  Length;\r
+  UINT8  DescType;\r
+  CHAR16 Unicode[126];\r
+} UFS_STRING_DESC;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.2 - Flags\r
+//\r
+typedef enum {\r
+  UfsFlagDevInit         = 0x01,\r
+  UfsFlagPermWpEn        = 0x02,\r
+  UfsFlagPowerOnWpEn     = 0x03,\r
+  UfsFlagBgOpsEn         = 0x04,\r
+  UfsFlagPurgeEn         = 0x06,\r
+  UfsFlagPhyResRemoval   = 0x08,\r
+  UfsFlagBusyRtc         = 0x09,\r
+  UfsFlagPermDisFwUpdate = 0x0B    \r
+} UFS_FLAGS_IDN;\r
+\r
+//\r
+// UFS 2.0 Spec Section 14.2 - Attributes\r
+//\r
+typedef enum {\r
+  UfsAttrBootLunEn         = 0x00,\r
+  UfsAttrCurPowerMode      = 0x02,\r
+  UfsAttrActiveIccLevel    = 0x03,\r
+  UfsAttrOutOfOrderDataEn  = 0x04,\r
+  UfsAttrBgOpStatus        = 0x05,\r
+  UfsAttrPurgeStatus       = 0x06,\r
+  UfsAttrMaxDataInSize     = 0x07,\r
+  UfsAttrMaxDataOutSize    = 0x08,\r
+  UfsAttrDynCapNeeded      = 0x09,\r
+  UfsAttrRefClkFreq        = 0x0a,\r
+  UfsAttrConfigDescLock    = 0x0b,\r
+  UfsAttrMaxNumOfRtt       = 0x0c,\r
+  UfsAttrExceptionEvtCtrl  = 0x0d,\r
+  UfsAttrExceptionEvtSts   = 0x0e,\r
+  UfsAttrSecondsPassed     = 0x0f,\r
+  UfsAttrContextConf       = 0x10,\r
+  UfsAttrCorrPrgBlkNum     = 0x11\r
+} UFS_ATTR_IDN;\r
+\r
+typedef enum {\r
+  UfsNoData                = 0,\r
+  UfsDataOut               = 1,\r
+  UfsDataIn                = 2,\r
+  UfsDdReserved\r
+} UFS_DATA_DIRECTION;\r
+\r
+\r
+#pragma pack()\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Include/Ppi/UfsHostController.h b/MdeModulePkg/Include/Ppi/UfsHostController.h
new file mode 100644 (file)
index 0000000..1296365
--- /dev/null
@@ -0,0 +1,60 @@
+/** @file\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EDKII_PEI_UFS_HOST_CONTROLLER_PPI_H_\r
+#define _EDKII_PEI_UFS_HOST_CONTROLLER_PPI_H_\r
+\r
+///\r
+/// Global ID for the EDKII_UFS_HOST_CONTROLLER_PPI.\r
+///\r
+#define EDKII_UFS_HOST_CONTROLLER_PPI_GUID \\r
+  { \\r
+    0xdc54b283, 0x1a77, 0x4cd6, { 0x83, 0xbb, 0xfd, 0xda, 0x46, 0x9a, 0x2e, 0xc6 } \\r
+  }\r
+\r
+///\r
+/// Forward declaration for the UFS_HOST_CONTROLLER_PPI.\r
+///\r
+typedef struct _EDKII_UFS_HOST_CONTROLLER_PPI  EDKII_UFS_HOST_CONTROLLER_PPI;\r
+\r
+/**\r
+  Get the MMIO base address of UFS host controller.\r
+\r
+  @param[in]  This               The protocol instance pointer.\r
+  @param[in]  ControllerId       The ID of the UFS host controller.\r
+  @param[out] MmioBar            Pointer to the UFS host controller MMIO base address.\r
+\r
+  @retval EFI_SUCCESS            The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_UFS_HC_GET_MMIO_BAR)(\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PPI    *This,\r
+  IN     UINT8                            ControllerId,\r
+     OUT UINTN                            *MmioBar\r
+  );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the UFS host controller.\r
+///\r
+struct _EDKII_UFS_HOST_CONTROLLER_PPI {\r
+  EDKII_UFS_HC_GET_MMIO_BAR               GetUfsHcMmioBar;\r
+};\r
+\r
+extern EFI_GUID gEdkiiPeiUfsHostControllerPpiGuid;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Include/Protocol/UfsHostController.h b/MdeModulePkg/Include/Protocol/UfsHostController.h
new file mode 100644 (file)
index 0000000..83db1a7
--- /dev/null
@@ -0,0 +1,205 @@
+/** @file\r
+\r
+  EDKII Universal Flash Storage Host Controller Protocol.\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef __EDKII_UFS_HC_PROTOCOL_H__\r
+#define __EDKII_UFS_HC_PROTOCOL_H__\r
+\r
+//\r
+// UFS Host Controller Protocol GUID value\r
+//\r
+#define EDKII_UFS_HOST_CONTROLLER_PROTOCOL_GUID \\r
+    { \\r
+      0xebc01af5, 0x7a9, 0x489e, { 0xb7, 0xce, 0xdc, 0x8, 0x9e, 0x45, 0x9b, 0x2f } \\r
+    }\r
+\r
+//\r
+// Forward reference for pure ANSI compatability\r
+//\r
+typedef struct _EDKII_UFS_HOST_CONTROLLER_PROTOCOL  EDKII_UFS_HOST_CONTROLLER_PROTOCOL;\r
+\r
+\r
+/**\r
+  Get the MMIO base address of UFS host controller.\r
+\r
+  @param  This          The protocol instance pointer.\r
+  @param  MmioBar       Pointer to the UFS host controller MMIO base address.\r
+\r
+  @retval EFI_SUCCESS            The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_UFS_HC_GET_MMIO_BAR)(\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL     *This,\r
+     OUT UINTN                                  *MmioBar\r
+  );\r
+\r
+///\r
+/// *******************************************************\r
+/// EFI_UFS_HOST_CONTROLLER_OPERATION\r
+/// *******************************************************\r
+///\r
+typedef enum {\r
+  ///\r
+  /// A read operation from system memory by a bus master.\r
+  ///\r
+  EdkiiUfsHcOperationBusMasterRead,\r
+  ///\r
+  /// A write operation from system memory by a bus master.\r
+  ///\r
+  EdkiiUfsHcOperationBusMasterWrite,\r
+  ///\r
+  /// Provides both read and write access to system memory by both the processor and a\r
+  /// bus master. The buffer is coherent from both the processor's and the bus master's point of view.\r
+  ///\r
+  EdkiiUfsHcOperationBusMasterCommonBuffer,\r
+  EdkiiUfsHcOperationMaximum\r
+} EDKII_UFS_HOST_CONTROLLER_OPERATION;\r
+\r
+/**                                                                 \r
+  Provides the UFS controller-specific addresses needed to access system memory.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
+  @param  HostAddress           The system memory address to map to the UFS controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
+                                that were mapped.                                                 \r
+  @param  DeviceAddress         The resulting map address for the bus master UFS controller to use to\r
+                                access the hosts HostAddress.                                        \r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.                                \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
+                                   \r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_UFS_HC_MAP)(\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This,\r
+  IN     EDKII_UFS_HOST_CONTROLLER_OPERATION  Operation,\r
+  IN     VOID                                 *HostAddress,\r
+  IN OUT UINTN                                *NumberOfBytes,\r
+     OUT EFI_PHYSICAL_ADDRESS                 *DeviceAddress,\r
+     OUT VOID                                 **Mapping\r
+  );\r
+\r
+/**                                                                 \r
+  Completes the Map() operation and releases any corresponding resources.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.                                      \r
+  @param  Mapping               The mapping value returned from Map().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+                                   \r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_UFS_HC_UNMAP)(\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL     *This,\r
+  IN  VOID                                   *Mapping\r
+  );\r
+\r
+/**                                                                 \r
+  Allocates pages that are suitable for an EfiUfsHcOperationBusMasterCommonBuffer\r
+  mapping.                                                                       \r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.\r
+  @param  Type                  This parameter is not used and must be ignored.\r
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
+                                EfiRuntimeServicesData.                               \r
+  @param  Pages                 The number of pages to allocate.                                \r
+  @param  HostAddress           A pointer to store the base system memory address of the\r
+                                allocated range.                                        \r
+  @param  Attributes            The requested bit mask of attributes for the allocated range.\r
+                                  \r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.                     \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.  \r
+                                   \r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_UFS_HC_ALLOCATE_BUFFER)(\r
+  IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This,\r
+  IN     EFI_ALLOCATE_TYPE                    Type,\r
+  IN     EFI_MEMORY_TYPE                      MemoryType,\r
+  IN     UINTN                                Pages,\r
+     OUT VOID                                 **HostAddress,\r
+  IN     UINT64                               Attributes\r
+  );\r
+\r
+/**                                                                 \r
+  Frees memory that was allocated with AllocateBuffer().\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.  \r
+  @param  Pages                 The number of pages to free.                                \r
+  @param  HostAddress           The base system memory address of the allocated range.                                    \r
+                                  \r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+                                was not allocated with AllocateBuffer().\r
+                                     \r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_UFS_HC_FREE_BUFFER)(\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This,\r
+  IN  UINTN                                Pages,\r
+  IN  VOID                                 *HostAddress\r
+  );\r
+\r
+/**                                                                 \r
+  Flushes all posted write transactions from the UFS bus to attached UFS device.\r
+            \r
+  @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.  \r
+                                  \r
+  @retval EFI_SUCCESS           The posted write transactions were flushed from the UFS bus\r
+                                to attached UFS device.                                      \r
+  @retval EFI_DEVICE_ERROR      The posted write transactions were not flushed from the UFS\r
+                                bus to attached UFS device due to a hardware error.                           \r
+                                     \r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_UFS_HC_FLUSH)(\r
+  IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This\r
+  );\r
+\r
+///\r
+///  UFS Host Controller Protocol structure.\r
+///\r
+struct _EDKII_UFS_HOST_CONTROLLER_PROTOCOL {\r
+  EDKII_UFS_HC_GET_MMIO_BAR           GetUfsHcMmioBar;\r
+  EDKII_UFS_HC_ALLOCATE_BUFFER        AllocateBuffer;\r
+  EDKII_UFS_HC_FREE_BUFFER            FreeBuffer;\r
+  EDKII_UFS_HC_MAP                    Map;\r
+  EDKII_UFS_HC_UNMAP                  Unmap;\r
+  EDKII_UFS_HC_FLUSH                  Flush;\r
+};\r
+\r
+///\r
+///  UFS Host Controller Protocol GUID variable.\r
+///\r
+extern EFI_GUID gEdkiiUfsHostControllerProtocolGuid;\r
+\r
+#endif\r
index 421c6977abeda7de8c5d8f4e05f277fbf5eedac4..5591b2f068faffd874e5e50c29f16fc72b7a7b7d 100644 (file)
   ## Include/Ppi/SerialPortPei.h\r
   gPeiSerialPortPpiGuid         =  { 0x490e9d85, 0x8aef, 0x4193, { 0x8e, 0x56, 0xf7, 0x34, 0xa9, 0xff, 0xac, 0x8b}}\r
 \r
   ## Include/Ppi/SerialPortPei.h\r
   gPeiSerialPortPpiGuid         =  { 0x490e9d85, 0x8aef, 0x4193, { 0x8e, 0x56, 0xf7, 0x34, 0xa9, 0xff, 0xac, 0x8b}}\r
 \r
+  ## Include/Ppi/UfsHostController.h\r
+  gEdkiiPeiUfsHostControllerPpiGuid  =  { 0xdc54b283, 0x1a77, 0x4cd6, { 0x83, 0xbb, 0xfd, 0xda, 0x46, 0x9a, 0x2e, 0xc6 }}\r
+\r
 [Protocols]\r
   ## Load File protocol provides capability to load and unload EFI image into memory and execute it.\r
   #  Include/Protocol/LoadPe32Image.h\r
 [Protocols]\r
   ## Load File protocol provides capability to load and unload EFI image into memory and execute it.\r
   #  Include/Protocol/LoadPe32Image.h\r
   ## Include/Protocol/FormBrowserEx2.h\r
   gEdkiiFormBrowserEx2ProtocolGuid = { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb } }\r
 \r
   ## Include/Protocol/FormBrowserEx2.h\r
   gEdkiiFormBrowserEx2ProtocolGuid = { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb } }\r
 \r
+  ## Include/Protocol/UfsHostController.h\r
+  gEdkiiUfsHostControllerProtocolGuid = { 0xebc01af5, 0x7a9, 0x489e, { 0xb7, 0xce, 0xdc, 0x8, 0x9e, 0x45, 0x9b, 0x2f } }\r
+\r
 #\r
 # [Error.gEfiMdeModulePkgTokenSpaceGuid]\r
 #   0x80000001 | Invalid value provided.\r
 #\r
 # [Error.gEfiMdeModulePkgTokenSpaceGuid]\r
 #   0x80000001 | Invalid value provided.\r
   # @Prompt Disk I/O - Number of Data Buffer block.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdDiskIoDataBufferBlockNum|64|UINT32|0x30001039\r
 \r
   # @Prompt Disk I/O - Number of Data Buffer block.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdDiskIoDataBufferBlockNum|64|UINT32|0x30001039\r
 \r
+  ## This PCD specifies the PCI-based UFS host controller mmio base address.\r
+  # Define the mmio base address of the pci-based UFS host controller. If there are multiple UFS\r
+  # host controllers, their mmio base addresses are calculated one by one from this base address.\r
+  # @Prompt Mmio base address of pci-based UFS host controller.\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUfsPciHostControllerMmioBase|0xd0000000|UINT32|0x10000061\r
+\r
 [PcdsPatchableInModule]\r
   ## Specify memory size with page number for PEI code when\r
   #  Loading Module at Fixed Address feature is enabled.\r
 [PcdsPatchableInModule]\r
   ## Specify memory size with page number for PEI code when\r
   #  Loading Module at Fixed Address feature is enabled.\r
index b9df820d6de87889447c04184dd5b87dbe1dd198..0bf3cca871db1ded522f166c74c8c49055435e1a 100644 (file)
   MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
   MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
   MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf\r
   MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
   MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
   MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf\r
+  MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf\r
+  MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf\r
+  MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf\r
+  MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf\r
   MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf\r
   MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf\r
   MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf\r
   MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf\r
   MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf\r
   MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf\r
index add9a51e565eda75e20ae3035f8993a7820acb20..1527453712bf9f01e6ef99fcdd2a2208be914a42 100644 (file)
Binary files a/MdeModulePkg/MdeModulePkg.uni and b/MdeModulePkg/MdeModulePkg.uni differ