Commit b11bfb9a authored by Robert Hancock's avatar Robert Hancock Committed by David S. Miller

net: axienet: Enable more clocks

This driver was only enabling the first clock on the device, regardless
of its name. However, this controller logic can have multiple clocks
which should all be enabled. Add support for enabling additional clocks.
The clock names used are matching those used in the Xilinx version of this
driver as well as the Xilinx device tree generator, except for mgt_clk
which is not present there.

For backward compatibility, if no named clocks are present, the first
clock present is used for determining the MDIO bus clock divider.
Reviewed-by: default avatarRadhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: default avatarRobert Hancock <robert.hancock@calian.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a0e55dcd
...@@ -376,6 +376,8 @@ struct axidma_bd { ...@@ -376,6 +376,8 @@ struct axidma_bd {
struct sk_buff *skb; struct sk_buff *skb;
} __aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT); } __aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT);
#define XAE_NUM_MISC_CLOCKS 3
/** /**
* struct axienet_local - axienet private per device data * struct axienet_local - axienet private per device data
* @ndev: Pointer for net_device to which it will be attached. * @ndev: Pointer for net_device to which it will be attached.
...@@ -385,7 +387,8 @@ struct axidma_bd { ...@@ -385,7 +387,8 @@ struct axidma_bd {
* @phylink_config: phylink configuration settings * @phylink_config: phylink configuration settings
* @pcs_phy: Reference to PCS/PMA PHY if used * @pcs_phy: Reference to PCS/PMA PHY if used
* @switch_x_sgmii: Whether switchable 1000BaseX/SGMII mode is enabled in the core * @switch_x_sgmii: Whether switchable 1000BaseX/SGMII mode is enabled in the core
* @clk: Clock for AXI bus * @axi_clk: AXI4-Lite bus clock
* @misc_clks: Misc ethernet clocks (AXI4-Stream, Ref, MGT clocks)
* @mii_bus: Pointer to MII bus structure * @mii_bus: Pointer to MII bus structure
* @mii_clk_div: MII bus clock divider value * @mii_clk_div: MII bus clock divider value
* @regs_start: Resource start for axienet device addresses * @regs_start: Resource start for axienet device addresses
...@@ -434,7 +437,8 @@ struct axienet_local { ...@@ -434,7 +437,8 @@ struct axienet_local {
bool switch_x_sgmii; bool switch_x_sgmii;
struct clk *clk; struct clk *axi_clk;
struct clk_bulk_data misc_clks[XAE_NUM_MISC_CLOCKS];
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
u8 mii_clk_div; u8 mii_clk_div;
......
...@@ -1863,17 +1863,35 @@ static int axienet_probe(struct platform_device *pdev) ...@@ -1863,17 +1863,35 @@ static int axienet_probe(struct platform_device *pdev)
lp->rx_bd_num = RX_BD_NUM_DEFAULT; lp->rx_bd_num = RX_BD_NUM_DEFAULT;
lp->tx_bd_num = TX_BD_NUM_DEFAULT; lp->tx_bd_num = TX_BD_NUM_DEFAULT;
lp->clk = devm_clk_get_optional(&pdev->dev, NULL); lp->axi_clk = devm_clk_get_optional(&pdev->dev, "s_axi_lite_clk");
if (IS_ERR(lp->clk)) { if (!lp->axi_clk) {
ret = PTR_ERR(lp->clk); /* For backward compatibility, if named AXI clock is not present,
* treat the first clock specified as the AXI clock.
*/
lp->axi_clk = devm_clk_get_optional(&pdev->dev, NULL);
}
if (IS_ERR(lp->axi_clk)) {
ret = PTR_ERR(lp->axi_clk);
goto free_netdev; goto free_netdev;
} }
ret = clk_prepare_enable(lp->clk); ret = clk_prepare_enable(lp->axi_clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Unable to enable clock: %d\n", ret); dev_err(&pdev->dev, "Unable to enable AXI clock: %d\n", ret);
goto free_netdev; goto free_netdev;
} }
lp->misc_clks[0].id = "axis_clk";
lp->misc_clks[1].id = "ref_clk";
lp->misc_clks[2].id = "mgt_clk";
ret = devm_clk_bulk_get_optional(&pdev->dev, XAE_NUM_MISC_CLOCKS, lp->misc_clks);
if (ret)
goto cleanup_clk;
ret = clk_bulk_prepare_enable(XAE_NUM_MISC_CLOCKS, lp->misc_clks);
if (ret)
goto cleanup_clk;
/* Map device registers */ /* Map device registers */
ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0); ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
lp->regs = devm_ioremap_resource(&pdev->dev, ethres); lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
...@@ -2109,7 +2127,8 @@ static int axienet_probe(struct platform_device *pdev) ...@@ -2109,7 +2127,8 @@ static int axienet_probe(struct platform_device *pdev)
of_node_put(lp->phy_node); of_node_put(lp->phy_node);
cleanup_clk: cleanup_clk:
clk_disable_unprepare(lp->clk); clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks);
clk_disable_unprepare(lp->axi_clk);
free_netdev: free_netdev:
free_netdev(ndev); free_netdev(ndev);
...@@ -2132,7 +2151,8 @@ static int axienet_remove(struct platform_device *pdev) ...@@ -2132,7 +2151,8 @@ static int axienet_remove(struct platform_device *pdev)
axienet_mdio_teardown(lp); axienet_mdio_teardown(lp);
clk_disable_unprepare(lp->clk); clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks);
clk_disable_unprepare(lp->axi_clk);
of_node_put(lp->phy_node); of_node_put(lp->phy_node);
lp->phy_node = NULL; lp->phy_node = NULL;
......
...@@ -159,8 +159,8 @@ int axienet_mdio_enable(struct axienet_local *lp) ...@@ -159,8 +159,8 @@ int axienet_mdio_enable(struct axienet_local *lp)
lp->mii_clk_div = 0; lp->mii_clk_div = 0;
if (lp->clk) { if (lp->axi_clk) {
host_clock = clk_get_rate(lp->clk); host_clock = clk_get_rate(lp->axi_clk);
} else { } else {
struct device_node *np1; struct device_node *np1;
......
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