Merge branch '2021-09-02-assorted-platform-and-bugfixes' into next

- Add position independent execution support for ARMv7
- Snapdragon, synquacer, vexpress64 fixes / improvements
- Prevent NEON register use on ARMv8
- Other assorted fixes
diff --git a/.mailmap b/.mailmap
index b76f022..3d15a09 100644
--- a/.mailmap
+++ b/.mailmap
@@ -29,6 +29,7 @@
 Jagan Teki <jaganna@xilinx.com>
 Jagan Teki <jagannadh.teki@gmail.com>
 Jagan Teki <jagannadha.sutradharudu-teki@xilinx.com>
+Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
 Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@linaro.org>
 Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@toradex.com>
 Markus Klotzbuecher <mk@denx.de>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c815ad4..47f0945 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -9,9 +9,9 @@
 	select PHYS_64BIT
 	select SYS_CACHE_SHIFT_6
 
-if ARM64
 config POSITION_INDEPENDENT
 	bool "Generate position-independent pre-relocation code"
+	depends on ARM64 || CPU_V7A
 	help
 	  U-Boot expects to be linked to a specific hard-coded address, and to
 	  be loaded to and run from that address. This option lifts that
@@ -22,6 +22,7 @@
 
 config INIT_SP_RELATIVE
 	bool "Specify the early stack pointer relative to the .bss section"
+	depends on ARM64
 	default n if ARCH_QEMU
 	default y if POSITION_INDEPENDENT
 	help
@@ -37,6 +38,7 @@
 
 config SYS_INIT_SP_BSS_OFFSET
 	int "Early stack offset from the .bss base address"
+	depends on ARM64
 	depends on INIT_SP_RELATIVE
 	default 524288
 	help
@@ -46,6 +48,7 @@
 	  do not overlap any appended DTB.
 
 config LINUX_KERNEL_IMAGE_HEADER
+	depends on ARM64
 	bool
 	help
 	  Place a Linux kernel image header at the start of the U-Boot binary.
@@ -54,14 +57,12 @@
 	  image header reports the amount of memory (BSS and similar) that
 	  U-Boot needs to use, but which isn't part of the binary.
 
-if LINUX_KERNEL_IMAGE_HEADER
 config LNX_KRNL_IMG_TEXT_OFFSET_BASE
+	depends on LINUX_KERNEL_IMAGE_HEADER
 	hex
 	help
 	  The value subtracted from CONFIG_SYS_TEXT_BASE to calculate the
 	  TEXT_OFFSET value written to the Linux kernel image header.
-endif
-endif
 
 config GICV2
 	bool
@@ -1184,6 +1185,13 @@
 	select PL01X_SERIAL
 	select SEMIHOSTING
 
+config TARGET_VEXPRESS64_BASER_FVP
+	bool "Support Versatile Express ARMv8r64 FVP BASE model"
+	select ARM64
+	select DM
+	select DM_SERIAL
+	select PL01X_SERIAL
+
 config TARGET_VEXPRESS64_JUNO
 	bool "Support Versatile Express Juno Development Platform"
 	select ARM64
diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index b684d8b..b107b1a 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -25,6 +25,7 @@
 
 PLATFORM_RELFLAGS += -fno-common -ffixed-r9
 PLATFORM_RELFLAGS += $(call cc-option, -msoft-float) \
+		     $(call cc-option,-mgeneral-regs-only) \
       $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
 
 # LLVM support
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index 87329d2..698e15b 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -39,6 +39,42 @@
 	/* Allow the board to save important registers */
 	b	save_boot_params
 save_boot_params_ret:
+#ifdef CONFIG_POSITION_INDEPENDENT
+	/*
+	 * Fix .rela.dyn relocations. This allows U-Boot to loaded to and
+	 * executed at a different address than it was linked at.
+	 */
+pie_fixup:
+	adr	r0, reset	/* r0 <- Runtime value of reset label */
+	ldr	r1, =reset	/* r1 <- Linked value of reset label */
+	subs	r4, r0, r1	/* r4 <- Runtime-vs-link offset */
+	beq	pie_fixup_done
+
+	adr	r0, pie_fixup
+	ldr	r1, _rel_dyn_start_ofs
+	add	r2, r0, r1	/* r2 <- Runtime &__rel_dyn_start */
+	ldr	r1, _rel_dyn_end_ofs
+	add	r3, r0, r1	/* r3 <- Runtime &__rel_dyn_end */
+
+pie_fix_loop:
+	ldr	r0, [r2]	/* r0 <- Link location */
+	ldr	r1, [r2, #4]	/* r1 <- fixup */
+	cmp	r1, #23		/* relative fixup? */
+	bne	pie_skip_reloc
+
+	/* relative fix: increase location by offset */
+	add	r0, r4
+	ldr	r1, [r0]
+	add	r1, r4
+	str	r1, [r0]
+	str	r0, [r2]
+	add	r2, #8
+pie_skip_reloc:
+	cmp	r2, r3
+	blo	pie_fix_loop
+pie_fixup_done:
+#endif
+
 #ifdef CONFIG_ARMV7_LPAE
 /*
  * check for Hypervisor support
@@ -340,3 +376,10 @@
 	b	lowlevel_init		@ go setup pll,mux,memory
 ENDPROC(cpu_init_crit)
 #endif
+
+#if CONFIG_POSITION_INDEPENDENT
+_rel_dyn_start_ofs:
+	.word	__rel_dyn_start - pie_fixup
+_rel_dyn_end_ofs:
+	.word	__rel_dyn_end - pie_fixup
+#endif
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index 3de18c7..4662567 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -15,6 +15,7 @@
 #include <asm/global_data.h>
 #include <asm/system.h>
 #include <asm/armv8/mmu.h>
+#include <asm/armv8/mpu.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -365,6 +366,86 @@
 	return size;
 }
 
+static void mpu_clear_regions(void)
+{
+	int i;
+
+	for (i = 0; mpu_mem_map[i].end || mpu_mem_map[i].attrs; i++) {
+		setup_el2_mpu_region(i, 0, 0);
+	}
+}
+
+static struct mpu_region default_mpu_mem_map[] = {{0,}};
+__weak struct mpu_region *mpu_mem_map = default_mpu_mem_map;
+
+static void mpu_setup(void)
+{
+	int i;
+
+	if (current_el() != 2) {
+		panic("MPU configuration is only supported at EL2");
+	}
+
+	set_sctlr(get_sctlr() & ~(CR_M | CR_WXN));
+
+	asm volatile("msr MAIR_EL2, %0" : : "r" MEMORY_ATTRIBUTES);
+
+	for (i = 0; mpu_mem_map[i].end || mpu_mem_map[i].attrs; i++) {
+		setup_el2_mpu_region(i,
+			PRBAR_ADDRESS(mpu_mem_map[i].start)
+				| PRBAR_OUTER_SH | PRBAR_AP_RW_ANY,
+			PRLAR_ADDRESS(mpu_mem_map[i].end)
+				| mpu_mem_map[i].attrs | PRLAR_EN_BIT
+			);
+	}
+
+	set_sctlr(get_sctlr() | CR_M);
+}
+
+static bool el_has_mmu(void)
+{
+	uint64_t id_aa64mmfr0;
+	asm volatile("mrs %0, id_aa64mmfr0_el1"
+			: "=r" (id_aa64mmfr0) : : "cc");
+	uint64_t msa = id_aa64mmfr0 & ID_AA64MMFR0_EL1_MSA_MASK;
+	uint64_t msa_frac = id_aa64mmfr0 & ID_AA64MMFR0_EL1_MSA_FRAC_MASK;
+
+	switch (msa) {
+		case ID_AA64MMFR0_EL1_MSA_VMSA:
+			/*
+			 * VMSA supported in all translation regimes.
+			 * No support for PMSA.
+			 */
+			return true;
+		case ID_AA64MMFR0_EL1_MSA_USE_FRAC:
+			/* See MSA_frac for the supported MSAs. */
+			switch (msa_frac) {
+				case ID_AA64MMFR0_EL1_MSA_FRAC_NO_PMSA:
+					/*
+					 * PMSA not supported in any translation
+					 * regime.
+					 */
+					return true;
+				case ID_AA64MMFR0_EL1_MSA_FRAC_VMSA:
+					/*
+					* PMSA supported in all translation
+					* regimes. No support for VMSA.
+					*/
+				case ID_AA64MMFR0_EL1_MSA_FRAC_PMSA:
+					/*
+					 * PMSA supported in all translation
+					 * regimes.
+					 */
+					return false;
+				default:
+					panic("Unsupported id_aa64mmfr0_el1 " \
+						"MSA_frac value");
+			}
+		default:
+			panic("Unsupported id_aa64mmfr0_el1 MSA value");
+	}
+}
+
 void setup_pgtables(void)
 {
 	int i;
@@ -479,8 +560,13 @@
 	/* The data cache is not active unless the mmu is enabled */
 	if (!(get_sctlr() & CR_M)) {
 		invalidate_dcache_all();
-		__asm_invalidate_tlb_all();
-		mmu_setup();
+
+		if (el_has_mmu()) {
+			__asm_invalidate_tlb_all();
+			mmu_setup();
+		} else {
+			mpu_setup();
+		}
 	}
 
 	set_sctlr(get_sctlr() | CR_C);
@@ -499,7 +585,11 @@
 	set_sctlr(sctlr & ~(CR_C|CR_M));
 
 	flush_dcache_all();
-	__asm_invalidate_tlb_all();
+
+	if (el_has_mmu())
+		__asm_invalidate_tlb_all();
+	else
+		mpu_clear_regions();
 }
 
 int dcache_status(void)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/spintable.S b/arch/arm/cpu/armv8/fsl-layerscape/spintable.S
index 363ded0..d6bd188 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/spintable.S
+++ b/arch/arm/cpu/armv8/fsl-layerscape/spintable.S
@@ -93,7 +93,7 @@
 4:
 #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
 	switch_el x7, _dead_loop, 0f, _dead_loop
-0:	armv8_switch_to_el1_m x4, x6, x7
+0:	armv8_switch_to_el1_m x4, x6, x7, x9
 #else
 	switch_el x7, 0f, _dead_loop, _dead_loop
 0:	armv8_switch_to_el2_m x4, x6, x7
diff --git a/arch/arm/cpu/armv8/transition.S b/arch/arm/cpu/armv8/transition.S
index a31af4f..9dbdff3 100644
--- a/arch/arm/cpu/armv8/transition.S
+++ b/arch/arm/cpu/armv8/transition.S
@@ -40,7 +40,7 @@
 	 * now, jump to the address saved in x4.
 	 */
 	br x4
-1:	armv8_switch_to_el1_m x4, x5, x6
+1:	armv8_switch_to_el1_m x4, x5, x6, x7
 ENDPROC(armv8_switch_to_el1)
 .popsection
 
diff --git a/arch/arm/include/asm/armv8/mpu.h b/arch/arm/include/asm/armv8/mpu.h
new file mode 100644
index 0000000..c6c8828
--- /dev/null
+++ b/arch/arm/include/asm/armv8/mpu.h
@@ -0,0 +1,61 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2021 Arm Limited
+ */
+
+#ifndef _ASM_ARMV8_MPU_H_
+#define _ASM_ARMV8_MPU_H_
+
+#include <asm/armv8/mmu.h>
+#include <asm/barriers.h>
+#include <linux/stringify.h>
+
+#define PRSELR_EL2		S3_4_c6_c2_1
+#define PRBAR_EL2		S3_4_c6_c8_0
+#define PRLAR_EL2		S3_4_c6_c8_1
+#define MPUIR_EL2		S3_4_c0_c0_4
+
+#define PRBAR_ADDRESS(addr)	((addr) & ~(0x3fULL))
+
+/* Access permissions */
+#define PRBAR_AP(val)		(((val) & 0x3) << 2)
+#define PRBAR_AP_RW_HYP		PRBAR_AP(0x0)
+#define PRBAR_AP_RW_ANY		PRBAR_AP(0x1)
+#define PRBAR_AP_RO_HYP		PRBAR_AP(0x2)
+#define PRBAR_AP_RO_ANY		PRBAR_AP(0x3)
+
+/* Shareability */
+#define PRBAR_SH(val)		(((val) & 0x3) << 4)
+#define PRBAR_NON_SH		PRBAR_SH(0x0)
+#define PRBAR_OUTER_SH		PRBAR_SH(0x2)
+#define PRBAR_INNER_SH		PRBAR_SH(0x3)
+
+/* Memory attribute (MAIR idx) */
+#define PRLAR_ATTRIDX(val)	(((val) & 0x7) << 1)
+#define PRLAR_EN_BIT		(0x1)
+#define PRLAR_ADDRESS(addr)	((addr) & ~(0x3fULL))
+
+#ifndef __ASSEMBLY__
+
+static inline void setup_el2_mpu_region(uint8_t region, uint64_t base, uint64_t limit)
+{
+	asm volatile("msr " __stringify(PRSELR_EL2) ", %0" : : "r" (region));
+	isb();
+	asm volatile("msr " __stringify(PRBAR_EL2) ", %0" : : "r" (base));
+	asm volatile("msr " __stringify(PRLAR_EL2) ", %0" : : "r" (limit));
+	dsb();
+	isb();
+}
+
+#endif
+
+struct mpu_region {
+	u64 start;
+	u64 end;
+	u64 attrs;
+};
+
+extern struct mpu_region *mpu_mem_map;
+
+#endif /* _ASM_ARMV8_MPU_H_ */
diff --git a/arch/arm/include/asm/macro.h b/arch/arm/include/asm/macro.h
index 485310d..ecd8221 100644
--- a/arch/arm/include/asm/macro.h
+++ b/arch/arm/include/asm/macro.h
@@ -256,7 +256,7 @@
  * For loading 64-bit OS, x0 is physical address to the FDT blob.
  * They will be passed to the guest.
  */
-.macro armv8_switch_to_el1_m, ep, flag, tmp
+.macro armv8_switch_to_el1_m, ep, flag, tmp, tmp2
 	/* Initialize Generic Timers */
 	mrs	\tmp, cnthctl_el2
 	/* Enable EL1 access to timers */
@@ -306,9 +306,33 @@
 	b.eq	1f
 
 	/* Initialize HCR_EL2 */
-	ldr	\tmp, =(HCR_EL2_RW_AARCH64 | HCR_EL2_HCD_DIS)
+	/* Only disable PAuth traps if PAuth is supported */
+	mrs	\tmp, id_aa64isar1_el1
+	ldr	\tmp2, =(ID_AA64ISAR1_EL1_GPI | ID_AA64ISAR1_EL1_GPA | \
+		      ID_AA64ISAR1_EL1_API | ID_AA64ISAR1_EL1_APA)
+	tst	\tmp, \tmp2
+	mov	\tmp2, #(HCR_EL2_RW_AARCH64 | HCR_EL2_HCD_DIS)
+	orr	\tmp, \tmp2, #(HCR_EL2_APK | HCR_EL2_API)
+	csel	\tmp, \tmp2, \tmp, eq
 	msr	hcr_el2, \tmp
 
+	/*
+	 * Detect whether the system has a configurable memory system
+	 * architecture at EL1&0
+	 */
+	mrs	\tmp, id_aa64mmfr0_el1
+	lsr	\tmp, \tmp, #48
+	and	\tmp, \tmp, #((ID_AA64MMFR0_EL1_MSA_MASK | \
+			ID_AA64MMFR0_EL1_MSA_FRAC_MASK) >> 48)
+	cmp	\tmp, #((ID_AA64MMFR0_EL1_MSA_USE_FRAC | \
+			ID_AA64MMFR0_EL1_MSA_FRAC_VMSA) >> 48)
+	bne	2f
+
+	/* Ensure the EL1&0 VMSA is enabled */
+	mov	\tmp, #(VTCR_EL2_MSA)
+	msr	vtcr_el2, \tmp
+2:
+
 	/* Return to the EL1_SP1 mode from EL2 */
 	ldr	\tmp, =(SPSR_EL_DEBUG_MASK | SPSR_EL_SERR_MASK |\
 			SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 8b3a54e..1ec6237 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -75,11 +75,50 @@
 /*
  * HCR_EL2 bits definitions
  */
+#define HCR_EL2_API		(1 << 41) /* Trap pointer authentication
+				             instructions                     */
+#define HCR_EL2_APK		(1 << 40) /* Trap pointer authentication
+				             key access                       */
 #define HCR_EL2_RW_AARCH64	(1 << 31) /* EL1 is AArch64                   */
 #define HCR_EL2_RW_AARCH32	(0 << 31) /* Lower levels are AArch32         */
 #define HCR_EL2_HCD_DIS		(1 << 29) /* Hypervisor Call disabled         */
 
 /*
+ * VTCR_EL2 bits definitions
+ */
+#define VTCR_EL2_MSA      	(1 << 31) /* EL1&0 memory architecture        */
+
+/*
+ * ID_AA64MMFR0_EL1 bits definitions
+ */
+#define ID_AA64MMFR0_EL1_MSA_FRAC_MASK		(0xFUL << 52) /* Memory system
+								 architecture
+								 frac         */
+#define ID_AA64MMFR0_EL1_MSA_FRAC_VMSA		(0x2UL << 52) /* EL1&0 supports
+								 VMSA         */
+#define ID_AA64MMFR0_EL1_MSA_FRAC_PMSA		(0x1UL << 52) /* EL1&0 only
+							         supports PMSA*/
+#define ID_AA64MMFR0_EL1_MSA_FRAC_NO_PMSA	(0x0UL << 52) /* No PMSA
+								 support      */
+#define ID_AA64MMFR0_EL1_MSA_MASK		(0xFUL << 48) /* Memory system
+								 architecture */
+#define ID_AA64MMFR0_EL1_MSA_USE_FRAC		(0xFUL << 48) /* Use MSA_FRAC */
+#define ID_AA64MMFR0_EL1_MSA_VMSA		(0x0UL << 48) /* Memory system
+								 architecture
+								 is VMSA      */
+
+/*
+ * ID_AA64ISAR1_EL1 bits definitions
+ */
+#define ID_AA64ISAR1_EL1_GPI	(0xF << 28) /* Implementation-defined generic
+				               code auth algorithm            */
+#define ID_AA64ISAR1_EL1_GPA	(0xF << 24) /* QARMA generic code auth
+				               algorithm                      */
+#define ID_AA64ISAR1_EL1_API	(0xF << 8)  /* Implementation-defined address
+				               auth algorithm                 */
+#define ID_AA64ISAR1_EL1_APA	(0xF << 4)  /* QARMA address auth algorithm   */
+
+/*
  * ID_AA64PFR0_EL1 bits definitions
  */
 #define ID_AA64PFR0_EL1_EL3	(0xF << 12) /* EL3 implemented                */
@@ -551,7 +590,6 @@
 u32 psci_migrate_info_type(void);
 void psci_system_off(void);
 void psci_system_reset(void);
-s32 psci_features(u32 function_id, u32 psci_fid);
 #endif
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index f60ee3a..ea9bfe7 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -317,7 +317,6 @@
 {
 }
 
-#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
 static void switch_to_el1(void)
 {
 	if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
@@ -332,7 +331,6 @@
 				    ES_TO_AARCH64);
 }
 #endif
-#endif
 
 /* Subcommand: GO */
 static void boot_jump_linux(bootm_headers_t *images, int flag)
@@ -359,21 +357,33 @@
 
 		update_os_arch_secondary_cores(images->os.arch);
 
-#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
-		armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
-				    (u64)switch_to_el1, ES_TO_AARCH64);
+#ifdef CONFIG_ARMV8_MULTIENTRY
+		int armv8_switch_to_el1 = -1;
 #else
-		if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
-		    (images->os.arch == IH_ARCH_ARM))
-			armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number,
-					    (u64)images->ft_addr, 0,
-					    (u64)images->ep,
-					    ES_TO_AARCH32);
-		else
-			armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
-					    images->ep,
-					    ES_TO_AARCH64);
+		int armv8_switch_to_el1 = env_get_yesno("armv8_switch_to_el1");
 #endif
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+		if (armv8_switch_to_el1 == -1) {
+			armv8_switch_to_el1 = 1;
+		}
+#endif
+		if (armv8_switch_to_el1 == 1) {
+			armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
+					    (u64)switch_to_el1, ES_TO_AARCH64);
+		} else {
+			if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
+					(images->os.arch == IH_ARCH_ARM))
+				armv8_switch_to_el2(0,
+						    (u64)gd->bd->bi_arch_number,
+						    (u64)images->ft_addr, 0,
+						    (u64)images->ep,
+						    ES_TO_AARCH32);
+			else
+				armv8_switch_to_el2((u64)images->ft_addr,
+						    0, 0, 0,
+						    images->ep,
+						    ES_TO_AARCH64);
+		}
 	}
 #else
 	unsigned long machid = gd->bd->bi_arch_number;
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S
index 46b6be2..956d258 100644
--- a/arch/arm/lib/crt0.S
+++ b/arch/arm/lib/crt0.S
@@ -130,6 +130,14 @@
 	ldr	r9, [r9, #GD_NEW_GD]		/* r9 <- gd->new_gd */
 
 	adr	lr, here
+#if defined(CONFIG_POSITION_INDEPENDENT)
+	adr	r0, _main
+	ldr	r1, _start_ofs
+	add	r0, r1
+	ldr	r1, =CONFIG_SYS_TEXT_BASE
+	sub	r1, r0
+	add	lr, r1
+#endif
 	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
 	add	lr, lr, r0
 #if defined(CONFIG_CPU_V7M)
@@ -180,3 +188,6 @@
 #endif
 
 ENDPROC(_main)
+
+_start_ofs:
+	.word	_start - _main
diff --git a/arch/arm/lib/relocate.S b/arch/arm/lib/relocate.S
index e5f7267..14b7f61 100644
--- a/arch/arm/lib/relocate.S
+++ b/arch/arm/lib/relocate.S
@@ -78,22 +78,28 @@
  */
 
 ENTRY(relocate_code)
-	ldr	r1, =__image_copy_start	/* r1 <- SRC &__image_copy_start */
-	subs	r4, r0, r1		/* r4 <- relocation offset */
-	beq	relocate_done		/* skip relocation */
-	ldr	r2, =__image_copy_end	/* r2 <- SRC &__image_copy_end */
-
+	adr	r3, relocate_code
+	ldr	r1, _image_copy_start_ofs
+	add	r1, r3			/* r1 <- Run &__image_copy_start */
+	subs	r4, r0, r1		/* r4 <- Run to copy offset      */
+	beq	relocate_done		/* skip relocation               */
+	ldr	r1, _image_copy_start_ofs
+	add	r1, r3			/* r1 <- Run &__image_copy_start */
+	ldr	r2, _image_copy_end_ofs
+	add	r2, r3			/* r2 <- Run &__image_copy_end   */
 copy_loop:
-	ldmia	r1!, {r10-r11}		/* copy from source address [r1]    */
-	stmia	r0!, {r10-r11}		/* copy to   target address [r0]    */
-	cmp	r1, r2			/* until source end address [r2]    */
+	ldmia	r1!, {r10-r11}		/* copy from source address [r1] */
+	stmia	r0!, {r10-r11}		/* copy to   target address [r0] */
+	cmp	r1, r2			/* until source end address [r2] */
 	blo	copy_loop
 
 	/*
 	 * fix .rel.dyn relocations
 	 */
-	ldr	r2, =__rel_dyn_start	/* r2 <- SRC &__rel_dyn_start */
-	ldr	r3, =__rel_dyn_end	/* r3 <- SRC &__rel_dyn_end */
+	ldr	r1, _rel_dyn_start_ofs
+	add	r2, r1, r3		/* r2 <- Run &__rel_dyn_start */
+	ldr	r1, _rel_dyn_end_ofs
+	add	r3, r1, r3		/* r3 <- Run &__rel_dyn_end */
 fixloop:
 	ldmia	r2!, {r0-r1}		/* (r0,r1) <- (SRC location,fixup) */
 	and	r1, r1, #0xff
@@ -129,3 +135,12 @@
 #endif
 
 ENDPROC(relocate_code)
+
+_image_copy_start_ofs:
+	.word	__image_copy_start - relocate_code
+_image_copy_end_ofs:
+	.word	__image_copy_end - relocate_code
+_rel_dyn_start_ofs:
+	.word	__rel_dyn_start - relocate_code
+_rel_dyn_end_ofs:
+	.word	__rel_dyn_end - relocate_code
diff --git a/arch/arm/mach-snapdragon/misc.c b/arch/arm/mach-snapdragon/misc.c
index 985625a..7d452f4 100644
--- a/arch/arm/mach-snapdragon/misc.c
+++ b/arch/arm/mach-snapdragon/misc.c
@@ -9,6 +9,7 @@
 #include <common.h>
 #include <mmc.h>
 #include <asm/arch/misc.h>
+#include <asm/unaligned.h>
 
 /* UNSTUFF_BITS macro taken from Linux Kernel: drivers/mmc/core/sd.c */
 #define UNSTUFF_BITS(resp, start, size) \
@@ -33,21 +34,22 @@
 	if (!mmc_dev)
 		return 0;
 
+	if (mmc_init(mmc_dev))
+		return 0;
+
 	return UNSTUFF_BITS(mmc_dev->cid, 16, 32);
 }
 
 void msm_generate_mac_addr(u8 *mac)
 {
-	int i;
-	char sn[9];
-
-	snprintf(sn, 9, "%08x", msm_board_serial());
-
-	/* fill in the mac with serialno, use locally adminstrated pool */
+	/* use locally adminstrated pool */
 	mac[0] = 0x02;
-	mac[1] = 00;
-	for (i = 3; i >= 0; i--) {
-		mac[i + 2] = hextoul(&sn[2 * i], NULL);
-		sn[2 * i] = 0;
-	}
+	mac[1] = 0x00;
+
+	/*
+	 * Put the 32-bit serial number in the last 32-bit of the MAC address.
+	 * Use big endian order so it is consistent with the serial number
+	 * written as a hexadecimal string, e.g. 0x1234abcd -> 02:00:12:34:ab:cd
+	 */
+	put_unaligned_be32(msm_board_serial(), &mac[2]);
 }
diff --git a/board/armltd/vexpress64/Kconfig b/board/armltd/vexpress64/Kconfig
index 1d13f54..1f0c7ad 100644
--- a/board/armltd/vexpress64/Kconfig
+++ b/board/armltd/vexpress64/Kconfig
@@ -1,4 +1,5 @@
-if TARGET_VEXPRESS64_BASE_FVP || TARGET_VEXPRESS64_JUNO
+if TARGET_VEXPRESS64_BASE_FVP || TARGET_VEXPRESS64_JUNO || \
+	TARGET_VEXPRESS64_BASER_FVP
 
 config SYS_BOARD
 	default "vexpress64"
@@ -7,7 +8,7 @@
 	default "armltd"
 
 config SYS_CONFIG_NAME
-	default "vexpress_aemv8a"
+	default "vexpress_aemv8"
 
 config JUNO_DTB_PART
 	string "NOR flash partition holding DTB"
diff --git a/board/armltd/vexpress64/MAINTAINERS b/board/armltd/vexpress64/MAINTAINERS
index 0ba044d..875401a 100644
--- a/board/armltd/vexpress64/MAINTAINERS
+++ b/board/armltd/vexpress64/MAINTAINERS
@@ -14,3 +14,8 @@
 M:	Linus Walleij <linus.walleij@linaro.org>
 S:	Maintained
 F:	configs/vexpress_aemv8a_juno_defconfig
+
+VEXPRESS64 BASER_FVP
+M:	Peter Hoyes <Peter.Hoyes@arm.com>
+S:	Maintained
+F:	configs/vexpress_aemv8r_defconfig
diff --git a/board/armltd/vexpress64/vexpress64.c b/board/armltd/vexpress64/vexpress64.c
index 2e42602..eb4951d 100644
--- a/board/armltd/vexpress64/vexpress64.c
+++ b/board/armltd/vexpress64/vexpress64.c
@@ -18,6 +18,7 @@
 #include <dm/platform_data/serial_pl01x.h>
 #include "pcie.h"
 #include <asm/armv8/mmu.h>
+#include <asm/armv8/mpu.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -54,6 +55,27 @@
 
 struct mm_region *mem_map = vexpress64_mem_map;
 
+static struct mpu_region vexpress64_aemv8r_mem_map[] = {
+	{
+		.start = 0x0UL,
+		.end = 0x7fffffffUL,
+		.attrs = PRLAR_ATTRIDX(MT_NORMAL)
+	}, {
+		.start = 0x80000000UL,
+		.end = 0xffffffffUL,
+		.attrs = PRLAR_ATTRIDX(MT_DEVICE_NGNRNE)
+	}, {
+		.start = 0x100000000UL,
+		.end = 0xffffffffffUL,
+		.attrs = PRLAR_ATTRIDX(MT_NORMAL)
+	}, {
+		/* List terminator */
+		0,
+	}
+};
+
+struct mpu_region *mpu_mem_map = vexpress64_aemv8r_mem_map;
+
 /* This function gets replaced by platforms supporting PCIe.
  * The replacement function, eg. on Juno, initialises the PCIe bus.
  */
diff --git a/configs/sifive_unleashed_defconfig b/configs/sifive_unleashed_defconfig
index cf50101..be947be 100644
--- a/configs/sifive_unleashed_defconfig
+++ b/configs/sifive_unleashed_defconfig
@@ -24,7 +24,6 @@
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_SPI_LOAD=y
-CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_SPL_CLK=y
diff --git a/configs/sifive_unmatched_defconfig b/configs/sifive_unmatched_defconfig
index 890d3a0..3d478ad 100644
--- a/configs/sifive_unmatched_defconfig
+++ b/configs/sifive_unmatched_defconfig
@@ -23,7 +23,6 @@
 CONFIG_ID_EEPROM=y
 CONFIG_SPL_SEPARATE_BSS=y
 CONFIG_SPL_DM_RESET=y
-CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_CMD_EEPROM=y
 CONFIG_CMD_MEMINFO=y
 CONFIG_CMD_PWM=y
diff --git a/configs/synquacer_developerbox_defconfig b/configs/synquacer_developerbox_defconfig
index 802f181..a88856b 100644
--- a/configs/synquacer_developerbox_defconfig
+++ b/configs/synquacer_developerbox_defconfig
@@ -1,7 +1,6 @@
 CONFIG_ARM=y
-CONFIG_POSITION_INDEPENDENT=y
 CONFIG_ARCH_SYNQUACER=y
-CONFIG_SYS_TEXT_BASE=0x00000000
+CONFIG_SYS_TEXT_BASE=0x08200000
 CONFIG_ENV_SIZE=0x30000
 CONFIG_ENV_OFFSET=0x300000
 CONFIG_ENV_SECT_SIZE=0x10000
diff --git a/configs/vexpress_aemv8r_defconfig b/configs/vexpress_aemv8r_defconfig
new file mode 100644
index 0000000..bb4d1e5
--- /dev/null
+++ b/configs/vexpress_aemv8r_defconfig
@@ -0,0 +1,19 @@
+CONFIG_ARM=y
+CONFIG_TARGET_VEXPRESS64_BASER_FVP=y
+CONFIG_SYS_TEXT_BASE=0x00001000
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_SYS_MEMTEST_START=0x80000000
+CONFIG_SYS_MEMTEST_END=0xff000000
+CONFIG_ENV_SIZE=0x40000
+CONFIG_ENV_SECT_SIZE=0x40000
+CONFIG_IDENT_STRING=" vexpress_aemv8r64"
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyAMA0 earlycon=pl011,0x9c090000 rootfstype=ext4 root=/dev/vda1 rw rootwait"
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="fdt addr ${fdt_addr}; fdt resize; booti $kernel_addr - $fdt_addr"
+# CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_SYS_PROMPT="VExpress64# "
+CONFIG_OF_LIBFDT=y
diff --git a/disk/part_iso.c b/disk/part_iso.c
index 822f2c4..1061f34 100644
--- a/disk/part_iso.c
+++ b/disk/part_iso.c
@@ -220,7 +220,7 @@
 	printf("Part   Start     Sect x Size Type\n");
 	i=1;
 	do {
-		printf(" %2d " LBAFU " " LBAFU " %6ld %.32s\n",
+		printf(" %2d %8" LBAFlength "u %8" LBAFlength "u %6ld %.32s\n",
 		       i, info.start, info.size, info.blksz, info.type);
 		i++;
 	} while (part_get_info_iso_verb(dev_desc, i, &info, 0) != -1);
diff --git a/doc/README.semihosting b/doc/README.semihosting
index c019999..f382d01 100644
--- a/doc/README.semihosting
+++ b/doc/README.semihosting
@@ -25,7 +25,7 @@
 Rather than create a new armv8 board similar to armltd/vexpress64, add
 semihosting calls to the existing one, enabled with CONFIG_SEMIHOSTING
 and CONFIG_BASE_FVP both set. Also reuse the existing board config file
-vexpress_aemv8a.h but differentiate the two models by the presence or
+vexpress_aemv8.h but differentiate the two models by the presence or
 absence of CONFIG_BASE_FVP. This change is tested and works on both the
 Foundation and Base fastmodel simulators.
 
diff --git a/doc/arch/arm64.rst b/doc/arch/arm64.rst
index 80498f6..f20eb8f 100644
--- a/doc/arch/arm64.rst
+++ b/doc/arch/arm64.rst
@@ -18,7 +18,8 @@
    classical firmware (like initial hardware setup, CPU errata workarounds
    or SMP bringup). U-Boot can be entered in EL2 when its main purpose is
    that of a boot loader. It can drop to lower exception levels before
-   entering the OS.
+   entering the OS. For ARMv8-R it is recommened to enter at S-EL2, as for this
+   architecture there is no S-EL3.
 
 2. U-Boot for arm64 is compiled with AArch64-gcc. AArch64-gcc
    use rela relocation format, a tool(tools/relocate-rela) by Scott Wood
diff --git a/doc/board/armltd/index.rst b/doc/board/armltd/index.rst
new file mode 100644
index 0000000..b6786c1
--- /dev/null
+++ b/doc/board/armltd/index.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Arm Ltd
+=============
+
+.. toctree::
+   :maxdepth: 2
+
+   vexpress64.rst
diff --git a/doc/board/armltd/vexpress64.rst b/doc/board/armltd/vexpress64.rst
new file mode 100644
index 0000000..37ef564
--- /dev/null
+++ b/doc/board/armltd/vexpress64.rst
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Arm Versatile Express
+=====================
+
+The vexpress_* board configuration supports the following platforms:
+
+ * FVP_Base_RevC-2xAEMvA
+ * FVP_BaseR_AEMv8R
+ * Juno development board
+
+Fixed Virtual Platforms
+-----------------------
+
+The Fixed Virtual Platforms (FVP) are complete simulations of an Arm system,
+including processor, memory and peripherals. They are set out in a "programmer's
+view", which gives a comprehensive model on which to build and test software.
+
+The supported FVPs are available free of charge and can be downloaded from the
+Arm developer site [1]_ (user registration might be required).
+
+Supported features:
+
+ * GICv3
+ * Generic timer
+ * PL011 UART
+ * SMC91111 network interface
+
+The default configuration assumes that U-Boot is boostrapped from the start of
+the DRAM (address 0x80000000 for AEMvA; 0x00000000 for AEMv8R) using a suitable
+bootloader. Alternatively, U-Boot can be launched directly by mapping the binary
+to the same address (using the FVP's --data argument).
+
+The FVPs can be debugged using Arm Development Studio [2]_.
+
+FVP_BaseR
+^^^^^^^^^
+
+On Armv8r64 platforms (such as the FVP_BaseR), U-Boot runs at S-EL2, so
+CONFIG_ARMV8_SWITCH_TO_EL1 is defined so that the next stage boots at S-EL1. If
+S-EL2 is desired instead, the *armv8_switch_to_el1* environment variable is
+available. This can be set to *n* to override the config flag and boot the next
+stage at S-EL2 instead.
+
+Juno
+----
+
+The Juno development board is an open, vendor-neutral Armv8-A development
+platform that supports an out-of-the-box Linux software package. A range of
+plug-in expansion options enables hardware and software applications to be
+developed and debugged.
+
+References
+----------
+
+.. [1] https://developer.arm.com/tools-and-software/simulation-models/fixed-virtual-platforms
+.. [2] https://developer.arm.com/tools-and-software/embedded/arm-development-studio
diff --git a/doc/board/index.rst b/doc/board/index.rst
index 8588e45..827f086 100644
--- a/doc/board/index.rst
+++ b/doc/board/index.rst
@@ -10,6 +10,7 @@
    advantech/index
    AndesTech/index
    amlogic/index
+   armltd/index
    atmel/index
    congatec/index
    coreboot/index
diff --git a/drivers/pci/pcie_iproc.c b/drivers/pci/pcie_iproc.c
index 12ce9d5..be03dcb 100644
--- a/drivers/pci/pcie_iproc.c
+++ b/drivers/pci/pcie_iproc.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright (C) 2020 Broadcom
+ * Copyright (C) 2020-2021 Broadcom
  *
  */
 
@@ -12,6 +12,7 @@
 #include <malloc.h>
 #include <asm/io.h>
 #include <dm/device_compat.h>
+#include <linux/delay.h>
 #include <linux/log2.h>
 
 #define EP_PERST_SOURCE_SELECT_SHIFT 2
@@ -884,7 +885,7 @@
 	for (i = 0; i < hose->region_count; i++) {
 		if (hose->regions[i].flags == PCI_REGION_MEM ||
 		    hose->regions[i].flags == PCI_REGION_PREFETCH) {
-			debug("%d: bus_addr %p, axi_addr %p, size 0x%lx\n",
+			debug("%d: bus_addr %p, axi_addr %p, size 0x%llx\n",
 			      i, &hose->regions[i].bus_start,
 			      &hose->regions[i].phys_start,
 			      hose->regions[i].size);
@@ -1049,7 +1050,7 @@
 
 	while (!pci_get_dma_regions(pcie->dev, &regions, i)) {
 		dev_dbg(pcie->dev,
-			"dma %d: bus_addr %#lx, axi_addr %#llx, size %#lx\n",
+			"dma %d: bus_addr %#llx, axi_addr %#llx, size %#llx\n",
 			i, regions.bus_start, regions.phys_start, regions.size);
 
 		/* Each range entry corresponds to an inbound mapping region */
diff --git a/include/configs/vexpress_aemv8a.h b/include/configs/vexpress_aemv8.h
similarity index 84%
rename from include/configs/vexpress_aemv8a.h
rename to include/configs/vexpress_aemv8.h
index df22584..3447f02 100644
--- a/include/configs/vexpress_aemv8a.h
+++ b/include/configs/vexpress_aemv8.h
@@ -10,30 +10,36 @@
 #define CONFIG_REMAKE_ELF
 
 /* Link Definitions */
-#ifdef CONFIG_TARGET_VEXPRESS64_BASE_FVP
+#ifdef CONFIG_TARGET_VEXPRESS64_JUNO
+#define CONFIG_SYS_INIT_SP_ADDR         (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
+#else
 /* ATF loads u-boot here for BASE_FVP model */
 #define CONFIG_SYS_INIT_SP_ADDR         (CONFIG_SYS_SDRAM_BASE + 0x03f00000)
-#elif CONFIG_TARGET_VEXPRESS64_JUNO
-#define CONFIG_SYS_INIT_SP_ADDR         (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
 #endif
 
 #define CONFIG_SYS_BOOTM_LEN (64 << 20)      /* Increase max gunzip size */
 
 /* CS register bases for the original memory map. */
-#define V2M_PA_CS0			0x00000000
-#define V2M_PA_CS1			0x14000000
-#define V2M_PA_CS2			0x18000000
-#define V2M_PA_CS3			0x1c000000
-#define V2M_PA_CS4			0x0c000000
-#define V2M_PA_CS5			0x10000000
+#ifdef CONFIG_TARGET_VEXPRESS64_BASER_FVP
+#define V2M_BASE			0x00000000
+#define V2M_PA_BASE			0x80000000
+#else
+#define V2M_BASE			0x80000000
+#define V2M_PA_BASE			0x00000000
+#endif
+
+#define V2M_PA_CS0			(V2M_PA_BASE + 0x00000000)
+#define V2M_PA_CS1			(V2M_PA_BASE + 0x14000000)
+#define V2M_PA_CS2			(V2M_PA_BASE + 0x18000000)
+#define V2M_PA_CS3			(V2M_PA_BASE + 0x1c000000)
+#define V2M_PA_CS4			(V2M_PA_BASE + 0x0c000000)
+#define V2M_PA_CS5			(V2M_PA_BASE + 0x10000000)
 
 #define V2M_PERIPH_OFFSET(x)		(x << 16)
 #define V2M_SYSREGS			(V2M_PA_CS3 + V2M_PERIPH_OFFSET(1))
 #define V2M_SYSCTL			(V2M_PA_CS3 + V2M_PERIPH_OFFSET(2))
 #define V2M_SERIAL_BUS_PCI		(V2M_PA_CS3 + V2M_PERIPH_OFFSET(3))
 
-#define V2M_BASE			0x80000000
-
 /* Common peripherals relative to CS7. */
 #define V2M_AACI			(V2M_PA_CS3 + V2M_PERIPH_OFFSET(4))
 #define V2M_MMCI			(V2M_PA_CS3 + V2M_PERIPH_OFFSET(5))
@@ -68,27 +74,27 @@
 #define V2M_SYS_CFGSTAT			(V2M_SYSREGS + 0x0a8)
 
 /* Generic Timer Definitions */
-#define COUNTER_FREQUENCY		24000000	/* 24MHz */
+#define COUNTER_FREQUENCY		100000000	/* 100MHz */
 
 /* Generic Interrupt Controller Definitions */
 #ifdef CONFIG_GICV3
-#define GICD_BASE			(0x2f000000)
-#define GICR_BASE			(0x2f100000)
+#define GICD_BASE			(V2M_PA_BASE + 0x2f000000)
+#define GICR_BASE			(V2M_PA_BASE + 0x2f100000)
 #else
 
-#ifdef CONFIG_TARGET_VEXPRESS64_BASE_FVP
-#define GICD_BASE			(0x2f000000)
-#define GICC_BASE			(0x2c000000)
-#elif CONFIG_TARGET_VEXPRESS64_JUNO
+#ifdef CONFIG_TARGET_VEXPRESS64_JUNO
 #define GICD_BASE			(0x2C010000)
 #define GICC_BASE			(0x2C02f000)
+#else
+#define GICD_BASE			(V2M_PA_BASE + 0x2f000000)
+#define GICC_BASE			(V2M_PA_BASE + 0x2c000000)
 #endif
 #endif /* !CONFIG_GICV3 */
 
 #ifndef CONFIG_TARGET_VEXPRESS64_JUNO
 /* The Vexpress64 simulators use SMSC91C111 */
 #define CONFIG_SMC91111			1
-#define CONFIG_SMC91111_BASE		(0x01A000000)
+#define CONFIG_SMC91111_BASE		(V2M_PA_BASE + 0x01A000000)
 #endif
 
 /* PL011 Serial Configuration */
@@ -113,7 +119,7 @@
 #ifdef CONFIG_TARGET_VEXPRESS64_JUNO
 #define PHYS_SDRAM_2			(0x880000000)
 #define PHYS_SDRAM_2_SIZE		0x180000000
-#elif CONFIG_TARGET_VEXPRESS64_BASE_FVP && CONFIG_NR_DRAM_BANKS == 2
+#elif CONFIG_NR_DRAM_BANKS == 2
 #define PHYS_SDRAM_2			(0x880000000)
 #define PHYS_SDRAM_2_SIZE		0x80000000
 #endif
@@ -200,6 +206,12 @@
 				"  booti $kernel_addr - $fdt_addr; " \
 				"fi"
 #endif
+
+#elif CONFIG_TARGET_VEXPRESS64_BASER_FVP
+#define CONFIG_EXTRA_ENV_SETTINGS	\
+				"kernel_addr=0x00800000\0"	\
+				"fdt_addr=0x03000000\0"		\
+				"boot_addr=0x0007f800\0"
 #endif
 
 /* Monitor Command Prompt */
@@ -213,7 +225,7 @@
 /* Store environment at top of flash in the same location as blank.img */
 /* in the Juno firmware. */
 #else
-#define CONFIG_SYS_FLASH_BASE		0x0C000000
+#define CONFIG_SYS_FLASH_BASE		(V2M_PA_BASE + 0x0C000000)
 /* 256 x 256KiB sectors */
 #define CONFIG_SYS_MAX_FLASH_SECT	256
 /* Store environment at top of flash */
@@ -230,4 +242,8 @@
 #define CONFIG_SYS_FLASH_EMPTY_INFO	/* flinfo indicates empty blocks */
 #define FLASH_MAX_SECTOR_SIZE		0x00040000
 
+#ifdef CONFIG_TARGET_VEXPRESS64_BASER_FVP
+#define CONFIG_ARMV8_SWITCH_TO_EL1
+#endif
+
 #endif /* __VEXPRESS_AEMV8A_H */
diff --git a/lib/Makefile b/lib/Makefile
index 8ba745f..2d29cda 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -88,6 +88,7 @@
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o
 obj-$(CONFIG_$(SPL_TPL_)HASH_SUPPORT) += crc16.o
+obj-$(CONFIG_MMC_SPI_CRC_ON) += crc16.o
 obj-y += net_utils.o
 endif
 obj-$(CONFIG_ADDR_MAP) += addr_map.o
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 2a61a5d..e39c39e 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -951,21 +951,23 @@
 				DEVNAME(dev), strerror(errno));
 			return -1;
 		}
-		if (rc != readlen) {
-			fprintf(stderr,
-				"Read error on %s: Attempted to read %zd bytes but got %d\n",
-				DEVNAME(dev), readlen, rc);
-			return -1;
-		}
 #ifdef DEBUG
 		fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
 			rc, (unsigned long long)blockstart + block_seek,
 			DEVNAME(dev));
 #endif
-		processed += readlen;
-		readlen = min(blocklen, count - processed);
-		block_seek = 0;
-		blockstart += blocklen;
+		processed += rc;
+		if (rc != readlen) {
+			fprintf(stderr,
+				"Warning on %s: Attempted to read %zd bytes but got %d\n",
+				DEVNAME(dev), readlen, rc);
+			readlen -= rc;
+			block_seek += rc;
+		} else {
+			blockstart += blocklen;
+			readlen = min(blocklen, count - processed);
+			block_seek = 0;
+		}
 	}
 
 	return processed;