// SPDX-License-Identifier: GPL-2.0-only /******************************************************************************* STMMAC Ethernet Driver -- MDIO bus implementation Provides Bus interface for MII registers
Copyright (C) 2007-2009 STMicroelectronics Ltd
Author: Carl Shaw <carl.shaw@st.com> Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
staticvoid stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, int phyreg, u32 *hw_addr)
{
u32 tmp = 0;
if (priv->synopsys_id < DWXGMAC_CORE_2_20) { /* Until ver 2.20 XGMAC does not support C22 addr >= 4. Those * bits above bit 3 of XGMAC_MDIO_C22P register are reserved.
*/
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
tmp &= ~MII_XGMAC_C22P_MASK;
} /* Set port as Clause 22 */
tmp |= BIT(phyaddr);
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
ret = pm_runtime_resume_and_get(priv->device); if (ret < 0) return ret;
/* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
ret = -EBUSY; goto err_disable_clks;
}
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
value |= MII_XGMAC_READ;
/* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
ret = -EBUSY; goto err_disable_clks;
}
/* Set the MII address register to read */
writel(addr, priv->ioaddr + mii_address);
writel(value, priv->ioaddr + mii_data);
/* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
ret = -EBUSY; goto err_disable_clks;
}
/* Read the data from the MII data register */
ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
err_disable_clks:
pm_runtime_put(priv->device);
return ret;
}
staticint stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
{ struct net_device *ndev = bus->priv; struct stmmac_priv *priv;
u32 addr;
priv = netdev_priv(ndev);
/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */ if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
phyaddr > MII_XGMAC_MAX_C22ADDR) return -ENODEV;
ret = pm_runtime_resume_and_get(priv->device); if (ret < 0) return ret;
/* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
ret = -EBUSY; goto err_disable_clks;
}
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
value |= phydata;
value |= MII_XGMAC_WRITE;
/* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
ret = -EBUSY; goto err_disable_clks;
}
/* Set the MII address register to write */
writel(addr, priv->ioaddr + mii_address);
writel(value, priv->ioaddr + mii_data);
/* Wait until any existing MII operation is complete */
ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
!(tmp & MII_XGMAC_BUSY), 100, 10000);
/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */ if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
phyaddr > MII_XGMAC_MAX_C22ADDR) return -ENODEV;
/* Read the data from the MII data register */ return readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
}
/** * stmmac_mdio_read_c22 * @bus: points to the mii_bus structure * @phyaddr: MII addr * @phyreg: MII reg * Description: it reads data from the MII register from within the phy device. * For the 7111 GMAC, we must set the bit 0 in the MII address register while * accessing the PHY registers. * Fortunately, it seems this has no drawback for the 7109 MAC.
*/ staticint stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
{ struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev);
u32 value = MII_BUSY; int data = 0;
data = pm_runtime_resume_and_get(priv->device); if (data < 0) return data;
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask; if (priv->plat->has_gmac4)
value |= MII_GMAC4_READ;
data = stmmac_mdio_read(priv, data, value);
pm_runtime_put(priv->device);
return data;
}
/** * stmmac_mdio_read_c45 * @bus: points to the mii_bus structure * @phyaddr: MII addr * @devad: device address to read * @phyreg: MII reg * Description: it reads data from the MII register from within the phy device. * For the 7111 GMAC, we must set the bit 0 in the MII address register while * accessing the PHY registers. * Fortunately, it seems this has no drawback for the 7109 MAC.
*/ staticint stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad, int phyreg)
{ struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev);
u32 value = MII_BUSY; int data = 0;
data = pm_runtime_get_sync(priv->device); if (data < 0) {
pm_runtime_put_noidle(priv->device); return data;
}
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
value |= MII_GMAC4_READ;
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
/* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000)) return -EBUSY;
/* Set the MII address register to write */
writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
/* Wait until any existing MII operation is complete */ return readl_poll_timeout(priv->ioaddr + mii_address, v,
!(v & MII_BUSY), 100, 10000);
}
/** * stmmac_mdio_write_c22 * @bus: points to the mii_bus structure * @phyaddr: MII addr * @phyreg: MII reg * @phydata: phy data * Description: it writes the data into the MII register from within the device.
*/ staticint stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg,
u16 phydata)
{ struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev); int ret, data = phydata;
u32 value = MII_BUSY;
ret = pm_runtime_resume_and_get(priv->device); if (ret < 0) return ret;
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask; if (priv->plat->has_gmac4)
value |= MII_GMAC4_WRITE; else
value |= MII_WRITE;
ret = stmmac_mdio_write(priv, data, value);
pm_runtime_put(priv->device);
return ret;
}
/** * stmmac_mdio_write_c45 * @bus: points to the mii_bus structure * @phyaddr: MII addr * @phyreg: MII reg * @devad: device address to read * @phydata: phy data * Description: it writes the data into the MII register from within the device.
*/ staticint stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr, int devad, int phyreg, u16 phydata)
{ struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev); int ret, data = phydata;
u32 value = MII_BUSY;
ret = pm_runtime_get_sync(priv->device); if (ret < 0) {
pm_runtime_put_noidle(priv->device); return ret;
}
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
value |= MII_GMAC4_WRITE;
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
ret = stmmac_mdio_write(priv, data, value);
pm_runtime_put(priv->device);
return ret;
}
/** * stmmac_mdio_reset * @bus: points to the mii_bus structure * Description: reset the MII bus
*/ int stmmac_mdio_reset(struct mii_bus *bus)
{ #if IS_ENABLED(CONFIG_STMMAC_PLATFORM) struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev); unsignedint mii_address = priv->hw->mii.addr;
if (delays[0])
msleep(DIV_ROUND_UP(delays[0], 1000));
gpiod_set_value_cansleep(reset_gpio, 1); if (delays[1])
msleep(DIV_ROUND_UP(delays[1], 1000));
gpiod_set_value_cansleep(reset_gpio, 0); if (delays[2])
msleep(DIV_ROUND_UP(delays[2], 1000));
} #endif
/* This is a workaround for problems with the STE101P PHY. * It doesn't complete its reset until at least one clock cycle * on MDC, so perform a dummy mdio read. To be updated for GMAC4 * if needed.
*/ if (!priv->plat->has_gmac4)
writel(0, priv->ioaddr + mii_address); #endif return 0;
}
int stmmac_pcs_setup(struct net_device *ndev)
{ struct fwnode_handle *devnode, *pcsnode; struct dw_xpcs *xpcs = NULL; struct stmmac_priv *priv; int addr, ret;
err = of_mdiobus_register(new_bus, mdio_node); if (err == -ENODEV) {
err = 0;
dev_info(dev, "MDIO bus is disabled\n"); goto bus_register_fail;
} elseif (err) {
dev_err_probe(dev, err, "Cannot register the MDIO bus\n"); goto bus_register_fail;
}
/* Looks like we need a dummy read for XGMAC only and C45 PHYs */ if (priv->plat->has_xgmac)
stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
/* If fixed-link is set, skip PHY scanning */
fwnode = priv->plat->port_node; if (!fwnode)
fwnode = dev_fwnode(priv->device);
if (fwnode) {
fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link"); if (fixed_node) {
fwnode_handle_put(fixed_node); goto bus_register_done;
}
}
if (priv->plat->phy_node || mdio_node) goto bus_register_done;
found = 0; for (addr = 0; addr < max_addr; addr++) { struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
if (!phydev) continue;
/* * If an IRQ was provided to be assigned after * the bus probe, do it here.
*/ if (!mdio_bus_data->irqs &&
(mdio_bus_data->probed_phy_irq > 0)) {
new_bus->irq[addr] = mdio_bus_data->probed_phy_irq;
phydev->irq = mdio_bus_data->probed_phy_irq;
}
/* * If we're going to bind the MAC to this PHY bus, * and no PHY number was provided to the MAC, * use the one probed here.
*/ if (priv->plat->phy_addr == -1)
priv->plat->phy_addr = addr;
phy_attached_info(phydev);
found = 1;
}
if (!found && !mdio_node) {
dev_warn(dev, "No PHY found\n");
err = -ENODEV; goto no_phy_found;
}
/** * stmmac_mdio_unregister * @ndev: net device structure * Description: it unregisters the MII bus
*/ int stmmac_mdio_unregister(struct net_device *ndev)
{ struct stmmac_priv *priv = netdev_priv(ndev);
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.