Merge tag 'arc-for-2019.10-rc4' of https://gitlab.denx.de/u-boot/custodians/u-boot-arc

These are some very late changes mostly required to get 64-bit
division working on ARC boards.

For that we had to import missing parts of libgcc and add compiler
flags to EMSDP which otherwise used very simple profile for compliation.

And while at it another fix for EM SDP initialization is inluded as well.
diff --git a/arch/arm/include/asm/mach-imx/mxc_i2c.h b/arch/arm/include/asm/mach-imx/mxc_i2c.h
index 8e1ea9a..81fd981 100644
--- a/arch/arm/include/asm/mach-imx/mxc_i2c.h
+++ b/arch/arm/include/asm/mach-imx/mxc_i2c.h
@@ -6,6 +6,9 @@
 #define __ASM_ARCH_MXC_MXC_I2C_H__
 #include <asm-generic/gpio.h>
 #include <asm/mach-imx/iomux-v3.h>
+#if CONFIG_IS_ENABLED(CLK)
+#include <clk.h>
+#endif
 
 struct i2c_pin_ctrl {
 	iomux_v3_cfg_t i2c_mode;
@@ -47,6 +50,9 @@
 	ulong driver_data;
 	int speed;
 	struct i2c_pads_info *pads_info;
+#if CONFIG_IS_ENABLED(CLK)
+	struct clk per_clk;
+#endif
 #ifndef CONFIG_DM_I2C
 	int (*idle_bus_fn)(void *p);
 	void *idle_bus_data;
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index f4b59cb..d411a79 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -6,6 +6,7 @@
 	imply RISCV_TIMER
 	imply ANDES_PLIC if (RISCV_MMODE || SPL_RISCV_MMODE)
 	imply ANDES_PLMT if (RISCV_MMODE || SPL_RISCV_MMODE)
+	imply V5L2_CACHE
 	help
 	  Run U-Boot on AndeStar V5 platforms and use some specific features
 	  which are provided by Andes Technology AndeStar V5 families.
diff --git a/arch/riscv/cpu/ax25/cache.c b/arch/riscv/cpu/ax25/cache.c
index cd95058..41de30c 100644
--- a/arch/riscv/cpu/ax25/cache.c
+++ b/arch/riscv/cpu/ax25/cache.c
@@ -5,17 +5,24 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <cache.h>
+#include <asm/csr.h>
+
+#ifdef CONFIG_RISCV_NDS_CACHE
+/* mcctlcommand */
+#define CCTL_REG_MCCTLCOMMAND_NUM	0x7cc
+
+/* D-cache operation */
+#define CCTL_L1D_WBINVAL_ALL	6
+#endif
 
 void flush_dcache_all(void)
 {
-	/*
-	 * Andes' AX25 does not have a coherence agent. U-Boot must use data
-	 * cache flush and invalidate functions to keep data in the system
-	 * coherent.
-	 * The implementation of the fence instruction in the AX25 flushes the
-	 * data cache and is used for this purpose.
-	 */
-	asm volatile ("fence" ::: "memory");
+#ifdef CONFIG_RISCV_NDS_CACHE
+	csr_write(CCTL_REG_MCCTLCOMMAND_NUM, CCTL_L1D_WBINVAL_ALL);
+#endif
 }
 
 void flush_dcache_range(unsigned long start, unsigned long end)
@@ -59,11 +66,18 @@
 {
 #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
 #ifdef CONFIG_RISCV_NDS_CACHE
+	struct udevice *dev = NULL;
+
 	asm volatile (
 		"csrr t1, mcache_ctl\n\t"
 		"ori t0, t1, 0x2\n\t"
 		"csrw mcache_ctl, t0\n\t"
 	);
+
+	uclass_find_first_device(UCLASS_CACHE, &dev);
+
+	if (dev)
+		cache_enable(dev);
 #endif
 #endif
 }
@@ -72,12 +86,19 @@
 {
 #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
 #ifdef CONFIG_RISCV_NDS_CACHE
+	struct udevice *dev = NULL;
+
+	csr_write(CCTL_REG_MCCTLCOMMAND_NUM, CCTL_L1D_WBINVAL_ALL);
 	asm volatile (
-		"fence\n\t"
 		"csrr t1, mcache_ctl\n\t"
 		"andi t0, t1, ~0x2\n\t"
 		"csrw mcache_ctl, t0\n\t"
 	);
+
+	uclass_find_first_device(UCLASS_CACHE, &dev);
+
+	if (dev)
+		cache_disable(dev);
 #endif
 #endif
 }
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index b15209d..0a2ce6d 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -269,7 +269,7 @@
 /*
  * skip first reserved entry: address, type, addend
  */
-	bne	t1, t2, 7f
+	j	10f
 
 6:
 	LREG	t5, -(REGBYTES*2)(t1)	/* t5 <-- relocation info:type */
@@ -280,9 +280,7 @@
 	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
 	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
 	SREG	t5, 0(t3)
-7:
-	addi	t1, t1, (REGBYTES*3)
-	ble	t1, t2, 6b
+	j	10f
 
 8:
 	la	t4, __dyn_sym_start
@@ -299,13 +297,15 @@
 	li	t5, SYM_SIZE
 	mul	t0, t0, t5
 	add	s5, t4, t0
+	LREG	t0, -(REGBYTES)(t1)	/* t0 <-- addend */
 	LREG	t5, REGBYTES(s5)
+	add	t5, t5, t0
 	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
 	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
 	SREG	t5, 0(t3)
 10:
 	addi	t1, t1, (REGBYTES*3)
-	ble	t1, t2, 9b
+	ble	t1, t2, 6b
 
 /*
  * trap update
diff --git a/arch/riscv/dts/ae350_32.dts b/arch/riscv/dts/ae350_32.dts
index cb6ee13..97b7cee 100644
--- a/arch/riscv/dts/ae350_32.dts
+++ b/arch/riscv/dts/ae350_32.dts
@@ -62,13 +62,18 @@
 				compatible = "riscv,cpu-intc";
 			};
 		};
+	};
 
-		L2: l2-cache@e0500000 {
-			compatible = "cache";
-			cache-level = <2>;
-			cache-size = <0x40000>;
-			reg = <0x0 0xe0500000 0x0 0x40000>;
-		};
+	L2: l2-cache@e0500000 {
+		compatible = "v5l2cache";
+		cache-level = <2>;
+		cache-size = <0x40000>;
+		reg = <0xe0500000 0x40000>;
+		andes,inst-prefetch = <3>;
+		andes,data-prefetch = <3>;
+		/* The value format is <XRAMOCTL XRAMICTL> */
+		andes,tag-ram-ctl = <0 0>;
+		andes,data-ram-ctl = <0 0>;
 	};
 
 	memory@0 {
diff --git a/arch/riscv/dts/ae350_64.dts b/arch/riscv/dts/ae350_64.dts
index 705491a..d8f00f8 100644
--- a/arch/riscv/dts/ae350_64.dts
+++ b/arch/riscv/dts/ae350_64.dts
@@ -62,13 +62,18 @@
 				compatible = "riscv,cpu-intc";
 			};
 		};
+	};
 
-		L2: l2-cache@e0500000 {
-			compatible = "cache";
-			cache-level = <2>;
-			cache-size = <0x40000>;
-			reg = <0x0 0xe0500000 0x0 0x40000>;
-		};
+	L2: l2-cache@e0500000 {
+		compatible = "v5l2cache";
+		cache-level = <2>;
+		cache-size = <0x40000>;
+		reg = <0x0 0xe0500000 0x0 0x40000>;
+		andes,inst-prefetch = <3>;
+		andes,data-prefetch = <3>;
+		/* The value format is <XRAMOCTL XRAMICTL> */
+		andes,tag-ram-ctl = <0 0>;
+		andes,data-ram-ctl = <0 0>;
 	};
 
 	memory@0 {
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
index 2ffe49a..28568e4 100644
--- a/arch/riscv/lib/andes_plic.c
+++ b/arch/riscv/lib/andes_plic.c
@@ -44,15 +44,12 @@
 		}							\
 	} while (0)
 
-static int enable_ipi(int harts)
+static int enable_ipi(int hart)
 {
-	int i;
-	int en = ENABLE_HART_IPI;
+	int en;
 
-	for (i = 0; i < harts; i++) {
-		en = en >> i;
-		writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, i));
-	}
+	en = ENABLE_HART_IPI >> hart;
+	writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, hart));
 
 	return 0;
 }
@@ -60,18 +57,35 @@
 static int init_plic(void)
 {
 	struct udevice *dev;
+	ofnode node;
 	int ret;
+	u32 reg;
 
 	ret = uclass_find_first_device(UCLASS_CPU, &dev);
 	if (ret)
 		return ret;
 
 	if (ret == 0 && dev) {
-		ret = cpu_get_count(dev);
-		if (ret < 0)
-			return ret;
+		ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
+			const char *device_type;
+
+			device_type = ofnode_read_string(node, "device_type");
+			if (!device_type)
+				continue;
+
+			if (strcmp(device_type, "cpu"))
+				continue;
+
+			/* skip if hart is marked as not available */
+			if (!ofnode_is_available(node))
+				continue;
+
+			/* read hart ID of CPU */
+			ret = ofnode_read_u32(node, "reg", &reg);
+			if (ret == 0)
+				enable_ipi(reg);
+		}
 
-		enable_ipi(ret);
 		return 0;
 	}
 
diff --git a/board/AndesTech/ax25-ae350/ax25-ae350.c b/board/AndesTech/ax25-ae350/ax25-ae350.c
index 3d65ce7..b43eebb 100644
--- a/board/AndesTech/ax25-ae350/ax25-ae350.c
+++ b/board/AndesTech/ax25-ae350/ax25-ae350.c
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <faraday/ftsmc020.h>
 #include <fdtdec.h>
+#include <dm.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -93,10 +94,18 @@
 	return 0;
 }
 
+static void v5l2_init(void)
+{
+	struct udevice *dev;
+
+	uclass_get_device(UCLASS_CACHE, 0, &dev);
+}
+
 #ifdef CONFIG_BOARD_EARLY_INIT_F
 int board_early_init_f(void)
 {
 	smc_init();
+	v5l2_init();
 
 	return 0;
 }
diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c
index 11daf1a..47a2090 100644
--- a/board/sifive/fu540/fu540.c
+++ b/board/sifive/fu540/fu540.c
@@ -122,10 +122,20 @@
 
 int misc_init_r(void)
 {
-	/* Set ethaddr environment variable if not set */
-	if (!env_get("ethaddr"))
-		fu540_setup_macaddr(fu540_read_serialnum());
+	u32 serial_num;
+	char buf[9] = {0};
 
+	/* Set ethaddr environment variable from board serial number */
+	if (!env_get("serial#")) {
+		serial_num = fu540_read_serialnum();
+		if (!serial_num) {
+			WARN(true, "Board serial number should not be 0 !!\n");
+			return 0;
+		}
+		snprintf(buf, sizeof(buf), "%08x", serial_num);
+		env_set("serial#", buf);
+		fu540_setup_macaddr(serial_num);
+	}
 	return 0;
 }
 
diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
index 24def7a..629039e 100644
--- a/drivers/cache/Kconfig
+++ b/drivers/cache/Kconfig
@@ -22,4 +22,13 @@
 	  ARMv7(32-bit) devices. The driver configures the cache settings
 	  found in the device tree.
 
+config V5L2_CACHE
+	bool "Andes V5L2 cache driver"
+	select CACHE
+	depends on RISCV_NDS_CACHE
+	help
+	  Support Andes V5L2 cache controller in AE350 platform.
+	  It will configure tag and data ram timing control from the
+	  device tree and enable L2 cache.
+
 endmenu
diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
index 9deb961..4a6458c 100644
--- a/drivers/cache/Makefile
+++ b/drivers/cache/Makefile
@@ -2,3 +2,4 @@
 obj-$(CONFIG_CACHE) += cache-uclass.o
 obj-$(CONFIG_SANDBOX) += sandbox_cache.o
 obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o
+obj-$(CONFIG_V5L2_CACHE) += cache-v5l2.o
diff --git a/drivers/cache/cache-uclass.c b/drivers/cache/cache-uclass.c
index 97ce024..3b20a10 100644
--- a/drivers/cache/cache-uclass.c
+++ b/drivers/cache/cache-uclass.c
@@ -17,6 +17,26 @@
 	return ops->get_info(dev, info);
 }
 
+int cache_enable(struct udevice *dev)
+{
+	struct cache_ops *ops = cache_get_ops(dev);
+
+	if (!ops->enable)
+		return -ENOSYS;
+
+	return ops->enable(dev);
+}
+
+int cache_disable(struct udevice *dev)
+{
+	struct cache_ops *ops = cache_get_ops(dev);
+
+	if (!ops->disable)
+		return -ENOSYS;
+
+	return ops->disable(dev);
+}
+
 UCLASS_DRIVER(cache) = {
 	.id		= UCLASS_CACHE,
 	.name		= "cache",
diff --git a/drivers/cache/cache-v5l2.c b/drivers/cache/cache-v5l2.c
new file mode 100644
index 0000000..d367171
--- /dev/null
+++ b/drivers/cache/cache-v5l2.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <cache.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <dm/ofnode.h>
+
+struct l2cache {
+	volatile u64	configure;
+	volatile u64	control;
+	volatile u64	hpm0;
+	volatile u64	hpm1;
+	volatile u64	hpm2;
+	volatile u64	hpm3;
+	volatile u64	error_status;
+	volatile u64	ecc_error;
+	volatile u64	cctl_command0;
+	volatile u64	cctl_access_line0;
+	volatile u64	cctl_command1;
+	volatile u64	cctl_access_line1;
+	volatile u64	cctl_command2;
+	volatile u64	cctl_access_line2;
+	volatile u64	cctl_command3;
+	volatile u64	cctl_access_line4;
+	volatile u64	cctl_status;
+};
+
+/* Control Register */
+#define L2_ENABLE	0x1
+/* prefetch */
+#define IPREPETCH_OFF	3
+#define DPREPETCH_OFF	5
+#define IPREPETCH_MSK	(3 << IPREPETCH_OFF)
+#define DPREPETCH_MSK	(3 << DPREPETCH_OFF)
+/* tag ram */
+#define TRAMOCTL_OFF	8
+#define TRAMICTL_OFF	10
+#define TRAMOCTL_MSK	(3 << TRAMOCTL_OFF)
+#define TRAMICTL_MSK	BIT(TRAMICTL_OFF)
+/* data ram */
+#define DRAMOCTL_OFF	11
+#define DRAMICTL_OFF	13
+#define DRAMOCTL_MSK	(3 << DRAMOCTL_OFF)
+#define DRAMICTL_MSK	BIT(DRAMICTL_OFF)
+
+/* CCTL Command Register */
+#define CCTL_CMD_REG(base, hart)	((ulong)(base) + 0x40 + (hart) * 0x10)
+#define L2_WBINVAL_ALL	0x12
+
+/* CCTL Status Register */
+#define CCTL_STATUS_MSK(hart)		(0xf << ((hart) * 4))
+#define CCTL_STATUS_IDLE(hart)		(0 << ((hart) * 4))
+#define CCTL_STATUS_PROCESS(hart)	(1 << ((hart) * 4))
+#define CCTL_STATUS_ILLEGAL(hart)	(2 << ((hart) * 4))
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct v5l2_plat {
+	struct l2cache	*regs;
+	u32		iprefetch;
+	u32		dprefetch;
+	u32 		tram_ctl[2];
+	u32 		dram_ctl[2];
+};
+
+static int v5l2_enable(struct udevice *dev)
+{
+	struct v5l2_plat *plat = dev_get_platdata(dev);
+	volatile struct l2cache *regs = plat->regs;
+
+	if (regs)
+		setbits_le32(&regs->control, L2_ENABLE);
+
+	return 0;
+}
+
+static int v5l2_disable(struct udevice *dev)
+{
+	struct v5l2_plat *plat = dev_get_platdata(dev);
+	volatile struct l2cache *regs = plat->regs;
+	u8 hart = gd->arch.boot_hart;
+	void __iomem *cctlcmd = (void __iomem *)CCTL_CMD_REG(regs, hart);
+
+	if ((regs) && (readl(&regs->control) & L2_ENABLE)) {
+		writel(L2_WBINVAL_ALL, cctlcmd);
+
+		while ((readl(&regs->cctl_status) & CCTL_STATUS_MSK(hart))) {
+			if ((readl(&regs->cctl_status) & CCTL_STATUS_ILLEGAL(hart))) {
+				printf("L2 flush illegal! hanging...");
+				hang();
+			}
+		}
+		clrbits_le32(&regs->control, L2_ENABLE);
+	}
+
+	return 0;
+}
+
+static int v5l2_ofdata_to_platdata(struct udevice *dev)
+{
+	struct v5l2_plat *plat = dev_get_platdata(dev);
+	struct l2cache *regs;
+
+	regs = (struct l2cache *)dev_read_addr(dev);
+	plat->regs = regs;
+
+	plat->iprefetch = -EINVAL;
+	plat->dprefetch = -EINVAL;
+	plat->tram_ctl[0] = -EINVAL;
+	plat->dram_ctl[0] = -EINVAL;
+
+	/* Instruction and data fetch prefetch depth */
+	dev_read_u32(dev, "andes,inst-prefetch", &plat->iprefetch);
+	dev_read_u32(dev, "andes,data-prefetch", &plat->dprefetch);
+
+	/* Set tag RAM and data RAM setup and output cycle */
+	dev_read_u32_array(dev, "andes,tag-ram-ctl", plat->tram_ctl, 2);
+	dev_read_u32_array(dev, "andes,data-ram-ctl", plat->dram_ctl, 2);
+
+	return 0;
+}
+
+static int v5l2_probe(struct udevice *dev)
+{
+	struct v5l2_plat *plat = dev_get_platdata(dev);
+	struct l2cache *regs = plat->regs;
+	u32 ctl_val;
+
+	ctl_val = readl(&regs->control);
+
+	if (!(ctl_val & L2_ENABLE))
+		ctl_val |= L2_ENABLE;
+
+	if (plat->iprefetch != -EINVAL) {
+		ctl_val &= ~(IPREPETCH_MSK);
+		ctl_val |= (plat->iprefetch << IPREPETCH_OFF);
+	}
+
+	if (plat->dprefetch != -EINVAL) {
+		ctl_val &= ~(DPREPETCH_MSK);
+		ctl_val |= (plat->dprefetch << DPREPETCH_OFF);
+	}
+
+	if (plat->tram_ctl[0] != -EINVAL) {
+		ctl_val &= ~(TRAMOCTL_MSK | TRAMICTL_MSK);
+		ctl_val |= plat->tram_ctl[0] << TRAMOCTL_OFF;
+		ctl_val |= plat->tram_ctl[1] << TRAMICTL_OFF;
+	}
+
+	if (plat->dram_ctl[0] != -EINVAL) {
+		ctl_val &= ~(DRAMOCTL_MSK | DRAMICTL_MSK);
+		ctl_val |= plat->dram_ctl[0] << DRAMOCTL_OFF;
+		ctl_val |= plat->dram_ctl[1] << DRAMICTL_OFF;
+	}
+
+	writel(ctl_val, &regs->control);
+
+	return 0;
+}
+
+static const struct udevice_id v5l2_cache_ids[] = {
+	{ .compatible = "v5l2cache" },
+	{}
+};
+
+static const struct cache_ops v5l2_cache_ops = {
+	.enable		= v5l2_enable,
+	.disable	= v5l2_disable,
+};
+
+U_BOOT_DRIVER(v5l2_cache) = {
+	.name   = "v5l2_cache",
+	.id     = UCLASS_CACHE,
+	.of_match = v5l2_cache_ids,
+	.ofdata_to_platdata = v5l2_ofdata_to_platdata,
+	.probe	= v5l2_probe,
+	.platdata_auto_alloc_size = sizeof(struct v5l2_plat),
+	.ops = &v5l2_cache_ops,
+	.flags  = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/cache/sandbox_cache.c b/drivers/cache/sandbox_cache.c
index 14cc6b0..9050c4c 100644
--- a/drivers/cache/sandbox_cache.c
+++ b/drivers/cache/sandbox_cache.c
@@ -17,8 +17,21 @@
 	return 0;
 }
 
+static int sandbox_enable(struct udevice *dev)
+{
+	return 0;
+}
+
+static int snadbox_disable(struct udevice *dev)
+{
+	return 0;
+}
+
+
 static const struct cache_ops sandbox_cache_ops = {
 	.get_info	= sandbox_get_info,
+	.enable 	= sandbox_enable,
+	.disable	= snadbox_disable,
 };
 
 static const struct udevice_id sandbox_cache_ids[] = {
diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c
index f77c126..28ad0aa 100644
--- a/drivers/cpu/riscv_cpu.c
+++ b/drivers/cpu/riscv_cpu.c
@@ -46,6 +46,10 @@
 	ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
 		const char *device_type;
 
+		/* skip if hart is marked as not available in the device tree */
+		if (!ofnode_is_available(node))
+			continue;
+
 		device_type = ofnode_read_string(node, "device_type");
 		if (!device_type)
 			continue;
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index 20f6dc4..786b5a2 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -149,7 +149,12 @@
 #endif
 
 	/* Divider value calculation */
+#if CONFIG_IS_ENABLED(CLK)
+	i2c_clk_rate = clk_get_rate(&i2c_bus->per_clk);
+#else
 	i2c_clk_rate = mxc_get_clock(MXC_I2C_CLK);
+#endif
+
 	div = (i2c_clk_rate + rate - 1) / rate;
 	if (div < i2c_clk_div[0][0])
 		clk_div = 0;
@@ -891,9 +896,22 @@
 	i2c_bus->bus = bus;
 
 	/* Enable clk */
+#if CONFIG_IS_ENABLED(CLK)
+	ret = clk_get_by_index(bus, 0, &i2c_bus->per_clk);
+	if (ret) {
+		printf("Failed to get i2c clk\n");
+		return ret;
+	}
+	ret = clk_enable(&i2c_bus->per_clk);
+	if (ret) {
+		printf("Failed to enable i2c clk\n");
+		return ret;
+	}
+#else
 	ret = enable_i2c_clk(1, bus->seq);
 	if (ret < 0)
 		return ret;
+#endif
 
 	/*
 	 * See Documentation/devicetree/bindings/i2c/i2c-imx.txt
diff --git a/include/cache.h b/include/cache.h
index c6334ca..32f59fd 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -22,6 +22,22 @@
 	 * @return 0 if OK, -ve on error
 	 */
 	int (*get_info)(struct udevice *dev, struct cache_info *info);
+
+	/**
+	 * enable() - Enable cache
+	 *
+	 * @dev:	Device to check (UCLASS_CACHE)
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*enable)(struct udevice *dev);
+
+	/**
+	 * disable() - Flush and disable cache
+	 *
+	 * @dev:	Device to check (UCLASS_CACHE)
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*disable)(struct udevice *dev);
 };
 
 #define cache_get_ops(dev)	((struct cache_ops *)(dev)->driver->ops)
@@ -35,4 +51,19 @@
  */
 int cache_get_info(struct udevice *dev, struct cache_info *info);
 
+/**
+ * cache_enable() - Enable cache
+ *
+ * @dev:	Device to check (UCLASS_CACHE)
+ * @return 0 if OK, -ve on error
+ */
+int cache_enable(struct udevice *dev);
+
+/**
+ * cache_disable() - Flush and disable cache
+ *
+ * @dev:	Device to check (UCLASS_CACHE)
+ * @return 0 if OK, -ve on error
+ */
+int cache_disable(struct udevice *dev);
 #endif
diff --git a/include/configs/sifive-fu540.h b/include/configs/sifive-fu540.h
index 858b7a7..736ceb1 100644
--- a/include/configs/sifive-fu540.h
+++ b/include/configs/sifive-fu540.h
@@ -26,6 +26,7 @@
 #define CONFIG_ENV_SIZE			SZ_128K
 
 #define BOOT_TARGET_DEVICES(func) \
+	func(MMC, mmc, 0) \
 	func(DHCP, dhcp, na)
 
 #include <config_distro_bootcmd.h>
diff --git a/test/dm/cache.c b/test/dm/cache.c
index d4144aa..2e244b1 100644
--- a/test/dm/cache.c
+++ b/test/dm/cache.c
@@ -14,6 +14,8 @@
 
 	ut_assertok(uclass_get_device(UCLASS_CACHE, 0, &dev_cache));
 	ut_assertok(cache_get_info(dev, &info));
+	ut_assertok(cache_enable(dev));
+	ut_assertok(cache_disable(dev));
 
 	return 0;
 }
diff --git a/tools/prelink-riscv.inc b/tools/prelink-riscv.inc
index 8b40ec4..f2b5467 100644
--- a/tools/prelink-riscv.inc
+++ b/tools/prelink-riscv.inc
@@ -27,6 +27,8 @@
 #define target32_to_cpu CONCAT(PRELINK_BYTEORDER, 32_to_cpu)
 #define target64_to_cpu CONCAT(PRELINK_BYTEORDER, 64_to_cpu)
 #define targetnn_to_cpu CONCAT3(PRELINK_BYTEORDER, PRELINK_INC_BITS, _to_cpu)
+#define cpu_to_target32 CONCAT3(cpu_to_, PRELINK_BYTEORDER, 32)
+#define cpu_to_target64 CONCAT3(cpu_to_, PRELINK_BYTEORDER, 64)
 
 static void* get_offset_bonn (void* data, Elf_Phdr* phdrs, size_t phnum, Elf_Addr addr)
 {
@@ -92,9 +94,9 @@
 		if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_RELATIVE)
 			*((uintnn_t*) buf) = r->r_addend;
 		else if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_32)
-			*((uint32_t*) buf) = dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value;
+			*((uint32_t*) buf) = cpu_to_target32(targetnn_to_cpu(dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value) + targetnn_to_cpu(r->r_addend));
 		else if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_64)
-			*((uint64_t*) buf) = dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value;
+			*((uint64_t*) buf) = cpu_to_target64(targetnn_to_cpu(dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value) + targetnn_to_cpu(r->r_addend));
 	}
 }
 
@@ -113,6 +115,8 @@
 #undef target32_to_cpu
 #undef target64_to_cpu
 #undef targetnn_to_cpu
+#undef cpu_to_target32
+#undef cpu_to_target64
 
 #undef CONCAT_IMPL
 #undef CONCAT