aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv/cpu/andesv5/Kconfig1
-rw-r--r--arch/riscv/cpu/fu540/spl.c2
-rw-r--r--arch/riscv/cpu/fu740/spl.c2
-rw-r--r--arch/riscv/cpu/jh7110/spl.c2
-rw-r--r--arch/riscv/dts/cv1800b-milkv-duo.dts18
-rw-r--r--arch/riscv/dts/cv18xx.dtsi40
-rw-r--r--arch/riscv/include/asm/arch-fu540/spl.h2
-rw-r--r--arch/riscv/include/asm/arch-fu740/spl.h2
-rw-r--r--arch/riscv/include/asm/arch-jh7110/spl.h2
-rw-r--r--arch/riscv/include/asm/sbi.h1
-rw-r--r--board/sifive/unleashed/spl.c4
-rw-r--r--board/sifive/unmatched/spl.c4
-rw-r--r--board/sophgo/milkv_duo/Makefile3
-rw-r--r--board/sophgo/milkv_duo/board.c10
-rw-r--r--board/sophgo/milkv_duo/ethernet.c79
-rw-r--r--board/sophgo/milkv_duo/ethernet.h11
-rw-r--r--board/starfive/visionfive2/spl.c4
-rw-r--r--cmd/riscv/sbi.c3
-rw-r--r--configs/milkv_duo_defconfig10
-rw-r--r--drivers/mmc/cv1800b_sdhci.c4
-rw-r--r--drivers/net/designware.c1
-rw-r--r--drivers/spi/Kconfig8
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/cv1800b_spif.c321
-rw-r--r--drivers/sysreset/Kconfig5
-rw-r--r--drivers/sysreset/Makefile1
-rw-r--r--drivers/sysreset/sysreset_cv1800b.c64
27 files changed, 591 insertions, 14 deletions
diff --git a/arch/riscv/cpu/andesv5/Kconfig b/arch/riscv/cpu/andesv5/Kconfig
index f311291aedb..e3efb0de8f0 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 45657b79096..cedb70b66a2 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 c6816e9ed4c..16b307f0361 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 6bdf8b9c72f..87aaf865246 100644
--- a/arch/riscv/cpu/jh7110/spl.c
+++ b/arch/riscv/cpu/jh7110/spl.c
@@ -28,7 +28,7 @@ static bool check_ddr_size(phys_size_t size)
}
}
-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 94e64ddce8f..e7cc0e8bd14 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 ec99c4deeb6..4b0143450e8 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 4697279f438..519e7eb210f 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 15ad9e7c8b7..b327ac50361 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 23ce8871b3a..d73355bf35d 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 d1113f3d703..ad32dedb589 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -34,6 +34,7 @@ enum sbi_ext_id {
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 fe27316b2d9..9df9c68604e 100644
--- a/board/sifive/unleashed/spl.c
+++ b/board/sifive/unleashed/spl.c
@@ -27,9 +27,9 @@ int spl_board_init_f(void)
{
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 e69bed9d99d..6fc1d809540 100644
--- a/board/sifive/unmatched/spl.c
+++ b/board/sifive/unmatched/spl.c
@@ -134,9 +134,9 @@ int spl_board_init_f(void)
{
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 a087013f5c6..d0525eba853 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 eaa47be1739..9adbb08f5ce 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 00000000000..e997ce1037f
--- /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 00000000000..7b21f1b0f66
--- /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 45848db6d8b..ca61b5be227 100644
--- a/board/starfive/visionfive2/spl.c
+++ b/board/starfive/visionfive2/spl.c
@@ -285,9 +285,9 @@ int spl_board_init_f(void)
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 bd9d9c4765d..2d8ee7e5bbb 100644
--- a/cmd/riscv/sbi.c
+++ b/cmd/riscv/sbi.c
@@ -29,6 +29,8 @@ static struct sbi_imp implementations[] = {
{ 6, "Coffer" },
{ 7, "Xen Project" },
{ 8, "PolarFire Hart Software Services" },
+ { 9, "coreboot" },
+ { 10, "oreboot" },
};
static struct sbi_ext extensions[] = {
@@ -54,6 +56,7 @@ static struct sbi_ext extensions[] = {
{ 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 e8413d7aa94..0cb2922de44 100644
--- a/configs/milkv_duo_defconfig
+++ b/configs/milkv_duo_defconfig
@@ -19,14 +19,24 @@ CONFIG_HUSH_PARSER=y
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 9af6b971984..4e75051c317 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 @@ struct cv1800b_sdhci_plat {
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 4c1642b29a8..682045cea2c 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -871,6 +871,7 @@ static const struct udevice_id designware_eth_ids[] = {
{ .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 612434633b3..35030ab3556 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -168,6 +168,14 @@ config CF_SPI
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 14bdb97f189..32d7bf7237a 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o
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 00000000000..9c077f3ff90
--- /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 49c0787b26d..b64bfadb207 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -59,6 +59,11 @@ config SYSRESET_CMD_POWEROFF
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 e0e732205df..d59299aa318 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
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 00000000000..9cd62772ef4
--- /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
+};