1 // SPDX-License-Identifier: GPL-2.0
3 * Texas Instruments CPSW Port's PHY Interface Mode selection Driver
5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
7 * Based on cpsw-phy-sel.c driver created by Mugunthan V N <mugunthanvnm@ti.com>
10 #include <linux/platform_device.h>
11 #include <linux/module.h>
12 #include <linux/mfd/syscon.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>
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
25 /* J72xx SoC specific definitions for the CONTROL port */
26 #define J72XX_GMII_SEL_MODE_SGMII 3
27 #define J72XX_GMII_SEL_MODE_QSGMII 4
28 #define J72XX_GMII_SEL_MODE_USXGMII 5
29 #define J72XX_GMII_SEL_MODE_QSGMII_SUB 6
31 #define PHY_GMII_PORT(n) BIT((n) - 1)
34 PHY_GMII_SEL_PORT_MODE
= 0,
35 PHY_GMII_SEL_RGMII_ID_MODE
,
36 PHY_GMII_SEL_RMII_IO_CLK_EN
,
40 struct phy_gmii_sel_phy_priv
{
41 struct phy_gmii_sel_priv
*priv
;
44 int rmii_clock_external
;
46 struct regmap_field
*fields
[PHY_GMII_SEL_LAST
];
49 struct phy_gmii_sel_soc_data
{
52 const struct reg_field (*regfields
)[PHY_GMII_SEL_LAST
];
55 u32 num_qsgmii_main_ports
;
58 struct phy_gmii_sel_priv
{
60 const struct phy_gmii_sel_soc_data
*soc_data
;
61 struct regmap
*regmap
;
62 struct phy_provider
*phy_provider
;
63 struct phy_gmii_sel_phy_priv
*if_phys
;
66 u32 qsgmii_main_ports
;
70 static int phy_gmii_sel_mode(struct phy
*phy
, enum phy_mode mode
, int submode
)
72 struct phy_gmii_sel_phy_priv
*if_phy
= phy_get_drvdata(phy
);
73 const struct phy_gmii_sel_soc_data
*soc_data
= if_phy
->priv
->soc_data
;
74 struct device
*dev
= if_phy
->priv
->dev
;
75 struct regmap_field
*regfield
;
76 int ret
, rgmii_id
= 0;
77 u32 gmii_sel_mode
= 0;
79 if (mode
!= PHY_MODE_ETHERNET
)
83 case PHY_INTERFACE_MODE_RMII
:
84 gmii_sel_mode
= AM33XX_GMII_SEL_MODE_RMII
;
87 case PHY_INTERFACE_MODE_RGMII
:
88 case PHY_INTERFACE_MODE_RGMII_RXID
:
89 gmii_sel_mode
= AM33XX_GMII_SEL_MODE_RGMII
;
92 case PHY_INTERFACE_MODE_RGMII_ID
:
93 case PHY_INTERFACE_MODE_RGMII_TXID
:
94 gmii_sel_mode
= AM33XX_GMII_SEL_MODE_RGMII
;
98 case PHY_INTERFACE_MODE_MII
:
99 case PHY_INTERFACE_MODE_GMII
:
100 gmii_sel_mode
= AM33XX_GMII_SEL_MODE_MII
;
103 case PHY_INTERFACE_MODE_QSGMII
:
104 if (!(soc_data
->extra_modes
& BIT(PHY_INTERFACE_MODE_QSGMII
)))
106 if (if_phy
->priv
->qsgmii_main_ports
& BIT(if_phy
->id
- 1))
107 gmii_sel_mode
= J72XX_GMII_SEL_MODE_QSGMII
;
109 gmii_sel_mode
= J72XX_GMII_SEL_MODE_QSGMII_SUB
;
112 case PHY_INTERFACE_MODE_SGMII
:
113 if (!(soc_data
->extra_modes
& BIT(PHY_INTERFACE_MODE_SGMII
)))
116 gmii_sel_mode
= J72XX_GMII_SEL_MODE_SGMII
;
119 case PHY_INTERFACE_MODE_USXGMII
:
120 if (!(soc_data
->extra_modes
& BIT(PHY_INTERFACE_MODE_USXGMII
)))
123 gmii_sel_mode
= J72XX_GMII_SEL_MODE_USXGMII
;
130 if_phy
->phy_if_mode
= submode
;
132 dev_dbg(dev
, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n",
133 __func__
, if_phy
->id
, submode
, rgmii_id
,
134 if_phy
->rmii_clock_external
);
136 regfield
= if_phy
->fields
[PHY_GMII_SEL_PORT_MODE
];
137 ret
= regmap_field_write(regfield
, gmii_sel_mode
);
139 dev_err(dev
, "port%u: set mode fail %d", if_phy
->id
, ret
);
143 if (soc_data
->features
& BIT(PHY_GMII_SEL_RGMII_ID_MODE
) &&
144 if_phy
->fields
[PHY_GMII_SEL_RGMII_ID_MODE
]) {
145 regfield
= if_phy
->fields
[PHY_GMII_SEL_RGMII_ID_MODE
];
146 ret
= regmap_field_write(regfield
, rgmii_id
);
151 if (soc_data
->features
& BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
) &&
152 if_phy
->fields
[PHY_GMII_SEL_RMII_IO_CLK_EN
]) {
153 regfield
= if_phy
->fields
[PHY_GMII_SEL_RMII_IO_CLK_EN
];
154 ret
= regmap_field_write(regfield
,
155 if_phy
->rmii_clock_external
);
161 dev_warn(dev
, "port%u: unsupported mode: \"%s\"\n",
162 if_phy
->id
, phy_modes(submode
));
167 struct reg_field phy_gmii_sel_fields_am33xx
[][PHY_GMII_SEL_LAST
] = {
169 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x650, 0, 1),
170 [PHY_GMII_SEL_RGMII_ID_MODE
] = REG_FIELD(0x650, 4, 4),
171 [PHY_GMII_SEL_RMII_IO_CLK_EN
] = REG_FIELD(0x650, 6, 6),
174 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x650, 2, 3),
175 [PHY_GMII_SEL_RGMII_ID_MODE
] = REG_FIELD(0x650, 5, 5),
176 [PHY_GMII_SEL_RMII_IO_CLK_EN
] = REG_FIELD(0x650, 7, 7),
181 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am33xx
= {
183 .features
= BIT(PHY_GMII_SEL_RGMII_ID_MODE
) |
184 BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
),
185 .regfields
= phy_gmii_sel_fields_am33xx
,
189 struct reg_field phy_gmii_sel_fields_dra7
[][PHY_GMII_SEL_LAST
] = {
191 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x554, 0, 1),
194 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x554, 4, 5),
199 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dra7
= {
201 .regfields
= phy_gmii_sel_fields_dra7
,
205 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814
= {
207 .features
= BIT(PHY_GMII_SEL_RGMII_ID_MODE
),
208 .regfields
= phy_gmii_sel_fields_am33xx
,
212 struct reg_field phy_gmii_sel_fields_am654
[][PHY_GMII_SEL_LAST
] = {
213 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x0, 0, 2), },
214 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x4, 0, 2), },
215 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x8, 0, 2), },
216 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0xC, 0, 2), },
217 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x10, 0, 2), },
218 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x14, 0, 2), },
219 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x18, 0, 2), },
220 { [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x1C, 0, 2), },
224 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654
= {
226 .regfields
= phy_gmii_sel_fields_am654
,
230 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200
= {
232 .regfields
= phy_gmii_sel_fields_am654
,
233 .extra_modes
= BIT(PHY_INTERFACE_MODE_QSGMII
) | BIT(PHY_INTERFACE_MODE_SGMII
) |
234 BIT(PHY_INTERFACE_MODE_USXGMII
),
236 .num_qsgmii_main_ports
= 1,
240 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e
= {
242 .regfields
= phy_gmii_sel_fields_am654
,
243 .extra_modes
= BIT(PHY_INTERFACE_MODE_QSGMII
) | BIT(PHY_INTERFACE_MODE_SGMII
),
245 .num_qsgmii_main_ports
= 2,
249 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j784s4
= {
251 .regfields
= phy_gmii_sel_fields_am654
,
252 .extra_modes
= BIT(PHY_INTERFACE_MODE_QSGMII
) | BIT(PHY_INTERFACE_MODE_SGMII
) |
253 BIT(PHY_INTERFACE_MODE_USXGMII
),
255 .num_qsgmii_main_ports
= 2,
258 static const struct of_device_id phy_gmii_sel_id_table
[] = {
260 .compatible
= "ti,am3352-phy-gmii-sel",
261 .data
= &phy_gmii_sel_soc_am33xx
,
264 .compatible
= "ti,dra7xx-phy-gmii-sel",
265 .data
= &phy_gmii_sel_soc_dra7
,
268 .compatible
= "ti,am43xx-phy-gmii-sel",
269 .data
= &phy_gmii_sel_soc_am33xx
,
272 .compatible
= "ti,dm814-phy-gmii-sel",
273 .data
= &phy_gmii_sel_soc_dm814
,
276 .compatible
= "ti,am654-phy-gmii-sel",
277 .data
= &phy_gmii_sel_soc_am654
,
280 .compatible
= "ti,j7200-cpsw5g-phy-gmii-sel",
281 .data
= &phy_gmii_sel_cpsw5g_soc_j7200
,
284 .compatible
= "ti,j721e-cpsw9g-phy-gmii-sel",
285 .data
= &phy_gmii_sel_cpsw9g_soc_j721e
,
288 .compatible
= "ti,j784s4-cpsw9g-phy-gmii-sel",
289 .data
= &phy_gmii_sel_cpsw9g_soc_j784s4
,
293 MODULE_DEVICE_TABLE(of
, phy_gmii_sel_id_table
);
295 static const struct phy_ops phy_gmii_sel_ops
= {
296 .set_mode
= phy_gmii_sel_mode
,
297 .owner
= THIS_MODULE
,
300 static struct phy
*phy_gmii_sel_of_xlate(struct device
*dev
,
301 const struct of_phandle_args
*args
)
303 struct phy_gmii_sel_priv
*priv
= dev_get_drvdata(dev
);
304 int phy_id
= args
->args
[0];
306 if (args
->args_count
< 1)
307 return ERR_PTR(-EINVAL
);
308 if (!priv
|| !priv
->if_phys
)
309 return ERR_PTR(-ENODEV
);
310 if (priv
->soc_data
->features
& BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
) &&
311 args
->args_count
< 2)
312 return ERR_PTR(-EINVAL
);
313 if (phy_id
> priv
->num_ports
)
314 return ERR_PTR(-EINVAL
);
315 if (phy_id
!= priv
->if_phys
[phy_id
- 1].id
)
316 return ERR_PTR(-EINVAL
);
319 if (priv
->soc_data
->features
& BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
))
320 priv
->if_phys
[phy_id
].rmii_clock_external
= args
->args
[1];
321 dev_dbg(dev
, "%s id:%u ext:%d\n", __func__
,
322 priv
->if_phys
[phy_id
].id
, args
->args
[1]);
324 return priv
->if_phys
[phy_id
].if_phy
;
327 static int phy_gmii_init_phy(struct phy_gmii_sel_priv
*priv
, int port
,
328 struct phy_gmii_sel_phy_priv
*if_phy
)
330 const struct phy_gmii_sel_soc_data
*soc_data
= priv
->soc_data
;
331 struct device
*dev
= priv
->dev
;
332 const struct reg_field
*fields
;
333 struct regmap_field
*regfield
;
334 struct reg_field field
;
340 fields
= soc_data
->regfields
[port
- 1];
342 field
.reg
+= priv
->reg_offset
;
343 dev_dbg(dev
, "%s field %x %d %d\n", __func__
,
344 field
.reg
, field
.msb
, field
.lsb
);
346 regfield
= devm_regmap_field_alloc(dev
, priv
->regmap
, field
);
347 if (IS_ERR(regfield
))
348 return PTR_ERR(regfield
);
349 if_phy
->fields
[PHY_GMII_SEL_PORT_MODE
] = regfield
;
352 field
.reg
+= priv
->reg_offset
;
353 if (soc_data
->features
& BIT(PHY_GMII_SEL_RGMII_ID_MODE
)) {
354 regfield
= devm_regmap_field_alloc(dev
,
357 if (IS_ERR(regfield
))
358 return PTR_ERR(regfield
);
359 if_phy
->fields
[PHY_GMII_SEL_RGMII_ID_MODE
] = regfield
;
360 dev_dbg(dev
, "%s field %x %d %d\n", __func__
,
361 field
.reg
, field
.msb
, field
.lsb
);
365 field
.reg
+= priv
->reg_offset
;
366 if (soc_data
->features
& BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
)) {
367 regfield
= devm_regmap_field_alloc(dev
,
370 if (IS_ERR(regfield
))
371 return PTR_ERR(regfield
);
372 if_phy
->fields
[PHY_GMII_SEL_RMII_IO_CLK_EN
] = regfield
;
373 dev_dbg(dev
, "%s field %x %d %d\n", __func__
,
374 field
.reg
, field
.msb
, field
.lsb
);
377 if_phy
->if_phy
= devm_phy_create(dev
,
380 if (IS_ERR(if_phy
->if_phy
)) {
381 ret
= PTR_ERR(if_phy
->if_phy
);
382 dev_err(dev
, "Failed to create phy%d %d\n", port
, ret
);
385 phy_set_drvdata(if_phy
->if_phy
, if_phy
);
390 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv
*priv
)
392 const struct phy_gmii_sel_soc_data
*soc_data
= priv
->soc_data
;
393 struct phy_gmii_sel_phy_priv
*if_phys
;
394 struct device
*dev
= priv
->dev
;
397 if (soc_data
->use_of_data
) {
398 const __be32
*offset
;
401 offset
= of_get_address(dev
->of_node
, 0, &size
, NULL
);
404 priv
->num_ports
= size
/ sizeof(u32
);
405 if (!priv
->num_ports
)
407 if (!priv
->no_offset
)
408 priv
->reg_offset
= __be32_to_cpu(*offset
);
411 if_phys
= devm_kcalloc(dev
, priv
->num_ports
,
412 sizeof(*if_phys
), GFP_KERNEL
);
415 dev_dbg(dev
, "%s %d\n", __func__
, priv
->num_ports
);
417 for (i
= 0; i
< priv
->num_ports
; i
++) {
418 ret
= phy_gmii_init_phy(priv
, i
+ 1, &if_phys
[i
]);
423 priv
->if_phys
= if_phys
;
427 static int phy_gmii_sel_probe(struct platform_device
*pdev
)
429 struct device
*dev
= &pdev
->dev
;
430 const struct phy_gmii_sel_soc_data
*soc_data
;
431 struct device_node
*node
= dev
->of_node
;
432 const struct of_device_id
*of_id
;
433 struct phy_gmii_sel_priv
*priv
;
438 of_id
= of_match_node(phy_gmii_sel_id_table
, pdev
->dev
.of_node
);
442 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
446 priv
->dev
= &pdev
->dev
;
447 priv
->soc_data
= of_id
->data
;
448 soc_data
= priv
->soc_data
;
449 priv
->num_ports
= priv
->soc_data
->num_ports
;
450 priv
->qsgmii_main_ports
= 0;
453 * Based on the compatible, try to read the appropriate number of
454 * QSGMII main ports from the "ti,qsgmii-main-ports" property from
455 * the device-tree node.
457 for (i
= 0; i
< soc_data
->num_qsgmii_main_ports
; i
++) {
458 of_property_read_u32_index(node
, "ti,qsgmii-main-ports", i
, &main_ports
);
460 * Ensure that main_ports is within bounds.
462 if (main_ports
< 1 || main_ports
> soc_data
->num_ports
) {
463 dev_err(dev
, "Invalid qsgmii main port provided\n");
466 priv
->qsgmii_main_ports
|= PHY_GMII_PORT(main_ports
);
469 priv
->regmap
= syscon_node_to_regmap(node
->parent
);
470 if (IS_ERR(priv
->regmap
)) {
471 priv
->regmap
= device_node_to_regmap(node
);
472 if (IS_ERR(priv
->regmap
))
473 return dev_err_probe(dev
, PTR_ERR(priv
->regmap
),
474 "Failed to get syscon\n");
475 priv
->no_offset
= true;
478 ret
= phy_gmii_sel_init_ports(priv
);
482 dev_set_drvdata(&pdev
->dev
, priv
);
485 devm_of_phy_provider_register(dev
,
486 phy_gmii_sel_of_xlate
);
487 if (IS_ERR(priv
->phy_provider
))
488 return dev_err_probe(dev
, PTR_ERR(priv
->phy_provider
),
489 "Failed to create phy provider\n");
494 static int phy_gmii_sel_resume_noirq(struct device
*dev
)
496 struct phy_gmii_sel_priv
*priv
= dev_get_drvdata(dev
);
497 struct phy_gmii_sel_phy_priv
*if_phys
= priv
->if_phys
;
500 for (i
= 0; i
< priv
->num_ports
; i
++) {
501 if (if_phys
[i
].phy_if_mode
) {
502 ret
= phy_gmii_sel_mode(if_phys
[i
].if_phy
,
503 PHY_MODE_ETHERNET
, if_phys
[i
].phy_if_mode
);
505 dev_err(dev
, "port%u: restore mode fail %d\n",
506 if_phys
[i
].if_phy
->id
, ret
);
515 static DEFINE_NOIRQ_DEV_PM_OPS(phy_gmii_sel_pm_ops
, NULL
, phy_gmii_sel_resume_noirq
);
517 static struct platform_driver phy_gmii_sel_driver
= {
518 .probe
= phy_gmii_sel_probe
,
520 .name
= "phy-gmii-sel",
521 .of_match_table
= phy_gmii_sel_id_table
,
522 .pm
= pm_sleep_ptr(&phy_gmii_sel_pm_ops
),
525 module_platform_driver(phy_gmii_sel_driver
);
527 MODULE_LICENSE("GPL v2");
528 MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>");
529 MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver");