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