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
UfsHcGetMmioBar(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This,OUT UINTN * MmioBar)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
UfsHcMap(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This,IN EDKII_UFS_HOST_CONTROLLER_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)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
UfsHcUnmap(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This,IN VOID * Mapping)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
UfsHcAllocateBuffer(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,OUT VOID ** HostAddress,IN UINT64 Attributes)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
UfsHcFreeBuffer(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This,IN UINTN Pages,IN VOID * HostAddress)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
UfsHcFlush(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This)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
UfsHcMmioRead(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This,IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH Width,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
UfsHcMmioWrite(IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL * This,IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH Width,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
UfsHcDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
UfsHcDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
UfsHcDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
UfsHcDriverEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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