Merge https://source.denx.de/u-boot/custodians/u-boot-riscv
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index 85592f5..296e458 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -140,3 +140,14 @@
 {
 	return riscv_cpu_probe();
 }
+
+/**
+ * harts_early_init() - A callback function called by start.S to configure
+ * feature settings of each hart.
+ *
+ * In a multi-core system, memory access shall be careful here, it shall
+ * take care of race conditions.
+ */
+__weak void harts_early_init(void)
+{
+}
diff --git a/arch/riscv/cpu/fu540/spl.c b/arch/riscv/cpu/fu540/spl.c
index 45657b7..1740ef9 100644
--- a/arch/riscv/cpu/fu540/spl.c
+++ b/arch/riscv/cpu/fu540/spl.c
@@ -6,6 +6,9 @@
 
 #include <dm.h>
 #include <log.h>
+#include <asm/csr.h>
+
+#define CSR_U74_FEATURE_DISABLE	0x7c1
 
 int spl_soc_init(void)
 {
@@ -21,3 +24,15 @@
 
 	return 0;
 }
+
+void harts_early_init(void)
+{
+	/*
+	 * Feature Disable CSR
+	 *
+	 * Clear feature disable CSR to '0' to turn on all features for
+	 * each core. This operation must be in M-mode.
+	 */
+	if (CONFIG_IS_ENABLED(RISCV_MMODE))
+		csr_write(CSR_U74_FEATURE_DISABLE, 0);
+}
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 8589509..308b0a9 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -117,6 +117,10 @@
 	mv	sp, a0
 #endif
 
+	/* Configure proprietary settings and customized CSRs of harts */
+call_harts_early_init:
+	jal	harts_early_init
+
 #ifndef CONFIG_XIP
 	/*
 	 * Pick hart to initialize global data and run U-Boot. The other harts
diff --git a/cmd/riscv/exception.c b/cmd/riscv/exception.c
index 9687cec..7a08061 100644
--- a/cmd/riscv/exception.c
+++ b/cmd/riscv/exception.c
@@ -8,6 +8,13 @@
 #include <common.h>
 #include <command.h>
 
+static int do_ebreak(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	asm volatile ("ebreak\n");
+	return CMD_RET_FAILURE;
+}
+
 static int do_unaligned(struct cmd_tbl *cmdtp, int flag, int argc,
 			char *const argv[])
 {
@@ -28,6 +35,8 @@
 }
 
 static struct cmd_tbl cmd_sub[] = {
+	U_BOOT_CMD_MKENT(ebreak, CONFIG_SYS_MAXARGS, 1, do_ebreak,
+			 "", ""),
 	U_BOOT_CMD_MKENT(unaligned, CONFIG_SYS_MAXARGS, 1, do_unaligned,
 			 "", ""),
 	U_BOOT_CMD_MKENT(undefined, CONFIG_SYS_MAXARGS, 1, do_undefined,
@@ -37,6 +46,7 @@
 static char exception_help_text[] =
 	"<ex>\n"
 	"  The following exceptions are available:\n"
+	"  ebreak    - breakpoint\n"
 	"  undefined - illegal instruction\n"
 	"  unaligned - load address misaligned\n"
 	;
diff --git a/doc/usage/exception.rst b/doc/usage/exception.rst
index db1490f..27df88b 100644
--- a/doc/usage/exception.rst
+++ b/doc/usage/exception.rst
@@ -31,6 +31,9 @@
 
   **RISC-V:**
 
+  ebreak
+    breakpoint exception
+
   unaligned
     load address misaligned
 
diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c
index 634cd56..775b9ff 100644
--- a/drivers/spi/atcspi200_spi.c
+++ b/drivers/spi/atcspi200_spi.c
@@ -201,7 +201,7 @@
 		size_t cmd_len = ns->cmd_len;
 		unsigned long data_len = bitlen / 8;
 		int rf_cnt;
-		int ret = 0;
+		int ret = 0, timeout = 0;
 
 		max_tran_len = ns->max_transfer_length;
 		switch (flags) {
@@ -243,11 +243,12 @@
 			ns->tran_len = tran_len;
 			num_blks = DIV_ROUND_UP(tran_len , CHUNK_SIZE);
 			num_bytes = (tran_len) % CHUNK_SIZE;
+			timeout = SPI_TIMEOUT;
 			if(num_bytes == 0)
 				num_bytes = CHUNK_SIZE;
 			__atcspi200_spi_start(ns);
 
-			while (num_blks) {
+			while (num_blks && (timeout--)) {
 				event = in_le32(&ns->regs->status);
 				if ((event & TXEPTY) && (data_out)) {
 					__nspi_espi_tx(ns, dout);
@@ -269,6 +270,11 @@
 						din = (unsigned char *)din + rx_bytes;
 					}
 				}
+
+				if (!timeout) {
+					debug("spi_xfer: %s() timeout\n", __func__);
+					break;
+				}
 			}
 
 			data_len -= tran_len;