From: Domenico Andreoli <[email-masked]>

Thinking at multiplatform kernels we cannot miss DeviceTrees. So here we
add some new glue to select tags also using dt_compat fields, mandatory
in case of pure DT boards without numeric machine id.

Note the care required to pack, relocate and unpack all those strings.

Signed-off-by: Domenico Andreoli <[email-masked]>
---
 arch/arm/boot/compressed/Makefile       |    2 --
 arch/arm/boot/compressed/arch.c         |   24 ++++++++++++++++++++++++
 arch/arm/boot/compressed/atags_to_fdt.c |   15 +++++++++++++++
 include/linux/decompress/arch.h         |    1 +
 4 files changed, 40 insertions(+), 2 deletions(-)

Index: b/arch/arm/boot/compressed/atags_to_fdt.c
===================================================================
--- a/arch/arm/boot/compressed/atags_to_fdt.c
+++ b/arch/arm/boot/compressed/atags_to_fdt.c
@@ -97,3 +97,18 @@ int atags_to_fdt(void *atag_list, void *
 
 	return fdt_pack(fdt);
 }
+
+const char *get_fdt_prop(void *fdt, const char *path, const char *prop)
+{
+	int len, offset;
+
+	/* if we don't get a DTB here we're done already */
+	if (*(u32 *) fdt != fdt32_to_cpu(FDT_MAGIC))
+		return NULL;
+
+	offset = fdt_path_offset(fdt, path);
+	if (offset < 0)
+		return NULL;
+
+	return fdt_getprop(fdt, offset, prop, &len);
+}
Index: b/arch/arm/boot/compressed/arch.c
===================================================================
--- a/arch/arm/boot/compressed/arch.c
+++ b/arch/arm/boot/compressed/arch.c
@@ -24,6 +24,8 @@ unsigned int __machine_arch_type;
 
 #include "arch.h"
 
+const char *get_fdt_prop(void *fdt, const char *path, const char *prop);
+
 unsigned long free_mem_ptr;
 unsigned long free_mem_end_ptr;
 
@@ -57,6 +59,15 @@ extern const struct decomp_tag_hdr __dec
 	     (p) < __decomp_tags_end;           \
 	     p = ((void *) p) + (p)->size)
 
+static bool is_compatible(const char (*dt_compat)[16], const char *compatible)
+{
+	for ( ; strlen(*dt_compat); dt_compat++)
+		if (!strcmp(*dt_compat, compatible))
+			return true;
+
+	return false;
+}
+
 void arch_setup(unsigned int arch_id, void *atag_fdt,
 		unsigned long free_mem_ptr_p,
 		unsigned long free_mem_ptr_end_p)
@@ -65,7 +76,11 @@ void arch_setup(unsigned int arch_id, vo
 	const struct decomp_tag_hdr *hdr;
 	void (*arch_setup_p)(void);
 
+	const char (*dt_compat)[16];
+	const char *compatible;
+
 	__machine_arch_type = arch_id;
+	compatible = get_fdt_prop(atag_fdt, "/", "compatible");
 
 	arch_setup_p = fallback_arch_setup;
 	arch_error_p = fallback_arch_error;
@@ -77,6 +92,15 @@ void arch_setup(unsigned int arch_id, vo
 		if (hdr->arch_id != arch_id)
 			continue;
 
+		/*
+		 * In case of DT entry, further inspection of the dt_compat
+		 * table is required before accepting the tag.
+		 */
+		dt_compat = (const char (*)[16]) fix_data_ptr(hdr->dt_compat);
+		if (arch_id == ~0 && compatible && dt_compat &&
+		    !is_compatible(dt_compat, compatible))
+			continue;
+
 		if (hdr->type == DECOMP_TAG_ARCH) {
 			arch_tag = (struct decomp_arch_tag *) hdr;
 			arch_setup_p = fix_text_ptr(arch_tag->setup);
Index: b/include/linux/decompress/arch.h
===================================================================
--- a/include/linux/decompress/arch.h
+++ b/include/linux/decompress/arch.h
@@ -24,6 +24,7 @@ enum decomp_tag_type {
 
 struct decomp_tag_hdr {
 	unsigned int arch_id;
+	const char (*dt_compat)[16];
 	unsigned short type;
 	unsigned short size;
 };
Index: b/arch/arm/boot/compressed/Makefile
===================================================================
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -107,9 +107,7 @@ $(addprefix $(obj)/,$(libfdt) $(libfdt_h
 $(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
 	$(addprefix $(obj)/,$(libfdt_hdrs))
 
-ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
 OBJS	+= $(libfdt_objs) atags_to_fdt.o
-endif
 
 targets       := vmlinux vmlinux.lds \
 		 piggy.$(suffix_y) piggy.$(suffix_y).o \