diff options
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 69 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 |
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 | ||
39 | static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) | 42 | static 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 | ||
138 | static 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 | |||
149 | static 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 | |||
128 | const struct stmmac_of_data socfpga_gmac_data = { | 195 | const 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 | ||