# Device Tree Processing Makefile
#
# This makefile provides device tree parsing, validation, and C header
# generation using Zephyr's device tree infrastructure.
#
# Targets:
#   all          - Parse DTS, validate against bindings, generate C header (default)
#   validate     - Parse and validate DTS only, no code generation
#   debug        - Generate debug outputs (edt.pickle and preprocessed.dts)
#   clean        - Remove all generated outputs
#   help         - Show usage information
#
# Variables:
#   BINDINGS_DIR - Directory containing YAML bindings (default: bindings)
#   PYTHON       - Python interpreter (default: python3)
#   CPP          - C preprocessor for DTS preprocessing (default: cpp)

# Configuration
PYTHON ?= python3
CPP ?= cpp
DTC ?= dtc

# Directories
SCRIPT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
ZEPHYR_DIR := $(SCRIPT_DIR)zephyr
BINDINGS_DIR ?= $(SCRIPT_DIR)bindings
REPORTS_DIR := $(SCRIPT_DIR)reports

# SoC selection for workflow
SOC ?= j722s

#===============================================================================
# Device Tree Header Generation (dt-header targets)
#===============================================================================
# Device tree configuration for header generation with overlay support
# DTS_CONFIG_OVERLAY_PATH points to dt_configurator root (this directory)
DTS_CONFIG_OVERLAY_PATH ?= $(abspath $(CURDIR))
DT_DTS_PATH_HEADER := $(DTS_CONFIG_OVERLAY_PATH)/dts/

# Output configuration for header generation
DT_WORK_DIR := $(DTS_CONFIG_OVERLAY_PATH)/dt-build
DT_OUTPUT_DIR_HEADER := $(DTS_CONFIG_OVERLAY_PATH)/output
DT_HEADER_FILE := $(DT_OUTPUT_DIR_HEADER)/devicetree_generated.h

# Input/Output files
EDT_PICKLE := $(DT_OUTPUT_DIR_HEADER)/edt.pickle
PREPROCESSED_DTS := $(DT_OUTPUT_DIR_HEADER)/preprocessed.dts

# Zephyr scripts
GEN_EDT_PY := $(ZEPHYR_DIR)/gen_edt.py
GEN_DEFINES_PY := $(ZEPHYR_DIR)/gen_defines.py

# Find all YAML binding files
BINDINGS := $(shell find $(BINDINGS_DIR) -name '*.yaml' 2>/dev/null)

# Python path setup (add zephyr directory to PYTHONPATH)
export PYTHONPATH := $(ZEPHYR_DIR):$(PYTHONPATH)


# Default target
.DEFAULT_GOAL := all

# Base DTS file for header generation
DTS_BASE ?= $(DT_DTS_PATH_HEADER)/$(SOC)/$(SOC)-hw-init.dts

# Phony targets
.PHONY: all validate debug clean help dt-header dt-header-clean

# Help target
help:
	@echo "Device Tree Processing Makefile (Header Generation)"
	@echo ""
	@echo "Usage:"
	@echo "  make [target]"
	@echo ""
	@echo "Targets:"
	@echo "  all                        - Parse, validate, and generate C header (default)"
	@echo "  validate                   - Parse and validate DTS only"
	@echo "  debug                      - Generate debug outputs (pickle + preprocessed DTS)"
	@echo "  clean                      - Remove all generated files"
	@echo "  dt-header                  - Generate device tree header with overlay support"
	@echo "  dt-header-clean            - Clean device tree generation files"
	@echo "  help                       - Show this help message"
	@echo ""
	@echo "Variables:"
	@echo "  BINDINGS_DIR - YAML bindings directory (default: $(BINDINGS_DIR))"
	@echo "  SOC          - SoC for workflow (default: $(SOC))"
	@echo "  PYTHON       - Python interpreter (default: $(PYTHON))"
	@echo ""
	@echo "Examples:"
	@echo "  make all DTS_BASE=dts/<soc>/<soc>-hw-init.dts"
	@echo "  make validate DTS_BASE=dts/<soc>/<soc>-hw-init.dts"
	@echo "  make debug"
	@echo ""
	@echo "For device tree preparation tasks (preprocessing, extraction, overlays, validation):"
	@echo "  make -f Makefile.dts-prep help"
	@echo ""

# Check dependencies
check-deps:
	@echo "Checking dependencies..."
	@if ! command -v $(PYTHON) >/dev/null 2>&1; then \
		echo "Error: Python not found. Please install Python 3.6+"; \
		exit 1; \
	fi
	@if ! $(PYTHON) -c "import yaml" 2>/dev/null; then \
		echo "Error: PyYAML not found. Install with: pip install pyyaml"; \
		exit 1; \
	fi
	@echo "Dependencies OK"

# Main target: Generate C header
ifneq ($(DTS_CONFIG_OVERLAY), none)
all: dt-header
	@echo "Device tree processing complete!"
	@echo "Generated: $(DT_HEADER_FILE)"
endif

# Generate EDT pickle (parse and validate)
$(EDT_PICKLE): check-deps $(DTS_BASE) $(BINDINGS) $(PREPROCESSED_DTS) | $(DT_OUTPUT_DIR_HEADER)
	@echo "Parsing and validating device tree..."
	@echo "  Input: $(PREPROCESSED_DTS)"
	@echo "  Bindings: $(BINDINGS_DIR)"
	$(PYTHON) $(GEN_EDT_PY) \
		--dts $(PREPROCESSED_DTS) \
		--dtc-flags="" \
		--bindings-dirs $(BINDINGS_DIR) \
		--dts-out $(DT_OUTPUT_DIR_HEADER)/preprocessed2.dts \
		--edt-pickle-out $@
	@echo "EDT pickle generated: $@"

# Validate target: parse and validate only
validate: $(EDT_PICKLE)
	@echo "Validation complete - no errors found!"

# Debug target: generate debugging outputs
debug: $(EDT_PICKLE) $(PREPROCESSED_DTS)
	@echo "Debug outputs generated:"
	@echo "  - EDT pickle: $(EDT_PICKLE)"
	@echo "  - Preprocessed DTS: $(PREPROCESSED_DTS)"

# Generate preprocessed DTS for debugging
$(PREPROCESSED_DTS): $(DTS_BASE) | $(DT_OUTPUT_DIR_HEADER)
	@echo "Preprocessing device tree..."
	$(CPP) -nostdinc -undef -x assembler-with-cpp -P $(DTS_BASE) -o $@
	@echo "Preprocessed DTS generated: $@"

# Clean target
clean:
	@echo "Cleaning generated files..."
	rm -rf $(DT_OUTPUT_DIR_HEADER) $(DT_OUTPUT_DIR_HEADER)_* $(REPORTS_DIR)
	@echo "Clean complete"

# Additional target for DTC validation (optional, if dtc is available)
dtc-validate: $(PREPROCESSED_DTS)
	@if command -v $(DTC) >/dev/null 2>&1; then \
		echo "Running DTC validation..."; \
		$(DTC) -I dts -O dtb $(PREPROCESSED_DTS) -o $(DT_OUTPUT_DIR_HEADER)/test.dtb; \
		echo "DTC validation passed"; \
	else \
		echo "DTC not found, skipping DTC validation"; \
	fi

# Show configuration
config:
	@echo "Device Tree Configuration:"
	@echo "  DTS_BASE      = $(DTS_BASE)"
	@echo "  BINDINGS_DIR   = $(BINDINGS_DIR)"
	@echo "  DT_OUTPUT_DIR_HEADER     = $(DT_OUTPUT_DIR_HEADER)"
	@echo "  PYTHON         = $(PYTHON)"
	@echo "  ZEPHYR_DIR     = $(ZEPHYR_DIR)"
	@echo "  SOC            = $(SOC)"
	@echo "  Bindings found: $(words $(BINDINGS)) files"



#===============================================================================
# dt-header targets: Generate device tree headers with overlay support
#===============================================================================
# These targets are designed to be invoked from the top-level makefile
# when DTS_CONFIG_OVERLAY is enabled.

ifneq ($(DTS_CONFIG_OVERLAY), none)
# Device tree infrastructure enabled: generate DT header with base DTS or overlays
# Force regeneration by removing outputs first, then rebuilding
dt-header: check-deps
	@rm -f $(DT_HEADER_FILE) $(EDT_PICKLE) $(PREPROCESSED_DTS)
	@$(MAKE) $(DT_HEADER_FILE)

$(DT_HEADER_FILE): $(DTS_BASE) | $(DT_OUTPUT_DIR_HEADER)
	@echo "Generating device tree header for $(SOC)..."
	@mkdir -p $(DT_WORK_DIR)
	@if [ "$(DTS_CONFIG_OVERLAY)" = "base" ]; then \
		echo "  Using base DTS (no overlays)"; \
		cp $(DTS_BASE) $(DT_WORK_DIR)/combined.dts; \
	else \
		echo "  Applying overlay(s): $(DTS_CONFIG_OVERLAY)"; \
		OVERLAY_LIST=$$(echo "$(DTS_CONFIG_OVERLAY)" | tr ',' ' '); \
		OVERLAY_COUNT=$$(echo $$OVERLAY_LIST | wc -w); \
		echo "  Overlay count: $$OVERLAY_COUNT"; \
		RESOLVED_OVERLAYS=""; \
		for overlay_file in $$OVERLAY_LIST; do \
			overlay_file=$$(echo $$overlay_file | xargs); \
			if [ -f "$(DT_DTS_PATH_HEADER)/$(SOC)/overlay/$$overlay_file" ]; then \
				OVERLAY_PATH="$(DT_DTS_PATH_HEADER)/$(SOC)/overlay/$$overlay_file"; \
				echo "    Found: $$overlay_file"; \
				RESOLVED_OVERLAYS="$$RESOLVED_OVERLAYS $$OVERLAY_PATH"; \
			else \
				echo "Error: Overlay file not found: $$overlay_file"; \
				echo "  Searched in: $(DT_DTS_PATH_HEADER)/$(SOC)/overlay/"; \
				exit 1; \
			fi; \
		done; \
		cp $(DTS_BASE) $(DT_WORK_DIR)/combined.dts; \
		echo '' >> $(DT_WORK_DIR)/combined.dts; \
		echo '/* Overlay modifications */' >> $(DT_WORK_DIR)/combined.dts; \
		for overlay_path in $$RESOLVED_OVERLAYS; do \
			echo "/include/ \"$$overlay_path\"" >> $(DT_WORK_DIR)/combined.dts; \
		done; \
	fi

	@echo "  Generating header from device tree..."
	@echo "  Preprocessing device tree..."
	@$(CPP) -nostdinc -undef -x assembler-with-cpp -P $(DT_WORK_DIR)/combined.dts -o $(PREPROCESSED_DTS)
	@echo "  Parsing and validating device tree..."
	@$(PYTHON) $(GEN_EDT_PY) \
		--dts $(DT_OUTPUT_DIR_HEADER)/preprocessed.dts \
		--dtc-flags="" \
		--bindings-dirs $(BINDINGS_DIR) \
		--dts-out $(DT_OUTPUT_DIR_HEADER)/preprocessed2.dts \
		--edt-pickle-out $(EDT_PICKLE)
	@echo "  Generating C header..."
	@$(PYTHON) $(GEN_DEFINES_PY) \
		--edt-pickle $(EDT_PICKLE) \
		--header-out $(DT_HEADER_FILE)
	@echo "  Device tree header generated: $(DT_HEADER_FILE)"

# Ensure output directory exists
$(DT_OUTPUT_DIR_HEADER):
	@mkdir -p $(DT_OUTPUT_DIR_HEADER)

else
# DT infrastructure disabled: no header generation
dt-header:
	@echo "DTS_CONFIG_OVERLAY set to 'none' - skipping device tree header generation"
endif

dt-header-clean:
	-rm -rf $(DT_WORK_DIR) $(DT_OUTPUT_DIR_HEADER)
	@echo "Cleaned device tree generation files"
