diff --git a/Makefile b/Makefile
index 37cc4c3..dc881fa 100644
--- a/Makefile
+++ b/Makefile
@@ -606,6 +606,8 @@ KBUILD_CFLAGS += $(KCFLAGS)
 UBOOTINCLUDE    := \
 		-Iinclude \
 		$(if $(KBUILD_SRC), -I$(srctree)/include) \
+		$(if $(CONFIG_SYS_THUMB_BUILD), $(if $(CONFIG_HAS_THUMB2),, \
+			-I$(srctree)/arch/$(ARCH)/thumb1/include),) \
 		-I$(srctree)/arch/$(ARCH)/include \
 		-include $(srctree)/include/linux/kconfig.h
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0829235..906afd0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -10,6 +10,9 @@ config ARM64
 config HAS_VBAR
         bool
 
+config HAS_THUMB2
+        bool
+
 config CPU_ARM720T
         bool
 
@@ -32,9 +35,11 @@ config CPU_ARM1176
 config CPU_V7
         bool
         select HAS_VBAR
+        select HAS_THUMB2
 
 config CPU_V7M
 	bool
+        select HAS_THUMB2
 
 config CPU_PXA
         bool
diff --git a/arch/arm/cpu/arm926ejs/Makefile b/arch/arm/cpu/arm926ejs/Makefile
index 63fa159..fe78922 100644
--- a/arch/arm/cpu/arm926ejs/Makefile
+++ b/arch/arm/cpu/arm926ejs/Makefile
@@ -20,3 +20,14 @@ obj-$(CONFIG_MX25) += mx25/
 obj-$(CONFIG_MX27) += mx27/
 obj-$(if $(filter mxs,$(SOC)),y) += mxs/
 obj-$(if $(filter spear,$(SOC)),y) += spear/
+
+# some files can only build in ARM or THUMB2, not THUMB1
+
+ifdef CONFIG_SYS_THUMB_BUILD
+ifndef CONFIG_HAS_THUMB2
+
+CFLAGS_cpu.o := -marm
+CFLAGS_cache.o := -marm
+
+endif
+endif
diff --git a/arch/arm/cpu/arm926ejs/cache.c b/arch/arm/cpu/arm926ejs/cache.c
index 8d7873c..f12e365 100644
--- a/arch/arm/cpu/arm926ejs/cache.c
+++ b/arch/arm/cpu/arm926ejs/cache.c
@@ -99,4 +99,9 @@ void flush_cache(unsigned long start, unsigned long size)
 /*
  * Stub implementations for l2 cache operations
  */
+
 __weak void l2_cache_disable(void) {}
+
+#if defined CONFIG_SYS_THUMB_BUILD
+__weak void invalidate_l2_cache(void) {}
+#endif
diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
index a836e9f..1f63127 100644
--- a/arch/arm/include/asm/cache.h
+++ b/arch/arm/include/asm/cache.h
@@ -16,6 +16,9 @@
 /*
  * Invalidate L2 Cache using co-proc instruction
  */
+#ifdef CONFIG_SYS_THUMB_BUILD
+void invalidate_l2_cache(void);
+#else
 static inline void invalidate_l2_cache(void)
 {
 	unsigned int val=0;
@@ -24,6 +27,7 @@ static inline void invalidate_l2_cache(void)
 		: : "r" (val) : "cc");
 	isb();
 }
+#endif
 
 void l2_cache_enable(void);
 void l2_cache_disable(void);
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 9a631d1..4272d2f 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -60,3 +60,27 @@ obj-$(CONFIG_DEBUG_LL)	+= debug.o
 ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS)))
 extra-y	+= eabi_compat.o
 endif
+
+# some files can only build in ARM or THUMB2, not THUMB1
+
+ifdef CONFIG_SYS_THUMB_BUILD
+ifndef CONFIG_HAS_THUMB2
+
+# for C files, just apend -marm, which will override previous -mthumb*
+
+CFLAGS_cache.o := -marm
+CFLAGS_cache-cp15.o := -marm
+
+# For .S, drop -mthumb* and other thumb-related options.
+# CFLAGS_REMOVE_* would not have an effet, so AFLAGS_REMOVE_*
+# was implemented and is used here.
+# Also, define ${target}_NO_THUMB_BUILD for these two targets
+# so that the code knows it should not use Thumb.
+
+AFLAGS_REMOVE_memset.o := -mthumb -mthumb-interwork
+AFLAGS_REMOVE_memcpy.o := -mthumb -mthumb-interwork
+AFLAGS_memset.o := -DMEMSET_NO_THUMB_BUILD
+AFLAGS_memcpy.o := -DMEMCPY_NO_THUMB_BUILD
+
+endif
+endif
diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
index 74cfde6..7c8878d 100644
--- a/arch/arm/lib/cache.c
+++ b/arch/arm/lib/cache.c
@@ -95,3 +95,14 @@ phys_addr_t noncached_alloc(size_t size, size_t align)
 	return next;
 }
 #endif /* CONFIG_SYS_NONCACHED_MEMORY */
+
+#if defined(CONFIG_SYS_THUMB_BUILD)
+void invalidate_l2_cache(void)
+{
+	unsigned int val = 0;
+
+	asm volatile("mcr p15, 1, %0, c15, c11, 0 @ invl l2 cache"
+		: : "r" (val) : "cc");
+	isb();
+}
+#endif
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S
index ffaee74..409d5f7 100644
--- a/arch/arm/lib/memcpy.S
+++ b/arch/arm/lib/memcpy.S
@@ -13,7 +13,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-#ifdef CONFIG_SYS_THUMB_BUILD
+#if defined(CONFIG_SYS_THUMB_BUILD) && !defined(MEMCPY_NO_THUMB_BUILD)
 #define W(instr)	instr.w
 #else
 #define W(instr)	instr
@@ -62,7 +62,7 @@
 
 /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
 	.syntax unified
-#ifdef CONFIG_SYS_THUMB_BUILD
+#if defined(CONFIG_SYS_THUMB_BUILD) && !defined(MEMCPY_NO_THUMB_BUILD)
 	.thumb
 	.thumb_func
 #endif
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S
index 49bdff7..b586055 100644
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -16,7 +16,7 @@
 	.align	5
 
 	.syntax unified
-#ifdef CONFIG_SYS_THUMB_BUILD
+#if defined(CONFIG_SYS_THUMB_BUILD) && !defined(MEMSET_NO_THUMB_BUILD)
 	.thumb
 	.thumb_func
 #endif
diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile
index 546ebcb..33dcad4 100644
--- a/arch/arm/mach-orion5x/Makefile
+++ b/arch/arm/mach-orion5x/Makefile
@@ -16,3 +16,13 @@ obj-y	+= timer.o
 ifndef CONFIG_SKIP_LOWLEVEL_INIT
 obj-y	+= lowlevel_init.o
 endif
+
+# some files can only build in ARM or THUMB2, not THUMB1
+
+ifdef CONFIG_SYS_THUMB_BUILD
+ifndef CONFIG_HAS_THUMB2
+
+CFLAGS_cpu.o := -marm
+
+endif
+endif
diff --git a/arch/arm/thumb1/include/asm/proc-armv/system.h b/arch/arm/thumb1/include/asm/proc-armv/system.h
new file mode 100644
index 0000000..7dfbf3d
--- /dev/null
+++ b/arch/arm/thumb1/include/asm/proc-armv/system.h
@@ -0,0 +1,69 @@
+/*
+ *  Thumb-1 drop-in for the linux/include/asm-arm/proc-armv/system.h
+ *
+ *  (C) Copyright 2015
+ *  Albert ARIBAUD <albert.u.boot@aribaud.net>
+ *
+ * The original file does not build in Thumb mode. However, in U-Boot
+ * we don't use interrupt context, so we can redefine these as empty
+ * memory barriers, which makes Thumb-1 compiler happy.
+ *
+ *  SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Use the same macro name as linux/include/asm-arm/proc-armv/system.h
+ * here, so that if the original ever gets included after us, it won't
+ * try to re-redefine anything.
+ */
+
+#ifndef __ASM_PROC_SYSTEM_H
+#define __ASM_PROC_SYSTEM_H
+
+/*
+ * Redefine all original macros with static inline functions containing
+ * a simple memory barrier, so that they produce the same instruction
+ * ordering constraints as their original counterparts.
+ * We use static inline functions rather than macros so that we can tell
+ * the compiler to not complain about unused arguments.
+ */
+
+static inline void local_irq_save(
+	unsigned long flags __attribute__((unused)))
+{
+	__asm__ __volatile__ ("" : : : "memory");
+}
+
+static inline void local_irq_enable(void)
+{
+	__asm__ __volatile__ ("" : : : "memory");
+}
+
+static inline void local_irq_disable(void)
+{
+	__asm__ __volatile__ ("" : : : "memory");
+}
+
+static inline void __stf(void)
+{
+	__asm__ __volatile__ ("" : : : "memory");
+}
+
+static inline void __clf(void)
+{
+	__asm__ __volatile__ ("" : : : "memory");
+}
+
+static inline void local_save_flags(
+	unsigned long flags __attribute__((unused)))
+{
+	__asm__ __volatile__ ("" : : : "memory");
+}
+
+static inline void local_irq_restore(
+	unsigned long flags __attribute__((unused)))
+{
+	__asm__ __volatile__ ("" : : : "memory");
+}
+
+#endif /*  __ASM_PROC_SYSTEM_H */
diff --git a/examples/standalone/Makefile b/examples/standalone/Makefile
index 0863a8c..5a6ae00 100644
--- a/examples/standalone/Makefile
+++ b/examples/standalone/Makefile
@@ -73,3 +73,13 @@ $(obj)/%.srec: $(obj)/% FORCE
 $(obj)/%.bin: OBJCOPYFLAGS := -O binary
 $(obj)/%.bin: $(obj)/% FORCE
 	$(call if_changed,objcopy)
+
+# some files can only build in ARM or THUMB2, not THUMB1
+
+ifdef CONFIG_SYS_THUMB_BUILD
+ifndef CONFIG_HAS_THUMB2
+
+CFLAGS_stubs.o := -marm
+
+endif
+endif
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 8731fc6..3d5c872 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -104,8 +104,9 @@ modname_flags  = $(if $(filter 1,$(words $(modname))),\
 orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
                  $(ccflags-y) $(CFLAGS_$(basetarget).o)
 _c_flags       = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
-_a_flags       = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
+orig_a_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
                  $(asflags-y) $(AFLAGS_$(basetarget).o)
+_a_flags       = $(filter-out $(AFLAGS_REMOVE_$(basetarget).o), $(orig_a_flags))
 _cpp_flags     = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
 
 #
