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 
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 
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 
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 
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 
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 
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 
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
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 
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