#
# Copyright (c) 2025-2026, Advanced Micro Devices, Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Custom Package Integration for AMD Platforms
#

# Flag to track if custom package is included
CUSTOM_PKG_INCLUDED := 0

# ============================================================================
# Custom Package Integration (supports multiple packages)
# ============================================================================
# This framework:
# 1. Includes each package's custom_pkg.mk for build rules and flags
# 2. Discovers custom_pkg.ld.S files for linker script consolidation
# 3. Prepares them for preprocessing into the final plat.ld.S
#
# Each package provides:
# - custom_pkg.mk: Build configuration, source files, and package-specific macros
# - custom_pkg.ld.S: Memory layout (MEMORY regions and SECTIONS)
# ============================================================================

ifdef CUSTOM_PKG_PATH
    # Split CUSTOM_PKG_PATH by space, colon, or semicolon to support multiple paths
    _CUSTOM_PKG_PATHS := $(strip $(subst ;, ,$(subst :, ,$(CUSTOM_PKG_PATH))))
    # Normalize to absolute paths to handle both relative and absolute inputs
    _CUSTOM_PKG_PATHS_ABS := $(foreach pkg_path,$(_CUSTOM_PKG_PATHS),$(abspath $(pkg_path)))

    # Include each package's custom_pkg.mk
    $(foreach pkg_path,$(_CUSTOM_PKG_PATHS_ABS), \
        $(eval PKG_PATH_CLEAN := $(strip $(pkg_path))) \
        $(eval PKG_MK := $(PKG_PATH_CLEAN)/custom_pkg.mk) \
        $(if $(wildcard $(PKG_MK)), \
            $(eval include $(PKG_MK)) \
            $(eval CUSTOM_PKG_INCLUDED := 1) \
            $(info Including custom package from: $(PKG_PATH_CLEAN)), \
            $(error CUSTOM_PKG_PATH contains $(PKG_PATH_CLEAN) but custom_pkg.mk not found) \
        ) \
    )

    # Find all custom_pkg.ld.S files in package directories (absolute paths)
    CUSTOM_PKG_LD_SCRIPTS := $(wildcard $(addsuffix /custom_pkg.ld.S,$(_CUSTOM_PKG_PATHS_ABS)))

    # Auto-discover package linker script (prefer first hit) and set TF-A flag
    $(foreach pkg_path,$(_CUSTOM_PKG_PATHS_ABS), \
        $(eval _PKG_LS := $(wildcard $(pkg_path)/plat.ld.S $(pkg_path)/inc/plat.ld.S)) \
        $(if $(_PKG_LS), \
            $(if $(PLAT_EXTRA_LD_SCRIPT_PATH),, \
                $(eval PLAT_EXTRA_LD_SCRIPT_PATH := $(word 1,$(_PKG_LS))) \
                $(info Auto-discovered linker script: $(PLAT_EXTRA_LD_SCRIPT_PATH)) \
            ) \
        ) \
    )

    # If a package linker script is present, export the TF-A define (value = 1)
    ifdef PLAT_EXTRA_LD_SCRIPT_PATH
        PLAT_EXTRA_LD_SCRIPT := 1
        $(eval $(call add_define_val,PLAT_EXTRA_LD_SCRIPT,1))
        $(info Enabling PLAT_EXTRA_LD_SCRIPT=1 (script: $(PLAT_EXTRA_LD_SCRIPT_PATH)))
    endif

    ifneq ($(CUSTOM_PKG_LD_SCRIPTS),)
        $(info Custom Package Linker Scripts Found:)
        $(foreach _LS,$(CUSTOM_PKG_LD_SCRIPTS),$(info  - $(_LS)))

        # Generate paths for preprocessed scripts (.ld.S -> .ld.pp)
        CUSTOM_PKG_LD_SCRIPTS_PP := $(patsubst %.ld.S,%.ld.pp,$(CUSTOM_PKG_LD_SCRIPTS))

        # Collect include directories from all custom packages for linker script preprocessing
        CUSTOM_PKG_LD_INCLUDES := $(foreach pkg_path,$(_CUSTOM_PKG_PATHS_ABS), \
            $(if $(wildcard $(pkg_path)/inc),-I$(pkg_path)/inc) \
            $(if $(wildcard $(pkg_path)/include),-I$(pkg_path)/include))

        # Make them available to linker script generation
        export CUSTOM_PKG_LD_SCRIPTS_PP
        export CUSTOM_PKG_LD_INCLUDES
    else
        $(info No custom_pkg.ld.S files found - using platform defaults)
        CUSTOM_PKG_LD_INCLUDES :=
    endif
endif

# ============================================================================
# Note: Package-specific macros are defined in each package's custom_pkg.mk
# and passed to preprocessor via ASFLAGS
# ============================================================================

# ============================================================================
# Custom Package Linker Script Preprocessing
# ============================================================================
# This handles preprocessing of custom package linker scripts
# and generation of the final consolidated plat.ld.S
#
# Two-stage preprocessing using TF-A's standard C preprocessor:
# Stage 1: Preprocess custom_pkg.ld.S files
#   Input: custom_pkg.ld.S (contains package-specific macros)
#   Process: $($(ARCH)-cpp) -E -P with ASFLAGS containing package macro definitions
#   Output: custom_pkg.ld.pp (macros expanded)
#
# Stage 2: Preprocess template with all preprocessed scripts included
#   Input: plat.ld.S.tpl (contains #include CUSTOM_PKG_LD_SCRIPTS_PP)
#   Process: $($(ARCH)-cpp) -E -P with all macro definitions
#   Output: build/versal2/release/bl31/plat.ld.S (final linker script)
# ============================================================================

# Directories
BUILD_DIR := $(shell pwd)/build/$(PLAT)
BL31_BUILD_DIR := $(BUILD_DIR)/bl31

# Linker script template and output
PLAT_LD_TEMPLATE := plat/amd/versal2/plat.ld.S.tpl
PLAT_LD_SCRIPT := $(BL31_BUILD_DIR)/plat.ld.S

# Rule 1: Preprocess individual custom_pkg.ld.S files
# Uses TF-A's standard architecture-specific C preprocessor
# Includes custom package include directories for proper header resolution
%.ld.pp: %.ld.S
	@echo "  PP      $<"
	$(Q)$($(ARCH)-cpp) -E -P $(CUSTOM_PKG_LD_INCLUDES) $(ASFLAGS) -o $@ $<

# Rule 2: Generate final plat.ld.S from template + preprocessed scripts
# Uses TF-A's standard architecture-specific C preprocessor
# Includes custom package include directories for proper header resolution
$(PLAT_LD_SCRIPT): $(PLAT_LD_TEMPLATE) $(CUSTOM_PKG_LD_SCRIPTS_PP)
	@echo "  GEN     $@"
	@mkdir -p $(BL31_BUILD_DIR)
	$(Q)$($(ARCH)-cpp) -E -P \
		-DCUSTOM_PKG_LD_SCRIPTS_PP="$(CUSTOM_PKG_LD_SCRIPTS_PP)" \
		$(CUSTOM_PKG_LD_INCLUDES) \
		$(ASFLAGS) \
		-o $@ \
		$(PLAT_LD_TEMPLATE)

# Ensure final linker script exists before linking BL31
bl31: $(PLAT_LD_SCRIPT)

# ============================================================================
# Build Summary
# ============================================================================
$(info ============================================================)
$(info Custom Package Configuration:)
$(info   Custom Package: $(if $(filter 1,$(CUSTOM_PKG_INCLUDED)),ENABLED,DISABLED))
$(if $(filter 1,$(CUSTOM_PKG_INCLUDED)), \
    $(foreach pkg_path,$(_CUSTOM_PKG_PATHS_ABS), \
        $(info   - $(strip $(pkg_path))) \
    ) \
)
$(info ============================================================)
