diff --git a/sys/dev/eqos/if_eqos.c b/sys/dev/eqos/if_eqos.c --- a/sys/dev/eqos/if_eqos.c +++ b/sys/dev/eqos/if_eqos.c @@ -456,7 +456,7 @@ int retry; WR4(sc, GMAC_DMA_MODE, GMAC_DMA_MODE_SWR); - for (retry = 2000; retry > 0; retry--) { + for (retry = 10000; retry > 0; retry--) { DELAY(1000); val = RD4(sc, GMAC_DMA_MODE); if (!(val & GMAC_DMA_MODE_SWR)) @@ -491,7 +491,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 --- 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_var.h b/sys/dev/eqos/if_eqos_var.h --- a/sys/dev/eqos/if_eqos_var.h +++ b/sys/dev/eqos/if_eqos_var.h @@ -85,6 +85,13 @@ 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; @@ -94,6 +101,8 @@ struct eqos_ring rx; }; +int eqos_phy_reset(device_t dev); + DECLARE_CLASS(eqos_driver); #endif diff --git a/sys/dev/mii/mcommphy.c b/sys/dev/mii/mcommphy.c --- a/sys/dev/mii/mcommphy.c +++ b/sys/dev/mii/mcommphy.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2022 Jared McNeill * Copyright (c) 2022 Soren Schmidt + * Copyright (c) 2024 Jari Sihvola * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,7 +27,8 @@ */ /* - * Motorcomm YT8511C / YT8511H Integrated 10/100/1000 Gigabit Ethernet phy + * Motorcomm YT8511C/YT8511H/YT8531 + * Integrated 10/100/1000 Gigabit Ethernet phy */ #include @@ -42,12 +44,16 @@ #include #include +#include +#include "miidevs.h" #include "miibus_if.h" -#define MCOMMPHY_OUI 0x000000 -#define MCOMMPHY_MODEL 0x10 -#define MCOMMPHY_REV 0x0a +#define MCOMMPHY_YT8511_OUI 0x000000 +#define MCOMMPHY_YT8511_MODEL 0x10 +#define MCOMMPHY_YT8511_REV 0x0a + +#define MCOMMPHY_YT8531_MODEL 0x11 #define EXT_REG_ADDR 0x1e #define EXT_REG_DATA 0x1f @@ -61,9 +67,49 @@ #define PHY_SLEEP_CONTROL1_REG 0x27 #define PLLON_IN_SLP 0x4000 +/* Registers and values for YT8531 */ +#define YT8531_CHIP_CONFIG 0xa001 +#define RXC_DLY_EN (1 << 8) + +#define YT8531_PAD_DRSTR_CFG 0xa010 +#define PAD_RXC_MASK 0x7 +#define PAD_RXC_SHIFT 13 +#define JH7110_RGMII_RXC_STRENGTH 6 + +#define YT8531_RGMII_CONFIG1 0xa003 +#define RX_DELAY_SEL_SHIFT 10 +#define RX_DELAY_SEL_MASK 0xf +#define RXC_DLY_THRESH 2250 +#define RXC_DLY_ADDON 1900 +#define TX_DELAY_SEL_FE_MASK 0xf +#define TX_DELAY_SEL_FE_SHIFT 4 +#define TX_DELAY_SEL_MASK 0xf +#define TX_DELAY_SEL_SHIFT 0 +#define TX_CLK_SEL (1 << 14) +#define INTERNAL_DLY_DIV 150 + +#define YT8531_SYNCE_CFG 0xa012 +#define EN_SYNC_E (1 << 6) + #define LOWEST_SET_BIT(mask) ((((mask) - 1) & (mask)) ^ (mask)) #define SHIFTIN(x, mask) ((x) * LOWEST_SET_BIT(mask)) +static const struct mii_phydesc mcommphys[] = { + MII_PHY_DESC(MOTORCOMM, YT8511), + MII_PHY_DESC(MOTORCOMM2, YT8531), + MII_PHY_END +}; + +struct mcommphy_softc { + mii_softc_t mii_sc; + device_t dev; + bool tx_10_inv; + bool tx_100_inv; + bool tx_1000_inv; +}; + +static void mcommphy_yt8531_speed_adjustment(struct mii_softc *sc); + static int mcommphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { @@ -79,11 +125,22 @@ if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; + } /* Update the media status. */ PHY_STATUS(sc); + /* + * For the needs of JH7110 which has two Ethernet devices with + * different TX inverted configuration depending on speed used + */ + if (sc->mii_mpd_model == MCOMMPHY_YT8531_MODEL && + sc->mii_media_active != mii->mii_media_active && + sc->mii_media_status != mii->mii_media_status) { + mcommphy_yt8531_speed_adjustment(sc); + } + /* Callback if something changed. */ mii_phy_update(sc, cmd); @@ -105,26 +162,22 @@ * The YT8511C reports an OUI of 0. Best we can do here is to match * exactly the contents of the PHY identification registers. */ - if (MII_OUI(ma->mii_id1, ma->mii_id2) == MCOMMPHY_OUI && - MII_MODEL(ma->mii_id2) == MCOMMPHY_MODEL && - MII_REV(ma->mii_id2) == MCOMMPHY_REV) { + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MCOMMPHY_YT8511_OUI && + MII_MODEL(ma->mii_id2) == MCOMMPHY_YT8511_MODEL && + MII_REV(ma->mii_id2) == MCOMMPHY_YT8511_REV) { device_set_desc(dev, "Motorcomm YT8511 media interface"); - return BUS_PROBE_DEFAULT; + return (BUS_PROBE_DEFAULT); } - return (ENXIO); + + /* YT8531 follows a conventional procedure */ + return (mii_phy_dev_probe(dev, mcommphys, BUS_PROBE_DEFAULT)); } -static int -mcommphy_attach(device_t dev) +static void +mcommphy_yt8511_setup(struct mii_softc *sc) { - struct mii_softc *sc = device_get_softc(dev); uint16_t oldaddr, data; - mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &mcommphy_funcs, 0); - - PHY_RESET(sc); - - /* begin chip stuff */ oldaddr = PHY_READ(sc, EXT_REG_ADDR); PHY_WRITE(sc, EXT_REG_ADDR, PHY_CLOCK_GATING_REG); @@ -150,21 +203,187 @@ PHY_WRITE(sc, EXT_REG_DATA, data); PHY_WRITE(sc, EXT_REG_ADDR, oldaddr); - /* end chip stuff */ +} + +static void +mcommphy_yt8531_speed_adjustment(struct mii_softc *sc) +{ + struct mcommphy_softc *mcomm_sc = (struct mcommphy_softc *)sc; + struct mii_data *mii = sc->mii_pdata; + bool tx_clk_inv = false; + uint16_t reg, oldaddr; + + /* + * Due to conflict between Callout API's lock and waiting malloc in + * mii_fdt_get_config() the device tree cannot be read here and its + * data is stored beforehand + */ + + if ((mii->mii_media_active & IFM_1000_T) != 0 && + mcomm_sc->tx_1000_inv == true) + tx_clk_inv = true; + else if ((mii->mii_media_active & IFM_100_TX) != 0 && + mcomm_sc->tx_100_inv == true) + tx_clk_inv = true; + else if ((mii->mii_media_active & IFM_10_T) != 0 && + mcomm_sc->tx_10_inv == true) + tx_clk_inv = true; + + oldaddr = PHY_READ(sc, EXT_REG_ADDR); + + PHY_WRITE(sc, EXT_REG_ADDR, YT8531_RGMII_CONFIG1); + reg = PHY_READ(sc, EXT_REG_DATA); + if (tx_clk_inv == true) + reg |= TX_CLK_SEL; + else + reg &= ~TX_CLK_SEL; + PHY_WRITE(sc, EXT_REG_DATA, reg); + + PHY_WRITE(sc, EXT_REG_ADDR, oldaddr); + + return; +} + +static int +mcommphy_yt8531_setup_delay(struct mii_softc *sc) +{ + struct mcommphy_softc *mcomm_sc = (struct mcommphy_softc *)sc; + mii_fdt_phy_config_t *cfg = mii_fdt_get_config(mcomm_sc->dev); + pcell_t val; + uint16_t reg, oldaddr; + int rx_delay, tx_delay = 0; + bool rxc_dly_en_off = false; + + if (OF_getencprop(cfg->phynode, "rx-internal-delay-ps", &val, + sizeof(val)) > 0) { + if (val <= RXC_DLY_THRESH && val % INTERNAL_DLY_DIV == 0) { + rx_delay = val / INTERNAL_DLY_DIV; + rxc_dly_en_off = true; + } else { + rx_delay = (val - RXC_DLY_ADDON) / INTERNAL_DLY_DIV; + if ((val - RXC_DLY_ADDON) % INTERNAL_DLY_DIV != 0) + return (ENXIO); + } + } + + if (OF_getencprop(cfg->phynode, "tx-internal-delay-ps", &val, + sizeof(val)) > 0) { + tx_delay = val / INTERNAL_DLY_DIV; + if (val % INTERNAL_DLY_DIV != 0) + return (ENXIO); + } + + mii_fdt_free_config(cfg); + + oldaddr = PHY_READ(sc, EXT_REG_ADDR); + + /* Modifying Chip Config register */ + PHY_WRITE(sc, EXT_REG_ADDR, YT8531_CHIP_CONFIG); + reg = PHY_READ(sc, EXT_REG_DATA); + if (rxc_dly_en_off == true) + reg &= ~(RXC_DLY_EN); + PHY_WRITE(sc, EXT_REG_DATA, reg); + + /* Modifying RGMII Config1 register */ + PHY_WRITE(sc, EXT_REG_ADDR, YT8531_RGMII_CONFIG1); + reg = PHY_READ(sc, EXT_REG_DATA); + reg &= ~(RX_DELAY_SEL_MASK << RX_DELAY_SEL_SHIFT); + reg |= rx_delay << RX_DELAY_SEL_SHIFT; + reg &= ~(TX_DELAY_SEL_MASK << TX_DELAY_SEL_SHIFT); + reg |= tx_delay << TX_DELAY_SEL_SHIFT; + PHY_WRITE(sc, EXT_REG_DATA, reg); + + PHY_WRITE(sc, EXT_REG_ADDR, oldaddr); + + return (0); +} + +static int +mcommphy_yt8531_setup(struct mii_softc *sc) +{ + struct mcommphy_softc *mcomm_sc = (struct mcommphy_softc *)sc; + mii_fdt_phy_config_t *cfg = mii_fdt_get_config(mcomm_sc->dev); + uint16_t reg, oldaddr; + + if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-10-inverted")) + mcomm_sc->tx_10_inv = true; + else + mcomm_sc->tx_10_inv = false; + + if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-100-inverted")) + mcomm_sc->tx_100_inv = true; + else + mcomm_sc->tx_100_inv = false; + + if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-1000-inverted")) + mcomm_sc->tx_1000_inv = true; + else + mcomm_sc->tx_1000_inv = false; + + mii_fdt_free_config(cfg); + + oldaddr = PHY_READ(sc, EXT_REG_ADDR); + + /* Modifying Pad Drive Strength register */ + PHY_WRITE(sc, EXT_REG_ADDR, YT8531_PAD_DRSTR_CFG); + reg = PHY_READ(sc, EXT_REG_DATA); + reg &= ~(PAD_RXC_MASK << PAD_RXC_SHIFT); + reg |= (JH7110_RGMII_RXC_STRENGTH << PAD_RXC_SHIFT); + PHY_WRITE(sc, EXT_REG_DATA, reg); + + /* Modifying SyncE Config register */ + PHY_WRITE(sc, EXT_REG_ADDR, YT8531_SYNCE_CFG); + reg = PHY_READ(sc, EXT_REG_DATA); + reg &= ~(EN_SYNC_E); + PHY_WRITE(sc, EXT_REG_DATA, reg); + + PHY_WRITE(sc, EXT_REG_ADDR, oldaddr); + + if (mcommphy_yt8531_setup_delay(sc) != 0) + return (ENXIO); + + return (0); +} - sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; - if (sc->mii_capabilities & BMSR_EXTSTAT) - sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); +static int +mcommphy_attach(device_t dev) +{ + struct mcommphy_softc *mcomm_sc = device_get_softc(dev); + mii_softc_t *mii_sc = &mcomm_sc->mii_sc; + int ret = 0; + + mcomm_sc->dev = dev; + + mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &mcommphy_funcs, 0); + + PHY_RESET(mii_sc); + + if (mii_sc->mii_mpd_model == MCOMMPHY_YT8511_MODEL) + mcommphy_yt8511_setup(mii_sc); + else if (mii_sc->mii_mpd_model == MCOMMPHY_YT8531_MODEL) + ret = mcommphy_yt8531_setup(mii_sc); + else { + device_printf(dev, "no PHY model detected\n"); + return (ENXIO); + } + if (ret) { + device_printf(dev, "PHY setup failed, error: %d\n", ret); + return (ret); + } + + mii_sc->mii_capabilities = PHY_READ(mii_sc, MII_BMSR) & + mii_sc->mii_capmask; + if (mii_sc->mii_capabilities & BMSR_EXTSTAT) + mii_sc->mii_extcapabilities = PHY_READ(mii_sc, MII_EXTSR); device_printf(dev, " "); - mii_phy_add_media(sc); + mii_phy_add_media(mii_sc); printf("\n"); - MIIBUS_MEDIAINIT(sc->mii_dev); + MIIBUS_MEDIAINIT(mii_sc->mii_dev); return (0); } - static device_method_t mcommphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, mcommphy_probe), @@ -177,7 +396,7 @@ static driver_t mcommphy_driver = { "mcommphy", mcommphy_methods, - sizeof(struct mii_softc) + sizeof(struct mcommphy_softc) }; DRIVER_MODULE(mcommphy, miibus, mcommphy_driver, 0, 0); diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs --- a/sys/dev/mii/miidevs +++ b/sys/dev/mii/miidevs @@ -63,6 +63,7 @@ oui MARVELL 0x005043 Marvell Semiconductor oui MICREL 0x0010a1 Micrel oui MOTORCOMM 0x000000 Motorcomm +oui MOTORCOMM2 0xc82b5e Motorcomm oui MYSON 0x00c0b4 Myson Technology oui NATSEMI 0x080017 National Semiconductor oui PMCSIERRA 0x00e004 PMC-Sierra @@ -295,6 +296,7 @@ /* Motorcomm PHYs */ model MOTORCOMM YT8511 0x010a Motorcomm YT8511 10/100/1000 PHY +model MOTORCOMM2 YT8531 0x0011 Motorcomm YT8531 10/100/1000 PHY /* Myson Technology PHYs */ model xxMYSON MTD972 0x0000 MTD972 10/100 media interface diff --git a/sys/riscv/starfive/starfive_if_eqos.c b/sys/riscv/starfive/starfive_if_eqos.c new file mode 100644 --- /dev/null +++ b/sys/riscv/starfive/starfive_if_eqos.c @@ -0,0 +1,220 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Mitchell Horne + * Copyright (c) 2024 Jari Sihvola + */ + +#include "opt_platform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "if_eqos_if.h" +#include "gpio_if.h" + +#include + +/* 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);