[PATCH v5 00/11] Add ethernet driver for StarFive JH7110 SoC

This series of patches base on the latest branch/master,and adds ethernet support for the StarFive JH7110 RISC-V SoC. The series includes EEPROM, PHY and MAC drivers. The PHY model is YT8531 (from Motorcomm Inc), and the MAC version is dwmac-5.20 (from Synopsys DesignWare).
The implementation of the phy driver is ported from linux, but it has been adjusted for the u-boot framework.
EEPROM stores board-related information, such as DDR capacity, PCB version, MAC address, etc.
The main difference between StarFive VisionFive 2 1.2A and 1.3B is gmac, but the difference in gmac is not defined in DT, but reads the PCB version from EEPROM, and then dynamically configures the difference of gmac according to different PCB versions, which is compatible with 1.2A and 1.3B versions, which is more user-friendly.
The PHY and MAC driver has been tested on the StarFive VisionFive 2 1.2A and 1.3B boards and works normally.
For more information and support,you can visit RVspace wiki[1]. [1] https://wiki.rvspace.org/
v5: - Reorder a series of patches to make each patch is independent. - Move CONFIG_DEFAULT_FDT_FILE and CONFIG_DEFAULT_DEVICE_TREE changes to patch 4. - Move the definition of 'board_fdt_blob_setup' to patch 9.
v4: - Reworded the definition of the 'pbuf' variable in visionfive2-i2c-eeprom.c from a const pointer to const union. - Added the section (".data") attribute to the 'pbuf' and 'has_been_read' global variables in visionfive2-i2-eeprom.c.
v3: - Added EEPROM support. - Combine the board device tree of 1.2A and 1.3B into one. - Removed the delay configuration of gmac phy clock from DT. - Dynamically configure gmac differences of 1.2A and 1.3B to DT according to the PCB version. - DDR capacity information is read from EEPROM first, if not, it is defined by default in DT.
v2: - Reworded the phy driver. Added platform private data struct to save the configuration data read from dts. - Reworded the MAC driver. Added platform private data struct to save the configuration data read from dts.
Previous versions: v1 - https://patchwork.ozlabs.org/project/uboot/cover/20230317010536.17860-1-yanh... v2 - https://patchwork.ozlabs.org/project/uboot/cover/20230329102720.25439-1-yanh... v3 - https://patchwork.ozlabs.org/project/uboot/cover/20230428022515.29393-1-yanh... v4 - https://patchwork.ozlabs.org/project/uboot/cover/20230525093637.31364-1-yanh...
Yanhong Wang (11): net: phy: Add driver for Motorcomm yt8531 gigabit ethernet phy net: dwc_eth_qos: Add StarFive ethernet driver glue layer riscv: dts: jh7110: Add ethernet device tree nodes riscv: dts: jh7110: Combine the board device tree files of 1.2A and 1.3B doc: board: starfive: Reword the make defconfig information configs: starfive: Enable ethernet configuration for StarFive VisionFive2 eeprom: starfive: Enable ID EEPROM configuration riscv: dts: starfive: Add support eeprom device tree node configs: starfive: Enable ID EEPROM configuration ram: starfive: Read memory size information from EEPROM board: starfive: Dynamic configuration of DT for 1.2A and 1.3B
arch/riscv/cpu/jh7110/spl.c | 32 +- arch/riscv/dts/Makefile | 3 +- ... jh7110-starfive-visionfive-2-u-boot.dtsi} | 39 +- .../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 +- .../dts/jh7110-starfive-visionfive-2.dtsi | 40 ++ arch/riscv/dts/jh7110.dtsi | 69 +++ arch/riscv/include/asm/arch-jh7110/eeprom.h | 13 + board/starfive/visionfive2/Makefile | 1 + board/starfive/visionfive2/spl.c | 157 +++++ .../visionfive2/starfive_visionfive2.c | 13 + .../visionfive2/visionfive2-i2c-eeprom.c | 561 ++++++++++++++++++ configs/starfive_visionfive2_defconfig | 32 +- doc/board/starfive/visionfive2.rst | 6 +- 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 ++++++++ drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/motorcomm.c | 437 ++++++++++++++ drivers/ram/starfive/starfive_ddr.c | 2 - 24 files changed, 1665 insertions(+), 95 deletions(-) rename arch/riscv/dts/{jh7110-starfive-visionfive-2-v1.2a-u-boot.dtsi => jh7110-starfive-visionfive-2-u-boot.dtsi} (58%) 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%) create mode 100644 arch/riscv/include/asm/arch-jh7110/eeprom.h create mode 100644 board/starfive/visionfive2/visionfive2-i2c-eeprom.c create mode 100644 drivers/net/dwc_eth_qos_starfive.c create mode 100644 drivers/net/phy/motorcomm.c
base-commit: 19b77d3d23966a0d6dbb3c86187765f11100fb6f

Add a driver for the motorcomm yt8531 gigabit ethernet phy. We have verified the driver on StarFive VisionFive2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com Reviewed-by: Ramon Fried rfried.dev@gmail.com --- 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 24158776f5..0c3c39a550 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 85d17f109c..2487f366e1 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 0000000000..e822fd76f2 --- /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 <config.h> +#include <common.h> +#include <malloc.h> +#include <phy.h> +#include <linux/bitfield.h> + +#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, +};

The StarFive ETHQOS hardware has its own clock and reset,so add a corresponding glue driver to configure them.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com Reviewed-by: Ramon Fried rfried.dev@gmail.com --- 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 09039a283e..5540f0ea18 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 46a40e2ed9..d4af253b6f 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 9bbba6eed0..1e92bd9ca9 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 fddbe9336c..a6b719af80 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 0000000000..5be8ac0f1a --- /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 Wangyanhong.wang@starfivetech.com + */ + +#include <common.h> +#include <asm/cache.h> +#include <asm/gpio.h> +#include <clk.h> +#include <dm.h> +#include <eth_phy.h> +#include <net.h> +#include <regmap.h> +#include <reset.h> +#include <syscon.h> + +#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 +};

Add ethernet device tree node to support StarFive ethernet driver for the JH7110 RISC-V SoC.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com --- .../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 c6b6dfa940..3c1148ae2d 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 bd60879615..58e332e9d7 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>;

On Thu, Jun 15, 2023 at 05:36:44PM +0800, Yanhong Wang wrote:
Add ethernet device tree node to support StarFive ethernet driver for the JH7110 RISC-V SoC.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com
.../dts/jh7110-starfive-visionfive-2.dtsi | 34 +++++++++ arch/riscv/dts/jh7110.dtsi | 69 +++++++++++++++++++ 2 files changed, 103 insertions(+)
Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com

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 yanhong.wang@starfivetech.com --- 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 79a58694f5..7940fe466d 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 3c322c5c97..2afcec30b8 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 b9d26d7af7..0000000000 --- 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 3c322c5c97..0000000000 --- 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 3b3b3453a1..288ea39493 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 ffbc4b9476..566d2c3d0e 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

On Thu, Jun 15, 2023 at 05:36:45PM +0800, Yanhong Wang wrote:
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 yanhong.wang@starfivetech.com
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%)
Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com

The defconfig file name for StarFive VisionFive2 has been changed, and the documentation description has also changed.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com --- 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 4d43ac9729..951e0d80fb 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 <U-Boot-dir> - 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)

On Thu, Jun 15, 2023 at 05:36:46PM +0800, Yanhong Wang wrote:
The defconfig file name for StarFive VisionFive2 has been changed, and the documentation description has also changed.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com
doc/board/starfive/visionfive2.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com

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 yanhong.wang@starfivetech.com --- configs/starfive_visionfive2_defconfig | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index 566d2c3d0e..c57708199d 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

On Thu, Jun 15, 2023 at 05:36:47PM +0800, Yanhong Wang wrote:
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 yanhong.wang@starfivetech.com
configs/starfive_visionfive2_defconfig | 9 +++++++++ 1 file changed, 9 insertions(+)
Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com

Enabled ID_EEPROM configuration for StarFive VisionFive2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com --- 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 0000000000..f354d5c60c --- /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 Wangyanhong.wang@starfivetech.com + */ + +#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 66c854df39..c7ba4f7ed6 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 0000000000..befe7888c4 --- /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 Wangyanhong.wang@starfivetech.com + */ + +#include <common.h> +#include <command.h> +#include <env.h> +#include <i2c.h> +#include <init.h> +#include <u-boot/crc.h> +#include <linux/delay.h> + +#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 xx:xx:xx:xx:xx:xx\n" + " - stores a MAC0 address into the local EEPROM copy\n" + "mac mac1_address xx:xx:xx:xx:xx:xx\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 <A>\n" + " - stores a StarFive BOM revision into the local EEPROM copy\n" + "mac product_id <VF7110A1-2228-D008E000-xxxxxxxx>\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;" + * "<product>-<date>-<DDR&eMMC>-<serial_number>" + * <date>: 4Byte, should be the output of `date +%y%W` + * <DDR&eMMC>: 8Byte, "D008" means 8GB, "D01T" means 1TB; + * "E000" means no eMMC,"E032" means 32GB, "E01T" means 1TB. + * <serial_number>: 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); +}

On Thu, Jun 15, 2023 at 05:36:48PM +0800, Yanhong Wang wrote:
Enabled ID_EEPROM configuration for StarFive VisionFive2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com
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
Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com

Add support "atmel,24c04" eeprom for StarFive VisionFive2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com --- .../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 2afcec30b8..13f69da31e 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 3c1148ae2d..710b082766 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 {

On Thu, Jun 15, 2023 at 05:36:49PM +0800, Yanhong Wang wrote:
Add support "atmel,24c04" eeprom for StarFive VisionFive2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com
.../dts/jh7110-starfive-visionfive-2-u-boot.dtsi | 14 ++++++++++++++ arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi | 6 ++++++ 2 files changed, 20 insertions(+)
Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com

Enabled ID_EEPROM and I2C configuration for StarFive VisionFive2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com --- .../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 613fe793c4..07dcca26b3 100644 --- a/board/starfive/visionfive2/starfive_visionfive2.c +++ b/board/starfive/visionfive2/starfive_visionfive2.c @@ -6,7 +6,9 @@
#include <common.h> #include <asm/io.h> +#include <asm/sections.h> #include <cpu_func.h> +#include <dm.h> #include <linux/bitops.h>
#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 c57708199d..570a1f53a1 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

On Thu, Jun 15, 2023 at 05:36:50PM +0800, Yanhong Wang wrote:
Enabled ID_EEPROM and I2C configuration for StarFive VisionFive2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com
.../visionfive2/starfive_visionfive2.c | 13 +++++++++++++ configs/starfive_visionfive2_defconfig | 19 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-)
Reviewed-By: Leo Yu-Chi Linag ycliang@andestech.com

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 yanhong.wang@starfivetech.com --- 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 104f0fe949..72adcefa0e 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 Wangyanhong.wang@starfivetech.com */ - +#include <common.h> +#include <asm/arch/eeprom.h> #include <asm/csr.h> #include <asm/sections.h> #include <dm.h> +#include <linux/sizes.h> #include <log.h> +#include <init.h>
#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 553f2ce6f4..a0a3d6b33d 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;

On Thu, Jun 15, 2023 at 05:36:51PM +0800, Yanhong Wang wrote:
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 yanhong.wang@starfivetech.com
arch/riscv/cpu/jh7110/spl.c | 32 ++++++++++++++++++++++++++++- drivers/ram/starfive/starfive_ddr.c | 2 -- 2 files changed, 31 insertions(+), 3 deletions(-)
Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com

On Jun 15 2023, Yanhong Wang wrote:
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.
Does that acutally work? I see that read_eeprom fails in SPL.

On 15.06.23 11:36, Yanhong Wang wrote:
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 yanhong.wang@starfivetech.com Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com
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 104f0fe949..72adcefa0e 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 Wangyanhong.wang@starfivetech.com
*/
+#include <common.h> +#include <asm/arch/eeprom.h> #include <asm/csr.h> #include <asm/sections.h> #include <dm.h> +#include <linux/sizes.h> #include <log.h> +#include <init.h>
#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;
On origin/master for a 4 GiB board with a serial number VF7110B1-2253-D004E000-4000xxxx this always fails. This results in memory reported as 8 GiB and Linux crashing.
i2c_get_chip_for_busnum() returns -EINVAL in read_eeprom() [board/starfive/visionfive2/visionfive2-i2c-eeprom.c:335].
Is the driver model really expected to be fully initialized before setting up memory?
Best regards
Heinrich
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 553f2ce6f4..a0a3d6b33d 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;

On 11.10.23 04:54, Heinrich Schuchardt wrote:
On 15.06.23 11:36, Yanhong Wang wrote:
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 yanhong.wang@starfivetech.com Reviewed-by: Leo Yu-Chi Liang ycliang@andestech.com
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 104f0fe949..72adcefa0e 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 Wangyanhong.wang@starfivetech.com */
+#include <common.h> +#include <asm/arch/eeprom.h> #include <asm/csr.h> #include <asm/sections.h> #include <dm.h> +#include <linux/sizes.h> #include <log.h> +#include <init.h> #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;
On origin/master for a 4 GiB board with a serial number VF7110B1-2253-D004E000-4000xxxx this always fails. This results in memory reported as 8 GiB and Linux crashing.
i2c_get_chip_for_busnum() returns -EINVAL in read_eeprom() [board/starfive/visionfive2/visionfive2-i2c-eeprom.c:335].
Is the driver model really expected to be fully initialized before setting up memory?
Best regards
Heinrich
The root cause seems to be in dw_i2c_calc_timing(). Probing of the i2c_designware device fails with:
dw_i2c: mode 0, ic_clk 1000000, speed 100000, period 10 rise 1 fall 1 tlow 5 thigh 4 spk 0 dw_i2c: bad counts. hcnt = -4 lcnt = 4 device_probe: i2c@12050000 failed to probe -22
When I change the hcnt timing calculation, by replacing the offset of 7 to 1, the device is probed correctly and I get the correct memory size for my board.
Best regards
Heinrich
+ 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 553f2ce6f4..a0a3d6b33d 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;

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 yanhong.wang@starfivetech.com --- 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 db0b4cb433..7acd3995aa 100644 --- a/board/starfive/visionfive2/spl.c +++ b/board/starfive/visionfive2/spl.c @@ -5,16 +5,173 @@ */
#include <common.h> +#include <asm/arch/eeprom.h> #include <asm/arch/regs.h> #include <asm/arch/spl.h> #include <asm/io.h> +#include <dt-bindings/clock/starfive,jh7110-crg.h> +#include <fdt_support.h> +#include <linux/libfdt.h> #include <log.h> #include <spl.h>
+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;
participants (4)
-
Andreas Schwab
-
Heinrich Schuchardt
-
Leo Liang
-
Yanhong Wang