Home | History | Annotate | Download | only in UfsPciHcDxe
      1 /** @file
      2   UfsHcDxe driver is used to provide platform-dependent info, mainly UFS host controller
      3   MMIO base, to upper layer UFS drivers.
      4 
      5   Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "UfsPciHcDxe.h"
     17 
     18 //
     19 // NVM Express Driver Binding Protocol Instance
     20 //
     21 EFI_DRIVER_BINDING_PROTOCOL gUfsHcDriverBinding = {
     22   UfsHcDriverBindingSupported,
     23   UfsHcDriverBindingStart,
     24   UfsHcDriverBindingStop,
     25   0x10,
     26   NULL,
     27   NULL
     28 };
     29 
     30 //
     31 // Template for Ufs host controller private data.
     32 //
     33 UFS_HOST_CONTROLLER_PRIVATE_DATA gUfsHcTemplate = {
     34   UFS_HC_PRIVATE_DATA_SIGNATURE,  // Signature
     35   NULL,                           // Handle
     36   {                               // UfsHcProtocol
     37     UfsHcGetMmioBar,
     38     UfsHcAllocateBuffer,
     39     UfsHcFreeBuffer,
     40     UfsHcMap,
     41     UfsHcUnmap,
     42     UfsHcFlush,
     43     UfsHcMmioRead,
     44     UfsHcMmioWrite
     45   },
     46   NULL,                           // PciIo
     47   0,                              // BarIndex
     48   0                               // PciAttributes
     49 };
     50 
     51 /**
     52   Get the MMIO base of the UFS host controller.
     53 
     54   @param[in]   This             A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
     55   @param[out]  MmioBar          The MMIO base address of UFS host controller.
     56 
     57   @retval EFI_SUCCESS           The operation succeeds.
     58   @retval others                The operation fails.
     59 **/
     60 EFI_STATUS
     61 EFIAPI
     62 UfsHcGetMmioBar (
     63   IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
     64      OUT UINTN                              *MmioBar
     65   )
     66 {
     67   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
     68   EFI_PCI_IO_PROTOCOL               *PciIo;
     69   EFI_STATUS                        Status;
     70   UINT8                             BarIndex;
     71   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
     72 
     73   if ((This == NULL) || (MmioBar == NULL)) {
     74     return EFI_INVALID_PARAMETER;
     75   }
     76 
     77   BarDesc  = NULL;
     78   Private  = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
     79   PciIo    = Private->PciIo;
     80   BarIndex = Private->BarIndex;
     81 
     82   Status = PciIo->GetBarAttributes (
     83                     PciIo,
     84                     BarIndex,
     85                     NULL,
     86                     (VOID**) &BarDesc
     87                     );
     88   if (EFI_ERROR (Status)) {
     89     return Status;
     90   }
     91 
     92   *MmioBar = (UINTN)BarDesc->AddrRangeMin;
     93 
     94   FreePool (BarDesc);
     95 
     96   return Status;
     97 }
     98 
     99 /**
    100   Provides the UFS controller-specific addresses needed to access system memory.
    101 
    102   @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
    103   @param  Operation             Indicates if the bus master is going to read or write to system memory.
    104   @param  HostAddress           The system memory address to map to the UFS controller.
    105   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
    106                                 that were mapped.
    107   @param  DeviceAddress         The resulting map address for the bus master UFS controller to use to
    108                                 access the hosts HostAddress.
    109   @param  Mapping               A resulting value to pass to Unmap().
    110 
    111   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
    112   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
    113   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    114   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    115   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
    116 
    117 **/
    118 EFI_STATUS
    119 EFIAPI
    120 UfsHcMap (
    121   IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *This,
    122   IN     EDKII_UFS_HOST_CONTROLLER_OPERATION  Operation,
    123   IN     VOID                                 *HostAddress,
    124   IN OUT UINTN                                *NumberOfBytes,
    125      OUT EFI_PHYSICAL_ADDRESS                 *DeviceAddress,
    126      OUT VOID                                 **Mapping
    127   )
    128 {
    129   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    130   EFI_PCI_IO_PROTOCOL               *PciIo;
    131   EFI_STATUS                        Status;
    132 
    133   if ((This == NULL) || (HostAddress == NULL) || (NumberOfBytes == NULL) || (DeviceAddress == NULL) || (Mapping == NULL)) {
    134     return EFI_INVALID_PARAMETER;
    135   }
    136 
    137   Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
    138   PciIo   = Private->PciIo;
    139 
    140   Status  = PciIo->Map (PciIo, (EFI_PCI_IO_PROTOCOL_OPERATION)Operation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
    141   return Status;
    142 }
    143 
    144 /**
    145   Completes the Map() operation and releases any corresponding resources.
    146 
    147   @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
    148   @param  Mapping               The mapping value returned from Map().
    149 
    150   @retval EFI_SUCCESS           The range was unmapped.
    151   @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
    152 
    153 **/
    154 EFI_STATUS
    155 EFIAPI
    156 UfsHcUnmap (
    157   IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
    158   IN  VOID                               *Mapping
    159   )
    160 {
    161   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    162   EFI_PCI_IO_PROTOCOL               *PciIo;
    163   EFI_STATUS                        Status;
    164 
    165   if ((This == NULL) || (Mapping == NULL)) {
    166     return EFI_INVALID_PARAMETER;
    167   }
    168 
    169   Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
    170   PciIo   = Private->PciIo;
    171 
    172   Status  = PciIo->Unmap (PciIo, Mapping);
    173   return Status;
    174 }
    175 
    176 /**
    177   Allocates pages that are suitable for an EfiUfsHcOperationBusMasterCommonBuffer
    178   mapping.
    179 
    180   @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
    181   @param  Type                  This parameter is not used and must be ignored.
    182   @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
    183                                 EfiRuntimeServicesData.
    184   @param  Pages                 The number of pages to allocate.
    185   @param  HostAddress           A pointer to store the base system memory address of the
    186                                 allocated range.
    187   @param  Attributes            The requested bit mask of attributes for the allocated range.
    188 
    189   @retval EFI_SUCCESS           The requested memory pages were allocated.
    190   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
    191                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
    192   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    193   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
    194 
    195 **/
    196 EFI_STATUS
    197 EFIAPI
    198 UfsHcAllocateBuffer (
    199   IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
    200   IN     EFI_ALLOCATE_TYPE                  Type,
    201   IN     EFI_MEMORY_TYPE                    MemoryType,
    202   IN     UINTN                              Pages,
    203      OUT VOID                               **HostAddress,
    204   IN     UINT64                             Attributes
    205   )
    206 {
    207   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    208   EFI_PCI_IO_PROTOCOL               *PciIo;
    209   EFI_STATUS                        Status;
    210 
    211   if ((This == NULL) || (HostAddress == NULL)) {
    212     return EFI_INVALID_PARAMETER;
    213   }
    214 
    215   Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
    216   PciIo   = Private->PciIo;
    217 
    218   Status  = PciIo->AllocateBuffer (PciIo, Type, MemoryType, Pages, HostAddress, Attributes);
    219   return Status;
    220 }
    221 
    222 /**
    223   Frees memory that was allocated with AllocateBuffer().
    224 
    225   @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
    226   @param  Pages                 The number of pages to free.
    227   @param  HostAddress           The base system memory address of the allocated range.
    228 
    229   @retval EFI_SUCCESS           The requested memory pages were freed.
    230   @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
    231                                 was not allocated with AllocateBuffer().
    232 
    233 **/
    234 EFI_STATUS
    235 EFIAPI
    236 UfsHcFreeBuffer (
    237   IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
    238   IN  UINTN                              Pages,
    239   IN  VOID                               *HostAddress
    240   )
    241 {
    242   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    243   EFI_PCI_IO_PROTOCOL               *PciIo;
    244   EFI_STATUS                        Status;
    245 
    246   if ((This == NULL) || (HostAddress == NULL)) {
    247     return EFI_INVALID_PARAMETER;
    248   }
    249 
    250   Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
    251   PciIo   = Private->PciIo;
    252 
    253   Status  = PciIo->FreeBuffer (PciIo, Pages, HostAddress);
    254   return Status;
    255 }
    256 
    257 /**
    258   Flushes all posted write transactions from the UFS bus to attached UFS device.
    259 
    260   @param  This                  A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
    261 
    262   @retval EFI_SUCCESS           The posted write transactions were flushed from the UFS bus
    263                                 to attached UFS device.
    264   @retval EFI_DEVICE_ERROR      The posted write transactions were not flushed from the UFS
    265                                 bus to attached UFS device due to a hardware error.
    266 
    267 **/
    268 EFI_STATUS
    269 EFIAPI
    270 UfsHcFlush (
    271   IN  EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This
    272   )
    273 {
    274   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    275   EFI_PCI_IO_PROTOCOL               *PciIo;
    276   EFI_STATUS                        Status;
    277 
    278   Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
    279   PciIo   = Private->PciIo;
    280 
    281   Status  = PciIo->Flush (PciIo);
    282   return Status;
    283 }
    284 
    285 /**
    286   Enable a UFS bus driver to access UFS MMIO registers in the UFS Host Controller memory space.
    287 
    288   @param  This                  A pointer to the EDKII_UFS_HOST_CONTROLLER_PROTOCOL instance.
    289   @param  Width                 Signifies the width of the memory operations.
    290   @param  Offset                The offset within the UFS Host Controller MMIO space to start the
    291                                 memory operation.
    292   @param  Count                 The number of memory operations to perform.
    293   @param  Buffer                For read operations, the destination buffer to store the results.
    294                                 For write operations, the source buffer to write data from.
    295 
    296   @retval EFI_SUCCESS           The data was read from or written to the UFS host controller.
    297   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    298                                 valid for the UFS Host Controller memory space.
    299   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    300   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    301 
    302 **/
    303 EFI_STATUS
    304 EFIAPI
    305 UfsHcMmioRead (
    306   IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL        *This,
    307   IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH  Width,
    308   IN     UINT64                                    Offset,
    309   IN     UINTN                                     Count,
    310   IN OUT VOID                                      *Buffer
    311   )
    312 {
    313   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    314   EFI_PCI_IO_PROTOCOL               *PciIo;
    315   EFI_STATUS                        Status;
    316   UINT8                             BarIndex;
    317 
    318   Private  = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
    319   PciIo    = Private->PciIo;
    320   BarIndex = Private->BarIndex;
    321 
    322   Status   = PciIo->Mem.Read (PciIo, (EFI_PCI_IO_PROTOCOL_WIDTH)Width, BarIndex, Offset, Count, Buffer);
    323 
    324   return Status;
    325 }
    326 
    327 /**
    328   Enable a UFS bus driver to access UFS MMIO registers in the UFS Host Controller memory space.
    329 
    330   @param  This                  A pointer to the EDKII_UFS_HOST_CONTROLLER_PROTOCOL instance.
    331   @param  Width                 Signifies the width of the memory operations.
    332   @param  Offset                The offset within the UFS Host Controller MMIO space to start the
    333                                 memory operation.
    334   @param  Count                 The number of memory operations to perform.
    335   @param  Buffer                For read operations, the destination buffer to store the results.
    336                                 For write operations, the source buffer to write data from.
    337 
    338   @retval EFI_SUCCESS           The data was read from or written to the UFS host controller.
    339   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    340                                 valid for the UFS Host Controller memory space.
    341   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    342   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    343 
    344 **/
    345 EFI_STATUS
    346 EFIAPI
    347 UfsHcMmioWrite (
    348   IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL        *This,
    349   IN     EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH  Width,
    350   IN     UINT64                                    Offset,
    351   IN     UINTN                                     Count,
    352   IN OUT VOID                                      *Buffer
    353   )
    354 {
    355   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    356   EFI_PCI_IO_PROTOCOL               *PciIo;
    357   EFI_STATUS                        Status;
    358   UINT8                             BarIndex;
    359 
    360   Private  = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
    361   PciIo    = Private->PciIo;
    362   BarIndex = Private->BarIndex;
    363 
    364   Status   = PciIo->Mem.Write (PciIo, (EFI_PCI_IO_PROTOCOL_WIDTH)Width, BarIndex, Offset, Count, Buffer);
    365 
    366   return Status;
    367 }
    368 
    369 /**
    370   Tests to see if this driver supports a given controller. If a child device is provided,
    371   it further tests to see if this driver supports creating a handle for the specified child device.
    372 
    373   This function checks to see if the driver specified by This supports the device specified by
    374   ControllerHandle. Drivers will typically use the device path attached to
    375   ControllerHandle and/or the services from the bus I/O abstraction attached to
    376   ControllerHandle to determine if the driver supports ControllerHandle. This function
    377   may be called many times during platform initialization. In order to reduce boot times, the tests
    378   performed by this function must be very small, and take as little time as possible to execute. This
    379   function must not change the state of any hardware devices, and this function must be aware that the
    380   device specified by ControllerHandle may already be managed by the same driver or a
    381   different driver. This function must match its calls to AllocatePages() with FreePages(),
    382   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
    383   Since ControllerHandle may have been previously started by the same driver, if a protocol is
    384   already in the opened state, then it must not be closed with CloseProtocol(). This is required
    385   to guarantee the state of ControllerHandle is not modified by this function.
    386 
    387   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    388   @param[in]  ControllerHandle     The handle of the controller to test. This handle
    389                                    must support a protocol interface that supplies
    390                                    an I/O abstraction to the driver.
    391   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    392                                    parameter is ignored by device drivers, and is optional for bus
    393                                    drivers. For bus drivers, if this parameter is not NULL, then
    394                                    the bus driver must determine if the bus controller specified
    395                                    by ControllerHandle and the child controller specified
    396                                    by RemainingDevicePath are both supported by this
    397                                    bus driver.
    398 
    399   @retval EFI_SUCCESS              The device specified by ControllerHandle and
    400                                    RemainingDevicePath is supported by the driver specified by This.
    401   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
    402                                    RemainingDevicePath is already being managed by the driver
    403                                    specified by This.
    404   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
    405                                    RemainingDevicePath is already being managed by a different
    406                                    driver or an application that requires exclusive access.
    407                                    Currently not implemented.
    408   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
    409                                    RemainingDevicePath is not supported by the driver specified by This.
    410 **/
    411 EFI_STATUS
    412 EFIAPI
    413 UfsHcDriverBindingSupported (
    414   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    415   IN EFI_HANDLE                   Controller,
    416   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    417   )
    418 {
    419   EFI_STATUS                Status;
    420   BOOLEAN                   UfsHcFound;
    421   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
    422   EFI_PCI_IO_PROTOCOL       *PciIo;
    423   PCI_TYPE00                PciData;
    424 
    425   PciIo            = NULL;
    426   ParentDevicePath = NULL;
    427   UfsHcFound       = FALSE;
    428 
    429   //
    430   // UfsHcDxe is a device driver, and should ingore the
    431   // "RemainingDevicePath" according to EFI spec
    432   //
    433   Status = gBS->OpenProtocol (
    434                   Controller,
    435                   &gEfiDevicePathProtocolGuid,
    436                   (VOID *) &ParentDevicePath,
    437                   This->DriverBindingHandle,
    438                   Controller,
    439                   EFI_OPEN_PROTOCOL_BY_DRIVER
    440                   );
    441   if (EFI_ERROR (Status)) {
    442     //
    443     // EFI_ALREADY_STARTED is also an error
    444     //
    445     return Status;
    446   }
    447   //
    448   // Close the protocol because we don't use it here
    449   //
    450   gBS->CloseProtocol (
    451         Controller,
    452         &gEfiDevicePathProtocolGuid,
    453         This->DriverBindingHandle,
    454         Controller
    455         );
    456 
    457   //
    458   // Now test the EfiPciIoProtocol
    459   //
    460   Status = gBS->OpenProtocol (
    461                   Controller,
    462                   &gEfiPciIoProtocolGuid,
    463                   (VOID **) &PciIo,
    464                   This->DriverBindingHandle,
    465                   Controller,
    466                   EFI_OPEN_PROTOCOL_BY_DRIVER
    467                   );
    468   if (EFI_ERROR (Status)) {
    469     return Status;
    470   }
    471   //
    472   // Now further check the PCI header: Base class (offset 0x0B) and
    473   // Sub Class (offset 0x0A). This controller should be an UFS controller
    474   //
    475   Status = PciIo->Pci.Read (
    476                         PciIo,
    477                         EfiPciIoWidthUint8,
    478                         0,
    479                         sizeof (PciData),
    480                         &PciData
    481                         );
    482   if (EFI_ERROR (Status)) {
    483     gBS->CloseProtocol (
    484           Controller,
    485           &gEfiPciIoProtocolGuid,
    486           This->DriverBindingHandle,
    487           Controller
    488           );
    489     return EFI_UNSUPPORTED;
    490   }
    491   //
    492   // Since we already got the PciData, we can close protocol to avoid to carry it on for multiple exit points.
    493   //
    494   gBS->CloseProtocol (
    495         Controller,
    496         &gEfiPciIoProtocolGuid,
    497         This->DriverBindingHandle,
    498         Controller
    499         );
    500 
    501   //
    502   // Examine UFS Host Controller PCI Configuration table fields
    503   //
    504   if (PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE) {
    505     if (PciData.Hdr.ClassCode[1] == 0x09 ) { //UFS Controller Subclass
    506       UfsHcFound = TRUE;
    507     }
    508   }
    509 
    510   if (!UfsHcFound) {
    511     return EFI_UNSUPPORTED;
    512   }
    513 
    514   return Status;
    515 }
    516 
    517 
    518 /**
    519   Starts a device controller or a bus controller.
    520 
    521   The Start() function is designed to be invoked from the EFI boot service ConnectController().
    522   As a result, much of the error checking on the parameters to Start() has been moved into this
    523   common boot service. It is legal to call Start() from other locations,
    524   but the following calling restrictions must be followed or the system behavior will not be deterministic.
    525   1. ControllerHandle must be a valid EFI_HANDLE.
    526   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
    527      EFI_DEVICE_PATH_PROTOCOL.
    528   3. Prior to calling Start(), the Supported() function for the driver specified by This must
    529      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
    530 
    531   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    532   @param[in]  ControllerHandle     The handle of the controller to start. This handle
    533                                    must support a protocol interface that supplies
    534                                    an I/O abstraction to the driver.
    535   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    536                                    parameter is ignored by device drivers, and is optional for bus
    537                                    drivers. For a bus driver, if this parameter is NULL, then handles
    538                                    for all the children of Controller are created by this driver.
    539                                    If this parameter is not NULL and the first Device Path Node is
    540                                    not the End of Device Path Node, then only the handle for the
    541                                    child device specified by the first Device Path Node of
    542                                    RemainingDevicePath is created by this driver.
    543                                    If the first Device Path Node of RemainingDevicePath is
    544                                    the End of Device Path Node, no child handle is created by this
    545                                    driver.
    546 
    547   @retval EFI_SUCCESS              The device was started.
    548   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
    549   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
    550   @retval Others                   The driver failded to start the device.
    551 
    552 **/
    553 EFI_STATUS
    554 EFIAPI
    555 UfsHcDriverBindingStart (
    556   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    557   IN EFI_HANDLE                   Controller,
    558   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    559   )
    560 {
    561   EFI_STATUS                        Status;
    562   EFI_PCI_IO_PROTOCOL               *PciIo;
    563   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;
    564   UINT64                            Supports;
    565   UINT8                             BarIndex;
    566   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
    567 
    568   PciIo    = NULL;
    569   Private  = NULL;
    570   Supports = 0;
    571   BarDesc  = NULL;
    572 
    573   //
    574   // Now test and open the EfiPciIoProtocol
    575   //
    576   Status = gBS->OpenProtocol (
    577                   Controller,
    578                   &gEfiPciIoProtocolGuid,
    579                   (VOID **) &PciIo,
    580                   This->DriverBindingHandle,
    581                   Controller,
    582                   EFI_OPEN_PROTOCOL_BY_DRIVER
    583                   );
    584   //
    585   // Status == 0 - A normal execution flow, SUCCESS and the program proceeds.
    586   // Status == ALREADY_STARTED - A non-zero Status code returned. It indicates
    587   //           that the protocol has been opened and should be treated as a
    588   //           normal condition and the program proceeds. The Protocol will not
    589   //           opened 'again' by this call.
    590   // Status != ALREADY_STARTED - Error status, terminate program execution
    591   //
    592   if (EFI_ERROR (Status)) {
    593     //
    594     // EFI_ALREADY_STARTED is also an error
    595     //
    596     return Status;
    597   }
    598 
    599   Private = AllocateCopyPool (sizeof (UFS_HOST_CONTROLLER_PRIVATE_DATA), &gUfsHcTemplate);
    600   if (Private == NULL) {
    601     Status = EFI_OUT_OF_RESOURCES;
    602     goto Done;
    603   }
    604 
    605   Private->PciIo = PciIo;
    606 
    607   for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
    608     Status = PciIo->GetBarAttributes (
    609                       PciIo,
    610                       BarIndex,
    611                       NULL,
    612                       (VOID**) &BarDesc
    613                       );
    614     if (Status == EFI_UNSUPPORTED) {
    615       continue;
    616     } else if (EFI_ERROR (Status)) {
    617       goto Done;
    618     }
    619 
    620     if (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
    621       Private->BarIndex = BarIndex;
    622       FreePool (BarDesc);
    623       break;
    624     }
    625 
    626     FreePool (BarDesc);
    627   }
    628 
    629   Status = PciIo->Attributes (
    630                     PciIo,
    631                     EfiPciIoAttributeOperationGet,
    632                     0,
    633                     &Private->PciAttributes
    634                     );
    635 
    636   if (EFI_ERROR (Status)) {
    637     goto Done;
    638   }
    639 
    640   Status = PciIo->Attributes (
    641                     PciIo,
    642                     EfiPciIoAttributeOperationSupported,
    643                     0,
    644                     &Supports
    645                     );
    646 
    647   if (!EFI_ERROR (Status)) {
    648     Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
    649     Status    = PciIo->Attributes (
    650                          PciIo,
    651                          EfiPciIoAttributeOperationEnable,
    652                          Supports,
    653                          NULL
    654                          );
    655   } else {
    656     goto Done;
    657   }
    658 
    659   ///
    660   /// Install UFS_HOST_CONTROLLER protocol
    661   ///
    662   Status = gBS->InstallProtocolInterface (
    663                   &Controller,
    664                   &gEdkiiUfsHostControllerProtocolGuid,
    665                   EFI_NATIVE_INTERFACE,
    666                   (VOID*)&(Private->UfsHc)
    667                   );
    668 
    669 Done:
    670   if (EFI_ERROR (Status)) {
    671     if ((Private != NULL) && (Private->PciAttributes != 0)) {
    672       //
    673       // Restore original PCI attributes
    674       //
    675       Status = PciIo->Attributes (
    676                         PciIo,
    677                         EfiPciIoAttributeOperationSet,
    678                         Private->PciAttributes,
    679                         NULL
    680                         );
    681       ASSERT_EFI_ERROR (Status);
    682     }
    683     gBS->CloseProtocol (
    684           Controller,
    685           &gEfiPciIoProtocolGuid,
    686           This->DriverBindingHandle,
    687           Controller
    688           );
    689     if (Private != NULL) {
    690       FreePool (Private);
    691     }
    692   }
    693 
    694   return Status;
    695 }
    696 
    697 
    698 /**
    699   Stops a device controller or a bus controller.
    700 
    701   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
    702   As a result, much of the error checking on the parameters to Stop() has been moved
    703   into this common boot service. It is legal to call Stop() from other locations,
    704   but the following calling restrictions must be followed or the system behavior will not be deterministic.
    705   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
    706      same driver's Start() function.
    707   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
    708      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
    709      Start() function, and the Start() function must have called OpenProtocol() on
    710      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
    711 
    712   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    713   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    714                                 support a bus specific I/O protocol for the driver
    715                                 to use to stop the device.
    716   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    717   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    718                                 if NumberOfChildren is 0.
    719 
    720   @retval EFI_SUCCESS           The device was stopped.
    721   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    722 
    723 **/
    724 EFI_STATUS
    725 EFIAPI
    726 UfsHcDriverBindingStop (
    727   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    728   IN  EFI_HANDLE                      Controller,
    729   IN  UINTN                           NumberOfChildren,
    730   IN  EFI_HANDLE                      *ChildHandleBuffer
    731   )
    732 {
    733   EFI_STATUS                          Status;
    734   UFS_HOST_CONTROLLER_PRIVATE_DATA    *Private;
    735   EDKII_UFS_HOST_CONTROLLER_PROTOCOL  *UfsHc;
    736 
    737   ///
    738   /// Get private data
    739   ///
    740   Status = gBS->OpenProtocol (
    741                   Controller,
    742                   &gEdkiiUfsHostControllerProtocolGuid,
    743                   (VOID **) &UfsHc,
    744                   This->DriverBindingHandle,
    745                   Controller,
    746                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    747                   );
    748 
    749   if (EFI_ERROR (Status)) {
    750     return EFI_DEVICE_ERROR;
    751   }
    752 
    753   Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (UfsHc);
    754 
    755   Status = gBS->UninstallProtocolInterface (
    756                   Controller,
    757                   &gEdkiiUfsHostControllerProtocolGuid,
    758                   &(Private->UfsHc)
    759                   );
    760   if (!EFI_ERROR (Status)) {
    761     //
    762     // Restore original PCI attributes
    763     //
    764     Status = Private->PciIo->Attributes (
    765                                Private->PciIo,
    766                                EfiPciIoAttributeOperationSet,
    767                                Private->PciAttributes,
    768                                NULL
    769                                );
    770     ASSERT_EFI_ERROR (Status);
    771 
    772     //
    773     // Close protocols opened by UFS host controller driver
    774     //
    775     gBS->CloseProtocol (
    776            Controller,
    777            &gEfiPciIoProtocolGuid,
    778            This->DriverBindingHandle,
    779            Controller
    780            );
    781 
    782     FreePool (Private);
    783   }
    784 
    785   return Status;
    786 }
    787 
    788 /**
    789   The entry point for UFS host controller driver, used to install this driver on the ImageHandle.
    790 
    791   @param[in]  ImageHandle   The firmware allocated handle for this driver image.
    792   @param[in]  SystemTable   Pointer to the EFI system table.
    793 
    794   @retval EFI_SUCCESS   Driver loaded.
    795   @retval other         Driver not loaded.
    796 
    797 **/
    798 EFI_STATUS
    799 EFIAPI
    800 UfsHcDriverEntry (
    801   IN EFI_HANDLE        ImageHandle,
    802   IN EFI_SYSTEM_TABLE  *SystemTable
    803   )
    804 {
    805   EFI_STATUS           Status;
    806 
    807   Status = EfiLibInstallDriverBindingComponentName2 (
    808              ImageHandle,
    809              SystemTable,
    810              &gUfsHcDriverBinding,
    811              ImageHandle,
    812              &gUfsHcComponentName,
    813              &gUfsHcComponentName2
    814              );
    815   ASSERT_EFI_ERROR (Status);
    816 
    817   return Status;
    818 }
    819