xref: /linux/drivers/net/mdio/mdio-pic64hpsc.c (revision c4dde411bc366f568dbe33366253bbfea049e8ea)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Microchip PIC64-HPSC/HX MDIO controller driver
3  *
4  * Copyright (c) 2026 Microchip Technology Inc. and its subsidiaries.
5  */
6 
7 #include <linux/bitops.h>
8 #include <linux/clk.h>
9 #include <linux/io.h>
10 #include <linux/iopoll.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/of_mdio.h>
14 #include <linux/platform_device.h>
15 
16 #define MDIO_REG_PRESCALER     0x20
17 #define MDIO_CFG_PRESCALE_MASK GENMASK(7, 0)
18 
19 #define MDIO_REG_FRAME_CFG_1 0x24
20 #define MDIO_WDATA_MASK	     GENMASK(15, 0)
21 
22 #define MDIO_REG_FRAME_CFG_2	 0x28
23 #define MDIO_TRIGGER_BIT	 BIT(31)
24 #define MDIO_REG_DEV_ADDR_MASK	 GENMASK(20, 16)
25 #define MDIO_PHY_PRT_ADDR_MASK	 GENMASK(8, 4)
26 #define MDIO_OPERATION_MASK	 GENMASK(3, 2)
27 #define MDIO_START_OF_FRAME_MASK GENMASK(1, 0)
28 
29 /* Possible value of MDIO_OPERATION_MASK */
30 #define MDIO_OPERATION_WRITE BIT(0)
31 #define MDIO_OPERATION_READ  BIT(1)
32 
33 #define MDIO_REG_FRAME_STATUS 0x2C
34 #define MDIO_READOK_BIT	      BIT(24)
35 #define MDIO_RDATA_MASK	      GENMASK(15, 0)
36 
37 struct pic64hpsc_mdio_dev {
38 	void __iomem *regs;
39 };
40 
41 static int pic64hpsc_mdio_wait_trigger(struct mii_bus *bus)
42 {
43 	struct pic64hpsc_mdio_dev *priv = bus->priv;
44 	u32 val;
45 	int ret;
46 
47 	/* The MDIO_TRIGGER bit returns 0 when a transaction has completed. */
48 	ret = readl_poll_timeout(priv->regs + MDIO_REG_FRAME_CFG_2, val,
49 				 !(val & MDIO_TRIGGER_BIT), 50, 10000);
50 
51 	if (ret < 0)
52 		dev_dbg(&bus->dev, "TRIGGER bit timeout: %x\n", val);
53 
54 	return ret;
55 }
56 
57 static int pic64hpsc_mdio_c22_read(struct mii_bus *bus, int mii_id, int regnum)
58 {
59 	struct pic64hpsc_mdio_dev *priv = bus->priv;
60 	u32 val;
61 	int ret;
62 
63 	ret = pic64hpsc_mdio_wait_trigger(bus);
64 	if (ret)
65 		return ret;
66 
67 	writel(MDIO_TRIGGER_BIT | FIELD_PREP(MDIO_REG_DEV_ADDR_MASK, regnum) |
68 		       FIELD_PREP(MDIO_PHY_PRT_ADDR_MASK, mii_id) |
69 		       FIELD_PREP(MDIO_OPERATION_MASK, MDIO_OPERATION_READ) |
70 		       FIELD_PREP(MDIO_START_OF_FRAME_MASK, 1),
71 	       priv->regs + MDIO_REG_FRAME_CFG_2);
72 
73 	ret = pic64hpsc_mdio_wait_trigger(bus);
74 	if (ret)
75 		return ret;
76 
77 	val = readl(priv->regs + MDIO_REG_FRAME_STATUS);
78 
79 	/* The MDIO_READOK is a 1-bit value reflecting the inverse of the MDIO
80 	 * bus value captured during the 2nd TA cycle. A PHY/Port should drive
81 	 * the MDIO bus with a logic 0 on the 2nd TA cycle, however, the
82 	 * PHY/Port could optionally drive a logic 1, to communicate a read
83 	 * failure. This feature is optional, not defined by the 802.3 standard
84 	 * and not supported in standard external PHYs.
85 	 */
86 	if (!(bus->phy_ignore_ta_mask & 1 << mii_id) &&
87 	    !FIELD_GET(MDIO_READOK_BIT, val)) {
88 		dev_dbg(&bus->dev, "READOK bit cleared\n");
89 		return -EIO;
90 	}
91 
92 	return FIELD_GET(MDIO_RDATA_MASK, val);
93 }
94 
95 static int pic64hpsc_mdio_c22_write(struct mii_bus *bus, int mii_id, int regnum,
96 				    u16 value)
97 {
98 	struct pic64hpsc_mdio_dev *priv = bus->priv;
99 	int ret;
100 
101 	ret = pic64hpsc_mdio_wait_trigger(bus);
102 	if (ret < 0)
103 		return ret;
104 
105 	writel(FIELD_PREP(MDIO_WDATA_MASK, value),
106 	       priv->regs + MDIO_REG_FRAME_CFG_1);
107 
108 	writel(MDIO_TRIGGER_BIT | FIELD_PREP(MDIO_REG_DEV_ADDR_MASK, regnum) |
109 		       FIELD_PREP(MDIO_PHY_PRT_ADDR_MASK, mii_id) |
110 		       FIELD_PREP(MDIO_OPERATION_MASK, MDIO_OPERATION_WRITE) |
111 		       FIELD_PREP(MDIO_START_OF_FRAME_MASK, 1),
112 	       priv->regs + MDIO_REG_FRAME_CFG_2);
113 
114 	return 0;
115 }
116 
117 static int pic64hpsc_mdio_probe(struct platform_device *pdev)
118 {
119 	struct device_node *np = pdev->dev.of_node;
120 	struct device *dev = &pdev->dev;
121 	struct pic64hpsc_mdio_dev *priv;
122 	struct mii_bus *bus;
123 	unsigned long rate;
124 	struct clk *clk;
125 	u32 bus_freq;
126 	u32 div;
127 	int ret;
128 
129 	bus = devm_mdiobus_alloc_size(dev, sizeof(*priv));
130 	if (!bus)
131 		return -ENOMEM;
132 
133 	priv = bus->priv;
134 
135 	priv->regs = devm_platform_ioremap_resource(pdev, 0);
136 	if (IS_ERR(priv->regs))
137 		return PTR_ERR(priv->regs);
138 
139 	bus->name = KBUILD_MODNAME;
140 	bus->read = pic64hpsc_mdio_c22_read;
141 	bus->write = pic64hpsc_mdio_c22_write;
142 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
143 	bus->parent = dev;
144 
145 	clk = devm_clk_get_enabled(dev, NULL);
146 	if (IS_ERR(clk))
147 		return PTR_ERR(clk);
148 
149 	if (of_property_read_u32(np, "clock-frequency", &bus_freq))
150 		bus_freq = 2500000;
151 
152 	rate = clk_get_rate(clk);
153 
154 	div = DIV_ROUND_UP(rate, 2 * bus_freq) - 1;
155 	if (div == 0 || div & ~MDIO_CFG_PRESCALE_MASK) {
156 		dev_err(dev, "MDIO clock-frequency out of range\n");
157 		return -EINVAL;
158 	}
159 
160 	dev_dbg(dev, "rate=%lu bus_freq=%u real_bus_freq=%lu div=%u\n", rate,
161 		bus_freq, rate / (2 * (1 + div)), div);
162 	writel(div, priv->regs + MDIO_REG_PRESCALER);
163 
164 	ret = devm_of_mdiobus_register(dev, bus, np);
165 	if (ret) {
166 		dev_err(dev, "Cannot register MDIO bus (%d)\n", ret);
167 		return ret;
168 	}
169 
170 	return 0;
171 }
172 
173 static const struct of_device_id pic64hpsc_mdio_match[] = {
174 	{ .compatible = "microchip,pic64hpsc-mdio" },
175 	{}
176 };
177 MODULE_DEVICE_TABLE(of, pic64hpsc_mdio_match);
178 
179 static struct platform_driver pic64hpsc_mdio_driver = {
180 	.probe = pic64hpsc_mdio_probe,
181 	.driver = {
182 		.name = KBUILD_MODNAME,
183 		.of_match_table = pic64hpsc_mdio_match,
184 	},
185 };
186 module_platform_driver(pic64hpsc_mdio_driver);
187 
188 MODULE_AUTHOR("Charles Perry <charles.perry@microchip.com>");
189 MODULE_DESCRIPTION("Microchip PIC64-HPSC/HX MDIO driver");
190 MODULE_LICENSE("GPL");
191