1 /** @file
2 *  PCIe Sata support for the Silicon Image I3132
3 *
4 *  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
5 *
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 "SataSiI3132.h"
17 
18 #include <IndustryStandard/Acpi10.h>
19 
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/DxeServicesTableLib.h>
23 #include <Library/BaseLib.h>
24 
25 #define ACPI_SPECFLAG_PREFETCHABLE      0x06
26 
27 EFI_DRIVER_BINDING_PROTOCOL
28 gSataSiI3132DriverBinding = {
29   SataSiI3132DriverBindingSupported,
30   SataSiI3132DriverBindingStart,
31   SataSiI3132DriverBindingStop,
32   0x30,
33   NULL,
34   NULL
35 };
36 
37 EFI_STATUS
SataSiI3132PortConstructor(IN SATA_SI3132_INSTANCE * SataSiI3132Instance,IN UINTN Index)38 SataSiI3132PortConstructor (
39   IN  SATA_SI3132_INSTANCE *SataSiI3132Instance,
40   IN  UINTN                Index
41   )
42 {
43   EFI_STATUS            Status;
44   SATA_SI3132_PORT      *Port;
45   VOID                  *HostPRB;
46   EFI_PHYSICAL_ADDRESS  PhysAddrHostPRB;
47   VOID                  *PciAllocMappingPRB;
48   UINTN                 NumberOfBytes;
49 
50   Port = &(SataSiI3132Instance->Ports[Index]);
51 
52   Port->Index    = Index;
53   Port->RegBase  = Index * 0x2000;
54   Port->Instance = SataSiI3132Instance;
55   InitializeListHead (&(Port->Devices));
56 
57   NumberOfBytes = sizeof (SATA_SI3132_PRB);
58   Status = SataSiI3132Instance->PciIo->AllocateBuffer (
59              SataSiI3132Instance->PciIo, AllocateAnyPages, EfiBootServicesData,
60              EFI_SIZE_TO_PAGES (NumberOfBytes), &HostPRB, 0
61              );
62   if (EFI_ERROR (Status)) {
63     return Status;
64   }
65 
66   // Check the alignment of the PCI Buffer
67   ASSERT (((UINTN)HostPRB & (0x1000 - 1)) == 0);
68   Status = SataSiI3132Instance->PciIo->Map (
69              SataSiI3132Instance->PciIo, EfiPciIoOperationBusMasterCommonBuffer, HostPRB,
70              &NumberOfBytes, &PhysAddrHostPRB, &PciAllocMappingPRB
71              );
72   if (EFI_ERROR (Status)) {
73     return Status;
74   }
75 
76   Port->HostPRB            = HostPRB;
77   Port->PhysAddrHostPRB    = PhysAddrHostPRB;
78   Port->PciAllocMappingPRB = PciAllocMappingPRB;
79 
80   return Status;
81 }
82 
83 STATIC
84 EFI_STATUS
SataSiI3132Constructor(IN EFI_PCI_IO_PROTOCOL * PciIo,OUT SATA_SI3132_INSTANCE ** SataSiI3132Instance)85 SataSiI3132Constructor (
86   IN  EFI_PCI_IO_PROTOCOL     *PciIo,
87   OUT SATA_SI3132_INSTANCE**  SataSiI3132Instance
88   )
89 {
90   SATA_SI3132_INSTANCE    *Instance;
91   EFI_ATA_PASS_THRU_MODE  *AtaPassThruMode;
92 
93   if (!SataSiI3132Instance) {
94     return EFI_INVALID_PARAMETER;
95   }
96 
97   Instance = (SATA_SI3132_INSTANCE*)AllocateZeroPool (sizeof (SATA_SI3132_INSTANCE));
98   if (Instance == NULL) {
99     return EFI_OUT_OF_RESOURCES;
100   }
101 
102   Instance->Signature           = SATA_SII3132_SIGNATURE;
103   Instance->PciIo               = PciIo;
104 
105   AtaPassThruMode = (EFI_ATA_PASS_THRU_MODE*)AllocatePool (sizeof (EFI_ATA_PASS_THRU_MODE));
106   AtaPassThruMode->Attributes = EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL;
107   AtaPassThruMode->IoAlign = 0x1000;
108 
109   // Initialize SiI3132 ports
110   SataSiI3132PortConstructor (Instance, 0);
111   SataSiI3132PortConstructor (Instance, 1);
112 
113   // Set ATA Pass Thru Protocol
114   Instance->AtaPassThruProtocol.Mode            = AtaPassThruMode;
115   Instance->AtaPassThruProtocol.PassThru        = SiI3132AtaPassThru;
116   Instance->AtaPassThruProtocol.GetNextPort     = SiI3132GetNextPort;
117   Instance->AtaPassThruProtocol.GetNextDevice   = SiI3132GetNextDevice;
118   Instance->AtaPassThruProtocol.BuildDevicePath = SiI3132BuildDevicePath;
119   Instance->AtaPassThruProtocol.GetDevice       = SiI3132GetDevice;
120   Instance->AtaPassThruProtocol.ResetPort       = SiI3132ResetPort;
121   Instance->AtaPassThruProtocol.ResetDevice     = SiI3132ResetDevice;
122 
123   *SataSiI3132Instance = Instance;
124 
125   return EFI_SUCCESS;
126 }
127 
128 EFI_STATUS
SiI3132SoftResetCommand(IN SATA_SI3132_PORT * Port,OUT UINT32 * Signature)129 SiI3132SoftResetCommand (
130   IN   SATA_SI3132_PORT *Port,
131   OUT  UINT32* Signature
132   )
133 {
134   EFI_STATUS                        Status;
135   EFI_ATA_PASS_THRU_COMMAND_PACKET  Packet;
136   EFI_ATA_STATUS_BLOCK              Asb;
137   EFI_ATA_COMMAND_BLOCK             Acb;
138   CONST UINT16                      PortMultiplierPort = 0;
139 
140   ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
141 
142   Acb.Reserved1[1] = 0;
143 
144   Packet.Asb      = &Asb;
145   Packet.Acb      = &Acb;
146   Packet.Timeout  = 100000;
147   Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET;
148 
149   Status = SiI3132AtaPassThruCommand (Port->Instance, Port, PortMultiplierPort, &Packet, 0);
150 
151   if (Status == EFI_SUCCESS) {
152     *Signature = (Asb.AtaCylinderHigh << 24) | (Asb.AtaCylinderLow << 16) |
153                  (Asb.AtaSectorNumber << 8 ) | (Asb.AtaSectorCount);
154   }
155   return Status;
156 }
157 
158 EFI_STATUS
SataSiI3132PortInitialization(IN SATA_SI3132_PORT * Port)159 SataSiI3132PortInitialization (
160   IN SATA_SI3132_PORT *Port
161   )
162 {
163   UINT32                  Value32;
164   SATA_SI3132_DEVICE*     Device;
165   UINT32                  Signature;
166   EFI_STATUS              Status;
167   EFI_PCI_IO_PROTOCOL*    PciIo;
168 
169   Status = SiI3132HwResetPort (Port);
170   if (EFI_ERROR (Status)) {
171     return Status;
172   }
173 
174   PciIo = Port->Instance->PciIo;
175 
176   // Is a device is present ?
177   Status = SATA_PORT_READ32 (Port->RegBase + SII3132_PORT_SSTATUS_REG, &Value32);
178   if (!EFI_ERROR (Status) && (Value32 & 0x3)) {
179     // Do a soft reset to see if it is a port multiplier
180     SATA_TRACE ("SataSiI3132PortInitialization: soft reset - it is a port multiplier\n");
181     Status = SiI3132SoftResetCommand (Port, &Signature);
182     if (!EFI_ERROR (Status)) {
183       if (Signature == SII3132_PORT_SIGNATURE_PMP) {
184         SATA_TRACE ("SataSiI3132PortInitialization(): a Port Multiplier is present");
185         if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
186           ASSERT (0); // Not supported yet
187         } else {
188           return EFI_UNSUPPORTED;
189         }
190       } else if (Signature == SII3132_PORT_SIGNATURE_ATAPI) {
191         ASSERT (0); // Not supported yet
192         SATA_TRACE ("SataSiI3132PortInitialization(): an ATAPI device is present");
193         return EFI_UNSUPPORTED;
194       } else if (Signature == SII3132_PORT_SIGNATURE_ATA) {
195         SATA_TRACE ("SataSiI3132PortInitialization(): an ATA device is present");
196       } else {
197         SATA_TRACE ("SataSiI3132PortInitialization(): Present device unknown!");
198         ASSERT (0); // Not supported
199         return EFI_UNSUPPORTED;
200       }
201 
202       // Create Device
203       Device            = (SATA_SI3132_DEVICE*)AllocatePool (sizeof (SATA_SI3132_DEVICE));
204       Device->Index     = Port->Index; //TODO: Could need to be fixed when SATA Port Multiplier support
205       Device->Port      = Port;
206       Device->BlockSize = 0;
207 
208       // Attached the device to the Sata Port
209       InsertTailList (&Port->Devices, &Device->Link);
210 
211       SATA_TRACE ("SataSiI3132PortInitialization(): Port Ready");
212     }
213   }
214   return Status;
215 }
216 
217 EFI_STATUS
SataSiI3132Initialization(IN SATA_SI3132_INSTANCE * SataSiI3132Instance)218 SataSiI3132Initialization (
219   IN SATA_SI3132_INSTANCE* SataSiI3132Instance
220   )
221 {
222   UINTN                 Index;
223   EFI_PCI_IO_PROTOCOL*  PciIo;
224 
225   if (!SataSiI3132Instance) {
226     return EFI_INVALID_PARAMETER;
227   }
228 
229   PciIo = SataSiI3132Instance->PciIo;
230 
231   // Turn Off GPIO
232   SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_FLASHADDR_REG, 0x0);
233 
234   // Clear Global Control Register
235   SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_CONTROL_REG, 0x0);
236 
237   for (Index = 0; Index < SATA_SII3132_MAXPORT; Index++) {
238     SataSiI3132PortInitialization (&(SataSiI3132Instance->Ports[Index]));
239   }
240 
241   return EFI_SUCCESS;
242 }
243 
244 /**
245   Test to see if this driver supports ControllerHandle.
246 
247   @param  This                 Protocol instance pointer.
248   @param  Controller           Handle of device to test.
249   @param  RemainingDevicePath  Not used.
250 
251   @return EFI_SUCCESS          This driver supports this device.
252   @return EFI_UNSUPPORTED      This driver does not support this device.
253 
254 **/
255 EFI_STATUS
256 EFIAPI
SataSiI3132DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)257 SataSiI3132DriverBindingSupported (
258   IN EFI_DRIVER_BINDING_PROTOCOL *This,
259   IN EFI_HANDLE                  Controller,
260   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
261   )
262 {
263   EFI_STATUS              Status;
264   EFI_PCI_IO_PROTOCOL     *PciIo;
265   UINT32                   PciID;
266 
267   //
268   // Test whether there is PCI IO Protocol attached on the controller handle.
269   //
270   Status = gBS->OpenProtocol (
271                 Controller,
272                 &gEfiPciIoProtocolGuid,
273                 (VOID **) &PciIo,
274                 This->DriverBindingHandle,
275                 Controller,
276                 EFI_OPEN_PROTOCOL_BY_DRIVER
277                 );
278   if (EFI_ERROR (Status)) {
279       return Status;
280   }
281 
282   Status = PciIo->Pci.Read (
283                       PciIo,
284                       EfiPciIoWidthUint32,
285                       PCI_VENDOR_ID_OFFSET,
286                       1,
287                       &PciID
288                       );
289   if (EFI_ERROR (Status)) {
290       Status = EFI_UNSUPPORTED;
291       goto ON_EXIT;
292   }
293 
294   //
295   // Test whether the controller belongs to SATA Mass Storage type
296   //
297   if (PciID != ((SATA_SII3132_DEVICE_ID << 16) | SATA_SII3132_VENDOR_ID)) {
298       Status = EFI_UNSUPPORTED;
299   }
300 
301 ON_EXIT:
302   gBS->CloseProtocol (
303        Controller,
304        &gEfiPciIoProtocolGuid,
305        This->DriverBindingHandle,
306        Controller
307        );
308 
309   return Status;
310 }
311 
312 BOOLEAN mbStarted = FALSE;
313 
314 /**
315   Starting the Pci SATA Driver.
316 
317   @param  This                 Protocol instance pointer.
318   @param  Controller           Handle of device to test.
319   @param  RemainingDevicePath  Not used.
320 
321   @return EFI_SUCCESS          supports this device.
322   @return EFI_UNSUPPORTED      do not support this device.
323   @return EFI_DEVICE_ERROR     cannot be started due to device Error.
324   @return EFI_OUT_OF_RESOURCES cannot allocate resources.
325 
326 **/
327 EFI_STATUS
328 EFIAPI
SataSiI3132DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)329 SataSiI3132DriverBindingStart (
330   IN EFI_DRIVER_BINDING_PROTOCOL *This,
331   IN EFI_HANDLE                  Controller,
332   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
333   )
334 {
335   EFI_STATUS              Status;
336   EFI_PCI_IO_PROTOCOL     *PciIo;
337   UINT64                  Supports;
338   UINT64                  OriginalPciAttributes;
339   BOOLEAN                 PciAttributesSaved;
340   UINT32                  PciID;
341   SATA_SI3132_INSTANCE    *SataSiI3132Instance = NULL;
342 
343   SATA_TRACE ("SataSiI3132DriverBindingStart()");
344 
345   //TODO: Find a nicer way to do it !
346   if (mbStarted) {
347     return EFI_SUCCESS; // Don't restart me !
348   }
349 
350   //
351   // Open the PciIo Protocol
352   //
353   Status = gBS->OpenProtocol (
354                 Controller,
355                 &gEfiPciIoProtocolGuid,
356                 (VOID **) &PciIo,
357                 This->DriverBindingHandle,
358                 Controller,
359                 EFI_OPEN_PROTOCOL_BY_DRIVER
360                 );
361   if (EFI_ERROR (Status)) {
362       return Status;
363   }
364 
365   PciAttributesSaved = FALSE;
366   //
367   // Save original PCI attributes
368   //
369   Status = PciIo->Attributes (
370                   PciIo,
371                   EfiPciIoAttributeOperationGet,
372                   0,
373                   &OriginalPciAttributes
374                   );
375   if (EFI_ERROR (Status)) {
376       goto CLOSE_PCIIO;
377   }
378   PciAttributesSaved = TRUE;
379 
380   Status = PciIo->Attributes (
381                   PciIo,
382                   EfiPciIoAttributeOperationSupported,
383                   0,
384                   &Supports
385                   );
386   if (!EFI_ERROR (Status)) {
387       Supports &= EFI_PCI_DEVICE_ENABLE;
388       Status = PciIo->Attributes (
389                         PciIo,
390                         EfiPciIoAttributeOperationEnable,
391                         Supports,
392                         NULL
393                         );
394   }
395   if (EFI_ERROR (Status)) {
396     DEBUG ((EFI_D_ERROR, "SataSiI3132DriverBindingStart: failed to enable controller\n"));
397     goto CLOSE_PCIIO;
398   }
399 
400   //
401   // Get the Pci device class code.
402   //
403   Status = PciIo->Pci.Read (
404                       PciIo,
405                       EfiPciIoWidthUint32,
406                       PCI_VENDOR_ID_OFFSET,
407                       1,
408                       &PciID
409                       );
410   if (EFI_ERROR (Status)) {
411     Status = EFI_UNSUPPORTED;
412     goto CLOSE_PCIIO;
413   }
414 
415   //
416   // Test whether the controller belongs to SATA Mass Storage type
417   //
418   if (PciID != ((SATA_SII3132_DEVICE_ID << 16) | SATA_SII3132_VENDOR_ID)) {
419     Status = EFI_UNSUPPORTED;
420     goto CLOSE_PCIIO;
421   }
422 
423   // Create SiI3132 Sata Instance
424   Status = SataSiI3132Constructor (PciIo, &SataSiI3132Instance);
425   if (EFI_ERROR (Status)) {
426     return Status;
427   }
428 
429   // Initialize SiI3132 Sata Controller
430   Status = SataSiI3132Initialization (SataSiI3132Instance);
431   if (EFI_ERROR (Status)) {
432     return Status;
433   }
434 
435   // Install Ata Pass Thru Protocol
436   Status = gBS->InstallProtocolInterface (
437               &Controller,
438               &gEfiAtaPassThruProtocolGuid,
439               EFI_NATIVE_INTERFACE,
440               &(SataSiI3132Instance->AtaPassThruProtocol)
441               );
442   if (EFI_ERROR (Status)) {
443     goto FREE_POOL;
444   }
445 
446 /*  //
447   // Create event to stop the HC when exit boot service.
448   //
449   Status = gBS->CreateEventEx (
450                 EVT_NOTIFY_SIGNAL,
451                 TPL_NOTIFY,
452                 EhcExitBootService,
453                 Ehc,
454                 &gEfiEventExitBootServicesGuid,
455                 &Ehc->ExitBootServiceEvent
456                 );
457   if (EFI_ERROR (Status)) {
458       goto UNINSTALL_USBHC;
459   }*/
460 
461   mbStarted = TRUE;
462 
463   SATA_TRACE ("SataSiI3132DriverBindingStart() Success!");
464   return EFI_SUCCESS;
465 
466 FREE_POOL:
467   //TODO: Free SATA Instance
468 
469 CLOSE_PCIIO:
470   if (PciAttributesSaved) {
471       //
472       // Restore original PCI attributes
473       //
474       PciIo->Attributes (
475                       PciIo,
476                       EfiPciIoAttributeOperationSet,
477                       OriginalPciAttributes,
478                       NULL
479                       );
480   }
481 
482   gBS->CloseProtocol (
483        Controller,
484        &gEfiPciIoProtocolGuid,
485        This->DriverBindingHandle,
486        Controller
487        );
488 
489   return Status;
490 }
491 
492 /**
493   Stop this driver on ControllerHandle. Support stoping any child handles
494   created by this driver.
495 
496   @param  This                 Protocol instance pointer.
497   @param  Controller           Handle of device to stop driver on.
498   @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
499   @param  ChildHandleBuffer    List of handles for the children we need to stop.
500 
501   @return EFI_SUCCESS          Success.
502   @return EFI_DEVICE_ERROR     Fail.
503 
504 **/
505 EFI_STATUS
506 EFIAPI
SataSiI3132DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)507 SataSiI3132DriverBindingStop (
508   IN EFI_DRIVER_BINDING_PROTOCOL *This,
509   IN EFI_HANDLE                  Controller,
510   IN UINTN                       NumberOfChildren,
511   IN EFI_HANDLE                  *ChildHandleBuffer
512   )
513 {
514   SATA_TRACE ("SataSiI3132DriverBindingStop()");
515   return EFI_UNSUPPORTED;
516 }
517 
518 /**
519   Entry point of this driver
520 
521   @param ImageHandle     Handle of driver image
522   @param SystemTable     Point to EFI_SYSTEM_TABLE
523 
524   @retval EFI_OUT_OF_RESOURCES  Can not allocate memory resource
525   @retval EFI_DEVICE_ERROR      Can not install the protocol instance
526   @retval EFI_SUCCESS           Success to initialize the Pci host bridge.
527 **/
528 EFI_STATUS
529 EFIAPI
InitializeSataSiI3132(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)530 InitializeSataSiI3132 (
531   IN EFI_HANDLE        ImageHandle,
532   IN EFI_SYSTEM_TABLE  *SystemTable
533   )
534 {
535   SATA_TRACE ("InitializeSataSiI3132 ()");
536 
537   return EfiLibInstallDriverBindingComponentName2 (
538          ImageHandle,
539          SystemTable,
540          &gSataSiI3132DriverBinding,
541          ImageHandle,
542          &gSataSiI3132ComponentName,
543          &gSataSiI3132ComponentName2
544          );
545 }
546