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
49enum ingenic_mac_version {
50 ID_JZ4775,
51 ID_X1000,
52 ID_X1600,
53 ID_X1830,
54 ID_X2000,
55};
56
57struct 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
66struct 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
73static 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
87static 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(map: mac->regmap, reg: 0, mask: mac->soc_info->mask, val);
127}
128
129static 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(map: mac->regmap, reg: 0, mask: mac->soc_info->mask, val: 0);
145}
146
147static 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(map: mac->regmap, reg: 0, mask: mac->soc_info->mask, val);
165}
166
167static 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(map: mac->regmap, reg: 0, mask: mac->soc_info->mask, val);
186}
187
188static 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(map: mac->regmap, reg: 0, mask: mac->soc_info->mask, val);
229}
230
231static 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: &stmmac_res);
241 if (ret)
242 return ret;
243
244 plat_dat = devm_stmmac_probe_config_dt(pdev, mac: stmmac_res.mac);
245 if (IS_ERR(ptr: plat_dat))
246 return PTR_ERR(ptr: plat_dat);
247
248 mac = devm_kzalloc(dev: &pdev->dev, size: sizeof(*mac), GFP_KERNEL);
249 if (!mac)
250 return -ENOMEM;
251
252 data = of_device_get_match_data(dev: &pdev->dev);
253 if (!data) {
254 dev_err(&pdev->dev, "No of match data provided\n");
255 return -EINVAL;
256 }
257
258 /* Get MAC PHY control register */
259 mac->regmap = syscon_regmap_lookup_by_phandle(np: pdev->dev.of_node, property: "mode-reg");
260 if (IS_ERR(ptr: mac->regmap)) {
261 dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);
262 return PTR_ERR(ptr: mac->regmap);
263 }
264
265 if (!of_property_read_u32(np: pdev->dev.of_node, propname: "tx-clk-delay-ps", out_value: &tx_delay_ps)) {
266 if (tx_delay_ps >= MACPHYC_TX_DELAY_PS_MIN &&
267 tx_delay_ps <= MACPHYC_TX_DELAY_PS_MAX) {
268 mac->tx_delay = tx_delay_ps * 1000;
269 } else {
270 dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
271 return -EINVAL;
272 }
273 }
274
275 if (!of_property_read_u32(np: pdev->dev.of_node, propname: "rx-clk-delay-ps", out_value: &rx_delay_ps)) {
276 if (rx_delay_ps >= MACPHYC_RX_DELAY_PS_MIN &&
277 rx_delay_ps <= MACPHYC_RX_DELAY_PS_MAX) {
278 mac->rx_delay = rx_delay_ps * 1000;
279 } else {
280 dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
281 return -EINVAL;
282 }
283 }
284
285 mac->soc_info = data;
286 mac->dev = &pdev->dev;
287
288 plat_dat->bsp_priv = mac;
289
290 ret = ingenic_mac_init(plat_dat);
291 if (ret)
292 return ret;
293
294 return stmmac_dvr_probe(device: &pdev->dev, plat_dat, res: &stmmac_res);
295}
296
297#ifdef CONFIG_PM_SLEEP
298static int ingenic_mac_suspend(struct device *dev)
299{
300 int ret;
301
302 ret = stmmac_suspend(dev);
303
304 return ret;
305}
306
307static int ingenic_mac_resume(struct device *dev)
308{
309 struct net_device *ndev = dev_get_drvdata(dev);
310 struct stmmac_priv *priv = netdev_priv(dev: ndev);
311 int ret;
312
313 ret = ingenic_mac_init(plat_dat: priv->plat);
314 if (ret)
315 return ret;
316
317 ret = stmmac_resume(dev);
318
319 return ret;
320}
321#endif /* CONFIG_PM_SLEEP */
322
323static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume);
324
325static struct ingenic_soc_info jz4775_soc_info = {
326 .version = ID_JZ4775,
327 .mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
328
329 .set_mode = jz4775_mac_set_mode,
330};
331
332static struct ingenic_soc_info x1000_soc_info = {
333 .version = ID_X1000,
334 .mask = MACPHYC_SOFT_RST_MASK,
335
336 .set_mode = x1000_mac_set_mode,
337};
338
339static struct ingenic_soc_info x1600_soc_info = {
340 .version = ID_X1600,
341 .mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
342
343 .set_mode = x1600_mac_set_mode,
344};
345
346static struct ingenic_soc_info x1830_soc_info = {
347 .version = ID_X1830,
348 .mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
349
350 .set_mode = x1830_mac_set_mode,
351};
352
353static struct ingenic_soc_info x2000_soc_info = {
354 .version = ID_X2000,
355 .mask = MACPHYC_TX_SEL_MASK | MACPHYC_TX_DELAY_MASK | MACPHYC_RX_SEL_MASK |
356 MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
357
358 .set_mode = x2000_mac_set_mode,
359};
360
361static const struct of_device_id ingenic_mac_of_matches[] = {
362 { .compatible = "ingenic,jz4775-mac", .data = &jz4775_soc_info },
363 { .compatible = "ingenic,x1000-mac", .data = &x1000_soc_info },
364 { .compatible = "ingenic,x1600-mac", .data = &x1600_soc_info },
365 { .compatible = "ingenic,x1830-mac", .data = &x1830_soc_info },
366 { .compatible = "ingenic,x2000-mac", .data = &x2000_soc_info },
367 { }
368};
369MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);
370
371static struct platform_driver ingenic_mac_driver = {
372 .probe = ingenic_mac_probe,
373 .remove_new = stmmac_pltfr_remove,
374 .driver = {
375 .name = "ingenic-mac",
376 .pm = pm_ptr(&ingenic_mac_pm_ops),
377 .of_match_table = ingenic_mac_of_matches,
378 },
379};
380module_platform_driver(ingenic_mac_driver);
381
382MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
383MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");
384MODULE_LICENSE("GPL v2");
385

source code of linux/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c