2 * PCIe Sata support for the Silicon Image I3132
4 * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
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
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.
16 #include "SataSiI3132.h"
18 #include <IndustryStandard/Acpi10.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/DxeServicesTableLib.h>
23 #include <Library/BaseLib.h>
25 #define ACPI_SPECFLAG_PREFETCHABLE 0x06
27 EFI_DRIVER_BINDING_PROTOCOL
28 gSataSiI3132DriverBinding
= {
29 SataSiI3132DriverBindingSupported
,
30 SataSiI3132DriverBindingStart
,
31 SataSiI3132DriverBindingStop
,
38 SataSiI3132PortConstructor (
39 IN SATA_SI3132_INSTANCE
*SataSiI3132Instance
,
44 SATA_SI3132_PORT
*Port
;
46 EFI_PHYSICAL_ADDRESS PhysAddrHostPRB
;
47 VOID
*PciAllocMappingPRB
;
50 Port
= &(SataSiI3132Instance
->Ports
[Index
]);
53 Port
->RegBase
= Index
* 0x2000;
54 Port
->Instance
= SataSiI3132Instance
;
55 InitializeListHead (&(Port
->Devices
));
57 NumberOfBytes
= sizeof (SATA_SI3132_PRB
);
58 Status
= SataSiI3132Instance
->PciIo
->AllocateBuffer (
59 SataSiI3132Instance
->PciIo
, AllocateAnyPages
, EfiBootServicesData
,
60 EFI_SIZE_TO_PAGES (NumberOfBytes
), &HostPRB
, 0
62 if (EFI_ERROR (Status
)) {
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
72 if (EFI_ERROR (Status
)) {
76 Port
->HostPRB
= HostPRB
;
77 Port
->PhysAddrHostPRB
= PhysAddrHostPRB
;
78 Port
->PciAllocMappingPRB
= PciAllocMappingPRB
;
85 SataSiI3132Constructor (
86 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
87 OUT SATA_SI3132_INSTANCE
** SataSiI3132Instance
90 SATA_SI3132_INSTANCE
*Instance
;
91 EFI_ATA_PASS_THRU_MODE
*AtaPassThruMode
;
93 if (!SataSiI3132Instance
) {
94 return EFI_INVALID_PARAMETER
;
97 Instance
= (SATA_SI3132_INSTANCE
*)AllocateZeroPool (sizeof (SATA_SI3132_INSTANCE
));
98 if (Instance
== NULL
) {
99 return EFI_OUT_OF_RESOURCES
;
102 Instance
->Signature
= SATA_SII3132_SIGNATURE
;
103 Instance
->PciIo
= PciIo
;
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;
109 // Initialize SiI3132 ports
110 SataSiI3132PortConstructor (Instance
, 0);
111 SataSiI3132PortConstructor (Instance
, 1);
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
;
123 *SataSiI3132Instance
= Instance
;
129 SiI3132SoftResetCommand (
130 IN SATA_SI3132_PORT
*Port
,
131 OUT UINT32
* Signature
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;
140 ZeroMem (&Acb
, sizeof (EFI_ATA_COMMAND_BLOCK
));
142 Acb
.Reserved1
[1] = 0;
146 Packet
.Timeout
= 100000;
147 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET
;
149 Status
= SiI3132AtaPassThruCommand (Port
->Instance
, Port
, PortMultiplierPort
, &Packet
, 0);
151 if (Status
== EFI_SUCCESS
) {
152 *Signature
= (Asb
.AtaCylinderHigh
<< 24) | (Asb
.AtaCylinderLow
<< 16) |
153 (Asb
.AtaSectorNumber
<< 8 ) | (Asb
.AtaSectorCount
);
159 SataSiI3132PortInitialization (
160 IN SATA_SI3132_PORT
*Port
164 SATA_SI3132_DEVICE
* Device
;
167 EFI_PCI_IO_PROTOCOL
* PciIo
;
169 Status
= SiI3132HwResetPort (Port
);
170 if (EFI_ERROR (Status
)) {
174 PciIo
= Port
->Instance
->PciIo
;
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
188 return EFI_UNSUPPORTED
;
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");
197 SATA_TRACE ("SataSiI3132PortInitialization(): Present device unknown!");
198 ASSERT (0); // Not supported
199 return EFI_UNSUPPORTED
;
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
206 Device
->BlockSize
= 0;
208 // Attached the device to the Sata Port
209 InsertTailList (&Port
->Devices
, &Device
->Link
);
211 SATA_TRACE ("SataSiI3132PortInitialization(): Port Ready");
218 SataSiI3132Initialization (
219 IN SATA_SI3132_INSTANCE
* SataSiI3132Instance
223 EFI_PCI_IO_PROTOCOL
* PciIo
;
225 if (!SataSiI3132Instance
) {
226 return EFI_INVALID_PARAMETER
;
229 PciIo
= SataSiI3132Instance
->PciIo
;
232 SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_FLASHADDR_REG
, 0x0);
234 // Clear Global Control Register
235 SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_CONTROL_REG
, 0x0);
237 for (Index
= 0; Index
< SATA_SII3132_MAXPORT
; Index
++) {
238 SataSiI3132PortInitialization (&(SataSiI3132Instance
->Ports
[Index
]));
245 Test to see if this driver supports ControllerHandle.
247 @param This Protocol instance pointer.
248 @param Controller Handle of device to test.
249 @param RemainingDevicePath Not used.
251 @return EFI_SUCCESS This driver supports this device.
252 @return EFI_UNSUPPORTED This driver does not support this device.
257 SataSiI3132DriverBindingSupported (
258 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
259 IN EFI_HANDLE Controller
,
260 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
264 EFI_PCI_IO_PROTOCOL
*PciIo
;
268 // Test whether there is PCI IO Protocol attached on the controller handle.
270 Status
= gBS
->OpenProtocol (
272 &gEfiPciIoProtocolGuid
,
274 This
->DriverBindingHandle
,
276 EFI_OPEN_PROTOCOL_BY_DRIVER
278 if (EFI_ERROR (Status
)) {
282 Status
= PciIo
->Pci
.Read (
285 PCI_VENDOR_ID_OFFSET
,
289 if (EFI_ERROR (Status
)) {
290 Status
= EFI_UNSUPPORTED
;
295 // Test whether the controller belongs to SATA Mass Storage type
297 if (PciID
!= ((SATA_SII3132_DEVICE_ID
<< 16) | SATA_SII3132_VENDOR_ID
)) {
298 Status
= EFI_UNSUPPORTED
;
304 &gEfiPciIoProtocolGuid
,
305 This
->DriverBindingHandle
,
312 BOOLEAN mbStarted
= FALSE
;
315 Starting the Pci SATA Driver.
317 @param This Protocol instance pointer.
318 @param Controller Handle of device to test.
319 @param RemainingDevicePath Not used.
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.
329 SataSiI3132DriverBindingStart (
330 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
331 IN EFI_HANDLE Controller
,
332 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
336 EFI_PCI_IO_PROTOCOL
*PciIo
;
338 UINT64 OriginalPciAttributes
;
339 BOOLEAN PciAttributesSaved
;
341 SATA_SI3132_INSTANCE
*SataSiI3132Instance
= NULL
;
343 SATA_TRACE ("SataSiI3132DriverBindingStart()");
345 //TODO: Find a nicer way to do it !
347 return EFI_SUCCESS
; // Don't restart me !
351 // Open the PciIo Protocol
353 Status
= gBS
->OpenProtocol (
355 &gEfiPciIoProtocolGuid
,
357 This
->DriverBindingHandle
,
359 EFI_OPEN_PROTOCOL_BY_DRIVER
361 if (EFI_ERROR (Status
)) {
365 PciAttributesSaved
= FALSE
;
367 // Save original PCI attributes
369 Status
= PciIo
->Attributes (
371 EfiPciIoAttributeOperationGet
,
373 &OriginalPciAttributes
375 if (EFI_ERROR (Status
)) {
378 PciAttributesSaved
= TRUE
;
380 Status
= PciIo
->Attributes (
382 EfiPciIoAttributeOperationSupported
,
386 if (!EFI_ERROR (Status
)) {
387 Supports
&= EFI_PCI_DEVICE_ENABLE
;
388 Status
= PciIo
->Attributes (
390 EfiPciIoAttributeOperationEnable
,
395 if (EFI_ERROR (Status
)) {
396 DEBUG ((EFI_D_ERROR
, "SataSiI3132DriverBindingStart: failed to enable controller\n"));
401 // Get the Pci device class code.
403 Status
= PciIo
->Pci
.Read (
406 PCI_VENDOR_ID_OFFSET
,
410 if (EFI_ERROR (Status
)) {
411 Status
= EFI_UNSUPPORTED
;
416 // Test whether the controller belongs to SATA Mass Storage type
418 if (PciID
!= ((SATA_SII3132_DEVICE_ID
<< 16) | SATA_SII3132_VENDOR_ID
)) {
419 Status
= EFI_UNSUPPORTED
;
423 // Create SiI3132 Sata Instance
424 Status
= SataSiI3132Constructor (PciIo
, &SataSiI3132Instance
);
425 if (EFI_ERROR (Status
)) {
429 // Initialize SiI3132 Sata Controller
430 Status
= SataSiI3132Initialization (SataSiI3132Instance
);
431 if (EFI_ERROR (Status
)) {
435 // Install Ata Pass Thru Protocol
436 Status
= gBS
->InstallProtocolInterface (
438 &gEfiAtaPassThruProtocolGuid
,
439 EFI_NATIVE_INTERFACE
,
440 &(SataSiI3132Instance
->AtaPassThruProtocol
)
442 if (EFI_ERROR (Status
)) {
447 // Create event to stop the HC when exit boot service.
449 Status = gBS->CreateEventEx (
454 &gEfiEventExitBootServicesGuid,
455 &Ehc->ExitBootServiceEvent
457 if (EFI_ERROR (Status)) {
458 goto UNINSTALL_USBHC;
463 SATA_TRACE ("SataSiI3132DriverBindingStart() Success!");
467 //TODO: Free SATA Instance
470 if (PciAttributesSaved
) {
472 // Restore original PCI attributes
476 EfiPciIoAttributeOperationSet
,
477 OriginalPciAttributes
,
484 &gEfiPciIoProtocolGuid
,
485 This
->DriverBindingHandle
,
493 Stop this driver on ControllerHandle. Support stoping any child handles
494 created by this driver.
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.
501 @return EFI_SUCCESS Success.
502 @return EFI_DEVICE_ERROR Fail.
507 SataSiI3132DriverBindingStop (
508 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
509 IN EFI_HANDLE Controller
,
510 IN UINTN NumberOfChildren
,
511 IN EFI_HANDLE
*ChildHandleBuffer
514 SATA_TRACE ("SataSiI3132DriverBindingStop()");
515 return EFI_UNSUPPORTED
;
519 Entry point of this driver
521 @param ImageHandle Handle of driver image
522 @param SystemTable Point to EFI_SYSTEM_TABLE
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.
530 InitializeSataSiI3132 (
531 IN EFI_HANDLE ImageHandle
,
532 IN EFI_SYSTEM_TABLE
*SystemTable
535 SATA_TRACE ("InitializeSataSiI3132 ()");
537 return EfiLibInstallDriverBindingComponentName2 (
540 &gSataSiI3132DriverBinding
,
542 &gSataSiI3132ComponentName
,
543 &gSataSiI3132ComponentName2