xref: /linux/drivers/net/pcs/pcs-xpcs-rk.c (revision e7cccfde61367452e9a43257a57eef0a95e7a6bf)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Rockchip XPCS platform device driver
4  *
5  * Based on the Synopsys DesignWare XPCS platform driver.
6  * Copyright (C) 2024 Serge Semin
7  *
8  * Adapted for Rockchip SoCs, with reference to the Rockchip OEM driver.
9  * Copyright (C) 2026 Coia Prant
10  */
11 
12 #include <linux/atomic.h>
13 #include <linux/bitfield.h>
14 #include <linux/clk.h>
15 #include <linux/device.h>
16 #include <linux/io.h>
17 #include <linux/iopoll.h>
18 #include <linux/math.h>
19 #include <linux/mdio.h>
20 #include <linux/module.h>
21 #include <linux/of.h>
22 #include <linux/of_platform.h>
23 #include <linux/pcs/pcs-xpcs-rk.h>
24 #include <linux/phy.h>
25 #include <linux/phy/phy.h>
26 #include <linux/platform_device.h>
27 #include <linux/pm_domain.h>
28 #include <linux/pm_runtime.h>
29 #include <linux/property.h>
30 #include <linux/sizes.h>
31 #include <linux/time.h>
32 
33 #include "pcs-xpcs.h"
34 
35 struct dw_xpcs_rk {
36 	struct platform_device *pdev;
37 	struct mii_bus *bus;
38 	void __iomem *reg_base;
39 	struct phy *serdes_phy;
40 	struct clk *csr_clk;
41 	struct clk *eee_clk;
42 	u8 eee_mult_fact;
43 };
44 
45 static ptrdiff_t xpcs_rk_addr_format(int dev, int reg)
46 {
47 	return FIELD_PREP(0x70000, dev) | FIELD_PREP(0xffff, reg);
48 }
49 
50 static int xpcs_rk_read_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg)
51 {
52 	ptrdiff_t csr;
53 	int ret;
54 
55 	csr = xpcs_rk_addr_format(dev, reg);
56 
57 	ret = pm_runtime_resume_and_get(&pxpcs->pdev->dev);
58 	if (ret)
59 		return ret;
60 
61 	ret = readl(pxpcs->reg_base + (csr << 2)) & 0xffff;
62 
63 	pm_runtime_put(&pxpcs->pdev->dev);
64 	return ret;
65 }
66 
67 static int xpcs_rk_write_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg, u16 val)
68 {
69 	ptrdiff_t csr;
70 	int ret;
71 
72 	csr = xpcs_rk_addr_format(dev, reg);
73 
74 	ret = pm_runtime_resume_and_get(&pxpcs->pdev->dev);
75 	if (ret)
76 		return ret;
77 
78 	writel(val, pxpcs->reg_base + (csr << 2));
79 
80 	pm_runtime_put(&pxpcs->pdev->dev);
81 	return 0;
82 }
83 
84 #define ROCKCHIP_MMD_MII1	2
85 #define ROCKCHIP_MMD_MII2	3
86 #define ROCKCHIP_MMD_MII3	4
87 #define ROCKCHIP_MMD_PMAPMD	6
88 #define ROCKCHIP_MMD_MII	7
89 
90 static bool xpcs_rk_mdio_addr_validate(int addr)
91 {
92 	return !(addr < 0 || addr > 3);
93 }
94 
95 static int xpcs_rk_mdio_read_remapping(int addr, int dev)
96 {
97 	switch (dev) {
98 	case MDIO_MMD_PMAPMD:
99 		return ROCKCHIP_MMD_PMAPMD;
100 	case MDIO_MMD_VEND2:
101 		break;
102 	default:
103 		return -ENXIO;
104 	}
105 
106 	/*
107 	 * Reads are redirected by hardware to the port's read-only mirror;
108 	 * only writes have to be targeted at MII (see the write path).
109 	 */
110 	switch (addr) {
111 	case 0:
112 		return ROCKCHIP_MMD_MII;
113 	case 1:
114 		return ROCKCHIP_MMD_MII1;
115 	case 2:
116 		return ROCKCHIP_MMD_MII2;
117 	case 3:
118 		return ROCKCHIP_MMD_MII3;
119 	default:
120 		return -ENODEV;
121 	}
122 }
123 
124 static int xpcs_rk_mdio_write_remapping(int addr, int dev, int reg)
125 {
126 	switch (dev) {
127 	case MDIO_MMD_PMAPMD:
128 		return ROCKCHIP_MMD_PMAPMD;
129 	case MDIO_MMD_VEND2:
130 		break;
131 	default:
132 		return -ENXIO;
133 	}
134 
135 	/*
136 	 * These registers physically live only in MII (the management port).
137 	 * Ports 1-3 expose read-only mirrors of these bits, so writes must
138 	 * always target MII; the read path remaps per address and the
139 	 * hardware redirects to the port's mirror.
140 	 */
141 	switch (reg) {
142 	case DW_VR_MII_AN_CTRL:
143 	case DW_VR_MII_AN_INTR_STS:
144 	case DW_VR_MII_EEE_MCTRL0:
145 	case DW_VR_MII_EEE_MCTRL1:
146 	case DW_VR_MII_DIG_CTRL2:
147 		return ROCKCHIP_MMD_MII;
148 	default:
149 		break;
150 	}
151 
152 	switch (addr) {
153 	case 0:
154 		return ROCKCHIP_MMD_MII;
155 	case 1:
156 		return ROCKCHIP_MMD_MII1;
157 	case 2:
158 		return ROCKCHIP_MMD_MII2;
159 	case 3:
160 		return ROCKCHIP_MMD_MII3;
161 	default:
162 		return -ENODEV;
163 	}
164 }
165 
166 static int xpcs_rk_read_c22(struct mii_bus *bus, int addr, int reg)
167 {
168 	struct dw_xpcs_rk *pxpcs = bus->priv;
169 	int dev;
170 
171 	if (!xpcs_rk_mdio_addr_validate(addr))
172 		return -ENODEV;
173 
174 	dev = xpcs_rk_mdio_read_remapping(addr, MDIO_MMD_VEND2);
175 	if (dev < 0)
176 		return 0xffff;
177 
178 	return xpcs_rk_read_reg(pxpcs, dev, reg);
179 }
180 
181 static int xpcs_rk_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)
182 {
183 	struct dw_xpcs_rk *pxpcs = bus->priv;
184 	int dev;
185 
186 	if (!xpcs_rk_mdio_addr_validate(addr))
187 		return -ENODEV;
188 
189 	dev = xpcs_rk_mdio_write_remapping(addr, MDIO_MMD_VEND2, reg);
190 	if (dev < 0)
191 		return 0;
192 
193 	return xpcs_rk_write_reg(pxpcs, dev, reg, val);
194 }
195 
196 static int xpcs_rk_read_c45(struct mii_bus *bus, int addr, int dev, int reg)
197 {
198 	struct dw_xpcs_rk *pxpcs = bus->priv;
199 
200 	if (!xpcs_rk_mdio_addr_validate(addr))
201 		return -ENODEV;
202 
203 	dev = xpcs_rk_mdio_read_remapping(addr, dev);
204 	if (dev < 0)
205 		return 0xffff;
206 
207 	return xpcs_rk_read_reg(pxpcs, dev, reg);
208 }
209 
210 static int xpcs_rk_write_c45(struct mii_bus *bus, int addr, int dev, int reg, u16 val)
211 {
212 	struct dw_xpcs_rk *pxpcs = bus->priv;
213 
214 	if (!xpcs_rk_mdio_addr_validate(addr))
215 		return -ENODEV;
216 
217 	dev = xpcs_rk_mdio_write_remapping(addr, dev, reg);
218 	if (dev < 0)
219 		return 0;
220 
221 	return xpcs_rk_write_reg(pxpcs, dev, reg, val);
222 }
223 
224 static struct dw_xpcs_rk *xpcs_rk_create_data(struct platform_device *pdev)
225 {
226 	struct dw_xpcs_rk *pxpcs;
227 
228 	pxpcs = devm_kzalloc(&pdev->dev, sizeof(*pxpcs), GFP_KERNEL);
229 	if (!pxpcs)
230 		return ERR_PTR(-ENOMEM);
231 
232 	pxpcs->pdev = pdev;
233 
234 	dev_set_drvdata(&pdev->dev, pxpcs);
235 
236 	return pxpcs;
237 }
238 
239 static int xpcs_rk_serdes_phy_init(struct dw_xpcs_rk *pxpcs)
240 {
241 	struct device *dev = &pxpcs->pdev->dev;
242 
243 	pxpcs->serdes_phy = devm_phy_get(dev, NULL);
244 	if (IS_ERR(pxpcs->serdes_phy))
245 		return dev_err_probe(dev, PTR_ERR(pxpcs->serdes_phy),
246 					"Failed to get SerDes PHY\n");
247 
248 	return 0;
249 }
250 
251 static void xpcs_rk_serdes_phy_poweroff(void *data)
252 {
253 	struct dw_xpcs_rk *pxpcs = data;
254 	struct device *dev = &pxpcs->pdev->dev;
255 
256 	phy_power_off(pxpcs->serdes_phy);
257 	phy_exit(pxpcs->serdes_phy);
258 
259 	dev_pm_genpd_rpm_always_on(dev, false);
260 }
261 
262 static int xpcs_rk_serdes_phy_poweron(struct dw_xpcs_rk *pxpcs)
263 {
264 	struct device *dev = &pxpcs->pdev->dev;
265 	int ret;
266 
267 	/*
268 	 * The power domain is required and must be enabled, which allows us to
269 	 * dynamically turn the CSR clock on/off using PM while keeping the PCS
270 	 * powered on.
271 	 */
272 	ret = dev_pm_genpd_rpm_always_on(dev, true);
273 	if (ret) {
274 		dev_err(dev, "Failed to power on power-domains\n");
275 		return ret;
276 	}
277 
278 	ret = phy_init(pxpcs->serdes_phy);
279 	if (ret) {
280 		dev_err(dev, "Failed to init SerDes PHY\n");
281 		goto pm_domain;
282 	}
283 
284 	ret = phy_power_on(pxpcs->serdes_phy);
285 	if (ret) {
286 		dev_err(dev, "Failed to power on SerDes PHY\n");
287 		goto serdes_phy;
288 	}
289 
290 	ret = devm_add_action_or_reset(dev, xpcs_rk_serdes_phy_poweroff, pxpcs);
291 	if (ret) {
292 		dev_err(dev, "Failed to register devm for SerDes PHY: %d\n", ret);
293 		return ret;
294 	}
295 
296 	return 0;
297 
298 serdes_phy:
299 	phy_exit(pxpcs->serdes_phy);
300 pm_domain:
301 	dev_pm_genpd_rpm_always_on(dev, false);
302 	return ret;
303 }
304 
305 static int xpcs_rk_init_res(struct dw_xpcs_rk *pxpcs)
306 {
307 	struct platform_device *pdev = pxpcs->pdev;
308 	struct device *dev = &pdev->dev;
309 	struct resource *res;
310 
311 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
312 	if (!res) {
313 		dev_err(dev, "No reg-space found\n");
314 		return -EINVAL;
315 	}
316 
317 	if (resource_size(res) < SZ_2M) {
318 		dev_err(dev, "Invalid reg-space size\n");
319 		return -EINVAL;
320 	}
321 
322 	pxpcs->reg_base = devm_ioremap_resource(dev, res);
323 	if (IS_ERR(pxpcs->reg_base)) {
324 		dev_err(dev, "Failed to map reg-space\n");
325 		return PTR_ERR(pxpcs->reg_base);
326 	}
327 
328 	return 0;
329 }
330 
331 static void xpcs_rk_exit_clk(void *data)
332 {
333 	struct dw_xpcs_rk *pxpcs = data;
334 	struct device *dev = &pxpcs->pdev->dev;
335 
336 	pm_runtime_force_suspend(dev);
337 	clk_disable_unprepare(pxpcs->eee_clk);
338 }
339 
340 static int xpcs_rk_init_clk(struct dw_xpcs_rk *pxpcs)
341 {
342 	struct device *dev = &pxpcs->pdev->dev;
343 	unsigned long rate;
344 	u64 mult;
345 	int ret;
346 
347 	pxpcs->csr_clk = devm_clk_get(dev, "csr");
348 	if (IS_ERR(pxpcs->csr_clk))
349 		return dev_err_probe(dev, PTR_ERR(pxpcs->csr_clk),
350 					 "Failed to get CSR clock\n");
351 
352 	pxpcs->eee_clk = devm_clk_get(dev, "eee");
353 	if (IS_ERR(pxpcs->eee_clk))
354 		return dev_err_probe(dev, PTR_ERR(pxpcs->eee_clk),
355 					 "Failed to get EEE clock\n");
356 
357 	ret = clk_prepare_enable(pxpcs->eee_clk);
358 	if (ret) {
359 		dev_err(dev, "Failed to enable EEE clock\n");
360 		return ret;
361 	}
362 
363 	pm_runtime_set_suspended(dev);
364 	pm_runtime_enable(dev);
365 
366 	ret = devm_add_action_or_reset(dev, xpcs_rk_exit_clk, pxpcs);
367 	if (ret) {
368 		dev_err(dev, "Failed to register devm for xpcs_rk_exit_clk: %d\n", ret);
369 		return ret;
370 	}
371 
372 	/*
373 	 * Compute the multiplier for the EEE clock so that
374 	 * clk_eee_period * (mult_fact + 1) falls within 80..120 ns.
375 	 *
376 	 * On RK3568, clk_xpcs_eee is muxed between gpll200 (200 MHz, 5 ns)
377 	 * and cpll125 (125 MHz, 8 ns), selected by CRU_CLKSEL_CON29 bit 13.
378 	 * The reset value is 0 (200 MHz), but derive the value at runtime to
379 	 * stay correct if the mux is changed by a board.
380 	 *
381 	 * Use a 64-bit intermediate: on 32-bit builds, 100 * 200000000
382 	 * does not fit in unsigned long. Clamp to the 4-bit
383 	 * DW_VR_MII_EEE_MULT_FACT_100NS field. The mux only provides
384 	 * 125 MHz or 200 MHz, so the rate cannot drop below the 5 MHz
385 	 * threshold where DIV_ROUND_CLOSEST_ULL() would return 0 and the
386 	 * subtraction below would underflow.
387 	 */
388 	rate = clk_get_rate(pxpcs->eee_clk);
389 	if (!rate)
390 		return dev_err_probe(dev, -EINVAL, "Invalid EEE clock rate\n");
391 
392 	mult = DIV_ROUND_CLOSEST_ULL(100ULL * rate, NSEC_PER_SEC) - 1;
393 	pxpcs->eee_mult_fact = min_t(u64, mult, 15);
394 	return 0;
395 }
396 
397 static int xpcs_rk_init_bus(struct dw_xpcs_rk *pxpcs)
398 {
399 	struct device *dev = &pxpcs->pdev->dev;
400 	static atomic_t id = ATOMIC_INIT(-1);
401 	struct mii_bus *bus;
402 	int ret;
403 
404 	bus = devm_mdiobus_alloc_size(dev, 0);
405 	if (!bus)
406 		return -ENOMEM;
407 
408 	bus->name = "Rockchip DW XPCS MCI/APB3";
409 	bus->read = xpcs_rk_read_c22;
410 	bus->write = xpcs_rk_write_c22;
411 	bus->read_c45 = xpcs_rk_read_c45;
412 	bus->write_c45 = xpcs_rk_write_c45;
413 	bus->phy_mask = ~0;
414 	bus->parent = dev;
415 	bus->priv = pxpcs;
416 
417 	snprintf(bus->id, MII_BUS_ID_SIZE,
418 		 "rockchip_dwxpcs-%x", atomic_inc_return(&id));
419 
420 	/*
421 	 * MDIO-bus here serves as just a back-end engine abstracting out
422 	 * the MDIO and MCI/APB3 IO interfaces utilized for the Rockchip DWXPCS CSRs
423 	 * access.
424 	 */
425 	ret = devm_mdiobus_register(dev, bus);
426 	if (ret) {
427 		dev_err(dev, "Failed to create MDIO bus\n");
428 		return ret;
429 	}
430 
431 	pxpcs->bus = bus;
432 	return 0;
433 }
434 
435 static int xpcs_rk_probe(struct platform_device *pdev)
436 {
437 	struct dw_xpcs_rk *pxpcs;
438 	int ret;
439 
440 	pxpcs = xpcs_rk_create_data(pdev);
441 	if (IS_ERR(pxpcs))
442 		return PTR_ERR(pxpcs);
443 
444 	/*
445 	 * The XPCS lives in the PD_PIPE power domain. The domain must be
446 	 * powered on before any register access, otherwise the SoC will
447 	 * trigger a synchronous external abort (SError).
448 	 *
449 	 * Accessing the XPCS registers also requires a TX clock from the
450 	 * SerDes, which is needed for the soft reset.
451 	 */
452 	ret = xpcs_rk_serdes_phy_init(pxpcs);
453 	if (ret)
454 		return ret;
455 
456 	ret = xpcs_rk_serdes_phy_poweron(pxpcs);
457 	if (ret)
458 		return ret;
459 
460 	ret = xpcs_rk_init_res(pxpcs);
461 	if (ret)
462 		return ret;
463 
464 	ret = xpcs_rk_init_clk(pxpcs);
465 	if (ret)
466 		return ret;
467 
468 	ret = xpcs_rk_init_bus(pxpcs);
469 	if (ret)
470 		return ret;
471 
472 	return 0;
473 }
474 
475 static const struct of_device_id xpcs_rk_of_ids[] = {
476 	{ .compatible = "rockchip,rk3568-xpcs" },
477 	{ /* sentinel */ },
478 };
479 MODULE_DEVICE_TABLE(of, xpcs_rk_of_ids);
480 
481 struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *pcs, int port)
482 {
483 	struct platform_device *pdev;
484 	struct dw_xpcs_rk *pxpcs;
485 	struct dw_xpcs *xpcs;
486 
487 	if (!of_device_is_available(pcs))
488 		return ERR_PTR(-ENODEV);
489 
490 	if (!of_match_node(xpcs_rk_of_ids, pcs))
491 		return ERR_PTR(-EINVAL);
492 
493 	if (!xpcs_rk_mdio_addr_validate(port))
494 		return ERR_PTR(-EINVAL);
495 
496 	pdev = of_find_device_by_node(pcs);
497 	if (!pdev)
498 		return ERR_PTR(-EPROBE_DEFER);
499 
500 	/*
501 	 * Establish the device link before reading the supplier's drvdata.
502 	 * device_link_add() does not fail on a supplier that is unbinding;
503 	 * it creates the link in DL_STATE_SUPPLIER_UNBIND.
504 	 *
505 	 * The check below only confirms that the supplier is bound at this
506 	 * point. It does not fully protect against a concurrent unbind
507 	 * between here and xpcs_create_mdiodev(); closing that window would
508 	 * require reading a managed link's status or device_lock(), neither
509 	 * of which is acceptable on this path. The window is small and
510 	 * requires an explicit unbind from userspace. Discussed on
511 	 * driver-core.
512 	 *
513 	 * The link is released automatically when the consumer device is
514 	 * destroyed (DL_FLAG_AUTOREMOVE_CONSUMER), so no explicit
515 	 * device_link_remove() is needed on the failure paths.
516 	 */
517 	if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) {
518 		put_device(&pdev->dev);
519 		return ERR_PTR(-EPROBE_DEFER);
520 	}
521 
522 	if (READ_ONCE(pdev->dev.links.status) != DL_DEV_DRIVER_BOUND) {
523 		put_device(&pdev->dev);
524 		return ERR_PTR(-EPROBE_DEFER);
525 	}
526 
527 	pxpcs = platform_get_drvdata(pdev);
528 	if (!pxpcs || !pxpcs->bus) {
529 		put_device(&pdev->dev);
530 		return ERR_PTR(-EPROBE_DEFER);
531 	}
532 
533 	xpcs = xpcs_create_mdiodev(pxpcs->bus, port);
534 	if (IS_ERR(xpcs)) {
535 		put_device(&pdev->dev);
536 		return xpcs;
537 	}
538 
539 	xpcs_config_eee_mult_fact(xpcs, pxpcs->eee_mult_fact);
540 	put_device(&pdev->dev);
541 	return xpcs;
542 }
543 EXPORT_SYMBOL_GPL(xpcs_rk_create);
544 
545 static int xpcs_rk_pm_runtime_suspend(struct device *dev)
546 {
547 	struct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);
548 
549 	clk_disable_unprepare(pxpcs->csr_clk);
550 
551 	return 0;
552 }
553 
554 static int xpcs_rk_pm_runtime_resume(struct device *dev)
555 {
556 	struct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);
557 
558 	return clk_prepare_enable(pxpcs->csr_clk);
559 }
560 
561 static int xpcs_rk_system_suspend(struct device *dev)
562 {
563 	/*
564 	 * Keep the PD_PIPE power domain on during system suspend.
565 	 *
566 	 * PD_PIPE is shared with SATA/PCIe and would be powered down by
567 	 * genpd once all its consumers are suspended, killing the SerDes
568 	 * and breaking MAC WoL.  Mark the XPCS as part of the wakeup path
569 	 * so genpd keeps the domain on.  Unconditional because the XPCS
570 	 * core has no callback to convey the MAC WoL state.
571 	 */
572 	device_set_wakeup_path(dev);
573 	return 0;
574 }
575 
576 static int xpcs_rk_system_resume(struct device *dev)
577 {
578 	return 0;
579 }
580 
581 static _DEFINE_DEV_PM_OPS(xpcs_rk_pm_ops,
582 			  xpcs_rk_system_suspend, xpcs_rk_system_resume,
583 			  xpcs_rk_pm_runtime_suspend, xpcs_rk_pm_runtime_resume,
584 			  NULL);
585 
586 static struct platform_driver xpcs_rk_driver = {
587 	.probe = xpcs_rk_probe,
588 	.driver = {
589 		.name = "rk_xpcs-dwxpcs",
590 		.pm = pm_ptr(&xpcs_rk_pm_ops),
591 		.of_match_table = xpcs_rk_of_ids,
592 	},
593 };
594 module_platform_driver(xpcs_rk_driver);
595 
596 MODULE_DESCRIPTION("Rockchip XPCS platform device driver");
597 MODULE_AUTHOR("Coia Prant <coiaprant@gmail.com>");
598 MODULE_LICENSE("GPL");
599