xref: /linux/drivers/net/mdio/mdio-ipq4019.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright (c) 2015, The Linux Foundation. All rights reserved. */
3 /* Copyright (c) 2020 Sartura Ltd. */
4 
5 #include <linux/delay.h>
6 #include <linux/io.h>
7 #include <linux/iopoll.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/of_address.h>
11 #include <linux/of_mdio.h>
12 #include <linux/phy.h>
13 #include <linux/platform_device.h>
14 #include <linux/clk.h>
15 
16 #define MDIO_MODE_REG				0x40
17 #define   MDIO_MODE_MDC_MODE			BIT(12)
18 /* 0 = Clause 22, 1 = Clause 45 */
19 #define   MDIO_MODE_C45				BIT(8)
20 #define   MDIO_MODE_DIV_MASK			GENMASK(7, 0)
21 #define     MDIO_MODE_DIV(x)			FIELD_PREP(MDIO_MODE_DIV_MASK, (x) - 1)
22 #define     MDIO_MODE_DIV_1			0x0
23 #define     MDIO_MODE_DIV_2			0x1
24 #define     MDIO_MODE_DIV_4			0x3
25 #define     MDIO_MODE_DIV_8			0x7
26 #define     MDIO_MODE_DIV_16			0xf
27 #define     MDIO_MODE_DIV_32			0x1f
28 #define     MDIO_MODE_DIV_64			0x3f
29 #define     MDIO_MODE_DIV_128			0x7f
30 #define     MDIO_MODE_DIV_256			0xff
31 #define MDIO_ADDR_REG				0x44
32 #define MDIO_DATA_WRITE_REG			0x48
33 #define MDIO_DATA_READ_REG			0x4c
34 #define MDIO_CMD_REG				0x50
35 #define MDIO_CMD_ACCESS_BUSY		BIT(16)
36 #define MDIO_CMD_ACCESS_START		BIT(8)
37 #define MDIO_CMD_ACCESS_CODE_READ	0
38 #define MDIO_CMD_ACCESS_CODE_WRITE	1
39 #define MDIO_CMD_ACCESS_CODE_C45_ADDR	0
40 #define MDIO_CMD_ACCESS_CODE_C45_WRITE	1
41 #define MDIO_CMD_ACCESS_CODE_C45_READ	2
42 
43 #define IPQ4019_MDIO_TIMEOUT	10000
44 #define IPQ4019_MDIO_SLEEP		10
45 
46 /* MDIO clock source frequency is fixed to 100M */
47 #define IPQ_MDIO_CLK_RATE	100000000
48 
49 #define IPQ_PHY_SET_DELAY_US	100000
50 
51 struct ipq4019_mdio_data {
52 	void __iomem	*membase;
53 	void __iomem *eth_ldo_rdy;
54 	struct clk *mdio_clk;
55 	unsigned int mdc_rate;
56 };
57 
ipq4019_mdio_wait_busy(struct mii_bus * bus)58 static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
59 {
60 	struct ipq4019_mdio_data *priv = bus->priv;
61 	unsigned int busy;
62 
63 	return readl_poll_timeout(priv->membase + MDIO_CMD_REG, busy,
64 				  (busy & MDIO_CMD_ACCESS_BUSY) == 0,
65 				  IPQ4019_MDIO_SLEEP, IPQ4019_MDIO_TIMEOUT);
66 }
67 
ipq4019_mdio_read_c45(struct mii_bus * bus,int mii_id,int mmd,int reg)68 static int ipq4019_mdio_read_c45(struct mii_bus *bus, int mii_id, int mmd,
69 				 int reg)
70 {
71 	struct ipq4019_mdio_data *priv = bus->priv;
72 	unsigned int data;
73 	unsigned int cmd;
74 
75 	if (ipq4019_mdio_wait_busy(bus))
76 		return -ETIMEDOUT;
77 
78 	data = readl(priv->membase + MDIO_MODE_REG);
79 
80 	data |= MDIO_MODE_C45;
81 
82 	writel(data, priv->membase + MDIO_MODE_REG);
83 
84 	/* issue the phy address and mmd */
85 	writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
86 
87 	/* issue reg */
88 	writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
89 
90 	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
91 
92 	/* issue read command */
93 	writel(cmd, priv->membase + MDIO_CMD_REG);
94 
95 	/* Wait read complete */
96 	if (ipq4019_mdio_wait_busy(bus))
97 		return -ETIMEDOUT;
98 
99 	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_READ;
100 
101 	writel(cmd, priv->membase + MDIO_CMD_REG);
102 
103 	if (ipq4019_mdio_wait_busy(bus))
104 		return -ETIMEDOUT;
105 
106 	/* Read and return data */
107 	return readl(priv->membase + MDIO_DATA_READ_REG);
108 }
109 
ipq4019_mdio_read_c22(struct mii_bus * bus,int mii_id,int regnum)110 static int ipq4019_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
111 {
112 	struct ipq4019_mdio_data *priv = bus->priv;
113 	unsigned int data;
114 	unsigned int cmd;
115 
116 	if (ipq4019_mdio_wait_busy(bus))
117 		return -ETIMEDOUT;
118 
119 	data = readl(priv->membase + MDIO_MODE_REG);
120 
121 	data &= ~MDIO_MODE_C45;
122 
123 	writel(data, priv->membase + MDIO_MODE_REG);
124 
125 	/* issue the phy address and reg */
126 	writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
127 
128 	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ;
129 
130 	/* issue read command */
131 	writel(cmd, priv->membase + MDIO_CMD_REG);
132 
133 	/* Wait read complete */
134 	if (ipq4019_mdio_wait_busy(bus))
135 		return -ETIMEDOUT;
136 
137 	/* Read and return data */
138 	return readl(priv->membase + MDIO_DATA_READ_REG);
139 }
140 
ipq4019_mdio_write_c45(struct mii_bus * bus,int mii_id,int mmd,int reg,u16 value)141 static int ipq4019_mdio_write_c45(struct mii_bus *bus, int mii_id, int mmd,
142 				  int reg, u16 value)
143 {
144 	struct ipq4019_mdio_data *priv = bus->priv;
145 	unsigned int data;
146 	unsigned int cmd;
147 
148 	if (ipq4019_mdio_wait_busy(bus))
149 		return -ETIMEDOUT;
150 
151 	data = readl(priv->membase + MDIO_MODE_REG);
152 
153 	data |= MDIO_MODE_C45;
154 
155 	writel(data, priv->membase + MDIO_MODE_REG);
156 
157 	/* issue the phy address and mmd */
158 	writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
159 
160 	/* issue reg */
161 	writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
162 
163 	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
164 
165 	writel(cmd, priv->membase + MDIO_CMD_REG);
166 
167 	if (ipq4019_mdio_wait_busy(bus))
168 		return -ETIMEDOUT;
169 
170 	/* issue write data */
171 	writel(value, priv->membase + MDIO_DATA_WRITE_REG);
172 
173 	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_WRITE;
174 	writel(cmd, priv->membase + MDIO_CMD_REG);
175 
176 	/* Wait write complete */
177 	if (ipq4019_mdio_wait_busy(bus))
178 		return -ETIMEDOUT;
179 
180 	return 0;
181 }
182 
ipq4019_mdio_write_c22(struct mii_bus * bus,int mii_id,int regnum,u16 value)183 static int ipq4019_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum,
184 				  u16 value)
185 {
186 	struct ipq4019_mdio_data *priv = bus->priv;
187 	unsigned int data;
188 	unsigned int cmd;
189 
190 	if (ipq4019_mdio_wait_busy(bus))
191 		return -ETIMEDOUT;
192 
193 	/* Enter Clause 22 mode */
194 	data = readl(priv->membase + MDIO_MODE_REG);
195 
196 	data &= ~MDIO_MODE_C45;
197 
198 	writel(data, priv->membase + MDIO_MODE_REG);
199 
200 	/* issue the phy address and reg */
201 	writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
202 
203 	/* issue write data */
204 	writel(value, priv->membase + MDIO_DATA_WRITE_REG);
205 
206 	/* issue write command */
207 	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
208 
209 	writel(cmd, priv->membase + MDIO_CMD_REG);
210 
211 	/* Wait write complete */
212 	if (ipq4019_mdio_wait_busy(bus))
213 		return -ETIMEDOUT;
214 
215 	return 0;
216 }
217 
ipq4019_mdio_set_div(struct ipq4019_mdio_data * priv)218 static int ipq4019_mdio_set_div(struct ipq4019_mdio_data *priv)
219 {
220 	unsigned long ahb_rate;
221 	int div;
222 	u32 val;
223 
224 	/* If we don't have a clock for AHB use the fixed value */
225 	ahb_rate = IPQ_MDIO_CLK_RATE;
226 	if (priv->mdio_clk)
227 		ahb_rate = clk_get_rate(priv->mdio_clk);
228 
229 	/* MDC rate is ahb_rate/(MDIO_MODE_DIV + 1)
230 	 * While supported, internal documentation doesn't
231 	 * assure correct functionality of the MDIO bus
232 	 * with divider of 1, 2 or 4.
233 	 */
234 	for (div = 8; div <= 256; div *= 2) {
235 		/* The requested rate is supported by the div */
236 		if (priv->mdc_rate == DIV_ROUND_UP(ahb_rate, div)) {
237 			val = readl(priv->membase + MDIO_MODE_REG);
238 			val &= ~MDIO_MODE_DIV_MASK;
239 			val |= MDIO_MODE_DIV(div);
240 			writel(val, priv->membase + MDIO_MODE_REG);
241 
242 			return 0;
243 		}
244 	}
245 
246 	/* The requested rate is not supported */
247 	return -EINVAL;
248 }
249 
ipq_mdio_reset(struct mii_bus * bus)250 static int ipq_mdio_reset(struct mii_bus *bus)
251 {
252 	struct ipq4019_mdio_data *priv = bus->priv;
253 	u32 val;
254 	int ret;
255 
256 	/* To indicate CMN_PLL that ethernet_ldo has been ready if platform resource 1
257 	 * is specified in the device tree.
258 	 */
259 	if (priv->eth_ldo_rdy) {
260 		val = readl(priv->eth_ldo_rdy);
261 		val |= BIT(0);
262 		writel(val, priv->eth_ldo_rdy);
263 		fsleep(IPQ_PHY_SET_DELAY_US);
264 	}
265 
266 	/* Configure MDIO clock source frequency if clock is specified in the device tree */
267 	ret = clk_set_rate(priv->mdio_clk, IPQ_MDIO_CLK_RATE);
268 	if (ret)
269 		return ret;
270 
271 	ret = clk_prepare_enable(priv->mdio_clk);
272 	if (ret)
273 		return ret;
274 
275 	mdelay(10);
276 
277 	/* Restore MDC rate */
278 	return ipq4019_mdio_set_div(priv);
279 }
280 
ipq4019_mdio_select_mdc_rate(struct platform_device * pdev,struct ipq4019_mdio_data * priv)281 static void ipq4019_mdio_select_mdc_rate(struct platform_device *pdev,
282 					 struct ipq4019_mdio_data *priv)
283 {
284 	unsigned long ahb_rate;
285 	int div;
286 	u32 val;
287 
288 	/* MDC rate defined in DT, we don't have to decide a default value */
289 	if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
290 				  &priv->mdc_rate))
291 		return;
292 
293 	/* If we don't have a clock for AHB use the fixed value */
294 	ahb_rate = IPQ_MDIO_CLK_RATE;
295 	if (priv->mdio_clk)
296 		ahb_rate = clk_get_rate(priv->mdio_clk);
297 
298 	/* Check what is the current div set */
299 	val = readl(priv->membase + MDIO_MODE_REG);
300 	div = FIELD_GET(MDIO_MODE_DIV_MASK, val);
301 
302 	/* div is not set to the default value of /256
303 	 * Probably someone changed that (bootloader, other drivers)
304 	 * Keep this and don't overwrite it.
305 	 */
306 	if (div != MDIO_MODE_DIV_256) {
307 		priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div + 1);
308 		return;
309 	}
310 
311 	/* If div is /256 assume nobody have set this value and
312 	 * try to find one MDC rate that is close the 802.3 spec of
313 	 * 2.5MHz
314 	 */
315 	for (div = 256; div >= 8; div /= 2) {
316 		/* Stop as soon as we found a divider that
317 		 * reached the closest value to 2.5MHz
318 		 */
319 		if (DIV_ROUND_UP(ahb_rate, div) > 2500000)
320 			break;
321 
322 		priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div);
323 	}
324 }
325 
ipq4019_mdio_probe(struct platform_device * pdev)326 static int ipq4019_mdio_probe(struct platform_device *pdev)
327 {
328 	struct ipq4019_mdio_data *priv;
329 	struct mii_bus *bus;
330 	struct resource *res;
331 	int ret;
332 
333 	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
334 	if (!bus)
335 		return -ENOMEM;
336 
337 	priv = bus->priv;
338 
339 	priv->membase = devm_platform_ioremap_resource(pdev, 0);
340 	if (IS_ERR(priv->membase))
341 		return PTR_ERR(priv->membase);
342 
343 	priv->mdio_clk = devm_clk_get_optional(&pdev->dev, "gcc_mdio_ahb_clk");
344 	if (IS_ERR(priv->mdio_clk))
345 		return PTR_ERR(priv->mdio_clk);
346 
347 	ipq4019_mdio_select_mdc_rate(pdev, priv);
348 	ret = ipq4019_mdio_set_div(priv);
349 	if (ret)
350 		return ret;
351 
352 	/* The platform resource is provided on the chipset IPQ5018 */
353 	/* This resource is optional */
354 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
355 	if (res)
356 		priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res);
357 
358 	bus->name = "ipq4019_mdio";
359 	bus->read = ipq4019_mdio_read_c22;
360 	bus->write = ipq4019_mdio_write_c22;
361 	bus->read_c45 = ipq4019_mdio_read_c45;
362 	bus->write_c45 = ipq4019_mdio_write_c45;
363 	bus->reset = ipq_mdio_reset;
364 	bus->parent = &pdev->dev;
365 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
366 
367 	ret = of_mdiobus_register(bus, pdev->dev.of_node);
368 	if (ret) {
369 		dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
370 		return ret;
371 	}
372 
373 	platform_set_drvdata(pdev, bus);
374 
375 	return 0;
376 }
377 
ipq4019_mdio_remove(struct platform_device * pdev)378 static void ipq4019_mdio_remove(struct platform_device *pdev)
379 {
380 	struct mii_bus *bus = platform_get_drvdata(pdev);
381 
382 	mdiobus_unregister(bus);
383 }
384 
385 static const struct of_device_id ipq4019_mdio_dt_ids[] = {
386 	{ .compatible = "qcom,ipq4019-mdio" },
387 	{ .compatible = "qcom,ipq5018-mdio" },
388 	{ }
389 };
390 MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids);
391 
392 static struct platform_driver ipq4019_mdio_driver = {
393 	.probe = ipq4019_mdio_probe,
394 	.remove_new = ipq4019_mdio_remove,
395 	.driver = {
396 		.name = "ipq4019-mdio",
397 		.of_match_table = ipq4019_mdio_dt_ids,
398 	},
399 };
400 
401 module_platform_driver(ipq4019_mdio_driver);
402 
403 MODULE_DESCRIPTION("ipq4019 MDIO interface driver");
404 MODULE_AUTHOR("Qualcomm Atheros");
405 MODULE_LICENSE("Dual BSD/GPL");
406