From 569779ec17583d0237e72815299921aec677a84e Mon Sep 17 00:00:00 2001 From: Wei Liang Lim Date: Thu, 19 Oct 2023 14:36:18 +0800 Subject: drivers: net: dwc_eth_qos: Add GMAC support for Dubhe Signed-off-by: Wei Liang Lim --- arch/riscv/dts/dubhe.dtsi | 57 +++++++ arch/riscv/dts/dubhe_fpga.dts | 42 ++++- board/starfive/dubhe_fpga/Kconfig | 2 +- configs/starfive_dubhe_fpga_defconfig | 19 ++- drivers/net/dwc_eth_qos.c | 310 ++++++++++++++++++++++++++++++++++ drivers/net/dwc_eth_qos.h | 4 + include/configs/starfive-dubhe-fpga.h | 11 -- 7 files changed, 425 insertions(+), 20 deletions(-) diff --git a/arch/riscv/dts/dubhe.dtsi b/arch/riscv/dts/dubhe.dtsi index f689389c73..3ce659e1e7 100644 --- a/arch/riscv/dts/dubhe.dtsi +++ b/arch/riscv/dts/dubhe.dtsi @@ -33,6 +33,28 @@ interrupt-controller; }; }; + + cpu@1 { + compatible = "starfive,dubhe", "riscv"; + d-cache-block-size = <64>; + d-cache-sets = <128>; + d-cache-size = <65536>; + device_type = "cpu"; + i-cache-block-size = <64>; + i-cache-sets = <512>; + i-cache-size = <65536>; + i-tlb-sets = <1>; + i-tlb-size = <32>; + mmu-type = "riscv,sv48"; + reg = <0x1>; + riscv,isa = "rv64imafdcbhnv"; + tlb-split; + cpu1_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; }; soc { @@ -98,5 +120,40 @@ clocks = <&pbus_clk>; status = "disabled"; }; + + stmmac_axi_setup: stmmac-axi-config { + snps,wr_osr_lmt = <0xf>; + snps,rd_osr_lmt = <0xf>; + snps,blen = <256 128 64 32 0 0 0>; + }; + + gmac0: gmac0@10100000 { + compatible = "starfive,dubhe-eqos-5.20"; + reg = <0x0 0x10100000 0x0 0x10000>; + clock-names = "gtx", + "tx", + "ptp_ref", + "stmmaceth", + "pclk", + "gtxc"; + interrupt-parent = <&plic0>; + interrupts = <8>, <11>, <12> ; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + max-frame-size = <1500>; + phy-mode = "rgmii-id"; + snps,multicast-filter-bins = <64>; + snps,perfect-filter-entries = <128>; + 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 = <4>; + snps,rxpbl = <4>; + status = "disabled"; + }; }; }; diff --git a/arch/riscv/dts/dubhe_fpga.dts b/arch/riscv/dts/dubhe_fpga.dts index 56cd3d2a03..5a04f9b6d3 100644 --- a/arch/riscv/dts/dubhe_fpga.dts +++ b/arch/riscv/dts/dubhe_fpga.dts @@ -27,6 +27,41 @@ }; soc { + fpga_2p5mhz_clk: fpga_2p5mhz_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <2500000>; + }; + + fpga_50mhz_clk: fpga_50mhz_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii-id"; + // clk_csr = <3>; + // max-speed = <10>; + phy-handle = <ðernet_phy0>; + clocks = <&fpga_2p5mhz_clk>, + <&fpga_2p5mhz_clk>, + <&fpga_2p5mhz_clk>, + <&fpga_50mhz_clk>, + <&fpga_50mhz_clk>, + <&fpga_2p5mhz_clk>; + + mdio0 { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + ethernet_phy0: ethernet-phy@0 { + reg = <0>; + max-speed = <10>; + }; }; }; @@ -149,12 +184,7 @@ qspi_ubootproper_opensbi_blob: blob-ext@2 { filename = "u-boot.itb"; - offset = <0x22000>; - }; - - qspi_kernel_blob: blob-ext@3 { - filename = "kernel.itb"; - offset = <0x400000>; + offset = <0x42000>; }; }; }; \ No newline at end of file diff --git a/board/starfive/dubhe_fpga/Kconfig b/board/starfive/dubhe_fpga/Kconfig index 99fe0e8508..6ffeb1a62f 100644 --- a/board/starfive/dubhe_fpga/Kconfig +++ b/board/starfive/dubhe_fpga/Kconfig @@ -15,7 +15,7 @@ config SYS_SOC config SYS_CONFIG_NAME default "starfive-dubhe-fpga" -config SYS_TEXT_BASE +config TEXT_BASE default 0x83000000 if SPL default 0x80000000 if !RISCV_SMODE default 0x80200000 if RISCV_SMODE diff --git a/configs/starfive_dubhe_fpga_defconfig b/configs/starfive_dubhe_fpga_defconfig index 519d2c8c04..01864bf666 100644 --- a/configs/starfive_dubhe_fpga_defconfig +++ b/configs/starfive_dubhe_fpga_defconfig @@ -48,5 +48,20 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_MMC=y CONFIG_MMC_SPI=y CONFIG_SPL_MMC_SUPPORT=y - - +CONFIG_SYS_LOAD_ADDR=0x84000000 +CONFIG_SPL_BSS_START_ADDR=0x80300000 +CONFIG_SPL_BSS_MAX_SIZE=0x00100000 +CONFIG_SPL_MAX_SIZE=0x00200000 +CONFIG_SYS_MALLOC_LEN=0x00100000 +CONFIG_SYS_BOOTM_LEN=0x04000000 +CONFIG_SYS_SPL_MALLOC_START=0x80400000 +CONFIG_SYS_SPL_MALLOC_SIZE=0x00100000 +CONFIG_SPL_STACK=0x80600000 +CONFIG_SYS_SDRAM_BASE=0x80000000 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x80600000 +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_PHY_MARVELL=y +CONFIG_DWC_ETH_QOS=y +CONFIG_DWC_ETH_QOS_STARFIVE=y +CONFIG_DM_GPIO=y diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 1e92bd9ca9..a0ba471365 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -346,6 +346,57 @@ err: #endif } +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) { + pr_err("clk_enable(clk_slave_bus) failed: %d", ret); + goto err; + } + + ret = clk_enable(&eqos->clk_master_bus); + if (ret < 0) { + pr_err("clk_enable(clk_master_bus) failed: %d", ret); + goto err_disable_clk_slave_bus; + } + + ret = clk_enable(&eqos->clk_ck); + if (ret < 0) { + pr_err("clk_enable(clk_ck) failed: %d", ret); + goto err_disable_clk_master_bus; + } + + ret = clk_enable(&eqos->clk_ptp_ref); + if (ret < 0) { + pr_err("clk_enable(clk_ptp_ref) failed: %d", ret); + goto err_disable_clk_gtx; + } + + ret = clk_enable(&eqos->clk_tx); + if (ret < 0) { + pr_err("clk_enable(clk_tx) failed: %d", ret); + goto err_disable_clk_ptp_ref; + } + + debug("%s: OK\n", __func__); + return 0; + +err_disable_clk_ptp_ref: + clk_disable(&eqos->clk_ptp_ref); +err_disable_clk_gtx: + clk_disable(&eqos->clk_rx); +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_tegra186(struct udevice *dev) { #ifdef CONFIG_CLK @@ -380,6 +431,20 @@ static int eqos_stop_clks_stm32(struct udevice *dev) return 0; } +static int eqos_stop_clks_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + clk_disable(&eqos->clk_tx); + clk_disable(&eqos->clk_ptp_ref); + clk_disable(&eqos->clk_ck); + clk_disable(&eqos->clk_master_bus); + clk_disable(&eqos->clk_slave_bus); + + debug("%s: OK\n", __func__); + return 0; +} + static int eqos_start_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -419,6 +484,29 @@ static int eqos_start_resets_tegra186(struct udevice *dev) return 0; } +#if 0 +static int eqos_start_resets_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + ret = reset_deassert_bulk(&eqos->reset_bulk); + if (ret < 0) { + pr_err("reset_deassert() failed: %d", ret); + return ret; + } + + ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); + if (ret < 0) { + pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret); + return ret; + } + + debug("%s: OK\n", __func__); + return 0; +} +#endif + static int eqos_stop_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -429,6 +517,16 @@ static int eqos_stop_resets_tegra186(struct udevice *dev) return 0; } +static int eqos_stop_resets_jh7110(struct udevice *dev) +{ +// struct eqos_priv *eqos = dev_get_priv(dev); + +// reset_assert_bulk(&eqos->reset_bulk); +// dm_gpio_set_value(&eqos->phy_reset_gpio, 0); + + return 0; +} + static int eqos_calibrate_pads_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -503,6 +601,16 @@ static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) #endif } +static ulong eqos_get_tick_clk_rate_jh7110(struct udevice *dev) +{ + return 4000000; +} + +__weak int jh7110_eqos_txclk_set_rate(unsigned long rate) +{ + return 0; +} + static int eqos_set_full_duplex(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -599,6 +707,36 @@ static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) return 0; } +static int eqos_set_tx_clk_speed_jh7110(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + ulong rate; + int ret; + + 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; + } + + ret = jh7110_eqos_txclk_set_rate(rate); + if (ret < 0) { + pr_err("jh7110 (tx_clk, %lu) failed: %d", rate, ret); + return ret; + } + + return 0; +} + static int eqos_adjust_link(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1484,11 +1622,103 @@ err_probe: return ret; } +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; + } + +#if 0 + ret = reset_get_bulk(dev, &eqos->reset_bulk); + if (ret) { + pr_err("Can't get reset: %d\n", ret); + return ret; + } + + ret = gpio_request_by_name(dev, "phy-reset-gpios", 0, + &eqos->phy_reset_gpio, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + if (ret) { + pr_err("gpio_request_by_name(phy reset) failed: %d", ret); + goto err_free_reset_eqos; + } +#endif + ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); + if (ret) { + pr_err("clk_get_by_name(master_bus) failed: %d", ret); + goto err_free_gpio_phy_reset; + } + + ret = clk_get_by_name(dev, "pclk", &eqos->clk_slave_bus); + if (ret) { + pr_err("clk_get_by_name(slave_bus) failed: %d", ret); + goto err_free_clk_master_bus; + } + + ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref); + if (ret) { + pr_err("clk_get_by_name(ptp_ref) failed: %d", ret); + goto err_free_clk_slave_bus; + return ret; + } + + ret = clk_get_by_name(dev, "gtx", &eqos->clk_ck); + if (ret) { + pr_err("clk_get_by_name(gtx) failed: %d", ret); + goto err_free_clk_ptp_ref; + } + + ret = clk_get_by_name(dev, "tx", &eqos->clk_tx); + if (ret) { + pr_err("clk_get_by_name(tx) failed: %d", ret); + goto err_free_clk_gtx; + } + + debug("%s: OK\n", __func__); + return 0; + +err_free_clk_gtx: + clk_free(&eqos->clk_ck); +err_free_clk_ptp_ref: + clk_free(&eqos->clk_ptp_ref); +err_free_clk_slave_bus: + clk_free(&eqos->clk_slave_bus); +err_free_clk_master_bus: + clk_free(&eqos->clk_master_bus); +err_free_gpio_phy_reset: + dm_gpio_free(dev, &eqos->phy_reset_gpio); +err_free_reset_eqos: + reset_free(&eqos->reset_ctl); + + return ret; +} + static phy_interface_t eqos_get_interface_tegra186(const struct udevice *dev) { return PHY_INTERFACE_MODE_MII; } +static phy_interface_t eqos_get_interface_jh7110(struct udevice *dev) +{ + const char *phy_mode; + phy_interface_t interface = PHY_INTERFACE_MODE_NA; + + debug("%s(dev=%p):\n", __func__, dev); + + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", NULL); + if (phy_mode) + interface = dev_read_phy_mode(dev); + + return interface; +} + static int eqos_remove_resources_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1527,6 +1757,22 @@ static int eqos_remove_resources_stm32(struct udevice *dev) 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_ptp_ref); + clk_free(&eqos->clk_ck); + clk_free(&eqos->clk_slave_bus); + clk_free(&eqos->clk_master_bus); + dm_gpio_free(dev, &eqos->phy_reset_gpio); + reset_free(&eqos->reset_ctl); + + debug("%s: OK\n", __func__); + return 0; +} + static int eqos_probe(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1699,6 +1945,64 @@ static const struct eqos_config __maybe_unused eqos_stm32_config = { .ops = &eqos_stm32_ops }; +static struct eqos_ops eqos_dubhe_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_null_ops, + .eqos_stop_resets = eqos_null_ops, + .eqos_start_resets = eqos_null_ops, + .eqos_stop_clks = eqos_null_ops, + .eqos_start_clks = eqos_null_ops, + .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_tick_clk_rate = eqos_get_tick_clk_rate_jh7110 +}; + +#if 0 +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_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 = eqos_get_interface_jh7110, + .ops = &eqos_jh7110_ops +}; +#endif + +struct eqos_config __maybe_unused eqos_dubhe_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 = eqos_get_interface_jh7110, + .ops = &eqos_dubhe_ops +}; + static const struct udevice_id eqos_ids[] = { #if IS_ENABLED(CONFIG_DWC_ETH_QOS_TEGRA186) { @@ -1726,11 +2030,17 @@ static const struct udevice_id eqos_ids[] = { }, #endif #if IS_ENABLED(CONFIG_DWC_ETH_QOS_STARFIVE) +#if 0 { .compatible = "starfive,jh7110-dwmac", .data = (ulong)&eqos_jh7110_config }, #endif + { + .compatible = "starfive,dubhe-eqos-5.20", + .data = (ulong)&eqos_dubhe_config + }, +#endif { } }; diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h index a6b719af80..cb2cc74dfd 100644 --- a/drivers/net/dwc_eth_qos.h +++ b/drivers/net/dwc_eth_qos.h @@ -83,7 +83,11 @@ struct eqos_mac_regs { #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 +#if CONFIG_IS_ENABLED(STARFIVE_JH7110) +#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 9 +#else #define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 +#endif #define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 #define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 diff --git a/include/configs/starfive-dubhe-fpga.h b/include/configs/starfive-dubhe-fpga.h index 86e94ba2fc..e59322ef51 100644 --- a/include/configs/starfive-dubhe-fpga.h +++ b/include/configs/starfive-dubhe-fpga.h @@ -1,16 +1,5 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define CONFIG_SPL_MAX_SIZE 0x00200000 -#define CONFIG_SPL_BSS_START_ADDR 0x80300000 -#define CONFIG_SPL_BSS_MAX_SIZE 0x00100000 -#define CONFIG_SYS_SPL_MALLOC_START 0x80400000 -#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00100000 -#define CONFIG_SPL_STACK 0x80600000 -#define CONFIG_SYS_SDRAM_BASE 0x80000000 -#define CONFIG_SYS_INIT_SP_ADDR 0x80600000 -#define CONFIG_SYS_LOAD_ADDR 0x84000000 -#define CONFIG_SYS_MALLOC_LEN 0x00100000 -#define CONFIG_SYS_BOOTM_LEN 0x04000000 #endif /* __CONFIG_H */ -- cgit v1.2.3