Merge patch series "net: dwc_eth_qos: Add glue driver for Intel MAC"

Philip Oberfichtner <pro@denx.de> says:

This patch series implements the dwc_eth_qos glue driver for Intel SOCs.
Before doing that, a few general adaptions to the dwc_eth_qos.c main
driver are required. Most notably, the preparation for PCI based driver
instances, which do not necessarily use a device tree.
This commit is contained in:
Tom Rini 2024-09-03 09:12:06 -06:00
commit 2c832abc73
15 changed files with 641 additions and 19 deletions

View file

@ -164,12 +164,12 @@ static inline void barrier_wait(atomic_t *b)
{ {
while (atomic_read(b) == 0) while (atomic_read(b) == 0)
asm("pause"); asm("pause");
mfence(); mb();
} }
static inline void release_barrier(atomic_t *b) static inline void release_barrier(atomic_t *b)
{ {
mfence(); mb();
atomic_set(b, 1); atomic_set(b, 1);
} }
@ -631,7 +631,7 @@ static int run_ap_work(struct mp_callback *callback, struct udevice *bsp,
if (cur_cpu != i) if (cur_cpu != i)
store_callback(&ap_callbacks[i], callback); store_callback(&ap_callbacks[i], callback);
} }
mfence(); mb();
/* Wait for all the APs to signal back that call has been accepted. */ /* Wait for all the APs to signal back that call has been accepted. */
start = get_timer(0); start = get_timer(0);
@ -656,7 +656,7 @@ static int run_ap_work(struct mp_callback *callback, struct udevice *bsp,
} while (cpus_accepted != num_aps); } while (cpus_accepted != num_aps);
/* Make sure we can see any data written by the APs */ /* Make sure we can see any data written by the APs */
mfence(); mb();
return 0; return 0;
} }
@ -692,7 +692,7 @@ static int ap_wait_for_instruction(struct udevice *cpu, void *unused)
/* Copy to local variable before using the value */ /* Copy to local variable before using the value */
memcpy(&lcb, cb, sizeof(lcb)); memcpy(&lcb, cb, sizeof(lcb));
mfence(); mb();
if (lcb.logical_cpu_number == MP_SELECT_ALL || if (lcb.logical_cpu_number == MP_SELECT_ALL ||
lcb.logical_cpu_number == MP_SELECT_APS || lcb.logical_cpu_number == MP_SELECT_APS ||
dev_seq(cpu) == lcb.logical_cpu_number) dev_seq(cpu) == lcb.logical_cpu_number)

View file

@ -185,11 +185,6 @@ static inline int flag_is_changeable_p(uint32_t flag)
} }
#endif #endif
static inline void mfence(void)
{
__asm__ __volatile__("mfence" : : : "memory");
}
/** /**
* cpu_enable_paging_pae() - Enable PAE-paging * cpu_enable_paging_pae() - Enable PAE-paging
* *

View file

@ -240,6 +240,7 @@ static inline void sync(void)
* have some advantages to use them instead of the simple one here. * have some advantages to use them instead of the simple one here.
*/ */
#define dmb() __asm__ __volatile__ ("" : : : "memory") #define dmb() __asm__ __volatile__ ("" : : : "memory")
#define mb() __asm__ __volatile__ ("mfence" : : : "memory")
#define __iormb() dmb() #define __iormb() dmb()
#define __iowmb() dmb() #define __iowmb() dmb()

View file

@ -243,6 +243,13 @@ config DWC_ETH_QOS_IMX
The Synopsys Designware Ethernet QOS IP block with the specific The Synopsys Designware Ethernet QOS IP block with the specific
configuration used in IMX soc. configuration used in IMX soc.
config DWC_ETH_QOS_INTEL
bool "Synopsys DWC Ethernet QOS device support for Intel"
depends on DWC_ETH_QOS
help
The Synopsys Designware Ethernet QOS IP block with the specific
configuration used in the Intel Elkhart-Lake soc.
config DWC_ETH_QOS_ROCKCHIP config DWC_ETH_QOS_ROCKCHIP
bool "Synopsys DWC Ethernet QOS device support for Rockchip SoCs" bool "Synopsys DWC Ethernet QOS device support for Rockchip SoCs"
depends on DWC_ETH_QOS depends on DWC_ETH_QOS

View file

@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.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_IMX) += dwc_eth_qos_imx.o
obj-$(CONFIG_DWC_ETH_QOS_INTEL) += dwc_eth_qos_intel.o
obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o
obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o
obj-$(CONFIG_DWC_ETH_XGMAC) += dwc_eth_xgmac.o obj-$(CONFIG_DWC_ETH_XGMAC) += dwc_eth_xgmac.o

View file

@ -32,6 +32,7 @@
#include <clk.h> #include <clk.h>
#include <cpu_func.h> #include <cpu_func.h>
#include <dm.h> #include <dm.h>
#include <dm/device_compat.h>
#include <errno.h> #include <errno.h>
#include <eth_phy.h> #include <eth_phy.h>
#include <log.h> #include <log.h>
@ -1301,6 +1302,13 @@ static int eqos_probe_resources_tegra186(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev); debug("%s(dev=%p):\n", __func__, dev);
ret = eqos_get_base_addr_dt(dev);
if (ret) {
pr_err("eqos_get_base_addr_dt failed: %d\n", ret);
return ret;
}
eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE);
ret = reset_get_by_name(dev, "eqos", &eqos->reset_ctl); ret = reset_get_by_name(dev, "eqos", &eqos->reset_ctl);
if (ret) { if (ret) {
pr_err("reset_get_by_name(rst) failed: %d\n", ret); pr_err("reset_get_by_name(rst) failed: %d\n", ret);
@ -1375,6 +1383,69 @@ static int eqos_remove_resources_tegra186(struct udevice *dev)
return 0; return 0;
} }
static int eqos_bind(struct udevice *dev)
{
static int dev_num;
const size_t name_sz = 16;
char name[name_sz];
/* Device name defaults to DT node name. */
if (ofnode_valid(dev_ofnode(dev)))
return 0;
/* Assign unique names in case there is no DT node. */
snprintf(name, name_sz, "eth_eqos#%d", dev_num++);
return device_set_name(dev, name);
}
/*
* Get driver data based on the device tree. Boards not using a device tree can
* overwrite this function.
*/
__weak void *eqos_get_driver_data(struct udevice *dev)
{
return (void *)dev_get_driver_data(dev);
}
static fdt_addr_t eqos_get_base_addr_common(struct udevice *dev, fdt_addr_t addr)
{
struct eqos_priv *eqos = dev_get_priv(dev);
if (addr == FDT_ADDR_T_NONE) {
#if CONFIG_IS_ENABLED(FDT_64BIT)
dev_err(dev, "addr=0x%llx is invalid.\n", addr);
#else
dev_err(dev, "addr=0x%x is invalid.\n", addr);
#endif
return -EINVAL;
}
eqos->regs = addr;
eqos->mac_regs = (void *)(addr + EQOS_MAC_REGS_BASE);
eqos->mtl_regs = (void *)(addr + EQOS_MTL_REGS_BASE);
eqos->dma_regs = (void *)(addr + EQOS_DMA_REGS_BASE);
return 0;
}
int eqos_get_base_addr_dt(struct udevice *dev)
{
fdt_addr_t addr = dev_read_addr(dev);
return eqos_get_base_addr_common(dev, addr);
}
int eqos_get_base_addr_pci(struct udevice *dev)
{
fdt_addr_t addr;
void *paddr;
paddr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
addr = paddr ? (fdt_addr_t)paddr : FDT_ADDR_T_NONE;
return eqos_get_base_addr_common(dev, addr);
}
static int eqos_probe(struct udevice *dev) static int eqos_probe(struct udevice *dev)
{ {
struct eqos_priv *eqos = dev_get_priv(dev); struct eqos_priv *eqos = dev_get_priv(dev);
@ -1383,17 +1454,12 @@ static int eqos_probe(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev); debug("%s(dev=%p):\n", __func__, dev);
eqos->dev = dev; eqos->dev = dev;
eqos->config = (void *)dev_get_driver_data(dev);
eqos->regs = dev_read_addr(dev); eqos->config = eqos_get_driver_data(dev);
if (eqos->regs == FDT_ADDR_T_NONE) { if (!eqos->config) {
pr_err("dev_read_addr() failed\n"); pr_err("Failed to get driver data.\n");
return -ENODEV; return -ENODEV;
} }
eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE);
eqos->mtl_regs = (void *)(eqos->regs + EQOS_MTL_REGS_BASE);
eqos->dma_regs = (void *)(eqos->regs + EQOS_DMA_REGS_BASE);
eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE);
eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0); eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0);
@ -1574,6 +1640,7 @@ U_BOOT_DRIVER(eth_eqos) = {
.name = "eth_eqos", .name = "eth_eqos",
.id = UCLASS_ETH, .id = UCLASS_ETH,
.of_match = of_match_ptr(eqos_ids), .of_match = of_match_ptr(eqos_ids),
.bind = eqos_bind,
.probe = eqos_probe, .probe = eqos_probe,
.remove = eqos_remove, .remove = eqos_remove,
.ops = &eqos_ops, .ops = &eqos_ops,

View file

@ -3,8 +3,11 @@
* Copyright 2022 NXP * Copyright 2022 NXP
*/ */
#include <phy_interface.h> #include <asm/gpio.h>
#include <clk.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <phy_interface.h>
#include <reset.h>
/* Core registers */ /* Core registers */
@ -286,7 +289,10 @@ void eqos_inval_desc_generic(void *desc);
void eqos_flush_desc_generic(void *desc); void eqos_flush_desc_generic(void *desc);
void eqos_inval_buffer_generic(void *buf, size_t size); void eqos_inval_buffer_generic(void *buf, size_t size);
void eqos_flush_buffer_generic(void *buf, size_t size); void eqos_flush_buffer_generic(void *buf, size_t size);
int eqos_get_base_addr_dt(struct udevice *dev);
int eqos_get_base_addr_pci(struct udevice *dev);
int eqos_null_ops(struct udevice *dev); int eqos_null_ops(struct udevice *dev);
void *eqos_get_driver_data(struct udevice *dev);
extern struct eqos_config eqos_imx_config; extern struct eqos_config eqos_imx_config;
extern struct eqos_config eqos_rockchip_config; extern struct eqos_config eqos_rockchip_config;

View file

@ -47,6 +47,12 @@ static int eqos_probe_resources_imx(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev); debug("%s(dev=%p):\n", __func__, dev);
ret = eqos_get_base_addr_dt(dev);
if (ret) {
dev_dbg(dev, "eqos_get_base_addr_dt failed: %d", ret);
goto err_probe;
}
interface = eqos->config->interface(dev); interface = eqos->config->interface(dev);
if (interface == PHY_INTERFACE_MODE_NA) { if (interface == PHY_INTERFACE_MODE_NA) {

View file

@ -0,0 +1,449 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023-2024 DENX Software Engineering GmbH
* Philip Oberfichtner <pro@denx.de>
*
* Based on linux v6.6.39, especially drivers/net/ethernet/stmicro/stmmac
*/
#include <asm/io.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <miiphy.h>
#include <net.h>
#include <pci.h>
#include "dwc_eth_qos.h"
#include "dwc_eth_qos_intel.h"
static struct pci_device_id intel_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_RGMII1G) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_SGMII1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_SGMII2G5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_PSE0_RGMII1G) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII1G) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII2G5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_PSE1_RGMII1G) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII1G) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII2G5) },
{}
};
static int pci_config(struct udevice *dev)
{
u32 val;
/* Try to enable I/O accesses and bus-mastering */
dm_pci_read_config32(dev, PCI_COMMAND, &val);
val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
dm_pci_write_config32(dev, PCI_COMMAND, val);
/* Make sure it worked */
dm_pci_read_config32(dev, PCI_COMMAND, &val);
if (!(val & PCI_COMMAND_MEMORY)) {
dev_err(dev, "%s: Can't enable I/O memory\n", __func__);
return -ENOSPC;
}
if (!(val & PCI_COMMAND_MASTER)) {
dev_err(dev, "%s: Can't enable bus-mastering\n", __func__);
return -EPERM;
}
return 0;
}
static void limit_fifo_size(struct udevice *dev)
{
/*
* As described in Intel Erratum EHL22, Document Number: 636674-2.1,
* the PSE GbE Controllers advertise a wrong RX and TX fifo size.
* Software should limit this value to 64KB.
*/
struct eqos_priv *eqos = dev_get_priv(dev);
eqos->tx_fifo_sz = 0x8000;
eqos->rx_fifo_sz = 0x8000;
}
static int serdes_status_poll(struct udevice *dev,
unsigned char phyaddr, unsigned char phyreg,
unsigned short mask, unsigned short val)
{
struct eqos_priv *eqos = dev_get_priv(dev);
unsigned int retries = 10;
unsigned short val_rd;
do {
miiphy_read(eqos->mii->name, phyaddr, phyreg, &val_rd);
if ((val_rd & mask) == (val & mask))
return 0;
udelay(POLL_DELAY_US);
} while (--retries);
return -ETIMEDOUT;
}
/* Returns -ve if MAC is unknown and 0 on success */
static int mac_check_pse(const struct udevice *dev, bool *is_pse)
{
struct pci_child_plat *plat = dev_get_parent_plat(dev);
if (!plat || plat->vendor != PCI_VENDOR_ID_INTEL)
return -ENXIO;
switch (plat->device) {
case PCI_DEVICE_ID_INTEL_EHL_PSE0_RGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_PSE1_RGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII2G5:
case PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII2G5:
*is_pse = 1;
return 0;
case PCI_DEVICE_ID_INTEL_EHL_RGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_SGMII1:
case PCI_DEVICE_ID_INTEL_EHL_SGMII2G5:
*is_pse = 0;
return 0;
};
return -ENXIO;
}
/* Check if we're in 2G5 mode */
static bool serdes_link_mode_2500(struct udevice *dev)
{
const unsigned char phyad = INTEL_MGBE_ADHOC_ADDR;
struct eqos_priv *eqos = dev_get_priv(dev);
unsigned short data;
miiphy_read(eqos->mii->name, phyad, SERDES_GCR, &data);
if (FIELD_GET(SERDES_LINK_MODE_MASK, data) == SERDES_LINK_MODE_2G5)
return true;
return false;
}
static int serdes_powerup(struct udevice *dev)
{
/* Based on linux/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c */
const unsigned char phyad = INTEL_MGBE_ADHOC_ADDR;
struct eqos_priv *eqos = dev_get_priv(dev);
unsigned short data;
int ret;
bool is_pse;
/* Set the serdes rate and the PCLK rate */
miiphy_read(eqos->mii->name, phyad, SERDES_GCR0, &data);
data &= ~SERDES_RATE_MASK;
data &= ~SERDES_PCLK_MASK;
if (serdes_link_mode_2500(dev))
data |= SERDES_RATE_PCIE_GEN2 << SERDES_RATE_PCIE_SHIFT |
SERDES_PCLK_37p5MHZ << SERDES_PCLK_SHIFT;
else
data |= SERDES_RATE_PCIE_GEN1 << SERDES_RATE_PCIE_SHIFT |
SERDES_PCLK_70MHZ << SERDES_PCLK_SHIFT;
miiphy_write(eqos->mii->name, phyad, SERDES_GCR0, data);
/* assert clk_req */
miiphy_read(eqos->mii->name, phyad, SERDES_GCR0, &data);
data |= SERDES_PLL_CLK;
miiphy_write(eqos->mii->name, phyad, SERDES_GCR0, data);
/* check for clk_ack assertion */
ret = serdes_status_poll(dev, phyad, SERDES_GSR0,
SERDES_PLL_CLK, SERDES_PLL_CLK);
if (ret) {
dev_err(dev, "Serdes PLL clk request timeout\n");
return ret;
}
/* assert lane reset*/
miiphy_read(eqos->mii->name, phyad, SERDES_GCR0, &data);
data |= SERDES_RST;
miiphy_write(eqos->mii->name, phyad, SERDES_GCR0, data);
/* check for assert lane reset reflection */
ret = serdes_status_poll(dev, phyad, SERDES_GSR0,
SERDES_RST, SERDES_RST);
if (ret) {
dev_err(dev, "Serdes assert lane reset timeout\n");
return ret;
}
/* move power state to P0 */
miiphy_read(eqos->mii->name, phyad, SERDES_GCR0, &data);
data &= ~SERDES_PWR_ST_MASK;
data |= SERDES_PWR_ST_P0 << SERDES_PWR_ST_SHIFT;
miiphy_write(eqos->mii->name, phyad, SERDES_GCR0, data);
/* Check for P0 state */
ret = serdes_status_poll(dev, phyad, SERDES_GSR0,
SERDES_PWR_ST_MASK,
SERDES_PWR_ST_P0 << SERDES_PWR_ST_SHIFT);
if (ret) {
dev_err(dev, "Serdes power state P0 timeout.\n");
return ret;
}
/* PSE only - ungate SGMII PHY Rx Clock*/
ret = mac_check_pse(dev, &is_pse);
if (ret) {
dev_err(dev, "Failed to determine MAC type.\n");
return ret;
}
if (is_pse) {
miiphy_read(eqos->mii->name, phyad, SERDES_GCR0, &data);
data |= SERDES_PHY_RX_CLK;
miiphy_write(eqos->mii->name, phyad, SERDES_GCR0, data);
}
return 0;
}
static int xpcs_access(struct udevice *dev, int reg, int v)
{
/*
* Common read/write helper function
*
* It may seem a bit odd at a first glance that we use bus->read()
* directly insetad of one of the wrapper functions. But:
*
* (1) phy_read() can't be used because we do not access an acutal PHY,
* but a MAC-internal submodule.
*
* (2) miiphy_read() can't be used because it assumes MDIO_DEVAD_NONE.
*/
int port = INTEL_MGBE_XPCS_ADDR;
int devad = 0x1f;
u16 val;
struct eqos_priv *eqos;
struct mii_dev *bus;
eqos = dev_get_priv(dev);
bus = eqos->mii;
if (v < 0)
return bus->read(bus, port, devad, reg);
val = v;
return bus->write(bus, port, devad, reg, val);
}
static int xpcs_read(struct udevice *dev, int reg)
{
return xpcs_access(dev, reg, -1);
}
static int xpcs_write(struct udevice *dev, int reg, u16 val)
{
return xpcs_access(dev, reg, val);
}
static int xpcs_clr_bits(struct udevice *dev, int reg, u16 bits)
{
int ret;
ret = xpcs_read(dev, reg);
if (ret < 0)
return ret;
ret &= ~bits;
return xpcs_write(dev, reg, ret);
}
static int xpcs_set_bits(struct udevice *dev, int reg, u16 bits)
{
int ret;
ret = xpcs_read(dev, reg);
if (ret < 0)
return ret;
ret |= bits;
return xpcs_write(dev, reg, ret);
}
static int xpcs_init(struct udevice *dev)
{
/* Based on linux/drivers/net/pcs/pcs-xpcs.c */
struct eqos_priv *eqos = dev_get_priv(dev);
phy_interface_t interface = eqos->config->interface(dev);
if (interface != PHY_INTERFACE_MODE_SGMII)
return 0;
if (xpcs_clr_bits(dev, VR_MII_MMD_CTRL, XPCS_AN_CL37_EN) ||
xpcs_set_bits(dev, VR_MII_AN_CTRL, XPCS_MODE_SGMII) ||
xpcs_set_bits(dev, VR_MII_DIG_CTRL1, XPCS_MAC_AUTO_SW) ||
xpcs_set_bits(dev, VR_MII_MMD_CTRL, XPCS_AN_CL37_EN))
return -EIO;
return 0;
}
static int eqos_probe_ressources_intel(struct udevice *dev)
{
int ret;
ret = eqos_get_base_addr_pci(dev);
if (ret) {
dev_err(dev, "eqos_get_base_addr_pci failed: %d\n", ret);
return ret;
}
limit_fifo_size(dev);
ret = pci_config(dev);
if (ret) {
dev_err(dev, "pci_config failed: %d\n", ret);
return ret;
}
return 0;
}
struct eqos_config eqos_intel_config;
/*
* overwrite __weak function from eqos_intel.c
*
* For PCI devices the devcie tree is optional. Choose driver data based on PCI
* IDs instead.
*/
void *eqos_get_driver_data(struct udevice *dev)
{
const struct pci_device_id *id;
const struct pci_child_plat *plat;
plat = dev_get_parent_plat(dev);
if (!plat)
return NULL;
/* last intel_pci_ids element is zero initialized */
for (id = intel_pci_ids; id->vendor != 0; id++) {
if (id->vendor == plat->vendor && id->device == plat->device)
return &eqos_intel_config;
}
return NULL;
}
static int eqos_start_resets_intel(struct udevice *dev)
{
int ret;
ret = xpcs_init(dev);
if (ret) {
dev_err(dev, "xpcs init failed.\n");
return ret;
}
ret = serdes_powerup(dev);
if (ret) {
dev_err(dev, "Failed to power up serdes.\n");
return ret;
}
return 0;
}
static ulong eqos_get_tick_clk_rate_intel(struct udevice *dev)
{
return 0;
}
static int eqos_get_enetaddr_intel(struct udevice *dev)
{
/* Assume MAC address is programmed by previous boot stage */
struct eth_pdata *plat = dev_get_plat(dev);
struct eqos_priv *eqos = dev_get_priv(dev);
u8 *lo = (u8 *)&eqos->mac_regs->address0_low;
u8 *hi = (u8 *)&eqos->mac_regs->address0_high;
plat->enetaddr[0] = lo[0];
plat->enetaddr[1] = lo[1];
plat->enetaddr[2] = lo[2];
plat->enetaddr[3] = lo[3];
plat->enetaddr[4] = hi[0];
plat->enetaddr[5] = hi[1];
return 0;
}
static phy_interface_t eqos_get_interface_intel(const struct udevice *dev)
{
struct pci_child_plat *plat = dev_get_parent_plat(dev);
if (!plat || plat->vendor != PCI_VENDOR_ID_INTEL)
return PHY_INTERFACE_MODE_NA;
switch (plat->device) {
/* The GbE Host Controller has no RGMII interface */
case PCI_DEVICE_ID_INTEL_EHL_RGMII1G:
return PHY_INTERFACE_MODE_NA;
case PCI_DEVICE_ID_INTEL_EHL_PSE0_RGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_PSE1_RGMII1G:
return PHY_INTERFACE_MODE_RGMII;
/* Host SGMII and Host SGMII2G5 share the same device id */
case PCI_DEVICE_ID_INTEL_EHL_SGMII1:
case PCI_DEVICE_ID_INTEL_EHL_SGMII2G5:
case PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII2G5:
case PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII1G:
case PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII2G5:
return PHY_INTERFACE_MODE_SGMII;
};
return PHY_INTERFACE_MODE_NA;
}
static struct eqos_ops eqos_intel_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_ressources_intel,
.eqos_remove_resources = eqos_null_ops,
.eqos_stop_resets = eqos_null_ops,
.eqos_start_resets = eqos_start_resets_intel,
.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_null_ops,
.eqos_get_enetaddr = eqos_get_enetaddr_intel,
.eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_intel,
};
struct eqos_config eqos_intel_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_intel,
.ops = &eqos_intel_ops
};
extern U_BOOT_DRIVER(eth_eqos);
U_BOOT_PCI_DEVICE(eth_eqos, intel_pci_ids);

View file

@ -0,0 +1,57 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (c) 2023-2024 DENX Software Engineering GmbH
* Philip Oberfichtner <pro@denx.de>
*
* This header is based on linux v6.6.39,
*
* drivers/net/pcs/pcs-xpcs.h
* drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h,
*
* Copyright (c) 2020 Synopsys, Inc. and/or its affiliates
* Copyright (c) 2020 Intel Corporation
*/
#ifndef __DWMAC_INTEL_H__
#define __DWMAC_INTEL_H__
#define POLL_DELAY_US 8
/* SERDES Register */
#define SERDES_GCR 0x0 /* Global Conguration */
#define SERDES_GSR0 0x5 /* Global Status Reg0 */
#define SERDES_GCR0 0xb /* Global Configuration Reg0 */
/* SERDES defines */
#define SERDES_PLL_CLK BIT(0) /* PLL clk valid signal */
#define SERDES_PHY_RX_CLK BIT(1) /* PSE SGMII PHY rx clk */
#define SERDES_RST BIT(2) /* Serdes Reset */
#define SERDES_PWR_ST_MASK GENMASK(6, 4) /* Serdes Power state*/
#define SERDES_RATE_MASK GENMASK(9, 8)
#define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */
#define SERDES_LINK_MODE_MASK GENMASK(2, 1)
#define SERDES_PWR_ST_SHIFT 4
#define SERDES_PWR_ST_P0 0x0
#define SERDES_PWR_ST_P3 0x3
#define SERDES_LINK_MODE_2G5 0x3
#define SERSED_LINK_MODE_1G 0x2
#define SERDES_PCLK_37p5MHZ 0x0
#define SERDES_PCLK_70MHZ 0x1
#define SERDES_RATE_PCIE_GEN1 0x0
#define SERDES_RATE_PCIE_GEN2 0x1
#define SERDES_RATE_PCIE_SHIFT 8
#define SERDES_PCLK_SHIFT 12
#define INTEL_MGBE_ADHOC_ADDR 0x15
#define INTEL_MGBE_XPCS_ADDR 0x16
/* XPCS defines */
#define XPCS_MODE_SGMII BIT(2)
#define XPCS_MAC_AUTO_SW BIT(9)
#define XPCS_AN_CL37_EN BIT(12)
#define VR_MII_MMD_CTRL 0x0000
#define VR_MII_DIG_CTRL1 0x8000
#define VR_MII_AN_CTRL 0x8001
#endif /* __DWMAC_INTEL_H__ */

View file

@ -522,6 +522,12 @@ static int eqos_probe_resources_qcom(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev); debug("%s(dev=%p):\n", __func__, dev);
ret = eqos_get_base_addr_dt(dev);
if (ret) {
pr_err("eqos_get_base_addr_dt failed: %d\n", ret);
return ret;
}
interface = eqos->config->interface(dev); interface = eqos->config->interface(dev);
if (interface == PHY_INTERFACE_MODE_NA) { if (interface == PHY_INTERFACE_MODE_NA) {

View file

@ -311,6 +311,12 @@ static int eqos_probe_resources_rk(struct udevice *dev)
int reset_flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE; int reset_flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE;
int ret; int ret;
ret = eqos_get_base_addr_dt(dev);
if (ret) {
dev_err(dev, "eqos_get_base_addr_dt failed: %d\n", ret);
return ret;
}
data = calloc(1, sizeof(struct rockchip_platform_data)); data = calloc(1, sizeof(struct rockchip_platform_data));
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;

View file

@ -183,6 +183,12 @@ static int eqos_probe_resources_jh7110(struct udevice *dev)
struct starfive_platform_data *data; struct starfive_platform_data *data;
int ret; int ret;
ret = eqos_get_base_addr_dt(dev);
if (ret) {
pr_err("eqos_get_base_addr_dt failed: %d\n", ret);
return ret;
}
data = calloc(1, sizeof(struct starfive_platform_data)); data = calloc(1, sizeof(struct starfive_platform_data));
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;

View file

@ -234,6 +234,12 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
interface = eqos->config->interface(dev); interface = eqos->config->interface(dev);
ret = eqos_get_base_addr_dt(dev);
if (ret) {
dev_err(dev, "eqos_get_base_addr_dt failed: %d\n", ret);
return ret;
}
if (interface == PHY_INTERFACE_MODE_NA) { if (interface == PHY_INTERFACE_MODE_NA) {
dev_err(dev, "Invalid PHY interface\n"); dev_err(dev, "Invalid PHY interface\n");
return -EINVAL; return -EINVAL;

View file

@ -2600,6 +2600,15 @@
#define PCI_DEVICE_ID_DCI_PCCOM2 0x0004 #define PCI_DEVICE_ID_DCI_PCCOM2 0x0004
#define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_EHL_RGMII1G 0x4b30
#define PCI_DEVICE_ID_INTEL_EHL_SGMII1 0x4b31
#define PCI_DEVICE_ID_INTEL_EHL_SGMII2G5 0x4b32
#define PCI_DEVICE_ID_INTEL_EHL_PSE0_RGMII1G 0x4ba0
#define PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII1G 0x4ba1
#define PCI_DEVICE_ID_INTEL_EHL_PSE0_SGMII2G5 0x4ba2
#define PCI_DEVICE_ID_INTEL_EHL_PSE1_RGMII1G 0x4bb0
#define PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII1G 0x4bb1
#define PCI_DEVICE_ID_INTEL_EHL_PSE1_SGMII2G5 0x4bb2
#define PCI_DEVICE_ID_INTEL_EESSC 0x0008 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008
#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100 #define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100
#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154 #define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154