xref: /linux/drivers/phy/ti/phy-gmii-sel.c (revision dd093fb0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Texas Instruments CPSW Port's PHY Interface Mode selection Driver
4  *
5  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6  *
7  * Based on cpsw-phy-sel.c driver created by Mugunthan V N <mugunthanvnm@ti.com>
8  */
9 
10 #include <linux/platform_device.h>
11 #include <linux/module.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/of.h>
14 #include <linux/of_address.h>
15 #include <linux/of_net.h>
16 #include <linux/phy.h>
17 #include <linux/phy/phy.h>
18 #include <linux/regmap.h>
19 
20 /* AM33xx SoC specific definitions for the CONTROL port */
21 #define AM33XX_GMII_SEL_MODE_MII	0
22 #define AM33XX_GMII_SEL_MODE_RMII	1
23 #define AM33XX_GMII_SEL_MODE_RGMII	2
24 
25 /* J72xx SoC specific definitions for the CONTROL port */
26 #define J72XX_GMII_SEL_MODE_QSGMII	4
27 #define J72XX_GMII_SEL_MODE_QSGMII_SUB	6
28 
29 #define PHY_GMII_PORT(n)	BIT((n) - 1)
30 
31 enum {
32 	PHY_GMII_SEL_PORT_MODE = 0,
33 	PHY_GMII_SEL_RGMII_ID_MODE,
34 	PHY_GMII_SEL_RMII_IO_CLK_EN,
35 	PHY_GMII_SEL_LAST,
36 };
37 
38 struct phy_gmii_sel_phy_priv {
39 	struct phy_gmii_sel_priv *priv;
40 	u32		id;
41 	struct phy	*if_phy;
42 	int		rmii_clock_external;
43 	int		phy_if_mode;
44 	struct regmap_field *fields[PHY_GMII_SEL_LAST];
45 };
46 
47 struct phy_gmii_sel_soc_data {
48 	u32 num_ports;
49 	u32 features;
50 	const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
51 	bool use_of_data;
52 	u64 extra_modes;
53 	u32 num_qsgmii_main_ports;
54 };
55 
56 struct phy_gmii_sel_priv {
57 	struct device *dev;
58 	const struct phy_gmii_sel_soc_data *soc_data;
59 	struct regmap *regmap;
60 	struct phy_provider *phy_provider;
61 	struct phy_gmii_sel_phy_priv *if_phys;
62 	u32 num_ports;
63 	u32 reg_offset;
64 	u32 qsgmii_main_ports;
65 };
66 
67 static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
68 {
69 	struct phy_gmii_sel_phy_priv *if_phy = phy_get_drvdata(phy);
70 	const struct phy_gmii_sel_soc_data *soc_data = if_phy->priv->soc_data;
71 	struct device *dev = if_phy->priv->dev;
72 	struct regmap_field *regfield;
73 	int ret, rgmii_id = 0;
74 	u32 gmii_sel_mode = 0;
75 
76 	if (mode != PHY_MODE_ETHERNET)
77 		return -EINVAL;
78 
79 	switch (submode) {
80 	case PHY_INTERFACE_MODE_RMII:
81 		gmii_sel_mode = AM33XX_GMII_SEL_MODE_RMII;
82 		break;
83 
84 	case PHY_INTERFACE_MODE_RGMII:
85 	case PHY_INTERFACE_MODE_RGMII_RXID:
86 		gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII;
87 		break;
88 
89 	case PHY_INTERFACE_MODE_RGMII_ID:
90 	case PHY_INTERFACE_MODE_RGMII_TXID:
91 		gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII;
92 		rgmii_id = 1;
93 		break;
94 
95 	case PHY_INTERFACE_MODE_MII:
96 	case PHY_INTERFACE_MODE_GMII:
97 		gmii_sel_mode = AM33XX_GMII_SEL_MODE_MII;
98 		break;
99 
100 	case PHY_INTERFACE_MODE_QSGMII:
101 		if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_QSGMII)))
102 			goto unsupported;
103 		if (if_phy->priv->qsgmii_main_ports & BIT(if_phy->id - 1))
104 			gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII;
105 		else
106 			gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII_SUB;
107 		break;
108 
109 	default:
110 		goto unsupported;
111 	}
112 
113 	if_phy->phy_if_mode = submode;
114 
115 	dev_dbg(dev, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n",
116 		__func__, if_phy->id, submode, rgmii_id,
117 		if_phy->rmii_clock_external);
118 
119 	regfield = if_phy->fields[PHY_GMII_SEL_PORT_MODE];
120 	ret = regmap_field_write(regfield, gmii_sel_mode);
121 	if (ret) {
122 		dev_err(dev, "port%u: set mode fail %d", if_phy->id, ret);
123 		return ret;
124 	}
125 
126 	if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE) &&
127 	    if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]) {
128 		regfield = if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE];
129 		ret = regmap_field_write(regfield, rgmii_id);
130 		if (ret)
131 			return ret;
132 	}
133 
134 	if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
135 	    if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]) {
136 		regfield = if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN];
137 		ret = regmap_field_write(regfield,
138 					 if_phy->rmii_clock_external);
139 	}
140 
141 	return 0;
142 
143 unsupported:
144 	dev_warn(dev, "port%u: unsupported mode: \"%s\"\n",
145 		 if_phy->id, phy_modes(submode));
146 	return -EINVAL;
147 }
148 
149 static const
150 struct reg_field phy_gmii_sel_fields_am33xx[][PHY_GMII_SEL_LAST] = {
151 	{
152 		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 0, 1),
153 		[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 4, 4),
154 		[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 6, 6),
155 	},
156 	{
157 		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 2, 3),
158 		[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 5, 5),
159 		[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 7, 7),
160 	},
161 };
162 
163 static const
164 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am33xx = {
165 	.num_ports = 2,
166 	.features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) |
167 		    BIT(PHY_GMII_SEL_RMII_IO_CLK_EN),
168 	.regfields = phy_gmii_sel_fields_am33xx,
169 };
170 
171 static const
172 struct reg_field phy_gmii_sel_fields_dra7[][PHY_GMII_SEL_LAST] = {
173 	{
174 		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 0, 1),
175 	},
176 	{
177 		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 4, 5),
178 	},
179 };
180 
181 static const
182 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dra7 = {
183 	.num_ports = 2,
184 	.regfields = phy_gmii_sel_fields_dra7,
185 };
186 
187 static const
188 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
189 	.num_ports = 2,
190 	.features = BIT(PHY_GMII_SEL_RGMII_ID_MODE),
191 	.regfields = phy_gmii_sel_fields_am33xx,
192 };
193 
194 static const
195 struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
196 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), },
197 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), },
198 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), },
199 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), },
200 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), },
201 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), },
202 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), },
203 	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), },
204 };
205 
206 static const
207 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
208 	.use_of_data = true,
209 	.regfields = phy_gmii_sel_fields_am654,
210 };
211 
212 static const
213 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = {
214 	.use_of_data = true,
215 	.regfields = phy_gmii_sel_fields_am654,
216 	.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII),
217 	.num_ports = 4,
218 	.num_qsgmii_main_ports = 1,
219 };
220 
221 static const
222 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = {
223 	.use_of_data = true,
224 	.regfields = phy_gmii_sel_fields_am654,
225 	.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII),
226 	.num_ports = 8,
227 	.num_qsgmii_main_ports = 2,
228 };
229 
230 static const struct of_device_id phy_gmii_sel_id_table[] = {
231 	{
232 		.compatible	= "ti,am3352-phy-gmii-sel",
233 		.data		= &phy_gmii_sel_soc_am33xx,
234 	},
235 	{
236 		.compatible	= "ti,dra7xx-phy-gmii-sel",
237 		.data		= &phy_gmii_sel_soc_dra7,
238 	},
239 	{
240 		.compatible	= "ti,am43xx-phy-gmii-sel",
241 		.data		= &phy_gmii_sel_soc_am33xx,
242 	},
243 	{
244 		.compatible	= "ti,dm814-phy-gmii-sel",
245 		.data		= &phy_gmii_sel_soc_dm814,
246 	},
247 	{
248 		.compatible	= "ti,am654-phy-gmii-sel",
249 		.data		= &phy_gmii_sel_soc_am654,
250 	},
251 	{
252 		.compatible	= "ti,j7200-cpsw5g-phy-gmii-sel",
253 		.data		= &phy_gmii_sel_cpsw5g_soc_j7200,
254 	},
255 	{
256 		.compatible	= "ti,j721e-cpsw9g-phy-gmii-sel",
257 		.data		= &phy_gmii_sel_cpsw9g_soc_j721e,
258 	},
259 	{}
260 };
261 MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
262 
263 static const struct phy_ops phy_gmii_sel_ops = {
264 	.set_mode	= phy_gmii_sel_mode,
265 	.owner		= THIS_MODULE,
266 };
267 
268 static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
269 					 struct of_phandle_args *args)
270 {
271 	struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev);
272 	int phy_id = args->args[0];
273 
274 	if (args->args_count < 1)
275 		return ERR_PTR(-EINVAL);
276 	if (!priv || !priv->if_phys)
277 		return ERR_PTR(-ENODEV);
278 	if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
279 	    args->args_count < 2)
280 		return ERR_PTR(-EINVAL);
281 	if (phy_id > priv->num_ports)
282 		return ERR_PTR(-EINVAL);
283 	if (phy_id != priv->if_phys[phy_id - 1].id)
284 		return ERR_PTR(-EINVAL);
285 
286 	phy_id--;
287 	if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN))
288 		priv->if_phys[phy_id].rmii_clock_external = args->args[1];
289 	dev_dbg(dev, "%s id:%u ext:%d\n", __func__,
290 		priv->if_phys[phy_id].id, args->args[1]);
291 
292 	return priv->if_phys[phy_id].if_phy;
293 }
294 
295 static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
296 			     struct phy_gmii_sel_phy_priv *if_phy)
297 {
298 	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
299 	struct device *dev = priv->dev;
300 	const struct reg_field *fields;
301 	struct regmap_field *regfield;
302 	struct reg_field field;
303 	int ret;
304 
305 	if_phy->id = port;
306 	if_phy->priv = priv;
307 
308 	fields = soc_data->regfields[port - 1];
309 	field = *fields++;
310 	field.reg += priv->reg_offset;
311 	dev_dbg(dev, "%s field %x %d %d\n", __func__,
312 		field.reg, field.msb, field.lsb);
313 
314 	regfield = devm_regmap_field_alloc(dev, priv->regmap, field);
315 	if (IS_ERR(regfield))
316 		return PTR_ERR(regfield);
317 	if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
318 
319 	field = *fields++;
320 	field.reg += priv->reg_offset;
321 	if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) {
322 		regfield = devm_regmap_field_alloc(dev,
323 						   priv->regmap,
324 						   field);
325 		if (IS_ERR(regfield))
326 			return PTR_ERR(regfield);
327 		if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE] = regfield;
328 		dev_dbg(dev, "%s field %x %d %d\n", __func__,
329 			field.reg, field.msb, field.lsb);
330 	}
331 
332 	field = *fields;
333 	field.reg += priv->reg_offset;
334 	if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) {
335 		regfield = devm_regmap_field_alloc(dev,
336 						   priv->regmap,
337 						   field);
338 		if (IS_ERR(regfield))
339 			return PTR_ERR(regfield);
340 		if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN] = regfield;
341 		dev_dbg(dev, "%s field %x %d %d\n", __func__,
342 			field.reg, field.msb, field.lsb);
343 	}
344 
345 	if_phy->if_phy = devm_phy_create(dev,
346 					 priv->dev->of_node,
347 					 &phy_gmii_sel_ops);
348 	if (IS_ERR(if_phy->if_phy)) {
349 		ret = PTR_ERR(if_phy->if_phy);
350 		dev_err(dev, "Failed to create phy%d %d\n", port, ret);
351 		return ret;
352 	}
353 	phy_set_drvdata(if_phy->if_phy, if_phy);
354 
355 	return 0;
356 }
357 
358 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
359 {
360 	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
361 	struct phy_gmii_sel_phy_priv *if_phys;
362 	struct device *dev = priv->dev;
363 	int i, ret;
364 
365 	if (soc_data->use_of_data) {
366 		const __be32 *offset;
367 		u64 size;
368 
369 		offset = of_get_address(dev->of_node, 0, &size, NULL);
370 		if (!offset)
371 			return -EINVAL;
372 		priv->num_ports = size / sizeof(u32);
373 		if (!priv->num_ports)
374 			return -EINVAL;
375 		priv->reg_offset = __be32_to_cpu(*offset);
376 	}
377 
378 	if_phys = devm_kcalloc(dev, priv->num_ports,
379 			       sizeof(*if_phys), GFP_KERNEL);
380 	if (!if_phys)
381 		return -ENOMEM;
382 	dev_dbg(dev, "%s %d\n", __func__, priv->num_ports);
383 
384 	for (i = 0; i < priv->num_ports; i++) {
385 		ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]);
386 		if (ret)
387 			return ret;
388 	}
389 
390 	priv->if_phys = if_phys;
391 	return 0;
392 }
393 
394 static int phy_gmii_sel_probe(struct platform_device *pdev)
395 {
396 	struct device *dev = &pdev->dev;
397 	const struct phy_gmii_sel_soc_data *soc_data;
398 	struct device_node *node = dev->of_node;
399 	const struct of_device_id *of_id;
400 	struct phy_gmii_sel_priv *priv;
401 	u32 main_ports = 1;
402 	int ret;
403 	u32 i;
404 
405 	of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node);
406 	if (!of_id)
407 		return -EINVAL;
408 
409 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
410 	if (!priv)
411 		return -ENOMEM;
412 
413 	priv->dev = &pdev->dev;
414 	priv->soc_data = of_id->data;
415 	soc_data = priv->soc_data;
416 	priv->num_ports = priv->soc_data->num_ports;
417 	priv->qsgmii_main_ports = 0;
418 
419 	/*
420 	 * Based on the compatible, try to read the appropriate number of
421 	 * QSGMII main ports from the "ti,qsgmii-main-ports" property from
422 	 * the device-tree node.
423 	 */
424 	for (i = 0; i < soc_data->num_qsgmii_main_ports; i++) {
425 		of_property_read_u32_index(node, "ti,qsgmii-main-ports", i, &main_ports);
426 		/*
427 		 * Ensure that main_ports is within bounds.
428 		 */
429 		if (main_ports < 1 || main_ports > soc_data->num_ports) {
430 			dev_err(dev, "Invalid qsgmii main port provided\n");
431 			return -EINVAL;
432 		}
433 		priv->qsgmii_main_ports |= PHY_GMII_PORT(main_ports);
434 	}
435 
436 	priv->regmap = syscon_node_to_regmap(node->parent);
437 	if (IS_ERR(priv->regmap)) {
438 		ret = PTR_ERR(priv->regmap);
439 		dev_err(dev, "Failed to get syscon %d\n", ret);
440 		return ret;
441 	}
442 
443 	ret = phy_gmii_sel_init_ports(priv);
444 	if (ret)
445 		return ret;
446 
447 	dev_set_drvdata(&pdev->dev, priv);
448 
449 	priv->phy_provider =
450 		devm_of_phy_provider_register(dev,
451 					      phy_gmii_sel_of_xlate);
452 	if (IS_ERR(priv->phy_provider)) {
453 		ret = PTR_ERR(priv->phy_provider);
454 		dev_err(dev, "Failed to create phy provider %d\n", ret);
455 		return ret;
456 	}
457 
458 	return 0;
459 }
460 
461 static struct platform_driver phy_gmii_sel_driver = {
462 	.probe		= phy_gmii_sel_probe,
463 	.driver		= {
464 		.name	= "phy-gmii-sel",
465 		.of_match_table = phy_gmii_sel_id_table,
466 	},
467 };
468 module_platform_driver(phy_gmii_sel_driver);
469 
470 MODULE_LICENSE("GPL v2");
471 MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>");
472 MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver");
473