aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVince Bridgers <vbridgers2013@gmail.com>2014-06-29 21:34:51 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-02 21:37:54 -0400
commit0acf16768740776feffac506ce93b1c06c059ac6 (patch)
treef08c82f4ffc615da24254cb98e80e3983c4f58c4
parent48bc03433cfdcac7a3bbb233d5c9f95297a0f5ab (diff)
net: stmmac: add platform init/exit for Altera's ARM socfpga
This patch adds platform init/exit functions and modifications to support suspend/resume for the Altera Cyclone 5 SOC Ethernet controller. The platform exit function puts the controller into reset using the socfpga reset controller driver. The platform init function sets up the Synopsys mac by first making sure the Ethernet controller is held in reset, programming the phy mode through external support logic, then deasserts reset through the socfpga reset manager driver. Signed-off-by: Vince Bridgers <vbridgers2013@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c69
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c4
2 files changed, 73 insertions, 0 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index fd8a217556a1..ec632e666c56 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -20,7 +20,9 @@
20#include <linux/of_net.h> 20#include <linux/of_net.h>
21#include <linux/phy.h> 21#include <linux/phy.h>
22#include <linux/regmap.h> 22#include <linux/regmap.h>
23#include <linux/reset.h>
23#include <linux/stmmac.h> 24#include <linux/stmmac.h>
25#include "stmmac.h"
24 26
25#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 27#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
26#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 28#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
@@ -34,6 +36,7 @@ struct socfpga_dwmac {
34 u32 reg_shift; 36 u32 reg_shift;
35 struct device *dev; 37 struct device *dev;
36 struct regmap *sys_mgr_base_addr; 38 struct regmap *sys_mgr_base_addr;
39 struct reset_control *stmmac_rst;
37}; 40};
38 41
39static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) 42static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
@@ -43,6 +46,13 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
43 u32 reg_offset, reg_shift; 46 u32 reg_offset, reg_shift;
44 int ret; 47 int ret;
45 48
49 dwmac->stmmac_rst = devm_reset_control_get(dev,
50 STMMAC_RESOURCE_NAME);
51 if (IS_ERR(dwmac->stmmac_rst)) {
52 dev_info(dev, "Could not get reset control!\n");
53 return -EINVAL;
54 }
55
46 dwmac->interface = of_get_phy_mode(np); 56 dwmac->interface = of_get_phy_mode(np);
47 57
48 sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); 58 sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
@@ -125,6 +135,65 @@ static void *socfpga_dwmac_probe(struct platform_device *pdev)
125 return dwmac; 135 return dwmac;
126} 136}
127 137
138static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv)
139{
140 struct socfpga_dwmac *dwmac = priv;
141
142 /* On socfpga platform exit, assert and hold reset to the
143 * enet controller - the default state after a hard reset.
144 */
145 if (dwmac->stmmac_rst)
146 reset_control_assert(dwmac->stmmac_rst);
147}
148
149static int socfpga_dwmac_init(struct platform_device *pdev, void *priv)
150{
151 struct socfpga_dwmac *dwmac = priv;
152 struct net_device *ndev = platform_get_drvdata(pdev);
153 struct stmmac_priv *stpriv = NULL;
154 int ret = 0;
155
156 if (ndev)
157 stpriv = netdev_priv(ndev);
158
159 /* Assert reset to the enet controller before changing the phy mode */
160 if (dwmac->stmmac_rst)
161 reset_control_assert(dwmac->stmmac_rst);
162
163 /* Setup the phy mode in the system manager registers according to
164 * devicetree configuration
165 */
166 ret = socfpga_dwmac_setup(dwmac);
167
168 /* Deassert reset for the phy configuration to be sampled by
169 * the enet controller, and operation to start in requested mode
170 */
171 if (dwmac->stmmac_rst)
172 reset_control_deassert(dwmac->stmmac_rst);
173
174 /* Before the enet controller is suspended, the phy is suspended.
175 * This causes the phy clock to be gated. The enet controller is
176 * resumed before the phy, so the clock is still gated "off" when
177 * the enet controller is resumed. This code makes sure the phy
178 * is "resumed" before reinitializing the enet controller since
179 * the enet controller depends on an active phy clock to complete
180 * a DMA reset. A DMA reset will "time out" if executed
181 * with no phy clock input on the Synopsys enet controller.
182 * Verified through Synopsys Case #8000711656.
183 *
184 * Note that the phy clock is also gated when the phy is isolated.
185 * Phy "suspend" and "isolate" controls are located in phy basic
186 * control register 0, and can be modified by the phy driver
187 * framework.
188 */
189 if (stpriv && stpriv->phydev)
190 phy_resume(stpriv->phydev);
191
192 return ret;
193}
194
128const struct stmmac_of_data socfpga_gmac_data = { 195const struct stmmac_of_data socfpga_gmac_data = {
129 .setup = socfpga_dwmac_probe, 196 .setup = socfpga_dwmac_probe,
197 .init = socfpga_dwmac_init,
198 .exit = socfpga_dwmac_exit,
130}; 199};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 057a1208e594..18315f34938b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2878,6 +2878,10 @@ int stmmac_suspend(struct net_device *ndev)
2878 clk_disable_unprepare(priv->stmmac_clk); 2878 clk_disable_unprepare(priv->stmmac_clk);
2879 } 2879 }
2880 spin_unlock_irqrestore(&priv->lock, flags); 2880 spin_unlock_irqrestore(&priv->lock, flags);
2881
2882 priv->oldlink = 0;
2883 priv->speed = 0;
2884 priv->oldduplex = -1;
2881 return 0; 2885 return 0;
2882} 2886}
2883 2887