Commit 148b1da8 authored by David S. Miller's avatar David S. Miller

Merge branch 'axiennet-mdio-bus-freq'

Andy Chiu says:

====================
net: axienet: Use a DT property to configure frequency of the MDIO bus

Some FPGA platforms have to set frequency of the MDIO bus lower than 2.5
MHz. Thus, we use a DT property, which is "clock-frequency", to work
with it at boot time. The default 2.5 MHz would be set if the property
is not pressent. Also, factor out mdio enable/disable functions due to
the api change since 253761a0.

Changelog:
--- v5 ---
1. Make dt-binding patch prior to the implementation patch.
2. Disable mdio bus in error path.
3. Update description of some functions.
--- v4 ---
1. change MAX_MDIO_FREQ to DEFAULT_MDIO_FREQ as suggested by Andrew.
--- v3 RESEND ---
1. Repost the exact same patch again
--- v3 ---
1. Fix coding style, and make probing of the driver fail if MDC overflow
--- v2 ---
1. Use clock-frequency, as defined in mdio.yaml, to configure MDIO
   clock.
2. Only print out frequency if it is set to a non-standard value.
3. Reduce the scope of axienet_mdio_enable and remove
   axienet_mdio_disable because no one really uses it anymore.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 62a45b38 2e1f2c10
......@@ -68,6 +68,8 @@ Optional properties:
- mdio : Child node for MDIO bus. Must be defined if PHY access is
required through the core's MDIO interface (i.e. always,
unless the PHY is accessed through a different bus).
Non-standard MDIO bus frequency is supported via
"clock-frequency", see mdio.yaml.
- pcs-handle: Phandle to the internal PCS/PMA PHY in SGMII or 1000Base-X
modes, where "pcs-handle" should be used to point
......
......@@ -611,8 +611,6 @@ static inline void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
#endif /* CONFIG_64BIT */
/* Function prototypes visible in xilinx_axienet_mdio.c for other files */
int axienet_mdio_enable(struct axienet_local *lp);
void axienet_mdio_disable(struct axienet_local *lp);
int axienet_mdio_setup(struct axienet_local *lp);
void axienet_mdio_teardown(struct axienet_local *lp);
......
......@@ -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,20 @@ 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.
* Return: 0 on success, -ETIMEDOUT on a timeout, -EOVERFLOW on a clock
* divisor overflow.
*
* Sets up the MDIO interface by initializing the MDIO clock and enabling the
* MDIO interface in hardware.
**/
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;
int ret;
lp->mii_clk_div = 0;
......@@ -184,6 +189,12 @@ 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,40 +220,42 @@ 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
* 1 to the clock divisor or we will surely be above 2.5 MHz
* fHOST / (mdio_freq * 2), then we need to add
* 1 to the clock divisor or we will surely be
* above the requested frequency
*/
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",
lp->mii_clk_div, host_clock);
axienet_iow(lp, XAE_MDIO_MC_OFFSET, lp->mii_clk_div | XAE_MDIO_MC_MDIOEN_MASK);
axienet_mdio_mdc_enable(lp);
return axienet_mdio_wait_until_ready(lp);
}
ret = axienet_mdio_wait_until_ready(lp);
if (ret)
axienet_mdio_mdc_disable(lp);
/**
* axienet_mdio_disable - MDIO hardware disable function
* @lp: Pointer to axienet local data structure.
*
* Disable the MDIO interface in hardware.
**/
void axienet_mdio_disable(struct axienet_local *lp)
{
axienet_iow(lp, XAE_MDIO_MC_OFFSET, 0);
return ret;
}
/**
* axienet_mdio_setup - MDIO setup function
* @lp: Pointer to axienet local data structure.
*
* Return: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
* mdiobus_alloc (to allocate memory for mii bus structure) fails.
* Return: 0 on success, -ETIMEDOUT on a timeout, -EOVERFLOW on a clock
* divisor overflow, -ENOMEM when mdiobus_alloc (to allocate
* memory for mii bus structure) fails.
*
* Sets up the MDIO interface by initializing the MDIO clock.
* Register the MDIO interface.
......@@ -253,10 +266,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;
......@@ -272,15 +281,23 @@ 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_mdio_enabled;
of_node_put(mdio_node);
axienet_mdio_mdc_disable(lp);
return 0;
unregister_mdio_enabled:
axienet_mdio_mdc_disable(lp);
unregister:
of_node_put(mdio_node);
if (ret) {
mdiobus_free(bus);
lp->mii_bus = NULL;
return ret;
}
axienet_mdio_mdc_disable(lp);
return 0;
}
/**
......
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