[PATCH v1 0/5] Add Ethernet driver for StarFive JH7110 SoC

This series adds ethernet support for the StarFive JH7110 RISC-V SoC. The series includes 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.
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]. This patchset should be applied after the patchset [2]. [1] https://wiki.rvspace.org/ [2] https://patchwork.ozlabs.org/project/uboot/cover/20230316025332.3297-1-yanho...
Yanhong Wang (5): 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: starfive: Add phy clock delay configuration for StarFive VisionFive2 board configs: starfive: Enable ethernet configuration for StarFive VisionFive 2
.../jh7110-starfive-visionfive-2-v1.2a.dts | 13 + .../jh7110-starfive-visionfive-2-v1.3b.dts | 27 ++ .../dts/jh7110-starfive-visionfive-2.dtsi | 34 ++ arch/riscv/dts/jh7110.dtsi | 69 +++ configs/starfive_visionfive2_defconfig | 13 + drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/dwc_eth_qos.c | 6 + drivers/net/dwc_eth_qos.h | 2 + drivers/net/dwc_eth_qos_starfive.c | 306 +++++++++++++ drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/motorcomm.c | 409 ++++++++++++++++++ drivers/net/phy/phy.c | 4 +- include/phy.h | 1 + 15 files changed, 898 insertions(+), 1 deletion(-) create mode 100644 drivers/net/dwc_eth_qos_starfive.c create mode 100644 drivers/net/phy/motorcomm.c
base-commit: 3ad7642443aee9369726844ffcfe5b9ae68c259e

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 --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/motorcomm.c | 409 ++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy.c | 4 +- include/phy.h | 1 + 5 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 drivers/net/phy/motorcomm.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 5eaff053a0..aba718566a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -212,6 +212,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 d38e99e717..e9523fed2e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PHY_MARVELL) += marvell.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..c7e44cfb63 --- /dev/null +++ b/drivers/net/phy/motorcomm.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Motorcomm 8531 PHY driver. + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + */ + +#include <config.h> +#include <common.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 + +/** + * 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, + const char *prop_name, + const struct ytphy_cfg_reg_map *tbl, + int tb_size, + u16 *rxc_dly_en, + u32 dflt) +{ + int tb_size_half = tb_size / 2; + u32 val; + int i; + + if (ofnode_read_u32(phydev->node, prop_name, &val)) + goto err_dts_val; + + /* 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 (tbl[i].cfg == val) { + if (rxc_dly_en && i < tb_size_half) + *rxc_dly_en = 0; + return tbl[i].reg; + } + } + + pr_warn("Unsupported value %d for %s using default (%u)\n", + val, prop_name, dflt); + +err_dts_val: + /* 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 dflt; +} + +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) +{ + int tb_size = ARRAY_SIZE(ytphy_rgmii_delays); + 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, "rx-internal-delay-ps", + ytphy_rgmii_delays, tb_size, + &rxc_dly_en, + YT8531_RC1R_RGMII_1_950_NS); + tx_reg = ytphy_get_delay_reg_value(phydev, "tx-internal-delay-ps", + ytphy_rgmii_delays, tb_size, NULL, + YT8531_RC1R_RGMII_1_950_NS); + + 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) +{ + bool tx_clk_adj_enabled = false; + bool tx_clk_1000_inverted = false; + bool tx_clk_100_inverted = false; + bool tx_clk_10_inverted = false; + u16 val = 0; + int ret; + + ret = genphy_update_link(phydev); + if (ret) + return ret; + + ret = yt8531_parse_status(phydev); + if (ret) + return ret; + + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled")) + tx_clk_adj_enabled = true; + + if (!tx_clk_adj_enabled) + return 0; + + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-10-inverted")) + tx_clk_10_inverted = true; + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-100-inverted")) + tx_clk_100_inverted = true; + if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-1000-inverted")) + tx_clk_1000_inverted = true; + + if (phydev->speed < 0) + return -EINVAL; + + switch (phydev->speed) { + case SPEED_1000: + if (tx_clk_1000_inverted) + val = YT8531_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_100: + if (tx_clk_100_inverted) + val = YT8531_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_10: + if (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 int yt8531_config(struct phy_device *phydev) +{ + int ret; + + ret = genphy_config_aneg(phydev); + if (ret < 0) + return ret; + + ret = ytphy_rgmii_clk_delay_config(phydev); + if (ret < 0) + return ret; + + if (ofnode_read_bool(phydev->node, "motorcomm,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 (ofnode_read_bool(phydev->node, "motorcomm,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) +{ + u16 mask, val; + u32 freq; + + if (ofnode_read_u32(phydev->node, "motorcomm,clk-out-frequency-hz", &freq)) + freq = YTPHY_DTS_OUTPUT_CLK_DIS; + + switch (freq) { + 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", freq); + return -EINVAL; + } + + return ytphy_modify_ext(phydev, YTPHY_SYNCE_CFG_REG, mask, + val); +} + +static struct phy_driver motorcomm8531_driver = { + .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, +}; + +int phy_motorcomm_init(void) +{ + phy_register(&motorcomm8531_driver); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 80230b907c..78bde61798 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -570,6 +570,9 @@ int phy_init(void) #endif #ifdef CONFIG_PHY_XILINX_GMII2RGMII phy_xilinx_gmii2rgmii_init(); +#endif +#ifdef CONFIG_PHY_MOTORCOMM + phy_motorcomm_init(); #endif genphy_init();
@@ -755,7 +758,6 @@ static struct phy_device *create_phy_by_mask(struct mii_dev *bus, while (phy_mask) { int addr = ffs(phy_mask) - 1; int r = get_phy_id(bus, addr, devad, &phy_id); - /* * If the PHY ID is flat 0 we ignore it. There are C45 PHYs * that return all 0s for C22 reads (like Aquantia AQR112) and diff --git a/include/phy.h b/include/phy.h index 87aa86c2e7..f7bb2fe0af 100644 --- a/include/phy.h +++ b/include/phy.h @@ -344,6 +344,7 @@ int phy_mscc_init(void); int phy_fixed_init(void); int phy_ncsi_init(void); int phy_xilinx_gmii2rgmii_init(void); +int phy_motorcomm_init(void);
int board_phy_config(struct phy_device *phydev); int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);

Hi Yanhong,
On Thu, 16 Mar 2023 at 19:06, Yanhong Wang yanhong.wang@starfivetech.com wrote:
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
drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/motorcomm.c | 409 ++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy.c | 4 +- include/phy.h | 1 + 5 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 drivers/net/phy/motorcomm.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 5eaff053a0..aba718566a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -212,6 +212,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 d38e99e717..e9523fed2e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PHY_MARVELL) += marvell.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..c7e44cfb63 --- /dev/null +++ b/drivers/net/phy/motorcomm.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
[..]
+static u32 ytphy_get_delay_reg_value(struct phy_device *phydev,
const char *prop_name,
const struct ytphy_cfg_reg_map *tbl,
int tb_size,
u16 *rxc_dly_en,
u32 dflt)
+{
int tb_size_half = tb_size / 2;
u32 val;
int i;
if (ofnode_read_u32(phydev->node, prop_name, &val))
goto err_dts_val;
Please move to your ofdata_to_plat() method.
Also, use dev_read_u32() when you have a device.
[.]
+static int yt8531_startup(struct phy_device *phydev) +{
bool tx_clk_adj_enabled = false;
bool tx_clk_1000_inverted = false;
bool tx_clk_100_inverted = false;
bool tx_clk_10_inverted = false;
u16 val = 0;
int ret;
ret = genphy_update_link(phydev);
if (ret)
return ret;
ret = yt8531_parse_status(phydev);
if (ret)
return ret;
if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled"))
tx_clk_adj_enabled = true;
priv->tx_clk_adj_enabled = ofnode_read_bool(...)
Please fix globally
Regards, Simon

On 2023/3/19 4:20, Simon Glass wrote:
Hi Yanhong,
On Thu, 16 Mar 2023 at 19:06, Yanhong Wang yanhong.wang@starfivetech.com wrote:
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
drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/motorcomm.c | 409 ++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy.c | 4 +- include/phy.h | 1 + 5 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 drivers/net/phy/motorcomm.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 5eaff053a0..aba718566a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -212,6 +212,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 d38e99e717..e9523fed2e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PHY_MARVELL) += marvell.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..c7e44cfb63 --- /dev/null +++ b/drivers/net/phy/motorcomm.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
[..]
+static u32 ytphy_get_delay_reg_value(struct phy_device *phydev,
const char *prop_name,
const struct ytphy_cfg_reg_map *tbl,
int tb_size,
u16 *rxc_dly_en,
u32 dflt)
+{
int tb_size_half = tb_size / 2;
u32 val;
int i;
if (ofnode_read_u32(phydev->node, prop_name, &val))
goto err_dts_val;
Please move to your ofdata_to_plat() method.
Also, use dev_read_u32() when you have a device.
[.]
Thanks. I will define a platform data structure for saving device-related configurations in the next version.
+static int yt8531_startup(struct phy_device *phydev) +{
bool tx_clk_adj_enabled = false;
bool tx_clk_1000_inverted = false;
bool tx_clk_100_inverted = false;
bool tx_clk_10_inverted = false;
u16 val = 0;
int ret;
ret = genphy_update_link(phydev);
if (ret)
return ret;
ret = yt8531_parse_status(phydev);
if (ret)
return ret;
if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled"))
tx_clk_adj_enabled = true;
priv->tx_clk_adj_enabled = ofnode_read_bool(...)
Please fix globally
Ok. I will fixed.
Regards, Simon

On 2023/3/19 4:20, Simon Glass wrote:
Hi Yanhong,
On Thu, 16 Mar 2023 at 19:06, Yanhong Wang yanhong.wang@starfivetech.com wrote:
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
drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/motorcomm.c | 409 ++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy.c | 4 +- include/phy.h | 1 + 5 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 drivers/net/phy/motorcomm.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 5eaff053a0..aba718566a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -212,6 +212,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 d38e99e717..e9523fed2e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PHY_MARVELL) += marvell.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..c7e44cfb63 --- /dev/null +++ b/drivers/net/phy/motorcomm.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
[..]
+static u32 ytphy_get_delay_reg_value(struct phy_device *phydev,
const char *prop_name,
const struct ytphy_cfg_reg_map *tbl,
int tb_size,
u16 *rxc_dly_en,
u32 dflt)
+{
int tb_size_half = tb_size / 2;
u32 val;
int i;
if (ofnode_read_u32(phydev->node, prop_name, &val))
goto err_dts_val;
Please move to your ofdata_to_plat() method.
Also, use dev_read_u32() when you have a device.
[.]
The ethernet-phy@x node is a sub-node of the ethernet@y node, and the phy driver is not registered through U_BOOT_DRIVER, there is no matching dev structure, so the method dev_read_u32() unavailable.
The phy driver is not registered through U_BOOT_DRIVER, and the of_to_plat() method in the driver structure unavailable.
+static int yt8531_startup(struct phy_device *phydev) +{
bool tx_clk_adj_enabled = false;
bool tx_clk_1000_inverted = false;
bool tx_clk_100_inverted = false;
bool tx_clk_10_inverted = false;
u16 val = 0;
int ret;
ret = genphy_update_link(phydev);
if (ret)
return ret;
ret = yt8531_parse_status(phydev);
if (ret)
return ret;
if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled"))
tx_clk_adj_enabled = true;
priv->tx_clk_adj_enabled = ofnode_read_bool(...)
Define a motorocomm_priv structure to save the configuration of phy, roughly as follows:
motorocomm_priv = malloc(...); phydev->priv = motorocomm_priv; motorocomm_priv->tx_clk_adj_enabled = ofnode_read_bool(...);
Is this ok?
Please fix globally
Regards, Simon

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 --- drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/dwc_eth_qos.c | 6 + drivers/net/dwc_eth_qos.h | 2 + drivers/net/dwc_eth_qos_starfive.c | 306 +++++++++++++++++++++++++++++ 5 files changed, 322 insertions(+) create mode 100644 drivers/net/dwc_eth_qos_starfive.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ceadee98a1..161289d00f 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 75daa5e694..69af678757 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 112deb546d..9aecd56e73 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1718,6 +1718,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..20450497a9 100644 --- a/drivers/net/dwc_eth_qos.h +++ b/drivers/net/dwc_eth_qos.h @@ -279,6 +279,7 @@ struct eqos_priv { bool clk_ck_enabled; unsigned int tx_fifo_sz, rx_fifo_sz; u32 reset_delays[3]; + struct reset_ctl reset_ahb; };
void eqos_inval_desc_generic(void *desc); @@ -289,3 +290,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..eeb45981bd --- /dev/null +++ b/drivers/net/dwc_eth_qos_starfive.c @@ -0,0 +1,306 @@ +// 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 <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 + +static int eqos_interface_init_jh7110(struct udevice *dev, + phy_interface_t interface_type) +{ + struct regmap *regmap; + struct ofnode_phandle_args args; + unsigned int mode; + int ret; + + switch (interface_type) { + 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; + + regmap = syscon_regmap_lookup_by_phandle(dev, "starfive,syscon"); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + pr_err("Failed to get regmap: %d\n", ret); + return ret; + } + + return regmap_update_bits(regmap, args.args[0], + STARFIVE_DWMAC_PHY_INFT_FIELD << args.args[1], + mode << args.args[1]); +} + +static int eqos_set_tx_clk_speed_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + 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 (dev_read_bool(dev, "starfive,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 eqos_priv *eqos = dev_get_priv(dev); + int ret; + + ret = clk_enable(&eqos->clk_slave_bus); + if (ret < 0) + goto err; + + ret = clk_enable(&eqos->clk_master_bus); + if (ret < 0) + goto err_disable_clk_slave_bus; + + ret = clk_enable(&eqos->clk_ptp_ref); + if (ret < 0) + goto err_disable_clk_master_bus; + + ret = clk_enable(&eqos->clk_tx); + if (ret < 0) + goto err_disable_clk_ptp_ref; + + ret = clk_enable(&eqos->clk_ck); + if (ret < 0) + goto err_disable_clk_tx; + + return 0; + +err_disable_clk_tx: + clk_disable(&eqos->clk_tx); +err_disable_clk_ptp_ref: + clk_disable(&eqos->clk_ptp_ref); +err_disable_clk_master_bus: + clk_disable(&eqos->clk_master_bus); +err_disable_clk_slave_bus: + clk_disable(&eqos->clk_slave_bus); +err: + debug("%s: FAILED: %d\n", __func__, ret); + + return ret; +} + +static int eqos_stop_clks_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + clk_disable(&eqos->clk_ck); + clk_disable(&eqos->clk_tx); + clk_disable(&eqos->clk_ptp_ref); + clk_disable(&eqos->clk_master_bus); + clk_disable(&eqos->clk_slave_bus); + + return 0; +} + +static int eqos_start_resets_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + ret = reset_deassert(&eqos->reset_ctl); + if (ret < 0) + return ret; + + ret = reset_deassert(&eqos->reset_ahb); + if (ret < 0) + goto err_free_reset_ctl; + + return 0; + +err_free_reset_ctl: + reset_assert(&eqos->reset_ctl); + return ret; +} + +static int eqos_stop_resets_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + reset_assert(&eqos->reset_ctl); + reset_assert(&eqos->reset_ahb); + + return 0; +} + +static int eqos_remove_resources_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + clk_free(&eqos->clk_tx); + clk_free(&eqos->clk_ck); + clk_free(&eqos->clk_slave_bus); + clk_free(&eqos->clk_master_bus); + reset_free(&eqos->reset_ahb); + reset_free(&eqos->reset_ctl); + + return 0; +} + +static int eqos_probe_resources_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + phy_interface_t interface; + int ret; + + interface = eqos->config->interface(dev); + + if (interface == PHY_INTERFACE_MODE_NA) { + pr_err("Invalid PHY interface\n"); + return -EINVAL; + } + + ret = reset_get_by_name(dev, "stmmaceth", &eqos->reset_ctl); + if (ret) + return ret; + + ret = reset_get_by_name(dev, "ahb", &eqos->reset_ahb); + if (ret) + goto err_free_reset_stmmaceth; + + ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); + if (ret) + goto err_free_reset_ahb; + + ret = clk_get_by_name(dev, "pclk", &eqos->clk_slave_bus); + if (ret) + goto err_free_clk_stmmaceth; + + ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref); + if (ret) + goto err_free_clk_pclk; + + ret = clk_get_by_name(dev, "tx", &eqos->clk_ck); + if (ret) + goto err_free_clk_ptp_ref; + + ret = clk_get_by_name(dev, "gtx", &eqos->clk_tx); + if (ret) + goto err_free_clk_tx; + + return eqos_interface_init_jh7110(dev, interface); + +err_free_clk_tx: + clk_free(&eqos->clk_tx); +err_free_clk_ptp_ref: + clk_free(&eqos->clk_ptp_ref); +err_free_clk_pclk: + clk_free(&eqos->clk_slave_bus); +err_free_clk_stmmaceth: + clk_free(&eqos->clk_master_bus); +err_free_reset_ahb: + reset_free(&eqos->reset_ahb); +err_free_reset_stmmaceth: + reset_free(&eqos->reset_ctl); + + return ret; +} + +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 +}; + +struct eqos_config __maybe_unused eqos_jh7110_config = { + .reg_access_always_ok = false, + .mdio_wait = 10, + .swr_wait = 50, + .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 +};

Hi Yanhong,
On Thu, 16 Mar 2023 at 19:07, Yanhong Wang yanhong.wang@starfivetech.com wrote:
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
drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/dwc_eth_qos.c | 6 + drivers/net/dwc_eth_qos.h | 2 + drivers/net/dwc_eth_qos_starfive.c | 306 +++++++++++++++++++++++++++++ 5 files changed, 322 insertions(+) create mode 100644 drivers/net/dwc_eth_qos_starfive.c
[..]
diff --git a/drivers/net/dwc_eth_qos_starfive.c b/drivers/net/dwc_eth_qos_starfive.c new file mode 100644 index 0000000000..eeb45981bd --- /dev/null +++ b/drivers/net/dwc_eth_qos_starfive.c @@ -0,0 +1,306 @@ +// 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 <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
+static int eqos_interface_init_jh7110(struct udevice *dev,
phy_interface_t interface_type)
+{
struct regmap *regmap;
struct ofnode_phandle_args args;
unsigned int mode;
int ret;
switch (interface_type) {
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);
You must read the DT in an ofdata_to_plat() method (or probe() if that doesn't suit). Put it in a struct.
You must not read it constantly at runtime throughout your driver. It is slow and error-prone. [..]
+struct eqos_config __maybe_unused eqos_jh7110_config = {
.reg_access_always_ok = false,
.mdio_wait = 10,
.swr_wait = 50,
.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
+};
2.17.1
What is that data for? Please add a comment.
Regards, SImom

On 2023/3/19 4:20, Simon Glass wrote:
Hi Yanhong,
On Thu, 16 Mar 2023 at 19:07, Yanhong Wang yanhong.wang@starfivetech.com wrote:
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
drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/dwc_eth_qos.c | 6 + drivers/net/dwc_eth_qos.h | 2 + drivers/net/dwc_eth_qos_starfive.c | 306 +++++++++++++++++++++++++++++ 5 files changed, 322 insertions(+) create mode 100644 drivers/net/dwc_eth_qos_starfive.c
[..]
diff --git a/drivers/net/dwc_eth_qos_starfive.c b/drivers/net/dwc_eth_qos_starfive.c new file mode 100644 index 0000000000..eeb45981bd --- /dev/null +++ b/drivers/net/dwc_eth_qos_starfive.c @@ -0,0 +1,306 @@ +// 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 <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
+static int eqos_interface_init_jh7110(struct udevice *dev,
phy_interface_t interface_type)
+{
struct regmap *regmap;
struct ofnode_phandle_args args;
unsigned int mode;
int ret;
switch (interface_type) {
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);
You must read the DT in an ofdata_to_plat() method (or probe() if that doesn't suit). Put it in a struct.
You must not read it constantly at runtime throughout your driver. It is slow and error-prone. [..]
Thanks. I will define a platform data structure for saving device-related configurations in the next version.
+struct eqos_config __maybe_unused eqos_jh7110_config = {
.reg_access_always_ok = false,
.mdio_wait = 10,
.swr_wait = 50,
.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
+};
2.17.1
What is that data for? Please add a comment.
The definition of these parameters refers to IMX platform, I will double confirm whether the definition of these parameters is accurate, and add corresponding comments in the next version.
Regards, SImom

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 --- arch/riscv/dts/jh7110.dtsi | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+)
diff --git a/arch/riscv/dts/jh7110.dtsi b/arch/riscv/dts/jh7110.dtsi index d3e9f92987..67267d9024 100644 --- a/arch/riscv/dts/jh7110.dtsi +++ b/arch/riscv/dts/jh7110.dtsi @@ -244,6 +244,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>; @@ -548,6 +555,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>;

The StarFive VisionFive2 board include 1.2A and 1.3B version.
v1.3B uses motorcomm YT8531(rgmii-id phy) x2, phy clock need delay and inverse configurations.
v1.2A gmac0 uses motorcomm YT8531(rgmii-id) PHY, and needs phy clock delay configurations.
v1.2A gmac1 uses motorcomm YT8512(rmii) PHY, and needs to switch rx and tx to external clock sources.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com --- .../jh7110-starfive-visionfive-2-v1.2a.dts | 13 +++++++ .../jh7110-starfive-visionfive-2-v1.3b.dts | 27 +++++++++++++++ .../dts/jh7110-starfive-visionfive-2.dtsi | 34 +++++++++++++++++++ 3 files changed, 74 insertions(+)
diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts b/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts index b9d26d7af7..918e77220a 100644 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts +++ b/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.2a.dts @@ -10,3 +10,16 @@ model = "StarFive VisionFive 2 v1.2A"; compatible = "starfive,visionfive-2-v1.2a", "starfive,jh7110"; }; + +&gmac1 { + phy-mode = "rmii"; + assigned-clocks = <&syscrg JH7110_SYSCLK_GMAC1_TX>, + <&syscrg JH7110_SYSCLK_GMAC1_RX>; + assigned-clock-parents = <&syscrg JH7110_SYSCLK_GMAC1_RMII_RTX>, + <&syscrg JH7110_SYSCLK_GMAC1_RMII_RTX>; +}; + +&phy0 { + rx-internal-delay-ps = <1900>; + tx-internal-delay-ps = <1350>; +}; diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b.dts b/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b.dts index 3b3b3453a1..0fcd6ab80f 100644 --- a/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b.dts +++ b/arch/riscv/dts/jh7110-starfive-visionfive-2-v1.3b.dts @@ -10,3 +10,30 @@ model = "StarFive VisionFive 2 v1.3B"; compatible = "starfive,visionfive-2-v1.3b", "starfive,jh7110"; }; + +&gmac0 { + starfive,tx-use-rgmii-clk; + assigned-clocks = <&aoncrg JH7110_AONCLK_GMAC0_TX>; + assigned-clock-parents = <&aoncrg JH7110_AONCLK_GMAC0_RMII_RTX>; +}; + +&gmac1 { + starfive,tx-use-rgmii-clk; + assigned-clocks = <&syscrg JH7110_SYSCLK_GMAC1_TX>; + assigned-clock-parents = <&syscrg JH7110_SYSCLK_GMAC1_RMII_RTX>; +}; + +&phy0 { + motorcomm,tx-clk-adj-enabled; + motorcomm,tx-clk-100-inverted; + motorcomm,tx-clk-1000-inverted; + rx-internal-delay-ps = <1900>; + tx-internal-delay-ps = <1500>; +}; + +&phy1 { + motorcomm,tx-clk-adj-enabled; + motorcomm,tx-clk-100-inverted; + rx-internal-delay-ps = <0>; + tx-internal-delay-ps = <0>; +}; 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>; + }; + }; +};

Enable DWC_ETH_QOS and PHY_MOTORCOMM configuration to support ethernet function for StarFive VisionFive 2 board.
Signed-off-by: Yanhong Wang yanhong.wang@starfivetech.com --- configs/starfive_visionfive2_defconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index 550d0ff3ab..18f0d8fd27 100644 --- a/configs/starfive_visionfive2_defconfig +++ b/configs/starfive_visionfive2_defconfig @@ -52,6 +52,9 @@ CONFIG_SYS_BOOTM_LEN=0x4000000 CONFIG_CMD_MEMINFO=y CONFIG_CMD_TFTPPUT=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y CONFIG_SPL_CLK_COMPOSITE_CCF=y CONFIG_CLK_COMPOSITE_CCF=y CONFIG_SPL_CLK_JH7110=y @@ -65,6 +68,15 @@ 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_PHY_MSCC is not set +CONFIG_DM_MDIO=y +CONFIG_DM_ETH_PHY=y +CONFIG_DWC_ETH_QOS=y +CONFIG_DWC_ETH_QOS_STARFIVE=y +CONFIG_RGMII=y +# CONFIG_MII is not set +CONFIG_RMII=y CONFIG_PINCTRL=y CONFIG_PINCONF=y CONFIG_SPL_PINCTRL=y @@ -72,6 +84,7 @@ CONFIG_SPL_PINCONF=y CONFIG_SPL_PINCTRL_STARFIVE=y CONFIG_SPL_PINCTRL_STARFIVE_JH7110=y CONFIG_PINCTRL_STARFIVE=y +# CONFIG_POWER is not set # CONFIG_RAM_SIFIVE is not set CONFIG_SYS_NS16550=y CONFIG_CADENCE_QSPI=y

On Fri, 17 Mar 2023 09:05:31 +0800 Yanhong Wang yanhong.wang@starfivetech.com wrote:
This series adds ethernet support for the StarFive JH7110 RISC-V SoC. The series includes 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.
The PHY and MAC driver has been tested on the StarFive VisionFive 2 1.2A and 1.3B boards and works normally.
At least a smoke test here succeeded as well, I'm seeing replies to DHCP. However:
| Model: StarFive VisionFive 2 v1.3B [...] | Net: | Warning: ethernet@16040000 (eth1) using random MAC address - e2:b9:39:bd:92:24 | | Warning: ethernet@16030000 (eth0) using random MAC address - 22:da:dc:e6:2c:17 | eth0: ethernet@16030000, eth1: ethernet@16040000 [...]
What's missing to read the correct MACs from the EEPROM?
Torsten

On 2023/3/24 20:53, Torsten Duwe wrote:
On Fri, 17 Mar 2023 09:05:31 +0800 Yanhong Wang yanhong.wang@starfivetech.com wrote:
This series adds ethernet support for the StarFive JH7110 RISC-V SoC. The series includes 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.
The PHY and MAC driver has been tested on the StarFive VisionFive 2 1.2A and 1.3B boards and works normally.
At least a smoke test here succeeded as well, I'm seeing replies to DHCP. However:
| Model: StarFive VisionFive 2 v1.3B [...] | Net: | Warning: ethernet@16040000 (eth1) using random MAC address - e2:b9:39:bd:92:24 | | Warning: ethernet@16030000 (eth0) using random MAC address - 22:da:dc:e6:2c:17 | eth0: ethernet@16030000, eth1: ethernet@16040000 [...]
What's missing to read the correct MACs from the EEPROM?
The minimum system of u-boot supporting JH7110 does not contain EEPROM and cannot read the MAC address from EEPROM, so enable the CONFIG_NET_RANDOM_ETHADDR, EEPROM will be supported in the future, and the MAC address will be read from EEPROM.
Torsten

On Mon, 27 Mar 2023 10:22:37 +0800 yanhong wang yanhong.wang@starfivetech.com wrote:
On 2023/3/24 20:53, Torsten Duwe wrote:
What's missing to read the correct MACs from the EEPROM?
The minimum system of u-boot supporting JH7110 does not contain EEPROM
[...]
Thanks for the info!
Torsten
participants (4)
-
Simon Glass
-
Torsten Duwe
-
Yanhong Wang
-
yanhong wang