From e92ed065bad3d2728340c1a279f306c4b769eda1 Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:42 +0800 Subject: [PATCH 01/18] net: phy: Add driver for Motorcomm yt8531 gigabit ethernet phy Add a driver for the motorcomm yt8531 gigabit ethernet phy. We have verified the driver on StarFive VisionFive2 board. Signed-off-by: Yanhong Wang Reviewed-by: Ramon Fried --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/motorcomm.c | 437 ++++++++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 drivers/net/phy/motorcomm.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 24158776f52..0c3c39a5504 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -220,6 +220,12 @@ config PHY_MICREL_KSZ8XXX endif # PHY_MICREL +config PHY_MOTORCOMM + tristate "Motorcomm PHYs" + help + Enables support for Motorcomm network PHYs. + Currently supports the YT8531 Gigabit Ethernet PHYs. + config PHY_MSCC bool "Microsemi Corp Ethernet PHYs support" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 85d17f109cd..2487f366e1c 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_PHY_MARVELL_10G) += marvell10g.o obj-$(CONFIG_PHY_MICREL_KSZ8XXX) += micrel_ksz8xxx.o obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o +obj-$(CONFIG_PHY_MOTORCOMM) += motorcomm.o obj-$(CONFIG_PHY_NATSEMI) += natsemi.o obj-$(CONFIG_PHY_NXP_C45_TJA11XX) += nxp-c45-tja11xx.o obj-$(CONFIG_PHY_NXP_TJA11XX) += nxp-tja11xx.o diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c new file mode 100644 index 00000000000..e822fd76f27 --- /dev/null +++ b/drivers/net/phy/motorcomm.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Motorcomm 8531 PHY driver. + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#define PHY_ID_YT8531 0x4f51e91b +#define PHY_ID_MASK GENMASK(31, 0) + +/* Extended Register's Address Offset Register */ +#define YTPHY_PAGE_SELECT 0x1E + +/* Extended Register's Data Register */ +#define YTPHY_PAGE_DATA 0x1F + +#define YTPHY_SYNCE_CFG_REG 0xA012 + +#define YTPHY_DTS_OUTPUT_CLK_DIS 0 +#define YTPHY_DTS_OUTPUT_CLK_25M 25000000 +#define YTPHY_DTS_OUTPUT_CLK_125M 125000000 + +#define YT8531_SCR_SYNCE_ENABLE BIT(6) +/* 1b0 output 25m clock *default* + * 1b1 output 125m clock + */ +#define YT8531_SCR_CLK_FRE_SEL_125M BIT(4) +#define YT8531_SCR_CLK_SRC_MASK GENMASK(3, 1) +#define YT8531_SCR_CLK_SRC_PLL_125M 0 +#define YT8531_SCR_CLK_SRC_UTP_RX 1 +#define YT8531_SCR_CLK_SRC_SDS_RX 2 +#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3 +#define YT8531_SCR_CLK_SRC_REF_25M 4 +#define YT8531_SCR_CLK_SRC_SSC_25M 5 + +/* 1b0 use original tx_clk_rgmii *default* + * 1b1 use inverted tx_clk_rgmii. + */ +#define YT8531_RC1R_TX_CLK_SEL_INVERTED BIT(14) +#define YT8531_RC1R_RX_DELAY_MASK GENMASK(13, 10) +#define YT8531_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4) +#define YT8531_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0) +#define YT8531_RC1R_RGMII_0_000_NS 0 +#define YT8531_RC1R_RGMII_0_150_NS 1 +#define YT8531_RC1R_RGMII_0_300_NS 2 +#define YT8531_RC1R_RGMII_0_450_NS 3 +#define YT8531_RC1R_RGMII_0_600_NS 4 +#define YT8531_RC1R_RGMII_0_750_NS 5 +#define YT8531_RC1R_RGMII_0_900_NS 6 +#define YT8531_RC1R_RGMII_1_050_NS 7 +#define YT8531_RC1R_RGMII_1_200_NS 8 +#define YT8531_RC1R_RGMII_1_350_NS 9 +#define YT8531_RC1R_RGMII_1_500_NS 10 +#define YT8531_RC1R_RGMII_1_650_NS 11 +#define YT8531_RC1R_RGMII_1_800_NS 12 +#define YT8531_RC1R_RGMII_1_950_NS 13 +#define YT8531_RC1R_RGMII_2_100_NS 14 +#define YT8531_RC1R_RGMII_2_250_NS 15 + +/* Phy gmii clock gating Register */ +#define YT8531_CLOCK_GATING_REG 0xC +#define YT8531_CGR_RX_CLK_EN BIT(12) + +/* Specific Status Register */ +#define YTPHY_SPECIFIC_STATUS_REG 0x11 +#define YTPHY_DUPLEX_MASK BIT(13) +#define YTPHY_DUPLEX_SHIFT 13 +#define YTPHY_SPEED_MODE_MASK GENMASK(15, 14) +#define YTPHY_SPEED_MODE_SHIFT 14 + +#define YT8531_EXTREG_SLEEP_CONTROL1_REG 0x27 +#define YT8531_ESC1R_SLEEP_SW BIT(15) +#define YT8531_ESC1R_PLLON_SLP BIT(14) + +#define YT8531_RGMII_CONFIG1_REG 0xA003 + +#define YT8531_CHIP_CONFIG_REG 0xA001 +#define YT8531_CCR_SW_RST BIT(15) +/* 1b0 disable 1.9ns rxc clock delay *default* + * 1b1 enable 1.9ns rxc clock delay + */ +#define YT8531_CCR_RXC_DLY_EN BIT(8) +#define YT8531_CCR_RXC_DLY_1_900_NS 1900 + +/* bits in struct ytphy_plat_priv->flag */ +#define TX_CLK_ADJ_ENABLED BIT(0) +#define AUTO_SLEEP_DISABLED BIT(1) +#define KEEP_PLL_ENABLED BIT(2) +#define TX_CLK_10_INVERTED BIT(3) +#define TX_CLK_100_INVERTED BIT(4) +#define TX_CLK_1000_INVERTED BIT(5) + +struct ytphy_plat_priv { + u32 rx_delay_ps; + u32 tx_delay_ps; + u32 clk_out_frequency; + u32 flag; +}; + +/** + * struct ytphy_cfg_reg_map - map a config value to a register value + * @cfg: value in device configuration + * @reg: value in the register + */ +struct ytphy_cfg_reg_map { + u32 cfg; + u32 reg; +}; + +static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = { + /* for tx delay / rx delay with YT8531_CCR_RXC_DLY_EN is not set. */ + { 0, YT8531_RC1R_RGMII_0_000_NS }, + { 150, YT8531_RC1R_RGMII_0_150_NS }, + { 300, YT8531_RC1R_RGMII_0_300_NS }, + { 450, YT8531_RC1R_RGMII_0_450_NS }, + { 600, YT8531_RC1R_RGMII_0_600_NS }, + { 750, YT8531_RC1R_RGMII_0_750_NS }, + { 900, YT8531_RC1R_RGMII_0_900_NS }, + { 1050, YT8531_RC1R_RGMII_1_050_NS }, + { 1200, YT8531_RC1R_RGMII_1_200_NS }, + { 1350, YT8531_RC1R_RGMII_1_350_NS }, + { 1500, YT8531_RC1R_RGMII_1_500_NS }, + { 1650, YT8531_RC1R_RGMII_1_650_NS }, + { 1800, YT8531_RC1R_RGMII_1_800_NS }, + { 1950, YT8531_RC1R_RGMII_1_950_NS }, /* default tx/rx delay */ + { 2100, YT8531_RC1R_RGMII_2_100_NS }, + { 2250, YT8531_RC1R_RGMII_2_250_NS }, + + /* only for rx delay with YT8531_CCR_RXC_DLY_EN is set. */ + { 0 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_000_NS }, + { 150 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_150_NS }, + { 300 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_300_NS }, + { 450 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_450_NS }, + { 600 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_600_NS }, + { 750 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_750_NS }, + { 900 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_900_NS }, + { 1050 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_050_NS }, + { 1200 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_200_NS }, + { 1350 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_350_NS }, + { 1500 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_500_NS }, + { 1650 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_650_NS }, + { 1800 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_800_NS }, + { 1950 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_950_NS }, + { 2100 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_2_100_NS }, + { 2250 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_2_250_NS } +}; + +static u32 ytphy_get_delay_reg_value(struct phy_device *phydev, + u32 val, + u16 *rxc_dly_en) +{ + int tb_size = ARRAY_SIZE(ytphy_rgmii_delays); + int tb_size_half = tb_size / 2; + int i; + + /* when rxc_dly_en is NULL, it is get the delay for tx, only half of + * tb_size is valid. + */ + if (!rxc_dly_en) + tb_size = tb_size_half; + + for (i = 0; i < tb_size; i++) { + if (ytphy_rgmii_delays[i].cfg == val) { + if (rxc_dly_en && i < tb_size_half) + *rxc_dly_en = 0; + return ytphy_rgmii_delays[i].reg; + } + } + + pr_warn("Unsupported value %d, using default (%u)\n", + val, YT8531_RC1R_RGMII_1_950_NS); + + /* when rxc_dly_en is not NULL, it is get the delay for rx. + * The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps, + * so YT8531_CCR_RXC_DLY_EN should not be set. + */ + if (rxc_dly_en) + *rxc_dly_en = 0; + + return YT8531_RC1R_RGMII_1_950_NS; +} + +static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask, + u16 set) +{ + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_SELECT, regnum); + if (ret < 0) + return ret; + + return phy_modify(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA, mask, set); +} + +static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) +{ + struct ytphy_plat_priv *priv = phydev->priv; + u16 rxc_dly_en = YT8531_CCR_RXC_DLY_EN; + u32 rx_reg, tx_reg; + u16 mask, val = 0; + int ret; + + rx_reg = ytphy_get_delay_reg_value(phydev, priv->rx_delay_ps, + &rxc_dly_en); + tx_reg = ytphy_get_delay_reg_value(phydev, priv->tx_delay_ps, + NULL); + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + rxc_dly_en = 0; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg); + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + rxc_dly_en = 0; + val |= FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg); + break; + case PHY_INTERFACE_MODE_RGMII_ID: + val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg) | + FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg); + break; + default: /* do not support other modes */ + return -EOPNOTSUPP; + } + + ret = ytphy_modify_ext(phydev, YT8531_CHIP_CONFIG_REG, + YT8531_CCR_RXC_DLY_EN, rxc_dly_en); + if (ret < 0) + return ret; + + /* Generally, it is not necessary to adjust YT8531_RC1R_FE_TX_DELAY */ + mask = YT8531_RC1R_RX_DELAY_MASK | YT8531_RC1R_GE_TX_DELAY_MASK; + return ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG, mask, val); +} + +static int yt8531_parse_status(struct phy_device *phydev) +{ + int val; + int speed, speed_mode; + + val = phy_read(phydev, MDIO_DEVAD_NONE, YTPHY_SPECIFIC_STATUS_REG); + if (val < 0) + return val; + + speed_mode = (val & YTPHY_SPEED_MODE_MASK) >> YTPHY_SPEED_MODE_SHIFT; + switch (speed_mode) { + case 2: + speed = SPEED_1000; + break; + case 1: + speed = SPEED_100; + break; + default: + speed = SPEED_10; + break; + } + + phydev->speed = speed; + phydev->duplex = (val & YTPHY_DUPLEX_MASK) >> YTPHY_DUPLEX_SHIFT; + + return 0; +} + +static int yt8531_startup(struct phy_device *phydev) +{ + struct ytphy_plat_priv *priv = phydev->priv; + u16 val = 0; + int ret; + + ret = genphy_update_link(phydev); + if (ret) + return ret; + + ret = yt8531_parse_status(phydev); + if (ret) + return ret; + + if (phydev->speed < 0) + return -EINVAL; + + if (!(priv->flag & TX_CLK_ADJ_ENABLED)) + return 0; + + switch (phydev->speed) { + case SPEED_1000: + if (priv->flag & TX_CLK_1000_INVERTED) + val = YT8531_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_100: + if (priv->flag & TX_CLK_100_INVERTED) + val = YT8531_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_10: + if (priv->flag & TX_CLK_10_INVERTED) + val = YT8531_RC1R_TX_CLK_SEL_INVERTED; + break; + default: + printf("UNKNOWN SPEED\n"); + return -EINVAL; + } + + ret = ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG, + YT8531_RC1R_TX_CLK_SEL_INVERTED, val); + if (ret < 0) + pr_warn("Modify TX_CLK_SEL err:%d\n", ret); + + return 0; +} + +static void ytphy_dt_parse(struct phy_device *phydev) +{ + struct ytphy_plat_priv *priv = phydev->priv; + + priv->clk_out_frequency = ofnode_read_u32_default(phydev->node, + "motorcomm,clk-out-frequency-hz", + YTPHY_DTS_OUTPUT_CLK_DIS); + priv->rx_delay_ps = ofnode_read_u32_default(phydev->node, + "rx-internal-delay-ps", + YT8531_RC1R_RGMII_1_950_NS); + priv->tx_delay_ps = ofnode_read_u32_default(phydev->node, + "tx-internal-delay-ps", + YT8531_RC1R_RGMII_1_950_NS); + + if (ofnode_read_bool(phydev->node, "motorcomm,auto-sleep-disabled")) + priv->flag |= AUTO_SLEEP_DISABLED; + + if (ofnode_read_bool(phydev->node, "motorcomm,keep-pll-enabled")) + priv->flag |= KEEP_PLL_ENABLED; + + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled")) + priv->flag |= TX_CLK_ADJ_ENABLED; + + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-10-inverted")) + priv->flag |= TX_CLK_10_INVERTED; + + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-100-inverted")) + priv->flag |= TX_CLK_100_INVERTED; + + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-1000-inverted")) + priv->flag |= TX_CLK_1000_INVERTED; +} + +static int yt8531_config(struct phy_device *phydev) +{ + struct ytphy_plat_priv *priv = phydev->priv; + u16 mask, val; + int ret; + + ret = genphy_config_aneg(phydev); + if (ret < 0) + return ret; + + ytphy_dt_parse(phydev); + switch (priv->clk_out_frequency) { + case YTPHY_DTS_OUTPUT_CLK_DIS: + mask = YT8531_SCR_SYNCE_ENABLE; + val = 0; + break; + case YTPHY_DTS_OUTPUT_CLK_25M: + mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | + YT8531_SCR_CLK_FRE_SEL_125M; + val = YT8531_SCR_SYNCE_ENABLE | + FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, + YT8531_SCR_CLK_SRC_REF_25M); + break; + case YTPHY_DTS_OUTPUT_CLK_125M: + mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | + YT8531_SCR_CLK_FRE_SEL_125M; + val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M | + FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, + YT8531_SCR_CLK_SRC_PLL_125M); + break; + default: + pr_warn("Freq err:%u\n", priv->clk_out_frequency); + return -EINVAL; + } + + ret = ytphy_modify_ext(phydev, YTPHY_SYNCE_CFG_REG, mask, + val); + if (ret < 0) + return ret; + + ret = ytphy_rgmii_clk_delay_config(phydev); + if (ret < 0) + return ret; + + if (priv->flag & AUTO_SLEEP_DISABLED) { + /* disable auto sleep */ + ret = ytphy_modify_ext(phydev, + YT8531_EXTREG_SLEEP_CONTROL1_REG, + YT8531_ESC1R_SLEEP_SW, 0); + if (ret < 0) + return ret; + } + + if (priv->flag & KEEP_PLL_ENABLED) { + /* enable RXC clock when no wire plug */ + ret = ytphy_modify_ext(phydev, + YT8531_CLOCK_GATING_REG, + YT8531_CGR_RX_CLK_EN, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static int yt8531_probe(struct phy_device *phydev) +{ + struct ytphy_plat_priv *priv; + + priv = calloc(1, sizeof(struct ytphy_plat_priv)); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return 0; +} + +U_BOOT_PHY_DRIVER(motorcomm8531) = { + .name = "YT8531 Gigabit Ethernet", + .uid = PHY_ID_YT8531, + .mask = PHY_ID_MASK, + .features = PHY_GBIT_FEATURES, + .probe = &yt8531_probe, + .config = &yt8531_config, + .startup = &yt8531_startup, + .shutdown = &genphy_shutdown, +}; From 736733b43a2b1d1d37a0fad340cc2fed13fc0447 Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:43 +0800 Subject: [PATCH 02/18] net: dwc_eth_qos: Add StarFive ethernet driver glue layer The StarFive ETHQOS hardware has its own clock and reset,so add a corresponding glue driver to configure them. Signed-off-by: Yanhong Wang Reviewed-by: Ramon Fried --- drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/dwc_eth_qos.c | 6 + drivers/net/dwc_eth_qos.h | 1 + drivers/net/dwc_eth_qos_starfive.c | 249 +++++++++++++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 drivers/net/dwc_eth_qos_starfive.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d662dd34989..0ed39a61e4d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -249,6 +249,13 @@ config DWC_ETH_QOS_QCOM The Synopsys Designware Ethernet QOS IP block with specific configuration used in Qcom QCS404 SoC. +config DWC_ETH_QOS_STARFIVE + bool "Synopsys DWC Ethernet QOS device support for STARFIVE" + depends on DWC_ETH_QOS + help + The Synopsys Designware Ethernet QOS IP block with specific + configuration used in STARFIVE JH7110 soc. + config E1000 bool "Intel PRO/1000 Gigabit Ethernet support" depends on PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46a40e2ed9f..d4af253b6f2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o +obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o obj-$(CONFIG_E1000) += e1000.o obj-$(CONFIG_E1000_SPI) += e1000_spi.o obj-$(CONFIG_EEPRO100) += eepro100.o diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 9bbba6eed07..1e92bd9ca9c 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1725,6 +1725,12 @@ static const struct udevice_id eqos_ids[] = { .data = (ulong)&eqos_qcom_config }, #endif +#if IS_ENABLED(CONFIG_DWC_ETH_QOS_STARFIVE) + { + .compatible = "starfive,jh7110-dwmac", + .data = (ulong)&eqos_jh7110_config + }, +#endif { } }; diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h index fddbe9336c9..a6b719af809 100644 --- a/drivers/net/dwc_eth_qos.h +++ b/drivers/net/dwc_eth_qos.h @@ -289,3 +289,4 @@ int eqos_null_ops(struct udevice *dev); extern struct eqos_config eqos_imx_config; extern struct eqos_config eqos_qcom_config; +extern struct eqos_config eqos_jh7110_config; diff --git a/drivers/net/dwc_eth_qos_starfive.c b/drivers/net/dwc_eth_qos_starfive.c new file mode 100644 index 00000000000..5be8ac0f1a5 --- /dev/null +++ b/drivers/net/dwc_eth_qos_starfive.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: Yanhong Wang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dwc_eth_qos.h" + +#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 +#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 +#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U + +struct starfive_platform_data { + struct regmap *regmap; + struct reset_ctl_bulk resets; + struct clk_bulk clks; + phy_interface_t interface; + u32 offset; + u32 shift; + bool tx_use_rgmii_clk; +}; + +static int eqos_interface_init_jh7110(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data = pdata->priv_pdata; + struct ofnode_phandle_args args; + unsigned int mode; + int ret; + + switch (data->interface) { + case PHY_INTERFACE_MODE_RMII: + mode = STARFIVE_DWMAC_PHY_INFT_RMII; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + mode = STARFIVE_DWMAC_PHY_INFT_RGMII; + break; + + default: + return -EINVAL; + } + + ret = dev_read_phandle_with_args(dev, "starfive,syscon", NULL, + 2, 0, &args); + if (ret) + return ret; + + if (args.args_count != 2) + return -EINVAL; + + data->offset = args.args[0]; + data->shift = args.args[1]; + data->regmap = syscon_regmap_lookup_by_phandle(dev, "starfive,syscon"); + if (IS_ERR(data->regmap)) { + ret = PTR_ERR(data->regmap); + pr_err("Failed to get regmap: %d\n", ret); + return ret; + } + + return regmap_update_bits(data->regmap, data->offset, + STARFIVE_DWMAC_PHY_INFT_FIELD << data->shift, + mode << data->shift); +} + +static int eqos_set_tx_clk_speed_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data = pdata->priv_pdata; + struct clk *pclk, *c; + ulong rate; + int ret; + + /* Generally, the rgmii_tx clock is provided by the internal clock, + * which needs to match the corresponding clock frequency according + * to different speeds. If the rgmii_tx clock is provided by the + * external rgmii_rxin, there is no need to configure the clock + * internally, because rgmii_rxin will be adaptively adjusted. + */ + if (data->tx_use_rgmii_clk) + return 0; + + switch (eqos->phy->speed) { + case SPEED_1000: + rate = 125 * 1000 * 1000; + break; + case SPEED_100: + rate = 25 * 1000 * 1000; + break; + case SPEED_10: + rate = 2.5 * 1000 * 1000; + break; + default: + pr_err("invalid speed %d", eqos->phy->speed); + return -EINVAL; + } + + /* eqos->clk_tx clock has no set rate operation, so just set the parent + * clock rate directly + */ + ret = clk_get_by_id(eqos->clk_tx.id, &c); + if (ret) + return ret; + + pclk = clk_get_parent(c); + if (pclk) { + ret = clk_set_rate(pclk, rate); + if (ret < 0) { + pr_err("jh7110 (clk_tx, %lu) failed: %d", rate, ret); + return ret; + } + } + + return 0; +} + +static ulong eqos_get_tick_clk_rate_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + return clk_get_rate(&eqos->clk_tx); +} + +static int eqos_start_clks_jh7110(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data = pdata->priv_pdata; + + return clk_enable_bulk(&data->clks); +} + +static int eqos_stop_clks_jh7110(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data = pdata->priv_pdata; + + return clk_disable_bulk(&data->clks); +} + +static int eqos_start_resets_jh7110(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data = pdata->priv_pdata; + + return reset_deassert_bulk(&data->resets); +} + +static int eqos_stop_resets_jh7110(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data = pdata->priv_pdata; + + return reset_assert_bulk(&data->resets); +} + +static int eqos_remove_resources_jh7110(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data = pdata->priv_pdata; + + reset_assert_bulk(&data->resets); + clk_disable_bulk(&data->clks); + + return 0; +} + +static int eqos_probe_resources_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct starfive_platform_data *data; + int ret; + + data = calloc(1, sizeof(struct starfive_platform_data)); + if (!data) + return -ENOMEM; + + pdata->priv_pdata = data; + data->interface = eqos->config->interface(dev); + if (data->interface == PHY_INTERFACE_MODE_NA) { + pr_err("Invalid PHY interface\n"); + return -EINVAL; + } + + ret = reset_get_bulk(dev, &data->resets); + if (ret < 0) + return ret; + + ret = clk_get_bulk(dev, &data->clks); + if (ret < 0) + return ret; + + ret = clk_get_by_name(dev, "gtx", &eqos->clk_tx); + if (ret) + return ret; + + data->tx_use_rgmii_clk = dev_read_bool(dev, "starfive,tx-use-rgmii-clk"); + + return eqos_interface_init_jh7110(dev); +} + +static struct eqos_ops eqos_jh7110_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_jh7110, + .eqos_remove_resources = eqos_remove_resources_jh7110, + .eqos_stop_resets = eqos_stop_resets_jh7110, + .eqos_start_resets = eqos_start_resets_jh7110, + .eqos_stop_clks = eqos_stop_clks_jh7110, + .eqos_start_clks = eqos_start_clks_jh7110, + .eqos_calibrate_pads = eqos_null_ops, + .eqos_disable_calibration = eqos_null_ops, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_jh7110, + .eqos_get_enetaddr = eqos_null_ops, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_jh7110 +}; + +/* mdio_wait: There is no need to wait after setting the MAC_MDIO_Address register + * swr_wait: Software reset bit must be read at least 4 CSR clock cycles + * after it is written to 1. + * config_mac: Enable rx queue to DCB mode. + * config_mac_mdio: CSR clock range is 250-300 Mhz. + * axi_bus_width: The width of the data bus is 64 bit. + */ +struct eqos_config __maybe_unused eqos_jh7110_config = { + .reg_access_always_ok = false, + .mdio_wait = 0, + .swr_wait = 4, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, + .axi_bus_width = EQOS_AXI_WIDTH_64, + .interface = dev_read_phy_mode, + .ops = &eqos_jh7110_ops +}; From 55a2b826902255da95ae8b39f022ec4b0941753c Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:44 +0800 Subject: [PATCH 03/18] riscv: dts: jh7110: Add ethernet device tree nodes Add ethernet device tree node to support StarFive ethernet driver for the JH7110 RISC-V SoC. Signed-off-by: Yanhong Wang Reviewed-by: Leo Yu-Chi Liang --- .../dts/jh7110-starfive-visionfive-2.dtsi | 34 +++++++++ arch/riscv/dts/jh7110.dtsi | 69 +++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi index c6b6dfa9407..3c1148ae2d4 100644 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi @@ -17,6 +17,8 @@ i2c2 = &i2c2; i2c5 = &i2c5; i2c6 = &i2c6; + ethernet0 = &gmac0; + ethernet1 = &gmac1; }; chosen { @@ -317,3 +319,35 @@ assigned-clock-parents = <&osc>; assigned-clock-rates = <0>; }; + +&gmac0 { + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; +}; + +&gmac1 { + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy1: ethernet-phy@1 { + reg = <0>; + }; + }; +}; diff --git a/arch/riscv/dts/jh7110.dtsi b/arch/riscv/dts/jh7110.dtsi index bd60879615a..58e332e9d71 100644 --- a/arch/riscv/dts/jh7110.dtsi +++ b/arch/riscv/dts/jh7110.dtsi @@ -235,6 +235,13 @@ #clock-cells = <0>; }; + stmmac_axi_setup: stmmac-axi-config { + snps,lpi_en; + snps,wr_osr_lmt = <4>; + snps,rd_osr_lmt = <4>; + snps,blen = <256 128 64 32 0 0 0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&plic>; @@ -539,6 +546,68 @@ status = "disabled"; }; + gmac0: ethernet@16030000 { + compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20"; + reg = <0x0 0x16030000 0x0 0x10000>; + clocks = <&aoncrg JH7110_AONCLK_GMAC0_AXI>, + <&aoncrg JH7110_AONCLK_GMAC0_AHB>, + <&syscrg JH7110_SYSCLK_GMAC0_PTP>, + <&aoncrg JH7110_AONCLK_GMAC0_TX_INV>, + <&syscrg JH7110_SYSCLK_GMAC0_GTXC>; + clock-names = "stmmaceth", "pclk", "ptp_ref", + "tx", "gtx"; + resets = <&aoncrg JH7110_AONRST_GMAC0_AXI>, + <&aoncrg JH7110_AONRST_GMAC0_AHB>; + reset-names = "stmmaceth", "ahb"; + interrupts = <7>, <6>, <5>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + snps,multicast-filter-bins = <64>; + snps,perfect-filter-entries = <8>; + rx-fifo-depth = <2048>; + tx-fifo-depth = <2048>; + snps,fixed-burst; + snps,no-pbl-x8; + snps,force_thresh_dma_mode; + snps,axi-config = <&stmmac_axi_setup>; + snps,tso; + snps,en-tx-lpi-clockgating; + snps,txpbl = <16>; + snps,rxpbl = <16>; + starfive,syscon = <&aon_syscon 0xc 0x12>; + status = "disabled"; + }; + + gmac1: ethernet@16040000 { + compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20"; + reg = <0x0 0x16040000 0x0 0x10000>; + clocks = <&syscrg JH7110_SYSCLK_GMAC1_AXI>, + <&syscrg JH7110_SYSCLK_GMAC1_AHB>, + <&syscrg JH7110_SYSCLK_GMAC1_PTP>, + <&syscrg JH7110_SYSCLK_GMAC1_TX_INV>, + <&syscrg JH7110_SYSCLK_GMAC1_GTXC>; + clock-names = "stmmaceth", "pclk", "ptp_ref", + "tx", "gtx"; + resets = <&syscrg JH7110_SYSRST_GMAC1_AXI>, + <&syscrg JH7110_SYSRST_GMAC1_AHB>; + reset-names = "stmmaceth", "ahb"; + interrupts = <78>, <77>, <76>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + snps,multicast-filter-bins = <64>; + snps,perfect-filter-entries = <8>; + rx-fifo-depth = <2048>; + tx-fifo-depth = <2048>; + snps,fixed-burst; + snps,no-pbl-x8; + snps,force_thresh_dma_mode; + snps,axi-config = <&stmmac_axi_setup>; + snps,tso; + snps,en-tx-lpi-clockgating; + snps,txpbl = <16>; + snps,rxpbl = <16>; + starfive,syscon = <&sys_syscon 0x90 0x2>; + status = "disabled"; + }; + aoncrg: clock-controller@17000000 { compatible = "starfive,jh7110-aoncrg"; reg = <0x0 0x17000000 0x0 0x10000>; From 9b7060bd15e7265179772d9a350a8652e58f0e40 Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:45 +0800 Subject: [PATCH 04/18] riscv: dts: jh7110: Combine the board device tree files of 1.2A and 1.3B The difference between 1.2A and 1.3B is dynamically configured according to the PCB version, and there is no difference on the board device tree, so the same DT file can be used. Signed-off-by: Yanhong Wang Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/dts/Makefile | 3 +- ... jh7110-starfive-visionfive-2-u-boot.dtsi} | 25 ++++++- .../jh7110-starfive-visionfive-2-v1.2a.dts | 12 ---- ...10-starfive-visionfive-2-v1.3b-u-boot.dtsi | 69 ------------------- ...b.dts => jh7110-starfive-visionfive-2.dts} | 3 +- configs/starfive_visionfive2_defconfig | 4 +- 6 files changed, 28 insertions(+), 88 deletions(-) rename arch/riscv/dts/{jh7110-starfive-visionfive-2-v1.2a-u-boot.dtsi => jh7110-starfive-visionfive-2-u-boot.dtsi} (66%) delete mode 100644 arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts delete mode 100644 arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b-u-boot.dtsi rename arch/riscv/dts/{jh7110-starfive-visionfive-2-v1.3b.dts => jh7110-starfive-visionfive-2.dts} (65%) diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile index 1d61eb80205..d9c050e2996 100644 --- a/arch/riscv/dts/Makefile +++ b/arch/riscv/dts/Makefile @@ -7,8 +7,7 @@ dtb-$(CONFIG_TARGET_OPENPITON_RISCV64) += openpiton-riscv64.dtb dtb-$(CONFIG_TARGET_SIFIVE_UNLEASHED) += hifive-unleashed-a00.dtb dtb-$(CONFIG_TARGET_SIFIVE_UNMATCHED) += hifive-unmatched-a00.dtb dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb -dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2-v1.3b.dtb -dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2-v1.2a.dtb +dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2.dtb include $(srctree)/scripts/Makefile.dts targets += $(dtb-y) diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a-u-boot.dtsi b/arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi similarity index 66% rename from arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a-u-boot.dtsi rename to arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi index 3c322c5c972..2afcec30b87 100644 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a-u-boot.dtsi +++ b/arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /* - * Copyright (C) 2022 StarFive Technology Co., Ltd. + * Copyright (C) 2023 StarFive Technology Co., Ltd. */ #include "binman.dtsi" @@ -67,3 +67,26 @@ }; }; +&binman { + itb { + fit { + images { + fdt-1 { + description = "NAME"; + load = <0x40400000>; + compression = "none"; + + uboot_fdt_blob: blob-ext { + filename = "u-boot.dtb"; + }; + }; + }; + + configurations { + conf-1 { + fdt = "fdt-1"; + }; + }; + }; + }; +}; diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts b/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts deleted file mode 100644 index b9d26d7af7c..00000000000 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* - * Copyright (C) 2022 StarFive Technology Co., Ltd. - */ - -/dts-v1/; -#include "jh7110-starfive-visionfive-2.dtsi" - -/ { - model = "StarFive VisionFive 2 v1.2A"; - compatible = "starfive,visionfive-2-v1.2a", "starfive,jh7110"; -}; diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b-u-boot.dtsi b/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b-u-boot.dtsi deleted file mode 100644 index 3c322c5c972..00000000000 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b-u-boot.dtsi +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* - * Copyright (C) 2022 StarFive Technology Co., Ltd. - */ - -#include "binman.dtsi" -#include "jh7110-u-boot.dtsi" -/ { - chosen { - bootph-pre-ram; - }; - - firmware { - spi0 = &qspi; - bootph-pre-ram; - }; - - config { - bootph-pre-ram; - u-boot,spl-payload-offset = <0x100000>; - }; - - memory@40000000 { - bootph-pre-ram; - }; -}; - -&uart0 { - bootph-pre-ram; -}; - -&mmc0 { - bootph-pre-ram; -}; - -&mmc1 { - bootph-pre-ram; -}; - -&qspi { - bootph-pre-ram; - - nor-flash@0 { - bootph-pre-ram; - }; -}; - -&sysgpio { - bootph-pre-ram; -}; - -&mmc0_pins { - bootph-pre-ram; - mmc0-pins-rest { - bootph-pre-ram; - }; -}; - -&mmc1_pins { - bootph-pre-ram; - mmc1-pins0 { - bootph-pre-ram; - }; - - mmc1-pins1 { - bootph-pre-ram; - }; -}; - diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b.dts b/arch/riscv/dts/jh7110-starfive-visionfive-2.dts similarity index 65% rename from arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b.dts rename to arch/riscv/dts/jh7110-starfive-visionfive-2.dts index 3b3b3453a17..288ea394939 100644 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b.dts +++ b/arch/riscv/dts/jh7110-starfive-visionfive-2.dts @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /* - * Copyright (C) 2022 StarFive Technology Co., Ltd. + * Copyright (C) 2023 StarFive Technology Co., Ltd. */ /dts-v1/; #include "jh7110-starfive-visionfive-2.dtsi" / { - model = "StarFive VisionFive 2 v1.3B"; compatible = "starfive,visionfive-2-v1.3b", "starfive,jh7110"; }; diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index ffbc4b94767..566d2c3d0e0 100644 --- a/configs/starfive_visionfive2_defconfig +++ b/configs/starfive_visionfive2_defconfig @@ -7,7 +7,7 @@ CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x80000000 CONFIG_SF_DEFAULT_SPEED=100000000 CONFIG_SPL_DM_SPI=y -CONFIG_DEFAULT_DEVICE_TREE="jh7110-starfive-visionfive-2-v1.3b" +CONFIG_DEFAULT_DEVICE_TREE="jh7110-starfive-visionfive-2" CONFIG_SPL_TEXT_BASE=0x8000000 CONFIG_SYS_PROMPT="StarFive #" CONFIG_OF_LIBFDT_OVERLAY=y @@ -31,7 +31,7 @@ CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200 debug rootwait earlycon=sbi" CONFIG_USE_PREBOOT=y CONFIG_PREBOOT="setenv fdt_addr ${fdtcontroladdr};fdt addr ${fdtcontroladdr};" -CONFIG_DEFAULT_FDT_FILE="starfive/jh7110-starfive-visionfive-2-v1.3b.dtb" +CONFIG_DEFAULT_FDT_FILE="starfive/jh7110-starfive-visionfive-2.dtb" CONFIG_DISPLAY_CPUINFO=y CONFIG_DISPLAY_BOARDINFO=y CONFIG_SPL_MAX_SIZE=0x40000 From ed3ff429c3f4ed74710d9abc268f4cefb3bc88e0 Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:46 +0800 Subject: [PATCH 05/18] =?UTF-8?q?doc:=20board:=20starfive:=E3=80=80Reword?= =?UTF-8?q?=20the=20make=20defconfig=20information?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The defconfig file name for StarFive VisionFive2 has been changed, and the documentation description has also changed. Signed-off-by: Yanhong Wang Reviewed-by: Leo Yu-Chi Liang --- doc/board/starfive/visionfive2.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/board/starfive/visionfive2.rst b/doc/board/starfive/visionfive2.rst index 4d43ac9729c..951e0d80fb9 100644 --- a/doc/board/starfive/visionfive2.rst +++ b/doc/board/starfive/visionfive2.rst @@ -62,7 +62,7 @@ Now build the U-Boot SPL and U-Boot proper .. code-block:: console cd - make starfive_visionfive2_13b_defconfig + make starfive_visionfive2_defconfig make OPENSBI=$(opensbi_dir)/opensbi/build/platform/generic/firmware/fw_dynamic.bin This will generate spl/u-boot-spl.bin and FIT image (u-boot.itb) @@ -118,7 +118,7 @@ Program the SD card sudo cp u-boot.itb /mnt/ sudo cp Image.gz /mnt/ sudo cp initramfs.cpio.gz /mnt/ - sudo cp jh7110-starfive-visionfive-2-v1.3b.dtb /mnt/ + sudo cp jh7110-starfive-visionfive-2.dtb /mnt/ sudo umount /mnt Booting @@ -264,7 +264,7 @@ Sample boot log from StarFive VisionFive2 board StarFive #fatload mmc 1:3 ${kernel_addr_r} Image.gz 6429424 bytes read in 394 ms (15.6 MiB/s) - StarFive #fatload mmc 1:3 ${fdt_addr_r} jh7110-starfive-visionfive-2-v1.3b.dtb + StarFive #fatload mmc 1:3 ${fdt_addr_r} jh7110-starfive-visionfive-2.dtb 11285 bytes read in 5 ms (2.2 MiB/s) StarFive #fatload mmc 1:3 ${ramdisk_addr_r} initramfs.cpio.gz 152848495 bytes read in 9271 ms (15.7 MiB/s) From ed430fe5e47c72bb665ce874405b46108229daea Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:47 +0800 Subject: [PATCH 06/18] configs: starfive: Enable ethernet configuration for StarFive VisionFive2 Enable DWC_ETH_QOS and PHY_MOTORCOMM configuration to support ethernet function for StarFive VisionFive 2 board,including versions 1.2A and 1.3B. Signed-off-by: Yanhong Wang Reviewed-by: Leo Yu-Chi Liang --- configs/starfive_visionfive2_defconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index 566d2c3d0e0..c57708199d7 100644 --- a/configs/starfive_visionfive2_defconfig +++ b/configs/starfive_visionfive2_defconfig @@ -54,6 +54,8 @@ CONFIG_SYS_BOOTM_LEN=0x4000000 CONFIG_CMD_MEMINFO=y CONFIG_CMD_TFTPPUT=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y CONFIG_SPL_CLK_COMPOSITE_CCF=y CONFIG_CLK_COMPOSITE_CCF=y CONFIG_SPL_CLK_JH7110=y @@ -66,6 +68,13 @@ CONFIG_SPI_FLASH_EON=y CONFIG_SPI_FLASH_GIGADEVICE=y CONFIG_SPI_FLASH_ISSI=y CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_PHY_MOTORCOMM=y +CONFIG_DM_MDIO=y +CONFIG_DM_ETH_PHY=y +CONFIG_DWC_ETH_QOS=y +CONFIG_DWC_ETH_QOS_STARFIVE=y +CONFIG_RGMII=y +CONFIG_RMII=y CONFIG_PINCTRL=y CONFIG_PINCONF=y CONFIG_SPL_PINCTRL=y From aea1bd95b61e5596000e2aa71b32b32801ac51d4 Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:48 +0800 Subject: [PATCH 07/18] eeprom: starfive: Enable ID EEPROM configuration Enabled ID_EEPROM configuration for StarFive VisionFive2 board. Signed-off-by: Yanhong Wang Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/include/asm/arch-jh7110/eeprom.h | 13 + board/starfive/visionfive2/Makefile | 1 + .../visionfive2/visionfive2-i2c-eeprom.c | 561 ++++++++++++++++++ 3 files changed, 575 insertions(+) create mode 100644 arch/riscv/include/asm/arch-jh7110/eeprom.h create mode 100644 board/starfive/visionfive2/visionfive2-i2c-eeprom.c diff --git a/arch/riscv/include/asm/arch-jh7110/eeprom.h b/arch/riscv/include/asm/arch-jh7110/eeprom.h new file mode 100644 index 00000000000..f354d5c60cd --- /dev/null +++ b/arch/riscv/include/asm/arch-jh7110/eeprom.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: Yanhong Wang + */ + +#ifndef _ASM_RISCV_EEPROM_H +#define _ASM_RISCV_EEPROM_H + +u8 get_pcb_revision_from_eeprom(void); +u32 get_ddr_size_from_eeprom(void); + +#endif /* _ASM_RISCV_EEPROM_H */ diff --git a/board/starfive/visionfive2/Makefile b/board/starfive/visionfive2/Makefile index 66c854df390..c7ba4f7ed67 100644 --- a/board/starfive/visionfive2/Makefile +++ b/board/starfive/visionfive2/Makefile @@ -5,3 +5,4 @@ obj-y := starfive_visionfive2.o obj-$(CONFIG_SPL_BUILD) += spl.o +obj-$(CONFIG_ID_EEPROM) += visionfive2-i2c-eeprom.o diff --git a/board/starfive/visionfive2/visionfive2-i2c-eeprom.c b/board/starfive/visionfive2/visionfive2-i2c-eeprom.c new file mode 100644 index 00000000000..befe7888c40 --- /dev/null +++ b/board/starfive/visionfive2/visionfive2-i2c-eeprom.c @@ -0,0 +1,561 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: Yanhong Wang + */ + +#include +#include +#include +#include +#include +#include +#include + +#define FORMAT_VERSION 0x2 +#define PCB_VERSION 0xB1 +#define BOM_VERSION 'A' +/* + * BYTES_PER_EEPROM_PAGE: the 24FC04H datasheet says that data can + * only be written in page mode, which means 16 bytes at a time: + * 16-Byte Page Write Buffer + */ +#define BYTES_PER_EEPROM_PAGE 16 + +/* + * EEPROM_WRITE_DELAY_MS: the 24FC04H datasheet says it takes up to + * 5ms to complete a given write: + * Write Cycle Time (byte or page) ro Page Write Time 5 ms, Maximum + */ +#define EEPROM_WRITE_DELAY_MS 5000 +/* + * StarFive OUI. Registration Date is 20xx-xx-xx + */ +#define STARFIVE_OUI_PREFIX "6C:CF:39:" +#define STARFIVE_DEFAULT_MAC0 "6C:CF:39:6C:DE:AD" +#define STARFIVE_DEFAULT_MAC1 "6C:CF:39:6C:DE:AE" + +/* Magic number at the first four bytes of EEPROM HATs */ +#define STARFIVE_EEPROM_HATS_SIG "SFVF" /* StarFive VisionFive */ + +#define STARFIVE_EEPROM_HATS_SIZE_MAX 256 /* Header + Atom1&4(v1) */ +#define STARFIVE_EEPROM_WP_OFFSET 0 /* Read only field */ +#define STARFIVE_EEPROM_ATOM1_PSTR "VF7110A1-2228-D008E000-00000001\0" +#define STARFIVE_EEPROM_ATOM1_PSTR_SIZE 32 +#define STARFIVE_EEPROM_ATOM1_SN_OFFSET 23 +#define STARFIVE_EEPROM_ATOM1_VSTR "StarFive Technology Co., Ltd.\0\0\0" +#define STARFIVE_EEPROM_ATOM1_VSTR_SIZE 32 + +#define MAGIC_NUMBER_BYTES 4 +#define MAC_ADDR_BYTES 6 +#define MAC_ADDR_STRLEN 17 + +/* + * Atom Types + * 0x0000 = invalid + * 0x0001 = vendor info + * 0x0002 = GPIO map + * 0x0003 = Linux device tree blob + * 0x0004 = manufacturer custom data + * 0x0005-0xfffe = reserved for future use + * 0xffff = invalid + */ + +#define HATS_ATOM_INVALID 0x0000 +#define HATS_ATOM_VENDOR 0x0001 +#define HATS_ATOM_GPIO 0x0002 +#define HATS_ATOM_DTB 0x0003 +#define HATS_ATOM_CUSTOM 0x0004 +#define HATS_ATOM_INVALID_END 0xffff + +struct eeprom_header { + char signature[MAGIC_NUMBER_BYTES]; /* ASCII table signature */ + u8 version; /* EEPROM data format version */ + /* (0x00 reserved, 0x01 = first version) */ + u8 reversed; /* 0x00, Reserved field */ + u16 numatoms; /* total atoms in EEPROM */ + u32 eeplen; /* total length in bytes of all eeprom data */ + /* (including this header) */ +}; + +struct eeprom_atom_header { + u16 type; + u16 count; + u32 dlen; +}; + +struct eeprom_atom1_data { + u8 uuid[16]; + u16 pid; + u16 pver; + u8 vslen; + u8 pslen; + uchar vstr[STARFIVE_EEPROM_ATOM1_VSTR_SIZE]; + uchar pstr[STARFIVE_EEPROM_ATOM1_PSTR_SIZE]; /* product SN */ +}; + +struct starfive_eeprom_atom1 { + struct eeprom_atom_header header; + struct eeprom_atom1_data data; + u16 crc; +}; + +struct eeprom_atom4_data { + u16 version; + u8 pcb_revision; /* PCB version */ + u8 bom_revision; /* BOM version */ + u8 mac0_addr[MAC_ADDR_BYTES]; /* Ethernet0 MAC */ + u8 mac1_addr[MAC_ADDR_BYTES]; /* Ethernet1 MAC */ + u8 reserved[2]; +}; + +struct starfive_eeprom_atom4 { + struct eeprom_atom_header header; + struct eeprom_atom4_data data; + u16 crc; +}; + +struct starfive_eeprom { + struct eeprom_header header; + struct starfive_eeprom_atom1 atom1; + struct starfive_eeprom_atom4 atom4; +}; + +static union { + struct starfive_eeprom eeprom; + uchar buf[STARFIVE_EEPROM_HATS_SIZE_MAX]; +} pbuf __section(".data"); + +/* Set to 1 if we've read EEPROM into memory */ +static int has_been_read __section(".data"); + +static inline int is_match_magic(void) +{ + return strncmp(pbuf.eeprom.header.signature, STARFIVE_EEPROM_HATS_SIG, + MAGIC_NUMBER_BYTES); +} + +/* Calculate the current CRC */ +static inline u32 calculate_crc16(struct eeprom_atom_header *head) +{ + uint len = sizeof(struct eeprom_atom_header) + head->dlen - sizeof(u16); + + return crc16(0, (void *)head, len); +} + +/* This function should be called after each update to the EEPROM structure */ +static inline void update_crc(void) +{ + pbuf.eeprom.atom1.crc = calculate_crc16(&pbuf.eeprom.atom1.header); + pbuf.eeprom.atom4.crc = calculate_crc16(&pbuf.eeprom.atom4.header); +} + +static void dump_raw_eeprom(void) +{ + unsigned int i; + u32 len; + + len = sizeof(struct starfive_eeprom); + for (i = 0; i < len; i++) { + if ((i % 16) == 0) + printf("%02X: ", i); + printf("%02X ", ((u8 *)pbuf.buf)[i]); + if (((i % 16) == 15) || (i == len - 1)) + printf("\n"); + } +} + +/** + * show_eeprom - display the contents of the EEPROM + */ +static void show_eeprom(void) +{ + if (has_been_read != 1) + return; + + printf("\n--------EEPROM INFO--------\n"); + printf("Vendor : %s\n", pbuf.eeprom.atom1.data.vstr); + printf("Product full SN: %s\n", pbuf.eeprom.atom1.data.pstr); + printf("data version: 0x%x\n", pbuf.eeprom.atom4.data.version); + if (pbuf.eeprom.atom4.data.version == 2) { + printf("PCB revision: 0x%x\n", pbuf.eeprom.atom4.data.pcb_revision); + printf("BOM revision: %c\n", pbuf.eeprom.atom4.data.bom_revision); + printf("Ethernet MAC0 address: %02x:%02x:%02x:%02x:%02x:%02x\n", + pbuf.eeprom.atom4.data.mac0_addr[0], pbuf.eeprom.atom4.data.mac0_addr[1], + pbuf.eeprom.atom4.data.mac0_addr[2], pbuf.eeprom.atom4.data.mac0_addr[3], + pbuf.eeprom.atom4.data.mac0_addr[4], pbuf.eeprom.atom4.data.mac0_addr[5]); + printf("Ethernet MAC1 address: %02x:%02x:%02x:%02x:%02x:%02x\n", + pbuf.eeprom.atom4.data.mac1_addr[0], pbuf.eeprom.atom4.data.mac1_addr[1], + pbuf.eeprom.atom4.data.mac1_addr[2], pbuf.eeprom.atom4.data.mac1_addr[3], + pbuf.eeprom.atom4.data.mac1_addr[4], pbuf.eeprom.atom4.data.mac1_addr[5]); + } else { + printf("Custom data v%d is not Supported\n", pbuf.eeprom.atom4.data.version); + } + printf("--------EEPROM INFO--------\n\n"); +} + +/** + * set_mac_address() - stores a MAC address into the local EEPROM copy + * + * This function takes a pointer to MAC address string + * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number), + * stores it in the MAC address field of the EEPROM local copy, and + * updates the local copy of the CRC. + */ +static void set_mac_address(char *string, int index) +{ + u8 i; + u8 *mac; + + if (strncasecmp(STARFIVE_OUI_PREFIX, string, + strlen(STARFIVE_OUI_PREFIX))) { + printf("The MAC address doesn't match StarFive OUI %s\n", + STARFIVE_OUI_PREFIX); + return; + } + mac = (index == 0) ? pbuf.eeprom.atom4.data.mac0_addr : + pbuf.eeprom.atom4.data.mac1_addr; + + for (i = 0; *string && (i < MAC_ADDR_BYTES); i++) { + mac[i] = hextoul(string, &string); + + if (*string == ':') + string++; + } + + update_crc(); +} + +/** + * init_local_copy() - initialize the in-memory EEPROM copy + * + * Initialize the in-memory EEPROM copy with the magic number. Must + * be done when preparing to initialize a blank EEPROM, or overwrite + * one with a corrupted magic number. + */ +static void init_local_copy(void) +{ + memset((void *)pbuf.buf, 0, sizeof(struct starfive_eeprom)); + memcpy(pbuf.eeprom.header.signature, STARFIVE_EEPROM_HATS_SIG, + strlen(STARFIVE_EEPROM_HATS_SIG)); + pbuf.eeprom.header.version = FORMAT_VERSION; + pbuf.eeprom.header.numatoms = 2; + pbuf.eeprom.header.eeplen = sizeof(struct starfive_eeprom); + + pbuf.eeprom.atom1.header.type = HATS_ATOM_VENDOR; + pbuf.eeprom.atom1.header.count = 1; + pbuf.eeprom.atom1.header.dlen = sizeof(struct eeprom_atom1_data) + sizeof(u16); + pbuf.eeprom.atom1.data.vslen = STARFIVE_EEPROM_ATOM1_VSTR_SIZE; + pbuf.eeprom.atom1.data.pslen = STARFIVE_EEPROM_ATOM1_PSTR_SIZE; + memcpy(pbuf.eeprom.atom1.data.vstr, STARFIVE_EEPROM_ATOM1_VSTR, + strlen(STARFIVE_EEPROM_ATOM1_VSTR)); + memcpy(pbuf.eeprom.atom1.data.pstr, STARFIVE_EEPROM_ATOM1_PSTR, + strlen(STARFIVE_EEPROM_ATOM1_PSTR)); + + pbuf.eeprom.atom4.header.type = HATS_ATOM_CUSTOM; + pbuf.eeprom.atom4.header.count = 2; + pbuf.eeprom.atom4.header.dlen = sizeof(struct eeprom_atom4_data) + sizeof(u16); + pbuf.eeprom.atom4.data.version = FORMAT_VERSION; + pbuf.eeprom.atom4.data.pcb_revision = PCB_VERSION; + pbuf.eeprom.atom4.data.bom_revision = BOM_VERSION; + set_mac_address(STARFIVE_DEFAULT_MAC0, 0); + set_mac_address(STARFIVE_DEFAULT_MAC1, 1); +} + +/** + * prog_eeprom() - write the EEPROM from memory + */ +static int prog_eeprom(unsigned int size) +{ + unsigned int i; + void *p; + uchar tmp_buff[STARFIVE_EEPROM_HATS_SIZE_MAX]; + struct udevice *dev; + int ret; + + if (is_match_magic()) { + printf("MAGIC ERROR, Please check the data@%p.\n", pbuf.buf); + return -1; + } + + ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM, + CONFIG_SYS_I2C_EEPROM_ADDR, + CONFIG_SYS_I2C_EEPROM_ADDR_LEN, + &dev); + if (ret) { + printf("Get i2c bus:%d addr:%d fail.\n", CONFIG_SYS_EEPROM_BUS_NUM, + CONFIG_SYS_I2C_EEPROM_ADDR); + return ret; + } + + for (i = 0, p = (u8 *)pbuf.buf; i < size; ) { + if (!ret) + ret = dm_i2c_write(dev, i, p, min((int)(size - i), + BYTES_PER_EEPROM_PAGE)); + if (ret) + break; + + udelay(EEPROM_WRITE_DELAY_MS); + i += BYTES_PER_EEPROM_PAGE; + p += BYTES_PER_EEPROM_PAGE; + } + + if (!ret) { + /* Verify the write by reading back the EEPROM and comparing */ + ret = dm_i2c_read(dev, + STARFIVE_EEPROM_WP_OFFSET, + tmp_buff, + STARFIVE_EEPROM_HATS_SIZE_MAX); + if (!ret && memcmp((void *)pbuf.buf, (void *)tmp_buff, + STARFIVE_EEPROM_HATS_SIZE_MAX)) + ret = -1; + } + + if (ret) { + has_been_read = -1; + printf("Programming failed.\n"); + return -1; + } + + printf("Programming passed.\n"); + return 0; +} + +/** + * read_eeprom() - read the EEPROM into memory, if it hasn't been read already + */ +static int read_eeprom(void) +{ + int ret; + struct udevice *dev; + + if (has_been_read == 1) + return 0; + + ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM, + CONFIG_SYS_I2C_EEPROM_ADDR, 1, &dev); + if (!ret) + ret = dm_i2c_read(dev, 0, (u8 *)pbuf.buf, + STARFIVE_EEPROM_HATS_SIZE_MAX); + + has_been_read = (ret == 0) ? 1 : 0; + + return ret; +} + +/** + * set_pcb_revision() - stores a StarFive PCB revision into the local EEPROM copy + * + * Takes a pointer to a string representing the numeric PCB revision in + * decimal ("0" - "255"), stores it in the pcb_revision field of the + * EEPROM local copy, and updates the CRC of the local copy. + */ +static void set_pcb_revision(char *string) +{ + u32 p; + + p = simple_strtoul(string, &string, 16); + if (p > U8_MAX) { + printf("%s must not be greater than %d\n", "PCB revision", + U8_MAX); + return; + } + + pbuf.eeprom.atom4.data.pcb_revision = p; + + update_crc(); +} + +/** + * set_bom_revision() - stores a StarFive BOM revision into the local EEPROM copy + * + * Takes a pointer to a uppercase ASCII character representing the BOM + * revision ("A" - "Z"), stores it in the bom_revision field of the + * EEPROM local copy, and updates the CRC of the local copy. + */ +static void set_bom_revision(char *string) +{ + if (string[0] < 'A' || string[0] > 'Z') { + printf("BOM revision must be an uppercase letter between A and Z\n"); + return; + } + + pbuf.eeprom.atom4.data.bom_revision = string[0]; + + update_crc(); +} + +/** + * set_product_id() - stores a StarFive product ID into the local EEPROM copy + * + * Takes a pointer to a string representing the numeric product ID in + * string ("VF7100A1-2150-D008E000-00000001\0"), stores it in the product string + * field of the EEPROM local copy, and updates the CRC of the local copy. + */ +static void set_product_id(char *string) +{ + u32 len; + + len = (strlen(string) > STARFIVE_EEPROM_ATOM1_PSTR_SIZE) ? + STARFIVE_EEPROM_ATOM1_PSTR_SIZE : strlen(string); + + memcpy((void *)pbuf.eeprom.atom1.data.pstr, (void *)string, len); + + update_crc(); +} + +static int print_usage(void) +{ + printf("display and program the system ID and MAC addresses in EEPROM\n" + "[read_eeprom|initialize|write_eeprom|mac_address|pcb_revision|bom_revision|product_id]\n" + "mac read_eeprom\n" + " - read EEPROM content into memory data structure\n" + "mac write_eeprom\n" + " - save memory data structure to the EEPROM\n" + "mac initialize\n" + " - initialize the in-memory EEPROM copy with default data\n" + "mac mac0_address \n" + " - stores a MAC0 address into the local EEPROM copy\n" + "mac mac1_address \n" + " - stores a MAC1 address into the local EEPROM copy\n" + "mac pcb_revision \n" + " - stores a StarFive PCB revision into the local EEPROM copy\n" + "mac bom_revision \n" + " - stores a StarFive BOM revision into the local EEPROM copy\n" + "mac product_id \n" + " - stores a StarFive product ID into the local EEPROM copy\n"); + return 0; +} + +int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + char *cmd; + + if (argc == 1) { + show_eeprom(); + return 0; + } + + if (argc > 3) + return print_usage(); + + cmd = argv[1]; + + /* Commands with no argument */ + if (!strcmp(cmd, "read_eeprom")) { + has_been_read = 0; + return read_eeprom(); + } else if (!strcmp(cmd, "initialize")) { + init_local_copy(); + return 0; + } else if (!strcmp(cmd, "write_eeprom")) { + return prog_eeprom(STARFIVE_EEPROM_HATS_SIZE_MAX); + } + + if (argc != 3) + return print_usage(); + + if (is_match_magic()) { + printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n"); + return 0; + } + + if (!strcmp(cmd, "mac0_address")) { + set_mac_address(argv[2], 0); + return 0; + } else if (!strcmp(cmd, "mac1_address")) { + set_mac_address(argv[2], 1); + return 0; + } else if (!strcmp(cmd, "pcb_revision")) { + set_pcb_revision(argv[2]); + return 0; + } else if (!strcmp(cmd, "bom_revision")) { + set_bom_revision(argv[2]); + return 0; + } else if (!strcmp(cmd, "product_id")) { + set_product_id(argv[2]); + return 0; + } + + return print_usage(); +} + +/** + * mac_read_from_eeprom() - read the MAC address & the serial number in EEPROM + * + * This function reads the MAC address and the serial number from EEPROM and + * sets the appropriate environment variables for each one read. + * + * The environment variables are only set if they haven't been set already. + * This ensures that any user-saved variables are never overwritten. + * + * If CONFIG_ID_EEPROM is enabled, this function will be called in + * "static init_fnc_t init_sequence_r[]" of u-boot/common/board_r.c. + */ +int mac_read_from_eeprom(void) +{ + /** + * try to fill the buff from EEPROM, + * always return SUCCESS, even some error happens. + */ + if (read_eeprom()) { + dump_raw_eeprom(); + return 0; + } + + // 1, setup ethaddr env + eth_env_set_enetaddr("eth0addr", pbuf.eeprom.atom4.data.mac0_addr); + eth_env_set_enetaddr("eth1addr", pbuf.eeprom.atom4.data.mac1_addr); + + /** + * 2, setup serial# env, reference to hifive-platform-i2c-eeprom.c, + * serial# can be a ASCII string, but not just a hex number, so we + * setup serial# in the 32Byte format: + * "VF7100A1-2201-D008E000-00000001;" + * "---" + * : 4Byte, should be the output of `date +%y%W` + * : 8Byte, "D008" means 8GB, "D01T" means 1TB; + * "E000" means no eMMC,"E032" means 32GB, "E01T" means 1TB. + * : 8Byte, the Unique Identifier of board in hex. + */ + if (!env_get("serial#")) + env_set("serial#", pbuf.eeprom.atom1.data.pstr); + + printf("StarFive EEPROM format v%u\n", pbuf.eeprom.header.version); + show_eeprom(); + return 0; +} + +/** + * get_pcb_revision_from_eeprom - get the PCB revision + * + * 1.2A return 'A'/'a', 1.3B return 'B'/'b',other values are illegal + */ +u8 get_pcb_revision_from_eeprom(void) +{ + u8 pv = 0xFF; + + if (read_eeprom()) + return pv; + + return pbuf.eeprom.atom1.data.pstr[6]; +} + +/** + * get_ddr_size_from_eeprom - get the DDR size + * pstr: VF7110A1-2228-D008E000-00000001 + * VF7110A1/VF7110B1 : VisionFive JH7110A /VisionFive JH7110B + * D008: 8GB LPDDR4 + * E000: No emmc device, ECxx: include emmc device, xx: Capacity size[GB] + * return: the field of 'D008E000' + */ + +u32 get_ddr_size_from_eeprom(void) +{ + u32 pv = 0xFFFFFFFF; + + if (read_eeprom()) + return pv; + + return hextoul(&pbuf.eeprom.atom1.data.pstr[14], NULL); +} From 3421a45fdaed3ae243ea5852bc22ba643c94fa9d Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:49 +0800 Subject: [PATCH 08/18] riscv: dts: starfive: Add support eeprom device tree node Add support "atmel,24c04" eeprom for StarFive VisionFive2 board. Signed-off-by: Yanhong Wang Reviewed-by: Leo Yu-Chi Liang --- .../dts/jh7110-starfive-visionfive-2-u-boot.dtsi | 14 ++++++++++++++ arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi b/arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi index 2afcec30b87..13f69da31ec 100644 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi +++ b/arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi @@ -67,6 +67,20 @@ }; }; +&i2c5_pins { + bootph-pre-ram; + i2c-pins { + bootph-pre-ram; + }; +}; + +&i2c5 { + bootph-pre-ram; + eeprom@50 { + bootph-pre-ram; + }; +}; + &binman { itb { fit { diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi index 3c1148ae2d4..710b082766d 100644 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi @@ -120,6 +120,12 @@ pinctrl-names = "default"; pinctrl-0 = <&i2c5_pins>; status = "okay"; + + eeprom@50 { + compatible = "atmel,24c04"; + reg = <0x50>; + pagesize = <16>; + }; }; &i2c6 { From 99f3a43d1cbc9abe14839734bb35444c1633f836 Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:50 +0800 Subject: [PATCH 09/18] configs: starfive: Enable ID EEPROM configuration Enabled ID_EEPROM and I2C configuration for StarFive VisionFive2 board. Signed-off-by: Yanhong Wang Reviewed-By: Leo Yu-Chi Linag --- .../visionfive2/starfive_visionfive2.c | 13 +++++++++++++ configs/starfive_visionfive2_defconfig | 19 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/board/starfive/visionfive2/starfive_visionfive2.c b/board/starfive/visionfive2/starfive_visionfive2.c index 613fe793c43..07dcca26b30 100644 --- a/board/starfive/visionfive2/starfive_visionfive2.c +++ b/board/starfive/visionfive2/starfive_visionfive2.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #define JH7110_L2_PREFETCHER_BASE_ADDR 0x2030000 @@ -38,3 +40,14 @@ int board_init(void) return 0; } + +void *board_fdt_blob_setup(int *err) +{ + *err = 0; + if (IS_ENABLED(CONFIG_OF_SEPARATE) || IS_ENABLED(CONFIG_OF_BOARD)) { + if (gd->arch.firmware_fdt_addr) + return (ulong *)(uintptr_t)gd->arch.firmware_fdt_addr; + } + + return (ulong *)&_end; +} diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index c57708199d7..570a1f53a19 100644 --- a/configs/starfive_visionfive2_defconfig +++ b/configs/starfive_visionfive2_defconfig @@ -13,6 +13,7 @@ CONFIG_SYS_PROMPT="StarFive #" CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_DM_RESET=y CONFIG_SPL_MMC=y +CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_STACK=0x8180000 CONFIG_SPL=y CONFIG_SPL_SPI_FLASH_SUPPORT=y @@ -23,6 +24,7 @@ CONFIG_SPL_OPENSBI_LOAD_ADDR=0x40000000 CONFIG_ARCH_RV64I=y CONFIG_CMODEL_MEDANY=y CONFIG_RISCV_SMODE=y +# CONFIG_OF_BOARD_FIXUP is not set CONFIG_FIT=y CONFIG_DISTRO_DEFAULTS=y CONFIG_QSPI_BOOT=y @@ -34,6 +36,8 @@ CONFIG_PREBOOT="setenv fdt_addr ${fdtcontroladdr};fdt addr ${fdtcontroladdr};" CONFIG_DEFAULT_FDT_FILE="starfive/jh7110-starfive-visionfive-2.dtb" CONFIG_DISPLAY_CPUINFO=y CONFIG_DISPLAY_BOARDINFO=y +CONFIG_ID_EEPROM=y +CONFIG_SYS_EEPROM_BUS_NUM=5 CONFIG_SPL_MAX_SIZE=0x40000 CONFIG_SPL_PAD_TO=0x0 CONFIG_SPL_BSS_START_ADDR=0x8040000 @@ -45,21 +49,34 @@ CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x80000000 CONFIG_SYS_SPL_MALLOC_SIZE=0x400000 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=0x2 +CONFIG_SPL_I2C=y CONFIG_SPL_DM_SPI_FLASH=y CONFIG_SPL_DM_RESET=y CONFIG_SPL_SPI_LOAD=y CONFIG_SYS_CBSIZE=256 CONFIG_SYS_PBSIZE=276 CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_CMD_EEPROM=y +CONFIG_SYS_EEPROM_SIZE=512 +CONFIG_SYS_EEPROM_PAGE_WRITE_BITS=4 +CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS=5 CONFIG_CMD_MEMINFO=y +CONFIG_CMD_I2C=y CONFIG_CMD_TFTPPUT=y +CONFIG_OF_BOARD=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_SPL_DM_SEQ_ALIAS=y CONFIG_REGMAP=y CONFIG_SYSCON=y CONFIG_SPL_CLK_COMPOSITE_CCF=y CONFIG_CLK_COMPOSITE_CCF=y CONFIG_SPL_CLK_JH7110=y -# CONFIG_I2C is not set +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_DW=y +CONFIG_MISC=y +CONFIG_I2C_EEPROM=y +CONFIG_SPL_I2C_EEPROM=y +CONFIG_SYS_I2C_EEPROM_ADDR=0X50 CONFIG_MMC_HS400_SUPPORT=y CONFIG_SPL_MMC_HS400_SUPPORT=y CONFIG_MMC_DW=y From 38d900b409199df02a1a26dfcb464d4d2b6e27d2 Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:51 +0800 Subject: [PATCH 10/18] ram: starfive: Read memory size information from EEPROM StarFive VisionFive 2 has two versions, 1.2A and 1.3B, each version of DDR capacity includes 2G/4G/8G, a DT can not support multiple capacities, so the capacity size information is recorded to EEPROM, when DDR initialization required capacity size information is read from EEPROM. If there is no information in EEPROM, it is initialized with the default size defined in DT. Signed-off-by: Yanhong Wang Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/cpu/jh7110/spl.c | 32 ++++++++++++++++++++++++++++- drivers/ram/starfive/starfive_ddr.c | 2 -- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/arch/riscv/cpu/jh7110/spl.c b/arch/riscv/cpu/jh7110/spl.c index 104f0fe9497..72adcefa0e9 100644 --- a/arch/riscv/cpu/jh7110/spl.c +++ b/arch/riscv/cpu/jh7110/spl.c @@ -3,19 +3,49 @@ * Copyright (C) 2022 StarFive Technology Co., Ltd. * Author: Yanhong Wang */ - +#include +#include #include #include #include +#include #include +#include #define CSR_U74_FEATURE_DISABLE 0x7c1 #define L2_LIM_MEM_END 0x81FFFFFUL +DECLARE_GLOBAL_DATA_PTR; + +static bool check_ddr_size(phys_size_t size) +{ + switch (size) { + case SZ_2: + case SZ_4: + case SZ_8: + case SZ_16: + return true; + default: + return false; + } +} + int spl_soc_init(void) { int ret; struct udevice *dev; + phys_size_t size; + + ret = fdtdec_setup_mem_size_base(); + if (ret) + return ret; + + /* Read the definition of the DDR size from eeprom, and if not, + * use the definition in DT + */ + size = (get_ddr_size_from_eeprom() >> 16) & 0xFF; + if (check_ddr_size(size)) + gd->ram_size = size << 30; /* DDR init */ ret = uclass_get_device(UCLASS_RAM, 0, &dev); diff --git a/drivers/ram/starfive/starfive_ddr.c b/drivers/ram/starfive/starfive_ddr.c index 553f2ce6f44..a0a3d6b33dc 100644 --- a/drivers/ram/starfive/starfive_ddr.c +++ b/drivers/ram/starfive/starfive_ddr.c @@ -72,8 +72,6 @@ static int starfive_ddr_probe(struct udevice *dev) u64 rate; int ret; - /* Read memory base and size from DT */ - fdtdec_setup_mem_size_base(); priv->info.base = gd->ram_base; priv->info.size = gd->ram_size; From c9745365f516a361be9cbe3568d2b8608084bbbf Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Thu, 15 Jun 2023 17:36:52 +0800 Subject: [PATCH 11/18] board: starfive: Dynamic configuration of DT for 1.2A and 1.3B The main difference between StarFive VisionFive 2 1.2A and 1.3B is gmac. You can read the PCB version of the current board by get_pcb_revision_from_eeprom(), and then dynamically configure the difference of gmac in spl_perform_fixups() according to different PCB versions, so that one DT and one defconfig can support both 1.2A and 1.3B versions, which is more user-friendly. Signed-off-by: Yanhong Wang Reviewed-by: Rick Chen --- board/starfive/visionfive2/spl.c | 157 +++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c index db0b4cb4335..7acd3995aad 100644 --- a/board/starfive/visionfive2/spl.c +++ b/board/starfive/visionfive2/spl.c @@ -5,16 +5,173 @@ */ #include +#include #include #include #include +#include +#include +#include #include #include +DECLARE_GLOBAL_DATA_PTR; #define JH7110_CLK_CPU_ROOT_OFFSET 0x0U #define JH7110_CLK_CPU_ROOT_SHIFT 24 #define JH7110_CLK_CPU_ROOT_MASK GENMASK(29, 24) +struct starfive_vf2_pro { + const char *path; + const char *name; + const char *value; +}; + +static const struct starfive_vf2_pro starfive_vera[] = { + {"/soc/ethernet@16030000/mdio/ethernet-phy@0", "rx-internal-delay-ps", + "1900"}, + {"/soc/ethernet@16030000/mdio/ethernet-phy@0", "tx-internal-delay-ps", + "1350"} +}; + +static const struct starfive_vf2_pro starfive_verb[] = { + {"/soc/ethernet@16030000", "starfive,tx-use-rgmii-clk", NULL}, + {"/soc/ethernet@16040000", "starfive,tx-use-rgmii-clk", NULL}, + + {"/soc/ethernet@16030000/mdio/ethernet-phy@0", + "motorcomm,tx-clk-adj-enabled", NULL}, + {"/soc/ethernet@16030000/mdio/ethernet-phy@0", + "motorcomm,tx-clk-100-inverted", NULL}, + {"/soc/ethernet@16030000/mdio/ethernet-phy@0", + "motorcomm,tx-clk-1000-inverted", NULL}, + {"/soc/ethernet@16030000/mdio/ethernet-phy@0", + "rx-internal-delay-ps", "1900"}, + {"/soc/ethernet@16030000/mdio/ethernet-phy@0", + "tx-internal-delay-ps", "1500"}, + + {"/soc/ethernet@16040000/mdio/ethernet-phy@1", + "motorcomm,tx-clk-adj-enabled", NULL}, + { "/soc/ethernet@16040000/mdio/ethernet-phy@1", + "motorcomm,tx-clk-100-inverted", NULL}, + {"/soc/ethernet@16040000/mdio/ethernet-phy@1", + "rx-internal-delay-ps", "0"}, + {"/soc/ethernet@16040000/mdio/ethernet-phy@1", + "tx-internal-delay-ps", "0"}, +}; + +void spl_fdt_fixup_version_a(void *fdt) +{ + u32 phandle; + u8 i; + int offset; + int ret; + + fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", + "StarFive VisionFive 2 v1.2A"); + + offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000"); + phandle = fdt_get_phandle(fdt, offset); + offset = fdt_path_offset(fdt, "/soc/ethernet@16040000"); + + fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX); + fdt_appendprop_u32(fdt, offset, "assigned-clocks", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_RX); + + fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", + JH7110_SYSCLK_GMAC1_RMII_RTX); + fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", + JH7110_SYSCLK_GMAC1_RMII_RTX); + + fdt_setprop_string(fdt, fdt_path_offset(fdt, "/soc/ethernet@16040000"), + "phy-mode", "rmii"); + + for (i = 0; i < ARRAY_SIZE(starfive_vera); i++) { + offset = fdt_path_offset(fdt, starfive_vera[i].path); + + if (starfive_vera[i].value) + ret = fdt_setprop_u32(fdt, offset, starfive_vera[i].name, + dectoul(starfive_vera[i].value, NULL)); + else + ret = fdt_setprop_empty(fdt, offset, starfive_vera[i].name); + + if (ret) { + pr_err("%s set prop %s fail.\n", __func__, starfive_vera[i].name); + break; + } + } +} + +void spl_fdt_fixup_version_b(void *fdt) +{ + u32 phandle; + u8 i; + int offset; + int ret; + + fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", + "StarFive VisionFive 2 v1.3B"); + + /* gmac0 */ + offset = fdt_path_offset(fdt, "/soc/clock-controller@17000000"); + phandle = fdt_get_phandle(fdt, offset); + offset = fdt_path_offset(fdt, "/soc/ethernet@16030000"); + + fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_AONCLK_GMAC0_TX); + fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", + JH7110_AONCLK_GMAC0_RMII_RTX); + + /* gmac1 */ + offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000"); + phandle = fdt_get_phandle(fdt, offset); + offset = fdt_path_offset(fdt, "/soc/ethernet@16040000"); + + fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX); + fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle); + fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", + JH7110_SYSCLK_GMAC1_RMII_RTX); + + for (i = 0; i < ARRAY_SIZE(starfive_verb); i++) { + offset = fdt_path_offset(fdt, starfive_verb[i].path); + + if (starfive_verb[i].value) + ret = fdt_setprop_u32(fdt, offset, starfive_verb[i].name, + dectoul(starfive_verb[i].value, NULL)); + else + ret = fdt_setprop_empty(fdt, offset, starfive_verb[i].name); + + if (ret) { + pr_err("%s set prop %s fail.\n", __func__, starfive_verb[i].name); + break; + } + } +} + +void spl_perform_fixups(struct spl_image_info *spl_image) +{ + u8 version; + + version = get_pcb_revision_from_eeprom(); + switch (version) { + case 'a': + case 'A': + spl_fdt_fixup_version_a(spl_image->fdt_addr); + break; + + case 'b': + case 'B': + default: + spl_fdt_fixup_version_b(spl_image->fdt_addr); + break; + }; + + /* Update the memory size which read form eeprom or DT */ + fdt_fixup_memory(spl_image->fdt_addr, 0x40000000, gd->ram_size); +} int spl_board_init_f(void) { int ret; From 5764acb2617658af76c25285685e791ce6d0b051 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 21 Jun 2023 23:11:44 +0800 Subject: [PATCH 12/18] riscv: timer: Update the sifive clint timer driver to support aclint This RISC-V ACLINT specification [1] defines a set of memory mapped devices which provide inter-processor interrupts (IPI) and timer functionalities for each HART on a multi-HART RISC-V platform. The RISC-V ACLINT specification is defined to be backward compatible with the SiFive CLINT specification, however the device tree binding is a new one. This change updates the sifive clint timer driver to support ACLINT mtimer device, using a per-driver data field to hold the mtimer offset to the base address encoded in the mtimer node. [1] https://github.com/riscv/riscv-aclint/blob/main/riscv-aclint.adoc Signed-off-by: Bin Meng Reviewed-by: Rick Chen --- drivers/timer/sifive_clint_timer.c | 16 +++++++++++----- include/configs/qemu-riscv.h | 2 +- include/configs/sifive-unleashed.h | 2 +- include/configs/starfive-visionfive2.h | 1 + 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/timer/sifive_clint_timer.c b/drivers/timer/sifive_clint_timer.c index 939b99d937d..be45f17ddfb 100644 --- a/drivers/timer/sifive_clint_timer.c +++ b/drivers/timer/sifive_clint_timer.c @@ -12,12 +12,16 @@ #include #include +#define CLINT_MTIME_OFFSET 0xbff8 +#define ACLINT_MTIME_OFFSET 0 + /* mtime register */ -#define MTIME_REG(base) ((ulong)(base) + 0xbff8) +#define MTIME_REG(base, offset) ((ulong)(base) + (offset)) static u64 notrace sifive_clint_get_count(struct udevice *dev) { - return readq((void __iomem *)MTIME_REG(dev_get_priv(dev))); + return readq((void __iomem *)MTIME_REG(dev_get_priv(dev), + dev_get_driver_data(dev))); } #if CONFIG_IS_ENABLED(RISCV_MMODE) && IS_ENABLED(CONFIG_TIMER_EARLY) @@ -35,7 +39,8 @@ unsigned long notrace timer_early_get_rate(void) */ u64 notrace timer_early_get_count(void) { - return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE)); + return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE, + RISCV_MMODE_TIMEROFF)); } #endif @@ -53,8 +58,9 @@ static int sifive_clint_probe(struct udevice *dev) } static const struct udevice_id sifive_clint_ids[] = { - { .compatible = "riscv,clint0" }, - { .compatible = "sifive,clint0" }, + { .compatible = "riscv,clint0", .data = CLINT_MTIME_OFFSET }, + { .compatible = "sifive,clint0", .data = CLINT_MTIME_OFFSET }, + { .compatible = "riscv,aclint-mtimer", .data = ACLINT_MTIME_OFFSET }, { } }; diff --git a/include/configs/qemu-riscv.h b/include/configs/qemu-riscv.h index 20135f569eb..f6d326bda0d 100644 --- a/include/configs/qemu-riscv.h +++ b/include/configs/qemu-riscv.h @@ -11,8 +11,8 @@ #define CFG_SYS_SDRAM_BASE 0x80000000 #define RISCV_MMODE_TIMERBASE 0x2000000 +#define RISCV_MMODE_TIMEROFF 0xbff8 #define RISCV_MMODE_TIMER_FREQ 1000000 - #define RISCV_SMODE_TIMER_FREQ 1000000 /* Environment options */ diff --git a/include/configs/sifive-unleashed.h b/include/configs/sifive-unleashed.h index de3a0dcdd59..f208f5e20db 100644 --- a/include/configs/sifive-unleashed.h +++ b/include/configs/sifive-unleashed.h @@ -14,8 +14,8 @@ #define CFG_SYS_SDRAM_BASE 0x80000000 #define RISCV_MMODE_TIMERBASE 0x2000000 +#define RISCV_MMODE_TIMEROFF 0xbff8 #define RISCV_MMODE_TIMER_FREQ 1000000 - #define RISCV_SMODE_TIMER_FREQ 1000000 /* Environment options */ diff --git a/include/configs/starfive-visionfive2.h b/include/configs/starfive-visionfive2.h index 93dcc22d366..4ee02b8420f 100644 --- a/include/configs/starfive-visionfive2.h +++ b/include/configs/starfive-visionfive2.h @@ -9,6 +9,7 @@ #define _STARFIVE_VISIONFIVE2_H #define RISCV_MMODE_TIMERBASE 0x2000000 +#define RISCV_MMODE_TIMEROFF 0xbff8 #define RISCV_MMODE_TIMER_FREQ 4000000 #define RISCV_SMODE_TIMER_FREQ 4000000 From 7f1a30fdeb6b51ddeb8ca8ecbfcc8069721db186 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 21 Jun 2023 23:11:45 +0800 Subject: [PATCH 13/18] riscv: clint: Update the sifive clint ipi driver to support aclint This RISC-V ACLINT specification [1] defines a set of memory mapped devices which provide inter-processor interrupts (IPI) and timer functionalities for each HART on a multi-HART RISC-V platform. The RISC-V ACLINT specification is defined to be backward compatible with the SiFive CLINT specification, however the device tree binding is a new one. This change updates the sifive clint ipi driver to support ACLINT mswi device, by checking the per-driver data field of the ACLINT mtimer driver to determine whether a syscon based approach needs to be taken to get the base address of the ACLINT mswi device. [1] https://github.com/riscv/riscv-aclint/blob/main/riscv-aclint.adoc Signed-off-by: Bin Meng Reviewed-by: Rick Chen --- arch/riscv/Kconfig | 4 ++++ arch/riscv/lib/sifive_clint.c | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index f6ed05906a2..9fcdd8c451c 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -188,6 +188,8 @@ config DMA_ADDR_T_64BIT config SIFIVE_CLINT bool depends on RISCV_MMODE + select REGMAP + select SYSCON help The SiFive CLINT block holds memory-mapped control and status registers associated with software and timer interrupts. @@ -195,6 +197,8 @@ config SIFIVE_CLINT config SPL_SIFIVE_CLINT bool depends on SPL_RISCV_MMODE + select SPL_REGMAP + select SPL_SYSCON help The SiFive CLINT block holds memory-mapped control and status registers associated with software and timer interrupts. diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c index ab22395c552..f2421683812 100644 --- a/arch/riscv/lib/sifive_clint.c +++ b/arch/riscv/lib/sifive_clint.c @@ -10,9 +10,12 @@ #include #include +#include +#include #include #include #include +#include #include /* MSIP registers */ @@ -30,7 +33,11 @@ int riscv_init_ipi(void) if (ret) return ret; - gd->arch.clint = dev_read_addr_ptr(dev); + if (dev_get_driver_data(dev) != 0) + gd->arch.clint = dev_read_addr_ptr(dev); + else + gd->arch.clint = syscon_get_first_range(RISCV_SYSCON_CLINT); + if (!gd->arch.clint) return -EINVAL; @@ -57,3 +64,15 @@ int riscv_get_ipi(int hart, int *pending) return 0; } + +static const struct udevice_id riscv_aclint_swi_ids[] = { + { .compatible = "riscv,aclint-mswi", .data = RISCV_SYSCON_CLINT }, + { } +}; + +U_BOOT_DRIVER(riscv_aclint_swi) = { + .name = "riscv_aclint_swi", + .id = UCLASS_SYSCON, + .of_match = riscv_aclint_swi_ids, + .flags = DM_FLAG_PRE_RELOC, +}; From 9675d9202780fd996c00ad34f0360c89376205b3 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 21 Jun 2023 23:11:46 +0800 Subject: [PATCH 14/18] riscv: Rename SiFive CLINT to RISC-V ALINT As the RISC-V ACLINT specification is defined to be backward compatible with the SiFive CLINT specification, we rename SiFive CLINT to RISC-V ALINT in the source tree to be future-proof. Signed-off-by: Bin Meng Reviewed-by: Rick Chen --- MAINTAINERS | 2 +- arch/riscv/Kconfig | 8 ++++---- arch/riscv/cpu/fu540/Kconfig | 2 +- arch/riscv/cpu/fu740/Kconfig | 2 +- arch/riscv/cpu/generic/Kconfig | 4 ++-- arch/riscv/cpu/jh7110/Kconfig | 2 +- arch/riscv/include/asm/global_data.h | 4 ++-- arch/riscv/include/asm/syscon.h | 2 +- arch/riscv/lib/Makefile | 2 +- .../lib/{sifive_clint.c => aclint_ipi.c} | 16 +++++++-------- board/openpiton/riscv64/Kconfig | 2 +- board/sipeed/maix/Kconfig | 2 +- drivers/timer/Makefile | 2 +- ...ive_clint_timer.c => riscv_aclint_timer.c} | 20 +++++++++---------- 14 files changed, 35 insertions(+), 35 deletions(-) rename arch/riscv/lib/{sifive_clint.c => aclint_ipi.c} (73%) rename drivers/timer/{sifive_clint_timer.c => riscv_aclint_timer.c} (75%) diff --git a/MAINTAINERS b/MAINTAINERS index 2477923a520..87991cccddb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1330,7 +1330,7 @@ F: doc/arch/riscv.rst F: doc/usage/sbi.rst F: drivers/sysreset/sysreset_sbi.c F: drivers/timer/andes_plmt_timer.c -F: drivers/timer/sifive_clint_timer.c +F: drivers/timer/riscv_aclint_timer.c F: tools/prelink-riscv.c RISC-V CANAAN KENDRYTE K210 diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 9fcdd8c451c..de7d5a95492 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -185,22 +185,22 @@ config DMA_ADDR_T_64BIT bool default y if 64BIT -config SIFIVE_CLINT +config RISCV_ACLINT bool depends on RISCV_MMODE select REGMAP select SYSCON help - The SiFive CLINT block holds memory-mapped control and status registers + The RISC-V ACLINT block holds memory-mapped control and status registers associated with software and timer interrupts. -config SPL_SIFIVE_CLINT +config SPL_RISCV_ACLINT bool depends on SPL_RISCV_MMODE select SPL_REGMAP select SPL_SYSCON help - The SiFive CLINT block holds memory-mapped control and status registers + The RISC-V ACLINT block holds memory-mapped control and status registers associated with software and timer interrupts. config SIFIVE_CACHE diff --git a/arch/riscv/cpu/fu540/Kconfig b/arch/riscv/cpu/fu540/Kconfig index 1604b412b48..c68209d8fb2 100644 --- a/arch/riscv/cpu/fu540/Kconfig +++ b/arch/riscv/cpu/fu540/Kconfig @@ -11,7 +11,7 @@ config SIFIVE_FU540 imply CPU imply CPU_RISCV imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) - imply SPL_SIFIVE_CLINT + imply SPL_RISCV_ACLINT imply CMD_CPU imply SPL_CPU imply SPL_OPENSBI diff --git a/arch/riscv/cpu/fu740/Kconfig b/arch/riscv/cpu/fu740/Kconfig index 3e0c1fddc88..d7ca9687171 100644 --- a/arch/riscv/cpu/fu740/Kconfig +++ b/arch/riscv/cpu/fu740/Kconfig @@ -11,7 +11,7 @@ config SIFIVE_FU740 imply CPU imply CPU_RISCV imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) - imply SPL_SIFIVE_CLINT + imply SPL_RISCV_ACLINT imply CMD_CPU imply SPL_CPU imply SPL_OPENSBI diff --git a/arch/riscv/cpu/generic/Kconfig b/arch/riscv/cpu/generic/Kconfig index e025134b23c..897765c3c68 100644 --- a/arch/riscv/cpu/generic/Kconfig +++ b/arch/riscv/cpu/generic/Kconfig @@ -9,8 +9,8 @@ config GENERIC_RISCV imply CPU imply CPU_RISCV imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) - imply SIFIVE_CLINT if RISCV_MMODE - imply SPL_SIFIVE_CLINT if SPL_RISCV_MMODE + imply RISCV_ACLINT if RISCV_MMODE + imply SPL_RISCV_ACLINT if SPL_RISCV_MMODE imply CMD_CPU imply SPL_CPU imply SPL_OPENSBI diff --git a/arch/riscv/cpu/jh7110/Kconfig b/arch/riscv/cpu/jh7110/Kconfig index 3f145415eb9..4d9581165bf 100644 --- a/arch/riscv/cpu/jh7110/Kconfig +++ b/arch/riscv/cpu/jh7110/Kconfig @@ -25,4 +25,4 @@ config STARFIVE_JH7110 imply SPL_CPU imply SPL_LOAD_FIT imply SPL_OPENSBI - imply SPL_SIFIVE_CLINT + imply SPL_RISCV_ACLINT diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index 31ba72693d7..9d97517e124 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -18,8 +18,8 @@ struct arch_global_data { long boot_hart; /* boot hart id */ phys_addr_t firmware_fdt_addr; -#if CONFIG_IS_ENABLED(SIFIVE_CLINT) - void __iomem *clint; /* clint base address */ +#if CONFIG_IS_ENABLED(RISCV_ACLINT) + void __iomem *aclint; /* aclint base address */ #endif #ifdef CONFIG_ANDES_PLICSW void __iomem *plicsw; /* andes plicsw base address */ diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h index f2b37975f37..5787702e746 100644 --- a/arch/riscv/include/asm/syscon.h +++ b/arch/riscv/include/asm/syscon.h @@ -12,7 +12,7 @@ */ enum { RISCV_NONE, - RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */ + RISCV_SYSCON_ACLINT, /* Advanced Core Local Interruptor (ACLINT) */ RISCV_SYSCON_PLICSW, /* Andes PLICSW */ }; diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index e5a81ba7223..02c4d8fcc6c 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_CMD_GO) += boot.o obj-y += cache.o obj-$(CONFIG_SIFIVE_CACHE) += sifive_cache.o ifeq ($(CONFIG_$(SPL_)RISCV_MMODE),y) -obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint.o +obj-$(CONFIG_$(SPL_)RISCV_ACLINT) += aclint_ipi.o obj-$(CONFIG_ANDES_PLICSW) += andes_plicsw.o else obj-$(CONFIG_SBI) += sbi.o diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/aclint_ipi.c similarity index 73% rename from arch/riscv/lib/sifive_clint.c rename to arch/riscv/lib/aclint_ipi.c index f2421683812..90b8e128cb1 100644 --- a/arch/riscv/lib/sifive_clint.c +++ b/arch/riscv/lib/aclint_ipi.c @@ -29,16 +29,16 @@ int riscv_init_ipi(void) struct udevice *dev; ret = uclass_get_device_by_driver(UCLASS_TIMER, - DM_DRIVER_GET(sifive_clint), &dev); + DM_DRIVER_GET(riscv_aclint_timer), &dev); if (ret) return ret; if (dev_get_driver_data(dev) != 0) - gd->arch.clint = dev_read_addr_ptr(dev); + gd->arch.aclint = dev_read_addr_ptr(dev); else - gd->arch.clint = syscon_get_first_range(RISCV_SYSCON_CLINT); + gd->arch.aclint = syscon_get_first_range(RISCV_SYSCON_ACLINT); - if (!gd->arch.clint) + if (!gd->arch.aclint) return -EINVAL; return 0; @@ -46,27 +46,27 @@ int riscv_init_ipi(void) int riscv_send_ipi(int hart) { - writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); + writel(1, (void __iomem *)MSIP_REG(gd->arch.aclint, hart)); return 0; } int riscv_clear_ipi(int hart) { - writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart)); + writel(0, (void __iomem *)MSIP_REG(gd->arch.aclint, hart)); return 0; } int riscv_get_ipi(int hart, int *pending) { - *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart)); + *pending = readl((void __iomem *)MSIP_REG(gd->arch.aclint, hart)); return 0; } static const struct udevice_id riscv_aclint_swi_ids[] = { - { .compatible = "riscv,aclint-mswi", .data = RISCV_SYSCON_CLINT }, + { .compatible = "riscv,aclint-mswi", .data = RISCV_SYSCON_ACLINT }, { } }; diff --git a/board/openpiton/riscv64/Kconfig b/board/openpiton/riscv64/Kconfig index eb0db8a64c8..21da1dc346d 100644 --- a/board/openpiton/riscv64/Kconfig +++ b/board/openpiton/riscv64/Kconfig @@ -29,7 +29,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy select SUPPORT_SPL imply CPU_RISCV imply RISCV_TIMER - imply SPL_SIFIVE_CLINT + imply SPL_RISCV_ACLINT imply CMD_CPU imply SPL_CPU_SUPPORT imply SPL_SMP diff --git a/board/sipeed/maix/Kconfig b/board/sipeed/maix/Kconfig index 2d212ec5a34..d34ea4be71f 100644 --- a/board/sipeed/maix/Kconfig +++ b/board/sipeed/maix/Kconfig @@ -34,7 +34,7 @@ config BOARD_SPECIFIC_OPTIONS imply SMP imply DM_SERIAL imply SIFIVE_SERIAL - imply SIFIVE_CLINT + imply RISCV_ACLINT imply POWER_DOMAIN imply SIMPLE_PM_BUS imply CLK_K210 diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index cdc20f5e946..1ca74805fd9 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o obj-$(CONFIG_SP804_TIMER) += sp804_timer.o -obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint_timer.o +obj-$(CONFIG_$(SPL_)RISCV_ACLINT) += riscv_aclint_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_TEGRA_TIMER) += tegra-timer.o diff --git a/drivers/timer/sifive_clint_timer.c b/drivers/timer/riscv_aclint_timer.c similarity index 75% rename from drivers/timer/sifive_clint_timer.c rename to drivers/timer/riscv_aclint_timer.c index be45f17ddfb..e29d527c8d7 100644 --- a/drivers/timer/sifive_clint_timer.c +++ b/drivers/timer/riscv_aclint_timer.c @@ -18,7 +18,7 @@ /* mtime register */ #define MTIME_REG(base, offset) ((ulong)(base) + (offset)) -static u64 notrace sifive_clint_get_count(struct udevice *dev) +static u64 notrace riscv_aclint_timer_get_count(struct udevice *dev) { return readq((void __iomem *)MTIME_REG(dev_get_priv(dev), dev_get_driver_data(dev))); @@ -44,11 +44,11 @@ u64 notrace timer_early_get_count(void) } #endif -static const struct timer_ops sifive_clint_ops = { - .get_count = sifive_clint_get_count, +static const struct timer_ops riscv_aclint_timer_ops = { + .get_count = riscv_aclint_timer_get_count, }; -static int sifive_clint_probe(struct udevice *dev) +static int riscv_aclint_timer_probe(struct udevice *dev) { dev_set_priv(dev, dev_read_addr_ptr(dev)); if (!dev_get_priv(dev)) @@ -57,18 +57,18 @@ static int sifive_clint_probe(struct udevice *dev) return timer_timebase_fallback(dev); } -static const struct udevice_id sifive_clint_ids[] = { +static const struct udevice_id riscv_aclint_timer_ids[] = { { .compatible = "riscv,clint0", .data = CLINT_MTIME_OFFSET }, { .compatible = "sifive,clint0", .data = CLINT_MTIME_OFFSET }, { .compatible = "riscv,aclint-mtimer", .data = ACLINT_MTIME_OFFSET }, { } }; -U_BOOT_DRIVER(sifive_clint) = { - .name = "sifive_clint", +U_BOOT_DRIVER(riscv_aclint_timer) = { + .name = "riscv_aclint_timer", .id = UCLASS_TIMER, - .of_match = sifive_clint_ids, - .probe = sifive_clint_probe, - .ops = &sifive_clint_ops, + .of_match = riscv_aclint_timer_ids, + .probe = riscv_aclint_timer_probe, + .ops = &riscv_aclint_timer_ops, .flags = DM_FLAG_PRE_RELOC, }; From 5f3a7fdb724976698e9d211e4e174e826c7c4abe Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Sat, 8 Jul 2023 19:24:32 +0800 Subject: [PATCH 15/18] riscv: t-head: licheepi4a: initial support added Add support for Sipeed's Lichee Pi 4A board which based on T-HEAD's TH1520 SoC, only minimal device tree and serial console are enabled, so it's capable of chain booting from T-HEAD's vendor u-boot. Reviewed-by: Wei Fu Signed-off-by: Yixun Lan --- arch/riscv/Kconfig | 5 ++++ board/thead/th1520_lpi4a/Kconfig | 42 ++++++++++++++++++++++++++++ board/thead/th1520_lpi4a/MAINTAINERS | 7 +++++ board/thead/th1520_lpi4a/Makefile | 5 ++++ board/thead/th1520_lpi4a/board.c | 15 ++++++++++ include/configs/th1520_lpi4a.h | 22 +++++++++++++++ 6 files changed, 96 insertions(+) create mode 100644 board/thead/th1520_lpi4a/Kconfig create mode 100644 board/thead/th1520_lpi4a/MAINTAINERS create mode 100644 board/thead/th1520_lpi4a/Makefile create mode 100644 board/thead/th1520_lpi4a/board.c create mode 100644 include/configs/th1520_lpi4a.h diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index de7d5a95492..867cbcbe74e 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -27,6 +27,10 @@ config TARGET_SIFIVE_UNMATCHED config TARGET_STARFIVE_VISIONFIVE2 bool "Support StarFive VisionFive2 Board" +config TARGET_TH1520_LPI4A + bool "Support Sipeed's TH1520 Lichee PI 4A Board" + select SYS_CACHE_SHIFT_6 + config TARGET_SIPEED_MAIX bool "Support Sipeed Maix Board" select SYS_CACHE_SHIFT_6 @@ -66,6 +70,7 @@ source "board/emulation/qemu-riscv/Kconfig" source "board/microchip/mpfs_icicle/Kconfig" source "board/sifive/unleashed/Kconfig" source "board/sifive/unmatched/Kconfig" +source "board/thead/th1520_lpi4a/Kconfig" source "board/openpiton/riscv64/Kconfig" source "board/sipeed/maix/Kconfig" source "board/starfive/visionfive2/Kconfig" diff --git a/board/thead/th1520_lpi4a/Kconfig b/board/thead/th1520_lpi4a/Kconfig new file mode 100644 index 00000000000..622246127c1 --- /dev/null +++ b/board/thead/th1520_lpi4a/Kconfig @@ -0,0 +1,42 @@ +if TARGET_TH1520_LPI4A + +config ARCH_THEAD + bool + default y + +config SYS_BOARD + default "th1520_lpi4a" + +config SYS_VENDOR + default "thead" + +config SYS_CPU + default "generic" + +config SYS_CONFIG_NAME + default "th1520_lpi4a" + +config TEXT_BASE + default 0x01b00000 if SPL + default 0x01c00000 if !RISCV_SMODE + default 0x01c00000 if RISCV_SMODE + +config SPL_TEXT_BASE + default 0x08000000 + +config SPL_OPENSBI_LOAD_ADDR + default 0x80000000 + +config BOARD_SPECIFIC_OPTIONS + def_bool y + select ARCH_EARLY_INIT_R + imply CPU + imply CPU_RISCV + imply RISCV_TIMER if RISCV_SMODE + imply CMD_CPU + imply SMP + imply SUPPORT_OF_CONTROL + imply OF_CONTROL + imply OF_REAL + +endif diff --git a/board/thead/th1520_lpi4a/MAINTAINERS b/board/thead/th1520_lpi4a/MAINTAINERS new file mode 100644 index 00000000000..36c7ab7cc30 --- /dev/null +++ b/board/thead/th1520_lpi4a/MAINTAINERS @@ -0,0 +1,7 @@ +Lichee PI 4A +M: Wei Fu +M: Yixun Lan +S: Maintained +F: board/thead/th1520_lpi4a/ +F: configs/th1520_lpi4a_defconfig +F: doc/board/thead/lpi4a.rst diff --git a/board/thead/th1520_lpi4a/Makefile b/board/thead/th1520_lpi4a/Makefile new file mode 100644 index 00000000000..9671b3bbb0b --- /dev/null +++ b/board/thead/th1520_lpi4a/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2023, Yixun Lan + +obj-y += board.o diff --git a/board/thead/th1520_lpi4a/board.c b/board/thead/th1520_lpi4a/board.c new file mode 100644 index 00000000000..16c3e456b3e --- /dev/null +++ b/board/thead/th1520_lpi4a/board.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023, Yixun Lan + * + */ + +#include +#include + +int board_init(void) +{ + enable_caches(); + + return 0; +} diff --git a/include/configs/th1520_lpi4a.h b/include/configs/th1520_lpi4a.h new file mode 100644 index 00000000000..87496a52c4c --- /dev/null +++ b/include/configs/th1520_lpi4a.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023 Yixun Lan + * + */ + +#ifndef __TH1520_LPI4A_H +#define __TH1520_LPI4A_H + +#include + +#define CFG_SYS_SDRAM_BASE 0x00000000 + +#define UART_BASE 0xffe7014000 +#define UART_REG_WIDTH 32 + +/* Environment options */ + +#define CFG_EXTRA_ENV_SETTINGS \ + "PS1=[LPi4A]# \0" + +#endif /* __TH1520_LPI4A_H */ From 4416f079402e663cf6935e3abdad3e304096d026 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Sat, 8 Jul 2023 19:24:33 +0800 Subject: [PATCH 16/18] riscv: dts: t-head: Add basic device tree for Sipeed Lichee PI 4A board Only add basic support for CPU, PLIC UART and Timer. Reviewed-by: Wei Fu Signed-off-by: Yixun Lan --- arch/riscv/dts/Makefile | 1 + arch/riscv/dts/th1520-lichee-module-4a.dtsi | 34 ++ arch/riscv/dts/th1520-lichee-pi-4a.dts | 32 ++ arch/riscv/dts/th1520.dtsi | 406 ++++++++++++++++++++ 4 files changed, 473 insertions(+) create mode 100644 arch/riscv/dts/th1520-lichee-module-4a.dtsi create mode 100644 arch/riscv/dts/th1520-lichee-pi-4a.dts create mode 100644 arch/riscv/dts/th1520.dtsi diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile index d9c050e2996..f1525cb6680 100644 --- a/arch/riscv/dts/Makefile +++ b/arch/riscv/dts/Makefile @@ -8,6 +8,7 @@ dtb-$(CONFIG_TARGET_SIFIVE_UNLEASHED) += hifive-unleashed-a00.dtb dtb-$(CONFIG_TARGET_SIFIVE_UNMATCHED) += hifive-unmatched-a00.dtb dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2.dtb +dtb-$(CONFIG_TARGET_TH1520_LPI4A) += th1520-lichee-pi-4a.dtb include $(srctree)/scripts/Makefile.dts targets += $(dtb-y) diff --git a/arch/riscv/dts/th1520-lichee-module-4a.dtsi b/arch/riscv/dts/th1520-lichee-module-4a.dtsi new file mode 100644 index 00000000000..dc00e3dfa02 --- /dev/null +++ b/arch/riscv/dts/th1520-lichee-module-4a.dtsi @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Jisheng Zhang + */ + +/dts-v1/; + +#include "th1520.dtsi" + +/ { + model = "Sipeed Lichee Module 4A"; + compatible = "sipeed,lichee-module-4a", "thead,th1520"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x00000000 0x2 0x00000000>; + }; +}; + +&osc { + clock-frequency = <24000000>; +}; + +&osc_32k { + clock-frequency = <32768>; +}; + +&apb_clk { + clock-frequency = <62500000>; +}; + +&uart_sclk { + clock-frequency = <100000000>; +}; diff --git a/arch/riscv/dts/th1520-lichee-pi-4a.dts b/arch/riscv/dts/th1520-lichee-pi-4a.dts new file mode 100644 index 00000000000..a1248b2ee3a --- /dev/null +++ b/arch/riscv/dts/th1520-lichee-pi-4a.dts @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Jisheng Zhang + */ + +#include "th1520-lichee-module-4a.dtsi" + +/ { + model = "Sipeed Lichee Pi 4A"; + compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520"; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/riscv/dts/th1520.dtsi b/arch/riscv/dts/th1520.dtsi new file mode 100644 index 00000000000..f7bfa422439 --- /dev/null +++ b/arch/riscv/dts/th1520.dtsi @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + * Copyright (C) 2023 Jisheng Zhang + */ + +#include + +/ { + compatible = "thead,th1520"; + #address-cells = <2>; + #size-cells = <2>; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <3000000>; + + c910_0: cpu@0 { + compatible = "thead,c910", "riscv"; + device_type = "cpu"; + riscv,isa = "rv64imafdc"; + reg = <0>; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + + c910_1: cpu@1 { + compatible = "thead,c910", "riscv"; + device_type = "cpu"; + riscv,isa = "rv64imafdc"; + reg = <1>; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; + + cpu1_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + + c910_2: cpu@2 { + compatible = "thead,c910", "riscv"; + device_type = "cpu"; + riscv,isa = "rv64imafdc"; + reg = <2>; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; + + cpu2_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + + c910_3: cpu@3 { + compatible = "thead,c910", "riscv"; + device_type = "cpu"; + riscv,isa = "rv64imafdc"; + reg = <3>; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; + + cpu3_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + + l2_cache: l2-cache { + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <1048576>; + cache-sets = <1024>; + cache-unified; + }; + }; + + osc: oscillator { + compatible = "fixed-clock"; + clock-output-names = "osc_24m"; + #clock-cells = <0>; + }; + + osc_32k: 32k-oscillator { + compatible = "fixed-clock"; + clock-output-names = "osc_32k"; + #clock-cells = <0>; + }; + + apb_clk: apb-clk-clock { + compatible = "fixed-clock"; + clock-output-names = "apb_clk"; + #clock-cells = <0>; + }; + + uart_sclk: uart-sclk-clock { + compatible = "fixed-clock"; + clock-output-names = "uart_sclk"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + plic: interrupt-controller@ffd8000000 { + compatible = "thead,th1520-plic", "thead,c900-plic"; + reg = <0xff 0xd8000000 0x0 0x01000000>; + interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>, + <&cpu1_intc 11>, <&cpu1_intc 9>, + <&cpu2_intc 11>, <&cpu2_intc 9>, + <&cpu3_intc 11>, <&cpu3_intc 9>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + riscv,ndev = <240>; + }; + + clint: timer@ffdc000000 { + compatible = "thead,th1520-clint", "thead,c900-clint"; + reg = <0xff 0xdc000000 0x0 0x00010000>; + interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>, + <&cpu1_intc 3>, <&cpu1_intc 7>, + <&cpu2_intc 3>, <&cpu2_intc 7>, + <&cpu3_intc 3>, <&cpu3_intc 7>; + }; + + uart0: serial@ffe7014000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xe7014000 0x0 0x100>; + interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart_sclk>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart1: serial@ffe7f00000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xe7f00000 0x0 0x100>; + interrupts = <37 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart_sclk>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart3: serial@ffe7f04000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xe7f04000 0x0 0x100>; + interrupts = <39 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart_sclk>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + gpio2: gpio@ffe7f34000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xe7f34000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portc: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <58 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio3: gpio@ffe7f38000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xe7f38000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portd: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <59 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio0: gpio@ffec005000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xec005000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + porta: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <56 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio1: gpio@ffec006000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xec006000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portb: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <57 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + uart2: serial@ffec010000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xec010000 0x0 0x4000>; + interrupts = <38 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart_sclk>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + timer0: timer@ffefc32000 { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xefc32000 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <16 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + timer1: timer@ffefc32014 { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xefc32014 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + timer2: timer@ffefc32028 { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xefc32028 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + timer3: timer@ffefc3203c { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xefc3203c 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + uart4: serial@fff7f08000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xf7f08000 0x0 0x4000>; + interrupts = <40 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart_sclk>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart5: serial@fff7f0c000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xf7f0c000 0x0 0x4000>; + interrupts = <41 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&uart_sclk>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + timer4: timer@ffffc33000 { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xffc33000 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + timer5: timer@ffffc33014 { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xffc33014 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <21 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + timer6: timer@ffffc33028 { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xffc33028 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + timer7: timer@ffffc3303c { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xffc3303c 0x0 0x14>; + clocks = <&apb_clk>; + clock-names = "timer"; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + ao_gpio0: gpio@fffff41000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xfff41000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + porte: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <76 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + ao_gpio1: gpio@fffff52000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xfff52000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portf: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <55 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + }; +}; From 12d02bba5516f545ebf0a62efe77ef296dd4f968 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Sat, 8 Jul 2023 19:24:34 +0800 Subject: [PATCH 17/18] configs: th1520_lpi4a_defconfig: Add initial config Add basic config for Sipeed Lichee PI 4A board which make it capable of booting into serial console. Reviewed-by: Wei Fu Signed-off-by: Yixun Lan --- configs/th1520_lpi4a_defconfig | 82 ++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 configs/th1520_lpi4a_defconfig diff --git a/configs/th1520_lpi4a_defconfig b/configs/th1520_lpi4a_defconfig new file mode 100644 index 00000000000..710ec6abf52 --- /dev/null +++ b/configs/th1520_lpi4a_defconfig @@ -0,0 +1,82 @@ +CONFIG_RISCV=y +CONFIG_SYS_MALLOC_LEN=0x800000 +CONFIG_SYS_MALLOC_F_LEN=0x3000 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x80200000 +CONFIG_DEFAULT_DEVICE_TREE="th1520-lichee-pi-4a" +CONFIG_SYS_PROMPT="LPI4A=> " +CONFIG_SYS_LOAD_ADDR=0x80200000 +# CONFIG_SMP is not set +CONFIG_TARGET_TH1520_LPI4A=y +CONFIG_ARCH_RV64I=y +CONFIG_OF_BOARD_FIXUP=y +CONFIG_SYS_BOOT_GET_CMDLINE=y +CONFIG_SYS_BOOT_GET_KBD=y +CONFIG_FIT=y +# CONFIG_FIT_FULL_CHECK is not set +# CONFIG_FIT_PRINT is not set +# CONFIG_BOOTSTD is not set +# CONFIG_LEGACY_IMAGE_FORMAT is not set +CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTARGS_SUBST=y +CONFIG_BOOTCOMMAND="" +CONFIG_DEFAULT_FDT_FILE="thead/th1520-lichee-pi-4a.dtb" +CONFIG_LOG=y +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_SYS_CBSIZE=256 +CONFIG_SYS_PBSIZE=276 +CONFIG_CMD_CONFIG=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_BOOTZ=y +# CONFIG_BOOTM_NETBSD is not set +# CONFIG_BOOTM_PLAN9 is not set +# CONFIG_BOOTM_RTEMS is not set +# CONFIG_BOOTM_VXWORKS is not set +CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_CMD_BOOTMENU=y +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMI is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_EXPORTENV is not set +# CONFIG_CMD_IMPORTENV is not set +# CONFIG_CMD_EDITENV is not set +# CONFIG_CMD_SAVEENV is not set +# CONFIG_CMD_CRC32 is not set +# CONFIG_CMD_MEMORY is not set +# CONFIG_CMD_LZMADEC is not set +# CONFIG_CMD_UNLZ4 is not set +# CONFIG_CMD_UNZIP is not set +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_ITEST is not set +# CONFIG_CMD_SOURCE is not set +# CONFIG_CMD_SETEXPR is not set +# CONFIG_CMD_SLEEP is not set +CONFIG_PARTITION_TYPE_GUID=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_VERSION_VARIABLE=y +# CONFIG_NET is not set +# CONFIG_BLOCK_CACHE is not set +# CONFIG_GPIO is not set +# CONFIG_I2C is not set +# CONFIG_INPUT is not set +# CONFIG_DM_MMC is not set +# CONFIG_MTD is not set +# CONFIG_POWER is not set +CONFIG_SYS_NS16550=y +CONFIG_RISCV_TIMER=y +CONFIG_AES=y +CONFIG_BLAKE2=y +CONFIG_SHA512=y +CONFIG_LZ4=y +CONFIG_LZMA=y +CONFIG_LZO=y +CONFIG_ZLIB_UNCOMPRESS=y +CONFIG_BZIP2=y +CONFIG_ZSTD=y +CONFIG_LIB_RATIONAL=y +# CONFIG_EFI_LOADER is not set +# CONFIG_LMB_USE_MAX_REGIONS is not set From 478fedfda42ea2a444991de1696fa0adc8bb16d4 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Sat, 8 Jul 2023 19:24:35 +0800 Subject: [PATCH 18/18] doc: t-head: lpi4a: document Lichee PI 4A board Reviewed-by: Wei Fu Signed-off-by: Yixun Lan --- doc/board/index.rst | 1 + doc/board/thead/index.rst | 9 +++ doc/board/thead/lpi4a.rst | 129 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 doc/board/thead/index.rst create mode 100644 doc/board/thead/lpi4a.rst diff --git a/doc/board/index.rst b/doc/board/index.rst index 9ef25b10915..aadc90af894 100644 --- a/doc/board/index.rst +++ b/doc/board/index.rst @@ -45,6 +45,7 @@ Board-specific doc starfive/index ste/index tbs/index + thead/index ti/index toradex/index variscite/index diff --git a/doc/board/thead/index.rst b/doc/board/thead/index.rst new file mode 100644 index 00000000000..41566d3a368 --- /dev/null +++ b/doc/board/thead/index.rst @@ -0,0 +1,9 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +T-HEAD +======== + +.. toctree:: + :maxdepth: 1 + + lpi4a diff --git a/doc/board/thead/lpi4a.rst b/doc/board/thead/lpi4a.rst new file mode 100644 index 00000000000..e395c6ae12c --- /dev/null +++ b/doc/board/thead/lpi4a.rst @@ -0,0 +1,129 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Sipeed's Lichee PI 4A based on T-HEAD TH1520 SoC +================================================ + +The LicheePi4A is a high-performance RISC-V SBC based on TH1520(4xC910@1.85GHz), +comes with 4/8/16 GB RAM, and up to 128GB eMMC, and rich peripherals. + + - SoC T-HEAD TH1520 SoC + - System Memory 4GB, 8GB, or 16GB LPDDR4X + - Storage eMMC flash with 8/32/128 GB + - external microSD slot + - Networking 2x Gigabit Ethernet + - WiFi+BT + - Display HDMI2.0, 4-lane MIPI DSI + - Camera 4-lane MIPI CSI + 2x2-lane MIPI CSI + - Audio Onboard Speaker, 2xMEMS MIC, 3.5mm headphone jack + - USB 4xUSB3.0 Type-A, 1xUSB2.0 Type-C + - GPIO 2x10Pin breakout, UART/IIC/SPI + - Power DC 12V/2A, POE 5V/2.4A, USB Type-C 5V/2A + +TH1520 RISC-V SoC +----------------- + +The TH1520 SoC consist of quad-core RISC-V Xuantie C910 (RV64GCV) processor, +Xuantie C906 audio DSP, low power Xuantie E902 core, it also integrate +Imagination GPU for graphics, and 4 TOPS NPU for AI acceleration. + +Mainline support +---------------- + +The support for following drivers are already enabled: + +1. ns16550 UART Driver. + +Building +~~~~~~~~ + +1. Add the RISC-V toolchain to your PATH. +2. Setup ARCH & cross compilation environment variable: + +.. code-block:: none + + export CROSS_COMPILE= + +The U-Boot is capable of running in M-Mode, so we can directly build it. + +.. code-block:: console + + cd + make th1520_lpi4a_defconfig + make + +This will generate u-boot-dtb.bin + +Booting +~~~~~~~ + +Currently, we rely on vendor u-boot to initialize the clock, pinctrl subsystem, +and chain load the mainline u-boot image either via tftp or emmc storage, +then bootup from it. + +Sample boot log from Lichee PI 4A board via tftp +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: none + + brom_ver 8 + [APP][E] protocol_connect failed, exit. + + U-Boot SPL 2020.01-00016-g8c870a6be8 (May 20 2023 - 01:04:49 +0000) + FM[1] lpddr4x dualrank freq=3733 64bit dbi_off=n sdram init + ddr initialized, jump to uboot + image has no header + + + U-Boot 2020.01-00016-g8c870a6be8 (May 20 2023 - 01:04:49 +0000) + + CPU: rv64imafdcvsu + Model: T-HEAD c910 light + DRAM: 8 GiB + C910 CPU FREQ: 750MHz + AHB2_CPUSYS_HCLK FREQ: 250MHz + AHB3_CPUSYS_PCLK FREQ: 125MHz + PERISYS_AHB_HCLK FREQ: 250MHz + PERISYS_APB_PCLK FREQ: 62MHz + GMAC PLL POSTDIV FREQ: 1000MHZ + DPU0 PLL POSTDIV FREQ: 1188MHZ + DPU1 PLL POSTDIV FREQ: 1188MHZ + MMC: sdhci@ffe7080000: 0, sd@ffe7090000: 1 + Loading Environment from MMC... OK + Error reading output register + Warning: cannot get lcd-en GPIO + LCD panel cannot be found : -121 + splash screen startup cost 16 ms + In: serial + Out: serial + Err: serial + Net: + Warning: ethernet@ffe7070000 using MAC address from ROM + eth0: ethernet@ffe7070000ethernet@ffe7070000:0 is connected to ethernet@ffe7070000. Reconnecting to ethernet@ffe7060000 + + Warning: ethernet@ffe7060000 (eth1) using random MAC address - 42:25:d4:16:5f:fc + , eth1: ethernet@ffe7060000 + Hit any key to stop autoboot: 2 + ethernet@ffe7060000 Waiting for PHY auto negotiation to complete.. done + Speed: 1000, full duplex + Using ethernet@ffe7070000 device + TFTP from server 192.168.8.50; our IP address is 192.168.8.45 + Filename 'u-boot-dtb.bin'. + Load address: 0x1c00000 + Loading: * ######################### + 8 MiB/s + done + Bytes transferred = 376686 (5bf6e hex) + ## Starting application at 0x01C00000 ... + + U-Boot 2023.07-rc2-00004-g1befbe31c1 (May 23 2023 - 18:40:01 +0800) + + CPU: rv64imafdc + Model: Sipeed Lichee Pi 4A + DRAM: 8 GiB + Core: 13 devices, 6 uclasses, devicetree: separate + Loading Environment from ... OK + In: serial@ffe7014000 + Out: serial@ffe7014000 + Err: serial@ffe7014000 + Model: Sipeed Lichee Pi 4A + LPI4A=>