# #############################################
# (2014) Benjamin Krill <benjamin@krll.de>
# #############################################
PWD = $(shell pwd)
ifndef TOP
  TOP = $(shell while ! test -d syn; do cd ..  ; done; pwd)
  export TOP
endif

PROJECT           := sockit
BUILD_DIR         := $(PWD)/build_$(PROJECT)
BUILD_QUARTUS_DIR := $(BUILD_DIR)/quartus

##### SOURCE FILES #####################################################################################
SOURCE_QIP = $(TOP)/top/$(PROJECT).qip

##### DEFAULT ##########################################################################################
.PHONY: default
default: help

##### QSYS #############################################################################################
.PHONY: qsys-generate qsys-edit

QSYS_FILE      = $(TOP)/soc/soc_system.qsys
QSYS_BASE      = $(basename $(notdir $(QSYS_FILE)))
QSYS_OUTDIR    = $(BUILD_DIR)/$(QSYS_BASE)
QSYS_QIP       = $(QSYS_OUTDIR)/$(QSYS_BASE).qip
QSYS_SOPCINFO  = $(QSYS_OUTDIR)/$(QSYS_BASE).sopcinfo
SOURCE_QIP    += $(QSYS_QIP)

$(QSYS_QIP): $(QSYS_FILE)
	mkdir -p $(QSYS_OUTDIR)
	ip-generate \
		--component-file=$(QSYS_FILE) \
		--file-set=QUARTUS_SYNTH \
		--output-name=$(QSYS_BASE) \
		--output-directory=$(QSYS_OUTDIR) \
		--reportfile=sopcinfo:$(QSYS_SOPCINFO) \
		--reportfile=qip:$@ \
		--language=vhdl
	touch $(QSYS_QIP)

qsys-generate: $(QSYS_QIP)

qsys-edit: $(QSYS_FILE)
	qsys-edit $^ &

HELP_TARGETS += qsys-generate qsys-edit
qsys-generate.HELP = Generate current QSYS implementation
qsys-edit.HELP     = Edit QSYS implementation

##### UBOOT / PRELOADER ################################################################################
.PHONY: preloader uboot uboot-script
PRELOADER_DIR      = $(BUILD_DIR)/software/preloader
QSYS_HPS_INST_NAME = hps_0
PRELOADER_HANDOFF  = $(BUILD_QUARTUS_DIR)/hps_isw_handoff/$(QSYS_BASE)_$(QSYS_HPS_INST_NAME)/
PRELOADER_ID       = $(PRELOADER_HANDOFF)/id
PRELOADER_IMG      = $(PRELOADER_DIR)/preloader-mkpimage.bin
UBOOT_IMG          = $(PRELOADER_DIR)/uboot-socfpga/u-boot.img

## uboot script
#bootcmd=run mmcload; run fpgaload; run mmcboot
#fpga=0
#fpgadata=0x2000000
#fpgadatasize=2126D5
#fpgaload=fatload mmc 0:1 0x2000000 $(PROJECT).rbf; fpga load 0 ${fpgadata} ${fi}

$(PRELOADER_DIR)/Makefile: $(PRELOADER_ID)
	mkdir -p $(PRELOADER_DIR)
	cd $(PRELOADER_DIR) && bsp-create-settings \
			--type spl \
			--bsp-dir . \
			--preloader-settings-dir "$(PRELOADER_HANDOFF)" \
			--settings settings.bsp \
			--set spl.boot.WATCHDOG_ENABLE false

preloader: $(PRELOADER_DIR)/Makefile
	make -C $(PRELOADER_DIR)

uboot: $(PRELOADER_DIR)/Makefile
	make -C $(PRELOADER_DIR) uboot

uboot-script: $(PRELOADER_DIR)/Makefile $(TOP)/soc/soc_system_uboot-scr.txt
	cd $(PRELOADER_DIR) && uboot-socfpga/tools/mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "SCRIPT" -d u-boot.txt u-boot.scr

$(PRELOADER_DIR)/u-boot.scr: uboot-script

bsp-edit: $(BUILD_DIR)/software/preloader/settings.bsp
	bsp-editor --settings $^ &

HELP_TARGETS  += bsp-edit preloader uboot
bsp-edit.HELP  = Edit BSP settings file
preloader.HELP = Build SoC preloader
uboot.HELP     = Build UBoot

##### Device Tree ######################################################################################
.PHONY: dtb dts
DTS_BOARDINFO      = $(TOP)/soc/soc_system_board_info.xml
DTS_CLKINFO        = $(TOP)/soc/soc_system_hps_clk_info.xml
DEVICE_TREE_SOURCE = $(patsubst %.sopcinfo,%.dts,$(QSYS_SOPCINFO))
DEVICE_TREE_BLOB   = $(patsubst %.dts,%.dtb,$(DEVICE_TREE_SOURCE))

$(DEVICE_TREE_SOURCE): %.dts: %.sopcinfo
	sopc2dts --input $< --output $@ --board $(DTS_BOARDINFO) --board $(DTS_CLKINFO)

$(DEVICE_TREE_BLOB): %.dtb: %.dts
	dtc -I dts -O dtb -o $@ $<

dts: $(DEVICE_TREE_SOURCE)
dtb: $(DEVICE_TREE_BLOB)

HELP_TARGETS += dts
dts.HELP      = Generate a device tree for this qsys design
HELP_TARGETS += dtb
dtb.HELP      = Generate a device tree blob for this qsys design

##### QUARTUS ##########################################################################################
.PHONY: quartus
QUARTUS_QPF  = $(PROJECT).qpf
QUARTUS_QSF  = $(PROJECT).qsf
SOURCE_SRC   = $(shell for q in $(SOURCE_QIP); do for s in `[ -e $$q ] && grep "\[file" $$q | sed 's/.*\[file//' | cut -d'"' -f 2`; do echo `dirname $$q`/$$s; done; done)
QUARTUS_SOF  = $(BUILD_QUARTUS_DIR)/output_files/sockit.sof
QUARTUS_RBF  = $(BUILD_QUARTUS_DIR)/output_files/sockit.rbf
func_quartus_find_tcl = $(shell find $(1) -name '*_pin_assignments.tcl')

$(BUILD_QUARTUS_DIR)/$(PROJECT).tcl_patch_done: $(BUILD_QUARTUS_DIR)/$(PROJECT).qsf
	@cd $(BUILD_QUARTUS_DIR) && for ptf in $(call func_quartus_find_tcl,$(BUILD_DIR)); do \
		quartus_map $(QUARTUS_QPF); \
		echo "Applying $$ptf to $(QUARTUS_QPF) ..."; \
		quartus_sta -t $$ptf $(QUARTUS_QPF); \
	done
	@touch $(BUILD_QUARTUS_DIR)/$(PROJECT).tcl_patch_done

$(QUARTUS_SOF) $(PRELOADER_ID): $(BUILD_QUARTUS_DIR)/$(PROJECT).tcl_patch_done $(SOURCE_SRC)
	cd $(BUILD_QUARTUS_DIR) && quartus_sh --flow compile $(QUARTUS_QPF)

$(QUARTUS_RBF): $(QUARTUS_SOF)
	quartus_cpf -c $< $@

quartus: $(QUARTUS_RBF)

HELP_TARGETS += quartus
quartus.HELP  = Geneate SOF bitfile

##### CONFIGURE BUILD ##################################################################################
.PHONY: config

$(BUILD_QUARTUS_DIR)/$(PROJECT).qsf: $(PROJECT).qsf_tmpl $(PROJECT).qpf_tmpl $(SOURCE_QIP)
	mkdir -p $(BUILD_QUARTUS_DIR)
	cp $(PROJECT).qsf_tmpl $(BUILD_QUARTUS_DIR)/$(PROJECT).qsf
	cp $(PROJECT).qpf_tmpl $(BUILD_QUARTUS_DIR)/$(PROJECT).qpf
	for I in $(SOURCE_QIP); do \
		echo "set_global_assignment -name QIP_FILE $$I" >> $(BUILD_QUARTUS_DIR)/$(PROJECT).qsf; \
	done

config: $(BUILD_QUARTUS_DIR)/$(PROJECT).qsf

HELP_TARGETS += config
config.HELP   = create build sandbox

##### SDCARD PREPARATION ###############################################################################
.PHONY: sdcard sd_rootfs sd_kernel sd_preloader sd_prepare
SD_DEV  ?= /dev/sdx
ifeq ($(origin SD_PREPARE), command line)
ifeq ($(SD_PREPARE), 1)
	SD_DEPENDENCY += sd_prepare
endif
endif
ifeq ($(origin KERNEL), command line)
	SD_DEPENDENCY += sd_kernel
endif
ifeq ($(origin ROOTFS), command line)
	SD_DEPENDENCY += sd_rootfs
endif
ifeq ($(origin SD_PRELOADER), command line)
	SD_DEPENDENCY += sd_preloader
endif

PART_EXT=p

sd_rootfs: $(SD_DEV)$(PART_EXT)2 $(ROOTFS)
	sudo mkfs.ext3 $(SD_DEV)$(PART_EXT)2
	sudo mount $(SD_DEV)$(PART_EXT)2 /mnt
	#sudo tar --strip-components 1 -xf $(ROOTFS) -C /mnt
	sudo tar -xf $(ROOTFS) -C /mnt
	sudo umount /mnt
	sync

sd_kernel: $(DEVICE_TREE_BLOB) $(QUARTUS_RBF) $(PRELOADER_DIR)/u-boot.scr $(KERNEL) $(SD_DEV)$(PART_EXT)1
	sudo mkdosfs $(SD_DEV)$(PART_EXT)1
	sudo mount $(SD_DEV)$(PART_EXT)1 /mnt
	sudo cp $(KERNEL) /mnt/zImage
	sudo cp $(DEVICE_TREE_BLOB) /mnt/socfpga.dtb
	sudo cp $(QUARTUS_RBF) /mnt/socfpga.rbf
	sudo cp $(PRELOADER_DIR)/u-boot.scr /mnt/
	sudo umount /mnt
	sync

sd_preloader: $(SD_DEV)$(PART_EXT)3
	sudo dd if=$(PRELOADER_IMG) of=$(SD_DEV)$(PART_EXT)3 seek=0 count=1
	sudo dd if=$(UBOOT_IMG) of=$(SD_DEV)$(PART_EXT)3 bs=64K seek=4

sd_prepare: $(SD_DEV)
	@echo "DEV_BOARD: Bootsel jumpers = 101 (booting from SD)"
	@echo "DEV_BOARD: MSEL jumpers = 00000 (enable the ARM to configure the FPGA)"
	sudo dd if=/dev/zero of=$(SD_DEV) bs=512 count=1
	# Partition-Table for a 4GB SDCARD
	@CMD="echo"; for c in n p 3 2048 +1024K t a2 n p 2 4096 +3814368K t 2 83 n p 1 7632896 " " t 1 b w; do \
		CMD="$$CMD;echo $$c"; \
	done; \
	CMD="( $$CMD ) | sudo fdisk $(SD_DEV)"; \
	echo "CREATE PARTITIONS [$$CMD]"; \
	eval $$CMD;
	sudo partprobe $(SD_DEV)

sdcard: $(SD_DEPENDENCY)

HELP_TARGETS += sdcard
sdcard.HELP   = prepare sdcard (SD_DEV=/dev/sdc SD_PREPARE=1 KERNEL=uImage.bin ROOTFS=rootfs.tar.gz SD_PRELOADER=1)

##### BUILD EVERYTHING #################################################################################
.PHONY: show all clean
func_check_file = $(shell test -e $(1) && echo $(1) || echo "not build")
show:
	@eval printf %.1s '={1..'"$${COLUMNS:-`tput cols`}"\}; echo
	@echo "DATE ............. : $(shell date)"
	@echo "QUARTUS SOF ...... : $(call func_check_file,$(QUARTUS_SOF))"
	@echo "QUARTUS RBF ...... : $(call func_check_file,$(QUARTUS_RBF))"
	@echo "PRELOADER ........ : $(call func_check_file,$(PRELOADER_IMG))"
	@echo "UBOOT ............ : $(call func_check_file,$(UBOOT_IMG))"
	@echo "DEVICE TREE BLOB . : $(call func_check_file,$(DEVICE_TREE_BLOB))"
	@eval printf %.1s '={1..'"$${COLUMNS:-`tput cols`}"\}; echo

all: $(QUARTUS_RBF) preloader uboot dtb show

clean:
	rm -rf $(BUILD_DIR)

HELP_TARGETS += all clean
all.HELP      = execute all needed steps
clean.HELP    = clean up build directory

##### HELP #############################################################################################
.PHONY: $(HELP_TARGETS_X) help
HELP_TARGETS += help
help.HELP     = Displays this info (i.e. the available targets)

help: help-header help-targets
HELP_TARGETS_X := $(patsubst %,help-%,$(sort $(HELP_TARGETS)))
help-targets: $(HELP_TARGETS_X)
$(HELP_TARGETS_X): help-%:
	@printf "%20s | %s\n" $* "$($*.HELP)"
help-header:
	@printf "%20s | %s\n" target description
	@eval printf %.1s '-{1..'"$${COLUMNS:-`tput cols`}"\}; echo
