|
|
|
@@ -976,8 +976,8 @@ fec_restart(struct net_device *ndev)
|
|
|
|
|
writel((__force u32)cpu_to_be32(temp_mac[1]),
|
|
|
|
|
fep->hwp + FEC_ADDR_HIGH);
|
|
|
|
|
|
|
|
|
|
/* Clear any outstanding interrupt. */
|
|
|
|
|
writel(0xffffffff, fep->hwp + FEC_IEVENT);
|
|
|
|
|
/* Clear any outstanding interrupt, except MDIO. */
|
|
|
|
|
writel((0xffffffff & ~FEC_ENET_MII), fep->hwp + FEC_IEVENT);
|
|
|
|
|
|
|
|
|
|
fec_enet_bd_init(ndev);
|
|
|
|
|
|
|
|
|
@@ -1123,7 +1123,7 @@ fec_restart(struct net_device *ndev)
|
|
|
|
|
if (fep->link)
|
|
|
|
|
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
|
|
|
|
|
else
|
|
|
|
|
writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
|
|
|
|
|
writel(0, fep->hwp + FEC_IMASK);
|
|
|
|
|
|
|
|
|
|
/* Init the interrupt coalescing */
|
|
|
|
|
fec_enet_itr_coal_init(ndev);
|
|
|
|
@@ -1652,6 +1652,10 @@ fec_enet_interrupt(int irq, void *dev_id)
|
|
|
|
|
irqreturn_t ret = IRQ_NONE;
|
|
|
|
|
|
|
|
|
|
int_events = readl(fep->hwp + FEC_IEVENT);
|
|
|
|
|
|
|
|
|
|
/* Don't clear MDIO events, we poll for those */
|
|
|
|
|
int_events &= ~FEC_ENET_MII;
|
|
|
|
|
|
|
|
|
|
writel(int_events, fep->hwp + FEC_IEVENT);
|
|
|
|
|
fec_enet_collect_events(fep, int_events);
|
|
|
|
|
|
|
|
|
@@ -1659,16 +1663,12 @@ fec_enet_interrupt(int irq, void *dev_id)
|
|
|
|
|
ret = IRQ_HANDLED;
|
|
|
|
|
|
|
|
|
|
if (napi_schedule_prep(&fep->napi)) {
|
|
|
|
|
/* Disable the NAPI interrupts */
|
|
|
|
|
writel(FEC_NAPI_IMASK, fep->hwp + FEC_IMASK);
|
|
|
|
|
/* Disable interrupts */
|
|
|
|
|
writel(0, fep->hwp + FEC_IMASK);
|
|
|
|
|
__napi_schedule(&fep->napi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (int_events & FEC_ENET_MII) {
|
|
|
|
|
ret = IRQ_HANDLED;
|
|
|
|
|
complete(&fep->mdio_done);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1818,11 +1818,24 @@ static void fec_enet_adjust_link(struct net_device *ndev)
|
|
|
|
|
phy_print_status(phy_dev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int fec_enet_mdio_wait(struct fec_enet_private *fep)
|
|
|
|
|
{
|
|
|
|
|
uint ievent;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = readl_poll_timeout_atomic(fep->hwp + FEC_IEVENT, ievent,
|
|
|
|
|
ievent & FEC_ENET_MII, 2, 30000);
|
|
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
|
writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
|
|
|
|
{
|
|
|
|
|
struct fec_enet_private *fep = bus->priv;
|
|
|
|
|
struct device *dev = &fep->pdev->dev;
|
|
|
|
|
unsigned long time_left;
|
|
|
|
|
int ret = 0, frame_start, frame_addr, frame_op;
|
|
|
|
|
bool is_c45 = !!(regnum & MII_ADDR_C45);
|
|
|
|
|
|
|
|
|
@@ -1830,8 +1843,6 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
reinit_completion(&fep->mdio_done);
|
|
|
|
|
|
|
|
|
|
if (is_c45) {
|
|
|
|
|
frame_start = FEC_MMFR_ST_C45;
|
|
|
|
|
|
|
|
|
@@ -1843,11 +1854,9 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
|
|
|
|
fep->hwp + FEC_MII_DATA);
|
|
|
|
|
|
|
|
|
|
/* wait for end of transfer */
|
|
|
|
|
time_left = wait_for_completion_timeout(&fep->mdio_done,
|
|
|
|
|
usecs_to_jiffies(FEC_MII_TIMEOUT));
|
|
|
|
|
if (time_left == 0) {
|
|
|
|
|
ret = fec_enet_mdio_wait(fep);
|
|
|
|
|
if (ret) {
|
|
|
|
|
netdev_err(fep->netdev, "MDIO address write timeout\n");
|
|
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1866,11 +1875,9 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
|
|
|
|
FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
|
|
|
|
|
|
|
|
|
|
/* wait for end of transfer */
|
|
|
|
|
time_left = wait_for_completion_timeout(&fep->mdio_done,
|
|
|
|
|
usecs_to_jiffies(FEC_MII_TIMEOUT));
|
|
|
|
|
if (time_left == 0) {
|
|
|
|
|
ret = fec_enet_mdio_wait(fep);
|
|
|
|
|
if (ret) {
|
|
|
|
|
netdev_err(fep->netdev, "MDIO read timeout\n");
|
|
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1888,7 +1895,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
|
|
|
|
|
{
|
|
|
|
|
struct fec_enet_private *fep = bus->priv;
|
|
|
|
|
struct device *dev = &fep->pdev->dev;
|
|
|
|
|
unsigned long time_left;
|
|
|
|
|
int ret, frame_start, frame_addr;
|
|
|
|
|
bool is_c45 = !!(regnum & MII_ADDR_C45);
|
|
|
|
|
|
|
|
|
@@ -1898,8 +1904,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
|
|
|
|
|
else
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
reinit_completion(&fep->mdio_done);
|
|
|
|
|
|
|
|
|
|
if (is_c45) {
|
|
|
|
|
frame_start = FEC_MMFR_ST_C45;
|
|
|
|
|
|
|
|
|
@@ -1911,11 +1915,9 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
|
|
|
|
|
fep->hwp + FEC_MII_DATA);
|
|
|
|
|
|
|
|
|
|
/* wait for end of transfer */
|
|
|
|
|
time_left = wait_for_completion_timeout(&fep->mdio_done,
|
|
|
|
|
usecs_to_jiffies(FEC_MII_TIMEOUT));
|
|
|
|
|
if (time_left == 0) {
|
|
|
|
|
ret = fec_enet_mdio_wait(fep);
|
|
|
|
|
if (ret) {
|
|
|
|
|
netdev_err(fep->netdev, "MDIO address write timeout\n");
|
|
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
@@ -1931,12 +1933,9 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
|
|
|
|
|
fep->hwp + FEC_MII_DATA);
|
|
|
|
|
|
|
|
|
|
/* wait for end of transfer */
|
|
|
|
|
time_left = wait_for_completion_timeout(&fep->mdio_done,
|
|
|
|
|
usecs_to_jiffies(FEC_MII_TIMEOUT));
|
|
|
|
|
if (time_left == 0) {
|
|
|
|
|
ret = fec_enet_mdio_wait(fep);
|
|
|
|
|
if (ret)
|
|
|
|
|
netdev_err(fep->netdev, "MDIO write timeout\n");
|
|
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
pm_runtime_mark_last_busy(dev);
|
|
|
|
@@ -2065,9 +2064,11 @@ static int fec_enet_mii_init(struct platform_device *pdev)
|
|
|
|
|
static struct mii_bus *fec0_mii_bus;
|
|
|
|
|
struct net_device *ndev = platform_get_drvdata(pdev);
|
|
|
|
|
struct fec_enet_private *fep = netdev_priv(ndev);
|
|
|
|
|
bool suppress_preamble = false;
|
|
|
|
|
struct device_node *node;
|
|
|
|
|
int err = -ENXIO;
|
|
|
|
|
u32 mii_speed, holdtime;
|
|
|
|
|
u32 bus_freq;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The i.MX28 dual fec interfaces are not equal.
|
|
|
|
@@ -2095,15 +2096,23 @@ static int fec_enet_mii_init(struct platform_device *pdev)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bus_freq = 2500000; /* 2.5MHz by default */
|
|
|
|
|
node = of_get_child_by_name(pdev->dev.of_node, "mdio");
|
|
|
|
|
if (node) {
|
|
|
|
|
of_property_read_u32(node, "clock-frequency", &bus_freq);
|
|
|
|
|
suppress_preamble = of_property_read_bool(node,
|
|
|
|
|
"suppress-preamble");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
|
|
|
|
|
* Set MII speed (= clk_get_rate() / 2 * phy_speed)
|
|
|
|
|
*
|
|
|
|
|
* The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
|
|
|
|
|
* for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28
|
|
|
|
|
* Reference Manual has an error on this, and gets fixed on i.MX6Q
|
|
|
|
|
* document.
|
|
|
|
|
*/
|
|
|
|
|
mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
|
|
|
|
|
mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), bus_freq * 2);
|
|
|
|
|
if (fep->quirks & FEC_QUIRK_ENET_MAC)
|
|
|
|
|
mii_speed--;
|
|
|
|
|
if (mii_speed > 63) {
|
|
|
|
@@ -2130,8 +2139,14 @@ static int fec_enet_mii_init(struct platform_device *pdev)
|
|
|
|
|
|
|
|
|
|
fep->phy_speed = mii_speed << 1 | holdtime << 8;
|
|
|
|
|
|
|
|
|
|
if (suppress_preamble)
|
|
|
|
|
fep->phy_speed |= BIT(7);
|
|
|
|
|
|
|
|
|
|
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
|
|
|
|
|
|
|
|
|
|
/* Clear any pending transaction complete indication */
|
|
|
|
|
writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
|
|
|
|
|
|
|
|
|
|
fep->mii_bus = mdiobus_alloc();
|
|
|
|
|
if (fep->mii_bus == NULL) {
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
@@ -2146,7 +2161,6 @@ static int fec_enet_mii_init(struct platform_device *pdev)
|
|
|
|
|
fep->mii_bus->priv = fep;
|
|
|
|
|
fep->mii_bus->parent = &pdev->dev;
|
|
|
|
|
|
|
|
|
|
node = of_get_child_by_name(pdev->dev.of_node, "mdio");
|
|
|
|
|
err = of_mdiobus_register(fep->mii_bus, node);
|
|
|
|
|
of_node_put(node);
|
|
|
|
|
if (err)
|
|
|
|
@@ -3674,7 +3688,6 @@ fec_probe(struct platform_device *pdev)
|
|
|
|
|
fep->irq[i] = irq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init_completion(&fep->mdio_done);
|
|
|
|
|
ret = fec_enet_mii_init(pdev);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto failed_mii_init;
|
|
|
|
|