if (phydev->autoneg)
phy_get_pause(phydev, &tx_pause, &rx_pause);
if (!tx_pause)
cmd_bits |= CMD_TX_PAUSE_IGNORE; if (!rx_pause)
cmd_bits |= CMD_RX_PAUSE_IGNORE;
}
/* Manual override */ if (!priv->rx_pause)
cmd_bits |= CMD_RX_PAUSE_IGNORE; if (!priv->tx_pause)
cmd_bits |= CMD_TX_PAUSE_IGNORE;
}
/* Program UMAC and RGMII block based on established * link speed, duplex, and pause. The speed set in * umac->cmd tell RGMII block which clock to use for * transmit -- 25MHz(100Mbps) or 125MHz(1Gbps). * Receive clock is provided by the PHY.
*/
reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
reg |= RGMII_LINK;
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
/* setup netdev link state when PHY link status change and * update UMAC and RGMII block when link up
*/ void bcmgenet_mii_setup(struct net_device *dev)
{ struct bcmgenet_priv *priv = netdev_priv(dev); struct phy_device *phydev = dev->phydev;
u32 reg;
/* EXT_GPHY_CTRL is only valid for GENETv4 and onward */ if (GENET_IS_V4(priv) || bcmgenet_has_ephy_16nm(priv)) {
reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL); if (enable) {
reg &= ~EXT_CK25_DIS;
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
mdelay(1);
switch (priv->phy_interface) { case PHY_INTERFACE_MODE_INTERNAL:
phy_name = "internal PHY";
fallthrough; case PHY_INTERFACE_MODE_MOCA: /* Irrespective of the actually configured PHY speed (100 or * 1000) GENETv4 only has an internal GPHY so we will just end * up masking the Gigabit features from what we support, not * switching to the EPHY
*/ if (GENET_IS_V4(priv))
port_ctrl = PORT_MODE_INT_GPHY; else
port_ctrl = PORT_MODE_INT_EPHY;
if (!phy_name) {
phy_name = "MoCA"; if (!GENET_IS_V5(priv))
port_ctrl |= LED_ACT_SOURCE_MAC;
bcmgenet_moca_phy_setup(priv);
} break;
case PHY_INTERFACE_MODE_REVMII:
phy_name = "external RvMII"; /* of_mdiobus_register took care of reading the 'max-speed' * PHY property for us, effectively limiting the PHY supported * capabilities, use that knowledge to also configure the * Reverse MII interface correctly.
*/ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
dev->phydev->supported))
port_ctrl = PORT_MODE_EXT_RVMII_50; else
port_ctrl = PORT_MODE_EXT_RVMII_25; break;
case PHY_INTERFACE_MODE_RGMII: /* RGMII_NO_ID: TXC transitions at the same time as TXD * (requires PCB or receiver-side delay) * * ID is implicitly disabled for 100Mbps (RG)MII operation.
*/
phy_name = "external RGMII (no delay)";
id_mode_dis = BIT(16);
port_ctrl = PORT_MODE_EXT_GPHY; break;
/* This is an external PHY (xMII), so we need to enable the RGMII * block for the interface to work, unconditionally clear the * Out-of-band disable since we do not need it.
*/
mutex_lock(&phydev->lock);
reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
reg &= ~OOB_DISABLE; if (priv->ext_phy) {
reg &= ~ID_MODE_DIS;
reg |= id_mode_dis; if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
reg |= RGMII_MODE_EN_V123; else
reg |= RGMII_MODE_EN;
}
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
mutex_unlock(&phydev->lock);
if (init)
dev_info(kdev, "configuring instance for %s\n", phy_name);
/* Communicate the integrated PHY revision */ if (priv->internal_phy)
phy_flags = priv->gphy_rev;
/* This is an ugly quirk but we have not been correctly interpreting * the phy_interface values and we have done that across different * drivers, so at least we are consistent in our mistakes. * * When the Generic PHY driver is in use either the PHY has been * strapped or programmed correctly by the boot loader so we should * stick to our incorrect interpretation since we have validated it. * * Now when a dedicated PHY driver is in use, we need to reverse the * meaning of the phy_interface_mode values to something that the PHY * driver will interpret and act on such that we have two mistakes * canceling themselves so to speak. We only do this for the two * modes that GENET driver officially supports on Broadcom STB chips: * PHY_INTERFACE_MODE_RGMII and PHY_INTERFACE_MODE_RGMII_TXID. Other * modes are not *officially* supported with the boot loader and the * scripted environment generating Device Tree blobs for those * platforms. * * Note that internal PHY, MoCA and fixed-link configurations are not * affected because they use different phy_interface_t values or the * Generic PHY driver.
*/ switch (priv->phy_interface) { case PHY_INTERFACE_MODE_RGMII:
phy_iface = PHY_INTERFACE_MODE_RGMII_ID; break; case PHY_INTERFACE_MODE_RGMII_TXID:
phy_iface = PHY_INTERFACE_MODE_RGMII_RXID; break; default: break;
}
if (dn) {
phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
phy_flags, phy_iface); if (!phydev) {
pr_err("could not attach to PHY\n"); return -ENODEV;
}
} else { if (has_acpi_companion(kdev)) { char mdio_bus_id[MII_BUS_ID_SIZE]; struct mii_bus *unimacbus;
unimacbus = mdio_find_bus(mdio_bus_id); if (!unimacbus) {
pr_err("Unable to find mii\n"); return -ENODEV;
}
phydev = phy_find_first(unimacbus);
put_device(&unimacbus->dev); if (!phydev) {
pr_err("Unable to find PHY\n"); return -ENODEV;
}
} else {
phydev = dev->phydev;
}
phydev->dev_flags = phy_flags;
ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup,
phy_iface); if (ret) {
pr_err("could not attach to PHY\n"); return -ENODEV;
}
}
/* Configure port multiplexer based on what the probed PHY device since * reading the 'max-speed' property determines the maximum supported * PHY speed which is needed for bcmgenet_mii_config() to configure * things appropriately.
*/
ret = bcmgenet_mii_config(dev, true); if (ret) {
phy_disconnect(dev->phydev); return ret;
}
/* The internal PHY has its link interrupts routed to the * Ethernet MAC ISRs. On GENETv5 there is a hardware issue * that prevents the signaling of link UP interrupts when * the link operates at 10Mbps, so fallback to polling for * those versions of GENET.
*/ if (priv->internal_phy && !GENET_IS_V5(priv))
dev->phydev->irq = PHY_MAC_INTERRUPT;
/* Indicate that the MAC is responsible for PHY PM */
dev->phydev->mac_managed_pm = true;
ppd.wait_func = bcmgenet_mii_wait;
ppd.wait_func_data = priv;
ppd.bus_name = "bcmgenet MII bus"; /* Pass a reference to our "main" clock which is used for MDIO * transfers
*/
ppd.clk = priv->clk;
/* Unimac MDIO bus controller starts at UniMAC offset + MDIO_CMD * and is 2 * 32-bits word long, 8 bytes total.
*/
res.start = pres->start + GENET_UMAC_OFF + UMAC_MDIO_CMD;
res.end = res.start + 8;
res.flags = IORESOURCE_MEM;
if (dn)
id = of_alias_get_id(dn, "eth"); else
id = pdev->id;
ppdev = platform_device_alloc(UNIMAC_MDIO_DRV_NAME, id); if (!ppdev) return -ENOMEM;
/* Retain this platform_device pointer for later cleanup */
priv->mii_pdev = ppdev;
ppdev->dev.parent = &pdev->dev; if (dn)
ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv); elseif (pdata)
bcmgenet_mii_pdata_init(priv, &ppd); else
ppd.phy_mask = ~0;
ret = platform_device_add_resources(ppdev, &res, 1); if (ret) goto out;
ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd)); if (ret) goto out;
ret = platform_device_add(ppdev); if (ret) goto out;
/* We need to specifically look up whether this PHY interface is * internal or not *before* we even try to probe the PHY driver * over MDIO as we may have shut down the internal PHY for power * saving purposes.
*/ if (priv->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
priv->internal_phy = true;
/* In the case of a fixed PHY, the DT node associated * to the PHY is the Ethernet MAC DT node.
*/ if (!priv->phy_dn && of_phy_is_fixed_link(dn)) {
ret = of_phy_register_fixed_link(dn); if (ret) return ret;
priv->phy_dn = of_node_get(dn);
}
/* Get the link mode */
ret = bcmgenet_phy_interface_init(priv); if (ret) return ret;
/* Make sure we initialize MoCA PHYs with a link down */ if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
phydev = of_phy_find_device(dn); if (phydev) {
phydev->link = 0;
put_device(&phydev->mdio.dev);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.