3 * Copyright (c) 2013-2015, ARM Limited. All rights reserved.
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
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.
15 #include "ArmJunoDxeInternal.h"
16 #include <ArmPlatform.h>
18 #include <IndustryStandard/Pci.h>
19 #include <Protocol/DevicePathFromText.h>
20 #include <Protocol/PciIo.h>
21 #include <Protocol/PciRootBridgeIo.h>
23 #include <Guid/EventGroup.h>
24 #include <Guid/GlobalVariable.h>
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/UefiRuntimeServicesTableLib.h>
32 #include <Library/IoLib.h>
33 #include <Library/PrintLib.h>
36 // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf
37 STATIC CONST EFI_GUID mJunoAcpiTableFile
= { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };
40 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
41 PCI_DEVICE_PATH PciDevicePath
;
42 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
43 } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH
;
45 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath
= {
49 { (UINT8
) (sizeof (ACPI_HID_DEVICE_PATH
)),
50 (UINT8
) ((sizeof (ACPI_HID_DEVICE_PATH
)) >> 8) }
56 { HARDWARE_DEVICE_PATH
,
58 { (UINT8
) (sizeof (PCI_DEVICE_PATH
)),
59 (UINT8
) ((sizeof (PCI_DEVICE_PATH
)) >> 8) }
66 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
67 { END_DEVICE_PATH_LENGTH
, 0 }
71 EFI_EVENT mAcpiRegistration
= NULL
;
74 This function reads PCI ID of the controller.
76 @param[in] PciIo PCI IO protocol handle
77 @param[in] PciId Looking for specified PCI ID Vendor/Device
81 ReadMarvellYoukonPciId (
82 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
89 Status
= PciIo
->Pci
.Read (
95 if (EFI_ERROR (Status
)) {
99 if (DevicePciId
!= PciId
) {
100 return EFI_NOT_FOUND
;
107 This function searches for Marvell Yukon NIC on the Juno
108 platform and returns PCI IO protocol handle for the controller.
110 @param[out] PciIo PCI IO protocol handle
114 GetMarvellYukonPciIoProtocol (
115 OUT EFI_PCI_IO_PROTOCOL
**PciIo
119 EFI_HANDLE
*HandleBuffer
;
123 Status
= gBS
->LocateHandleBuffer (
125 &gEfiPciIoProtocolGuid
,
129 if (EFI_ERROR (Status
)) {
133 for (HIndex
= 0; HIndex
< HandleCount
; ++HIndex
) {
134 // If PciIo opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL, the CloseProtocol() is not required
135 Status
= gBS
->OpenProtocol (
136 HandleBuffer
[HIndex
],
137 &gEfiPciIoProtocolGuid
,
141 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
142 if (EFI_ERROR (Status
)) {
146 Status
= ReadMarvellYoukonPciId (*PciIo
, JUNO_MARVELL_YUKON_ID
);
147 if (EFI_ERROR (Status
)) {
154 gBS
->FreePool (HandleBuffer
);
160 This function restore the original controller attributes
162 @param[in] PciIo PCI IO protocol handle
163 @param[in] PciAttr PCI controller attributes.
164 @param[in] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR
169 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
175 EfiPciIoAttributeOperationSet
,
182 This function returns PCI MMIO base address for a controller
184 @param[in] PciIo PCI IO protocol handle
185 @param[out] PciRegBase PCI base MMIO address
190 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
191 OUT UINT32
*PciRegBase
195 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*AcpiResDescriptor
;
196 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*AcpiCurrentDescriptor
;
198 // Marvell Yukon's Bar0 provides base memory address for control registers
199 Status
= PciIo
->GetBarAttributes (PciIo
, PCI_BAR_IDX0
, NULL
, (VOID
**)&AcpiResDescriptor
);
200 if (EFI_ERROR (Status
)) {
204 AcpiCurrentDescriptor
= AcpiResDescriptor
;
206 // Search for a memory type descriptor
207 while (AcpiCurrentDescriptor
->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
209 // Check if Bar is memory type one and fetch a base address
210 if (AcpiCurrentDescriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
&&
211 AcpiCurrentDescriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
&&
212 !(AcpiCurrentDescriptor
->SpecificFlag
& ACPI_SPECFLAG_PREFETCHABLE
)) {
213 *PciRegBase
= AcpiCurrentDescriptor
->AddrRangeMin
;
216 Status
= EFI_UNSUPPORTED
;
219 AcpiCurrentDescriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) (AcpiCurrentDescriptor
+ 1);
222 gBS
->FreePool (AcpiResDescriptor
);
228 This function provides PCI MMIO base address, old PCI controller attributes.
230 @param[in] PciIo PCI IO protocol handle
231 @param[out] PciRegBase PCI base MMIO address
232 @param[out] OldPciAttr Old PCI controller attributes.
237 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
238 OUT UINT32
*PciRegBase
,
239 OUT UINT64
*OldPciAttr
245 // Get controller's current attributes
246 Status
= PciIo
->Attributes (
248 EfiPciIoAttributeOperationGet
,
251 if (EFI_ERROR (Status
)) {
255 // Fetch supported attributes
256 Status
= PciIo
->Attributes (
258 EfiPciIoAttributeOperationSupported
,
261 if (EFI_ERROR (Status
)) {
265 // Enable EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY and
266 // EFI_PCI_IO_ATTRIBUTE_BUS_MASTER bits in the PCI Config Header
267 AttrSupports
&= EFI_PCI_DEVICE_ENABLE
;
268 Status
= PciIo
->Attributes (
270 EfiPciIoAttributeOperationEnable
,
273 if (EFI_ERROR (Status
)) {
277 Status
= BarIsDeviceMemory (PciIo
, PciRegBase
);
278 if (EFI_ERROR (Status
)) {
279 RestorePciDev (PciIo
, *OldPciAttr
);
286 This function reads MAC address from IOFPGA and writes it to Marvell Yukon NIC
288 @param[in] PciRegBase PCI base MMIO address
299 // Read MAC address from IOFPGA
300 MacHigh
= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H
);
301 MacLow
= MmioRead32 (ARM_JUNO_SYS_PCIGBE_L
);
303 // Set software reset control register to protect from deactivation
304 // the config write state
305 MmioWrite16 (PciRegBase
+ R_CONTROL_STATUS
, CS_RESET_CLR
);
307 // Convert to Marvell MAC Address register format
308 MacHigh
= SwapBytes32 ((MacHigh
& 0xFFFF) << 16 |
309 (MacLow
& 0xFFFF0000) >> 16);
310 MacLow
= SwapBytes32 (MacLow
) >> 16;
313 MmioWrite8 (PciRegBase
+ R_TST_CTRL_1
, TST_CFG_WRITE_ENABLE
);
314 MmioWrite32 (PciRegBase
+ R_MAC
, MacHigh
);
315 MmioWrite32 (PciRegBase
+ R_MAC_MAINT
, MacHigh
);
316 MmioWrite32 (PciRegBase
+ R_MAC
+ R_MAC_LOW
, MacLow
);
317 MmioWrite32 (PciRegBase
+ R_MAC_MAINT
+ R_MAC_LOW
, MacLow
);
318 MmioWrite8 (PciRegBase
+ R_TST_CTRL_1
, TST_CFG_WRITE_DISABLE
);
320 // Initiate device reset
321 MmioWrite16 (PciRegBase
+ R_CONTROL_STATUS
, CS_RESET_SET
);
322 MmioWrite16 (PciRegBase
+ R_CONTROL_STATUS
, CS_RESET_CLR
);
328 The function reads MAC address from Juno IOFPGA registers and writes it
329 into Marvell Yukon NIC.
333 ArmJunoSetNicMacAddress ()
336 EFI_PCI_IO_PROTOCOL
* PciIo
;
340 Status
= GetMarvellYukonPciIoProtocol (&PciIo
);
341 if (EFI_ERROR (Status
)) {
345 Status
= InitPciDev (PciIo
, &PciRegBase
, &OldPciAttr
);
346 if (EFI_ERROR (Status
)) {
350 Status
= WriteMacAddress (PciRegBase
);
352 RestorePciDev (PciIo
, OldPciAttr
);
358 Notification function of the event defined as belonging to the
359 EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in
360 the entry point of the driver.
362 This function is called when an event belonging to the
363 EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an
364 event is signalled once at the end of the dispatching of all
365 drivers (end of the so called DXE phase).
367 @param[in] Event Event declared in the entry point of the driver whose
368 notification function is being invoked.
369 @param[in] Context NULL
378 EFI_DEVICE_PATH_PROTOCOL
* PciRootComplexDevicePath
;
384 // PCI Root Complex initialization
385 // At the end of the DXE phase, we should get all the driver dispatched.
386 // Force the PCI Root Complex to be initialized. It allows the OS to skip
389 PciRootComplexDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &mPciRootComplexDevicePath
;
390 Status
= gBS
->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid
,
391 &PciRootComplexDevicePath
,
394 Status
= gBS
->ConnectController (Handle
, NULL
, PciRootComplexDevicePath
, FALSE
);
395 ASSERT_EFI_ERROR (Status
);
397 GetJunoRevision (JunoRevision
);
399 if (JunoRevision
!= JUNO_REVISION_R0
) {
400 Status
= ArmJunoSetNicMacAddress ();
401 if (EFI_ERROR (Status
)) {
402 DEBUG ((DEBUG_ERROR
, "ArmJunoDxe: Failed to set Marvell Yukon NIC MAC address\n"));
409 AcpiTableJunoR0Check (
410 IN EFI_ACPI_DESCRIPTION_HEADER
*AcpiHeader
418 AcpiTableJunoR1Check (
419 IN EFI_ACPI_DESCRIPTION_HEADER
*AcpiHeader
427 AcpiTableJunoR2Check (
428 IN EFI_ACPI_DESCRIPTION_HEADER
*AcpiHeader
438 IN EFI_HANDLE ImageHandle
,
439 IN EFI_SYSTEM_TABLE
*SystemTable
443 EFI_PHYSICAL_ADDRESS HypBase
;
444 CHAR16
*TextDevicePath
;
445 UINTN TextDevicePathSize
;
448 EFI_EVENT EndOfDxeEvent
;
450 Status
= PciEmulationEntryPoint ();
451 if (EFI_ERROR (Status
)) {
456 // If a hypervisor has been declared then we need to make sure its region is protected at runtime
458 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)
459 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.
461 if (FixedPcdGet32 (PcdHypFvSize
) != 0) {
462 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.
463 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.
464 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded
465 // to this size then there is a risk some non-runtime memory could be visible to the OS view.
466 if (((FixedPcdGet32 (PcdHypFvSize
) & EFI_PAGE_MASK
) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress
) & EFI_PAGE_MASK
) == 0)) {
467 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space
468 // as it contains the Firmware.
469 Status
= gDS
->AddMemorySpace (
470 EfiGcdMemoryTypeSystemMemory
,
471 FixedPcdGet32 (PcdHypFvBaseAddress
), FixedPcdGet32 (PcdHypFvSize
),
472 EFI_MEMORY_WB
| EFI_MEMORY_RUNTIME
474 if (!EFI_ERROR (Status
)) {
475 // We allocate the memory to ensure it is marked as runtime memory
476 HypBase
= FixedPcdGet32 (PcdHypFvBaseAddress
);
477 Status
= gBS
->AllocatePages (AllocateAddress
, EfiRuntimeServicesCode
,
478 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize
)), &HypBase
);
481 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned
482 // on a EFI_PAGE_SIZE boundary (ie: 4KB).
483 Status
= EFI_UNSUPPORTED
;
484 ASSERT_EFI_ERROR (Status
);
487 if (EFI_ERROR (Status
)) {
493 // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.
494 // The "OnEndOfDxe()" function is declared as the call back function.
495 // It will be called at the end of the DXE phase when an event of the
496 // same group is signalled to inform about the end of the DXE phase.
497 // Install the INSTALL_FDT_PROTOCOL protocol.
499 Status
= gBS
->CreateEventEx (
504 &gEfiEndOfDxeEventGroupGuid
,
508 // Install dynamic Shell command to run baremetal binaries.
509 Status
= ShellDynCmdRunAxfInstall (ImageHandle
);
510 if (EFI_ERROR (Status
)) {
511 DEBUG ((EFI_D_ERROR
, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));
514 GetJunoRevision(JunoRevision
);
517 // Try to install the ACPI Tables
519 if (JunoRevision
== JUNO_REVISION_R0
) {
520 Status
= LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile
, AcpiTableJunoR0Check
);
521 } else if (JunoRevision
== JUNO_REVISION_R1
) {
522 Status
= LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile
, AcpiTableJunoR1Check
);
523 } else if (JunoRevision
== JUNO_REVISION_R2
) {
524 Status
= LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile
, AcpiTableJunoR2Check
);
527 ASSERT_EFI_ERROR (Status
);
530 // Setup R1/R2 options if not already done.
532 if (JunoRevision
!= JUNO_REVISION_R0
) {
533 // Enable PCI enumeration
534 PcdSetBool (PcdPciDisableBusEnumeration
, FALSE
);
536 // Declare the related ACPI Tables
537 EfiCreateProtocolNotifyEvent (
538 &gEfiAcpiTableProtocolGuid
,
540 AcpiPciNotificationEvent
,
547 // Set up the device path to the FDT.
549 TextDevicePath
= (CHAR16
*)FixedPcdGetPtr (PcdJunoFdtDevicePath
);
550 if (TextDevicePath
!= NULL
) {
551 TextDevicePathSize
= StrSize (TextDevicePath
);
552 Buffer
= PcdSetPtr (PcdFdtDevicePaths
, &TextDevicePathSize
, TextDevicePath
);
553 Status
= (Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_BUFFER_TOO_SMALL
;
555 Status
= EFI_NOT_FOUND
;
558 if (EFI_ERROR (Status
)) {
561 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status
)