@@ -147,15 +147,18 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
/**
* axienet_mdio_enable - MDIO hardware setup function
* @lp: Pointer to axienet local data structure.
+ * @np: Pointer to mdio device tree node.
*
* Return: 0 on success, -ETIMEDOUT on a timeout.
*
* Sets up the MDIO interface by initializing the MDIO clock and enabling the
* MDIO interface in hardware.
**/
-static int axienet_mdio_enable(struct axienet_local *lp)
+static int axienet_mdio_enable(struct axienet_local *lp, struct device_node *np)
{
+ u32 mdio_freq = MAX_MDIO_FREQ;
u32 host_clock;
+ u32 clk_div;
lp->mii_clk_div = 0;
@@ -184,6 +187,12 @@ static int axienet_mdio_enable(struct axienet_local *lp)
host_clock);
}
+ if (np)
+ of_property_read_u32(np, "clock-frequency", &mdio_freq);
+ if (mdio_freq != MAX_MDIO_FREQ)
+ netdev_info(lp->ndev, "Setting non-standard mdio bus frequency to %u Hz\n",
+ mdio_freq);
+
/* clk_div can be calculated by deriving it from the equation:
* fMDIO = fHOST / ((1 + clk_div) * 2)
*
@@ -209,13 +218,20 @@ static int axienet_mdio_enable(struct axienet_local *lp)
* "clock-frequency" from the CPU
*/
- lp->mii_clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
+ clk_div = (host_clock / (mdio_freq * 2)) - 1;
/* If there is any remainder from the division of
- * fHOST / (MAX_MDIO_FREQ * 2), then we need to add
+ * fHOST / (mdio_freq * 2), then we need to add
* 1 to the clock divisor or we will surely be above 2.5 MHz
*/
- if (host_clock % (MAX_MDIO_FREQ * 2))
- lp->mii_clk_div++;
+ if (host_clock % (mdio_freq * 2))
+ clk_div++;
+
+ /* Check for overflow of mii_clk_div */
+ if (clk_div & ~XAE_MDIO_MC_CLOCK_DIVIDE_MAX) {
+ netdev_warn(lp->ndev, "MDIO clock divisor overflow\n");
+ return -EOVERFLOW;
+ }
+ lp->mii_clk_div = (u8)clk_div;
netdev_dbg(lp->ndev,
"Setting MDIO clock divisor to %u/%u Hz host clock.\n",
@@ -242,10 +258,6 @@ int axienet_mdio_setup(struct axienet_local *lp)
struct mii_bus *bus;
int ret;
- ret = axienet_mdio_enable(lp);
- if (ret < 0)
- return ret;
-
bus = mdiobus_alloc();
if (!bus)
return -ENOMEM;
@@ -261,15 +273,21 @@ int axienet_mdio_setup(struct axienet_local *lp)
lp->mii_bus = bus;
mdio_node = of_get_child_by_name(lp->dev->of_node, "mdio");
+ ret = axienet_mdio_enable(lp, mdio_node);
+ if (ret < 0)
+ goto unregister;
ret = of_mdiobus_register(bus, mdio_node);
+ if (ret)
+ goto unregister;
of_node_put(mdio_node);
- if (ret) {
- mdiobus_free(bus);
- lp->mii_bus = NULL;
- return ret;
- }
axienet_mdio_mdc_disable(lp);
return 0;
+
+unregister:
+ of_node_put(mdio_node);
+ mdiobus_free(bus);
+ lp->mii_bus = NULL;
+ return ret;
}
/**