env: Allow U-Boot scripts to be placed in a .env file

At present U-Boot environment variables, and thus scripts, are defined
by CONFIG_EXTRA_ENV_SETTINGS. It is painful to add large amounts of text
to this file and dealing with quoting and newlines is harder than it
should be. It would be better if we could just type the script into a
text file and have it included by U-Boot.

Add a feature that brings in a .env file associated with the board
config, if present. To use it, create a file in a board/<vendor>
directory, typically called <board>.env and controlled by the
CONFIG_ENV_SOURCE_FILE option.

The environment variables should be of the form "var=value". Values can
extend to multiple lines. See the README under 'Environment Variables:'
for more information and an example.

In many cases environment variables need access to the U-Boot CONFIG
variables to select different options. Enable this so that the environment
scripts can be as useful as the ones currently in the board config files.
This uses the C preprocessor, means that comments can be included in the
environment using /* ... */

Also support += to allow variables to be appended to. This is needed when
using the preprocessor.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Marek BehĂșn <marek.behun@nic.cz>
Tested-by: Marek BehĂșn <marek.behun@nic.cz>
diff --git a/Makefile b/Makefile
index 0220e8d..338ae33 100644
--- a/Makefile
+++ b/Makefile
@@ -517,6 +517,7 @@
 timestamp_h := include/generated/timestamp_autogenerated.h
 defaultenv_h := include/generated/defaultenv_autogenerated.h
 dt_h := include/generated/dt.h
+env_h := include/generated/environment.h
 
 no-dot-config-targets := clean clobber mrproper distclean \
 			 help %docs check% coccicheck \
@@ -1794,6 +1795,69 @@
 u-boot.sym: u-boot FORCE
 	$(call if_changed,sym)
 
+# Environment processing
+# ---------------------------------------------------------------------------
+
+# Directory where we expect the .env file, if it exists
+ENV_DIR := $(srctree)/board/$(BOARDDIR)
+
+# Basename of .env file, stripping quotes
+ENV_SOURCE_FILE := $(CONFIG_ENV_SOURCE_FILE:"%"=%)
+
+# Filename of .env file
+ENV_FILE_CFG := $(ENV_DIR)/$(ENV_SOURCE_FILE).env
+
+# Default filename, if CONFIG_ENV_SOURCE_FILE is empty
+ENV_FILE_BOARD := $(ENV_DIR)/$(CONFIG_SYS_BOARD:"%"=%).env
+
+# Select between the CONFIG_ENV_SOURCE_FILE and the default one
+ENV_FILE := $(if $(ENV_SOURCE_FILE),$(ENV_FILE_CFG),$(wildcard $(ENV_FILE_BOARD)))
+
+# Run the environment text file through the preprocessor, but only if it is
+# non-empty, to save time and possible build errors if something is wonky with
+# the board
+quiet_cmd_gen_envp = ENVP    $@
+      cmd_gen_envp = \
+	if [ -s "$(ENV_FILE)" ]; then \
+		$(CPP) -P $(CFLAGS) -x assembler-with-cpp -D__ASSEMBLY__ \
+			-D__UBOOT_CONFIG__ \
+			-I . -I include -I $(srctree)/include \
+			-include linux/kconfig.h -include include/config.h \
+			-I$(srctree)/arch/$(ARCH)/include \
+			$< -o $@; \
+	else \
+		echo -n >$@ ; \
+	fi
+include/generated/env.in: include/generated/env.txt FORCE
+	$(call cmd,gen_envp)
+
+# Regenerate the environment if it changes
+# We use 'wildcard' since the file is not required to exist (at present), in
+# which case we don't want this dependency, but instead should create an empty
+# file
+# This rule is useful since it shows the source file for the environment
+quiet_cmd_envc = ENVC    $@
+      cmd_envc = \
+	if [ -f "$<" ]; then \
+		cat $< > $@; \
+	elif [ -n "$(ENV_SOURCE_FILE)" ]; then \
+		echo "Missing file $(ENV_FILE_CFG)"; \
+	else \
+		echo -n >$@ ; \
+	fi
+
+include/generated/env.txt: $(wildcard $(ENV_FILE)) FORCE
+	$(call cmd,envc)
+
+# Write out the resulting environment, converted to a C string
+quiet_cmd_gen_envt = ENVT    $@
+      cmd_gen_envt = \
+	awk -f $(srctree)/scripts/env2string.awk $< >$@
+$(env_h): include/generated/env.in
+	$(call cmd,gen_envt)
+
+# ---------------------------------------------------------------------------
+
 # The actual objects are generated when descending,
 # make sure no implicit rule kicks in
 $(sort $(u-boot-init) $(u-boot-main)): $(u-boot-dirs) ;
@@ -1849,7 +1913,7 @@
 # prepare2 creates a makefile if using a separate output directory
 prepare2: prepare3 outputmakefile cfg
 
-prepare1: prepare2 $(version_h) $(timestamp_h) $(dt_h) \
+prepare1: prepare2 $(version_h) $(timestamp_h) $(dt_h) $(env_h) \
                    include/config/auto.conf
 ifeq ($(wildcard $(LDSCRIPT)),)
 	@echo >&2 "  Could not find linker script."