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