aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/stmicro
diff options
context:
space:
mode:
authorTien Hock Loh <thloh@altera.com>2016-07-07 23:23:30 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-11 01:07:50 -0400
commitfb3bbdb859891e6bc27fd1afb3a07319f82c2ee4 (patch)
tree199877544d3ac266c473bcf49a8495d19cf46c66 /drivers/net/ethernet/stmicro
parent927265bc6cd6374c9bafc43408ece4e92311b149 (diff)
net: ethernet: Add TSE PCS support to dwmac-socfpga
This adds support for TSE PCS that uses SGMII adapter when the phy-mode of the dwmac is set to sgmii. Signed-off-by: Tien Hock Loh <thloh@altera.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/stmicro')
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c274
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h36
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c140
4 files changed, 431 insertions, 22 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 0fb362d5a722..44b630cd1755 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -11,11 +11,12 @@ obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
11obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o 11obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
12obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o 12obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
13obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o 13obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
14obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o 14obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
15obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o 15obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
16obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o 16obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
17obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o 17obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
18stmmac-platform-objs:= stmmac_platform.o 18stmmac-platform-objs:= stmmac_platform.o
19dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o
19 20
20obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o 21obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
21stmmac-pci-objs:= stmmac_pci.o 22stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
new file mode 100644
index 000000000000..2920e2ee3864
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
@@ -0,0 +1,274 @@
1/* Copyright Altera Corporation (C) 2016. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License, version 2,
5 * as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * Author: Tien Hock Loh <thloh@altera.com>
16 */
17
18#include <linux/mfd/syscon.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include <linux/of_net.h>
22#include <linux/phy.h>
23#include <linux/regmap.h>
24#include <linux/reset.h>
25#include <linux/stmmac.h>
26
27#include "stmmac.h"
28#include "stmmac_platform.h"
29#include "altr_tse_pcs.h"
30
31#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0
32#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII BIT(1)
33#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII BIT(2)
34#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
35#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK GENMASK(1, 0)
36
37#define TSE_PCS_CONTROL_AN_EN_MASK BIT(12)
38#define TSE_PCS_CONTROL_REG 0x00
39#define TSE_PCS_CONTROL_RESTART_AN_MASK BIT(9)
40#define TSE_PCS_IF_MODE_REG 0x28
41#define TSE_PCS_LINK_TIMER_0_REG 0x24
42#define TSE_PCS_LINK_TIMER_1_REG 0x26
43#define TSE_PCS_SIZE 0x40
44#define TSE_PCS_STATUS_AN_COMPLETED_MASK BIT(5)
45#define TSE_PCS_STATUS_LINK_MASK 0x0004
46#define TSE_PCS_STATUS_REG 0x02
47#define TSE_PCS_SGMII_SPEED_1000 BIT(3)
48#define TSE_PCS_SGMII_SPEED_100 BIT(2)
49#define TSE_PCS_SGMII_SPEED_10 0x0
50#define TSE_PCS_SW_RST_MASK 0x8000
51#define TSE_PCS_PARTNER_ABILITY_REG 0x0A
52#define TSE_PCS_PARTNER_DUPLEX_FULL 0x1000
53#define TSE_PCS_PARTNER_DUPLEX_HALF 0x0000
54#define TSE_PCS_PARTNER_DUPLEX_MASK 0x1000
55#define TSE_PCS_PARTNER_SPEED_MASK GENMASK(11, 10)
56#define TSE_PCS_PARTNER_SPEED_1000 BIT(11)
57#define TSE_PCS_PARTNER_SPEED_100 BIT(10)
58#define TSE_PCS_PARTNER_SPEED_10 0x0000
59#define TSE_PCS_PARTNER_SPEED_1000 BIT(11)
60#define TSE_PCS_PARTNER_SPEED_100 BIT(10)
61#define TSE_PCS_PARTNER_SPEED_10 0x0000
62#define TSE_PCS_SGMII_SPEED_MASK GENMASK(3, 2)
63#define TSE_PCS_SGMII_LINK_TIMER_0 0x0D40
64#define TSE_PCS_SGMII_LINK_TIMER_1 0x0003
65#define TSE_PCS_SW_RESET_TIMEOUT 100
66#define TSE_PCS_USE_SGMII_AN_MASK BIT(2)
67#define TSE_PCS_USE_SGMII_ENA BIT(1)
68
69#define SGMII_ADAPTER_CTRL_REG 0x00
70#define SGMII_ADAPTER_DISABLE 0x0001
71#define SGMII_ADAPTER_ENABLE 0x0000
72
73#define AUTONEGO_LINK_TIMER 20
74
75static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs)
76{
77 int counter = 0;
78 u16 val;
79
80 val = readw(base + TSE_PCS_CONTROL_REG);
81 val |= TSE_PCS_SW_RST_MASK;
82 writew(val, base + TSE_PCS_CONTROL_REG);
83
84 while (counter < TSE_PCS_SW_RESET_TIMEOUT) {
85 val = readw(base + TSE_PCS_CONTROL_REG);
86 val &= TSE_PCS_SW_RST_MASK;
87 if (val == 0)
88 break;
89 counter++;
90 udelay(1);
91 }
92 if (counter >= TSE_PCS_SW_RESET_TIMEOUT) {
93 dev_err(pcs->dev, "PCS could not get out of sw reset\n");
94 return -ETIMEDOUT;
95 }
96
97 return 0;
98}
99
100int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs)
101{
102 int ret = 0;
103
104 writew(TSE_PCS_USE_SGMII_ENA, base + TSE_PCS_IF_MODE_REG);
105
106 writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG);
107 writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG);
108
109 ret = tse_pcs_reset(base, pcs);
110 if (ret == 0)
111 writew(SGMII_ADAPTER_ENABLE,
112 pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
113
114 return ret;
115}
116
117static void pcs_link_timer_callback(unsigned long data)
118{
119 u16 val = 0;
120 struct tse_pcs *pcs = (struct tse_pcs *)data;
121 void __iomem *tse_pcs_base = pcs->tse_pcs_base;
122 void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
123
124 val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
125 val &= TSE_PCS_STATUS_LINK_MASK;
126
127 if (val != 0) {
128 dev_dbg(pcs->dev, "Adapter: Link is established\n");
129 writew(SGMII_ADAPTER_ENABLE,
130 sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
131 } else {
132 mod_timer(&pcs->aneg_link_timer, jiffies +
133 msecs_to_jiffies(AUTONEGO_LINK_TIMER));
134 }
135}
136
137static void auto_nego_timer_callback(unsigned long data)
138{
139 u16 val = 0;
140 u16 speed = 0;
141 u16 duplex = 0;
142 struct tse_pcs *pcs = (struct tse_pcs *)data;
143 void __iomem *tse_pcs_base = pcs->tse_pcs_base;
144 void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
145
146 val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
147 val &= TSE_PCS_STATUS_AN_COMPLETED_MASK;
148
149 if (val != 0) {
150 dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n");
151 val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG);
152 speed = val & TSE_PCS_PARTNER_SPEED_MASK;
153 duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK;
154
155 if (speed == TSE_PCS_PARTNER_SPEED_10 &&
156 duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
157 dev_dbg(pcs->dev,
158 "Adapter: Link Partner is Up - 10/Full\n");
159 else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
160 duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
161 dev_dbg(pcs->dev,
162 "Adapter: Link Partner is Up - 100/Full\n");
163 else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
164 duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
165 dev_dbg(pcs->dev,
166 "Adapter: Link Partner is Up - 1000/Full\n");
167 else if (speed == TSE_PCS_PARTNER_SPEED_10 &&
168 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
169 dev_err(pcs->dev,
170 "Adapter does not support Half Duplex\n");
171 else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
172 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
173 dev_err(pcs->dev,
174 "Adapter does not support Half Duplex\n");
175 else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
176 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
177 dev_err(pcs->dev,
178 "Adapter does not support Half Duplex\n");
179 else
180 dev_err(pcs->dev,
181 "Adapter: Invalid Partner Speed and Duplex\n");
182
183 if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL &&
184 (speed == TSE_PCS_PARTNER_SPEED_10 ||
185 speed == TSE_PCS_PARTNER_SPEED_100 ||
186 speed == TSE_PCS_PARTNER_SPEED_1000))
187 writew(SGMII_ADAPTER_ENABLE,
188 sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
189 } else {
190 val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
191 val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
192 writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
193
194 tse_pcs_reset(tse_pcs_base, pcs);
195 mod_timer(&pcs->aneg_link_timer, jiffies +
196 msecs_to_jiffies(AUTONEGO_LINK_TIMER));
197 }
198}
199
200static void aneg_link_timer_callback(unsigned long data)
201{
202 struct tse_pcs *pcs = (struct tse_pcs *)data;
203
204 if (pcs->autoneg == AUTONEG_ENABLE)
205 auto_nego_timer_callback(data);
206 else if (pcs->autoneg == AUTONEG_DISABLE)
207 pcs_link_timer_callback(data);
208}
209
210void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
211 unsigned int speed)
212{
213 void __iomem *tse_pcs_base = pcs->tse_pcs_base;
214 void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
215 u32 val;
216
217 writew(SGMII_ADAPTER_ENABLE,
218 sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
219
220 pcs->autoneg = phy_dev->autoneg;
221
222 if (phy_dev->autoneg == AUTONEG_ENABLE) {
223 val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
224 val |= TSE_PCS_CONTROL_AN_EN_MASK;
225 writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
226
227 val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
228 val |= TSE_PCS_USE_SGMII_AN_MASK;
229 writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
230
231 val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
232 val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
233
234 tse_pcs_reset(tse_pcs_base, pcs);
235
236 setup_timer(&pcs->aneg_link_timer,
237 aneg_link_timer_callback, (unsigned long)pcs);
238 mod_timer(&pcs->aneg_link_timer, jiffies +
239 msecs_to_jiffies(AUTONEGO_LINK_TIMER));
240 } else if (phy_dev->autoneg == AUTONEG_DISABLE) {
241 val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
242 val &= ~TSE_PCS_CONTROL_AN_EN_MASK;
243 writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
244
245 val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
246 val &= ~TSE_PCS_USE_SGMII_AN_MASK;
247 writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
248
249 val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
250 val &= ~TSE_PCS_SGMII_SPEED_MASK;
251
252 switch (speed) {
253 case 1000:
254 val |= TSE_PCS_SGMII_SPEED_1000;
255 break;
256 case 100:
257 val |= TSE_PCS_SGMII_SPEED_100;
258 break;
259 case 10:
260 val |= TSE_PCS_SGMII_SPEED_10;
261 break;
262 default:
263 return;
264 }
265 writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
266
267 tse_pcs_reset(tse_pcs_base, pcs);
268
269 setup_timer(&pcs->aneg_link_timer,
270 aneg_link_timer_callback, (unsigned long)pcs);
271 mod_timer(&pcs->aneg_link_timer, jiffies +
272 msecs_to_jiffies(AUTONEGO_LINK_TIMER));
273 }
274}
diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
new file mode 100644
index 000000000000..2f5882450b06
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
@@ -0,0 +1,36 @@
1/* Copyright Altera Corporation (C) 2016. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License, version 2,
5 * as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * Author: Tien Hock Loh <thloh@altera.com>
16 */
17
18#ifndef __TSE_PCS_H__
19#define __TSE_PCS_H__
20
21#include <linux/phy.h>
22#include <linux/timer.h>
23
24struct tse_pcs {
25 struct device *dev;
26 void __iomem *tse_pcs_base;
27 void __iomem *sgmii_adapter_base;
28 struct timer_list aneg_link_timer;
29 int autoneg;
30};
31
32int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs);
33void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
34 unsigned int speed);
35
36#endif /* __TSE_PCS_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index f13499fa1f58..4bee2f934a73 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -27,6 +27,11 @@
27#include "stmmac.h" 27#include "stmmac.h"
28#include "stmmac_platform.h" 28#include "stmmac_platform.h"
29 29
30#include "altr_tse_pcs.h"
31
32#define SGMII_ADAPTER_CTRL_REG 0x00
33#define SGMII_ADAPTER_DISABLE 0x0001
34
30#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 35#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
31#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 36#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
32#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 37#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2
@@ -52,35 +57,46 @@ struct socfpga_dwmac {
52 struct reset_control *stmmac_rst; 57 struct reset_control *stmmac_rst;
53 void __iomem *splitter_base; 58 void __iomem *splitter_base;
54 bool f2h_ptp_ref_clk; 59 bool f2h_ptp_ref_clk;
60 struct tse_pcs pcs;
55}; 61};
56 62
57static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) 63static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
58{ 64{
59 struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; 65 struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
60 void __iomem *splitter_base = dwmac->splitter_base; 66 void __iomem *splitter_base = dwmac->splitter_base;
67 void __iomem *tse_pcs_base = dwmac->pcs.tse_pcs_base;
68 void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base;
69 struct device *dev = dwmac->dev;
70 struct net_device *ndev = dev_get_drvdata(dev);
71 struct phy_device *phy_dev = ndev->phydev;
61 u32 val; 72 u32 val;
62 73
63 if (!splitter_base) 74 if ((tse_pcs_base) && (sgmii_adapter_base))
64 return; 75 writew(SGMII_ADAPTER_DISABLE,
65 76 sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
66 val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); 77
67 val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; 78 if (splitter_base) {
68 79 val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG);
69 switch (speed) { 80 val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK;
70 case 1000: 81
71 val |= EMAC_SPLITTER_CTRL_SPEED_1000; 82 switch (speed) {
72 break; 83 case 1000:
73 case 100: 84 val |= EMAC_SPLITTER_CTRL_SPEED_1000;
74 val |= EMAC_SPLITTER_CTRL_SPEED_100; 85 break;
75 break; 86 case 100:
76 case 10: 87 val |= EMAC_SPLITTER_CTRL_SPEED_100;
77 val |= EMAC_SPLITTER_CTRL_SPEED_10; 88 break;
78 break; 89 case 10:
79 default: 90 val |= EMAC_SPLITTER_CTRL_SPEED_10;
80 return; 91 break;
92 default:
93 return;
94 }
95 writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG);
81 } 96 }
82 97
83 writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); 98 if (tse_pcs_base && sgmii_adapter_base)
99 tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed);
84} 100}
85 101
86static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) 102static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
@@ -88,9 +104,12 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
88 struct device_node *np = dev->of_node; 104 struct device_node *np = dev->of_node;
89 struct regmap *sys_mgr_base_addr; 105 struct regmap *sys_mgr_base_addr;
90 u32 reg_offset, reg_shift; 106 u32 reg_offset, reg_shift;
91 int ret; 107 int ret, index;
92 struct device_node *np_splitter; 108 struct device_node *np_splitter = NULL;
109 struct device_node *np_sgmii_adapter = NULL;
93 struct resource res_splitter; 110 struct resource res_splitter;
111 struct resource res_tse_pcs;
112 struct resource res_sgmii_adapter;
94 113
95 dwmac->interface = of_get_phy_mode(np); 114 dwmac->interface = of_get_phy_mode(np);
96 115
@@ -128,6 +147,77 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
128 } 147 }
129 } 148 }
130 149
150 np_sgmii_adapter = of_parse_phandle(np,
151 "altr,gmii-to-sgmii-converter", 0);
152 if (np_sgmii_adapter) {
153 index = of_property_match_string(np_sgmii_adapter, "reg-names",
154 "hps_emac_interface_splitter_avalon_slave");
155
156 if (index >= 0) {
157 if (of_address_to_resource(np_sgmii_adapter, index,
158 &res_splitter)) {
159 dev_err(dev,
160 "%s: ERROR: missing emac splitter address\n",
161 __func__);
162 return -EINVAL;
163 }
164
165 dwmac->splitter_base =
166 devm_ioremap_resource(dev, &res_splitter);
167
168 if (IS_ERR(dwmac->splitter_base)) {
169 dev_err(dev,
170 "%s: ERROR: failed mapping emac splitter\n",
171 __func__);
172 return PTR_ERR(dwmac->splitter_base);
173 }
174 }
175
176 index = of_property_match_string(np_sgmii_adapter, "reg-names",
177 "gmii_to_sgmii_adapter_avalon_slave");
178
179 if (index >= 0) {
180 if (of_address_to_resource(np_sgmii_adapter, index,
181 &res_sgmii_adapter)) {
182 dev_err(dev,
183 "%s: ERROR: failed mapping adapter\n",
184 __func__);
185 return -EINVAL;
186 }
187
188 dwmac->pcs.sgmii_adapter_base =
189 devm_ioremap_resource(dev, &res_sgmii_adapter);
190
191 if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) {
192 dev_err(dev, "%s: failed to mapping adapter\n",
193 __func__);
194 return PTR_ERR(dwmac->pcs.sgmii_adapter_base);
195 }
196 }
197
198 index = of_property_match_string(np_sgmii_adapter, "reg-names",
199 "eth_tse_control_port");
200
201 if (index >= 0) {
202 if (of_address_to_resource(np_sgmii_adapter, index,
203 &res_tse_pcs)) {
204 dev_err(dev,
205 "%s: ERROR: failed mapping tse control port\n",
206 __func__);
207 return -EINVAL;
208 }
209
210 dwmac->pcs.tse_pcs_base =
211 devm_ioremap_resource(dev, &res_tse_pcs);
212
213 if (IS_ERR(dwmac->pcs.tse_pcs_base)) {
214 dev_err(dev,
215 "%s: ERROR: failed mapping tse control port\n",
216 __func__);
217 return PTR_ERR(dwmac->pcs.sgmii_adapter_base);
218 }
219 }
220 }
131 dwmac->reg_offset = reg_offset; 221 dwmac->reg_offset = reg_offset;
132 dwmac->reg_shift = reg_shift; 222 dwmac->reg_shift = reg_shift;
133 dwmac->sys_mgr_base_addr = sys_mgr_base_addr; 223 dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
@@ -151,6 +241,7 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac)
151 break; 241 break;
152 case PHY_INTERFACE_MODE_MII: 242 case PHY_INTERFACE_MODE_MII:
153 case PHY_INTERFACE_MODE_GMII: 243 case PHY_INTERFACE_MODE_GMII:
244 case PHY_INTERFACE_MODE_SGMII:
154 val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; 245 val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
155 break; 246 break;
156 default: 247 default:
@@ -191,6 +282,12 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac)
191 */ 282 */
192 if (dwmac->stmmac_rst) 283 if (dwmac->stmmac_rst)
193 reset_control_deassert(dwmac->stmmac_rst); 284 reset_control_deassert(dwmac->stmmac_rst);
285 if (phymode == PHY_INTERFACE_MODE_SGMII) {
286 if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) {
287 dev_err(dwmac->dev, "Unable to initialize TSE PCS");
288 return -EINVAL;
289 }
290 }
194 291
195 return 0; 292 return 0;
196} 293}
@@ -225,6 +322,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
225 plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; 322 plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
226 323
227 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 324 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
325
228 if (!ret) { 326 if (!ret) {
229 struct net_device *ndev = platform_get_drvdata(pdev); 327 struct net_device *ndev = platform_get_drvdata(pdev);
230 struct stmmac_priv *stpriv = netdev_priv(ndev); 328 struct stmmac_priv *stpriv = netdev_priv(ndev);