git: cd92dd23241e - main - eqos: Add StarFive JH7110 variant

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Wed, 02 Apr 2025 16:57:10 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=cd92dd23241e22dce06ebeb0c8e98eec5afcc896

commit cd92dd23241e22dce06ebeb0c8e98eec5afcc896
Author:     Jari Sihvola <jsihv@gmx.com>
AuthorDate: 2025-04-02 16:30:23 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2025-04-02 16:56:38 +0000

    eqos: Add StarFive JH7110 variant
    
    Found on the VisionFive v2 SBC, and similar.
    
    Reviewed by:    mhorne
    Tested by:      mhorne
    Discussed with: sos
    Differential Revision:  https://reviews.freebsd.org/D45600
---
 sys/dev/eqos/if_eqos.c            |  33 ++++--
 sys/dev/eqos/if_eqos_reg.h        |   1 +
 sys/dev/eqos/if_eqos_starfive.c   | 219 ++++++++++++++++++++++++++++++++++++++
 sys/dev/eqos/if_eqos_var.h        |   7 ++
 sys/riscv/conf/std.starfive       |   2 +
 sys/riscv/starfive/files.starfive |   4 +
 6 files changed, 260 insertions(+), 6 deletions(-)

diff --git a/sys/dev/eqos/if_eqos.c b/sys/dev/eqos/if_eqos.c
index 6e2eea2e6c37..de3d8da7c3bf 100644
--- a/sys/dev/eqos/if_eqos.c
+++ b/sys/dev/eqos/if_eqos.c
@@ -456,7 +456,7 @@ eqos_reset(struct eqos_softc *sc)
 	int retry;
 
 	WR4(sc, GMAC_DMA_MODE, GMAC_DMA_MODE_SWR);
-	for (retry = 2000; retry > 0; retry--) {
+	for (retry = 5000; retry > 0; retry--) {
 		DELAY(1000);
 		val = RD4(sc, GMAC_DMA_MODE);
 		if (!(val & GMAC_DMA_MODE_SWR))
@@ -491,7 +491,7 @@ eqos_init(void *if_softc)
 	struct eqos_softc *sc = if_softc;
 	if_t ifp = sc->ifp;
 	struct mii_data *mii = device_get_softc(sc->miibus);
-	uint32_t val;
+	uint32_t val, mtl_tx_val, mtl_rx_val;
 
 	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
 		return;
@@ -508,13 +508,18 @@ eqos_init(void *if_softc)
 	val = RD4(sc, GMAC_DMA_CHAN0_CONTROL);
 	val &= ~GMAC_DMA_CHAN0_CONTROL_DSL_MASK;
 	val |= ((DESC_ALIGN - 16) / 8) << GMAC_DMA_CHAN0_CONTROL_DSL_SHIFT;
-	val |= GMAC_DMA_CHAN0_CONTROL_PBLX8;
+	if (sc->pblx8)
+		val |= GMAC_DMA_CHAN0_CONTROL_PBLX8;
 	WR4(sc, GMAC_DMA_CHAN0_CONTROL, val);
 	val = RD4(sc, GMAC_DMA_CHAN0_TX_CONTROL);
+	if (sc->txpbl > 0)
+		val |= (sc->txpbl << GMAC_DMA_CHAN0_TXRX_PBL_SHIFT);
 	val |= GMAC_DMA_CHAN0_TX_CONTROL_OSP;
 	val |= GMAC_DMA_CHAN0_TX_CONTROL_START;
 	WR4(sc, GMAC_DMA_CHAN0_TX_CONTROL, val);
 	val = RD4(sc, GMAC_DMA_CHAN0_RX_CONTROL);
+	if (sc->rxpbl > 0)
+		val |= (sc->rxpbl << GMAC_DMA_CHAN0_TXRX_PBL_SHIFT);
 	val &= ~GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_MASK;
 	val |= (MCLBYTES << GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT);
 	val |= GMAC_DMA_CHAN0_RX_CONTROL_START;
@@ -527,11 +532,19 @@ eqos_init(void *if_softc)
 	    GMAC_MMC_CONTROL_CNTPRSTLVL);
 
 	/* Configure operation modes */
+	if (sc->thresh_dma_mode) {
+		mtl_tx_val = sc->ttc;
+		mtl_rx_val = sc->rtc;
+	} else {
+		mtl_tx_val = GMAC_MTL_TXQ0_OPERATION_MODE_TSF;
+		mtl_rx_val = GMAC_MTL_RXQ0_OPERATION_MODE_RSF;
+	}
+
 	WR4(sc, GMAC_MTL_TXQ0_OPERATION_MODE,
-	    GMAC_MTL_TXQ0_OPERATION_MODE_TSF |
+	    mtl_tx_val |
 	    GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_EN);
 	WR4(sc, GMAC_MTL_RXQ0_OPERATION_MODE,
-	    GMAC_MTL_RXQ0_OPERATION_MODE_RSF |
+	    mtl_rx_val |
 	    GMAC_MTL_RXQ0_OPERATION_MODE_FEP |
 	    GMAC_MTL_RXQ0_OPERATION_MODE_FUP);
 
@@ -1112,6 +1125,14 @@ eqos_attach(device_t dev)
 	int error;
 	int n;
 
+	/* default values */
+	sc->thresh_dma_mode = false;
+	sc->pblx8 = true;
+	sc->txpbl = 0;
+	sc->rxpbl = 0;
+	sc->ttc = 0x10;
+	sc->rtc = 0;
+
 	/* setup resources */
 	if (bus_alloc_resources(dev, eqos_spec, sc->res)) {
 		device_printf(dev, "Could not allocate resources\n");
@@ -1128,7 +1149,7 @@ eqos_attach(device_t dev)
 	    GMAC_MAC_VERSION_USERVER_SHIFT;
 	snpsver = ver & GMAC_MAC_VERSION_SNPSVER_MASK;
 
-	if (snpsver != 0x51) {
+	if (snpsver != 0x51 && snpsver != 0x52) {
 		device_printf(dev, "EQOS version 0x%02x not supported\n",
 		    snpsver);
 		return (ENXIO);
diff --git a/sys/dev/eqos/if_eqos_reg.h b/sys/dev/eqos/if_eqos_reg.h
index f9e7f9368cf2..fe7440bd19c7 100644
--- a/sys/dev/eqos/if_eqos_reg.h
+++ b/sys/dev/eqos/if_eqos_reg.h
@@ -241,6 +241,7 @@
 #define	GMAC_DMA_CHAN0_RX_END_ADDR		0x1128
 #define	GMAC_DMA_CHAN0_TX_RING_LEN		0x112C
 #define	GMAC_DMA_CHAN0_RX_RING_LEN		0x1130
+#define	 GMAC_DMA_CHAN0_TXRX_PBL_SHIFT          16
 #define	GMAC_DMA_CHAN0_INTR_ENABLE		0x1134
 #define	 GMAC_DMA_CHAN0_INTR_ENABLE_NIE		(1U << 15)
 #define	 GMAC_DMA_CHAN0_INTR_ENABLE_AIE		(1U << 14)
diff --git a/sys/dev/eqos/if_eqos_starfive.c b/sys/dev/eqos/if_eqos_starfive.c
new file mode 100644
index 000000000000..62f8b3f38983
--- /dev/null
+++ b/sys/dev/eqos/if_eqos_starfive.c
@@ -0,0 +1,219 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
+ */
+
+#include "opt_platform.h"
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/gpio.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/hwreset/hwreset.h>
+#include <dev/regulator/regulator.h>
+
+#include <dev/eqos/if_eqos_var.h>
+
+#include "if_eqos_if.h"
+#include "gpio_if.h"
+
+#include <dev/clk/clk.h>
+
+/* JH7110's board specific code for eqos Ethernet controller driver */
+
+#define JH7110_CSR_FREQ		198000000
+
+#define	WR4(sc, o, v) bus_write_4(sc->base.res[EQOS_RES_MEM], (o), (v))
+
+static const struct ofw_compat_data compat_data[] = {
+	{"starfive,jh7110-dwmac",	1},
+	{ NULL,				0}
+};
+
+struct if_eqos_starfive_softc {
+	struct eqos_softc		base;
+	clk_t				gtx;
+	clk_t				tx;
+	clk_t				stmmaceth;
+	clk_t				pclk;
+};
+
+static int
+if_eqos_starfive_set_speed(device_t dev, int speed)
+{
+	struct if_eqos_starfive_softc *sc = device_get_softc(dev);
+	uint64_t freq;
+	int err;
+
+	switch (speed) {
+	case IFM_1000_T:
+	case IFM_1000_SX:
+		freq = 125000000;
+		break;
+	case IFM_100_TX:
+		freq = 25000000;
+		break;
+	case IFM_10_T:
+		freq = 2500000;
+		break;
+	default:
+		device_printf(dev, "unsupported media %u\n", speed);
+		return (-EINVAL);
+	}
+
+	clk_set_freq(sc->gtx, freq, 0);
+	err = clk_enable(sc->gtx);
+	if (err != 0) {
+		device_printf(dev, "Could not enable clock %s\n",
+		    clk_get_name(sc->gtx));
+	}
+
+	return (0);
+}
+
+
+
+static int
+if_eqos_starfive_clk_init(device_t dev)
+{
+	struct if_eqos_starfive_softc *sc = device_get_softc(dev);
+	int err;
+
+	if (clk_get_by_ofw_name(dev, 0, "gtx", &sc->gtx) != 0) {
+		device_printf(sc->base.dev, "could not get gtx clock\n");
+		return (ENXIO);
+	}
+
+	if (clk_get_by_ofw_name(dev, 0, "tx", &sc->tx) == 0) {
+		err = clk_enable(sc->tx);
+		if (err != 0) {
+			device_printf(dev, "Could not enable clock %s\n",
+			    clk_get_name(sc->tx));
+		}
+	}
+	if (clk_get_by_ofw_name(dev, 0, "stmmaceth", &sc->stmmaceth) == 0) {
+		err = clk_enable(sc->stmmaceth);
+		if (err != 0) {
+			device_printf(dev, "Could not enable clock %s\n",
+			    clk_get_name(sc->stmmaceth));
+		}
+	}
+	if (clk_get_by_ofw_name(dev, 0, "pclk", &sc->pclk) == 0) {
+		err = clk_enable(sc->pclk);
+		if (err != 0) {
+			device_printf(dev, "Could not enable clock %s\n",
+			    clk_get_name(sc->pclk));
+		}
+	}
+
+	return (0);
+}
+
+static int
+if_eqos_starfive_init(device_t dev)
+{
+	struct if_eqos_starfive_softc *sc = device_get_softc(dev);
+	hwreset_t rst_ahb, rst_stmmaceth;
+	phandle_t node;
+
+	node = ofw_bus_get_node(dev);
+
+	sc->base.ttc = 0x10;
+	sc->base.rtc = 0;
+
+	if (OF_hasprop(node, "snps,force_thresh_dma_mode"))
+		sc->base.thresh_dma_mode = true;
+
+	if (OF_hasprop(node, "snps,no-pbl-x8"))
+		sc->base.pblx8 = false;
+
+	if (OF_hasprop(node, "snps,txpbl")) {
+		OF_getencprop(node, "snps,txpbl", &sc->base.txpbl,
+		    sizeof(sc->base.txpbl));
+	}
+	if (OF_hasprop(node, "snps,rxpbl")) {
+		OF_getencprop(node, "snps,rxpbl", &sc->base.rxpbl,
+		    sizeof(sc->base.rxpbl));
+	}
+
+	if (hwreset_get_by_ofw_name(dev, 0, "ahb", &rst_ahb)) {
+		device_printf(dev, "Cannot get ahb reset\n");
+		return (ENXIO);
+	}
+	if (hwreset_assert(rst_ahb) != 0) {
+		device_printf(dev, "Cannot assert ahb reset\n");
+		return (ENXIO);
+	}
+
+	if (hwreset_get_by_ofw_name(dev, 0, "stmmaceth", &rst_stmmaceth)) {
+		device_printf(dev, "Cannot get stmmaceth reset\n");
+		return (ENXIO);
+	}
+	if (hwreset_assert(rst_stmmaceth) != 0) {
+		device_printf(dev, "Cannot assert stmmaceth reset\n");
+		return (ENXIO);
+	}
+
+	sc->base.csr_clock = JH7110_CSR_FREQ;
+	sc->base.csr_clock_range = GMAC_MAC_MDIO_ADDRESS_CR_150_250;
+
+	if (if_eqos_starfive_clk_init(dev) != 0) {
+		device_printf(dev, "Clock initialization failed\n");
+		return (ENXIO);
+	}
+	if (hwreset_deassert(rst_ahb) != 0) {
+		device_printf(dev, "Cannot deassert rst_ahb\n");
+		return (ENXIO);
+	}
+	if (hwreset_deassert(rst_stmmaceth) != 0) {
+		device_printf(dev, "Cannot deassert rst_stmmaceth\n");
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+eqos_starfive_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "DesignWare EQOS Gigabit Ethernet for JH7110");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+
+static device_method_t eqos_starfive_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		eqos_starfive_probe),
+
+	/* EQOS interface */
+	DEVMETHOD(if_eqos_init,		if_eqos_starfive_init),
+	DEVMETHOD(if_eqos_set_speed,	if_eqos_starfive_set_speed),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(eqos, eqos_starfive_driver, eqos_starfive_methods,
+    sizeof(struct if_eqos_starfive_softc), eqos_driver);
+DRIVER_MODULE(eqos_starfive, simplebus, eqos_starfive_driver, 0, 0);
diff --git a/sys/dev/eqos/if_eqos_var.h b/sys/dev/eqos/if_eqos_var.h
index c21a703747ec..892b15ba589e 100644
--- a/sys/dev/eqos/if_eqos_var.h
+++ b/sys/dev/eqos/if_eqos_var.h
@@ -85,6 +85,13 @@ struct eqos_softc {
 	bool			link_up;
 	int			tx_watchdog;
 
+	bool			thresh_dma_mode;
+	bool			pblx8;
+	uint32_t		txpbl;
+	uint32_t		rxpbl;
+	uint32_t		ttc;
+	uint32_t		rtc;
+
 	struct ifnet		*ifp;
 	device_t		miibus;
 	struct mtx		lock;
diff --git a/sys/riscv/conf/std.starfive b/sys/riscv/conf/std.starfive
index e4e3e7c46f3e..9bdb1af9e79c 100644
--- a/sys/riscv/conf/std.starfive
+++ b/sys/riscv/conf/std.starfive
@@ -4,6 +4,8 @@
 
 device		uart_snps	# DesignWare Synopsis UART driver
 
+device		eqos
+
 # MMC/SD/SDIO Card slot support
 device		dwmmc
 device		dwmmc_starfive
diff --git a/sys/riscv/starfive/files.starfive b/sys/riscv/starfive/files.starfive
index 10c56448970d..57d4618d00f9 100644
--- a/sys/riscv/starfive/files.starfive
+++ b/sys/riscv/starfive/files.starfive
@@ -5,4 +5,8 @@ dev/clk/starfive/jh7110_clk_sys.c	standard
 dev/clk/starfive/jh7110_clk_stg.c	standard
 dev/mmc/host/dwmmc_starfive.c		optional	dwmmc_starfive fdt
 
+dev/eqos/if_eqos.c			optional	eqos
+dev/eqos/if_eqos_if.m			optional	eqos
+dev/eqos/if_eqos_starfive.c		optional	eqos
+
 riscv/starfive/starfive_syscon.c	standard