Message ID | 20221117034751.1347105-3-andy.chiu@sifive.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | net: axienet: Use a DT property to configure frequency of the MDIO bus | expand |
> -----Original Message----- > From: Andy Chiu <andy.chiu@sifive.com> > Sent: Thursday, November 17, 2022 9:18 AM > To: davem@davemloft.net; andrew@lunn.ch; kuba@kernel.org; > michal.simek@xilinx.com; radhey.shyam.pandey@xilinx.com > Cc: netdev@vger.kernel.org; devicetree@vger.kernel.org; linux-arm- > kernel@lists.infradead.org; robh+dt@kernel.org; pabeni@redhat.com; > edumazet@google.com; andy.chiu@sifive.com; greentime.hu@sifive.com > Subject: [PATCH v4 net-next 2/3] net: axienet: set mdio clock according to > bus-frequency > > CAUTION: This message has originated from an External Source. Please use > proper judgment and caution when opening attachments, clicking links, or > responding to this email. > > > Some FPGA platforms have 80KHz MDIO bus frequency constraint when > connecting Ethernet to its on-board external Marvell PHY. Thus, we may have > to set MDIO clock according to the DT. Otherwise, use the default > 2.5 MHz, as specified by 802.3, if the entry is not present. > > Also, change MAX_MDIO_FREQ to DEFAULT_MDIO_FREQ because we may > actually set MDIO bus frequency higher than 2.5MHz if undelying devices > support it. > > Signed-off-by: Andy Chiu <andy.chiu@sifive.com> > Reviewed-by: Greentime Hu <greentime.hu@sifive.com> > Reviewed-by: Andrew Lunn <andrew@lunn.ch> > --- > .../net/ethernet/xilinx/xilinx_axienet_mdio.c | 48 +++++++++++++------ > 1 file changed, 33 insertions(+), 15 deletions(-) > > diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c > b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c > index e1f51a071888..789a90997f4b 100644 > --- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c > +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c > @@ -17,7 +17,7 @@ > > #include "xilinx_axienet.h" > > -#define MAX_MDIO_FREQ 2500000 /* 2.5 MHz */ > +#define DEFAULT_MDIO_FREQ 2500000 /* 2.5 MHz */ > #define DEFAULT_HOST_CLOCK 150000000 /* 150 MHz */ > > /* Wait till MDIO interface is ready to accept a new transaction.*/ @@ - > 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. We are now also returning -EOVERFLOW. Please update the description. > * > * 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 = DEFAULT_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); > } > Binding 3/3 patch should be before this patch. > + if (np) > + of_property_read_u32(np, "clock-frequency", &mdio_freq); > + if (mdio_freq != DEFAULT_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; Missing axienet_mdio_mdc_disable in error path. Also return documentation of axienet_mdio_setup needs a update. > 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; > } > > /** > -- > 2.36.0
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c index e1f51a071888..789a90997f4b 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c @@ -17,7 +17,7 @@ #include "xilinx_axienet.h" -#define MAX_MDIO_FREQ 2500000 /* 2.5 MHz */ +#define DEFAULT_MDIO_FREQ 2500000 /* 2.5 MHz */ #define DEFAULT_HOST_CLOCK 150000000 /* 150 MHz */ /* Wait till MDIO interface is ready to accept a new transaction.*/ @@ -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 = DEFAULT_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 != DEFAULT_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; } /**