Merge https://source.denx.de/u-boot/custodians/u-boot-riscv

CI: https://source.denx.de/u-boot/custodians/u-boot-riscv/-/pipelines/20596

- RISC-V: cmd: Add SBI implementation ID and extension ID
- Board: Rename spl_soc_init to spl_dram_init
- Board: milkv_duo: Add SPI NOR flash, Ethernet, Sysreset support
diff --git a/arch/riscv/cpu/andesv5/Kconfig b/arch/riscv/cpu/andesv5/Kconfig
index f311291..e3efb0d 100644
--- a/arch/riscv/cpu/andesv5/Kconfig
+++ b/arch/riscv/cpu/andesv5/Kconfig
@@ -1,6 +1,7 @@
 config RISCV_NDS
 	bool
 	select ARCH_EARLY_INIT_R
+	select SYS_CACHE_SHIFT_6
 	imply CPU
 	imply CPU_RISCV
 	imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
diff --git a/arch/riscv/cpu/fu540/spl.c b/arch/riscv/cpu/fu540/spl.c
index 45657b7..cedb70b 100644
--- a/arch/riscv/cpu/fu540/spl.c
+++ b/arch/riscv/cpu/fu540/spl.c
@@ -7,7 +7,7 @@
 #include <dm.h>
 #include <log.h>
 
-int spl_soc_init(void)
+int spl_dram_init(void)
 {
 	int ret;
 	struct udevice *dev;
diff --git a/arch/riscv/cpu/fu740/spl.c b/arch/riscv/cpu/fu740/spl.c
index c6816e9..16b307f 100644
--- a/arch/riscv/cpu/fu740/spl.c
+++ b/arch/riscv/cpu/fu740/spl.c
@@ -10,7 +10,7 @@
 
 #define CSR_U74_FEATURE_DISABLE	0x7c1
 
-int spl_soc_init(void)
+int spl_dram_init(void)
 {
 	int ret;
 	struct udevice *dev;
diff --git a/arch/riscv/cpu/jh7110/spl.c b/arch/riscv/cpu/jh7110/spl.c
index 6bdf8b9..87aaf86 100644
--- a/arch/riscv/cpu/jh7110/spl.c
+++ b/arch/riscv/cpu/jh7110/spl.c
@@ -28,7 +28,7 @@
 	}
 }
 
-int spl_soc_init(void)
+int spl_dram_init(void)
 {
 	int ret;
 	struct udevice *dev;
diff --git a/arch/riscv/dts/cv1800b-milkv-duo.dts b/arch/riscv/dts/cv1800b-milkv-duo.dts
index 94e64dd..e7cc0e8 100644
--- a/arch/riscv/dts/cv1800b-milkv-duo.dts
+++ b/arch/riscv/dts/cv1800b-milkv-duo.dts
@@ -29,6 +29,11 @@
 	};
 };
 
+&ethernet0 {
+	status = "okay";
+	phy-mode = "rmii";
+};
+
 &osc {
 	clock-frequency = <25000000>;
 };
@@ -41,6 +46,19 @@
 	no-sdio;
 };
 
+&spif {
+	status = "okay";
+
+	spiflash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <75000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+		m25p,fast-read;
+	};
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/riscv/dts/cv18xx.dtsi b/arch/riscv/dts/cv18xx.dtsi
index ec99c4d..4b01434 100644
--- a/arch/riscv/dts/cv18xx.dtsi
+++ b/arch/riscv/dts/cv18xx.dtsi
@@ -52,6 +52,27 @@
 		#clock-cells = <0>;
 	};
 
+	eth_csrclk: eth-csrclk {
+		compatible = "fixed-clock";
+		clock-frequency = <250000000>;
+		clock-output-names = "eth_csrclk";
+		#clock-cells = <0x0>;
+	};
+
+	eth_ptpclk: eth-ptpclk {
+		compatible = "fixed-clock";
+		clock-frequency = <50000000>;
+		clock-output-names = "eth_ptpclk";
+		#clock-cells = <0x0>;
+	};
+
+	spif_clk: spi-flash-clock {
+		compatible = "fixed-clock";
+		clock-frequency = <300000000>;
+		clock-output-names = "spif_clk";
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		interrupt-parent = <&plic>;
@@ -138,6 +159,15 @@
 			};
 		};
 
+		ethernet0: ethernet@4070000 {
+			compatible = "sophgo,cv1800b-dwmac";
+			reg = <0x04070000 0x10000>;
+			interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&eth_csrclk>, <&eth_ptpclk>;
+			clock-names = "stmmaceth", "ptp_ref";
+			status = "disabled";
+		};
+
 		uart0: serial@4140000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x04140000 0x100>;
@@ -197,6 +227,16 @@
 			status = "disabled";
 		};
 
+		spif: spi-nor@10000000 {
+			compatible = "sophgo,cv1800b-spif";
+			reg = <0x10000000 0x10000000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&spif_clk>;
+			interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
 		plic: interrupt-controller@70000000 {
 			reg = <0x70000000 0x4000000>;
 			interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>;
diff --git a/arch/riscv/include/asm/arch-fu540/spl.h b/arch/riscv/include/asm/arch-fu540/spl.h
index 4697279..519e7eb 100644
--- a/arch/riscv/include/asm/arch-fu540/spl.h
+++ b/arch/riscv/include/asm/arch-fu540/spl.h
@@ -9,6 +9,6 @@
 #ifndef _SPL_SIFIVE_H
 #define _SPL_SIFIVE_H
 
-int spl_soc_init(void);
+int spl_dram_init(void);
 
 #endif /* _SPL_SIFIVE_H */
diff --git a/arch/riscv/include/asm/arch-fu740/spl.h b/arch/riscv/include/asm/arch-fu740/spl.h
index 15ad9e7..b327ac5 100644
--- a/arch/riscv/include/asm/arch-fu740/spl.h
+++ b/arch/riscv/include/asm/arch-fu740/spl.h
@@ -9,6 +9,6 @@
 #ifndef _SPL_SIFIVE_H
 #define _SPL_SIFIVE_H
 
-int spl_soc_init(void);
+int spl_dram_init(void);
 
 #endif /* _SPL_SIFIVE_H */
diff --git a/arch/riscv/include/asm/arch-jh7110/spl.h b/arch/riscv/include/asm/arch-jh7110/spl.h
index 23ce887..d73355b 100644
--- a/arch/riscv/include/asm/arch-jh7110/spl.h
+++ b/arch/riscv/include/asm/arch-jh7110/spl.h
@@ -7,6 +7,6 @@
 #ifndef _SPL_STARFIVE_H
 #define _SPL_STARFIVE_H
 
-int spl_soc_init(void);
+int spl_dram_init(void);
 
 #endif /* _SPL_STARFIVE_H */
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index d1113f3..ad32ded 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -34,6 +34,7 @@
 	SBI_EXT_NACL = 0x4E41434C,
 	SBI_EXT_STA = 0x535441,
 	SBI_EXT_DBTR = 0x44425452,
+	SBI_EXT_SSE = 0x535345,
 };
 
 enum sbi_ext_base_fid {
diff --git a/board/sifive/unleashed/spl.c b/board/sifive/unleashed/spl.c
index fe27316..9df9c68 100644
--- a/board/sifive/unleashed/spl.c
+++ b/board/sifive/unleashed/spl.c
@@ -27,9 +27,9 @@
 {
 	int ret;
 
-	ret = spl_soc_init();
+	ret = spl_dram_init();
 	if (ret) {
-		debug("FU540 SPL init failed: %d\n", ret);
+		debug("FU540 DRAM init failed: %d\n", ret);
 		return ret;
 	}
 
diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c
index e69bed9..6fc1d80 100644
--- a/board/sifive/unmatched/spl.c
+++ b/board/sifive/unmatched/spl.c
@@ -134,9 +134,9 @@
 {
 	int ret;
 
-	ret = spl_soc_init();
+	ret = spl_dram_init();
 	if (ret) {
-		debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret);
+		debug("HiFive Unmatched FU740 DRAM init failed: %d\n", ret);
 		goto end;
 	}
 
diff --git a/board/sophgo/milkv_duo/Makefile b/board/sophgo/milkv_duo/Makefile
index a087013..d0525eb 100644
--- a/board/sophgo/milkv_duo/Makefile
+++ b/board/sophgo/milkv_duo/Makefile
@@ -2,4 +2,5 @@
 #
 # Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
 
-obj-y := board.o
+obj-y += board.o
+obj-$(CONFIG_NET) += ethernet.o
diff --git a/board/sophgo/milkv_duo/board.c b/board/sophgo/milkv_duo/board.c
index eaa47be..9adbb08 100644
--- a/board/sophgo/milkv_duo/board.c
+++ b/board/sophgo/milkv_duo/board.c
@@ -3,7 +3,17 @@
  * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
  */
 
+#include <dm/lists.h>
+
+#include "ethernet.h"
+
 int board_init(void)
 {
+	if (IS_ENABLED(CONFIG_SYSRESET_CV1800B))
+		device_bind_driver(gd->dm_root, "cv1800b_sysreset", "sysreset", NULL);
+
+	if (IS_ENABLED(CONFIG_NET))
+		cv1800b_ephy_init();
+
 	return 0;
 }
diff --git a/board/sophgo/milkv_duo/ethernet.c b/board/sophgo/milkv_duo/ethernet.c
new file mode 100644
index 0000000..e997ce1
--- /dev/null
+++ b/board/sophgo/milkv_duo/ethernet.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/mii.h>
+
+#define REG_EPHY_TOP_WRAP (u32 *)0x03009800
+#define REG_EPHY_BASE     (u32 *)0x03009000
+
+#define REG_EPHY_CTL         REG_EPHY_TOP_WRAP
+#define REG_EPHY_APB_RW_SEL  REG_EPHY_TOP_WRAP + 1
+
+/* Page 0 register */
+#define REG_PHY_ID1          REG_EPHY_BASE + MII_PHYSID1
+#define REG_PHY_ID2          REG_EPHY_BASE + MII_PHYSID2
+#define REG_PHY_PAGE_SEL     REG_EPHY_BASE + 0x1f
+
+/* Page 5 register */
+#define REG_PD_EN_CTL        REG_EPHY_BASE + 0x10
+
+/* REG_EPHY_CTL */
+#define REG_EPHY_SHUTDOWN    BIT(0)
+#define REG_EPHY_ANA_RST_N   BIT(1)
+#define REG_EPHY_DIG_RST_N   BIT(2)
+#define REG_EPHY_MAIN_RST_N  BIT(3)
+
+/* REG_PD_EN_CTL */
+#define REG_EN_ETH_TXRT          BIT(0)
+#define REG_EN_ETH_CLK100M       BIT(1)
+#define REG_EN_ETH_CLK125M       BIT(2)
+#define REG_EN_ETH_PLL_LCKDET    BIT(3)
+#define REG_EN_ETH_RXADC         BIT(4)
+#define REG_EN_ETH_RXPGA         BIT(5)
+#define REG_EN_ETH_RXRT          BIT(6)
+#define REG_EN_ETH_TXCROSSOVER   BIT(7)
+#define REG_PD_ETH_PLL           BIT(8)
+#define REG_PD_ETH_TXDAC         BIT(9)
+#define REG_PD_ETH_TXDACBST      BIT(10)
+#define REG_PD_ETH_TXECHO        BIT(11)
+#define REG_PD_ETH_TXDRV_NMOS    BIT(12)
+#define REG_PD_ETH_TXLDO         BIT(13)
+
+void cv1800b_ephy_init(void)
+{
+	u32 reg;
+	u32 phy_id = 1;
+
+	/* enable direct memory access for phy register */
+	writel(1, REG_EPHY_APB_RW_SEL);
+
+	reg = readl(REG_EPHY_CTL);
+	reg &= ~REG_EPHY_SHUTDOWN;
+	reg |= REG_EPHY_ANA_RST_N | REG_EPHY_DIG_RST_N | REG_EPHY_MAIN_RST_N;
+	writel(reg, REG_EPHY_CTL);
+
+	/* switch to page 5 */
+	writel(5 << 8, REG_PHY_PAGE_SEL);
+	reg = readl(REG_PD_EN_CTL);
+	reg &= ~(REG_PD_ETH_TXLDO | REG_PD_ETH_TXDRV_NMOS | REG_PD_ETH_TXDAC | REG_PD_ETH_PLL);
+	reg |= REG_EN_ETH_TXRT | REG_EN_ETH_CLK100M | REG_EN_ETH_CLK125M
+		| REG_EN_ETH_PLL_LCKDET | REG_EN_ETH_RXADC | REG_EN_ETH_RXPGA | REG_EN_ETH_RXRT;
+	writel(reg, REG_PD_EN_CTL);
+
+	/* switch to page 0 */
+	writel(0 << 8, REG_PHY_PAGE_SEL);
+	/*
+	 * As the phy_id in the cv1800b PHY register is initialized to 0, it
+	 * is necessary to manually initialize the phy_id to an arbitrary
+	 * value so that it could corresponds to the generic PHY driver.
+	 */
+	writel(phy_id >> 16, REG_PHY_ID1);
+	writel(phy_id & 0xffff, REG_PHY_ID2);
+
+	/* switch to MDIO control */
+	writel(0, REG_EPHY_APB_RW_SEL);
+}
diff --git a/board/sophgo/milkv_duo/ethernet.h b/board/sophgo/milkv_duo/ethernet.h
new file mode 100644
index 0000000..7b21f1b
--- /dev/null
+++ b/board/sophgo/milkv_duo/ethernet.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#ifndef __CV1800B_ETHERNET_H
+#define __CV1800B_ETHERNET_H
+
+void cv1800b_ephy_init(void);
+
+#endif
diff --git a/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c
index 45848db..ca61b5b 100644
--- a/board/starfive/visionfive2/spl.c
+++ b/board/starfive/visionfive2/spl.c
@@ -285,9 +285,9 @@
 
 	jh7110_jtag_init();
 
-	ret = spl_soc_init();
+	ret = spl_dram_init();
 	if (ret) {
-		debug("JH7110 SPL init failed: %d\n", ret);
+		debug("JH7110 DRAM init failed: %d\n", ret);
 		return ret;
 	}
 
diff --git a/cmd/riscv/sbi.c b/cmd/riscv/sbi.c
index bd9d9c4..2d8ee7e 100644
--- a/cmd/riscv/sbi.c
+++ b/cmd/riscv/sbi.c
@@ -29,6 +29,8 @@
 	{ 6, "Coffer" },
 	{ 7, "Xen Project" },
 	{ 8, "PolarFire Hart Software Services" },
+	{ 9, "coreboot" },
+	{ 10, "oreboot" },
 };
 
 static struct sbi_ext extensions[] = {
@@ -54,6 +56,7 @@
 	{ SBI_EXT_NACL,			      "Nested Acceleration Extension" },
 	{ SBI_EXT_STA,			      "Steal-time Accounting Extension" },
 	{ SBI_EXT_DBTR,			      "Debug Trigger Extension" },
+	{ SBI_EXT_SSE,			      "Supervisor Software Events" },
 };
 
 static int do_sbi(struct cmd_tbl *cmdtp, int flag, int argc,
diff --git a/configs/milkv_duo_defconfig b/configs/milkv_duo_defconfig
index e8413d7..0cb2922 100644
--- a/configs/milkv_duo_defconfig
+++ b/configs/milkv_duo_defconfig
@@ -19,14 +19,24 @@
 CONFIG_SYS_PROMPT="milkv_duo# "
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PART=y
+CONFIG_CMD_POWEROFF=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PXE=y
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_ENV_OVERWRITE=y
+CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_MMC=y
 CONFIG_MMC_IO_VOLTAGE=y
 CONFIG_MMC_UHS_SUPPORT=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_ADMA=y
 CONFIG_MMC_SDHCI_CV1800B=y
+CONFIG_ETH_DESIGNWARE=y
 CONFIG_SYS_NS16550=y
 CONFIG_SYS_NS16550_MEM32=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_CV1800B=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI=y
+CONFIG_CV1800B_SPIF=y
diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c
index 9af6b97..4e75051 100644
--- a/drivers/mmc/cv1800b_sdhci.c
+++ b/drivers/mmc/cv1800b_sdhci.c
@@ -12,6 +12,8 @@
 #define MMC_MAX_CLOCK        375000000
 #define TUNE_MAX_PHCODE      128
 
+#define PHY_TX_SRC_INVERT  BIT(8)
+
 struct cv1800b_sdhci_plat {
 	struct mmc_config cfg;
 	struct mmc mmc;
@@ -19,7 +21,7 @@
 
 static void cv1800b_set_tap_delay(struct sdhci_host *host, u16 tap)
 {
-	sdhci_writel(host, tap << 16, SDHCI_PHY_TX_RX_DLY);
+	sdhci_writel(host, PHY_TX_SRC_INVERT | tap << 16, SDHCI_PHY_TX_RX_DLY);
 }
 
 static void cv1800b_sdhci_reset(struct sdhci_host *host, u8 mask)
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 4c1642b..682045c 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -871,6 +871,7 @@
 	{ .compatible = "amlogic,meson6-dwmac" },
 	{ .compatible = "st,stm32-dwmac" },
 	{ .compatible = "snps,arc-dwmac-3.70a" },
+	{ .compatible = "sophgo,cv1800b-dwmac" },
 	{ }
 };
 
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 6124346..35030ab 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -168,6 +168,14 @@
           Enable the ColdFire SPI driver. This driver can be used on
           some m68k SoCs.
 
+config CV1800B_SPIF
+	bool "Sophgo cv1800b SPI Flash Controller driver"
+	depends on SPI_MEM
+	help
+	  Enable the Sophgo cv1800b SPI Flash Controller driver. This driver
+	  can be used to access the SPI NOR flash on platforms embedding this
+	  Sophgo cv1800b IP core.
+
 config DAVINCI_SPI
 	bool "Davinci & Keystone SPI driver"
 	depends on ARCH_DAVINCI || ARCH_KEYSTONE
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 14bdb97..32d7bf7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -30,6 +30,7 @@
 obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o
 obj-$(CONFIG_CF_SPI) += cf_spi.o
 obj-$(CONFIG_CORTINA_SFLASH) += ca_sflash.o
+obj-$(CONFIG_CV1800B_SPIF) += cv1800b_spif.o
 obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
 obj-$(CONFIG_DESIGNWARE_SPI) += designware_spi.o
 obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
diff --git a/drivers/spi/cv1800b_spif.c b/drivers/spi/cv1800b_spif.c
new file mode 100644
index 0000000..9c077f3
--- /dev/null
+++ b/drivers/spi/cv1800b_spif.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <spi-mem.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <wait_bit.h>
+
+#define CV1800B_SPI_CTRL_SCK_DIV_MASK                GENMASK(10, 0)
+#define CV1800B_SPI_CTRL_CPHA                        BIT(12)
+#define CV1800B_SPI_CTRL_CPOL                        BIT(13)
+
+#define CV1800B_SPI_CE_MANUAL                        BIT(0)
+#define CV1800B_SPI_CE_MANUAL_EN                     BIT(1)
+#define CV1800B_SPI_CE_ENABLE                        (CV1800B_SPI_CE_MANUAL | \
+						      CV1800B_SPI_CE_MANUAL_EN)
+#define CV1800B_SPI_CE_DISABLE                       CV1800B_SPI_CE_MANUAL_EN
+#define CV1800B_SPI_CE_HARDWARE                      0
+
+#define CV1800B_SPI_DLY_CTRL_NEG_SAMPLE              BIT(14)
+
+#define CV1800B_SPI_TRAN_MODE_RX                     BIT(0)
+#define CV1800B_SPI_TRAN_MODE_TX                     BIT(1)
+#define CV1800B_SPI_TRAN_FAST_MODE                   BIT(3)
+#define CV1800B_SPI_TRAN_BUS_WIDTH_1_BIT             0x0
+#define CV1800B_SPI_TRAN_BUS_WIDTH_2_BIT             BIT(4)
+#define CV1800B_SPI_TRAN_BUS_WIDTH_4_BIT             BIT(5)
+#define CV1800B_SPI_TRAN_ADDR_3_BYTES                (3 << 8)
+#define CV1800B_SPI_TRAN_ADDR_4_BYTES                (4 << 8)
+#define CV1800B_SPI_TRAN_WITH_CMD                    BIT(11)
+#define CV1800B_SPI_TRAN_GO_BUSY                     BIT(15)
+#define CV1800B_SPI_TRAN_DUMMY_CYC_MASK              GENMASK(19, 16)
+#define CV1800B_SPI_TRAN_DUMMY_CYC_OFFSET            16
+#define CV1800B_SPI_TRAN_BYTE4_EN                    BIT(20)
+#define CV1800B_SPI_TRAN_BYTE4_CMD                   BIT(21)
+
+#define CV1800B_SPI_FF_PT_AVAILABLE_MASK             GENMASK(3, 0)
+
+#define CV1800B_SPI_INT_TRAN_DONE                    BIT(0)
+#define CV1800B_SPI_INT_RD_FIFO                      BIT(2)
+#define CV1800B_SPI_INT_WR_FIFO                      BIT(3)
+
+#define CV1800B_FIFO_CAPACITY           8
+#define CV1800B_DEFAULT_DIV             4
+
+struct cv1800b_spif_regs {
+	u32 spi_ctrl;
+	u32 ce_ctrl;
+	u32 dly_ctrl;
+	u32 dmmr_ctrl;
+	u32 tran_csr;
+	u32 tran_num;
+	u32 ff_port;
+	u32 reserved0;
+	u32 ff_pt;
+	u32 reserved1;
+	u32 int_sts;
+	u32 int_en;
+};
+
+struct cv1800b_spi_priv {
+	struct cv1800b_spif_regs *regs;
+	uint clk_freq;
+	uint mode;
+	int div;
+};
+
+static int cv1800b_spi_probe(struct udevice *bus)
+{
+	struct cv1800b_spi_priv *priv = dev_get_priv(bus);
+	struct clk clkdev;
+	int ret;
+
+	priv->regs = (struct cv1800b_spif_regs *)dev_read_addr_ptr(bus);
+	if (priv->regs == 0)
+		return -EINVAL;
+
+	ret = clk_get_by_index(bus, 0, &clkdev);
+	if (ret)
+		return ret;
+	priv->clk_freq = clk_get_rate(&clkdev);
+
+	/* DMMR mode is enabled by default, disable it */
+	writel(0, &priv->regs->dmmr_ctrl);
+
+	return 0;
+}
+
+static void cv1800b_spi_config_dmmr(struct cv1800b_spi_priv *priv, struct spi_nor *flash)
+{
+	struct cv1800b_spif_regs *regs = priv->regs;
+	u32 read_cmd = flash->read_opcode;
+	u32 val;
+
+	val = CV1800B_SPI_TRAN_MODE_RX | CV1800B_SPI_TRAN_WITH_CMD;
+
+	switch (read_cmd) {
+	case SPINOR_OP_READ_4B:
+	case SPINOR_OP_READ_FAST_4B:
+	case SPINOR_OP_READ_1_1_2_4B:
+	case SPINOR_OP_READ_1_1_4_4B:
+		val |= CV1800B_SPI_TRAN_ADDR_4_BYTES |
+		       CV1800B_SPI_TRAN_BYTE4_EN | CV1800B_SPI_TRAN_BYTE4_CMD;
+		break;
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ_FAST:
+	case SPINOR_OP_READ_1_1_2:
+	case SPINOR_OP_READ_1_1_4:
+		val |= CV1800B_SPI_TRAN_ADDR_3_BYTES;
+		break;
+	}
+
+	switch (read_cmd) {
+	case SPINOR_OP_READ_FAST:
+	case SPINOR_OP_READ_FAST_4B:
+		val |= CV1800B_SPI_TRAN_FAST_MODE;
+		break;
+	}
+
+	switch (read_cmd) {
+	case SPINOR_OP_READ_1_1_2:
+	case SPINOR_OP_READ_1_1_2_4B:
+		val |= CV1800B_SPI_TRAN_BUS_WIDTH_2_BIT;
+		break;
+	case SPINOR_OP_READ_1_1_4:
+	case SPINOR_OP_READ_1_1_4_4B:
+		val |= CV1800B_SPI_TRAN_BUS_WIDTH_4_BIT;
+		break;
+	}
+
+	val |= (flash->read_dummy & CV1800B_SPI_TRAN_DUMMY_CYC_MASK)
+	       << CV1800B_SPI_TRAN_DUMMY_CYC_OFFSET;
+	writel(val, &regs->tran_csr);
+}
+
+static void cv1800b_set_clk_div(struct cv1800b_spi_priv *priv, u32 div)
+{
+	struct cv1800b_spif_regs *regs = priv->regs;
+	u32 neg_sample = 0;
+
+	clrsetbits_le32(&regs->spi_ctrl, CV1800B_SPI_CTRL_SCK_DIV_MASK, div);
+
+	if (div < CV1800B_DEFAULT_DIV)
+		neg_sample = CV1800B_SPI_DLY_CTRL_NEG_SAMPLE;
+	clrsetbits_le32(&regs->dly_ctrl, CV1800B_SPI_DLY_CTRL_NEG_SAMPLE, neg_sample);
+}
+
+static int cv1800b_spi_transfer(struct cv1800b_spi_priv *priv,
+				u8 *din, const u8 *dout, uint len, ulong flags)
+{
+	struct cv1800b_spif_regs *regs = priv->regs;
+	u32 tran_csr;
+	u32 xfer_size, off;
+	u32 fifo_cnt;
+	u32 interrupt_mask;
+
+	if (din) {
+		/* Slow down on receiving */
+		cv1800b_set_clk_div(priv, CV1800B_DEFAULT_DIV);
+		interrupt_mask = CV1800B_SPI_INT_RD_FIFO;
+	} else {
+		interrupt_mask = CV1800B_SPI_INT_WR_FIFO;
+	}
+
+	writel(0, &regs->ff_pt);
+	writel(len, &regs->tran_num);
+
+	tran_csr = CV1800B_SPI_TRAN_GO_BUSY;
+	if (din) {
+		tran_csr |= CV1800B_SPI_TRAN_MODE_RX;
+	} else {
+		tran_csr |= CV1800B_SPI_TRAN_MODE_TX;
+		if (!(flags & SPI_XFER_BEGIN) && (priv->mode & SPI_TX_QUAD))
+			tran_csr |= CV1800B_SPI_TRAN_BUS_WIDTH_4_BIT;
+	}
+	writel(tran_csr, &regs->tran_csr);
+
+	wait_for_bit_le32(&regs->int_sts, interrupt_mask, true, 3000, false);
+
+	off = 0;
+	while (off < len) {
+		xfer_size = min_t(u32, len - off, CV1800B_FIFO_CAPACITY);
+
+		fifo_cnt = readl(&regs->ff_pt) & CV1800B_SPI_FF_PT_AVAILABLE_MASK;
+		if (din)
+			xfer_size = min(xfer_size, fifo_cnt);
+		else
+			xfer_size = min(xfer_size, CV1800B_FIFO_CAPACITY - fifo_cnt);
+
+		while (xfer_size--) {
+			if (din)
+				din[off++] = readb(&regs->ff_port);
+			else
+				writeb(dout[off++], &regs->ff_port);
+		}
+	}
+
+	wait_for_bit_le32(&regs->int_sts, CV1800B_SPI_INT_TRAN_DONE, true, 3000, false);
+	writel(0, &regs->ff_pt);
+	clrbits_le32(&regs->int_sts, CV1800B_SPI_INT_TRAN_DONE | interrupt_mask);
+
+	if (din)
+		cv1800b_set_clk_div(priv, priv->div);
+	return 0;
+}
+
+static int cv1800b_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			    const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct cv1800b_spi_priv *priv = dev_get_priv(bus);
+	struct cv1800b_spif_regs *regs = priv->regs;
+
+	if (bitlen == 0)
+		goto out;
+
+	if (bitlen % 8) {
+		flags |= SPI_XFER_END;
+		goto out;
+	}
+
+	if (flags & SPI_XFER_BEGIN)
+		writel(CV1800B_SPI_CE_DISABLE, &regs->ce_ctrl);
+
+	if (din || dout)
+		cv1800b_spi_transfer(priv, din, dout, bitlen / 8, flags);
+
+out:
+	if (flags & SPI_XFER_END)
+		writel(CV1800B_SPI_CE_ENABLE, &regs->ce_ctrl);
+	return 0;
+}
+
+static int cv1800b_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct cv1800b_spi_priv *priv = dev_get_priv(bus);
+
+	priv->div = DIV_ROUND_CLOSEST(priv->clk_freq, speed * 2) - 1;
+	if (priv->div <= 0)
+		priv->div = CV1800B_DEFAULT_DIV;
+
+	cv1800b_set_clk_div(priv, priv->div);
+
+	return 0;
+}
+
+static int cv1800b_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct cv1800b_spi_priv *priv = dev_get_priv(bus);
+	struct cv1800b_spif_regs *regs = priv->regs;
+	u32 val = 0;
+
+	if (mode & SPI_CPHA)
+		val |= CV1800B_SPI_CTRL_CPHA;
+	if (mode & SPI_CPOL)
+		val |= CV1800B_SPI_CTRL_CPOL;
+	clrsetbits_le32(&regs->spi_ctrl, CV1800B_SPI_CTRL_CPHA | CV1800B_SPI_CTRL_CPOL, val);
+
+	priv->mode = mode;
+
+	return 0;
+}
+
+static int cv1800b_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
+{
+	struct udevice *bus = slave->dev->parent;
+	struct cv1800b_spi_priv *priv = dev_get_priv(bus);
+	struct cv1800b_spif_regs *regs = priv->regs;
+	struct spi_nor *flash = dev_get_uclass_priv(slave->dev);
+	u32 old_tran_csr;
+
+	if (!(op->data.nbytes > 0 && op->data.dir == SPI_MEM_DATA_IN) ||
+	    !(op->addr.nbytes > 0 && op->addr.nbytes <= 4))
+		return -ENOTSUPP;
+
+	old_tran_csr = readl(&regs->tran_csr);
+	writel(CV1800B_SPI_CE_HARDWARE, &regs->ce_ctrl);
+
+	cv1800b_spi_config_dmmr(priv, flash);
+
+	writel(1, &regs->dmmr_ctrl);
+	memcpy(op->data.buf.in, (void *)priv->regs + op->addr.val, op->data.nbytes);
+	writel(0, &regs->dmmr_ctrl);
+
+	writel(CV1800B_SPI_CE_ENABLE, &regs->ce_ctrl);
+	writel(old_tran_csr, &regs->tran_csr);
+
+	return 0;
+}
+
+static const struct spi_controller_mem_ops cv1800b_spi_mem_ops = {
+	.exec_op = cv1800b_spi_exec_op,
+};
+
+static const struct dm_spi_ops cv1800b_spi_ops = {
+	.xfer      = cv1800b_spi_xfer,
+	.mem_ops   = &cv1800b_spi_mem_ops,
+	.set_speed = cv1800b_spi_set_speed,
+	.set_mode  = cv1800b_spi_set_mode,
+};
+
+static const struct udevice_id cv1800b_spi_ids[] = {
+	{ .compatible = "sophgo,cv1800b-spif" },
+	{ }
+};
+
+U_BOOT_DRIVER(cv1800b_spi) = {
+	.name      = "cv1800b_spif",
+	.id        = UCLASS_SPI,
+	.of_match  = cv1800b_spi_ids,
+	.ops       = &cv1800b_spi_ops,
+	.priv_auto = sizeof(struct cv1800b_spi_priv),
+	.probe     = cv1800b_spi_probe,
+};
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 49c0787..b64bfad 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -59,6 +59,11 @@
 
 endif
 
+config SYSRESET_CV1800B
+	bool "Enable support for Sophgo cv1800b System Reset"
+	help
+	  Enable system reset support for Sophgo cv1800b SoC.
+
 config POWEROFF_GPIO
 	bool "Enable support for GPIO poweroff driver"
 	depends on DM_GPIO
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index e0e7322..d59299a 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -7,6 +7,7 @@
 obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
 obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
 obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
+obj-$(CONFIG_SYSRESET_CV1800B) += sysreset_cv1800b.o
 obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o
 obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
 obj-$(CONFIG_$(SPL_TPL_)SYSRESET_MAX77663) += sysreset_max77663.o
diff --git a/drivers/sysreset/sysreset_cv1800b.c b/drivers/sysreset/sysreset_cv1800b.c
new file mode 100644
index 0000000..9cd6277
--- /dev/null
+++ b/drivers/sysreset/sysreset_cv1800b.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <dm.h>
+#include <stdbool.h>
+#include <sysreset.h>
+#include <wait_bit.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+
+#define REG_RTC_BASE             (void *)0x05026000
+#define REG_RTC_CTRL_BASE        (void *)0x05025000
+#define REG_RTC_EN_SHDN_REQ      (REG_RTC_BASE + 0xc0)
+#define REG_RTC_EN_PWR_CYC_REQ   (REG_RTC_BASE + 0xc8)
+#define REG_RTC_EN_WARM_RST_REQ  (REG_RTC_BASE + 0xcc)
+#define REG_RTC_CTRL_UNLOCKKEY   (REG_RTC_CTRL_BASE + 0x4)
+#define REG_RTC_CTRL             (REG_RTC_CTRL_BASE + 0x8)
+
+#define CTRL_UNLOCKKEY_MAGIC     0xAB18
+
+/* REG_RTC_CTRL */
+#define BIT_REQ_SHDN       BIT(0)
+#define BIT_REQ_PWR_CYC    BIT(3)
+#define BIT_REQ_WARM_RST   BIT(4)
+
+static struct {
+	void *pre_req_reg;
+	u32 req_bit;
+} reset_info[SYSRESET_COUNT] = {
+	[SYSRESET_WARM]      = { REG_RTC_EN_WARM_RST_REQ, BIT_REQ_WARM_RST },
+	[SYSRESET_COLD]      = { REG_RTC_EN_WARM_RST_REQ, BIT_REQ_WARM_RST },
+	[SYSRESET_POWER]     = { REG_RTC_EN_PWR_CYC_REQ, BIT_REQ_PWR_CYC },
+	[SYSRESET_POWER_OFF] = { REG_RTC_EN_SHDN_REQ, BIT_REQ_SHDN },
+};
+
+static int cv1800b_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+	u32 reg;
+
+	writel(1, reset_info[type].pre_req_reg);
+	writel(CTRL_UNLOCKKEY_MAGIC, REG_RTC_CTRL_UNLOCKKEY);
+	reg = readl(REG_RTC_CTRL);
+	writel(0xFFFF0800 | reset_info[type].req_bit, REG_RTC_CTRL);
+
+	return -EINPROGRESS;
+}
+
+static struct sysreset_ops cv1800b_sysreset = {
+	.request = cv1800b_sysreset_request,
+};
+
+static const struct udevice_id cv1800b_sysreset_ids[] = {
+	{ .compatible = "sophgo,cv1800b-sysreset", },
+	{},
+};
+
+U_BOOT_DRIVER(sysreset_cv1800b) = {
+	.name = "cv1800b_sysreset",
+	.id	  = UCLASS_SYSRESET,
+	.ops  = &cv1800b_sysreset,
+	.of_match = cv1800b_sysreset_ids
+};