--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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