1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * dwmac-ingenic.c - Ingenic SoCs DWMAC specific glue layer
4 *
5 * Copyright (c) 2021 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
6 */
7
8 #include <linux/bitfield.h>
9 #include <linux/clk.h>
10 #include <linux/kernel.h>
11 #include <linux/mfd/syscon.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_net.h>
15 #include <linux/phy.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/slab.h>
19 #include <linux/stmmac.h>
20
21 #include "stmmac_platform.h"
22
23 #define MACPHYC_TXCLK_SEL_MASK GENMASK(31, 31)
24 #define MACPHYC_TXCLK_SEL_OUTPUT 0x1
25 #define MACPHYC_TXCLK_SEL_INPUT 0x0
26 #define MACPHYC_MODE_SEL_MASK GENMASK(31, 31)
27 #define MACPHYC_MODE_SEL_RMII 0x0
28 #define MACPHYC_TX_SEL_MASK GENMASK(19, 19)
29 #define MACPHYC_TX_SEL_ORIGIN 0x0
30 #define MACPHYC_TX_SEL_DELAY 0x1
31 #define MACPHYC_TX_DELAY_MASK GENMASK(18, 12)
32 #define MACPHYC_RX_SEL_MASK GENMASK(11, 11)
33 #define MACPHYC_RX_SEL_ORIGIN 0x0
34 #define MACPHYC_RX_SEL_DELAY 0x1
35 #define MACPHYC_RX_DELAY_MASK GENMASK(10, 4)
36 #define MACPHYC_SOFT_RST_MASK GENMASK(3, 3)
37 #define MACPHYC_PHY_INFT_MASK GENMASK(2, 0)
38 #define MACPHYC_PHY_INFT_RMII 0x4
39 #define MACPHYC_PHY_INFT_RGMII 0x1
40 #define MACPHYC_PHY_INFT_GMII 0x0
41 #define MACPHYC_PHY_INFT_MII 0x0
42
43 #define MACPHYC_TX_DELAY_PS_MAX 2496
44 #define MACPHYC_TX_DELAY_PS_MIN 20
45
46 #define MACPHYC_RX_DELAY_PS_MAX 2496
47 #define MACPHYC_RX_DELAY_PS_MIN 20
48
49 enum ingenic_mac_version {
50 ID_JZ4775,
51 ID_X1000,
52 ID_X1600,
53 ID_X1830,
54 ID_X2000,
55 };
56
57 struct ingenic_mac {
58 const struct ingenic_soc_info *soc_info;
59 struct device *dev;
60 struct regmap *regmap;
61
62 int rx_delay;
63 int tx_delay;
64 };
65
66 struct ingenic_soc_info {
67 enum ingenic_mac_version version;
68 u32 mask;
69
70 int (*set_mode)(struct plat_stmmacenet_data *plat_dat);
71 };
72
ingenic_mac_init(struct plat_stmmacenet_data * plat_dat)73 static int ingenic_mac_init(struct plat_stmmacenet_data *plat_dat)
74 {
75 struct ingenic_mac *mac = plat_dat->bsp_priv;
76 int ret;
77
78 if (mac->soc_info->set_mode) {
79 ret = mac->soc_info->set_mode(plat_dat);
80 if (ret)
81 return ret;
82 }
83
84 return 0;
85 }
86
jz4775_mac_set_mode(struct plat_stmmacenet_data * plat_dat)87 static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
88 {
89 struct ingenic_mac *mac = plat_dat->bsp_priv;
90 unsigned int val;
91
92 switch (plat_dat->mac_interface) {
93 case PHY_INTERFACE_MODE_MII:
94 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
95 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_MII);
96 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_MII\n");
97 break;
98
99 case PHY_INTERFACE_MODE_GMII:
100 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
101 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_GMII);
102 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_GMII\n");
103 break;
104
105 case PHY_INTERFACE_MODE_RMII:
106 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
107 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
108 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
109 break;
110
111 case PHY_INTERFACE_MODE_RGMII:
112 case PHY_INTERFACE_MODE_RGMII_ID:
113 case PHY_INTERFACE_MODE_RGMII_TXID:
114 case PHY_INTERFACE_MODE_RGMII_RXID:
115 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
116 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);
117 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");
118 break;
119
120 default:
121 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
122 return -EINVAL;
123 }
124
125 /* Update MAC PHY control register */
126 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
127 }
128
x1000_mac_set_mode(struct plat_stmmacenet_data * plat_dat)129 static int x1000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
130 {
131 struct ingenic_mac *mac = plat_dat->bsp_priv;
132
133 switch (plat_dat->mac_interface) {
134 case PHY_INTERFACE_MODE_RMII:
135 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
136 break;
137
138 default:
139 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
140 return -EINVAL;
141 }
142
143 /* Update MAC PHY control register */
144 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, 0);
145 }
146
x1600_mac_set_mode(struct plat_stmmacenet_data * plat_dat)147 static int x1600_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
148 {
149 struct ingenic_mac *mac = plat_dat->bsp_priv;
150 unsigned int val;
151
152 switch (plat_dat->mac_interface) {
153 case PHY_INTERFACE_MODE_RMII:
154 val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
155 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
156 break;
157
158 default:
159 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
160 return -EINVAL;
161 }
162
163 /* Update MAC PHY control register */
164 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
165 }
166
x1830_mac_set_mode(struct plat_stmmacenet_data * plat_dat)167 static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
168 {
169 struct ingenic_mac *mac = plat_dat->bsp_priv;
170 unsigned int val;
171
172 switch (plat_dat->mac_interface) {
173 case PHY_INTERFACE_MODE_RMII:
174 val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) |
175 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
176 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
177 break;
178
179 default:
180 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
181 return -EINVAL;
182 }
183
184 /* Update MAC PHY control register */
185 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
186 }
187
x2000_mac_set_mode(struct plat_stmmacenet_data * plat_dat)188 static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
189 {
190 struct ingenic_mac *mac = plat_dat->bsp_priv;
191 unsigned int val;
192
193 switch (plat_dat->mac_interface) {
194 case PHY_INTERFACE_MODE_RMII:
195 val = FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) |
196 FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN) |
197 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
198 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
199 break;
200
201 case PHY_INTERFACE_MODE_RGMII:
202 case PHY_INTERFACE_MODE_RGMII_ID:
203 case PHY_INTERFACE_MODE_RGMII_TXID:
204 case PHY_INTERFACE_MODE_RGMII_RXID:
205 val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);
206
207 if (mac->tx_delay == 0)
208 val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN);
209 else
210 val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_DELAY) |
211 FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1);
212
213 if (mac->rx_delay == 0)
214 val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN);
215 else
216 val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_DELAY) |
217 FIELD_PREP(MACPHYC_RX_DELAY_MASK, (mac->rx_delay + 9750) / 19500 - 1);
218
219 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");
220 break;
221
222 default:
223 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
224 return -EINVAL;
225 }
226
227 /* Update MAC PHY control register */
228 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
229 }
230
ingenic_mac_probe(struct platform_device * pdev)231 static int ingenic_mac_probe(struct platform_device *pdev)
232 {
233 struct plat_stmmacenet_data *plat_dat;
234 struct stmmac_resources stmmac_res;
235 struct ingenic_mac *mac;
236 const struct ingenic_soc_info *data;
237 u32 tx_delay_ps, rx_delay_ps;
238 int ret;
239
240 ret = stmmac_get_platform_resources(pdev, &stmmac_res);
241 if (ret)
242 return ret;
243
244 plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
245 if (IS_ERR(plat_dat))
246 return PTR_ERR(plat_dat);
247
248 mac = devm_kzalloc(&pdev->dev, sizeof(*mac), GFP_KERNEL);
249 if (!mac) {
250 ret = -ENOMEM;
251 goto err_remove_config_dt;
252 }
253
254 data = of_device_get_match_data(&pdev->dev);
255 if (!data) {
256 dev_err(&pdev->dev, "No of match data provided\n");
257 ret = -EINVAL;
258 goto err_remove_config_dt;
259 }
260
261 /* Get MAC PHY control register */
262 mac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mode-reg");
263 if (IS_ERR(mac->regmap)) {
264 dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);
265 ret = PTR_ERR(mac->regmap);
266 goto err_remove_config_dt;
267 }
268
269 if (!of_property_read_u32(pdev->dev.of_node, "tx-clk-delay-ps", &tx_delay_ps)) {
270 if (tx_delay_ps >= MACPHYC_TX_DELAY_PS_MIN &&
271 tx_delay_ps <= MACPHYC_TX_DELAY_PS_MAX) {
272 mac->tx_delay = tx_delay_ps * 1000;
273 } else {
274 dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
275 ret = -EINVAL;
276 goto err_remove_config_dt;
277 }
278 }
279
280 if (!of_property_read_u32(pdev->dev.of_node, "rx-clk-delay-ps", &rx_delay_ps)) {
281 if (rx_delay_ps >= MACPHYC_RX_DELAY_PS_MIN &&
282 rx_delay_ps <= MACPHYC_RX_DELAY_PS_MAX) {
283 mac->rx_delay = rx_delay_ps * 1000;
284 } else {
285 dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
286 ret = -EINVAL;
287 goto err_remove_config_dt;
288 }
289 }
290
291 mac->soc_info = data;
292 mac->dev = &pdev->dev;
293
294 plat_dat->bsp_priv = mac;
295
296 ret = ingenic_mac_init(plat_dat);
297 if (ret)
298 goto err_remove_config_dt;
299
300 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
301 if (ret)
302 goto err_remove_config_dt;
303
304 return 0;
305
306 err_remove_config_dt:
307 stmmac_remove_config_dt(pdev, plat_dat);
308
309 return ret;
310 }
311
312 #ifdef CONFIG_PM_SLEEP
ingenic_mac_suspend(struct device * dev)313 static int ingenic_mac_suspend(struct device *dev)
314 {
315 int ret;
316
317 ret = stmmac_suspend(dev);
318
319 return ret;
320 }
321
ingenic_mac_resume(struct device * dev)322 static int ingenic_mac_resume(struct device *dev)
323 {
324 struct net_device *ndev = dev_get_drvdata(dev);
325 struct stmmac_priv *priv = netdev_priv(ndev);
326 int ret;
327
328 ret = ingenic_mac_init(priv->plat);
329 if (ret)
330 return ret;
331
332 ret = stmmac_resume(dev);
333
334 return ret;
335 }
336 #endif /* CONFIG_PM_SLEEP */
337
338 static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume);
339
340 static struct ingenic_soc_info jz4775_soc_info = {
341 .version = ID_JZ4775,
342 .mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
343
344 .set_mode = jz4775_mac_set_mode,
345 };
346
347 static struct ingenic_soc_info x1000_soc_info = {
348 .version = ID_X1000,
349 .mask = MACPHYC_SOFT_RST_MASK,
350
351 .set_mode = x1000_mac_set_mode,
352 };
353
354 static struct ingenic_soc_info x1600_soc_info = {
355 .version = ID_X1600,
356 .mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
357
358 .set_mode = x1600_mac_set_mode,
359 };
360
361 static struct ingenic_soc_info x1830_soc_info = {
362 .version = ID_X1830,
363 .mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
364
365 .set_mode = x1830_mac_set_mode,
366 };
367
368 static struct ingenic_soc_info x2000_soc_info = {
369 .version = ID_X2000,
370 .mask = MACPHYC_TX_SEL_MASK | MACPHYC_TX_DELAY_MASK | MACPHYC_RX_SEL_MASK |
371 MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
372
373 .set_mode = x2000_mac_set_mode,
374 };
375
376 static const struct of_device_id ingenic_mac_of_matches[] = {
377 { .compatible = "ingenic,jz4775-mac", .data = &jz4775_soc_info },
378 { .compatible = "ingenic,x1000-mac", .data = &x1000_soc_info },
379 { .compatible = "ingenic,x1600-mac", .data = &x1600_soc_info },
380 { .compatible = "ingenic,x1830-mac", .data = &x1830_soc_info },
381 { .compatible = "ingenic,x2000-mac", .data = &x2000_soc_info },
382 { }
383 };
384 MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);
385
386 static struct platform_driver ingenic_mac_driver = {
387 .probe = ingenic_mac_probe,
388 .remove_new = stmmac_pltfr_remove,
389 .driver = {
390 .name = "ingenic-mac",
391 .pm = pm_ptr(&ingenic_mac_pm_ops),
392 .of_match_table = ingenic_mac_of_matches,
393 },
394 };
395 module_platform_driver(ingenic_mac_driver);
396
397 MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
398 MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");
399 MODULE_LICENSE("GPL v2");
400