Commit da1b0b5c authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-mdio-continue-separating-c22-and-c45'

Michael Walle says:

====================
net: mdio: Continue separating C22 and C45

I've picked this older series from Andrew up and rebased it onto
the latest net-next.

This is the second patch set in the series which separates the C22
and C45 MDIO bus transactions at the API level to the MDIO bus drivers.
====================

Link: https://lore.kernel.org/r/20230112-net-next-c45-seperation-part-2-v1-0-5eeaae931526@walle.ccSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 9b7fe804 80e87442
...@@ -954,8 +954,10 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) ...@@ -954,8 +954,10 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
return -ENOMEM; return -ENOMEM;
bus->name = "VSC9959 internal MDIO bus"; bus->name = "VSC9959 internal MDIO bus";
bus->read = enetc_mdio_read; bus->read = enetc_mdio_read_c22;
bus->write = enetc_mdio_write; bus->write = enetc_mdio_write_c22;
bus->read_c45 = enetc_mdio_read_c45;
bus->write_c45 = enetc_mdio_write_c45;
bus->parent = dev; bus->parent = dev;
mdio_priv = bus->priv; mdio_priv = bus->priv;
mdio_priv->hw = hw; mdio_priv->hw = hw;
......
...@@ -55,7 +55,8 @@ static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv) ...@@ -55,7 +55,8 @@ static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv)
is_busy, !is_busy, 10, 10 * 1000); is_busy, !is_busy, 10, 10 * 1000);
} }
int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum,
u16 value)
{ {
struct enetc_mdio_priv *mdio_priv = bus->priv; struct enetc_mdio_priv *mdio_priv = bus->priv;
u32 mdio_ctl, mdio_cfg; u32 mdio_ctl, mdio_cfg;
...@@ -63,14 +64,39 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) ...@@ -63,14 +64,39 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
int ret; int ret;
mdio_cfg = ENETC_EMDIO_CFG; mdio_cfg = ENETC_EMDIO_CFG;
if (regnum & MII_ADDR_C45) { dev_addr = regnum & 0x1f;
dev_addr = (regnum >> 16) & 0x1f; mdio_cfg &= ~MDIO_CFG_ENC45;
mdio_cfg |= MDIO_CFG_ENC45;
} else { enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
/* clause 22 (ie 1G) */
dev_addr = regnum & 0x1f; ret = enetc_mdio_wait_complete(mdio_priv);
mdio_cfg &= ~MDIO_CFG_ENC45; if (ret)
} return ret;
/* set port and dev addr */
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
/* write the value */
enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value);
ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(enetc_mdio_write_c22);
int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
int regnum, u16 value)
{
struct enetc_mdio_priv *mdio_priv = bus->priv;
u32 mdio_ctl, mdio_cfg;
int ret;
mdio_cfg = ENETC_EMDIO_CFG;
mdio_cfg |= MDIO_CFG_ENC45;
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
...@@ -83,13 +109,11 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) ...@@ -83,13 +109,11 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
/* set the register address */ /* set the register address */
if (regnum & MII_ADDR_C45) { enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
ret = enetc_mdio_wait_complete(mdio_priv); ret = enetc_mdio_wait_complete(mdio_priv);
if (ret) if (ret)
return ret; return ret;
}
/* write the value */ /* write the value */
enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value);
...@@ -100,9 +124,9 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) ...@@ -100,9 +124,9 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(enetc_mdio_write); EXPORT_SYMBOL_GPL(enetc_mdio_write_c45);
int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
{ {
struct enetc_mdio_priv *mdio_priv = bus->priv; struct enetc_mdio_priv *mdio_priv = bus->priv;
u32 mdio_ctl, mdio_cfg; u32 mdio_ctl, mdio_cfg;
...@@ -110,14 +134,51 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) ...@@ -110,14 +134,51 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
int ret; int ret;
mdio_cfg = ENETC_EMDIO_CFG; mdio_cfg = ENETC_EMDIO_CFG;
if (regnum & MII_ADDR_C45) { dev_addr = regnum & 0x1f;
dev_addr = (regnum >> 16) & 0x1f; mdio_cfg &= ~MDIO_CFG_ENC45;
mdio_cfg |= MDIO_CFG_ENC45;
} else { enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
dev_addr = regnum & 0x1f;
mdio_cfg &= ~MDIO_CFG_ENC45; ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
/* set port and device addr */
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
/* initiate the read */
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
/* return all Fs if nothing was there */
if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) {
dev_dbg(&bus->dev,
"Error while reading PHY%d reg at %d.%d\n",
phy_id, dev_addr, regnum);
return 0xffff;
} }
value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff;
return value;
}
EXPORT_SYMBOL_GPL(enetc_mdio_read_c22);
int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,
int regnum)
{
struct enetc_mdio_priv *mdio_priv = bus->priv;
u32 mdio_ctl, mdio_cfg;
u16 value;
int ret;
mdio_cfg = ENETC_EMDIO_CFG;
mdio_cfg |= MDIO_CFG_ENC45;
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
ret = enetc_mdio_wait_complete(mdio_priv); ret = enetc_mdio_wait_complete(mdio_priv);
...@@ -129,13 +190,11 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) ...@@ -129,13 +190,11 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
/* set the register address */ /* set the register address */
if (regnum & MII_ADDR_C45) { enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
ret = enetc_mdio_wait_complete(mdio_priv); ret = enetc_mdio_wait_complete(mdio_priv);
if (ret) if (ret)
return ret; return ret;
}
/* initiate the read */ /* initiate the read */
enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
...@@ -156,7 +215,7 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) ...@@ -156,7 +215,7 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
return value; return value;
} }
EXPORT_SYMBOL_GPL(enetc_mdio_read); EXPORT_SYMBOL_GPL(enetc_mdio_read_c45);
struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
{ {
......
...@@ -39,8 +39,10 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, ...@@ -39,8 +39,10 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
} }
bus->name = ENETC_MDIO_BUS_NAME; bus->name = ENETC_MDIO_BUS_NAME;
bus->read = enetc_mdio_read; bus->read = enetc_mdio_read_c22;
bus->write = enetc_mdio_write; bus->write = enetc_mdio_write_c22;
bus->read_c45 = enetc_mdio_read_c45;
bus->write_c45 = enetc_mdio_write_c45;
bus->parent = dev; bus->parent = dev;
mdio_priv = bus->priv; mdio_priv = bus->priv;
mdio_priv->hw = hw; mdio_priv->hw = hw;
......
...@@ -848,8 +848,10 @@ static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np) ...@@ -848,8 +848,10 @@ static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
return -ENOMEM; return -ENOMEM;
bus->name = "Freescale ENETC MDIO Bus"; bus->name = "Freescale ENETC MDIO Bus";
bus->read = enetc_mdio_read; bus->read = enetc_mdio_read_c22;
bus->write = enetc_mdio_write; bus->write = enetc_mdio_write_c22;
bus->read_c45 = enetc_mdio_read_c45;
bus->write_c45 = enetc_mdio_write_c45;
bus->parent = dev; bus->parent = dev;
mdio_priv = bus->priv; mdio_priv = bus->priv;
mdio_priv->hw = &pf->si->hw; mdio_priv->hw = &pf->si->hw;
...@@ -885,8 +887,10 @@ static int enetc_imdio_create(struct enetc_pf *pf) ...@@ -885,8 +887,10 @@ static int enetc_imdio_create(struct enetc_pf *pf)
return -ENOMEM; return -ENOMEM;
bus->name = "Freescale ENETC internal MDIO Bus"; bus->name = "Freescale ENETC internal MDIO Bus";
bus->read = enetc_mdio_read; bus->read = enetc_mdio_read_c22;
bus->write = enetc_mdio_write; bus->write = enetc_mdio_write_c22;
bus->read_c45 = enetc_mdio_read_c45;
bus->write_c45 = enetc_mdio_write_c45;
bus->parent = dev; bus->parent = dev;
bus->phy_mask = ~0; bus->phy_mask = ~0;
mdio_priv = bus->priv; mdio_priv = bus->priv;
......
...@@ -215,8 +215,8 @@ static int mtk_mdio_busy_wait(struct mtk_eth *eth) ...@@ -215,8 +215,8 @@ static int mtk_mdio_busy_wait(struct mtk_eth *eth)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg, static int _mtk_mdio_write_c22(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg,
u32 write_data) u32 write_data)
{ {
int ret; int ret;
...@@ -224,35 +224,13 @@ static int _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg, ...@@ -224,35 +224,13 @@ static int _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (phy_reg & MII_ADDR_C45) { mtk_w32(eth, PHY_IAC_ACCESS |
mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C22 |
PHY_IAC_START_C45 | PHY_IAC_CMD_WRITE |
PHY_IAC_CMD_C45_ADDR | PHY_IAC_REG(phy_reg) |
PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) | PHY_IAC_ADDR(phy_addr) |
PHY_IAC_ADDR(phy_addr) | PHY_IAC_DATA(write_data),
PHY_IAC_DATA(mdiobus_c45_regad(phy_reg)), MTK_PHY_IAC);
MTK_PHY_IAC);
ret = mtk_mdio_busy_wait(eth);
if (ret < 0)
return ret;
mtk_w32(eth, PHY_IAC_ACCESS |
PHY_IAC_START_C45 |
PHY_IAC_CMD_WRITE |
PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) |
PHY_IAC_ADDR(phy_addr) |
PHY_IAC_DATA(write_data),
MTK_PHY_IAC);
} else {
mtk_w32(eth, PHY_IAC_ACCESS |
PHY_IAC_START_C22 |
PHY_IAC_CMD_WRITE |
PHY_IAC_REG(phy_reg) |
PHY_IAC_ADDR(phy_addr) |
PHY_IAC_DATA(write_data),
MTK_PHY_IAC);
}
ret = mtk_mdio_busy_wait(eth); ret = mtk_mdio_busy_wait(eth);
if (ret < 0) if (ret < 0)
...@@ -261,7 +239,8 @@ static int _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg, ...@@ -261,7 +239,8 @@ static int _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg,
return 0; return 0;
} }
static int _mtk_mdio_read(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg) static int _mtk_mdio_write_c45(struct mtk_eth *eth, u32 phy_addr,
u32 devad, u32 phy_reg, u32 write_data)
{ {
int ret; int ret;
...@@ -269,33 +248,82 @@ static int _mtk_mdio_read(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg) ...@@ -269,33 +248,82 @@ static int _mtk_mdio_read(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (phy_reg & MII_ADDR_C45) { mtk_w32(eth, PHY_IAC_ACCESS |
mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 |
PHY_IAC_START_C45 | PHY_IAC_CMD_C45_ADDR |
PHY_IAC_CMD_C45_ADDR | PHY_IAC_REG(devad) |
PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) | PHY_IAC_ADDR(phy_addr) |
PHY_IAC_ADDR(phy_addr) | PHY_IAC_DATA(phy_reg),
PHY_IAC_DATA(mdiobus_c45_regad(phy_reg)), MTK_PHY_IAC);
MTK_PHY_IAC);
ret = mtk_mdio_busy_wait(eth);
ret = mtk_mdio_busy_wait(eth); if (ret < 0)
if (ret < 0) return ret;
return ret;
mtk_w32(eth, PHY_IAC_ACCESS |
mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 |
PHY_IAC_START_C45 | PHY_IAC_CMD_WRITE |
PHY_IAC_CMD_C45_READ | PHY_IAC_REG(devad) |
PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) | PHY_IAC_ADDR(phy_addr) |
PHY_IAC_ADDR(phy_addr), PHY_IAC_DATA(write_data),
MTK_PHY_IAC); MTK_PHY_IAC);
} else {
mtk_w32(eth, PHY_IAC_ACCESS | ret = mtk_mdio_busy_wait(eth);
PHY_IAC_START_C22 | if (ret < 0)
PHY_IAC_CMD_C22_READ | return ret;
PHY_IAC_REG(phy_reg) |
PHY_IAC_ADDR(phy_addr), return 0;
MTK_PHY_IAC); }
}
static int _mtk_mdio_read_c22(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg)
{
int ret;
ret = mtk_mdio_busy_wait(eth);
if (ret < 0)
return ret;
mtk_w32(eth, PHY_IAC_ACCESS |
PHY_IAC_START_C22 |
PHY_IAC_CMD_C22_READ |
PHY_IAC_REG(phy_reg) |
PHY_IAC_ADDR(phy_addr),
MTK_PHY_IAC);
ret = mtk_mdio_busy_wait(eth);
if (ret < 0)
return ret;
return mtk_r32(eth, MTK_PHY_IAC) & PHY_IAC_DATA_MASK;
}
static int _mtk_mdio_read_c45(struct mtk_eth *eth, u32 phy_addr,
u32 devad, u32 phy_reg)
{
int ret;
ret = mtk_mdio_busy_wait(eth);
if (ret < 0)
return ret;
mtk_w32(eth, PHY_IAC_ACCESS |
PHY_IAC_START_C45 |
PHY_IAC_CMD_C45_ADDR |
PHY_IAC_REG(devad) |
PHY_IAC_ADDR(phy_addr) |
PHY_IAC_DATA(phy_reg),
MTK_PHY_IAC);
ret = mtk_mdio_busy_wait(eth);
if (ret < 0)
return ret;
mtk_w32(eth, PHY_IAC_ACCESS |
PHY_IAC_START_C45 |
PHY_IAC_CMD_C45_READ |
PHY_IAC_REG(devad) |
PHY_IAC_ADDR(phy_addr),
MTK_PHY_IAC);
ret = mtk_mdio_busy_wait(eth); ret = mtk_mdio_busy_wait(eth);
if (ret < 0) if (ret < 0)
...@@ -304,19 +332,35 @@ static int _mtk_mdio_read(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg) ...@@ -304,19 +332,35 @@ static int _mtk_mdio_read(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg)
return mtk_r32(eth, MTK_PHY_IAC) & PHY_IAC_DATA_MASK; return mtk_r32(eth, MTK_PHY_IAC) & PHY_IAC_DATA_MASK;
} }
static int mtk_mdio_write(struct mii_bus *bus, int phy_addr, static int mtk_mdio_write_c22(struct mii_bus *bus, int phy_addr,
int phy_reg, u16 val) int phy_reg, u16 val)
{
struct mtk_eth *eth = bus->priv;
return _mtk_mdio_write_c22(eth, phy_addr, phy_reg, val);
}
static int mtk_mdio_write_c45(struct mii_bus *bus, int phy_addr,
int devad, int phy_reg, u16 val)
{
struct mtk_eth *eth = bus->priv;
return _mtk_mdio_write_c45(eth, phy_addr, devad, phy_reg, val);
}
static int mtk_mdio_read_c22(struct mii_bus *bus, int phy_addr, int phy_reg)
{ {
struct mtk_eth *eth = bus->priv; struct mtk_eth *eth = bus->priv;
return _mtk_mdio_write(eth, phy_addr, phy_reg, val); return _mtk_mdio_read_c22(eth, phy_addr, phy_reg);
} }
static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) static int mtk_mdio_read_c45(struct mii_bus *bus, int phy_addr, int devad,
int phy_reg)
{ {
struct mtk_eth *eth = bus->priv; struct mtk_eth *eth = bus->priv;
return _mtk_mdio_read(eth, phy_addr, phy_reg); return _mtk_mdio_read_c45(eth, phy_addr, devad, phy_reg);
} }
static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth, static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth,
...@@ -760,8 +804,10 @@ static int mtk_mdio_init(struct mtk_eth *eth) ...@@ -760,8 +804,10 @@ static int mtk_mdio_init(struct mtk_eth *eth)
} }
eth->mii_bus->name = "mdio"; eth->mii_bus->name = "mdio";
eth->mii_bus->read = mtk_mdio_read; eth->mii_bus->read = mtk_mdio_read_c22;
eth->mii_bus->write = mtk_mdio_write; eth->mii_bus->write = mtk_mdio_write_c22;
eth->mii_bus->read_c45 = mtk_mdio_read_c45;
eth->mii_bus->write_c45 = mtk_mdio_write_c45;
eth->mii_bus->probe_capabilities = MDIOBUS_C22_C45; eth->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
eth->mii_bus->priv = eth; eth->mii_bus->priv = eth;
eth->mii_bus->parent = eth->dev; eth->mii_bus->parent = eth->dev;
......
...@@ -792,7 +792,7 @@ static int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter) ...@@ -792,7 +792,7 @@ static int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter)
!(data & MAC_MII_ACC_MII_BUSY_), 0, 1000000); !(data & MAC_MII_ACC_MII_BUSY_), 0, 1000000);
} }
static int lan743x_mdiobus_read(struct mii_bus *bus, int phy_id, int index) static int lan743x_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int index)
{ {
struct lan743x_adapter *adapter = bus->priv; struct lan743x_adapter *adapter = bus->priv;
u32 val, mii_access; u32 val, mii_access;
...@@ -814,8 +814,8 @@ static int lan743x_mdiobus_read(struct mii_bus *bus, int phy_id, int index) ...@@ -814,8 +814,8 @@ static int lan743x_mdiobus_read(struct mii_bus *bus, int phy_id, int index)
return (int)(val & 0xFFFF); return (int)(val & 0xFFFF);
} }
static int lan743x_mdiobus_write(struct mii_bus *bus, static int lan743x_mdiobus_write_c22(struct mii_bus *bus,
int phy_id, int index, u16 regval) int phy_id, int index, u16 regval)
{ {
struct lan743x_adapter *adapter = bus->priv; struct lan743x_adapter *adapter = bus->priv;
u32 val, mii_access; u32 val, mii_access;
...@@ -835,12 +835,10 @@ static int lan743x_mdiobus_write(struct mii_bus *bus, ...@@ -835,12 +835,10 @@ static int lan743x_mdiobus_write(struct mii_bus *bus,
return ret; return ret;
} }
static u32 lan743x_mac_mmd_access(int id, int index, int op) static u32 lan743x_mac_mmd_access(int id, int dev_addr, int op)
{ {
u16 dev_addr;
u32 ret; u32 ret;
dev_addr = (index >> 16) & 0x1f;
ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) & ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) &
MAC_MII_ACC_PHY_ADDR_MASK_; MAC_MII_ACC_PHY_ADDR_MASK_;
ret |= (dev_addr << MAC_MII_ACC_MIIMMD_SHIFT_) & ret |= (dev_addr << MAC_MII_ACC_MIIMMD_SHIFT_) &
...@@ -858,7 +856,8 @@ static u32 lan743x_mac_mmd_access(int id, int index, int op) ...@@ -858,7 +856,8 @@ static u32 lan743x_mac_mmd_access(int id, int index, int op)
return ret; return ret;
} }
static int lan743x_mdiobus_c45_read(struct mii_bus *bus, int phy_id, int index) static int lan743x_mdiobus_read_c45(struct mii_bus *bus, int phy_id,
int dev_addr, int index)
{ {
struct lan743x_adapter *adapter = bus->priv; struct lan743x_adapter *adapter = bus->priv;
u32 mmd_access; u32 mmd_access;
...@@ -868,32 +867,30 @@ static int lan743x_mdiobus_c45_read(struct mii_bus *bus, int phy_id, int index) ...@@ -868,32 +867,30 @@ static int lan743x_mdiobus_c45_read(struct mii_bus *bus, int phy_id, int index)
ret = lan743x_mac_mii_wait_till_not_busy(adapter); ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (index & MII_ADDR_C45) {
/* Load Register Address */
lan743x_csr_write(adapter, MAC_MII_DATA, (u32)(index & 0xffff));
mmd_access = lan743x_mac_mmd_access(phy_id, index,
MMD_ACCESS_ADDRESS);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0)
return ret;
/* Read Data */
mmd_access = lan743x_mac_mmd_access(phy_id, index,
MMD_ACCESS_READ);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0)
return ret;
ret = lan743x_csr_read(adapter, MAC_MII_DATA);
return (int)(ret & 0xFFFF);
}
ret = lan743x_mdiobus_read(bus, phy_id, index); /* Load Register Address */
return ret; lan743x_csr_write(adapter, MAC_MII_DATA, index);
mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
MMD_ACCESS_ADDRESS);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0)
return ret;
/* Read Data */
mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
MMD_ACCESS_READ);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0)
return ret;
ret = lan743x_csr_read(adapter, MAC_MII_DATA);
return (int)(ret & 0xFFFF);
} }
static int lan743x_mdiobus_c45_write(struct mii_bus *bus, static int lan743x_mdiobus_write_c45(struct mii_bus *bus, int phy_id,
int phy_id, int index, u16 regval) int dev_addr, int index, u16 regval)
{ {
struct lan743x_adapter *adapter = bus->priv; struct lan743x_adapter *adapter = bus->priv;
u32 mmd_access; u32 mmd_access;
...@@ -903,26 +900,23 @@ static int lan743x_mdiobus_c45_write(struct mii_bus *bus, ...@@ -903,26 +900,23 @@ static int lan743x_mdiobus_c45_write(struct mii_bus *bus,
ret = lan743x_mac_mii_wait_till_not_busy(adapter); ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (index & MII_ADDR_C45) {
/* Load Register Address */
lan743x_csr_write(adapter, MAC_MII_DATA, (u32)(index & 0xffff));
mmd_access = lan743x_mac_mmd_access(phy_id, index,
MMD_ACCESS_ADDRESS);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0)
return ret;
/* Write Data */
lan743x_csr_write(adapter, MAC_MII_DATA, (u32)regval);
mmd_access = lan743x_mac_mmd_access(phy_id, index,
MMD_ACCESS_WRITE);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
ret = lan743x_mac_mii_wait_till_not_busy(adapter);
} else {
ret = lan743x_mdiobus_write(bus, phy_id, index, regval);
}
return ret; /* Load Register Address */
lan743x_csr_write(adapter, MAC_MII_DATA, (u32)index);
mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
MMD_ACCESS_ADDRESS);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
ret = lan743x_mac_mii_wait_till_not_busy(adapter);
if (ret < 0)
return ret;
/* Write Data */
lan743x_csr_write(adapter, MAC_MII_DATA, (u32)regval);
mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
MMD_ACCESS_WRITE);
lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
return lan743x_mac_mii_wait_till_not_busy(adapter);
} }
static int lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter *adapter) static int lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter *adapter)
...@@ -3286,8 +3280,10 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) ...@@ -3286,8 +3280,10 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
netif_dbg(adapter, drv, adapter->netdev, netif_dbg(adapter, drv, adapter->netdev,
"SGMII operation\n"); "SGMII operation\n");
adapter->mdiobus->probe_capabilities = MDIOBUS_C22_C45; adapter->mdiobus->probe_capabilities = MDIOBUS_C22_C45;
adapter->mdiobus->read = lan743x_mdiobus_c45_read; adapter->mdiobus->read = lan743x_mdiobus_read_c22;
adapter->mdiobus->write = lan743x_mdiobus_c45_write; adapter->mdiobus->write = lan743x_mdiobus_write_c22;
adapter->mdiobus->read_c45 = lan743x_mdiobus_read_c45;
adapter->mdiobus->write_c45 = lan743x_mdiobus_write_c45;
adapter->mdiobus->name = "lan743x-mdiobus-c45"; adapter->mdiobus->name = "lan743x-mdiobus-c45";
netif_dbg(adapter, drv, adapter->netdev, netif_dbg(adapter, drv, adapter->netdev,
"lan743x-mdiobus-c45\n"); "lan743x-mdiobus-c45\n");
...@@ -3300,15 +3296,15 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) ...@@ -3300,15 +3296,15 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
"RGMII operation\n"); "RGMII operation\n");
// Only C22 support when RGMII I/F // Only C22 support when RGMII I/F
adapter->mdiobus->probe_capabilities = MDIOBUS_C22; adapter->mdiobus->probe_capabilities = MDIOBUS_C22;
adapter->mdiobus->read = lan743x_mdiobus_read; adapter->mdiobus->read = lan743x_mdiobus_read_c22;
adapter->mdiobus->write = lan743x_mdiobus_write; adapter->mdiobus->write = lan743x_mdiobus_write_c22;
adapter->mdiobus->name = "lan743x-mdiobus"; adapter->mdiobus->name = "lan743x-mdiobus";
netif_dbg(adapter, drv, adapter->netdev, netif_dbg(adapter, drv, adapter->netdev,
"lan743x-mdiobus\n"); "lan743x-mdiobus\n");
} }
} else { } else {
adapter->mdiobus->read = lan743x_mdiobus_read; adapter->mdiobus->read = lan743x_mdiobus_read_c22;
adapter->mdiobus->write = lan743x_mdiobus_write; adapter->mdiobus->write = lan743x_mdiobus_write_c22;
adapter->mdiobus->name = "lan743x-mdiobus"; adapter->mdiobus->name = "lan743x-mdiobus";
netif_dbg(adapter, drv, adapter->netdev, "lan743x-mdiobus\n"); netif_dbg(adapter, drv, adapter->netdev, "lan743x-mdiobus\n");
} }
......
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
#define MII_XGMAC_PA_SHIFT 16 #define MII_XGMAC_PA_SHIFT 16
#define MII_XGMAC_DA_SHIFT 21 #define MII_XGMAC_DA_SHIFT 21
static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
int phyreg, u32 *hw_addr) int devad, int phyreg, u32 *hw_addr)
{ {
u32 tmp; u32 tmp;
...@@ -56,19 +56,14 @@ static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, ...@@ -56,19 +56,14 @@ static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff); *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff);
*hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT; *hw_addr |= devad << MII_XGMAC_DA_SHIFT;
return 0;
} }
static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, static void stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
int phyreg, u32 *hw_addr) int phyreg, u32 *hw_addr)
{ {
u32 tmp; u32 tmp;
/* HW does not support C22 addr >= 4 */
if (phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
/* Set port as Clause 22 */ /* Set port as Clause 22 */
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
tmp &= ~MII_XGMAC_C22P_MASK; tmp &= ~MII_XGMAC_C22P_MASK;
...@@ -76,16 +71,14 @@ static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, ...@@ -76,16 +71,14 @@ static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f); *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
return 0;
} }
static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr,
u32 value)
{ {
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr; unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data; unsigned int mii_data = priv->hw->mii.data;
u32 tmp, addr, value = MII_XGMAC_BUSY; u32 tmp;
int ret; int ret;
ret = pm_runtime_resume_and_get(priv->device); ret = pm_runtime_resume_and_get(priv->device);
...@@ -99,20 +92,6 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) ...@@ -99,20 +92,6 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
goto err_disable_clks; goto err_disable_clks;
} }
if (phyreg & MII_ADDR_C45) {
phyreg &= ~MII_ADDR_C45;
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
value |= MII_XGMAC_SADDR;
}
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask; & priv->hw->mii.clk_csr_mask;
value |= MII_XGMAC_READ; value |= MII_XGMAC_READ;
...@@ -144,14 +123,44 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) ...@@ -144,14 +123,44 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
return ret; return ret;
} }
static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr,
int phyreg, u16 phydata) int phyreg)
{ {
struct net_device *ndev = bus->priv; struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev); struct stmmac_priv *priv;
u32 addr;
priv = netdev_priv(ndev);
/* HW does not support C22 addr >= 4 */
if (phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
}
static int stmmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr,
int devad, int phyreg)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv;
u32 addr;
priv = netdev_priv(ndev);
stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
}
static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr,
u32 value, u16 phydata)
{
unsigned int mii_address = priv->hw->mii.addr; unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data; unsigned int mii_data = priv->hw->mii.data;
u32 addr, tmp, value = MII_XGMAC_BUSY; u32 tmp;
int ret; int ret;
ret = pm_runtime_resume_and_get(priv->device); ret = pm_runtime_resume_and_get(priv->device);
...@@ -165,20 +174,6 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, ...@@ -165,20 +174,6 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
goto err_disable_clks; goto err_disable_clks;
} }
if (phyreg & MII_ADDR_C45) {
phyreg &= ~MII_ADDR_C45;
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
value |= MII_XGMAC_SADDR;
}
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask; & priv->hw->mii.clk_csr_mask;
value |= phydata; value |= phydata;
...@@ -205,8 +200,63 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, ...@@ -205,8 +200,63 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
return ret; return ret;
} }
static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr,
int phyreg, u16 phydata)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv;
u32 addr;
priv = netdev_priv(ndev);
/* HW does not support C22 addr >= 4 */
if (phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
return stmmac_xgmac2_mdio_write(priv, addr,
MII_XGMAC_BUSY | MII_XGMAC_SADDR, phydata);
}
static int stmmac_xgmac2_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;
u32 addr;
priv = netdev_priv(ndev);
stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
return stmmac_xgmac2_mdio_write(priv, addr, MII_XGMAC_BUSY,
phydata);
}
static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value)
{
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 v;
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000))
return -EBUSY;
writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000))
return -EBUSY;
/* Read the data from the MII data register */
return readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
}
/** /**
* stmmac_mdio_read * stmmac_mdio_read_c22
* @bus: points to the mii_bus structure * @bus: points to the mii_bus structure
* @phyaddr: MII addr * @phyaddr: MII addr
* @phyreg: MII reg * @phyreg: MII reg
...@@ -215,15 +265,12 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, ...@@ -215,15 +265,12 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
* accessing the PHY registers. * accessing the PHY registers.
* Fortunately, it seems this has no drawback for the 7109 MAC. * Fortunately, it seems this has no drawback for the 7109 MAC.
*/ */
static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
{ {
struct net_device *ndev = bus->priv; struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev); struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 value = MII_BUSY; u32 value = MII_BUSY;
int data = 0; int data = 0;
u32 v;
data = pm_runtime_resume_and_get(priv->device); data = pm_runtime_resume_and_get(priv->device);
if (data < 0) if (data < 0)
...@@ -236,60 +283,94 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) ...@@ -236,60 +283,94 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
& priv->hw->mii.clk_csr_mask; & priv->hw->mii.clk_csr_mask;
if (priv->plat->has_gmac4) { if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ; value |= MII_GMAC4_READ;
if (phyreg & MII_ADDR_C45) {
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
priv->hw->mii.reg_shift) &
priv->hw->mii.reg_mask;
data |= (phyreg & MII_REGADDR_C45_MASK) <<
MII_GMAC4_REG_ADDR_SHIFT;
}
} }
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), data = stmmac_mdio_read(priv, data, value);
100, 10000)) {
data = -EBUSY;
goto err_disable_clks;
}
writel(data, priv->ioaddr + mii_data); pm_runtime_put(priv->device);
writel(value, priv->ioaddr + mii_address);
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), return data;
100, 10000)) { }
data = -EBUSY;
goto err_disable_clks; /**
* 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.
*/
static int 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;
} }
/* Read the data from the MII data register */ value |= (phyaddr << priv->hw->mii.addr_shift)
data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK; & 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;
data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
data = stmmac_mdio_read(priv, data, value);
err_disable_clks:
pm_runtime_put(priv->device); pm_runtime_put(priv->device);
return data; return data;
} }
static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value)
{
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 v;
/* 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 * stmmac_mdio_write_c22
* @bus: points to the mii_bus structure * @bus: points to the mii_bus structure
* @phyaddr: MII addr * @phyaddr: MII addr
* @phyreg: MII reg * @phyreg: MII reg
* @phydata: phy data * @phydata: phy data
* Description: it writes the data into the MII register from within the device. * Description: it writes the data into the MII register from within the device.
*/ */
static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg,
u16 phydata) u16 phydata)
{ {
struct net_device *ndev = bus->priv; struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev); struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
int ret, data = phydata; int ret, data = phydata;
u32 value = MII_BUSY; u32 value = MII_BUSY;
u32 v;
ret = pm_runtime_resume_and_get(priv->device); ret = pm_runtime_resume_and_get(priv->device);
if (ret < 0) if (ret < 0)
...@@ -301,38 +382,57 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, ...@@ -301,38 +382,57 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask; & priv->hw->mii.clk_csr_mask;
if (priv->plat->has_gmac4) { if (priv->plat->has_gmac4)
value |= MII_GMAC4_WRITE; value |= MII_GMAC4_WRITE;
if (phyreg & MII_ADDR_C45) { else
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
priv->hw->mii.reg_shift) &
priv->hw->mii.reg_mask;
data |= (phyreg & MII_REGADDR_C45_MASK) <<
MII_GMAC4_REG_ADDR_SHIFT;
}
} else {
value |= MII_WRITE; value |= MII_WRITE;
}
/* Wait until any existing MII operation is complete */ ret = stmmac_mdio_write(priv, data, value);
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000)) { pm_runtime_put(priv->device);
ret = -EBUSY;
goto err_disable_clks; 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.
*/
static int 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;
} }
/* Set the MII address register to write */ value |= (phyaddr << priv->hw->mii.addr_shift)
writel(data, priv->ioaddr + mii_data); & priv->hw->mii.addr_mask;
writel(value, priv->ioaddr + mii_address); value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
/* Wait until any existing MII operation is complete */ value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), & priv->hw->mii.clk_csr_mask;
100, 10000);
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);
err_disable_clks:
pm_runtime_put(priv->device); pm_runtime_put(priv->device);
return ret; return ret;
...@@ -457,8 +557,10 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -457,8 +557,10 @@ int stmmac_mdio_register(struct net_device *ndev)
new_bus->probe_capabilities = MDIOBUS_C22_C45; new_bus->probe_capabilities = MDIOBUS_C22_C45;
if (priv->plat->has_xgmac) { if (priv->plat->has_xgmac) {
new_bus->read = &stmmac_xgmac2_mdio_read; new_bus->read = &stmmac_xgmac2_mdio_read_c22;
new_bus->write = &stmmac_xgmac2_mdio_write; new_bus->write = &stmmac_xgmac2_mdio_write_c22;
new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45;
new_bus->write_c45 = &stmmac_xgmac2_mdio_write_c45;
/* Right now only C22 phys are supported */ /* Right now only C22 phys are supported */
max_addr = MII_XGMAC_MAX_C22ADDR + 1; max_addr = MII_XGMAC_MAX_C22ADDR + 1;
...@@ -468,8 +570,13 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -468,8 +570,13 @@ int stmmac_mdio_register(struct net_device *ndev)
dev_err(dev, "Unsupported phy_addr (max=%d)\n", dev_err(dev, "Unsupported phy_addr (max=%d)\n",
MII_XGMAC_MAX_C22ADDR); MII_XGMAC_MAX_C22ADDR);
} else { } else {
new_bus->read = &stmmac_mdio_read; new_bus->read = &stmmac_mdio_read_c22;
new_bus->write = &stmmac_mdio_write; new_bus->write = &stmmac_mdio_write_c22;
if (priv->plat->has_gmac4) {
new_bus->read_c45 = &stmmac_mdio_read_c45;
new_bus->write_c45 = &stmmac_mdio_write_c45;
}
max_addr = PHY_MAX_ADDR; max_addr = PHY_MAX_ADDR;
} }
...@@ -490,7 +597,7 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -490,7 +597,7 @@ int stmmac_mdio_register(struct net_device *ndev)
/* Looks like we need a dummy read for XGMAC only and C45 PHYs */ /* Looks like we need a dummy read for XGMAC only and C45 PHYs */
if (priv->plat->has_xgmac) if (priv->plat->has_xgmac)
stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45); stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
/* If fixed-link is set, skip PHY scanning */ /* If fixed-link is set, skip PHY scanning */
if (!fwnode) if (!fwnode)
......
...@@ -104,61 +104,36 @@ static int aspeed_mdio_write_c22(struct mii_bus *bus, int addr, int regnum, ...@@ -104,61 +104,36 @@ static int aspeed_mdio_write_c22(struct mii_bus *bus, int addr, int regnum,
addr, regnum, val); addr, regnum, val);
} }
static int aspeed_mdio_read_c45(struct mii_bus *bus, int addr, int regnum) static int aspeed_mdio_read_c45(struct mii_bus *bus, int addr, int devad,
int regnum)
{ {
u8 c45_dev = (regnum >> 16) & 0x1F;
u16 c45_addr = regnum & 0xFFFF;
int rc; int rc;
rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_ADDR, rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_ADDR,
addr, c45_dev, c45_addr); addr, devad, regnum);
if (rc < 0) if (rc < 0)
return rc; return rc;
rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_READ, rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_READ,
addr, c45_dev, 0); addr, devad, 0);
if (rc < 0) if (rc < 0)
return rc; return rc;
return aspeed_mdio_get_data(bus); return aspeed_mdio_get_data(bus);
} }
static int aspeed_mdio_write_c45(struct mii_bus *bus, int addr, int regnum, static int aspeed_mdio_write_c45(struct mii_bus *bus, int addr, int devad,
u16 val) int regnum, u16 val)
{ {
u8 c45_dev = (regnum >> 16) & 0x1F;
u16 c45_addr = regnum & 0xFFFF;
int rc; int rc;
rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_ADDR, rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_ADDR,
addr, c45_dev, c45_addr); addr, devad, regnum);
if (rc < 0) if (rc < 0)
return rc; return rc;
return aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_WRITE, return aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_WRITE,
addr, c45_dev, val); addr, devad, val);
}
static int aspeed_mdio_read(struct mii_bus *bus, int addr, int regnum)
{
dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d\n", __func__, addr,
regnum);
if (regnum & MII_ADDR_C45)
return aspeed_mdio_read_c45(bus, addr, regnum);
return aspeed_mdio_read_c22(bus, addr, regnum);
}
static int aspeed_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
{
dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d, val: 0x%x\n",
__func__, addr, regnum, val);
if (regnum & MII_ADDR_C45)
return aspeed_mdio_write_c45(bus, addr, regnum, val);
return aspeed_mdio_write_c22(bus, addr, regnum, val);
} }
static int aspeed_mdio_probe(struct platform_device *pdev) static int aspeed_mdio_probe(struct platform_device *pdev)
...@@ -185,8 +160,10 @@ static int aspeed_mdio_probe(struct platform_device *pdev) ...@@ -185,8 +160,10 @@ static int aspeed_mdio_probe(struct platform_device *pdev)
bus->name = DRV_NAME; bus->name = DRV_NAME;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id); snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
bus->parent = &pdev->dev; bus->parent = &pdev->dev;
bus->read = aspeed_mdio_read; bus->read = aspeed_mdio_read_c22;
bus->write = aspeed_mdio_write; bus->write = aspeed_mdio_write_c22;
bus->read_c45 = aspeed_mdio_read_c45;
bus->write_c45 = aspeed_mdio_write_c45;
bus->probe_capabilities = MDIOBUS_C22_C45; bus->probe_capabilities = MDIOBUS_C22_C45;
rc = of_mdiobus_register(bus, pdev->dev.of_node); rc = of_mdiobus_register(bus, pdev->dev.of_node);
......
...@@ -26,7 +26,7 @@ static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p, ...@@ -26,7 +26,7 @@ static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p,
} }
static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p, static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
int phy_id, int regnum) int phy_id, int devad, int regnum)
{ {
union cvmx_smix_cmd smi_cmd; union cvmx_smix_cmd smi_cmd;
union cvmx_smix_wr_dat smi_wr; union cvmx_smix_wr_dat smi_wr;
...@@ -38,12 +38,10 @@ static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p, ...@@ -38,12 +38,10 @@ static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
smi_wr.s.dat = regnum & 0xffff; smi_wr.s.dat = regnum & 0xffff;
oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
regnum = (regnum >> 16) & 0x1f;
smi_cmd.u64 = 0; smi_cmd.u64 = 0;
smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
smi_cmd.s.phy_adr = phy_id; smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum; smi_cmd.s.reg_adr = devad;
oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
do { do {
...@@ -59,28 +57,51 @@ static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p, ...@@ -59,28 +57,51 @@ static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
return 0; return 0;
} }
int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) int cavium_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int regnum)
{ {
struct cavium_mdiobus *p = bus->priv; struct cavium_mdiobus *p = bus->priv;
union cvmx_smix_cmd smi_cmd; union cvmx_smix_cmd smi_cmd;
union cvmx_smix_rd_dat smi_rd; union cvmx_smix_rd_dat smi_rd;
unsigned int op = 1; /* MDIO_CLAUSE_22_READ */
int timeout = 1000; int timeout = 1000;
if (regnum & MII_ADDR_C45) { cavium_mdiobus_set_mode(p, C22);
int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
smi_cmd.u64 = 0;
smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */;
smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum;
oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
do {
/* Wait 1000 clocks so we don't saturate the RSL bus
* doing reads.
*/
__delay(1000);
smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
} while (smi_rd.s.pending && --timeout);
if (smi_rd.s.val)
return smi_rd.s.dat;
else
return -EIO;
}
EXPORT_SYMBOL(cavium_mdiobus_read_c22);
if (r < 0) int cavium_mdiobus_read_c45(struct mii_bus *bus, int phy_id, int devad,
return r; int regnum)
{
struct cavium_mdiobus *p = bus->priv;
union cvmx_smix_cmd smi_cmd;
union cvmx_smix_rd_dat smi_rd;
int timeout = 1000;
int r;
regnum = (regnum >> 16) & 0x1f; r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);
op = 3; /* MDIO_CLAUSE_45_READ */ if (r < 0)
} else { return r;
cavium_mdiobus_set_mode(p, C22);
}
smi_cmd.u64 = 0; smi_cmd.u64 = 0;
smi_cmd.s.phy_op = op; smi_cmd.s.phy_op = 3; /* MDIO_CLAUSE_45_READ */
smi_cmd.s.phy_adr = phy_id; smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum; smi_cmd.s.reg_adr = regnum;
oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
...@@ -98,36 +119,64 @@ int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) ...@@ -98,36 +119,64 @@ int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
else else
return -EIO; return -EIO;
} }
EXPORT_SYMBOL(cavium_mdiobus_read); EXPORT_SYMBOL(cavium_mdiobus_read_c45);
int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val) int cavium_mdiobus_write_c22(struct mii_bus *bus, int phy_id, int regnum,
u16 val)
{ {
struct cavium_mdiobus *p = bus->priv; struct cavium_mdiobus *p = bus->priv;
union cvmx_smix_cmd smi_cmd; union cvmx_smix_cmd smi_cmd;
union cvmx_smix_wr_dat smi_wr; union cvmx_smix_wr_dat smi_wr;
unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */
int timeout = 1000; int timeout = 1000;
if (regnum & MII_ADDR_C45) { cavium_mdiobus_set_mode(p, C22);
int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
if (r < 0) smi_wr.u64 = 0;
return r; smi_wr.s.dat = val;
oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
regnum = (regnum >> 16) & 0x1f; smi_cmd.u64 = 0;
op = 1; /* MDIO_CLAUSE_45_WRITE */ smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */;
} else { smi_cmd.s.phy_adr = phy_id;
cavium_mdiobus_set_mode(p, C22); smi_cmd.s.reg_adr = regnum;
} oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
do {
/* Wait 1000 clocks so we don't saturate the RSL bus
* doing reads.
*/
__delay(1000);
smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
} while (smi_wr.s.pending && --timeout);
if (timeout <= 0)
return -EIO;
return 0;
}
EXPORT_SYMBOL(cavium_mdiobus_write_c22);
int cavium_mdiobus_write_c45(struct mii_bus *bus, int phy_id, int devad,
int regnum, u16 val)
{
struct cavium_mdiobus *p = bus->priv;
union cvmx_smix_cmd smi_cmd;
union cvmx_smix_wr_dat smi_wr;
int timeout = 1000;
int r;
r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);
if (r < 0)
return r;
smi_wr.u64 = 0; smi_wr.u64 = 0;
smi_wr.s.dat = val; smi_wr.s.dat = val;
oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
smi_cmd.u64 = 0; smi_cmd.u64 = 0;
smi_cmd.s.phy_op = op; smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_45_WRITE */
smi_cmd.s.phy_adr = phy_id; smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum; smi_cmd.s.reg_adr = devad;
oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
do { do {
...@@ -143,7 +192,7 @@ int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val) ...@@ -143,7 +192,7 @@ int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
return 0; return 0;
} }
EXPORT_SYMBOL(cavium_mdiobus_write); EXPORT_SYMBOL(cavium_mdiobus_write_c45);
MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers"); MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");
MODULE_AUTHOR("David Daney"); MODULE_AUTHOR("David Daney");
......
...@@ -114,5 +114,10 @@ static inline u64 oct_mdio_readq(void __iomem *addr) ...@@ -114,5 +114,10 @@ static inline u64 oct_mdio_readq(void __iomem *addr)
#define oct_mdio_readq(addr) readq(addr) #define oct_mdio_readq(addr) readq(addr)
#endif #endif
int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum); int cavium_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int regnum);
int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val); int cavium_mdiobus_write_c22(struct mii_bus *bus, int phy_id, int regnum,
u16 val);
int cavium_mdiobus_read_c45(struct mii_bus *bus, int phy_id, int devad,
int regnum);
int cavium_mdiobus_write_c45(struct mii_bus *bus, int phy_id, int devad,
int regnum, u16 val);
...@@ -30,7 +30,8 @@ static unsigned int i2c_mii_phy_addr(int phy_id) ...@@ -30,7 +30,8 @@ static unsigned int i2c_mii_phy_addr(int phy_id)
return phy_id + 0x40; return phy_id + 0x40;
} }
static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg) static int i2c_mii_read_default_c45(struct mii_bus *bus, int phy_id, int devad,
int reg)
{ {
struct i2c_adapter *i2c = bus->priv; struct i2c_adapter *i2c = bus->priv;
struct i2c_msg msgs[2]; struct i2c_msg msgs[2];
...@@ -41,8 +42,8 @@ static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg) ...@@ -41,8 +42,8 @@ static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg)
return 0xffff; return 0xffff;
p = addr; p = addr;
if (reg & MII_ADDR_C45) { if (devad >= 0) {
*p++ = 0x20 | ((reg >> 16) & 31); *p++ = 0x20 | devad;
*p++ = reg >> 8; *p++ = reg >> 8;
} }
*p++ = reg; *p++ = reg;
...@@ -64,8 +65,8 @@ static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg) ...@@ -64,8 +65,8 @@ static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg)
return data[0] << 8 | data[1]; return data[0] << 8 | data[1];
} }
static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg, static int i2c_mii_write_default_c45(struct mii_bus *bus, int phy_id,
u16 val) int devad, int reg, u16 val)
{ {
struct i2c_adapter *i2c = bus->priv; struct i2c_adapter *i2c = bus->priv;
struct i2c_msg msg; struct i2c_msg msg;
...@@ -76,8 +77,8 @@ static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg, ...@@ -76,8 +77,8 @@ static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg,
return 0; return 0;
p = data; p = data;
if (reg & MII_ADDR_C45) { if (devad >= 0) {
*p++ = (reg >> 16) & 31; *p++ = devad;
*p++ = reg >> 8; *p++ = reg >> 8;
} }
*p++ = reg; *p++ = reg;
...@@ -94,6 +95,17 @@ static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg, ...@@ -94,6 +95,17 @@ static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg,
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
} }
static int i2c_mii_read_default_c22(struct mii_bus *bus, int phy_id, int reg)
{
return i2c_mii_read_default_c45(bus, phy_id, -1, reg);
}
static int i2c_mii_write_default_c22(struct mii_bus *bus, int phy_id, int reg,
u16 val)
{
return i2c_mii_write_default_c45(bus, phy_id, -1, reg, val);
}
/* RollBall SFPs do not access internal PHY via I2C address 0x56, but /* RollBall SFPs do not access internal PHY via I2C address 0x56, but
* instead via address 0x51, when SFP page is set to 0x03 and password to * instead via address 0x51, when SFP page is set to 0x03 and password to
* 0xffffffff. * 0xffffffff.
...@@ -403,8 +415,10 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, ...@@ -403,8 +415,10 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
mii->write = i2c_mii_write_rollball; mii->write = i2c_mii_write_rollball;
break; break;
default: default:
mii->read = i2c_mii_read_default; mii->read = i2c_mii_read_default_c22;
mii->write = i2c_mii_write_default; mii->write = i2c_mii_write_default_c22;
mii->read_c45 = i2c_mii_read_default_c45;
mii->write_c45 = i2c_mii_write_default_c45;
break; break;
} }
......
...@@ -53,7 +53,8 @@ static int ipq4019_mdio_wait_busy(struct mii_bus *bus) ...@@ -53,7 +53,8 @@ static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
IPQ4019_MDIO_SLEEP, IPQ4019_MDIO_TIMEOUT); IPQ4019_MDIO_SLEEP, IPQ4019_MDIO_TIMEOUT);
} }
static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum) static int ipq4019_mdio_read_c45(struct mii_bus *bus, int mii_id, int mmd,
int reg)
{ {
struct ipq4019_mdio_data *priv = bus->priv; struct ipq4019_mdio_data *priv = bus->priv;
unsigned int data; unsigned int data;
...@@ -62,61 +63,71 @@ static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum) ...@@ -62,61 +63,71 @@ static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
if (ipq4019_mdio_wait_busy(bus)) if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT; return -ETIMEDOUT;
/* Clause 45 support */ data = readl(priv->membase + MDIO_MODE_REG);
if (regnum & MII_ADDR_C45) {
unsigned int mmd = (regnum >> 16) & 0x1F;
unsigned int reg = regnum & 0xFFFF;
/* Enter Clause 45 mode */ data |= MDIO_MODE_C45;
data = readl(priv->membase + MDIO_MODE_REG);
data |= MDIO_MODE_C45; writel(data, priv->membase + MDIO_MODE_REG);
writel(data, priv->membase + MDIO_MODE_REG); /* issue the phy address and mmd */
writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
/* issue the phy address and mmd */ /* issue reg */
writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG); writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
/* issue reg */ cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR; /* issue read command */
} else { writel(cmd, priv->membase + MDIO_CMD_REG);
/* Enter Clause 22 mode */
data = readl(priv->membase + MDIO_MODE_REG);
data &= ~MDIO_MODE_C45; /* Wait read complete */
if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT;
writel(data, priv->membase + MDIO_MODE_REG); cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_READ;
/* issue the phy address and reg */ writel(cmd, priv->membase + MDIO_CMD_REG);
writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ; if (ipq4019_mdio_wait_busy(bus))
} return -ETIMEDOUT;
/* issue read command */ /* Read and return data */
writel(cmd, priv->membase + MDIO_CMD_REG); return readl(priv->membase + MDIO_DATA_READ_REG);
}
static int ipq4019_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
{
struct ipq4019_mdio_data *priv = bus->priv;
unsigned int data;
unsigned int cmd;
/* Wait read complete */
if (ipq4019_mdio_wait_busy(bus)) if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT; return -ETIMEDOUT;
if (regnum & MII_ADDR_C45) { data = readl(priv->membase + MDIO_MODE_REG);
cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_READ;
writel(cmd, priv->membase + MDIO_CMD_REG); data &= ~MDIO_MODE_C45;
if (ipq4019_mdio_wait_busy(bus)) writel(data, priv->membase + MDIO_MODE_REG);
return -ETIMEDOUT;
} /* issue the phy address and reg */
writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ;
/* issue read command */
writel(cmd, priv->membase + MDIO_CMD_REG);
/* Wait read complete */
if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT;
/* Read and return data */ /* Read and return data */
return readl(priv->membase + MDIO_DATA_READ_REG); return readl(priv->membase + MDIO_DATA_READ_REG);
} }
static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum, static int ipq4019_mdio_write_c45(struct mii_bus *bus, int mii_id, int mmd,
u16 value) int reg, u16 value)
{ {
struct ipq4019_mdio_data *priv = bus->priv; struct ipq4019_mdio_data *priv = bus->priv;
unsigned int data; unsigned int data;
...@@ -125,50 +136,63 @@ static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum, ...@@ -125,50 +136,63 @@ static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
if (ipq4019_mdio_wait_busy(bus)) if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT; return -ETIMEDOUT;
/* Clause 45 support */ data = readl(priv->membase + MDIO_MODE_REG);
if (regnum & MII_ADDR_C45) {
unsigned int mmd = (regnum >> 16) & 0x1F;
unsigned int reg = regnum & 0xFFFF;
/* Enter Clause 45 mode */ data |= MDIO_MODE_C45;
data = readl(priv->membase + MDIO_MODE_REG);
data |= MDIO_MODE_C45; writel(data, priv->membase + MDIO_MODE_REG);
writel(data, priv->membase + MDIO_MODE_REG); /* issue the phy address and mmd */
writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
/* issue the phy address and mmd */ /* issue reg */
writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG); writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
/* issue reg */ cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR; writel(cmd, priv->membase + MDIO_CMD_REG);
writel(cmd, priv->membase + MDIO_CMD_REG); if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT;
if (ipq4019_mdio_wait_busy(bus)) /* issue write data */
return -ETIMEDOUT; writel(value, priv->membase + MDIO_DATA_WRITE_REG);
} else {
/* Enter Clause 22 mode */
data = readl(priv->membase + MDIO_MODE_REG);
data &= ~MDIO_MODE_C45; cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_WRITE;
writel(cmd, priv->membase + MDIO_CMD_REG);
writel(data, priv->membase + MDIO_MODE_REG); /* Wait write complete */
if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT;
/* issue the phy address and reg */ return 0;
writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG); }
}
static int ipq4019_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum,
u16 value)
{
struct ipq4019_mdio_data *priv = bus->priv;
unsigned int data;
unsigned int cmd;
if (ipq4019_mdio_wait_busy(bus))
return -ETIMEDOUT;
/* Enter Clause 22 mode */
data = readl(priv->membase + MDIO_MODE_REG);
data &= ~MDIO_MODE_C45;
writel(data, priv->membase + MDIO_MODE_REG);
/* issue the phy address and reg */
writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
/* issue write data */ /* issue write data */
writel(value, priv->membase + MDIO_DATA_WRITE_REG); writel(value, priv->membase + MDIO_DATA_WRITE_REG);
/* issue write command */ /* issue write command */
if (regnum & MII_ADDR_C45) cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_WRITE;
else
cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
writel(cmd, priv->membase + MDIO_CMD_REG); writel(cmd, priv->membase + MDIO_CMD_REG);
...@@ -235,8 +259,10 @@ static int ipq4019_mdio_probe(struct platform_device *pdev) ...@@ -235,8 +259,10 @@ static int ipq4019_mdio_probe(struct platform_device *pdev)
priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res); priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res);
bus->name = "ipq4019_mdio"; bus->name = "ipq4019_mdio";
bus->read = ipq4019_mdio_read; bus->read = ipq4019_mdio_read_c22;
bus->write = ipq4019_mdio_write; bus->write = ipq4019_mdio_write_c22;
bus->read_c45 = ipq4019_mdio_read_c45;
bus->write_c45 = ipq4019_mdio_write_c45;
bus->reset = ipq_mdio_reset; bus->reset = ipq_mdio_reset;
bus->parent = &pdev->dev; bus->parent = &pdev->dev;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id); snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
......
...@@ -98,7 +98,7 @@ static int iproc_mdio_wait_for_idle(void __iomem *base, bool result) ...@@ -98,7 +98,7 @@ static int iproc_mdio_wait_for_idle(void __iomem *base, bool result)
* Return value: Successful Read operation returns read reg values and write * Return value: Successful Read operation returns read reg values and write
* operation returns 0. Failure operation returns negative error code. * operation returns 0. Failure operation returns negative error code.
*/ */
static int start_miim_ops(void __iomem *base, static int start_miim_ops(void __iomem *base, bool c45,
u16 phyid, u32 reg, u16 val, u32 op) u16 phyid, u32 reg, u16 val, u32 op)
{ {
u32 param; u32 param;
...@@ -112,7 +112,7 @@ static int start_miim_ops(void __iomem *base, ...@@ -112,7 +112,7 @@ static int start_miim_ops(void __iomem *base,
param = readl(base + MDIO_PARAM_OFFSET); param = readl(base + MDIO_PARAM_OFFSET);
param |= phyid << MDIO_PARAM_PHY_ID; param |= phyid << MDIO_PARAM_PHY_ID;
param |= val << MDIO_PARAM_PHY_DATA; param |= val << MDIO_PARAM_PHY_DATA;
if (reg & MII_ADDR_C45) if (c45)
param |= BIT(MDIO_PARAM_C45_SEL); param |= BIT(MDIO_PARAM_C45_SEL);
writel(param, base + MDIO_PARAM_OFFSET); writel(param, base + MDIO_PARAM_OFFSET);
...@@ -131,28 +131,58 @@ static int start_miim_ops(void __iomem *base, ...@@ -131,28 +131,58 @@ static int start_miim_ops(void __iomem *base,
return ret; return ret;
} }
static int iproc_mdiomux_read(struct mii_bus *bus, int phyid, int reg) static int iproc_mdiomux_read_c22(struct mii_bus *bus, int phyid, int reg)
{ {
struct iproc_mdiomux_desc *md = bus->priv; struct iproc_mdiomux_desc *md = bus->priv;
int ret; int ret;
ret = start_miim_ops(md->base, phyid, reg, 0, MDIO_CTRL_READ_OP); ret = start_miim_ops(md->base, false, phyid, reg, 0, MDIO_CTRL_READ_OP);
if (ret < 0) if (ret < 0)
dev_err(&bus->dev, "mdiomux read operation failed!!!"); dev_err(&bus->dev, "mdiomux c22 read operation failed!!!");
return ret; return ret;
} }
static int iproc_mdiomux_write(struct mii_bus *bus, static int iproc_mdiomux_read_c45(struct mii_bus *bus, int phyid, int devad,
int phyid, int reg, u16 val) int reg)
{
struct iproc_mdiomux_desc *md = bus->priv;
int ret;
ret = start_miim_ops(md->base, true, phyid, reg | devad << 16, 0,
MDIO_CTRL_READ_OP);
if (ret < 0)
dev_err(&bus->dev, "mdiomux read c45 operation failed!!!");
return ret;
}
static int iproc_mdiomux_write_c22(struct mii_bus *bus,
int phyid, int reg, u16 val)
{
struct iproc_mdiomux_desc *md = bus->priv;
int ret;
/* Write val at reg offset */
ret = start_miim_ops(md->base, false, phyid, reg, val,
MDIO_CTRL_WRITE_OP);
if (ret < 0)
dev_err(&bus->dev, "mdiomux write c22 operation failed!!!");
return ret;
}
static int iproc_mdiomux_write_c45(struct mii_bus *bus,
int phyid, int devad, int reg, u16 val)
{ {
struct iproc_mdiomux_desc *md = bus->priv; struct iproc_mdiomux_desc *md = bus->priv;
int ret; int ret;
/* Write val at reg offset */ /* Write val at reg offset */
ret = start_miim_ops(md->base, phyid, reg, val, MDIO_CTRL_WRITE_OP); ret = start_miim_ops(md->base, true, phyid, reg | devad << 16, val,
MDIO_CTRL_WRITE_OP);
if (ret < 0) if (ret < 0)
dev_err(&bus->dev, "mdiomux write operation failed!!!"); dev_err(&bus->dev, "mdiomux write c45 operation failed!!!");
return ret; return ret;
} }
...@@ -223,8 +253,10 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev) ...@@ -223,8 +253,10 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev)
bus->name = "iProc MDIO mux bus"; bus->name = "iProc MDIO mux bus";
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
bus->parent = &pdev->dev; bus->parent = &pdev->dev;
bus->read = iproc_mdiomux_read; bus->read = iproc_mdiomux_read_c22;
bus->write = iproc_mdiomux_write; bus->write = iproc_mdiomux_write_c22;
bus->read_c45 = iproc_mdiomux_read_c45;
bus->write_c45 = iproc_mdiomux_write_c45;
bus->phy_mask = ~0; bus->phy_mask = ~0;
bus->dev.of_node = pdev->dev.of_node; bus->dev.of_node = pdev->dev.of_node;
......
...@@ -58,8 +58,10 @@ static int octeon_mdiobus_probe(struct platform_device *pdev) ...@@ -58,8 +58,10 @@ static int octeon_mdiobus_probe(struct platform_device *pdev)
snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%px", bus->register_base); snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%px", bus->register_base);
bus->mii_bus->parent = &pdev->dev; bus->mii_bus->parent = &pdev->dev;
bus->mii_bus->read = cavium_mdiobus_read; bus->mii_bus->read = cavium_mdiobus_read_c22;
bus->mii_bus->write = cavium_mdiobus_write; bus->mii_bus->write = cavium_mdiobus_write_c22;
bus->mii_bus->read_c45 = cavium_mdiobus_read_c45;
bus->mii_bus->write_c45 = cavium_mdiobus_write_c45;
platform_set_drvdata(pdev, bus); platform_set_drvdata(pdev, bus);
......
...@@ -93,8 +93,10 @@ static int thunder_mdiobus_pci_probe(struct pci_dev *pdev, ...@@ -93,8 +93,10 @@ static int thunder_mdiobus_pci_probe(struct pci_dev *pdev,
bus->mii_bus->name = KBUILD_MODNAME; bus->mii_bus->name = KBUILD_MODNAME;
snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", r.start); snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", r.start);
bus->mii_bus->parent = &pdev->dev; bus->mii_bus->parent = &pdev->dev;
bus->mii_bus->read = cavium_mdiobus_read; bus->mii_bus->read = cavium_mdiobus_read_c22;
bus->mii_bus->write = cavium_mdiobus_write; bus->mii_bus->write = cavium_mdiobus_write_c22;
bus->mii_bus->read_c45 = cavium_mdiobus_read_c45;
bus->mii_bus->write_c45 = cavium_mdiobus_write_c45;
err = of_mdiobus_register(bus->mii_bus, node); err = of_mdiobus_register(bus->mii_bus, node);
if (err) if (err)
......
...@@ -37,16 +37,27 @@ struct enetc_mdio_priv { ...@@ -37,16 +37,27 @@ struct enetc_mdio_priv {
#if IS_REACHABLE(CONFIG_FSL_ENETC_MDIO) #if IS_REACHABLE(CONFIG_FSL_ENETC_MDIO)
int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum); int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum);
int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value); int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum,
u16 value);
int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int devad, int regnum);
int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int devad, int regnum,
u16 value);
struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs); struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs);
#else #else
static inline int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) static inline int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id,
int regnum)
{ return -EINVAL; } { return -EINVAL; }
static inline int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, static inline int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id,
u16 value) int regnum, u16 value)
{ return -EINVAL; }
static inline int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id,
int devad, int regnum)
{ return -EINVAL; }
static inline int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id,
int devad, int regnum, u16 value)
{ return -EINVAL; } { return -EINVAL; }
struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
{ return ERR_PTR(-EINVAL); } { return ERR_PTR(-EINVAL); }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment