]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
ArmPlatformPkg: eliminate Juno gcc build warning
[mirror_edk2.git] / ArmPlatformPkg / ArmJunoPkg / Drivers / ArmJunoDxe / ArmJunoDxe.c
1 /** @file
2 *
3 * Copyright (c) 2013-2015, ARM Limited. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include "ArmJunoDxeInternal.h"
16 #include <ArmPlatform.h>
17
18 #include <IndustryStandard/Pci.h>
19 #include <Protocol/DevicePathFromText.h>
20 #include <Protocol/PciIo.h>
21 #include <Protocol/PciRootBridgeIo.h>
22
23 #include <Guid/EventGroup.h>
24 #include <Guid/GlobalVariable.h>
25
26 #include <Library/ArmShellCmdLib.h>
27 #include <Library/AcpiLib.h>
28 #include <Library/BaseMemoryLib.h>
29 #include <Library/DevicePathLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/NonDiscoverableDeviceRegistrationLib.h>
32 #include <Library/UefiRuntimeServicesTableLib.h>
33 #include <Library/IoLib.h>
34 #include <Library/PrintLib.h>
35
36
37 // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf
38 STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };
39
40 typedef struct {
41 ACPI_HID_DEVICE_PATH AcpiDevicePath;
42 PCI_DEVICE_PATH PciDevicePath;
43 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
44 } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
45
46 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = {
47 {
48 { ACPI_DEVICE_PATH,
49 ACPI_DP,
50 { (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
51 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) }
52 },
53 EISA_PNP_ID (0x0A03),
54 0
55 },
56 {
57 { HARDWARE_DEVICE_PATH,
58 HW_PCI_DP,
59 { (UINT8) (sizeof (PCI_DEVICE_PATH)),
60 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) }
61 },
62 0,
63 0
64 },
65 {
66 END_DEVICE_PATH_TYPE,
67 END_ENTIRE_DEVICE_PATH_SUBTYPE,
68 { END_DEVICE_PATH_LENGTH, 0 }
69 }
70 };
71
72 EFI_EVENT mAcpiRegistration = NULL;
73
74 /**
75 This function reads PCI ID of the controller.
76
77 @param[in] PciIo PCI IO protocol handle
78 @param[in] PciId Looking for specified PCI ID Vendor/Device
79 **/
80 STATIC
81 EFI_STATUS
82 ReadMarvellYoukonPciId (
83 IN EFI_PCI_IO_PROTOCOL *PciIo,
84 IN UINT32 PciId
85 )
86 {
87 UINT32 DevicePciId;
88 EFI_STATUS Status;
89
90 Status = PciIo->Pci.Read (
91 PciIo,
92 EfiPciIoWidthUint32,
93 PCI_VENDOR_ID_OFFSET,
94 1,
95 &DevicePciId);
96 if (EFI_ERROR (Status)) {
97 return Status;
98 }
99
100 if (DevicePciId != PciId) {
101 return EFI_NOT_FOUND;
102 }
103
104 return EFI_SUCCESS;
105 }
106
107 /**
108 This function searches for Marvell Yukon NIC on the Juno
109 platform and returns PCI IO protocol handle for the controller.
110
111 @param[out] PciIo PCI IO protocol handle
112 **/
113 STATIC
114 EFI_STATUS
115 GetMarvellYukonPciIoProtocol (
116 OUT EFI_PCI_IO_PROTOCOL **PciIo
117 )
118 {
119 UINTN HandleCount;
120 EFI_HANDLE *HandleBuffer;
121 UINTN HIndex;
122 EFI_STATUS Status;
123
124 Status = gBS->LocateHandleBuffer (
125 ByProtocol,
126 &gEfiPciIoProtocolGuid,
127 NULL,
128 &HandleCount,
129 &HandleBuffer);
130 if (EFI_ERROR (Status)) {
131 return (Status);
132 }
133
134 for (HIndex = 0; HIndex < HandleCount; ++HIndex) {
135 // If PciIo opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL, the CloseProtocol() is not required
136 Status = gBS->OpenProtocol (
137 HandleBuffer[HIndex],
138 &gEfiPciIoProtocolGuid,
139 (VOID **) PciIo,
140 NULL,
141 NULL,
142 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
143 if (EFI_ERROR (Status)) {
144 continue;
145 }
146
147 Status = ReadMarvellYoukonPciId (*PciIo, JUNO_MARVELL_YUKON_ID);
148 if (EFI_ERROR (Status)) {
149 continue;
150 } else {
151 break;
152 }
153 }
154
155 gBS->FreePool (HandleBuffer);
156
157 return Status;
158 }
159
160 /**
161 This function restore the original controller attributes
162
163 @param[in] PciIo PCI IO protocol handle
164 @param[in] PciAttr PCI controller attributes.
165 @param[in] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR
166 **/
167 STATIC
168 VOID
169 RestorePciDev (
170 IN EFI_PCI_IO_PROTOCOL *PciIo,
171 IN UINT64 PciAttr
172 )
173 {
174 PciIo->Attributes (
175 PciIo,
176 EfiPciIoAttributeOperationSet,
177 PciAttr,
178 NULL
179 );
180 }
181
182 /**
183 This function returns PCI MMIO base address for a controller
184
185 @param[in] PciIo PCI IO protocol handle
186 @param[out] PciRegBase PCI base MMIO address
187 **/
188 STATIC
189 EFI_STATUS
190 BarIsDeviceMemory (
191 IN EFI_PCI_IO_PROTOCOL *PciIo,
192 OUT UINT32 *PciRegBase
193 )
194 {
195 EFI_STATUS Status;
196 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiResDescriptor;
197 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiCurrentDescriptor;
198
199 // Marvell Yukon's Bar0 provides base memory address for control registers
200 Status = PciIo->GetBarAttributes (PciIo, PCI_BAR_IDX0, NULL, (VOID**)&AcpiResDescriptor);
201 if (EFI_ERROR (Status)) {
202 return Status;
203 }
204
205 AcpiCurrentDescriptor = AcpiResDescriptor;
206
207 // Search for a memory type descriptor
208 while (AcpiCurrentDescriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
209
210 // Check if Bar is memory type one and fetch a base address
211 if (AcpiCurrentDescriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&
212 AcpiCurrentDescriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM &&
213 !(AcpiCurrentDescriptor->SpecificFlag & ACPI_SPECFLAG_PREFETCHABLE)) {
214 *PciRegBase = AcpiCurrentDescriptor->AddrRangeMin;
215 break;
216 } else {
217 Status = EFI_UNSUPPORTED;
218 }
219
220 AcpiCurrentDescriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (AcpiCurrentDescriptor + 1);
221 }
222
223 gBS->FreePool (AcpiResDescriptor);
224
225 return Status;
226 }
227
228 /**
229 This function provides PCI MMIO base address, old PCI controller attributes.
230
231 @param[in] PciIo PCI IO protocol handle
232 @param[out] PciRegBase PCI base MMIO address
233 @param[out] OldPciAttr Old PCI controller attributes.
234 **/
235 STATIC
236 EFI_STATUS
237 InitPciDev (
238 IN EFI_PCI_IO_PROTOCOL *PciIo,
239 OUT UINT32 *PciRegBase,
240 OUT UINT64 *OldPciAttr
241 )
242 {
243 UINT64 AttrSupports;
244 EFI_STATUS Status;
245
246 // Get controller's current attributes
247 Status = PciIo->Attributes (
248 PciIo,
249 EfiPciIoAttributeOperationGet,
250 0,
251 OldPciAttr);
252 if (EFI_ERROR (Status)) {
253 return Status;
254 }
255
256 // Fetch supported attributes
257 Status = PciIo->Attributes (
258 PciIo,
259 EfiPciIoAttributeOperationSupported,
260 0,
261 &AttrSupports);
262 if (EFI_ERROR (Status)) {
263 return Status;
264 }
265
266 // Enable EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY and
267 // EFI_PCI_IO_ATTRIBUTE_BUS_MASTER bits in the PCI Config Header
268 AttrSupports &= EFI_PCI_DEVICE_ENABLE;
269 Status = PciIo->Attributes (
270 PciIo,
271 EfiPciIoAttributeOperationEnable,
272 AttrSupports,
273 NULL);
274 if (EFI_ERROR (Status)) {
275 return Status;
276 }
277
278 Status = BarIsDeviceMemory (PciIo, PciRegBase);
279 if (EFI_ERROR (Status)) {
280 RestorePciDev (PciIo, *OldPciAttr);
281 }
282
283 return Status;
284 }
285
286 /**
287 This function reads MAC address from IOFPGA and writes it to Marvell Yukon NIC
288
289 @param[in] PciRegBase PCI base MMIO address
290 **/
291 STATIC
292 EFI_STATUS
293 WriteMacAddress (
294 IN UINT32 PciRegBase
295 )
296 {
297 UINT32 MacHigh;
298 UINT32 MacLow;
299
300 // Read MAC address from IOFPGA
301 MacHigh= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H);
302 MacLow = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L);
303
304 // Set software reset control register to protect from deactivation
305 // the config write state
306 MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);
307
308 // Convert to Marvell MAC Address register format
309 MacHigh = SwapBytes32 ((MacHigh & 0xFFFF) << 16 |
310 (MacLow & 0xFFFF0000) >> 16);
311 MacLow = SwapBytes32 (MacLow) >> 16;
312
313 // Set MAC Address
314 MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_ENABLE);
315 MmioWrite32 (PciRegBase + R_MAC, MacHigh);
316 MmioWrite32 (PciRegBase + R_MAC_MAINT, MacHigh);
317 MmioWrite32 (PciRegBase + R_MAC + R_MAC_LOW, MacLow);
318 MmioWrite32 (PciRegBase + R_MAC_MAINT + R_MAC_LOW, MacLow);
319 MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_DISABLE);
320
321 // Initiate device reset
322 MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_SET);
323 MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);
324
325 return EFI_SUCCESS;
326 }
327
328 /**
329 The function reads MAC address from Juno IOFPGA registers and writes it
330 into Marvell Yukon NIC.
331 **/
332 STATIC
333 EFI_STATUS
334 ArmJunoSetNicMacAddress ()
335 {
336 UINT64 OldPciAttr;
337 EFI_PCI_IO_PROTOCOL* PciIo;
338 UINT32 PciRegBase;
339 EFI_STATUS Status;
340
341 Status = GetMarvellYukonPciIoProtocol (&PciIo);
342 if (EFI_ERROR (Status)) {
343 return Status;
344 }
345
346 PciRegBase = 0;
347 Status = InitPciDev (PciIo, &PciRegBase, &OldPciAttr);
348 if (EFI_ERROR (Status)) {
349 return Status;
350 }
351
352 Status = WriteMacAddress (PciRegBase);
353
354 RestorePciDev (PciIo, OldPciAttr);
355
356 return EFI_SUCCESS;
357 }
358
359 /**
360 Notification function of the event defined as belonging to the
361 EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in
362 the entry point of the driver.
363
364 This function is called when an event belonging to the
365 EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an
366 event is signalled once at the end of the dispatching of all
367 drivers (end of the so called DXE phase).
368
369 @param[in] Event Event declared in the entry point of the driver whose
370 notification function is being invoked.
371 @param[in] Context NULL
372 **/
373 STATIC
374 VOID
375 OnEndOfDxe (
376 IN EFI_EVENT Event,
377 IN VOID *Context
378 )
379 {
380 EFI_DEVICE_PATH_PROTOCOL* PciRootComplexDevicePath;
381 EFI_HANDLE Handle;
382 EFI_STATUS Status;
383
384 //
385 // PCI Root Complex initialization
386 // At the end of the DXE phase, we should get all the driver dispatched.
387 // Force the PCI Root Complex to be initialized. It allows the OS to skip
388 // this step.
389 //
390 PciRootComplexDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) &mPciRootComplexDevicePath;
391 Status = gBS->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid,
392 &PciRootComplexDevicePath,
393 &Handle);
394
395 Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE);
396 ASSERT_EFI_ERROR (Status);
397
398 Status = ArmJunoSetNicMacAddress ();
399 if (EFI_ERROR (Status)) {
400 DEBUG ((DEBUG_ERROR, "ArmJunoDxe: Failed to set Marvell Yukon NIC MAC address\n"));
401 }
402 }
403
404 EFI_STATUS
405 EFIAPI
406 ArmJunoEntryPoint (
407 IN EFI_HANDLE ImageHandle,
408 IN EFI_SYSTEM_TABLE *SystemTable
409 )
410 {
411 EFI_STATUS Status;
412 EFI_PHYSICAL_ADDRESS HypBase;
413 CHAR16 *TextDevicePath;
414 UINTN TextDevicePathSize;
415 VOID *Buffer;
416 UINT32 JunoRevision;
417 EFI_EVENT EndOfDxeEvent;
418
419 //
420 // Register the OHCI and EHCI controllers as non-coherent
421 // non-discoverable devices.
422 //
423 Status = RegisterNonDiscoverableMmioDevice (
424 NonDiscoverableDeviceTypeOhci,
425 NonDiscoverableDeviceDmaTypeNonCoherent,
426 NULL,
427 NULL,
428 1,
429 FixedPcdGet32 (PcdSynopsysUsbOhciBaseAddress),
430 SIZE_64KB
431 );
432 ASSERT_EFI_ERROR (Status);
433
434 Status = RegisterNonDiscoverableMmioDevice (
435 NonDiscoverableDeviceTypeEhci,
436 NonDiscoverableDeviceDmaTypeNonCoherent,
437 NULL,
438 NULL,
439 1,
440 FixedPcdGet32 (PcdSynopsysUsbEhciBaseAddress),
441 SIZE_64KB
442 );
443 ASSERT_EFI_ERROR (Status);
444
445 //
446 // If a hypervisor has been declared then we need to make sure its region is protected at runtime
447 //
448 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)
449 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.
450 //
451 if (FixedPcdGet32 (PcdHypFvSize) != 0) {
452 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.
453 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.
454 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded
455 // to this size then there is a risk some non-runtime memory could be visible to the OS view.
456 if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) {
457 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space
458 // as it contains the Firmware.
459 Status = gDS->AddMemorySpace (
460 EfiGcdMemoryTypeSystemMemory,
461 FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize),
462 EFI_MEMORY_WB | EFI_MEMORY_RUNTIME
463 );
464 if (!EFI_ERROR (Status)) {
465 // We allocate the memory to ensure it is marked as runtime memory
466 HypBase = FixedPcdGet32 (PcdHypFvBaseAddress);
467 Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode,
468 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase);
469 }
470 } else {
471 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned
472 // on a EFI_PAGE_SIZE boundary (ie: 4KB).
473 Status = EFI_UNSUPPORTED;
474 ASSERT_EFI_ERROR (Status);
475 }
476
477 if (EFI_ERROR (Status)) {
478 return Status;
479 }
480 }
481
482 // Install dynamic Shell command to run baremetal binaries.
483 Status = ShellDynCmdRunAxfInstall (ImageHandle);
484 if (EFI_ERROR (Status)) {
485 DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));
486 }
487
488 GetJunoRevision(JunoRevision);
489
490 //
491 // Try to install the ACPI Tables
492 //
493 Status = LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile);
494 ASSERT_EFI_ERROR (Status);
495
496 //
497 // Setup R1/R2 options if not already done.
498 //
499 if (JunoRevision != JUNO_REVISION_R0) {
500 // Enable PCI enumeration
501 PcdSetBool (PcdPciDisableBusEnumeration, FALSE);
502
503 //
504 // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.
505 // The "OnEndOfDxe()" function is declared as the call back function.
506 // It will be called at the end of the DXE phase when an event of the
507 // same group is signalled to inform about the end of the DXE phase.
508 // Install the INSTALL_FDT_PROTOCOL protocol.
509 //
510 Status = gBS->CreateEventEx (
511 EVT_NOTIFY_SIGNAL,
512 TPL_CALLBACK,
513 OnEndOfDxe,
514 NULL,
515 &gEfiEndOfDxeEventGroupGuid,
516 &EndOfDxeEvent
517 );
518
519 // Declare the related ACPI Tables
520 EfiCreateProtocolNotifyEvent (
521 &gEfiAcpiTableProtocolGuid,
522 TPL_CALLBACK,
523 AcpiPciNotificationEvent,
524 NULL,
525 &mAcpiRegistration
526 );
527 }
528
529 //
530 // Set up the device path to the FDT.
531 //
532 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoFdtDevicePath);
533 if (TextDevicePath != NULL) {
534 TextDevicePathSize = StrSize (TextDevicePath);
535 Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);
536 Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
537 } else {
538 Status = EFI_NOT_FOUND;
539 }
540
541 if (EFI_ERROR (Status)) {
542 DEBUG (
543 (EFI_D_ERROR,
544 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status)
545 );
546 return Status;
547 }
548
549 return Status;
550 }