2 * PCIe Sata support for the Silicon Image I3132
4 * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
6 * SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "SataSiI3132.h"
12 #include <IndustryStandard/Acpi10.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/DxeServicesTableLib.h>
17 #include <Library/BaseLib.h>
19 #define ACPI_SPECFLAG_PREFETCHABLE 0x06
21 EFI_DRIVER_BINDING_PROTOCOL
22 gSataSiI3132DriverBinding
= {
23 SataSiI3132DriverBindingSupported
,
24 SataSiI3132DriverBindingStart
,
25 SataSiI3132DriverBindingStop
,
32 SataSiI3132PortConstructor (
33 IN SATA_SI3132_INSTANCE
*SataSiI3132Instance
,
38 SATA_SI3132_PORT
*Port
;
40 EFI_PHYSICAL_ADDRESS PhysAddrHostPRB
;
41 VOID
*PciAllocMappingPRB
;
44 Port
= &(SataSiI3132Instance
->Ports
[Index
]);
47 Port
->RegBase
= Index
* 0x2000;
48 Port
->Instance
= SataSiI3132Instance
;
49 InitializeListHead (&(Port
->Devices
));
51 NumberOfBytes
= sizeof (SATA_SI3132_PRB
);
52 Status
= SataSiI3132Instance
->PciIo
->AllocateBuffer (
53 SataSiI3132Instance
->PciIo
, AllocateAnyPages
, EfiBootServicesData
,
54 EFI_SIZE_TO_PAGES (NumberOfBytes
), &HostPRB
, 0
56 if (EFI_ERROR (Status
)) {
60 // Check the alignment of the PCI Buffer
61 ASSERT (((UINTN
)HostPRB
& (0x1000 - 1)) == 0);
62 Status
= SataSiI3132Instance
->PciIo
->Map (
63 SataSiI3132Instance
->PciIo
, EfiPciIoOperationBusMasterCommonBuffer
, HostPRB
,
64 &NumberOfBytes
, &PhysAddrHostPRB
, &PciAllocMappingPRB
66 if (EFI_ERROR (Status
)) {
70 Port
->HostPRB
= HostPRB
;
71 Port
->PhysAddrHostPRB
= PhysAddrHostPRB
;
72 Port
->PciAllocMappingPRB
= PciAllocMappingPRB
;
79 SataSiI3132Constructor (
80 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
81 OUT SATA_SI3132_INSTANCE
** SataSiI3132Instance
84 SATA_SI3132_INSTANCE
*Instance
;
85 EFI_ATA_PASS_THRU_MODE
*AtaPassThruMode
;
87 if (!SataSiI3132Instance
) {
88 return EFI_INVALID_PARAMETER
;
91 Instance
= (SATA_SI3132_INSTANCE
*)AllocateZeroPool (sizeof (SATA_SI3132_INSTANCE
));
92 if (Instance
== NULL
) {
93 return EFI_OUT_OF_RESOURCES
;
96 Instance
->Signature
= SATA_SII3132_SIGNATURE
;
97 Instance
->PciIo
= PciIo
;
99 AtaPassThruMode
= (EFI_ATA_PASS_THRU_MODE
*)AllocatePool (sizeof (EFI_ATA_PASS_THRU_MODE
));
100 AtaPassThruMode
->Attributes
= EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL
;
101 AtaPassThruMode
->IoAlign
= 0x1000;
103 // Initialize SiI3132 ports
104 SataSiI3132PortConstructor (Instance
, 0);
105 SataSiI3132PortConstructor (Instance
, 1);
107 // Set ATA Pass Thru Protocol
108 Instance
->AtaPassThruProtocol
.Mode
= AtaPassThruMode
;
109 Instance
->AtaPassThruProtocol
.PassThru
= SiI3132AtaPassThru
;
110 Instance
->AtaPassThruProtocol
.GetNextPort
= SiI3132GetNextPort
;
111 Instance
->AtaPassThruProtocol
.GetNextDevice
= SiI3132GetNextDevice
;
112 Instance
->AtaPassThruProtocol
.BuildDevicePath
= SiI3132BuildDevicePath
;
113 Instance
->AtaPassThruProtocol
.GetDevice
= SiI3132GetDevice
;
114 Instance
->AtaPassThruProtocol
.ResetPort
= SiI3132ResetPort
;
115 Instance
->AtaPassThruProtocol
.ResetDevice
= SiI3132ResetDevice
;
117 *SataSiI3132Instance
= Instance
;
123 SiI3132SoftResetCommand (
124 IN SATA_SI3132_PORT
*Port
,
125 OUT UINT32
* Signature
129 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet
;
130 EFI_ATA_STATUS_BLOCK Asb
;
131 EFI_ATA_COMMAND_BLOCK Acb
;
132 CONST UINT16 PortMultiplierPort
= 0;
134 ZeroMem (&Acb
, sizeof (EFI_ATA_COMMAND_BLOCK
));
136 Acb
.Reserved1
[1] = 0;
140 Packet
.Timeout
= 100000;
141 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET
;
143 Status
= SiI3132AtaPassThruCommand (Port
->Instance
, Port
, PortMultiplierPort
, &Packet
, 0);
145 if (Status
== EFI_SUCCESS
) {
146 *Signature
= (Asb
.AtaCylinderHigh
<< 24) | (Asb
.AtaCylinderLow
<< 16) |
147 (Asb
.AtaSectorNumber
<< 8 ) | (Asb
.AtaSectorCount
);
153 SataSiI3132PortInitialization (
154 IN SATA_SI3132_PORT
*Port
158 SATA_SI3132_DEVICE
* Device
;
161 EFI_PCI_IO_PROTOCOL
* PciIo
;
163 Status
= SiI3132HwResetPort (Port
);
164 if (EFI_ERROR (Status
)) {
168 PciIo
= Port
->Instance
->PciIo
;
170 // Is a device is present ?
171 Status
= SATA_PORT_READ32 (Port
->RegBase
+ SII3132_PORT_SSTATUS_REG
, &Value32
);
172 if (!EFI_ERROR (Status
) && (Value32
& 0x3)) {
173 // Do a soft reset to see if it is a port multiplier
174 SATA_TRACE ("SataSiI3132PortInitialization: soft reset - it is a port multiplier\n");
175 Status
= SiI3132SoftResetCommand (Port
, &Signature
);
176 if (!EFI_ERROR (Status
)) {
177 if (Signature
== SII3132_PORT_SIGNATURE_PMP
) {
178 SATA_TRACE ("SataSiI3132PortInitialization(): a Port Multiplier is present");
179 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport
)) {
180 ASSERT (0); // Not supported yet
182 return EFI_UNSUPPORTED
;
184 } else if (Signature
== SII3132_PORT_SIGNATURE_ATAPI
) {
185 ASSERT (0); // Not supported yet
186 SATA_TRACE ("SataSiI3132PortInitialization(): an ATAPI device is present");
187 return EFI_UNSUPPORTED
;
188 } else if (Signature
== SII3132_PORT_SIGNATURE_ATA
) {
189 SATA_TRACE ("SataSiI3132PortInitialization(): an ATA device is present");
191 SATA_TRACE ("SataSiI3132PortInitialization(): Present device unknown!");
192 ASSERT (0); // Not supported
193 return EFI_UNSUPPORTED
;
197 Device
= (SATA_SI3132_DEVICE
*)AllocatePool (sizeof (SATA_SI3132_DEVICE
));
198 Device
->Index
= Port
->Index
; //TODO: Could need to be fixed when SATA Port Multiplier support
200 Device
->BlockSize
= 0;
202 // Attached the device to the Sata Port
203 InsertTailList (&Port
->Devices
, &Device
->Link
);
205 SATA_TRACE ("SataSiI3132PortInitialization(): Port Ready");
212 SataSiI3132Initialization (
213 IN SATA_SI3132_INSTANCE
* SataSiI3132Instance
217 EFI_PCI_IO_PROTOCOL
* PciIo
;
219 if (!SataSiI3132Instance
) {
220 return EFI_INVALID_PARAMETER
;
223 PciIo
= SataSiI3132Instance
->PciIo
;
226 SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_FLASHADDR_REG
, 0x0);
228 // Clear Global Control Register
229 SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_CONTROL_REG
, 0x0);
231 for (Index
= 0; Index
< SATA_SII3132_MAXPORT
; Index
++) {
232 SataSiI3132PortInitialization (&(SataSiI3132Instance
->Ports
[Index
]));
239 Test to see if this driver supports ControllerHandle.
241 @param This Protocol instance pointer.
242 @param Controller Handle of device to test.
243 @param RemainingDevicePath Not used.
245 @return EFI_SUCCESS This driver supports this device.
246 @return EFI_UNSUPPORTED This driver does not support this device.
251 SataSiI3132DriverBindingSupported (
252 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
253 IN EFI_HANDLE Controller
,
254 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
258 EFI_PCI_IO_PROTOCOL
*PciIo
;
262 // Test whether there is PCI IO Protocol attached on the controller handle.
264 Status
= gBS
->OpenProtocol (
266 &gEfiPciIoProtocolGuid
,
268 This
->DriverBindingHandle
,
270 EFI_OPEN_PROTOCOL_BY_DRIVER
272 if (EFI_ERROR (Status
)) {
276 Status
= PciIo
->Pci
.Read (
279 PCI_VENDOR_ID_OFFSET
,
283 if (EFI_ERROR (Status
)) {
284 Status
= EFI_UNSUPPORTED
;
289 // Test whether the controller belongs to SATA Mass Storage type
291 if (PciID
!= ((SATA_SII3132_DEVICE_ID
<< 16) | SATA_SII3132_VENDOR_ID
)) {
292 Status
= EFI_UNSUPPORTED
;
298 &gEfiPciIoProtocolGuid
,
299 This
->DriverBindingHandle
,
306 BOOLEAN mbStarted
= FALSE
;
309 Starting the Pci SATA Driver.
311 @param This Protocol instance pointer.
312 @param Controller Handle of device to test.
313 @param RemainingDevicePath Not used.
315 @return EFI_SUCCESS supports this device.
316 @return EFI_UNSUPPORTED do not support this device.
317 @return EFI_DEVICE_ERROR cannot be started due to device Error.
318 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
323 SataSiI3132DriverBindingStart (
324 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
325 IN EFI_HANDLE Controller
,
326 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
330 EFI_PCI_IO_PROTOCOL
*PciIo
;
332 UINT64 OriginalPciAttributes
;
333 BOOLEAN PciAttributesSaved
;
335 SATA_SI3132_INSTANCE
*SataSiI3132Instance
= NULL
;
337 SATA_TRACE ("SataSiI3132DriverBindingStart()");
339 //TODO: Find a nicer way to do it !
341 return EFI_SUCCESS
; // Don't restart me !
345 // Open the PciIo Protocol
347 Status
= gBS
->OpenProtocol (
349 &gEfiPciIoProtocolGuid
,
351 This
->DriverBindingHandle
,
353 EFI_OPEN_PROTOCOL_BY_DRIVER
355 if (EFI_ERROR (Status
)) {
359 PciAttributesSaved
= FALSE
;
361 // Save original PCI attributes
363 Status
= PciIo
->Attributes (
365 EfiPciIoAttributeOperationGet
,
367 &OriginalPciAttributes
369 if (EFI_ERROR (Status
)) {
372 PciAttributesSaved
= TRUE
;
374 Status
= PciIo
->Attributes (
376 EfiPciIoAttributeOperationSupported
,
380 if (!EFI_ERROR (Status
)) {
381 Supports
&= EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
;
382 Status
= PciIo
->Attributes (
384 EfiPciIoAttributeOperationEnable
,
389 if (EFI_ERROR (Status
)) {
390 DEBUG ((EFI_D_ERROR
, "SataSiI3132DriverBindingStart: failed to enable controller\n"));
395 // Get the Pci device class code.
397 Status
= PciIo
->Pci
.Read (
400 PCI_VENDOR_ID_OFFSET
,
404 if (EFI_ERROR (Status
)) {
405 Status
= EFI_UNSUPPORTED
;
410 // Test whether the controller belongs to SATA Mass Storage type
412 if (PciID
!= ((SATA_SII3132_DEVICE_ID
<< 16) | SATA_SII3132_VENDOR_ID
)) {
413 Status
= EFI_UNSUPPORTED
;
417 // Create SiI3132 Sata Instance
418 Status
= SataSiI3132Constructor (PciIo
, &SataSiI3132Instance
);
419 if (EFI_ERROR (Status
)) {
423 // Initialize SiI3132 Sata Controller
424 Status
= SataSiI3132Initialization (SataSiI3132Instance
);
425 if (EFI_ERROR (Status
)) {
429 // Install Ata Pass Thru Protocol
430 Status
= gBS
->InstallProtocolInterface (
432 &gEfiAtaPassThruProtocolGuid
,
433 EFI_NATIVE_INTERFACE
,
434 &(SataSiI3132Instance
->AtaPassThruProtocol
)
436 if (EFI_ERROR (Status
)) {
441 // Create event to stop the HC when exit boot service.
443 Status = gBS->CreateEventEx (
448 &gEfiEventExitBootServicesGuid,
449 &Ehc->ExitBootServiceEvent
451 if (EFI_ERROR (Status)) {
452 goto UNINSTALL_USBHC;
457 SATA_TRACE ("SataSiI3132DriverBindingStart() Success!");
461 //TODO: Free SATA Instance
464 if (PciAttributesSaved
) {
466 // Restore original PCI attributes
470 EfiPciIoAttributeOperationSet
,
471 OriginalPciAttributes
,
478 &gEfiPciIoProtocolGuid
,
479 This
->DriverBindingHandle
,
487 Stop this driver on ControllerHandle. Support stopping any child handles
488 created by this driver.
490 @param This Protocol instance pointer.
491 @param Controller Handle of device to stop driver on.
492 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
493 @param ChildHandleBuffer List of handles for the children we need to stop.
495 @return EFI_SUCCESS Success.
496 @return EFI_DEVICE_ERROR Fail.
501 SataSiI3132DriverBindingStop (
502 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
503 IN EFI_HANDLE Controller
,
504 IN UINTN NumberOfChildren
,
505 IN EFI_HANDLE
*ChildHandleBuffer
508 SATA_TRACE ("SataSiI3132DriverBindingStop()");
509 return EFI_UNSUPPORTED
;
513 Entry point of this driver
515 @param ImageHandle Handle of driver image
516 @param SystemTable Point to EFI_SYSTEM_TABLE
518 @retval EFI_OUT_OF_RESOURCES Can not allocate memory resource
519 @retval EFI_DEVICE_ERROR Can not install the protocol instance
520 @retval EFI_SUCCESS Success to initialize the Pci host bridge.
524 InitializeSataSiI3132 (
525 IN EFI_HANDLE ImageHandle
,
526 IN EFI_SYSTEM_TABLE
*SystemTable
529 SATA_TRACE ("InitializeSataSiI3132 ()");
531 return EfiLibInstallDriverBindingComponentName2 (
534 &gSataSiI3132DriverBinding
,
536 &gSataSiI3132ComponentName
,
537 &gSataSiI3132ComponentName2