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