diff options
-rw-r--r-- | drivers/net/mvneta.c | 109 |
1 files changed, 82 insertions, 27 deletions
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index a1e2136e35..8881cc77fe 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -191,11 +191,16 @@ DECLARE_GLOBAL_DATA_PTR; #define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c #define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0) #define MVNETA_GMAC_FORCE_LINK_PASS BIT(1) +#define MVNETA_GMAC_FORCE_LINK_UP (BIT(0) | BIT(1)) +#define MVNETA_GMAC_IB_BYPASS_AN_EN BIT(3) #define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5) #define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6) #define MVNETA_GMAC_AN_SPEED_EN BIT(7) +#define MVNETA_GMAC_SET_FC_EN BIT(8) +#define MVNETA_GMAC_ADVERT_FC_EN BIT(9) #define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12) #define MVNETA_GMAC_AN_DUPLEX_EN BIT(13) +#define MVNETA_GMAC_SAMPLE_TX_CFG_EN BIT(15) #define MVNETA_MIB_COUNTERS_BASE 0x3080 #define MVNETA_MIB_LATE_COLLISION 0x7c #define MVNETA_DA_FILT_SPEC_MCAST 0x3400 @@ -566,6 +571,13 @@ static void mvneta_rxq_buf_size_set(struct mvneta_port *pp, mvreg_write(pp, MVNETA_RXQ_SIZE_REG(rxq->id), val); } +static int mvneta_port_is_fixed_link(struct mvneta_port *pp) +{ + /* phy_addr is set to invalid value for fixed link */ + return pp->phyaddr > PHY_MAX_ADDR; +} + + /* Start the Ethernet port RX and TX activity */ static void mvneta_port_up(struct mvneta_port *pp) { @@ -816,10 +828,12 @@ static void mvneta_defaults_set(struct mvneta_port *pp) /* Assign port SDMA configuration */ mvreg_write(pp, MVNETA_SDMA_CONFIG, val); - /* Enable PHY polling in hardware for U-Boot */ - val = mvreg_read(pp, MVNETA_UNIT_CONTROL); - val |= MVNETA_PHY_POLLING_ENABLE; - mvreg_write(pp, MVNETA_UNIT_CONTROL, val); + /* Enable PHY polling in hardware if not in fixed-link mode */ + if (!mvneta_port_is_fixed_link(pp)) { + val = mvreg_read(pp, MVNETA_UNIT_CONTROL); + val |= MVNETA_PHY_POLLING_ENABLE; + mvreg_write(pp, MVNETA_UNIT_CONTROL, val); + } mvneta_set_ucast_table(pp, -1); mvneta_set_special_mcast_table(pp, -1); @@ -1137,6 +1151,11 @@ static void mvneta_adjust_link(struct udevice *dev) struct phy_device *phydev = pp->phydev; int status_change = 0; + if (mvneta_port_is_fixed_link(pp)) { + debug("Using fixed link, skip link adjust\n"); + return; + } + if (phydev->link) { if ((pp->speed != phydev->speed) || (pp->duplex != phydev->duplex)) { @@ -1507,28 +1526,54 @@ static int mvneta_start(struct udevice *dev) mvneta_port_power_up(pp, pp->phy_interface); if (!pp->init || pp->link == 0) { - /* Set phy address of the port */ - mvreg_write(pp, MVNETA_PHY_ADDR, pp->phyaddr); - phydev = phy_connect(pp->bus, pp->phyaddr, dev, - pp->phy_interface); - - pp->phydev = phydev; - phy_config(phydev); - phy_startup(phydev); - if (!phydev->link) { - printf("%s: No link.\n", phydev->dev->name); - return -1; - } + if (mvneta_port_is_fixed_link(pp)) { + u32 val; - /* Full init on first call */ - mvneta_init(dev); - pp->init = 1; - } else { - /* Upon all following calls, this is enough */ - mvneta_port_up(pp); - mvneta_port_enable(pp); + pp->init = 1; + pp->link = 1; + mvneta_init(dev); + + val = MVNETA_GMAC_FORCE_LINK_UP | + MVNETA_GMAC_IB_BYPASS_AN_EN | + MVNETA_GMAC_SET_FC_EN | + MVNETA_GMAC_ADVERT_FC_EN | + MVNETA_GMAC_SAMPLE_TX_CFG_EN; + + if (pp->duplex) + val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; + + if (pp->speed == SPEED_1000) + val |= MVNETA_GMAC_CONFIG_GMII_SPEED; + else if (pp->speed == SPEED_100) + val |= MVNETA_GMAC_CONFIG_MII_SPEED; + + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); + } else { + /* Set phy address of the port */ + mvreg_write(pp, MVNETA_PHY_ADDR, pp->phyaddr); + + phydev = phy_connect(pp->bus, pp->phyaddr, dev, + pp->phy_interface); + + pp->phydev = phydev; + phy_config(phydev); + phy_startup(phydev); + if (!phydev->link) { + printf("%s: No link.\n", phydev->dev->name); + return -1; + } + + /* Full init on first call */ + mvneta_init(dev); + pp->init = 1; + return 0; + } } + /* Upon all following calls, this is enough */ + mvneta_port_up(pp); + mvneta_port_enable(pp); + return 0; } @@ -1625,6 +1670,7 @@ static int mvneta_probe(struct udevice *dev) unsigned long addr; void *bd_space; int ret; + int fl_node; /* * Allocate buffer area for descs and rx_buffers. This is only @@ -1657,10 +1703,19 @@ static int mvneta_probe(struct udevice *dev) /* PHY interface is already decoded in mvneta_ofdata_to_platdata() */ pp->phy_interface = pdata->phy_interface; - /* Now read phyaddr from DT */ - addr = fdtdec_get_int(blob, node, "phy", 0); - addr = fdt_node_offset_by_phandle(blob, addr); - pp->phyaddr = fdtdec_get_int(blob, addr, "reg", 0); + /* fetch 'fixed-link' property from 'neta' node */ + fl_node = fdt_subnode_offset(blob, node, "fixed-link"); + if (fl_node != -FDT_ERR_NOTFOUND) { + /* set phy_addr to invalid value for fixed link */ + pp->phyaddr = PHY_MAX_ADDR + 1; + pp->duplex = fdtdec_get_bool(blob, fl_node, "full-duplex"); + pp->speed = fdtdec_get_int(blob, fl_node, "speed", 0); + } else { + /* Now read phyaddr from DT */ + addr = fdtdec_get_int(blob, node, "phy", 0); + addr = fdt_node_offset_by_phandle(blob, addr); + pp->phyaddr = fdtdec_get_int(blob, addr, "reg", 0); + } bus = mdio_alloc(); if (!bus) { |