diff options
27 files changed, 591 insertions, 14 deletions
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 @@ 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 94e64dd..e7cc0e8 100644 --- a/arch/riscv/dts/cv1800b-milkv-duo.dts +++ b/arch/riscv/dts/cv1800b-milkv-duo.dts @@ -29,6 +29,11 @@ }; }; +ðernet0 { + 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 = <ð_csrclk>, <ð_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 @@ 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 fe27316..9df9c68 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 e69bed9..6fc1d80 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 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 @@ 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 bd9d9c4..2d8ee7e 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 e8413d7..0cb2922 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 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 @@ 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 4c1642b..682045c 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 6124346..35030ab 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 14bdb97..32d7bf7 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 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, ®s->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(®s->spi_ctrl, CV1800B_SPI_CTRL_SCK_DIV_MASK, div); + + if (div < CV1800B_DEFAULT_DIV) + neg_sample = CV1800B_SPI_DLY_CTRL_NEG_SAMPLE; + clrsetbits_le32(®s->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, ®s->ff_pt); + writel(len, ®s->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, ®s->tran_csr); + + wait_for_bit_le32(®s->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(®s->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(®s->ff_port); + else + writeb(dout[off++], ®s->ff_port); + } + } + + wait_for_bit_le32(®s->int_sts, CV1800B_SPI_INT_TRAN_DONE, true, 3000, false); + writel(0, ®s->ff_pt); + clrbits_le32(®s->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, ®s->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, ®s->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(®s->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(®s->tran_csr); + writel(CV1800B_SPI_CE_HARDWARE, ®s->ce_ctrl); + + cv1800b_spi_config_dmmr(priv, flash); + + writel(1, ®s->dmmr_ctrl); + memcpy(op->data.buf.in, (void *)priv->regs + op->addr.val, op->data.nbytes); + writel(0, ®s->dmmr_ctrl); + + writel(CV1800B_SPI_CE_ENABLE, ®s->ce_ctrl); + writel(old_tran_csr, ®s->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 @@ 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 e0e7322..d59299a 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 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 +}; |