1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
3 * SerDes PHY driver for Microsemi Ocelot
5 * Copyright (c) 2018 Microsemi
10 #include <linux/mfd/syscon.h>
11 #include <linux/module.h>
13 #include <linux/of_platform.h>
14 #include <linux/phy/phy.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <soc/mscc/ocelot_hsio.h>
18 #include <dt-bindings/phy/phy-ocelot-serdes.h>
23 struct phy
*phys
[SERDES_MAX
];
28 /* Not used when in QSGMII or PCIe mode */
30 struct serdes_ctrl
*ctrl
;
33 #define MCB_S1G_CFG_TIMEOUT 50
35 static int __serdes_write_mcb_s1g(struct regmap
*regmap
, u8 macro
, u32 op
)
39 regmap_write(regmap
, HSIO_MCB_S1G_ADDR_CFG
, op
|
40 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(BIT(macro
)));
42 return regmap_read_poll_timeout(regmap
, HSIO_MCB_S1G_ADDR_CFG
, regval
,
43 (regval
& op
) != op
, 100,
44 MCB_S1G_CFG_TIMEOUT
* 1000);
47 static int serdes_commit_mcb_s1g(struct regmap
*regmap
, u8 macro
)
49 return __serdes_write_mcb_s1g(regmap
, macro
,
50 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT
);
53 static int serdes_update_mcb_s1g(struct regmap
*regmap
, u8 macro
)
55 return __serdes_write_mcb_s1g(regmap
, macro
,
56 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT
);
59 static int serdes_init_s1g(struct regmap
*regmap
, u8 serdes
)
63 ret
= serdes_update_mcb_s1g(regmap
, serdes
);
67 regmap_update_bits(regmap
, HSIO_S1G_COMMON_CFG
,
68 HSIO_S1G_COMMON_CFG_SYS_RST
|
69 HSIO_S1G_COMMON_CFG_ENA_LANE
|
70 HSIO_S1G_COMMON_CFG_ENA_ELOOP
|
71 HSIO_S1G_COMMON_CFG_ENA_FLOOP
,
72 HSIO_S1G_COMMON_CFG_ENA_LANE
);
74 regmap_update_bits(regmap
, HSIO_S1G_PLL_CFG
,
75 HSIO_S1G_PLL_CFG_PLL_FSM_ENA
|
76 HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M
,
77 HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(200) |
78 HSIO_S1G_PLL_CFG_PLL_FSM_ENA
);
80 regmap_update_bits(regmap
, HSIO_S1G_MISC_CFG
,
81 HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA
|
82 HSIO_S1G_MISC_CFG_LANE_RST
,
83 HSIO_S1G_MISC_CFG_LANE_RST
);
85 ret
= serdes_commit_mcb_s1g(regmap
, serdes
);
89 regmap_update_bits(regmap
, HSIO_S1G_COMMON_CFG
,
90 HSIO_S1G_COMMON_CFG_SYS_RST
,
91 HSIO_S1G_COMMON_CFG_SYS_RST
);
93 regmap_update_bits(regmap
, HSIO_S1G_MISC_CFG
,
94 HSIO_S1G_MISC_CFG_LANE_RST
, 0);
96 ret
= serdes_commit_mcb_s1g(regmap
, serdes
);
111 #define SERDES_MUX(_idx, _port, _mode, _mask, _mux) { \
119 #define SERDES_MUX_SGMII(i, p, m, c) SERDES_MUX(i, p, PHY_MODE_SGMII, m, c)
120 #define SERDES_MUX_QSGMII(i, p, m, c) SERDES_MUX(i, p, PHY_MODE_QSGMII, m, c)
122 static const struct serdes_mux ocelot_serdes_muxes
[] = {
123 SERDES_MUX_SGMII(SERDES1G(0), 0, 0, 0),
124 SERDES_MUX_SGMII(SERDES1G(1), 1, HSIO_HW_CFG_DEV1G_5_MODE
, 0),
125 SERDES_MUX_SGMII(SERDES1G(1), 5, HSIO_HW_CFG_QSGMII_ENA
|
126 HSIO_HW_CFG_DEV1G_5_MODE
, HSIO_HW_CFG_DEV1G_5_MODE
),
127 SERDES_MUX_SGMII(SERDES1G(2), 2, HSIO_HW_CFG_DEV1G_4_MODE
, 0),
128 SERDES_MUX_SGMII(SERDES1G(2), 4, HSIO_HW_CFG_QSGMII_ENA
|
129 HSIO_HW_CFG_DEV1G_4_MODE
, HSIO_HW_CFG_DEV1G_4_MODE
),
130 SERDES_MUX_SGMII(SERDES1G(3), 3, HSIO_HW_CFG_DEV1G_6_MODE
, 0),
131 SERDES_MUX_SGMII(SERDES1G(3), 6, HSIO_HW_CFG_QSGMII_ENA
|
132 HSIO_HW_CFG_DEV1G_6_MODE
, HSIO_HW_CFG_DEV1G_6_MODE
),
133 SERDES_MUX_SGMII(SERDES1G(4), 4, HSIO_HW_CFG_QSGMII_ENA
|
134 HSIO_HW_CFG_DEV1G_4_MODE
| HSIO_HW_CFG_DEV1G_9_MODE
,
136 SERDES_MUX_SGMII(SERDES1G(4), 9, HSIO_HW_CFG_DEV1G_4_MODE
|
137 HSIO_HW_CFG_DEV1G_9_MODE
, HSIO_HW_CFG_DEV1G_4_MODE
|
138 HSIO_HW_CFG_DEV1G_9_MODE
),
139 SERDES_MUX_SGMII(SERDES1G(5), 5, HSIO_HW_CFG_QSGMII_ENA
|
140 HSIO_HW_CFG_DEV1G_5_MODE
| HSIO_HW_CFG_DEV2G5_10_MODE
,
142 SERDES_MUX_SGMII(SERDES1G(5), 10, HSIO_HW_CFG_PCIE_ENA
|
143 HSIO_HW_CFG_DEV1G_5_MODE
| HSIO_HW_CFG_DEV2G5_10_MODE
,
144 HSIO_HW_CFG_DEV1G_5_MODE
| HSIO_HW_CFG_DEV2G5_10_MODE
),
145 SERDES_MUX_QSGMII(SERDES6G(0), 4, HSIO_HW_CFG_QSGMII_ENA
,
146 HSIO_HW_CFG_QSGMII_ENA
),
147 SERDES_MUX_QSGMII(SERDES6G(0), 5, HSIO_HW_CFG_QSGMII_ENA
,
148 HSIO_HW_CFG_QSGMII_ENA
),
149 SERDES_MUX_QSGMII(SERDES6G(0), 6, HSIO_HW_CFG_QSGMII_ENA
,
150 HSIO_HW_CFG_QSGMII_ENA
),
151 SERDES_MUX_SGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA
, 0),
152 SERDES_MUX_QSGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA
,
153 HSIO_HW_CFG_QSGMII_ENA
),
154 SERDES_MUX_SGMII(SERDES6G(1), 8, 0, 0),
155 SERDES_MUX_SGMII(SERDES6G(2), 10, HSIO_HW_CFG_PCIE_ENA
|
156 HSIO_HW_CFG_DEV2G5_10_MODE
, 0),
157 SERDES_MUX(SERDES6G(2), 10, PHY_MODE_PCIE
, HSIO_HW_CFG_PCIE_ENA
,
158 HSIO_HW_CFG_PCIE_ENA
),
161 static int serdes_set_mode(struct phy
*phy
, enum phy_mode mode
)
163 struct serdes_macro
*macro
= phy_get_drvdata(phy
);
167 for (i
= 0; i
< ARRAY_SIZE(ocelot_serdes_muxes
); i
++) {
168 if (macro
->idx
!= ocelot_serdes_muxes
[i
].idx
||
169 mode
!= ocelot_serdes_muxes
[i
].mode
)
172 if (mode
!= PHY_MODE_QSGMII
&&
173 macro
->port
!= ocelot_serdes_muxes
[i
].port
)
176 ret
= regmap_update_bits(macro
->ctrl
->regs
, HSIO_HW_CFG
,
177 ocelot_serdes_muxes
[i
].mask
,
178 ocelot_serdes_muxes
[i
].mux
);
182 if (macro
->idx
<= SERDES1G_MAX
)
183 return serdes_init_s1g(macro
->ctrl
->regs
, macro
->idx
);
185 /* SERDES6G and PCIe not supported yet */
192 static const struct phy_ops serdes_ops
= {
193 .set_mode
= serdes_set_mode
,
194 .owner
= THIS_MODULE
,
197 static struct phy
*serdes_simple_xlate(struct device
*dev
,
198 struct of_phandle_args
*args
)
200 struct serdes_ctrl
*ctrl
= dev_get_drvdata(dev
);
201 unsigned int port
, idx
, i
;
203 if (args
->args_count
!= 2)
204 return ERR_PTR(-EINVAL
);
206 port
= args
->args
[0];
209 for (i
= 0; i
< SERDES_MAX
; i
++) {
210 struct serdes_macro
*macro
= phy_get_drvdata(ctrl
->phys
[i
]);
212 if (idx
!= macro
->idx
)
215 /* SERDES6G(0) is the only SerDes capable of QSGMII */
216 if (idx
!= SERDES6G(0) && macro
->port
>= 0)
217 return ERR_PTR(-EBUSY
);
220 return ctrl
->phys
[i
];
223 return ERR_PTR(-ENODEV
);
226 static int serdes_phy_create(struct serdes_ctrl
*ctrl
, u8 idx
, struct phy
**phy
)
228 struct serdes_macro
*macro
;
230 *phy
= devm_phy_create(ctrl
->dev
, NULL
, &serdes_ops
);
232 return PTR_ERR(*phy
);
234 macro
= devm_kzalloc(ctrl
->dev
, sizeof(*macro
), GFP_KERNEL
);
242 phy_set_drvdata(*phy
, macro
);
247 static int serdes_probe(struct platform_device
*pdev
)
249 struct phy_provider
*provider
;
250 struct serdes_ctrl
*ctrl
;
254 ctrl
= devm_kzalloc(&pdev
->dev
, sizeof(*ctrl
), GFP_KERNEL
);
258 ctrl
->dev
= &pdev
->dev
;
259 ctrl
->regs
= syscon_node_to_regmap(pdev
->dev
.parent
->of_node
);
260 if (IS_ERR(ctrl
->regs
))
261 return PTR_ERR(ctrl
->regs
);
263 for (i
= 0; i
< SERDES_MAX
; i
++) {
264 ret
= serdes_phy_create(ctrl
, i
, &ctrl
->phys
[i
]);
269 dev_set_drvdata(&pdev
->dev
, ctrl
);
271 provider
= devm_of_phy_provider_register(ctrl
->dev
,
272 serdes_simple_xlate
);
274 return PTR_ERR_OR_ZERO(provider
);
277 static const struct of_device_id serdes_ids
[] = {
278 { .compatible
= "mscc,vsc7514-serdes", },
281 MODULE_DEVICE_TABLE(of
, serdes_ids
);
283 static struct platform_driver mscc_ocelot_serdes
= {
284 .probe
= serdes_probe
,
286 .name
= "mscc,ocelot-serdes",
287 .of_match_table
= of_match_ptr(serdes_ids
),
291 module_platform_driver(mscc_ocelot_serdes
);
293 MODULE_AUTHOR("Quentin Schulz <quentin.schulz@bootlin.com>");
294 MODULE_DESCRIPTION("SerDes driver for Microsemi Ocelot");
295 MODULE_LICENSE("Dual MIT/GPL");