xref: /linux/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c (revision a34b0e4e21d6be3c3d620aa7f9dfbf0e9550c19e)
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 
39 #define MACPHYC_TX_DELAY_PS_MAX		2496
40 #define MACPHYC_TX_DELAY_PS_MIN		20
41 
42 #define MACPHYC_RX_DELAY_PS_MAX		2496
43 #define MACPHYC_RX_DELAY_PS_MIN		20
44 
45 enum ingenic_mac_version {
46 	ID_JZ4775,
47 	ID_X1000,
48 	ID_X1600,
49 	ID_X1830,
50 	ID_X2000,
51 };
52 
53 struct ingenic_mac {
54 	const struct ingenic_soc_info *soc_info;
55 	struct plat_stmmacenet_data *plat_dat;
56 	struct device *dev;
57 	struct regmap *regmap;
58 
59 	int rx_delay;
60 	int tx_delay;
61 };
62 
63 struct ingenic_soc_info {
64 	enum ingenic_mac_version version;
65 	u32 mask;
66 
67 	int (*set_mode)(struct ingenic_mac *mac, u8 phy_intf_sel);
68 
69 	u8 valid_phy_intf_sel;
70 };
71 
72 static int jz4775_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel)
73 {
74 	unsigned int val;
75 
76 	val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel) |
77 	      FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT);
78 
79 	/* Update MAC PHY control register */
80 	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
81 }
82 
83 static int x1000_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel)
84 {
85 	/* Update MAC PHY control register */
86 	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, 0);
87 }
88 
89 static int x1600_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel)
90 {
91 	unsigned int val;
92 
93 	val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel);
94 
95 	/* Update MAC PHY control register */
96 	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
97 }
98 
99 static int x1830_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel)
100 {
101 	unsigned int val;
102 
103 	val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) |
104 	      FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel);
105 
106 	/* Update MAC PHY control register */
107 	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
108 }
109 
110 static int x2000_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel)
111 {
112 	unsigned int val;
113 
114 	val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel);
115 
116 	if (phy_intf_sel == PHY_INTF_SEL_RMII) {
117 		val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) |
118 		       FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN);
119 	} else if (phy_intf_sel == PHY_INTF_SEL_RGMII) {
120 		if (mac->tx_delay == 0)
121 			val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN);
122 		else
123 			val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_DELAY) |
124 			       FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1);
125 
126 		if (mac->rx_delay == 0)
127 			val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN);
128 		else
129 			val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_DELAY) |
130 				   FIELD_PREP(MACPHYC_RX_DELAY_MASK, (mac->rx_delay + 9750) / 19500 - 1);
131 	}
132 
133 	/* Update MAC PHY control register */
134 	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
135 }
136 
137 static int ingenic_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
138 {
139 	struct ingenic_mac *mac = bsp_priv;
140 
141 	if (!mac->soc_info->set_mode)
142 		return 0;
143 
144 	if (phy_intf_sel >= BITS_PER_BYTE ||
145 	    ~mac->soc_info->valid_phy_intf_sel & BIT(phy_intf_sel))
146 		return -EINVAL;
147 
148 	dev_dbg(mac->dev, "MAC PHY control register: interface %s\n",
149 		phy_modes(mac->plat_dat->phy_interface));
150 
151 	return mac->soc_info->set_mode(mac, phy_intf_sel);
152 }
153 
154 static int ingenic_mac_probe(struct platform_device *pdev)
155 {
156 	struct plat_stmmacenet_data *plat_dat;
157 	struct stmmac_resources stmmac_res;
158 	struct ingenic_mac *mac;
159 	const struct ingenic_soc_info *data;
160 	u32 tx_delay_ps, rx_delay_ps;
161 	int ret;
162 
163 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
164 	if (ret)
165 		return ret;
166 
167 	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
168 	if (IS_ERR(plat_dat))
169 		return PTR_ERR(plat_dat);
170 
171 	mac = devm_kzalloc(&pdev->dev, sizeof(*mac), GFP_KERNEL);
172 	if (!mac)
173 		return -ENOMEM;
174 
175 	data = of_device_get_match_data(&pdev->dev);
176 	if (!data) {
177 		dev_err(&pdev->dev, "No of match data provided\n");
178 		return -EINVAL;
179 	}
180 
181 	/* Get MAC PHY control register */
182 	mac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mode-reg");
183 	if (IS_ERR(mac->regmap)) {
184 		dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);
185 		return PTR_ERR(mac->regmap);
186 	}
187 
188 	if (!of_property_read_u32(pdev->dev.of_node, "tx-clk-delay-ps", &tx_delay_ps)) {
189 		if (tx_delay_ps >= MACPHYC_TX_DELAY_PS_MIN &&
190 			tx_delay_ps <= MACPHYC_TX_DELAY_PS_MAX) {
191 			mac->tx_delay = tx_delay_ps * 1000;
192 		} else {
193 			dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
194 			return -EINVAL;
195 		}
196 	}
197 
198 	if (!of_property_read_u32(pdev->dev.of_node, "rx-clk-delay-ps", &rx_delay_ps)) {
199 		if (rx_delay_ps >= MACPHYC_RX_DELAY_PS_MIN &&
200 			rx_delay_ps <= MACPHYC_RX_DELAY_PS_MAX) {
201 			mac->rx_delay = rx_delay_ps * 1000;
202 		} else {
203 			dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
204 			return -EINVAL;
205 		}
206 	}
207 
208 	mac->soc_info = data;
209 	mac->dev = &pdev->dev;
210 	mac->plat_dat = plat_dat;
211 
212 	plat_dat->bsp_priv = mac;
213 	plat_dat->set_phy_intf_sel = ingenic_set_phy_intf_sel;
214 
215 	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
216 }
217 
218 static struct ingenic_soc_info jz4775_soc_info = {
219 	.version = ID_JZ4775,
220 	.mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
221 
222 	.set_mode = jz4775_mac_set_mode,
223 	.valid_phy_intf_sel = BIT(PHY_INTF_SEL_GMII_MII) |
224 			      BIT(PHY_INTF_SEL_RGMII) |
225 			      BIT(PHY_INTF_SEL_RMII),
226 };
227 
228 static struct ingenic_soc_info x1000_soc_info = {
229 	.version = ID_X1000,
230 	.mask = MACPHYC_SOFT_RST_MASK,
231 
232 	.set_mode = x1000_mac_set_mode,
233 	.valid_phy_intf_sel = BIT(PHY_INTF_SEL_RMII),
234 };
235 
236 static struct ingenic_soc_info x1600_soc_info = {
237 	.version = ID_X1600,
238 	.mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
239 
240 	.set_mode = x1600_mac_set_mode,
241 	.valid_phy_intf_sel = BIT(PHY_INTF_SEL_RMII),
242 };
243 
244 static struct ingenic_soc_info x1830_soc_info = {
245 	.version = ID_X1830,
246 	.mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
247 
248 	.set_mode = x1830_mac_set_mode,
249 	.valid_phy_intf_sel = BIT(PHY_INTF_SEL_RMII),
250 };
251 
252 static struct ingenic_soc_info x2000_soc_info = {
253 	.version = ID_X2000,
254 	.mask = MACPHYC_TX_SEL_MASK | MACPHYC_TX_DELAY_MASK | MACPHYC_RX_SEL_MASK |
255 			MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
256 
257 	.set_mode = x2000_mac_set_mode,
258 	.valid_phy_intf_sel = BIT(PHY_INTF_SEL_RGMII) |
259 			      BIT(PHY_INTF_SEL_RMII),
260 };
261 
262 static const struct of_device_id ingenic_mac_of_matches[] = {
263 	{ .compatible = "ingenic,jz4775-mac", .data = &jz4775_soc_info },
264 	{ .compatible = "ingenic,x1000-mac", .data = &x1000_soc_info },
265 	{ .compatible = "ingenic,x1600-mac", .data = &x1600_soc_info },
266 	{ .compatible = "ingenic,x1830-mac", .data = &x1830_soc_info },
267 	{ .compatible = "ingenic,x2000-mac", .data = &x2000_soc_info },
268 	{ }
269 };
270 MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);
271 
272 static struct platform_driver ingenic_mac_driver = {
273 	.probe		= ingenic_mac_probe,
274 	.driver		= {
275 		.name	= "ingenic-mac",
276 		.pm		= &stmmac_pltfr_pm_ops,
277 		.of_match_table = ingenic_mac_of_matches,
278 	},
279 };
280 module_platform_driver(ingenic_mac_driver);
281 
282 MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
283 MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");
284 MODULE_LICENSE("GPL v2");
285