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(mac->regmap, 0, 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(mac->regmap, 0, mac->soc_info->mask, 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(mac->regmap, 0, 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(mac->regmap, 0, 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(mac->regmap, 0, 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);
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
306err_remove_config_dt:
307	stmmac_remove_config_dt(pdev, plat_dat);
308
309	return ret;
310}
311
312#ifdef CONFIG_PM_SLEEP
313static int ingenic_mac_suspend(struct device *dev)
314{
315	int ret;
316
317	ret = stmmac_suspend(dev);
318
319	return ret;
320}
321
322static 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
338static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume);
339
340static 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
347static 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
354static 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
361static 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
368static 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
376static 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};
384MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);
385
386static 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};
395module_platform_driver(ingenic_mac_driver);
396
397MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
398MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");
399MODULE_LICENSE("GPL v2");
400