feat(intel): add FDT support for Altera products
Support FDT for Agilex5 platform
1. Created wrapper file socfpga_dt.c
2. Added in Agilex5 dts file
3. Implemented fdt_check_header
4. Implemented gic configuration
5. Implemented dram configuration
Remove init of FDT as Agilex5 has no plan to roll
out FDT at the moment.
Change-Id: If3990ed9524c6da5b3cb8966b63bc4a95d01fcda
Signed-off-by: Jit Loon Lim <jit.loon.lim@altera.com>
diff --git a/plat/intel/soc/common/fdts/agilex5_fdt.dts b/plat/intel/soc/common/fdts/agilex5_fdt.dts
new file mode 100644
index 0000000..e16034f
--- /dev/null
+++ b/plat/intel/soc/common/fdts/agilex5_fdt.dts
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019-2024, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ model = "ALTERA SOCFPGA AGILEX5";
+ compatible = "arm,altera socfpga-agilex5";
+ owner = "jit.loon.lim@intel.com";
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+ method = "smc";
+
+ cpu_on = <0xdeadc0de>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "psci";
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <0>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <1>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <2>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <3>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x90000000>;
+ };
+
+ gic: interrupt-controller@2c010000 {
+ compatible = "arm,gic-600", "arm,gic-v3";
+ #address-cells = <2>;
+ #interrupt-cells = <3>;
+ #size-cells = <1>;
+ #ranges;
+ interrupt-controller;
+ reg = <0x1D000000 0>, /* GICD */
+ <0x1D060000 0>; /* GICR */
+ interrupts = <0x1 0x9 0x4>;
+ };
+
+ serial0: uart@1a200000 {
+ compatible = "arm,console-16550";
+ reg = <0x10C02000 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 8 0xf04>;
+ clock-frequency = <100000000>;
+ uart-baudrate = <115200>;
+ };
+
+ timer0: timer@1a040000 {
+ compatible = "arm,armv7-timer-mem";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0x1a040000 0x1000>;
+ clock-frequency = <7500000>;
+
+ frame@1a050000 {
+ frame-number = <0>;
+ interrupts = <0 2 0xf04>;
+ reg = <0x1a050000 0x1000>;
+ };
+ };
+
+};
diff --git a/plat/intel/soc/common/include/socfpga_dt.h b/plat/intel/soc/common/include/socfpga_dt.h
new file mode 100644
index 0000000..3ff4cb7
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_dt.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_DT_H
+#define SOCFPGA_DT_H
+
+
+#include <stdlib.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+/*
+ * This macro takes three arguments:
+ * config: Configuration identifier
+ * name: property namespace
+ * callback: populate() function
+ */
+#define SOCFPGA_REGISTER_POPULATOR(config, name, callback) \
+ __section(".socfpga_populator") __used \
+ static const struct socfpga_populator (name##__populator) = { \
+ .config_type = (#config), \
+ .info = (#name), \
+ .populate = (callback) \
+ }
+
+/*
+ * Populator callback
+ *
+ * This structure are used by the fconf_populate function and should only be
+ * defined by the SOCFPGA_REGISTER_POPULATOR macro.
+ */
+struct socfpga_populator {
+ /* Description of the data loaded by the callback */
+ const char *config_type;
+ const char *info;
+
+ /* Callback used by fconf_populate function with a provided config dtb.
+ * Return 0 on success, err_code < 0 otherwise.
+ */
+ int (*populate)(uintptr_t config);
+};
+
+/* Hardware Config related getter */
+#define hw_config__gicv3_config_getter(prop) plat_gicv3_gic_data.prop
+
+/* Function Definitions */
+int socfpga_dt_open_and_check(uintptr_t dt_addr, char *compatible_str);
+int socfpga_dt_populate_gicv3_config(uintptr_t dt_addr, gicv3_driver_data_t *plat_driver_data);
+int socfpga_dt_populate_dram_layout(uintptr_t dt_addr);
+
+#endif
diff --git a/plat/intel/soc/common/socfpga_dt.c b/plat/intel/soc/common/socfpga_dt.c
new file mode 100644
index 0000000..0333b9b
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_dt.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <libfdt.h>
+#include <platform_def.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "socfpga_dt.h"
+
+static const void *fdt;
+/*******************************************************************************
+ * This function checks device tree file with its header.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+int socfpga_dt_open_and_check(uintptr_t dt_addr, char *compatible_str)
+{
+ int ret = 0;
+ int node = 1;
+
+ ret = fdt_check_header((void *)dt_addr);
+
+ if (ret != 0) {
+ ERROR("SOCFPGA: FDT Header invalid\n");
+ return ret;
+ }
+
+ fdt = (const void *)dt_addr;
+
+ /* As libfdt use void *, we can't avoid this cast */
+ const void *dtb = (void *)dt_addr;
+
+ /* Assert the node offset point to compatible property */
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("SOCFPGA: Can't find `%s` compatible in dtb\n",
+ compatible_str);
+ return node;
+ }
+
+ NOTICE("SOCFPGA: Successfully open and check FDT\n");
+
+ return ret;
+}
+
+int socfpga_dt_populate_gicv3_config(uintptr_t dt_addr, gicv3_driver_data_t *plat_driver_data)
+{
+ int err;
+ int node;
+ uintptr_t addr;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)dt_addr;
+ /*
+ * Find the offset of the node containing "arm,gic-v3" compatible property.
+ * Populating fconf strucutures dynamically is not supported for legacy
+ * systems which use GICv2 IP. Simply skip extracting GIC properties.
+ */
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3");
+ if (node < 0) {
+ ERROR("SOCFPGA: Unable to locate node with arm,gic-v3 compatible property\n");
+ return 0;
+ }
+ /* The GICv3 DT binding holds at least two address/size pairs,
+ * the first describing the distributor, the second the redistributors.
+ * See: bindings/interrupt-controller/arm,gic-v3.yaml
+ */
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL);
+ if (err < 0) {
+ ERROR("SOCFPGA: Failed to read GICD reg property of GIC node\n");
+ } else {
+ plat_driver_data->gicd_base = addr;
+ }
+
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL);
+ if (err < 0) {
+ ERROR("SOCFPGA: Failed to read GICR reg property of GIC node\n");
+ } else {
+ plat_driver_data->gicr_base = addr;
+ }
+ return err;
+}
+
+int socfpga_dt_populate_dram_layout(uintptr_t dt_addr)
+{
+ int node;
+ uintptr_t addr;
+ size_t size;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)dt_addr;
+
+ /* Find 'memory' node */
+ node = fdt_node_offset_by_prop_value(hw_config_dtb, -1, "device_type",
+ "memory", sizeof("memory"));
+ if (node < 0) {
+ NOTICE("SOCFPGA: Unable to locate 'memory' node\n");
+ return node;
+ }
+
+ int err = fdt_get_reg_props_by_index(
+ hw_config_dtb, node, 0,
+ &addr, (size_t *)&size);
+
+ NOTICE("SOCFPGA: Mem base 0x%lx, Mem size 0x%lx\n", addr, size);
+ if (err < 0) {
+ ERROR("SOCFPGA: Failed to read 'reg' property of 'memory' node\n");
+ return err;
+ }
+
+ return 0;
+}