Commit 1fcf77c8 authored by Andy Fleming's avatar Andy Fleming Committed by David S. Miller

net/fsl: Add mEMAC MDIO support to XGMAC MDIO

The Freescale mEMAC supports operating at 10/100/1000/10G, and
its associated MDIO controller is likewise capable of operating
both Clause 22 and Clause 45 MDIO buses. It is nearly identical
to the MDIO controller on the XGMAC, so we just modify that
driver.

Portions of this driver developed by:

Sandeep Singh <sandeep@freescale.com>
Roy Zang <tie-fei.zang@freescale.com>
Signed-off-by: default avatarAndy Fleming <afleming@gmail.com>
Signed-off-by: default avatarShaohui Xie <Shaohui.Xie@freescale.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2f438366
...@@ -69,7 +69,8 @@ config FSL_XGMAC_MDIO ...@@ -69,7 +69,8 @@ config FSL_XGMAC_MDIO
select PHYLIB select PHYLIB
select OF_MDIO select OF_MDIO
---help--- ---help---
This driver supports the MDIO bus on the Fman 10G Ethernet MACs. This driver supports the MDIO bus on the Fman 10G Ethernet MACs, and
on the FMan mEMAC (which supports both Clauses 22 and 45)
config UCC_GETH config UCC_GETH
tristate "Freescale QE Gigabit Ethernet" tristate "Freescale QE Gigabit Ethernet"
......
...@@ -32,6 +32,7 @@ struct tgec_mdio_controller { ...@@ -32,6 +32,7 @@ struct tgec_mdio_controller {
__be32 mdio_addr; /* MDIO address */ __be32 mdio_addr; /* MDIO address */
} __packed; } __packed;
#define MDIO_STAT_ENC BIT(6)
#define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8)
#define MDIO_STAT_BSY (1 << 0) #define MDIO_STAT_BSY (1 << 0)
#define MDIO_STAT_RD_ER (1 << 1) #define MDIO_STAT_RD_ER (1 << 1)
...@@ -91,20 +92,40 @@ static int xgmac_wait_until_done(struct device *dev, ...@@ -91,20 +92,40 @@ static int xgmac_wait_until_done(struct device *dev,
static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
{ {
struct tgec_mdio_controller __iomem *regs = bus->priv; struct tgec_mdio_controller __iomem *regs = bus->priv;
uint16_t dev_addr = regnum >> 16; uint16_t dev_addr;
u32 mdio_ctl, mdio_stat;
int ret; int ret;
/* Set the port and dev addr */ mdio_stat = in_be32(&regs->mdio_stat);
out_be32(&regs->mdio_ctl, if (regnum & MII_ADDR_C45) {
MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr)); /* Clause 45 (ie 10G) */
dev_addr = (regnum >> 16) & 0x1f;
mdio_stat |= MDIO_STAT_ENC;
} else {
/* Clause 22 (ie 1G) */
dev_addr = regnum & 0x1f;
mdio_stat &= ~MDIO_STAT_ENC;
}
/* Set the register address */ out_be32(&regs->mdio_stat, mdio_stat);
out_be32(&regs->mdio_addr, regnum & 0xffff);
ret = xgmac_wait_until_free(&bus->dev, regs); ret = xgmac_wait_until_free(&bus->dev, regs);
if (ret) if (ret)
return ret; return ret;
/* Set the port and dev addr */
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
out_be32(&regs->mdio_ctl, mdio_ctl);
/* Set the register address */
if (regnum & MII_ADDR_C45) {
out_be32(&regs->mdio_addr, regnum & 0xffff);
ret = xgmac_wait_until_free(&bus->dev, regs);
if (ret)
return ret;
}
/* Write the value to the register */ /* Write the value to the register */
out_be32(&regs->mdio_data, MDIO_DATA(value)); out_be32(&regs->mdio_data, MDIO_DATA(value));
...@@ -123,21 +144,39 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val ...@@ -123,21 +144,39 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val
static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
{ {
struct tgec_mdio_controller __iomem *regs = bus->priv; struct tgec_mdio_controller __iomem *regs = bus->priv;
uint16_t dev_addr = regnum >> 16; uint16_t dev_addr;
uint32_t mdio_stat;
uint32_t mdio_ctl; uint32_t mdio_ctl;
uint16_t value; uint16_t value;
int ret; int ret;
mdio_stat = in_be32(&regs->mdio_stat);
if (regnum & MII_ADDR_C45) {
dev_addr = (regnum >> 16) & 0x1f;
mdio_stat |= MDIO_STAT_ENC;
} else {
dev_addr = regnum & 0x1f;
mdio_stat = ~MDIO_STAT_ENC;
}
out_be32(&regs->mdio_stat, mdio_stat);
ret = xgmac_wait_until_free(&bus->dev, regs);
if (ret)
return ret;
/* Set the Port and Device Addrs */ /* Set the Port and Device Addrs */
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
out_be32(&regs->mdio_ctl, mdio_ctl); out_be32(&regs->mdio_ctl, mdio_ctl);
/* Set the register address */ /* Set the register address */
out_be32(&regs->mdio_addr, regnum & 0xffff); if (regnum & MII_ADDR_C45) {
out_be32(&regs->mdio_addr, regnum & 0xffff);
ret = xgmac_wait_until_free(&bus->dev, regs); ret = xgmac_wait_until_free(&bus->dev, regs);
if (ret) if (ret)
return ret; return ret;
}
/* Initiate the read */ /* Initiate the read */
out_be32(&regs->mdio_ctl, mdio_ctl | MDIO_CTL_READ); out_be32(&regs->mdio_ctl, mdio_ctl | MDIO_CTL_READ);
...@@ -224,6 +263,9 @@ static struct of_device_id xgmac_mdio_match[] = { ...@@ -224,6 +263,9 @@ static struct of_device_id xgmac_mdio_match[] = {
{ {
.compatible = "fsl,fman-xmdio", .compatible = "fsl,fman-xmdio",
}, },
{
.compatible = "fsl,fman-memac-mdio",
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, xgmac_mdio_match); MODULE_DEVICE_TABLE(of, xgmac_mdio_match);
......
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