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