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 = devm_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		return -ENOMEM;
251
252	data = of_device_get_match_data(&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(pdev->dev.of_node, "mode-reg");
260	if (IS_ERR(mac->regmap)) {
261		dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);
262		return PTR_ERR(mac->regmap);
263	}
264
265	if (!of_property_read_u32(pdev->dev.of_node, "tx-clk-delay-ps", &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(pdev->dev.of_node, "rx-clk-delay-ps", &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(&pdev->dev, plat_dat, &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(ndev);
311	int ret;
312
313	ret = ingenic_mac_init(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