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
This commit is contained in:
Tom Rini 2024-05-01 19:40:32 -06:00
commit 62825d48c4
27 changed files with 591 additions and 14 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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";
};

View File

@ -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>;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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" },
{ }
};

View File

@ -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

View File

@ -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

321
drivers/spi/cv1800b_spif.c Normal file
View File

@ -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,
};

View File

@ -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

View File

@ -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

View File

@ -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
};