summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2022-11-21 11:36:04 +0100
committerDavid S. Miller <davem@davemloft.net>2022-11-21 11:36:04 +0100
commit148b1da88605bd8e357fa3f8f4d5e3a8eccff3c5 (patch)
treec754a19cf450810b8f3b1f8f751edbf1c432d20b
parentnet: microchip: sparx5: prevent uninitialized variable (diff)
parentnet: axienet: set mdio clock according to bus-frequency (diff)
downloadlinux-148b1da88605bd8e357fa3f8f4d5e3a8eccff3c5.tar.xz
linux-148b1da88605bd8e357fa3f8f4d5e3a8eccff3c5.zip
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 253761a0e61b7. 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: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/xilinx_axienet.txt2
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h2
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c79
3 files changed, 50 insertions, 33 deletions
diff --git a/Documentation/devicetree/bindings/net/xilinx_axienet.txt b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
index 1aa4c6006cd0..80e505a2fda1 100644
--- a/Documentation/devicetree/bindings/net/xilinx_axienet.txt
+++ b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
@@ -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
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 6370c447ac5c..575ff9de8985 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -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);
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index 0b3b6935c558..2f07fde361aa 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,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);
- if (ret) {
- mdiobus_free(bus);
- lp->mii_bus = NULL;
- return ret;
- }
axienet_mdio_mdc_disable(lp);
return 0;
+
+unregister_mdio_enabled:
+ axienet_mdio_mdc_disable(lp);
+unregister:
+ of_node_put(mdio_node);
+ mdiobus_free(bus);
+ lp->mii_bus = NULL;
+ return ret;
}
/**